d_zero = NodeManager::currentNM()->mkConst( Rational( 0 ) );
d_one = NodeManager::currentNM()->mkConst( Rational( 1 ) );
d_neg_one = NodeManager::currentNM()->mkConst(Rational(-1));
- d_emptyString = Word::mkEmptyWord(CONST_STRING);
d_true = NodeManager::currentNM()->mkConst( true );
d_false = NodeManager::currentNM()->mkConst( false );
- d_type = NodeManager::currentNM()->stringType();
}
CoreSolver::~CoreSolver() {
<< "Found endpoint (in a) with non-empty b = " << b
<< ", whose flat form is " << d_flat_form[b] << std::endl;
// endpoint
+ Node emp = Word::mkEmptyWord(a.getType());
std::vector<Node> conc_c;
for (unsigned j = count; j < bsize; j++)
{
- conc_c.push_back(b[d_flat_form_index[b][j]].eqNode(d_emptyString));
+ conc_c.push_back(b[d_flat_form_index[b][j]].eqNode(emp));
}
Assert(!conc_c.empty());
conc = utils::mkAnd(conc_c);
<< "Found endpoint in b = " << b << ", whose flat form is "
<< d_flat_form[b] << std::endl;
// endpoint
+ Node emp = Word::mkEmptyWord(a.getType());
std::vector<Node> conc_c;
for (size_t j = count; j < asize; j++)
{
- conc_c.push_back(a[d_flat_form_index[a][j]].eqNode(d_emptyString));
+ conc_c.push_back(a[d_flat_form_index[a][j]].eqNode(emp));
}
Assert(!conc_c.empty());
conc = utils::mkAnd(conc_c);
}
ssize_t startj = isRev ? jj + 1 : 0;
ssize_t endj = isRev ? c.getNumChildren() : jj;
+ Node emp = Word::mkEmptyWord(a.getType());
for (ssize_t j = startj; j < endj; j++)
{
- if (d_state.areEqual(c[j], d_emptyString))
+ if (d_state.areEqual(c[j], emp))
{
- d_im.addToExplanation(c[j], d_emptyString, exp);
+ d_im.addToExplanation(c[j], emp, exp);
}
}
}
return eqc;
}else if( std::find( d_strings_eqc.begin(), d_strings_eqc.end(), eqc )==d_strings_eqc.end() ){
curr.push_back( eqc );
+ Node emp = Word::mkEmptyWord(eqc.getType());
//look at all terms in this equivalence class
eq::EqualityEngine* ee = d_state.getEqualityEngine();
eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, ee );
if( !d_bsolver.isCongruent(n) ){
if( n.getKind() == kind::STRING_CONCAT ){
Trace("strings-cycle") << eqc << " check term : " << n << " in " << eqc << std::endl;
- if( eqc!=d_emptyString ){
+ if (eqc != emp)
+ {
d_eqc[eqc].push_back( n );
}
for( unsigned i=0; i<n.getNumChildren(); i++ ){
Node nr = d_state.getRepresentative(n[i]);
- if( eqc==d_emptyString ){
+ if (eqc == emp)
+ {
//for empty eqc, ensure all components are empty
- if( nr!=d_emptyString ){
+ if (nr != emp)
+ {
std::vector<Node> exps;
- exps.push_back(n.eqNode(d_emptyString));
- d_im.sendInference(
- exps, n[i].eqNode(d_emptyString), "I_CYCLE_E");
+ exps.push_back(n.eqNode(emp));
+ d_im.sendInference(exps, n[i].eqNode(emp), "I_CYCLE_E");
return Node::null();
}
}else{
- if( nr!=d_emptyString ){
+ if (nr != emp)
+ {
d_flat_form[n].push_back( nr );
d_flat_form_index[n].push_back( i );
}
//can infer all other components must be empty
for( unsigned j=0; j<n.getNumChildren(); j++ ){
//take first non-empty
- if (j != i && !d_state.areEqual(n[j], d_emptyString))
+ if (j != i && !d_state.areEqual(n[j], emp))
{
- d_im.sendInference(
- exp, n[j].eqNode(d_emptyString), "I_CYCLE");
+ d_im.sendInference(exp, n[j].eqNode(emp), "I_CYCLE");
return Node::null();
}
}
std::map<Node, Node> eqc_to_exp;
for (const Node& eqc : d_strings_eqc)
{
+ TypeNode stype = eqc.getType();
Trace("strings-process-debug") << "- Verify normal forms are the same for "
<< eqc << std::endl;
- normalizeEquivalenceClass(eqc);
+ normalizeEquivalenceClass(eqc, stype);
Trace("strings-debug") << "Finished normalizing eqc..." << std::endl;
if (d_im.hasProcessed())
{
return;
}
NormalForm& nfe = getNormalForm(eqc);
- Node nf_term = utils::mkNConcat(nfe.d_nf, d_type);
+ Node nf_term = utils::mkNConcat(nfe.d_nf, stype);
std::map<Node, Node>::iterator itn = nf_to_eqc.find(nf_term);
if (itn != nf_to_eqc.end())
{
}
//compute d_normal_forms_(base,exp,exp_depend)[eqc]
-void CoreSolver::normalizeEquivalenceClass( Node eqc ) {
+void CoreSolver::normalizeEquivalenceClass(Node eqc, TypeNode stype)
+{
Trace("strings-process-debug") << "Process equivalence class " << eqc << std::endl;
- if (d_state.areEqual(eqc, d_emptyString))
+ Node emp = Word::mkEmptyWord(stype);
+ if (d_state.areEqual(eqc, emp))
{
#ifdef CVC4_ASSERTIONS
for( unsigned j=0; j<d_eqc[eqc].size(); j++ ){
Node n = d_eqc[eqc][j];
for( unsigned i=0; i<n.getNumChildren(); i++ ){
- Assert(d_state.areEqual(n[i], d_emptyString));
+ Assert(d_state.areEqual(n[i], emp));
}
}
#endif
//do nothing
Trace("strings-process-debug") << "Return process equivalence class " << eqc << " : empty." << std::endl;
- d_normal_form[eqc].init(d_emptyString);
+ d_normal_form[eqc].init(emp);
}
else
{
// map each term to its index in the above vector
std::map<Node, unsigned> term_to_nf_index;
// get the normal forms
- getNormalForms(eqc, normal_forms, term_to_nf_index);
+ getNormalForms(eqc, normal_forms, term_to_nf_index, stype);
if (d_im.hasProcessed())
{
return;
}
// process the normal forms
- processNEqc(normal_forms);
+ processNEqc(normal_forms, stype);
if (d_im.hasProcessed())
{
return;
if (!x.isConst())
{
Node xr = d_state.getRepresentative(x);
+ TypeNode stype = xr.getType();
std::map<Node, NormalForm>::iterator it = d_normal_form.find(xr);
if (it != d_normal_form.end())
{
NormalForm& nf = it->second;
- Node ret = utils::mkNConcat(nf.d_nf, d_type);
+ Node ret = utils::mkNConcat(nf.d_nf, stype);
nf_exp.insert(nf_exp.end(), nf.d_exp.begin(), nf.d_exp.end());
d_im.addToExplanation(x, nf.d_base, nf_exp);
Trace("strings-debug")
Node nc = getNormalString(x[i], nf_exp);
vec_nodes.push_back(nc);
}
- return utils::mkNConcat(vec_nodes, d_type);
+ return utils::mkNConcat(vec_nodes, stype);
}
}
return x;
}
void CoreSolver::getNormalForms(Node eqc,
- std::vector<NormalForm>& normal_forms,
- std::map<Node, unsigned>& term_to_nf_index)
+ std::vector<NormalForm>& normal_forms,
+ std::map<Node, unsigned>& term_to_nf_index,
+ TypeNode stype)
{
+ Node emp = Word::mkEmptyWord(stype);
//constant for equivalence class
Node eqc_non_c = eqc;
Trace("strings-process-debug") << "Get normal forms " << eqc << std::endl;
normal_forms.push_back(nf_curr);
}else{
//this was redundant: combination of self + empty string(s)
- Node nn = currv.size() == 0 ? d_emptyString : currv[0];
+ Node nn = currv.size() == 0 ? emp : currv[0];
Assert(d_state.areEqual(nn, eqc));
}
}else{
}
}
-void CoreSolver::processNEqc(std::vector<NormalForm>& normal_forms)
+void CoreSolver::processNEqc(std::vector<NormalForm>& normal_forms,
+ TypeNode stype)
{
//the possible inferences
std::vector< InferInfo > pinfer;
unsigned rindex = 0;
nfi.reverse();
nfj.reverse();
- processSimpleNEq(nfi, nfj, rindex, true, 0, pinfer);
+ processSimpleNEq(nfi, nfj, rindex, true, 0, pinfer, stype);
nfi.reverse();
nfj.reverse();
if (d_im.hasProcessed())
//rindex = 0;
unsigned index = 0;
- processSimpleNEq(nfi, nfj, index, false, rindex, pinfer);
+ processSimpleNEq(nfi, nfj, index, false, rindex, pinfer, stype);
if (d_im.hasProcessed())
{
return;
unsigned& index,
bool isRev,
unsigned rproc,
- std::vector<InferInfo>& pinfer)
+ std::vector<InferInfo>& pinfer,
+ TypeNode stype)
{
NodeManager* nm = NodeManager::currentNM();
eq::EqualityEngine* ee = d_state.getEqualityEngine();
+ Node emp = Word::mkEmptyWord(stype);
const std::vector<Node>& nfiv = nfi.d_nf;
const std::vector<Node>& nfjv = nfj.d_nf;
while (!d_state.isInConflict() && index_k < (nfkv.size() - rproc))
{
// can infer that this string must be empty
- Node eq = nfkv[index_k].eqNode(d_emptyString);
- Assert(!d_state.areEqual(d_emptyString, nfkv[index_k]));
+ Node eq = nfkv[index_k].eqNode(emp);
+ Assert(!d_state.areEqual(emp, nfkv[index_k]));
d_im.sendInference(curr_exp, eq, Inference::N_ENDPOINT_EMP);
index_k++;
}
eqnc.push_back(nfkv[i]);
}
}
- eqn[r] = utils::mkNConcat(eqnc, d_type);
+ eqn[r] = utils::mkNConcat(eqnc, stype);
}
if (!d_state.areEqual(eqn[0], eqn[1]))
{
Node nc = nfncv[index];
Assert(!nc.isConst()) << "Other string is not constant.";
Assert(nc.getKind() != STRING_CONCAT) << "Other string is not CONCAT.";
- if (!ee->areDisequal(nc, d_emptyString, true))
+ if (!ee->areDisequal(nc, emp, true))
{
// The non-constant side may be equal to the empty string. Split on
// whether it is.
//
// E.g. "abc" ++ ... = nc ++ ... ---> (nc = "") v (nc != "")
- Node eq = nc.eqNode(d_emptyString);
+ Node eq = nc.eqNode(emp);
eq = Rewriter::rewrite(eq);
if (eq.isConst())
{
// purify variable for this string to communicate that
// we have inferred whether it is empty.
Node p = d_skCache.mkSkolemCached(nc, SkolemCache::SK_PURIFY, "lsym");
- Node pEq = p.eqNode(d_emptyString);
+ Node pEq = p.eqNode(emp);
// should not be constant
Assert(!Rewriter::rewrite(pEq).isConst());
// infer the purification equality, and the (dis)equality
// At this point, we know that `nc` is non-empty, so we add that to our
// explanation.
- Node ncnz = nc.eqNode(d_emptyString).negate();
+ Node ncnz = nc.eqNode(emp).negate();
info.d_ant.push_back(ncnz);
size_t ncIndex = index + 1;
//
// E.g. "abc" ++ ... = nc ++ "b" ++ ... ---> nc = "a" ++ k
size_t cIndex = index;
- Node constStr = nfc.collectConstantStringAt(cIndex);
- Assert(!constStr.isNull());
- CVC4::String stra = constStr.getConst<String>();
- CVC4::String strb = nextConstStr.getConst<String>();
+ Node stra = nfc.collectConstantStringAt(cIndex);
+ size_t straLen = Word::getLength(stra);
+ Assert(!stra.isNull());
+ Node strb = nextConstStr;
// Since `nc` is non-empty, we start with character 1
size_t p;
if (isRev)
{
- CVC4::String stra1 = stra.prefix(stra.size() - 1);
- p = stra.size() - stra1.roverlap(strb);
- Trace("strings-csp-debug") << "Compute roverlap : " << constStr << " "
- << nextConstStr << std::endl;
- size_t p2 = stra1.rfind(strb);
+ Node stra1 = Word::prefix(stra, straLen - 1);
+ p = straLen - Word::roverlap(stra1, strb);
+ Trace("strings-csp-debug")
+ << "Compute roverlap : " << stra1 << " " << strb << std::endl;
+ size_t p2 = Word::rfind(stra1, strb);
p = p2 == std::string::npos ? p : (p > p2 + 1 ? p2 + 1 : p);
Trace("strings-csp-debug")
<< "roverlap : " << stra1 << " " << strb << " returned " << p
}
else
{
- CVC4::String stra1 = stra.substr(1);
- p = stra.size() - stra1.overlap(strb);
- Trace("strings-csp-debug") << "Compute overlap : " << constStr << " "
- << nextConstStr << std::endl;
- size_t p2 = stra1.find(strb);
+ Node stra1 = Word::substr(stra, 1);
+ p = straLen - Word::overlap(stra1, strb);
+ Trace("strings-csp-debug")
+ << "Compute overlap : " << stra1 << " " << strb << std::endl;
+ size_t p2 = Word::find(stra1, strb);
p = p2 == std::string::npos ? p : (p > p2 + 1 ? p2 + 1 : p);
Trace("strings-csp-debug")
<< "overlap : " << stra1 << " " << strb << " returned " << p
{
NormalForm::getExplanationForPrefixEq(
nfc, nfnc, cIndex, ncIndex, info.d_ant);
- Node prea = p == stra.size() ? constStr
- : nm->mkConst(isRev ? stra.suffix(p)
- : stra.prefix(p));
+ Node prea = p == straLen ? stra
+ : (isRev ? Word::suffix(stra, p)
+ : Word::prefix(stra, p));
Node sk = d_skCache.mkSkolemCached(
nc,
prea,
// to start with the first character of the constant.
//
// E.g. "abc" ++ ... = nc ++ ... ---> nc = "a" ++ k
- Node constStr = nfcv[index];
- CVC4::String stra = constStr.getConst<String>();
- Node firstChar = stra.size() == 1 ? constStr
- : nm->mkConst(isRev ? stra.suffix(1)
- : stra.prefix(1));
+ Node stra = nfcv[index];
+ size_t straLen = Word::getLength(stra);
+ Node firstChar = straLen == 1 ? stra
+ : (isRev ? Word::suffix(stra, 1)
+ : Word::prefix(stra, 1));
Node sk = d_skCache.mkSkolemCached(
nc,
isRev ? SkolemCache::SK_ID_VC_SPT_REV : SkolemCache::SK_ID_VC_SPT,
"c_spt");
Trace("strings-csp") << "Const Split: " << firstChar
- << " is removed from " << constStr << " (serial) "
+ << " is removed from " << stra << " (serial) "
<< std::endl;
NormalForm::getExplanationForPrefixEq(nfi, nfj, index, index, info.d_ant);
info.d_conc = nc.eqNode(isRev ? utils::mkNConcat(sk, firstChar)
for (unsigned xory = 0; xory < 2; xory++)
{
Node t = xory == 0 ? x : y;
- Node tnz = x.eqNode(d_emptyString).negate();
- if (ee->areDisequal(x, d_emptyString, true))
+ Node tnz = x.eqNode(emp).negate();
+ if (ee->areDisequal(x, emp, true))
{
info.d_ant.push_back(tnz);
}
const std::vector<Node>& veci = nfi.d_nf;
const std::vector<Node>& vecoi = nfj.d_nf;
+ TypeNode stype = veci[loop_index].getType();
+
Trace("strings-loop") << "Detected possible loop for " << veci[loop_index]
<< std::endl;
Trace("strings-loop") << " ... (X)= " << vecoi[index] << std::endl;
Trace("strings-loop") << " ... T(Y.Z)= ";
std::vector<Node> vec_t(veci.begin() + index, veci.begin() + loop_index);
- Node t_yz = utils::mkNConcat(vec_t, d_type);
+ Node t_yz = utils::mkNConcat(vec_t, stype);
Trace("strings-loop") << " (" << t_yz << ")" << std::endl;
Trace("strings-loop") << " ... S(Z.Y)= ";
std::vector<Node> vec_s(vecoi.begin() + index + 1, vecoi.end());
- Node s_zy = utils::mkNConcat(vec_s, d_type);
+ Node s_zy = utils::mkNConcat(vec_s, stype);
Trace("strings-loop") << s_zy << std::endl;
Trace("strings-loop") << " ... R= ";
std::vector<Node> vec_r(veci.begin() + loop_index + 1, veci.end());
- Node r = utils::mkNConcat(vec_r, d_type);
+ Node r = utils::mkNConcat(vec_r, stype);
Trace("strings-loop") << r << std::endl;
- if (s_zy.isConst() && r.isConst() && r != d_emptyString)
+ Node emp = Word::mkEmptyWord(stype);
+
+ if (s_zy.isConst() && r.isConst() && r != emp)
{
int c;
bool flag = true;
{
if (c >= 0)
{
- s_zy = nm->mkConst(s_zy.getConst<String>().substr(0, c));
- r = d_emptyString;
+ s_zy = Word::substr(s_zy, 0, c);
+ r = emp;
vec_r.clear();
Trace("strings-loop") << "Strings::Loop: Refactor S(Z.Y)= " << s_zy
<< ", c=" << c << std::endl;
for (unsigned i = 0; i < 2; i++)
{
Node t = i == 0 ? veci[loop_index] : t_yz;
- split_eq = t.eqNode(d_emptyString);
+ split_eq = t.eqNode(emp);
Node split_eqr = Rewriter::rewrite(split_eq);
// the equality could rewrite to false
if (!split_eqr.isConst())
{
- if (!d_state.areDisequal(t, d_emptyString))
+ if (!d_state.areDisequal(t, emp))
{
// try to make t equal to empty to avoid loop
info.d_conc = nm->mkNode(kind::OR, split_eq, split_eq.negate());
info.d_antn.push_back(ant);
Node str_in_re;
- if (s_zy == t_yz && r == d_emptyString && s_zy.isConst()
+ if (s_zy == t_yz && r == emp && s_zy.isConst()
&& s_zy.getConst<String>().isRepeated())
{
- Node rep_c = nm->mkConst(s_zy.getConst<String>().substr(0, 1));
+ Node rep_c = Word::substr(s_zy, 0, 1);
Trace("strings-loop") << "Special case (X)=" << vecoi[index] << " "
<< std::endl;
Trace("strings-loop") << "... (C)=" << rep_c << " " << std::endl;
Node z = Word::substr(t_yz, len, size - len);
Node restr = s_zy;
Node cc;
- if (r != d_emptyString)
+ if (r != emp)
{
std::vector<Node> v2(vec_r);
v2.insert(v2.begin(), y);
v2.insert(v2.begin(), z);
restr = utils::mkNConcat(z, y);
- cc = Rewriter::rewrite(s_zy.eqNode(utils::mkNConcat(v2, d_type)));
+ cc = Rewriter::rewrite(s_zy.eqNode(utils::mkNConcat(v2, stype)));
}
else
{
// s1 * ... * sk = z * y * r
vec_r.insert(vec_r.begin(), sk_y);
vec_r.insert(vec_r.begin(), sk_z);
- Node conc2 = s_zy.eqNode(utils::mkNConcat(vec_r, d_type));
+ Node conc2 = s_zy.eqNode(utils::mkNConcat(vec_r, stype));
Node conc3 = vecoi[index].eqNode(utils::mkNConcat(sk_y, sk_w));
- Node restr = r == d_emptyString ? s_zy : utils::mkNConcat(sk_z, sk_y);
+ Node restr = r == emp ? s_zy : utils::mkNConcat(sk_z, sk_y);
str_in_re =
nm->mkNode(kind::STRING_IN_REGEXP,
sk_w,
vec_conc.push_back(conc2);
vec_conc.push_back(conc3);
vec_conc.push_back(str_in_re);
- // vec_conc.push_back(sk_y.eqNode(d_emptyString).negate());//by mkskolems
conc = nm->mkNode(kind::AND, vec_conc);
} // normal case
Node const_k = i.isConst() ? i : j;
Node nconst_k = i.isConst() ? j : i;
Node lnck = i.isConst() ? lj : li;
- if( !ee->areDisequal( nconst_k, d_emptyString, true ) ){
- Node eq = nconst_k.eqNode( d_emptyString );
+ Node emp = Word::mkEmptyWord(nconst_k.getType());
+ if (!ee->areDisequal(nconst_k, emp, true))
+ {
+ Node eq = nconst_k.eqNode(emp);
Node conc = NodeManager::currentNM()->mkNode( kind::OR, eq, eq.negate() );
d_im.sendInference(d_emptyVec, conc, "D-DISL-Emp-Split");
return;
antec.end(), nfni.d_exp.begin(), nfni.d_exp.end());
antec.insert(
antec.end(), nfnj.d_exp.begin(), nfnj.d_exp.end());
- antec.push_back( nconst_k.eqNode( d_emptyString ).negate() );
+ antec.push_back(nconst_k.eqNode(emp).negate());
d_im.sendInference(
antec,
nm->mkNode(
Node sk3 = d_skCache.mkSkolemCached(
i, j, SkolemCache::SK_ID_DEQ_Z, "z_dsplit");
d_im.registerLength(sk3, LENGTH_GEQ_ONE);
- //Node nemp = sk3.eqNode(d_emptyString).negate();
- //conc.push_back(nemp);
Node lsk1 = utils::mkNLength(sk1);
conc.push_back( lsk1.eqNode( li ) );
Node lsk2 = utils::mkNLength(sk2);
}
}
}
+ TypeNode stype = ni.getType();
+ Node emp = Word::mkEmptyWord(stype);
NormalForm& nfni = getNormalForm(ni);
NormalForm& nfnj = getNormalForm(nj);
while( index<nfi.size() || index<nfj.size() ) {
std::vector< Node > cc;
std::vector< Node >& nfk = index>=nfi.size() ? nfj : nfi;
for( unsigned index_k=index; index_k<nfk.size(); index_k++ ){
- cc.push_back( nfk[index_k].eqNode( d_emptyString ) );
+ cc.push_back(nfk[index_k].eqNode(emp));
}
Node conc = cc.size()==1 ? cc[0] : NodeManager::currentNM()->mkNode( kind::AND, cc );
conc = Rewriter::rewrite( conc );
size_t lenI = Word::getLength(i);
size_t lenJ = Word::getLength(j);
unsigned int len_short = lenI < lenJ ? lenI : lenJ;
- bool isSameFix = isRev ? i.getConst<String>().rstrncmp(j.getConst<String>(), len_short): i.getConst<String>().strncmp(j.getConst<String>(), len_short);
+ bool isSameFix = isRev ? Word::rstrncmp(i, j, len_short)
+ : Word::strncmp(i, j, len_short);
if( isSameFix ) {
//same prefix/suffix
//k is the index of the string that is shorter
void CoreSolver::checkLengthsEqc() {
for (unsigned i = 0; i < d_strings_eqc.size(); i++)
{
+ TypeNode stype = d_strings_eqc[i].getType();
NormalForm& nfi = getNormalForm(d_strings_eqc[i]);
Trace("strings-process-debug")
<< "Process length constraints for " << d_strings_eqc[i] << std::endl;
// now, check if length normalization has occurred
if (ei->d_normalizedLength.get().isNull())
{
- Node nf = utils::mkNConcat(nfi.d_nf, d_type);
+ Node nf = utils::mkNConcat(nfi.d_nf, stype);
if (Trace.isOn("strings-process-debug"))
{
Trace("strings-process-debug")