Branch data Line data Source code
1 : : /****************************************************************************** 2 : : * This file is part of the cvc5 project. 3 : : * 4 : : * Copyright (c) 2009-2026 by the authors listed in the file AUTHORS 5 : : * in the top-level source directory and their institutional affiliations. 6 : : * All rights reserved. See the file COPYING in the top-level source 7 : : * directory for licensing information. 8 : : * **************************************************************************** 9 : : * 10 : : * Implementation of equivalence class info for the theory of strings. 11 : : */ 12 : : 13 : : #include "theory/strings/eqc_info.h" 14 : : 15 : : #include "theory/strings/theory_strings_utils.h" 16 : : #include "theory/strings/word.h" 17 : : 18 : : using namespace std; 19 : : using namespace cvc5::context; 20 : : using namespace cvc5::internal::kind; 21 : : 22 : : namespace cvc5::internal { 23 : : namespace theory { 24 : : namespace strings { 25 : : 26 : 125724 : EqcInfo::EqcInfo(context::Context* c) 27 : 125724 : : d_lengthTerm(c), 28 : 125724 : d_codeTerm(c), 29 : 125724 : d_cardinalityLemK(c), 30 : 125724 : d_normalizedLength(c), 31 : 125724 : d_firstBound(c), 32 : 125724 : d_secondBound(c) 33 : : { 34 : 125724 : } 35 : : 36 : 156352 : Node EqcInfo::addEndpointConst(Node t, Node c, bool isSuf) 37 : : { 38 : : // check conflict 39 [ + + ]: 156352 : Node prev = isSuf ? d_secondBound : d_firstBound; 40 [ + + ]: 156352 : if (!prev.isNull()) 41 : : { 42 [ + - ]: 272596 : Trace("strings-eager-pconf-debug") << "Check conflict " << prev << ", " << t 43 : 136298 : << " post=" << isSuf << std::endl; 44 : 136298 : Node prevC = utils::getConstantEndpoint(prev, isSuf); 45 [ - + ][ - + ]: 136298 : Assert(!prevC.isNull()); [ - - ] 46 [ - + ][ - + ]: 136298 : Assert(prevC.isConst()); [ - - ] 47 [ + + ]: 136298 : if (c.isNull()) 48 : : { 49 : 136130 : c = utils::getConstantEndpoint(t, isSuf); 50 [ - + ][ - + ]: 136130 : Assert(!c.isNull()); [ - - ] 51 : : } 52 [ - + ][ - + ]: 136298 : Assert(c.isConst()); [ - - ] 53 : 136298 : bool conflict = false; 54 : : // if the constant prefixes are different 55 [ + + ]: 136298 : if (c != prevC) 56 : : { 57 : : // conflicts between constants should be handled by equality engine 58 [ - + ][ - - ]: 26886 : Assert(!t.isConst() || !prev.isConst()); [ - + ][ - + ] [ - - ] 59 [ + - ]: 53772 : Trace("strings-eager-pconf-debug") 60 : 26886 : << "Check conflict constants " << prevC << ", " << c << std::endl; 61 : 26886 : size_t pvs = Word::getLength(prevC); 62 : 26886 : size_t cvs = Word::getLength(c); 63 [ + + ][ + - ]: 26701 : if (pvs == cvs || (pvs > cvs && t.isConst()) 64 [ + + ][ + + ]: 53587 : || (cvs > pvs && prev.isConst())) [ + + ][ + + ] 65 : : { 66 : : // If equal length, cannot be equal due to node check above. 67 : : // If one is fully constant and has less length than the other, then the 68 : : // other will not fit and we are in conflict. 69 : 548 : conflict = true; 70 : : } 71 : : else 72 : : { 73 [ + + ]: 26338 : Node larges = pvs > cvs ? prevC : c; 74 [ + + ]: 26338 : Node smalls = pvs > cvs ? c : prevC; 75 [ + + ]: 26338 : if (isSuf) 76 : : { 77 : 19041 : conflict = !Word::hasSuffix(larges, smalls); 78 : : } 79 : : else 80 : : { 81 : 7297 : conflict = !Word::hasPrefix(larges, smalls); 82 : : } 83 : 26338 : } 84 [ + + ][ + + ]: 26886 : if (!conflict && (pvs > cvs || prev.isConst())) [ - + ][ + + ] 85 : : { 86 : : // current is subsumed, either shorter prefix or the other is a full 87 : : // constant 88 : 25609 : return Node::null(); 89 : : } 90 : : } 91 [ + - ]: 109412 : else if (!t.isConst()) 92 : : { 93 : : // current is subsumed since the other may be a full constant 94 : 109412 : return Node::null(); 95 : : } 96 [ + + ]: 1277 : if (conflict) 97 : : { 98 [ + - ]: 1536 : Trace("strings-eager-pconf") 99 : 768 : << "Conflict for " << prevC << ", " << c << std::endl; 100 : 1536 : Node ret = mkMergeConflict(t, prev, false); 101 [ + - ]: 1536 : Trace("strings-eager-pconf") 102 : 768 : << "String: eager prefix conflict: " << ret << std::endl; 103 : 768 : return ret; 104 : 768 : } 105 [ + + ]: 136298 : } 106 [ + + ]: 20563 : if (isSuf) 107 : : { 108 : 11774 : d_secondBound = t; 109 : : } 110 : : else 111 : : { 112 : 8789 : d_firstBound = t; 113 : : } 114 : 20563 : return Node::null(); 115 : 156352 : } 116 : : 117 : 1136 : Node EqcInfo::mkMergeConflict(Node t, Node prev, bool isArith) 118 : : { 119 [ + - ]: 2272 : Trace("strings-eager-debug") 120 : 1136 : << "mkMergeConflict " << t << ", " << prev << std::endl; 121 : 1136 : NodeManager* nm = t.getNodeManager(); 122 : 1136 : std::vector<Node> ccs; 123 [ + + ]: 6816 : Node r[2]; 124 [ + + ]: 3408 : for (unsigned i = 0; i < 2; i++) 125 : : { 126 [ + + ]: 2272 : Node tp = i == 0 ? t : prev; 127 [ + + ]: 2272 : if (tp.getKind() == Kind::STRING_IN_REGEXP) 128 : : { 129 : 387 : ccs.push_back(tp); 130 : 387 : r[i] = isArith ? nm->mkNode(Kind::STRING_LENGTH, tp[0]) : tp[0]; 131 : : } 132 : : else 133 : : { 134 : 1885 : r[i] = tp; 135 : : } 136 : 2272 : } 137 [ + - ]: 1136 : if (r[0] != r[1]) 138 : : { 139 : 1136 : ccs.push_back(r[0].eqNode(r[1])); 140 : : } 141 [ - + ][ - + ]: 1136 : Assert(!ccs.empty()); [ - - ] 142 : 2272 : return nm->mkAnd(ccs); 143 [ + + ][ - - ]: 4544 : } 144 : : 145 : : } // namespace strings 146 : : } // namespace theory 147 : : } // namespace cvc5::internal