1 /********************* */ 2 /*! \file equality_engine.h 3 ** \verbatim 4 ** Top contributors (to current version): 5 ** Dejan Jovanovic, Morgan Deters, Guy Katz 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 11 ** 12 ** \brief [[ Add one-line brief description here ]] 13 ** 14 ** [[ Add lengthier description here ]] 15 ** \todo document this file 16 **/ 17 18 #include "cvc4_private.h" 19 20 #pragma once 21 22 #include <deque> 23 #include <queue> 24 #include <memory> 25 #include <unordered_map> 26 #include <vector> 27 28 #include "base/output.h" 29 #include "context/cdhashmap.h" 30 #include "context/cdo.h" 31 #include "expr/kind_map.h" 32 #include "expr/node.h" 33 #include "theory/rewriter.h" 34 #include "theory/theory.h" 35 #include "theory/uf/equality_engine_types.h" 36 #include "util/statistics_registry.h" 37 38 namespace CVC4 { 39 namespace theory { 40 namespace eq { 41 42 43 class EqProof; 44 class EqClassesIterator; 45 class EqClassIterator; 46 47 /** 48 * Interface for equality engine notifications. All the notifications 49 * are safe as TNodes, but not necessarily for negations. 50 */ 51 class EqualityEngineNotify { 52 53 friend class EqualityEngine; 54 55 public: 56 ~EqualityEngineNotify()57 virtual ~EqualityEngineNotify() {}; 58 59 /** 60 * Notifies about a trigger equality that became true or false. 61 * 62 * @param equality the equality that became true or false 63 * @param value the value of the equality 64 */ 65 virtual bool eqNotifyTriggerEquality(TNode equality, bool value) = 0; 66 67 /** 68 * Notifies about a trigger predicate that became true or false. 69 * 70 * @param predicate the trigger predicate that became true or false 71 * @param value the value of the predicate 72 */ 73 virtual bool eqNotifyTriggerPredicate(TNode predicate, bool value) = 0; 74 75 /** 76 * Notifies about the merge of two trigger terms. 77 * 78 * @param tag the theory that both triggers were tagged with 79 * @param t1 a term marked as trigger 80 * @param t2 a term marked as trigger 81 * @param value true if equal, false if dis-equal 82 */ 83 virtual bool eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value) = 0; 84 85 /** 86 * Notifies about the merge of two constant terms. After this, all work is suspended and all you 87 * can do is ask for explanations. 88 * 89 * @param t1 a constant term 90 * @param t2 a constant term 91 */ 92 virtual void eqNotifyConstantTermMerge(TNode t1, TNode t2) = 0; 93 94 /** 95 * Notifies about the creation of a new equality class. 96 * 97 * @param t the term forming the new class 98 */ 99 virtual void eqNotifyNewClass(TNode t) = 0; 100 101 /** 102 * Notifies about the merge of two classes (just before the merge). 103 * 104 * @param t1 a term 105 * @param t2 a term 106 */ 107 virtual void eqNotifyPreMerge(TNode t1, TNode t2) = 0; 108 109 /** 110 * Notifies about the merge of two classes (just after the merge). 111 * 112 * @param t1 a term 113 * @param t2 a term 114 */ 115 virtual void eqNotifyPostMerge(TNode t1, TNode t2) = 0; 116 117 /** 118 * Notifies about the disequality of two terms. 119 * 120 * @param t1 a term 121 * @param t2 a term 122 * @param reason the reason 123 */ 124 virtual void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) = 0; 125 126 };/* class EqualityEngineNotify */ 127 128 /** 129 * Implementation of the notification interface that ignores all the 130 * notifications. 131 */ 132 class EqualityEngineNotifyNone : public EqualityEngineNotify { 133 public: eqNotifyTriggerEquality(TNode equality,bool value)134 bool eqNotifyTriggerEquality(TNode equality, bool value) override 135 { 136 return true; 137 } eqNotifyTriggerPredicate(TNode predicate,bool value)138 bool eqNotifyTriggerPredicate(TNode predicate, bool value) override 139 { 140 return true; 141 } eqNotifyTriggerTermEquality(TheoryId tag,TNode t1,TNode t2,bool value)142 bool eqNotifyTriggerTermEquality(TheoryId tag, 143 TNode t1, 144 TNode t2, 145 bool value) override 146 { 147 return true; 148 } eqNotifyConstantTermMerge(TNode t1,TNode t2)149 void eqNotifyConstantTermMerge(TNode t1, TNode t2) override {} eqNotifyNewClass(TNode t)150 void eqNotifyNewClass(TNode t) override {} eqNotifyPreMerge(TNode t1,TNode t2)151 void eqNotifyPreMerge(TNode t1, TNode t2) override {} eqNotifyPostMerge(TNode t1,TNode t2)152 void eqNotifyPostMerge(TNode t1, TNode t2) override {} eqNotifyDisequal(TNode t1,TNode t2,TNode reason)153 void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) override {} 154 };/* class EqualityEngineNotifyNone */ 155 156 /** 157 * An interface for equality engine notifications during equality path reconstruction. 158 * Can be used to add theory-specific logic for, e.g., proof construction. 159 */ 160 class PathReconstructionNotify { 161 public: 162 ~PathReconstructionNotify()163 virtual ~PathReconstructionNotify() {} 164 165 virtual void notify(unsigned reasonType, Node reason, Node a, Node b, 166 std::vector<TNode>& equalities, 167 EqProof* proof) const = 0; 168 }; 169 170 /** 171 * Class for keeping an incremental congruence closure over a set of terms. It provides 172 * notifications via an EqualityEngineNotify object. 173 */ 174 class EqualityEngine : public context::ContextNotifyObj { 175 176 friend class EqClassesIterator; 177 friend class EqClassIterator; 178 179 /** Default implementation of the notification object */ 180 static EqualityEngineNotifyNone s_notifyNone; 181 182 /** 183 * Master equality engine that gets all the equality information from 184 * this one, or null if none. 185 */ 186 EqualityEngine* d_masterEqualityEngine; 187 188 public: 189 190 /** 191 * Initialize the equality engine, given the notification class. 192 */ 193 EqualityEngine(EqualityEngineNotify& notify, context::Context* context, std::string name, bool constantsAreTriggers); 194 195 /** 196 * Initialize the equality engine with no notification class. 197 */ 198 EqualityEngine(context::Context* context, std::string name, bool constantsAreTriggers); 199 200 /** 201 * Just a destructor. 202 */ 203 virtual ~EqualityEngine(); 204 205 /** 206 * Set the master equality engine for this one. Master engine will get copies of all 207 * the terms and equalities from this engine. 208 */ 209 void setMasterEqualityEngine(EqualityEngine* master); 210 211 /** Statistics about the equality engine instance */ 212 struct Statistics { 213 /** Total number of merges */ 214 IntStat mergesCount; 215 /** Number of terms managed by the system */ 216 IntStat termsCount; 217 /** Number of function terms managed by the system */ 218 IntStat functionTermsCount; 219 /** Number of constant terms managed by the system */ 220 IntStat constantTermsCount; 221 222 Statistics(std::string name); 223 224 ~Statistics(); 225 };/* struct EqualityEngine::statistics */ 226 227 private: 228 229 /** The context we are using */ 230 context::Context* d_context; 231 232 /** If we are done, we don't except any new assertions */ 233 context::CDO<bool> d_done; 234 235 /** Whether to notify or not (temporarily disabled on equality checks) */ 236 bool d_performNotify; 237 238 /** The class to notify when a representative changes for a term */ 239 EqualityEngineNotify& d_notify; 240 241 /** The map of kinds to be treated as function applications */ 242 KindMap d_congruenceKinds; 243 244 /** The map of kinds to be treated as interpreted function applications (for evaluation of constants) */ 245 KindMap d_congruenceKindsInterpreted; 246 247 /** The map of kinds with operators to be considered external (for higher-order) */ 248 KindMap d_congruenceKindsExtOperators; 249 250 /** Objects that need to be notified during equality path reconstruction */ 251 std::map<unsigned, const PathReconstructionNotify*> d_pathReconstructionTriggers; 252 253 /** Map from nodes to their ids */ 254 std::unordered_map<TNode, EqualityNodeId, TNodeHashFunction> d_nodeIds; 255 256 /** Map from function applications to their ids */ 257 typedef std::unordered_map<FunctionApplication, EqualityNodeId, FunctionApplicationHashFunction> ApplicationIdsMap; 258 259 /** 260 * A map from a pair (a', b') to a function application f(a, b), where a' and b' are the current representatives 261 * of a and b. 262 */ 263 ApplicationIdsMap d_applicationLookup; 264 265 /** Application lookups in order, so that we can backtrack. */ 266 std::vector<FunctionApplication> d_applicationLookups; 267 268 /** Number of application lookups, for backtracking. */ 269 context::CDO<DefaultSizeType> d_applicationLookupsCount; 270 271 /** 272 * Store the application lookup, with enough information to backtrack 273 */ 274 void storeApplicationLookup(FunctionApplication& funNormalized, EqualityNodeId funId); 275 276 /** Map from ids to the nodes (these need to be nodes as we pick up the operators) */ 277 std::vector<Node> d_nodes; 278 279 /** A context-dependents count of nodes */ 280 context::CDO<DefaultSizeType> d_nodesCount; 281 282 /** Map from ids to the applications */ 283 std::vector<FunctionApplicationPair> d_applications; 284 285 /** Map from ids to the equality nodes */ 286 std::vector<EqualityNode> d_equalityNodes; 287 288 /** Number of asserted equalities we have so far */ 289 context::CDO<DefaultSizeType> d_assertedEqualitiesCount; 290 291 /** Memory for the use-list nodes */ 292 std::vector<UseListNode> d_useListNodes; 293 294 /** A fresh merge reason type to return upon request */ 295 unsigned d_freshMergeReasonType; 296 297 /** 298 * We keep a list of asserted equalities. Not among original terms, but 299 * among the class representatives. 300 */ 301 struct Equality { 302 /** Left hand side of the equality */ 303 EqualityNodeId lhs; 304 /** Right hand side of the equality */ 305 EqualityNodeId rhs; 306 /** Equality constructor */ 307 Equality(EqualityNodeId lhs = null_id, EqualityNodeId rhs = null_id) lhsEquality308 : lhs(lhs), rhs(rhs) {} 309 };/* struct EqualityEngine::Equality */ 310 311 /** The ids of the classes we have merged */ 312 std::vector<Equality> d_assertedEqualities; 313 314 /** The reasons for the equalities */ 315 316 /** 317 * An edge in the equality graph. This graph is an undirected graph (both edges added) 318 * containing the actual asserted equalities. 319 */ 320 class EqualityEdge { 321 322 // The id of the RHS of this equality 323 EqualityNodeId d_nodeId; 324 // The next edge 325 EqualityEdgeId d_nextId; 326 // Type of reason for this equality 327 unsigned d_mergeType; 328 // Reason of this equality 329 TNode d_reason; 330 331 public: 332 EqualityEdge()333 EqualityEdge(): 334 d_nodeId(null_edge), d_nextId(null_edge), d_mergeType(MERGED_THROUGH_CONGRUENCE) {} 335 EqualityEdge(EqualityNodeId nodeId,EqualityNodeId nextId,unsigned type,TNode reason)336 EqualityEdge(EqualityNodeId nodeId, EqualityNodeId nextId, unsigned type, TNode reason): 337 d_nodeId(nodeId), d_nextId(nextId), d_mergeType(type), d_reason(reason) {} 338 339 /** Returns the id of the next edge */ getNext()340 EqualityEdgeId getNext() const { return d_nextId; } 341 342 /** Returns the id of the target edge node */ getNodeId()343 EqualityNodeId getNodeId() const { return d_nodeId; } 344 345 /** The reason of this edge */ getReasonType()346 unsigned getReasonType() const { return d_mergeType; } 347 348 /** The reason of this edge */ getReason()349 TNode getReason() const { return d_reason; } 350 };/* class EqualityEngine::EqualityEdge */ 351 352 /** 353 * All the equality edges (twice as many as the number of asserted equalities. If an equality 354 * t1 = t2 is asserted, the edges added are -> t2, -> t1 (in this order). Hence, having the index 355 * of one of the edges you can reconstruct the original equality. 356 */ 357 std::vector<EqualityEdge> d_equalityEdges; 358 359 /** 360 * Returns the string representation of the edges. 361 */ 362 std::string edgesToString(EqualityEdgeId edgeId) const; 363 364 /** 365 * Map from a node to its first edge in the equality graph. Edges are added to the front of the 366 * list which makes the insertion/backtracking easy. 367 */ 368 std::vector<EqualityEdgeId> d_equalityGraph; 369 370 /** Add an edge to the equality graph */ 371 void addGraphEdge(EqualityNodeId t1, EqualityNodeId t2, unsigned type, TNode reason); 372 373 /** Returns the equality node of the given node */ 374 EqualityNode& getEqualityNode(TNode node); 375 376 /** Returns the equality node of the given node */ 377 const EqualityNode& getEqualityNode(TNode node) const; 378 379 /** Returns the equality node of the given node */ 380 EqualityNode& getEqualityNode(EqualityNodeId nodeId); 381 382 /** Returns the equality node of the given node */ 383 const EqualityNode& getEqualityNode(EqualityNodeId nodeId) const; 384 385 /** Returns the id of the node */ 386 EqualityNodeId getNodeId(TNode node) const; 387 388 /** 389 * Merge the class2 into class1 390 * @return true if ok, false if to break out 391 */ 392 bool merge(EqualityNode& class1, EqualityNode& class2, std::vector<TriggerId>& triggers); 393 394 /** Undo the merge of class2 into class1 */ 395 void undoMerge(EqualityNode& class1, EqualityNode& class2, EqualityNodeId class2Id); 396 397 /** Backtrack the information if necessary */ 398 void backtrack(); 399 400 /** 401 * Trigger that will be updated 402 */ 403 struct Trigger { 404 /** The current class id of the LHS of the trigger */ 405 EqualityNodeId classId; 406 /** Next trigger for class */ 407 TriggerId nextTrigger; 408 409 Trigger(EqualityNodeId classId = null_id, TriggerId nextTrigger = null_trigger) classIdTrigger410 : classId(classId), nextTrigger(nextTrigger) {} 411 };/* struct EqualityEngine::Trigger */ 412 413 /** 414 * Vector of triggers. Triggers come in pairs for an 415 * equality trigger (t1, t2): one at position 2k for t1, and one at position 2k + 1 for t2. When 416 * updating triggers we always know where the other one is (^1). 417 */ 418 std::vector<Trigger> d_equalityTriggers; 419 420 /** 421 * Vector of original equalities of the triggers. 422 */ 423 std::vector<TriggerInfo> d_equalityTriggersOriginal; 424 425 /** 426 * Context dependent count of triggers 427 */ 428 context::CDO<DefaultSizeType> d_equalityTriggersCount; 429 430 /** 431 * Trigger lists per node. The begin id changes as we merge, but the end always points to 432 * the actual end of the triggers for this node. 433 */ 434 std::vector<TriggerId> d_nodeTriggers; 435 436 /** 437 * Map from ids to whether they are constants (constants are always 438 * representatives of their class. 439 */ 440 std::vector<bool> d_isConstant; 441 442 /** 443 * Map from ids of proper terms, to the number of non-constant direct subterms. If we update an interpreted 444 * application to a constant, we can decrease this value. If we hit 0, we can evaluate the term. 445 * 446 */ 447 std::vector<unsigned> d_subtermsToEvaluate; 448 449 /** 450 * For nodes that we need to postpone evaluation. 451 */ 452 std::queue<EqualityNodeId> d_evaluationQueue; 453 454 /** 455 * Evaluate all terms in the evaluation queue. 456 */ 457 void processEvaluationQueue(); 458 459 /** Vector of nodes that evaluate. */ 460 std::vector<EqualityNodeId> d_subtermEvaluates; 461 462 /** Size of the nodes that evaluate vector. */ 463 context::CDO<unsigned> d_subtermEvaluatesSize; 464 465 /** Set the node evaluate flag */ 466 void subtermEvaluates(EqualityNodeId id); 467 468 /** 469 * Returns the evaluation of the term when all (direct) children are replaced with 470 * the constant representatives. 471 */ 472 Node evaluateTerm(TNode node); 473 474 /** 475 * Returns true if it's a constant 476 */ isConstant(EqualityNodeId id)477 bool isConstant(EqualityNodeId id) const { 478 return d_isConstant[getEqualityNode(id).getFind()]; 479 } 480 481 /** 482 * Map from ids to whether they are Boolean. 483 */ 484 std::vector<bool> d_isEquality; 485 486 /** 487 * Map from ids to whether the nods is internal. An internal node is a node 488 * that corresponds to a partially currified node, for example. 489 */ 490 std::vector<bool> d_isInternal; 491 492 /** 493 * Adds the trigger with triggerId to the beginning of the trigger list of the node with id nodeId. 494 */ 495 void addTriggerToList(EqualityNodeId nodeId, TriggerId triggerId); 496 497 /** Statistics */ 498 Statistics d_stats; 499 500 /** Add a new function application node to the database, i.e APP t1 t2 */ 501 EqualityNodeId newApplicationNode(TNode original, EqualityNodeId t1, EqualityNodeId t2, FunctionApplicationType type); 502 503 /** Add a new node to the database */ 504 EqualityNodeId newNode(TNode t); 505 506 /** Propagation queue */ 507 std::deque<MergeCandidate> d_propagationQueue; 508 509 /** Enqueue to the propagation queue */ 510 void enqueue(const MergeCandidate& candidate, bool back = true); 511 512 /** Do the propagation */ 513 void propagate(); 514 515 /** Are we in propagate */ 516 bool d_inPropagate; 517 518 /** 519 * Get an explanation of the equality t1 = t2. Returns the asserted equalities that 520 * imply t1 = t2. Returns TNodes as the assertion equalities should be hashed somewhere 521 * else. 522 */ 523 void getExplanation(EqualityEdgeId t1Id, EqualityNodeId t2Id, std::vector<TNode>& equalities, EqProof* eqp) const; 524 525 /** 526 * Print the equality graph. 527 */ 528 void debugPrintGraph() const; 529 530 /** The true node */ 531 Node d_true; 532 /** True node id */ 533 EqualityNodeId d_trueId; 534 535 /** The false node */ 536 Node d_false; 537 /** False node id */ 538 EqualityNodeId d_falseId; 539 540 /** 541 * Adds an equality of terms t1 and t2 to the database. 542 */ 543 void assertEqualityInternal(TNode t1, TNode t2, TNode reason, unsigned pid = MERGED_THROUGH_EQUALITY); 544 545 /** 546 * Adds a trigger equality to the database with the trigger node and polarity for notification. 547 */ 548 void addTriggerEqualityInternal(TNode t1, TNode t2, TNode trigger, bool polarity); 549 550 /** 551 * This method gets called on backtracks from the context manager. 552 */ contextNotifyPop()553 void contextNotifyPop() override { backtrack(); } 554 555 /** 556 * Constructor initialization stuff. 557 */ 558 void init(); 559 560 /** Set of trigger terms */ 561 struct TriggerTermSet { 562 /** Set of theories in this set */ 563 Theory::Set tags; 564 /** The trigger terms */ 565 EqualityNodeId triggers[0]; 566 /** Returns the theory tags */ hasTriggerTriggerTermSet567 Theory::Set hasTrigger(TheoryId tag) const { return Theory::setContains(tag, tags); } 568 /** Returns a trigger by tag */ getTriggerTriggerTermSet569 EqualityNodeId getTrigger(TheoryId tag) const { 570 return triggers[Theory::setIndex(tag, tags)]; 571 } 572 };/* struct EqualityEngine::TriggerTermSet */ 573 574 /** Are the constants triggers */ 575 bool d_constantsAreTriggers; 576 577 /** The information about trigger terms is stored in this easily maintained memory. */ 578 char* d_triggerDatabase; 579 580 /** Allocated size of the trigger term database */ 581 DefaultSizeType d_triggerDatabaseAllocatedSize; 582 583 /** Reference for the trigger terms set */ 584 typedef DefaultSizeType TriggerTermSetRef; 585 586 /** Null reference */ 587 static const TriggerTermSetRef null_set_id = (TriggerTermSetRef)(-1); 588 589 /** Create new trigger term set based on the internally set information */ 590 TriggerTermSetRef newTriggerTermSet(Theory::Set newSetTags, EqualityNodeId* newSetTriggers, unsigned newSetTriggersSize); 591 592 /** Get the trigger set give a reference */ getTriggerTermSet(TriggerTermSetRef ref)593 TriggerTermSet& getTriggerTermSet(TriggerTermSetRef ref) { 594 Assert(ref < d_triggerDatabaseSize); 595 return *(reinterpret_cast<TriggerTermSet*>(d_triggerDatabase + ref)); 596 } 597 598 /** Get the trigger set give a reference */ getTriggerTermSet(TriggerTermSetRef ref)599 const TriggerTermSet& getTriggerTermSet(TriggerTermSetRef ref) const { 600 Assert(ref < d_triggerDatabaseSize); 601 return *(reinterpret_cast<const TriggerTermSet*>(d_triggerDatabase + ref)); 602 } 603 604 /** Used part of the trigger term database */ 605 context::CDO<DefaultSizeType> d_triggerDatabaseSize; 606 607 struct TriggerSetUpdate { 608 EqualityNodeId classId; 609 TriggerTermSetRef oldValue; 610 TriggerSetUpdate(EqualityNodeId classId = null_id, TriggerTermSetRef oldValue = null_set_id) classIdTriggerSetUpdate611 : classId(classId), oldValue(oldValue) {} 612 };/* struct EqualityEngine::TriggerSetUpdate */ 613 614 /** 615 * List of trigger updates for backtracking. 616 */ 617 std::vector<TriggerSetUpdate> d_triggerTermSetUpdates; 618 619 /** 620 * Size of the individual triggers list. 621 */ 622 context::CDO<unsigned> d_triggerTermSetUpdatesSize; 623 624 /** 625 * Map from ids to the individual trigger set representatives. 626 */ 627 std::vector<TriggerTermSetRef> d_nodeIndividualTrigger; 628 629 typedef std::unordered_map<EqualityPair, DisequalityReasonRef, EqualityPairHashFunction> DisequalityReasonsMap; 630 631 /** 632 * A map from pairs of disequal terms, to the reason why we deduced they are disequal. 633 */ 634 DisequalityReasonsMap d_disequalityReasonsMap; 635 636 /** 637 * A list of all the disequalities we deduced. 638 */ 639 std::vector<EqualityPair> d_deducedDisequalities; 640 641 /** 642 * Context dependent size of the deduced disequalities 643 */ 644 context::CDO<size_t> d_deducedDisequalitiesSize; 645 646 /** 647 * For each disequality deduced, we add the pairs of equivalences needed to explain it. 648 */ 649 std::vector<EqualityPair> d_deducedDisequalityReasons; 650 651 /** 652 * Size of the memory for disequality reasons. 653 */ 654 context::CDO<size_t> d_deducedDisequalityReasonsSize; 655 656 /** 657 * Map from equalities to the tags that have received the notification. 658 */ 659 typedef context::CDHashMap<EqualityPair, Theory::Set, EqualityPairHashFunction> PropagatedDisequalitiesMap; 660 PropagatedDisequalitiesMap d_propagatedDisequalities; 661 662 /** 663 * Has this equality been propagated to anyone. 664 */ 665 bool hasPropagatedDisequality(EqualityNodeId lhsId, EqualityNodeId rhsId) const; 666 667 /** 668 * Has this equality been propagated to the tag owner. 669 */ 670 bool hasPropagatedDisequality(TheoryId tag, EqualityNodeId lhsId, EqualityNodeId rhsId) const; 671 672 /** 673 * Stores a propagated disequality for explanation purposes and remembers the reasons. The 674 * reasons should be pushed on the reasons vector. 675 */ 676 void storePropagatedDisequality(TheoryId tag, EqualityNodeId lhsId, EqualityNodeId rhsId); 677 678 /** 679 * An equality tagged with a set of tags. 680 */ 681 struct TaggedEquality { 682 /** Id of the equality */ 683 EqualityNodeId equalityId; 684 /** TriggerSet reference for the class of one of the sides */ 685 TriggerTermSetRef triggerSetRef; 686 /** Is trigger equivalent to the lhs (rhs otherwise) */ 687 bool lhs; 688 689 TaggedEquality(EqualityNodeId equalityId = null_id, TriggerTermSetRef triggerSetRef = null_set_id, bool lhs = true) equalityIdTaggedEquality690 : equalityId(equalityId), triggerSetRef(triggerSetRef), lhs(lhs) {} 691 }; 692 693 /** A map from equivalence class id's to tagged equalities */ 694 typedef std::vector<TaggedEquality> TaggedEqualitiesSet; 695 696 /** 697 * Returns a set of equalities that have been asserted false where one side of the equality 698 * belongs to the given equivalence class. The equalities are restricted to the ones where 699 * one side of the equality is in the tags set, but the other one isn't. Each returned 700 * dis-equality is associated with the tags that are the subset of the input tags, such that 701 * exactly one side of the equality is not in the set yet. 702 * 703 * @param classId the equivalence class to search 704 * @param inputTags the tags to filter the equalities 705 * @param out the output equalities, as described above 706 */ 707 void getDisequalities(bool allowConstants, EqualityNodeId classId, Theory::Set inputTags, TaggedEqualitiesSet& out); 708 709 /** 710 * Propagates the remembered disequalities with given tags the original triggers for those tags, 711 * and the set of disequalities produced by above. 712 */ 713 bool propagateTriggerTermDisequalities(Theory::Set tags, 714 TriggerTermSetRef triggerSetRef, const TaggedEqualitiesSet& disequalitiesToNotify); 715 716 /** Name of the equality engine */ 717 std::string d_name; 718 719 /** The internal addTerm */ 720 void addTermInternal(TNode t, bool isOperator = false); 721 722 public: 723 724 /** 725 * Adds a term to the term database. 726 */ addTerm(TNode t)727 void addTerm(TNode t) { 728 addTermInternal(t, false); 729 } 730 731 /** 732 * Add a kind to treat as function applications. 733 * When extOperator is true, this equality engine will treat the operators of this kind 734 * as "external" e.g. not internal nodes (see d_isInternal). This means that we will 735 * consider equivalence classes containing the operators of such terms, and "hasTerm" will 736 * return true. 737 */ 738 void addFunctionKind(Kind fun, bool interpreted = false, bool extOperator = false); 739 740 /** 741 * Returns true if this kind is used for congruence closure. 742 */ isFunctionKind(Kind fun)743 bool isFunctionKind(Kind fun) const { 744 return d_congruenceKinds.tst(fun); 745 } 746 747 /** 748 * Returns true if this kind is used for congruence closure + evaluation of constants. 749 */ isInterpretedFunctionKind(Kind fun)750 bool isInterpretedFunctionKind(Kind fun) const { 751 return d_congruenceKindsInterpreted.tst(fun); 752 } 753 754 /** 755 * Returns true if this kind has an operator that is considered external (e.g. not internal). 756 */ isExternalOperatorKind(Kind fun)757 bool isExternalOperatorKind(Kind fun) const { 758 return d_congruenceKindsExtOperators.tst(fun); 759 } 760 761 /** 762 * Check whether the node is already in the database. 763 */ 764 bool hasTerm(TNode t) const; 765 766 /** 767 * Adds a predicate p with given polarity. The predicate asserted 768 * should be in the congruence closure kinds (otherwise it's 769 * useless). 770 * 771 * @param p the (non-negated) predicate 772 * @param polarity true if asserting the predicate, false if 773 * asserting the negated predicate 774 * @param reason the reason to keep for building explanations 775 */ 776 void assertPredicate(TNode p, bool polarity, TNode reason, unsigned pid = MERGED_THROUGH_EQUALITY); 777 778 /** 779 * Adds predicate p and q and makes them equal. 780 */ 781 void mergePredicates(TNode p, TNode q, TNode reason); 782 783 /** 784 * Adds an equality eq with the given polarity to the database. 785 * 786 * @param eq the (non-negated) equality 787 * @param polarity true if asserting the equality, false if 788 * asserting the negated equality 789 * @param reason the reason to keep for building explanations 790 */ 791 void assertEquality(TNode eq, bool polarity, TNode reason, unsigned pid = MERGED_THROUGH_EQUALITY); 792 793 /** 794 * Returns the current representative of the term t. 795 */ 796 TNode getRepresentative(TNode t) const; 797 798 /** 799 * Add all the terms where the given term appears as a first child 800 * (directly or implicitly). 801 */ 802 void getUseListTerms(TNode t, std::set<TNode>& output); 803 804 /** 805 * Get an explanation of the equality t1 = t2 being true or false. 806 * Returns the reasons (added when asserting) that imply it 807 * in the assertions vector. 808 */ 809 void explainEquality(TNode t1, TNode t2, bool polarity, 810 std::vector<TNode>& assertions, 811 EqProof* eqp = nullptr) const; 812 813 /** 814 * Get an explanation of the predicate being true or false. 815 * Returns the reasons (added when asserting) that imply imply it 816 * in the assertions vector. 817 */ 818 void explainPredicate(TNode p, bool polarity, std::vector<TNode>& assertions, 819 EqProof* eqp = nullptr) const; 820 821 /** 822 * Add term to the set of trigger terms with a corresponding tag. The notify class will get 823 * notified when two trigger terms with the same tag become equal or dis-equal. The notification 824 * will not happen on all the terms, but only on the ones that are represent the class. Note that 825 * a term can be added more than once with different tags, and each tag appearance will merit 826 * it's own notification. 827 * 828 * @param t the trigger term 829 * @param theoryTag tag for this trigger (do NOT use THEORY_LAST) 830 */ 831 void addTriggerTerm(TNode t, TheoryId theoryTag); 832 833 /** 834 * Returns true if t is a trigger term or in the same equivalence 835 * class as some other trigger term. 836 */ 837 bool isTriggerTerm(TNode t, TheoryId theoryTag) const; 838 839 /** 840 * Returns the representative trigger term of the given term. 841 * 842 * @param t the term to check where isTriggerTerm(t) should be true 843 */ 844 TNode getTriggerTermRepresentative(TNode t, TheoryId theoryTag) const; 845 846 /** 847 * Adds a notify trigger for equality. When equality becomes true eqNotifyTriggerEquality 848 * will be called with value = true, and when equality becomes false eqNotifyTriggerEquality 849 * will be called with value = false. 850 */ 851 void addTriggerEquality(TNode equality); 852 853 /** 854 * Adds a notify trigger for the predicate p. When the predicate becomes true 855 * eqNotifyTriggerPredicate will be called with value = true, and when equality becomes false 856 * eqNotifyTriggerPredicate will be called with value = false. 857 */ 858 void addTriggerPredicate(TNode predicate); 859 860 /** 861 * Returns true if the two terms are equal. Requires both terms to 862 * be in the database. 863 */ 864 bool areEqual(TNode t1, TNode t2) const; 865 866 /** 867 * Check whether the two term are dis-equal. Requires both terms to 868 * be in the database. 869 */ 870 bool areDisequal(TNode t1, TNode t2, bool ensureProof) const; 871 872 /** 873 * Return the number of nodes in the equivalence class containing t 874 * Adds t if not already there. 875 */ 876 size_t getSize(TNode t); 877 878 /** 879 * Returns true if the engine is in a consistent state. 880 */ consistent()881 bool consistent() const { return !d_done; } 882 883 /** 884 * Marks an object for merge type based notification during equality path reconstruction. 885 */ 886 void addPathReconstructionTrigger(unsigned trigger, const PathReconstructionNotify* notify); 887 888 /** 889 * Returns a fresh merge reason type tag for the client to use. 890 */ 891 unsigned getFreshMergeReasonType(); 892 }; 893 894 /** 895 * Iterator to iterate over the equivalence classes. 896 */ 897 class EqClassesIterator { 898 const eq::EqualityEngine* d_ee; 899 size_t d_it; 900 public: 901 EqClassesIterator(); 902 EqClassesIterator(const eq::EqualityEngine* ee); 903 Node operator*() const; 904 bool operator==(const EqClassesIterator& i) const; 905 bool operator!=(const EqClassesIterator& i) const; 906 EqClassesIterator& operator++(); 907 EqClassesIterator operator++(int); 908 bool isFinished() const; 909 };/* class EqClassesIterator */ 910 911 /** 912 * Iterator to iterate over the equivalence class members. 913 */ 914 class EqClassIterator { 915 const eq::EqualityEngine* d_ee; 916 /** Starting node */ 917 EqualityNodeId d_start; 918 /** Current node */ 919 EqualityNodeId d_current; 920 public: 921 EqClassIterator(); 922 EqClassIterator(Node eqc, const eq::EqualityEngine* ee); 923 Node operator*() const; 924 bool operator==(const EqClassIterator& i) const; 925 bool operator!=(const EqClassIterator& i) const; 926 EqClassIterator& operator++(); 927 EqClassIterator operator++(int); 928 bool isFinished() const; 929 };/* class EqClassIterator */ 930 931 class EqProof 932 { 933 public: 934 class PrettyPrinter { 935 public: ~PrettyPrinter()936 virtual ~PrettyPrinter() {} 937 virtual std::string printTag(unsigned tag) = 0; 938 }; 939 EqProof()940 EqProof() : d_id(MERGED_THROUGH_REFLEXIVITY){} 941 unsigned d_id; 942 Node d_node; 943 std::vector<std::shared_ptr<EqProof>> d_children; 944 void debug_print(const char* c, unsigned tb = 0, 945 PrettyPrinter* prettyPrinter = nullptr) const; 946 };/* class EqProof */ 947 948 } // Namespace eq 949 } // Namespace theory 950 } // Namespace CVC4 951