This includes all minor remaining changes from proof-new for strings that were not merged to master.
This includes mostly minor changes to make proofs pass, including reordering assertions. It also removes some non-standard pedantic checks as these are now subsumed by standard ones.
It also makes the strings rewriter slightly more safe when checking arithmetic entailment under assumptions. This code used substitution, which was not safe when quantifiers were involved. This is replaced by capture avoiding substitution here.
#include "theory/strings/arith_entail.h"
#include "expr/attribute.h"
+#include "expr/node_algorithm.h"
#include "theory/arith/arith_msum.h"
#include "theory/rewriter.h"
#include "theory/strings/theory_strings_utils.h"
{
Assert(assumption.getKind() == kind::EQUAL);
Assert(Rewriter::rewrite(assumption) == assumption);
+ Trace("strings-entail") << "checkWithEqAssumption: " << assumption << " " << a
+ << ", strict=" << strict << std::endl;
// Find candidates variables to compute substitutions for
std::unordered_set<Node, NodeHashFunction> candVars;
// Could not solve for v
return false;
}
+ Trace("strings-entail") << "checkWithEqAssumption: subs " << v << " -> "
+ << solution << std::endl;
- a = a.substitute(TNode(v), TNode(solution));
+ // use capture avoiding substitution
+ a = expr::substituteCaptureAvoiding(a, v, solution);
return check(a, strict);
}
ei->d_cardinalityLemK.set(int_k + 1);
if (!cons.isConst() || !cons.getConst<bool>())
{
- std::vector<Node> emptyVec;
d_im.sendInference(
- emptyVec, expn, cons, Inference::CARDINALITY, true);
+ expn, expn, cons, Inference::CARDINALITY, false, true);
return;
}
}
}
if (!bei.d_exp.isNull())
{
- exp.push_back(bei.d_exp);
+ utils::flattenOp(AND, bei.d_exp, exp);
}
if (!bei.d_base.isNull())
{
Assert(!bei.d_bestContent.isNull());
if (!bei.d_exp.isNull())
{
- exp.push_back(bei.d_exp);
+ utils::flattenOp(AND, bei.d_exp, exp);
}
if (!bei.d_base.isNull())
{
ps.d_rule = PfRule::STRING_TRUST;
// add to stats
d_statistics.d_inferencesNoPf << infer;
- if (options::proofNewPedantic() > 0)
- {
- std::stringstream serr;
- serr << "InferProofCons::convert: Failed " << infer
- << (isRev ? " :rev " : " ") << conc << std::endl;
- for (const Node& ec : exp)
- {
- serr << " e: " << ec << std::endl;
- }
- Unhandled() << serr.str();
- }
}
if (Trace.isOn("strings-ipc-debug"))
{
unsigned new_val,
unsigned new_rev_val)
{
+ Assert(!exp.isConst());
if (std::find(d_exp.begin(), d_exp.end(), exp) == d_exp.end())
{
d_exp.push_back(exp);
Trace("strings-explain-prefix")
<< "Included " << curr_exp.size() << " / "
<< (nfi.d_exp.size() + nfj.d_exp.size()) << std::endl;
- if (nfi.d_base != nfj.d_base)
- {
- Node eq = nfi.d_base.eqNode(nfj.d_base);
- curr_exp.push_back(eq);
- }
+ // add explanation for why they are equal
+ Node eq = nfi.d_base.eqNode(nfj.d_base);
+ curr_exp.push_back(eq);
}
} // namespace strings
Trace("strings-lemma") << "Strings::Lemma SK-GEQ-ONE : " << len_geq_one
<< std::endl;
Trace("strings-assert") << "(assert " << len_geq_one << ")" << std::endl;
- if (options::proofNewPedantic() > 0)
- {
- Unhandled() << "Unhandled lemma Strings::Lemma SK-GEQ-ONE : "
- << len_geq_one << std::endl;
- }
return TrustNode::mkTrustLemma(len_geq_one, nullptr);
}
Trace("strings-lemma") << "Strings::Lemma SK-ONE : " << len_one
<< std::endl;
Trace("strings-assert") << "(assert " << len_one << ")" << std::endl;
- if (options::proofNewPedantic() > 0)
- {
- Unhandled() << "Unhandled lemma Strings::Lemma SK-ONE : " << len_one
- << std::endl;
- }
return TrustNode::mkTrustLemma(len_one, nullptr);
}
Assert(s == LENGTH_SPLIT);
{
Node ltp = sc->mkTypedSkolemCached(
nm->booleanType(), t, SkolemCache::SK_PURIFY, "ltp");
- Node k = nm->mkSkolem("k", nm->integerType());
+ Node k = SkolemCache::mkIndexVar(t);
std::vector<Node> conj;
conj.push_back(nm->mkNode(GEQ, k, zero));
}
conj.push_back(nm->mkNode(ITE, ite_ch));
+ Node conjn = nm->mkNode(
+ EXISTS, nm->mkNode(BOUND_VAR_LIST, k), nm->mkNode(AND, conj));
// Intuitively, the reduction says either x and y are equal, or they have
// some (maximal) common prefix after which their characters at position k
// are distinct, and the comparison of their code matches the return value
// assert:
// IF x=y
// THEN: ltp
- // ELSE: k >= 0 AND k <= len( x ) AND k <= len( y ) AND
+ // ELSE: exists k.
+ // k >= 0 AND k <= len( x ) AND k <= len( y ) AND
// substr( x, 0, k ) = substr( y, 0, k ) AND
// IF ltp
// THEN: str.code(substr( x, k, 1 )) < str.code(substr( y, k, 1 ))
// ELSE: str.code(substr( x, k, 1 )) > str.code(substr( y, k, 1 ))
- Node assert =
- nm->mkNode(ITE, t[0].eqNode(t[1]), ltp, nm->mkNode(AND, conj));
+ Node assert = nm->mkNode(ITE, t[0].eqNode(t[1]), ltp, conjn);
asserts.push_back(assert);
// Thus, str.<=( x, y ) = ltp