mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 11:42:28 +00:00 
			
		
		
		
	Implement batch initialization fix for O(n²) datatype performance issue
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									115da30317
								
							
						
					
					
						commit
						b518327650
					
				
					 3 changed files with 55 additions and 0 deletions
				
			
		|  | @ -1121,6 +1121,56 @@ namespace datatype { | ||||||
|         return d; |         return d; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     void util::batch_initialize_constructor_functions(sort * datatype) { | ||||||
|  |         SASSERT(is_datatype(datatype)); | ||||||
|  |         def const& dd = get_def(datatype); | ||||||
|  |          | ||||||
|  |         // Get all constructors for this datatype
 | ||||||
|  |         ptr_vector<func_decl> const* constructors = get_datatype_constructors(datatype); | ||||||
|  |         if (!constructors) return; | ||||||
|  |          | ||||||
|  |         // Process all constructors in a single pass to avoid O(n²) behavior
 | ||||||
|  |         for (func_decl * con : *constructors) { | ||||||
|  |             // Initialize recognizer if not already cached
 | ||||||
|  |             if (!plugin().m_constructor2recognizer.contains(con)) { | ||||||
|  |                 symbol r; | ||||||
|  |                 for (constructor const* c : dd) { | ||||||
|  |                     if (c->name() == con->get_name()) { | ||||||
|  |                         r = c->recognizer(); | ||||||
|  |                         break; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 parameter ps[2] = { parameter(con), parameter(r) }; | ||||||
|  |                 func_decl* d = m.mk_func_decl(fid(), OP_DT_RECOGNISER, 2, ps, 1, &datatype); | ||||||
|  |                 plugin().add_ast(con); | ||||||
|  |                 plugin().add_ast(d); | ||||||
|  |                 plugin().m_constructor2recognizer.insert(con, d); | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             // Initialize accessors if not already cached
 | ||||||
|  |             if (!plugin().m_constructor2accessors.contains(con)) { | ||||||
|  |                 ptr_vector<func_decl>* res = alloc(ptr_vector<func_decl>); | ||||||
|  |                 plugin().add_ast(con); | ||||||
|  |                 plugin().m_vectors.push_back(res); | ||||||
|  |                 plugin().m_constructor2accessors.insert(con, res); | ||||||
|  |                  | ||||||
|  |                 if (con->get_arity() > 0) { | ||||||
|  |                     // Find the constructor definition and create accessors
 | ||||||
|  |                     for (constructor const* c : dd) { | ||||||
|  |                         if (c->name() == con->get_name()) { | ||||||
|  |                             for (accessor const* a : *c) { | ||||||
|  |                                 func_decl_ref fn = a->instantiate(datatype); | ||||||
|  |                                 res->push_back(fn); | ||||||
|  |                                 plugin().add_ast(fn); | ||||||
|  |                             } | ||||||
|  |                             break; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     app* util::mk_is(func_decl * c, expr *f) { |     app* util::mk_is(func_decl * c, expr *f) { | ||||||
|         return m.mk_app(get_constructor_is(c), f); |         return m.mk_app(get_constructor_is(c), f); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -373,6 +373,7 @@ namespace datatype { | ||||||
|         func_decl * get_constructor_recognizer(func_decl * constructor); |         func_decl * get_constructor_recognizer(func_decl * constructor); | ||||||
|         func_decl * get_constructor_is(func_decl * constructor); |         func_decl * get_constructor_is(func_decl * constructor); | ||||||
|         ptr_vector<func_decl> const * get_constructor_accessors(func_decl * constructor); |         ptr_vector<func_decl> const * get_constructor_accessors(func_decl * constructor); | ||||||
|  |         void batch_initialize_constructor_functions(sort * datatype); | ||||||
|         func_decl * get_accessor_constructor(func_decl * accessor); |         func_decl * get_accessor_constructor(func_decl * accessor); | ||||||
|         func_decl * get_recognizer_constructor(func_decl * recognizer) const; |         func_decl * get_recognizer_constructor(func_decl * recognizer) const; | ||||||
|         func_decl * get_update_accessor(func_decl * update) const; |         func_decl * get_update_accessor(func_decl * update) const; | ||||||
|  |  | ||||||
|  | @ -2471,6 +2471,10 @@ cmd_context::dt_eh::dt_eh(cmd_context & owner): | ||||||
| 
 | 
 | ||||||
| void cmd_context::dt_eh::operator()(sort * dt, pdecl* pd) { | void cmd_context::dt_eh::operator()(sort * dt, pdecl* pd) { | ||||||
|     TRACE(new_dt_eh, tout << "new datatype: "; m_owner.pm().display(tout, dt); tout << "\n";); |     TRACE(new_dt_eh, tout << "new datatype: "; m_owner.pm().display(tout, dt); tout << "\n";); | ||||||
|  |      | ||||||
|  |     // Batch initialize all constructor functions to avoid O(n²) behavior for large datatypes  
 | ||||||
|  |     m_dt_util.batch_initialize_constructor_functions(dt); | ||||||
|  |      | ||||||
|     for (func_decl * c : *m_dt_util.get_datatype_constructors(dt)) { |     for (func_decl * c : *m_dt_util.get_datatype_constructors(dt)) { | ||||||
|         TRACE(new_dt_eh, tout << "new constructor: " << c->get_name() << "\n";); |         TRACE(new_dt_eh, tout << "new constructor: " << c->get_name() << "\n";); | ||||||
|         m_owner.insert(c); |         m_owner.insert(c); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue