This PR adds support for seq.nth operator by eliminating it during expandDefinitions, based on sub-sequences.
Tests that use this operator are also included.
{SEQ_SUFFIX, CVC4::Kind::STRING_SUFFIX},
{CONST_SEQUENCE, CVC4::Kind::CONST_SEQUENCE},
{SEQ_UNIT, CVC4::Kind::SEQ_UNIT},
+ {SEQ_NTH, CVC4::Kind::SEQ_NTH},
/* Quantifiers --------------------------------------------------------- */
{FORALL, CVC4::Kind::FORALL},
{EXISTS, CVC4::Kind::EXISTS},
{CVC4::Kind::REGEXP_COMPLEMENT, REGEXP_COMPLEMENT},
{CVC4::Kind::CONST_SEQUENCE, CONST_SEQUENCE},
{CVC4::Kind::SEQ_UNIT, SEQ_UNIT},
+ {CVC4::Kind::SEQ_NTH, SEQ_NTH},
/* Quantifiers ----------------------------------------------------- */
{CVC4::Kind::FORALL, FORALL},
{CVC4::Kind::EXISTS, EXISTS},
* mkTerm(Kind kind, Term child1)
*/
SEQ_UNIT,
+ /**
+ * Sequence nth, corresponding to the nth element of a sequence.
+ * Parameters: 2
+ * -[1] Sequence term.
+ * -[2] Integer term.
+ * Create with:
+ * mkTerm(Kind kind, Term child1, Term child2)
+ */
+ SEQ_NTH,
/* Quantifiers ----------------------------------------------------------- */
addOperator(api::SEQ_REV, "seq.rev");
addOperator(api::SEQ_REPLACE_ALL, "seq.replace_all");
addOperator(api::SEQ_UNIT, "seq.unit");
+ addOperator(api::SEQ_NTH, "seq.nth");
}
// at the moment, we only use this syntax for smt2.6
if (getLanguage() == language::input::LANG_SMTLIB_V2_6
case kind::REGEXP_EMPTY:
case kind::REGEXP_SIGMA:
case kind::SEQ_UNIT:
+ case kind::SEQ_NTH:
case kind::SEQUENCE_TYPE: out << smtKindString(k, d_variant) << " "; break;
case kind::CARDINALITY_CONSTRAINT: out << "fmf.card "; break;
case kind::REGEXP_COMPLEMENT: return "re.comp";
case kind::SEQUENCE_TYPE: return "Seq";
case kind::SEQ_UNIT: return "seq.unit";
+ case kind::SEQ_NTH: return "seq.nth";
//sep theory
case kind::SEP_STAR: return "sep";
Notice() << "SmtEngine::checkModel(): checking assertion " << assertion
<< endl;
Node n = assertion;
-
+ Node nr = Rewriter::rewrite(substitutions.apply(n));
+ Trace("boolean-terms") << "n: " << n << endl;
+ Trace("boolean-terms") << "nr: " << nr << endl;
+ if (nr.isConst() && nr.getConst<bool>())
+ {
+ continue;
+ }
// Apply any define-funs from the problem.
{
unordered_map<Node, Node, NodeHashFunction> cache;
"a sequence of characters"
operator SEQ_UNIT 1 "a sequence of length one"
+operator SEQ_NTH 2 "The nth element of a sequence"
# equal equal / less than / output
operator STRING_TO_REGEXP 1 "convert string to regexp"
typerule CONST_SEQUENCE ::CVC4::theory::strings::ConstSequenceTypeRule
typerule SEQ_UNIT ::CVC4::theory::strings::SeqUnitTypeRule
+typerule SEQ_NTH ::CVC4::theory::strings::SeqNthTypeRule
endtheory
case Rewrite::LEN_SEQ_UNIT: return "LEN_SEQ_UNIT";
case Rewrite::CHARAT_ELIM: return "CHARAT_ELIM";
case Rewrite::SEQ_UNIT_EVAL: return "SEQ_UNIT_EVAL";
+ case Rewrite::SEQ_NTH_EVAL: return "SEQ_NTH_EVAL";
default: return "?";
}
}
LEN_CONV_INV,
LEN_SEQ_UNIT,
CHARAT_ELIM,
- SEQ_UNIT_EVAL
+ SEQ_UNIT_EVAL,
+ SEQ_NTH_EVAL
};
/**
{
retNode = rewriteSeqUnit(node);
}
+ else if (nk == SEQ_NTH)
+ {
+ retNode = rewriteSeqNth(node);
+ }
Trace("sequences-postrewrite")
<< "Strings::SequencesRewriter::postRewrite returning " << retNode
return RewriteResponse(REWRITE_DONE, node);
}
+Node SequencesRewriter::rewriteSeqNth(Node node)
+{
+ Assert(node.getKind() == SEQ_NTH);
+ Node ret;
+ Node s = node[0];
+ Node i = node[1];
+ if (s.isConst() && i.isConst())
+ {
+ size_t len = Word::getLength(s);
+ size_t pos = i.getConst<Rational>().getNumerator().toUnsignedInt();
+ if (pos < len)
+ {
+ std::vector<Node> elements = Word::getChars(s);
+ ret = elements[pos];
+ return returnRewrite(node, ret, Rewrite::SEQ_NTH_EVAL);
+ }
+ else
+ {
+ return node;
+ }
+ }
+ else
+ {
+ return node;
+ }
+}
+
Node SequencesRewriter::rewriteCharAt(Node node)
{
Assert(node.getKind() == STRING_CHARAT);
*/
Node rewriteSeqUnit(Node node);
+ /** rewrite seq.nth
+ * This is the entry point for post-rewriting terms n of the form
+ * seq.nth(s, i)
+ * Returns the rewritten form of node.
+ */
+ Node rewriteSeqNth(Node node);
+
/** length preserving rewrite
*
* Given input n, this returns a string n' whose length is equivalent to n.
// where b is a regular expression, n is the number of occurrences of b
// in a, and k(0)=0.
SK_OCCUR_LEN,
+ // For function k: ((Seq U) x Int) -> U
+ // exists k.
+ // forall s, n.
+ // k(s, n) is some undefined value of sort U
+ SK_NTH,
};
/**
* Returns a skolem of type string that is cached for (a,b,id) and has
return TrustNode::mkTrustRewrite(node, ret, nullptr);
}
+ if (node.getKind() == SEQ_NTH)
+ {
+ // str.nth(s,i) --->
+ // ite(0<=i<=len(s), witness k. 0<=i<=len(s)->unit(k) = seq.at(s,i),
+ // uf(s,i))
+ NodeManager* nm = NodeManager::currentNM();
+ Node s = node[0];
+ Node i = node[1];
+ Node len = nm->mkNode(STRING_LENGTH, s);
+ Node cond =
+ nm->mkNode(AND, nm->mkNode(LEQ, d_zero, i), nm->mkNode(LT, i, len));
+ TypeNode elemType = s.getType().getSequenceElementType();
+ Node k = nm->mkBoundVar(elemType);
+ Node bvl = nm->mkNode(BOUND_VAR_LIST, k);
+ std::vector<TypeNode> argTypes;
+ argTypes.push_back(s.getType());
+ argTypes.push_back(nm->integerType());
+ TypeNode ufType = nm->mkFunctionType(argTypes, elemType);
+ SkolemCache* sc = d_termReg.getSkolemCache();
+ Node uf = sc->mkTypedSkolemCached(
+ ufType, Node::null(), Node::null(), SkolemCache::SK_NTH, "Uf");
+ Node ret = nm->mkNode(
+ ITE,
+ cond,
+ nm->mkNode(WITNESS,
+ bvl,
+ nm->mkNode(IMPLIES,
+ cond,
+ nm->mkNode(SEQ_UNIT, k)
+ .eqNode(nm->mkNode(STRING_CHARAT, s, i)))),
+ nm->mkNode(APPLY_UF, uf, s, i));
+ return TrustNode::mkTrustRewrite(node, ret, nullptr);
+ }
+
return TrustNode::null();
}
}
};
+class SeqNthTypeRule
+{
+ public:
+ static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ {
+ TypeNode t = n[0].getType(check);
+ TypeNode t1 = t.getSequenceElementType();
+ if (check)
+ {
+ if (!t.isSequence())
+ {
+ throw TypeCheckingExceptionPrivate(n, "expecting a sequence in nth");
+ }
+ TypeNode t2 = n[1].getType(check);
+ if (!t2.isInteger())
+ {
+ throw TypeCheckingExceptionPrivate(
+ n, "expecting an integer start term in nth");
+ }
+ }
+ return t1;
+ }
+};
+
/** Properties of the sequence type */
struct SequenceProperties
{
regress0/sep/skolem_emp.smt2
regress0/sep/trees-1.smt2
regress0/sep/wand-crash.smt2
+ regress0/seq/intseq.smt2
+ regress0/seq/intseq_dt.smt2
regress0/seq/seq-2var.smt2
regress0/seq/seq-ex1.smt2
regress0/seq/seq-ex2.smt2
regress0/seq/seq-ex5-dd.smt2
regress0/seq/seq-ex5.smt2
regress0/seq/seq-nemp.smt2
+ regress0/seq/seq-nth.smt2
+ regress0/seq/seq-nth-uf.smt2
+ regress0/seq/seq-nth-uf-z.smt2
+ regress0/seq/seq-nth-undef.smt2
regress0/seq/seq-rewrites.smt2
regress0/sets/abt-min.smt2
regress0/sets/abt-te-exh.smt2
--- /dev/null
+;EXPECT: unsat
+(set-logic ALL)
+(declare-fun tickleBool (Bool) Bool)
+(assert (and (tickleBool true) (tickleBool false)))
+(declare-fun ControlFlow (Int Int) Int)
+(declare-fun s@0 () (Seq Int))
+(declare-fun s@1 () (Seq Int))
+(declare-fun s@2 () (Seq Int))
+(assert (not
+ (=> (= (ControlFlow 0 0) 170) (let ((anon0_correct (=> (= s@0 (seq.++ (as seq.empty (Seq Int)) (seq.unit 0))) (=> (and (= s@1 (seq.++ s@0 (seq.unit 1))) (= s@2 (seq.++ s@1 (seq.unit 2)))) (and (=> (= (ControlFlow 0 135) (- 0 217)) (= (seq.len s@2) 3)) (=> (= (seq.len s@2) 3) (=> (= (ControlFlow 0 135) (- 0 224)) (= (seq.extract s@2 1 2) (seq.++ (seq.unit 1) (seq.unit 2))))))))))
+(let ((PreconditionGeneratedEntry_correct (=> (= (ControlFlow 0 170) 135) anon0_correct)))
+PreconditionGeneratedEntry_correct)))
+))
+(check-sat)
--- /dev/null
+;COMMAND-LINE: --dt-nested-rec
+;EXPECT: unsat
+(set-logic ALL)
+(declare-fun tickleBool (Bool) Bool)
+(assert (and (tickleBool true) (tickleBool false)))
+(declare-datatypes ((T@Value 0)(T@ValueArray 0)) (((Integer (|i#Integer| Int) ) (Vector (|v#Vector| T@ValueArray) ) ) ((ValueArray (|v#ValueArray| (Seq T@Value)) ) ) ))
+(declare-fun ControlFlow (Int Int) Int)
+(declare-fun s@0 () T@ValueArray)
+(declare-fun s@1 () T@ValueArray)
+(declare-fun s@2 () T@ValueArray)
+(declare-fun s@3 () T@ValueArray)
+(declare-fun s@4 () T@ValueArray)
+(declare-fun s@5 () T@ValueArray)
+(set-info :boogie-vc-id test)
+(assert (not
+ (=> (= (ControlFlow 0 0) 427) (let ((anon0_correct (=> (= s@0 (ValueArray (as seq.empty (Seq T@Value)))) (and (=> (= (ControlFlow 0 331) (- 0 448)) (= (seq.len (|v#ValueArray| s@0)) 0)) (=> (= (seq.len (|v#ValueArray| s@0)) 0) (=> (= s@1 (ValueArray (seq.++ (|v#ValueArray| s@0) (seq.unit (Integer 0))))) (=> (and (= s@2 (ValueArray (seq.++ (|v#ValueArray| s@1) (seq.unit (Integer 1))))) (= s@3 (ValueArray (seq.++ (|v#ValueArray| s@2) (seq.unit (Integer 2)))))) (and (=> (= (ControlFlow 0 331) (- 0 490)) (= (seq.len (|v#ValueArray| s@3)) 3)) (=> (= (seq.len (|v#ValueArray| s@3)) 3) (and (=> (= (ControlFlow 0 331) (- 0 497)) (= (seq.nth (|v#ValueArray| s@3) 1) (Integer 1))) (=> (= (seq.nth (|v#ValueArray| s@3) 1) (Integer 1)) (=> (= s@4 (ValueArray (seq.extract (|v#ValueArray| s@3) 0 (- (seq.len (|v#ValueArray| s@3)) 1)))) (and (=> (= (ControlFlow 0 331) (- 0 517)) (= (seq.len (|v#ValueArray| s@4)) 2)) (=> (= (seq.len (|v#ValueArray| s@4)) 2) (=> (= s@5 (ValueArray (seq.++ (|v#ValueArray| s@4) (|v#ValueArray| s@4)))) (and (=> (= (ControlFlow 0 331) (- 0 534)) (= (seq.len (|v#ValueArray| s@5)) 4)) (=> (= (seq.len (|v#ValueArray| s@5)) 4) (=> (= (ControlFlow 0 331) (- 0 541)) (= (seq.nth (|v#ValueArray| s@5) 3) (Integer 1))))))))))))))))))))
+(let ((PreconditionGeneratedEntry_correct (=> (= (ControlFlow 0 427) 331) anon0_correct)))
+PreconditionGeneratedEntry_correct)))
+))
+(check-sat)
--- /dev/null
+;EXPECT: unsat
+(set-logic ALL)
+(declare-fun a () (Seq Int))
+(declare-fun b () (Seq Int))
+(declare-fun x () Int)
+(declare-fun y () Int)
+(declare-fun z () Int)
+(assert (or (= x z) (= y z)))
+(assert (not (= (seq.nth a x) (seq.nth a z))))
+(assert (not (= (seq.nth b y) (seq.nth b z))))
+(check-sat)
\ No newline at end of file
--- /dev/null
+(set-logic QF_UFSLIA)
+(set-info :status unsat)
+(declare-fun a () (Seq Int))
+(declare-fun b () (Seq Int))
+(declare-fun c () (Seq Int))
+(declare-fun x () Int)
+(declare-fun y () Int)
+(assert (or (= a b) (= a c)))
+(assert (not (= (seq.nth a x) (seq.nth b x))))
+(assert (not (= (seq.nth a y) (seq.nth c y))))
+(check-sat)
--- /dev/null
+;EXPECT: sat
+(set-logic ALL)
+(declare-fun s () (Seq Int))
+(assert (= 5 (seq.nth s 5)))
+(assert (= 2 (seq.len s)))
+(check-sat)
--- /dev/null
+;EXPECT: sat
+(set-logic ALL)
+(declare-fun s () (Seq Int))
+(assert (= 5 (seq.nth s 5)))
+(assert (= 2 (seq.len s)))
+(check-sat)