diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 2e08d3dab..cc81160fb 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -2286,6 +2286,230 @@ namespace Microsoft.Z3 #endregion + #region Sequence, string and regular expresions + + /// + /// Create the empty sequence. + /// + public SeqExpr MkEmptySeq(Sort s) + { + Contract.Requires(s != null); + Contract.Ensures(Contract.Result() != null); + return new SeqExpr(this, Native.Z3_mk_seq_empty(nCtx, s.NativeObject)); + } + + /// + /// Create the singleton sequence. + /// + public SeqExpr MkUnit(Expr elem) + { + Contract.Requires(elem != null); + Contract.Ensures(Contract.Result() != null); + return new SeqExpr(this, Native.Z3_mk_seq_unit(nCtx, elem.NativeObject)); + } + + /// + /// Create a string constant. + /// + public SeqExpr MkString(string s) + { + Contract.Requires(s != null); + Contract.Ensures(Contract.Result() != null); + return new SeqExpr(this, Native.Z3_mk_string(nCtx, s)); + } + + /// + /// Concatentate sequences. + /// + public SeqExpr MkConcat(params SeqExpr[] t) + { + Contract.Requires(t != null); + Contract.Requires(Contract.ForAll(t, a => a != null)); + Contract.Ensures(Contract.Result() != null); + + CheckContextMatch(t); + return new SeqExpr(this, Native.Z3_mk_seq_concat(nCtx, (uint)t.Length, AST.ArrayToNative(t))); + } + + + /// + /// Retrieve the length of a given sequence. + /// + public IntExpr MkLength(SeqExpr s) + { + Contract.Requires(s != null); + Contract.Ensures(Contract.Result() != null); + return (IntExpr) Expr.Create(this, Native.Z3_mk_seq_length(nCtx, s.NativeObject)); + } + + /// + /// Check for sequence prefix. + /// + public BoolExpr MkPrefixOf(SeqExpr s1, SeqExpr s2) + { + Contract.Requires(s1 != null); + Contract.Requires(s2 != null); + Contract.Ensures(Contract.Result() != null); + CheckContextMatch(s1, s2); + return new BoolExpr(this, Native.Z3_mk_seq_prefix(nCtx, s1.NativeObject, s2.NativeObject)); + } + + /// + /// Check for sequence suffix. + /// + public BoolExpr MkSuffixOf(SeqExpr s1, SeqExpr s2) + { + Contract.Requires(s1 != null); + Contract.Requires(s2 != null); + Contract.Ensures(Contract.Result() != null); + CheckContextMatch(s1, s2); + return new BoolExpr(this, Native.Z3_mk_seq_suffix(nCtx, s1.NativeObject, s2.NativeObject)); + } + + /// + /// Check for sequence containment of s2 in s1. + /// + public BoolExpr MkContains(SeqExpr s1, SeqExpr s2) + { + Contract.Requires(s1 != null); + Contract.Requires(s2 != null); + Contract.Ensures(Contract.Result() != null); + CheckContextMatch(s1, s2); + return new BoolExpr(this, Native.Z3_mk_seq_contains(nCtx, s1.NativeObject, s2.NativeObject)); + } + + /// + /// Retrieve sequence of length one at index. + /// + public SeqExpr MkAt(SeqExpr s, IntExpr index) + { + Contract.Requires(s != null); + Contract.Requires(index != null); + Contract.Ensures(Contract.Result() != null); + CheckContextMatch(s, index); + return new SeqExpr(this, Native.Z3_mk_seq_at(nCtx, s.NativeObject, index.NativeObject)); + } + + /// + /// Extract subsequence. + /// + public SeqExpr MkExtract(SeqExpr s, IntExpr offset, IntExpr length) + { + Contract.Requires(s != null); + Contract.Requires(offset != null); + Contract.Requires(length != null); + Contract.Ensures(Contract.Result() != null); + CheckContextMatch(s, offset, length); + return new SeqExpr(this, Native.Z3_mk_seq_extract(nCtx, s.NativeObject, offset.NativeObject, length.NativeObject)); + } + + /// + /// Extract index of sub-string starting at offset. + /// + public IntExpr MkIndexOf(SeqExpr s, SeqExpr substr, ArithExpr offset) + { + Contract.Requires(s != null); + Contract.Requires(offset != null); + Contract.Requires(substr != null); + Contract.Ensures(Contract.Result() != null); + CheckContextMatch(s, substr, offset); + return new IntExpr(this, Native.Z3_mk_seq_index(nCtx, s.NativeObject, substr.NativeObject, offset.NativeObject)); + } + + /// + /// Replace the first occurrence of src by dst in s. + /// + public SeqExpr MkReplace(SeqExpr s, SeqExpr src, SeqExpr dst) + { + Contract.Requires(s != null); + Contract.Requires(src != null); + Contract.Requires(dst != null); + Contract.Ensures(Contract.Result() != null); + CheckContextMatch(s, src, dst); + return new SeqExpr(this, Native.Z3_mk_seq_replace(nCtx, s.NativeObject, src.NativeObject, dst.NativeObject)); + } + + /// + /// Convert a regular expression that accepts sequence s. + /// + public ReExpr MkToRe(SeqExpr s) + { + Contract.Requires(s != null); + Contract.Ensures(Contract.Result() != null); + return new ReExpr(this, Native.Z3_mk_seq_to_re(nCtx, s.NativeObject)); + } + + + /// + /// Check for regular expression membership. + /// + public BoolExpr MkInRe(SeqExpr s, ReExpr re) + { + Contract.Requires(s != null); + Contract.Requires(re != null); + Contract.Ensures(Contract.Result() != null); + CheckContextMatch(s, re); + return new BoolExpr(this, Native.Z3_mk_seq_in_re(nCtx, s.NativeObject, re.NativeObject)); + } + + /// + /// Take the Kleene star of a regular expression. + /// + public ReExpr MkStar(ReExpr re) + { + Contract.Requires(re != null); + Contract.Ensures(Contract.Result() != null); + return new ReExpr(this, Native.Z3_mk_re_star(nCtx, re.NativeObject)); + } + + /// + /// Take the Kleene plus of a regular expression. + /// + public ReExpr MPlus(ReExpr re) + { + Contract.Requires(re != null); + Contract.Ensures(Contract.Result() != null); + return new ReExpr(this, Native.Z3_mk_re_plus(nCtx, re.NativeObject)); + } + + /// + /// Create the optional regular expression. + /// + public ReExpr MOption(ReExpr re) + { + Contract.Requires(re != null); + Contract.Ensures(Contract.Result() != null); + return new ReExpr(this, Native.Z3_mk_re_option(nCtx, re.NativeObject)); + } + + /// + /// Create the concatenation of regular languages. + /// + public ReExpr MkConcat(params ReExpr[] t) + { + Contract.Requires(t != null); + Contract.Requires(Contract.ForAll(t, a => a != null)); + Contract.Ensures(Contract.Result() != null); + + CheckContextMatch(t); + return new ReExpr(this, Native.Z3_mk_re_concat(nCtx, (uint)t.Length, AST.ArrayToNative(t))); + } + + /// + /// Create the union of regular languages. + /// + public ReExpr MkUnion(params ReExpr[] t) + { + Contract.Requires(t != null); + Contract.Requires(Contract.ForAll(t, a => a != null)); + Contract.Ensures(Contract.Result() != null); + + CheckContextMatch(t); + return new ReExpr(this, Native.Z3_mk_re_union(nCtx, (uint)t.Length, AST.ArrayToNative(t))); + } + + #endregion + #region Pseudo-Boolean constraints /// @@ -4448,6 +4672,26 @@ namespace Microsoft.Z3 throw new Z3Exception("Context mismatch"); } + [Pure] + internal void CheckContextMatch(Z3Object other1, Z3Object other2) + { + Contract.Requires(other1 != null); + Contract.Requires(other2 != null); + CheckContextMatch(other1); + CheckContextMatch(other2); + } + + [Pure] + internal void CheckContextMatch(Z3Object other1, Z3Object other2, Z3Object other3) + { + Contract.Requires(other1 != null); + Contract.Requires(other2 != null); + Contract.Requires(other3 != null); + CheckContextMatch(other1); + CheckContextMatch(other2); + CheckContextMatch(other3); + } + [Pure] internal void CheckContextMatch(Z3Object[] arr) { diff --git a/src/api/dotnet/Expr.cs b/src/api/dotnet/Expr.cs index 599cbf756..c995a12bd 100644 --- a/src/api/dotnet/Expr.cs +++ b/src/api/dotnet/Expr.cs @@ -1826,6 +1826,8 @@ namespace Microsoft.Z3 case Z3_sort_kind.Z3_FLOATING_POINT_SORT: return new FPExpr(ctx, obj); case Z3_sort_kind.Z3_ROUNDING_MODE_SORT: return new FPRMExpr(ctx, obj); case Z3_sort_kind.Z3_FINITE_DOMAIN_SORT: return new FiniteDomainExpr(ctx, obj); + case Z3_sort_kind.Z3_RE_SORT: return new ReExpr(ctx, obj); + case Z3_sort_kind.Z3_SEQ_SORT: return new SeqExpr(ctx, obj); } return new Expr(ctx, obj); diff --git a/src/api/dotnet/ReExpr.cs b/src/api/dotnet/ReExpr.cs new file mode 100644 index 000000000..6a10d535f --- /dev/null +++ b/src/api/dotnet/ReExpr.cs @@ -0,0 +1,42 @@ +/*++ +Copyright () 2016 Microsoft Corporation + +Module Name: + + ReExpr.cs + +Abstract: + + Z3 Managed API: Regular Expressions + +Author: + + Christoph Wintersteiger (cwinter) 2012-11-23 + +Notes: + +--*/ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using System.Diagnostics.Contracts; + +namespace Microsoft.Z3 +{ + /// + /// Regular expression expressions + /// + public class ReExpr : Expr + { + #region Internal + /// Constructor for ReExpr + internal ReExpr(Context ctx, IntPtr obj) + : base(ctx, obj) + { + Contract.Requires(ctx != null); + } + #endregion + } +} diff --git a/src/api/dotnet/ReSort.cs b/src/api/dotnet/ReSort.cs new file mode 100644 index 000000000..bc420603d --- /dev/null +++ b/src/api/dotnet/ReSort.cs @@ -0,0 +1,43 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +Module Name: + + ReSort.cs + +Abstract: + + Z3 Managed API: Regular expression Sorts + +Author: + + Christoph Wintersteiger (cwinter) 2012-11-23 + +Notes: + +--*/ + +using System; +using System.Diagnostics.Contracts; + +namespace Microsoft.Z3 +{ + /// + /// A regular expression sort + /// + public class ReSort : Sort + { + #region Internal + internal ReSort(Context ctx, IntPtr obj) + : base(ctx, obj) + { + Contract.Requires(ctx != null); + } + internal ReSort(Context ctx) + : base(ctx, Native.Z3_mk_int_sort(ctx.nCtx)) + { + Contract.Requires(ctx != null); + } + #endregion + } +} diff --git a/src/api/dotnet/SeqExpr.cs b/src/api/dotnet/SeqExpr.cs new file mode 100644 index 000000000..c9fdd03a8 --- /dev/null +++ b/src/api/dotnet/SeqExpr.cs @@ -0,0 +1,42 @@ +/*++ +Copyright () 2016 Microsoft Corporation + +Module Name: + + SeqExpr.cs + +Abstract: + + Z3 Managed API: Sequence Expressions + +Author: + + Christoph Wintersteiger (cwinter) 2012-11-23 + +Notes: + +--*/ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using System.Diagnostics.Contracts; + +namespace Microsoft.Z3 +{ + /// + /// Sequence expressions + /// + public class SeqExpr : Expr + { + #region Internal + /// Constructor for SeqExpr + internal SeqExpr(Context ctx, IntPtr obj) + : base(ctx, obj) + { + Contract.Requires(ctx != null); + } + #endregion + } +} diff --git a/src/api/dotnet/SeqSort.cs b/src/api/dotnet/SeqSort.cs new file mode 100644 index 000000000..b2be11291 --- /dev/null +++ b/src/api/dotnet/SeqSort.cs @@ -0,0 +1,43 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +Module Name: + + SeqSort.cs + +Abstract: + + Z3 Managed API: Sequence Sorts + +Author: + + Christoph Wintersteiger (cwinter) 2012-11-23 + +Notes: + +--*/ + +using System; +using System.Diagnostics.Contracts; + +namespace Microsoft.Z3 +{ + /// + /// A Sequence sort + /// + public class SeqSort : Sort + { + #region Internal + internal SeqSort(Context ctx, IntPtr obj) + : base(ctx, obj) + { + Contract.Requires(ctx != null); + } + internal SeqSort(Context ctx) + : base(ctx, Native.Z3_mk_int_sort(ctx.nCtx)) + { + Contract.Requires(ctx != null); + } + #endregion + } +} diff --git a/src/api/dotnet/Sort.cs b/src/api/dotnet/Sort.cs index 412398ddd..e1b8ca1b7 100644 --- a/src/api/dotnet/Sort.cs +++ b/src/api/dotnet/Sort.cs @@ -147,6 +147,8 @@ namespace Microsoft.Z3 case Z3_sort_kind.Z3_RELATION_SORT: return new RelationSort(ctx, obj); case Z3_sort_kind.Z3_FLOATING_POINT_SORT: return new FPSort(ctx, obj); case Z3_sort_kind.Z3_ROUNDING_MODE_SORT: return new FPRMSort(ctx, obj); + case Z3_sort_kind.Z3_SEQ_SORT: return new SeqSort(ctx, obj); + case Z3_sort_kind.Z3_RE_SORT: return new ReSort(ctx, obj); default: throw new Z3Exception("Unknown sort kind"); } diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 88988d2b4..1d640fe78 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -209,7 +209,7 @@ final_check_status theory_seq::final_check_eh() { TRACE("seq", tout << ">>branch_variable\n";); return FC_CONTINUE; } - if (!check_length_coherence()) { + if (check_length_coherence()) { ++m_stats.m_check_length_coherence; TRACE("seq", tout << ">>check_length_coherence\n";); return FC_CONTINUE; @@ -374,29 +374,36 @@ bool theory_seq::propagate_length_coherence(expr* e) { expr_ref high2(m_autil.mk_le(m_util.str.mk_length(seq), m_autil.mk_numeral(hi-lo, true)), m); add_axiom(~mk_literal(high1), mk_literal(high2)); } - m_trail_stack.push(push_replay(alloc(replay_length_coherence, m, e))); return true; } +bool theory_seq::check_length_coherence(expr* e) { + if (is_var(e) && m_rep.is_root(e)) { + expr_ref emp(m_util.str.mk_empty(m.get_sort(e)), m); + expr_ref head(m), tail(m); + if (!propagate_length_coherence(e) && + l_false == assume_equality(e, emp)) { + // e = emp \/ e = unit(head.elem(e))*tail(e) + mk_decompose(e, head, tail); + expr_ref conc(m_util.str.mk_concat(head, tail), m); + propagate_is_conc(e, conc); + assume_equality(tail, emp); + } + m_trail_stack.push(push_replay(alloc(replay_length_coherence, m, e))); + return true; + } + return false; +} + bool theory_seq::check_length_coherence() { obj_hashtable::iterator it = m_length.begin(), end = m_length.end(); for (; it != end; ++it) { expr* e = *it; - if (is_var(e) && m_rep.is_root(e)) { - expr_ref emp(m_util.str.mk_empty(m.get_sort(e)), m); - expr_ref head(m), tail(m); - if (!propagate_length_coherence(e) && - l_false == assume_equality(e, emp)) { - // e = emp \/ e = unit(head.elem(e))*tail(e) - mk_decompose(e, head, tail); - expr_ref conc(m_util.str.mk_concat(head, tail), m); - propagate_is_conc(e, conc); - assume_equality(tail, emp); - } - return false; + if (check_length_coherence(e)) { + return true; } } - return true; + return false; } /* @@ -936,6 +943,12 @@ bool theory_seq::simplify_and_solve_eqs() { bool theory_seq::internalize_term(app* term) { TRACE("seq", tout << mk_pp(term, m) << "\n";); context & ctx = get_context(); + if (ctx.e_internalized(term)) { + enode* e = ctx.get_enode(term); + mk_var(e); + return true; + } + unsigned num_args = term->get_num_args(); expr* arg; for (unsigned i = 0; i < num_args; i++) { @@ -947,6 +960,7 @@ bool theory_seq::internalize_term(app* term) { ctx.set_var_theory(bv, get_id()); ctx.mark_as_relevant(bv); } + enode* e = 0; if (ctx.e_internalized(term)) { e = ctx.get_enode(term); @@ -1049,7 +1063,9 @@ void theory_seq::display_disequation(std::ostream& out, ne const& e) const { for (unsigned j = 0; j < e.m_lhs.size(); ++j) { out << mk_pp(e.m_lhs[j], m) << " != " << mk_pp(e.m_rhs[j], m) << "\n"; } - display_deps(out, e.m_dep); + if (e.m_dep) { + display_deps(out, e.m_dep); + } } void theory_seq::display_deps(std::ostream& out, dependency* dep) const { @@ -1063,8 +1079,7 @@ void theory_seq::display_deps(std::ostream& out, dependency* dep) const { literal lit = lits[i]; get_context().display_literals_verbose(out << "\n ", 1, &lit); } - out << "\n"; - + out << "\n"; } void theory_seq::collect_statistics(::statistics & st) const { @@ -1287,7 +1302,7 @@ expr_ref theory_seq::expand(expr* e0, dependency*& eqs) { m_rep.add_cache(e0, edr); eqs = m_dm.mk_join(eqs, deps); TRACE("seq_verbose", tout << mk_pp(e0, m) << " |--> " << result << "\n"; - display_deps(tout, eqs);); + if (eqs) display_deps(tout, eqs);); return result; } diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index db5fa0f8b..40fce2695 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -257,7 +257,7 @@ namespace smt { public: replay_length_coherence(ast_manager& m, expr* e) : m_e(e, m) {} virtual void operator()(theory_seq& th) { - th.propagate_length_coherence(m_e); + th.check_length_coherence(m_e); } }; @@ -348,6 +348,7 @@ namespace smt { bool split_variable(); // split a variable bool is_solved(); bool check_length_coherence(); + bool check_length_coherence(expr* e); bool propagate_length_coherence(expr* e); bool solve_eqs(unsigned start);