1 /********************* */
2 /*! \file theory_model_builder.cpp
4 ** Top contributors (to current version):
5 ** Andrew Reynolds, Clark Barrett, Andres Noetzli
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
8 ** in the top-level source directory) and their institutional affiliations.
9 ** All rights reserved. See the file COPYING in the top-level source
10 ** directory for licensing information.\endverbatim
12 ** \brief Implementation of theory model buidler class
14 #include "theory/theory_model_builder.h"
16 #include "options/quantifiers_options.h"
17 #include "options/smt_options.h"
18 #include "options/uf_options.h"
19 #include "theory/theory_engine.h"
20 #include "theory/uf/theory_uf_model.h"
23 using namespace CVC4::kind
;
24 using namespace CVC4::context
;
29 TheoryEngineModelBuilder::TheoryEngineModelBuilder(TheoryEngine
* te
) : d_te(te
)
33 bool TheoryEngineModelBuilder::isAssignable(TNode n
)
35 if (n
.getKind() == kind::SELECT
|| n
.getKind() == kind::APPLY_SELECTOR_TOTAL
)
37 // selectors are always assignable (where we guarantee that they are not
41 Assert(!n
.getType().isFunction());
46 // might be a function field
47 return !n
.getType().isFunction();
50 else if (n
.getKind() == kind::FLOATINGPOINT_COMPONENT_SIGN
)
52 // Extracting the sign of a floating-point number acts similar to a
53 // selector on a datatype, i.e. if `(sign x)` wasn't assigned a value, we
54 // can pick an arbitrary one. Note that the other components of a
55 // floating-point number should always be assigned a value.
60 // non-function variables, and fully applied functions
63 // no functions exist, all functions are fully applied
64 Assert(n
.getKind() != kind::HO_APPLY
);
65 Assert(!n
.getType().isFunction());
66 return n
.isVar() || n
.getKind() == kind::APPLY_UF
;
70 // Assert( n.getKind() != kind::APPLY_UF );
71 return (n
.isVar() && !n
.getType().isFunction())
72 || n
.getKind() == kind::APPLY_UF
73 || (n
.getKind() == kind::HO_APPLY
74 && n
[0].getType().getNumChildren() == 2);
79 void TheoryEngineModelBuilder::addAssignableSubterms(TNode n
,
87 if (cache
.find(n
) != cache
.end())
93 tm
->d_equalityEngine
->addTerm(n
);
95 for (TNode::iterator child_it
= n
.begin(); child_it
!= n
.end(); ++child_it
)
97 addAssignableSubterms(*child_it
, tm
, cache
);
102 void TheoryEngineModelBuilder::assignConstantRep(TheoryModel
* tm
,
106 d_constantReps
[eqc
] = const_rep
;
107 Trace("model-builder") << " Assign: Setting constant rep of " << eqc
108 << " to " << const_rep
<< endl
;
109 tm
->d_rep_set
.setTermForRepresentative(const_rep
, eqc
);
112 bool TheoryEngineModelBuilder::isExcludedCdtValue(
114 std::set
<Node
>* repSet
,
115 std::map
<Node
, Node
>& assertedReps
,
118 Trace("model-builder-debug")
119 << "Is " << val
<< " and excluded codatatype value for " << eqc
<< "? "
121 for (set
<Node
>::iterator i
= repSet
->begin(); i
!= repSet
->end(); ++i
)
123 Assert(assertedReps
.find(*i
) != assertedReps
.end());
124 Node rep
= assertedReps
[*i
];
125 Trace("model-builder-debug") << " Rep : " << rep
<< std::endl
;
126 // check matching val to rep with eqc as a free variable
128 if (isCdtValueMatch(val
, rep
, eqc
, eqc_m
))
130 Trace("model-builder-debug") << " ...matches with " << eqc
<< " -> "
131 << eqc_m
<< std::endl
;
132 if (eqc_m
.getKind() == kind::UNINTERPRETED_CONSTANT
)
134 Trace("model-builder-debug") << "*** " << val
135 << " is excluded datatype for " << eqc
144 bool TheoryEngineModelBuilder::isCdtValueMatch(Node v
,
157 // only if an uninterpreted constant?
166 else if (v
.getKind() == kind::APPLY_CONSTRUCTOR
167 && r
.getKind() == kind::APPLY_CONSTRUCTOR
)
169 if (v
.getOperator() == r
.getOperator())
171 for (unsigned i
= 0; i
< v
.getNumChildren(); i
++)
173 if (!isCdtValueMatch(v
[i
], r
[i
], eqc
, eqc_m
))
184 bool TheoryEngineModelBuilder::involvesUSort(TypeNode tn
)
190 else if (tn
.isArray())
192 return involvesUSort(tn
.getArrayIndexType())
193 || involvesUSort(tn
.getArrayConstituentType());
197 return involvesUSort(tn
.getSetElementType());
199 else if (tn
.isDatatype())
201 const Datatype
& dt
= ((DatatypeType
)(tn
).toType()).getDatatype();
202 return dt
.involvesUninterpretedType();
210 bool TheoryEngineModelBuilder::isExcludedUSortValue(
211 std::map
<TypeNode
, unsigned>& eqc_usort_count
,
213 std::map
<Node
, bool>& visited
)
216 if (visited
.find(v
) == visited
.end())
219 TypeNode tn
= v
.getType();
222 Trace("model-builder-debug") << "Is excluded usort value : " << v
<< " "
224 unsigned card
= eqc_usort_count
[tn
];
225 Trace("model-builder-debug") << " Cardinality is " << card
<< std::endl
;
227 v
.getConst
<UninterpretedConstant
>().getIndex().toUnsignedInt();
228 Trace("model-builder-debug") << " Index is " << index
<< std::endl
;
229 return index
> 0 && index
>= card
;
231 for (unsigned i
= 0; i
< v
.getNumChildren(); i
++)
233 if (isExcludedUSortValue(eqc_usort_count
, v
[i
], visited
))
242 void TheoryEngineModelBuilder::addToTypeList(
244 std::vector
<TypeNode
>& type_list
,
245 std::unordered_set
<TypeNode
, TypeNodeHashFunction
>& visiting
)
247 if (std::find(type_list
.begin(), type_list
.end(), tn
) == type_list
.end())
249 if (visiting
.find(tn
) == visiting
.end())
252 /* This must make a recursive call on all types that are subterms of
253 * values of the current type.
254 * Note that recursive traversal here is over enumerated expressions
255 * (very low expression depth). */
258 addToTypeList(tn
.getArrayIndexType(), type_list
, visiting
);
259 addToTypeList(tn
.getArrayConstituentType(), type_list
, visiting
);
263 addToTypeList(tn
.getSetElementType(), type_list
, visiting
);
265 else if (tn
.isDatatype())
267 const Datatype
& dt
= ((DatatypeType
)(tn
).toType()).getDatatype();
268 for (unsigned i
= 0; i
< dt
.getNumConstructors(); i
++)
270 for (unsigned j
= 0; j
< dt
[i
].getNumArgs(); j
++)
272 TypeNode ctn
= TypeNode::fromType(dt
[i
][j
].getRangeType());
273 addToTypeList(ctn
, type_list
, visiting
);
277 Assert(std::find(type_list
.begin(), type_list
.end(), tn
)
279 type_list
.push_back(tn
);
284 bool TheoryEngineModelBuilder::buildModel(Model
* m
)
286 Trace("model-builder") << "TheoryEngineModelBuilder: buildModel" << std::endl
;
287 TheoryModel
* tm
= (TheoryModel
*)m
;
289 // buildModel should only be called once per check
290 Assert(!tm
->isBuilt());
296 tm
->d_modelBuilt
= true;
297 tm
->d_modelBuiltSuccess
= false;
299 // Collect model info from the theories
300 Trace("model-builder") << "TheoryEngineModelBuilder: Collect model info..."
302 if (!d_te
->collectModelInfo(tm
))
304 Trace("model-builder")
305 << "TheoryEngineModelBuilder: fail collect model info" << std::endl
;
309 Trace("model-builder")
310 << "TheoryEngineModelBuilder: Preprocess build model..." << std::endl
;
311 // model-builder specific initialization
312 if (!preProcessBuildModel(tm
))
314 Trace("model-builder")
315 << "TheoryEngineModelBuilder: fail preprocess build model."
320 Trace("model-builder")
321 << "TheoryEngineModelBuilder: Add assignable subterms..." << std::endl
;
322 // Loop through all terms and make sure that assignable sub-terms are in the
324 // Also, record #eqc per type (for finite model finding)
325 std::map
<TypeNode
, unsigned> eqc_usort_count
;
326 eq::EqClassesIterator eqcs_i
= eq::EqClassesIterator(tm
->d_equalityEngine
);
329 for (; !eqcs_i
.isFinished(); ++eqcs_i
)
331 eq::EqClassIterator eqc_i
=
332 eq::EqClassIterator((*eqcs_i
), tm
->d_equalityEngine
);
333 for (; !eqc_i
.isFinished(); ++eqc_i
)
335 addAssignableSubterms(*eqc_i
, tm
, cache
);
337 TypeNode tn
= (*eqcs_i
).getType();
340 if (eqc_usort_count
.find(tn
) == eqc_usort_count
.end())
342 eqc_usort_count
[tn
] = 1;
346 eqc_usort_count
[tn
]++;
352 Trace("model-builder") << "Collect representatives..." << std::endl
;
354 // Process all terms in the equality engine, store representatives for each EC
355 d_constantReps
.clear();
356 std::map
<Node
, Node
> assertedReps
;
357 TypeSet typeConstSet
, typeRepSet
, typeNoRepSet
;
358 TypeEnumeratorProperties tep
;
359 if (options::finiteModelFind())
361 tep
.d_fixed_usort_card
= true;
362 for (std::map
<TypeNode
, unsigned>::iterator it
= eqc_usort_count
.begin();
363 it
!= eqc_usort_count
.end();
366 Trace("model-builder") << "Fixed bound (#eqc) for " << it
->first
<< " : "
367 << it
->second
<< std::endl
;
368 tep
.d_fixed_card
[it
->first
] = Integer(it
->second
);
370 typeConstSet
.setTypeEnumeratorProperties(&tep
);
372 // AJR: build ordered list of types that ensures that base types are
374 // (I think) this is only strictly necessary for finite model finding +
375 // parametric types instantiated with uninterpreted sorts, but is probably
376 // a good idea to do in general since it leads to models with smaller term
378 std::vector
<TypeNode
> type_list
;
379 eqcs_i
= eq::EqClassesIterator(tm
->d_equalityEngine
);
380 for (; !eqcs_i
.isFinished(); ++eqcs_i
)
382 // eqc is the equivalence class representative
383 Node eqc
= (*eqcs_i
);
384 Trace("model-builder") << "Processing EC: " << eqc
<< endl
;
385 Assert(tm
->d_equalityEngine
->getRepresentative(eqc
) == eqc
);
386 TypeNode eqct
= eqc
.getType();
387 Assert(assertedReps
.find(eqc
) == assertedReps
.end());
388 Assert(d_constantReps
.find(eqc
) == d_constantReps
.end());
390 // Loop through terms in this EC
392 eq::EqClassIterator eqc_i
= eq::EqClassIterator(eqc
, tm
->d_equalityEngine
);
393 for (; !eqc_i
.isFinished(); ++eqc_i
)
396 Trace("model-builder") << " Processing Term: " << n
<< endl
;
397 // Record as rep if this node was specified as a representative
398 if (tm
->d_reps
.find(n
) != tm
->d_reps
.end())
400 // AJR: I believe this assertion is too strict,
401 // e.g. datatypes may assert representative for two constructor terms
402 // that are not in the care graph and are merged during
404 // Assert(rep.isNull());
406 Assert(!rep
.isNull());
407 Trace("model-builder") << " Rep( " << eqc
<< " ) = " << rep
410 // Record as const_rep if this node is constant
413 Assert(const_rep
.isNull());
415 Trace("model-builder") << " ConstRep( " << eqc
<< " ) = " << const_rep
418 // model-specific processing of the term
419 tm
->addTermInternal(n
);
422 // Assign representative for this EC
423 if (!const_rep
.isNull())
425 // Theories should not specify a rep if there is already a constant in the
427 // AJR: I believe this assertion is too strict, eqc with asserted reps may
428 // merge with constant eqc
429 // Assert(rep.isNull() || rep == const_rep);
430 assignConstantRep(tm
, eqc
, const_rep
);
431 typeConstSet
.add(eqct
.getBaseType(), const_rep
);
433 else if (!rep
.isNull())
435 assertedReps
[eqc
] = rep
;
436 typeRepSet
.add(eqct
.getBaseType(), eqc
);
437 std::unordered_set
<TypeNode
, TypeNodeHashFunction
> visiting
;
438 addToTypeList(eqct
.getBaseType(), type_list
, visiting
);
442 typeNoRepSet
.add(eqct
, eqc
);
443 std::unordered_set
<TypeNode
, TypeNodeHashFunction
> visiting
;
444 addToTypeList(eqct
, type_list
, visiting
);
448 // Need to ensure that each EC has a constant representative.
450 Trace("model-builder") << "Processing EC's..." << std::endl
;
452 TypeSet::iterator it
;
453 vector
<TypeNode
>::iterator type_it
;
454 set
<Node
>::iterator i
, i2
;
455 bool changed
, unassignedAssignable
, assignOne
= false;
456 set
<TypeNode
> evaluableSet
;
458 // Double-fixed-point loop
459 // Outer loop handles a special corner case (see code at end of loop for
463 // Inner fixed-point loop: we are trying to learn constant values for every
464 // EC. Each time through this loop, we process all of the
465 // types by type and may learn some new EC values. EC's in one type may
466 // depend on EC's in another type, so we need a fixed-point loop
467 // to ensure that we learn as many EC values as possible
471 unassignedAssignable
= false;
472 evaluableSet
.clear();
474 // Iterate over all types we've seen
475 for (type_it
= type_list
.begin(); type_it
!= type_list
.end(); ++type_it
)
477 TypeNode t
= *type_it
;
478 TypeNode tb
= t
.getBaseType();
479 set
<Node
>* noRepSet
= typeNoRepSet
.getSet(t
);
481 // 1. Try to evaluate the EC's in this type
482 if (noRepSet
!= NULL
&& !noRepSet
->empty())
484 Trace("model-builder") << " Eval phase, working on type: " << t
486 bool assignable
, evaluable
, evaluated
;
487 d_normalizedCache
.clear();
488 for (i
= noRepSet
->begin(); i
!= noRepSet
->end();)
495 Trace("model-builder-debug") << "Look at eqc : " << (*i2
)
497 eq::EqClassIterator eqc_i
=
498 eq::EqClassIterator(*i2
, tm
->d_equalityEngine
);
499 for (; !eqc_i
.isFinished(); ++eqc_i
)
502 Trace("model-builder-debug") << "Look at term : " << n
507 Trace("model-builder-debug") << "...assignable" << std::endl
;
512 Trace("model-builder-debug") << "...try to normalize"
514 Node normalized
= normalize(tm
, n
, true);
515 if (normalized
.isConst())
517 typeConstSet
.add(tb
, normalized
);
518 assignConstantRep(tm
, *i2
, normalized
);
519 Trace("model-builder") << " Eval: Setting constant rep of "
520 << (*i2
) << " to " << normalized
533 evaluableSet
.insert(tb
);
537 unassignedAssignable
= true;
543 // 2. Normalize any non-const representative terms for this type
544 set
<Node
>* repSet
= typeRepSet
.getSet(t
);
545 if (repSet
!= NULL
&& !repSet
->empty())
547 Trace("model-builder")
548 << " Normalization phase, working on type: " << t
<< endl
;
549 d_normalizedCache
.clear();
550 for (i
= repSet
->begin(); i
!= repSet
->end();)
552 Assert(assertedReps
.find(*i
) != assertedReps
.end());
553 Node rep
= assertedReps
[*i
];
554 Node normalized
= normalize(tm
, rep
, false);
555 Trace("model-builder") << " Normalizing rep (" << rep
556 << "), normalized to (" << normalized
<< ")"
558 if (normalized
.isConst())
561 typeConstSet
.add(tb
, normalized
);
562 assignConstantRep(tm
, *i
, normalized
);
563 assertedReps
.erase(*i
);
570 if (normalized
!= rep
)
572 assertedReps
[*i
] = normalized
;
582 if (!unassignedAssignable
)
587 // 3. Assign unassigned assignable EC's using type enumeration - assign a
588 // value *different* from all other EC's if the type is infinite
589 // Assign first value from type enumerator otherwise - for finite types, we
590 // rely on polite framework to ensure that EC's that have to be
591 // different are different.
593 // Only make assignments on a type if:
594 // 1. there are no terms that share the same base type with un-normalized
596 // 2. there are no terms that share teh same base type that are unevaluated
598 // Alternatively, if 2 or 3 don't hold but we are in a special
599 // deadlock-breaking mode where assignOne is true, go ahead and make one
602 // must iterate over the ordered type list to ensure that we do not
603 // enumerate values with subterms
604 // having types that we are currently enumerating (when possible)
605 // for example, this ensures we enumerate uninterpreted sort U before (List
606 // of U) and (Array U U)
607 // however, it does not break cyclic type dependencies for mutually
608 // recursive datatypes, but this is handled
609 // by recording all subterms of enumerated values in TypeSet::addSubTerms.
610 for (type_it
= type_list
.begin(); type_it
!= type_list
.end(); ++type_it
)
612 TypeNode t
= *type_it
;
613 // continue if there are no more equivalence classes of this type to
615 std::set
<Node
>* noRepSetPtr
= typeNoRepSet
.getSet(t
);
616 if (noRepSetPtr
== NULL
)
620 set
<Node
>& noRepSet
= *noRepSetPtr
;
621 if (noRepSet
.empty())
626 // get properties of this type
627 bool isCorecursive
= false;
630 const Datatype
& dt
= ((DatatypeType
)(t
).toType()).getDatatype();
632 dt
.isCodatatype() && (!dt
.isFinite(t
.toType())
633 || dt
.isRecursiveSingleton(t
.toType()));
635 #ifdef CVC4_ASSERTIONS
636 bool isUSortFiniteRestricted
= false;
637 if (options::finiteModelFind())
639 isUSortFiniteRestricted
= !t
.isSort() && involvesUSort(t
);
643 set
<Node
>* repSet
= typeRepSet
.getSet(t
);
644 TypeNode tb
= t
.getBaseType();
647 set
<Node
>* repSet
= typeRepSet
.getSet(tb
);
648 if (repSet
!= NULL
&& !repSet
->empty())
652 if (evaluableSet
.find(tb
) != evaluableSet
.end())
657 Trace("model-builder") << " Assign phase, working on type: " << t
659 bool assignable
, evaluable CVC4_UNUSED
;
660 for (i
= noRepSet
.begin(); i
!= noRepSet
.end();)
664 eq::EqClassIterator eqc_i
=
665 eq::EqClassIterator(*i2
, tm
->d_equalityEngine
);
668 for (; !eqc_i
.isFinished(); ++eqc_i
)
680 Trace("model-builder-debug")
681 << " eqc " << *i2
<< " is assignable=" << assignable
682 << ", evaluable=" << evaluable
<< std::endl
;
685 Assert(!evaluable
|| assignOne
);
686 // this assertion ensures that if we are assigning to a term of
687 // Boolean type, then the term is either a variable or an APPLY_UF.
688 // Note we only assign to terms of Boolean type if the term occurs in
689 // a singleton equivalence class; otherwise the term would have been
690 // in the equivalence class of true or false and would not need
692 Assert(!t
.isBoolean() || (*i2
).isVar()
693 || (*i2
).getKind() == kind::APPLY_UF
);
700 Trace("model-builder-debug") << "Enumerate term of type " << t
702 n
= typeConstSet
.nextTypeEnum(t
, true);
703 //--- AJR: this code checks whether n is a legal value
706 Trace("model-builder-debug") << "Check if excluded : " << n
708 #ifdef CVC4_ASSERTIONS
709 if (isUSortFiniteRestricted
)
711 // must not involve uninterpreted constants beyond cardinality
712 // bound (which assumed to coincide with #eqc)
713 // this is just an assertion now, since TypeEnumeratorProperties
714 // should ensure that only legal values are enumerated wrt this
716 std::map
<Node
, bool> visited
;
717 success
= !isExcludedUSortValue(eqc_usort_count
, n
, visited
);
720 Trace("model-builder")
721 << "Excluded value for " << t
<< " : " << n
722 << " due to out of range uninterpreted constant."
728 if (success
&& isCorecursive
)
730 if (repSet
!= NULL
&& !repSet
->empty())
732 // in the case of codatatypes, check if it is in the set of
733 // values that we cannot assign
734 success
= !isExcludedCdtValue(n
, repSet
, assertedReps
, *i2
);
737 Trace("model-builder")
738 << "Excluded value : " << n
739 << " due to alpha-equivalent codatatype expression."
749 TypeEnumerator
te(t
);
753 assignConstantRep(tm
, *i2
, n
);
765 // Corner case - I'm not sure this can even happen - but it's theoretically
766 // possible to have a cyclical dependency
767 // in EC assignment/evaluation, e.g. EC1 = {a, b + 1}; EC2 = {b, a - 1}. In
768 // this case, neither one will get assigned because we are waiting
769 // to be able to evaluate. But we will never be able to evaluate because
770 // the variables that need to be assigned are in
771 // these same EC's. In this case, repeat the whole fixed-point computation
772 // with the difference that the first EC
773 // that has both assignable and evaluable expressions will get assigned.
776 Assert(!assignOne
); // check for infinite loop!
781 #ifdef CVC4_ASSERTIONS
782 // Assert that all representatives have been converted to constants
783 for (it
= typeRepSet
.begin(); it
!= typeRepSet
.end(); ++it
)
785 set
<Node
>& repSet
= TypeSet::getSet(it
);
788 Trace("model-builder") << "***Non-empty repSet, size = " << repSet
.size()
789 << ", first = " << *(repSet
.begin()) << endl
;
793 #endif /* CVC4_ASSERTIONS */
795 Trace("model-builder") << "Copy representatives to model..." << std::endl
;
797 std::map
<Node
, Node
>::iterator itMap
;
798 for (itMap
= d_constantReps
.begin(); itMap
!= d_constantReps
.end(); ++itMap
)
800 tm
->d_reps
[itMap
->first
] = itMap
->second
;
801 tm
->d_rep_set
.add(itMap
->second
.getType(), itMap
->second
);
804 Trace("model-builder") << "Make sure ECs have reps..." << std::endl
;
805 // Make sure every EC has a rep
806 for (itMap
= assertedReps
.begin(); itMap
!= assertedReps
.end(); ++itMap
)
808 tm
->d_reps
[itMap
->first
] = itMap
->second
;
809 tm
->d_rep_set
.add(itMap
->second
.getType(), itMap
->second
);
811 for (it
= typeNoRepSet
.begin(); it
!= typeNoRepSet
.end(); ++it
)
813 set
<Node
>& noRepSet
= TypeSet::getSet(it
);
814 set
<Node
>::iterator i
;
815 for (i
= noRepSet
.begin(); i
!= noRepSet
.end(); ++i
)
818 tm
->d_rep_set
.add((*i
).getType(), *i
);
822 // modelBuilder-specific initialization
823 if (!processBuildModel(tm
))
825 Trace("model-builder")
826 << "TheoryEngineModelBuilder: fail process build model." << std::endl
;
829 Trace("model-builder") << "TheoryEngineModelBuilder: success" << std::endl
;
830 tm
->d_modelBuiltSuccess
= true;
834 void TheoryEngineModelBuilder::postProcessModel(bool incomplete
, Model
* m
)
836 // if we are incomplete, there is no guarantee on the model.
837 // thus, we do not check the model here.
842 TheoryModel
* tm
= static_cast<TheoryModel
*>(m
);
843 Assert(tm
!= nullptr);
844 // debug-check the model if the checkModels() is enabled.
845 if (options::checkModels())
851 void TheoryEngineModelBuilder::debugCheckModel(TheoryModel
* tm
)
853 #ifdef CVC4_ASSERTIONS
854 Assert(tm
->isBuilt());
855 eq::EqClassesIterator eqcs_i
= eq::EqClassesIterator(tm
->d_equalityEngine
);
856 std::map
<Node
, Node
>::iterator itMap
;
857 // Check that every term evaluates to its representative in the model
858 for (eqcs_i
= eq::EqClassesIterator(tm
->d_equalityEngine
);
859 !eqcs_i
.isFinished();
862 // eqc is the equivalence class representative
863 Node eqc
= (*eqcs_i
);
864 // get the representative
865 Node rep
= tm
->getRepresentative(eqc
);
866 if (!rep
.isConst() && eqc
.getType().isBoolean())
868 // if Boolean, it does not necessarily have a constant representative, use
870 rep
= tm
->getValue(eqc
);
871 Assert(rep
.isConst());
873 eq::EqClassIterator eqc_i
= eq::EqClassIterator(eqc
, tm
->d_equalityEngine
);
874 for (; !eqc_i
.isFinished(); ++eqc_i
)
877 static int repCheckInstance
= 0;
880 // non-linear mult is not necessarily accurate wrt getValue
881 if (n
.getKind() != kind::NONLINEAR_MULT
)
883 Debug("check-model::rep-checking") << "( " << repCheckInstance
<< ") "
884 << "n: " << n
<< endl
885 << "getValue(n): " << tm
->getValue(n
)
887 << "rep: " << rep
<< endl
;
888 Assert(tm
->getValue(*eqc_i
) == rep
)
889 << "run with -d check-model::rep-checking for details";
893 #endif /* CVC4_ASSERTIONS */
895 // builder-specific debugging
899 Node
TheoryEngineModelBuilder::normalize(TheoryModel
* m
, TNode r
, bool evalOnly
)
901 std::map
<Node
, Node
>::iterator itMap
= d_constantReps
.find(r
);
902 if (itMap
!= d_constantReps
.end())
904 return (*itMap
).second
;
906 NodeMap::iterator it
= d_normalizedCache
.find(r
);
907 if (it
!= d_normalizedCache
.end())
911 Trace("model-builder-debug") << "do normalize on " << r
<< std::endl
;
913 if (r
.getNumChildren() > 0)
915 std::vector
<Node
> children
;
916 if (r
.getMetaKind() == kind::metakind::PARAMETERIZED
)
918 children
.push_back(r
.getOperator());
920 bool childrenConst
= true;
921 for (size_t i
= 0; i
< r
.getNumChildren(); ++i
)
927 if (m
->d_equalityEngine
->hasTerm(ri
))
930 d_constantReps
.find(m
->d_equalityEngine
->getRepresentative(ri
));
931 if (itMap
!= d_constantReps
.end())
933 ri
= (*itMap
).second
;
943 ri
= normalize(m
, ri
, evalOnly
);
947 childrenConst
= false;
950 children
.push_back(ri
);
952 retNode
= NodeManager::currentNM()->mkNode(r
.getKind(), children
);
955 retNode
= Rewriter::rewrite(retNode
);
956 Assert(retNode
.getKind() == kind::APPLY_UF
957 || !retNode
.getType().isFirstClass() || retNode
.isConst());
960 d_normalizedCache
[r
] = retNode
;
964 bool TheoryEngineModelBuilder::preProcessBuildModel(TheoryModel
* m
)
969 bool TheoryEngineModelBuilder::processBuildModel(TheoryModel
* m
)
971 if (m
->areFunctionValuesEnabled())
978 void TheoryEngineModelBuilder::assignFunction(TheoryModel
* m
, Node f
)
980 Assert(!options::ufHo());
981 uf::UfModelTree
ufmt(f
);
983 for (size_t i
= 0; i
< m
->d_uf_terms
[f
].size(); i
++)
985 Node un
= m
->d_uf_terms
[f
][i
];
986 vector
<TNode
> children
;
987 children
.push_back(f
);
988 Trace("model-builder-debug") << " process term : " << un
<< std::endl
;
989 for (size_t j
= 0; j
< un
.getNumChildren(); ++j
)
991 Node rc
= m
->getRepresentative(un
[j
]);
992 Trace("model-builder-debug2") << " get rep : " << un
[j
] << " returned "
994 Assert(rc
.isConst());
995 children
.push_back(rc
);
997 Node simp
= NodeManager::currentNM()->mkNode(un
.getKind(), children
);
998 Node v
= m
->getRepresentative(un
);
999 Trace("model-builder") << " Setting (" << simp
<< ") to (" << v
<< ")"
1001 ufmt
.setValue(m
, simp
, v
);
1004 if (default_v
.isNull())
1006 // choose default value from model if none exists
1007 TypeEnumerator
te(f
.getType().getRangeType());
1010 ufmt
.setDefaultValue(m
, default_v
);
1011 bool condenseFuncValues
= options::condenseFunctionValues();
1012 if (condenseFuncValues
)
1016 std::stringstream ss
;
1018 Node val
= ufmt
.getFunctionValue(ss
.str().c_str(), condenseFuncValues
);
1019 m
->assignFunctionDefinition(f
, val
);
1020 // ufmt.debugPrint( std::cout, m );
1023 void TheoryEngineModelBuilder::assignHoFunction(TheoryModel
* m
, Node f
)
1025 Assert(options::ufHo());
1026 TypeNode type
= f
.getType();
1027 std::vector
<TypeNode
> argTypes
= type
.getArgTypes();
1028 std::vector
<Node
> args
;
1029 std::vector
<TNode
> apply_args
;
1030 for (unsigned i
= 0; i
< argTypes
.size(); i
++)
1032 Node v
= NodeManager::currentNM()->mkBoundVar(argTypes
[i
]);
1036 apply_args
.push_back(v
);
1039 // start with the base return value (currently we use the same default value
1040 // for all functions)
1041 TypeEnumerator
te(type
.getRangeType());
1043 std::map
<Node
, std::vector
<Node
> >::iterator itht
= m
->d_ho_uf_terms
.find(f
);
1044 if (itht
!= m
->d_ho_uf_terms
.end())
1046 for (size_t i
= 0; i
< itht
->second
.size(); i
++)
1048 Node hn
= itht
->second
[i
];
1049 Trace("model-builder-debug") << " process : " << hn
<< std::endl
;
1050 Assert(hn
.getKind() == kind::HO_APPLY
);
1051 Assert(m
->areEqual(hn
[0], f
));
1052 Node hni
= m
->getRepresentative(hn
[1]);
1053 Trace("model-builder-debug2") << " get rep : " << hn
[0]
1054 << " returned " << hni
<< std::endl
;
1055 Assert(hni
.isConst());
1056 Assert(hni
.getType().isSubtypeOf(args
[0].getType()));
1057 hni
= Rewriter::rewrite(args
[0].eqNode(hni
));
1058 Node hnv
= m
->getRepresentative(hn
);
1059 Trace("model-builder-debug2") << " get rep val : " << hn
1060 << " returned " << hnv
<< std::endl
;
1061 Assert(hnv
.isConst());
1062 if (!apply_args
.empty())
1064 Assert(hnv
.getKind() == kind::LAMBDA
1065 && hnv
[0].getNumChildren() + 1 == args
.size());
1066 std::vector
<TNode
> largs
;
1067 for (unsigned j
= 0; j
< hnv
[0].getNumChildren(); j
++)
1069 largs
.push_back(hnv
[0][j
]);
1071 Assert(largs
.size() == apply_args
.size());
1072 hnv
= hnv
[1].substitute(
1073 largs
.begin(), largs
.end(), apply_args
.begin(), apply_args
.end());
1074 hnv
= Rewriter::rewrite(hnv
);
1076 Assert(!TypeNode::leastCommonTypeNode(hnv
.getType(), curr
.getType())
1078 curr
= NodeManager::currentNM()->mkNode(kind::ITE
, hni
, hnv
, curr
);
1081 Node val
= NodeManager::currentNM()->mkNode(
1083 NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST
, args
),
1085 m
->assignFunctionDefinition(f
, val
);
1088 // This struct is used to sort terms by the "size" of their type
1089 // The size of the type is the number of nodes in the type, for example
1091 // size of Function( Int, Int ) is 3
1092 // size of Function( Function( Bool, Int ), Int ) is 5
1095 // stores the size of the type
1096 std::map
<TypeNode
, unsigned> d_type_size
;
1097 // get the size of type tn
1098 unsigned getTypeSize(TypeNode tn
)
1100 std::map
<TypeNode
, unsigned>::iterator it
= d_type_size
.find(tn
);
1101 if (it
!= d_type_size
.end())
1108 for (unsigned i
= 0; i
< tn
.getNumChildren(); i
++)
1110 sum
+= getTypeSize(tn
[i
]);
1112 d_type_size
[tn
] = sum
;
1118 // compares the type size of i and j
1119 // returns true iff the size of i is less than that of j
1120 // tiebreaks are determined by node value
1121 bool operator()(Node i
, Node j
)
1123 int si
= getTypeSize(i
.getType());
1124 int sj
= getTypeSize(j
.getType());
1140 void TheoryEngineModelBuilder::assignFunctions(TheoryModel
* m
)
1142 if (!options::assignFunctionValues())
1146 Trace("model-builder") << "Assigning function values..." << std::endl
;
1147 std::vector
<Node
> funcs_to_assign
= m
->getFunctionsToAssign();
1149 if (options::ufHo())
1151 // sort based on type size if higher-order
1152 Trace("model-builder") << "Sort functions by type..." << std::endl
;
1154 std::sort(funcs_to_assign
.begin(), funcs_to_assign
.end(), sts
);
1157 if (Trace
.isOn("model-builder"))
1159 Trace("model-builder") << "...have " << funcs_to_assign
.size()
1160 << " functions to assign:" << std::endl
;
1161 for (unsigned k
= 0; k
< funcs_to_assign
.size(); k
++)
1163 Node f
= funcs_to_assign
[k
];
1164 Trace("model-builder") << " [" << k
<< "] : " << f
<< " : "
1165 << f
.getType() << std::endl
;
1169 // construct function values
1170 for (unsigned k
= 0; k
< funcs_to_assign
.size(); k
++)
1172 Node f
= funcs_to_assign
[k
];
1173 Trace("model-builder") << " Function #" << k
<< " is " << f
<< std::endl
;
1174 // std::map< Node, std::vector< Node > >::iterator itht =
1175 // m->d_ho_uf_terms.find( f );
1176 if (!options::ufHo())
1178 Trace("model-builder") << " Assign function value for " << f
1179 << " based on APPLY_UF" << std::endl
;
1180 assignFunction(m
, f
);
1184 Trace("model-builder") << " Assign function value for " << f
1185 << " based on curried HO_APPLY" << std::endl
;
1186 assignHoFunction(m
, f
);
1189 Trace("model-builder") << "Finished assigning function values." << std::endl
;
1192 } /* namespace CVC4::theory */
1193 } /* namespace CVC4 */