From 6ae3929a92f4b3f30445f71716b0041de0a2bd02 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Mon, 19 Nov 2012 14:05:52 -0800 Subject: [PATCH 001/925] test Signed-off-by: Leonardo de Moura --- README | 3 --- 1 file changed, 3 deletions(-) diff --git a/README b/README index a85d13726..cf028ef79 100644 --- a/README +++ b/README @@ -43,6 +43,3 @@ Remark: clang does not support OpenMP yet. python scripts/mk_make.py cd build make - - - From dcf82918603a419025ad3a0ddcc20a6b4850c13e Mon Sep 17 00:00:00 2001 From: Yuto Takei Date: Tue, 20 Nov 2012 13:08:40 +0900 Subject: [PATCH 002/925] fix for OCaml API build --- src/api/ml/build-lib.sh | 4 ++-- src/api/ml/z3.ml | 8 ++++---- src/api/ml/z3.mli | 7 +++---- src/api/ml/z3_stubs.c | 32 ++++++++++++++++---------------- 4 files changed, 25 insertions(+), 26 deletions(-) mode change 100644 => 100755 src/api/ml/build-lib.sh diff --git a/src/api/ml/build-lib.sh b/src/api/ml/build-lib.sh old mode 100644 new mode 100755 index 93c7262b1..8b73d7aa5 --- a/src/api/ml/build-lib.sh +++ b/src/api/ml/build-lib.sh @@ -3,7 +3,7 @@ # Script to compile the Z3 OCaml API # Expects to find ../lib/libz3{,_dbg}.{a,so,dylib} -CFLAGS="-ccopt -Wno-discard-qual -ccopt -I../include" +CFLAGS="-ccopt -Wno-discard-qual" XCDBG="-g -ccopt -g $CFLAGS" XCOPT="-ccopt -O3 -ccopt -fomit-frame-pointer $CFLAGS" @@ -26,6 +26,6 @@ ocamlopt -a $XCDBG -cclib -L$PWD/../lib -cclib -lz3_dbg -cclib -lcamlidl -cclib ocamlopt -a $XCOPT -cclib -L$PWD/../lib -cclib -lz3 -cclib -lcamlidl -cclib -lz3stubs z3.cmx -o z3.cmxa -ocamlmktop -o ocamlz3 z3.cma -cclib -L. +ocamlmktop -o ocamlz3 z3.cma -ccopt -L. -cclib -lz3 -cclib -lcamlidl rm z3.cm{o,x} *.o diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index 76536ef43..7498a0d46 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -1219,13 +1219,13 @@ external get_smtlib_sort : context -> int -> sort external get_smtlib_error : context -> string = "camlidl_z3_Z3_get_smtlib_error" - +(* external parse_z3_string : context -> string -> ast = "camlidl_z3_Z3_parse_z3_string" external parse_z3_file : context -> string -> ast = "camlidl_z3_Z3_parse_z3_file" - +*) external set_error : context -> error_code -> unit = "camlidl_z3_Z3_set_error" @@ -2930,13 +2930,13 @@ external get_smtlib_sort : context -> int -> sort external get_smtlib_error : context -> string = "camlidl_z3V3_Z3_get_smtlib_error" - +(* external parse_z3_string : context -> string -> ast = "camlidl_z3_Z3_parse_z3V3_string" external parse_z3_file : context -> string -> ast = "camlidl_z3_Z3_parse_z3V3_file" - +*) external get_version : unit -> int * int * int * int = "camlidl_z3V3_Z3_get_version" diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli index b0935f03c..9f58ba06a 100644 --- a/src/api/ml/z3.mli +++ b/src/api/ml/z3.mli @@ -4787,7 +4787,6 @@ external get_smtlib_sort : context -> int -> sort external get_smtlib_error : context -> string = "camlidl_z3_Z3_get_smtlib_error" -*) (** Summary: \[ [ parse_z3_string c str ] \] Parse the given string using the Z3 native parser. @@ -4806,7 +4805,7 @@ external parse_z3_string : context -> string -> ast *) external parse_z3_file : context -> string -> ast = "camlidl_z3_Z3_parse_z3_file" - +*) (** {2 {L Error Handling}} *) @@ -10198,7 +10197,7 @@ external get_smtlib_sort : context -> int -> sort *) external get_smtlib_error : context -> string = "camlidl_z3V3_Z3_get_smtlib_error" - +(* (** Summary: \[ [ parse_z3_string c str ] \] Parse the given string using the Z3 native parser. @@ -10217,7 +10216,7 @@ external parse_z3_string : context -> string -> ast *) external parse_z3_file : context -> string -> ast = "camlidl_z3_Z3_parse_z3V3_file" - +*) (** {2 {L Miscellaneous}} *) diff --git a/src/api/ml/z3_stubs.c b/src/api/ml/z3_stubs.c index 0f32cb20e..08100573a 100644 --- a/src/api/ml/z3_stubs.c +++ b/src/api/ml/z3_stubs.c @@ -8169,13 +8169,13 @@ check_error_code(c); /* end user-supplied deallocation sequence */ return _vres; } - +/* value camlidl_z3_Z3_parse_z3_string( value _v_c, value _v_str) { - Z3_context c; /*in*/ - Z3_string str; /*in*/ + Z3_context c; /*in + Z3_string str; /*in Z3_ast _res; value _vres; @@ -8186,9 +8186,9 @@ value camlidl_z3_Z3_parse_z3_string( _res = Z3_parse_z3_string(c, str); _vres = camlidl_c2ml_z3_Z3_ast(&_res, _ctx); camlidl_free(_ctx); - /* begin user-supplied deallocation sequence */ + /* begin user-supplied deallocation sequence check_error_code(c); - /* end user-supplied deallocation sequence */ + /* end user-supplied deallocation sequence return _vres; } @@ -8196,8 +8196,8 @@ value camlidl_z3_Z3_parse_z3_file( value _v_c, value _v_file_name) { - Z3_context c; /*in*/ - Z3_string file_name; /*in*/ + Z3_context c; /*in + Z3_string file_name; /*in Z3_ast _res; value _vres; @@ -8208,12 +8208,12 @@ value camlidl_z3_Z3_parse_z3_file( _res = Z3_parse_z3_file(c, file_name); _vres = camlidl_c2ml_z3_Z3_ast(&_res, _ctx); camlidl_free(_ctx); - /* begin user-supplied deallocation sequence */ + /* begin user-supplied deallocation sequence check_error_code(c); - /* end user-supplied deallocation sequence */ + /* end user-supplied deallocation sequence return _vres; } - +*/ value camlidl_z3_Z3_set_error( value _v_c, value _v_e) @@ -17569,13 +17569,13 @@ value camlidl_z3V3_Z3_get_smtlib_error( camlidl_free(_ctx); return _vres; } - +/* value camlidl_z3_Z3_parse_z3V3_string( value _v_c, value _v_str) { - Z3_context c; /*in*/ - Z3_string str; /*in*/ + Z3_context c; /*in + Z3_string str; /*in Z3_ast _res; value _vres; @@ -17593,8 +17593,8 @@ value camlidl_z3_Z3_parse_z3V3_file( value _v_c, value _v_file_name) { - Z3_context c; /*in*/ - Z3_string file_name; /*in*/ + Z3_context c; /*in + Z3_string file_name; /*in Z3_ast _res; value _vres; @@ -17607,7 +17607,7 @@ value camlidl_z3_Z3_parse_z3V3_file( camlidl_free(_ctx); return _vres; } - +*/ value camlidl_z3V3_Z3_get_version(value _unit) { unsigned int *major; /*out*/ From 0bee012f2c740178dbb6ade5879d39cd49d76dc0 Mon Sep 17 00:00:00 2001 From: Yuto Takei Date: Tue, 20 Nov 2012 13:12:37 +0900 Subject: [PATCH 003/925] typo --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index cf028ef79..3344cea6f 100644 --- a/README +++ b/README @@ -12,7 +12,7 @@ Z3 can be built using Visual Studio Command Prompt and make/g++. 2) Building Z3 using make/g++ and Python Execute: - autconf + autoconf ./configure python scripts/mk_make.py cd build From c6e22cd2b0611f86338502b9da9000d9a904dab9 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Mon, 19 Nov 2012 21:27:27 -0800 Subject: [PATCH 004/925] hack for compiling ML API with recent changes in the Z3 API Signed-off-by: Leonardo de Moura --- src/api/ml/z3_stubs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/ml/z3_stubs.c b/src/api/ml/z3_stubs.c index 08100573a..dcc434196 100644 --- a/src/api/ml/z3_stubs.c +++ b/src/api/ml/z3_stubs.c @@ -8708,7 +8708,7 @@ value camlidl_z3_Z3_fixedpoint_simplify_rules( camlidl_ml2c_z3_Z3_func_decl(_v6, &outputs[_c5], _ctx); } num_outputs = _c4; - _res = Z3_fixedpoint_simplify_rules(c, f, num_rules, rules, num_outputs, outputs); + // _res = Z3_fixedpoint_simplify_rules(c, f, num_rules, rules, num_outputs, outputs); _vres = camlidl_c2ml_z3_Z3_ast_vector(&_res, _ctx); camlidl_free(_ctx); /* begin user-supplied deallocation sequence */ From 0ccae8e2e350365debf2fb0e95949be065ef1fde Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 22 Nov 2012 14:23:18 +0000 Subject: [PATCH 005/925] remove unused m_max_num_cex parameter Signed-off-by: Nuno Lopes --- src/front_end_params/front_end_params.cpp | 2 -- src/front_end_params/front_end_params.h | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/front_end_params/front_end_params.cpp b/src/front_end_params/front_end_params.cpp index 2dc037e1b..a30e1dfd3 100644 --- a/src/front_end_params/front_end_params.cpp +++ b/src/front_end_params/front_end_params.cpp @@ -28,8 +28,6 @@ void front_end_params::register_params(ini_params & p) { p.register_int_param("ENGINE", 0, 2, reinterpret_cast(m_engine), "0: SMT solver, 1: Superposition prover, 2: EPR solver, true"); z3_solver_params::register_params(p); model_params::register_params(p); - p.register_unsigned_param("MAX_COUNTEREXAMPLES", m_max_num_cex, - "set the maximum number of counterexamples when using Simplify front end"); p.register_bool_param("AT_LABELS_CEX", m_at_labels_cex, "only use labels that contain '@' when building multiple counterexamples"); p.register_bool_param("CHECK_AT_LABELS", m_check_at_labels, diff --git a/src/front_end_params/front_end_params.h b/src/front_end_params/front_end_params.h index d13c01076..cd582e28a 100644 --- a/src/front_end_params/front_end_params.h +++ b/src/front_end_params/front_end_params.h @@ -41,7 +41,6 @@ struct front_end_params : public preprocessor_params, public spc_params, public { ref m_param_vector; engine m_engine; - unsigned m_max_num_cex; // maximum number of counterexamples bool m_at_labels_cex; // only use labels which contains the @ symbol when building multiple counterexamples. bool m_check_at_labels; // check that @ labels are inserted to generate unique counter-examples. bool m_default_qid; @@ -76,7 +75,6 @@ struct front_end_params : public preprocessor_params, public spc_params, public front_end_params(): m_param_vector(alloc(param_vector, this)), m_engine(ENG_SMT), - m_max_num_cex(1), m_at_labels_cex(false), m_check_at_labels(false), m_default_qid(false), From 5af1e4bdf436d1217654cc55538ea14432baaeb0 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 22 Nov 2012 15:03:11 +0000 Subject: [PATCH 006/925] remove redudant is_well_sorted checks after var_subst var_subst already checks for well sortedness of the resulting expression Signed-off-by: Nuno Lopes --- src/ast/macros/macro_util.cpp | 1 - src/ast/normal_forms/nnf.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/src/ast/macros/macro_util.cpp b/src/ast/macros/macro_util.cpp index 86f30ed73..4e457d270 100644 --- a/src/ast/macros/macro_util.cpp +++ b/src/ast/macros/macro_util.cpp @@ -489,7 +489,6 @@ void macro_util::normalize_expr(app * head, expr * t, expr_ref & norm_t) const { tout << "#" << i << " -> " << mk_pp(var_mapping[i], m_manager) << "\n"; }); subst(t, var_mapping.size(), var_mapping.c_ptr(), norm_t); - SASSERT(is_well_sorted(m_manager, norm_t)); } else { norm_t = t; diff --git a/src/ast/normal_forms/nnf.cpp b/src/ast/normal_forms/nnf.cpp index 4d8849178..8f46139f7 100644 --- a/src/ast/normal_forms/nnf.cpp +++ b/src/ast/normal_forms/nnf.cpp @@ -102,7 +102,6 @@ class skolemizer { } } s(body, substitution.size(), substitution.c_ptr(), r); - SASSERT(is_well_sorted(m(), r)); p = 0; if (m().proofs_enabled()) { if (q->is_forall()) From a37fd146b0dbb68c54223c1d828b33a35121d17f Mon Sep 17 00:00:00 2001 From: "ThanhVu (Vu) Nguyen" Date: Sun, 2 Dec 2012 23:41:31 -0500 Subject: [PATCH 007/925] added is_expr_var and is_expr_val to check if a given expression is a value or a variable --- src/api/python/z3util.py | 56 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 src/api/python/z3util.py diff --git a/src/api/python/z3util.py b/src/api/python/z3util.py new file mode 100644 index 000000000..402d29174 --- /dev/null +++ b/src/api/python/z3util.py @@ -0,0 +1,56 @@ +""" +In Z3, variables are caleld *uninterpreted* consts and +variables are *interpreted* consts. +""" + +def is_expr_var(v): + """ + EXAMPLES: + + >>> is_expr_var(Int('7')) + True + >>> is_expr_var(IntVal('7')) + False + >>> is_expr_var(Bool('y')) + True + >>> is_expr_var(Int('x') + 7 == Int('y')) + False + >>> LOnOff, (On,Off) = EnumSort("LOnOff",['On','Off']) + >>> Block,Reset,SafetyInjection=Consts("Block Reset SafetyInjection",LOnOff) + >>> is_expr_var(LOnOff) + False + >>> is_expr_var(On) + False + >>> is_expr_var(Block) + True + >>> is_expr_var(SafetyInjection) + True + """ + + return is_const(v) and v.decl().kind()==Z3_OP_UNINTERPRETED + +def is_expr_val(v): + """ + EXAMPLES: + + >>> is_expr_val(Int('7')) + False + >>> is_expr_val(IntVal('7')) + True + >>> is_expr_val(Bool('y')) + False + >>> is_expr_val(Int('x') + 7 == Int('y')) + False + >>> LOnOff, (On,Off) = EnumSort("LOnOff",['On','Off']) + >>> Block,Reset,SafetyInjection=Consts("Block Reset SafetyInjection",LOnOff) + >>> is_expr_val(LOnOff) + False + >>> is_expr_val(On) + True + >>> is_expr_val(Block) + False + >>> is_expr_val(SafetyInjection) + False + """ + return is_const(v) and v.decl().kind()!=Z3_OP_UNINTERPRETED + From f533e5cfd751445943d9893cd19b09d677101a6f Mon Sep 17 00:00:00 2001 From: "ThanhVu (Vu) Nguyen" Date: Sun, 2 Dec 2012 23:42:16 -0500 Subject: [PATCH 008/925] added is_expr_var and is_expr_val to check if a given expression is a value or a variable --- src/api/python/z3util.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/api/python/z3util.py b/src/api/python/z3util.py index 402d29174..6d309d9e9 100644 --- a/src/api/python/z3util.py +++ b/src/api/python/z3util.py @@ -1,3 +1,5 @@ +from z3 import * + """ In Z3, variables are caleld *uninterpreted* consts and variables are *interpreted* consts. From 72a250c01ac3f2623b266b9f85e52a84a4f0ea33 Mon Sep 17 00:00:00 2001 From: "ThanhVu (Vu) Nguyen" Date: Thu, 6 Dec 2012 13:54:57 -0500 Subject: [PATCH 009/925] =?UTF-8?q?moving=20my=20common=20z3=20stuff=20to?= =?UTF-8?q?=20z3util.py=20=20=20=E2=80=A6=20=20note=20the=20vset()=20call?= =?UTF-8?q?=20essentially=20returns=20a=20list=20with=20no=20duplicate=20e?= =?UTF-8?q?lements,=20=20it's=20like=20set=20but=20allows=20the=20user=20t?= =?UTF-8?q?o=20add=20in=20a=20function=20to=20compute=20the=20representati?= =?UTF-8?q?on=20of=20the=20list=20elements.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/python/z3util.py | 410 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 410 insertions(+) diff --git a/src/api/python/z3util.py b/src/api/python/z3util.py index 6d309d9e9..6cdd4de32 100644 --- a/src/api/python/z3util.py +++ b/src/api/python/z3util.py @@ -1,5 +1,46 @@ +""" +Usage: +import common_z3 as CM_Z3 +""" + +import common as CM from z3 import * +def get_z3_version(as_str=False): + major = ctypes.c_uint(0) + minor = ctypes.c_uint(0) + build = ctypes.c_uint(0) + rev = ctypes.c_uint(0) + Z3_get_version(major,minor,build,rev) + rs = map(int,(major.value,minor.value,build.value,rev.value)) + if as_str: + return "{}.{}.{}.{}".format(*rs) + else: + return rs + + + + + +def ehash(v): + """ + Returns a 'stronger' hash value than the default hash() method. + The result from hash() is not enough to distinguish between 2 + z3 expressions in some cases. + + >>> x1 = Bool('x'); x2 = Bool('x'); x3 = Int('x') + >>> print x1.hash(),x2.hash(),x3.hash() #BAD: all same hash values + 783810685 783810685 783810685 + >>> print ehash(x1), ehash(x2), ehash(x3) + x_783810685_1 x_783810685_1 x_783810685_2 + + """ + if __debug__: + assert is_expr(v) + + return "{}_{}_{}".format(str(v),v.hash(),v.sort_kind()) + + """ In Z3, variables are caleld *uninterpreted* consts and variables are *interpreted* consts. @@ -56,3 +97,372 @@ def is_expr_val(v): """ return is_const(v) and v.decl().kind()!=Z3_OP_UNINTERPRETED + + + +def get_vars(f,rs=[]): + """ + >>> x,y = Ints('x y') + >>> a,b = Bools('a b') + >>> get_vars(Implies(And(x+y==0,x*2==10),Or(a,Implies(a,b==False)))) + [x, y, a, b] + + """ + if __debug__: + assert is_expr(f) + + if is_const(f): + if is_expr_val(f): + return rs + else: #variable + return CM.vset(rs + [f],str) + + else: + for f_ in f.children(): + rs = get_vars(f_,rs) + + return CM.vset(rs,str) + + + +def mk_var(name,vsort): + if vsort.kind() == Z3_INT_SORT: + v = Int(name) + elif vsort.kind() == Z3_REAL_SORT: + v = Real(name) + elif vsort.kind() == Z3_BOOL_SORT: + v = Bool(name) + elif vsort.kind() == Z3_DATATYPE_SORT: + v = Const(name,vsort) + + else: + assert False, 'Cannot handle this sort (s: %sid: %d)'\ + %(vsort,vsort.kind()) + + return v + + + +def prove(claim,assume=None,verbose=0): + """ + >>> r,m = prove(BoolVal(True),verbose=0); r,model_str(m,as_str=False) + (True, None) + + #infinite counter example when proving contradiction + >>> r,m = prove(BoolVal(False)); r,model_str(m,as_str=False) + (False, []) + + >>> x,y,z=Bools('x y z') + >>> r,m = prove(And(x,Not(x))); r,model_str(m,as_str=True) + (False, '[]') + + >>> r,m = prove(True,assume=And(x,Not(x)),verbose=0) + Traceback (most recent call last): + ... + AssertionError: Assumption is alway False! + + >>> r,m = prove(Implies(x,x),assume=y,verbose=2); r,model_str(m,as_str=False) + assume: + y + claim: + Implies(x, x) + to_prove: + Implies(y, Implies(x, x)) + (True, None) + + >>> r,m = prove(And(x,True),assume=y,verbose=0); r,model_str(m,as_str=False) + (False, [(x, False), (y, True)]) + + >>> r,m = prove(And(x,y),assume=y,verbose=0) + >>> print r + False + >>> print model_str(m,as_str=True) + x = False + y = True + + >>> a,b = Ints('a b') + >>> r,m = prove(a**b == b**a,assume=None,verbose=0) + E: cannot solve ! + >>> r is None and m is None + True + + """ + + if __debug__: + assert not assume or is_expr(assume) + + + to_prove = claim + if assume: + if __debug__: + is_proved,_ = prove(Not(assume)) + + def _f(): + emsg = "Assumption is alway False!" + if verbose >= 2: + emsg = "{}\n{}".format(assume,emsg) + return emsg + + assert is_proved==False, _f() + + to_prove = Implies(assume,to_prove) + + + + if verbose >= 2: + print 'assume: ' + print assume + print 'claim: ' + print claim + print 'to_prove: ' + print to_prove + + f = Not(to_prove) + + models = get_models(f,k=1) + if models is None: #unknown + print 'E: cannot solve !' + return None, None + elif models == False: #unsat + return True,None + else: #sat + if __debug__: + assert isinstance(models,list) + + if models: + return False, models[0] #the first counterexample + else: + return False, [] #infinite counterexample,models + + +def get_models(f,k): + """ + Returns the first k models satisfiying f. + If f is not satisfiable, returns False. + If f cannot be solved, returns None + If f is satisfiable, returns the first k models + Note that if f is a tautology, e.g.\ True, then the result is [] + + Based on http://stackoverflow.com/questions/11867611/z3py-checking-all-solutions-for-equation + + EXAMPLES: + >>> x, y = Ints('x y') + >>> len(get_models(And(0<=x,x <= 4),k=11)) + 5 + >>> get_models(And(0<=x**y,x <= 1),k=2) is None + True + >>> get_models(And(0<=x,x <= -1),k=2) + False + >>> len(get_models(x+y==7,5)) + 5 + >>> len(get_models(And(x<=5,x>=1),7)) + 5 + >>> get_models(And(x<=0,x>=5),7) + False + + >>> x = Bool('x') + >>> get_models(And(x,Not(x)),k=1) + False + >>> get_models(Implies(x,x),k=1) + [] + >>> get_models(BoolVal(True),k=1) + [] + + + + """ + + if __debug__: + assert is_expr(f) + assert k>=1 + + + + s = Solver() + s.add(f) + + models = [] + i = 0 + while s.check() == sat and i < k: + i = i + 1 + + m = s.model() + + if not m: #if m == [] + break + + models.append(m) + + + #create new constraint to block the current model + block = Not(And([v() == m[v] for v in m])) + s.add(block) + + + if s.check() == unknown: + return None + elif s.check() == unsat and i==0: + return False + else: + return models + +def is_tautology(claim,verbose=0): + """ + >>> is_tautology(Implies(Bool('x'),Bool('x'))) + True + + >>> is_tautology(Implies(Bool('x'),Bool('y'))) + False + + >>> is_tautology(BoolVal(True)) + True + + >>> is_tautology(BoolVal(False)) + False + + """ + return prove(claim=claim,assume=None,verbose=verbose)[0] + + +def is_contradiction(claim,verbose=0): + """ + >>> x,y=Bools('x y') + >>> is_contradiction(BoolVal(False)) + True + + >>> is_contradiction(BoolVal(True)) + False + + >>> is_contradiction(x) + False + + >>> is_contradiction(Implies(x,y)) + False + + >>> is_contradiction(Implies(x,x)) + False + + >>> is_contradiction(And(x,Not(x))) + True + """ + + return prove(claim=Not(claim),assume=None,verbose=verbose)[0] + + +def exact_one_model(f): + """ + return True if f has exactly 1 model, False otherwise. + + EXAMPLES: + + >>> x, y = Ints('x y') + >>> exact_one_model(And(0<=x**y,x <= 0)) + False + + >>> exact_one_model(And(0<=x,x <= 0)) + True + + >>> exact_one_model(And(0<=x,x <= 1)) + False + + >>> exact_one_model(And(0<=x,x <= -1)) + False + """ + + models = get_models(f,k=2) + if isinstance(models,list): + return len(models)==1 + else: + return False + + + +def myBinOp(op,*L): + """ + >>> myAnd(*[Bool('x'),Bool('y')]) + And(x, y) + + >>> myAnd(*[Bool('x'),None]) + x + + >>> myAnd(*[Bool('x')]) + x + + >>> myAnd(*[]) + + >>> myAnd(Bool('x'),Bool('y')) + And(x, y) + + >>> myAnd(*[Bool('x'),Bool('y')]) + And(x, y) + + >>> myAnd([Bool('x'),Bool('y')]) + And(x, y) + + >>> myAnd((Bool('x'),Bool('y'))) + And(x, y) + + >>> myAnd(*[Bool('x'),Bool('y'),True]) + Traceback (most recent call last): + ... + AssertionError + """ + + if __debug__: + assert op == Z3_OP_OR or op == Z3_OP_AND or op == Z3_OP_IMPLIES + + if len(L)==1 and (isinstance(L[0],list) or isinstance(L[0],tuple)): + L = L[0] + + if __debug__: + assert all(not isinstance(l,bool) for l in L) + + L = [l for l in L if is_expr(l)] + if L: + if len(L)==1: + return L[0] + else: + if op == Z3_OP_OR: + return Or(L) + elif op == Z3_OP_AND: + return And(L) + else: #IMPLIES + return Implies(L[0],L[1]) + else: + return None + + +def myAnd(*L): return myBinOp(Z3_OP_AND,*L) +def myOr(*L): return myBinOp(Z3_OP_OR,*L) +def myImplies(a,b):return myBinOp(Z3_OP_IMPLIES,[a,b]) + + + +Iff = lambda f,g: And(Implies(f,g),Implies(g,f)) + + + +def model_str(m,as_str=True): + """ + Returned a 'sorted' model (so that it's easier to see) + The model is sorted by its key, + e.g. if the model is y = 3 , x = 10, then the result is + x = 10, y = 3 + + EXAMPLES: + see doctest exampels from function prove() + + """ + if __debug__: + assert m is None or m == [] or isinstance(m,ModelRef) + + if m : + vs = [(v,m[v]) for v in m] + vs = sorted(vs,key=lambda (a,_): str(a)) + if as_str: + return '\n'.join(['{} = {}'.format(k,v) for (k,v) in vs]) + else: + return vs + else: + return str(m) if as_str else m + From 4681281765c8876188f10ceee68cb65c64256e31 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Mon, 31 Dec 2012 14:37:54 -0800 Subject: [PATCH 010/925] Add example sent by Ganesh Signed-off-by: Leonardo de Moura --- examples/python/hamiltonian/hamiltonian.py | 88 ++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 examples/python/hamiltonian/hamiltonian.py diff --git a/examples/python/hamiltonian/hamiltonian.py b/examples/python/hamiltonian/hamiltonian.py new file mode 100644 index 000000000..75b7599a7 --- /dev/null +++ b/examples/python/hamiltonian/hamiltonian.py @@ -0,0 +1,88 @@ +############################################ +# Copyright (c) 2012 Ganesh Gopalakrishnan ganesh@cs.utah.edu +# +# Hamiltonian +# +# Author: Ganesh Gopalakrishnan ganesh@cs.utah.edu +############################################ +from z3 import * + +def gencon(gr): + """ + Input a graph as an adjacency list, e.g. {0:[1,2], 1:[2], 2:[1,0]}. + Produces solver to check if the given graph has + a Hamiltonian cycle. Query the solver using s.check() and if sat, + then s.model() spells out the cycle. Two example graphs from + http://en.wikipedia.org/wiki/Hamiltonian_path are tested. + + ======================================================= + + Explanation: + + Generate a list of Int vars. Constrain the first Int var ("Node 0") to be 0. + Pick a node i, and attempt to number all nodes reachable from i to have a + number one higher (mod L) than assigned to node i (use an Or constraint). + + ======================================================= + """ + L = len(gr) + cv = [Int('cv%s'%i) for i in range(L)] + s = Solver() + s.add(cv[0]==0) + for i in range(L): + s.add(Or([cv[j]==(cv[i]+1)%L for j in gr[i]])) + return s + +def examples(): + # Example Graphs: The Dodecahedral graph from http://en.wikipedia.org/wiki/Hamiltonian_path + grdodec = { 0: [1, 4, 5], + 1: [0, 7, 2], + 2: [1, 9, 3], + 3: [2, 11, 4], + 4: [3, 13, 0], + 5: [0, 14, 6], + 6: [5, 16, 7], + 7: [6, 8, 1], + 8: [7, 17, 9], + 9: [8, 10, 2], + 10: [9, 18, 11], + 11: [10, 3, 12], + 12: [11, 19, 13], + 13: [12, 14, 4], + 14: [13, 15, 5], + 15: [14, 16, 19], + 16: [6, 17, 15], + 17: [16, 8, 18], + 18: [10, 19, 17], + 19: [18, 12, 15] } + import pprint + pp = pprint.PrettyPrinter(indent=4) + pp.pprint(grdodec) + + sdodec=gencon(grdodec) + print(sdodec.check()) + print(sdodec.model()) + # ======================================================= + # See http://en.wikipedia.org/wiki/Hamiltonian_path for the Herschel graph + # being the smallest possible polyhdral graph that does not have a Hamiltonian + # cycle. + # + grherschel = { 0: [1, 9, 10, 7], + 1: [0, 8, 2], + 2: [1, 9, 3], + 3: [2, 8, 4], + 4: [3, 9, 10, 5], + 5: [4, 8, 6], + 6: [5, 10, 7], + 7: [6, 8, 0], + 8: [1, 3, 5, 7], + 9: [2, 0, 4], + 10: [6, 4, 0] } + pp.pprint(grherschel) + sherschel=gencon(grherschel) + print(sherschel.check()) + # ======================================================= + +if __name__ == "__main__": + examples() + From 1235b3ea24d942e23f39eb62152a27e8adc4c44d Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Mon, 31 Dec 2012 14:40:52 -0800 Subject: [PATCH 011/925] Fix header Signed-off-by: Leonardo de Moura --- examples/python/hamiltonian/hamiltonian.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/python/hamiltonian/hamiltonian.py b/examples/python/hamiltonian/hamiltonian.py index 75b7599a7..32c911379 100644 --- a/examples/python/hamiltonian/hamiltonian.py +++ b/examples/python/hamiltonian/hamiltonian.py @@ -1,7 +1,7 @@ ############################################ # Copyright (c) 2012 Ganesh Gopalakrishnan ganesh@cs.utah.edu # -# Hamiltonian +# Check if the given graph has a Hamiltonian cycle. # # Author: Ganesh Gopalakrishnan ganesh@cs.utah.edu ############################################ From 8fb7de5110a870e9b5e82e41f70a61eec48296fd Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Tue, 9 Apr 2013 11:44:16 +0200 Subject: [PATCH 012/925] expose Z3_model_has_interp to C API --- src/api/api_model.cpp | 12 ++++++++++++ src/api/z3_api.h | 9 +++++++++ 2 files changed, 21 insertions(+) diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index a6ada4ae6..8bf1f39d9 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -62,6 +62,18 @@ extern "C" { Z3_CATCH_RETURN(0); } + Z3_bool Z3_API Z3_model_has_interp(Z3_context c, Z3_model m, Z3_func_decl a) { + Z3_TRY; + LOG_Z3_model_has_interp(c, m, a); + CHECK_NON_NULL(m, 0); + if (to_model_ref(m)->has_interpretation(to_func_decl(a))) { + return Z3_TRUE; + } else { + return Z3_FALSE; + } + Z3_CATCH_RETURN(Z3_FALSE); + } + Z3_func_interp Z3_API Z3_model_get_func_interp(Z3_context c, Z3_model m, Z3_func_decl f) { Z3_TRY; LOG_Z3_model_get_func_interp(c, m, f); diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 8d00fb044..050c648e9 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -4455,6 +4455,15 @@ END_MLAPI_EXCLUDE */ Z3_ast_opt Z3_API Z3_model_get_const_interp(__in Z3_context c, __in Z3_model m, __in Z3_func_decl a); + /** + \brief Test if there exists an interpretation (i.e., assignment) of constant \c a in the model \c m. + + \pre Z3_get_arity(c, a) == 0 + + def_API('Z3_model_has_interp', BOOL, (_in(CONTEXT), _in(MODEL), _in(FUNC_DECL))) + */ + Z3_bool Z3_API Z3_model_has_interp(__in Z3_context c, __in Z3_model m, __in Z3_func_decl a); + /** \brief Return the interpretation of the function \c f in the model \c m. Return \mlonly [None], \endmlonly \conly \c NULL, From 8e20b3f24895e80a26dc5ce5873320d17f2957c0 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Tue, 9 Apr 2013 08:56:01 -0700 Subject: [PATCH 013/925] Remove unnecessary pre-condition. Signed-off-by: Leonardo de Moura --- src/api/z3_api.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 468dfdf7b..0f0f4cfd5 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -4515,9 +4515,7 @@ END_MLAPI_EXCLUDE Z3_ast_opt Z3_API Z3_model_get_const_interp(__in Z3_context c, __in Z3_model m, __in Z3_func_decl a); /** - \brief Test if there exists an interpretation (i.e., assignment) of constant \c a in the model \c m. - - \pre Z3_get_arity(c, a) == 0 + \brief Test if there exists an interpretation (i.e., assignment) for \c a in the model \c m. def_API('Z3_model_has_interp', BOOL, (_in(CONTEXT), _in(MODEL), _in(FUNC_DECL))) */ From 095ba806ab012ad66f204ab3cc85f82064ae7907 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Wed, 5 Jun 2013 14:06:53 -0700 Subject: [PATCH 014/925] Apply patch submitted by David Cok Signed-off-by: Leonardo de Moura --- src/smt/smt_clause.h | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/smt/smt_clause.h b/src/smt/smt_clause.h index 200508c53..c7378dc39 100644 --- a/src/smt/smt_clause.h +++ b/src/smt/smt_clause.h @@ -65,6 +65,13 @@ namespace smt { unsigned r = sizeof(clause) + sizeof(literal) * num_lits; if (k != CLS_AUX) r += sizeof(unsigned); + /* dvitek: Fix alignment issues on 64-bit platforms. The + * 'if' statement below probably isn't worthwhile since + * I'm guessing the allocator is probably going to round + * up internally anyway. + */ + //if (has_atoms || has_del_eh || has_justification) + r = (r + (sizeof(void*)-1)) & ~(sizeof(void*)-1); if (has_atoms) r += sizeof(expr*) * num_lits; if (has_del_eh) @@ -86,7 +93,13 @@ namespace smt { unsigned const * addr = get_activity_addr(); if (is_lemma()) addr ++; - return reinterpret_cast(addr); + /* dvitek: It would be better to use uintptr_t than + * size_t, but we need to wait until c++11 support is + * really available. + */ + size_t as_int = reinterpret_cast(addr); + as_int = (as_int + sizeof(void*)-1) & ~static_cast(sizeof(void*)-1); + return reinterpret_cast(as_int); } justification * const * get_justification_addr() const { From 38d1f30dba0661792c3f208a3542b0d835b92405 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Wed, 5 Jun 2013 14:11:11 -0700 Subject: [PATCH 015/925] Apply patch submitted by David Cok Signed-off-by: Leonardo de Moura --- src/smt/watch_list.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/smt/watch_list.cpp b/src/smt/watch_list.cpp index 731e021fe..ed73b9ed5 100644 --- a/src/smt/watch_list.cpp +++ b/src/smt/watch_list.cpp @@ -48,12 +48,17 @@ namespace smt { *mem = DEFAULT_WATCH_LIST_SIZE; ++mem; m_data = reinterpret_cast(mem); + SASSERT( begin_lits_core() % sizeof(literal) == 0 ); } else { unsigned curr_begin_bin = begin_lits_core(); unsigned curr_capacity = end_lits_core(); unsigned bin_bytes = curr_capacity - curr_begin_bin; - unsigned new_capacity = (curr_capacity * 3 + sizeof(clause *)) >> 1; + /* dvitek: Added +3&~3U to fix alignment issues on + * sparc64/solaris. ("literal"s must be 4-byte aligned). Should + * also help performance elsewhere. + */ + unsigned new_capacity = (((curr_capacity * 3 + sizeof(clause *)) >> 1)+3)&~3U; unsigned * mem = reinterpret_cast(alloc_svect(char, new_capacity + HEADER_SIZE)); unsigned curr_end_cls = end_cls_core(); #ifdef _AMD64_ @@ -71,6 +76,7 @@ namespace smt { memcpy(reinterpret_cast(mem) + new_begin_bin, m_data + curr_begin_bin, bin_bytes); destroy(); m_data = reinterpret_cast(mem); + SASSERT( begin_lits_core() % sizeof(literal) == 0 ); } } From 726f66a77c19d41284d9793463f7925c2e2b3216 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 14 Oct 2013 17:08:24 -0700 Subject: [PATCH 016/925] initial opt commands Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 3 +- src/cmd_context/cmd_context.cpp | 2 +- src/opt/opt_cmds.cpp | 150 ++++++++++++++++++++++++++++++++ src/opt/opt_cmds.h | 28 ++++++ src/shell/smtlib_frontend.cpp | 2 + 5 files changed, 183 insertions(+), 2 deletions(-) create mode 100644 src/opt/opt_cmds.cpp create mode 100644 src/opt/opt_cmds.h diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 6054f4769..ccae41dcb 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -63,6 +63,7 @@ def init_project_def(): add_lib('tab', ['muz', 'transforms'], 'muz/tab') add_lib('bmc', ['muz', 'transforms'], 'muz/bmc') add_lib('fp', ['muz', 'pdr', 'clp', 'tab', 'rel', 'bmc'], 'muz/fp') + add_lib('opt', ['smt'], 'opt') add_lib('smtlogic_tactics', ['arith_tactics', 'bv_tactics', 'nlsat_tactic', 'smt_tactic', 'aig_tactic', 'fp', 'muz','qe'], 'tactic/smtlogics') add_lib('ufbv_tactic', ['normal_forms', 'core_tactics', 'macros', 'smt_tactic', 'rewriter'], 'tactic/ufbv') add_lib('portfolio', ['smtlogic_tactics', 'ufbv_tactic', 'fpa', 'aig_tactic', 'fp', 'qe','sls_tactic', 'subpaving_tactic'], 'tactic/portfolio') @@ -70,7 +71,7 @@ def init_project_def(): API_files = ['z3_api.h', 'z3_algebraic.h', 'z3_polynomial.h', 'z3_rcf.h'] add_lib('api', ['portfolio', 'user_plugin', 'smtparser', 'realclosure'], includes2install=['z3.h', 'z3_v1.h', 'z3_macros.h'] + API_files) - add_exe('shell', ['api', 'sat', 'extra_cmds'], exe_name='z3') + add_exe('shell', ['api', 'sat', 'extra_cmds','opt'], exe_name='z3') add_exe('test', ['api', 'fuzzing'], exe_name='test-z3', install=False) add_dll('api_dll', ['api', 'sat', 'extra_cmds'], 'api/dll', reexports=['api'], diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 261af3092..023b30903 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -335,10 +335,10 @@ cmd_context::~cmd_context() { if (m_main_ctx) { set_verbose_stream(std::cerr); } - reset(true); finalize_cmds(); finalize_tactic_cmds(); finalize_probes(); + reset(true); m_solver = 0; m_check_sat_result = 0; } diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp new file mode 100644 index 000000000..e4a64ae6c --- /dev/null +++ b/src/opt/opt_cmds.cpp @@ -0,0 +1,150 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + opt_cmds.cpp + +Abstract: + Commands for optimization benchmarks + +Author: + + Anh-Phan Dung (t-anphan) 2013-10-14 + +Notes: + +--*/ +#include "opt_cmds.h" +#include "cmd_context.h" +#include "ast_pp.h" + +class opt_context { + ast_manager& m; + expr_ref_vector m_formulas; + vector m_weights; +public: + opt_context(ast_manager& m): + m(m), + m_formulas(m) + {} + + void add_formula(expr* f, rational const& w) { + m_formulas.push_back(f); + m_weights.push_back(w); + } + + expr_ref_vector const& formulas() const { return m_formulas; } + vector const& weights() const { return m_weights; } +}; + +class assert_weighted_cmd : public cmd { + opt_context* m_opt_ctx; + unsigned m_idx; + expr_ref m_formula; + rational m_weight; +public: + assert_weighted_cmd(cmd_context& ctx, opt_context* opt_ctx): + cmd("assert-weighted"), + m_opt_ctx(opt_ctx), + m_idx(0), + m_formula(ctx.m()), + m_weight(0) + {} + + virtual ~assert_weighted_cmd() { + dealloc(m_opt_ctx); + } + + virtual void reset(cmd_context & ctx) { + m_idx = 0; + m_formula = 0; + } + virtual char const * get_usage() const { return " "; } + virtual char const * get_descr(cmd_context & ctx) const { return "assert soft constraint with weight"; } + virtual unsigned get_arity() const { return 2; } + + // command invocation + virtual void prepare(cmd_context & ctx) {} + virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { if (m_idx == 0) return CPK_EXPR; return CPK_NUMERAL; } + virtual void set_next_arg(cmd_context & ctx, rational const & val) { + SASSERT(m_idx == 1); + if (!val.is_pos()) { + throw cmd_exception("Invalid weight. Weights must be positive."); + } + m_weight = val; + ++m_idx; + } + + virtual void set_next_arg(cmd_context & ctx, expr * t) { + SASSERT(m_idx == 0); + if (!ctx.m().is_bool(t)) { + throw cmd_exception("Invalid type for expression. Expected Boolean type."); + } + m_formula = t; + ++m_idx; + } + + virtual void failure_cleanup(cmd_context & ctx) { + reset(ctx); + } + + virtual void execute(cmd_context & ctx) { + std::cout << "TODO: " << mk_pp(m_formula, ctx.m()) << " " << m_weight << "\n"; + m_opt_ctx->add_formula(m_formula, m_weight); + reset(ctx); + } + + virtual void finalize(cmd_context & ctx) { + std::cout << "FINALIZE\n"; + } + +}; + +// what amounts to check-sat, but uses the *single* objective function. +// alternative is to register multiple objective functions using +// minimize/maximize and then use check-sat or some variant of it +// to do the feasibility check. +class min_maximize_cmd : public cmd { + bool m_is_max; + opt_context* m_opt_ctx; +public: + min_maximize_cmd(cmd_context& ctx, opt_context* opt_ctx, bool is_max): + cmd(is_max?"maximize":"minimize"), + m_is_max(is_max), + m_opt_ctx(opt_ctx) + {} + + virtual char const * get_usage() const { return ""; } + virtual char const * get_descr(cmd_context & ctx) const { return "check sat modulo objective function";} + virtual unsigned get_arity() const { return 1; } + + // etc. TODO: Phan, add the appropriate callbacks as a warmup. + + virtual void execute(cmd_context & ctx) { + // here is how to retrieve the soft constraints: + m_opt_ctx->formulas(); + m_opt_ctx->weights(); + get_background(ctx); + // reset m_opt_ctx? + } + +private: + void get_background(cmd_context& ctx) { + ptr_vector::const_iterator it = ctx.begin_assertions(); + ptr_vector::const_iterator end = ctx.end_assertions(); + for (; it != end; ++it) { + // need a solver object that supports soft constraints + // m_solver.assert_expr(*it); + } + } + +}; + + +void install_opt_cmds(cmd_context & ctx) { + opt_context* opt_ctx = alloc(opt_context, ctx.m()); + ctx.insert(alloc(assert_weighted_cmd, ctx, opt_ctx)); + ctx.insert(alloc(min_maximize_cmd, ctx, opt_ctx, true)); + ctx.insert(alloc(min_maximize_cmd, ctx, opt_ctx, false)); +} diff --git a/src/opt/opt_cmds.h b/src/opt/opt_cmds.h new file mode 100644 index 000000000..0ba028c63 --- /dev/null +++ b/src/opt/opt_cmds.h @@ -0,0 +1,28 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + opt_cmds.h + +Abstract: + Commands for optimization benchmarks + +Author: + + Anh-Phan Dung (t-anphan) 2013-10-14 + +Notes: + +--*/ +#ifndef _OPT_CMDS_H_ +#define _OPT_CMDS_H_ + +#include "ast.h" + +class cmd_context; + +void install_opt_cmds(cmd_context & ctx); + + +#endif diff --git a/src/shell/smtlib_frontend.cpp b/src/shell/smtlib_frontend.cpp index b5d8635da..2ec1e200a 100644 --- a/src/shell/smtlib_frontend.cpp +++ b/src/shell/smtlib_frontend.cpp @@ -26,6 +26,7 @@ Revision History: #include"smt2parser.h" #include"dl_cmds.h" #include"dbg_cmds.h" +#include"opt_cmds.h" #include"polynomial_cmds.h" #include"subpaving_cmds.h" #include"smt_strategic_solver.h" @@ -110,6 +111,7 @@ unsigned read_smtlib2_commands(char const * file_name) { install_dbg_cmds(ctx); install_polynomial_cmds(ctx); install_subpaving_cmds(ctx); + install_opt_cmds(ctx); g_cmd_context = &ctx; signal(SIGINT, on_ctrl_c); From ac97a12bb8482c0d991b841a2b5eb20d96c0b99c Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Tue, 15 Oct 2013 11:52:27 -0700 Subject: [PATCH 017/925] Create callbacks for min_maximize_cmd Enable VS_PROJ = true for temporary use --- scripts/mk_util.py | 2 +- src/opt/opt_cmds.cpp | 29 ++++++++++++++++++++++++----- src/opt/opt_cmds.h | 2 +- src/opt/plan.txt | 9 +++++++++ 4 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 src/opt/plan.txt diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 98f213dd5..b65af4335 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -59,7 +59,7 @@ SHOW_CPPS = True VS_X64 = False ONLY_MAKEFILES = False Z3PY_SRC_DIR=None -VS_PROJ = False +VS_PROJ = True TRACE = False DOTNET_ENABLED=False JAVA_ENABLED=False diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index e4a64ae6c..b5b7d1ddd 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -10,7 +10,7 @@ Abstract: Author: - Anh-Phan Dung (t-anphan) 2013-10-14 + Anh-Dung Phan (t-anphan) 2013-10-14 Notes: @@ -23,6 +23,7 @@ class opt_context { ast_manager& m; expr_ref_vector m_formulas; vector m_weights; + public: opt_context(ast_manager& m): m(m), @@ -43,6 +44,7 @@ class assert_weighted_cmd : public cmd { unsigned m_idx; expr_ref m_formula; rational m_weight; + public: assert_weighted_cmd(cmd_context& ctx, opt_context* opt_ctx): cmd("assert-weighted"), @@ -60,6 +62,7 @@ public: m_idx = 0; m_formula = 0; } + virtual char const * get_usage() const { return " "; } virtual char const * get_descr(cmd_context & ctx) const { return "assert soft constraint with weight"; } virtual unsigned get_arity() const { return 2; } @@ -107,22 +110,39 @@ public: // to do the feasibility check. class min_maximize_cmd : public cmd { bool m_is_max; + expr_ref m_term; opt_context* m_opt_ctx; + public: min_maximize_cmd(cmd_context& ctx, opt_context* opt_ctx, bool is_max): cmd(is_max?"maximize":"minimize"), m_is_max(is_max), + m_term(ctx.m()), m_opt_ctx(opt_ctx) {} + virtual void reset(cmd_context & ctx) { + m_term = 0; + } + virtual char const * get_usage() const { return ""; } virtual char const * get_descr(cmd_context & ctx) const { return "check sat modulo objective function";} virtual unsigned get_arity() const { return 1; } - // etc. TODO: Phan, add the appropriate callbacks as a warmup. + virtual void prepare(cmd_context & ctx) {} + virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { return CPK_EXPR; } + + virtual void set_next_arg(cmd_context & ctx, expr * t) { + m_term = t; + } + + virtual void failure_cleanup(cmd_context & ctx) { + reset(ctx); + } virtual void execute(cmd_context & ctx) { - // here is how to retrieve the soft constraints: + std::cout << "TODO: " << mk_pp(m_term, ctx.m()) << "\n"; + // Here is how to retrieve the soft constraints m_opt_ctx->formulas(); m_opt_ctx->weights(); get_background(ctx); @@ -134,14 +154,13 @@ private: ptr_vector::const_iterator it = ctx.begin_assertions(); ptr_vector::const_iterator end = ctx.end_assertions(); for (; it != end; ++it) { - // need a solver object that supports soft constraints + // Need a solver object that supports soft constraints // m_solver.assert_expr(*it); } } }; - void install_opt_cmds(cmd_context & ctx) { opt_context* opt_ctx = alloc(opt_context, ctx.m()); ctx.insert(alloc(assert_weighted_cmd, ctx, opt_ctx)); diff --git a/src/opt/opt_cmds.h b/src/opt/opt_cmds.h index 0ba028c63..048871987 100644 --- a/src/opt/opt_cmds.h +++ b/src/opt/opt_cmds.h @@ -10,7 +10,7 @@ Abstract: Author: - Anh-Phan Dung (t-anphan) 2013-10-14 + Anh-Dung Phan (t-anphan) 2013-10-14 Notes: diff --git a/src/opt/plan.txt b/src/opt/plan.txt new file mode 100644 index 000000000..f728747ed --- /dev/null +++ b/src/opt/plan.txt @@ -0,0 +1,9 @@ +Create file with command-line extensions. +Similar to muz\fp\dl_cmds: + - Add command (minimize ) + - Add command (assert-weighted [:id]) the weight is a positive + rational number, 1 can be handled as a special case sd not weighted SAT, + but as ordinary MAXSAT (e.g., using Fu Malik algorithm. This is a sample). + Identifier is optional and used to group constraints together. + The F# sample illustrates what is meant. + From 45eda6c6ad138b6d2c6533150c1596c2fa105c86 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 15 Oct 2013 17:03:52 -0700 Subject: [PATCH 018/925] Fu&Malik v1 Signed-off-by: Nikolaj Bjorner --- src/opt/fu_malik.cpp | 144 +++++++++++++++++++++++++++++++++++++++++++ src/opt/fu_malik.h | 34 ++++++++++ 2 files changed, 178 insertions(+) create mode 100644 src/opt/fu_malik.cpp create mode 100644 src/opt/fu_malik.h diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp new file mode 100644 index 000000000..977174681 --- /dev/null +++ b/src/opt/fu_malik.cpp @@ -0,0 +1,144 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + fu_malik.cpp + +Abstract: + Fu&Malik built-in optimization method. + Adapted from sample code. + +Author: + + Anh-Dung Phan (t-anphan) 2013-10-15 + +Notes: + +--*/ + +#include "fu_malik.h" + +/** + \brief Fu & Malik procedure for MaxSAT. This procedure is based on + unsat core extraction and the at-most-one constraint. + + Return the number of soft-constraints that can be + satisfied. Return -1 if the hard-constraints cannot be + satisfied. That is, the formula cannot be satisfied even if all + soft-constraints are ignored. + + For more information on the Fu & Malik procedure: + + Z. Fu and S. Malik, On solving the partial MAX-SAT problem, in International + Conference on Theory and Applications of Satisfiability Testing, 2006. +*/ +namespace opt { + + class fu_malik { + ast_manager& m; + solver& s; + expr_ref_vector& m_soft; + expr_ref_vector m_aux; + public: + fu_malik(ast_manager& m, solver& s, expr_ref_vector& soft): + m(m), + s(s), + m_soft(soft), + m_aux_vars(m) + { + m_aux.reset(); + for (unsigned i = 0; i < m_soft.size(); i++) { + m_aux.push_back(m.mk_fresh_const("p",m.mk_bool())); + s.assert_expr(m.mk_or(m_soft[i].get(), m_aux[i].get())); + } + } + + + /** + \brief Implement one step of the Fu&Malik algorithm. + See fu_malik_maxsat function for more details. + + Input: soft constraints + aux-vars (aka answer literals) + Output: done/not-done when not done return updated set of soft-constraints and aux-vars. + - if SAT --> terminates + - if UNSAT + * compute unsat core + * add blocking variable to soft-constraints in the core + - replace soft-constraint with the one with the blocking variable + - we should also add an aux-var + - replace aux-var with a new one + * add at-most-one constraint with blocking + */ + + bool step() { + expr_ref_vector assumptions(m), block_vars(m); + for (unsigned i = 0; i < m_soft.size(); ++i) { + assumptions.push_back(m.mk_not(m_aux[i].get())); + } + lbool is_sat = s.check_sat(assumptions.size(), assumptions.c_ptr()); + if (is_sat != l_false) { + return true; + } + + ptr_vector core; + s.get_unsat_core(core); + + // update soft-constraints and aux_vars + for (i = 0; i < m_soft.size(); i++) { + + bool found = false; + for (unsigned j = 0; !found && j < core.size(); ++j) { + found = m_soft[i].get() == core[j]; + } + if (!found) { + continue; + } + expr_ref block_var(m); + block_var = m.mk_fresh_const("block_var", m.mk_bool_sort()); + m_aux[i] = m.mk_fresh_const("aux", m.mk_bool_sort()); + m_soft[i] = m.mk_or(m_soft[i].get(), block_var); + block_vars.push_back(block_var); + s.assert_expr(m.mk_or(m_soft[i].get(), m_aux[i].get())); + } + assert_at_most_one(block_vars); + return false; + } + + private: + + void assert_at_most_one(expr_ref_vector const& block_vars) { + + } + +#if 0 + expr_ref mk_at_most_one(unsigned n, expr* const * vars) { + if (n <= 1) { + return expr_ref(m.mk_true(), m); + } + unsigned mid = n/2; + + } +#endif + + }; + + + lbool fu_malik_maxsat(solver& s, expr_ref_vector& soft_constraints) { + ast_manager m = soft_constraints.get_manager(); + lbool is_sat = s.check(); + if (is_sat != l_true) { + return is_sat; + } + if (soft_constraints.empty()) { + return is_sat; + } + s.push(); + fu_malik fm(m, s, soft_constraints); + while (!fm.step()); + s.pop(); + // we are done and soft_constraints has been updated with the max-sat assignment. + } +}; + + diff --git a/src/opt/fu_malik.h b/src/opt/fu_malik.h new file mode 100644 index 000000000..7f3bb7eb0 --- /dev/null +++ b/src/opt/fu_malik.h @@ -0,0 +1,34 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + fu_malik.h + +Abstract: + Fu&Malik built-in optimization method. + Adapted from sample code. + +Author: + + Anh-Dung Phan (t-anphan) 2013-10-15 + +Notes: + +--*/ +#ifndef _OPT_FU_MALIK_H_ +#define _OPT_FU_MALIK_H_ + +#include "solver.h" + +namespace opt { + /** + takes solver with hard constraints added. + Returns a maximal satisfying subset of soft_constraints + that are still consistent with the solver state. + */ + + lbool fu_malik_maxsat(solver& s, expr_ref_vector& soft_constraints); +}; + +#endif From 8ae0b06912f8edfe48d2835d6316388df38a423d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 16 Oct 2013 02:07:30 -0700 Subject: [PATCH 019/925] fill in details on max sat Signed-off-by: Nikolaj Bjorner --- src/opt/fu_malik.cpp | 67 ++++++++++++++++++++++++++------------------ src/opt/opt_cmds.cpp | 52 ++++++++++++++++++++++++++-------- 2 files changed, 80 insertions(+), 39 deletions(-) diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index 977174681..92b26ad0b 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -38,26 +38,24 @@ namespace opt { class fu_malik { ast_manager& m; solver& s; - expr_ref_vector& m_soft; + expr_ref_vector m_soft; expr_ref_vector m_aux; public: - fu_malik(ast_manager& m, solver& s, expr_ref_vector& soft): + fu_malik(ast_manager& m, solver& s, expr_ref_vector const& soft): m(m), s(s), m_soft(soft), - m_aux_vars(m) + m_aux(m) { - m_aux.reset(); for (unsigned i = 0; i < m_soft.size(); i++) { - m_aux.push_back(m.mk_fresh_const("p",m.mk_bool())); - s.assert_expr(m.mk_or(m_soft[i].get(), m_aux[i].get())); + m_aux.push_back(m.mk_fresh_const("p", m.mk_bool_sort())); + s.assert_expr(m.mk_or(soft[i], m_aux[i].get())); } } /** - \brief Implement one step of the Fu&Malik algorithm. - See fu_malik_maxsat function for more details. + \brief One step of the Fu&Malik algorithm. Input: soft constraints + aux-vars (aka answer literals) Output: done/not-done when not done return updated set of soft-constraints and aux-vars. @@ -85,7 +83,7 @@ namespace opt { s.get_unsat_core(core); // update soft-constraints and aux_vars - for (i = 0; i < m_soft.size(); i++) { + for (unsigned i = 0; i < m_soft.size(); i++) { bool found = false; for (unsigned j = 0; !found && j < core.size(); ++j) { @@ -108,36 +106,49 @@ namespace opt { private: void assert_at_most_one(expr_ref_vector const& block_vars) { - + expr_ref has_one(m), no_one(m), at_most_one(m); + mk_at_most_one(block_vars.size(), block_vars.c_ptr(), has_one, no_one); + at_most_one = m.mk_or(has_one, no_one); + s.assert_expr(at_most_one); } -#if 0 - expr_ref mk_at_most_one(unsigned n, expr* const * vars) { - if (n <= 1) { - return expr_ref(m.mk_true(), m); + void mk_at_most_one(unsigned n, expr* const * vars, expr_ref& has_one, expr_ref& no_one) { + if (n == 1) { + has_one = vars[0]; + no_one = m.mk_not(vars[0]); + } + else { + unsigned mid = n/2; + expr_ref has_one1(m), has_one2(m), no_one1(m), no_one2(m); + mk_at_most_one(mid, vars, has_one1, no_one1); + mk_at_most_one(n-mid, vars+mid, has_one2, no_one2); + has_one = m.mk_or(m.mk_and(has_one1, no_one2), m.mk_and(has_one2, no_one1)); + no_one = m.mk_and(no_one1, no_one2); } - unsigned mid = n/2; - } -#endif }; + // TBD: the vector of soft constraints gets updated + // but we really want to return the maximal set of + // original soft constraints that are satisfied. + // so we need to read out of the model what soft constraints + // were satisfied. + lbool fu_malik_maxsat(solver& s, expr_ref_vector& soft_constraints) { ast_manager m = soft_constraints.get_manager(); - lbool is_sat = s.check(); - if (is_sat != l_true) { - return is_sat; + lbool is_sat = s.check_sat(0,0); + if (!soft_constraints.empty() && is_sat == l_true) { + s.push(); + fu_malik fm(m, s, soft_constraints); + while (!fm.step()); + s.pop(1); } - if (soft_constraints.empty()) { - return is_sat; - } - s.push(); - fu_malik fm(m, s, soft_constraints); - while (!fm.step()); - s.pop(); - // we are done and soft_constraints has been updated with the max-sat assignment. + // we are done and soft_constraints has + // been updated with the max-sat assignment. + + return is_sat; } }; diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index b5b7d1ddd..8c0a458d5 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -18,6 +18,8 @@ Notes: #include "opt_cmds.h" #include "cmd_context.h" #include "ast_pp.h" +#include "smt_solver.h" +#include "fu_malik.h" class opt_context { ast_manager& m; @@ -35,7 +37,7 @@ public: m_weights.push_back(w); } - expr_ref_vector const& formulas() const { return m_formulas; } + expr_ref_vector const & formulas() const { return m_formulas; } vector const& weights() const { return m_weights; } }; @@ -93,7 +95,6 @@ public: } virtual void execute(cmd_context & ctx) { - std::cout << "TODO: " << mk_pp(m_formula, ctx.m()) << " " << m_weight << "\n"; m_opt_ctx->add_formula(m_formula, m_weight); reset(ctx); } @@ -141,22 +142,51 @@ public: } virtual void execute(cmd_context & ctx) { + ast_manager& m = m_term.get_manager(); std::cout << "TODO: " << mk_pp(m_term, ctx.m()) << "\n"; // Here is how to retrieve the soft constraints - m_opt_ctx->formulas(); - m_opt_ctx->weights(); - get_background(ctx); - // reset m_opt_ctx? - } + expr_ref_vector const& fmls = m_opt_ctx->formulas(); + vector const& ws = m_opt_ctx->weights(); + + // TODO: move most functionaltiy to separate module, because it is going to grow.. + ref s; + symbol logic; + params_ref p; + p.set_bool("model", true); + p.set_bool("unsat_core", true); + s = mk_smt_solver(m, p, logic); -private: - void get_background(cmd_context& ctx) { ptr_vector::const_iterator it = ctx.begin_assertions(); ptr_vector::const_iterator end = ctx.end_assertions(); for (; it != end; ++it) { - // Need a solver object that supports soft constraints - // m_solver.assert_expr(*it); + s->assert_expr(*it); } + expr_ref_vector fmls_copy(fmls); + if (is_maxsat_problem(ws)) { + lbool is_sat = opt::fu_malik_maxsat(*s, fmls_copy); + std::cout << "is-sat: " << is_sat << "\n"; + if (is_sat == l_true) { + for (unsigned i = 0; i < fmls_copy.size(); ++i) { + std::cout << mk_pp(fmls_copy[i].get(), m) << "\n"; + } + } + } + else { + NOT_IMPLEMENTED_YET(); + } + + // handle optimization criterion. + } + +private: + + bool is_maxsat_problem(vector const& ws) const { + for (unsigned i = 0; i < ws.size(); ++i) { + if (!ws[i].is_one()) { + return false; + } + } + return true; } }; From 3da47a280e419547ea7d5324102a6b2c0d47e123 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Wed, 16 Oct 2013 17:55:53 -0700 Subject: [PATCH 020/925] Complete Fu & Malik MAXSAT implementation Mistakes: (1) ast_manager shouldn't be replicated. (2) assumptions should be used to compare with unsat cores --- src/opt/fu_malik.cpp | 65 ++++++++++++++++++++++++++------------------ src/opt/fu_malik.h | 4 +-- 2 files changed, 41 insertions(+), 28 deletions(-) diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index 92b26ad0b..07d256d9e 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -6,8 +6,8 @@ Module Name: fu_malik.cpp Abstract: - Fu&Malik built-in optimization method. - Adapted from sample code. + Fu & Malik built-in optimization method. + Adapted from sample code in C. Author: @@ -40,16 +40,18 @@ namespace opt { solver& s; expr_ref_vector m_soft; expr_ref_vector m_aux; + public: + fu_malik(ast_manager& m, solver& s, expr_ref_vector const& soft): m(m), s(s), m_soft(soft), m_aux(m) { - for (unsigned i = 0; i < m_soft.size(); i++) { + for (unsigned i = 0; i < m_soft.size(); ++i) { m_aux.push_back(m.mk_fresh_const("p", m.mk_bool_sort())); - s.assert_expr(m.mk_or(soft[i], m_aux[i].get())); + s.assert_expr(m.mk_or(m_soft[i].get(), m_aux[i].get())); } } @@ -82,12 +84,12 @@ namespace opt { ptr_vector core; s.get_unsat_core(core); - // update soft-constraints and aux_vars - for (unsigned i = 0; i < m_soft.size(); i++) { + // Update soft-constraints and aux_vars + for (unsigned i = 0; i < m_soft.size(); ++i) { bool found = false; for (unsigned j = 0; !found && j < core.size(); ++j) { - found = m_soft[i].get() == core[j]; + found = assumptions[i].get() == core[j]; } if (!found) { continue; @@ -106,46 +108,57 @@ namespace opt { private: void assert_at_most_one(expr_ref_vector const& block_vars) { - expr_ref has_one(m), no_one(m), at_most_one(m); - mk_at_most_one(block_vars.size(), block_vars.c_ptr(), has_one, no_one); - at_most_one = m.mk_or(has_one, no_one); + expr_ref has_one(m), has_zero(m), at_most_one(m); + mk_at_most_one(block_vars.size(), block_vars.c_ptr(), has_one, has_zero); + at_most_one = m.mk_or(has_one, has_zero); s.assert_expr(at_most_one); } - void mk_at_most_one(unsigned n, expr* const * vars, expr_ref& has_one, expr_ref& no_one) { + void mk_at_most_one(unsigned n, expr* const * vars, expr_ref& has_one, expr_ref& has_zero) { + SASSERT(n != 0); if (n == 1) { has_one = vars[0]; - no_one = m.mk_not(vars[0]); + has_zero = m.mk_not(vars[0]); } else { unsigned mid = n/2; - expr_ref has_one1(m), has_one2(m), no_one1(m), no_one2(m); - mk_at_most_one(mid, vars, has_one1, no_one1); - mk_at_most_one(n-mid, vars+mid, has_one2, no_one2); - has_one = m.mk_or(m.mk_and(has_one1, no_one2), m.mk_and(has_one2, no_one1)); - no_one = m.mk_and(no_one1, no_one2); + expr_ref has_one1(m), has_one2(m), has_zero1(m), has_zero2(m); + mk_at_most_one(mid, vars, has_one1, has_zero1); + mk_at_most_one(n-mid, vars+mid, has_one2, has_zero2); + has_one = m.mk_or(m.mk_and(has_one1, has_zero2), m.mk_and(has_one2, has_zero1)); + has_zero = m.mk_and(has_zero1, has_zero2); } } }; - - // TBD: the vector of soft constraints gets updated - // but we really want to return the maximal set of - // original soft constraints that are satisfied. - // so we need to read out of the model what soft constraints - // were satisfied. - lbool fu_malik_maxsat(solver& s, expr_ref_vector& soft_constraints) { - ast_manager m = soft_constraints.get_manager(); + ast_manager& m = soft_constraints.get_manager(); lbool is_sat = s.check_sat(0,0); if (!soft_constraints.empty() && is_sat == l_true) { s.push(); + fu_malik fm(m, s, soft_constraints); while (!fm.step()); + + // Get a list of satisfying soft_constraints + model_ref model; + s.get_model(model); + + expr_ref_vector result(m); + for (unsigned i = 0; i < soft_constraints.size(); ++i) { + expr_ref val(m); + VERIFY(model->eval(soft_constraints[i].get(), val)); + if (!m.is_false(val)) { + result.push_back(soft_constraints[i].get()); + } + } + soft_constraints.reset(); + soft_constraints.append(result); + s.pop(1); } - // we are done and soft_constraints has + // We are done and soft_constraints has // been updated with the max-sat assignment. return is_sat; diff --git a/src/opt/fu_malik.h b/src/opt/fu_malik.h index 7f3bb7eb0..6bfe37f63 100644 --- a/src/opt/fu_malik.h +++ b/src/opt/fu_malik.h @@ -7,7 +7,7 @@ Module Name: Abstract: Fu&Malik built-in optimization method. - Adapted from sample code. + Adapted from sample code in C. Author: @@ -23,7 +23,7 @@ Notes: namespace opt { /** - takes solver with hard constraints added. + Takes solver with hard constraints added. Returns a maximal satisfying subset of soft_constraints that are still consistent with the solver state. */ From f4e2b232380f16b11e86280231eeedce3e0e05d9 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Wed, 16 Oct 2013 17:56:35 -0700 Subject: [PATCH 021/925] Create placeholders to optimization methods --- scripts/mk_util.py | 2 +- src/opt/opt_cmds.cpp | 100 +++++++++++--------------------- src/opt/opt_context.cpp | 94 ++++++++++++++++++++++++++++++ src/opt/opt_context.h | 66 +++++++++++++++++++++ src/opt/optimize_objectives.cpp | 60 +++++++++++++++++++ src/opt/optimize_objectives.h | 35 +++++++++++ src/opt/plan.txt | 8 +++ src/opt/weighted_maxsat.cpp | 33 +++++++++++ src/opt/weighted_maxsat.h | 33 +++++++++++ 9 files changed, 363 insertions(+), 68 deletions(-) create mode 100644 src/opt/opt_context.cpp create mode 100644 src/opt/opt_context.h create mode 100644 src/opt/optimize_objectives.cpp create mode 100644 src/opt/optimize_objectives.h create mode 100644 src/opt/weighted_maxsat.cpp create mode 100644 src/opt/weighted_maxsat.h diff --git a/scripts/mk_util.py b/scripts/mk_util.py index b65af4335..98f213dd5 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -59,7 +59,7 @@ SHOW_CPPS = True VS_X64 = False ONLY_MAKEFILES = False Z3PY_SRC_DIR=None -VS_PROJ = True +VS_PROJ = False TRACE = False DOTNET_ENABLED=False JAVA_ENABLED=False diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index 8c0a458d5..b4b6d62f2 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -18,37 +18,18 @@ Notes: #include "opt_cmds.h" #include "cmd_context.h" #include "ast_pp.h" -#include "smt_solver.h" -#include "fu_malik.h" -class opt_context { - ast_manager& m; - expr_ref_vector m_formulas; - vector m_weights; +#include "opt_context.h" -public: - opt_context(ast_manager& m): - m(m), - m_formulas(m) - {} - - void add_formula(expr* f, rational const& w) { - m_formulas.push_back(f); - m_weights.push_back(w); - } - - expr_ref_vector const & formulas() const { return m_formulas; } - vector const& weights() const { return m_weights; } -}; class assert_weighted_cmd : public cmd { - opt_context* m_opt_ctx; + opt::context* m_opt_ctx; unsigned m_idx; expr_ref m_formula; rational m_weight; public: - assert_weighted_cmd(cmd_context& ctx, opt_context* opt_ctx): + assert_weighted_cmd(cmd_context& ctx, opt::context* opt_ctx): cmd("assert-weighted"), m_opt_ctx(opt_ctx), m_idx(0), @@ -95,12 +76,11 @@ public: } virtual void execute(cmd_context & ctx) { - m_opt_ctx->add_formula(m_formula, m_weight); + m_opt_ctx->add_soft_constraint(m_formula, m_weight); reset(ctx); } virtual void finalize(cmd_context & ctx) { - std::cout << "FINALIZE\n"; } }; @@ -111,19 +91,16 @@ public: // to do the feasibility check. class min_maximize_cmd : public cmd { bool m_is_max; - expr_ref m_term; - opt_context* m_opt_ctx; + opt::context* m_opt_ctx; public: - min_maximize_cmd(cmd_context& ctx, opt_context* opt_ctx, bool is_max): + min_maximize_cmd(cmd_context& ctx, opt::context* opt_ctx, bool is_max): cmd(is_max?"maximize":"minimize"), m_is_max(is_max), - m_term(ctx.m()), m_opt_ctx(opt_ctx) {} virtual void reset(cmd_context & ctx) { - m_term = 0; } virtual char const * get_usage() const { return ""; } @@ -134,7 +111,9 @@ public: virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { return CPK_EXPR; } virtual void set_next_arg(cmd_context & ctx, expr * t) { - m_term = t; + // TODO: type check objective term. It should pass basic sanity being + // integer, real (, bit-vector) or other supported objective function type. + m_opt_ctx->add_objective(t, m_is_max); } virtual void failure_cleanup(cmd_context & ctx) { @@ -142,58 +121,45 @@ public: } virtual void execute(cmd_context & ctx) { - ast_manager& m = m_term.get_manager(); - std::cout << "TODO: " << mk_pp(m_term, ctx.m()) << "\n"; - // Here is how to retrieve the soft constraints - expr_ref_vector const& fmls = m_opt_ctx->formulas(); - vector const& ws = m_opt_ctx->weights(); + } - // TODO: move most functionaltiy to separate module, because it is going to grow.. - ref s; - symbol logic; - params_ref p; - p.set_bool("model", true); - p.set_bool("unsat_core", true); - s = mk_smt_solver(m, p, logic); + +}; + +class optimize_cmd : public cmd { + opt::context* m_opt_ctx; +public: + optimize_cmd(opt::context* opt_ctx): + cmd("optimize"), + m_opt_ctx(opt_ctx) + {} + virtual char const * get_descr(cmd_context & ctx) const { return "check sat modulo objective function";} + virtual unsigned get_arity() const { return 0; } + virtual void prepare(cmd_context & ctx) {} + virtual void failure_cleanup(cmd_context & ctx) { + reset(ctx); + } + + virtual void execute(cmd_context & ctx) { ptr_vector::const_iterator it = ctx.begin_assertions(); ptr_vector::const_iterator end = ctx.end_assertions(); for (; it != end; ++it) { - s->assert_expr(*it); - } - expr_ref_vector fmls_copy(fmls); - if (is_maxsat_problem(ws)) { - lbool is_sat = opt::fu_malik_maxsat(*s, fmls_copy); - std::cout << "is-sat: " << is_sat << "\n"; - if (is_sat == l_true) { - for (unsigned i = 0; i < fmls_copy.size(); ++i) { - std::cout << mk_pp(fmls_copy[i].get(), m) << "\n"; - } - } - } - else { - NOT_IMPLEMENTED_YET(); + m_opt_ctx->add_hard_constraint(*it); } + m_opt_ctx->optimize(); - // handle optimization criterion. + } - private: - bool is_maxsat_problem(vector const& ws) const { - for (unsigned i = 0; i < ws.size(); ++i) { - if (!ws[i].is_one()) { - return false; - } - } - return true; - } }; void install_opt_cmds(cmd_context & ctx) { - opt_context* opt_ctx = alloc(opt_context, ctx.m()); + opt::context* opt_ctx = alloc(opt::context, ctx.m()); ctx.insert(alloc(assert_weighted_cmd, ctx, opt_ctx)); ctx.insert(alloc(min_maximize_cmd, ctx, opt_ctx, true)); ctx.insert(alloc(min_maximize_cmd, ctx, opt_ctx, false)); + ctx.insert(alloc(optimize_cmd, opt_ctx)); } diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp new file mode 100644 index 000000000..dbbcffa7c --- /dev/null +++ b/src/opt/opt_context.cpp @@ -0,0 +1,94 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + opt_context.cpp + +Abstract: + Facility for running optimization problem. + +Author: + + Anh-Dung Phan (t-anphan) 2013-10-16 + +Notes: + +--*/ + + +#include "opt_context.h" +#include "smt_solver.h" +#include "fu_malik.h" +#include "weighted_maxsat.h" +#include "optimize_objectives.h" +#include "ast_pp.h" + +namespace opt { + + void context::optimize() { + + expr_ref_vector const& fmls = m_soft_constraints; + + ref s; + symbol logic; + params_ref p; + p.set_bool("model", true); + p.set_bool("unsat_core", true); + s = mk_smt_solver(m, p, logic); + + for (unsigned i = 0; i < m_hard_constraints.size(); ++i) { + s->assert_expr(m_hard_constraints[i].get()); + } + + expr_ref_vector fmls_copy(fmls); + lbool is_sat; + if (!fmls.empty()) { + if (is_maxsat_problem()) { + is_sat = opt::fu_malik_maxsat(*s, fmls_copy); + } + else { + is_sat = weighted_maxsat(*s, fmls_copy, m_weights); + } + std::cout << "is-sat: " << is_sat << "\n"; + if (is_sat != l_true) { + return; + } + for (unsigned i = 0; i < fmls_copy.size(); ++i) { + std::cout << "Satisfying soft constraint: " << mk_pp(fmls_copy[i].get(), m) << "\n"; + } + } + + if (!m_objectives.empty()) { + vector > values; + for (unsigned i = 0; i < fmls_copy.size(); ++i) { + s->assert_expr(fmls_copy[i].get()); + } + is_sat = optimize_objectives(*s, m_objectives, m_is_max, values); + std::cout << "is-sat: " << is_sat << "\n"; + if (is_sat != l_true) { + return; + } + for (unsigned i = 0; i < values.size(); ++i) { + // display + } + } + + if (m_objectives.empty() && m_soft_constraints.empty()) { + is_sat = s->check_sat(0,0); + std::cout << "nothing to optimize: is-sat " << is_sat << "\n"; + } + + } + + bool context::is_maxsat_problem() const { + vector const& ws = m_weights; + for (unsigned i = 0; i < ws.size(); ++i) { + if (!ws[i].is_one()) { + return false; + } + } + return true; + } + +} diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h new file mode 100644 index 000000000..9e226389e --- /dev/null +++ b/src/opt/opt_context.h @@ -0,0 +1,66 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + opt_context.h + +Abstract: + Facility for running optimization problem. + +Author: + + Anh-Dung Phan (t-anphan) 2013-10-16 + +Notes: + +--*/ +#ifndef _OPT_CONTEXT_H_ +#define _OPT_CONTEXT_H_ + +#include "ast.h" + +namespace opt { + + class context { + ast_manager& m; + expr_ref_vector m_hard_constraints; + expr_ref_vector m_soft_constraints; + vector m_weights; + + expr_ref_vector m_objectives; + svector m_is_max; + + public: + context(ast_manager& m): + m(m), + m_hard_constraints(m), + m_soft_constraints(m), + m_objectives(m) + {} + + void add_soft_constraint(expr* f, rational const& w) { + m_soft_constraints.push_back(f); + m_weights.push_back(w); + } + + void add_objective(expr* t, bool is_max) { + m_objectives.push_back(t); + m_is_max.push_back(is_max); + } + + void add_hard_constraint(expr* f) { + m_hard_constraints.push_back(f); + } + + void optimize(); + + private: + bool is_maxsat_problem() const; + + }; + + +} + +#endif \ No newline at end of file diff --git a/src/opt/optimize_objectives.cpp b/src/opt/optimize_objectives.cpp new file mode 100644 index 000000000..6f7f5c85e --- /dev/null +++ b/src/opt/optimize_objectives.cpp @@ -0,0 +1,60 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + optimize_objectives.cpp + +Abstract: + + Objective optimization method. + +Author: + + Anh-Dung Phan (t-anphan) 2013-10-16 + +Notes: + +--*/ + + +#include "optimize_objectives.h" + +namespace opt { + + /* + Enumerate locally optimal assignments until fixedpoint. + */ + lbool mathsat_style_opt(solver& s, + expr_ref_vector& objectives, svector const& is_max, + vector >& values) { + lbool is_sat; + is_sat = s.check_sat(0,0); + if (is_sat != l_true) { + return is_sat; + } + // assume that s is instrumented to produce locally optimal assignments. + + while (is_sat != l_false) { + model_ref model; + s.get_model(model); + // extract values for objectives. + // store them in values. + // assert there must be something better. + is_sat = s.check_sat(0,0); + } + return l_true; + + } + + /** + Takes solver with hard constraints added. + Returns an optimal assignment to objective functions. + */ + + lbool optimize_objectives(solver& s, + expr_ref_vector& objectives, svector const& is_max, + vector >& values) { + return mathsat_style_opt(s, objectives, is_max, values); + } +} diff --git a/src/opt/optimize_objectives.h b/src/opt/optimize_objectives.h new file mode 100644 index 000000000..a6c8e3602 --- /dev/null +++ b/src/opt/optimize_objectives.h @@ -0,0 +1,35 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + optimize_objectives.h + +Abstract: + + Objective optimization method. + +Author: + + Anh-Dung Phan (t-anphan) 2013-10-16 + +Notes: + +--*/ +#ifndef _OPT_OBJECTIVES_H_ +#define _OPT_OBJECTIVES_H_ + +#include "solver.h" + +namespace opt { + /** + Takes solver with hard constraints added. + Returns an optimal assignment to objective functions. + */ + + lbool optimize_objectives(solver& s, + expr_ref_vector& objectives, svector const& is_max, + vector >& values); +}; + +#endif \ No newline at end of file diff --git a/src/opt/plan.txt b/src/opt/plan.txt index f728747ed..aabad6cc3 100644 --- a/src/opt/plan.txt +++ b/src/opt/plan.txt @@ -7,3 +7,11 @@ Similar to muz\fp\dl_cmds: Identifier is optional and used to group constraints together. The F# sample illustrates what is meant. +Next steps: + - replace solver by opt_solver. + - create a file called opt_solver, copy most from smt_solver into it. + Add some functions to enable/disable post-optimization on feasiable state. + - Add methods to theory_arith.h to enable/disable post-optimization + - Add method(s) to theory_arith.h to register objective functions. + - Add post-optimization step to theory_arith_core.h + - (Figure out how to do multi-objective in this framework directly besides naive loop) diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp new file mode 100644 index 000000000..832793e32 --- /dev/null +++ b/src/opt/weighted_maxsat.cpp @@ -0,0 +1,33 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + weighted_maxsat.h + +Abstract: + Weighted MAXSAT module + +Author: + + Anh-Dung Phan (t-anphan) 2013-10-16 + +Notes: + +--*/ + +#include "weighted_maxsat.h" + +namespace opt { + /** + Takes solver with hard constraints added. + Returns a maximal satisfying subset of weighted soft_constraints + that are still consistent with the solver state. + */ + + lbool weighted_maxsat(solver& s, expr_ref_vector& soft_constraints, vector const& weights) { + NOT_IMPLEMENTED_YET(); + return l_false; + } +}; + diff --git a/src/opt/weighted_maxsat.h b/src/opt/weighted_maxsat.h new file mode 100644 index 000000000..542d0bafc --- /dev/null +++ b/src/opt/weighted_maxsat.h @@ -0,0 +1,33 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + weighted_maxsat.h + +Abstract: + Weighted MAXSAT module + +Author: + + Anh-Dung Phan (t-anphan) 2013-10-16 + +Notes: + +--*/ +#ifndef _OPT_WEIGHTED_MAX_SAT_H_ +#define _OPT_WEIGHTED_MAX_SAT_H_ + +#include "solver.h" + +namespace opt { + /** + Takes solver with hard constraints added. + Returns a maximal satisfying subset of weighted soft_constraints + that are still consistent with the solver state. + */ + + lbool weighted_maxsat(solver& s, expr_ref_vector& soft_constraints, vector const& weights); +}; + +#endif From cfedbe3dfde6c4adf82d640acb290f88986cea2f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 17 Oct 2013 17:33:43 -0700 Subject: [PATCH 022/925] add opt_solver layer Signed-off-by: Nikolaj Bjorner --- src/opt/fu_malik.cpp | 6 +- src/opt/fu_malik.h | 2 +- src/opt/opt_context.cpp | 20 +++--- src/opt/opt_context.h | 8 ++- src/opt/opt_solver.cpp | 122 ++++++++++++++++++++++++++++++++ src/opt/opt_solver.h | 66 +++++++++++++++++ src/opt/optimize_objectives.cpp | 9 ++- src/opt/optimize_objectives.h | 6 +- src/smt/theory_arith.h | 9 +++ src/smt/theory_arith_aux.h | 18 +++++ 10 files changed, 248 insertions(+), 18 deletions(-) create mode 100644 src/opt/opt_solver.cpp create mode 100644 src/opt/opt_solver.h diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index 07d256d9e..f242c1a37 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -37,13 +37,13 @@ namespace opt { class fu_malik { ast_manager& m; - solver& s; + ::solver& s; expr_ref_vector m_soft; expr_ref_vector m_aux; public: - fu_malik(ast_manager& m, solver& s, expr_ref_vector const& soft): + fu_malik(ast_manager& m, ::solver& s, expr_ref_vector const& soft): m(m), s(s), m_soft(soft), @@ -132,7 +132,7 @@ namespace opt { }; - lbool fu_malik_maxsat(solver& s, expr_ref_vector& soft_constraints) { + lbool fu_malik_maxsat(::solver& s, expr_ref_vector& soft_constraints) { ast_manager& m = soft_constraints.get_manager(); lbool is_sat = s.check_sat(0,0); if (!soft_constraints.empty() && is_sat == l_true) { diff --git a/src/opt/fu_malik.h b/src/opt/fu_malik.h index 6bfe37f63..e46032adf 100644 --- a/src/opt/fu_malik.h +++ b/src/opt/fu_malik.h @@ -28,7 +28,7 @@ namespace opt { that are still consistent with the solver state. */ - lbool fu_malik_maxsat(solver& s, expr_ref_vector& soft_constraints); + lbool fu_malik_maxsat(::solver& s, expr_ref_vector& soft_constraints); }; #endif diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index dbbcffa7c..b02d78466 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -18,11 +18,11 @@ Notes: #include "opt_context.h" -#include "smt_solver.h" #include "fu_malik.h" #include "weighted_maxsat.h" #include "optimize_objectives.h" #include "ast_pp.h" +#include "opt_solver.h" namespace opt { @@ -30,12 +30,14 @@ namespace opt { expr_ref_vector const& fmls = m_soft_constraints; - ref s; - symbol logic; - params_ref p; - p.set_bool("model", true); - p.set_bool("unsat_core", true); - s = mk_smt_solver(m, p, logic); + if (!m_solver) { + symbol logic; + params_ref p; + p.set_bool("model", true); + p.set_bool("unsat_core", true); + set_solver(alloc(opt_solver, m, p, logic)); + } + solver* s = m_solver.get(); for (unsigned i = 0; i < m_hard_constraints.size(); ++i) { s->assert_expr(m_hard_constraints[i].get()); @@ -64,7 +66,9 @@ namespace opt { for (unsigned i = 0; i < fmls_copy.size(); ++i) { s->assert_expr(fmls_copy[i].get()); } - is_sat = optimize_objectives(*s, m_objectives, m_is_max, values); + // SASSERT(instanceof(*s, opt_solver)); + // if (!instsanceof ...) { throw ... invalid usage ..} + is_sat = optimize_objectives(dynamic_cast(*s), m_objectives, m_is_max, values); std::cout << "is-sat: " << is_sat << "\n"; if (is_sat != l_true) { return; diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 9e226389e..0555cdd83 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -19,6 +19,7 @@ Notes: #define _OPT_CONTEXT_H_ #include "ast.h" +#include "solver.h" namespace opt { @@ -30,6 +31,7 @@ namespace opt { expr_ref_vector m_objectives; svector m_is_max; + ref<::solver> m_solver; public: context(ast_manager& m): @@ -53,6 +55,10 @@ namespace opt { m_hard_constraints.push_back(f); } + void set_solver(::solver* s) { + m_solver = s; + } + void optimize(); private: @@ -63,4 +69,4 @@ namespace opt { } -#endif \ No newline at end of file +#endif diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp new file mode 100644 index 000000000..4989993b4 --- /dev/null +++ b/src/opt/opt_solver.cpp @@ -0,0 +1,122 @@ +#include"reg_decl_plugins.h" +#include"opt_solver.h" +#include"smt_context.h" +#include"theory_arith.h" + +namespace opt { + + opt_solver::opt_solver(ast_manager & m, params_ref const & p, symbol const & l): + solver_na2as(m), + m_params(p), + m_context(m, m_params), + m_objective_enabled(false) { + m_logic = l; + if (m_logic != symbol::null) + m_context.set_logic(m_logic); + } + + opt_solver::~opt_solver() { + } + + void opt_solver::updt_params(params_ref const & p) { + m_params.updt_params(p); + m_context.updt_params(p); + } + + void opt_solver::collect_param_descrs(param_descrs & r) { + m_context.collect_param_descrs(r); + } + + void opt_solver::collect_statistics(statistics & st) const { + m_context.collect_statistics(st); + } + + void opt_solver::assert_expr(expr * t) { + m_context.assert_expr(t); + } + + void opt_solver::push_core() { + m_context.push(); + } + + void opt_solver::pop_core(unsigned n) { + m_context.pop(n); + } + +#define ACCESS_ARITHMETIC_CLASS(_code_) \ + smt::context& ctx = m_context.get_context(); \ + smt::theory_id arith_id = m_context.m().get_family_id("arith"); \ + smt::theory* arith_theory = ctx.get_theory(arith_id); \ + if (typeid(smt::theory_mi_arith) == typeid(*arith_theory)) { \ + smt::theory_mi_arith& th = dynamic_cast(*arith_theory); \ + _code_; \ + } \ + else if (typeid(smt::theory_i_arith) == typeid(*arith_theory)) { \ + smt::theory_i_arith& th = dynamic_cast(*arith_theory); \ + _code_; \ + } + + + lbool opt_solver::check_sat_core(unsigned num_assumptions, expr * const * assumptions) { + TRACE("opt_solver_na2as", tout << "smt_opt_solver::check_sat_core: " << num_assumptions << "\n";); + lbool r = m_context.check(num_assumptions, assumptions); + if (r == l_true &&& m_objective_enabled) { + ACCESS_ARITHMETIC_CLASS(th.min(m_objective_var);); + } + return r; + } + + void opt_solver::get_unsat_core(ptr_vector & r) { + unsigned sz = m_context.get_unsat_core_size(); + for (unsigned i = 0; i < sz; i++) + r.push_back(m_context.get_unsat_core_expr(i)); + } + + void opt_solver::get_model(model_ref & m) { + m_context.get_model(m); + } + + proof * opt_solver::get_proof() { + return m_context.get_proof(); + } + + std::string opt_solver::reason_unknown() const { + return m_context.last_failure_as_string(); + } + + void opt_solver::get_labels(svector & r) { + buffer tmp; + m_context.get_relevant_labels(0, tmp); + r.append(tmp.size(), tmp.c_ptr()); + } + + void opt_solver::set_cancel(bool f) { + m_context.set_cancel(f); + } + + void opt_solver::set_progress_callback(progress_callback * callback) { + m_callback = callback; + m_context.set_progress_callback(callback); + } + + unsigned opt_solver::get_num_assertions() const { + return m_context.size(); + } + + expr * opt_solver::get_assertion(unsigned idx) const { + SASSERT(idx < get_num_assertions()); + return m_context.get_formulas()[idx]; + } + + void opt_solver::display(std::ostream & out) const { + m_context.display(out); + } + + void opt_solver::set_objective(app* term) { + ACCESS_ARITHMETIC_CLASS(m_objective_var = th.set_objective(term);); + } + + void opt_solver::toggle_objective(bool enable) { + m_objective_enabled = enable; + } +} diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h new file mode 100644 index 000000000..a6a48d3f9 --- /dev/null +++ b/src/opt/opt_solver.h @@ -0,0 +1,66 @@ +/*++ +Copyright (c) 2012 Microsoft Corporation + +Module Name: + + smt_solver.h + +Abstract: + + Wraps smt::kernel as a solver for the external API and cmd_context. + +Author: + + Leonardo (leonardo) 2012-10-21 + +Notes: + + Variant of smt_solver that exposes kernel object. +--*/ +#ifndef _OPT_SOLVER_H_ +#define _OPT_SOLVER_H_ + +#include"ast.h" +#include"params.h" +#include"solver_na2as.h" +#include"smt_kernel.h" +#include"smt_params.h" +#include"smt_types.h" + +namespace opt { + + class opt_solver : public solver_na2as { + smt_params m_params; + smt::kernel m_context; + progress_callback * m_callback; + symbol m_logic; + bool m_objective_enabled; + smt::theory_var m_objective_var; + public: + opt_solver(ast_manager & m, params_ref const & p, symbol const & l); + virtual ~opt_solver(); + + virtual void updt_params(params_ref const & p); + virtual void collect_param_descrs(param_descrs & r); + virtual void collect_statistics(statistics & st) const; + virtual void assert_expr(expr * t); + virtual void push_core(); + virtual void pop_core(unsigned n); + virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions); + virtual void get_unsat_core(ptr_vector & r); + virtual void get_model(model_ref & m); + virtual proof * get_proof(); + virtual std::string reason_unknown() const; + virtual void get_labels(svector & r); + virtual void set_cancel(bool f); + virtual void set_progress_callback(progress_callback * callback); + virtual unsigned get_num_assertions() const; + virtual expr * get_assertion(unsigned idx) const; + virtual void display(std::ostream & out) const; + + void set_objective(app* term); + void toggle_objective(bool enable); + }; +} + +#endif diff --git a/src/opt/optimize_objectives.cpp b/src/opt/optimize_objectives.cpp index 6f7f5c85e..0d865d7f9 100644 --- a/src/opt/optimize_objectives.cpp +++ b/src/opt/optimize_objectives.cpp @@ -17,15 +17,18 @@ Notes: --*/ +#ifndef _OPT_OBJECTIVE_H_ +#define _OPT_OBJECTIVE_H_ #include "optimize_objectives.h" +#include "opt_solver.h" namespace opt { /* Enumerate locally optimal assignments until fixedpoint. */ - lbool mathsat_style_opt(solver& s, + lbool mathsat_style_opt(opt_solver& s, expr_ref_vector& objectives, svector const& is_max, vector >& values) { lbool is_sat; @@ -52,9 +55,11 @@ namespace opt { Returns an optimal assignment to objective functions. */ - lbool optimize_objectives(solver& s, + lbool optimize_objectives(opt_solver& s, expr_ref_vector& objectives, svector const& is_max, vector >& values) { return mathsat_style_opt(s, objectives, is_max, values); } } + +#endif diff --git a/src/opt/optimize_objectives.h b/src/opt/optimize_objectives.h index a6c8e3602..f14cb37db 100644 --- a/src/opt/optimize_objectives.h +++ b/src/opt/optimize_objectives.h @@ -19,7 +19,7 @@ Notes: #ifndef _OPT_OBJECTIVES_H_ #define _OPT_OBJECTIVES_H_ -#include "solver.h" +#include "opt_solver.h" namespace opt { /** @@ -27,9 +27,9 @@ namespace opt { Returns an optimal assignment to objective functions. */ - lbool optimize_objectives(solver& s, + lbool optimize_objectives(opt_solver& s, expr_ref_vector& objectives, svector const& is_max, vector >& values); }; -#endif \ No newline at end of file +#endif diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index e7037f31a..d9c0efb72 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -985,6 +985,15 @@ namespace smt { // ----------------------------------- virtual bool get_value(enode * n, expr_ref & r); + // ----------------------------------- + // + // Optimization + // + // ----------------------------------- + + void min(theory_var v); + theory_var set_objective(app* term); + // ----------------------------------- // diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 9f77934e5..e668997fc 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -948,6 +948,24 @@ namespace smt { return x_i; } + /** + \brief minimize the given variable. + TODO: max_min returns a bool. What does this do? + */ + template + void theory_arith::min(theory_var v) { + max_min(v, false); + } + + // set_objective(expr* term) internalizes the arithmetic term and creates + // a row for it if it is not already internalized. Then return the variable + // corresponding to the term. + // TODO handle case where internalize fails. e.g., check for this in a suitable way. + template + theory_var theory_arith::set_objective(app* term) { + return internalize_term_core(term); + } + /** \brief Maximize (Minimize) the given temporary row. Return true if succeeded. From 898609a3ef4e923f6041cfc0f0ad5306ce30bb6d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 17 Oct 2013 20:50:33 -0700 Subject: [PATCH 023/925] cleanup macro usage Signed-off-by: Nikolaj Bjorner --- src/opt/opt_solver.cpp | 30 +++++++++++++++++------------- src/opt/opt_solver.h | 3 +++ src/smt/theory_arith.h | 11 +++++------ src/smt/theory_arith_aux.h | 21 +++++++-------------- src/smt/theory_opt.h | 32 ++++++++++++++++++++++++++++++++ 5 files changed, 64 insertions(+), 33 deletions(-) create mode 100644 src/smt/theory_opt.h diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 4989993b4..8f041e9c2 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -43,17 +43,21 @@ namespace opt { m_context.pop(n); } -#define ACCESS_ARITHMETIC_CLASS(_code_) \ - smt::context& ctx = m_context.get_context(); \ - smt::theory_id arith_id = m_context.m().get_family_id("arith"); \ - smt::theory* arith_theory = ctx.get_theory(arith_id); \ - if (typeid(smt::theory_mi_arith) == typeid(*arith_theory)) { \ - smt::theory_mi_arith& th = dynamic_cast(*arith_theory); \ - _code_; \ - } \ - else if (typeid(smt::theory_i_arith) == typeid(*arith_theory)) { \ - smt::theory_i_arith& th = dynamic_cast(*arith_theory); \ - _code_; \ + + smt::theory_opt& opt_solver::get_optimizer() { + smt::context& ctx = m_context.get_context(); + smt::theory_id arith_id = m_context.m().get_family_id("arith"); + smt::theory* arith_theory = ctx.get_theory(arith_id); + if (typeid(smt::theory_mi_arith) == typeid(*arith_theory)) { + return dynamic_cast(*arith_theory); + } + else if (typeid(smt::theory_i_arith) == typeid(*arith_theory)) { + return dynamic_cast(*arith_theory); + } + else { + UNREACHABLE(); + return dynamic_cast(*arith_theory); + } } @@ -61,7 +65,7 @@ namespace opt { TRACE("opt_solver_na2as", tout << "smt_opt_solver::check_sat_core: " << num_assumptions << "\n";); lbool r = m_context.check(num_assumptions, assumptions); if (r == l_true &&& m_objective_enabled) { - ACCESS_ARITHMETIC_CLASS(th.min(m_objective_var);); + VERIFY(get_optimizer().max_min(m_objective_var, false)); } return r; } @@ -113,7 +117,7 @@ namespace opt { } void opt_solver::set_objective(app* term) { - ACCESS_ARITHMETIC_CLASS(m_objective_var = th.set_objective(term);); + m_objective_var = get_optimizer().add_objective(term); } void opt_solver::toggle_objective(bool enable) { diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index a6a48d3f9..c9fd48ed2 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -26,6 +26,7 @@ Notes: #include"smt_kernel.h" #include"smt_params.h" #include"smt_types.h" +#include"theory_opt.h" namespace opt { @@ -60,6 +61,8 @@ namespace opt { void set_objective(app* term); void toggle_objective(bool enable); + private: + smt::theory_opt& get_optimizer(); }; } diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index d9c0efb72..f007492a7 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -36,6 +36,7 @@ Revision History: #include"grobner.h" #include"arith_simplifier_plugin.h" #include"arith_eq_solver.h" +#include"theory_opt.h" namespace smt { @@ -80,7 +81,7 @@ namespace smt { */ template - class theory_arith : public theory, private Ext { + class theory_arith : public theory, public theory_opt, private Ext { public: typedef typename Ext::numeral numeral; typedef typename Ext::inf_numeral inf_numeral; @@ -855,7 +856,6 @@ namespace smt { template void add_tmp_row_entry(row & r, numeral const & coeff, theory_var v); bool max_min(row & r, bool max); - bool max_min(theory_var v, bool max); bool max_min(svector const & vars); // ----------------------------------- @@ -985,15 +985,14 @@ namespace smt { // ----------------------------------- virtual bool get_value(enode * n, expr_ref & r); + // ----------------------------------- // // Optimization // // ----------------------------------- - - void min(theory_var v); - theory_var set_objective(app* term); - + virtual bool max_min(theory_var v, bool max); + virtual theory_var add_objective(app* term); // ----------------------------------- // diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index e668997fc..12658a979 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -948,22 +948,15 @@ namespace smt { return x_i; } - /** - \brief minimize the given variable. - TODO: max_min returns a bool. What does this do? - */ - template - void theory_arith::min(theory_var v) { - max_min(v, false); - } - + // // set_objective(expr* term) internalizes the arithmetic term and creates - // a row for it if it is not already internalized. Then return the variable - // corresponding to the term. - // TODO handle case where internalize fails. e.g., check for this in a suitable way. + // a row for it if it is not already internalized. + // Then return the variable corresponding to the term. + // + template - theory_var theory_arith::set_objective(app* term) { - return internalize_term_core(term); + theory_var theory_arith::add_objective(app* term) { + return internalize_term(term); } /** diff --git a/src/smt/theory_opt.h b/src/smt/theory_opt.h new file mode 100644 index 000000000..f0759e9fc --- /dev/null +++ b/src/smt/theory_opt.h @@ -0,0 +1,32 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + theory_opt.h + +Abstract: + + Interface utilities used by optimization providing + theory solvers. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-10-18 + +Notes: + +--*/ + +#ifndef _THEORY_OPT_H_ +#define _THEORY_OPT_H_ + +namespace smt { + class theory_opt { + public: + virtual bool max_min(theory_var v, bool max) { UNREACHABLE(); return false; }; + virtual theory_var add_objective(app* term) { UNREACHABLE(); return null_theory_var; } + }; +} + +#endif From a44044fb156cd2c13a84b105e7f68ef9f9d47388 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Fri, 18 Oct 2013 18:00:24 -0700 Subject: [PATCH 024/925] A rudimentary version of MathSAT optimization Remarks: (1) The core procedure accepts maximization only (2) Add lazy initialization to min_maximize_cmd (3) The procedure isn't working with composite objective yet. --- src/opt/opt_cmds.cpp | 44 +++++++++++++++++++--------- src/opt/opt_context.cpp | 7 ++++- src/opt/opt_solver.cpp | 17 +++++++++-- src/opt/opt_solver.h | 4 +++ src/opt/optimize_objectives.cpp | 51 ++++++++++++++++++++++++--------- src/smt/theory_arith.h | 5 +++- src/smt/theory_arith_aux.h | 16 +++++++++-- src/smt/theory_opt.h | 3 +- 8 files changed, 114 insertions(+), 33 deletions(-) diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index b4b6d62f2..6c0aeb3d0 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -22,18 +22,32 @@ Notes: #include "opt_context.h" +class opt_context { + cmd_context& ctx; + scoped_ptr m_opt; +public: + opt_context(cmd_context& ctx): ctx(ctx) {} + opt::context& operator()() { + if (!m_opt) { + m_opt = alloc(opt::context, ctx.m()); + } + return *m_opt; + } +}; + + class assert_weighted_cmd : public cmd { - opt::context* m_opt_ctx; + opt_context* m_opt_ctx; unsigned m_idx; - expr_ref m_formula; + expr* m_formula; rational m_weight; public: - assert_weighted_cmd(cmd_context& ctx, opt::context* opt_ctx): + assert_weighted_cmd(cmd_context& ctx, opt_context* opt_ctx): cmd("assert-weighted"), m_opt_ctx(opt_ctx), m_idx(0), - m_formula(ctx.m()), + m_formula(0), m_weight(0) {} @@ -42,6 +56,9 @@ public: } virtual void reset(cmd_context & ctx) { + if (m_formula) { + ctx.m().dec_ref(m_formula); + } m_idx = 0; m_formula = 0; } @@ -68,6 +85,7 @@ public: throw cmd_exception("Invalid type for expression. Expected Boolean type."); } m_formula = t; + ctx.m().inc_ref(t); ++m_idx; } @@ -76,7 +94,7 @@ public: } virtual void execute(cmd_context & ctx) { - m_opt_ctx->add_soft_constraint(m_formula, m_weight); + (*m_opt_ctx)().add_soft_constraint(m_formula, m_weight); reset(ctx); } @@ -91,10 +109,10 @@ public: // to do the feasibility check. class min_maximize_cmd : public cmd { bool m_is_max; - opt::context* m_opt_ctx; + opt_context* m_opt_ctx; public: - min_maximize_cmd(cmd_context& ctx, opt::context* opt_ctx, bool is_max): + min_maximize_cmd(cmd_context& ctx, opt_context* opt_ctx, bool is_max): cmd(is_max?"maximize":"minimize"), m_is_max(is_max), m_opt_ctx(opt_ctx) @@ -113,7 +131,7 @@ public: virtual void set_next_arg(cmd_context & ctx, expr * t) { // TODO: type check objective term. It should pass basic sanity being // integer, real (, bit-vector) or other supported objective function type. - m_opt_ctx->add_objective(t, m_is_max); + (*m_opt_ctx)().add_objective(t, m_is_max); } virtual void failure_cleanup(cmd_context & ctx) { @@ -127,9 +145,9 @@ public: }; class optimize_cmd : public cmd { - opt::context* m_opt_ctx; + opt_context* m_opt_ctx; public: - optimize_cmd(opt::context* opt_ctx): + optimize_cmd(opt_context* opt_ctx): cmd("optimize"), m_opt_ctx(opt_ctx) {} @@ -145,9 +163,9 @@ public: ptr_vector::const_iterator it = ctx.begin_assertions(); ptr_vector::const_iterator end = ctx.end_assertions(); for (; it != end; ++it) { - m_opt_ctx->add_hard_constraint(*it); + (*m_opt_ctx)().add_hard_constraint(*it); } - m_opt_ctx->optimize(); + (*m_opt_ctx)().optimize(); } @@ -157,7 +175,7 @@ private: }; void install_opt_cmds(cmd_context & ctx) { - opt::context* opt_ctx = alloc(opt::context, ctx.m()); + opt_context* opt_ctx = alloc(opt_context, ctx); ctx.insert(alloc(assert_weighted_cmd, ctx, opt_ctx)); ctx.insert(alloc(min_maximize_cmd, ctx, opt_ctx, true)); ctx.insert(alloc(min_maximize_cmd, ctx, opt_ctx, false)); diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index b02d78466..b11078b3f 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -73,8 +73,13 @@ namespace opt { if (is_sat != l_true) { return; } + for (unsigned i = 0; i < values.size(); ++i) { - // display + if (values[i]) { + std::cout << "objective function: " << mk_pp(m_objectives[i].get(), m) << " -> " << *values[i] << "\n"; + } else { + std::cout << "objective function: " << mk_pp(m_objectives[i].get(), m) << " -> unbounded\n"; + } } } diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 8f041e9c2..311d90275 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -7,6 +7,7 @@ namespace opt { opt_solver::opt_solver(ast_manager & m, params_ref const & p, symbol const & l): solver_na2as(m), + m_manager(m), m_params(p), m_context(m, m_params), m_objective_enabled(false) { @@ -48,6 +49,7 @@ namespace opt { smt::context& ctx = m_context.get_context(); smt::theory_id arith_id = m_context.m().get_family_id("arith"); smt::theory* arith_theory = ctx.get_theory(arith_id); + if (typeid(smt::theory_mi_arith) == typeid(*arith_theory)) { return dynamic_cast(*arith_theory); } @@ -64,8 +66,14 @@ namespace opt { lbool opt_solver::check_sat_core(unsigned num_assumptions, expr * const * assumptions) { TRACE("opt_solver_na2as", tout << "smt_opt_solver::check_sat_core: " << num_assumptions << "\n";); lbool r = m_context.check(num_assumptions, assumptions); - if (r == l_true &&& m_objective_enabled) { - VERIFY(get_optimizer().max_min(m_objective_var, false)); + if (r == l_true && m_objective_enabled) { + bool is_bounded = get_optimizer().max(m_objective_var); + if (is_bounded) { + m_objective_value = get_optimizer().get_objective_value(m_objective_var); + } else { + optional r; + m_objective_value = r; + } } return r; } @@ -123,4 +131,9 @@ namespace opt { void opt_solver::toggle_objective(bool enable) { m_objective_enabled = enable; } + + optional opt_solver::get_objective_value() { + return m_objective_value; + } + } diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index c9fd48ed2..0c8147f03 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -37,6 +37,8 @@ namespace opt { symbol m_logic; bool m_objective_enabled; smt::theory_var m_objective_var; + ast_manager& m_manager; + optional m_objective_value; public: opt_solver(ast_manager & m, params_ref const & p, symbol const & l); virtual ~opt_solver(); @@ -61,6 +63,8 @@ namespace opt { void set_objective(app* term); void toggle_objective(bool enable); + + optional get_objective_value(); private: smt::theory_opt& get_optimizer(); }; diff --git a/src/opt/optimize_objectives.cpp b/src/opt/optimize_objectives.cpp index 0d865d7f9..81d71e507 100644 --- a/src/opt/optimize_objectives.cpp +++ b/src/opt/optimize_objectives.cpp @@ -22,6 +22,7 @@ Notes: #include "optimize_objectives.h" #include "opt_solver.h" +#include "arith_decl_plugin.h" namespace opt { @@ -31,23 +32,47 @@ namespace opt { lbool mathsat_style_opt(opt_solver& s, expr_ref_vector& objectives, svector const& is_max, vector >& values) { - lbool is_sat; - is_sat = s.check_sat(0,0); - if (is_sat != l_true) { - return is_sat; + enable_trace("maximize"); + // First check_sat call for initialize theories + lbool is_sat = s.check_sat(0, 0); + if (is_sat == l_false) { + return l_false; } - // assume that s is instrumented to produce locally optimal assignments. + // Assume there is only one objective function + ast_manager& m = objectives.get_manager(); + arith_util autil(m); + app* objective = is_max[0] ? (app*) objectives[0].get() : autil.mk_uminus(objectives[0].get()); + s.set_objective(objective); + s.toggle_objective(true); + is_sat = s.check_sat(0, 0); + while (is_sat != l_false) { - model_ref model; - s.get_model(model); - // extract values for objectives. - // store them in values. - // assert there must be something better. - is_sat = s.check_sat(0,0); - } - return l_true; + // Extract values for objectives. + optional rat; + rat = s.get_objective_value(); + // Unbounded objective + if (!rat) { + values.reset(); + values.push_back(rat); + return l_true; + } + + // If values have initial data, they will be dropped. + values.reset(); + values.push_back(rat); + + // Assert there must be something better. + expr_ref_vector assumptions(m); + expr* bound = m.mk_fresh_const("bound", m.mk_bool_sort()); + assumptions.push_back(bound); + expr* r = autil.mk_numeral(*rat, false); + s.assert_expr(m.mk_eq(bound, is_max[0] ? autil.mk_gt(objectives[0].get(), r) : autil.mk_lt(objectives[0].get(), r))); + is_sat = s.check_sat(1, assumptions.c_ptr()); + } + + return l_true; } /** diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index f007492a7..0f5f33756 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -855,6 +855,7 @@ namespace smt { theory_var pick_var_to_leave(theory_var x_j, bool inc, numeral & a_ij, inf_numeral & gain); template void add_tmp_row_entry(row & r, numeral const & coeff, theory_var v); + bool max_min(theory_var v, bool max); bool max_min(row & r, bool max); bool max_min(svector const & vars); @@ -991,8 +992,10 @@ namespace smt { // Optimization // // ----------------------------------- - virtual bool max_min(theory_var v, bool max); + virtual bool max(theory_var v) { return max_min(v, true); } virtual theory_var add_objective(app* term); + virtual optional get_objective_value(theory_var v); + inf_rational m_objective; // ----------------------------------- // diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 12658a979..87624acb6 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -956,7 +956,16 @@ namespace smt { template theory_var theory_arith::add_objective(app* term) { - return internalize_term(term); + return internalize_term_core(term); + } + + template + optional theory_arith::get_objective_value(theory_var v) { + optional rat; + if (m_objective.is_rational()) { + rat = m_objective.get_rational(); + }; + return rat; } /** @@ -1106,7 +1115,7 @@ namespace smt { \brief Maximize/Minimize the given variable. The bounds of v are update if procedure succeeds. */ template - bool theory_arith::max_min(theory_var v, bool max) { + bool theory_arith::max_min(theory_var v, bool max) { TRACE("maximize", tout << (max ? "maximizing" : "minimizing") << " v" << v << "...\n";); SASSERT(valid_row_assignment()); SASSERT(satisfy_bounds()); @@ -1130,7 +1139,10 @@ namespace smt { TRACE("maximize", tout << "v" << v << " " << (max ? "max" : "min") << " value is: " << get_value(v) << "\n"; display_row(tout, m_tmp_row, true); display_row_info(tout, m_tmp_row);); + m_objective = get_value(v); + mk_bound_from_row(v, get_value(v), max ? B_UPPER : B_LOWER, m_tmp_row); + return true; } return false; diff --git a/src/smt/theory_opt.h b/src/smt/theory_opt.h index f0759e9fc..4f742f73b 100644 --- a/src/smt/theory_opt.h +++ b/src/smt/theory_opt.h @@ -24,8 +24,9 @@ Notes: namespace smt { class theory_opt { public: - virtual bool max_min(theory_var v, bool max) { UNREACHABLE(); return false; }; + virtual bool max(theory_var v) { UNREACHABLE(); return false; }; virtual theory_var add_objective(app* term) { UNREACHABLE(); return null_theory_var; } + virtual optional get_objective_value(theory_var v) { UNREACHABLE(); optional r; return r;} }; } From 53f78f7d19f8ca4a0ffcb3aa6230dd17e460ab49 Mon Sep 17 00:00:00 2001 From: Phan Anh Dung Date: Sat, 19 Oct 2013 06:03:21 +0200 Subject: [PATCH 025/925] Replace the use of optional by inf_eps_rational Also handle composite objectives correctly. --- src/opt/opt_context.cpp | 9 ++------ src/opt/opt_context.h | 1 - src/opt/opt_solver.cpp | 11 +++++----- src/opt/opt_solver.h | 6 ++--- src/opt/optimize_objectives.cpp | 39 ++++++++++++++++++++------------- src/opt/optimize_objectives.h | 2 +- src/smt/theory_arith.h | 4 ++-- src/smt/theory_arith_aux.h | 11 +++++----- src/smt/theory_opt.h | 10 +++++++-- 9 files changed, 50 insertions(+), 43 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index b11078b3f..ac6e7f084 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -16,7 +16,6 @@ Notes: --*/ - #include "opt_context.h" #include "fu_malik.h" #include "weighted_maxsat.h" @@ -62,7 +61,7 @@ namespace opt { } if (!m_objectives.empty()) { - vector > values; + vector > values; for (unsigned i = 0; i < fmls_copy.size(); ++i) { s->assert_expr(fmls_copy[i].get()); } @@ -75,11 +74,7 @@ namespace opt { } for (unsigned i = 0; i < values.size(); ++i) { - if (values[i]) { - std::cout << "objective function: " << mk_pp(m_objectives[i].get(), m) << " -> " << *values[i] << "\n"; - } else { - std::cout << "objective function: " << mk_pp(m_objectives[i].get(), m) << " -> unbounded\n"; - } + std::cout << "objective function: " << mk_pp(m_objectives[i].get(), m) << " -> " << values[i].to_string() << "\n"; } } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 0555cdd83..9e7658625 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -66,7 +66,6 @@ namespace opt { }; - } #endif diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 311d90275..c2a01f92f 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -7,7 +7,6 @@ namespace opt { opt_solver::opt_solver(ast_manager & m, params_ref const & p, symbol const & l): solver_na2as(m), - m_manager(m), m_params(p), m_context(m, m_params), m_objective_enabled(false) { @@ -15,7 +14,7 @@ namespace opt { if (m_logic != symbol::null) m_context.set_logic(m_logic); } - + opt_solver::~opt_solver() { } @@ -64,14 +63,14 @@ namespace opt { lbool opt_solver::check_sat_core(unsigned num_assumptions, expr * const * assumptions) { - TRACE("opt_solver_na2as", tout << "smt_opt_solver::check_sat_core: " << num_assumptions << "\n";); + TRACE("opt_solver_na2as", tout << "opt_opt_solver::check_sat_core: " << num_assumptions << "\n";); lbool r = m_context.check(num_assumptions, assumptions); if (r == l_true && m_objective_enabled) { - bool is_bounded = get_optimizer().max(m_objective_var); + bool is_bounded = get_optimizer().maximize(m_objective_var); if (is_bounded) { m_objective_value = get_optimizer().get_objective_value(m_objective_var); } else { - optional r; + inf_eps_rational r(rational(1), rational(0)); m_objective_value = r; } } @@ -132,7 +131,7 @@ namespace opt { m_objective_enabled = enable; } - optional opt_solver::get_objective_value() { + inf_eps_rational opt_solver::get_objective_value() { return m_objective_value; } diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 0c8147f03..3904a3646 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -20,6 +20,7 @@ Notes: #ifndef _OPT_SOLVER_H_ #define _OPT_SOLVER_H_ +#include"inf_eps_rational.h" #include"ast.h" #include"params.h" #include"solver_na2as.h" @@ -37,8 +38,7 @@ namespace opt { symbol m_logic; bool m_objective_enabled; smt::theory_var m_objective_var; - ast_manager& m_manager; - optional m_objective_value; + inf_eps_rational m_objective_value; public: opt_solver(ast_manager & m, params_ref const & p, symbol const & l); virtual ~opt_solver(); @@ -64,7 +64,7 @@ namespace opt { void set_objective(app* term); void toggle_objective(bool enable); - optional get_objective_value(); + inf_eps_rational get_objective_value(); private: smt::theory_opt& get_optimizer(); }; diff --git a/src/opt/optimize_objectives.cpp b/src/opt/optimize_objectives.cpp index 81d71e507..8dc942c32 100644 --- a/src/opt/optimize_objectives.cpp +++ b/src/opt/optimize_objectives.cpp @@ -31,7 +31,7 @@ namespace opt { */ lbool mathsat_style_opt(opt_solver& s, expr_ref_vector& objectives, svector const& is_max, - vector >& values) { + vector >& values) { enable_trace("maximize"); // First check_sat call for initialize theories lbool is_sat = s.check_sat(0, 0); @@ -39,38 +39,47 @@ namespace opt { return l_false; } + s.push(); + // Assume there is only one objective function ast_manager& m = objectives.get_manager(); arith_util autil(m); - app* objective = is_max[0] ? (app*) objectives[0].get() : autil.mk_uminus(objectives[0].get()); + app* objective = m.mk_fresh_const("objective", autil.mk_real()); + if (is_max[0]) { + s.assert_expr(autil.mk_eq(objective, objectives[0].get())); + } else { + s.assert_expr(autil.mk_eq(objective, autil.mk_uminus(objectives[0].get()))); + }; s.set_objective(objective); s.toggle_objective(true); is_sat = s.check_sat(0, 0); while (is_sat != l_false) { - // Extract values for objectives. - optional rat; - rat = s.get_objective_value(); + // Extract values for objectives + inf_eps_rational val; + val = is_max[0] ? s.get_objective_value() : -s.get_objective_value(); - // Unbounded objective - if (!rat) { + // Check whether objective is unbounded + if (!val.is_rational()) { values.reset(); - values.push_back(rat); - return l_true; + values.push_back(val); + break; } - // If values have initial data, they will be dropped. + // If values have initial data, they will be dropped values.reset(); - values.push_back(rat); + values.push_back(val); - // Assert there must be something better. + // Assert there must be something better expr_ref_vector assumptions(m); expr* bound = m.mk_fresh_const("bound", m.mk_bool_sort()); assumptions.push_back(bound); - expr* r = autil.mk_numeral(*rat, false); + expr* r = autil.mk_numeral(val.get_rational(), false); s.assert_expr(m.mk_eq(bound, is_max[0] ? autil.mk_gt(objectives[0].get(), r) : autil.mk_lt(objectives[0].get(), r))); is_sat = s.check_sat(1, assumptions.c_ptr()); - } + } + + s.pop(1); return l_true; } @@ -82,7 +91,7 @@ namespace opt { lbool optimize_objectives(opt_solver& s, expr_ref_vector& objectives, svector const& is_max, - vector >& values) { + vector >& values) { return mathsat_style_opt(s, objectives, is_max, values); } } diff --git a/src/opt/optimize_objectives.h b/src/opt/optimize_objectives.h index f14cb37db..aa02a992e 100644 --- a/src/opt/optimize_objectives.h +++ b/src/opt/optimize_objectives.h @@ -29,7 +29,7 @@ namespace opt { lbool optimize_objectives(opt_solver& s, expr_ref_vector& objectives, svector const& is_max, - vector >& values); + vector >& values); }; #endif diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 0f5f33756..99b7e34f3 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -992,9 +992,9 @@ namespace smt { // Optimization // // ----------------------------------- - virtual bool max(theory_var v) { return max_min(v, true); } + virtual bool maximize(theory_var v) { return max_min(v, true); } virtual theory_var add_objective(app* term); - virtual optional get_objective_value(theory_var v); + virtual inf_eps_rational get_objective_value(theory_var v); inf_rational m_objective; // ----------------------------------- diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 87624acb6..da56f8b0f 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -19,6 +19,7 @@ Revision History: #ifndef _THEORY_ARITH_AUX_H_ #define _THEORY_ARITH_AUX_H_ +#include"inf_eps_rational.h" #include"theory_arith.h" namespace smt { @@ -960,12 +961,10 @@ namespace smt { } template - optional theory_arith::get_objective_value(theory_var v) { - optional rat; - if (m_objective.is_rational()) { - rat = m_objective.get_rational(); - }; - return rat; + inf_eps_rational theory_arith::get_objective_value(theory_var v) { + inf_eps_rational val; + val = m_objective.get_rational(); + return val; } /** diff --git a/src/smt/theory_opt.h b/src/smt/theory_opt.h index 4f742f73b..4a558a09c 100644 --- a/src/smt/theory_opt.h +++ b/src/smt/theory_opt.h @@ -18,15 +18,21 @@ Notes: --*/ +#include "inf_eps_rational.h" + #ifndef _THEORY_OPT_H_ #define _THEORY_OPT_H_ namespace smt { class theory_opt { public: - virtual bool max(theory_var v) { UNREACHABLE(); return false; }; + virtual bool maximize(theory_var v) { UNREACHABLE(); return false; }; virtual theory_var add_objective(app* term) { UNREACHABLE(); return null_theory_var; } - virtual optional get_objective_value(theory_var v) { UNREACHABLE(); optional r; return r;} + virtual inf_eps_rational get_objective_value(theory_var v) { + UNREACHABLE(); + inf_eps_rational r(rational(1), rational(0)); + return r; + } }; } From 3996f58a8e1d9ed62db9e91b6f6a56eacce3c8bd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Oct 2013 12:22:56 -0700 Subject: [PATCH 026/925] tidy & todo notes Signed-off-by: Nikolaj Bjorner --- src/opt/fu_malik.cpp | 6 +-- src/opt/fu_malik.h | 2 +- src/opt/opt_cmds.cpp | 85 ++++++++++++++++++++++++----------------- src/opt/opt_context.cpp | 19 +++++++++ src/opt/opt_context.h | 14 ++++++- src/smt/theory_opt.h | 4 +- 6 files changed, 86 insertions(+), 44 deletions(-) diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index f242c1a37..07d256d9e 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -37,13 +37,13 @@ namespace opt { class fu_malik { ast_manager& m; - ::solver& s; + solver& s; expr_ref_vector m_soft; expr_ref_vector m_aux; public: - fu_malik(ast_manager& m, ::solver& s, expr_ref_vector const& soft): + fu_malik(ast_manager& m, solver& s, expr_ref_vector const& soft): m(m), s(s), m_soft(soft), @@ -132,7 +132,7 @@ namespace opt { }; - lbool fu_malik_maxsat(::solver& s, expr_ref_vector& soft_constraints) { + lbool fu_malik_maxsat(solver& s, expr_ref_vector& soft_constraints) { ast_manager& m = soft_constraints.get_manager(); lbool is_sat = s.check_sat(0,0); if (!soft_constraints.empty() && is_sat == l_true) { diff --git a/src/opt/fu_malik.h b/src/opt/fu_malik.h index e46032adf..6bfe37f63 100644 --- a/src/opt/fu_malik.h +++ b/src/opt/fu_malik.h @@ -28,7 +28,7 @@ namespace opt { that are still consistent with the solver state. */ - lbool fu_malik_maxsat(::solver& s, expr_ref_vector& soft_constraints); + lbool fu_malik_maxsat(solver& s, expr_ref_vector& soft_constraints); }; #endif diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index 6c0aeb3d0..58a404328 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -14,12 +14,26 @@ Author: Notes: + TODO: + - integrate with parameters. + Parameter infrastructure lets us control setttings, such as + timeouts and control which backend optimization approach to + use during experiments. + + - Display statistics properly on exit when configured to do so. + Also add appropriate statistics tracking to opt::context + + - Deal with push/pop (later) + + - Revisit weighted constraints if we want to group them using identifiers. + --*/ #include "opt_cmds.h" #include "cmd_context.h" #include "ast_pp.h" - #include "opt_context.h" +#include "cancel_eh.h" +#include "scoped_ctrl_c.h" class opt_context { @@ -37,13 +51,13 @@ public: class assert_weighted_cmd : public cmd { - opt_context* m_opt_ctx; - unsigned m_idx; - expr* m_formula; - rational m_weight; + opt_context& m_opt_ctx; + unsigned m_idx; + expr* m_formula; + rational m_weight; public: - assert_weighted_cmd(cmd_context& ctx, opt_context* opt_ctx): + assert_weighted_cmd(cmd_context& ctx, opt_context& opt_ctx): cmd("assert-weighted"), m_opt_ctx(opt_ctx), m_idx(0), @@ -52,7 +66,7 @@ public: {} virtual ~assert_weighted_cmd() { - dealloc(m_opt_ctx); + dealloc(&m_opt_ctx); } virtual void reset(cmd_context & ctx) { @@ -94,7 +108,7 @@ public: } virtual void execute(cmd_context & ctx) { - (*m_opt_ctx)().add_soft_constraint(m_formula, m_weight); + m_opt_ctx().add_soft_constraint(m_formula, m_weight); reset(ctx); } @@ -103,23 +117,18 @@ public: }; -// what amounts to check-sat, but uses the *single* objective function. -// alternative is to register multiple objective functions using -// minimize/maximize and then use check-sat or some variant of it -// to do the feasibility check. class min_maximize_cmd : public cmd { - bool m_is_max; - opt_context* m_opt_ctx; + bool m_is_max; + opt_context& m_opt_ctx; public: - min_maximize_cmd(cmd_context& ctx, opt_context* opt_ctx, bool is_max): + min_maximize_cmd(cmd_context& ctx, opt_context& opt_ctx, bool is_max): cmd(is_max?"maximize":"minimize"), m_is_max(is_max), m_opt_ctx(opt_ctx) {} - virtual void reset(cmd_context & ctx) { - } + virtual void reset(cmd_context & ctx) { } virtual char const * get_usage() const { return ""; } virtual char const * get_descr(cmd_context & ctx) const { return "check sat modulo objective function";} @@ -129,9 +138,7 @@ public: virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { return CPK_EXPR; } virtual void set_next_arg(cmd_context & ctx, expr * t) { - // TODO: type check objective term. It should pass basic sanity being - // integer, real (, bit-vector) or other supported objective function type. - (*m_opt_ctx)().add_objective(t, m_is_max); + m_opt_ctx().add_objective(t, m_is_max); } virtual void failure_cleanup(cmd_context & ctx) { @@ -140,14 +147,12 @@ public: virtual void execute(cmd_context & ctx) { } - - }; class optimize_cmd : public cmd { - opt_context* m_opt_ctx; + opt_context& m_opt_ctx; public: - optimize_cmd(opt_context* opt_ctx): + optimize_cmd(opt_context& opt_ctx): cmd("optimize"), m_opt_ctx(opt_ctx) {} @@ -159,25 +164,33 @@ public: } virtual void execute(cmd_context & ctx) { - + opt::context& opt = m_opt_ctx(); ptr_vector::const_iterator it = ctx.begin_assertions(); ptr_vector::const_iterator end = ctx.end_assertions(); for (; it != end; ++it) { - (*m_opt_ctx)().add_hard_constraint(*it); + opt.add_hard_constraint(*it); + } + cancel_eh eh(opt); + { + scoped_ctrl_c ctrlc(eh); + cmd_context::scoped_watch sw(ctx); + try { + opt.optimize(); + } + catch (z3_error& ex) { + ctx.regular_stream() << "(error: " << ex.msg() << "\")" << std::endl; + } + catch (z3_exception& ex) { + ctx.regular_stream() << "(error: " << ex.msg() << "\")" << std::endl; + } } - (*m_opt_ctx)().optimize(); - - } -private: - - }; void install_opt_cmds(cmd_context & ctx) { opt_context* opt_ctx = alloc(opt_context, ctx); - ctx.insert(alloc(assert_weighted_cmd, ctx, opt_ctx)); - ctx.insert(alloc(min_maximize_cmd, ctx, opt_ctx, true)); - ctx.insert(alloc(min_maximize_cmd, ctx, opt_ctx, false)); - ctx.insert(alloc(optimize_cmd, opt_ctx)); + ctx.insert(alloc(assert_weighted_cmd, ctx, *opt_ctx)); + ctx.insert(alloc(min_maximize_cmd, ctx, *opt_ctx, true)); + ctx.insert(alloc(min_maximize_cmd, ctx, *opt_ctx, false)); + ctx.insert(alloc(optimize_cmd, *opt_ctx)); } diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index ac6e7f084..45b945d73 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -14,6 +14,13 @@ Author: Notes: + TODO: + + - there are race conditions for cancelation. + - it would also be a good idea to maintain a volatile bool to track + cancelation and then bail out of loops inside optimize() and derived + functions. + --*/ #include "opt_context.h" @@ -95,4 +102,16 @@ namespace opt { return true; } + void context::cancel() { + if (m_solver) { + m_solver->cancel(); + } + } + + void context::reset_cancel() { + if (m_solver) { + m_solver->reset_cancel(); + } + } + } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 9e7658625..914ee3edb 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -14,6 +14,13 @@ Author: Notes: + TODO: + + - type check objective term and assertions. It should pass basic sanity being + integer, real (, bit-vector) or other supported objective function type. + + - add appropriate statistics tracking to opt::context + --*/ #ifndef _OPT_CONTEXT_H_ #define _OPT_CONTEXT_H_ @@ -31,7 +38,7 @@ namespace opt { expr_ref_vector m_objectives; svector m_is_max; - ref<::solver> m_solver; + ref m_solver; public: context(ast_manager& m): @@ -55,12 +62,15 @@ namespace opt { m_hard_constraints.push_back(f); } - void set_solver(::solver* s) { + void set_solver(solver* s) { m_solver = s; } void optimize(); + void cancel(); + void reset_cancel(); + private: bool is_maxsat_problem() const; diff --git a/src/smt/theory_opt.h b/src/smt/theory_opt.h index 4a558a09c..c3765a1fc 100644 --- a/src/smt/theory_opt.h +++ b/src/smt/theory_opt.h @@ -28,11 +28,11 @@ namespace smt { public: virtual bool maximize(theory_var v) { UNREACHABLE(); return false; }; virtual theory_var add_objective(app* term) { UNREACHABLE(); return null_theory_var; } - virtual inf_eps_rational get_objective_value(theory_var v) { + virtual inf_eps_rational get_objective_value(theory_var v) { UNREACHABLE(); inf_eps_rational r(rational(1), rational(0)); return r; - } + } }; } From 3dd72f8f16adbea0b23cebb8779985cbc4b05b1d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Oct 2013 17:43:59 -0700 Subject: [PATCH 027/925] more updates Signed-off-by: Nikolaj Bjorner --- src/opt/opt_cmds.cpp | 5 ++- src/opt/opt_context.h | 11 +++-- src/opt/optimize_objectives.cpp | 76 +++++++++++++++++++-------------- src/opt/optimize_objectives.h | 4 +- 4 files changed, 54 insertions(+), 42 deletions(-) diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index 58a404328..aa02eae4f 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -138,7 +138,10 @@ public: virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { return CPK_EXPR; } virtual void set_next_arg(cmd_context & ctx, expr * t) { - m_opt_ctx().add_objective(t, m_is_max); + if (!is_app(t)) { + throw cmd_exception("malformed objective term: it cannot be a quantifier or bound variable"); + } + m_opt_ctx().add_objective(to_app(t), m_is_max); } virtual void failure_cleanup(cmd_context & ctx) { diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 914ee3edb..a08260cb1 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -32,13 +32,12 @@ namespace opt { class context { ast_manager& m; - expr_ref_vector m_hard_constraints; + expr_ref_vector m_hard_constraints; expr_ref_vector m_soft_constraints; vector m_weights; - - expr_ref_vector m_objectives; - svector m_is_max; - ref m_solver; + app_ref_vector m_objectives; + svector m_is_max; + ref m_solver; public: context(ast_manager& m): @@ -53,7 +52,7 @@ namespace opt { m_weights.push_back(w); } - void add_objective(expr* t, bool is_max) { + void add_objective(app* t, bool is_max) { m_objectives.push_back(t); m_is_max.push_back(is_max); } diff --git a/src/opt/optimize_objectives.cpp b/src/opt/optimize_objectives.cpp index 8dc942c32..f7bcb362c 100644 --- a/src/opt/optimize_objectives.cpp +++ b/src/opt/optimize_objectives.cpp @@ -29,58 +29,68 @@ namespace opt { /* Enumerate locally optimal assignments until fixedpoint. */ - lbool mathsat_style_opt(opt_solver& s, - expr_ref_vector& objectives, svector const& is_max, - vector >& values) { - enable_trace("maximize"); + lbool mathsat_style_opt( + opt_solver& s, + app_ref_vector& objectives, + svector const& is_max, + vector >& values) + { + SASSERT(is_max.size() == objectives.size()); + + enable_trace("maximize"); // NSB review: OK for now for debugging. Otherwise, use command-line /tr:maximize + // First check_sat call for initialize theories lbool is_sat = s.check_sat(0, 0); - if (is_sat == l_false) { - return l_false; + if (is_sat != l_false) { + return is_sat; } s.push(); + // Assume there is only one objective function + SASSERT(is_max.size() == 1); ast_manager& m = objectives.get_manager(); arith_util autil(m); - app* objective = m.mk_fresh_const("objective", autil.mk_real()); - if (is_max[0]) { - s.assert_expr(autil.mk_eq(objective, objectives[0].get())); - } else { - s.assert_expr(autil.mk_eq(objective, autil.mk_uminus(objectives[0].get()))); - }; - s.set_objective(objective); + bool ismax = is_max[0]; + app_ref objective_var(m), objective_term(m), obj_eq(m); + objective_term = ismax?objectives[0].get():autil.mk_uminus(objectives[0].get()); + sort* srt = m.get_sort(objective_term); + objective_var = m.mk_fresh_const("objective", srt); + obj_eq = autil.mk_eq(objective_var, objective_term); + s.assert_expr(obj_eq); + s.set_objective(objective_var); // NSB review: I would change signature of set_objective to take is_max and decide whether to add equation. + // Otherwise, the difference logic backends will not work. s.toggle_objective(true); is_sat = s.check_sat(0, 0); - - while (is_sat != l_false) { + + while (is_sat == l_true) { // Extract values for objectives inf_eps_rational val; - val = is_max[0] ? s.get_objective_value() : -s.get_objective_value(); + val = is_max[0] ? s.get_objective_value() : -s.get_objective_value(); // Check whether objective is unbounded - if (!val.is_rational()) { - values.reset(); - values.push_back(val); - break; - } - - // If values have initial data, they will be dropped + // NSB: review: what if optimal is 1-epsilon. Then the check also fails. + values.reset(); values.push_back(val); - - // Assert there must be something better - expr_ref_vector assumptions(m); - expr* bound = m.mk_fresh_const("bound", m.mk_bool_sort()); - assumptions.push_back(bound); - expr* r = autil.mk_numeral(val.get_rational(), false); - s.assert_expr(m.mk_eq(bound, is_max[0] ? autil.mk_gt(objectives[0].get(), r) : autil.mk_lt(objectives[0].get(), r))); - is_sat = s.check_sat(1, assumptions.c_ptr()); + + if (!val.is_rational()) { + break; + } + + expr_ref constraint(m); + constraint = autil.mk_gt(objective_term, autil.mk_numeral(val.get_rational(), srt)); + s.assert_expr(constraint); + is_sat = s.check_sat(0, 0); } s.pop(1); - + + if (is_sat == l_undef) { + return is_sat; + } + SASSERT(is_sat == l_false); // NSB review: not really water-tight with cancellation and with infinitesimal solutions. return l_true; } @@ -90,7 +100,7 @@ namespace opt { */ lbool optimize_objectives(opt_solver& s, - expr_ref_vector& objectives, svector const& is_max, + app_ref_vector& objectives, svector const& is_max, vector >& values) { return mathsat_style_opt(s, objectives, is_max, values); } diff --git a/src/opt/optimize_objectives.h b/src/opt/optimize_objectives.h index aa02a992e..94a6f591a 100644 --- a/src/opt/optimize_objectives.h +++ b/src/opt/optimize_objectives.h @@ -28,8 +28,8 @@ namespace opt { */ lbool optimize_objectives(opt_solver& s, - expr_ref_vector& objectives, svector const& is_max, - vector >& values); + app_ref_vector& objectives, svector const& is_max, + vector >& values); }; #endif From 3441fc29427242dc334204d36c2861623d4d4941 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Mon, 21 Oct 2013 17:25:34 -0700 Subject: [PATCH 028/925] A few changes based on previous reviews Tested the optimization procedure with: - unbounded objectives - bounded with rational solutions - bounded with irrational solutions --- src/opt/opt_context.cpp | 3 ++- src/opt/opt_solver.cpp | 4 ++-- src/opt/opt_solver.h | 5 +++-- src/opt/optimize_objectives.cpp | 24 ++++++++++-------------- src/opt/optimize_objectives.h | 2 +- src/smt/theory_arith.h | 2 +- src/smt/theory_arith_aux.h | 5 ++--- src/smt/theory_opt.h | 5 +++-- 8 files changed, 24 insertions(+), 26 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 45b945d73..ff49a5c8d 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -68,7 +68,7 @@ namespace opt { } if (!m_objectives.empty()) { - vector > values; + vector > values; for (unsigned i = 0; i < fmls_copy.size(); ++i) { s->assert_expr(fmls_copy[i].get()); } @@ -76,6 +76,7 @@ namespace opt { // if (!instsanceof ...) { throw ... invalid usage ..} is_sat = optimize_objectives(dynamic_cast(*s), m_objectives, m_is_max, values); std::cout << "is-sat: " << is_sat << "\n"; + if (is_sat != l_true) { return; } diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index c2a01f92f..220ae0143 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -70,7 +70,7 @@ namespace opt { if (is_bounded) { m_objective_value = get_optimizer().get_objective_value(m_objective_var); } else { - inf_eps_rational r(rational(1), rational(0)); + inf_eps_rational r(rational(1), inf_rational(0)); m_objective_value = r; } } @@ -131,7 +131,7 @@ namespace opt { m_objective_enabled = enable; } - inf_eps_rational opt_solver::get_objective_value() { + inf_eps_rational opt_solver::get_objective_value() { return m_objective_value; } diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 3904a3646..9b59bf93b 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -20,6 +20,7 @@ Notes: #ifndef _OPT_SOLVER_H_ #define _OPT_SOLVER_H_ +#include"inf_rational.h" #include"inf_eps_rational.h" #include"ast.h" #include"params.h" @@ -38,7 +39,7 @@ namespace opt { symbol m_logic; bool m_objective_enabled; smt::theory_var m_objective_var; - inf_eps_rational m_objective_value; + inf_eps_rational m_objective_value; public: opt_solver(ast_manager & m, params_ref const & p, symbol const & l); virtual ~opt_solver(); @@ -64,7 +65,7 @@ namespace opt { void set_objective(app* term); void toggle_objective(bool enable); - inf_eps_rational get_objective_value(); + inf_eps_rational get_objective_value(); private: smt::theory_opt& get_optimizer(); }; diff --git a/src/opt/optimize_objectives.cpp b/src/opt/optimize_objectives.cpp index f7bcb362c..e167922cc 100644 --- a/src/opt/optimize_objectives.cpp +++ b/src/opt/optimize_objectives.cpp @@ -33,23 +33,20 @@ namespace opt { opt_solver& s, app_ref_vector& objectives, svector const& is_max, - vector >& values) + vector >& values) { SASSERT(is_max.size() == objectives.size()); - enable_trace("maximize"); // NSB review: OK for now for debugging. Otherwise, use command-line /tr:maximize - // First check_sat call for initialize theories lbool is_sat = s.check_sat(0, 0); - if (is_sat != l_false) { + if (is_sat == l_false) { return is_sat; } s.push(); - - // Assume there is only one objective function - SASSERT(is_max.size() == 1); + // Temporarily ignore the assertion to run the first objective function + //SASSERT(is_max.size() == 1); ast_manager& m = objectives.get_manager(); arith_util autil(m); bool ismax = is_max[0]; @@ -62,20 +59,19 @@ namespace opt { s.set_objective(objective_var); // NSB review: I would change signature of set_objective to take is_max and decide whether to add equation. // Otherwise, the difference logic backends will not work. s.toggle_objective(true); - is_sat = s.check_sat(0, 0); + is_sat = s.check_sat(0, 0); while (is_sat == l_true) { // Extract values for objectives - inf_eps_rational val; - val = is_max[0] ? s.get_objective_value() : -s.get_objective_value(); + inf_eps_rational val; + val = ismax ? s.get_objective_value() : -s.get_objective_value(); // Check whether objective is unbounded - // NSB: review: what if optimal is 1-epsilon. Then the check also fails. values.reset(); values.push_back(val); - if (!val.is_rational()) { + if (!val.get_infinity().is_zero()) { break; } @@ -90,7 +86,7 @@ namespace opt { if (is_sat == l_undef) { return is_sat; } - SASSERT(is_sat == l_false); // NSB review: not really water-tight with cancellation and with infinitesimal solutions. + //SASSERT(is_sat == l_false); // NSB review: not really water-tight with cancellation and with infinitesimal solutions. return l_true; } @@ -101,7 +97,7 @@ namespace opt { lbool optimize_objectives(opt_solver& s, app_ref_vector& objectives, svector const& is_max, - vector >& values) { + vector >& values) { return mathsat_style_opt(s, objectives, is_max, values); } } diff --git a/src/opt/optimize_objectives.h b/src/opt/optimize_objectives.h index 94a6f591a..fcf388fc9 100644 --- a/src/opt/optimize_objectives.h +++ b/src/opt/optimize_objectives.h @@ -29,7 +29,7 @@ namespace opt { lbool optimize_objectives(opt_solver& s, app_ref_vector& objectives, svector const& is_max, - vector >& values); + vector >& values); }; #endif diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 99b7e34f3..e0e535189 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -994,7 +994,7 @@ namespace smt { // ----------------------------------- virtual bool maximize(theory_var v) { return max_min(v, true); } virtual theory_var add_objective(app* term); - virtual inf_eps_rational get_objective_value(theory_var v); + virtual inf_eps_rational get_objective_value(theory_var v); inf_rational m_objective; // ----------------------------------- diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index da56f8b0f..8d010be71 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -961,9 +961,8 @@ namespace smt { } template - inf_eps_rational theory_arith::get_objective_value(theory_var v) { - inf_eps_rational val; - val = m_objective.get_rational(); + inf_eps_rational theory_arith::get_objective_value(theory_var v) { + inf_eps_rational val(m_objective); return val; } diff --git a/src/smt/theory_opt.h b/src/smt/theory_opt.h index c3765a1fc..9b013612b 100644 --- a/src/smt/theory_opt.h +++ b/src/smt/theory_opt.h @@ -18,6 +18,7 @@ Notes: --*/ +#include "inf_rational.h" #include "inf_eps_rational.h" #ifndef _THEORY_OPT_H_ @@ -28,9 +29,9 @@ namespace smt { public: virtual bool maximize(theory_var v) { UNREACHABLE(); return false; }; virtual theory_var add_objective(app* term) { UNREACHABLE(); return null_theory_var; } - virtual inf_eps_rational get_objective_value(theory_var v) { + virtual inf_eps_rational get_objective_value(theory_var v) { UNREACHABLE(); - inf_eps_rational r(rational(1), rational(0)); + inf_eps_rational r(rational(1), inf_rational(0)); return r; } }; From 36d7948399d71168b31f34d72305436540c7f67a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 22 Oct 2013 10:36:13 +0800 Subject: [PATCH 029/925] fixing optimizer for multi-objectives and epsilon Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 22 ++++++++- src/opt/opt_context.h | 5 +- src/opt/opt_solver.cpp | 39 ++++++++++----- src/opt/opt_solver.h | 32 ++++++++---- src/opt/optimize_objectives.cpp | 87 +++++++++++++++++++++------------ src/opt/optimize_objectives.h | 2 +- 6 files changed, 127 insertions(+), 60 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index ff49a5c8d..095c8f1f6 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -29,6 +29,9 @@ Notes: #include "optimize_objectives.h" #include "ast_pp.h" #include "opt_solver.h" +#include "arith_decl_plugin.h" +#include "th_rewriter.h" + namespace opt { @@ -74,7 +77,7 @@ namespace opt { } // SASSERT(instanceof(*s, opt_solver)); // if (!instsanceof ...) { throw ... invalid usage ..} - is_sat = optimize_objectives(dynamic_cast(*s), m_objectives, m_is_max, values); + is_sat = optimize_objectives(dynamic_cast(*s), m_objectives, values); std::cout << "is-sat: " << is_sat << "\n"; if (is_sat != l_true) { @@ -82,6 +85,9 @@ namespace opt { } for (unsigned i = 0; i < values.size(); ++i) { + if (!m_is_max[i]) { + values[i].neg(); + } std::cout << "objective function: " << mk_pp(m_objectives[i].get(), m) << " -> " << values[i].to_string() << "\n"; } } @@ -115,4 +121,18 @@ namespace opt { } } + void context::add_objective(app* t, bool is_max) { + expr_ref t1(t, m), t2(m); + th_rewriter rw(m); + if (!is_max) { + arith_util a(m); + t1 = a.mk_uminus(t); + } + rw(t1, t2); + SASSERT(is_app(t2)); + m_objectives.push_back(to_app(t2)); + m_is_max.push_back(is_max); + } + + } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index a08260cb1..a388bc952 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -52,10 +52,7 @@ namespace opt { m_weights.push_back(w); } - void add_objective(app* t, bool is_max) { - m_objectives.push_back(t); - m_is_max.push_back(is_max); - } + void add_objective(app* t, bool is_max); void add_hard_constraint(expr* f) { m_hard_constraints.push_back(f); diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 220ae0143..edeaf0441 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -66,12 +66,16 @@ namespace opt { TRACE("opt_solver_na2as", tout << "opt_opt_solver::check_sat_core: " << num_assumptions << "\n";); lbool r = m_context.check(num_assumptions, assumptions); if (r == l_true && m_objective_enabled) { - bool is_bounded = get_optimizer().maximize(m_objective_var); - if (is_bounded) { - m_objective_value = get_optimizer().get_objective_value(m_objective_var); - } else { - inf_eps_rational r(rational(1), inf_rational(0)); - m_objective_value = r; + m_objective_values.reset(); + for (unsigned i = 0; i < m_objective_vars.size(); ++i) { + smt::theory_var v = m_objective_vars[i]; + bool is_bounded = get_optimizer().maximize(v); + if (is_bounded) { + m_objective_values.push_back(get_optimizer().get_objective_value(v)); + } else { + inf_eps_rational r(rational(1), inf_rational(0)); + m_objective_values.push_back(r); + } } } return r; @@ -123,16 +127,27 @@ namespace opt { m_context.display(out); } - void opt_solver::set_objective(app* term) { - m_objective_var = get_optimizer().add_objective(term); + smt::theory_var opt_solver::add_objective(app* term) { + m_objective_vars.push_back(get_optimizer().add_objective(term)); + return m_objective_vars.back(); } - void opt_solver::toggle_objective(bool enable) { - m_objective_enabled = enable; + vector const& opt_solver::get_objective_values() { + return m_objective_values; } - inf_eps_rational opt_solver::get_objective_value() { - return m_objective_value; + void opt_solver::reset_objectives() { + m_objective_vars.reset(); + m_objective_values.reset(); } + opt_solver::toggle_objective::toggle_objective(opt_solver& s, bool new_value): s(s), m_old_value(s.m_objective_enabled) { + s.m_objective_enabled = new_value; + } + + opt_solver::toggle_objective::~toggle_objective() { + s.m_objective_enabled = m_old_value; + } + + } diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 9b59bf93b..ce07233e3 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -1,21 +1,22 @@ /*++ -Copyright (c) 2012 Microsoft Corporation +Copyright (c) 2013 Microsoft Corporation Module Name: - smt_solver.h + opt_solver.h Abstract: - Wraps smt::kernel as a solver for the external API and cmd_context. + Wraps smt::kernel as a solver for optimization Author: - Leonardo (leonardo) 2012-10-21 + Anh-Dung Phan (t-anphan) 2013-10-16 Notes: + + Based directly on smt_solver. - Variant of smt_solver that exposes kernel object. --*/ #ifndef _OPT_SOLVER_H_ #define _OPT_SOLVER_H_ @@ -33,13 +34,16 @@ Notes: namespace opt { class opt_solver : public solver_na2as { + public: + typedef inf_eps_rational inf_value; + private: smt_params m_params; smt::kernel m_context; progress_callback * m_callback; symbol m_logic; bool m_objective_enabled; - smt::theory_var m_objective_var; - inf_eps_rational m_objective_value; + svector m_objective_vars; + vector m_objective_values; public: opt_solver(ast_manager & m, params_ref const & p, symbol const & l); virtual ~opt_solver(); @@ -62,10 +66,18 @@ namespace opt { virtual expr * get_assertion(unsigned idx) const; virtual void display(std::ostream & out) const; - void set_objective(app* term); - void toggle_objective(bool enable); + smt::theory_var add_objective(app* term); + void reset_objectives(); + + vector const& get_objective_values(); - inf_eps_rational get_objective_value(); + class toggle_objective { + opt_solver& s; + bool m_old_value; + public: + toggle_objective(opt_solver& s, bool new_value); + ~toggle_objective(); + }; private: smt::theory_opt& get_optimizer(); }; diff --git a/src/opt/optimize_objectives.cpp b/src/opt/optimize_objectives.cpp index e167922cc..ef247ee3c 100644 --- a/src/opt/optimize_objectives.cpp +++ b/src/opt/optimize_objectives.cpp @@ -15,6 +15,26 @@ Author: Notes: + + Suppose we obtain solution t1 = k1, ..., tn = kn-epsilon + Assert: + t1 > k1 \/ t2 > k2 \/ ... \/ tn >= kn + If this solution is satisfiable, then for each t_i, maximize the + assignment and assert the new frontier. + Claim: we don't necessarily have to freeze assignments of + t_i when optimizing assignment for t_j + because the state will always satisfy the disjunction. + If one of the k_i is unbounded, then omit a disjunction for it. + Claim: the end result (when the constraints are no longer feasible) + is Pareto optimal, but convergence will probably not be as fast + as when fixing one parameter at a time. + E.g., a different approach is first to find a global maximal for one + variable. Then add a method to "freeze" that variable at the extremum if it is finite. + To do this, add lower and upper bounds for that variable using infinitesimals. + If the variable is unbounded, then this is of course not sufficient by itself. + + + --*/ #ifndef _OPT_OBJECTIVE_H_ @@ -31,13 +51,14 @@ namespace opt { */ lbool mathsat_style_opt( opt_solver& s, - app_ref_vector& objectives, - svector const& is_max, + app_ref_vector const& objectives, vector >& values) { - SASSERT(is_max.size() == objectives.size()); + ast_manager& m = objectives.get_manager(); + arith_util autil(m); - // First check_sat call for initialize theories + s.reset_objectives(); + // First check_sat call to initialize theories lbool is_sat = s.check_sat(0, 0); if (is_sat == l_false) { return is_sat; @@ -45,38 +66,41 @@ namespace opt { s.push(); - // Temporarily ignore the assertion to run the first objective function - //SASSERT(is_max.size() == 1); - ast_manager& m = objectives.get_manager(); - arith_util autil(m); - bool ismax = is_max[0]; - app_ref objective_var(m), objective_term(m), obj_eq(m); - objective_term = ismax?objectives[0].get():autil.mk_uminus(objectives[0].get()); - sort* srt = m.get_sort(objective_term); - objective_var = m.mk_fresh_const("objective", srt); - obj_eq = autil.mk_eq(objective_var, objective_term); - s.assert_expr(obj_eq); - s.set_objective(objective_var); // NSB review: I would change signature of set_objective to take is_max and decide whether to add equation. - // Otherwise, the difference logic backends will not work. - s.toggle_objective(true); + opt_solver::toggle_objective _t(s, true); + + for (unsigned i = 0; i < objectives.size(); ++i) { + s.add_objective(objectives[i]); + } + is_sat = s.check_sat(0, 0); while (is_sat == l_true) { // Extract values for objectives - inf_eps_rational val; - val = ismax ? s.get_objective_value() : -s.get_objective_value(); - - // Check whether objective is unbounded - values.reset(); - values.push_back(val); + values.append(s.get_objective_values()); + IF_VERBOSE(1, + for (unsigned i = 0; i < values.size(); ++i) { + verbose_stream() << values[i] << " "; + } + verbose_stream() << "\n";); + expr_ref_vector disj(m); + expr_ref constraint(m), num(m); + for (unsigned i = 0; i < objectives.size(); ++i) { - if (!val.get_infinity().is_zero()) { - break; + if (!values[i].get_infinity().is_zero()) { + continue; + } + num = autil.mk_numeral(values[i].get_rational(), m.get_sort(objectives[i])); + + SASSERT(values[i].get_infinitesimal().is_nonpos()); + if (values[i].get_infinitesimal().is_neg()) { + disj.push_back(autil.mk_ge(objectives[i], num)); + } + else { + disj.push_back(autil.mk_gt(objectives[i], num)); + } } - - expr_ref constraint(m); - constraint = autil.mk_gt(objective_term, autil.mk_numeral(val.get_rational(), srt)); + constraint = m.mk_or(disj.size(), disj.c_ptr()); s.assert_expr(constraint); is_sat = s.check_sat(0, 0); } @@ -86,7 +110,6 @@ namespace opt { if (is_sat == l_undef) { return is_sat; } - //SASSERT(is_sat == l_false); // NSB review: not really water-tight with cancellation and with infinitesimal solutions. return l_true; } @@ -96,9 +119,9 @@ namespace opt { */ lbool optimize_objectives(opt_solver& s, - app_ref_vector& objectives, svector const& is_max, + app_ref_vector& objectives, vector >& values) { - return mathsat_style_opt(s, objectives, is_max, values); + return mathsat_style_opt(s, objectives, values); } } diff --git a/src/opt/optimize_objectives.h b/src/opt/optimize_objectives.h index fcf388fc9..f2ce5baca 100644 --- a/src/opt/optimize_objectives.h +++ b/src/opt/optimize_objectives.h @@ -28,7 +28,7 @@ namespace opt { */ lbool optimize_objectives(opt_solver& s, - app_ref_vector& objectives, svector const& is_max, + app_ref_vector& objectives, vector >& values); }; From 6919f335a112dcc9764cd8f292664910cfdab006 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Tue, 22 Oct 2013 16:28:03 -0700 Subject: [PATCH 030/925] Sketch a skeleton of Difference Logic optimizer --- src/opt/opt_context.cpp | 7 ++-- src/opt/opt_solver.cpp | 7 ++++ src/smt/theory_diff_logic.h | 63 +++++++++++++++++++++++++++++++-- src/smt/theory_diff_logic_def.h | 18 ++++++++++ 4 files changed, 89 insertions(+), 6 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 095c8f1f6..754b2adb2 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -78,7 +78,7 @@ namespace opt { // SASSERT(instanceof(*s, opt_solver)); // if (!instsanceof ...) { throw ... invalid usage ..} is_sat = optimize_objectives(dynamic_cast(*s), m_objectives, values); - std::cout << "is-sat: " << is_sat << "\n"; + std::cout << "is-sat: " << is_sat << std::endl; if (is_sat != l_true) { return; @@ -88,15 +88,14 @@ namespace opt { if (!m_is_max[i]) { values[i].neg(); } - std::cout << "objective function: " << mk_pp(m_objectives[i].get(), m) << " -> " << values[i].to_string() << "\n"; + std::cout << "objective value: " << mk_pp(m_objectives[i].get(), m) << " -> " << values[i].to_string() << std::endl; } } if (m_objectives.empty() && m_soft_constraints.empty()) { is_sat = s->check_sat(0,0); - std::cout << "nothing to optimize: is-sat " << is_sat << "\n"; + std::cout << "nothing to optimize: is-sat " << is_sat << std::endl; } - } bool context::is_maxsat_problem() const { diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index edeaf0441..6cf7c59ed 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -2,6 +2,7 @@ #include"opt_solver.h" #include"smt_context.h" #include"theory_arith.h" +#include"theory_diff_logic.h" namespace opt { @@ -55,6 +56,12 @@ namespace opt { else if (typeid(smt::theory_i_arith) == typeid(*arith_theory)) { return dynamic_cast(*arith_theory); } + else if (typeid(smt::theory_rdl&) == typeid(*arith_theory)) { + return dynamic_cast(*arith_theory); + } + else if (typeid(smt::theory_idl&) == typeid(*arith_theory)) { + return dynamic_cast(*arith_theory); + } else { UNREACHABLE(); return dynamic_cast(*arith_theory); diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h index 7302ccfd4..579195c84 100644 --- a/src/smt/theory_diff_logic.h +++ b/src/smt/theory_diff_logic.h @@ -37,7 +37,7 @@ Revision History: #include"smt_model_generator.h" #include"numeral_factory.h" #include"smt_clause.h" - +#include"theory_opt.h" // The DL theory can represent term such as n + k, where n is an enode and k is a numeral. namespace smt { @@ -59,7 +59,7 @@ namespace smt { }; template - class theory_diff_logic : public theory, private Ext { + class theory_diff_logic : public theory, public theory_opt, private Ext { typedef typename Ext::numeral numeral; @@ -296,6 +296,18 @@ namespace smt { virtual void collect_statistics(::statistics & st) const; + + // ----------------------------------- + // + // Optimization + // + // ----------------------------------- + + virtual bool maximize(theory_var v); + virtual theory_var add_objective(app* term); + virtual inf_eps_rational get_objective_value(theory_var v); + inf_rational m_objective; + private: virtual void new_eq_eh(theory_var v1, theory_var v2, justification& j); @@ -374,6 +386,53 @@ namespace smt { srdl_ext() : m_epsilon(s_integer(0),true) {} }; + // Solve minimum cost flow problem using Network Simplex algorithm + class network_simplex { + svector m_nodes; + svector m_edges; + // Denote costs c_ij on edge (i, j) + vector m_costs; + // Denote supply/demand b_i on node i + vector m_capacities; + + // Keep optimal solution of the min cost flow problem + inf_rational m_objective; + + public: + // Create a spanning tree using Kruskal algorithm + virtual svector & create_spanning_tree(); + + // A spanning tree is a basis in network simplex. + // Check whether the edges' associated costs could be reduced + virtual rational calculate_reduced_costs(svector & spanning_tree); + + // If all reduced costs are non-negative, the current flow is optimal + virtual bool is_optimal(svector & spanning_tree); + + // Choose an edge with negative reduced cost + virtual edge_id choose_entering_edge(); + + // Send as much flow as possible around the cycle, the first basic edge with flow 0 will leave + edge_id choose_leaving_edge(); + + virtual bool is_unbounded(); + + // Minimize cost flows + // Return true if found an optimal solution, and return false if unbounded + virtual bool minimize(); + }; + + /* Notes: + + We need a function to reduce DL constraints to min cost flow problem + and another function to convert from min cost flow solution to DL solution. + + It remains unclear how to convert DL assignment to a basic feasible solution of Network Simplex. + A naive approach is to run Kruskal in order to get a spanning tree. + + The network_simplex class hasn't had multiple pivoting strategies yet. + */ + typedef theory_diff_logic theory_idl; typedef theory_diff_logic theory_fidl; diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index 390803957..60505146d 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -996,5 +996,23 @@ void theory_diff_logic::get_implied_bound_antecedents(edge_id bridge_edge, m_graph.explain_subsumed_lazy(bridge_edge, subsumed_edge, f); } +template +bool theory_diff_logic::maximize(theory_var v) { + NOT_IMPLEMENTED_YET(); + return false; +} + +template +theory_var theory_diff_logic::add_objective(app* term) { + // Internalizing may not succeed since objective can be LRA + return null_theory_var; +} + +template +inf_eps_rational theory_diff_logic::get_objective_value(theory_var v) { + inf_eps_rational val(m_objective); + return val; +} + #endif /* _THEORY_DIFF_LOGIC_DEF_H_ */ From 11010086be4beb571a4036ee4da45293c0447b2e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 Oct 2013 11:57:30 +0800 Subject: [PATCH 031/925] fixing bug with optimization Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith.h | 1 + src/smt/theory_arith_aux.h | 120 +++++++++++++++++++++++++++++++++---- 2 files changed, 111 insertions(+), 10 deletions(-) diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index e0e535189..8d0011ec1 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -853,6 +853,7 @@ namespace smt { void add_tmp_row(row & r1, numeral const & coeff, row const & r2); theory_var pick_var_to_leave(theory_var x_j, bool inc, numeral & a_ij, inf_numeral & gain); + void move_to_bound(theory_var x_i, bool inc); template void add_tmp_row_entry(row & r, numeral const & coeff, theory_var v); bool max_min(theory_var v, bool max); diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 8d010be71..d50b1d505 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -912,6 +912,16 @@ namespace smt { If no x_i imposes a restriction on x_j, then return null_theory_var. That is, x_j is free to move to its upper bound (lower bound). + + Get the equations for x_j: + + x_i1 = coeff_1 * x_j + rest_1 + ... + x_in = coeff_n * x_j + rest_n + + gain_k := (upper_bound(x_ik) - value(x_ik))/coeff_k + + */ template theory_var theory_arith::pick_var_to_leave(theory_var x_j, bool inc, numeral & a_ij, inf_numeral & gain) { @@ -939,10 +949,15 @@ namespace smt { x_i = s; a_ij = coeff; gain = curr_gain; + TRACE("maximize", + tout << "x_i: v" << x_i << ", gain: " << gain << "\n"; + tout << "value(s): (" << get_value(s) << " - " << b->get_value() << ")/" << coeff << "\n"; + display_row(tout, r, true); + ); } } } - TRACE("maximize", tout << "x_j: v" << x_i << ", gain: " << gain << "\n";); + TRACE("maximize", tout << "x_i: v" << x_i << ", gain: " << gain << "\n";); } } TRACE("maximize", tout << "x_i v" << x_i << "\n";); @@ -982,7 +997,7 @@ namespace smt { theory_var x_j = null_theory_var; bool inc = false; numeral a_ij, curr_a_ij, coeff, curr_coeff; - inf_numeral curr_gain, gain; + inf_numeral gain, curr_gain; #ifdef _TRACE unsigned i = 0; #endif @@ -1071,19 +1086,45 @@ namespace smt { continue; } - TRACE("maximize", tout << "max: " << max << ", x_i: v" << x_i << ", x_j: v" << x_j << ", a_ij: " << a_ij << ", coeff: " << coeff << "\n";); + TRACE("maximize", tout << "max: " << max << ", x_i: v" << x_i << ", x_j: v" << x_j << ", a_ij: " << a_ij << ", coeff: " << coeff << "\n"; + if (upper(x_i)) tout << "upper x_i: " << upper_bound(x_i) << " "; + if (lower(x_i)) tout << "lower x_i: " << lower_bound(x_i) << " "; + tout << "value x_i: " << get_value(x_i) << "\n"; + if (upper(x_j)) tout << "upper x_j: " << upper_bound(x_j) << " "; + if (lower(x_j)) tout << "lower x_j: " << lower_bound(x_j) << " "; + tout << "value x_j: " << get_value(x_j) << "\n"; + ); + pivot(x_i, x_j, a_ij, false); + + TRACE("maximize", tout << "max: " << max << ", x_i: v" << x_i << ", x_j: v" << x_j << ", a_ij: " << a_ij << ", coeff: " << coeff << "\n"; + if (upper(x_i)) tout << "upper x_i: " << upper_bound(x_i) << " "; + if (lower(x_i)) tout << "lower x_i: " << lower_bound(x_i) << " "; + tout << "value x_i: " << get_value(x_i) << "\n"; + if (upper(x_j)) tout << "upper x_j: " << upper_bound(x_j) << " "; + if (lower(x_j)) tout << "lower x_j: " << lower_bound(x_j) << " "; + tout << "value x_j: " << get_value(x_j) << "\n"; + + ); + + SASSERT(is_non_base(x_i)); + SASSERT(is_base(x_j)); + bool move_xi_to_lower; if (inc) move_xi_to_lower = a_ij.is_pos(); else move_xi_to_lower = a_ij.is_neg(); - pivot(x_i, x_j, a_ij, false); - SASSERT(is_non_base(x_i)); - SASSERT(is_base(x_j)); - if (move_xi_to_lower) - update_value(x_i, lower_bound(x_i) - get_value(x_i)); - else - update_value(x_i, upper_bound(x_i) - get_value(x_i)); + move_to_bound(x_i, move_xi_to_lower); + + TRACE("maximize", tout << "max: " << max << ", x_i: v" << x_i << ", x_j: v" << x_j << ", a_ij: " << a_ij << ", coeff: " << coeff << "\n"; + if (upper(x_i)) tout << "upper x_i: " << upper_bound(x_i) << " "; + if (lower(x_i)) tout << "lower x_i: " << lower_bound(x_i) << " "; + tout << "value x_i: " << get_value(x_i) << "\n"; + if (upper(x_j)) tout << "upper x_j: " << upper_bound(x_j) << " "; + if (lower(x_j)) tout << "lower x_j: " << lower_bound(x_j) << " "; + tout << "value x_j: " << get_value(x_j) << "\n"; + ); + row & r2 = m_rows[get_var_row(x_j)]; coeff.neg(); add_tmp_row(r, coeff, r2); @@ -1093,6 +1134,65 @@ namespace smt { } } + /** + Move the variable x_i maximally towards its bound as long as + bounds of other variables are not violated. + */ + + template + void theory_arith::move_to_bound(theory_var x_i, bool move_to_lower) { + inf_numeral delta, delta_abs; + + if (move_to_lower) { + delta = lower_bound(x_i) - get_value(x_i); + SASSERT(!delta.is_pos()); + } + else { + delta = upper_bound(x_i) - get_value(x_i); + SASSERT(!delta.is_neg()); + } + + TRACE("maximize", tout << "Original delta: " << delta << "\n";); + + delta_abs = abs(delta); + // + // Decrease absolute value of delta according to bounds on rows where x_i is used. + // + column & c = m_columns[x_i]; + typename svector::iterator it = c.begin_entries(); + typename svector::iterator end = c.end_entries(); + for (; it != end && delta_abs.is_pos(); ++it) { + if (!it->is_dead()) { + row & r = m_rows[it->m_row_id]; + theory_var s = r.get_base_var(); + if (s != null_theory_var && !is_quasi_base(s)) { + numeral const & coeff = r[it->m_row_idx].m_coeff; + SASSERT(!coeff.is_zero()); + bool inc_s = coeff.is_pos() ? move_to_lower : !move_to_lower; // NSB: review this.. + bound * b = get_bound(s, inc_s); + if (b) { + inf_numeral delta2 = abs((get_value(s) - b->get_value())/coeff); + if (delta2 < delta_abs) { + delta_abs = delta2; + } + } + } + } + } + + + if (move_to_lower) { + delta = -delta_abs; + } + else { + delta = delta_abs; + } + + TRACE("maximize", tout << "Safe delta: " << delta << "\n";); + + update_value(x_i, delta); + } + /** \brief Add an entry to a temporary row. From 7c8fbbb06a580f5cf69500ed19eb4754b1c87ade Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 Oct 2013 12:03:05 +0800 Subject: [PATCH 032/925] fixing bug with optimization Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith.h | 2 +- src/smt/theory_arith_aux.h | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 8d0011ec1..cf2ec7ff4 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -993,7 +993,7 @@ namespace smt { // Optimization // // ----------------------------------- - virtual bool maximize(theory_var v) { return max_min(v, true); } + virtual bool maximize(theory_var v); virtual theory_var add_objective(app* term); virtual inf_eps_rational get_objective_value(theory_var v); inf_rational m_objective; diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index d50b1d505..26c272548 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -975,6 +975,13 @@ namespace smt { return internalize_term_core(term); } + template + bool theory_arith::maximize(theory_var v) { + bool r = max_min(v, true); + return r || at_upper(v); + } + + template inf_eps_rational theory_arith::get_objective_value(theory_var v) { inf_eps_rational val(m_objective); From 1ff373072def5a981e97c26ac377a3ae42cce0d6 Mon Sep 17 00:00:00 2001 From: Phan Anh Dung Date: Thu, 24 Oct 2013 08:57:21 +0200 Subject: [PATCH 033/925] Add objective functions to difference logic solver --- src/smt/theory_diff_logic.h | 6 +++- src/smt/theory_diff_logic_def.h | 58 +++++++++++++++++++++++++++++++-- 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h index 579195c84..1a7d2baac 100644 --- a/src/smt/theory_diff_logic.h +++ b/src/smt/theory_diff_logic.h @@ -306,7 +306,11 @@ namespace smt { virtual bool maximize(theory_var v); virtual theory_var add_objective(app* term); virtual inf_eps_rational get_objective_value(theory_var v); - inf_rational m_objective; + + typedef vector > objective_term; + vector m_objectives; + + void internalize_objective(app * n, objective_term & objective); private: diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index 60505146d..5f9e80d9b 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -998,21 +998,73 @@ void theory_diff_logic::get_implied_bound_antecedents(edge_id bridge_edge, template bool theory_diff_logic::maximize(theory_var v) { + IF_VERBOSE(1, + objective_term objective = m_objectives[v]; + for (unsigned i = 0; i < objective.size(); ++i) { + verbose_stream() << "coefficient " << objective[i].second << " of theory_var " << objective[i].first << "\n"; + } + verbose_stream() << "\n";); NOT_IMPLEMENTED_YET(); return false; } template theory_var theory_diff_logic::add_objective(app* term) { - // Internalizing may not succeed since objective can be LRA - return null_theory_var; + objective_term objective; + internalize_objective(term, objective); + m_objectives.push_back(objective); + return m_objectives.size()-1; } template inf_eps_rational theory_diff_logic::get_objective_value(theory_var v) { - inf_eps_rational val(m_objective); + inf_rational objective; + inf_eps_rational val(objective); return val; } +template +void theory_diff_logic::internalize_objective(app * n, objective_term & objective) { + // TODO: Need some simplification on n to ensure no bad case + SASSERT(!m_util.is_div(n)); + SASSERT(!m_util.is_idiv(n)); + SASSERT(!m_util.is_mod(n)); + SASSERT(!m_util.is_rem(n)); + SASSERT(!m_util.is_to_real(n)); + SASSERT(!m_util.is_to_int(n)); + SASSERT(!m_util.is_power(n)); + SASSERT(!m_util.is_irrational_algebraic_numeral(n)); + + // Compile term into objective_term format + rational r; + if (m_util.is_numeral(n, r)) { + theory_var v = mk_num(n, r); + objective.push_back(std::make_pair(v, r)); + } + else if (m_util.is_add(n)) { + for (unsigned i = 0; i < n->get_num_args(); ++i) { + internalize_objective(to_app(n->get_arg(i)), objective); + }; + } + else if (m_util.is_mul(n)) { + SASSERT(n->get_num_args() == 2); + rational r; + app * lhs = to_app(n->get_arg(0)); + app * rhs = to_app(n->get_arg(1)); + SASSERT(m_util.is_numeral(lhs, r) || m_util.is_numeral(rhs, r)); + + if (!m_util.is_numeral(lhs, r)) + std::swap(lhs, rhs); + m_util.is_numeral(lhs, r); + theory_var v = mk_var(rhs); + objective.push_back(std::make_pair(v, r)); + } + else { + theory_var v = mk_var(n); + rational r(1); + objective.push_back(std::make_pair(v, r)); + } +} + #endif /* _THEORY_DIFF_LOGIC_DEF_H_ */ From be81e77c707dae12b7b721d57effe3d526600b55 Mon Sep 17 00:00:00 2001 From: Phan Anh Dung Date: Thu, 24 Oct 2013 09:50:12 +0200 Subject: [PATCH 034/925] Some progress on Network Simplex --- src/smt/theory_diff_logic.h | 49 +++++++++++++++++++++++---------- src/smt/theory_diff_logic_def.h | 29 +++++++++---------- 2 files changed, 50 insertions(+), 28 deletions(-) diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h index 1a7d2baac..f904a600a 100644 --- a/src/smt/theory_diff_logic.h +++ b/src/smt/theory_diff_logic.h @@ -397,33 +397,54 @@ namespace smt { // Denote costs c_ij on edge (i, j) vector m_costs; // Denote supply/demand b_i on node i - vector m_capacities; + vector m_potentials; // Keep optimal solution of the min cost flow problem inf_rational m_objective; + // Data structure of spanning trees + svector m_pred; + svector m_depth; + svector m_thread; + public: - // Create a spanning tree using Kruskal algorithm - virtual svector & create_spanning_tree(); + // Initialize the network with a feasible spanning tree + virtual void initialize(); + + virtual void compute_potentials(); + + virtual void compute_flows(); - // A spanning tree is a basis in network simplex. - // Check whether the edges' associated costs could be reduced - virtual rational calculate_reduced_costs(svector & spanning_tree); - // If all reduced costs are non-negative, the current flow is optimal - virtual bool is_optimal(svector & spanning_tree); - - // Choose an edge with negative reduced cost - virtual edge_id choose_entering_edge(); + // If not optimal, return a violated edge in the corresponding variable + virtual bool is_optimal(edge_id & violated_edge); // Send as much flow as possible around the cycle, the first basic edge with flow 0 will leave - edge_id choose_leaving_edge(); + virtual edge_id choose_leaving_edge(); + + virtual void update_tree(edge_id entering_edge, edge_id leaving_edge); virtual bool is_unbounded(); + // Compute the optimal solution + virtual void compute_solution(); + // Minimize cost flows // Return true if found an optimal solution, and return false if unbounded - virtual bool minimize(); + bool minimize() { + initialize(); + compute_potentials(); + compute_flows(); + edge_id entering_edge; + while (!is_optimal(entering_edge)) { + edge_id leaving_edge = choose_leaving_edge(); + update_tree(entering_edge, leaving_edge); + + if (is_unbounded()) + return false; + } + return true; + } }; /* Notes: @@ -432,7 +453,7 @@ namespace smt { and another function to convert from min cost flow solution to DL solution. It remains unclear how to convert DL assignment to a basic feasible solution of Network Simplex. - A naive approach is to run Kruskal in order to get a spanning tree. + A naive approach is to run an algorithm on max flow in order to get a spanning tree. The network_simplex class hasn't had multiple pivoting strategies yet. */ diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index 5f9e80d9b..684850d77 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -1038,8 +1038,8 @@ void theory_diff_logic::internalize_objective(app * n, objective_term & obj // Compile term into objective_term format rational r; if (m_util.is_numeral(n, r)) { - theory_var v = mk_num(n, r); - objective.push_back(std::make_pair(v, r)); + theory_var v = mk_num(n, r); + objective.push_back(std::make_pair(v, r)); } else if (m_util.is_add(n)) { for (unsigned i = 0; i < n->get_num_args(); ++i) { @@ -1047,22 +1047,23 @@ void theory_diff_logic::internalize_objective(app * n, objective_term & obj }; } else if (m_util.is_mul(n)) { - SASSERT(n->get_num_args() == 2); - rational r; - app * lhs = to_app(n->get_arg(0)); - app * rhs = to_app(n->get_arg(1)); - SASSERT(m_util.is_numeral(lhs, r) || m_util.is_numeral(rhs, r)); + SASSERT(n->get_num_args() == 2); + rational r; + app * lhs = to_app(n->get_arg(0)); + app * rhs = to_app(n->get_arg(1)); + SASSERT(m_util.is_numeral(lhs, r) || m_util.is_numeral(rhs, r)); if (!m_util.is_numeral(lhs, r)) - std::swap(lhs, rhs); - m_util.is_numeral(lhs, r); - theory_var v = mk_var(rhs); - objective.push_back(std::make_pair(v, r)); + std::swap(lhs, rhs); + + m_util.is_numeral(lhs, r); + theory_var v = mk_var(rhs); + objective.push_back(std::make_pair(v, r)); } else { - theory_var v = mk_var(n); - rational r(1); - objective.push_back(std::make_pair(v, r)); + theory_var v = mk_var(n); + rational r(1); + objective.push_back(std::make_pair(v, r)); } } From ebed5fa037b7ef6773085ff56703492f220336b9 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Thu, 24 Oct 2013 17:58:15 -0700 Subject: [PATCH 035/925] WIP on min cost flow problem Remarks: 1. Follow the template structure of diff_logic.h 2. Try to reuse dl_graph with some ready-to-use graph algorithms 3. Need to add 'explanation' to 'GExt' in order to instantiate dl_graph<_> --- src/smt/diff_logic.h | 18 +++++ src/smt/network_flow.h | 102 +++++++++++++++++++++++++ src/smt/network_flow_def.h | 148 ++++++++++++++++++++++++++++++++++++ src/smt/theory_diff_logic.h | 72 +----------------- 4 files changed, 271 insertions(+), 69 deletions(-) create mode 100644 src/smt/network_flow.h create mode 100644 src/smt/network_flow_def.h diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index 2717e4a92..74a5dbbd2 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -931,6 +931,24 @@ public: return found; } + // Return true if there is an edge source --> target. + // If there is such edge, return it in parameter e. + bool get_edge(dl_var source, dl_var target, edge & e) { + edge_id_vector & edges = m_out_edges[source]; + typename edge_id_vector::iterator it = edges.begin(); + typename edge_id_vector::iterator end = edges.end(); + bool found = false; + for (; it != end; ++it) { + edge_id e_id = *it; + edge & e0 = m_edges[e_id]; + if (e0.is_enabled() && e0.get_target() == target && !found) { + e = e0; + found = true; + } + } + return found; + } + template void enumerate_edges(dl_var source, dl_var target, Functor& f) { edge_id_vector & edges = m_out_edges[source]; diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h new file mode 100644 index 000000000..d10ccf005 --- /dev/null +++ b/src/smt/network_flow.h @@ -0,0 +1,102 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + network_flow.h + +Abstract: + + Implements Network Simplex algorithm for min cost flow problem + +Author: + + Anh-Dung Phan (t-anphan) 2013-10-24 + +Notes: + + This will be used to solve the dual of min cost flow problem + i.e. optimization of difference constraint. + + We need a function to reduce DL constraints to min cost flow problem + and another function to convert from min cost flow solution to DL solution. + + It remains unclear how to convert DL assignment to a basic feasible solution of Network Simplex. + A naive approach is to run an algorithm on max flow in order to get a spanning tree. + + The network_simplex class hasn't had multiple pivoting strategies yet. + +--*/ +#ifndef _NETWORK_FLOW_H_ +#define _NETWORK_FLOW_H_ + +#include"inf_rational.h" +#include"diff_logic.h" + +namespace smt { + + // Solve minimum cost flow problem using Network Simplex algorithm + template + class network_flow : private Ext { + struct GExt : public Ext { + typedef literal explanation; + }; + + typedef dl_var node; + typedef dl_edge edge; + typedef dl_graph graph; + typedef typename Ext::numeral numeral; + graph m_graph; + + // Denote supply/demand b_i on node i + vector m_balances; + + vector m_potentials; + + // Keep optimal solution of the min cost flow problem + inf_rational m_objective; + + // Basic feasible flows + vector m_flows; + + // Denote the spanning tree of basic edges + vector m_basics; + // Denote non-basic edges with flow 0 for uncapicitated networks + vector m_nonbasics; + + // Store the parent of a node in the spanning tree + svector m_pred; + // Store the number of edge on the path to the root + svector m_depth; + // Store the pointer to the next node in depth first search ordering + svector m_thread; + + public: + // Initialize the network with a feasible spanning tree + void initialize(); + + void compute_potentials(); + + void compute_flows(); + + // If all reduced costs are non-negative, the current flow is optimal + // If not optimal, return a violating edge in the corresponding variable + bool is_optimal(edge & violating_edge); + + // Send as much flow as possible around the cycle, the first basic edge with flow 0 will leave + edge choose_leaving_edge(const edge & entering_edge); + + void update_basics(const edge & entering_edge, const edge & leaving_edge); + + bool is_unbounded(); + + // Compute the optimal solution + void get_optimal_solution(numeral & objective, vector & flows); + + // Minimize cost flows + // Return true if found an optimal solution, and return false if unbounded + bool min_cost(); + }; +} + +#endif diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h new file mode 100644 index 000000000..8ce0a2458 --- /dev/null +++ b/src/smt/network_flow_def.h @@ -0,0 +1,148 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + network_flow_def.h + +Abstract: + + Implements Network Simplex algorithm for min cost flow problem + +Author: + + Anh-Dung Phan (t-anphan) 2013-10-24 + +Notes: + +--*/ + +#ifndef _NETWORK_FLOW_DEF_H_ +#define _NETWORK_FLOW_DEF_H_ + +#include"network_flow.h" + +namespace smt { + + template + void network_flow::initialize() { + // TODO: construct an initial spanning tree i.e. inializing m_pred, m_depth and m_thread. + compute_potentials(); + compute_flows(); + } + + template + void network_flow::compute_potentials() { + SASSERT(!m_potentials.empty()); + SASSERT(!m_thread.empty()); + SASSERT(m_thread.size() == m_pred.size()); + + array potentials; + std::copy(m_potentials.begin(), m_potentials.end(), potentials); + rational zero(0); + potentials[0] = zero; + node next = m_thread[0]; + + while (next != 0) { + node current = m_pred[next]; + edge e; + if (m_graph.get_edge(current, next, e)) { + potentials[next] = potentials[current] - e.get_weight(); + } + if (m_graph.get_edge(next, current, e)) { + potentials[next] = potentials[current] + e.get_weight(); + } + next = m_thread[next]; + } + std::copy(potentials.begin(), potentials.end(), m_potentials); + } + + template + void network_flow::compute_flows() { + vector balances(m_balances); + numeral zero; + m_flows.fill(zero); + vector basics(m_basics); + // TODO: need a way to find a leaf node of a spanning tree + while (!basics.empty()) { + return; + } + } + + template + bool network_flow::is_optimal(edge & violating_edge) { + typename vector::iterator it = m_nonbasics.begin(); + typename vector::iterator end = m_nonbasics.end(); + bool found = false; + for (unsigned int i = 0; i < m_nonbasics.size(); ++i) { + edge & e = m_nonbasics[i]; + if (e.is_enabled()) { + node source = e.get_source(); + node target = e.get_target(); + numeral cost = e.get_weight() - m_potentials[source] + m_potentials[target]; + // Choose the first negative-cost edge to be the violating edge + // TODO: add multiple pivoting strategies + if (cost < 0) { + violating_edge = e; + found = true; + break; + } + } + } + return !found; + } + + template + dl_edge::GExt> network_flow::choose_leaving_edge(const edge & entering_edge) { + node source = entering_edge.get_source(); + node target = entering_edge.get_target(); + while (source != target) { + if (m_depth[source] > m_depth[target]) + source = m_pred[source]; + else if (m_depth[source] < m_depth[target]) + target = m_pred[target]; + else { + source = m_pred[source]; + target = m_pred[target]; + } + } + edge e; + m_graph.get_edge(source, target, e); + return e; + } + + template + void network_flow::update_basics(const edge & entering_edge, const edge & leaving_edge) { + + } + + template + bool network_flow::is_unbounded() { + return false; + } + + // Get the optimal solution + template + void network_flow::get_optimal_solution(numeral & objective, vector & flows) { + flows.reset(); + flows.append(m_flows); + // TODO: calculate objective value + } + + // Minimize cost flows + // Return true if found an optimal solution, and return false if unbounded + template + bool network_flow::min_cost() { + initialize(); + edge & entering_edge; + while (!is_optimal(entering_edge)) { + edge & leaving_edge = choose_leaving_edge(); + update_tree(entering_edge, leaving_edge); + if (is_unbounded()) + return false; + } + return true; + } +} + +#endif diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h index f904a600a..9447b0d3e 100644 --- a/src/smt/theory_diff_logic.h +++ b/src/smt/theory_diff_logic.h @@ -38,6 +38,7 @@ Revision History: #include"numeral_factory.h" #include"smt_clause.h" #include"theory_opt.h" +#include"network_flow_def.h" // The DL theory can represent term such as n + k, where n is an enode and k is a numeral. namespace smt { @@ -312,6 +313,8 @@ namespace smt { void internalize_objective(app * n, objective_term & objective); + network_flow m_network_flow; + private: virtual void new_eq_eh(theory_var v1, theory_var v2, justification& j); @@ -390,75 +393,6 @@ namespace smt { srdl_ext() : m_epsilon(s_integer(0),true) {} }; - // Solve minimum cost flow problem using Network Simplex algorithm - class network_simplex { - svector m_nodes; - svector m_edges; - // Denote costs c_ij on edge (i, j) - vector m_costs; - // Denote supply/demand b_i on node i - vector m_potentials; - - // Keep optimal solution of the min cost flow problem - inf_rational m_objective; - - // Data structure of spanning trees - svector m_pred; - svector m_depth; - svector m_thread; - - public: - // Initialize the network with a feasible spanning tree - virtual void initialize(); - - virtual void compute_potentials(); - - virtual void compute_flows(); - - // If all reduced costs are non-negative, the current flow is optimal - // If not optimal, return a violated edge in the corresponding variable - virtual bool is_optimal(edge_id & violated_edge); - - // Send as much flow as possible around the cycle, the first basic edge with flow 0 will leave - virtual edge_id choose_leaving_edge(); - - virtual void update_tree(edge_id entering_edge, edge_id leaving_edge); - - virtual bool is_unbounded(); - - // Compute the optimal solution - virtual void compute_solution(); - - // Minimize cost flows - // Return true if found an optimal solution, and return false if unbounded - bool minimize() { - initialize(); - compute_potentials(); - compute_flows(); - edge_id entering_edge; - while (!is_optimal(entering_edge)) { - edge_id leaving_edge = choose_leaving_edge(); - update_tree(entering_edge, leaving_edge); - - if (is_unbounded()) - return false; - } - return true; - } - }; - - /* Notes: - - We need a function to reduce DL constraints to min cost flow problem - and another function to convert from min cost flow solution to DL solution. - - It remains unclear how to convert DL assignment to a basic feasible solution of Network Simplex. - A naive approach is to run an algorithm on max flow in order to get a spanning tree. - - The network_simplex class hasn't had multiple pivoting strategies yet. - */ - - typedef theory_diff_logic theory_idl; typedef theory_diff_logic theory_fidl; typedef theory_diff_logic theory_rdl; From 532c345fd119e0b2b08534c171cd0ca568040056 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Fri, 25 Oct 2013 17:42:03 -0700 Subject: [PATCH 036/925] Reduce difference logic solver to min cost flow --- src/smt/diff_logic.h | 14 ++-- src/smt/network_flow.h | 33 ++++---- src/smt/network_flow_def.h | 134 ++++++++++++++++++++++---------- src/smt/theory_diff_logic.h | 3 +- src/smt/theory_diff_logic_def.h | 33 +++++++- 5 files changed, 152 insertions(+), 65 deletions(-) diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index 74a5dbbd2..23f0de06c 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -932,23 +932,27 @@ public: } // Return true if there is an edge source --> target. - // If there is such edge, return it in parameter e. - bool get_edge(dl_var source, dl_var target, edge & e) { + // If there is such edge, return its edge_id in parameter id. + bool get_edge_id(dl_var source, dl_var target, edge_id & id) { edge_id_vector & edges = m_out_edges[source]; typename edge_id_vector::iterator it = edges.begin(); typename edge_id_vector::iterator end = edges.end(); bool found = false; for (; it != end; ++it) { edge_id e_id = *it; - edge & e0 = m_edges[e_id]; - if (e0.is_enabled() && e0.get_target() == target && !found) { - e = e0; + edge & e = m_edges[e_id]; + if (e.is_enabled() && e.get_target() == target && !found) { + id = e_id; found = true; } } return found; } + edges & get_all_edges() { + return m_edges; + } + template void enumerate_edges(dl_var source, dl_var target, Functor& f) { edge_id_vector & edges = m_out_edges[source]; diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index d10ccf005..8232f4d0a 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -38,31 +38,29 @@ namespace smt { // Solve minimum cost flow problem using Network Simplex algorithm template class network_flow : private Ext { - struct GExt : public Ext { - typedef literal explanation; - }; - typedef dl_var node; - typedef dl_edge edge; - typedef dl_graph graph; - typedef typename Ext::numeral numeral; + typedef dl_edge edge; + typedef dl_graph graph; + typedef typename Ext::numeral numeral; graph m_graph; // Denote supply/demand b_i on node i vector m_balances; + // Duals of flows which are convenient to compute dual solutions vector m_potentials; // Keep optimal solution of the min cost flow problem inf_rational m_objective; + // Costs on edges + vector & m_costs; + // Basic feasible flows vector m_flows; - // Denote the spanning tree of basic edges - vector m_basics; - // Denote non-basic edges with flow 0 for uncapicitated networks - vector m_nonbasics; + // An element is true if the corresponding edge points upwards (compared to the root node) + svector m_upwards; // Store the parent of a node in the spanning tree svector m_pred; @@ -71,7 +69,12 @@ namespace smt { // Store the pointer to the next node in depth first search ordering svector m_thread; + bool m_is_optimal; + public: + + network_flow(graph & g, vector & costs); + // Initialize the network with a feasible spanning tree void initialize(); @@ -81,13 +84,13 @@ namespace smt { // If all reduced costs are non-negative, the current flow is optimal // If not optimal, return a violating edge in the corresponding variable - bool is_optimal(edge & violating_edge); + bool is_optimal(edge_id & violating_edge); // Send as much flow as possible around the cycle, the first basic edge with flow 0 will leave - edge choose_leaving_edge(const edge & entering_edge); - - void update_basics(const edge & entering_edge, const edge & leaving_edge); + edge_id choose_leaving_edge(edge_id entering_edge); + void update_spanning_tree(edge_id entering_edge, edge_id leaving_edge); + bool is_unbounded(); // Compute the optimal solution diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index 8ce0a2458..3c5106ac6 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -24,6 +24,12 @@ Notes: namespace smt { + template + network_flow::network_flow(graph & g, vector & costs) : + m_graph(g), + m_costs(costs) { + } + template void network_flow::initialize() { // TODO: construct an initial spanning tree i.e. inializing m_pred, m_depth and m_thread. @@ -36,54 +42,74 @@ namespace smt { SASSERT(!m_potentials.empty()); SASSERT(!m_thread.empty()); SASSERT(m_thread.size() == m_pred.size()); - - array potentials; - std::copy(m_potentials.begin(), m_potentials.end(), potentials); - rational zero(0); - potentials[0] = zero; - node next = m_thread[0]; - while (next != 0) { - node current = m_pred[next]; - edge e; - if (m_graph.get_edge(current, next, e)) { - potentials[next] = potentials[current] - e.get_weight(); + numeral zero(0); + m_potentials.set(0, zero); + node target = m_thread[0]; + + while (target != 0) { + node source = m_pred[target]; + edge_id e_id; + if (m_graph.get_edge_id(source, target, e_id)) { + m_potentials.set(target, m_potentials[source] - m_graph.get_weight(e_id)); } - if (m_graph.get_edge(next, current, e)) { - potentials[next] = potentials[current] + e.get_weight(); + if (m_graph.get_edge_id(target, source, e_id)) { + m_potentials.set(target, m_potentials[source] + m_graph.get_weight(e_id)); } - next = m_thread[next]; + target = m_thread[target]; } - std::copy(potentials.begin(), potentials.end(), m_potentials); } template void network_flow::compute_flows() { vector balances(m_balances); - numeral zero; - m_flows.fill(zero); - vector basics(m_basics); - // TODO: need a way to find a leaf node of a spanning tree + + // OPTIMIZE: Need a set data structure for efficiently removing elements + vector basics; while (!basics.empty()) { - return; + // Find a leaf node of a spanning tree + node target; + for (unsigned int i = 0; i < m_thread.size(); ++i) { + if (m_depth[i] <= m_depth[m_thread[i]]) { + target = i; + break; + } + } + node source = m_pred[target]; + edge_id e_id; + if (m_graph.get_edge_id(source, target, e_id)) { + m_flows.set(e_id, -m_graph.get_weight(basics[target])); + basics[source] += basics[target]; + basics.erase(e_id); + } + else if (m_graph.get_edge_id(target, source, e_id)) { + m_flows.set(e_id, m_graph.get_weight(basics[target])); + basics[source] += basics[target]; + basics.erase(e_id); + } } } template - bool network_flow::is_optimal(edge & violating_edge) { - typename vector::iterator it = m_nonbasics.begin(); - typename vector::iterator end = m_nonbasics.end(); + bool network_flow::is_optimal(edge_id & violating_edge) { + // TODO: how to get nonbasics vector? + vector nonbasics; + typename vector::iterator it = nonbasics.begin(); + typename vector::iterator end = nonbasics.end(); bool found = false; - for (unsigned int i = 0; i < m_nonbasics.size(); ++i) { - edge & e = m_nonbasics[i]; + for (unsigned int i = 0; i < nonbasics.size(); ++i) { + edge & e = nonbasics[i]; if (e.is_enabled()) { node source = e.get_source(); node target = e.get_target(); numeral cost = e.get_weight() - m_potentials[source] + m_potentials[target]; // Choose the first negative-cost edge to be the violating edge // TODO: add multiple pivoting strategies - if (cost < 0) { - violating_edge = e; + numeral zero(0); + if (cost < zero) { + edge_id e_id; + m_graph.get_edge_id(source, target, e_id); + violating_edge = e_id; found = true; break; } @@ -93,9 +119,9 @@ namespace smt { } template - dl_edge::GExt> network_flow::choose_leaving_edge(const edge & entering_edge) { - node source = entering_edge.get_source(); - node target = entering_edge.get_target(); + edge_id network_flow::choose_leaving_edge(edge_id entering_edge) { + node source = m_graph.get_source(entering_edge); + node target = m_graph.get_target(entering_edge); while (source != target) { if (m_depth[source] > m_depth[target]) source = m_pred[source]; @@ -106,14 +132,28 @@ namespace smt { target = m_pred[target]; } } - edge e; - m_graph.get_edge(source, target, e); - return e; + edge_id e_id; + m_graph.get_edge_id(source, target, e_id); + return e_id; } template - void network_flow::update_basics(const edge & entering_edge, const edge & leaving_edge) { - + void network_flow::update_spanning_tree(edge_id entering_edge, edge_id leaving_edge) { + // Need special handling in case two edges are identical + SASSERT(entering_edge != leaving_edge); + + // Update potentials + node target = m_upwards[leaving_edge] ? m_graph.get_source(leaving_edge) : m_graph.get_target(leaving_edge); + numeral src_pot = m_potentials[m_graph.get_source(entering_edge)]; + numeral tgt_pot = m_potentials[m_graph.get_target(entering_edge)]; + numeral weight = m_graph.get_weight(entering_edge); + numeral change = m_upwards[entering_edge] ? (weight - src_pot + tgt_pot) : (-weight + src_pot - tgt_pot); + m_potentials[target] += change; + node start = m_thread[target]; + while (m_depth[start] > m_depth[target]) { + m_potentials[start] += change; + start = m_thread[start]; + } } template @@ -124,24 +164,34 @@ namespace smt { // Get the optimal solution template void network_flow::get_optimal_solution(numeral & objective, vector & flows) { + SASSERT(m_is_optimal); flows.reset(); flows.append(m_flows); - // TODO: calculate objective value + numeral cost(0); + for (unsigned int i = 0; i < m_flows.size(); ++i) { + // FIXME: this * operator is not supported + //cost += m_costs[i] * m_flows[i]; + } + objective = cost; } // Minimize cost flows // Return true if found an optimal solution, and return false if unbounded template bool network_flow::min_cost() { + SASSERT(!m_graph.get_all_edges().empty()); initialize(); - edge & entering_edge; + edge_id entering_edge; while (!is_optimal(entering_edge)) { - edge & leaving_edge = choose_leaving_edge(); - update_tree(entering_edge, leaving_edge); - if (is_unbounded()) - return false; + edge_id leaving_edge = choose_leaving_edge(entering_edge); + update_spanning_tree(entering_edge, leaving_edge); + if (is_unbounded()) { + m_is_optimal = false; + return m_is_optimal; + } } - return true; + m_is_optimal = true; + return m_is_optimal; } } diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h index 9447b0d3e..3af150e64 100644 --- a/src/smt/theory_diff_logic.h +++ b/src/smt/theory_diff_logic.h @@ -307,14 +307,13 @@ namespace smt { virtual bool maximize(theory_var v); virtual theory_var add_objective(app* term); virtual inf_eps_rational get_objective_value(theory_var v); + numeral m_objective_value; typedef vector > objective_term; vector m_objectives; void internalize_objective(app * n, objective_term & objective); - network_flow m_network_flow; - private: virtual void new_eq_eh(theory_var v1, theory_var v2, justification& j); diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index 684850d77..841375253 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -1005,7 +1005,37 @@ bool theory_diff_logic::maximize(theory_var v) { } verbose_stream() << "\n";); NOT_IMPLEMENTED_YET(); - return false; + // Double the number of edges in the new graph + dl_graph g; + vector> es = m_graph.get_all_edges(); + dl_var offset = m_graph.get_num_edges(); + for (unsigned i = 0; i < es.size(); ++i) { + dl_edge e(es[i]); + g.enable_edge(g.add_edge(e)); + g.enable_edge(g.add_edge(e.get_target() + offset, e.get_source() + offset, e.get_weight(), e.get_explanation())); + } + + // Objective coefficients now become costs + vector base_costs, aux_costs; + for (unsigned i = 0; i < m_objectives[v].size(); ++i) { + numeral cost(m_objectives[v][i].second); + base_costs.push_back(cost); + aux_costs.push_back(-cost); + } + vector costs; + costs.append(base_costs); + costs.append(aux_costs); + + network_flow net_flow(g, costs); + bool is_optimal = net_flow.min_cost(); + if (is_optimal) { + numeral objective_value; + vector flows; + net_flow.get_optimal_solution(objective_value, flows); + m_objective_value = objective_value.get_rational(); + // TODO: return the model of the optimal solution + } + return is_optimal; } template @@ -1018,6 +1048,7 @@ theory_var theory_diff_logic::add_objective(app* term) { template inf_eps_rational theory_diff_logic::get_objective_value(theory_var v) { + NOT_IMPLEMENTED_YET(); inf_rational objective; inf_eps_rational val(objective); return val; From 3d943bf70dc40ed8e02f185ace60c53c8dcfecc6 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Sat, 26 Oct 2013 05:22:52 +0200 Subject: [PATCH 037/925] Fix a mistake in previous commit causing imcompilable code Also correct my alias --- src/smt/theory_diff_logic_def.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index 841375253..41fbf7566 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -1010,8 +1010,8 @@ bool theory_diff_logic::maximize(theory_var v) { vector> es = m_graph.get_all_edges(); dl_var offset = m_graph.get_num_edges(); for (unsigned i = 0; i < es.size(); ++i) { - dl_edge e(es[i]); - g.enable_edge(g.add_edge(e)); + dl_edge & e = es[i]; + g.enable_edge(g.add_edge(e.get_source(), e.get_target(), e.get_weight(), e.get_explanation())); g.enable_edge(g.add_edge(e.get_target() + offset, e.get_source() + offset, e.get_weight(), e.get_explanation())); } From 3852b3a75397675a84c0103a9e88746465c26f3a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 26 Oct 2013 15:03:39 +0800 Subject: [PATCH 038/925] working on internalizer Signed-off-by: Nikolaj Bjorner --- src/smt/theory_diff_logic.h | 1 + src/smt/theory_diff_logic_def.h | 53 ++++++++++++++++++--------------- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h index 9447b0d3e..ab47b9423 100644 --- a/src/smt/theory_diff_logic.h +++ b/src/smt/theory_diff_logic.h @@ -310,6 +310,7 @@ namespace smt { typedef vector > objective_term; vector m_objectives; + vector m_objective_vars; void internalize_objective(app * n, objective_term & objective); diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index 684850d77..f392ac423 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -55,6 +55,8 @@ std::ostream& theory_diff_logic::atom::display(theory_diff_logic const& th, template void theory_diff_logic::nc_functor::reset() { m_antecedents.reset(); + m_objectives.reset(); + m_objective_vars.reset(); } @@ -999,11 +1001,11 @@ void theory_diff_logic::get_implied_bound_antecedents(edge_id bridge_edge, template bool theory_diff_logic::maximize(theory_var v) { IF_VERBOSE(1, - objective_term objective = m_objectives[v]; - for (unsigned i = 0; i < objective.size(); ++i) { - verbose_stream() << "coefficient " << objective[i].second << " of theory_var " << objective[i].first << "\n"; - } - verbose_stream() << "\n";); + objective_term const& objective = m_objectives[v]; + for (unsigned i = 0; i < objective.size(); ++i) { + verbose_stream() << "coefficient " << objective[i].second << " of theory_var " << objective[i].first << "\n"; + } + verbose_stream() << m_objective_vars[v] << "\n";); NOT_IMPLEMENTED_YET(); return false; } @@ -1011,39 +1013,38 @@ bool theory_diff_logic::maximize(theory_var v) { template theory_var theory_diff_logic::add_objective(app* term) { objective_term objective; - internalize_objective(term, objective); - m_objectives.push_back(objective); - return m_objectives.size()-1; + theory_var result = m_objectives.size(); + rational q(1), r(0); + if (!internalize_objective(term, q, r, objective)) { + result = null_theory_var; + } + else { + m_objectives.push_back(objective); + m_objective_vars.push_back(r); + } + return result; } template inf_eps_rational theory_diff_logic::get_objective_value(theory_var v) { - inf_rational objective; + inf_rational objective; inf_eps_rational val(objective); return val; } template -void theory_diff_logic::internalize_objective(app * n, objective_term & objective) { - // TODO: Need some simplification on n to ensure no bad case - SASSERT(!m_util.is_div(n)); - SASSERT(!m_util.is_idiv(n)); - SASSERT(!m_util.is_mod(n)); - SASSERT(!m_util.is_rem(n)); - SASSERT(!m_util.is_to_real(n)); - SASSERT(!m_util.is_to_int(n)); - SASSERT(!m_util.is_power(n)); - SASSERT(!m_util.is_irrational_algebraic_numeral(n)); +bool theory_diff_logic::internalize_objective(app * n, rational& q, objective_term & objective) { // Compile term into objective_term format rational r; if (m_util.is_numeral(n, r)) { - theory_var v = mk_num(n, r); - objective.push_back(std::make_pair(v, r)); + q += r; } else if (m_util.is_add(n)) { for (unsigned i = 0; i < n->get_num_args(); ++i) { - internalize_objective(to_app(n->get_arg(i)), objective); + if (!internalize_objective(to_app(n->get_arg(i)), objective)) { + return false; + } }; } else if (m_util.is_mul(n)) { @@ -1054,17 +1055,21 @@ void theory_diff_logic::internalize_objective(app * n, objective_term & obj SASSERT(m_util.is_numeral(lhs, r) || m_util.is_numeral(rhs, r)); if (!m_util.is_numeral(lhs, r)) - std::swap(lhs, rhs); - + std::swap(lhs, rhs); + m_util.is_numeral(lhs, r); theory_var v = mk_var(rhs); objective.push_back(std::make_pair(v, r)); } + else if (n->get_family_id() == m_util.get_family_id()) { + return false; + } else { theory_var v = mk_var(n); rational r(1); objective.push_back(std::make_pair(v, r)); } + return true; } #endif /* _THEORY_DIFF_LOGIC_DEF_H_ */ From 72c3473400b94866f4fa34529f54d0be7eb50f9f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 26 Oct 2013 20:48:19 +0800 Subject: [PATCH 039/925] cleanup Signed-off-by: Nikolaj Bjorner --- src/smt/network_flow_def.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index 464747141..7f6add1eb 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -166,12 +166,10 @@ namespace smt { SASSERT(m_is_optimal); flows.reset(); flows.append(m_flows); - numeral cost(0); + objective = numeral::zero(); for (unsigned int i = 0; i < m_flows.size(); ++i) { - // FIXME: this * operator is not supported - cost += m_costs[i] * m_flows[i]; + objective += m_costs[i] * m_flows[i]; } - objective = cost; } // Minimize cost flows From d78d22deb60ab2c32d8b22e628df2504db568247 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 28 Oct 2013 17:13:23 -0700 Subject: [PATCH 040/925] working on weighted max smt Signed-off-by: Nikolaj Bjorner --- src/opt/weighted_maxsat.cpp | 79 +++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 832793e32..a97c237e2 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -17,8 +17,87 @@ Notes: --*/ #include "weighted_maxsat.h" +#include "smt_theory.h" +#include "smt_context.h" namespace opt { + + class theory_weighted_maxsat : public smt::theory { + vector m_weights; // weights of theory variables. + svector m_costs; // set of asserted theory variables + rational m_cost; // current sum of asserted costs + rational m_min_cost; // current minimal cost assignment. + svector m_assignment; // current best assignment. + public: + theory_weighted_maxsat(ast_manager& m): + theory(m.get_family_id("weighted_maxsat")) + {} + + void assert_weighted(expr* fml, rational const& w) { + smt::bool_var v = smt::null_theory_var; + // internalize fml + // assert weighted clause. v \/ fml + // + m_weights.push_back(w); + m_min_cost += w; + } + + virtual void assign_eh(smt::bool_var v, bool is_true) { + smt::context& ctx = get_context(); + if (is_true) { + rational const& w = m_weights[v]; + ctx.push_trail(value_trail(m_cost)); + // TBD: ctx.push_trail(...trail.pop_back(m_costly)); + m_cost += w; + m_costs.push_back(v); + if (m_cost > m_min_cost) { + block(); + } + } + } + + virtual smt::final_check_status final_check_eh() { + if (m_cost < m_min_cost) { + m_min_cost = m_cost; + m_assignment.reset(); + m_assignment.append(m_costs); + } + block(); + return smt::FC_DONE; + } + + private: + + class compare_cost { + theory_weighted_maxsat& m_th; + public: + compare_cost(theory_weighted_maxsat& t):m_th(t) {} + bool operator() (smt::theory_var v, smt::theory_var w) const { + return m_th.m_weights[v] < m_th.m_weights[w]; + } + }; + + void block() { + ast_manager& m = get_manager(); + smt::context& ctx = get_context(); + smt::literal_vector lits; + compare_cost compare_cost(*this); + std::sort(m_costs.begin(), m_costs.end(), compare_cost); + rational weight(0); + for (unsigned i = 0; i < m_costs.size() && + weight < m_min_cost; ++i) { + weight += m_weights[m_costs[i]]; + lits.push_back(~smt::literal(m_costs[i])); + } + smt::justification * js = 0; + if (m.proofs_enabled()) { + js = new (ctx.get_region()) + smt::theory_lemma_justification(get_id(), ctx, lits.size(), lits.c_ptr()); + } + ctx.mk_clause(lits.size(), lits.c_ptr(), js, smt::CLS_AUX_LEMMA, 0); + } + }; + /** Takes solver with hard constraints added. Returns a maximal satisfying subset of weighted soft_constraints From 906bbb4eeb95a3a48c3d852298900b7c7dd4aba2 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Mon, 28 Oct 2013 18:29:14 -0700 Subject: [PATCH 041/925] Update Network Simplex implementation --- src/muz/rel/dl_interval_relation.cpp | 2 +- src/smt/network_flow.h | 50 +++-- src/smt/network_flow_def.h | 276 +++++++++++++++------------ src/smt/theory_diff_logic_def.h | 24 +-- 4 files changed, 200 insertions(+), 152 deletions(-) diff --git a/src/muz/rel/dl_interval_relation.cpp b/src/muz/rel/dl_interval_relation.cpp index c04269b02..88c262cbe 100644 --- a/src/muz/rel/dl_interval_relation.cpp +++ b/src/muz/rel/dl_interval_relation.cpp @@ -598,7 +598,7 @@ namespace datalog { // 0 <= y - x - k - 1 if (is_le(to_app(cond->get_arg(0)), x, k, y, is_int) && is_int) { k.neg(); - k -= rational::one(); + k -= rational::one(); std::swap(x, y); return true; } diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index 81f9aff1f..37afda136 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -38,6 +38,10 @@ namespace smt { // Solve minimum cost flow problem using Network Simplex algorithm template class network_flow : private Ext { + enum edge_state { + NON_BASIS = 0, + BASIS = 1 + }; typedef dl_var node; typedef dl_edge edge; typedef dl_graph graph; @@ -46,56 +50,66 @@ namespace smt { graph m_graph; // Denote supply/demand b_i on node i - vector m_balances; + vector m_balances; // Duals of flows which are convenient to compute dual solutions vector m_potentials; // Keep optimal solution of the min cost flow problem - inf_int_rational m_objective; + numeral m_objective_value; // Costs on edges - vector const & m_costs; + vector m_costs; // Basic feasible flows vector m_flows; + + svector m_states; // An element is true if the corresponding edge points upwards (compared to the root node) svector m_upwards; - // Store the parent of a node in the spanning tree + // Store the parent of a node i in the spanning tree svector m_pred; - // Store the number of edge on the path to the root + // Store the number of edge on the path from node i to the root svector m_depth; - // Store the pointer to the next node in depth first search ordering + // Store the pointer from node i to the next node in depth first search ordering svector m_thread; + // Reverse orders of m_thread + svector m_rev_thread; + // Store a final node of the sub tree rooted at node i + svector m_final; + // Number of nodes in the sub tree rooted at node i + svector m_num_node; - bool m_is_optimal; + edge_id m_entering_edge; + edge_id m_leaving_edge; + node m_join_node; + numeral m_delta; public: - network_flow(graph & g, vector const & costs); + network_flow(graph & g, vector const & balances); // Initialize the network with a feasible spanning tree void initialize(); - void compute_potentials(); + void update_potentials(); - void compute_flows(); + void update_flows(); - // If all reduced costs are non-negative, the current flow is optimal - // If not optimal, return a violating edge in the corresponding variable - bool is_optimal(edge_id & violating_edge); + // If all reduced costs are non-negative, return false since the current spanning tree is optimal + // Otherwise return true and update m_entering_edge + bool choose_entering_edge(); // Send as much flow as possible around the cycle, the first basic edge with flow 0 will leave - edge_id choose_leaving_edge(edge_id entering_edge); + // Return false if the problem is unbounded + bool choose_leaving_edge(); - void update_spanning_tree(edge_id entering_edge, edge_id leaving_edge); + void update_spanning_tree(); - bool is_unbounded(); - // Compute the optimal solution - void get_optimal_solution(numeral & objective, vector & flows); + numeral get_optimal_solution(vector & result, bool is_dual); // Minimize cost flows // Return true if found an optimal solution, and return false if unbounded diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index 7f6add1eb..f39042bac 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -25,170 +25,212 @@ Notes: namespace smt { template - network_flow::network_flow(graph & g, vector const& costs) : + network_flow::network_flow(graph & g, vector const& balances) : m_graph(g), - m_costs(costs) { + m_balances(balances) { + unsigned num_nodes = m_balances.size() + 1; + unsigned num_edges = m_graph.get_num_edges(); + + vector const & es = m_graph.get_all_edges(); + for (unsigned i = 0; i < num_edges; ++i) { + fin_numeral cost(es[i].get_weight().get_rational()); + m_costs.push_back(cost); + } + + m_balances.resize(num_nodes); + for (unsigned i = 0; i < balances.size(); ++i) { + m_costs.push_back(balances[i]); + } + + m_potentials.resize(num_nodes); + m_costs.resize(num_edges); + m_flows.resize(num_edges); + m_states.resize(num_edges); + + m_upwards.resize(num_nodes); + m_pred.resize(num_nodes); + m_depth.resize(num_nodes); + m_thread.resize(num_nodes); + m_rev_thread.resize(num_nodes); + m_final.resize(num_nodes); + m_num_node.resize(num_nodes); } template void network_flow::initialize() { - // TODO: construct an initial spanning tree i.e. inializing m_pred, m_depth and m_thread. - compute_potentials(); - compute_flows(); - } + // Create an artificial root node to construct initial spanning tree + unsigned num_nodes = m_balances.size(); + unsigned num_edges = m_graph.get_num_edges(); + node root = num_nodes; + m_pred[root] = -1; + m_thread[root] = 0; + m_rev_thread[0] = root; + m_num_node[root] = num_nodes + 1; + m_final[root] = root - 1; + m_potentials[root] = numeral::zero(); - template - void network_flow::compute_potentials() { - SASSERT(!m_potentials.empty()); - SASSERT(!m_thread.empty()); - SASSERT(m_thread.size() == m_pred.size()); - - m_potentials.set(0, numeral::zero()); - node target = m_thread[0]; - - while (target != 0) { - node source = m_pred[target]; - edge_id e_id; - if (m_graph.get_edge_id(source, target, e_id)) { - m_potentials.set(target, m_potentials[source] - m_graph.get_weight(e_id)); - } - if (m_graph.get_edge_id(target, source, e_id)) { - m_potentials.set(target, m_potentials[source] + m_graph.get_weight(e_id)); - } - target = m_thread[target]; + fin_numeral sum_supply = fin_numeral::zero(); + for (unsigned i = 0; i < m_balances.size(); ++i) { + sum_supply += m_balances[i]; + } + m_balances[root] = -sum_supply; + + m_states.resize(num_nodes + num_edges); + m_states.fill(NON_BASIS); + + // Create artificial edges and initialize the spanning tree + for (unsigned i = 0; i < num_nodes; ++i) { + m_upwards[i] = m_balances[i] >= fin_numeral::zero(); + m_pred[i] = root; + m_depth[i] = 1; + m_thread[i] = i + 1; + m_final[i] = i; + m_rev_thread[i] = (i = 0) ? root : i - 1; + m_num_node[i] = 1; + m_states[num_edges + i] = BASIS; } } template - void network_flow::compute_flows() { - vector balances(m_balances); - - // OPTIMIZE: Need a set data structure for efficiently removing elements - vector basics; - while (!basics.empty()) { - // Find a leaf node of a spanning tree - node target; - for (unsigned int i = 0; i < m_thread.size(); ++i) { - if (m_depth[i] <= m_depth[m_thread[i]]) { - target = i; - break; - } - } - node source = m_pred[target]; + void network_flow::update_potentials() { + node src = m_graph.get_source(m_entering_edge); + node tgt = m_graph.get_source(m_entering_edge); + numeral cost = m_graph.get_weight(m_entering_edge); + numeral change = m_upwards[src] ? (cost - m_potentials[src] + m_potentials[tgt]) : + (-cost + m_potentials[src] - m_potentials[tgt]); + node last = m_thread[m_final[src]]; + for (node u = src; u != last; u = m_thread[u]) { + m_potentials[u] += change; + } + } + + template + void network_flow::update_flows() { + numeral val = m_state[m_entering_edge] == NON_BASIS ? numeral::zero() : m_delta; + m_flows[m_entering_edge] += val; + for (unsigned u = m_graph.get_source(m_entering_edge); u != m_join_node; u = m_pred[u]) { edge_id e_id; - if (m_graph.get_edge_id(source, target, e_id)) { - m_flows.set(e_id, -m_graph.get_weight(basics[target])); - basics[source] += basics[target]; - basics.erase(e_id); - } - else if (m_graph.get_edge_id(target, source, e_id)) { - m_flows.set(e_id, m_graph.get_weight(basics[target])); - basics[source] += basics[target]; - basics.erase(e_id); - } + m_graph.get_edge_id(u, m_pred[u], e_id); + m_flows[e_id] += m_upwards[u] ? -val : val; + } + for (unsigned u = m_graph.get_target(m_entering_edge); u != m_join_node; u = m_pred[u]) { + edge_id e_id; + m_graph.get_edge_id(u, m_pred[u], e_id); + m_flows[e_id] += m_upwards[u] ? val : -val; } } template - bool network_flow::is_optimal(edge_id & violating_edge) { - // TODO: how to get nonbasics vector? - vector nonbasics; - typename vector::iterator it = nonbasics.begin(); - typename vector::iterator end = nonbasics.end(); - bool found = false; - for (unsigned int i = 0; i < nonbasics.size(); ++i) { - edge & e = nonbasics[i]; - if (e.is_enabled()) { + bool network_flow::choose_entering_edge() { + vector const & es = m_graph.get_all_edges(); + for (unsigned int i = 0; i < es.size(); ++i) { + edge const & e = es[i]; + edge_id e_id; + if (e.is_enabled() && m_graph.get_edge_id(e.get_source(), e.get_target(), e_id) && m_states[e_id] == BASIS) { node source = e.get_source(); node target = e.get_target(); numeral cost = e.get_weight() - m_potentials[source] + m_potentials[target]; // Choose the first negative-cost edge to be the violating edge // TODO: add multiple pivoting strategies - numeral zero(0); - if (cost < zero) { - edge_id e_id; - m_graph.get_edge_id(source, target, e_id); - violating_edge = e_id; - found = true; - break; + if (cost < numeral::zero()) { + m_entering_edge = e_id; + return true; } } } - return !found; + return false; } template - edge_id network_flow::choose_leaving_edge(edge_id entering_edge) { - node source = m_graph.get_source(entering_edge); - node target = m_graph.get_target(entering_edge); - while (source != target) { - if (m_depth[source] > m_depth[target]) - source = m_pred[source]; - else if (m_depth[source] < m_depth[target]) - target = m_pred[target]; + bool network_flow::choose_leaving_edge() { + node source = m_graph.get_source(m_entering_edge); + node target = m_graph.get_target(m_entering_edge); + node u = source, v = target; + while (u != v) { + if (m_depth[u] > m_depth[v]) + u = m_pred[u]; + else if (m_depth[u] < m_depth[v]) + v = m_pred[v]; else { - source = m_pred[source]; - target = m_pred[target]; + u = m_pred[u]; + v = m_pred[v]; } } - edge_id e_id; - m_graph.get_edge_id(source, target, e_id); - return e_id; - } - - template - void network_flow::update_spanning_tree(edge_id entering_edge, edge_id leaving_edge) { - // Need special handling in case two edges are identical - SASSERT(entering_edge != leaving_edge); - - // Update potentials - node target = m_upwards[leaving_edge] ? m_graph.get_source(leaving_edge) : m_graph.get_target(leaving_edge); - numeral src_pot = m_potentials[m_graph.get_source(entering_edge)]; - numeral tgt_pot = m_potentials[m_graph.get_target(entering_edge)]; - numeral weight = m_graph.get_weight(entering_edge); - numeral change = m_upwards[entering_edge] ? (weight - src_pot + tgt_pot) : (-weight + src_pot - tgt_pot); - m_potentials[target] += change; - node start = m_thread[target]; - while (m_depth[start] > m_depth[target]) { - m_potentials[start] += change; - start = m_thread[start]; + // Found first common ancestor of source and target + m_join_node = u; + // FIXME: need to get truly finite value + numeral infty = numeral(INT_MAX); + m_delta = infty; + node src, tgt; + // Send flows along the path from source to the ancestor + for (unsigned u = source; u != m_join_node; u = m_pred[u]) { + edge_id e_id; + m_graph.get_edge_id(u, m_pred[u], e_id); + numeral d = m_upwards[u] ? m_flows[e_id] : infty; + if (d < m_delta) { + m_delta = d; + src = u; + tgt = m_pred[u]; + } } + + // Send flows along the path from target to the ancestor + for (unsigned u = target; u != m_join_node; u = m_pred[u]) { + edge_id e_id; + m_graph.get_edge_id(u, m_pred[u], e_id); + numeral d = m_upwards[u] ? infty : m_flows[e_id]; + if (d <= m_delta) { + m_delta = d; + src = u; + tgt = m_pred[u]; + } + } + + if (m_delta < infty) { + m_graph.get_edge_id(src, tgt, m_leaving_edge); + return true; + } + return false; } template - bool network_flow::is_unbounded() { - return false; + void network_flow::update_spanning_tree() { + } // Get the optimal solution template - void network_flow::get_optimal_solution(numeral & objective, vector & flows) { - SASSERT(m_is_optimal); - flows.reset(); - flows.append(m_flows); - objective = numeral::zero(); - for (unsigned int i = 0; i < m_flows.size(); ++i) { - objective += m_costs[i] * m_flows[i]; + typename network_flow::numeral network_flow::get_optimal_solution(vector & result, bool is_dual) { + m_objective_value = numeral::zero(); + for (unsigned i = 0; i < m_flows.size(); ++i) { + m_objective_value += m_costs[i] * m_flows[i]; } + result.reset(); + if (is_dual) { + result.append(m_potentials); + } + else { + result.append(m_flows); + } + return m_objective_value; } // Minimize cost flows // Return true if found an optimal solution, and return false if unbounded template bool network_flow::min_cost() { - SASSERT(!m_graph.get_all_edges().empty()); initialize(); - edge_id entering_edge; - while (!is_optimal(entering_edge)) { - edge_id leaving_edge = choose_leaving_edge(entering_edge); - update_spanning_tree(entering_edge, leaving_edge); - if (is_unbounded()) { - m_is_optimal = false; - return m_is_optimal; + while (choose_entering_edge()) { + bool bounded = choose_leaving_edge(); + if (!bounded) return false; + if (m_entering_edge != m_leaving_edge) { + m_states[m_entering_edge] = BASIS; + m_states[m_leaving_edge] = NON_BASIS; + update_spanning_tree(); + update_potentials(); } } - m_is_optimal = true; - return m_is_optimal; + return true; } } diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index 478b80964..9fa97097f 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -1016,34 +1016,26 @@ bool theory_diff_logic::maximize(theory_var v) { // m_graph as well. dl_graph g; vector > const& es = m_graph.get_all_edges(); - dl_var offset = m_graph.get_num_edges(); for (unsigned i = 0; i < es.size(); ++i) { dl_edge const & e = es[i]; if (e.is_enabled()) { g.enable_edge(g.add_edge(e.get_source(), e.get_target(), e.get_weight(), e.get_explanation())); - g.enable_edge(g.add_edge(e.get_target() + offset, e.get_source() + offset, e.get_weight(), e.get_explanation())); } } - // Objective coefficients now become costs - vector base_costs, aux_costs; + // Objective coefficients now become balances + vector balances; for (unsigned i = 0; i < objective.size(); ++i) { - fin_numeral cost(objective[i].second); - base_costs.push_back(cost); - aux_costs.push_back(-cost); + fin_numeral balance(objective[i].second); + balances.push_back(balance); } - vector costs; - costs.append(base_costs); - costs.append(aux_costs); - network_flow net_flow(g, costs); + network_flow net_flow(g, balances); bool is_optimal = net_flow.min_cost(); if (is_optimal) { - numeral objective_value; - vector flows; - net_flow.get_optimal_solution(objective_value, flows); - m_objective_value = objective_value.get_rational(); - // TODO: return the model of the optimal solution + vector potentials; + m_objective_value = net_flow.get_optimal_solution(potentials, true); + // TODO: return the model of the optimal solution from potential } return is_optimal; } From d30f183476b538b813b7dd13edcde59ca3c591a6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 28 Oct 2013 21:30:57 -0700 Subject: [PATCH 042/925] working on weighted maxsat Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 16 +++-- src/opt/opt_context.h | 4 ++ src/opt/opt_solver.h | 3 + src/opt/weighted_maxsat.cpp | 118 +++++++++++++++++++++++++++--------- src/opt/weighted_maxsat.h | 4 +- 5 files changed, 109 insertions(+), 36 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 754b2adb2..2c4e22492 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -59,14 +59,15 @@ namespace opt { is_sat = opt::fu_malik_maxsat(*s, fmls_copy); } else { - is_sat = weighted_maxsat(*s, fmls_copy, m_weights); + is_sat = weighted_maxsat(get_opt_solver(*s), fmls_copy, m_weights); } std::cout << "is-sat: " << is_sat << "\n"; if (is_sat != l_true) { return; } + std::cout << "Satisfying soft constraints\n"; for (unsigned i = 0; i < fmls_copy.size(); ++i) { - std::cout << "Satisfying soft constraint: " << mk_pp(fmls_copy[i].get(), m) << "\n"; + std::cout << mk_pp(fmls_copy[i].get(), m) << "\n"; } } @@ -75,9 +76,7 @@ namespace opt { for (unsigned i = 0; i < fmls_copy.size(); ++i) { s->assert_expr(fmls_copy[i].get()); } - // SASSERT(instanceof(*s, opt_solver)); - // if (!instsanceof ...) { throw ... invalid usage ..} - is_sat = optimize_objectives(dynamic_cast(*s), m_objectives, values); + is_sat = optimize_objectives(get_opt_solver(*s), m_objectives, values); std::cout << "is-sat: " << is_sat << std::endl; if (is_sat != l_true) { @@ -108,6 +107,13 @@ namespace opt { return true; } + opt_solver& context::get_opt_solver(solver& s) { + if (typeid(opt_solver) != typeid(s)) { + throw default_exception("BUG: optimization context has not been initialized correctly"); + } + return dynamic_cast(s); + } + void context::cancel() { if (m_solver) { m_solver->cancel(); diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index a388bc952..866bdf7d3 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -30,6 +30,8 @@ Notes: namespace opt { + class opt_solver; + class context { ast_manager& m; expr_ref_vector m_hard_constraints; @@ -70,6 +72,8 @@ namespace opt { private: bool is_maxsat_problem() const; + opt_solver& get_opt_solver(solver& s); + }; } diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index ce07233e3..a9f8da3b0 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -78,6 +78,9 @@ namespace opt { toggle_objective(opt_solver& s, bool new_value); ~toggle_objective(); }; + + smt::context& get_context() { return m_context.get_context(); } // used by weighted maxsat. + private: smt::theory_opt& get_optimizer(); }; diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index a97c237e2..6ec5c4ead 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -20,34 +20,59 @@ Notes: #include "smt_theory.h" #include "smt_context.h" -namespace opt { +namespace smt { - class theory_weighted_maxsat : public smt::theory { + class theory_weighted_maxsat : public theory { + expr_ref_vector m_vars; + expr_ref_vector m_fmls; vector m_weights; // weights of theory variables. - svector m_costs; // set of asserted theory variables + svector m_costs; // set of asserted theory variables rational m_cost; // current sum of asserted costs rational m_min_cost; // current minimal cost assignment. - svector m_assignment; // current best assignment. + svector m_assignment; // current best assignment. public: theory_weighted_maxsat(ast_manager& m): - theory(m.get_family_id("weighted_maxsat")) + theory(m.get_family_id("weighted_maxsat")), + m_vars(m), + m_fmls(m) {} + void get_assignment(expr_ref_vector& result) { + result.reset(); + for (unsigned i = 0; i < m_assignment.size(); ++i) { + result.push_back(m_fmls[m_assignment[i]].get()); + } + } + void assert_weighted(expr* fml, rational const& w) { - smt::bool_var v = smt::null_theory_var; - // internalize fml - // assert weighted clause. v \/ fml - // + context & ctx = get_context(); + ast_manager& m = get_manager(); + expr_ref var(m); + var = m.mk_fresh_const("w", m.mk_bool_sort()); + ctx.internalize(fml, false); // TBD: assume or require simplification? + ctx.internalize(var, false); + enode* x, *y; + x = ctx.get_enode(fml); + y = ctx.get_enode(var); + theory_var v = mk_var(y); + SASSERT(v == m_vars.size()); + SASSERT(v == m_weights.size()); + m_vars.push_back(var); + m_fmls.push_back(fml); + ctx.attach_th_var(y, this, v); + literal lx(ctx.get_bool_var(fml)); + literal ly(ctx.get_bool_var(var)); + ctx.mk_th_axiom(get_id(), lx, ly); m_weights.push_back(w); m_min_cost += w; } - virtual void assign_eh(smt::bool_var v, bool is_true) { - smt::context& ctx = get_context(); + virtual void assign_eh(bool_var v, bool is_true) { if (is_true) { + context& ctx = get_context(); rational const& w = m_weights[v]; - ctx.push_trail(value_trail(m_cost)); - // TBD: ctx.push_trail(...trail.pop_back(m_costly)); + ctx.push_trail(value_trail(m_cost)); + ctx.push_trail(push_back_vector >(m_costs)); m_cost += w; m_costs.push_back(v); if (m_cost > m_min_cost) { @@ -56,57 +81,92 @@ namespace opt { } } - virtual smt::final_check_status final_check_eh() { + virtual final_check_status final_check_eh() { if (m_cost < m_min_cost) { m_min_cost = m_cost; m_assignment.reset(); m_assignment.append(m_costs); } block(); - return smt::FC_DONE; + return FC_DONE; } + virtual void reset_eh() { + theory::reset_eh(); + m_vars.reset(); + m_weights.reset(); + m_costs.reset(); + m_cost.reset(); + m_min_cost.reset(); + m_assignment.reset(); + } + + virtual theory * mk_fresh(context * new_ctx) { UNREACHABLE(); return 0;} // TBD + virtual bool internalize_atom(app * atom, bool gate_ctx) { return false; } + virtual bool internalize_term(app * term) { return false; } + virtual void new_eq_eh(theory_var v1, theory_var v2) { UNREACHABLE(); } + virtual void new_diseq_eh(theory_var v1, theory_var v2) { UNREACHABLE(); } + + private: class compare_cost { theory_weighted_maxsat& m_th; public: compare_cost(theory_weighted_maxsat& t):m_th(t) {} - bool operator() (smt::theory_var v, smt::theory_var w) const { + bool operator() (theory_var v, theory_var w) const { return m_th.m_weights[v] < m_th.m_weights[w]; } }; void block() { ast_manager& m = get_manager(); - smt::context& ctx = get_context(); - smt::literal_vector lits; + context& ctx = get_context(); + literal_vector lits; compare_cost compare_cost(*this); - std::sort(m_costs.begin(), m_costs.end(), compare_cost); + svector costs(m_costs); + std::sort(costs.begin(), costs.end(), compare_cost); rational weight(0); - for (unsigned i = 0; i < m_costs.size() && - weight < m_min_cost; ++i) { - weight += m_weights[m_costs[i]]; - lits.push_back(~smt::literal(m_costs[i])); + for (unsigned i = 0; i < costs.size() && weight < m_min_cost; ++i) { + weight += m_weights[costs[i]]; + lits.push_back(~literal(costs[i])); } - smt::justification * js = 0; + justification * js = 0; if (m.proofs_enabled()) { js = new (ctx.get_region()) - smt::theory_lemma_justification(get_id(), ctx, lits.size(), lits.c_ptr()); + theory_lemma_justification(get_id(), ctx, lits.size(), lits.c_ptr()); } - ctx.mk_clause(lits.size(), lits.c_ptr(), js, smt::CLS_AUX_LEMMA, 0); + ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); } }; +} + +namespace opt { + + /** Takes solver with hard constraints added. Returns a maximal satisfying subset of weighted soft_constraints that are still consistent with the solver state. */ - lbool weighted_maxsat(solver& s, expr_ref_vector& soft_constraints, vector const& weights) { - NOT_IMPLEMENTED_YET(); - return l_false; + lbool weighted_maxsat(opt_solver& s, expr_ref_vector& soft_constraints, vector const& weights) { + ast_manager& m = soft_constraints.get_manager(); + smt::context& ctx = s.get_context(); + smt::theory_id th_id = m.get_family_id("weighted_maxsat"); + smt::theory* th = ctx.get_theory(th_id); + if (!th) { + th = alloc(smt::theory_weighted_maxsat, m); + ctx.register_plugin(th); + } + smt::theory_weighted_maxsat* wth = dynamic_cast(th); + for (unsigned i = 0; i < soft_constraints.size(); ++i) { + wth->assert_weighted(soft_constraints[i].get(), weights[i]); + } + lbool result = s.check_sat_core(0,0); + wth->get_assignment(soft_constraints); + return result; } }; diff --git a/src/opt/weighted_maxsat.h b/src/opt/weighted_maxsat.h index 542d0bafc..120609a8c 100644 --- a/src/opt/weighted_maxsat.h +++ b/src/opt/weighted_maxsat.h @@ -18,7 +18,7 @@ Notes: #ifndef _OPT_WEIGHTED_MAX_SAT_H_ #define _OPT_WEIGHTED_MAX_SAT_H_ -#include "solver.h" +#include "opt_solver.h" namespace opt { /** @@ -27,7 +27,7 @@ namespace opt { that are still consistent with the solver state. */ - lbool weighted_maxsat(solver& s, expr_ref_vector& soft_constraints, vector const& weights); + lbool weighted_maxsat(opt_solver& s, expr_ref_vector& soft_constraints, vector const& weights); }; #endif From 1878d64b02b0c977e0cff2fafb95e8afcd3441b9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 28 Oct 2013 21:32:41 -0700 Subject: [PATCH 043/925] working on weighted maxsat Signed-off-by: Nikolaj Bjorner --- src/opt/weighted_maxsat.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 6ec5c4ead..fc14a0b64 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -166,6 +166,9 @@ namespace opt { } lbool result = s.check_sat_core(0,0); wth->get_assignment(soft_constraints); + if (!soft_constraints.empty() && result == l_false) { + result = l_true; + } return result; } }; From 905f230b8fb2b6d249c324344efe6aac82924b6e Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Tue, 29 Oct 2013 14:20:29 -0700 Subject: [PATCH 044/925] Add pretty printing for network_flow Reuse the original graph as much as possible --- src/smt/diff_logic.h | 2 + src/smt/network_flow.h | 27 ++--- src/smt/network_flow_def.h | 203 ++++++++++++++++++++++++++------ src/smt/theory_diff_logic_def.h | 25 ++-- 4 files changed, 190 insertions(+), 67 deletions(-) diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index 71b638b9e..b96a038eb 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -281,6 +281,8 @@ public: unsigned get_num_edges() const { return m_edges.size(); } + unsigned get_num_nodes() const { return m_out_edges.size(); } + dl_var get_source(edge_id id) const { return m_edges[id].get_source(); } dl_var get_target(edge_id id) const { return m_edges[id].get_target(); } diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index 37afda136..b0539811e 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -47,7 +47,7 @@ namespace smt { typedef dl_graph graph; typedef typename Ext::numeral numeral; typedef typename Ext::fin_numeral fin_numeral; - graph m_graph; + graph & m_graph; // Denote supply/demand b_i on node i vector m_balances; @@ -57,10 +57,7 @@ namespace smt { // Keep optimal solution of the min cost flow problem numeral m_objective_value; - - // Costs on edges - vector m_costs; - + // Basic feasible flows vector m_flows; @@ -79,18 +76,12 @@ namespace smt { svector m_rev_thread; // Store a final node of the sub tree rooted at node i svector m_final; - // Number of nodes in the sub tree rooted at node i - svector m_num_node; edge_id m_entering_edge; edge_id m_leaving_edge; node m_join_node; numeral m_delta; - public: - - network_flow(graph & g, vector const & balances); - // Initialize the network with a feasible spanning tree void initialize(); @@ -107,13 +98,21 @@ namespace smt { bool choose_leaving_edge(); void update_spanning_tree(); - - // Compute the optimal solution - numeral get_optimal_solution(vector & result, bool is_dual); + std::string pp_vector(std::string const & label, svector v, bool has_header = false); + std::string pp_vector(std::string const & label, vector v, bool has_header = false); + + public: + + network_flow(graph & g, vector const & balances); + // Minimize cost flows // Return true if found an optimal solution, and return false if unbounded bool min_cost(); + + // Compute the optimal solution + numeral get_optimal_solution(vector & result, bool is_dual); + }; } diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index f39042bac..07548d2f6 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -25,25 +25,15 @@ Notes: namespace smt { template - network_flow::network_flow(graph & g, vector const& balances) : + network_flow::network_flow(graph & g, vector const & balances) : m_graph(g), m_balances(balances) { - unsigned num_nodes = m_balances.size() + 1; + unsigned num_nodes = m_graph.get_num_nodes() + 1; unsigned num_edges = m_graph.get_num_edges(); - vector const & es = m_graph.get_all_edges(); - for (unsigned i = 0; i < num_edges; ++i) { - fin_numeral cost(es[i].get_weight().get_rational()); - m_costs.push_back(cost); - } - m_balances.resize(num_nodes); - for (unsigned i = 0; i < balances.size(); ++i) { - m_costs.push_back(balances[i]); - } - m_potentials.resize(num_nodes); - m_costs.resize(num_edges); + m_potentials.resize(num_nodes); m_flows.resize(num_edges); m_states.resize(num_edges); @@ -53,19 +43,18 @@ namespace smt { m_thread.resize(num_nodes); m_rev_thread.resize(num_nodes); m_final.resize(num_nodes); - m_num_node.resize(num_nodes); } template void network_flow::initialize() { + TRACE("network_flow", tout << "initialize...\n";); // Create an artificial root node to construct initial spanning tree - unsigned num_nodes = m_balances.size(); + unsigned num_nodes = m_graph.get_num_nodes(); unsigned num_edges = m_graph.get_num_edges(); node root = num_nodes; m_pred[root] = -1; m_thread[root] = 0; m_rev_thread[0] = root; - m_num_node[root] = num_nodes + 1; m_final[root] = root - 1; m_potentials[root] = numeral::zero(); @@ -85,14 +74,17 @@ namespace smt { m_depth[i] = 1; m_thread[i] = i + 1; m_final[i] = i; - m_rev_thread[i] = (i = 0) ? root : i - 1; - m_num_node[i] = 1; + m_rev_thread[i] = (i == 0) ? root : i - 1; m_states[num_edges + i] = BASIS; } + + TRACE("network_flow", tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Threads", m_thread) + << pp_vector("Reverse Threads", m_rev_thread) << pp_vector("Last Successors", m_final) << pp_vector("Depths", m_depth);); } template void network_flow::update_potentials() { + TRACE("network_flow", tout << "update_potentials...\n";); node src = m_graph.get_source(m_entering_edge); node tgt = m_graph.get_source(m_entering_edge); numeral cost = m_graph.get_weight(m_entering_edge); @@ -102,31 +94,37 @@ namespace smt { for (node u = src; u != last; u = m_thread[u]) { m_potentials[u] += change; } + TRACE("network_flow", tout << pp_vector("Potentials", m_potentials, true);); } template void network_flow::update_flows() { + TRACE("network_flow", tout << "update_flows...\n";); numeral val = m_state[m_entering_edge] == NON_BASIS ? numeral::zero() : m_delta; m_flows[m_entering_edge] += val; - for (unsigned u = m_graph.get_source(m_entering_edge); u != m_join_node; u = m_pred[u]) { + node source = m_graph.get_source(m_entering_edge); + for (unsigned u = source; u != m_join_node; u = m_pred[u]) { edge_id e_id; m_graph.get_edge_id(u, m_pred[u], e_id); m_flows[e_id] += m_upwards[u] ? -val : val; } - for (unsigned u = m_graph.get_target(m_entering_edge); u != m_join_node; u = m_pred[u]) { + node target = m_graph.get_target(m_entering_edge); + for (unsigned u = target; u != m_join_node; u = m_pred[u]) { edge_id e_id; m_graph.get_edge_id(u, m_pred[u], e_id); m_flows[e_id] += m_upwards[u] ? val : -val; } + TRACE("network_flow", tout << pp_vector("Flows", m_flows, true);); } template bool network_flow::choose_entering_edge() { + TRACE("network_flow", tout << "choose_entering_edge...\n";); vector const & es = m_graph.get_all_edges(); for (unsigned int i = 0; i < es.size(); ++i) { edge const & e = es[i]; edge_id e_id; - if (e.is_enabled() && m_graph.get_edge_id(e.get_source(), e.get_target(), e_id) && m_states[e_id] == BASIS) { + if (e.is_enabled() && m_graph.get_edge_id(e.get_source(), e.get_target(), e_id) && m_states[e_id] == NON_BASIS) { node source = e.get_source(); node target = e.get_target(); numeral cost = e.get_weight() - m_potentials[source] + m_potentials[target]; @@ -134,15 +132,18 @@ namespace smt { // TODO: add multiple pivoting strategies if (cost < numeral::zero()) { m_entering_edge = e_id; + TRACE("network_flow", tout << "Found entering edge " << e_id << " between node " << source << " and node " << target << "...\n";); return true; } } } + TRACE("network_flow", tout << "Found no entering edge... It's probably optimal.\n";); return false; } template bool network_flow::choose_leaving_edge() { + TRACE("network_flow", tout << "choose_leaving_edge...\n";); node source = m_graph.get_source(m_entering_edge); node target = m_graph.get_target(m_entering_edge); node u = source, v = target; @@ -158,9 +159,9 @@ namespace smt { } // Found first common ancestor of source and target m_join_node = u; - // FIXME: need to get truly finite value + // FIXME: need to get truly infinite value numeral infty = numeral(INT_MAX); - m_delta = infty; + m_delta = infty; node src, tgt; // Send flows along the path from source to the ancestor for (unsigned u = source; u != m_join_node; u = m_pred[u]) { @@ -188,31 +189,143 @@ namespace smt { if (m_delta < infty) { m_graph.get_edge_id(src, tgt, m_leaving_edge); + TRACE("network_flow", tout << "Found leaving edge" << m_leaving_edge << "between node " << src << " and node " << tgt << "...\n";); return true; } + TRACE("network_flow", tout << "Can't find a leaving edge... The problem is unbounded.\n";); return false; } template - void network_flow::update_spanning_tree() { + void network_flow::update_spanning_tree() { + node src_in = m_graph.get_source(m_entering_edge); + node tgt_in = m_graph.get_target(m_entering_edge); + node src_out = m_graph.get_source(m_leaving_edge); + node tgt_out = m_graph.get_target(m_leaving_edge); + TRACE("network_flow", tout << "update_spanning_tree: (" << src_in << ", " << tgt_in << ") enters, (" + << src_out << ", " << tgt_out << ") leaves\n";); + node root = m_graph.get_num_nodes(); + node rev_thread_out = m_rev_thread[src_out]; + + node x = m_final[src_in]; + node y = m_thread[x]; + node z = m_final[src_out]; + + // Update m_pred (for nodes in the stem from tgt_in to tgt_out) + node u = tgt_in; + node last = m_pred[tgt_out]; + node parent = src_in; + while (u != last) { + node next = m_pred[u]; + m_pred[u] = parent; + u = next; + } + + // Graft T_q and T_r' + m_thread[x] = src_out; + m_thread[z] = y; + u = src_out; + while (u != m_final[src_out]) { + m_depth[u] += 1 + m_depth[src_in]; + u = m_pred[u]; + } + + node gamma = m_thread[m_final[src_in]]; + last = m_pred[gamma] != 0 ? gamma : root; + for (node u = src_in; u == last; u = m_pred[u]) { + m_final[u] = z; + } + + // Update T_r' + node phi = m_thread[tgt_out]; + node theta = m_thread[m_final[tgt_out]]; + m_thread[phi] = theta; + + gamma = m_thread[m_final[tgt_out]]; + // REVIEW: check f(u) is not in T_v + node delta = m_final[src_out] != m_final[tgt_out] ? m_final[src_out] : m_rev_thread[tgt_out]; + last = m_pred[gamma] != 0 ? gamma : root; + for (node u = src_in; u == last; u = m_pred[u]) { + m_final[u] = delta; + } + + // Reroot T_v at q + if (src_out != tgt_in) { + node u = m_pred[src_out]; + m_thread[m_final[src_out]] = u; + last = tgt_in; + node alpha1, alpha2; + unsigned count = 0; + while (u != last) { + // Find all immediate successors of u + node t1 = m_thread[u]; + node t2 = m_thread[m_final[t1]]; + node t3 = m_thread[m_final[t2]]; + if (t1 = m_pred[u]) { + alpha1 = t2; + alpha2 = t3; + } + else if (t2 = m_pred[u]) { + alpha1 = t1; + alpha2 = t3; + } + else { + alpha1 = t1; + alpha2 = t2; + } + m_thread[u] = alpha1; + m_thread[m_final[alpha1]] = alpha2; + u = m_pred[u]; + m_thread[m_final[alpha2]] = u; + // Decrease depth of all children in the subtree + ++count; + int d = m_depth[u] - count; + for (node v = m_thread[u]; v == m_final[u]; v = m_thread[v]) { + m_depth[v] -= d; + } + } + m_thread[m_final[alpha2]] = src_out; + } + + TRACE("network_flow", tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Threads", m_thread) + << pp_vector("Reverse Threads", m_rev_thread) << pp_vector("Last Successors", m_final) << pp_vector("Depths", m_depth);); + } + + template + std::string network_flow::pp_vector(std::string const & label, svector v, bool has_header) { + std::ostringstream oss; + if (has_header) { + oss << "Index "; + for (unsigned i = 0; i < v.size(); ++i) { + oss << i << " "; + } + oss << std::endl; + } + oss << label << " "; + for (unsigned i = 0; i < v.size(); ++i) { + oss << v[i] << " "; + } + oss << std::endl; + return oss.str(); } - // Get the optimal solution template - typename network_flow::numeral network_flow::get_optimal_solution(vector & result, bool is_dual) { - m_objective_value = numeral::zero(); - for (unsigned i = 0; i < m_flows.size(); ++i) { - m_objective_value += m_costs[i] * m_flows[i]; + std::string network_flow::pp_vector(std::string const & label, vector v, bool has_header) { + std::ostringstream oss; + if (has_header) { + oss << "Index "; + for (unsigned i = 0; i < v.size(); ++i) { + oss << i << " "; + } + oss << std::endl; } - result.reset(); - if (is_dual) { - result.append(m_potentials); + oss << label << " "; + for (unsigned i = 0; i < v.size(); ++i) { + oss << v[i] << " "; } - else { - result.append(m_flows); - } - return m_objective_value; + oss << std::endl; + return oss.str(); } // Minimize cost flows @@ -232,6 +345,24 @@ namespace smt { } return true; } + + // Get the optimal solution + template + typename network_flow::numeral network_flow::get_optimal_solution(vector & result, bool is_dual) { + m_objective_value = numeral::zero(); + for (unsigned i = 0; i < m_flows.size(); ++i) { + fin_numeral cost = m_graph.get_weight(i).get_rational(); + m_objective_value += cost * m_flows[i]; + } + result.reset(); + if (is_dual) { + result.append(m_potentials); + } + else { + result.append(m_flows); + } + return m_objective_value; + } } #endif diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index 9fa97097f..70fc681a7 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -1008,34 +1008,25 @@ bool theory_diff_logic::maximize(theory_var v) { verbose_stream() << "coefficient " << objective[i].second << " of theory_var " << objective[i].first << "\n"; } verbose_stream() << m_objective_consts[v] << "\n";); - NOT_IMPLEMENTED_YET(); - // Double the number of edges in the new graph - - // NSB review: what about disabled edges? They should not be added, right? - // For efficiency we probably want to reuse m_graph and keep extra edges on the side or add them to - // m_graph as well. - dl_graph g; - vector > const& es = m_graph.get_all_edges(); - for (unsigned i = 0; i < es.size(); ++i) { - dl_edge const & e = es[i]; - if (e.is_enabled()) { - g.enable_edge(g.add_edge(e.get_source(), e.get_target(), e.get_weight(), e.get_explanation())); - } - } // Objective coefficients now become balances - vector balances; + vector balances(m_graph.get_num_nodes()); + balances.fill(fin_numeral::zero()); for (unsigned i = 0; i < objective.size(); ++i) { fin_numeral balance(objective[i].second); - balances.push_back(balance); + balances[objective[i].first] = balance; } - network_flow net_flow(g, balances); + network_flow net_flow(m_graph, balances); bool is_optimal = net_flow.min_cost(); if (is_optimal) { vector potentials; m_objective_value = net_flow.get_optimal_solution(potentials, true); + std::cout << "Objective value of " << v << ": " << m_objective_value << std::endl; // TODO: return the model of the optimal solution from potential + } + else { + std::cout << "Unbounded" << std::endl; } return is_optimal; } From e715ccbc987b8fdafa9c80ecda95d2fcb3cbd015 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Tue, 29 Oct 2013 15:49:53 -0700 Subject: [PATCH 045/925] Minor updates --- src/smt/network_flow.h | 5 +++- src/smt/network_flow_def.h | 43 +++++++++++++++++++++------------ src/smt/theory_diff_logic_def.h | 2 +- 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index b0539811e..5177af2e4 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -47,7 +47,7 @@ namespace smt { typedef dl_graph graph; typedef typename Ext::numeral numeral; typedef typename Ext::fin_numeral fin_numeral; - graph & m_graph; + graph m_graph; // Denote supply/demand b_i on node i vector m_balances; @@ -85,6 +85,9 @@ namespace smt { // Initialize the network with a feasible spanning tree void initialize(); + bool get_edge_id(dl_var source, dl_var target, edge_id & id); + + void update_potentials(); void update_flows(); diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index 07548d2f6..ba156c712 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -33,9 +33,7 @@ namespace smt { m_balances.resize(num_nodes); - m_potentials.resize(num_nodes); - m_flows.resize(num_edges); - m_states.resize(num_edges); + m_potentials.resize(num_nodes); m_upwards.resize(num_nodes); m_pred.resize(num_nodes); @@ -58,12 +56,15 @@ namespace smt { m_final[root] = root - 1; m_potentials[root] = numeral::zero(); + m_graph.init_var(root); + fin_numeral sum_supply = fin_numeral::zero(); for (unsigned i = 0; i < m_balances.size(); ++i) { sum_supply += m_balances[i]; } m_balances[root] = -sum_supply; + m_flows.resize(num_nodes + num_edges); m_states.resize(num_nodes + num_edges); m_states.fill(NON_BASIS); @@ -74,14 +75,25 @@ namespace smt { m_depth[i] = 1; m_thread[i] = i + 1; m_final[i] = i; - m_rev_thread[i] = (i == 0) ? root : i - 1; + m_rev_thread[i + 1] = i; m_states[num_edges + i] = BASIS; + node src = m_upwards[i] ? i : root; + node tgt = m_upwards[i] ? root : i; + + m_flows[num_edges + i] = m_upwards[i] ? m_balances[i] : -m_balances[i]; + m_graph.enable_edge(m_graph.add_edge(src, tgt, numeral::one(), explanation())); } TRACE("network_flow", tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Threads", m_thread) << pp_vector("Reverse Threads", m_rev_thread) << pp_vector("Last Successors", m_final) << pp_vector("Depths", m_depth);); } + template + bool network_flow::get_edge_id(dl_var source, dl_var target, edge_id & id) { + // m_upwards decides which node is the real source + return m_upwards[source] ? m_graph.get_edge_id(source, target, id) : m_graph.get_edge_id(target, source, id); + } + template void network_flow::update_potentials() { TRACE("network_flow", tout << "update_potentials...\n";); @@ -105,13 +117,13 @@ namespace smt { node source = m_graph.get_source(m_entering_edge); for (unsigned u = source; u != m_join_node; u = m_pred[u]) { edge_id e_id; - m_graph.get_edge_id(u, m_pred[u], e_id); + get_edge_id(u, m_pred[u], e_id); m_flows[e_id] += m_upwards[u] ? -val : val; } node target = m_graph.get_target(m_entering_edge); for (unsigned u = target; u != m_join_node; u = m_pred[u]) { edge_id e_id; - m_graph.get_edge_id(u, m_pred[u], e_id); + get_edge_id(u, m_pred[u], e_id); m_flows[e_id] += m_upwards[u] ? val : -val; } TRACE("network_flow", tout << pp_vector("Flows", m_flows, true);); @@ -159,6 +171,7 @@ namespace smt { } // Found first common ancestor of source and target m_join_node = u; + TRACE("network_flow", tout << "Found join node " << m_join_node << std::endl;); // FIXME: need to get truly infinite value numeral infty = numeral(INT_MAX); m_delta = infty; @@ -166,7 +179,7 @@ namespace smt { // Send flows along the path from source to the ancestor for (unsigned u = source; u != m_join_node; u = m_pred[u]) { edge_id e_id; - m_graph.get_edge_id(u, m_pred[u], e_id); + get_edge_id(u, m_pred[u], e_id); numeral d = m_upwards[u] ? m_flows[e_id] : infty; if (d < m_delta) { m_delta = d; @@ -178,7 +191,7 @@ namespace smt { // Send flows along the path from target to the ancestor for (unsigned u = target; u != m_join_node; u = m_pred[u]) { edge_id e_id; - m_graph.get_edge_id(u, m_pred[u], e_id); + get_edge_id(u, m_pred[u], e_id); numeral d = m_upwards[u] ? infty : m_flows[e_id]; if (d <= m_delta) { m_delta = d; @@ -188,8 +201,8 @@ namespace smt { } if (m_delta < infty) { - m_graph.get_edge_id(src, tgt, m_leaving_edge); - TRACE("network_flow", tout << "Found leaving edge" << m_leaving_edge << "between node " << src << " and node " << tgt << "...\n";); + get_edge_id(src, tgt, m_leaving_edge); + TRACE("network_flow", tout << "Found leaving edge " << m_leaving_edge << " between node " << src << " and node " << tgt << "...\n";); return true; } TRACE("network_flow", tout << "Can't find a leaving edge... The problem is unbounded.\n";); @@ -232,8 +245,8 @@ namespace smt { } node gamma = m_thread[m_final[src_in]]; - last = m_pred[gamma] != 0 ? gamma : root; - for (node u = src_in; u == last; u = m_pred[u]) { + last = m_pred[gamma] != -1 ? gamma : root; + for (node u = src_in; u != last; u = m_pred[u]) { m_final[u] = z; } @@ -245,8 +258,8 @@ namespace smt { gamma = m_thread[m_final[tgt_out]]; // REVIEW: check f(u) is not in T_v node delta = m_final[src_out] != m_final[tgt_out] ? m_final[src_out] : m_rev_thread[tgt_out]; - last = m_pred[gamma] != 0 ? gamma : root; - for (node u = src_in; u == last; u = m_pred[u]) { + last = m_pred[gamma] != -1 ? gamma : root; + for (node u = src_in; u != last; u = m_pred[u]) { m_final[u] = delta; } @@ -281,7 +294,7 @@ namespace smt { // Decrease depth of all children in the subtree ++count; int d = m_depth[u] - count; - for (node v = m_thread[u]; v == m_final[u]; v = m_thread[v]) { + for (node v = m_thread[u]; v != m_final[u]; v = m_thread[v]) { m_depth[v] -= d; } } diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index 70fc681a7..e26947ed5 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -1015,7 +1015,7 @@ bool theory_diff_logic::maximize(theory_var v) { for (unsigned i = 0; i < objective.size(); ++i) { fin_numeral balance(objective[i].second); balances[objective[i].first] = balance; - } + } network_flow net_flow(m_graph, balances); bool is_optimal = net_flow.min_cost(); From 96562962fa6d4c4d9952e7cafd274904ae9959be Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 29 Oct 2013 17:40:37 -0700 Subject: [PATCH 046/925] working on wmaxsat Signed-off-by: Nikolaj Bjorner --- src/opt/weighted_maxsat.cpp | 101 +++++++++++++++++++++----------- src/smt/theory_diff_logic_def.h | 2 +- 2 files changed, 69 insertions(+), 34 deletions(-) diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index fc14a0b64..d54c4857b 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -19,20 +19,23 @@ Notes: #include "weighted_maxsat.h" #include "smt_theory.h" #include "smt_context.h" +#include "ast_pp.h" namespace smt { class theory_weighted_maxsat : public theory { - expr_ref_vector m_vars; + app_ref_vector m_vars; expr_ref_vector m_fmls; vector m_weights; // weights of theory variables. svector m_costs; // set of asserted theory variables rational m_cost; // current sum of asserted costs rational m_min_cost; // current minimal cost assignment. svector m_assignment; // current best assignment. + u_map m_bool2var; // bool_var -> theory_var + u_map m_var2bool; // theory_var -> bool_var public: theory_weighted_maxsat(ast_manager& m): - theory(m.get_family_id("weighted_maxsat")), + theory(m.mk_family_id("weighted_maxsat")), m_vars(m), m_fmls(m) {} @@ -44,37 +47,58 @@ namespace smt { } } + virtual void init_search_eh() { + context & ctx = get_context(); + ast_manager& m = get_manager(); + for (unsigned i = 0; i < m_vars.size(); ++i) { + app* var = m_vars[i].get(); + bool_var bv; + enode* x; + if (!ctx.e_internalized(var)) { + x = ctx.mk_enode(var, false, true, true); + } + else { + x = ctx.get_enode(var); + } + if (ctx.b_internalized(var)) { + bv = ctx.get_bool_var(var); + } + else { + bv = ctx.mk_bool_var(var); + } + ctx.set_var_theory(bv, get_id()); + ctx.set_enode_flag(bv, true); + theory_var v = mk_var(x); + ctx.attach_th_var(x, this, v); + m_bool2var.insert(bv,v); + m_var2bool.insert(v,bv); + } + } + void assert_weighted(expr* fml, rational const& w) { context & ctx = get_context(); ast_manager& m = get_manager(); - expr_ref var(m); + app_ref var(m), wfml(m); var = m.mk_fresh_const("w", m.mk_bool_sort()); - ctx.internalize(fml, false); // TBD: assume or require simplification? - ctx.internalize(var, false); - enode* x, *y; - x = ctx.get_enode(fml); - y = ctx.get_enode(var); - theory_var v = mk_var(y); - SASSERT(v == m_vars.size()); - SASSERT(v == m_weights.size()); + wfml = m.mk_or(var, fml); + ctx.assert_expr(wfml); + m_weights.push_back(w); m_vars.push_back(var); m_fmls.push_back(fml); - ctx.attach_th_var(y, this, v); - literal lx(ctx.get_bool_var(fml)); - literal ly(ctx.get_bool_var(var)); - ctx.mk_th_axiom(get_id(), lx, ly); - m_weights.push_back(w); m_min_cost += w; + // std::cout << mk_pp(var, m) << " " << w << " " << m_min_cost << "\n"; } virtual void assign_eh(bool_var v, bool is_true) { + IF_VERBOSE(2, verbose_stream() << "Assign " << v << " " << is_true << "\n";); if (is_true) { context& ctx = get_context(); - rational const& w = m_weights[v]; + theory_var tv = m_bool2var[v]; + rational const& w = m_weights[tv]; ctx.push_trail(value_trail(m_cost)); ctx.push_trail(push_back_vector >(m_costs)); m_cost += w; - m_costs.push_back(v); + m_costs.push_back(tv); if (m_cost > m_min_cost) { block(); } @@ -82,15 +106,23 @@ namespace smt { } virtual final_check_status final_check_eh() { - if (m_cost < m_min_cost) { - m_min_cost = m_cost; - m_assignment.reset(); - m_assignment.append(m_costs); + if (block()) { + return FC_CONTINUE; + } + else { + return FC_DONE; } - block(); - return FC_DONE; } + virtual bool use_diseqs() const { + return false; + } + + virtual bool build_models() const { + return false; + } + + virtual void reset_eh() { theory::reset_eh(); m_vars.reset(); @@ -104,8 +136,8 @@ namespace smt { virtual theory * mk_fresh(context * new_ctx) { UNREACHABLE(); return 0;} // TBD virtual bool internalize_atom(app * atom, bool gate_ctx) { return false; } virtual bool internalize_term(app * term) { return false; } - virtual void new_eq_eh(theory_var v1, theory_var v2) { UNREACHABLE(); } - virtual void new_diseq_eh(theory_var v1, theory_var v2) { UNREACHABLE(); } + virtual void new_eq_eh(theory_var v1, theory_var v2) { } + virtual void new_diseq_eh(theory_var v1, theory_var v2) { } private: @@ -119,7 +151,7 @@ namespace smt { } }; - void block() { + bool block() { ast_manager& m = get_manager(); context& ctx = get_context(); literal_vector lits; @@ -129,14 +161,17 @@ namespace smt { rational weight(0); for (unsigned i = 0; i < costs.size() && weight < m_min_cost; ++i) { weight += m_weights[costs[i]]; - lits.push_back(~literal(costs[i])); + lits.push_back(~literal(m_var2bool[costs[i]])); } - justification * js = 0; - if (m.proofs_enabled()) { - js = new (ctx.get_region()) - theory_lemma_justification(get_id(), ctx, lits.size(), lits.c_ptr()); + IF_VERBOSE(2, verbose_stream() << "block: " << m_costs.size() << " " << lits.size() << " " << m_min_cost << "\n";); + + ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); + if (m_cost < m_min_cost) { + m_min_cost = weight; + m_assignment.reset(); + m_assignment.append(m_costs); } - ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); + return !lits.empty(); } }; diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index 9fa97097f..f4cdcc2fe 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -1030,7 +1030,7 @@ bool theory_diff_logic::maximize(theory_var v) { balances.push_back(balance); } - network_flow net_flow(g, balances); + network_flow net_flow(m_graph, balances); bool is_optimal = net_flow.min_cost(); if (is_optimal) { vector potentials; From b67d333cf946a8101bd038bd516f5b0024262fe7 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Tue, 29 Oct 2013 18:32:10 -0700 Subject: [PATCH 047/925] First complete version of Network Simplex --- src/smt/network_flow.h | 9 +- src/smt/network_flow_def.h | 148 +++++++++++++++++++------------- src/smt/theory_arith.h | 2 +- src/smt/theory_arith_aux.h | 4 +- src/smt/theory_diff_logic_def.h | 11 ++- src/util/s_integer.h | 2 +- 6 files changed, 105 insertions(+), 71 deletions(-) diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index 5177af2e4..39574fd55 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -35,6 +35,12 @@ Notes: namespace smt { + template + std::string pp_vector(std::string const & label, svector v, bool has_header = false); + + template + std::string pp_vector(std::string const & label, vector v, bool has_header = false); + // Solve minimum cost flow problem using Network Simplex algorithm template class network_flow : private Ext { @@ -102,9 +108,6 @@ namespace smt { void update_spanning_tree(); - std::string pp_vector(std::string const & label, svector v, bool has_header = false); - std::string pp_vector(std::string const & label, vector v, bool has_header = false); - public: network_flow(graph & g, vector const & balances); diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index ba156c712..2950a77c3 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -24,6 +24,42 @@ Notes: namespace smt { + template + std::string pp_vector(std::string const & label, svector v, bool has_header) { + std::ostringstream oss; + if (has_header) { + oss << "Index "; + for (unsigned i = 0; i < v.size(); ++i) { + oss << i << " "; + } + oss << std::endl; + } + oss << label << " "; + for (unsigned i = 0; i < v.size(); ++i) { + oss << v[i] << " "; + } + oss << std::endl; + return oss.str(); + } + + template + std::string pp_vector(std::string const & label, vector v, bool has_header) { + std::ostringstream oss; + if (has_header) { + oss << "Index "; + for (unsigned i = 0; i < v.size(); ++i) { + oss << i << " "; + } + oss << std::endl; + } + oss << label << " "; + for (unsigned i = 0; i < v.size(); ++i) { + oss << v[i] << " "; + } + oss << std::endl; + return oss.str(); + } + template network_flow::network_flow(graph & g, vector const & balances) : m_graph(g), @@ -32,7 +68,6 @@ namespace smt { unsigned num_edges = m_graph.get_num_edges(); m_balances.resize(num_nodes); - m_potentials.resize(num_nodes); m_upwards.resize(num_nodes); @@ -78,14 +113,32 @@ namespace smt { m_rev_thread[i + 1] = i; m_states[num_edges + i] = BASIS; node src = m_upwards[i] ? i : root; - node tgt = m_upwards[i] ? root : i; - + node tgt = m_upwards[i] ? root : i; m_flows[num_edges + i] = m_upwards[i] ? m_balances[i] : -m_balances[i]; m_graph.enable_edge(m_graph.add_edge(src, tgt, numeral::one(), explanation())); } - TRACE("network_flow", tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Threads", m_thread) - << pp_vector("Reverse Threads", m_rev_thread) << pp_vector("Last Successors", m_final) << pp_vector("Depths", m_depth);); + // Compute initial potentials + node u = m_thread[root]; + while (u != root) { + node v = m_pred[u]; + edge_id e_id; + get_edge_id(u, v, e_id); + if (m_upwards[u]) { + m_potentials[u] = m_potentials[v] + m_graph.get_weight(e_id); + } + else { + m_potentials[u] = m_potentials[v] - m_graph.get_weight(e_id); + } + u = m_thread[u]; + } + + TRACE("network_flow", { + tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Threads", m_thread); + tout << pp_vector("Reverse Threads", m_rev_thread) << pp_vector("Last Successors", m_final); + tout << pp_vector("Depths", m_depth) << pp_vector("Upwards", m_upwards); + tout << pp_vector("Potentials", m_potentials) << pp_vector("Flows", m_flows); + }); } template @@ -144,12 +197,15 @@ namespace smt { // TODO: add multiple pivoting strategies if (cost < numeral::zero()) { m_entering_edge = e_id; - TRACE("network_flow", tout << "Found entering edge " << e_id << " between node " << source << " and node " << target << "...\n";); + TRACE("network_flow", { + tout << "Found entering edge " << e_id << " between node "; + tout << source << " and node " << target << "...\n"; + }); return true; } } } - TRACE("network_flow", tout << "Found no entering edge... It's probably optimal.\n";); + TRACE("network_flow", tout << "Found no entering edge...\n";); return false; } @@ -192,7 +248,7 @@ namespace smt { for (unsigned u = target; u != m_join_node; u = m_pred[u]) { edge_id e_id; get_edge_id(u, m_pred[u], e_id); - numeral d = m_upwards[u] ? infty : m_flows[e_id]; + numeral d = m_upwards[u] ? m_flows[e_id] : infty; if (d <= m_delta) { m_delta = d; src = u; @@ -202,7 +258,10 @@ namespace smt { if (m_delta < infty) { get_edge_id(src, tgt, m_leaving_edge); - TRACE("network_flow", tout << "Found leaving edge " << m_leaving_edge << " between node " << src << " and node " << tgt << "...\n";); + TRACE("network_flow", { + tout << "Found leaving edge " << m_leaving_edge; + tout << " between node " << src << " and node " << tgt << "...\n"; + }); return true; } TRACE("network_flow", tout << "Can't find a leaving edge... The problem is unbounded.\n";); @@ -215,12 +274,12 @@ namespace smt { node tgt_in = m_graph.get_target(m_entering_edge); node src_out = m_graph.get_source(m_leaving_edge); node tgt_out = m_graph.get_target(m_leaving_edge); - TRACE("network_flow", tout << "update_spanning_tree: (" << src_in << ", " << tgt_in << ") enters, (" - << src_out << ", " << tgt_out << ") leaves\n";); + TRACE("network_flow", { + tout << "update_spanning_tree: (" << src_in << ", " << tgt_in << ") enters, ("; + tout << src_out << ", " << tgt_out << ") leaves\n"; + }); node root = m_graph.get_num_nodes(); - node rev_thread_out = m_rev_thread[src_out]; - node x = m_final[src_in]; node y = m_thread[x]; node z = m_final[src_out]; @@ -232,6 +291,8 @@ namespace smt { while (u != last) { node next = m_pred[u]; m_pred[u] = parent; + m_upwards[u] = !m_upwards[u]; + parent = u; u = next; } @@ -245,8 +306,7 @@ namespace smt { } node gamma = m_thread[m_final[src_in]]; - last = m_pred[gamma] != -1 ? gamma : root; - for (node u = src_in; u != last; u = m_pred[u]) { + for (node u = src_in; u != gamma; u = m_pred[u]) { m_final[u] = z; } @@ -258,8 +318,7 @@ namespace smt { gamma = m_thread[m_final[tgt_out]]; // REVIEW: check f(u) is not in T_v node delta = m_final[src_out] != m_final[tgt_out] ? m_final[src_out] : m_rev_thread[tgt_out]; - last = m_pred[gamma] != -1 ? gamma : root; - for (node u = src_in; u != last; u = m_pred[u]) { + for (node u = src_in; u != gamma; u = m_pred[u]) { m_final[u] = delta; } @@ -301,44 +360,11 @@ namespace smt { m_thread[m_final[alpha2]] = src_out; } - TRACE("network_flow", tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Threads", m_thread) - << pp_vector("Reverse Threads", m_rev_thread) << pp_vector("Last Successors", m_final) << pp_vector("Depths", m_depth);); - } - - template - std::string network_flow::pp_vector(std::string const & label, svector v, bool has_header) { - std::ostringstream oss; - if (has_header) { - oss << "Index "; - for (unsigned i = 0; i < v.size(); ++i) { - oss << i << " "; - } - oss << std::endl; - } - oss << label << " "; - for (unsigned i = 0; i < v.size(); ++i) { - oss << v[i] << " "; - } - oss << std::endl; - return oss.str(); - } - - template - std::string network_flow::pp_vector(std::string const & label, vector v, bool has_header) { - std::ostringstream oss; - if (has_header) { - oss << "Index "; - for (unsigned i = 0; i < v.size(); ++i) { - oss << i << " "; - } - oss << std::endl; - } - oss << label << " "; - for (unsigned i = 0; i < v.size(); ++i) { - oss << v[i] << " "; - } - oss << std::endl; - return oss.str(); + TRACE("network_flow", { + tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Threads", m_thread); + tout << pp_vector("Reverse Threads", m_rev_thread) << pp_vector("Last Successors", m_final); + tout << pp_vector("Depths", m_depth) << pp_vector("Upwards", m_upwards); + }); } // Minimize cost flows @@ -356,6 +382,7 @@ namespace smt { update_potentials(); } } + TRACE("network_flow", tout << "Found optimal solution.\n";); return true; } @@ -363,9 +390,14 @@ namespace smt { template typename network_flow::numeral network_flow::get_optimal_solution(vector & result, bool is_dual) { m_objective_value = numeral::zero(); - for (unsigned i = 0; i < m_flows.size(); ++i) { - fin_numeral cost = m_graph.get_weight(i).get_rational(); - m_objective_value += cost * m_flows[i]; + vector const & es = m_graph.get_all_edges(); + fin_numeral cost; + for (unsigned i = 0; i < es.size(); ++i) { + edge const & e = es[i]; + if (e.is_enabled() && m_states[i] == BASIS) { + cost = e.get_weight().get_rational(); + m_objective_value += cost * m_flows[i]; + } } result.reset(); if (is_dual) { diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index cf2ec7ff4..f5e6214ef 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -996,7 +996,7 @@ namespace smt { virtual bool maximize(theory_var v); virtual theory_var add_objective(app* term); virtual inf_eps_rational get_objective_value(theory_var v); - inf_rational m_objective; + inf_rational m_objective_value; // ----------------------------------- // diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 26c272548..1da4fb364 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -984,7 +984,7 @@ namespace smt { template inf_eps_rational theory_arith::get_objective_value(theory_var v) { - inf_eps_rational val(m_objective); + inf_eps_rational val(m_objective_value); return val; } @@ -1244,7 +1244,7 @@ namespace smt { TRACE("maximize", tout << "v" << v << " " << (max ? "max" : "min") << " value is: " << get_value(v) << "\n"; display_row(tout, m_tmp_row, true); display_row_info(tout, m_tmp_row);); - m_objective = get_value(v); + m_objective_value = get_value(v); mk_bound_from_row(v, get_value(v), max ? B_UPPER : B_LOWER, m_tmp_row); diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index e26947ed5..2304183b0 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -1022,11 +1022,11 @@ bool theory_diff_logic::maximize(theory_var v) { if (is_optimal) { vector potentials; m_objective_value = net_flow.get_optimal_solution(potentials, true); - std::cout << "Objective value of " << v << ": " << m_objective_value << std::endl; + std::cout << "Objective value of var " << v << ": " << m_objective_value << std::endl; // TODO: return the model of the optimal solution from potential } else { - std::cout << "Unbounded" << std::endl; + std::cout << "Unbounded objective" << std::endl; } return is_optimal; } @@ -1048,10 +1048,9 @@ theory_var theory_diff_logic::add_objective(app* term) { template inf_eps_rational theory_diff_logic::get_objective_value(theory_var v) { - NOT_IMPLEMENTED_YET(); - inf_rational objective; - inf_eps_rational val(objective); - return val; + rational r = m_objective_value.get_rational().to_rational(); + rational i = m_objective_value.get_infinitesimal().to_rational(); + return inf_eps_rational(inf_rational(r, i)); } template diff --git a/src/util/s_integer.h b/src/util/s_integer.h index 4e50269c5..92321a7c3 100644 --- a/src/util/s_integer.h +++ b/src/util/s_integer.h @@ -67,7 +67,7 @@ public: s_integer const& get_s_integer() const { return *this; } s_integer const& get_infinitesimal() const { return zero(); } static bool is_rational() { return true; } - s_integer const& get_rational() const { return *this; } + s_integer const& get_rational() const { return *this; } s_integer & operator=(const s_integer & r) { m_val = r.m_val; return *this; } friend inline s_integer numerator(const s_integer & r) { return r; } friend inline s_integer denominator(const s_integer & r) { return one(); } From bc44bcad102f9f07e8a694be4a3f0189da86ebda Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 29 Oct 2013 20:26:54 -0700 Subject: [PATCH 048/925] push blocking code to optimizer context Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 3 +- src/opt/opt_solver.cpp | 21 +++++++-- src/opt/opt_solver.h | 11 +++-- src/opt/optimize_objectives.cpp | 77 ++++++++++++++++++--------------- src/opt/optimize_objectives.h | 24 ++++++++-- src/smt/theory_arith.h | 1 + src/smt/theory_arith_aux.h | 17 +++++++- src/smt/theory_diff_logic.h | 6 ++- src/smt/theory_diff_logic_def.h | 36 +++++++++++++++ src/smt/theory_opt.h | 1 + src/util/inf_eps_rational.h | 4 ++ 11 files changed, 152 insertions(+), 49 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 2c4e22492..d3a034e8f 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -76,7 +76,8 @@ namespace opt { for (unsigned i = 0; i < fmls_copy.size(); ++i) { s->assert_expr(fmls_copy[i].get()); } - is_sat = optimize_objectives(get_opt_solver(*s), m_objectives, values); + optimize_objectives obj(m, get_opt_solver(*s)); // TBD: make an attribute + is_sat = obj(m_objectives, values); std::cout << "is-sat: " << is_sat << std::endl; if (is_sat != l_true) { diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 6cf7c59ed..5cde65cdb 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -6,10 +6,11 @@ namespace opt { - opt_solver::opt_solver(ast_manager & m, params_ref const & p, symbol const & l): - solver_na2as(m), + opt_solver::opt_solver(ast_manager & mgr, params_ref const & p, symbol const & l): + solver_na2as(mgr), m_params(p), - m_context(m, m_params), + m_context(mgr, m_params), + m(mgr), m_objective_enabled(false) { m_logic = l; if (m_logic != symbol::null) @@ -139,9 +140,21 @@ namespace opt { return m_objective_vars.back(); } - vector const& opt_solver::get_objective_values() { + vector const& opt_solver::get_objective_values() { return m_objective_values; } + + expr_ref opt_solver::block_lower_bound(unsigned var, inf_eps const& val) { + if (val.get_infinity().is_pos()) { + return expr_ref(m.mk_false(), m); + } + else if (val.get_infinity().is_neg()) { + return expr_ref(m.mk_true(), m); + } + else { + return expr_ref(get_optimizer().block_lower_bound(m_objective_vars[var], val.get_numeral()), m); + } + } void opt_solver::reset_objectives() { m_objective_vars.reset(); diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index a9f8da3b0..075aea1c5 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -33,17 +33,19 @@ Notes: namespace opt { + typedef inf_eps_rational inf_eps; + + class opt_solver : public solver_na2as { - public: - typedef inf_eps_rational inf_value; private: smt_params m_params; smt::kernel m_context; + ast_manager& m; progress_callback * m_callback; symbol m_logic; bool m_objective_enabled; svector m_objective_vars; - vector m_objective_values; + vector m_objective_values; public: opt_solver(ast_manager & m, params_ref const & p, symbol const & l); virtual ~opt_solver(); @@ -69,7 +71,8 @@ namespace opt { smt::theory_var add_objective(app* term); void reset_objectives(); - vector const& get_objective_values(); + vector const& get_objective_values(); + expr_ref block_lower_bound(unsigned obj_index, inf_eps const& val); class toggle_objective { opt_solver& s; diff --git a/src/opt/optimize_objectives.cpp b/src/opt/optimize_objectives.cpp index ef247ee3c..6d2d7168e 100644 --- a/src/opt/optimize_objectives.cpp +++ b/src/opt/optimize_objectives.cpp @@ -46,83 +46,92 @@ Notes: namespace opt { + class scoped_push { + opt_solver& s; + public: + scoped_push(opt_solver& s):s(s) { + s.push(); + } + ~scoped_push() { + s.pop(1); + } + }; + + void optimize_objectives::set_cancel(bool f) { + m_cancel = true; + } + + void optimize_objectives::set_max(vector& dst, vector const& src) { + for (unsigned i = 0; i < src.size(); ++i) { + if (src[i] > dst[i]) { + dst[i] = src[i]; + } + } + } + + /* Enumerate locally optimal assignments until fixedpoint. */ - lbool mathsat_style_opt( - opt_solver& s, - app_ref_vector const& objectives, - vector >& values) + lbool optimize_objectives::basic_opt(app_ref_vector& objectives, vector& values) { ast_manager& m = objectives.get_manager(); arith_util autil(m); s.reset_objectives(); + values.reset(); // First check_sat call to initialize theories lbool is_sat = s.check_sat(0, 0); if (is_sat == l_false) { return is_sat; } - s.push(); + scoped_push _push(s); opt_solver::toggle_objective _t(s, true); for (unsigned i = 0; i < objectives.size(); ++i) { - s.add_objective(objectives[i]); + s.add_objective(objectives[i].get()); + values.push_back(inf_eps(rational(-1),inf_rational(0))); } is_sat = s.check_sat(0, 0); + - while (is_sat == l_true) { - // Extract values for objectives - values.reset(); - values.append(s.get_objective_values()); + while (is_sat == l_true && !m_cancel) { + set_max(values, s.get_objective_values()); IF_VERBOSE(1, for (unsigned i = 0; i < values.size(); ++i) { verbose_stream() << values[i] << " "; } verbose_stream() << "\n";); expr_ref_vector disj(m); - expr_ref constraint(m), num(m); - for (unsigned i = 0; i < objectives.size(); ++i) { + expr_ref constraint(m); - if (!values[i].get_infinity().is_zero()) { - continue; - } - num = autil.mk_numeral(values[i].get_rational(), m.get_sort(objectives[i])); - - SASSERT(values[i].get_infinitesimal().is_nonpos()); - if (values[i].get_infinitesimal().is_neg()) { - disj.push_back(autil.mk_ge(objectives[i], num)); - } - else { - disj.push_back(autil.mk_gt(objectives[i], num)); - } + for (unsigned i = 0; i < objectives.size(); ++i) { + inf_eps const& v = values[i]; + disj.push_back(s.block_lower_bound(i, v)); } constraint = m.mk_or(disj.size(), disj.c_ptr()); s.assert_expr(constraint); is_sat = s.check_sat(0, 0); } - s.pop(1); - - if (is_sat == l_undef) { - return is_sat; + + if (m_cancel || is_sat == l_undef) { + return l_undef; } - return l_true; + return l_true; } /** Takes solver with hard constraints added. Returns an optimal assignment to objective functions. */ - - lbool optimize_objectives(opt_solver& s, - app_ref_vector& objectives, - vector >& values) { - return mathsat_style_opt(s, objectives, values); + lbool optimize_objectives::operator()(app_ref_vector& objectives, vector& values) { + return basic_opt(objectives, values); } + } #endif diff --git a/src/opt/optimize_objectives.h b/src/opt/optimize_objectives.h index f2ce5baca..449b39df5 100644 --- a/src/opt/optimize_objectives.h +++ b/src/opt/optimize_objectives.h @@ -26,10 +26,26 @@ namespace opt { Takes solver with hard constraints added. Returns an optimal assignment to objective functions. */ - - lbool optimize_objectives(opt_solver& s, - app_ref_vector& objectives, - vector >& values); + + class optimize_objectives { + ast_manager& m; + opt_solver& s; + volatile bool m_cancel; + public: + optimize_objectives(ast_manager& m, opt_solver& s): m(m), s(s), m_cancel(false) {} + + lbool operator()(app_ref_vector& objectives, vector& values); + + void set_cancel(bool f); + + private: + + lbool basic_opt(app_ref_vector& objectives, vector& values); + + void set_max(vector& dst, vector const& src); + + }; + }; #endif diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index f5e6214ef..a434c2e83 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -996,6 +996,7 @@ namespace smt { virtual bool maximize(theory_var v); virtual theory_var add_objective(app* term); virtual inf_eps_rational get_objective_value(theory_var v); + virtual expr* block_lower_bound(theory_var v, inf_rational const& val); inf_rational m_objective_value; // ----------------------------------- diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 1da4fb364..86b2ff28a 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -965,11 +965,12 @@ namespace smt { } // - // set_objective(expr* term) internalizes the arithmetic term and creates + // add_objective(expr* term) internalizes the arithmetic term and creates // a row for it if it is not already internalized. // Then return the variable corresponding to the term. // + template theory_var theory_arith::add_objective(app* term) { return internalize_term_core(term); @@ -981,6 +982,20 @@ namespace smt { return r || at_upper(v); } + template + expr* theory_arith::block_lower_bound(theory_var v, inf_rational const& val) { + ast_manager& m = get_manager(); + expr* obj = get_enode(v)->get_owner(); + expr_ref e(m); + e = m_util.mk_numeral(val.get_rational(), m.get_sort(obj)); + + if (val.get_infinitesimal().is_neg()) { + return m_util.mk_ge(obj, e); + } + else { + return m_util.mk_gt(obj, e); + } + } template inf_eps_rational theory_arith::get_objective_value(theory_var v) { diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h index f7f574cd0..158ea3209 100644 --- a/src/smt/theory_diff_logic.h +++ b/src/smt/theory_diff_logic.h @@ -307,7 +307,11 @@ namespace smt { virtual bool maximize(theory_var v); virtual theory_var add_objective(app* term); virtual inf_eps_rational get_objective_value(theory_var v); - numeral m_objective_value; + virtual expr* block_lower_bound(theory_var v, inf_rational const& val); + + // TBD: why are these public?: + numeral m_objective_value; + typedef vector > objective_term; vector m_objectives; diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index 2304183b0..46565b0e6 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -1053,6 +1053,42 @@ inf_eps_rational theory_diff_logic::get_objective_value(theor return inf_eps_rational(inf_rational(r, i)); } +template +expr* theory_diff_logic::block_lower_bound(theory_var v, inf_rational const& val) { + ast_manager& m = get_manager(); + objective_term const& t = m_objectives[v]; + expr_ref e(m), f(m), f2(m); + // hacky implementation for now. + if (t.size() == 1 && t[0].second.is_one()) { + f = get_enode(t[0].first)->get_owner(); + } + else if (t.size() == 1 && t[0].second.is_minus_one()) { + f = m_util.mk_uminus(get_enode(t[0].first)->get_owner()); + } + else if (t.size() == 2 && t[0].second.is_one() && t[1].second.is_minus_one()) { + f = get_enode(t[0].first)->get_owner(); + f2 = get_enode(t[1].first)->get_owner(); + f = m_util.mk_sub(f, f2); + } + else if (t.size() == 2 && t[1].second.is_one() && t[0].second.is_minus_one()) { + f = get_enode(t[1].first)->get_owner(); + f2 = get_enode(t[0].first)->get_owner(); + f = m_util.mk_sub(f, f2); + } + else { + NOT_IMPLEMENTED_YET(); + } + inf_rational new_val = val - inf_rational(m_objective_consts[v]); + e = m_util.mk_numeral(new_val.get_rational(), m.get_sort(f)); + + if (new_val.get_infinitesimal().is_neg()) { + return m_util.mk_ge(f, e); + } + else { + return m_util.mk_gt(f, e); + } +} + template bool theory_diff_logic::internalize_objective(expr * n, rational const& m, rational& q, objective_term & objective) { diff --git a/src/smt/theory_opt.h b/src/smt/theory_opt.h index 9b013612b..f1c6c242d 100644 --- a/src/smt/theory_opt.h +++ b/src/smt/theory_opt.h @@ -34,6 +34,7 @@ namespace smt { inf_eps_rational r(rational(1), inf_rational(0)); return r; } + virtual expr* block_lower_bound(theory_var v, inf_rational const& val) { return 0; } }; } diff --git a/src/util/inf_eps_rational.h b/src/util/inf_eps_rational.h index 659fdc400..1d6d04818 100644 --- a/src/util/inf_eps_rational.h +++ b/src/util/inf_eps_rational.h @@ -127,6 +127,10 @@ class inf_eps_rational { return m_r.get_uint64(); } + Numeral const& get_numeral() const { + return m_r; + } + rational const& get_rational() const { return m_r.get_rational(); } From f5e6a1801527b489d2f03de02db9d9c101ac5cf0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 29 Oct 2013 21:16:02 -0700 Subject: [PATCH 049/925] working on wmaxsmt Signed-off-by: Nikolaj Bjorner --- src/opt/weighted_maxsat.cpp | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index d54c4857b..24c0e768a 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -28,9 +28,9 @@ namespace smt { expr_ref_vector m_fmls; vector m_weights; // weights of theory variables. svector m_costs; // set of asserted theory variables + svector m_cost_save; // set of asserted theory variables rational m_cost; // current sum of asserted costs rational m_min_cost; // current minimal cost assignment. - svector m_assignment; // current best assignment. u_map m_bool2var; // bool_var -> theory_var u_map m_var2bool; // theory_var -> bool_var public: @@ -40,10 +40,19 @@ namespace smt { m_fmls(m) {} + /** + \brief return the complement of variables that are currently assigned. + */ void get_assignment(expr_ref_vector& result) { result.reset(); - for (unsigned i = 0; i < m_assignment.size(); ++i) { - result.push_back(m_fmls[m_assignment[i]].get()); + std::sort(m_cost_save.begin(), m_cost_save.end()); + for (unsigned i = 0, j = 0; i < m_vars.size(); ++i) { + if (j < m_cost_save.size() && m_cost_save[j] == i) { + ++j; + } + else { + result.push_back(m_fmls[i].get()); + } } } @@ -70,8 +79,8 @@ namespace smt { ctx.set_enode_flag(bv, true); theory_var v = mk_var(x); ctx.attach_th_var(x, this, v); - m_bool2var.insert(bv,v); - m_var2bool.insert(v,bv); + m_bool2var.insert(bv, v); + m_var2bool.insert(v, bv); } } @@ -86,11 +95,10 @@ namespace smt { m_vars.push_back(var); m_fmls.push_back(fml); m_min_cost += w; - // std::cout << mk_pp(var, m) << " " << w << " " << m_min_cost << "\n"; } virtual void assign_eh(bool_var v, bool is_true) { - IF_VERBOSE(2, verbose_stream() << "Assign " << v << " " << is_true << "\n";); + IF_VERBOSE(3, verbose_stream() << "Assign " << v << " " << is_true << "\n";); if (is_true) { context& ctx = get_context(); theory_var tv = m_bool2var[v]; @@ -130,7 +138,7 @@ namespace smt { m_costs.reset(); m_cost.reset(); m_min_cost.reset(); - m_assignment.reset(); + m_cost_save.reset(); } virtual theory * mk_fresh(context * new_ctx) { UNREACHABLE(); return 0;} // TBD @@ -147,7 +155,7 @@ namespace smt { public: compare_cost(theory_weighted_maxsat& t):m_th(t) {} bool operator() (theory_var v, theory_var w) const { - return m_th.m_weights[v] < m_th.m_weights[w]; + return m_th.m_weights[v] > m_th.m_weights[w]; } }; @@ -168,8 +176,8 @@ namespace smt { ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); if (m_cost < m_min_cost) { m_min_cost = weight; - m_assignment.reset(); - m_assignment.append(m_costs); + m_cost_save.reset(); + m_cost_save.append(m_costs); } return !lits.empty(); } From a6e103dd36f989b7d6d32cd3eb68e01838bcefff Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Wed, 30 Oct 2013 06:30:51 +0100 Subject: [PATCH 050/925] Make a few variables private --- src/smt/network_flow_def.h | 4 ++-- src/smt/theory_arith.h | 5 +++-- src/smt/theory_arith_aux.h | 5 ++--- src/smt/theory_diff_logic.h | 16 +++++++--------- src/smt/theory_diff_logic_def.h | 15 ++++++++++----- 5 files changed, 24 insertions(+), 21 deletions(-) diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index 2950a77c3..b3be85a2f 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -125,10 +125,10 @@ namespace smt { edge_id e_id; get_edge_id(u, v, e_id); if (m_upwards[u]) { - m_potentials[u] = m_potentials[v] + m_graph.get_weight(e_id); + m_potentials[u] = m_potentials[v] - m_graph.get_weight(e_id); } else { - m_potentials[u] = m_potentials[v] - m_graph.get_weight(e_id); + m_potentials[u] = m_potentials[v] + m_graph.get_weight(e_id); } u = m_thread[u]; } diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index a434c2e83..20631ea27 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -432,6 +432,8 @@ namespace smt { bool m_eager_gcd; // true if gcd should be applied at every add_row unsigned m_final_check_idx; + inf_rational m_objective_value; + // backtracking svector m_bound_trail; svector m_unassigned_atoms_trail; @@ -997,8 +999,7 @@ namespace smt { virtual theory_var add_objective(app* term); virtual inf_eps_rational get_objective_value(theory_var v); virtual expr* block_lower_bound(theory_var v, inf_rational const& val); - inf_rational m_objective_value; - + // ----------------------------------- // // Pretty Printing diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 86b2ff28a..d43d1ef24 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -998,9 +998,8 @@ namespace smt { } template - inf_eps_rational theory_arith::get_objective_value(theory_var v) { - inf_eps_rational val(m_objective_value); - return val; + inf_eps_rational theory_arith::get_objective_value(theory_var v) { + return inf_eps_rational(m_objective_value); } /** diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h index 158ea3209..3b566d8c2 100644 --- a/src/smt/theory_diff_logic.h +++ b/src/smt/theory_diff_logic.h @@ -185,7 +185,13 @@ namespace smt { arith_factory * m_factory; rational m_delta; - nc_functor m_nc_functor; + nc_functor m_nc_functor; + + // For optimization purpose + typedef vector > objective_term; + vector m_objectives; + vector m_objective_consts; + numeral m_objective_value; // Set a conflict due to a negative cycle. void set_neg_cycle_conflict(); @@ -309,14 +315,6 @@ namespace smt { virtual inf_eps_rational get_objective_value(theory_var v); virtual expr* block_lower_bound(theory_var v, inf_rational const& val); - // TBD: why are these public?: - numeral m_objective_value; - - - typedef vector > objective_term; - vector m_objectives; - vector m_objective_consts; - bool internalize_objective(expr * n, rational const& m, rational& r, objective_term & objective); private: diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index 46565b0e6..bcf22a2de 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -1004,10 +1004,10 @@ bool theory_diff_logic::maximize(theory_var v) { objective_term const& objective = m_objectives[v]; IF_VERBOSE(1, - for (unsigned i = 0; i < objective.size(); ++i) { - verbose_stream() << "coefficient " << objective[i].second << " of theory_var " << objective[i].first << "\n"; - } - verbose_stream() << m_objective_consts[v] << "\n";); + for (unsigned i = 0; i < objective.size(); ++i) { + verbose_stream() << "coefficient " << objective[i].second << " of theory_var " << objective[i].first << "\n"; + } + verbose_stream() << m_objective_consts[v] << "\n";); // Objective coefficients now become balances vector balances(m_graph.get_num_nodes()); @@ -1023,7 +1023,12 @@ bool theory_diff_logic::maximize(theory_var v) { vector potentials; m_objective_value = net_flow.get_optimal_solution(potentials, true); std::cout << "Objective value of var " << v << ": " << m_objective_value << std::endl; - // TODO: return the model of the optimal solution from potential + // TODO: return the model of the optimal solution from potentials + IF_VERBOSE(1, + for (unsigned i = 0; i < potentials.size(); ++i) { + verbose_stream() << "v" << i << " -> " << potentials[i] << "\n"; + }); + } else { std::cout << "Unbounded objective" << std::endl; From 6302d1b7dbb79f275b1682a692d971f353cb6faa Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 Oct 2013 01:18:10 -0700 Subject: [PATCH 051/925] wmax nits Signed-off-by: Nikolaj Bjorner --- src/opt/weighted_maxsat.cpp | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 24c0e768a..449c79ee1 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -24,15 +24,15 @@ Notes: namespace smt { class theory_weighted_maxsat : public theory { - app_ref_vector m_vars; - expr_ref_vector m_fmls; + app_ref_vector m_vars; // Auxiliary variables per soft clause + expr_ref_vector m_fmls; // Formulas per soft clause vector m_weights; // weights of theory variables. svector m_costs; // set of asserted theory variables svector m_cost_save; // set of asserted theory variables rational m_cost; // current sum of asserted costs rational m_min_cost; // current minimal cost assignment. u_map m_bool2var; // bool_var -> theory_var - u_map m_var2bool; // theory_var -> bool_var + svector m_var2bool; // theory_var -> bool_var public: theory_weighted_maxsat(ast_manager& m): theory(m.mk_family_id("weighted_maxsat")), @@ -80,7 +80,8 @@ namespace smt { theory_var v = mk_var(x); ctx.attach_th_var(x, this, v); m_bool2var.insert(bv, v); - m_var2bool.insert(v, bv); + SASSERT(v == m_var2bool.size()); + m_var2bool.push_back(bv); } } @@ -130,18 +131,24 @@ namespace smt { return false; } + void reset() { + reset_eh(); + } virtual void reset_eh() { theory::reset_eh(); m_vars.reset(); + m_fmls.reset(); m_weights.reset(); m_costs.reset(); m_cost.reset(); - m_min_cost.reset(); m_cost_save.reset(); + m_min_cost.reset(); + m_bool2var.reset(); + m_var2bool.reset(); } - virtual theory * mk_fresh(context * new_ctx) { UNREACHABLE(); return 0;} // TBD + virtual theory * mk_fresh(context * new_ctx) { return alloc(theory_weighted_maxsat, new_ctx->get_manager()); } virtual bool internalize_atom(app * atom, bool gate_ctx) { return false; } virtual bool internalize_term(app * term) { return false; } virtual void new_eq_eh(theory_var v1, theory_var v2) { } @@ -199,11 +206,16 @@ namespace opt { smt::context& ctx = s.get_context(); smt::theory_id th_id = m.get_family_id("weighted_maxsat"); smt::theory* th = ctx.get_theory(th_id); - if (!th) { - th = alloc(smt::theory_weighted_maxsat, m); - ctx.register_plugin(th); + smt::theory_weighted_maxsat* wth; + if (th) { + wth = dynamic_cast(th); + wth->reset(); } - smt::theory_weighted_maxsat* wth = dynamic_cast(th); + else { + wth = alloc(smt::theory_weighted_maxsat, m); + ctx.register_plugin(wth); + } + for (unsigned i = 0; i < soft_constraints.size(); ++i) { wth->assert_weighted(soft_constraints[i].get(), weights[i]); } From 42cbbe830ed7d802f25aba06d1082b1166b81153 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 Oct 2013 01:28:50 -0700 Subject: [PATCH 052/925] working on wmaxsmt Signed-off-by: Nikolaj Bjorner --- src/opt/opt_solver.h | 7 +++++++ src/opt/optimize_objectives.cpp | 13 +------------ src/opt/weighted_maxsat.cpp | 1 + 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 075aea1c5..3c149aefd 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -82,6 +82,13 @@ namespace opt { ~toggle_objective(); }; + class scoped_push { + opt_solver& s; + public: + scoped_push(opt_solver& s):s(s) { s.push(); } + ~scoped_push() { s.pop(1); } + }; + smt::context& get_context() { return m_context.get_context(); } // used by weighted maxsat. private: diff --git a/src/opt/optimize_objectives.cpp b/src/opt/optimize_objectives.cpp index 6d2d7168e..8ae2cd0a4 100644 --- a/src/opt/optimize_objectives.cpp +++ b/src/opt/optimize_objectives.cpp @@ -46,17 +46,6 @@ Notes: namespace opt { - class scoped_push { - opt_solver& s; - public: - scoped_push(opt_solver& s):s(s) { - s.push(); - } - ~scoped_push() { - s.pop(1); - } - }; - void optimize_objectives::set_cancel(bool f) { m_cancel = true; } @@ -86,7 +75,7 @@ namespace opt { return is_sat; } - scoped_push _push(s); + opt_solver::scoped_push _push(s); opt_solver::toggle_objective _t(s, true); diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 449c79ee1..cfb49bf2d 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -216,6 +216,7 @@ namespace opt { ctx.register_plugin(wth); } + opt_solver::scoped_push _s(s); for (unsigned i = 0; i < soft_constraints.size(); ++i) { wth->assert_weighted(soft_constraints[i].get(), weights[i]); } From 49aba844b8b5c0a9f177b956b4dc3f7aa52921a1 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Wed, 30 Oct 2013 10:04:56 -0700 Subject: [PATCH 053/925] Refactor network_flow Use a template method for pretty printing --- src/smt/network_flow.h | 9 ++---- src/smt/network_flow_def.h | 60 ++++++++++++-------------------------- 2 files changed, 22 insertions(+), 47 deletions(-) diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index 39574fd55..33f9bf7a6 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -35,11 +35,8 @@ Notes: namespace smt { - template - std::string pp_vector(std::string const & label, svector v, bool has_header = false); - - template - std::string pp_vector(std::string const & label, vector v, bool has_header = false); + template + std::string pp_vector(std::string const & label, TV v, bool has_header = false); // Solve minimum cost flow problem using Network Simplex algorithm template @@ -91,7 +88,7 @@ namespace smt { // Initialize the network with a feasible spanning tree void initialize(); - bool get_edge_id(dl_var source, dl_var target, edge_id & id); + edge_id get_edge_id(dl_var source, dl_var target); void update_potentials(); diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index b3be85a2f..f321f3385 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -24,8 +24,8 @@ Notes: namespace smt { - template - std::string pp_vector(std::string const & label, svector v, bool has_header) { + template + std::string pp_vector(std::string const & label, TV v, bool has_header) { std::ostringstream oss; if (has_header) { oss << "Index "; @@ -42,23 +42,6 @@ namespace smt { return oss.str(); } - template - std::string pp_vector(std::string const & label, vector v, bool has_header) { - std::ostringstream oss; - if (has_header) { - oss << "Index "; - for (unsigned i = 0; i < v.size(); ++i) { - oss << i << " "; - } - oss << std::endl; - } - oss << label << " "; - for (unsigned i = 0; i < v.size(); ++i) { - oss << v[i] << " "; - } - oss << std::endl; - return oss.str(); - } template network_flow::network_flow(graph & g, vector const & balances) : @@ -105,7 +88,7 @@ namespace smt { // Create artificial edges and initialize the spanning tree for (unsigned i = 0; i < num_nodes; ++i) { - m_upwards[i] = m_balances[i] >= fin_numeral::zero(); + m_upwards[i] = !m_balances[i].is_neg(); m_pred[i] = root; m_depth[i] = 1; m_thread[i] = i + 1; @@ -122,8 +105,7 @@ namespace smt { node u = m_thread[root]; while (u != root) { node v = m_pred[u]; - edge_id e_id; - get_edge_id(u, v, e_id); + edge_id e_id = get_edge_id(u, v); if (m_upwards[u]) { m_potentials[u] = m_potentials[v] - m_graph.get_weight(e_id); } @@ -142,16 +124,18 @@ namespace smt { } template - bool network_flow::get_edge_id(dl_var source, dl_var target, edge_id & id) { + edge_id network_flow::get_edge_id(dl_var source, dl_var target) { // m_upwards decides which node is the real source - return m_upwards[source] ? m_graph.get_edge_id(source, target, id) : m_graph.get_edge_id(target, source, id); + edge_id id; + VERIFY(m_upwards[source] ? m_graph.get_edge_id(source, target, id) : m_graph.get_edge_id(target, source, id)); + return id; } template void network_flow::update_potentials() { TRACE("network_flow", tout << "update_potentials...\n";); node src = m_graph.get_source(m_entering_edge); - node tgt = m_graph.get_source(m_entering_edge); + node tgt = m_graph.get_target(m_entering_edge); numeral cost = m_graph.get_weight(m_entering_edge); numeral change = m_upwards[src] ? (cost - m_potentials[src] + m_potentials[tgt]) : (-cost + m_potentials[src] - m_potentials[tgt]); @@ -169,14 +153,12 @@ namespace smt { m_flows[m_entering_edge] += val; node source = m_graph.get_source(m_entering_edge); for (unsigned u = source; u != m_join_node; u = m_pred[u]) { - edge_id e_id; - get_edge_id(u, m_pred[u], e_id); + edge_id e_id = get_edge_id(u, m_pred[u]); m_flows[e_id] += m_upwards[u] ? -val : val; } node target = m_graph.get_target(m_entering_edge); for (unsigned u = target; u != m_join_node; u = m_pred[u]) { - edge_id e_id; - get_edge_id(u, m_pred[u], e_id); + edge_id e_id = get_edge_id(u, m_pred[u]); m_flows[e_id] += m_upwards[u] ? val : -val; } TRACE("network_flow", tout << pp_vector("Flows", m_flows, true);); @@ -189,13 +171,13 @@ namespace smt { for (unsigned int i = 0; i < es.size(); ++i) { edge const & e = es[i]; edge_id e_id; - if (e.is_enabled() && m_graph.get_edge_id(e.get_source(), e.get_target(), e_id) && m_states[e_id] == NON_BASIS) { - node source = e.get_source(); - node target = e.get_target(); + node source = e.get_source(); + node target = e.get_target(); + if (e.is_enabled() && m_graph.get_edge_id(source, target, e_id) && m_states[e_id] == NON_BASIS) { numeral cost = e.get_weight() - m_potentials[source] + m_potentials[target]; // Choose the first negative-cost edge to be the violating edge // TODO: add multiple pivoting strategies - if (cost < numeral::zero()) { + if (cost.is_neg()) { m_entering_edge = e_id; TRACE("network_flow", { tout << "Found entering edge " << e_id << " between node "; @@ -234,8 +216,7 @@ namespace smt { node src, tgt; // Send flows along the path from source to the ancestor for (unsigned u = source; u != m_join_node; u = m_pred[u]) { - edge_id e_id; - get_edge_id(u, m_pred[u], e_id); + edge_id e_id = get_edge_id(u, m_pred[u]); numeral d = m_upwards[u] ? m_flows[e_id] : infty; if (d < m_delta) { m_delta = d; @@ -246,8 +227,7 @@ namespace smt { // Send flows along the path from target to the ancestor for (unsigned u = target; u != m_join_node; u = m_pred[u]) { - edge_id e_id; - get_edge_id(u, m_pred[u], e_id); + edge_id e_id = get_edge_id(u, m_pred[u]); numeral d = m_upwards[u] ? m_flows[e_id] : infty; if (d <= m_delta) { m_delta = d; @@ -257,7 +237,7 @@ namespace smt { } if (m_delta < infty) { - get_edge_id(src, tgt, m_leaving_edge); + m_leaving_edge = get_edge_id(src, tgt); TRACE("network_flow", { tout << "Found leaving edge " << m_leaving_edge; tout << " between node " << src << " and node " << tgt << "...\n"; @@ -391,12 +371,10 @@ namespace smt { typename network_flow::numeral network_flow::get_optimal_solution(vector & result, bool is_dual) { m_objective_value = numeral::zero(); vector const & es = m_graph.get_all_edges(); - fin_numeral cost; for (unsigned i = 0; i < es.size(); ++i) { edge const & e = es[i]; if (e.is_enabled() && m_states[i] == BASIS) { - cost = e.get_weight().get_rational(); - m_objective_value += cost * m_flows[i]; + m_objective_value += e.get_weight().get_rational() * m_flows[i]; } } result.reset(); From 9fc84f13898774e24d7eff65fba60a26f09ad67d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 Oct 2013 13:23:04 -0700 Subject: [PATCH 054/925] adding timeout, parameters, statistics Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.cpp | 1 - src/opt/opt_cmds.cpp | 45 +++++++++++++++++++++++++++------ src/opt/opt_context.cpp | 29 ++++++++++++++++++--- src/opt/opt_context.h | 14 +++++----- 4 files changed, 69 insertions(+), 20 deletions(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 023b30903..01536d78e 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1119,7 +1119,6 @@ void cmd_context::insert_aux_pdecl(pdecl * p) { } void cmd_context::reset(bool finalize) { - m_check_sat_result = 0; m_logic = symbol::null; m_check_sat_result = 0; m_numeral_as_real = false; diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index aa02eae4f..01d8b833e 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -25,8 +25,6 @@ Notes: - Deal with push/pop (later) - - Revisit weighted constraints if we want to group them using identifiers. - --*/ #include "opt_cmds.h" #include "cmd_context.h" @@ -34,6 +32,8 @@ Notes: #include "opt_context.h" #include "cancel_eh.h" #include "scoped_ctrl_c.h" +#include "scoped_timer.h" +#include "parametric_cmd.h" class opt_context { @@ -152,30 +152,44 @@ public: } }; -class optimize_cmd : public cmd { +class optimize_cmd : public parametric_cmd { opt_context& m_opt_ctx; public: optimize_cmd(opt_context& opt_ctx): - cmd("optimize"), + parametric_cmd("optimize"), m_opt_ctx(opt_ctx) {} - virtual char const * get_descr(cmd_context & ctx) const { return "check sat modulo objective function";} - virtual unsigned get_arity() const { return 0; } - virtual void prepare(cmd_context & ctx) {} + + virtual void init_pdescrs(cmd_context & ctx, param_descrs & p) { + insert_timeout(p); + insert_max_memory(p); + p.insert("print_statistics", CPK_BOOL, "(default: false) print statistics."); + } + + virtual char const * get_main_descr() const { return "check sat modulo objective function";} + virtual char const * get_usage() const { return "( )*"; } + virtual void prepare(cmd_context & ctx) { + parametric_cmd::prepare(ctx); + } virtual void failure_cleanup(cmd_context & ctx) { reset(ctx); } virtual void execute(cmd_context & ctx) { + params_ref p = ctx.params().merge_default_params(ps()); opt::context& opt = m_opt_ctx(); + opt.updt_params(p); + unsigned timeout = p.get_uint("timeout", UINT_MAX); + ptr_vector::const_iterator it = ctx.begin_assertions(); ptr_vector::const_iterator end = ctx.end_assertions(); for (; it != end; ++it) { opt.add_hard_constraint(*it); } - cancel_eh eh(opt); + cancel_eh eh(opt); { scoped_ctrl_c ctrlc(eh); + scoped_timer timer(timeout, &eh); cmd_context::scoped_watch sw(ctx); try { opt.optimize(); @@ -187,6 +201,21 @@ public: ctx.regular_stream() << "(error: " << ex.msg() << "\")" << std::endl; } } + if (p.get_bool("print_statistics", false)) { + display_statistics(ctx); + } + } +private: + + void display_statistics(cmd_context& ctx) { + statistics stats; + unsigned long long max_mem = memory::get_max_used_memory(); + unsigned long long mem = memory::get_allocation_size(); + stats.update("time", ctx.get_seconds()); + stats.update("memory", static_cast(mem)/static_cast(1024*1024)); + stats.update("max memory", static_cast(max_mem)/static_cast(1024*1024)); + m_opt_ctx().collect_statistics(stats); + stats.display_smt2(ctx.regular_stream()); } }; diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index d3a034e8f..64905a9fa 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -35,16 +35,23 @@ Notes: namespace opt { + context::context(ast_manager& m): + m(m), + m_hard_constraints(m), + m_soft_constraints(m), + m_objectives(m) + { + m_params.set_bool("model", true); + m_params.set_bool("unsat_core", true); + } + void context::optimize() { expr_ref_vector const& fmls = m_soft_constraints; if (!m_solver) { symbol logic; - params_ref p; - p.set_bool("model", true); - p.set_bool("unsat_core", true); - set_solver(alloc(opt_solver, m, p, logic)); + set_solver(alloc(opt_solver, m, m_params, logic)); } solver* s = m_solver.get(); @@ -140,5 +147,19 @@ namespace opt { m_is_max.push_back(is_max); } + void context::collect_statistics(statistics& stats) { + if (m_solver) { + m_solver->collect_statistics(stats); + } + } + + void context::updt_params(params_ref& p) { + m_params.append(p); + if (m_solver) { + m_solver->updt_params(m_params); + } + + } + } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 866bdf7d3..e2881906f 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -40,14 +40,10 @@ namespace opt { app_ref_vector m_objectives; svector m_is_max; ref m_solver; - + params_ref m_params; + public: - context(ast_manager& m): - m(m), - m_hard_constraints(m), - m_soft_constraints(m), - m_objectives(m) - {} + context(ast_manager& m); void add_soft_constraint(expr* f, rational const& w) { m_soft_constraints.push_back(f); @@ -69,6 +65,10 @@ namespace opt { void cancel(); void reset_cancel(); + void collect_statistics(statistics& stats); + + void updt_params(params_ref& p); + private: bool is_maxsat_problem() const; From 946b888b32d79e783e9793ff8bcbd4c491f2858e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 Oct 2013 13:24:21 -0700 Subject: [PATCH 055/925] adding timeout, parameters, statistics Signed-off-by: Nikolaj Bjorner --- src/opt/opt_cmds.cpp | 7 +------ src/opt/opt_solver.cpp | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index 01d8b833e..5acbec9dd 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -15,13 +15,8 @@ Author: Notes: TODO: - - integrate with parameters. - Parameter infrastructure lets us control setttings, such as - timeouts and control which backend optimization approach to - use during experiments. - - Display statistics properly on exit when configured to do so. - Also add appropriate statistics tracking to opt::context + - Add appropriate statistics tracking to opt::context - Deal with push/pop (later) diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 5cde65cdb..64d8a32be 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -1,3 +1,23 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + opt_solver.cpp + +Abstract: + + Wraps smt::kernel as a solver for optimization + +Author: + + Anh-Dung Phan (t-anphan) 2013-10-16 + +Notes: + + Based directly on smt_solver. + +--*/ #include"reg_decl_plugins.h" #include"opt_solver.h" #include"smt_context.h" From 86151b4d520d50665a87109e9f1495aab2a4e30f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 Oct 2013 13:38:47 -0700 Subject: [PATCH 056/925] dealing with cancel Signed-off-by: Nikolaj Bjorner --- src/opt/opt_cmds.cpp | 7 ++++++- src/opt/opt_context.cpp | 9 +++++---- src/opt/opt_context.h | 3 ++- src/opt/optimize_objectives.cpp | 23 ++++++++++++----------- src/opt/optimize_objectives.h | 6 +++--- 5 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index 5acbec9dd..bb8bf3e73 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -170,11 +170,16 @@ public: reset(ctx); } + virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { + return parametric_cmd::next_arg_kind(ctx); + } + + virtual void execute(cmd_context & ctx) { params_ref p = ctx.params().merge_default_params(ps()); opt::context& opt = m_opt_ctx(); opt.updt_params(p); - unsigned timeout = p.get_uint("timeout", UINT_MAX); + unsigned timeout = p.get_uint("timeout", UINT_MAX); ptr_vector::const_iterator it = ctx.begin_assertions(); ptr_vector::const_iterator end = ctx.end_assertions(); diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 64905a9fa..781b6582e 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -26,7 +26,6 @@ Notes: #include "opt_context.h" #include "fu_malik.h" #include "weighted_maxsat.h" -#include "optimize_objectives.h" #include "ast_pp.h" #include "opt_solver.h" #include "arith_decl_plugin.h" @@ -39,7 +38,8 @@ namespace opt { m(m), m_hard_constraints(m), m_soft_constraints(m), - m_objectives(m) + m_objectives(m), + m_opt_objectives(m) { m_params.set_bool("model", true); m_params.set_bool("unsat_core", true); @@ -83,8 +83,7 @@ namespace opt { for (unsigned i = 0; i < fmls_copy.size(); ++i) { s->assert_expr(fmls_copy[i].get()); } - optimize_objectives obj(m, get_opt_solver(*s)); // TBD: make an attribute - is_sat = obj(m_objectives, values); + is_sat = m_opt_objectives(get_opt_solver(*s), m_objectives, values); std::cout << "is-sat: " << is_sat << std::endl; if (is_sat != l_true) { @@ -126,12 +125,14 @@ namespace opt { if (m_solver) { m_solver->cancel(); } + m_opt_objectives.set_cancel(true); } void context::reset_cancel() { if (m_solver) { m_solver->reset_cancel(); } + m_opt_objectives.set_cancel(false); } void context::add_objective(app* t, bool is_max) { diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index e2881906f..c71b941c7 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -27,6 +27,7 @@ Notes: #include "ast.h" #include "solver.h" +#include "optimize_objectives.h" namespace opt { @@ -41,7 +42,7 @@ namespace opt { svector m_is_max; ref m_solver; params_ref m_params; - + optimize_objectives m_opt_objectives; public: context(ast_manager& m); diff --git a/src/opt/optimize_objectives.cpp b/src/opt/optimize_objectives.cpp index 8ae2cd0a4..d310abba6 100644 --- a/src/opt/optimize_objectives.cpp +++ b/src/opt/optimize_objectives.cpp @@ -67,28 +67,28 @@ namespace opt { ast_manager& m = objectives.get_manager(); arith_util autil(m); - s.reset_objectives(); + s->reset_objectives(); values.reset(); // First check_sat call to initialize theories - lbool is_sat = s.check_sat(0, 0); + lbool is_sat = s->check_sat(0, 0); if (is_sat == l_false) { return is_sat; } - opt_solver::scoped_push _push(s); + opt_solver::scoped_push _push(*s); - opt_solver::toggle_objective _t(s, true); + opt_solver::toggle_objective _t(*s, true); for (unsigned i = 0; i < objectives.size(); ++i) { - s.add_objective(objectives[i].get()); + s->add_objective(objectives[i].get()); values.push_back(inf_eps(rational(-1),inf_rational(0))); } - is_sat = s.check_sat(0, 0); + is_sat = s->check_sat(0, 0); while (is_sat == l_true && !m_cancel) { - set_max(values, s.get_objective_values()); + set_max(values, s->get_objective_values()); IF_VERBOSE(1, for (unsigned i = 0; i < values.size(); ++i) { verbose_stream() << values[i] << " "; @@ -99,11 +99,11 @@ namespace opt { for (unsigned i = 0; i < objectives.size(); ++i) { inf_eps const& v = values[i]; - disj.push_back(s.block_lower_bound(i, v)); + disj.push_back(s->block_lower_bound(i, v)); } constraint = m.mk_or(disj.size(), disj.c_ptr()); - s.assert_expr(constraint); - is_sat = s.check_sat(0, 0); + s->assert_expr(constraint); + is_sat = s->check_sat(0, 0); } @@ -117,7 +117,8 @@ namespace opt { Takes solver with hard constraints added. Returns an optimal assignment to objective functions. */ - lbool optimize_objectives::operator()(app_ref_vector& objectives, vector& values) { + lbool optimize_objectives::operator()(opt_solver& solver, app_ref_vector& objectives, vector& values) { + s = &solver; return basic_opt(objectives, values); } diff --git a/src/opt/optimize_objectives.h b/src/opt/optimize_objectives.h index 449b39df5..bacc27b09 100644 --- a/src/opt/optimize_objectives.h +++ b/src/opt/optimize_objectives.h @@ -29,12 +29,12 @@ namespace opt { class optimize_objectives { ast_manager& m; - opt_solver& s; + opt_solver* s; volatile bool m_cancel; public: - optimize_objectives(ast_manager& m, opt_solver& s): m(m), s(s), m_cancel(false) {} + optimize_objectives(ast_manager& m): m(m), s(0), m_cancel(false) {} - lbool operator()(app_ref_vector& objectives, vector& values); + lbool operator()(opt_solver& s, app_ref_vector& objectives, vector& values); void set_cancel(bool f); From 01c3dd779b5f36a32bf5686f3382023473a5ad74 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Wed, 30 Oct 2013 16:52:37 -0700 Subject: [PATCH 057/925] Add visualization of spanning trees --- src/smt/network_flow.h | 4 + src/smt/network_flow_def.h | 161 +++++++++++++++++++++----------- src/smt/theory_diff_logic_def.h | 6 +- 3 files changed, 112 insertions(+), 59 deletions(-) diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index 33f9bf7a6..865ac9791 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -85,6 +85,8 @@ namespace smt { node m_join_node; numeral m_delta; + unsigned m_step; + // Initialize the network with a feasible spanning tree void initialize(); @@ -105,6 +107,8 @@ namespace smt { void update_spanning_tree(); + std::string display_spanning_tree(); + public: network_flow(graph & g, vector const & balances); diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index f321f3385..32a98ce13 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -59,6 +59,8 @@ namespace smt { m_thread.resize(num_nodes); m_rev_thread.resize(num_nodes); m_final.resize(num_nodes); + + m_step = 0; } template @@ -69,6 +71,7 @@ namespace smt { unsigned num_edges = m_graph.get_num_edges(); node root = num_nodes; m_pred[root] = -1; + m_depth[root] = 0; m_thread[root] = 0; m_rev_thread[0] = root; m_final[root] = root - 1; @@ -121,11 +124,12 @@ namespace smt { tout << pp_vector("Depths", m_depth) << pp_vector("Upwards", m_upwards); tout << pp_vector("Potentials", m_potentials) << pp_vector("Flows", m_flows); }); + TRACE("network_flow", tout << "Spanning tree:\n" << display_spanning_tree();); } template edge_id network_flow::get_edge_id(dl_var source, dl_var target) { - // m_upwards decides which node is the real source + // m_upwards[source] decides which node is the real source edge_id id; VERIFY(m_upwards[source] ? m_graph.get_edge_id(source, target, id) : m_graph.get_edge_id(target, source, id)); return id; @@ -137,8 +141,7 @@ namespace smt { node src = m_graph.get_source(m_entering_edge); node tgt = m_graph.get_target(m_entering_edge); numeral cost = m_graph.get_weight(m_entering_edge); - numeral change = m_upwards[src] ? (cost - m_potentials[src] + m_potentials[tgt]) : - (-cost + m_potentials[src] - m_potentials[tgt]); + numeral change = m_upwards[src] ? (-cost + m_potentials[src] - m_potentials[tgt]) : (cost - m_potentials[src] + m_potentials[tgt]); node last = m_thread[m_final[src]]; for (node u = src; u != last; u = m_thread[u]) { m_potentials[u] += change; @@ -149,7 +152,7 @@ namespace smt { template void network_flow::update_flows() { TRACE("network_flow", tout << "update_flows...\n";); - numeral val = m_state[m_entering_edge] == NON_BASIS ? numeral::zero() : m_delta; + numeral val = m_states[m_entering_edge] == BASIS ? numeral::zero() : m_delta; m_flows[m_entering_edge] += val; node source = m_graph.get_source(m_entering_edge); for (unsigned u = source; u != m_join_node; u = m_pred[u]) { @@ -160,6 +163,7 @@ namespace smt { for (unsigned u = target; u != m_join_node; u = m_pred[u]) { edge_id e_id = get_edge_id(u, m_pred[u]); m_flows[e_id] += m_upwards[u] ? val : -val; + TRACE("network_flow", tout << u << ", " << m_pred[u] << ", " << e_id << ", " << m_upwards[u] << ", " << val;); } TRACE("network_flow", tout << pp_vector("Flows", m_flows, true);); } @@ -217,7 +221,7 @@ namespace smt { // Send flows along the path from source to the ancestor for (unsigned u = source; u != m_join_node; u = m_pred[u]) { edge_id e_id = get_edge_id(u, m_pred[u]); - numeral d = m_upwards[u] ? m_flows[e_id] : infty; + numeral d = m_upwards[u] ? infty : m_flows[e_id]; if (d < m_delta) { m_delta = d; src = u; @@ -250,75 +254,88 @@ namespace smt { template void network_flow::update_spanning_tree() { - node src_in = m_graph.get_source(m_entering_edge); - node tgt_in = m_graph.get_target(m_entering_edge); - node src_out = m_graph.get_source(m_leaving_edge); - node tgt_out = m_graph.get_target(m_leaving_edge); + node p = m_graph.get_source(m_entering_edge); + node q = m_graph.get_target(m_entering_edge); + node u = m_graph.get_source(m_leaving_edge); + node v = m_graph.get_target(m_leaving_edge); + TRACE("network_flow", { - tout << "update_spanning_tree: (" << src_in << ", " << tgt_in << ") enters, ("; - tout << src_out << ", " << tgt_out << ") leaves\n"; + tout << "update_spanning_tree: (" << p << ", " << q << ") enters, ("; + tout << u << ", " << v << ") leaves\n"; }); - node root = m_graph.get_num_nodes(); - node x = m_final[src_in]; + node x = m_final[p]; node y = m_thread[x]; - node z = m_final[src_out]; + node z = m_final[q]; - // Update m_pred (for nodes in the stem from tgt_in to tgt_out) - node u = tgt_in; - node last = m_pred[tgt_out]; - node parent = src_in; - while (u != last) { - node next = m_pred[u]; - m_pred[u] = parent; - m_upwards[u] = !m_upwards[u]; - parent = u; - u = next; + // Update m_pred (for nodes in the stem from q to v) + node n = q; + node last = m_pred[v]; + node parent = p; + while (n != last) { + node next = m_pred[n]; + m_pred[n] = parent; + m_upwards[n] = !m_upwards[n]; + parent = n; + n = next; } + TRACE("network_flow", tout << "Graft T_q and T_r'\n";); + // Graft T_q and T_r' - m_thread[x] = src_out; + m_thread[x] = q; m_thread[z] = y; - u = src_out; - while (u != m_final[src_out]) { - m_depth[u] += 1 + m_depth[src_in]; - u = m_pred[u]; + n = u; + last = m_final[u]; + while (n != last) { + m_depth[n] += 1 + m_depth[p]; + n = m_pred[n]; } - node gamma = m_thread[m_final[src_in]]; - for (node u = src_in; u != gamma; u = m_pred[u]) { - m_final[u] = z; + node gamma = m_thread[m_final[p]]; + n = p; + last = m_pred[gamma]; + while (n != last) { + m_final[n] = z; + n = m_pred[n]; } + TRACE("network_flow", tout << "Update T_r'\n";); + // Update T_r' - node phi = m_thread[tgt_out]; - node theta = m_thread[m_final[tgt_out]]; + node phi = m_rev_thread[v]; + node theta = m_thread[m_final[v]]; m_thread[phi] = theta; - gamma = m_thread[m_final[tgt_out]]; - // REVIEW: check f(u) is not in T_v - node delta = m_final[src_out] != m_final[tgt_out] ? m_final[src_out] : m_rev_thread[tgt_out]; - for (node u = src_in; u != gamma; u = m_pred[u]) { - m_final[u] = delta; + gamma = m_thread[m_final[v]]; + // REVIEW: check f(n) is not in T_v + node delta = m_final[u] != m_final[v] ? m_final[u] : phi; + n = u; + last = m_pred[gamma]; + while (n != last) { + m_final[n] = delta; + n = m_pred[n]; } // Reroot T_v at q - if (src_out != tgt_in) { - node u = m_pred[src_out]; - m_thread[m_final[src_out]] = u; - last = tgt_in; + if (u != q) { + TRACE("network_flow", tout << "Reroot T_v at q\n";); + + node n = m_pred[q]; + m_thread[m_final[q]] = n; + last = v; node alpha1, alpha2; unsigned count = 0; - while (u != last) { - // Find all immediate successors of u - node t1 = m_thread[u]; + while (n != last) { + // Find all immediate successors of n + node t1 = m_thread[n]; node t2 = m_thread[m_final[t1]]; node t3 = m_thread[m_final[t2]]; - if (t1 = m_pred[u]) { + if (t1 = m_pred[n]) { alpha1 = t2; alpha2 = t3; } - else if (t2 = m_pred[u]) { + else if (t2 == m_pred[n]) { alpha1 = t1; alpha2 = t3; } @@ -326,18 +343,18 @@ namespace smt { alpha1 = t1; alpha2 = t2; } - m_thread[u] = alpha1; + m_thread[n] = alpha1; m_thread[m_final[alpha1]] = alpha2; - u = m_pred[u]; - m_thread[m_final[alpha2]] = u; + n = m_pred[n]; + m_thread[m_final[alpha2]] = n; // Decrease depth of all children in the subtree ++count; - int d = m_depth[u] - count; - for (node v = m_thread[u]; v != m_final[u]; v = m_thread[v]) { - m_depth[v] -= d; + int d = m_depth[n] - count; + for (node m = m_thread[n]; m != m_final[n]; m = m_thread[m]) { + m_depth[m] -= d; } } - m_thread[m_final[alpha2]] = src_out; + m_thread[m_final[alpha2]] = v; } TRACE("network_flow", { @@ -347,6 +364,36 @@ namespace smt { }); } + template + std::string network_flow::display_spanning_tree() { + ++m_step;; + std::ostringstream oss; + std::string prefix = "T"; + prefix.append(std::to_string(m_step)); + prefix.append("_"); + unsigned root = m_graph.get_num_nodes() - 1; + for (unsigned i = 0; i < root; ++i) { + oss << prefix << i << "[shape=circle,label=\"" << prefix << i << " [" << m_potentials[i] << "]\"];\n"; + } + oss << prefix << root << "[shape=doublecircle,label=\"" << prefix << root << " [" << m_potentials[root] << "]\"];\n"; + + vector const & es = m_graph.get_all_edges(); + for (unsigned i = 0; i < es.size(); ++i) { + edge const & e = es[i]; + if (e.is_enabled()) { + oss << prefix << e.get_source() << " -> " << prefix << e.get_target(); + if (m_states[i] == BASIS) { + oss << "[color=red,penwidth=3.0,label=\"" << m_flows[i] << "\"];\n"; + } + else { + oss << "[label=\"" << m_flows[i] << "\"];\n"; + } + } + } + oss << std::endl; + return oss.str(); + } + // Minimize cost flows // Return true if found an optimal solution, and return false if unbounded template @@ -355,11 +402,13 @@ namespace smt { while (choose_entering_edge()) { bool bounded = choose_leaving_edge(); if (!bounded) return false; + update_flows(); if (m_entering_edge != m_leaving_edge) { m_states[m_entering_edge] = BASIS; m_states[m_leaving_edge] = NON_BASIS; update_spanning_tree(); - update_potentials(); + update_potentials(); + TRACE("network_flow", tout << "Spanning tree:\n" << display_spanning_tree();); } } TRACE("network_flow", tout << "Found optimal solution.\n";); diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index bcf22a2de..df78a2763 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -1007,7 +1007,7 @@ bool theory_diff_logic::maximize(theory_var v) { for (unsigned i = 0; i < objective.size(); ++i) { verbose_stream() << "coefficient " << objective[i].second << " of theory_var " << objective[i].first << "\n"; } - verbose_stream() << m_objective_consts[v] << "\n";); + verbose_stream() << "free coefficient " << m_objective_consts[v] << "\n";); // Objective coefficients now become balances vector balances(m_graph.get_num_nodes()); @@ -1024,9 +1024,9 @@ bool theory_diff_logic::maximize(theory_var v) { m_objective_value = net_flow.get_optimal_solution(potentials, true); std::cout << "Objective value of var " << v << ": " << m_objective_value << std::endl; // TODO: return the model of the optimal solution from potentials - IF_VERBOSE(1, + TRACE("network_flow", for (unsigned i = 0; i < potentials.size(); ++i) { - verbose_stream() << "v" << i << " -> " << potentials[i] << "\n"; + tout << "v" << i << " -> " << potentials[i] << "\n"; }); } From a3a7af84c5759d7f04d8a33f865ba815faeb6d64 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Wed, 30 Oct 2013 18:25:39 -0700 Subject: [PATCH 058/925] Minor updates --- src/smt/network_flow_def.h | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index 32a98ce13..02dd60e59 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -108,13 +108,8 @@ namespace smt { node u = m_thread[root]; while (u != root) { node v = m_pred[u]; - edge_id e_id = get_edge_id(u, v); - if (m_upwards[u]) { - m_potentials[u] = m_potentials[v] - m_graph.get_weight(e_id); - } - else { - m_potentials[u] = m_potentials[v] + m_graph.get_weight(e_id); - } + edge_id e_id = get_edge_id(u, v); + m_potentials[u] = m_potentials[v] + (m_upwards[u] ? - m_graph.get_weight(e_id) : m_graph.get_weight(e_id)); u = m_thread[u]; } @@ -163,7 +158,6 @@ namespace smt { for (unsigned u = target; u != m_join_node; u = m_pred[u]) { edge_id e_id = get_edge_id(u, m_pred[u]); m_flows[e_id] += m_upwards[u] ? val : -val; - TRACE("network_flow", tout << u << ", " << m_pred[u] << ", " << e_id << ", " << m_upwards[u] << ", " << val;); } TRACE("network_flow", tout << pp_vector("Flows", m_flows, true);); } @@ -175,10 +169,10 @@ namespace smt { for (unsigned int i = 0; i < es.size(); ++i) { edge const & e = es[i]; edge_id e_id; - node source = e.get_source(); - node target = e.get_target(); + node source = e.get_source(); + node target = e.get_target(); if (e.is_enabled() && m_graph.get_edge_id(source, target, e_id) && m_states[e_id] == NON_BASIS) { - numeral cost = e.get_weight() - m_potentials[source] + m_potentials[target]; + numeral cost = e.get_weight() - m_potentials[source] + m_potentials[target]; // Choose the first negative-cost edge to be the violating edge // TODO: add multiple pivoting strategies if (cost.is_neg()) { @@ -285,8 +279,8 @@ namespace smt { // Graft T_q and T_r' m_thread[x] = q; m_thread[z] = y; - n = u; - last = m_final[u]; + n = q; + last = m_final[q]; while (n != last) { m_depth[n] += 1 + m_depth[p]; n = m_pred[n]; @@ -373,9 +367,11 @@ namespace smt { prefix.append("_"); unsigned root = m_graph.get_num_nodes() - 1; for (unsigned i = 0; i < root; ++i) { - oss << prefix << i << "[shape=circle,label=\"" << prefix << i << " [" << m_potentials[i] << "]\"];\n"; + oss << prefix << i << "[shape=circle,label=\"" << prefix << i << " ["; + oss << m_potentials[i] << "/" << m_balances[i] << "]\"];\n"; } - oss << prefix << root << "[shape=doublecircle,label=\"" << prefix << root << " [" << m_potentials[root] << "]\"];\n"; + oss << prefix << root << "[shape=doublecircle,label=\"" << prefix << root << " ["; + oss << m_potentials[root] << "/" << m_balances[root] << "]\"];\n"; vector const & es = m_graph.get_all_edges(); for (unsigned i = 0; i < es.size(); ++i) { @@ -383,10 +379,10 @@ namespace smt { if (e.is_enabled()) { oss << prefix << e.get_source() << " -> " << prefix << e.get_target(); if (m_states[i] == BASIS) { - oss << "[color=red,penwidth=3.0,label=\"" << m_flows[i] << "\"];\n"; + oss << "[color=red,penwidth=3.0,label=\"" << m_flows[i] << "/" << e.get_weight() << "\"];\n"; } else { - oss << "[label=\"" << m_flows[i] << "\"];\n"; + oss << "[label=\"" << m_flows[i] << "/" << e.get_weight() << "\"];\n"; } } } From acc7aa1636f35b182b17119323656ff7f94f1e63 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 31 Oct 2013 00:57:36 -0700 Subject: [PATCH 059/925] use iterative weighted algorithm Signed-off-by: Nikolaj Bjorner --- src/opt/weighted_maxsat.cpp | 81 ++++++++++++++++++++++++++++++++++--- 1 file changed, 76 insertions(+), 5 deletions(-) diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index cfb49bf2d..81aa42586 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -26,6 +26,8 @@ namespace smt { class theory_weighted_maxsat : public theory { app_ref_vector m_vars; // Auxiliary variables per soft clause expr_ref_vector m_fmls; // Formulas per soft clause + app_ref m_min_cost_atom; // atom tracking modified lower bound + bool_var m_min_cost_bv; // min cost Boolean variable vector m_weights; // weights of theory variables. svector m_costs; // set of asserted theory variables svector m_cost_save; // set of asserted theory variables @@ -37,7 +39,8 @@ namespace smt { theory_weighted_maxsat(ast_manager& m): theory(m.mk_family_id("weighted_maxsat")), m_vars(m), - m_fmls(m) + m_fmls(m), + m_min_cost_atom(m) {} /** @@ -59,6 +62,7 @@ namespace smt { virtual void init_search_eh() { context & ctx = get_context(); ast_manager& m = get_manager(); + m_var2bool.reset(); for (unsigned i = 0; i < m_vars.size(); ++i) { app* var = m_vars[i].get(); bool_var bv; @@ -82,6 +86,20 @@ namespace smt { m_bool2var.insert(bv, v); SASSERT(v == m_var2bool.size()); m_var2bool.push_back(bv); + SASSERT(ctx.bool_var2enode(bv)); + } + if (m_min_cost_atom) { + app* var = m_min_cost_atom; + if (!ctx.e_internalized(var)) { + ctx.mk_enode(var, false, true, true); + } + if (ctx.b_internalized(var)) { + m_min_cost_bv = ctx.get_bool_var(var); + } + else { + m_min_cost_bv = ctx.mk_bool_var(var); + } + ctx.set_enode_flag(m_min_cost_bv, true); } } @@ -98,6 +116,23 @@ namespace smt { m_min_cost += w; } + rational const& get_min_cost() const { + return m_min_cost; + } + + expr* set_min_cost(rational const& c) { + ast_manager& m = get_manager(); + std::ostringstream strm; + strm << "cost <= " << c; + m_min_cost = c; + m_min_cost_atom = m.mk_fresh_const(strm.str().c_str(), m.mk_bool_sort()); + return m_min_cost_atom; + } + + bool found_solution() const { + return !m_cost_save.empty(); + } + virtual void assign_eh(bool_var v, bool is_true) { IF_VERBOSE(3, verbose_stream() << "Assign " << v << " " << is_true << "\n";); if (is_true) { @@ -109,13 +144,13 @@ namespace smt { m_cost += w; m_costs.push_back(tv); if (m_cost > m_min_cost) { - block(); + block(false); } } } virtual final_check_status final_check_eh() { - if (block()) { + if (block(true)) { return FC_CONTINUE; } else { @@ -146,6 +181,7 @@ namespace smt { m_min_cost.reset(); m_bool2var.reset(); m_var2bool.reset(); + m_min_cost_atom = 0; } virtual theory * mk_fresh(context * new_ctx) { return alloc(theory_weighted_maxsat, new_ctx->get_manager()); } @@ -166,7 +202,7 @@ namespace smt { } }; - bool block() { + bool block(bool is_final) { ast_manager& m = get_manager(); context& ctx = get_context(); literal_vector lits; @@ -178,22 +214,52 @@ namespace smt { weight += m_weights[costs[i]]; lits.push_back(~literal(m_var2bool[costs[i]])); } + if (m_min_cost_atom) { + lits.push_back(~literal(m_min_cost_bv)); + } IF_VERBOSE(2, verbose_stream() << "block: " << m_costs.size() << " " << lits.size() << " " << m_min_cost << "\n";); ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); - if (m_cost < m_min_cost) { + if (is_final && m_cost < m_min_cost) { m_min_cost = weight; m_cost_save.reset(); m_cost_save.append(m_costs); } return !lits.empty(); } + + }; } namespace opt { + /** + Iteratively increase min-cost until there is an assignment during + final_check that satisfies min_cost. + */ + + static lbool iterative_weighted_maxsat(opt_solver& s, smt::theory_weighted_maxsat& wth) { + ast_manager& m = s.get_context().get_manager(); + rational cost = wth.get_min_cost(); + rational log_cost(1), tmp(1); + while (tmp < cost) { + ++log_cost; + tmp *= rational(2); + } + expr_ref_vector bounds(m); + expr_ref bound(m); + lbool result = l_false; + while (log_cost <= cost && !wth.found_solution() && result != l_undef) { + std::cout << "cost: " << log_cost << "\n"; + bound = wth.set_min_cost(log_cost); + bounds.push_back(bound); + result = s.check_sat_core(1,bounds.c_ptr()+bounds.size()-1); + log_cost *= rational(2); + } + return result; + } /** Takes solver with hard constraints added. @@ -220,7 +286,12 @@ namespace opt { for (unsigned i = 0; i < soft_constraints.size(); ++i) { wth->assert_weighted(soft_constraints[i].get(), weights[i]); } +#if 0 lbool result = s.check_sat_core(0,0); +#else + lbool result = iterative_weighted_maxsat(s, *wth); +#endif + wth->get_assignment(soft_constraints); if (!soft_constraints.empty() && result == l_false) { result = l_true; From 0b65aa83e801c68b8159b892af282f60ac02d547 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 31 Oct 2013 02:02:37 -0700 Subject: [PATCH 060/925] preparing for inf extension of arithmetic Signed-off-by: Nikolaj Bjorner --- src/opt/optimize_objectives.cpp | 66 ++++++++++++++++++--------------- src/opt/optimize_objectives.h | 8 +++- src/smt/theory_arith.cpp | 3 +- src/smt/theory_arith.h | 22 +++++++++++ src/util/inf_eps_rational.h | 16 +++++++- src/util/inf_rational.h | 2 +- 6 files changed, 83 insertions(+), 34 deletions(-) diff --git a/src/opt/optimize_objectives.cpp b/src/opt/optimize_objectives.cpp index d310abba6..ffba96a9e 100644 --- a/src/opt/optimize_objectives.cpp +++ b/src/opt/optimize_objectives.cpp @@ -43,9 +43,11 @@ Notes: #include "optimize_objectives.h" #include "opt_solver.h" #include "arith_decl_plugin.h" +#include "smt_context.h" namespace opt { + void optimize_objectives::set_cancel(bool f) { m_cancel = true; } @@ -62,50 +64,29 @@ namespace opt { /* Enumerate locally optimal assignments until fixedpoint. */ - lbool optimize_objectives::basic_opt(app_ref_vector& objectives, vector& values) - { - ast_manager& m = objectives.get_manager(); + lbool optimize_objectives::basic_opt(app_ref_vector& objectives) { arith_util autil(m); - s->reset_objectives(); - values.reset(); + m_lower.reset(); + m_upper.reset(); // First check_sat call to initialize theories lbool is_sat = s->check_sat(0, 0); - if (is_sat == l_false) { + if (is_sat != l_true) { return is_sat; } opt_solver::scoped_push _push(*s); - opt_solver::toggle_objective _t(*s, true); for (unsigned i = 0; i < objectives.size(); ++i) { s->add_objective(objectives[i].get()); - values.push_back(inf_eps(rational(-1),inf_rational(0))); + m_lower.push_back(inf_eps(rational(-1),inf_rational(0))); + m_upper.push_back(inf_eps(rational(1), inf_rational(0))); } - - is_sat = s->check_sat(0, 0); - while (is_sat == l_true && !m_cancel) { - set_max(values, s->get_objective_values()); - IF_VERBOSE(1, - for (unsigned i = 0; i < values.size(); ++i) { - verbose_stream() << values[i] << " "; - } - verbose_stream() << "\n";); - expr_ref_vector disj(m); - expr_ref constraint(m); - - for (unsigned i = 0; i < objectives.size(); ++i) { - inf_eps const& v = values[i]; - disj.push_back(s->block_lower_bound(i, v)); - } - constraint = m.mk_or(disj.size(), disj.c_ptr()); - s->assert_expr(constraint); - is_sat = s->check_sat(0, 0); + is_sat = update_lower(); } - if (m_cancel || is_sat == l_undef) { return l_undef; @@ -113,13 +94,40 @@ namespace opt { return l_true; } + lbool optimize_objectives::update_lower() { + lbool is_sat = s->check_sat(0, 0); + set_max(m_lower, s->get_objective_values()); + IF_VERBOSE(1, + for (unsigned i = 0; i < m_lower.size(); ++i) { + verbose_stream() << m_lower[i] << " "; + } + verbose_stream() << "\n";); + expr_ref_vector disj(m); + expr_ref constraint(m); + + for (unsigned i = 0; i < m_lower.size(); ++i) { + inf_eps const& v = m_lower[i]; + disj.push_back(s->block_lower_bound(i, v)); + } + constraint = m.mk_or(disj.size(), disj.c_ptr()); + s->assert_expr(constraint); + return is_sat; + } + + lbool optimize_objectives::update_upper() { + return l_undef; + } + /** Takes solver with hard constraints added. Returns an optimal assignment to objective functions. */ lbool optimize_objectives::operator()(opt_solver& solver, app_ref_vector& objectives, vector& values) { s = &solver; - return basic_opt(objectives, values); + lbool result = basic_opt(objectives); + values.reset(); + values.append(m_lower); + return result; } } diff --git a/src/opt/optimize_objectives.h b/src/opt/optimize_objectives.h index bacc27b09..cb3176d0d 100644 --- a/src/opt/optimize_objectives.h +++ b/src/opt/optimize_objectives.h @@ -31,6 +31,8 @@ namespace opt { ast_manager& m; opt_solver* s; volatile bool m_cancel; + vector m_lower; + vector m_upper; public: optimize_objectives(ast_manager& m): m(m), s(0), m_cancel(false) {} @@ -40,10 +42,14 @@ namespace opt { private: - lbool basic_opt(app_ref_vector& objectives, vector& values); + lbool basic_opt(app_ref_vector& objectives); void set_max(vector& dst, vector const& src); + lbool update_lower(); + + lbool update_upper(); + }; }; diff --git a/src/smt/theory_arith.cpp b/src/smt/theory_arith.cpp index 0bb356b95..6c18b66c3 100644 --- a/src/smt/theory_arith.cpp +++ b/src/smt/theory_arith.cpp @@ -25,5 +25,6 @@ namespace smt { template class theory_arith; // template class theory_arith; // template class theory_arith; - + + // TBD: template class smt::theory_arith; }; diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 20631ea27..80731ab1d 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -1121,11 +1121,33 @@ namespace smt { } smi_ext() : m_int_epsilon(s_integer(1)), m_real_epsilon(s_integer(0), true) {} }; + + class inf_ext { + public: + typedef rational numeral; + typedef inf_eps_rational inf_numeral; + inf_numeral m_int_epsilon; + inf_numeral m_real_epsilon; + numeral fractional_part(inf_numeral const& n) { + SASSERT(n.is_rational()); + return n.get_rational() - floor(n); + } + static numeral fractional_part(numeral const & n) { + return n - floor(n); + } + static inf_numeral mk_inf_numeral(numeral const & n, numeral const & r) { + return inf_numeral(inf_rational(n, r)); + } + inf_ext() : m_int_epsilon(inf_rational(rational(1))), m_real_epsilon(inf_rational(rational(0), true)) {} + }; + typedef theory_arith theory_mi_arith; typedef theory_arith theory_i_arith; + typedef smt::theory_arith theory_inf_arith; // typedef theory_arith theory_si_arith; // typedef theory_arith theory_smi_arith; + }; diff --git a/src/util/inf_eps_rational.h b/src/util/inf_eps_rational.h index 1d6d04818..a8d32e2b2 100644 --- a/src/util/inf_eps_rational.h +++ b/src/util/inf_eps_rational.h @@ -143,16 +143,28 @@ class inf_eps_rational { return m_infty; } + static const inf_eps_rational & zero() { + return inf_eps_rational(Numeral::zero()); + } + + static const inf_eps_rational & one() { + return inf_eps_rational(Numeral::one()); + } + + static const inf_eps_rational & minus_one() { + return inf_eps_rational(Numeral::minus_one()); + } + inf_eps_rational & operator=(const inf_eps_rational & r) { m_infty = r.m_infty; m_r = r.m_r; return *this; } - inf_eps_rational & operator=(const rational & r) { + inf_eps_rational & operator=(const Numeral & r) { m_infty.reset(); m_r = r; - return *this; + return *this; } inf_eps_rational & operator+=(const inf_eps_rational & r) { diff --git a/src/util/inf_rational.h b/src/util/inf_rational.h index 5cdfe9e93..2da99cca5 100644 --- a/src/util/inf_rational.h +++ b/src/util/inf_rational.h @@ -88,7 +88,7 @@ class inf_rational { m_second(pos_inf?rational(1):rational(-1)) {} - explicit inf_rational(rational const& r): + inf_rational(rational const& r): m_first(r) { m_second.reset(); From 5106c74b3e17a973ca16c8aa47025e59669519ad Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 31 Oct 2013 02:13:24 -0700 Subject: [PATCH 061/925] preparing for inf extension of arithmetic Signed-off-by: Nikolaj Bjorner --- src/opt/optimize_objectives.cpp | 3 ++- src/smt/theory_arith.cpp | 2 +- src/smt/theory_arith.h | 2 +- src/smt/theory_arith_aux.h | 2 +- src/util/inf_eps_rational.h | 6 +++--- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/opt/optimize_objectives.cpp b/src/opt/optimize_objectives.cpp index ffba96a9e..8e76a2914 100644 --- a/src/opt/optimize_objectives.cpp +++ b/src/opt/optimize_objectives.cpp @@ -43,7 +43,7 @@ Notes: #include "optimize_objectives.h" #include "opt_solver.h" #include "arith_decl_plugin.h" -#include "smt_context.h" +#include "theory_arith.h" namespace opt { @@ -115,6 +115,7 @@ namespace opt { } lbool optimize_objectives::update_upper() { + NOT_IMPLEMENTED_YET(); return l_undef; } diff --git a/src/smt/theory_arith.cpp b/src/smt/theory_arith.cpp index 6c18b66c3..9a7d08151 100644 --- a/src/smt/theory_arith.cpp +++ b/src/smt/theory_arith.cpp @@ -26,5 +26,5 @@ namespace smt { // template class theory_arith; // template class theory_arith; - // TBD: template class smt::theory_arith; + template class smt::theory_arith; }; diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 80731ab1d..75a0f9ff3 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -432,7 +432,7 @@ namespace smt { bool m_eager_gcd; // true if gcd should be applied at every add_row unsigned m_final_check_idx; - inf_rational m_objective_value; + inf_eps_rational m_objective_value; // backtracking svector m_bound_trail; diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index d43d1ef24..a1fff392f 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -999,7 +999,7 @@ namespace smt { template inf_eps_rational theory_arith::get_objective_value(theory_var v) { - return inf_eps_rational(m_objective_value); + return m_objective_value; } /** diff --git a/src/util/inf_eps_rational.h b/src/util/inf_eps_rational.h index a8d32e2b2..d7fdaf4fc 100644 --- a/src/util/inf_eps_rational.h +++ b/src/util/inf_eps_rational.h @@ -143,15 +143,15 @@ class inf_eps_rational { return m_infty; } - static const inf_eps_rational & zero() { + static inf_eps_rational zero() { return inf_eps_rational(Numeral::zero()); } - static const inf_eps_rational & one() { + static inf_eps_rational one() { return inf_eps_rational(Numeral::one()); } - static const inf_eps_rational & minus_one() { + static inf_eps_rational minus_one() { return inf_eps_rational(Numeral::minus_one()); } From 637b63cbe1cd221b1b90e066315d92a67c495ed8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 31 Oct 2013 02:15:08 -0700 Subject: [PATCH 062/925] preparing for inf extension of arithmetic Signed-off-by: Nikolaj Bjorner --- src/opt/optimize_objectives.cpp | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/opt/optimize_objectives.cpp b/src/opt/optimize_objectives.cpp index 8e76a2914..8e111953e 100644 --- a/src/opt/optimize_objectives.cpp +++ b/src/opt/optimize_objectives.cpp @@ -96,21 +96,23 @@ namespace opt { lbool optimize_objectives::update_lower() { lbool is_sat = s->check_sat(0, 0); - set_max(m_lower, s->get_objective_values()); - IF_VERBOSE(1, - for (unsigned i = 0; i < m_lower.size(); ++i) { - verbose_stream() << m_lower[i] << " "; - } - verbose_stream() << "\n";); - expr_ref_vector disj(m); - expr_ref constraint(m); - - for (unsigned i = 0; i < m_lower.size(); ++i) { - inf_eps const& v = m_lower[i]; - disj.push_back(s->block_lower_bound(i, v)); + if (is_sat == l_true) { + set_max(m_lower, s->get_objective_values()); + IF_VERBOSE(1, + for (unsigned i = 0; i < m_lower.size(); ++i) { + verbose_stream() << m_lower[i] << " "; + } + verbose_stream() << "\n";); + expr_ref_vector disj(m); + expr_ref constraint(m); + + for (unsigned i = 0; i < m_lower.size(); ++i) { + inf_eps const& v = m_lower[i]; + disj.push_back(s->block_lower_bound(i, v)); + } + constraint = m.mk_or(disj.size(), disj.c_ptr()); + s->assert_expr(constraint); } - constraint = m.mk_or(disj.size(), disj.c_ptr()); - s->assert_expr(constraint); return is_sat; } From 72e82532b2495cb51938b104fc830e3f2867e793 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 31 Oct 2013 09:43:15 -0700 Subject: [PATCH 063/925] enabling upper bound test Signed-off-by: Nikolaj Bjorner --- src/opt/opt_solver.cpp | 6 +++- src/opt/opt_solver.h | 1 - src/opt/optimize_objectives.cpp | 63 +++++++++++++++++++++++---------- src/opt/optimize_objectives.h | 1 + src/smt/theory_arith.h | 8 ++--- src/smt/theory_arith_aux.h | 36 +++++++++---------- src/smt/theory_arith_core.h | 8 ++--- src/smt/theory_arith_pp.h | 2 +- src/smt/theory_opt.h | 8 +++-- 9 files changed, 82 insertions(+), 51 deletions(-) diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 64d8a32be..515edcbff 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -77,6 +77,9 @@ namespace opt { else if (typeid(smt::theory_i_arith) == typeid(*arith_theory)) { return dynamic_cast(*arith_theory); } + else if (typeid(smt::theory_inf_arith) == typeid(*arith_theory)) { + return dynamic_cast(*arith_theory); + } else if (typeid(smt::theory_rdl&) == typeid(*arith_theory)) { return dynamic_cast(*arith_theory); } @@ -172,7 +175,8 @@ namespace opt { return expr_ref(m.mk_true(), m); } else { - return expr_ref(get_optimizer().block_lower_bound(m_objective_vars[var], val.get_numeral()), m); + inf_rational n = val.get_numeral(); + return expr_ref(get_optimizer().block_lower_bound(m_objective_vars[var], n), m); } } diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 3c149aefd..4afa65f31 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -91,7 +91,6 @@ namespace opt { smt::context& get_context() { return m_context.get_context(); } // used by weighted maxsat. - private: smt::theory_opt& get_optimizer(); }; } diff --git a/src/opt/optimize_objectives.cpp b/src/opt/optimize_objectives.cpp index 8e111953e..086c52bf4 100644 --- a/src/opt/optimize_objectives.cpp +++ b/src/opt/optimize_objectives.cpp @@ -66,24 +66,16 @@ namespace opt { */ lbool optimize_objectives::basic_opt(app_ref_vector& objectives) { arith_util autil(m); - s->reset_objectives(); - m_lower.reset(); - m_upper.reset(); - // First check_sat call to initialize theories - lbool is_sat = s->check_sat(0, 0); - if (is_sat != l_true) { - return is_sat; - } opt_solver::scoped_push _push(*s); opt_solver::toggle_objective _t(*s, true); for (unsigned i = 0; i < objectives.size(); ++i) { - s->add_objective(objectives[i].get()); - m_lower.push_back(inf_eps(rational(-1),inf_rational(0))); - m_upper.push_back(inf_eps(rational(1), inf_rational(0))); + m_vars.push_back(s->add_objective(objectives[i].get())); } - + + lbool is_sat = l_true; + // ready to test: is_sat = update_upper(); while (is_sat == l_true && !m_cancel) { is_sat = update_lower(); } @@ -117,8 +109,31 @@ namespace opt { } lbool optimize_objectives::update_upper() { - NOT_IMPLEMENTED_YET(); - return l_undef; + smt::theory_opt& opt = s->get_optimizer(); + + if (typeid(smt::theory_inf_arith) != typeid(opt)) { + return l_true; + } + smt::theory_inf_arith& th = dynamic_cast(opt); + + expr_ref bound(m); + lbool is_sat = l_true; + + for (unsigned i = 0; i < m_lower.size(); ++i) { + if (m_lower[i] < m_upper[i]) { + opt_solver::scoped_push _push(*s); + smt::theory_var v = m_vars[i]; + bound = th.block_upper_bound(v, m_upper[i]); + expr* bounds[1] = { bound }; + is_sat = s->check_sat(1, bounds); + if (is_sat) { + IF_VERBOSE(1, verbose_stream() << "Setting lower bound for " << v << " to " << m_upper[i] << "\n";); + m_lower[i] = m_upper[i]; + } + // else: TBD extract Farkas coefficients. + } + } + return l_true; } /** @@ -127,10 +142,22 @@ namespace opt { */ lbool optimize_objectives::operator()(opt_solver& solver, app_ref_vector& objectives, vector& values) { s = &solver; - lbool result = basic_opt(objectives); - values.reset(); - values.append(m_lower); - return result; + s->reset_objectives(); + m_lower.reset(); + m_upper.reset(); + for (unsigned i = 0; i < objectives.size(); ++i) { + m_lower.push_back(inf_eps(rational(-1),inf_rational(0))); + m_upper.push_back(inf_eps(rational(1), inf_rational(0))); + } + + // First check_sat call to initialize theories + lbool is_sat = s->check_sat(0, 0); + if (is_sat == l_true) { + is_sat = basic_opt(objectives); + values.reset(); + values.append(m_lower); + } + return is_sat; } } diff --git a/src/opt/optimize_objectives.h b/src/opt/optimize_objectives.h index cb3176d0d..227cd8f00 100644 --- a/src/opt/optimize_objectives.h +++ b/src/opt/optimize_objectives.h @@ -33,6 +33,7 @@ namespace opt { volatile bool m_cancel; vector m_lower; vector m_upper; + svector m_vars; public: optimize_objectives(ast_manager& m): m(m), s(0), m_cancel(false) {} diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 75a0f9ff3..56c361a93 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -273,14 +273,14 @@ namespace smt { class atom : public bound { protected: bool_var m_bvar; - numeral m_k; + inf_numeral m_k; unsigned m_atom_kind:2; // atom kind unsigned m_is_true:1; // cache: true if the atom was assigned to true. public: - atom(bool_var bv, theory_var v, numeral const & k, atom_kind kind); + atom(bool_var bv, theory_var v, inf_numeral const & k, atom_kind kind); atom_kind get_atom_kind() const { return static_cast(m_atom_kind); } virtual ~atom() {} - numeral const & get_k() const { return m_k; } + inf_numeral const & get_k() const { return m_k; } bool_var get_bool_var() const { return m_bvar; } bool is_true() const { return m_is_true; } void assign_eh(bool is_true, inf_numeral const & epsilon); @@ -999,7 +999,7 @@ namespace smt { virtual theory_var add_objective(app* term); virtual inf_eps_rational get_objective_value(theory_var v); virtual expr* block_lower_bound(theory_var v, inf_rational const& val); - + virtual expr* block_upper_bound(theory_var v, inf_numeral const& val); // ----------------------------------- // // Pretty Printing diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index a1fff392f..a84a9ebf9 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -367,7 +367,7 @@ namespace smt { // ----------------------------------- template - theory_arith::atom::atom(bool_var bv, theory_var v, numeral const & k, atom_kind kind): + theory_arith::atom::atom(bool_var bv, theory_var v, inf_numeral const & k, atom_kind kind): bound(v, inf_numeral::zero(), B_LOWER, true), m_bvar(bv), m_k(k), @@ -997,6 +997,22 @@ namespace smt { } } + template + expr* theory_arith::block_upper_bound(theory_var v, inf_numeral const& val) { + ast_manager& m = get_manager(); + context& ctx = get_context(); + std::ostringstream strm; + strm << val << " <= " << v; + expr* b = m.mk_fresh_const(strm.str().c_str(), m.mk_bool_sort()); + bool_var bv = ctx.mk_bool_var(b); + atom* a = alloc(atom, bv, v, val, A_LOWER); + m_unassigned_atoms[v]++; + m_var_occs[v].push_back(a); + m_atoms.push_back(a); + insert_bv2a(bv, a); + return b; + } + template inf_eps_rational theory_arith::get_objective_value(theory_var v) { return m_objective_value; @@ -1117,15 +1133,6 @@ namespace smt { ); pivot(x_i, x_j, a_ij, false); - TRACE("maximize", tout << "max: " << max << ", x_i: v" << x_i << ", x_j: v" << x_j << ", a_ij: " << a_ij << ", coeff: " << coeff << "\n"; - if (upper(x_i)) tout << "upper x_i: " << upper_bound(x_i) << " "; - if (lower(x_i)) tout << "lower x_i: " << lower_bound(x_i) << " "; - tout << "value x_i: " << get_value(x_i) << "\n"; - if (upper(x_j)) tout << "upper x_j: " << upper_bound(x_j) << " "; - if (lower(x_j)) tout << "lower x_j: " << lower_bound(x_j) << " "; - tout << "value x_j: " << get_value(x_j) << "\n"; - - ); SASSERT(is_non_base(x_i)); SASSERT(is_base(x_j)); @@ -1137,15 +1144,6 @@ namespace smt { move_xi_to_lower = a_ij.is_neg(); move_to_bound(x_i, move_xi_to_lower); - TRACE("maximize", tout << "max: " << max << ", x_i: v" << x_i << ", x_j: v" << x_j << ", a_ij: " << a_ij << ", coeff: " << coeff << "\n"; - if (upper(x_i)) tout << "upper x_i: " << upper_bound(x_i) << " "; - if (lower(x_i)) tout << "lower x_i: " << lower_bound(x_i) << " "; - tout << "value x_i: " << get_value(x_i) << "\n"; - if (upper(x_j)) tout << "upper x_j: " << upper_bound(x_j) << " "; - if (lower(x_j)) tout << "lower x_j: " << lower_bound(x_j) << " "; - tout << "value x_j: " << get_value(x_j) << "\n"; - ); - row & r2 = m_rows[get_var_row(x_j)]; coeff.neg(); add_tmp_row(r, coeff, r2); diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 195d78e25..11484c779 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -801,7 +801,7 @@ namespace smt { void theory_arith::mk_bound_axioms(atom * a1) { theory_var v = a1->get_var(); literal l1(a1->get_bool_var()); - numeral const & k1(a1->get_k()); + inf_numeral const & k1(a1->get_k()); atom_kind kind1 = a1->get_atom_kind(); TRACE("mk_bound_axioms", tout << "making bound axioms for v" << v << " " << kind1 << " " << k1 << "\n";); atoms & occs = m_var_occs[v]; @@ -810,7 +810,7 @@ namespace smt { for (; it != end; ++it) { atom * a2 = *it; literal l2(a2->get_bool_var()); - numeral const & k2 = a2->get_k(); + inf_numeral const & k2 = a2->get_k(); atom_kind kind2 = a2->get_atom_kind(); SASSERT(k1 != k2 || kind1 != kind2); SASSERT(a2->get_var() == v); @@ -880,7 +880,7 @@ namespace smt { ctx.set_var_theory(bv, get_id()); rational _k; m_util.is_numeral(rhs, _k); - numeral k(_k); + inf_numeral k(_k); atom * a = alloc(atom, bv, v, k, kind); mk_bound_axioms(a); m_unassigned_atoms[v]++; @@ -2475,7 +2475,7 @@ namespace smt { bool_var bv = a->get_bool_var(); literal l(bv); if (get_context().get_assignment(bv) == l_undef) { - numeral const & k2 = a->get_k(); + inf_numeral const & k2 = a->get_k(); delta.reset(); if (a->get_atom_kind() == A_LOWER) { // v >= k k >= k2 |- v >= k2 diff --git a/src/smt/theory_arith_pp.h b/src/smt/theory_arith_pp.h index 274cd5499..4eeb6a189 100644 --- a/src/smt/theory_arith_pp.h +++ b/src/smt/theory_arith_pp.h @@ -428,7 +428,7 @@ namespace smt { template void theory_arith::display_atom(std::ostream & out, atom * a, bool show_sign) const { theory_var v = a->get_var(); - numeral const & k = a->get_k(); + inf_numeral const & k = a->get_k(); enode * e = get_enode(v); if (show_sign) { if (!a->is_true()) diff --git a/src/smt/theory_opt.h b/src/smt/theory_opt.h index f1c6c242d..d57875712 100644 --- a/src/smt/theory_opt.h +++ b/src/smt/theory_opt.h @@ -27,14 +27,16 @@ Notes: namespace smt { class theory_opt { public: + typedef inf_eps_rational inf_eps; virtual bool maximize(theory_var v) { UNREACHABLE(); return false; }; virtual theory_var add_objective(app* term) { UNREACHABLE(); return null_theory_var; } - virtual inf_eps_rational get_objective_value(theory_var v) { + virtual inf_eps get_objective_value(theory_var v) { UNREACHABLE(); - inf_eps_rational r(rational(1), inf_rational(0)); - return r; + return inf_eps(rational(1), inf_rational(0)); } virtual expr* block_lower_bound(theory_var v, inf_rational const& val) { return 0; } + + }; } From 1a32a64b96a2269253aae57428cc0006bb81fcb1 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Thu, 31 Oct 2013 12:11:56 -0700 Subject: [PATCH 064/925] Use constraint graphs for minimum cost flow correctly --- src/smt/diff_logic.h | 4 +- src/smt/network_flow.h | 5 +- src/smt/network_flow_def.h | 120 ++++++++++++++++++++++++------------- 3 files changed, 85 insertions(+), 44 deletions(-) diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index b96a038eb..cf0d5f5a6 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -933,7 +933,7 @@ public: return found; } - // Return true if there is an edge source --> target. + // Return true if there is an edge source --> target (also counting disabled edges). // If there is such edge, return its edge_id in parameter id. bool get_edge_id(dl_var source, dl_var target, edge_id & id) { edge_id_vector & edges = m_out_edges[source]; @@ -942,7 +942,7 @@ public: for (; it != end; ++it) { id = *it; edge & e = m_edges[id]; - if (e.is_enabled() && e.get_target() == target) { + if (e.get_target() == target) { return true; } } diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index 865ac9791..02ac563d1 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -66,14 +66,15 @@ namespace smt { svector m_states; - // An element is true if the corresponding edge points upwards (compared to the root node) + // m_upwards[i] is true if the corresponding edge + // (i, m_pred[i]) points upwards (pointing toward the root node) svector m_upwards; // Store the parent of a node i in the spanning tree svector m_pred; // Store the number of edge on the path from node i to the root svector m_depth; - // Store the pointer from node i to the next node in depth first search ordering + // Store the pointer from node i to the next node in depth-first search order svector m_thread; // Reverse orders of m_thread svector m_rev_thread; diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index 02dd60e59..a3a1b86b8 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -45,8 +45,20 @@ namespace smt { template network_flow::network_flow(graph & g, vector const & balances) : - m_graph(g), m_balances(balances) { + // Network flow graph has the edges in the reversed order compared to constraint graph + // We only take enabled edges from the original graph + for (unsigned i = 0; i < g.get_num_nodes(); ++i) { + m_graph.init_var(i); + } + vector const & es = g.get_all_edges(); + for (unsigned i = 0; i < es.size(); ++i) { + edge const & e = es[i]; + if (e.is_enabled()) { + m_graph.add_edge(e.get_target(), e.get_source(), e.get_weight(), explanation()); + } + } + unsigned num_nodes = m_graph.get_num_nodes() + 1; unsigned num_edges = m_graph.get_num_edges(); @@ -89,7 +101,7 @@ namespace smt { m_states.resize(num_nodes + num_edges); m_states.fill(NON_BASIS); - // Create artificial edges and initialize the spanning tree + // Create artificial edges from/to root node to/from other nodes and initialize the spanning tree for (unsigned i = 0; i < num_nodes; ++i) { m_upwards[i] = !m_balances[i].is_neg(); m_pred[i] = root; @@ -101,12 +113,13 @@ namespace smt { node src = m_upwards[i] ? i : root; node tgt = m_upwards[i] ? root : i; m_flows[num_edges + i] = m_upwards[i] ? m_balances[i] : -m_balances[i]; - m_graph.enable_edge(m_graph.add_edge(src, tgt, numeral::one(), explanation())); + m_graph.add_edge(src, tgt, numeral::one(), explanation()); } // Compute initial potentials node u = m_thread[root]; while (u != root) { + bool direction = m_upwards[u]; node v = m_pred[u]; edge_id e_id = get_edge_id(u, v); m_potentials[u] = m_potentials[v] + (m_upwards[u] ? - m_graph.get_weight(e_id) : m_graph.get_weight(e_id)); @@ -166,20 +179,19 @@ namespace smt { bool network_flow::choose_entering_edge() { TRACE("network_flow", tout << "choose_entering_edge...\n";); vector const & es = m_graph.get_all_edges(); - for (unsigned int i = 0; i < es.size(); ++i) { - edge const & e = es[i]; - edge_id e_id; - node source = e.get_source(); - node target = e.get_target(); - if (e.is_enabled() && m_graph.get_edge_id(source, target, e_id) && m_states[e_id] == NON_BASIS) { - numeral cost = e.get_weight() - m_potentials[source] + m_potentials[target]; + for (unsigned i = 0; i < es.size(); ++i) { + node src = m_graph.get_source(i); + node tgt = m_graph.get_target(i); + if (m_states[i] == NON_BASIS) { + numeral cost = m_graph.get_weight(i); + numeral change = cost - m_potentials[src] + m_potentials[tgt]; // Choose the first negative-cost edge to be the violating edge // TODO: add multiple pivoting strategies - if (cost.is_neg()) { - m_entering_edge = e_id; + if (change.is_neg()) { + m_entering_edge = i; TRACE("network_flow", { - tout << "Found entering edge " << e_id << " between node "; - tout << source << " and node " << target << "...\n"; + tout << "Found entering edge " << i << " between node "; + tout << src << " and node " << tgt << "...\n"; }); return true; } @@ -215,7 +227,7 @@ namespace smt { // Send flows along the path from source to the ancestor for (unsigned u = source; u != m_join_node; u = m_pred[u]) { edge_id e_id = get_edge_id(u, m_pred[u]); - numeral d = m_upwards[u] ? infty : m_flows[e_id]; + numeral d = m_upwards[u] ? m_flows[e_id] : infty; if (d < m_delta) { m_delta = d; src = u; @@ -226,7 +238,7 @@ namespace smt { // Send flows along the path from target to the ancestor for (unsigned u = target; u != m_join_node; u = m_pred[u]) { edge_id e_id = get_edge_id(u, m_pred[u]); - numeral d = m_upwards[u] ? m_flows[e_id] : infty; + numeral d = m_upwards[u] ? infty : m_flows[e_id]; if (d <= m_delta) { m_delta = d; src = u; @@ -249,9 +261,26 @@ namespace smt { template void network_flow::update_spanning_tree() { node p = m_graph.get_source(m_entering_edge); - node q = m_graph.get_target(m_entering_edge); + node q = m_graph.get_target(m_entering_edge); node u = m_graph.get_source(m_leaving_edge); node v = m_graph.get_target(m_leaving_edge); + // v is parent of u so T_u does not contain root node + if (m_pred[u] == v) { + node temp = u; + u = v; + v = temp; + } + node n = p; + while (n != -1) { + if (n == v) { + // q should be in T_v so swap p and q + node temp = p; + p = q; + q = temp; + break; + } + n = m_pred[n]; + } TRACE("network_flow", { tout << "update_spanning_tree: (" << p << ", " << q << ") enters, ("; @@ -263,16 +292,22 @@ namespace smt { node z = m_final[q]; // Update m_pred (for nodes in the stem from q to v) - node n = q; + n = q; node last = m_pred[v]; node parent = p; while (n != last) { node next = m_pred[n]; - m_pred[n] = parent; - m_upwards[n] = !m_upwards[n]; + m_pred[n] = parent; parent = n; n = next; } + n = v; + while (n != q) { + node next = m_pred[n]; + m_upwards[n] = !m_upwards[next]; + n = next; + } + m_upwards[q] = true; TRACE("network_flow", tout << "Graft T_q and T_r'\n";); @@ -289,7 +324,7 @@ namespace smt { node gamma = m_thread[m_final[p]]; n = p; last = m_pred[gamma]; - while (n != last) { + while (n != last && n != -1) { m_final[n] = z; n = m_pred[n]; } @@ -299,33 +334,34 @@ namespace smt { // Update T_r' node phi = m_rev_thread[v]; node theta = m_thread[m_final[v]]; - m_thread[phi] = theta; - + gamma = m_thread[m_final[v]]; - // REVIEW: check f(n) is not in T_v + // REVIEW: check f(u) is not in T_v node delta = m_final[u] != m_final[v] ? m_final[u] : phi; n = u; last = m_pred[gamma]; - while (n != last) { + while (n != last && n != -1) { m_final[n] = delta; n = m_pred[n]; } + m_thread[phi] = theta; + // Reroot T_v at q - if (u != q) { + if (v != q) { TRACE("network_flow", tout << "Reroot T_v at q\n";); - node n = m_pred[q]; + node n = v; m_thread[m_final[q]] = n; - last = v; - node alpha1, alpha2; + last = q; + node alpha1, alpha2 = -1; unsigned count = 0; while (n != last) { // Find all immediate successors of n node t1 = m_thread[n]; node t2 = m_thread[m_final[t1]]; node t3 = m_thread[m_final[t2]]; - if (t1 = m_pred[n]) { + if (t1 == m_pred[n]) { alpha1 = t2; alpha2 = t3; } @@ -348,7 +384,13 @@ namespace smt { m_depth[m] -= d; } } - m_thread[m_final[alpha2]] = v; + if (alpha2 != -1) { + m_thread[m_final[alpha2]] = v; + } + } + + for (unsigned i = 0; i < m_thread.size(); ++i) { + m_rev_thread[m_thread[i]] = i; } TRACE("network_flow", { @@ -376,14 +418,12 @@ namespace smt { vector const & es = m_graph.get_all_edges(); for (unsigned i = 0; i < es.size(); ++i) { edge const & e = es[i]; - if (e.is_enabled()) { - oss << prefix << e.get_source() << " -> " << prefix << e.get_target(); - if (m_states[i] == BASIS) { - oss << "[color=red,penwidth=3.0,label=\"" << m_flows[i] << "/" << e.get_weight() << "\"];\n"; - } - else { - oss << "[label=\"" << m_flows[i] << "/" << e.get_weight() << "\"];\n"; - } + oss << prefix << e.get_source() << " -> " << prefix << e.get_target(); + if (m_states[i] == BASIS) { + oss << "[color=red,penwidth=3.0,label=\"" << m_flows[i] << "/" << e.get_weight() << "\"];\n"; + } + else { + oss << "[label=\"" << m_flows[i] << "/" << e.get_weight() << "\"];\n"; } } oss << std::endl; @@ -418,7 +458,7 @@ namespace smt { vector const & es = m_graph.get_all_edges(); for (unsigned i = 0; i < es.size(); ++i) { edge const & e = es[i]; - if (e.is_enabled() && m_states[i] == BASIS) { + if (m_states[i] == BASIS) { m_objective_value += e.get_weight().get_rational() * m_flows[i]; } } From 29622229cb70121b89b5e8dac3b48e3872564a70 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Thu, 31 Oct 2013 13:03:24 -0700 Subject: [PATCH 065/925] Add lower bound case for edge_state --- src/smt/network_flow.h | 6 ++-- src/smt/network_flow_def.h | 58 +++++++++++++++++++++----------------- 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index 02ac563d1..bb9c0ed07 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -42,8 +42,9 @@ namespace smt { template class network_flow : private Ext { enum edge_state { - NON_BASIS = 0, - BASIS = 1 + LOWER = 1, + BASIS = 0, + UPPER = -1 }; typedef dl_var node; typedef dl_edge edge; @@ -85,6 +86,7 @@ namespace smt { edge_id m_leaving_edge; node m_join_node; numeral m_delta; + bool m_in_edge_dir; unsigned m_step; diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index a3a1b86b8..134046316 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -99,7 +99,7 @@ namespace smt { m_flows.resize(num_nodes + num_edges); m_states.resize(num_nodes + num_edges); - m_states.fill(NON_BASIS); + m_states.fill(LOWER); // Create artificial edges from/to root node to/from other nodes and initialize the spanning tree for (unsigned i = 0; i < num_nodes; ++i) { @@ -149,7 +149,7 @@ namespace smt { node src = m_graph.get_source(m_entering_edge); node tgt = m_graph.get_target(m_entering_edge); numeral cost = m_graph.get_weight(m_entering_edge); - numeral change = m_upwards[src] ? (-cost + m_potentials[src] - m_potentials[tgt]) : (cost - m_potentials[src] + m_potentials[tgt]); + numeral change = m_upwards[src] ? (-cost - m_potentials[src] + m_potentials[tgt]) : (cost + m_potentials[src] - m_potentials[tgt]); node last = m_thread[m_final[src]]; for (node u = src; u != last; u = m_thread[u]) { m_potentials[u] += change; @@ -160,7 +160,7 @@ namespace smt { template void network_flow::update_flows() { TRACE("network_flow", tout << "update_flows...\n";); - numeral val = m_states[m_entering_edge] == BASIS ? numeral::zero() : m_delta; + numeral val = fin_numeral(m_states[m_entering_edge]) * m_delta; m_flows[m_entering_edge] += val; node source = m_graph.get_source(m_entering_edge); for (unsigned u = source; u != m_join_node; u = m_pred[u]) { @@ -182,9 +182,8 @@ namespace smt { for (unsigned i = 0; i < es.size(); ++i) { node src = m_graph.get_source(i); node tgt = m_graph.get_target(i); - if (m_states[i] == NON_BASIS) { - numeral cost = m_graph.get_weight(i); - numeral change = cost - m_potentials[src] + m_potentials[tgt]; + if (m_states[i] != BASIS) { + numeral change = fin_numeral(m_states[i]) * (m_graph.get_weight(i) + m_potentials[src] - m_potentials[tgt]); // Choose the first negative-cost edge to be the violating edge // TODO: add multiple pivoting strategies if (change.is_neg()) { @@ -206,6 +205,11 @@ namespace smt { TRACE("network_flow", tout << "choose_leaving_edge...\n";); node source = m_graph.get_source(m_entering_edge); node target = m_graph.get_target(m_entering_edge); + if (m_states[m_entering_edge] == UPPER) { + node temp = source; + source = target; + target = temp; + } node u = source, v = target; while (u != v) { if (m_depth[u] > m_depth[v]) @@ -232,6 +236,7 @@ namespace smt { m_delta = d; src = u; tgt = m_pred[u]; + m_in_edge_dir = true; } } @@ -243,6 +248,7 @@ namespace smt { m_delta = d; src = u; tgt = m_pred[u]; + m_in_edge_dir = false; } } @@ -269,18 +275,13 @@ namespace smt { node temp = u; u = v; v = temp; - } - node n = p; - while (n != -1) { - if (n == v) { - // q should be in T_v so swap p and q - node temp = p; - p = q; - q = temp; - break; - } - n = m_pred[n]; - } + } + if ((m_states[m_entering_edge] == UPPER) == m_in_edge_dir) { + // q should be in T_v so swap p and q + node temp = p; + p = q; + q = temp; + } TRACE("network_flow", { tout << "update_spanning_tree: (" << p << ", " << q << ") enters, ("; @@ -292,7 +293,7 @@ namespace smt { node z = m_final[q]; // Update m_pred (for nodes in the stem from q to v) - n = q; + node n = q; node last = m_pred[v]; node parent = p; while (n != last) { @@ -302,9 +303,11 @@ namespace smt { n = next; } n = v; - while (n != q) { + while (n != q && n != -1) { node next = m_pred[n]; - m_upwards[n] = !m_upwards[next]; + if (next != -1) { + m_upwards[n] = !m_upwards[next]; + } n = next; } m_upwards[q] = true; @@ -356,7 +359,7 @@ namespace smt { last = q; node alpha1, alpha2 = -1; unsigned count = 0; - while (n != last) { + while (n != last && n != -1) { // Find all immediate successors of n node t1 = m_thread[n]; node t2 = m_thread[m_final[t1]]; @@ -374,15 +377,15 @@ namespace smt { alpha2 = t2; } m_thread[n] = alpha1; - m_thread[m_final[alpha1]] = alpha2; - n = m_pred[n]; - m_thread[m_final[alpha2]] = n; + m_thread[m_final[alpha1]] = alpha2; // Decrease depth of all children in the subtree ++count; int d = m_depth[n] - count; for (node m = m_thread[n]; m != m_final[n]; m = m_thread[m]) { m_depth[m] -= d; } + n = m_pred[n]; + m_thread[m_final[alpha2]] = n; } if (alpha2 != -1) { m_thread[m_final[alpha2]] = v; @@ -441,10 +444,13 @@ namespace smt { update_flows(); if (m_entering_edge != m_leaving_edge) { m_states[m_entering_edge] = BASIS; - m_states[m_leaving_edge] = NON_BASIS; + m_states[m_leaving_edge] = (m_flows[m_leaving_edge].is_zero()) ? LOWER : UPPER; update_spanning_tree(); update_potentials(); TRACE("network_flow", tout << "Spanning tree:\n" << display_spanning_tree();); + } + else { + m_states[m_leaving_edge] = m_states[m_leaving_edge] == LOWER ? UPPER : LOWER; } } TRACE("network_flow", tout << "Found optimal solution.\n";); From cfac32c57dc554318c144529bdca88af5046a33c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 31 Oct 2013 17:21:10 -0700 Subject: [PATCH 066/925] add outline of object invariant Signed-off-by: Nikolaj Bjorner --- src/smt/network_flow.h | 2 ++ src/smt/network_flow_def.h | 67 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index bb9c0ed07..6b7081b89 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -112,6 +112,8 @@ namespace smt { std::string display_spanning_tree(); + bool check_well_formed(); + public: network_flow(graph & g, vector const & balances); diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index 134046316..6ca6e5d1d 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -133,6 +133,7 @@ namespace smt { tout << pp_vector("Potentials", m_potentials) << pp_vector("Flows", m_flows); }); TRACE("network_flow", tout << "Spanning tree:\n" << display_spanning_tree();); + SASSERT(check_well_formed()); } template @@ -395,6 +396,7 @@ namespace smt { for (unsigned i = 0; i < m_thread.size(); ++i) { m_rev_thread[m_thread[i]] = i; } + SASSERT(check_well_formed()); TRACE("network_flow", { tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Threads", m_thread); @@ -439,6 +441,7 @@ namespace smt { bool network_flow::min_cost() { initialize(); while (choose_entering_edge()) { + SASSERT(check_well_formed()); bool bounded = choose_leaving_edge(); if (!bounded) return false; update_flows(); @@ -477,6 +480,70 @@ namespace smt { } return m_objective_value; } + + static unsigned find(svector& roots, unsigned x) { + unsigned old_x = x; + while (roots[x] >= 0) { + x = roots[x]; + } + roots[old_x] = x; + return x; + } + + static void merge(svector& roots, unsigned x, unsigned y) { + x = find(roots, x); + y = find(roots, y); + SASSERT(roots[x] < 0 && roots[y] < 0); + if (x == y) { + return; + } + if (roots[x] > roots[y]) { + std::swap(x, y); + } + SASSERT(roots[x] <= roots[y]); + roots[y] = x; + roots[x] += roots[y]; + } + + template + bool network_flow::check_well_formed() { + // m_thread is depth-first stack + // m_pred is predecessor link + // m_depth depth counting from a root note. + // m_graph + + node root = m_pred.size()-1; + for (unsigned i = 0; i < m_upwards.size(); ++i) { + if (m_upwards[i]) { + node p = m_pred[i]; + edge_id e = get_edge_id(i, p); + // we are either the root or the predecessor points up. + SASSERT(p == root || m_upwards[p]); + } + } + + // m_thread forms a spanning tree over [0..root] + // union-find structure: + svector roots(root+1, -1); + +#if 0 + for (unsigned i = 0; i < m_thread.size(); ++i) { + if (m_states[i] == BASIS) { + node x = m_thread[i]; + node y = i; + // we are now going to check the edge between x and y: + SASSERT(find(roots, x) != find(roots, y)); + merge(roots, x, y); + } + else { + // ? LOWER, UPPER + } + } +#endif + + return true; + } + } #endif From 195df69a1bdc4280a588899b02c48db36826ab83 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Thu, 31 Oct 2013 18:34:40 -0700 Subject: [PATCH 067/925] Use optional<_> for infinite check --- src/smt/network_flow.h | 2 +- src/smt/network_flow_def.h | 68 +++++++++++++++----------------------- 2 files changed, 27 insertions(+), 43 deletions(-) diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index bb9c0ed07..0e270cc43 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -85,7 +85,7 @@ namespace smt { edge_id m_entering_edge; edge_id m_leaving_edge; node m_join_node; - numeral m_delta; + optional m_delta; bool m_in_edge_dir; unsigned m_step; diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index 134046316..681d9da27 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -160,7 +160,7 @@ namespace smt { template void network_flow::update_flows() { TRACE("network_flow", tout << "update_flows...\n";); - numeral val = fin_numeral(m_states[m_entering_edge]) * m_delta; + numeral val = fin_numeral(m_states[m_entering_edge]) * (*m_delta); m_flows[m_entering_edge] += val; node source = m_graph.get_source(m_entering_edge); for (unsigned u = source; u != m_join_node; u = m_pred[u]) { @@ -223,17 +223,14 @@ namespace smt { } // Found first common ancestor of source and target m_join_node = u; - TRACE("network_flow", tout << "Found join node " << m_join_node << std::endl;); - // FIXME: need to get truly infinite value - numeral infty = numeral(INT_MAX); - m_delta = infty; + TRACE("network_flow", tout << "Found join node " << m_join_node << std::endl;); + m_delta.set_invalid(); node src, tgt; // Send flows along the path from source to the ancestor for (unsigned u = source; u != m_join_node; u = m_pred[u]) { - edge_id e_id = get_edge_id(u, m_pred[u]); - numeral d = m_upwards[u] ? m_flows[e_id] : infty; - if (d < m_delta) { - m_delta = d; + edge_id e_id = get_edge_id(u, m_pred[u]); + if (m_upwards[u] && (!m_delta || m_flows[e_id] < *m_delta)) { + m_delta = m_flows[e_id]; src = u; tgt = m_pred[u]; m_in_edge_dir = true; @@ -243,16 +240,15 @@ namespace smt { // Send flows along the path from target to the ancestor for (unsigned u = target; u != m_join_node; u = m_pred[u]) { edge_id e_id = get_edge_id(u, m_pred[u]); - numeral d = m_upwards[u] ? infty : m_flows[e_id]; - if (d <= m_delta) { - m_delta = d; + if (!m_upwards[u] && (!m_delta || m_flows[e_id] <= *m_delta)) { + m_delta = m_flows[e_id]; src = u; tgt = m_pred[u]; m_in_edge_dir = false; } } - if (m_delta < infty) { + if (m_delta) { m_leaving_edge = get_edge_id(src, tgt); TRACE("network_flow", { tout << "Found leaving edge " << m_leaving_edge; @@ -295,22 +291,14 @@ namespace smt { // Update m_pred (for nodes in the stem from q to v) node n = q; node last = m_pred[v]; - node parent = p; - while (n != last) { + node prev = p; + while (n != last && n != -1) { node next = m_pred[n]; - m_pred[n] = parent; - parent = n; + m_pred[n] = prev; + m_upwards[n] = !m_upwards[prev]; + prev = n; n = next; - } - n = v; - while (n != q && n != -1) { - node next = m_pred[n]; - if (next != -1) { - m_upwards[n] = !m_upwards[next]; - } - n = next; - } - m_upwards[q] = true; + } TRACE("network_flow", tout << "Graft T_q and T_r'\n";); @@ -339,7 +327,7 @@ namespace smt { node theta = m_thread[m_final[v]]; gamma = m_thread[m_final[v]]; - // REVIEW: check f(u) is not in T_v + // Check that f(u) is not in T_v node delta = m_final[u] != m_final[v] ? m_final[u] : phi; n = u; last = m_pred[gamma]; @@ -355,10 +343,9 @@ namespace smt { TRACE("network_flow", tout << "Reroot T_v at q\n";); node n = v; - m_thread[m_final[q]] = n; last = q; - node alpha1, alpha2 = -1; - unsigned count = 0; + node alpha1, alpha2; + node prev = q; while (n != last && n != -1) { // Find all immediate successors of n node t1 = m_thread[n]; @@ -378,18 +365,15 @@ namespace smt { } m_thread[n] = alpha1; m_thread[m_final[alpha1]] = alpha2; - // Decrease depth of all children in the subtree - ++count; - int d = m_depth[n] - count; - for (node m = m_thread[n]; m != m_final[n]; m = m_thread[m]) { - m_depth[m] -= d; - } - n = m_pred[n]; - m_thread[m_final[alpha2]] = n; - } - if (alpha2 != -1) { - m_thread[m_final[alpha2]] = v; + m_thread[m_final[alpha2]] = prev; + prev = n; + n = m_pred[n]; } + m_thread[m_final[q]] = prev; + } + + for (node n = m_thread[v]; m_pred[n] != -1; n = m_pred[n]) { + m_depth[n] = m_depth[m_pred[n]] + 1; } for (unsigned i = 0; i < m_thread.size(); ++i) { From 6baa469073edab11dba6c43e88fc9370d09e1aa2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 31 Oct 2013 21:32:11 -0700 Subject: [PATCH 068/925] local updates to opt_solver Signed-off-by: Nikolaj Bjorner --- src/opt/opt_solver.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 64d8a32be..9b28af631 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -77,6 +77,9 @@ namespace opt { else if (typeid(smt::theory_i_arith) == typeid(*arith_theory)) { return dynamic_cast(*arith_theory); } + else if (typeid(smt::theory_inf_arith) == typeid(*arith_theory)) { + return dynamic_cast(*arith_theory); + } else if (typeid(smt::theory_rdl&) == typeid(*arith_theory)) { return dynamic_cast(*arith_theory); } From 87141f4cb30e0af7a969c39e243fec84d1c7640a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 31 Oct 2013 22:09:52 -0700 Subject: [PATCH 069/925] fix bugs Signed-off-by: Nikolaj Bjorner --- src/opt/optimize_objectives.cpp | 14 ++++++++------ src/smt/theory_arith_aux.h | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/opt/optimize_objectives.cpp b/src/opt/optimize_objectives.cpp index 086c52bf4..933de3201 100644 --- a/src/opt/optimize_objectives.cpp +++ b/src/opt/optimize_objectives.cpp @@ -68,7 +68,6 @@ namespace opt { arith_util autil(m); opt_solver::scoped_push _push(*s); - opt_solver::toggle_objective _t(*s, true); for (unsigned i = 0; i < objectives.size(); ++i) { m_vars.push_back(s->add_objective(objectives[i].get())); @@ -77,6 +76,7 @@ namespace opt { lbool is_sat = l_true; // ready to test: is_sat = update_upper(); while (is_sat == l_true && !m_cancel) { + opt_solver::toggle_objective _t(*s, true); is_sat = update_lower(); } @@ -117,20 +117,22 @@ namespace opt { smt::theory_inf_arith& th = dynamic_cast(opt); expr_ref bound(m); - lbool is_sat = l_true; - for (unsigned i = 0; i < m_lower.size(); ++i) { + for (unsigned i = 0; i < m_lower.size() && !m_cancel; ++i) { if (m_lower[i] < m_upper[i]) { opt_solver::scoped_push _push(*s); smt::theory_var v = m_vars[i]; + // TBD: this version just works for m_upper[i] being infinity. bound = th.block_upper_bound(v, m_upper[i]); expr* bounds[1] = { bound }; - is_sat = s->check_sat(1, bounds); - if (is_sat) { + lbool is_sat = s->check_sat(1, bounds); + if (is_sat == l_true) { IF_VERBOSE(1, verbose_stream() << "Setting lower bound for " << v << " to " << m_upper[i] << "\n";); m_lower[i] = m_upper[i]; } - // else: TBD extract Farkas coefficients. + else if (is_sat == l_false) { + // else: TBD extract Farkas coefficients. + } } } return l_true; diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index a84a9ebf9..179a04e9d 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -1005,7 +1005,7 @@ namespace smt { strm << val << " <= " << v; expr* b = m.mk_fresh_const(strm.str().c_str(), m.mk_bool_sort()); bool_var bv = ctx.mk_bool_var(b); - atom* a = alloc(atom, bv, v, val, A_LOWER); + atom* a = alloc(atom, bv, v, val+Ext::m_real_epsilon, A_LOWER); m_unassigned_atoms[v]++; m_var_occs[v].push_back(a); m_atoms.push_back(a); From 736d43c084600c10045e6d429ecf4d270217c2b6 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Fri, 1 Nov 2013 08:05:29 +0100 Subject: [PATCH 070/925] Block lower bound of difference logic objectives --- src/smt/network_flow_def.h | 7 +++---- src/smt/theory_diff_logic.h | 5 +++-- src/smt/theory_diff_logic_def.h | 34 ++++++++++++++++++++++++++++++--- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index 5d7f5018b..e4fb13f37 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -308,7 +308,7 @@ namespace smt { m_thread[z] = y; n = q; last = m_final[q]; - while (n != last) { + while (n != last && n != -1) { m_depth[n] += 1 + m_depth[p]; n = m_pred[n]; } @@ -495,7 +495,7 @@ namespace smt { // m_pred is predecessor link // m_depth depth counting from a root note. // m_graph - +#if 0 node root = m_pred.size()-1; for (unsigned i = 0; i < m_upwards.size(); ++i) { if (m_upwards[i]) { @@ -509,8 +509,7 @@ namespace smt { // m_thread forms a spanning tree over [0..root] // union-find structure: svector roots(root+1, -1); - -#if 0 + for (unsigned i = 0; i < m_thread.size(); ++i) { if (m_states[i] == BASIS) { node x = m_thread[i]; diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h index 3b566d8c2..ecb512bda 100644 --- a/src/smt/theory_diff_logic.h +++ b/src/smt/theory_diff_logic.h @@ -189,8 +189,9 @@ namespace smt { // For optimization purpose typedef vector > objective_term; - vector m_objectives; - vector m_objective_consts; + vector m_objectives; + vector m_objective_consts; + vector > m_objective_assignments; numeral m_objective_value; // Set a conflict due to a negative cycle. diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index df78a2763..98bd2268e 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -778,6 +778,7 @@ void theory_diff_logic::reset_eh() { m_non_diff_logic_exprs = false; m_objectives .reset(); m_objective_consts.reset(); + m_objective_assignments.reset(); theory::reset_eh(); } @@ -1023,7 +1024,7 @@ bool theory_diff_logic::maximize(theory_var v) { vector potentials; m_objective_value = net_flow.get_optimal_solution(potentials, true); std::cout << "Objective value of var " << v << ": " << m_objective_value << std::endl; - // TODO: return the model of the optimal solution from potentials + m_objective_assignments[v] = potentials; TRACE("network_flow", for (unsigned i = 0; i < potentials.size(); ++i) { tout << "v" << i << " -> " << potentials[i] << "\n"; @@ -1041,9 +1042,11 @@ theory_var theory_diff_logic::add_objective(app* term) { objective_term objective; theory_var result = m_objectives.size(); rational q(1), r(0); + vector vr; if (internalize_objective(term, q, r, objective)) { m_objectives.push_back(objective); m_objective_consts.push_back(r); + m_objective_assignments.push_back(vr); } else { result = null_theory_var; @@ -1063,7 +1066,6 @@ expr* theory_diff_logic::block_lower_bound(theory_var v, inf_rational const ast_manager& m = get_manager(); objective_term const& t = m_objectives[v]; expr_ref e(m), f(m), f2(m); - // hacky implementation for now. if (t.size() == 1 && t[0].second.is_one()) { f = get_enode(t[0].first)->get_owner(); } @@ -1081,8 +1083,34 @@ expr* theory_diff_logic::block_lower_bound(theory_var v, inf_rational const f = m_util.mk_sub(f, f2); } else { - NOT_IMPLEMENTED_YET(); + expr_ref_vector disj(m); + vector const & ns = m_objective_assignments[v]; + inf_rational val; + rational r, s; + for (unsigned i = 0; i < t.size(); ++i) { + r = ns[i].get_rational().to_rational(); + s = ns[i].get_infinitesimal().to_rational(); + val = inf_rational(r, s); + f = get_enode(t[i].first)->get_owner(); + e = m_util.mk_numeral(val.get_rational(), m.get_sort(f)); + if (t[i].second.is_neg() && val.get_infinitesimal().is_pos()) { + disj.push_back(m_util.mk_le(f, e)); + } + else if (t[i].second.is_neg()) { + disj.push_back(m_util.mk_lt(f, e)); + } + else if (t[i].second.is_pos() && val.get_infinitesimal().is_neg()) { + disj.push_back(m_util.mk_ge(f, e)); + } + else if (t[i].second.is_pos()) { + disj.push_back(m_util.mk_gt(f, e)); + } + else { + } + } + return m.mk_or(disj.size(), disj.c_ptr()); } + inf_rational new_val = val - inf_rational(m_objective_consts[v]); e = m_util.mk_numeral(new_val.get_rational(), m.get_sort(f)); From 2a907ea52a82c4a9ef40cd41d95b3242637a7f17 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 1 Nov 2013 12:45:26 -0700 Subject: [PATCH 071/925] fix objective value regression in simplex maximation Signed-off-by: Nikolaj Bjorner --- src/opt/opt_solver.cpp | 7 ++++--- src/opt/optimize_objectives.cpp | 9 +++++++-- src/smt/theory_arith_aux.h | 3 +++ 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 515edcbff..e863f4e89 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -98,13 +98,14 @@ namespace opt { lbool r = m_context.check(num_assumptions, assumptions); if (r == l_true && m_objective_enabled) { m_objective_values.reset(); + smt::theory_opt& opt = get_optimizer(); for (unsigned i = 0; i < m_objective_vars.size(); ++i) { smt::theory_var v = m_objective_vars[i]; - bool is_bounded = get_optimizer().maximize(v); + bool is_bounded = opt.maximize(v); if (is_bounded) { - m_objective_values.push_back(get_optimizer().get_objective_value(v)); + m_objective_values.push_back(opt.get_objective_value(v)); } else { - inf_eps_rational r(rational(1), inf_rational(0)); + inf_eps r(rational(1), inf_rational(0)); m_objective_values.push_back(r); } } diff --git a/src/opt/optimize_objectives.cpp b/src/opt/optimize_objectives.cpp index 933de3201..f9ebe8b7b 100644 --- a/src/opt/optimize_objectives.cpp +++ b/src/opt/optimize_objectives.cpp @@ -44,6 +44,8 @@ Notes: #include "opt_solver.h" #include "arith_decl_plugin.h" #include "theory_arith.h" +#include "ast_pp.h" +#include "model_pp.h" namespace opt { @@ -68,6 +70,7 @@ namespace opt { arith_util autil(m); opt_solver::scoped_push _push(*s); + opt_solver::toggle_objective _t(*s, true); for (unsigned i = 0; i < objectives.size(); ++i) { m_vars.push_back(s->add_objective(objectives[i].get())); @@ -76,7 +79,6 @@ namespace opt { lbool is_sat = l_true; // ready to test: is_sat = update_upper(); while (is_sat == l_true && !m_cancel) { - opt_solver::toggle_objective _t(*s, true); is_sat = update_lower(); } @@ -89,12 +91,15 @@ namespace opt { lbool optimize_objectives::update_lower() { lbool is_sat = s->check_sat(0, 0); if (is_sat == l_true) { + model_ref md; + s->get_model(md); set_max(m_lower, s->get_objective_values()); IF_VERBOSE(1, for (unsigned i = 0; i < m_lower.size(); ++i) { verbose_stream() << m_lower[i] << " "; } - verbose_stream() << "\n";); + verbose_stream() << "\n"; + model_pp(verbose_stream(), *md);); expr_ref_vector disj(m); expr_ref constraint(m); diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 179a04e9d..09ab33c93 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -979,6 +979,9 @@ namespace smt { template bool theory_arith::maximize(theory_var v) { bool r = max_min(v, true); + if (!r && at_upper(v)) { + m_objective_value = get_value(v); + } return r || at_upper(v); } From 926f2e08347bd0ecb3bec5bce0e4e76788397a51 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Fri, 1 Nov 2013 14:50:17 -0700 Subject: [PATCH 072/925] Add more object invariants --- src/smt/network_flow_def.h | 106 +++++++++++++++++++++++-------------- 1 file changed, 66 insertions(+), 40 deletions(-) diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index e4fb13f37..fe7d323f6 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -42,7 +42,6 @@ namespace smt { return oss.str(); } - template network_flow::network_flow(graph & g, vector const & balances) : m_balances(balances) { @@ -98,6 +97,7 @@ namespace smt { m_balances[root] = -sum_supply; m_flows.resize(num_nodes + num_edges); + m_flows.fill(numeral::zero()); m_states.resize(num_nodes + num_edges); m_states.fill(LOWER); @@ -269,15 +269,11 @@ namespace smt { node v = m_graph.get_target(m_leaving_edge); // v is parent of u so T_u does not contain root node if (m_pred[u] == v) { - node temp = u; - u = v; - v = temp; + std::swap(u, v); } if ((m_states[m_entering_edge] == UPPER) == m_in_edge_dir) { // q should be in T_v so swap p and q - node temp = p; - p = q; - q = temp; + std::swap(p, q); } TRACE("network_flow", { @@ -329,7 +325,14 @@ namespace smt { gamma = m_thread[m_final[v]]; // Check that f(u) is not in T_v - node delta = m_final[u] != m_final[v] ? m_final[u] : phi; + bool found_final_u = false; + for (node n = v; n == m_final[v]; n = m_thread[n]) { + if (n == m_final[u]) { + found_final_u = true; + break; + } + } + node delta = found_final_u ? phi : m_final[u]; n = u; last = m_pred[gamma]; while (n != last && n != -1) { @@ -379,14 +382,14 @@ namespace smt { for (unsigned i = 0; i < m_thread.size(); ++i) { m_rev_thread[m_thread[i]] = i; - } - SASSERT(check_well_formed()); + } TRACE("network_flow", { tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Threads", m_thread); tout << pp_vector("Reverse Threads", m_rev_thread) << pp_vector("Last Successors", m_final); tout << pp_vector("Depths", m_depth) << pp_vector("Upwards", m_upwards); }); + SASSERT(check_well_formed()); } template @@ -424,7 +427,7 @@ namespace smt { template bool network_flow::min_cost() { initialize(); - while (choose_entering_edge()) { + while (choose_entering_edge()) { SASSERT(check_well_formed()); bool bounded = choose_leaving_edge(); if (!bounded) return false; @@ -438,7 +441,7 @@ namespace smt { } else { m_states[m_leaving_edge] = m_states[m_leaving_edge] == LOWER ? UPPER : LOWER; - } + } } TRACE("network_flow", tout << "Found optimal solution.\n";); return true; @@ -470,7 +473,10 @@ namespace smt { while (roots[x] >= 0) { x = roots[x]; } - roots[old_x] = x; + SASSERT(roots[x] < 0); + if (old_x != x) { + roots[old_x] = x; + } return x; } @@ -485,45 +491,65 @@ namespace smt { std::swap(x, y); } SASSERT(roots[x] <= roots[y]); - roots[y] = x; roots[x] += roots[y]; + roots[y] = x; + } + + static int get_final(int root, svector const & thread, svector const & depth) { + int n = root; + while (depth[thread[n]] > depth[root]) { + n = thread[n]; + } + return n; } template bool network_flow::check_well_formed() { - // m_thread is depth-first stack - // m_pred is predecessor link - // m_depth depth counting from a root note. - // m_graph -#if 0 node root = m_pred.size()-1; + + // m_upwards show correct direction for (unsigned i = 0; i < m_upwards.size(); ++i) { - if (m_upwards[i]) { - node p = m_pred[i]; - edge_id e = get_edge_id(i, p); - // we are either the root or the predecessor points up. - SASSERT(p == root || m_upwards[p]); - } + node p = m_pred[i]; + edge_id id; + SASSERT(m_upwards[i] == m_graph.get_edge_id(i, p, id)); + } + + // m_depth[x] denotes distance from x to the root node + for (node x = m_thread[root]; x != root; x = m_thread[x]) { + SASSERT(m_depth[x] == m_depth[m_pred[x]] + 1); + } + + // m_final of a node denotes the last node with a bigger depth + for (unsigned i = 0; i < m_final.size(); ++i) { + SASSERT(m_final[i] == get_final(i, m_thread, m_depth)); } // m_thread forms a spanning tree over [0..root] - // union-find structure: - svector roots(root+1, -1); - - for (unsigned i = 0; i < m_thread.size(); ++i) { - if (m_states[i] == BASIS) { - node x = m_thread[i]; - node y = i; - // we are now going to check the edge between x and y: - SASSERT(find(roots, x) != find(roots, y)); - merge(roots, x, y); - } - else { - // ? LOWER, UPPER - } + // Union-find structure + svector roots(m_pred.size(), -1); + + for (node x = m_thread[root]; x != root; x = m_thread[x]) { + node y = m_pred[x]; + // We are now going to check the edge between x and y + SASSERT(find(roots, x) != find(roots, y)); + merge(roots, x, y); + } + + std::cout << "roots" << std::endl; + for (unsigned i = 0; i < roots.size(); ++i) { + std::cout << i << " |-> " << roots[i] << std::endl; } -#endif + // All nodes belong to the same spanning tree + for (unsigned i = 0; i < roots.size(); ++i) { + SASSERT(i == 0 ? roots[i] + roots.size() == 0 : roots[i] == 0); + } + + // m_flows are zero on non-basic edges + for (unsigned i = 0; i < m_flows.size(); ++i) { + SASSERT(m_states[i] == BASIS || m_flows[i].is_zero()); + } + return true; } From 3c6f0c737ad62f8ce532673bc21a9af3e813782f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 1 Nov 2013 17:26:27 -0700 Subject: [PATCH 073/925] debugging infinite upper bound checking Signed-off-by: Nikolaj Bjorner --- src/opt/optimize_objectives.cpp | 35 +++++++++++++++++++++------- src/smt/params/theory_arith_params.h | 3 ++- src/smt/smt_setup.cpp | 3 +++ src/smt/theory_arith.h | 11 +++++++++ src/smt/theory_arith_aux.h | 15 +++++++++--- src/smt/theory_arith_core.h | 6 +++++ 6 files changed, 60 insertions(+), 13 deletions(-) diff --git a/src/opt/optimize_objectives.cpp b/src/opt/optimize_objectives.cpp index f9ebe8b7b..bcc2b52be 100644 --- a/src/opt/optimize_objectives.cpp +++ b/src/opt/optimize_objectives.cpp @@ -70,14 +70,16 @@ namespace opt { arith_util autil(m); opt_solver::scoped_push _push(*s); - opt_solver::toggle_objective _t(*s, true); for (unsigned i = 0; i < objectives.size(); ++i) { m_vars.push_back(s->add_objective(objectives[i].get())); } lbool is_sat = l_true; - // ready to test: is_sat = update_upper(); + // ready to test: + is_sat = update_upper(); + opt_solver::toggle_objective _t(*s, true); + while (is_sat == l_true && !m_cancel) { is_sat = update_lower(); } @@ -99,7 +101,8 @@ namespace opt { verbose_stream() << m_lower[i] << " "; } verbose_stream() << "\n"; - model_pp(verbose_stream(), *md);); + // model_pp(verbose_stream(), *md); + ); expr_ref_vector disj(m); expr_ref constraint(m); @@ -115,24 +118,38 @@ namespace opt { lbool optimize_objectives::update_upper() { smt::theory_opt& opt = s->get_optimizer(); - + + IF_VERBOSE(1, verbose_stream() << typeid(opt).name() << "\n";); if (typeid(smt::theory_inf_arith) != typeid(opt)) { return l_true; } smt::theory_inf_arith& th = dynamic_cast(opt); expr_ref bound(m); + expr_ref_vector bounds(m); + + opt_solver::scoped_push _push(*s); + // + // NB: we have to create all bound expressions before calling check_sat + // because the state after check_sat is not at base level. + // for (unsigned i = 0; i < m_lower.size() && !m_cancel; ++i) { if (m_lower[i] < m_upper[i]) { - opt_solver::scoped_push _push(*s); + SASSERT(m_upper[i].get_infinity().is_pos()); smt::theory_var v = m_vars[i]; - // TBD: this version just works for m_upper[i] being infinity. bound = th.block_upper_bound(v, m_upper[i]); - expr* bounds[1] = { bound }; - lbool is_sat = s->check_sat(1, bounds); + bounds.push_back(bound); + } + else { + bounds.push_back(0); + } + } + for (unsigned i = 0; i < m_lower.size() && !m_cancel; ++i) { + if (m_lower[i] < m_upper[i]) { + lbool is_sat = s->check_sat(1, bounds.c_ptr() + i); if (is_sat == l_true) { - IF_VERBOSE(1, verbose_stream() << "Setting lower bound for " << v << " to " << m_upper[i] << "\n";); + IF_VERBOSE(2, verbose_stream() << "Setting lower bound for v" << m_vars[i] << " to " << m_upper[i] << "\n";); m_lower[i] = m_upper[i]; } else if (is_sat == l_false) { diff --git a/src/smt/params/theory_arith_params.h b/src/smt/params/theory_arith_params.h index 30bc65b6d..b02ae3980 100644 --- a/src/smt/params/theory_arith_params.h +++ b/src/smt/params/theory_arith_params.h @@ -28,7 +28,8 @@ enum arith_solver_id { AS_ARITH, AS_DENSE_DIFF_LOGIC, AS_UTVPI, - AS_HORN + AS_HORN, + AS_OPTINF }; enum bound_prop_mode { diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index f91a58f87..52ad14155 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -737,6 +737,9 @@ namespace smt { else m_context.register_plugin(alloc(smt::theory_rutvpi, m_manager)); break; + case AS_OPTINF: + m_context.register_plugin(alloc(smt::theory_inf_arith, m_manager, m_params)); + break; default: if (m_params.m_arith_int_only) m_context.register_plugin(alloc(smt::theory_i_arith, m_manager, m_params)); diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 56c361a93..724cce200 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -1067,6 +1067,7 @@ namespace smt { static inf_numeral mk_inf_numeral(numeral const & n, numeral const & r) { return inf_numeral(n, r); } + static bool is_infinite(inf_numeral const& ) { return false; } mi_ext() : m_int_epsilon(rational(1)), m_real_epsilon(rational(0), true) {} }; @@ -1083,6 +1084,8 @@ namespace smt { UNREACHABLE(); return inf_numeral(n); } + static bool is_infinite(inf_numeral const& ) { return false; } + i_ext() : m_int_epsilon(1), m_real_epsilon(1) {} }; @@ -1099,6 +1102,8 @@ namespace smt { UNREACHABLE(); return inf_numeral(n); } + static bool is_infinite(inf_numeral const& ) { return false; } + si_ext(): m_int_epsilon(s_integer(1)), m_real_epsilon(s_integer(1)) {} }; @@ -1119,6 +1124,8 @@ namespace smt { static inf_numeral mk_inf_numeral(numeral const& n, numeral const& i) { return inf_numeral(n, i); } + static bool is_infinite(inf_numeral const& ) { return false; } + smi_ext() : m_int_epsilon(s_integer(1)), m_real_epsilon(s_integer(0), true) {} }; @@ -1138,6 +1145,10 @@ namespace smt { static inf_numeral mk_inf_numeral(numeral const & n, numeral const & r) { return inf_numeral(inf_rational(n, r)); } + static bool is_infinite(inf_numeral const& n) { + return !n.get_infinity().is_zero(); + } + inf_ext() : m_int_epsilon(inf_rational(rational(1))), m_real_epsilon(inf_rational(rational(0), true)) {} }; diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 09ab33c93..e864db589 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -1005,14 +1005,23 @@ namespace smt { ast_manager& m = get_manager(); context& ctx = get_context(); std::ostringstream strm; - strm << val << " <= " << v; - expr* b = m.mk_fresh_const(strm.str().c_str(), m.mk_bool_sort()); + strm << val << " <= v" << v; + expr* b = m.mk_const(symbol(strm.str().c_str()), m.mk_bool_sort()); bool_var bv = ctx.mk_bool_var(b); - atom* a = alloc(atom, bv, v, val+Ext::m_real_epsilon, A_LOWER); + ctx.set_var_theory(bv, get_id()); + // ctx.set_enode_flag(bv, true); + inf_numeral val1 = val; + if (!Ext::is_infinite(val)) { + val1 += Ext::m_real_epsilon; + } + atom* a = alloc(atom, bv, v, val1, A_LOWER); m_unassigned_atoms[v]++; m_var_occs[v].push_back(a); m_atoms.push_back(a); insert_bv2a(bv, a); + TRACE("arith", tout << mk_pp(b, m) << "\n"; + display_atom(tout, a, false); + display_atoms(tout);); return b; } diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 11484c779..983d0a9ea 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -927,6 +927,7 @@ namespace smt { template void theory_arith::assign_eh(bool_var v, bool is_true) { + TRACE("arith", tout << "v" << v << " " << is_true << "\n";); atom * a = get_bv2a(v); if (!a) return; SASSERT(get_context().get_assignment(a->get_bool_var()) != l_undef); @@ -2421,6 +2422,8 @@ namespace smt { if (val == l_undef) continue; // TODO: check if the following line is a bottleneck + TRACE("arith", tout << "v" << a->get_bool_var() << " " << (val == l_true) << "\n";); + a->assign_eh(val == l_true, get_epsilon(a->get_var())); if (val != l_undef && a->get_bound_kind() == b->get_bound_kind()) { SASSERT((ctx.get_assignment(bv) == l_true) == a->is_true()); @@ -2789,6 +2792,9 @@ namespace smt { if (is_int(v)) continue; inf_numeral const & val = get_value(v); + if (Ext::is_infinite(val)) { + continue; + } rational value = val.get_rational().to_rational() + m_epsilon.to_rational() * val.get_infinitesimal().to_rational(); theory_var v2; if (mapping.find(value, v2)) { From e5698119d75569acdd796bc1924a5d88a291ef24 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 1 Nov 2013 17:27:24 -0700 Subject: [PATCH 074/925] debugging infinite upper bound checking Signed-off-by: Nikolaj Bjorner --- src/opt/optimize_objectives.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/opt/optimize_objectives.cpp b/src/opt/optimize_objectives.cpp index bcc2b52be..870d0d2f1 100644 --- a/src/opt/optimize_objectives.cpp +++ b/src/opt/optimize_objectives.cpp @@ -76,8 +76,8 @@ namespace opt { } lbool is_sat = l_true; - // ready to test: - is_sat = update_upper(); + // Disabled while testing and tuning: + // is_sat = update_upper(); opt_solver::toggle_objective _t(*s, true); while (is_sat == l_true && !m_cancel) { From c0de1e34acdcd35a624168fa3db041c1d2504b20 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Nov 2013 14:54:42 -0800 Subject: [PATCH 075/925] working on upper bound optimziation Signed-off-by: Nikolaj Bjorner --- src/ast/ast_smt2_pp.cpp | 9 ++ src/ast/ast_smt2_pp.h | 3 + src/muz/pdr/pdr_farkas_learner.cpp | 4 +- src/opt/opt_cmds.cpp | 1 + src/opt/opt_context.cpp | 11 +- src/opt/opt_context.h | 2 + src/opt/opt_solver.cpp | 8 +- src/opt/optimize_objectives.cpp | 153 ++++++++++++++++--------- src/opt/optimize_objectives.h | 9 +- src/smt/theory_arith.h | 15 ++- src/smt/theory_arith_aux.h | 174 +++++++++++++++++++++++++---- src/smt/theory_arith_core.h | 26 +++-- src/smt/theory_arith_int.h | 12 +- src/smt/theory_diff_logic.h | 3 +- src/smt/theory_diff_logic_def.h | 15 +-- src/smt/theory_opt.h | 8 +- src/util/inf_eps_rational.h | 15 +++ 17 files changed, 343 insertions(+), 125 deletions(-) diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index 1ad2b8222..ce2c426ea 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -1110,6 +1110,15 @@ std::ostream& operator<<(std::ostream& out, mk_ismt2_pp const & p) { return out; } +std::ostream& operator<<(std::ostream& out, expr_ref const& e) { + return out << mk_ismt2_pp(e.get(), e.get_manager()); +} + +std::ostream& operator<<(std::ostream& out, app_ref const& e) { + return out << mk_ismt2_pp(e.get(), e.get_manager()); +} + + #ifdef Z3DEBUG void pp(expr const * n, ast_manager & m) { std::cout << mk_ismt2_pp(const_cast(n), m) << std::endl; diff --git a/src/ast/ast_smt2_pp.h b/src/ast/ast_smt2_pp.h index aa84d6e03..175ec9c4a 100644 --- a/src/ast/ast_smt2_pp.h +++ b/src/ast/ast_smt2_pp.h @@ -110,4 +110,7 @@ struct mk_ismt2_pp { std::ostream& operator<<(std::ostream& out, mk_ismt2_pp const & p); +std::ostream& operator<<(std::ostream& out, expr_ref const& e); +std::ostream& operator<<(std::ostream& out, app_ref const& e); + #endif diff --git a/src/muz/pdr/pdr_farkas_learner.cpp b/src/muz/pdr/pdr_farkas_learner.cpp index 7c38bf86f..5946ccb2a 100644 --- a/src/muz/pdr/pdr_farkas_learner.cpp +++ b/src/muz/pdr/pdr_farkas_learner.cpp @@ -34,8 +34,6 @@ Revision History: #include "proof_utils.h" #include "reg_decl_plugins.h" -#define PROOF_MODE PGM_FINE -//#define PROOF_MODE PGM_COARSE namespace pdr { @@ -374,7 +372,7 @@ namespace pdr { farkas_learner::farkas_learner(smt_params& params, ast_manager& outer_mgr) : m_proof_params(get_proof_params(params)), - m_pr(PROOF_MODE), + m_pr(PGM_FINE), m_constr(0), m_combine_farkas_coefficients(true), p2o(m_pr, outer_mgr), diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index bb8bf3e73..e08b9652f 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -159,6 +159,7 @@ public: insert_timeout(p); insert_max_memory(p); p.insert("print_statistics", CPK_BOOL, "(default: false) print statistics."); + opt::context::collect_param_descrs(p); } virtual char const * get_main_descr() const { return "check sat modulo objective function";} diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 781b6582e..e1b664f4c 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -17,9 +17,6 @@ Notes: TODO: - there are race conditions for cancelation. - - it would also be a good idea to maintain a volatile bool to track - cancelation and then bail out of loops inside optimize() and derived - functions. --*/ @@ -30,6 +27,7 @@ Notes: #include "opt_solver.h" #include "arith_decl_plugin.h" #include "th_rewriter.h" +#include "opt_params.hpp" namespace opt { @@ -154,12 +152,17 @@ namespace opt { } } + void context::collect_param_descrs(param_descrs & r) { + opt_params::collect_param_descrs(r); + } + void context::updt_params(params_ref& p) { m_params.append(p); if (m_solver) { m_solver->updt_params(m_params); } - + opt_params _p(m_params); + m_opt_objectives.set_engine(_p.engine()); } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index c71b941c7..0aa137748 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -68,6 +68,8 @@ namespace opt { void collect_statistics(statistics& stats); + static void collect_param_descrs(param_descrs & r); + void updt_params(params_ref& p); private: diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index e863f4e89..1c4a5bc4c 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -101,13 +101,7 @@ namespace opt { smt::theory_opt& opt = get_optimizer(); for (unsigned i = 0; i < m_objective_vars.size(); ++i) { smt::theory_var v = m_objective_vars[i]; - bool is_bounded = opt.maximize(v); - if (is_bounded) { - m_objective_values.push_back(opt.get_objective_value(v)); - } else { - inf_eps r(rational(1), inf_rational(0)); - m_objective_values.push_back(r); - } + m_objective_values.push_back(opt.maximize(v)); } } return r; diff --git a/src/opt/optimize_objectives.cpp b/src/opt/optimize_objectives.cpp index 870d0d2f1..589214476 100644 --- a/src/opt/optimize_objectives.cpp +++ b/src/opt/optimize_objectives.cpp @@ -62,26 +62,18 @@ namespace opt { } } - /* Enumerate locally optimal assignments until fixedpoint. */ - lbool optimize_objectives::basic_opt(app_ref_vector& objectives) { - arith_util autil(m); - - opt_solver::scoped_push _push(*s); - - for (unsigned i = 0; i < objectives.size(); ++i) { - m_vars.push_back(s->add_objective(objectives[i].get())); - } - + lbool optimize_objectives::basic_opt() { + opt_solver::toggle_objective _t(*s, true); lbool is_sat = l_true; - // Disabled while testing and tuning: - // is_sat = update_upper(); - opt_solver::toggle_objective _t(*s, true); while (is_sat == l_true && !m_cancel) { - is_sat = update_lower(); + is_sat = s->check_sat(0, 0); + if (is_sat == l_true) { + update_lower(); + } } if (m_cancel || is_sat == l_undef) { @@ -90,73 +82,117 @@ namespace opt { return l_true; } - lbool optimize_objectives::update_lower() { - lbool is_sat = s->check_sat(0, 0); - if (is_sat == l_true) { - model_ref md; - s->get_model(md); - set_max(m_lower, s->get_objective_values()); - IF_VERBOSE(1, - for (unsigned i = 0; i < m_lower.size(); ++i) { - verbose_stream() << m_lower[i] << " "; - } - verbose_stream() << "\n"; - // model_pp(verbose_stream(), *md); - ); - expr_ref_vector disj(m); - expr_ref constraint(m); - - for (unsigned i = 0; i < m_lower.size(); ++i) { - inf_eps const& v = m_lower[i]; - disj.push_back(s->block_lower_bound(i, v)); - } - constraint = m.mk_or(disj.size(), disj.c_ptr()); - s->assert_expr(constraint); + /* + Enumerate locally optimal assignments until fixedpoint. + */ + lbool optimize_objectives::farkas_opt() { + smt::theory_opt& opt = s->get_optimizer(); + + IF_VERBOSE(1, verbose_stream() << typeid(opt).name() << "\n";); + if (typeid(smt::theory_inf_arith) != typeid(opt)) { + return l_undef; } - return is_sat; + + opt_solver::toggle_objective _t(*s, true); + lbool is_sat= l_true; + + while (is_sat == l_true && !m_cancel) { + is_sat = update_upper(); + } + + if (m_cancel || is_sat == l_undef) { + return l_undef; + } + return l_true; + } + + void optimize_objectives::update_lower() { + model_ref md; + s->get_model(md); + set_max(m_lower, s->get_objective_values()); + IF_VERBOSE(1, + for (unsigned i = 0; i < m_lower.size(); ++i) { + verbose_stream() << m_lower[i] << " "; + } + verbose_stream() << "\n"; + // model_pp(verbose_stream(), *md); + ); + expr_ref_vector disj(m); + expr_ref constraint(m); + + for (unsigned i = 0; i < m_lower.size(); ++i) { + inf_eps const& v = m_lower[i]; + disj.push_back(s->block_lower_bound(i, v)); + } + constraint = m.mk_or(disj.size(), disj.c_ptr()); + s->assert_expr(constraint); } lbool optimize_objectives::update_upper() { smt::theory_opt& opt = s->get_optimizer(); - IF_VERBOSE(1, verbose_stream() << typeid(opt).name() << "\n";); - if (typeid(smt::theory_inf_arith) != typeid(opt)) { - return l_true; - } + SASSERT(typeid(smt::theory_inf_arith) == typeid(opt)); + smt::theory_inf_arith& th = dynamic_cast(opt); expr_ref bound(m); expr_ref_vector bounds(m); opt_solver::scoped_push _push(*s); + // // NB: we have to create all bound expressions before calling check_sat // because the state after check_sat is not at base level. // + vector mid; + for (unsigned i = 0; i < m_lower.size() && !m_cancel; ++i) { if (m_lower[i] < m_upper[i]) { - SASSERT(m_upper[i].get_infinity().is_pos()); smt::theory_var v = m_vars[i]; - bound = th.block_upper_bound(v, m_upper[i]); + mid.push_back((m_upper[i]+m_lower[i])/rational(2)); + bound = th.block_upper_bound(v, mid[i]); bounds.push_back(bound); } else { bounds.push_back(0); + mid.push_back(inf_eps()); } } + bool progress = false; for (unsigned i = 0; i < m_lower.size() && !m_cancel; ++i) { - if (m_lower[i] < m_upper[i]) { + if (m_lower[i] <= mid[i] && mid[i] <= m_upper[i] && m_lower[i] < m_upper[i]) { + th.enable_record_conflict(bounds[i].get()); lbool is_sat = s->check_sat(1, bounds.c_ptr() + i); - if (is_sat == l_true) { + th.enable_record_conflict(0); + switch(is_sat) { + case l_true: IF_VERBOSE(2, verbose_stream() << "Setting lower bound for v" << m_vars[i] << " to " << m_upper[i] << "\n";); - m_lower[i] = m_upper[i]; - } - else if (is_sat == l_false) { - // else: TBD extract Farkas coefficients. + m_lower[i] = mid[i]; + update_lower(); + break; + case l_false: + if (!th.conflict_minimize().get_infinity().is_zero()) { + // bounds is not in the core. The context is unsat. + m_upper[i] = m_lower[i]; + return l_false; + } + else { + m_upper[i] = std::min(m_upper[i], th.conflict_minimize()); + } + break; + default: + return l_undef; } + progress = true; } } + if (m_cancel) { + return l_undef; + } + if (!progress) { + return l_false; + } return l_true; } @@ -177,7 +213,24 @@ namespace opt { // First check_sat call to initialize theories lbool is_sat = s->check_sat(0, 0); if (is_sat == l_true) { - is_sat = basic_opt(objectives); + opt_solver::scoped_push _push(*s); + + for (unsigned i = 0; i < objectives.size(); ++i) { + m_vars.push_back(s->add_objective(objectives[i].get())); + } + + if (m_engine == symbol("basic")) { + is_sat = basic_opt(); + } + else if (m_engine == symbol("farkas")) { + is_sat = farkas_opt(); + } + else { + // TODO: implement symba engine + // report error on bad configuration. + NOT_IMPLEMENTED_YET(); + UNREACHABLE(); + } values.reset(); values.append(m_lower); } diff --git a/src/opt/optimize_objectives.h b/src/opt/optimize_objectives.h index 227cd8f00..cb9f2241b 100644 --- a/src/opt/optimize_objectives.h +++ b/src/opt/optimize_objectives.h @@ -34,6 +34,7 @@ namespace opt { vector m_lower; vector m_upper; svector m_vars; + symbol m_engine; public: optimize_objectives(ast_manager& m): m(m), s(0), m_cancel(false) {} @@ -41,13 +42,17 @@ namespace opt { void set_cancel(bool f); + void set_engine(symbol const& e) { m_engine = e; } + private: - lbool basic_opt(app_ref_vector& objectives); + lbool basic_opt(); + + lbool farkas_opt(); void set_max(vector& dst, vector const& src); - lbool update_lower(); + void update_lower(); lbool update_upper(); diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 724cce200..45e2ffdfa 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -90,6 +90,7 @@ namespace smt { static const int dead_row_id = -1; protected: bool proofs_enabled() const { return get_manager().proofs_enabled(); } + bool coeffs_enabled() const { return proofs_enabled() || m_bound_watch != null_bool_var; } struct linear_monomial { numeral m_coeff; @@ -995,11 +996,19 @@ namespace smt { // Optimization // // ----------------------------------- - virtual bool maximize(theory_var v); + virtual inf_eps_rational maximize(theory_var v); virtual theory_var add_objective(app* term); - virtual inf_eps_rational get_objective_value(theory_var v); virtual expr* block_lower_bound(theory_var v, inf_rational const& val); - virtual expr* block_upper_bound(theory_var v, inf_numeral const& val); + expr* block_upper_bound(theory_var v, inf_numeral const& val); + void enable_record_conflict(expr* bound); + void record_conflict(unsigned num_lits, literal const * lits, + unsigned num_eqs, enode_pair const * eqs, + unsigned num_params, parameter* params); + inf_eps_rational conflict_minimize(); + private: + bool_var m_bound_watch; + inf_eps_rational m_upper_bound; + public: // ----------------------------------- // // Pretty Printing diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index e864db589..cdd28e130 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -21,6 +21,8 @@ Revision History: #include"inf_eps_rational.h" #include"theory_arith.h" +#include"smt_farkas_util.h" +#include"th_rewriter.h" namespace smt { @@ -977,14 +979,20 @@ namespace smt { } template - bool theory_arith::maximize(theory_var v) { + inf_eps_rational theory_arith::maximize(theory_var v) { bool r = max_min(v, true); - if (!r && at_upper(v)) { + if (at_upper(v)) { m_objective_value = get_value(v); } - return r || at_upper(v); + else if (!r) { + m_objective_value = inf_eps_rational::infinity(); + } + return m_objective_value; } + /** + \brief: assert val < v + */ template expr* theory_arith::block_lower_bound(theory_var v, inf_rational const& val) { ast_manager& m = get_manager(); @@ -1000,6 +1008,9 @@ namespace smt { } } + /** + \brief assert val <= v + */ template expr* theory_arith::block_upper_bound(theory_var v, inf_numeral const& val) { ast_manager& m = get_manager(); @@ -1007,29 +1018,154 @@ namespace smt { std::ostringstream strm; strm << val << " <= v" << v; expr* b = m.mk_const(symbol(strm.str().c_str()), m.mk_bool_sort()); - bool_var bv = ctx.mk_bool_var(b); - ctx.set_var_theory(bv, get_id()); - // ctx.set_enode_flag(bv, true); - inf_numeral val1 = val; - if (!Ext::is_infinite(val)) { - val1 += Ext::m_real_epsilon; + if (!ctx.b_internalized(b)) { + bool_var bv = ctx.mk_bool_var(b); + ctx.set_var_theory(bv, get_id()); + // ctx.set_enode_flag(bv, true); + atom* a = alloc(atom, bv, v, val, A_LOWER); + m_unassigned_atoms[v]++; + m_var_occs[v].push_back(a); + m_atoms.push_back(a); + insert_bv2a(bv, a); + TRACE("arith", tout << mk_pp(b, m) << "\n"; + display_atom(tout, a, false);); } - atom* a = alloc(atom, bv, v, val1, A_LOWER); - m_unassigned_atoms[v]++; - m_var_occs[v].push_back(a); - m_atoms.push_back(a); - insert_bv2a(bv, a); - TRACE("arith", tout << mk_pp(b, m) << "\n"; - display_atom(tout, a, false); - display_atoms(tout);); return b; } + + /** + \brief enable watching bound atom. + */ template - inf_eps_rational theory_arith::get_objective_value(theory_var v) { - return m_objective_value; + void theory_arith::enable_record_conflict(expr* bound) { + m_params.m_arith_bound_prop = BP_NONE; + SASSERT(propagation_mode() == BP_NONE); // bound propagtion rules are not (yet) handled. + if (bound) { + context& ctx = get_context(); + m_bound_watch = ctx.get_bool_var(bound); + } + else { + m_bound_watch = null_bool_var; + } + m_upper_bound = -inf_eps_rational::infinity(); } + /** + \brief + pos < 0 + == + r(Ax <= b) + q(v <= val) + == + val' <= q*v & q*v <= q*val + + q*v - val' >= 0 + + => + (q*v - val' - q*v)/q >= -v + == + val/q <= v + */ + + template + void theory_arith::record_conflict( + unsigned num_lits, literal const * lits, + unsigned num_eqs, enode_pair const * eqs, + unsigned num_params, parameter* params) { + ast_manager& m = get_manager(); + context& ctx = get_context(); + if (null_bool_var == m_bound_watch) { + return; + } + unsigned idx = num_lits; + for (unsigned i = 0; i < num_lits; ++i) { + if (m_bound_watch == lits[i].var()) { + //SASSERT(!lits[i].sign()); + idx = i; + break; + } + } + if (idx == num_lits) { + return; + } + SASSERT(num_params == 1 + num_lits + num_eqs); + SASSERT(params[0].is_symbol()); + SASSERT(params[0].get_symbol() == symbol("farkas")); // for now, just handle this rule. + farkas_util farkas(m); + expr_ref tmp(m), vq(m); + expr* x, *y, *e; + rational q; + for (unsigned i = 0; i < num_lits; ++i) { + parameter const& pa = params[i+1]; + SASSERT(pa.is_rational()); + if (idx == i) { + q = abs(pa.get_rational()); + continue; + } + ctx.literal2expr(~lits[i], tmp); + farkas.add(abs(pa.get_rational()), to_app(tmp)); + } + for (unsigned i = 0; i < num_eqs; ++i) { + enode_pair const& p = eqs[i]; + x = p.first->get_owner(); + y = p.second->get_owner(); + tmp = m.mk_not(m.mk_eq(x,y)); + parameter const& pa = params[1 + num_lits + i]; + SASSERT(pa.is_rational()); + farkas.add(abs(pa.get_rational()), to_app(tmp)); + } + tmp = farkas.get(); + std::cout << tmp << "\n"; + atom* a = get_bv2a(m_bound_watch); + SASSERT(a); + expr_ref_vector terms(m); + vector mults; + bool strict = false; + if (m_util.is_le(tmp, x, y) || m_util.is_ge(tmp, y, x)) { + } + else if (m_util.is_lt(tmp, x, y) || m_util.is_gt(tmp, y, x)) { + strict = true; + } + else if (m.is_eq(tmp, x, y)) { + } + else { + UNREACHABLE(); + } + e = var2expr(a->get_var()); + q = -q*farkas.get_normalize_factor(); + SASSERT(!m_util.is_int(e) || q.is_int()); // TBD: not fully handled. + if (q.is_one()) { + vq = e; + } + else { + vq = m_util.mk_mul(m_util.mk_numeral(q, q.is_int()), e); + } + vq = m_util.mk_add(m_util.mk_sub(x, y), vq); + if (!q.is_one()) { + vq = m_util.mk_div(vq, m_util.mk_numeral(q, q.is_int())); + } + th_rewriter rw(m); + rw(vq, tmp); + IF_VERBOSE(1, verbose_stream() << tmp << "\n";); + VERIFY(m_util.is_numeral(tmp, q)); + if (m_upper_bound < q) { + m_upper_bound = q; + if (strict) { + m_upper_bound -= get_epsilon(a->get_var()); + } + } + } + + /** + \brief find the minimal upper bound on the variable that was last enabled + for conflict recording. + */ + template + inf_eps_rational theory_arith::conflict_minimize() { + return m_upper_bound; + } + + /** \brief Maximize (Minimize) the given temporary row. Return true if succeeded. diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 983d0a9ea..68900cb50 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -879,7 +879,7 @@ namespace smt { bool_var bv = ctx.mk_bool_var(n); ctx.set_var_theory(bv, get_id()); rational _k; - m_util.is_numeral(rhs, _k); + VERIFY(m_util.is_numeral(rhs, _k)); inf_numeral k(_k); atom * a = alloc(atom, bv, v, k, kind); mk_bound_axioms(a); @@ -1315,7 +1315,8 @@ namespace smt { m_assume_eq_head(0), m_nl_rounds(0), m_nl_gb_exhausted(false), - m_nl_new_exprs(m) { + m_nl_new_exprs(m), + m_bound_watch(null_bool_var) { } template @@ -1980,7 +1981,7 @@ namespace smt { tout << "is_below_lower: " << below_lower(x_i) << ", is_above_upper: " << above_upper(x_i) << "\n";); antecedents& ante = get_antecedents(); explain_bound(r, idx, !is_below, delta, ante); - b->push_justification(ante, numeral(1), proofs_enabled()); + b->push_justification(ante, numeral(1), coeffs_enabled()); set_conflict(ante.lits().size(), ante.lits().c_ptr(), @@ -2123,8 +2124,8 @@ namespace smt { void theory_arith::sign_bound_conflict(bound * b1, bound * b2) { SASSERT(b1->get_var() == b2->get_var()); antecedents& ante = get_antecedents(); - b1->push_justification(ante, numeral(1), proofs_enabled()); - b2->push_justification(ante, numeral(1), proofs_enabled()); + b1->push_justification(ante, numeral(1), coeffs_enabled()); + b2->push_justification(ante, numeral(1), coeffs_enabled()); set_conflict(ante.lits().size(), ante.lits().c_ptr(), ante.eqs().size(), ante.eqs().c_ptr(), ante, is_int(b1->get_var()), "farkas"); TRACE("arith_conflict", tout << "bound conflict\n";); @@ -2383,7 +2384,7 @@ namespace smt { if (!b->has_justification()) continue; if (!relax_bounds() || delta.is_zero()) { - b->push_justification(ante, it->m_coeff, proofs_enabled()); + b->push_justification(ante, it->m_coeff, coeffs_enabled()); continue; } numeral coeff = it->m_coeff; @@ -2445,7 +2446,7 @@ namespace smt { SASSERT(!is_b_lower || k_2 <= k_1); SASSERT(is_b_lower || k_2 >= k_1); if (new_atom == 0) { - b->push_justification(ante, coeff, proofs_enabled()); + b->push_justification(ante, coeff, coeffs_enabled()); continue; } SASSERT(!is_b_lower || k_2 < k_1); @@ -2459,7 +2460,7 @@ namespace smt { delta -= coeff*(k_2 - k_1); } TRACE("propagate_bounds", tout << "delta (after replace): " << delta << "\n";); - new_atom->push_justification(ante, coeff, proofs_enabled()); + new_atom->push_justification(ante, coeff, coeffs_enabled()); SASSERT(delta >= inf_numeral::zero()); } } @@ -2659,13 +2660,13 @@ namespace smt { for (unsigned i = 0; i < num_literals; i++) { ctx.display_detailed_literal(tout, lits[i]); tout << " "; - if (proofs_enabled()) { + if (coeffs_enabled()) { tout << "bound: " << bounds.lit_coeffs()[i] << "\n"; } } for (unsigned i = 0; i < num_eqs; i++) { tout << "#" << eqs[i].first->get_owner_id() << "=#" << eqs[i].second->get_owner_id() << " "; - if (proofs_enabled()) { + if (coeffs_enabled()) { tout << "bound: " << bounds.eq_coeffs()[i] << "\n"; } } @@ -2673,6 +2674,7 @@ namespace smt { tout << bounds.params(proof_rule)[i] << "\n"; } tout << "\n";); + record_conflict(num_literals, lits, num_eqs, eqs, bounds.num_params(), bounds.params(proof_rule)); ctx.set_conflict( ctx.mk_justification( ext_theory_conflict_justification(get_id(), r, num_literals, lits, num_eqs, eqs, @@ -2689,8 +2691,8 @@ namespace smt { typename vector::const_iterator end = r.end_entries(); for (; it != end; ++it) { if (!it->is_dead() && is_fixed(it->m_var)) { - lower(it->m_var)->push_justification(antecedents, it->m_coeff, proofs_enabled()); - upper(it->m_var)->push_justification(antecedents, it->m_coeff, proofs_enabled()); + lower(it->m_var)->push_justification(antecedents, it->m_coeff, coeffs_enabled()); + upper(it->m_var)->push_justification(antecedents, it->m_coeff, coeffs_enabled()); } } } diff --git a/src/smt/theory_arith_int.h b/src/smt/theory_arith_int.h index e0ecc087a..a80f55de8 100644 --- a/src/smt/theory_arith_int.h +++ b/src/smt/theory_arith_int.h @@ -525,7 +525,7 @@ namespace smt { } // k += new_a_ij * lower_bound(x_j).get_rational(); k.addmul(new_a_ij, lower_bound(x_j).get_rational()); - lower(x_j)->push_justification(ante, numeral::zero(), proofs_enabled()); + lower(x_j)->push_justification(ante, numeral::zero(), coeffs_enabled()); } else { SASSERT(at_upper(x_j)); @@ -541,7 +541,7 @@ namespace smt { } // k += new_a_ij * upper_bound(x_j).get_rational(); k.addmul(new_a_ij, upper_bound(x_j).get_rational()); - upper(x_j)->push_justification(ante, numeral::zero(), proofs_enabled()); + upper(x_j)->push_justification(ante, numeral::zero(), coeffs_enabled()); } pol.push_back(row_entry(new_a_ij, x_j)); } @@ -566,7 +566,7 @@ namespace smt { } // k += new_a_ij * lower_bound(x_j).get_rational(); k.addmul(new_a_ij, lower_bound(x_j).get_rational()); - lower(x_j)->push_justification(ante, numeral::zero(), proofs_enabled()); + lower(x_j)->push_justification(ante, numeral::zero(), coeffs_enabled()); } else { SASSERT(at_upper(x_j)); @@ -579,7 +579,7 @@ namespace smt { new_a_ij.neg(); // the upper terms are inverted // k += new_a_ij * upper_bound(x_j).get_rational(); k.addmul(new_a_ij, upper_bound(x_j).get_rational()); - upper(x_j)->push_justification(ante, numeral::zero(), proofs_enabled()); + upper(x_j)->push_justification(ante, numeral::zero(), coeffs_enabled()); } TRACE("gomory_cut_detail", tout << "new_a_ij: " << new_a_ij << "\n";); pol.push_back(row_entry(new_a_ij, x_j)); @@ -772,8 +772,8 @@ namespace smt { // u += ncoeff * lower_bound(v).get_rational(); u.addmul(ncoeff, lower_bound(v).get_rational()); } - lower(v)->push_justification(ante, numeral::zero(), proofs_enabled()); - upper(v)->push_justification(ante, numeral::zero(), proofs_enabled()); + lower(v)->push_justification(ante, numeral::zero(), coeffs_enabled()); + upper(v)->push_justification(ante, numeral::zero(), coeffs_enabled()); } else if (gcds.is_zero()) { gcds = abs_ncoeff; diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h index ecb512bda..9cc01e260 100644 --- a/src/smt/theory_diff_logic.h +++ b/src/smt/theory_diff_logic.h @@ -311,9 +311,8 @@ namespace smt { // // ----------------------------------- - virtual bool maximize(theory_var v); + virtual inf_eps_rational maximize(theory_var v); virtual theory_var add_objective(app* term); - virtual inf_eps_rational get_objective_value(theory_var v); virtual expr* block_lower_bound(theory_var v, inf_rational const& val); bool internalize_objective(expr * n, rational const& m, rational& r, objective_term & objective); diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index 98bd2268e..e6e3e94ca 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -1001,7 +1001,7 @@ void theory_diff_logic::get_implied_bound_antecedents(edge_id bridge_edge, } template -bool theory_diff_logic::maximize(theory_var v) { +inf_eps_rational theory_diff_logic::maximize(theory_var v) { objective_term const& objective = m_objectives[v]; IF_VERBOSE(1, @@ -1029,12 +1029,14 @@ bool theory_diff_logic::maximize(theory_var v) { for (unsigned i = 0; i < potentials.size(); ++i) { tout << "v" << i << " -> " << potentials[i] << "\n"; }); - + rational r = m_objective_value.get_rational().to_rational(); + rational i = m_objective_value.get_infinitesimal().to_rational(); + return inf_eps_rational(inf_rational(r, i)); } else { std::cout << "Unbounded objective" << std::endl; + return inf_eps_rational::infinity(); } - return is_optimal; } template @@ -1054,13 +1056,6 @@ theory_var theory_diff_logic::add_objective(app* term) { return result; } -template -inf_eps_rational theory_diff_logic::get_objective_value(theory_var v) { - rational r = m_objective_value.get_rational().to_rational(); - rational i = m_objective_value.get_infinitesimal().to_rational(); - return inf_eps_rational(inf_rational(r, i)); -} - template expr* theory_diff_logic::block_lower_bound(theory_var v, inf_rational const& val) { ast_manager& m = get_manager(); diff --git a/src/smt/theory_opt.h b/src/smt/theory_opt.h index d57875712..774e4abd1 100644 --- a/src/smt/theory_opt.h +++ b/src/smt/theory_opt.h @@ -28,15 +28,9 @@ namespace smt { class theory_opt { public: typedef inf_eps_rational inf_eps; - virtual bool maximize(theory_var v) { UNREACHABLE(); return false; }; + virtual inf_eps_rational maximize(theory_var v) { UNREACHABLE(); return inf_eps::infinity(); } virtual theory_var add_objective(app* term) { UNREACHABLE(); return null_theory_var; } - virtual inf_eps get_objective_value(theory_var v) { - UNREACHABLE(); - return inf_eps(rational(1), inf_rational(0)); - } virtual expr* block_lower_bound(theory_var v, inf_rational const& val) { return 0; } - - }; } diff --git a/src/util/inf_eps_rational.h b/src/util/inf_eps_rational.h index d7fdaf4fc..268bb8109 100644 --- a/src/util/inf_eps_rational.h +++ b/src/util/inf_eps_rational.h @@ -155,6 +155,11 @@ class inf_eps_rational { return inf_eps_rational(Numeral::minus_one()); } + static inf_eps_rational infinity() { + return inf_eps_rational(rational::one(), Numeral::zero()); + } + + inf_eps_rational & operator=(const inf_eps_rational & r) { m_infty = r.m_infty; m_r = r.m_r; @@ -179,6 +184,16 @@ class inf_eps_rational { return *this; } + inf_eps_rational & operator-=(const inf_rational & r) { + m_r -= r; + return *this; + } + + inf_eps_rational & operator+=(const inf_rational & r) { + m_r += r; + return *this; + } + inf_eps_rational & operator+=(const rational & r) { m_r += r; return *this; From a0d52e835be8cfd0337486437ccad8abed152e77 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Nov 2013 14:55:39 -0800 Subject: [PATCH 076/925] missing new files Signed-off-by: Nikolaj Bjorner --- src/smt/smt_farkas_util.cpp | 356 ++++++++++++++++++++++++++++++++++++ src/smt/smt_farkas_util.h | 96 ++++++++++ 2 files changed, 452 insertions(+) create mode 100644 src/smt/smt_farkas_util.cpp create mode 100644 src/smt/smt_farkas_util.h diff --git a/src/smt/smt_farkas_util.cpp b/src/smt/smt_farkas_util.cpp new file mode 100644 index 000000000..eb854294b --- /dev/null +++ b/src/smt/smt_farkas_util.cpp @@ -0,0 +1,356 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + smt_farkas_util.cpp + +Abstract: + + Utility for combining inequalities using coefficients obtained from Farkas lemmas. + +Author: + + Nikolaj Bjorner (nbjorne) 2013-11-2. + +Revision History: + + NB. This utility is specialized to proofs generated by the arithmetic solvers. + +--*/ + +#include "smt_farkas_util.h" +#include "ast_pp.h" +#include "th_rewriter.h" +#include "bool_rewriter.h" + + +namespace smt { + + farkas_util::farkas_util(ast_manager& m): + m(m), + a(m), + m_ineqs(m), + m_split_literals(false), + m_time(0) { + } + + void farkas_util::mk_coerce(expr*& e1, expr*& e2) { + if (a.is_int(e1) && a.is_real(e2)) { + e1 = a.mk_to_real(e1); + } + else if (a.is_int(e2) && a.is_real(e1)) { + e2 = a.mk_to_real(e2); + } + } + + // TBD: arith_decl_util now supports coercion, so this should be deprecated. + app* farkas_util::mk_add(expr* e1, expr* e2) { + mk_coerce(e1, e2); + return a.mk_add(e1, e2); + } + + app* farkas_util::mk_mul(expr* e1, expr* e2) { + mk_coerce(e1, e2); + return a.mk_mul(e1, e2); + } + + app* farkas_util::mk_le(expr* e1, expr* e2) { + mk_coerce(e1, e2); + return a.mk_le(e1, e2); + } + + app* farkas_util::mk_ge(expr* e1, expr* e2) { + mk_coerce(e1, e2); + return a.mk_gt(e1, e2); + } + + app* farkas_util::mk_gt(expr* e1, expr* e2) { + mk_coerce(e1, e2); + return a.mk_gt(e1, e2); + } + + app* farkas_util::mk_lt(expr* e1, expr* e2) { + mk_coerce(e1, e2); + return a.mk_lt(e1, e2); + } + + void farkas_util::mul(rational const& c, expr* e, expr_ref& res) { + expr_ref tmp(m); + if (c.is_one()) { + tmp = e; + } + else { + tmp = mk_mul(a.mk_numeral(c, c.is_int() && a.is_int(e)), e); + } + res = mk_add(res, tmp); + } + + bool farkas_util::is_int_sort(app* c) { + SASSERT(m.is_eq(c) || a.is_le(c) || a.is_lt(c) || a.is_gt(c) || a.is_ge(c)); + SASSERT(a.is_int(c->get_arg(0)) || a.is_real(c->get_arg(0))); + return a.is_int(c->get_arg(0)); + } + + bool farkas_util::is_int_sort() { + SASSERT(!m_ineqs.empty()); + return is_int_sort(m_ineqs[0].get()); + } + + void farkas_util::normalize_coeffs() { + rational l(1); + for (unsigned i = 0; i < m_coeffs.size(); ++i) { + l = lcm(l, denominator(m_coeffs[i])); + } + if (!l.is_one()) { + for (unsigned i = 0; i < m_coeffs.size(); ++i) { + m_coeffs[i] *= l; + } + } + m_normalize_factor = l; + } + + app* farkas_util::mk_one() { + return a.mk_numeral(rational(1), true); + } + + app* farkas_util::fix_sign(bool is_pos, app* c) { + expr* x, *y; + SASSERT(m.is_eq(c) || a.is_le(c) || a.is_lt(c) || a.is_gt(c) || a.is_ge(c)); + bool is_int = is_int_sort(c); + if (is_int && is_pos && (a.is_lt(c, x, y) || a.is_gt(c, y, x))) { + return mk_le(mk_add(x, mk_one()), y); + } + if (is_int && !is_pos && (a.is_le(c, x, y) || a.is_ge(c, y, x))) { + // !(x <= y) <=> x > y <=> x >= y + 1 + return mk_ge(x, mk_add(y, mk_one())); + } + if (is_pos) { + return c; + } + if (a.is_le(c, x, y)) return mk_gt(x, y); + if (a.is_lt(c, x, y)) return mk_ge(x, y); + if (a.is_ge(c, x, y)) return mk_lt(x, y); + if (a.is_gt(c, x, y)) return mk_le(x, y); + UNREACHABLE(); + return c; + } + + void farkas_util::partition_ineqs() { + m_reps.reset(); + m_his.reset(); + ++m_time; + for (unsigned i = 0; i < m_ineqs.size(); ++i) { + m_reps.push_back(process_term(m_ineqs[i].get())); + } + unsigned head = 0; + while (head < m_ineqs.size()) { + unsigned r = find(m_reps[head]); + unsigned tail = head; + for (unsigned i = head+1; i < m_ineqs.size(); ++i) { + if (find(m_reps[i]) == r) { + ++tail; + if (tail != i) { + SASSERT(tail < i); + std::swap(m_reps[tail], m_reps[i]); + app_ref tmp(m); + tmp = m_ineqs[i].get(); + m_ineqs[i] = m_ineqs[tail].get(); + m_ineqs[tail] = tmp; + std::swap(m_coeffs[tail], m_coeffs[i]); + } + } + } + head = tail + 1; + m_his.push_back(head); + } + } + + unsigned farkas_util::find(unsigned idx) { + if (m_ts.size() <= idx) { + m_roots.resize(idx+1); + m_size.resize(idx+1); + m_ts.resize(idx+1); + m_roots[idx] = idx; + m_ts[idx] = m_time; + m_size[idx] = 1; + return idx; + } + if (m_ts[idx] != m_time) { + m_size[idx] = 1; + m_ts[idx] = m_time; + m_roots[idx] = idx; + return idx; + } + while (true) { + if (m_roots[idx] == idx) { + return idx; + } + idx = m_roots[idx]; + } + } + + void farkas_util::merge(unsigned i, unsigned j) { + i = find(i); + j = find(j); + if (i == j) { + return; + } + if (m_size[i] > m_size[j]) { + std::swap(i, j); + } + m_roots[i] = j; + m_size[j] += m_size[i]; + } + unsigned farkas_util::process_term(expr* e) { + unsigned r = e->get_id(); + ptr_vector todo; + ast_mark mark; + todo.push_back(e); + while (!todo.empty()) { + e = todo.back(); + todo.pop_back(); + if (mark.is_marked(e)) { + continue; + } + mark.mark(e, true); + if (is_uninterp(e)) { + merge(r, e->get_id()); + } + if (is_app(e)) { + app* a = to_app(e); + for (unsigned i = 0; i < a->get_num_args(); ++i) { + todo.push_back(a->get_arg(i)); + } + } + } + return r; + } + expr_ref farkas_util::extract_consequence(unsigned lo, unsigned hi) { + bool is_int = is_int_sort(); + app_ref zero(a.mk_numeral(rational::zero(), is_int), m); + expr_ref res(m); + res = zero; + bool is_strict = false; + bool is_eq = true; + expr* x, *y; + for (unsigned i = lo; i < hi; ++i) { + app* c = m_ineqs[i].get(); + if (m.is_eq(c, x, y)) { + mul(m_coeffs[i], x, res); + mul(-m_coeffs[i], y, res); + } + if (a.is_lt(c, x, y) || a.is_gt(c, y, x)) { + mul(m_coeffs[i], x, res); + mul(-m_coeffs[i], y, res); + is_strict = true; + is_eq = false; + } + if (a.is_le(c, x, y) || a.is_ge(c, y, x)) { + mul(m_coeffs[i], x, res); + mul(-m_coeffs[i], y, res); + is_eq = false; + } + } + + zero = a.mk_numeral(rational::zero(), a.is_int(res)); + if (is_eq) { + res = m.mk_eq(res, zero); + } + else if (is_strict) { + res = mk_lt(res, zero); + } + else { + res = mk_le(res, zero); + } + res = m.mk_not(res); + th_rewriter rw(m); + params_ref params; + params.set_bool("gcd_rounding", true); + rw.updt_params(params); + proof_ref pr(m); + expr_ref result(m); + rw(res, result, pr); + fix_dl(result); + return result; + } + + void farkas_util::fix_dl(expr_ref& r) { + expr* e; + if (m.is_not(r, e)) { + r = e; + fix_dl(r); + r = m.mk_not(r); + return; + } + expr* e1, *e2, *e3, *e4; + if ((m.is_eq(r, e1, e2) || a.is_lt(r, e1, e2) || a.is_gt(r, e1, e2) || + a.is_le(r, e1, e2) || a.is_ge(r, e1, e2))) { + if (a.is_add(e1, e3, e4) && a.is_mul(e3)) { + r = m.mk_app(to_app(r)->get_decl(), a.mk_add(e4,e3), e2); + } + } + } + + void farkas_util::reset() { + m_ineqs.reset(); + m_coeffs.reset(); + } + + void farkas_util::add(rational const & coef, app * c) { + bool is_pos = true; + expr* e; + while (m.is_not(c, e)) { + is_pos = !is_pos; + c = to_app(e); + } + + if (!coef.is_zero() && !m.is_true(c)) { + m_coeffs.push_back(coef); + m_ineqs.push_back(fix_sign(is_pos, c)); + } + } + + expr_ref farkas_util::get() { + m_normalize_factor = rational::one(); + expr_ref res(m); + if (m_coeffs.empty()) { + res = m.mk_false(); + return res; + } + bool is_int = is_int_sort(); + if (is_int) { + normalize_coeffs(); + } + + if (m_split_literals) { + // partition equalities into variable disjoint sets. + // take the conjunction of these instead of the + // linear combination. + partition_ineqs(); + expr_ref_vector lits(m); + unsigned lo = 0; + for (unsigned i = 0; i < m_his.size(); ++i) { + unsigned hi = m_his[i]; + lits.push_back(extract_consequence(lo, hi)); + lo = hi; + } + bool_rewriter(m).mk_or(lits.size(), lits.c_ptr(), res); + IF_VERBOSE(2, { if (lits.size() > 1) { verbose_stream() << "combined lemma: " << mk_pp(res, m) << "\n"; } }); + } + else { + res = extract_consequence(0, m_coeffs.size()); + } + + TRACE("arith", + for (unsigned i = 0; i < m_coeffs.size(); ++i) { + tout << m_coeffs[i] << " * (" << mk_pp(m_ineqs[i].get(), m) << ") "; + } + tout << "\n"; + tout << res << "\n"; + ); + + return res; + } +} + diff --git a/src/smt/smt_farkas_util.h b/src/smt/smt_farkas_util.h new file mode 100644 index 000000000..0152ee289 --- /dev/null +++ b/src/smt/smt_farkas_util.h @@ -0,0 +1,96 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + smt_farkas_util.h + +Abstract: + + Utility for combining inequalities using coefficients obtained from Farkas lemmas. + +Author: + + Nikolaj Bjorner (nbjorne) 2013-11-2. + +Revision History: + + NB. This utility is specialized to proofs generated by the arithmetic solvers. + +--*/ + +#ifndef __FARKAS_UTIL_H_ +#define __FARKAS_UTIL_H_ + +#include "arith_decl_plugin.h" + +namespace smt { + + class farkas_util { + ast_manager& m; + arith_util a; + app_ref_vector m_ineqs; + vector m_coeffs; + rational m_normalize_factor; + // utilities for separating coefficients + bool m_split_literals; + unsigned m_time; + unsigned_vector m_roots, m_size, m_his, m_reps, m_ts; + + void mk_coerce(expr*& e1, expr*& e2); + app* mk_add(expr* e1, expr* e2); + app* mk_mul(expr* e1, expr* e2); + app* mk_le(expr* e1, expr* e2); + app* mk_ge(expr* e1, expr* e2); + app* mk_gt(expr* e1, expr* e2); + app* mk_lt(expr* e1, expr* e2); + void mul(rational const& c, expr* e, expr_ref& res); + bool is_int_sort(app* c); + bool is_int_sort(); + void normalize_coeffs(); + app* mk_one(); + app* fix_sign(bool is_pos, app* c); + void partition_ineqs(); + unsigned find(unsigned idx); + void merge(unsigned i, unsigned j); + unsigned process_term(expr* e); + expr_ref extract_consequence(unsigned lo, unsigned hi); + void fix_dl(expr_ref& r); + + public: + farkas_util(ast_manager& m); + + /** + \brief Reset state + */ + void reset(); + + /** + \brief add a multiple of constraint c to the current state + */ + void add(rational const & coef, app * c); + + /** + \brief Extract the complement of premises multiplied by Farkas coefficients. + */ + expr_ref get(); + + /** + \brief Coefficients are normalized for integer problems. + Retrieve multiplicant for normalization. + */ + rational const& get_normalize_factor() const { return m_normalize_factor; } + + /** + \brief extract one or multiple consequences based on literal partition. + Multiple consequences are strongst modulo a partition of variables. + Consequence generation under literal partitioning maintains difference logic constraints. + That is, if the original constraints are difference logic, then the consequent + produced by literal partitioning is also difference logic. + */ + void set_split_literals(bool f) { m_split_literals = f; } + + }; +} + +#endif From a26bd69a5edd92135831d5632a44ffb764da2e60 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Nov 2013 14:55:48 -0800 Subject: [PATCH 077/925] missing new files Signed-off-by: Nikolaj Bjorner --- src/opt/opt_params.pyg | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/opt/opt_params.pyg diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg new file mode 100644 index 000000000..ae6e43aea --- /dev/null +++ b/src/opt/opt_params.pyg @@ -0,0 +1,11 @@ +def_module_params('opt', + description='optimization parameters', + export=True, + params=(('timeout', UINT, UINT_MAX, 'set timeout'), + ('engine', SYMBOL, 'basic', "select optimization engine: 'basic', 'farkas', 'symba'"), + )) + + + + + From 883018b405ec47a8a54f15d3d86abc65d63e9eb2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Nov 2013 19:27:06 -0800 Subject: [PATCH 078/925] v1 of conflict driven optimization Signed-off-by: Nikolaj Bjorner --- src/opt/optimize_objectives.cpp | 6 +++++- src/smt/theory_arith_aux.h | 28 +++++++++++++++++++--------- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/opt/optimize_objectives.cpp b/src/opt/optimize_objectives.cpp index 589214476..bcda00381 100644 --- a/src/opt/optimize_objectives.cpp +++ b/src/opt/optimize_objectives.cpp @@ -151,6 +151,7 @@ namespace opt { if (m_lower[i] < m_upper[i]) { smt::theory_var v = m_vars[i]; mid.push_back((m_upper[i]+m_lower[i])/rational(2)); + //mid.push_back(m_upper[i]); bound = th.block_upper_bound(v, mid[i]); bounds.push_back(bound); } @@ -164,14 +165,15 @@ namespace opt { if (m_lower[i] <= mid[i] && mid[i] <= m_upper[i] && m_lower[i] < m_upper[i]) { th.enable_record_conflict(bounds[i].get()); lbool is_sat = s->check_sat(1, bounds.c_ptr() + i); - th.enable_record_conflict(0); switch(is_sat) { case l_true: IF_VERBOSE(2, verbose_stream() << "Setting lower bound for v" << m_vars[i] << " to " << m_upper[i] << "\n";); m_lower[i] = mid[i]; + th.enable_record_conflict(0); update_lower(); break; case l_false: + IF_VERBOSE(2, verbose_stream() << "conflict: " << th.conflict_minimize() << "\n";); if (!th.conflict_minimize().get_infinity().is_zero()) { // bounds is not in the core. The context is unsat. m_upper[i] = m_lower[i]; @@ -182,8 +184,10 @@ namespace opt { } break; default: + th.enable_record_conflict(0); return l_undef; } + th.enable_record_conflict(0); progress = true; } } diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index cdd28e130..430e29358 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -1028,7 +1028,7 @@ namespace smt { m_atoms.push_back(a); insert_bv2a(bv, a); TRACE("arith", tout << mk_pp(b, m) << "\n"; - display_atom(tout, a, false);); + display_atom(tout, a, false);); } return b; } @@ -1074,6 +1074,8 @@ namespace smt { unsigned num_params, parameter* params) { ast_manager& m = get_manager(); context& ctx = get_context(); + expr_ref tmp(m), vq(m); + expr* x, *y, *e; if (null_bool_var == m_bound_watch) { return; } @@ -1088,12 +1090,20 @@ namespace smt { if (idx == num_lits) { return; } + for (unsigned i = 0; i < num_lits; ++i) { + ctx.literal2expr(lits[i], tmp); + } + for (unsigned i = 0; i < num_eqs; ++i) { + enode_pair const& p = eqs[i]; + x = p.first->get_owner(); + y = p.second->get_owner(); + tmp = m.mk_eq(x,y); + } + SASSERT(num_params == 1 + num_lits + num_eqs); SASSERT(params[0].is_symbol()); SASSERT(params[0].get_symbol() == symbol("farkas")); // for now, just handle this rule. farkas_util farkas(m); - expr_ref tmp(m), vq(m); - expr* x, *y, *e; rational q; for (unsigned i = 0; i < num_lits; ++i) { parameter const& pa = params[i+1]; @@ -1102,20 +1112,20 @@ namespace smt { q = abs(pa.get_rational()); continue; } - ctx.literal2expr(~lits[i], tmp); + ctx.literal2expr(lits[i], tmp); farkas.add(abs(pa.get_rational()), to_app(tmp)); } for (unsigned i = 0; i < num_eqs; ++i) { enode_pair const& p = eqs[i]; x = p.first->get_owner(); y = p.second->get_owner(); - tmp = m.mk_not(m.mk_eq(x,y)); + tmp = m.mk_eq(x,y); parameter const& pa = params[1 + num_lits + i]; SASSERT(pa.is_rational()); farkas.add(abs(pa.get_rational()), to_app(tmp)); } tmp = farkas.get(); - std::cout << tmp << "\n"; + // IF_VERBOSE(1, verbose_stream() << "Farkas result: " << tmp << "\n";); atom* a = get_bv2a(m_bound_watch); SASSERT(a); expr_ref_vector terms(m); @@ -1123,7 +1133,7 @@ namespace smt { bool strict = false; if (m_util.is_le(tmp, x, y) || m_util.is_ge(tmp, y, x)) { } - else if (m_util.is_lt(tmp, x, y) || m_util.is_gt(tmp, y, x)) { + else if (m.is_not(tmp, e) && (m_util.is_le(e, y, x) || m_util.is_ge(e, x, y))) { strict = true; } else if (m.is_eq(tmp, x, y)) { @@ -1132,7 +1142,7 @@ namespace smt { UNREACHABLE(); } e = var2expr(a->get_var()); - q = -q*farkas.get_normalize_factor(); + q *= farkas.get_normalize_factor(); SASSERT(!m_util.is_int(e) || q.is_int()); // TBD: not fully handled. if (q.is_one()) { vq = e; @@ -1146,13 +1156,13 @@ namespace smt { } th_rewriter rw(m); rw(vq, tmp); - IF_VERBOSE(1, verbose_stream() << tmp << "\n";); VERIFY(m_util.is_numeral(tmp, q)); if (m_upper_bound < q) { m_upper_bound = q; if (strict) { m_upper_bound -= get_epsilon(a->get_var()); } + IF_VERBOSE(1, verbose_stream() << "new upper bound: " << m_upper_bound << "\n";); } } From 53d365bc44532fe40b790192a1f1416594ef5533 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Mon, 4 Nov 2013 09:12:25 +0100 Subject: [PATCH 079/925] Debug Network Simplex implementation --- src/smt/network_flow_def.h | 96 +++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 49 deletions(-) diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index fe7d323f6..3b4b93d51 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -271,9 +271,13 @@ namespace smt { if (m_pred[u] == v) { std::swap(u, v); } - if ((m_states[m_entering_edge] == UPPER) == m_in_edge_dir) { + + for (node n = p; n != -1; n = m_pred[n]) { // q should be in T_v so swap p and q - std::swap(p, q); + if (n == v) { + std::swap(p, q); + break; + } } TRACE("network_flow", { @@ -297,60 +301,62 @@ namespace smt { n = next; } - TRACE("network_flow", tout << "Graft T_q and T_r'\n";); + TRACE("network_flow", tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Upwards", m_upwards);); - // Graft T_q and T_r' - m_thread[x] = q; - m_thread[z] = y; - n = q; - last = m_final[q]; - while (n != last && n != -1) { - m_depth[n] += 1 + m_depth[p]; - n = m_pred[n]; - } - - node gamma = m_thread[m_final[p]]; - n = p; - last = m_pred[gamma]; - while (n != last && n != -1) { - m_final[n] = z; - n = m_pred[n]; - } - - TRACE("network_flow", tout << "Update T_r'\n";); - - // Update T_r' - node phi = m_rev_thread[v]; + // Do this before updating data structures + node gamma_p = m_pred[m_thread[m_final[p]]]; + node gamma_v = m_pred[m_thread[m_final[v]]]; node theta = m_thread[m_final[v]]; - - gamma = m_thread[m_final[v]]; + // Check that f(u) is not in T_v bool found_final_u = false; - for (node n = v; n == m_final[v]; n = m_thread[n]) { + for (node n = v; n != theta; n = m_thread[n]) { if (n == m_final[u]) { found_final_u = true; break; } } + node phi = m_rev_thread[v]; node delta = found_final_u ? phi : m_final[u]; - n = u; - last = m_pred[gamma]; - while (n != last && n != -1) { - m_final[n] = delta; - n = m_pred[n]; + + TRACE("network_flow", tout << "Graft T_q and T_r'\n";); + + // Graft T_q and T_r' + for (node n = p; n != gamma_p && n != -1; n = m_pred[n]) { + TRACE("network_flow", tout << "1: m_final[" << n << "] |-> " << z << "\n";); + m_final[n] = z; } + m_thread[x] = q; + m_rev_thread[q] = x; + m_thread[z] = y; + m_rev_thread[y] = z; + // Increase depths of all children in T_q + last = m_thread[m_final[q]]; + for (node n = q; n != last; n = m_thread[n]) { + m_depth[n] += 1 + m_depth[p] - m_depth[q]; + } + + TRACE("network_flow", tout << "Update T_r'\n";); + + // Update T_r' m_thread[phi] = theta; + m_rev_thread[theta] = phi; + + for (node n = u; n != gamma_v && n != -1; n = m_pred[n]) { + TRACE("network_flow", tout << "2: m_final[" << n << "] |-> " << delta << "\n";); + m_final[n] = delta; + } + + TRACE("network_flow", tout << pp_vector("Last Successors", m_final, true) << pp_vector("Depths", m_depth);); // Reroot T_v at q if (v != q) { TRACE("network_flow", tout << "Reroot T_v at q\n";); - - node n = v; - last = q; + node alpha1, alpha2; node prev = q; - while (n != last && n != -1) { + for (node n = v; n != q && n != -1; n = m_pred[n]) { // Find all immediate successors of n node t1 = m_thread[n]; node t2 = m_thread[m_final[t1]]; @@ -370,26 +376,18 @@ namespace smt { m_thread[n] = alpha1; m_thread[m_final[alpha1]] = alpha2; m_thread[m_final[alpha2]] = prev; - prev = n; - n = m_pred[n]; + prev = n; } m_thread[m_final[q]] = prev; } - for (node n = m_thread[v]; m_pred[n] != -1; n = m_pred[n]) { - m_depth[n] = m_depth[m_pred[n]] + 1; - } - for (unsigned i = 0; i < m_thread.size(); ++i) { m_rev_thread[m_thread[i]] = i; } TRACE("network_flow", { - tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Threads", m_thread); - tout << pp_vector("Reverse Threads", m_rev_thread) << pp_vector("Last Successors", m_final); - tout << pp_vector("Depths", m_depth) << pp_vector("Upwards", m_upwards); + tout << pp_vector("Threads", m_thread, true) << pp_vector("Reverse Threads", m_rev_thread); }); - SASSERT(check_well_formed()); } template @@ -427,8 +425,7 @@ namespace smt { template bool network_flow::min_cost() { initialize(); - while (choose_entering_edge()) { - SASSERT(check_well_formed()); + while (choose_entering_edge()) { bool bounded = choose_leaving_edge(); if (!bounded) return false; update_flows(); @@ -438,6 +435,7 @@ namespace smt { update_spanning_tree(); update_potentials(); TRACE("network_flow", tout << "Spanning tree:\n" << display_spanning_tree();); + SASSERT(check_well_formed()); } else { m_states[m_leaving_edge] = m_states[m_leaving_edge] == LOWER ? UPPER : LOWER; From 89989627d08f8d48e96d9968943e7e04a74248fa Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 4 Nov 2013 13:33:02 -0800 Subject: [PATCH 080/925] add blast method for ite terms Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 2 +- src/muz/pdr/pdr_context.cpp | 3 +- src/muz/pdr/pdr_util.cpp | 63 ------ src/muz/pdr/pdr_util.h | 6 - src/opt/fu_malik.cpp | 44 +++-- src/smt/diff_logic.h | 10 +- src/smt/network_flow.h | 5 +- src/smt/network_flow_def.h | 80 +++++++- src/tactic/core/blast_term_ite_tactic.cpp | 221 ++++++++++++++++++++++ src/tactic/core/blast_term_ite_tactic.h | 38 ++++ 10 files changed, 369 insertions(+), 103 deletions(-) create mode 100644 src/tactic/core/blast_term_ite_tactic.cpp create mode 100644 src/tactic/core/blast_term_ite_tactic.h diff --git a/scripts/mk_project.py b/scripts/mk_project.py index ccae41dcb..e92899436 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -58,7 +58,7 @@ def init_project_def(): add_lib('muz', ['smt', 'sat', 'smt2parser', 'aig_tactic', 'qe'], 'muz/base') add_lib('transforms', ['muz', 'hilbert'], 'muz/transforms') add_lib('rel', ['muz', 'transforms'], 'muz/rel') - add_lib('pdr', ['muz', 'transforms', 'arith_tactics', 'smt_tactic'], 'muz/pdr') + add_lib('pdr', ['muz', 'transforms', 'arith_tactics', 'core_tactics', 'smt_tactic'], 'muz/pdr') add_lib('clp', ['muz', 'transforms'], 'muz/clp') add_lib('tab', ['muz', 'transforms'], 'muz/tab') add_lib('bmc', ['muz', 'transforms'], 'muz/bmc') diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index aab7b1388..d2ac29689 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -47,6 +47,7 @@ Notes: #include "dl_boogie_proof.h" #include "qe_util.h" #include "scoped_proof.h" +#include "blast_term_ite_tactic.h" namespace pdr { @@ -601,7 +602,7 @@ namespace pdr { th_rewriter rw(m); rw(fml); if (ctx.is_dl() || ctx.is_utvpi()) { - hoist_non_bool_if(fml); + blast_term_ite(fml); } TRACE("pdr", tout << mk_pp(fml, m) << "\n";); SASSERT(is_ground(fml)); diff --git a/src/muz/pdr/pdr_util.cpp b/src/muz/pdr/pdr_util.cpp index f122f1e2c..33c98fae4 100644 --- a/src/muz/pdr/pdr_util.cpp +++ b/src/muz/pdr/pdr_util.cpp @@ -1030,68 +1030,6 @@ namespace pdr { fml = m.mk_and(conjs.size(), conjs.c_ptr()); } - // - // (f (if c1 (if c2 e1 e2) e3) b c) -> - // (if c1 (if c2 (f e1 b c) - - class ite_hoister { - ast_manager& m; - public: - ite_hoister(ast_manager& m): m(m) {} - - br_status mk_app_core(func_decl* f, unsigned num_args, expr* const* args, expr_ref& result) { - if (m.is_ite(f)) { - return BR_FAILED; - } - for (unsigned i = 0; i < num_args; ++i) { - expr* c, *t, *e; - if (!m.is_bool(args[i]) && m.is_ite(args[i], c, t, e)) { - expr_ref e1(m), e2(m); - ptr_vector args1(num_args, args); - args1[i] = t; - e1 = m.mk_app(f, num_args, args1.c_ptr()); - if (t == e) { - result = e1; - return BR_REWRITE1; - } - args1[i] = e; - e2 = m.mk_app(f, num_args, args1.c_ptr()); - result = m.mk_app(f, num_args, args); - result = m.mk_ite(c, e1, e2); - return BR_REWRITE3; - } - } - return BR_FAILED; - } - }; - - struct ite_hoister_cfg: public default_rewriter_cfg { - ite_hoister m_r; - bool rewrite_patterns() const { return false; } - br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - return m_r.mk_app_core(f, num, args, result); - } - ite_hoister_cfg(ast_manager & m, params_ref const & p):m_r(m) {} - }; - - class ite_hoister_star : public rewriter_tpl { - ite_hoister_cfg m_cfg; - public: - ite_hoister_star(ast_manager & m, params_ref const & p): - rewriter_tpl(m, false, m_cfg), - m_cfg(m, p) {} - }; - - void hoist_non_bool_if(expr_ref& fml) { - ast_manager& m = fml.get_manager(); - scoped_no_proof _sp(m); - params_ref p; - ite_hoister_star ite_rw(m, p); - expr_ref tmp(m); - ite_rw(fml, tmp); - fml = tmp; - } - class test_diff_logic { ast_manager& m; arith_util a; @@ -1441,7 +1379,6 @@ namespace pdr { } -template class rewriter_tpl; template class rewriter_tpl; diff --git a/src/muz/pdr/pdr_util.h b/src/muz/pdr/pdr_util.h index 446bde8aa..150cf2bb5 100644 --- a/src/muz/pdr/pdr_util.h +++ b/src/muz/pdr/pdr_util.h @@ -143,12 +143,6 @@ namespace pdr { */ void reduce_disequalities(model& model, unsigned threshold, expr_ref& fml); - /** - \brief hoist non-boolean if expressions. - */ - void hoist_non_bool_if(expr_ref& fml); - - /** \brief normalize coefficients in polynomials so that least coefficient is 1. */ diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index 07d256d9e..10fbc05c5 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -71,14 +71,15 @@ namespace opt { * add at-most-one constraint with blocking */ - bool step() { + lbool step() { + IF_VERBOSE(1, verbose_stream() << "(opt.max_sat step)\n";); expr_ref_vector assumptions(m), block_vars(m); for (unsigned i = 0; i < m_soft.size(); ++i) { assumptions.push_back(m.mk_not(m_aux[i].get())); } lbool is_sat = s.check_sat(assumptions.size(), assumptions.c_ptr()); if (is_sat != l_false) { - return true; + return is_sat; } ptr_vector core; @@ -102,7 +103,7 @@ namespace opt { s.assert_expr(m.mk_or(m_soft[i].get(), m_aux[i].get())); } assert_at_most_one(block_vars); - return false; + return l_false; } private: @@ -139,23 +140,28 @@ namespace opt { s.push(); fu_malik fm(m, s, soft_constraints); - while (!fm.step()); - - // Get a list of satisfying soft_constraints - model_ref model; - s.get_model(model); - - expr_ref_vector result(m); - for (unsigned i = 0; i < soft_constraints.size(); ++i) { - expr_ref val(m); - VERIFY(model->eval(soft_constraints[i].get(), val)); - if (!m.is_false(val)) { - result.push_back(soft_constraints[i].get()); - } - } - soft_constraints.reset(); - soft_constraints.append(result); + lbool is_sat = l_true; + do { + is_sat = fm.step(); + } + while (is_sat == l_false); + + if (is_sat == l_true) { + // Get a list of satisfying soft_constraints + model_ref model; + s.get_model(model); + expr_ref_vector result(m); + for (unsigned i = 0; i < soft_constraints.size(); ++i) { + expr_ref val(m); + VERIFY(model->eval(soft_constraints[i].get(), val)); + if (!m.is_false(val)) { + result.push_back(soft_constraints[i].get()); + } + } + soft_constraints.reset(); + soft_constraints.append(result); + } s.pop(1); } // We are done and soft_constraints has diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index cf0d5f5a6..ff01a4792 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -935,13 +935,13 @@ public: // Return true if there is an edge source --> target (also counting disabled edges). // If there is such edge, return its edge_id in parameter id. - bool get_edge_id(dl_var source, dl_var target, edge_id & id) { - edge_id_vector & edges = m_out_edges[source]; - typename edge_id_vector::iterator it = edges.begin(); - typename edge_id_vector::iterator end = edges.end(); + bool get_edge_id(dl_var source, dl_var target, edge_id & id) const { + edge_id_vector const & edges = m_out_edges[source]; + typename edge_id_vector::const_iterator it = edges.begin(); + typename edge_id_vector::const_iterator end = edges.end(); for (; it != end; ++it) { id = *it; - edge & e = m_edges[id]; + edge const & e = m_edges[id]; if (e.get_target() == target) { return true; } diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index a19cae0a2..8d3a9a75b 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -93,7 +93,7 @@ namespace smt { // Initialize the network with a feasible spanning tree void initialize(); - edge_id get_edge_id(dl_var source, dl_var target); + edge_id get_edge_id(dl_var source, dl_var target) const; void update_potentials(); @@ -112,6 +112,9 @@ namespace smt { std::string display_spanning_tree(); + bool edge_in_tree(edge_id id) const; + bool edge_in_tree(node src, node dst) const; + bool check_well_formed(); public: diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index 3b4b93d51..25ff6ee0c 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -137,7 +137,7 @@ namespace smt { } template - edge_id network_flow::get_edge_id(dl_var source, dl_var target) { + edge_id network_flow::get_edge_id(dl_var source, dl_var target) const { // m_upwards[source] decides which node is the real source edge_id id; VERIFY(m_upwards[source] ? m_graph.get_edge_id(source, target, id) : m_graph.get_edge_id(target, source, id)); @@ -234,6 +234,7 @@ namespace smt { m_delta = m_flows[e_id]; src = u; tgt = m_pred[u]; + SASSERT(edge_in_tree(src,tgt)); m_in_edge_dir = true; } } @@ -245,6 +246,7 @@ namespace smt { m_delta = m_flows[e_id]; src = u; tgt = m_pred[u]; + SASSERT(edge_in_tree(src,tgt)); m_in_edge_dir = false; } } @@ -267,10 +269,12 @@ namespace smt { node q = m_graph.get_target(m_entering_edge); node u = m_graph.get_source(m_leaving_edge); node v = m_graph.get_target(m_leaving_edge); + // v is parent of u so T_u does not contain root node if (m_pred[u] == v) { std::swap(u, v); } + SASSERT(m_pred[v] == u); for (node n = p; n != -1; n = m_pred[n]) { // q should be in T_v so swap p and q @@ -285,13 +289,10 @@ namespace smt { tout << u << ", " << v << ") leaves\n"; }); - node x = m_final[p]; - node y = m_thread[x]; - node z = m_final[q]; // Update m_pred (for nodes in the stem from q to v) node n = q; - node last = m_pred[v]; + node last = m_pred[v]; // review: m_pred[v] == u holds, so why not 'u'? node prev = p; while (n != last && n != -1) { node next = m_pred[n]; @@ -303,6 +304,11 @@ namespace smt { TRACE("network_flow", tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Upwards", m_upwards);); + node x = m_final[p]; + node y = m_thread[x]; + node z = m_final[q]; + + // Do this before updating data structures node gamma_p = m_pred[m_thread[m_final[p]]]; node gamma_v = m_pred[m_thread[m_final[v]]]; @@ -430,6 +436,8 @@ namespace smt { if (!bounded) return false; update_flows(); if (m_entering_edge != m_leaving_edge) { + SASSERT(edge_in_tree(m_leaving_edge)); + SASSERT(!edge_in_tree(m_entering_edge)); m_states[m_entering_edge] = BASIS; m_states[m_leaving_edge] = (m_flows[m_leaving_edge].is_zero()) ? LOWER : UPPER; update_spanning_tree(); @@ -494,6 +502,7 @@ namespace smt { } static int get_final(int root, svector const & thread, svector const & depth) { + // really final or should one take into account connected tree? int n = root; while (depth[thread[n]] > depth[root]) { n = thread[n]; @@ -501,19 +510,76 @@ namespace smt { return n; } + template + bool network_flow::edge_in_tree(edge_id id) const { + return m_states[id] == BASIS; + } + + template + bool network_flow::edge_in_tree(node src, node dst) const { + return edge_in_tree(get_edge_id(src,dst)); + } + + /** + \brief Check invariants of main data-structures. + + Spanning tree of m_graph + root is represented using: + + svector m_states; edge_id |-> edge_state + svector m_upwards; node |-> bool + svector m_pred; node |-> node + svector m_depth; node |-> int + svector m_thread; node |-> node + svector m_rev_thread; node |-> node + svector m_final; node |-> node + + m_thread[m_rev_thread[n]] == n for each node n + + Tree is determined by m_pred: + - m_pred[root] == -1 + - m_pred[n] = m != n for each node n, acyclic until reaching root. + - m_depth[m_pred[n]] + 1 == m_depth[n] for each n != root + + m_thread is a linked list traversing all nodes. + Furthermore, the nodes linked in m_thread follows a + depth-first traversal order. + + m_final[n] is deepest most node in a sub-tree rooted at n. + + */ + template bool network_flow::check_well_formed() { node root = m_pred.size()-1; + // Check that m_thread traverses each node. + // This gets checked using union-find as well. + svector found(m_thread.size(), false); + found[root] = true; + for (node x = m_thread[root]; x != root; x = m_thread[x]) { + found[x] = true; + } + for (unsigned i = 0; i < found.size(); ++i) { + SASSERT(found[i]); + } + + // m_pred is acyclic, and points to root. + SASSERT(m_pred[root] == -1); + SASSERT(m_depth[root] == 0); + for (node i = 0; i < root; ++i) { + SASSERT(m_depth[m_pred[i]] < m_depth[i]); + } + // m_upwards show correct direction for (unsigned i = 0; i < m_upwards.size(); ++i) { node p = m_pred[i]; edge_id id; - SASSERT(m_upwards[i] == m_graph.get_edge_id(i, p, id)); + SASSERT(!m_upwards[i] || m_graph.get_edge_id(i, p, id)); } // m_depth[x] denotes distance from x to the root node for (node x = m_thread[root]; x != root; x = m_thread[x]) { + SASSERT(m_depth[x] > 0); SASSERT(m_depth[x] == m_depth[m_pred[x]] + 1); } @@ -540,7 +606,7 @@ namespace smt { // All nodes belong to the same spanning tree for (unsigned i = 0; i < roots.size(); ++i) { - SASSERT(i == 0 ? roots[i] + roots.size() == 0 : roots[i] == 0); + SASSERT(roots[i] + roots.size() == 0 || roots[i] >= 0); } // m_flows are zero on non-basic edges diff --git a/src/tactic/core/blast_term_ite_tactic.cpp b/src/tactic/core/blast_term_ite_tactic.cpp new file mode 100644 index 000000000..c69849253 --- /dev/null +++ b/src/tactic/core/blast_term_ite_tactic.cpp @@ -0,0 +1,221 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + blast_term_ite_tactic.cpp + +Abstract: + + Blast term if-then-else by hoisting them up. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-11-4 + +Notes: + +--*/ +#include"tactical.h" +#include"defined_names.h" +#include"rewriter_def.h" +#include"filter_model_converter.h" +#include"cooperate.h" +#include"scoped_proof.h" + + + +// +// (f (if c1 (if c2 e1 e2) e3) b c) -> +// (if c1 (if c2 (f e1 b c) +// + + +class blast_term_ite_tactic : public tactic { + + struct rw_cfg : public default_rewriter_cfg { + ast_manager& m; + unsigned long long m_max_memory; // in bytes + unsigned m_num_fresh; // number of expansions + + rw_cfg(ast_manager & _m, params_ref const & p): + m(_m), + m_num_fresh(0) { + updt_params(p); + } + + void updt_params(params_ref const & p) { + m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX)); + } + + bool max_steps_exceeded(unsigned num_steps) const { + cooperate("blast term ite"); + if (memory::get_allocation_size() > m_max_memory) + throw tactic_exception(TACTIC_MAX_MEMORY_MSG); + return false; + } + + br_status mk_app_core(func_decl* f, unsigned num_args, expr* const* args, expr_ref& result) { + if (m.is_ite(f)) { + return BR_FAILED; + } + for (unsigned i = 0; i < num_args; ++i) { + expr* c, *t, *e; + if (!m.is_bool(args[i]) && m.is_ite(args[i], c, t, e)) { + expr_ref e1(m), e2(m); + ptr_vector args1(num_args, args); + args1[i] = t; + ++m_num_fresh; + e1 = m.mk_app(f, num_args, args1.c_ptr()); + if (t == e) { + result = e1; + return BR_REWRITE1; + } + args1[i] = e; + e2 = m.mk_app(f, num_args, args1.c_ptr()); + result = m.mk_app(f, num_args, args); + result = m.mk_ite(c, e1, e2); + return BR_REWRITE3; + } + } + return BR_FAILED; + } + + bool rewrite_patterns() const { return false; } + + br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { + return mk_app_core(f, num, args, result); + } + + }; + + struct rw : public rewriter_tpl { + rw_cfg m_cfg; + + rw(ast_manager & m, params_ref const & p): + rewriter_tpl(m, m.proofs_enabled(), m_cfg), + m_cfg(m, p) { + } + }; + + struct imp { + ast_manager & m; + rw m_rw; + + imp(ast_manager & _m, params_ref const & p): + m(_m), + m_rw(m, p) { + } + + void set_cancel(bool f) { + m_rw.set_cancel(f); + } + + void updt_params(params_ref const & p) { + m_rw.cfg().updt_params(p); + } + + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) { + SASSERT(g->is_well_sorted()); + mc = 0; pc = 0; core = 0; + tactic_report report("blast-term-ite", *g); + bool produce_proofs = g->proofs_enabled(); + + expr_ref new_curr(m); + proof_ref new_pr(m); + unsigned size = g->size(); + for (unsigned idx = 0; idx < size; idx++) { + expr * curr = g->form(idx); + m_rw(curr, new_curr, new_pr); + if (produce_proofs) { + proof * pr = g->pr(idx); + new_pr = m.mk_modus_ponens(pr, new_pr); + } + g->update(idx, new_curr, new_pr, g->dep(idx)); + } + report_tactic_progress(":blast-term-ite-consts", m_rw.m_cfg.m_num_fresh); + g->inc_depth(); + result.push_back(g.get()); + TRACE("blast_term_ite", g->display(tout);); + SASSERT(g->is_well_sorted()); + } + }; + + imp * m_imp; + params_ref m_params; +public: + blast_term_ite_tactic(ast_manager & m, params_ref const & p): + m_params(p) { + m_imp = alloc(imp, m, p); + } + + virtual tactic * translate(ast_manager & m) { + return alloc(blast_term_ite_tactic, m, m_params); + } + + virtual ~blast_term_ite_tactic() { + dealloc(m_imp); + } + + virtual void updt_params(params_ref const & p) { + m_params = p; + m_imp->m_rw.cfg().updt_params(p); + } + + virtual void collect_param_descrs(param_descrs & r) { + insert_max_memory(r); + insert_max_steps(r); + r.insert("max_args", CPK_UINT, + "(default: 128) maximum number of arguments (per application) that will be considered by the greedy (quadratic) heuristic."); + } + + virtual void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) { + (*m_imp)(in, result, mc, pc, core); + } + + virtual void cleanup() { + ast_manager & m = m_imp->m; + imp * d = m_imp; + #pragma omp critical (tactic_cancel) + { + m_imp = 0; + } + dealloc(d); + d = alloc(imp, m, m_params); + #pragma omp critical (tactic_cancel) + { + m_imp = d; + } + } + + virtual void set_cancel(bool f) { + if (m_imp) + m_imp->set_cancel(f); + } + + static void blast_term_ite(expr_ref& fml) { + ast_manager& m = fml.get_manager(); + scoped_no_proof _sp(m); + params_ref p; + rw ite_rw(m, p); + expr_ref tmp(m); + ite_rw(fml, tmp); + fml = tmp; + } +}; + +tactic * mk_blast_term_ite_tactic(ast_manager & m, params_ref const & p) { + return clean(alloc(blast_term_ite_tactic, m, p)); +} + +void blast_term_ite(expr_ref& fml) { + blast_term_ite_tactic::blast_term_ite(fml); +} diff --git a/src/tactic/core/blast_term_ite_tactic.h b/src/tactic/core/blast_term_ite_tactic.h new file mode 100644 index 000000000..6756b29d3 --- /dev/null +++ b/src/tactic/core/blast_term_ite_tactic.h @@ -0,0 +1,38 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + blast_term_ite_tactic.h + +Abstract: + + Blast term if-then-else by hoisting them up. + This is expensive but useful in some cases, such as + for enforcing constraints being in difference logic. + Use elim-term-ite elsewhere when possible. + + +Author: + + Nikolaj Bjorner (nbjorner) 2013-11-4 + +Notes: + +--*/ +#ifndef _BLAST_TERM_ITE_TACTIC_H_ +#define _BLAST_TERM_ITE_TACTIC_H_ + +#include"params.h" +class ast_manager; +class tactic; + +tactic * mk_blast_term_ite_tactic(ast_manager & m, params_ref const & p = params_ref()); + +/* + ADD_TACTIC("blast-term-ite", "blast term if-then-else by hoisting them.", "mk_blast_term_ite_tactic(m, p)") +*/ + +void blast_term_ite(expr_ref& fml); + +#endif From acb26d0cf9ce675d816f74d0f4b8446c2c0c767d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 4 Nov 2013 16:00:50 -0800 Subject: [PATCH 081/925] review of network flow Signed-off-by: Nikolaj Bjorner --- src/opt/fu_malik.cpp | 42 +++++++------- src/opt/opt_context.cpp | 1 + src/smt/network_flow.h | 9 ++- src/smt/network_flow_def.h | 111 ++++++++++++++++++++++++++---------- src/smt/smt_farkas_util.cpp | 2 +- 5 files changed, 111 insertions(+), 54 deletions(-) diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index 10fbc05c5..306b3e579 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -140,28 +140,28 @@ namespace opt { s.push(); fu_malik fm(m, s, soft_constraints); - lbool is_sat = l_true; + lbool is_sat = l_true; do { - is_sat = fm.step(); - } - while (is_sat == l_false); - - if (is_sat == l_true) { - // Get a list of satisfying soft_constraints - model_ref model; - s.get_model(model); - - expr_ref_vector result(m); - for (unsigned i = 0; i < soft_constraints.size(); ++i) { - expr_ref val(m); - VERIFY(model->eval(soft_constraints[i].get(), val)); - if (!m.is_false(val)) { - result.push_back(soft_constraints[i].get()); - } - } - soft_constraints.reset(); - soft_constraints.append(result); - } + is_sat = fm.step(); + } + while (is_sat == l_false); + + if (is_sat == l_true) { + // Get a list of satisfying soft_constraints + model_ref model; + s.get_model(model); + + expr_ref_vector result(m); + for (unsigned i = 0; i < soft_constraints.size(); ++i) { + expr_ref val(m); + VERIFY(model->eval(soft_constraints[i].get(), val)); + if (!m.is_false(val)) { + result.push_back(soft_constraints[i].get()); + } + } + soft_constraints.reset(); + soft_constraints.append(result); + } s.pop(1); } // We are done and soft_constraints has diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index e1b664f4c..fbc2981ca 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -60,6 +60,7 @@ namespace opt { expr_ref_vector fmls_copy(fmls); lbool is_sat; if (!fmls.empty()) { + // TBD: bug when cancel flag is set, fu_malik returns is_sat == l_true instead of l_undef if (is_maxsat_problem()) { is_sat = opt::fu_malik_maxsat(*s, fmls_copy); } diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index 8d3a9a75b..405b5c7c6 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -77,8 +77,6 @@ namespace smt { svector m_depth; // Store the pointer from node i to the next node in depth-first search order svector m_thread; - // Reverse orders of m_thread - svector m_rev_thread; // Store a final node of the sub tree rooted at node i svector m_final; @@ -115,6 +113,13 @@ namespace smt { bool edge_in_tree(edge_id id) const; bool edge_in_tree(node src, node dst) const; + bool is_ancestor_of(node ancestor, node child) const; + + /** + \brief find node that points to 'n' in m_thread + */ + node find_rev_thread(node n, node ancestor) const; + bool check_well_formed(); public: diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index 25ff6ee0c..6fa6ac03e 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -68,7 +68,6 @@ namespace smt { m_pred.resize(num_nodes); m_depth.resize(num_nodes); m_thread.resize(num_nodes); - m_rev_thread.resize(num_nodes); m_final.resize(num_nodes); m_step = 0; @@ -84,7 +83,6 @@ namespace smt { m_pred[root] = -1; m_depth[root] = 0; m_thread[root] = 0; - m_rev_thread[0] = root; m_final[root] = root - 1; m_potentials[root] = numeral::zero(); @@ -108,7 +106,6 @@ namespace smt { m_depth[i] = 1; m_thread[i] = i + 1; m_final[i] = i; - m_rev_thread[i + 1] = i; m_states[num_edges + i] = BASIS; node src = m_upwards[i] ? i : root; node tgt = m_upwards[i] ? root : i; @@ -128,7 +125,7 @@ namespace smt { TRACE("network_flow", { tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Threads", m_thread); - tout << pp_vector("Reverse Threads", m_rev_thread) << pp_vector("Last Successors", m_final); + tout << pp_vector("Last Successors", m_final); tout << pp_vector("Depths", m_depth) << pp_vector("Upwards", m_upwards); tout << pp_vector("Potentials", m_potentials) << pp_vector("Flows", m_flows); }); @@ -263,12 +260,63 @@ namespace smt { return false; } + template + bool network_flow::is_ancestor_of(node ancestor, node child) const { + for (node n = child; n != -1; n = m_pred[n]) { + // q should be in T_v so swap p and q + if (n == ancestor) { + return true; + } + } + return false; + } + + template + dl_var network_flow::find_rev_thread(node n, node ancestor) const { + while (m_thread[ancestor] != n) { + ancestor = m_thread[ancestor]; + } + return ancestor; + } + + /** + \brief add entering_edge, remove leaving_edge from spanning tree. + + Old tree: + root + / \ + x y + / \ / \ + u w' + | / + v w + / \ \ + z p + \ + q + + New tree: + root + / \ + x y + / \ / \ + u w' + / + v w + / \ \ + z p + \ / + q + + */ + template void network_flow::update_spanning_tree() { node p = m_graph.get_source(m_entering_edge); node q = m_graph.get_target(m_entering_edge); node u = m_graph.get_source(m_leaving_edge); node v = m_graph.get_target(m_leaving_edge); + bool q_upwards = false; // v is parent of u so T_u does not contain root node if (m_pred[u] == v) { @@ -276,13 +324,11 @@ namespace smt { } SASSERT(m_pred[v] == u); - for (node n = p; n != -1; n = m_pred[n]) { - // q should be in T_v so swap p and q - if (n == v) { - std::swap(p, q); - break; - } + if (is_ancestor_of(v, p)) { + std::swap(p, q); + q_upwards = true; } + SASSERT(is_ancestor_of(v, q)); TRACE("network_flow", { tout << "update_spanning_tree: (" << p << ", " << q << ") enters, ("; @@ -291,24 +337,34 @@ namespace smt { // Update m_pred (for nodes in the stem from q to v) - node n = q; - node last = m_pred[v]; // review: m_pred[v] == u holds, so why not 'u'? - node prev = p; - while (n != last && n != -1) { + // Note: m_pred[v] == u + // Initialize m_upwards[q] = q_upwards + + bool prev_upwards = q_upwards; + for (node n = q, prev = p; n != u; ) { + SASSERT(m_pred[n] != u || n == v); // the last processed node is v node next = m_pred[n]; - m_pred[n] = prev; - m_upwards[n] = !m_upwards[prev]; + m_pred[n] = prev; + std::swap(m_upwards[n], prev_upwards); + prev_upwards = !prev_upwards; // flip previous version of upwards. prev = n; n = next; + SASSERT(n != -1); } + // At this point m_pred and m_upwards have been updated. + TRACE("network_flow", tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Upwards", m_upwards);); + + // node x = m_final[p]; node y = m_thread[x]; node z = m_final[q]; - + // ---- + // update m_final. + // Do this before updating data structures node gamma_p = m_pred[m_thread[m_final[p]]]; node gamma_v = m_pred[m_thread[m_final[v]]]; @@ -322,7 +378,7 @@ namespace smt { break; } } - node phi = m_rev_thread[v]; + node phi = find_rev_thread(v, u); node delta = found_final_u ? phi : m_final[u]; TRACE("network_flow", tout << "Graft T_q and T_r'\n";); @@ -333,12 +389,13 @@ namespace smt { m_final[n] = z; } + // + m_thread[x] = q; - m_rev_thread[q] = x; m_thread[z] = y; - m_rev_thread[y] = z; // Increase depths of all children in T_q - last = m_thread[m_final[q]]; + node last = m_thread[m_final[q]]; + // NSB review: depth update looks wrong to me for (node n = q; n != last; n = m_thread[n]) { m_depth[n] += 1 + m_depth[p] - m_depth[q]; } @@ -347,7 +404,6 @@ namespace smt { // Update T_r' m_thread[phi] = theta; - m_rev_thread[theta] = phi; for (node n = u; n != gamma_v && n != -1; n = m_pred[n]) { TRACE("network_flow", tout << "2: m_final[" << n << "] |-> " << delta << "\n";); @@ -387,12 +443,8 @@ namespace smt { m_thread[m_final[q]] = prev; } - for (unsigned i = 0; i < m_thread.size(); ++i) { - m_rev_thread[m_thread[i]] = i; - } - TRACE("network_flow", { - tout << pp_vector("Threads", m_thread, true) << pp_vector("Reverse Threads", m_rev_thread); + tout << pp_vector("Threads", m_thread, true); }); } @@ -530,11 +582,8 @@ namespace smt { svector m_pred; node |-> node svector m_depth; node |-> int svector m_thread; node |-> node - svector m_rev_thread; node |-> node svector m_final; node |-> node - m_thread[m_rev_thread[n]] == n for each node n - Tree is determined by m_pred: - m_pred[root] == -1 - m_pred[n] = m != n for each node n, acyclic until reaching root. @@ -545,6 +594,8 @@ namespace smt { depth-first traversal order. m_final[n] is deepest most node in a sub-tree rooted at n. + + m_upwards direction of edge from i to m_pred[i] m_graph */ diff --git a/src/smt/smt_farkas_util.cpp b/src/smt/smt_farkas_util.cpp index eb854294b..c1a303299 100644 --- a/src/smt/smt_farkas_util.cpp +++ b/src/smt/smt_farkas_util.cpp @@ -11,7 +11,7 @@ Abstract: Author: - Nikolaj Bjorner (nbjorne) 2013-11-2. + Nikolaj Bjorner (nbjorner) 2013-11-2. Revision History: From 8b776569e0171950ed888ca62d505a9123200abf Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Tue, 5 Nov 2013 07:30:42 +0100 Subject: [PATCH 082/925] Add fix_depth --- src/smt/network_flow.h | 2 ++ src/smt/network_flow_def.h | 34 ++++++++++++++++++---------------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index 405b5c7c6..d24d6f91b 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -120,6 +120,8 @@ namespace smt { */ node find_rev_thread(node n, node ancestor) const; + void fix_depth(node start, node end); + bool check_well_formed(); public: diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index 6fa6ac03e..f2829e6a2 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -116,7 +116,6 @@ namespace smt { // Compute initial potentials node u = m_thread[root]; while (u != root) { - bool direction = m_upwards[u]; node v = m_pred[u]; edge_id e_id = get_edge_id(u, v); m_potentials[u] = m_potentials[v] + (m_upwards[u] ? - m_graph.get_weight(e_id) : m_graph.get_weight(e_id)); @@ -204,9 +203,7 @@ namespace smt { node source = m_graph.get_source(m_entering_edge); node target = m_graph.get_target(m_entering_edge); if (m_states[m_entering_edge] == UPPER) { - node temp = source; - source = target; - target = temp; + std::swap(source, target); } node u = source, v = target; while (u != v) { @@ -279,6 +276,18 @@ namespace smt { return ancestor; } + template + void network_flow::fix_depth(node start, node end) { + SASSERT(m_pred[start] != -1); + // Increase depths of all children in T_q by the same amount + int d = 1 + m_depth[m_pred[start]] - m_depth[start]; + do { + m_depth[start] += d; + start = m_thread[start]; + } + while (start != end); + } + /** \brief add entering_edge, remove leaving_edge from spanning tree. @@ -383,7 +392,6 @@ namespace smt { TRACE("network_flow", tout << "Graft T_q and T_r'\n";); - // Graft T_q and T_r' for (node n = p; n != gamma_p && n != -1; n = m_pred[n]) { TRACE("network_flow", tout << "1: m_final[" << n << "] |-> " << z << "\n";); m_final[n] = z; @@ -393,16 +401,11 @@ namespace smt { m_thread[x] = q; m_thread[z] = y; - // Increase depths of all children in T_q - node last = m_thread[m_final[q]]; - // NSB review: depth update looks wrong to me - for (node n = q; n != last; n = m_thread[n]) { - m_depth[n] += 1 + m_depth[p] - m_depth[q]; - } + + fix_depth(q, m_final[q]); TRACE("network_flow", tout << "Update T_r'\n";); - // Update T_r' m_thread[phi] = theta; for (node n = u; n != gamma_v && n != -1; n = m_pred[n]) { @@ -412,7 +415,6 @@ namespace smt { TRACE("network_flow", tout << pp_vector("Last Successors", m_final, true) << pp_vector("Depths", m_depth);); - // Reroot T_v at q if (v != q) { TRACE("network_flow", tout << "Reroot T_v at q\n";); @@ -553,10 +555,10 @@ namespace smt { roots[y] = x; } - static int get_final(int root, svector const & thread, svector const & depth) { + static int get_final(int start, svector const & thread, svector const & depth) { // really final or should one take into account connected tree? - int n = root; - while (depth[thread[n]] > depth[root]) { + int n = start; + while (depth[thread[n]] > depth[start]) { n = thread[n]; } return n; From 2853b322ca79044d4cb09c38ea7102ef08488c29 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 5 Nov 2013 01:30:34 -0800 Subject: [PATCH 083/925] sketch cardinality plugin module Signed-off-by: Nikolaj Bjorner --- src/ast/card_decl_plugin.cpp | 72 ++++++++++ src/ast/card_decl_plugin.h | 83 +++++++++++ src/opt/theory_card.cpp | 272 +++++++++++++++++++++++++++++++++++ src/opt/theory_card.h | 78 ++++++++++ src/opt/weighted_maxsat.cpp | 2 +- 5 files changed, 506 insertions(+), 1 deletion(-) create mode 100644 src/ast/card_decl_plugin.cpp create mode 100644 src/ast/card_decl_plugin.h create mode 100644 src/opt/theory_card.cpp create mode 100644 src/opt/theory_card.h diff --git a/src/ast/card_decl_plugin.cpp b/src/ast/card_decl_plugin.cpp new file mode 100644 index 000000000..bbf4b28bd --- /dev/null +++ b/src/ast/card_decl_plugin.cpp @@ -0,0 +1,72 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + card_decl_plugin.cpp + +Abstract: + + Cardinality Constraints plugin + +Author: + + Nikolaj Bjorner (nbjorner) 2013-05-11 + +Revision History: + +--*/ + +#include "card_decl_plugin.h" + +card_decl_plugin::card_decl_plugin(): + m_at_most_sym("at_most") +{} + +func_decl * card_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) { + SASSERT(m_manager); + ast_manager& m = *m_manager; + for (unsigned i = 0; i < arity; ++i) { + if (!m.is_bool(domain[i])) { + m.raise_exception("invalid non-Boolean sort applied to 'at_most_k'"); + } + } + if (num_parameters != 1 || !parameters[0].is_int() || parameters[0].get_int() < 0) { + m.raise_exception("function 'at_most_k' expects one non-negative integer parameter"); + } + func_decl_info info(m_family_id, OP_AT_MOST_K, 1, parameters); + return m.mk_func_decl(m_at_most_sym, arity, domain, m.mk_bool_sort(), info); +} + +void card_decl_plugin::get_op_names(svector & op_names, symbol const & logic) { + if (logic == symbol::null) { + op_names.push_back(builtin_name("at-most-k", OP_AT_MOST_K)); + } +} + + +app * card_util::mk_at_most_k(unsigned num_args, expr * const * args, unsigned k) { + parameter param(1); + return m.mk_app(m_fid, OP_AT_MOST_K, 1, ¶m, num_args, args, m.mk_bool_sort()); +} + +bool card_util::is_at_most_k(app *a) const { + return is_app_of(a, m_fid, OP_AT_MOST_K); +} + +bool card_util::is_at_most_k(app *a, unsigned& k) const { + if (is_at_most_k(a)) { + k = get_k(a); + return true; + } + else { + return false; + } +} + +unsigned card_util::get_k(app *a) const { + SASSERT(is_at_most_k(a)); + return static_cast(a->get_decl()->get_parameter(0).get_int()); +} + diff --git a/src/ast/card_decl_plugin.h b/src/ast/card_decl_plugin.h new file mode 100644 index 000000000..9d4e95b13 --- /dev/null +++ b/src/ast/card_decl_plugin.h @@ -0,0 +1,83 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + card_decl_plugin.h + +Abstract: + + Cardinality Constraints plugin + +Author: + + Nikolaj Bjorner (nbjorner) 2013-05-11 + +Notes: + + + (at-most-k x1 .... x_n) means x1 + ... + x_n <= k + +hence: + + (not (at-most-k x1 .... x_n)) means x1 + ... + x_n >= k + 1 + + +--*/ +#ifndef _CARD_DECL_PLUGIN_H_ +#define _CARD_DECL_PLUGIN_H_ + +#include"ast.h" + + + +enum card_op_kind { + OP_AT_MOST_K, + LAST_CARD_OP +}; + + +class card_decl_plugin : public decl_plugin { + symbol m_at_most_sym; + func_decl * mk_at_most(unsigned arity, unsigned k); +public: + card_decl_plugin(); + virtual ~card_decl_plugin() {} + + virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) { + UNREACHABLE(); + return 0; + } + + virtual decl_plugin * mk_fresh() { + return alloc(card_decl_plugin); + } + + // + // Contract for func_decl: + // parameters[0] - integer (at most k elements) + // all sorts are Booleans + virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range); + virtual void get_op_names(svector & op_names, symbol const & logic); + virtual void get_sort_names(svector & sort_names, symbol const & logic); + virtual expr * get_some_value(sort * s); + virtual bool is_fully_interp(sort const * s) const; +}; + + +class card_util { + ast_manager & m; + family_id m_fid; +public: + card_util(ast_manager& m):m(m), m_fid(m.mk_family_id("card")) {} + ast_manager & get_manager() const { return m; } + app * mk_at_most_k(unsigned num_args, expr * const * args, unsigned k); + bool is_at_most_k(app *a) const; + bool is_at_most_k(app *a, unsigned& k) const; + unsigned get_k(app *a) const; +}; + + +#endif /* _CARD_DECL_PLUGIN_H_ */ + diff --git a/src/opt/theory_card.cpp b/src/opt/theory_card.cpp new file mode 100644 index 000000000..f303306b3 --- /dev/null +++ b/src/opt/theory_card.cpp @@ -0,0 +1,272 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + theory_card.cpp + +Abstract: + + Cardinality theory plugin. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-11-05 + +Notes: + + - count number of clauses per cardinality constraint. + - when number of conflicts exceeds n^2 or n*log(n), then create a sorting circuit. + where n is the arity of the cardinality constraint. + - extra: do clauses get re-created? keep track of gc status of created clauses. + +--*/ + +#include "theory_card.h" +#include "smt_context.h" + +namespace smt { + + theory_card::theory_card(ast_manager& m): + theory(m.mk_family_id("card")), + m_util(m) + {} + + theory_card::~theory_card() { + reset_eh(); + } + + theory * theory_card::mk_fresh(context * new_ctx) { + return alloc(theory_card, new_ctx->get_manager()); + } + + bool theory_card::internalize_atom(app * atom, bool gate_ctx) { + context& ctx = get_context(); + ast_manager& m = get_manager(); + unsigned num_args = atom->get_num_args(); + SASSERT(m_util.is_at_most_k(atom)); + unsigned k = m_util.get_k(atom); + bool_var bv; + if (ctx.b_internalized(atom)) { + return false; + } + SASSERT(!ctx.b_internalized(atom)); + bv = ctx.mk_bool_var(atom); + card* c = alloc(card, atom, bv, k); + add_card(c); + // + // TBD take repeated bv into account. + // base case: throw exception. + // refinement: adjust argument list and k for non-repeated values. + // + for (unsigned i = 0; i < num_args; ++i) { + expr* arg = atom->get_arg(i); + if (!ctx.b_internalized(arg)) { + bv = ctx.mk_bool_var(arg); + } + else { + bv = ctx.get_bool_var(arg); + } + ctx.set_var_theory(bv, get_id()); + add_watch(bv, c); + } + return true; + } + + void theory_card::add_watch(bool_var bv, card* c) { + ptr_vector* cards; + if (!m_watch.find(bv, cards)) { + cards = alloc(ptr_vector); + m_watch.insert(bv, cards); + } + cards->push_back(c); + m_watch_trail.push_back(bv); + } + + + void theory_card::reset_eh() { + + // m_watch; + u_map*>::iterator it = m_watch.begin(), end = m_watch.end(); + for (; it != end; ++it) { + dealloc(it->m_value); + } + u_map::iterator itc = m_cards.begin(), endc = m_cards.end(); + for (; itc != endc; ++itc) { + dealloc(itc->m_value); + } + m_watch.reset(); + m_cards.reset(); + m_cards_trail.reset(); + m_cards_lim.reset(); + m_watch_trail.reset(); + m_watch_lim.reset(); + } + + void theory_card::assign_eh(bool_var v, bool is_true) { + context& ctx = get_context(); + ptr_vector* cards = 0; + card* c = 0; + if (m_watch.find(v, cards)) { + for (unsigned i = 0; i < cards->size(); ++i) { + c = (*cards)[i]; + app* atm = c->m_atom; + // + // is_true && m_t + 1 > k -> force false + // !is_true && m_f + 1 >= arity - k -> force true + // + if (is_true && c->m_t >= c->m_k) { + unsigned k = c->m_k; + // force false + switch (ctx.get_assignment(c->m_bv)) { + case l_true: + case l_undef: { + literal_vector& lits = get_lits(); + lits.push_back(literal(v)); + for (unsigned i = 0; i < atm->get_num_args() && lits.size() <= k + 1; ++i) { + expr* arg = atm->get_arg(i); + if (ctx.get_assignment(arg) == l_true) { + lits.push_back(literal(ctx.get_bool_var(arg))); + } + } + SASSERT(lits.size() == k + 1); + add_clause(lits); + break; + } + default: + break; + } + } + else if (!is_true && c->m_k >= atm->get_num_args() - c->m_f) { + // forced true + switch (ctx.get_assignment(c->m_bv)) { + case l_false: + case l_undef: { + literal_vector& lits = get_lits(); + lits.push_back(~literal(v)); + for (unsigned i = 0; i < atm->get_num_args(); ++i) { + expr* arg = atm->get_arg(i); + if (ctx.get_assignment(arg) == l_false) { + lits.push_back(~literal(ctx.get_bool_var(arg))); + } + } + add_clause(lits); + break; + } + default: + break; + } + } + else if (is_true) { + ctx.push_trail(value_trail(c->m_t)); + c->m_t++; + } + else { + ctx.push_trail(value_trail(c->m_f)); + c->m_f++; + } + } + } + if (m_cards.find(v, c)) { + app* atm = to_app(ctx.bool_var2expr(v)); + SASSERT(atm->get_num_args() >= c->m_f + c->m_t); + bool_var bv; + + // at most k + // propagate false to children that are not yet assigned. + // v & t1 & ... & tk => ~l_j + if (is_true && c->m_k <= c->m_t) { + + literal_vector& lits = get_lits(); + lits.push_back(literal(v)); + bool done = false; + for (unsigned i = 0; !done && i < atm->get_num_args(); ++i) { + bv = ctx.get_bool_var(atm->get_arg(i)); + if (ctx.get_assignment(bv) == l_true) { + lits.push_back(literal(bv)); + } + if (lits.size() > c->m_k + 1) { + add_clause(lits); + done = true; + } + } + SASSERT(done || lits.size() == c->m_k + 1); + for (unsigned i = 0; !done && i < atm->get_num_args(); ++i) { + bv = ctx.get_bool_var(atm->get_arg(i)); + if (ctx.get_assignment(bv) == l_undef) { + lits.push_back(literal(bv)); + add_clause(lits); + lits.pop_back(); + } + } + } + // at least k+1: + // !v & !f1 & .. & !f_m => l_j + // for m + k + 1 = arity() + if (!is_true && atm->get_num_args() == 1 + c->m_f + c->m_k) { + literal_vector& lits = get_lits(); + lits.push_back(~literal(v)); + bool done = false; + for (unsigned i = 0; !done && i < atm->get_num_args(); ++i) { + bv = ctx.get_bool_var(atm->get_arg(i)); + if (ctx.get_assignment(bv) == l_false) { + lits.push_back(~literal(bv)); + } + if (lits.size() > c->m_k + 1) { + add_clause(lits); + done = true; + } + } + SASSERT(done || lits.size() == c->m_k + 1); + for (unsigned i = 0; !done && i < atm->get_num_args(); ++i) { + bv = ctx.get_bool_var(atm->get_arg(i)); + if (ctx.get_assignment(bv) != l_false) { + lits.push_back(~literal(bv)); + add_clause(lits); + lits.pop_back(); + } + } + } + } + } + + void theory_card::init_search_eh() { + + } + + void theory_card::push_scope_eh() { + m_watch_lim.push_back(m_watch_trail.size()); + m_cards_lim.push_back(m_cards_trail.size()); + } + + void theory_card::pop_scope_eh(unsigned num_scopes) { + unsigned sz = m_watch_lim[m_watch_lim.size()-num_scopes]; + for (unsigned i = m_watch_trail.size(); i > sz; ) { + --i; + ptr_vector* cards = 0; + VERIFY(m_watch.find(m_watch_trail[i], cards)); + SASSERT(cards && !cards->empty()); + cards->pop_back(); + } + m_watch_lim.resize(m_watch_lim.size()-num_scopes); + sz = m_cards_lim[m_cards_lim.size()-num_scopes]; + for (unsigned i = m_cards_trail.size(); i > sz; ) { + --i; + SASSERT(m_cards.contains(m_cards_trail[i])); + m_cards.remove(m_cards_trail[i]); + } + m_cards_lim.resize(m_cards_lim.size()-num_scopes); + } + + + literal_vector& theory_card::get_lits() { + m_literals.reset(); + return m_literals; + } + + void theory_card::add_clause(literal_vector const& lits) { + context& ctx = get_context(); + ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); + } + +} diff --git a/src/opt/theory_card.h b/src/opt/theory_card.h new file mode 100644 index 000000000..f38084292 --- /dev/null +++ b/src/opt/theory_card.h @@ -0,0 +1,78 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + theory_card.h + +Abstract: + + Cardinality theory plugin. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-11-05 + +Notes: + + This custom theory handles cardinality constraints + It performs unit propagation and switches to creating + sorting circuits if it keeps having to propagate (create new clauses). +--*/ + +#include "smt_theory.h" +#include "card_decl_plugin.h" + +namespace smt { + class theory_card : public theory { + struct card { + unsigned m_k; + bool_var m_bv; + unsigned m_t; + unsigned m_f; + app* m_atom; + card(app* a, bool_var bv, unsigned k): + m_k(k), m_bv(bv), m_atom(a), m_t(0), m_f(0) + {} + }; + + u_map*> m_watch; // use-list of literals. + u_map m_cards; // bool_var |-> card + unsigned_vector m_cards_trail; + unsigned_vector m_cards_lim; + unsigned_vector m_watch_trail; + unsigned_vector m_watch_lim; + literal_vector m_literals; + card_util m_util; + + void add_watch(bool_var bv, card* c); + + void add_card(card* c) { + m_cards.insert(c->m_bv, c); + m_cards_trail.push_back(c->m_bv); + } + void add_clause(literal_vector const& lits); + literal_vector& get_lits(); + + public: + theory_card(ast_manager& m); + + virtual ~theory_card(); + + virtual theory * mk_fresh(context * new_ctx); + virtual bool internalize_atom(app * atom, bool gate_ctx); + virtual bool internalize_term(app * term) { UNREACHABLE(); return false; } + virtual void new_eq_eh(theory_var v1, theory_var v2) { } + virtual void new_diseq_eh(theory_var v1, theory_var v2) { } + virtual bool use_diseqs() const { return false; } + virtual bool build_models() const { return false; } + virtual final_check_status final_check_eh() { return FC_DONE; } + + virtual void reset_eh(); + virtual void assign_eh(bool_var v, bool is_true); + virtual void init_search_eh(); + virtual void push_scope_eh(); + virtual void pop_scope_eh(unsigned num_scopes); + + }; +}; diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 81aa42586..204e6d656 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -3,7 +3,7 @@ Copyright (c) 2013 Microsoft Corporation Module Name: - weighted_maxsat.h + weighted_maxsat.cpp Abstract: Weighted MAXSAT module From 9467806a5caa2310a94c4c79ee666d7639c3887e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 5 Nov 2013 09:39:28 -0800 Subject: [PATCH 084/925] debugging cardinality theory Signed-off-by: Nikolaj Bjorner --- src/ast/card_decl_plugin.cpp | 8 ++++---- src/ast/card_decl_plugin.h | 5 ----- src/ast/reg_decl_plugins.cpp | 4 ++++ src/cmd_context/cmd_context.cpp | 3 +++ src/smt/smt_setup.cpp | 6 ++++++ src/smt/smt_setup.h | 2 +- src/{opt => smt}/theory_card.cpp | 16 +++++++++++----- src/{opt => smt}/theory_card.h | 0 8 files changed, 29 insertions(+), 15 deletions(-) rename src/{opt => smt}/theory_card.cpp (94%) rename src/{opt => smt}/theory_card.h (100%) diff --git a/src/ast/card_decl_plugin.cpp b/src/ast/card_decl_plugin.cpp index bbf4b28bd..20c9af09f 100644 --- a/src/ast/card_decl_plugin.cpp +++ b/src/ast/card_decl_plugin.cpp @@ -20,7 +20,7 @@ Revision History: #include "card_decl_plugin.h" card_decl_plugin::card_decl_plugin(): - m_at_most_sym("at_most") + m_at_most_sym("at-most") {} func_decl * card_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, @@ -29,11 +29,11 @@ func_decl * card_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, ast_manager& m = *m_manager; for (unsigned i = 0; i < arity; ++i) { if (!m.is_bool(domain[i])) { - m.raise_exception("invalid non-Boolean sort applied to 'at_most_k'"); + m.raise_exception("invalid non-Boolean sort applied to 'at-most'"); } } if (num_parameters != 1 || !parameters[0].is_int() || parameters[0].get_int() < 0) { - m.raise_exception("function 'at_most_k' expects one non-negative integer parameter"); + m.raise_exception("function 'at-most' expects one non-negative integer parameter"); } func_decl_info info(m_family_id, OP_AT_MOST_K, 1, parameters); return m.mk_func_decl(m_at_most_sym, arity, domain, m.mk_bool_sort(), info); @@ -41,7 +41,7 @@ func_decl * card_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, void card_decl_plugin::get_op_names(svector & op_names, symbol const & logic) { if (logic == symbol::null) { - op_names.push_back(builtin_name("at-most-k", OP_AT_MOST_K)); + op_names.push_back(builtin_name(m_at_most_sym.bare_str(), OP_AT_MOST_K)); } } diff --git a/src/ast/card_decl_plugin.h b/src/ast/card_decl_plugin.h index 9d4e95b13..3529a1a04 100644 --- a/src/ast/card_decl_plugin.h +++ b/src/ast/card_decl_plugin.h @@ -28,8 +28,6 @@ hence: #define _CARD_DECL_PLUGIN_H_ #include"ast.h" - - enum card_op_kind { OP_AT_MOST_K, @@ -60,9 +58,6 @@ public: virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range); virtual void get_op_names(svector & op_names, symbol const & logic); - virtual void get_sort_names(svector & sort_names, symbol const & logic); - virtual expr * get_some_value(sort * s); - virtual bool is_fully_interp(sort const * s) const; }; diff --git a/src/ast/reg_decl_plugins.cpp b/src/ast/reg_decl_plugins.cpp index ab1844e07..541964038 100644 --- a/src/ast/reg_decl_plugins.cpp +++ b/src/ast/reg_decl_plugins.cpp @@ -25,6 +25,7 @@ Revision History: #include"dl_decl_plugin.h" #include"seq_decl_plugin.h" #include"float_decl_plugin.h" +#include"card_decl_plugin.h" void reg_decl_plugins(ast_manager & m) { if (!m.get_plugin(m.mk_family_id(symbol("arith")))) { @@ -48,4 +49,7 @@ void reg_decl_plugins(ast_manager & m) { if (!m.get_plugin(m.mk_family_id(symbol("float")))) { m.register_plugin(symbol("float"), alloc(float_decl_plugin)); } + if (!m.get_plugin(m.mk_family_id(symbol("card")))) { + m.register_plugin(symbol("card"), alloc(card_decl_plugin)); + } } diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 01536d78e..626272412 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -25,6 +25,7 @@ Notes: #include"datatype_decl_plugin.h" #include"seq_decl_plugin.h" #include"float_decl_plugin.h" +#include"card_decl_plugin.h" #include"ast_pp.h" #include"var_subst.h" #include"pp.h" @@ -529,6 +530,7 @@ bool cmd_context::logic_has_floats() const { return !has_logic() || m_logic == "QF_FPA" || m_logic == "QF_FPABV"; } + bool cmd_context::logic_has_array_core(symbol const & s) const { return s == "QF_AX" || @@ -571,6 +573,7 @@ void cmd_context::init_manager_core(bool new_manager) { register_plugin(symbol("datatype"), alloc(datatype_decl_plugin), logic_has_datatype()); register_plugin(symbol("seq"), alloc(seq_decl_plugin), logic_has_seq()); register_plugin(symbol("float"), alloc(float_decl_plugin), logic_has_floats()); + register_plugin(symbol("card"), alloc(card_decl_plugin), !has_logic()); } else { // the manager was created by an external module, we must register all plugins available in the manager. diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 52ad14155..90694b29a 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -31,6 +31,7 @@ Revision History: #include"theory_dummy.h" #include"theory_dl.h" #include"theory_seq_empty.h" +#include"theory_card.h" namespace smt { @@ -790,6 +791,10 @@ namespace smt { m_context.register_plugin(alloc(theory_seq_empty, m_manager)); } + void setup::setup_card() { + m_context.register_plugin(alloc(theory_card, m_manager)); + } + void setup::setup_unknown() { setup_arith(); setup_arrays(); @@ -797,6 +802,7 @@ namespace smt { setup_datatypes(); setup_dl(); setup_seq(); + setup_card(); } void setup::setup_unknown(static_features & st) { diff --git a/src/smt/smt_setup.h b/src/smt/smt_setup.h index e0188537e..91b48dbe3 100644 --- a/src/smt/smt_setup.h +++ b/src/smt/smt_setup.h @@ -92,7 +92,7 @@ namespace smt { void setup_arith(); void setup_dl(); void setup_seq(); - void setup_instgen(); + void setup_card(); void setup_i_arith(); void setup_mi_arith(); public: diff --git a/src/opt/theory_card.cpp b/src/smt/theory_card.cpp similarity index 94% rename from src/opt/theory_card.cpp rename to src/smt/theory_card.cpp index f303306b3..13b9e93c3 100644 --- a/src/opt/theory_card.cpp +++ b/src/smt/theory_card.cpp @@ -67,7 +67,12 @@ namespace smt { else { bv = ctx.get_bool_var(arg); } - ctx.set_var_theory(bv, get_id()); + if (null_theory_var == ctx.get_var_theory(bv)) { + ctx.set_var_theory(bv, get_id()); + } + else { + SASSERT(ctx.get_var_theory(bv) == get_id()); // TBD, fishy + } add_watch(bv, c); } return true; @@ -122,11 +127,11 @@ namespace smt { case l_true: case l_undef: { literal_vector& lits = get_lits(); - lits.push_back(literal(v)); - for (unsigned i = 0; i < atm->get_num_args() && lits.size() <= k + 1; ++i) { + lits.push_back(~literal(c->m_bv)); + for (unsigned i = 0; i < atm->get_num_args() && lits.size() < k + 1; ++i) { expr* arg = atm->get_arg(i); if (ctx.get_assignment(arg) == l_true) { - lits.push_back(literal(ctx.get_bool_var(arg))); + lits.push_back(~literal(ctx.get_bool_var(arg))); } } SASSERT(lits.size() == k + 1); @@ -143,7 +148,7 @@ namespace smt { case l_false: case l_undef: { literal_vector& lits = get_lits(); - lits.push_back(~literal(v)); + lits.push_back(~literal(c->m_bv)); for (unsigned i = 0; i < atm->get_num_args(); ++i) { expr* arg = atm->get_arg(i); if (ctx.get_assignment(arg) == l_false) { @@ -266,6 +271,7 @@ namespace smt { void theory_card::add_clause(literal_vector const& lits) { context& ctx = get_context(); + TRACE("card", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";); ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); } diff --git a/src/opt/theory_card.h b/src/smt/theory_card.h similarity index 100% rename from src/opt/theory_card.h rename to src/smt/theory_card.h From bd33e466c2cdbb77dfe270bc916eedf9b85c880d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 5 Nov 2013 16:10:51 -0800 Subject: [PATCH 085/925] network update Signed-off-by: Nikolaj Bjorner --- src/smt/network_flow.h | 6 +- src/smt/network_flow_def.h | 283 ++++++++++++++++--------- src/smt/theory_card.cpp | 420 +++++++++++++++++++++++++++++++++---- src/smt/theory_card.h | 6 +- 4 files changed, 578 insertions(+), 137 deletions(-) diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index d24d6f91b..ce9ce385a 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -118,12 +118,16 @@ namespace smt { /** \brief find node that points to 'n' in m_thread */ - node find_rev_thread(node n, node ancestor) const; + node find_rev_thread(node n) const; void fix_depth(node start, node end); + void swap_order(node q, node v); + bool check_well_formed(); + bool is_preorder_traversal(node start, node end); + public: network_flow(graph & g, vector const & balances); diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index f2829e6a2..079a5ae70 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -21,6 +21,7 @@ Notes: #define _NETWORK_FLOW_DEF_H_ #include"network_flow.h" +#include"uint_set.h" namespace smt { @@ -269,7 +270,9 @@ namespace smt { } template - dl_var network_flow::find_rev_thread(node n, node ancestor) const { + dl_var network_flow::find_rev_thread(node n) const { + node ancestor = m_pred[n]; + SASSERT(ancestor != -1); while (m_thread[ancestor] != n) { ancestor = m_thread[ancestor]; } @@ -279,21 +282,19 @@ namespace smt { template void network_flow::fix_depth(node start, node end) { SASSERT(m_pred[start] != -1); - // Increase depths of all children in T_q by the same amount - int d = 1 + m_depth[m_pred[start]] - m_depth[start]; - do { - m_depth[start] += d; - start = m_thread[start]; + m_depth[start] = m_depth[m_pred[start]]+1; + while (start != end) { + start = m_thread[start]; + m_depth[start] = m_depth[m_pred[start]]+1; } - while (start != end); } /** \brief add entering_edge, remove leaving_edge from spanning tree. - Old tree: - root - / \ + Old tree: New tree: + root root + / \ / \ x y / \ / \ u w' @@ -304,9 +305,6 @@ namespace smt { \ q - New tree: - root - / \ x y / \ / \ u w' @@ -350,6 +348,7 @@ namespace smt { // Initialize m_upwards[q] = q_upwards bool prev_upwards = q_upwards; +#if 0 for (node n = q, prev = p; n != u; ) { SASSERT(m_pred[n] != u || n == v); // the last processed node is v node next = m_pred[n]; @@ -360,96 +359,79 @@ namespace smt { n = next; SASSERT(n != -1); } +#else + node old_pred = m_pred[q]; + m_pred[q] = p; + for (node n = q; n != u; ) { + SASSERT(old_pred != u || n == v); // the last processed node is v + SASSERT(-1 != m_pred[old_pred]); + node next_old_pred = m_pred[old_pred]; + swap_order(n, old_pred); + std::swap(m_upwards[n], prev_upwards); + prev_upwards = !prev_upwards; // flip previous version of upwards. + n = old_pred; + old_pred = next_old_pred; + } - // At this point m_pred and m_upwards have been updated. - - TRACE("network_flow", tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Upwards", m_upwards);); +#endif - - // - node x = m_final[p]; - node y = m_thread[x]; - node z = m_final[q]; - - // ---- - // update m_final. - - // Do this before updating data structures - node gamma_p = m_pred[m_thread[m_final[p]]]; - node gamma_v = m_pred[m_thread[m_final[v]]]; - node theta = m_thread[m_final[v]]; - - // Check that f(u) is not in T_v - bool found_final_u = false; - for (node n = v; n != theta; n = m_thread[n]) { - if (n == m_final[u]) { - found_final_u = true; - break; - } - } - node phi = find_rev_thread(v, u); - node delta = found_final_u ? phi : m_final[u]; - - TRACE("network_flow", tout << "Graft T_q and T_r'\n";); - - for (node n = p; n != gamma_p && n != -1; n = m_pred[n]) { - TRACE("network_flow", tout << "1: m_final[" << n << "] |-> " << z << "\n";); - m_final[n] = z; - } - - // - - m_thread[x] = q; - m_thread[z] = y; + // m_thread and m_final were updated. + // update the depth. fix_depth(q, m_final[q]); - TRACE("network_flow", tout << "Update T_r'\n";); - - m_thread[phi] = theta; - - for (node n = u; n != gamma_v && n != -1; n = m_pred[n]) { - TRACE("network_flow", tout << "2: m_final[" << n << "] |-> " << delta << "\n";); - m_final[n] = delta; - } - - TRACE("network_flow", tout << pp_vector("Last Successors", m_final, true) << pp_vector("Depths", m_depth);); - - if (v != q) { - TRACE("network_flow", tout << "Reroot T_v at q\n";); - - node alpha1, alpha2; - node prev = q; - for (node n = v; n != q && n != -1; n = m_pred[n]) { - // Find all immediate successors of n - node t1 = m_thread[n]; - node t2 = m_thread[m_final[t1]]; - node t3 = m_thread[m_final[t2]]; - if (t1 == m_pred[n]) { - alpha1 = t2; - alpha2 = t3; - } - else if (t2 == m_pred[n]) { - alpha1 = t1; - alpha2 = t3; - } - else { - alpha1 = t1; - alpha2 = t2; - } - m_thread[n] = alpha1; - m_thread[m_final[alpha1]] = alpha2; - m_thread[m_final[alpha2]] = prev; - prev = n; - } - m_thread[m_final[q]] = prev; - } - TRACE("network_flow", { tout << pp_vector("Threads", m_thread, true); }); } + /** + swap v and q in tree. + - fixup m_final + - fixup m_thread + - fixup m_pred + + Case 1: final(q) == final(v) + ------- + Old thread: prev -> v -*-> alpha -> q -*-> final(q) -> next + New thread: prev -> q -*-> final(q) -> v -*-> alpha -> next + + Case 2: final(q) != final(v) + ------- + Old thread: prev -> v -*-> alpha -> q -*-> final(q) -> beta -*-> final(v) -> next + New thread: prev -> q -*-> final(q) -> v -*-> alpha -> beta -*-> final(v) -> next + + */ + + template + void network_flow::swap_order(node q, node v) { + SASSERT(q != v); + SASSERT(m_pred[q] == v); + SASSERT(is_preorder_traversal(v, m_final[v])); + node prev = find_rev_thread(v); + node final_q = m_final[q]; + node final_v = m_final[v]; + node next = m_thread[final_v]; + node alpha = find_rev_thread(q); + + if (final_q == final_v) { + m_thread[final_q] = v; + m_thread[alpha] = next; + m_final[q] = alpha; + m_final[v] = alpha; + } + else { + node beta = m_thread[final_q]; + m_thread[final_q] = v; + m_thread[alpha] = beta; + m_final[q] = final_v; + } + m_thread[prev] = q; + m_pred[v] = q; + SASSERT(is_preorder_traversal(q, m_final[q])); + } + + template std::string network_flow::display_spanning_tree() { ++m_step;; @@ -595,7 +577,8 @@ namespace smt { Furthermore, the nodes linked in m_thread follows a depth-first traversal order. - m_final[n] is deepest most node in a sub-tree rooted at n. + m_final[n] is the last node in depth-first traversal order, + starting from n, that is still a child of n. m_upwards direction of edge from i to m_pred[i] m_graph @@ -670,6 +653,118 @@ namespace smt { return true; } + template + bool network_flow::is_preorder_traversal(node start, node end) { + + // get children of start: + uint_set children; + children.insert(start); + node root = m_pred.size()-1; + for (int i = 0; i < root; ++i) { + for (int j = 0; j < root; ++j) { + if (children.contains(m_pred[j])) { + children.insert(j); + } + } + } + // visit children using m_thread + children.remove(start); + do { + start = m_thread[start]; + SASSERT(children.contains(start)); + children.remove(start); + } + while (start != end); + SASSERT(children.empty()); + return true; + } + } #endif + +#if 0 + + // At this point m_pred and m_upwards have been updated. + + TRACE("network_flow", tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Upwards", m_upwards);); + + + // + node x = m_final[p]; + node y = m_thread[x]; + node z = m_final[q]; + + // ---- + // update m_final. + + // Do this before updating data structures + node gamma_p = m_pred[m_thread[m_final[p]]]; + node gamma_v = m_pred[m_thread[m_final[v]]]; + node theta = m_thread[m_final[v]]; + + // Check that f(u) is not in T_v + bool found_final_u = false; + for (node n = v; n != theta; n = m_thread[n]) { + if (n == m_final[u]) { + found_final_u = true; + break; + } + } + node phi = find_rev_thread(v); + node delta = found_final_u ? phi : m_final[u]; + + TRACE("network_flow", tout << "Graft T_q and T_r'\n";); + + for (node n = p; n != gamma_p && n != -1; n = m_pred[n]) { + TRACE("network_flow", tout << "1: m_final[" << n << "] |-> " << z << "\n";); + m_final[n] = z; + } + + // + + m_thread[x] = q; + m_thread[z] = y; + + + TRACE("network_flow", tout << "Update T_r'\n";); + + m_thread[phi] = theta; + + for (node n = u; n != gamma_v && n != -1; n = m_pred[n]) { + TRACE("network_flow", tout << "2: m_final[" << n << "] |-> " << delta << "\n";); + m_final[n] = delta; + } + + TRACE("network_flow", tout << pp_vector("Last Successors", m_final, true) << pp_vector("Depths", m_depth);); + + if (v != q) { + TRACE("network_flow", tout << "Reroot T_v at q\n";); + + node alpha1, alpha2; + node prev = q; + for (node n = v; n != q && n != -1; n = m_pred[n]) { + // Find all immediate successors of n + node t1 = m_thread[n]; + node t2 = m_thread[m_final[t1]]; + node t3 = m_thread[m_final[t2]]; + if (t1 == m_pred[n]) { + alpha1 = t2; + alpha2 = t3; + } + else if (t2 == m_pred[n]) { + alpha1 = t1; + alpha2 = t3; + } + else { + alpha1 = t1; + alpha2 = t2; + } + m_thread[n] = alpha1; + m_thread[m_final[alpha1]] = alpha2; + m_thread[m_final[alpha2]] = prev; + prev = n; + } + m_thread[m_final[q]] = prev; + } +#endif diff --git a/src/smt/theory_card.cpp b/src/smt/theory_card.cpp index 13b9e93c3..ecba59f1c 100644 --- a/src/smt/theory_card.cpp +++ b/src/smt/theory_card.cpp @@ -24,6 +24,7 @@ Notes: #include "theory_card.h" #include "smt_context.h" +#include "ast_pp.h" namespace smt { @@ -46,33 +47,59 @@ namespace smt { unsigned num_args = atom->get_num_args(); SASSERT(m_util.is_at_most_k(atom)); unsigned k = m_util.get_k(atom); - bool_var bv; + if (ctx.b_internalized(atom)) { return false; } + + TRACE("card", tout << "internalize: " << mk_pp(atom, m) << "\n";); + + if (k >= atom->get_num_args()) { + + NOT_IMPLEMENTED_YET(); + } + if (k == 0) { + NOT_IMPLEMENTED_YET(); + } + SASSERT(0 < k && k < atom->get_num_args()); SASSERT(!ctx.b_internalized(atom)); - bv = ctx.mk_bool_var(atom); - card* c = alloc(card, atom, bv, k); + bool_var bv = ctx.mk_bool_var(atom); + card* c = alloc(card, bv, k); add_card(c); - // - // TBD take repeated bv into account. - // base case: throw exception. - // refinement: adjust argument list and k for non-repeated values. - // for (unsigned i = 0; i < num_args; ++i) { expr* arg = atom->get_arg(i); if (!ctx.b_internalized(arg)) { - bv = ctx.mk_bool_var(arg); + ctx.internalize(arg, false); } - else { + + bool has_bv = false; + if (!m.is_not(arg) && ctx.b_internalized(arg)) { bv = ctx.get_bool_var(arg); + + if (null_theory_var == ctx.get_var_theory(bv)) { + ctx.set_var_theory(bv, get_id()); + has_bv = true; + } + else if (get_id() == ctx.get_var_theory(bv)) { + has_bv = true; + } } - if (null_theory_var == ctx.get_var_theory(bv)) { + // pre-processing should better remove negations under cardinality. + // assumes relevancy level = 2 or 0. + if (!has_bv) { + expr_ref tmp(m), fml(m); + tmp = m.mk_fresh_const("card_proxy",m.mk_bool_sort()); + fml = m.mk_iff(tmp, arg); + ctx.internalize(fml, false); + SASSERT(ctx.b_internalized(tmp)); + bv = ctx.get_bool_var(tmp); + SASSERT(null_theory_var == ctx.get_var_theory(bv)); ctx.set_var_theory(bv, get_id()); + literal lit(ctx.get_bool_var(fml)); + ctx.mk_th_axiom(get_id(), 1, &lit); + ctx.mark_as_relevant(tmp); } - else { - SASSERT(ctx.get_var_theory(bv) == get_id()); // TBD, fishy - } + c->m_args.push_back(bv); add_watch(bv, c); } return true; @@ -110,12 +137,15 @@ namespace smt { void theory_card::assign_eh(bool_var v, bool is_true) { context& ctx = get_context(); + ast_manager& m = get_manager(); ptr_vector* cards = 0; card* c = 0; + TRACE("card", tout << "assign: " << mk_pp(ctx.bool_var2expr(v), m) << " <- " << is_true << "\n";); + if (m_watch.find(v, cards)) { for (unsigned i = 0; i < cards->size(); ++i) { c = (*cards)[i]; - app* atm = c->m_atom; + svector const& args = c->m_args; // // is_true && m_t + 1 > k -> force false // !is_true && m_f + 1 >= arity - k -> force true @@ -128,10 +158,9 @@ namespace smt { case l_undef: { literal_vector& lits = get_lits(); lits.push_back(~literal(c->m_bv)); - for (unsigned i = 0; i < atm->get_num_args() && lits.size() < k + 1; ++i) { - expr* arg = atm->get_arg(i); - if (ctx.get_assignment(arg) == l_true) { - lits.push_back(~literal(ctx.get_bool_var(arg))); + for (unsigned i = 0; i < args.size() && lits.size() < k + 1; ++i) { + if (ctx.get_assignment(args[i]) == l_true) { + lits.push_back(~literal(args[i])); } } SASSERT(lits.size() == k + 1); @@ -142,17 +171,17 @@ namespace smt { break; } } - else if (!is_true && c->m_k >= atm->get_num_args() - c->m_f) { + else if (!is_true && c->m_k >= args.size() - c->m_f - 1) { // forced true switch (ctx.get_assignment(c->m_bv)) { case l_false: case l_undef: { + unsigned deficit = args.size() - c->m_k; literal_vector& lits = get_lits(); - lits.push_back(~literal(c->m_bv)); - for (unsigned i = 0; i < atm->get_num_args(); ++i) { - expr* arg = atm->get_arg(i); - if (ctx.get_assignment(arg) == l_false) { - lits.push_back(~literal(ctx.get_bool_var(arg))); + lits.push_back(literal(c->m_bv)); + for (unsigned i = 0; i < args.size() && lits.size() <= deficit; ++i) { + if (ctx.get_assignment(args[i]) == l_false) { + lits.push_back(literal(args[i])); } } add_clause(lits); @@ -173,10 +202,12 @@ namespace smt { } } if (m_cards.find(v, c)) { - app* atm = to_app(ctx.bool_var2expr(v)); - SASSERT(atm->get_num_args() >= c->m_f + c->m_t); + svector const& args = c->m_args; + SASSERT(args.size() >= c->m_f + c->m_t); bool_var bv; + TRACE("card", tout << " t:" << is_true << " k:" << c->m_k << " t:" << c->m_t << " f:" << c->m_f << "\n";); + // at most k // propagate false to children that are not yet assigned. // v & t1 & ... & tk => ~l_j @@ -185,8 +216,8 @@ namespace smt { literal_vector& lits = get_lits(); lits.push_back(literal(v)); bool done = false; - for (unsigned i = 0; !done && i < atm->get_num_args(); ++i) { - bv = ctx.get_bool_var(atm->get_arg(i)); + for (unsigned i = 0; !done && i < args.size(); ++i) { + bv = args[i]; if (ctx.get_assignment(bv) == l_true) { lits.push_back(literal(bv)); } @@ -196,8 +227,8 @@ namespace smt { } } SASSERT(done || lits.size() == c->m_k + 1); - for (unsigned i = 0; !done && i < atm->get_num_args(); ++i) { - bv = ctx.get_bool_var(atm->get_arg(i)); + for (unsigned i = 0; !done && i < args.size(); ++i) { + bv = args[i]; if (ctx.get_assignment(bv) == l_undef) { lits.push_back(literal(bv)); add_clause(lits); @@ -208,23 +239,22 @@ namespace smt { // at least k+1: // !v & !f1 & .. & !f_m => l_j // for m + k + 1 = arity() - if (!is_true && atm->get_num_args() == 1 + c->m_f + c->m_k) { + if (!is_true && args.size() <= 1 + c->m_f + c->m_k) { literal_vector& lits = get_lits(); - lits.push_back(~literal(v)); + lits.push_back(literal(v)); bool done = false; - for (unsigned i = 0; !done && i < atm->get_num_args(); ++i) { - bv = ctx.get_bool_var(atm->get_arg(i)); + for (unsigned i = 0; !done && i < args.size(); ++i) { + bv = args[i]; if (ctx.get_assignment(bv) == l_false) { - lits.push_back(~literal(bv)); + lits.push_back(literal(bv)); } if (lits.size() > c->m_k + 1) { add_clause(lits); done = true; } } - SASSERT(done || lits.size() == c->m_k + 1); - for (unsigned i = 0; !done && i < atm->get_num_args(); ++i) { - bv = ctx.get_bool_var(atm->get_arg(i)); + for (unsigned i = 0; !done && i < args.size(); ++i) { + bv = args[i]; if (ctx.get_assignment(bv) != l_false) { lits.push_back(~literal(bv)); add_clause(lits); @@ -276,3 +306,315 @@ namespace smt { } } + +#if 0 + +class sorting { + void exchange(unsigned i, unsigned j, expr_ref_vector& es) { + SASSERT(i <= j); + if (i == j) { + return; + } + expr* ei = es[i].get(); + expr* ej = es[j].get(); + es[i] = m.mk_ite(mk_le(ei,ej), ei, ej); + es[j] = m.mk_ite(mk_le(ej,ei), ei, ej); + } + + void sort(unsigned k) { + if (k == 2) { + for (unsigned i = 0; i < m_es.size()/2; ++i) { + exchange(current(2*i), current(2*i+1), m_es); + next(2*i) = current(2*i); + next(2*i+1) = current(2*i+1); + } + std::swap(m_current, m_next); + } + else { + + for (unsigned i = 0; i < m_es.size()/k; ++i) { + for (unsigned j = 0; j < k / 2; ++j) { + next((k * i) + j) = current((k * i) + (2 * j)); + next((k * i) + (k / 2) + j) = current((k * i) + (2 * j) + 1); + } + } + + std::swap(m_current, m_next); + sort(k / 2); + for (unsigned i = 0; i < m_es.size() / k; ++i) { + for (unsigned j = 0; j < k / 2; ++j) { + next((k * i) + (2 * j)) = current((k * i) + j); + next((k * i) + (2 * j) + 1) = current((k * i) + (k / 2) + j); + } + + for (unsigned j = 0; j < (k / 2) - 1; ++j) { + exchange(next((k * i) + (2 * j) + 1), next((k * i) + (2 * (j + 1)))); + } + } + std::swap(m_current, m_next); + } + } + + private Term[] Merge(Term[] l1, Term[] l2) + { + if (l1.Length == 0) + { + return l2; + } + else if (l2.Length == 0) + { + return l1; + } + else if (l1.Length == 1 && l2.Length == 1) + { + var merged = new Term[2]; + merged[0] = l1[0]; + merged[1] = l2[0]; + Exchange(0, 1, merged); + return merged; + } + + var l1o = l1.Length / 2; + var l2o = l2.Length / 2; + var l1e = (l1.Length % 2 == 1) ? l1o + 1 : l1o; + var l2e = (l2.Length % 2 == 1) ? l2o + 1 : l2o; + + Term[] evenl1 = new Term[l1e]; + Term[] oddl1 = new Term[l1o]; + for (int i = 0; i < l1.Length; ++i) + { + if (i % 2 == 0) + { + evenl1[i / 2] = l1[i]; + } + else + { + oddl1[i / 2] = l1[i]; + } + } + + Term[] evenl2 = new Term[l2e]; + Term[] oddl2 = new Term[l2o]; + for (int i = 0; i < l2.Length; ++i) + { + if (i % 2 == 0) + { + evenl2[i / 2] = l2[i]; + } + else + { + oddl2[i / 2] = l2[i]; + } + } + + var even = Merge(evenl1, evenl2); + var odd = Merge(oddl1, oddl2); + + Term[] merge = new Term[l1.Length + l2.Length]; + + for (int i = 0; i < merge.Length; ++i) + { + if (i % 2 == 0) + { + merge[i] = even[i / 2]; + if (i > 0) + { + Exchange(i - 1, i, merge); + } + } + else + { + if (i / 2 < odd.Length) + { + merge[i] = odd[i / 2]; + } + else + { + merge[i] = even[(i / 2) + 1]; + } + } + } + + return merge; + } + +}; + +Sorting networks used in Formula: + +namespace Microsoft.Formula.Execution +{ + using System; + using System.Diagnostics.Contracts; + using Microsoft.Z3; + + internal class SortingNetwork + { + private Term[] elements; + private int[] current; + private int[] next; + + public SortingNetwork(SymbolicState owner, Term[] inputs, Sort sortingDomain) + { + Contract.Requires(owner != null && inputs != null && sortingDomain != null); + Contract.Requires(inputs.Length > 0); + + Owner = owner; + Size = (int)Math.Pow(2, (int)Math.Ceiling(Math.Log(inputs.Length, 2))); + + if (Size == 1) + { + elements = new Term[1]; + elements[0] = inputs[0]; + } + else if (Size > 1) + { + var defaultElement = owner.Context.MkNumeral(0, sortingDomain); + + current = new int[Size]; + next = new int[Size]; + elements = new Term[Size]; + for (int i = 0; i < Size; ++i) + { + current[i] = i; + elements[i] = (i < Size - inputs.Length) ? defaultElement : inputs[i - (Size - inputs.Length)]; + } + + int k = 2; + Term xi; + while (k <= Size) + { + Sort(k); + + for (int i = 0; i < Size; ++i) + { + xi = owner.Context.MkFreshConst("x", sortingDomain); + owner.Context.AssertCnstr(owner.Context.MkEq(xi, elements[i])); + elements[i] = xi; + } + + for (int i = 0; i < elements.Length / k; ++i) + { + for (int j = 0; j < k - 1; ++j) + { + owner.Context.AssertCnstr(owner.Context.MkBvUle(elements[(k * i) + j], elements[(k * i) + j + 1])); + } + } + + k *= 2; + } + } + } + + public Term[] Outputs + { + get { return elements; } + } + + public int Size + { + get; + private set; + } + + public SymbolicState Owner + { + get; + private set; + } + + + private void Swap() + { + var tmp = current; + current = next; + next = tmp; + } + + private Term[] Merge(Term[] l1, Term[] l2) + { + if (l1.Length == 0) + { + return l2; + } + else if (l2.Length == 0) + { + return l1; + } + else if (l1.Length == 1 && l2.Length == 1) + { + var merged = new Term[2]; + merged[0] = l1[0]; + merged[1] = l2[0]; + Exchange(0, 1, merged); + return merged; + } + + var l1o = l1.Length / 2; + var l2o = l2.Length / 2; + var l1e = (l1.Length % 2 == 1) ? l1o + 1 : l1o; + var l2e = (l2.Length % 2 == 1) ? l2o + 1 : l2o; + + Term[] evenl1 = new Term[l1e]; + Term[] oddl1 = new Term[l1o]; + for (int i = 0; i < l1.Length; ++i) + { + if (i % 2 == 0) + { + evenl1[i / 2] = l1[i]; + } + else + { + oddl1[i / 2] = l1[i]; + } + } + + Term[] evenl2 = new Term[l2e]; + Term[] oddl2 = new Term[l2o]; + for (int i = 0; i < l2.Length; ++i) + { + if (i % 2 == 0) + { + evenl2[i / 2] = l2[i]; + } + else + { + oddl2[i / 2] = l2[i]; + } + } + + var even = Merge(evenl1, evenl2); + var odd = Merge(oddl1, oddl2); + + Term[] merge = new Term[l1.Length + l2.Length]; + + for (int i = 0; i < merge.Length; ++i) + { + if (i % 2 == 0) + { + merge[i] = even[i / 2]; + if (i > 0) + { + Exchange(i - 1, i, merge); + } + } + else + { + if (i / 2 < odd.Length) + { + merge[i] = odd[i / 2]; + } + else + { + merge[i] = even[(i / 2) + 1]; + } + } + } + + return merge; + } + } +} + + +#endif diff --git a/src/smt/theory_card.h b/src/smt/theory_card.h index f38084292..ca1d5a061 100644 --- a/src/smt/theory_card.h +++ b/src/smt/theory_card.h @@ -30,9 +30,9 @@ namespace smt { bool_var m_bv; unsigned m_t; unsigned m_f; - app* m_atom; - card(app* a, bool_var bv, unsigned k): - m_k(k), m_bv(bv), m_atom(a), m_t(0), m_f(0) + svector m_args; + card(bool_var bv, unsigned k): + m_k(k), m_bv(bv), m_t(0), m_f(0) {} }; From cf75a7743e75d28234c73aac2fc2985cc4a39186 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 5 Nov 2013 16:18:21 -0800 Subject: [PATCH 086/925] network update Signed-off-by: Nikolaj Bjorner --- src/smt/theory_diff_logic_def.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index e6e3e94ca..b654d9c31 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -160,6 +160,7 @@ template void theory_diff_logic::found_non_diff_logic_expr(expr * n) { if (!m_non_diff_logic_exprs) { TRACE("non_diff_logic", tout << "found non diff logic expression:\n" << mk_pp(n, get_manager()) << "\n";); + IF_VERBOSE(0, verbose_stream() << "(smt.diff_logic: non-diff logic expression " << mk_pp(n, get_manager()) << ")\n";); get_context().push_trail(value_trail(m_non_diff_logic_exprs)); m_non_diff_logic_exprs = true; } From e84c5e7e904fb96883d8da9f097134865ab3a0d2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 5 Nov 2013 16:53:35 -0800 Subject: [PATCH 087/925] adding simple sorting network Signed-off-by: Nikolaj Bjorner --- src/smt/theory_card.cpp | 298 +++++++++++++--------------------------- 1 file changed, 95 insertions(+), 203 deletions(-) diff --git a/src/smt/theory_card.cpp b/src/smt/theory_card.cpp index ecba59f1c..a500d042a 100644 --- a/src/smt/theory_card.cpp +++ b/src/smt/theory_card.cpp @@ -309,7 +309,12 @@ namespace smt { #if 0 -class sorting { +class sorting_network { + ast_manager& m; + expr_ref_vector m_es; + expr_ref_vector* m_current; + expr_ref_vector* m_next; + void exchange(unsigned i, unsigned j, expr_ref_vector& es) { SASSERT(i <= j); if (i == j) { @@ -338,7 +343,7 @@ class sorting { next((k * i) + (k / 2) + j) = current((k * i) + (2 * j) + 1); } } - + std::swap(m_current, m_next); sort(k / 2); for (unsigned i = 0; i < m_es.size() / k; ++i) { @@ -346,7 +351,7 @@ class sorting { next((k * i) + (2 * j)) = current((k * i) + j); next((k * i) + (2 * j) + 1) = current((k * i) + (k / 2) + j); } - + for (unsigned j = 0; j < (k / 2) - 1; ++j) { exchange(next((k * i) + (2 * j) + 1), next((k * i) + (2 * (j + 1)))); } @@ -355,105 +360,99 @@ class sorting { } } - private Term[] Merge(Term[] l1, Term[] l2) - { - if (l1.Length == 0) - { - return l2; - } - else if (l2.Length == 0) - { - return l1; - } - else if (l1.Length == 1 && l2.Length == 1) - { - var merged = new Term[2]; - merged[0] = l1[0]; - merged[1] = l2[0]; - Exchange(0, 1, merged); - return merged; - } - - var l1o = l1.Length / 2; - var l2o = l2.Length / 2; - var l1e = (l1.Length % 2 == 1) ? l1o + 1 : l1o; - var l2e = (l2.Length % 2 == 1) ? l2o + 1 : l2o; - - Term[] evenl1 = new Term[l1e]; - Term[] oddl1 = new Term[l1o]; - for (int i = 0; i < l1.Length; ++i) - { - if (i % 2 == 0) - { - evenl1[i / 2] = l1[i]; - } - else - { - oddl1[i / 2] = l1[i]; - } - } - - Term[] evenl2 = new Term[l2e]; - Term[] oddl2 = new Term[l2o]; - for (int i = 0; i < l2.Length; ++i) - { - if (i % 2 == 0) - { - evenl2[i / 2] = l2[i]; - } - else - { - oddl2[i / 2] = l2[i]; - } - } - - var even = Merge(evenl1, evenl2); - var odd = Merge(oddl1, oddl2); - - Term[] merge = new Term[l1.Length + l2.Length]; - - for (int i = 0; i < merge.Length; ++i) - { - if (i % 2 == 0) - { - merge[i] = even[i / 2]; - if (i > 0) - { - Exchange(i - 1, i, merge); - } - } - else - { - if (i / 2 < odd.Length) - { - merge[i] = odd[i / 2]; - } - else - { - merge[i] = even[(i / 2) + 1]; - } - } - } - - return merge; + expr_ref_vector merge(expr_ref_vector const& l1, expr_ref_vector& l2) { + if (l1.empty()) { + return l2; } + if (l2.empty()) { + return l1; + } + expr_ref_vector result(m); + if (l1.size() == 1 && l2.size() == 1) { + result.push_back(l1[0]); + result.push_back(l2[0]); + exchange(0, 1, result); + return result; + } + unsigned l1o = l1.size()/2; + unsigned l2o = l2.size()/2; + unsigned l1e = (l1.size() % 2 == 1) ? l1o + 1 : l1o; + unsigned l2e = (l2.size() % 2 == 1) ? l2o + 1 : l2o; + expr_ref_vector evenl1(m, l1e); + expr_ref_vector oddl1(m, l1o); + expr_ref_vector evenl2(m, l2e); + expr_ref_vector oddl2(m, l2o); + for (unsigned i = 0; i < l1.size(); ++i) { + if (i % 2 == 0) { + evenl1[i/2] = l1[i]; + } + else { + oddl1[i/2] = l1[i]; + } + } + for (unsigned i = 0; i < l2.size(); ++i) { + if (i % 2 == 0) { + evenl2[i/2] = l2[i]; + } + else { + oddl2[i/2] = l2[i]; + } + } + expr_ref_vector even = merge(evenl1, evenl2); + expr_ref_vector odd = merge(oddl1, oddl2); + result.resize(l1.size() + l2.size()); + for (unsigned i = 0; i < result.size(); ++i) { + if (i % 2 == 0) { + result[i] = even[i/2].get(); + if (i > 0) { + exchange(i - 1, i, result); + } + } + else { + if (i /2 < odd.size()) { + result[i] = odd[i/2].get(); + } + else { + result[i] = even[(i/2)+1].get(); + } + } + } + return result; + } + +public: + sorting_network(ast_manager& m): + m(m), + m_es(m), + m_current(0), + m_next(0) + {} + + expr_ref_vector operator()(expr_ref_vector const& inputs) { + if (inputs.size() <= 1) { + return inputs; + } + m_es.reset(); + m_es.append(inputs); + while (!is_power_of2(m_es.size())) { + m_es.push_back(m.mk_false()); + } + m_es.reverse(); + for (unsigned i = 0; i < m_es.size(); ++i) { + current(i) = i; + } + unsigned k = 2; + while (k <= m_es.size()) { + sort(k); + // TBD + k *= 2; + } + } }; Sorting networks used in Formula: -namespace Microsoft.Formula.Execution -{ - using System; - using System.Diagnostics.Contracts; - using Microsoft.Z3; - - internal class SortingNetwork - { - private Term[] elements; - private int[] current; - private int[] next; - public SortingNetwork(SymbolicState owner, Term[] inputs, Sort sortingDomain) { Contract.Requires(owner != null && inputs != null && sortingDomain != null); @@ -506,114 +505,7 @@ namespace Microsoft.Formula.Execution } } - public Term[] Outputs - { - get { return elements; } - } - public int Size - { - get; - private set; - } - - public SymbolicState Owner - { - get; - private set; - } - - - private void Swap() - { - var tmp = current; - current = next; - next = tmp; - } - - private Term[] Merge(Term[] l1, Term[] l2) - { - if (l1.Length == 0) - { - return l2; - } - else if (l2.Length == 0) - { - return l1; - } - else if (l1.Length == 1 && l2.Length == 1) - { - var merged = new Term[2]; - merged[0] = l1[0]; - merged[1] = l2[0]; - Exchange(0, 1, merged); - return merged; - } - - var l1o = l1.Length / 2; - var l2o = l2.Length / 2; - var l1e = (l1.Length % 2 == 1) ? l1o + 1 : l1o; - var l2e = (l2.Length % 2 == 1) ? l2o + 1 : l2o; - - Term[] evenl1 = new Term[l1e]; - Term[] oddl1 = new Term[l1o]; - for (int i = 0; i < l1.Length; ++i) - { - if (i % 2 == 0) - { - evenl1[i / 2] = l1[i]; - } - else - { - oddl1[i / 2] = l1[i]; - } - } - - Term[] evenl2 = new Term[l2e]; - Term[] oddl2 = new Term[l2o]; - for (int i = 0; i < l2.Length; ++i) - { - if (i % 2 == 0) - { - evenl2[i / 2] = l2[i]; - } - else - { - oddl2[i / 2] = l2[i]; - } - } - - var even = Merge(evenl1, evenl2); - var odd = Merge(oddl1, oddl2); - - Term[] merge = new Term[l1.Length + l2.Length]; - - for (int i = 0; i < merge.Length; ++i) - { - if (i % 2 == 0) - { - merge[i] = even[i / 2]; - if (i > 0) - { - Exchange(i - 1, i, merge); - } - } - else - { - if (i / 2 < odd.Length) - { - merge[i] = odd[i / 2]; - } - else - { - merge[i] = even[(i / 2) + 1]; - } - } - } - - return merge; - } - } } From 2f04918c39f8ddb344223fb2b3d0023470ed0286 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 6 Nov 2013 12:33:09 -0800 Subject: [PATCH 088/925] working on cardinality tactic Signed-off-by: Nikolaj Bjorner --- src/ast/card_decl_plugin.cpp | 2 +- src/smt/theory_card.cpp | 33 +- src/tactic/arith/lia2card_tactic.cpp | 431 +++++++++++++++++++++++++++ src/tactic/arith/lia2card_tactic.h | 33 ++ 4 files changed, 488 insertions(+), 11 deletions(-) create mode 100644 src/tactic/arith/lia2card_tactic.cpp create mode 100644 src/tactic/arith/lia2card_tactic.h diff --git a/src/ast/card_decl_plugin.cpp b/src/ast/card_decl_plugin.cpp index 20c9af09f..acb6d8adb 100644 --- a/src/ast/card_decl_plugin.cpp +++ b/src/ast/card_decl_plugin.cpp @@ -47,7 +47,7 @@ void card_decl_plugin::get_op_names(svector & op_names, symbol con app * card_util::mk_at_most_k(unsigned num_args, expr * const * args, unsigned k) { - parameter param(1); + parameter param(k); return m.mk_app(m_fid, OP_AT_MOST_K, 1, ¶m, num_args, args, m.mk_bool_sort()); } diff --git a/src/smt/theory_card.cpp b/src/smt/theory_card.cpp index a500d042a..81d778f58 100644 --- a/src/smt/theory_card.cpp +++ b/src/smt/theory_card.cpp @@ -54,18 +54,16 @@ namespace smt { TRACE("card", tout << "internalize: " << mk_pp(atom, m) << "\n";); - if (k >= atom->get_num_args()) { - - NOT_IMPLEMENTED_YET(); - } - if (k == 0) { - NOT_IMPLEMENTED_YET(); - } - SASSERT(0 < k && k < atom->get_num_args()); SASSERT(!ctx.b_internalized(atom)); bool_var bv = ctx.mk_bool_var(atom); + + if (k >= atom->get_num_args()) { + literal lit(bv); + ctx.mk_th_axiom(get_id(), 1, &lit); + return true; + } + card* c = alloc(card, bv, k); - add_card(c); for (unsigned i = 0; i < num_args; ++i) { expr* arg = atom->get_arg(i); if (!ctx.b_internalized(arg)) { @@ -100,7 +98,22 @@ namespace smt { ctx.mark_as_relevant(tmp); } c->m_args.push_back(bv); - add_watch(bv, c); + if (0 < k) { + add_watch(bv, c); + } + } + if (0 < k) { + add_card(c); + } + else { + // bv <=> (and (not bv1) ... (not bv_n)) + literal_vector& lits = get_lits(); + lits.push_back(literal(bv)); + for (unsigned i = 0; i < c->m_args.size(); ++i) { + ctx.mk_th_axiom(get_id(), ~literal(bv), ~literal(c->m_args[i])); + lits.push_back(literal(c->m_args[i])); + } + ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); } return true; } diff --git a/src/tactic/arith/lia2card_tactic.cpp b/src/tactic/arith/lia2card_tactic.cpp new file mode 100644 index 000000000..7d257d86e --- /dev/null +++ b/src/tactic/arith/lia2card_tactic.cpp @@ -0,0 +1,431 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + lia2card_tactic.cpp + +Abstract: + + Convert 0-1 integer variables cardinality constraints to built-in cardinality operator. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-11-5 + +Notes: + +--*/ +#include"tactical.h" +#include"cooperate.h" +#include"bound_manager.h" +#include"ast_pp.h" +#include"expr_safe_replace.h" // NB: should use proof-producing expr_substitute in polished version. + +#include"card_decl_plugin.h" +#include"arith_decl_plugin.h" + +class lia2card_tactic : public tactic { + + struct imp { + typedef obj_hashtable expr_set; + ast_manager & m; + arith_util a; + card_util m_card; + obj_map > m_uses; + obj_map m_converted; + expr_set m_01s; + + imp(ast_manager & _m, params_ref const & p): + m(_m), + a(m), + m_card(m) { + } + + void set_cancel(bool f) { + } + + void updt_params(params_ref const & p) { + } + + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) { + SASSERT(g->is_well_sorted()); + mc = 0; pc = 0; core = 0; + m_01s.reset(); + m_uses.reset(); + m_converted.reset(); + + tactic_report report("cardinality-intro", *g); + + bound_manager bounds(m); + bounds(*g); + + bound_manager::iterator bit = bounds.begin(), bend = bounds.end(); + for (; bit != bend; ++bit) { + expr* x = *bit; + bool s1, s2; + rational lo, hi; + if (a.is_int(x) && + bounds.has_lower(x, lo, s1) && !s1 && lo.is_zero() && + bounds.has_upper(x, hi, s2) && !s2 && hi.is_one()) { + m_01s.insert(x); + TRACE("card", tout << "add bound " << mk_pp(x, m) << "\n";); + } + } + if (m_01s.empty()) { + result.push_back(g.get()); + return; + } + expr_set::iterator it = m_01s.begin(), end = m_01s.end(); + for (; it != end; ++it) { + m_uses.insert(*it, ptr_vector()); + } + for (unsigned j = 0; j < g->size(); ++j) { + ast_mark mark; + collect_uses(mark, g->form(j)); + } + + it = m_01s.begin(), end = m_01s.end(); + for (; it != end; ++it) { + if (!validate_uses(m_uses.find(*it))) { + m_uses.remove(*it); + m_01s.remove(*it); + it = m_01s.begin(); + end = m_01s.end(); + } + } + if (m_01s.empty()) { + result.push_back(g.get()); + return; + } + + expr_safe_replace sub(m); + extract_substitution(sub); + + expr_ref new_curr(m); + proof_ref new_pr(m); + + for (unsigned i = 0; i < g->size(); i++) { + expr * curr = g->form(i); + sub(curr, new_curr); + g->update(i, new_curr, new_pr, g->dep(i)); + } + g->inc_depth(); + result.push_back(g.get()); + TRACE("card", g->display(tout);); + SASSERT(g->is_well_sorted()); + + // TBD: convert models for 0-1 variables. + // TBD: support proof conversion (or not..) + } + + void extract_substitution(expr_safe_replace& sub) { + expr_set::iterator it = m_01s.begin(), end = m_01s.end(); + for (; it != end; ++it) { + extract_substitution(sub, *it); + } + } + + void extract_substitution(expr_safe_replace& sub, expr* x) { + ptr_vector const& use_list = m_uses.find(x); + for (unsigned i = 0; i < use_list.size(); ++i) { + expr* u = use_list[i]; + convert_01(sub, u); + } + } + + expr_ref mk_le(expr* x, rational const& bound) { + if (bound.is_pos()) { + return expr_ref(m.mk_true(), m); + } + else if (bound.is_zero()) { + return expr_ref(m.mk_not(mk_01(x)), m); + } + else { + return expr_ref(m.mk_false(), m); + } + } + + expr_ref mk_ge(expr* x, rational const& bound) { + if (bound.is_one()) { + return expr_ref(mk_01(x), m); + } + else if (bound.is_pos()) { + return expr_ref(m.mk_false(), m); + } + else { + return expr_ref(m.mk_true(), m); + } + } + + bool is_01var(expr* x) const { + return m_01s.contains(x); + } + + void convert_01(expr_safe_replace& sub, expr* fml) { + rational n; + unsigned k; + expr_ref_vector args(m); + expr_ref result(m); + expr* x, *y; + if (a.is_le(fml, x, y) || a.is_ge(fml, y, x)) { + if (is_01var(x) && a.is_numeral(y, n)) { + sub.insert(fml, mk_le(x, n)); + return; + } + if (is_01var(y) && a.is_numeral(x, n)) { + sub.insert(fml, mk_ge(y, n)); + return; + } + if (is_add(x, args) && is_unsigned(y, k)) { // x <= k + sub.insert(fml, m_card.mk_at_most_k(args.size(), args.c_ptr(), k)); + return; + } + if (is_add(y, args) && is_unsigned(x, k)) { // k <= y <=> not (y <= k-1) + if (k == 0) + sub.insert(fml, m.mk_true()); + else + sub.insert(fml, m.mk_not(m_card.mk_at_most_k(args.size(), args.c_ptr(), k-1))); + return; + } + UNREACHABLE(); + } + + if (a.is_lt(fml, x, y) || a.is_gt(fml, y, x)) { + if (is_01var(x) && a.is_numeral(y, n)) { + sub.insert(fml, mk_le(x, n-rational(1))); + return; + } + if (is_01var(y) && a.is_numeral(x, n)) { + sub.insert(fml, mk_ge(y, n+rational(1))); + return; + } + if (is_add(x, args) && is_unsigned(y, k)) { // x < k + if (k == 0) + sub.insert(fml, m.mk_false()); + else + sub.insert(fml, m_card.mk_at_most_k(args.size(), args.c_ptr(), k-1)); + return; + } + + if (is_add(y, args) && is_unsigned(x, k)) { // k < y <=> not (y <= k) + sub.insert(fml, m.mk_not(m_card.mk_at_most_k(args.size(), args.c_ptr(), k))); + return; + } + UNREACHABLE(); + } + if (m.is_eq(fml, x, y)) { + if (!is_01var(x)) { + std::swap(x, y); + } + if (is_01var(x) && a.is_numeral(y, n)) { + if (n.is_one()) { + sub.insert(fml, mk_01(x)); + } + else if (n.is_zero()) { + sub.insert(fml, m.mk_not(mk_01(x))); + } + else { + sub.insert(fml, m.mk_false()); + } + return; + } + UNREACHABLE(); + } + if (is_sum(fml)) { + SASSERT(m_uses.contains(fml)); + ptr_vector const& u = m_uses.find(fml); + for (unsigned i = 0; i < u.size(); ++i) { + convert_01(sub, u[i]); + } + return; + } + UNREACHABLE(); + } + + expr_ref mk_01(expr* x) { + expr* r; + SASSERT(is_01var(x)); + if (!m_converted.find(x, r)) { + symbol name = to_app(x)->get_decl()->get_name(); + r = m.mk_fresh_const(name.str().c_str(), m.mk_bool_sort()); + m_converted.insert(x, r); + } + return expr_ref(r, m); + } + + + bool is_add(expr* x, expr_ref_vector& args) { + if (a.is_add(x)) { + app* ap = to_app(x); + for (unsigned i = 0; i < ap->get_num_args(); ++i) { + args.push_back(mk_01(ap->get_arg(i))); + } + return true; + } + else { + return false; + } + } + + bool validate_uses(ptr_vector const& use_list) { + for (unsigned i = 0; i < use_list.size(); ++i) { + if (!validate_use(use_list[i])) { + return false; + } + } + return true; + } + + bool validate_use(expr* fml) { + expr* x, *y; + if (a.is_le(fml, x, y) || + a.is_ge(fml, x, y) || + a.is_lt(fml, x, y) || + a.is_gt(fml, x, y) || + m.is_eq(fml, x, y)) { + if (a.is_numeral(x)) { + std::swap(x,y); + } + if ((is_one(y) || a.is_zero(y)) && is_01var(x)) + return true; + if (a.is_numeral(y) && is_sum(x) && !m.is_eq(fml)) { + return true; + } + } + if (is_sum(fml)) { + SASSERT(m_uses.contains(fml)); + ptr_vector const& u = m_uses.find(fml); + for (unsigned i = 0; i < u.size(); ++i) { + if (!validate_use(u[i])) { + return false; + } + } + return true; + } + TRACE("card", tout << "Use not validated: " << mk_pp(fml, m) << "\n";); + + return false; + } + + bool is_sum(expr* x) const { + if (a.is_add(x)) { + app* ap = to_app(x); + for (unsigned i = 0; i < ap->get_num_args(); ++i) { + if (!is_01var(ap->get_arg(i))) { + return false; + } + } + return true; + } + return false; + } + + bool is_unsigned(expr* x, unsigned& k) { + rational r; + if (a.is_numeral(x, r) && r.is_unsigned()) { + k = r.get_unsigned(); + SASSERT(rational(k) == r); + return true; + } + else { + return false; + } + } + + bool is_one(expr* x) { + rational r; + return a.is_numeral(x, r) && r.is_one(); + } + + void collect_uses(ast_mark& mark, expr* f) { + ptr_vector todo; + todo.push_back(f); + while (!todo.empty()) { + f = todo.back(); + todo.pop_back(); + if (mark.is_marked(f)) { + continue; + } + mark.mark(f, true); + if (is_var(f)) { + continue; + } + if (is_quantifier(f)) { + todo.push_back(to_quantifier(f)->get_expr()); + continue; + } + app* a = to_app(f); + for (unsigned i = 0; i < a->get_num_args(); ++i) { + expr* arg = a->get_arg(i); + if (!m_uses.contains(arg)) { + m_uses.insert(arg, ptr_vector()); + } + m_uses.find(arg).push_back(a); + todo.push_back(arg); + } + } + } + }; + + imp * m_imp; + params_ref m_params; +public: + lia2card_tactic(ast_manager & m, params_ref const & p): + m_params(p) { + m_imp = alloc(imp, m, p); + } + + virtual tactic * translate(ast_manager & m) { + return alloc(lia2card_tactic, m, m_params); + } + + virtual ~lia2card_tactic() { + dealloc(m_imp); + } + + virtual void updt_params(params_ref const & p) { + m_params = p; + m_imp->updt_params(p); + } + + virtual void collect_param_descrs(param_descrs & r) { + } + + virtual void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) { + (*m_imp)(in, result, mc, pc, core); + } + + virtual void cleanup() { + ast_manager & m = m_imp->m; + imp * d = m_imp; + #pragma omp critical (tactic_cancel) + { + m_imp = 0; + } + dealloc(d); + d = alloc(imp, m, m_params); + #pragma omp critical (tactic_cancel) + { + m_imp = d; + } + } + + virtual void set_cancel(bool f) { + if (m_imp) + m_imp->set_cancel(f); + } +}; + +tactic * mk_lia2card_tactic(ast_manager & m, params_ref const & p) { + return clean(alloc(lia2card_tactic, m, p)); +} + diff --git a/src/tactic/arith/lia2card_tactic.h b/src/tactic/arith/lia2card_tactic.h new file mode 100644 index 000000000..69a5f3f60 --- /dev/null +++ b/src/tactic/arith/lia2card_tactic.h @@ -0,0 +1,33 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + lia2card_tactic.h + +Abstract: + + Extract 0-1 integer variables used in + cardinality constraints and replace them by Booleans. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-11-5 + +Notes: + +--*/ +#ifndef _LIA2CARD_TACTIC_H_ +#define _LIA2CARD_TACTIC_H_ + +#include"params.h" +class ast_manager; +class tactic; + +tactic * mk_lia2card_tactic(ast_manager & m, params_ref const & p = params_ref()); + +/* + ADD_TACTIC("lia2card", "introduce cardinality constraints from 0-1 integer.", "mk_lia2card_tactic(m, p)") +*/ + +#endif From 05b37b2f0737596a2972c531e7f1906008cff393 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 6 Nov 2013 12:40:56 -0800 Subject: [PATCH 089/925] working on cardinality tactic Signed-off-by: Nikolaj Bjorner --- src/smt/theory_card.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/smt/theory_card.cpp b/src/smt/theory_card.cpp index 81d778f58..edae63108 100644 --- a/src/smt/theory_card.cpp +++ b/src/smt/theory_card.cpp @@ -55,21 +55,21 @@ namespace smt { TRACE("card", tout << "internalize: " << mk_pp(atom, m) << "\n";); SASSERT(!ctx.b_internalized(atom)); - bool_var bv = ctx.mk_bool_var(atom); + bool_var abv = ctx.mk_bool_var(atom); if (k >= atom->get_num_args()) { - literal lit(bv); + literal lit(abv); ctx.mk_th_axiom(get_id(), 1, &lit); return true; } - card* c = alloc(card, bv, k); + card* c = alloc(card, abv, k); for (unsigned i = 0; i < num_args; ++i) { expr* arg = atom->get_arg(i); if (!ctx.b_internalized(arg)) { ctx.internalize(arg, false); } - + bool_var bv; bool has_bv = false; if (!m.is_not(arg) && ctx.b_internalized(arg)) { bv = ctx.get_bool_var(arg); @@ -108,12 +108,13 @@ namespace smt { else { // bv <=> (and (not bv1) ... (not bv_n)) literal_vector& lits = get_lits(); - lits.push_back(literal(bv)); + lits.push_back(literal(abv)); for (unsigned i = 0; i < c->m_args.size(); ++i) { - ctx.mk_th_axiom(get_id(), ~literal(bv), ~literal(c->m_args[i])); + ctx.mk_th_axiom(get_id(), ~literal(abv), ~literal(c->m_args[i])); lits.push_back(literal(c->m_args[i])); } ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); + dealloc(c); } return true; } From 034b33b6dae700c854994115bd8622df1786a009 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Wed, 6 Nov 2013 13:30:29 -0800 Subject: [PATCH 090/925] Remove m_final from spanning tree representation --- src/opt/opt_solver.cpp | 9 +- src/opt/optimize_objectives.cpp | 2 +- src/smt/network_flow.h | 1 + src/smt/network_flow_def.h | 111 ++++++++-------------- src/tactic/core/blast_term_ite_tactic.cpp | 6 +- 5 files changed, 55 insertions(+), 74 deletions(-) diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 1c4a5bc4c..998214464 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -23,6 +23,7 @@ Notes: #include"smt_context.h" #include"theory_arith.h" #include"theory_diff_logic.h" +#include "ast_pp.h" namespace opt { @@ -94,7 +95,13 @@ namespace opt { lbool opt_solver::check_sat_core(unsigned num_assumptions, expr * const * assumptions) { - TRACE("opt_solver_na2as", tout << "opt_opt_solver::check_sat_core: " << num_assumptions << "\n";); + TRACE("opt_solver_na2as", { + tout << "opt_opt_solver::check_sat_core: " << m_context.size() << "\n"; + for (unsigned i = 0; i < m_context.size(); ++i) { + tout << mk_pp(m_context.get_formulas()[i], m_context.m()) << "\n"; + } + }); + lbool r = m_context.check(num_assumptions, assumptions); if (r == l_true && m_objective_enabled) { m_objective_values.reset(); diff --git a/src/opt/optimize_objectives.cpp b/src/opt/optimize_objectives.cpp index bcda00381..9705652fb 100644 --- a/src/opt/optimize_objectives.cpp +++ b/src/opt/optimize_objectives.cpp @@ -115,7 +115,7 @@ namespace opt { verbose_stream() << m_lower[i] << " "; } verbose_stream() << "\n"; - // model_pp(verbose_stream(), *md); + model_pp(verbose_stream(), *md); ); expr_ref_vector disj(m); expr_ref constraint(m); diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index ce9ce385a..a90e901e8 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -127,6 +127,7 @@ namespace smt { bool check_well_formed(); bool is_preorder_traversal(node start, node end); + node get_final(int start); public: diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index 079a5ae70..96557301f 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -69,7 +69,6 @@ namespace smt { m_pred.resize(num_nodes); m_depth.resize(num_nodes); m_thread.resize(num_nodes); - m_final.resize(num_nodes); m_step = 0; } @@ -84,7 +83,6 @@ namespace smt { m_pred[root] = -1; m_depth[root] = 0; m_thread[root] = 0; - m_final[root] = root - 1; m_potentials[root] = numeral::zero(); m_graph.init_var(root); @@ -106,7 +104,6 @@ namespace smt { m_pred[i] = root; m_depth[i] = 1; m_thread[i] = i + 1; - m_final[i] = i; m_states[num_edges + i] = BASIS; node src = m_upwards[i] ? i : root; node tgt = m_upwards[i] ? root : i; @@ -125,7 +122,6 @@ namespace smt { TRACE("network_flow", { tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Threads", m_thread); - tout << pp_vector("Last Successors", m_final); tout << pp_vector("Depths", m_depth) << pp_vector("Upwards", m_upwards); tout << pp_vector("Potentials", m_potentials) << pp_vector("Flows", m_flows); }); @@ -148,7 +144,7 @@ namespace smt { node tgt = m_graph.get_target(m_entering_edge); numeral cost = m_graph.get_weight(m_entering_edge); numeral change = m_upwards[src] ? (-cost - m_potentials[src] + m_potentials[tgt]) : (cost + m_potentials[src] - m_potentials[tgt]); - node last = m_thread[m_final[src]]; + node last = m_thread[get_final(src)]; for (node u = src; u != last; u = m_thread[u]) { m_potentials[u] += change; } @@ -261,7 +257,6 @@ namespace smt { template bool network_flow::is_ancestor_of(node ancestor, node child) const { for (node n = child; n != -1; n = m_pred[n]) { - // q should be in T_v so swap p and q if (n == ancestor) { return true; } @@ -295,26 +290,15 @@ namespace smt { Old tree: New tree: root root / \ / \ - x y - / \ / \ - u w' - | / - v w - / \ \ - z p - \ - q - - x y - / \ / \ - u w' - / - v w - / \ \ - z p - \ / - q - + x y x y + / \ / \ / \ / \ + u s u s + | / / + v w v w + / \ \ / \ \ + z p z p + \ \ / + q q */ template @@ -359,35 +343,39 @@ namespace smt { n = next; SASSERT(n != -1); } -#else - node old_pred = m_pred[q]; +#else + node old_pred = m_pred[q]; + if (q != v) { + for (node n = q; n != u; ) { + SASSERT(old_pred != u || n == v); // the last processed node is v + TRACE("network_flow", { + tout << pp_vector("Predecessors", m_pred, true); + }); + SASSERT(-1 != m_pred[old_pred]); + node next_old_pred = m_pred[old_pred]; + swap_order(n, old_pred); + std::swap(m_upwards[n], prev_upwards); + prev_upwards = !prev_upwards; // flip previous version of upwards. + n = old_pred; + old_pred = next_old_pred; + } + } m_pred[q] = p; - for (node n = q; n != u; ) { - SASSERT(old_pred != u || n == v); // the last processed node is v - SASSERT(-1 != m_pred[old_pred]); - node next_old_pred = m_pred[old_pred]; - swap_order(n, old_pred); - std::swap(m_upwards[n], prev_upwards); - prev_upwards = !prev_upwards; // flip previous version of upwards. - n = old_pred; - old_pred = next_old_pred; - } - #endif - // m_thread and m_final were updated. + // m_thread were updated. // update the depth. - fix_depth(q, m_final[q]); + fix_depth(q, get_final(q)); TRACE("network_flow", { - tout << pp_vector("Threads", m_thread, true); + tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Threads", m_thread); + tout << pp_vector("Depths", m_depth) << pp_vector("Upwards", m_upwards); }); } /** swap v and q in tree. - - fixup m_final - fixup m_thread - fixup m_pred @@ -407,31 +395,27 @@ namespace smt { void network_flow::swap_order(node q, node v) { SASSERT(q != v); SASSERT(m_pred[q] == v); - SASSERT(is_preorder_traversal(v, m_final[v])); + SASSERT(is_preorder_traversal(v, get_final(v))); node prev = find_rev_thread(v); - node final_q = m_final[q]; - node final_v = m_final[v]; + node final_q = get_final(q); + node final_v = get_final(v); node next = m_thread[final_v]; node alpha = find_rev_thread(q); if (final_q == final_v) { m_thread[final_q] = v; m_thread[alpha] = next; - m_final[q] = alpha; - m_final[v] = alpha; } else { - node beta = m_thread[final_q]; + node beta = m_thread[final_q]; m_thread[final_q] = v; m_thread[alpha] = beta; - m_final[q] = final_v; } m_thread[prev] = q; m_pred[v] = q; - SASSERT(is_preorder_traversal(q, m_final[q])); + SASSERT(is_preorder_traversal(q, get_final(q))); } - template std::string network_flow::display_spanning_tree() { ++m_step;; @@ -537,11 +521,11 @@ namespace smt { roots[y] = x; } - static int get_final(int start, svector const & thread, svector const & depth) { - // really final or should one take into account connected tree? + template + dl_var network_flow::get_final(int start) { int n = start; - while (depth[thread[n]] > depth[start]) { - n = thread[n]; + while (m_depth[m_thread[n]] > m_depth[start]) { + n = m_thread[n]; } return n; } @@ -566,7 +550,6 @@ namespace smt { svector m_pred; node |-> node svector m_depth; node |-> int svector m_thread; node |-> node - svector m_final; node |-> node Tree is determined by m_pred: - m_pred[root] == -1 @@ -577,9 +560,6 @@ namespace smt { Furthermore, the nodes linked in m_thread follows a depth-first traversal order. - m_final[n] is the last node in depth-first traversal order, - starting from n, that is still a child of n. - m_upwards direction of edge from i to m_pred[i] m_graph */ @@ -593,6 +573,7 @@ namespace smt { svector found(m_thread.size(), false); found[root] = true; for (node x = m_thread[root]; x != root; x = m_thread[x]) { + SASSERT(x != m_thread[x]); found[x] = true; } for (unsigned i = 0; i < found.size(); ++i) { @@ -619,11 +600,6 @@ namespace smt { SASSERT(m_depth[x] == m_depth[m_pred[x]] + 1); } - // m_final of a node denotes the last node with a bigger depth - for (unsigned i = 0; i < m_final.size(); ++i) { - SASSERT(m_final[i] == get_final(i, m_thread, m_depth)); - } - // m_thread forms a spanning tree over [0..root] // Union-find structure svector roots(m_pred.size(), -1); @@ -635,11 +611,6 @@ namespace smt { merge(roots, x, y); } - std::cout << "roots" << std::endl; - for (unsigned i = 0; i < roots.size(); ++i) { - std::cout << i << " |-> " << roots[i] << std::endl; - } - // All nodes belong to the same spanning tree for (unsigned i = 0; i < roots.size(); ++i) { SASSERT(roots[i] + roots.size() == 0 || roots[i] >= 0); diff --git a/src/tactic/core/blast_term_ite_tactic.cpp b/src/tactic/core/blast_term_ite_tactic.cpp index c69849253..fbc66c418 100644 --- a/src/tactic/core/blast_term_ite_tactic.cpp +++ b/src/tactic/core/blast_term_ite_tactic.cpp @@ -50,8 +50,8 @@ class blast_term_ite_tactic : public tactic { bool max_steps_exceeded(unsigned num_steps) const { cooperate("blast term ite"); - if (memory::get_allocation_size() > m_max_memory) - throw tactic_exception(TACTIC_MAX_MEMORY_MSG); + // if (memory::get_allocation_size() > m_max_memory) + // throw tactic_exception(TACTIC_MAX_MEMORY_MSG); return false; } @@ -62,6 +62,8 @@ class blast_term_ite_tactic : public tactic { for (unsigned i = 0; i < num_args; ++i) { expr* c, *t, *e; if (!m.is_bool(args[i]) && m.is_ite(args[i], c, t, e)) { + enable_trace("blast_term_ite"); + TRACE("blast_term_ite", result = m.mk_app(f, num_args, args); tout << result << "\n";); expr_ref e1(m), e2(m); ptr_vector args1(num_args, args); args1[i] = t; From f7fdf134fd2b7713b3affc48e66e4a9835d8c67a Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Wed, 6 Nov 2013 17:42:09 -0800 Subject: [PATCH 091/925] Create a separate class for spanning tree Remarks: 1. Templates should be in header files only 2. Should pass in svector<_> instead of returning a local one --- src/smt/network_flow.h | 36 +-- src/smt/network_flow_def.h | 570 ++++++----------------------------- src/smt/spanning_tree.cpp | 356 ++++++++++++++++++++++ src/smt/spanning_tree.h | 63 ++++ src/smt/spanning_tree_base.h | 71 +++++ 5 files changed, 586 insertions(+), 510 deletions(-) create mode 100644 src/smt/spanning_tree.cpp create mode 100644 src/smt/spanning_tree.h create mode 100644 src/smt/spanning_tree_base.h diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index a90e901e8..489cf351e 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -32,12 +32,10 @@ Notes: #include"inf_rational.h" #include"diff_logic.h" +#include"spanning_tree.h" namespace smt { - template - std::string pp_vector(std::string const & label, TV v, bool has_header = false); - // Solve minimum cost flow problem using Network Simplex algorithm template class network_flow : private Ext { @@ -51,7 +49,9 @@ namespace smt { typedef dl_graph graph; typedef typename Ext::numeral numeral; typedef typename Ext::fin_numeral fin_numeral; + graph m_graph; + thread_spanning_tree tree; // Denote supply/demand b_i on node i vector m_balances; @@ -67,18 +67,7 @@ namespace smt { svector m_states; - // m_upwards[i] is true if the corresponding edge - // (i, m_pred[i]) points upwards (pointing toward the root node) - svector m_upwards; - - // Store the parent of a node i in the spanning tree - svector m_pred; - // Store the number of edge on the path from node i to the root - svector m_depth; - // Store the pointer from node i to the next node in depth-first search order - svector m_thread; - // Store a final node of the sub tree rooted at node i - svector m_final; + unsigned m_step; edge_id m_entering_edge; edge_id m_leaving_edge; @@ -86,14 +75,11 @@ namespace smt { optional m_delta; bool m_in_edge_dir; - unsigned m_step; - // Initialize the network with a feasible spanning tree void initialize(); edge_id get_edge_id(dl_var source, dl_var target) const; - void update_potentials(); void update_flows(); @@ -113,22 +99,8 @@ namespace smt { bool edge_in_tree(edge_id id) const; bool edge_in_tree(node src, node dst) const; - bool is_ancestor_of(node ancestor, node child) const; - - /** - \brief find node that points to 'n' in m_thread - */ - node find_rev_thread(node n) const; - - void fix_depth(node start, node end); - - void swap_order(node q, node v); - bool check_well_formed(); - bool is_preorder_traversal(node start, node end); - node get_final(int start); - public: network_flow(graph & g, vector const & balances); diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index 96557301f..834cfc075 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -25,24 +25,6 @@ Notes: namespace smt { - template - std::string pp_vector(std::string const & label, TV v, bool has_header) { - std::ostringstream oss; - if (has_header) { - oss << "Index "; - for (unsigned i = 0; i < v.size(); ++i) { - oss << i << " "; - } - oss << std::endl; - } - oss << label << " "; - for (unsigned i = 0; i < v.size(); ++i) { - oss << v[i] << " "; - } - oss << std::endl; - return oss.str(); - } - template network_flow::network_flow(graph & g, vector const & balances) : m_balances(balances) { @@ -63,14 +45,9 @@ namespace smt { unsigned num_edges = m_graph.get_num_edges(); m_balances.resize(num_nodes); - m_potentials.resize(num_nodes); + m_potentials.resize(num_nodes); - m_upwards.resize(num_nodes); - m_pred.resize(num_nodes); - m_depth.resize(num_nodes); - m_thread.resize(num_nodes); - - m_step = 0; + tree = thread_spanning_tree(); } template @@ -79,13 +56,10 @@ namespace smt { // Create an artificial root node to construct initial spanning tree unsigned num_nodes = m_graph.get_num_nodes(); unsigned num_edges = m_graph.get_num_edges(); + node root = num_nodes; - m_pred[root] = -1; - m_depth[root] = 0; - m_thread[root] = 0; - m_potentials[root] = numeral::zero(); - m_graph.init_var(root); + m_potentials[root] = numeral::zero(); fin_numeral sum_supply = fin_numeral::zero(); for (unsigned i = 0; i < m_balances.size(); ++i) { @@ -99,31 +73,31 @@ namespace smt { m_states.fill(LOWER); // Create artificial edges from/to root node to/from other nodes and initialize the spanning tree + svector upwards(num_nodes, false); for (unsigned i = 0; i < num_nodes; ++i) { - m_upwards[i] = !m_balances[i].is_neg(); - m_pred[i] = root; - m_depth[i] = 1; - m_thread[i] = i + 1; + upwards[i] = !m_balances[i].is_neg(); m_states[num_edges + i] = BASIS; - node src = m_upwards[i] ? i : root; - node tgt = m_upwards[i] ? root : i; - m_flows[num_edges + i] = m_upwards[i] ? m_balances[i] : -m_balances[i]; + node src = upwards[i] ? i : root; + node tgt = upwards[i] ? root : i; + m_flows[num_edges + i] = upwards[i] ? m_balances[i] : -m_balances[i]; m_graph.add_edge(src, tgt, numeral::one(), explanation()); } + tree.initialize(upwards, num_nodes); + // Compute initial potentials - node u = m_thread[root]; - while (u != root) { - node v = m_pred[u]; + svector descendants; + tree.get_descendants(root, descendants); + // Skip root node + for (unsigned i = 1; i < descendants.size(); ++i) { + node u = descendants[i]; + node v = tree.get_parent(u); edge_id e_id = get_edge_id(u, v); - m_potentials[u] = m_potentials[v] + (m_upwards[u] ? - m_graph.get_weight(e_id) : m_graph.get_weight(e_id)); - u = m_thread[u]; + m_potentials[u] = m_potentials[v] + (tree.get_arc_direction(u) ? - m_graph.get_weight(e_id) : m_graph.get_weight(e_id)); } TRACE("network_flow", { - tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Threads", m_thread); - tout << pp_vector("Depths", m_depth) << pp_vector("Upwards", m_upwards); - tout << pp_vector("Potentials", m_potentials) << pp_vector("Flows", m_flows); + tout << pp_vector("Potentials", m_potentials, true) << pp_vector("Flows", m_flows); }); TRACE("network_flow", tout << "Spanning tree:\n" << display_spanning_tree();); SASSERT(check_well_formed()); @@ -131,9 +105,9 @@ namespace smt { template edge_id network_flow::get_edge_id(dl_var source, dl_var target) const { - // m_upwards[source] decides which node is the real source + // tree.get_arc_direction(source) decides which node is the real source edge_id id; - VERIFY(m_upwards[source] ? m_graph.get_edge_id(source, target, id) : m_graph.get_edge_id(target, source, id)); + VERIFY(tree.get_arc_direction(source) ? m_graph.get_edge_id(source, target, id) : m_graph.get_edge_id(target, source, id)); return id; } @@ -143,9 +117,11 @@ namespace smt { node src = m_graph.get_source(m_entering_edge); node tgt = m_graph.get_target(m_entering_edge); numeral cost = m_graph.get_weight(m_entering_edge); - numeral change = m_upwards[src] ? (-cost - m_potentials[src] + m_potentials[tgt]) : (cost + m_potentials[src] - m_potentials[tgt]); - node last = m_thread[get_final(src)]; - for (node u = src; u != last; u = m_thread[u]) { + numeral change = tree.get_arc_direction(src) ? (-cost - m_potentials[src] + m_potentials[tgt]) : (cost + m_potentials[src] - m_potentials[tgt]); + svector descendants; + tree.get_descendants(src, descendants); + for (unsigned i = 0; i < descendants.size(); ++i) { + node u = descendants[i]; m_potentials[u] += change; } TRACE("network_flow", tout << pp_vector("Potentials", m_potentials, true);); @@ -157,14 +133,20 @@ namespace smt { numeral val = fin_numeral(m_states[m_entering_edge]) * (*m_delta); m_flows[m_entering_edge] += val; node source = m_graph.get_source(m_entering_edge); - for (unsigned u = source; u != m_join_node; u = m_pred[u]) { - edge_id e_id = get_edge_id(u, m_pred[u]); - m_flows[e_id] += m_upwards[u] ? -val : val; + svector ancestors; + tree.get_ancestors(source, ancestors); + for (unsigned i = 0; i < ancestors.size() && ancestors[i] != m_join_node; ++i) { + node u = ancestors[i]; + edge_id e_id = get_edge_id(u, tree.get_parent(u)); + m_flows[e_id] += tree.get_arc_direction(u) ? -val : val; } + node target = m_graph.get_target(m_entering_edge); - for (unsigned u = target; u != m_join_node; u = m_pred[u]) { - edge_id e_id = get_edge_id(u, m_pred[u]); - m_flows[e_id] += m_upwards[u] ? val : -val; + tree.get_ancestors(target,ancestors); + for (unsigned i = 0; i < ancestors.size() && ancestors[i] != m_join_node; ++i) { + node u = ancestors[i]; + edge_id e_id = get_edge_id(u, tree.get_parent(u)); + m_flows[e_id] += tree.get_arc_direction(u) ? val : -val; } TRACE("network_flow", tout << pp_vector("Flows", m_flows, true);); } @@ -202,41 +184,37 @@ namespace smt { if (m_states[m_entering_edge] == UPPER) { std::swap(source, target); } - node u = source, v = target; - while (u != v) { - if (m_depth[u] > m_depth[v]) - u = m_pred[u]; - else if (m_depth[u] < m_depth[v]) - v = m_pred[v]; - else { - u = m_pred[u]; - v = m_pred[v]; - } - } - // Found first common ancestor of source and target - m_join_node = u; + + m_join_node = tree.get_common_ancestor(source, target); + TRACE("network_flow", tout << "Found join node " << m_join_node << std::endl;); m_delta.set_invalid(); node src, tgt; + // Send flows along the path from source to the ancestor - for (unsigned u = source; u != m_join_node; u = m_pred[u]) { - edge_id e_id = get_edge_id(u, m_pred[u]); - if (m_upwards[u] && (!m_delta || m_flows[e_id] < *m_delta)) { + svector ancestors; + tree.get_ancestors(source, ancestors); + for (unsigned i = 0; i < ancestors.size() && ancestors[i] != m_join_node; ++i) { + node u = ancestors[i]; + edge_id e_id = get_edge_id(u, tree.get_parent(u)); + if (tree.get_arc_direction(u) && (!m_delta || m_flows[e_id] < *m_delta)) { m_delta = m_flows[e_id]; src = u; - tgt = m_pred[u]; + tgt = tree.get_parent(u); SASSERT(edge_in_tree(src,tgt)); m_in_edge_dir = true; } } // Send flows along the path from target to the ancestor - for (unsigned u = target; u != m_join_node; u = m_pred[u]) { - edge_id e_id = get_edge_id(u, m_pred[u]); - if (!m_upwards[u] && (!m_delta || m_flows[e_id] <= *m_delta)) { + tree.get_ancestors(target, ancestors); + for (unsigned i = 0; i < ancestors.size() && ancestors[i] != m_join_node; ++i) { + node u = ancestors[i]; + edge_id e_id = get_edge_id(u, tree.get_parent(u)); + if (!tree.get_arc_direction(u) && (!m_delta || m_flows[e_id] <= *m_delta)) { m_delta = m_flows[e_id]; src = u; - tgt = m_pred[u]; + tgt = tree.get_parent(u); SASSERT(edge_in_tree(src,tgt)); m_in_edge_dir = false; } @@ -254,196 +232,14 @@ namespace smt { return false; } - template - bool network_flow::is_ancestor_of(node ancestor, node child) const { - for (node n = child; n != -1; n = m_pred[n]) { - if (n == ancestor) { - return true; - } - } - return false; - } - - template - dl_var network_flow::find_rev_thread(node n) const { - node ancestor = m_pred[n]; - SASSERT(ancestor != -1); - while (m_thread[ancestor] != n) { - ancestor = m_thread[ancestor]; - } - return ancestor; - } - - template - void network_flow::fix_depth(node start, node end) { - SASSERT(m_pred[start] != -1); - m_depth[start] = m_depth[m_pred[start]]+1; - while (start != end) { - start = m_thread[start]; - m_depth[start] = m_depth[m_pred[start]]+1; - } - } - - /** - \brief add entering_edge, remove leaving_edge from spanning tree. - - Old tree: New tree: - root root - / \ / \ - x y x y - / \ / \ / \ / \ - u s u s - | / / - v w v w - / \ \ / \ \ - z p z p - \ \ / - q q - */ - template void network_flow::update_spanning_tree() { node p = m_graph.get_source(m_entering_edge); node q = m_graph.get_target(m_entering_edge); node u = m_graph.get_source(m_leaving_edge); node v = m_graph.get_target(m_leaving_edge); - bool q_upwards = false; - - // v is parent of u so T_u does not contain root node - if (m_pred[u] == v) { - std::swap(u, v); - } - SASSERT(m_pred[v] == u); - - if (is_ancestor_of(v, p)) { - std::swap(p, q); - q_upwards = true; - } - SASSERT(is_ancestor_of(v, q)); - - TRACE("network_flow", { - tout << "update_spanning_tree: (" << p << ", " << q << ") enters, ("; - tout << u << ", " << v << ") leaves\n"; - }); - - - // Update m_pred (for nodes in the stem from q to v) - // Note: m_pred[v] == u - // Initialize m_upwards[q] = q_upwards - - bool prev_upwards = q_upwards; -#if 0 - for (node n = q, prev = p; n != u; ) { - SASSERT(m_pred[n] != u || n == v); // the last processed node is v - node next = m_pred[n]; - m_pred[n] = prev; - std::swap(m_upwards[n], prev_upwards); - prev_upwards = !prev_upwards; // flip previous version of upwards. - prev = n; - n = next; - SASSERT(n != -1); - } -#else - node old_pred = m_pred[q]; - if (q != v) { - for (node n = q; n != u; ) { - SASSERT(old_pred != u || n == v); // the last processed node is v - TRACE("network_flow", { - tout << pp_vector("Predecessors", m_pred, true); - }); - SASSERT(-1 != m_pred[old_pred]); - node next_old_pred = m_pred[old_pred]; - swap_order(n, old_pred); - std::swap(m_upwards[n], prev_upwards); - prev_upwards = !prev_upwards; // flip previous version of upwards. - n = old_pred; - old_pred = next_old_pred; - } - } - m_pred[q] = p; -#endif - - // m_thread were updated. - // update the depth. - - fix_depth(q, get_final(q)); - - TRACE("network_flow", { - tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Threads", m_thread); - tout << pp_vector("Depths", m_depth) << pp_vector("Upwards", m_upwards); - }); - } - - /** - swap v and q in tree. - - fixup m_thread - - fixup m_pred - - Case 1: final(q) == final(v) - ------- - Old thread: prev -> v -*-> alpha -> q -*-> final(q) -> next - New thread: prev -> q -*-> final(q) -> v -*-> alpha -> next - - Case 2: final(q) != final(v) - ------- - Old thread: prev -> v -*-> alpha -> q -*-> final(q) -> beta -*-> final(v) -> next - New thread: prev -> q -*-> final(q) -> v -*-> alpha -> beta -*-> final(v) -> next - - */ - - template - void network_flow::swap_order(node q, node v) { - SASSERT(q != v); - SASSERT(m_pred[q] == v); - SASSERT(is_preorder_traversal(v, get_final(v))); - node prev = find_rev_thread(v); - node final_q = get_final(q); - node final_v = get_final(v); - node next = m_thread[final_v]; - node alpha = find_rev_thread(q); - - if (final_q == final_v) { - m_thread[final_q] = v; - m_thread[alpha] = next; - } - else { - node beta = m_thread[final_q]; - m_thread[final_q] = v; - m_thread[alpha] = beta; - } - m_thread[prev] = q; - m_pred[v] = q; - SASSERT(is_preorder_traversal(q, get_final(q))); - } - - template - std::string network_flow::display_spanning_tree() { - ++m_step;; - std::ostringstream oss; - std::string prefix = "T"; - prefix.append(std::to_string(m_step)); - prefix.append("_"); - unsigned root = m_graph.get_num_nodes() - 1; - for (unsigned i = 0; i < root; ++i) { - oss << prefix << i << "[shape=circle,label=\"" << prefix << i << " ["; - oss << m_potentials[i] << "/" << m_balances[i] << "]\"];\n"; - } - oss << prefix << root << "[shape=doublecircle,label=\"" << prefix << root << " ["; - oss << m_potentials[root] << "/" << m_balances[root] << "]\"];\n"; - - vector const & es = m_graph.get_all_edges(); - for (unsigned i = 0; i < es.size(); ++i) { - edge const & e = es[i]; - oss << prefix << e.get_source() << " -> " << prefix << e.get_target(); - if (m_states[i] == BASIS) { - oss << "[color=red,penwidth=3.0,label=\"" << m_flows[i] << "/" << e.get_weight() << "\"];\n"; - } - else { - oss << "[label=\"" << m_flows[i] << "/" << e.get_weight() << "\"];\n"; - } - } - oss << std::endl; - return oss.str(); + + tree.update(p, q, u, v); } // Minimize cost flows @@ -494,42 +290,6 @@ namespace smt { return m_objective_value; } - static unsigned find(svector& roots, unsigned x) { - unsigned old_x = x; - while (roots[x] >= 0) { - x = roots[x]; - } - SASSERT(roots[x] < 0); - if (old_x != x) { - roots[old_x] = x; - } - return x; - } - - static void merge(svector& roots, unsigned x, unsigned y) { - x = find(roots, x); - y = find(roots, y); - SASSERT(roots[x] < 0 && roots[y] < 0); - if (x == y) { - return; - } - if (roots[x] > roots[y]) { - std::swap(x, y); - } - SASSERT(roots[x] <= roots[y]); - roots[x] += roots[y]; - roots[y] = x; - } - - template - dl_var network_flow::get_final(int start) { - int n = start; - while (m_depth[m_thread[n]] > m_depth[start]) { - n = m_thread[n]; - } - return n; - } - template bool network_flow::edge_in_tree(edge_id id) const { return m_states[id] == BASIS; @@ -540,202 +300,56 @@ namespace smt { return edge_in_tree(get_edge_id(src,dst)); } - /** - \brief Check invariants of main data-structures. - - Spanning tree of m_graph + root is represented using: - - svector m_states; edge_id |-> edge_state - svector m_upwards; node |-> bool - svector m_pred; node |-> node - svector m_depth; node |-> int - svector m_thread; node |-> node - - Tree is determined by m_pred: - - m_pred[root] == -1 - - m_pred[n] = m != n for each node n, acyclic until reaching root. - - m_depth[m_pred[n]] + 1 == m_depth[n] for each n != root - - m_thread is a linked list traversing all nodes. - Furthermore, the nodes linked in m_thread follows a - depth-first traversal order. - - m_upwards direction of edge from i to m_pred[i] m_graph - - */ - + template bool network_flow::check_well_formed() { - node root = m_pred.size()-1; - - // Check that m_thread traverses each node. - // This gets checked using union-find as well. - svector found(m_thread.size(), false); - found[root] = true; - for (node x = m_thread[root]; x != root; x = m_thread[x]) { - SASSERT(x != m_thread[x]); - found[x] = true; - } - for (unsigned i = 0; i < found.size(); ++i) { - SASSERT(found[i]); - } - - // m_pred is acyclic, and points to root. - SASSERT(m_pred[root] == -1); - SASSERT(m_depth[root] == 0); - for (node i = 0; i < root; ++i) { - SASSERT(m_depth[m_pred[i]] < m_depth[i]); - } - - // m_upwards show correct direction - for (unsigned i = 0; i < m_upwards.size(); ++i) { - node p = m_pred[i]; - edge_id id; - SASSERT(!m_upwards[i] || m_graph.get_edge_id(i, p, id)); - } - - // m_depth[x] denotes distance from x to the root node - for (node x = m_thread[root]; x != root; x = m_thread[x]) { - SASSERT(m_depth[x] > 0); - SASSERT(m_depth[x] == m_depth[m_pred[x]] + 1); - } - - // m_thread forms a spanning tree over [0..root] - // Union-find structure - svector roots(m_pred.size(), -1); - - for (node x = m_thread[root]; x != root; x = m_thread[x]) { - node y = m_pred[x]; - // We are now going to check the edge between x and y - SASSERT(find(roots, x) != find(roots, y)); - merge(roots, x, y); - } - - // All nodes belong to the same spanning tree - for (unsigned i = 0; i < roots.size(); ++i) { - SASSERT(roots[i] + roots.size() == 0 || roots[i] >= 0); - } + SASSERT(tree.check_well_formed()); // m_flows are zero on non-basic edges for (unsigned i = 0; i < m_flows.size(); ++i) { SASSERT(m_states[i] == BASIS || m_flows[i].is_zero()); } + + // m_upwards show correct direction + for (unsigned i = 0; i < m_potentials.size(); ++i) { + node p = tree.get_parent(i); + edge_id id; + SASSERT(!tree.get_arc_direction(i) || m_graph.get_edge_id(i, p, id)); + } + return true; } template - bool network_flow::is_preorder_traversal(node start, node end) { - - // get children of start: - uint_set children; - children.insert(start); - node root = m_pred.size()-1; - for (int i = 0; i < root; ++i) { - for (int j = 0; j < root; ++j) { - if (children.contains(m_pred[j])) { - children.insert(j); + std::string network_flow:: display_spanning_tree() { + ++m_step;; + std::ostringstream oss; + std::string prefix = "T"; + prefix.append(std::to_string(m_step)); + prefix.append("_"); + unsigned root = m_graph.get_num_nodes() - 1; + for (unsigned i = 0; i < root; ++i) { + oss << prefix << i << "[shape=circle,label=\"" << prefix << i << " ["; + oss << m_potentials[i] << "/" << m_balances[i] << "]\"];\n"; + } + oss << prefix << root << "[shape=doublecircle,label=\"" << prefix << root << " ["; + oss << m_potentials[root] << "/" << m_balances[root] << "]\"];\n"; + + vector const & es = m_graph.get_all_edges(); + for (unsigned i = 0; i < es.size(); ++i) { + edge const & e = es[i]; + oss << prefix << e.get_source() << " -> " << prefix << e.get_target(); + if (m_states[i] == BASIS) { + oss << "[color=red,penwidth=3.0,label=\"" << m_flows[i] << "/" << e.get_weight() << "\"];\n"; + } + else { + oss << "[label=\"" << m_flows[i] << "/" << e.get_weight() << "\"];\n"; } } - } - // visit children using m_thread - children.remove(start); - do { - start = m_thread[start]; - SASSERT(children.contains(start)); - children.remove(start); - } - while (start != end); - SASSERT(children.empty()); - return true; + oss << std::endl; + return oss.str(); } - } #endif - -#if 0 - - // At this point m_pred and m_upwards have been updated. - - TRACE("network_flow", tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Upwards", m_upwards);); - - - // - node x = m_final[p]; - node y = m_thread[x]; - node z = m_final[q]; - - // ---- - // update m_final. - - // Do this before updating data structures - node gamma_p = m_pred[m_thread[m_final[p]]]; - node gamma_v = m_pred[m_thread[m_final[v]]]; - node theta = m_thread[m_final[v]]; - - // Check that f(u) is not in T_v - bool found_final_u = false; - for (node n = v; n != theta; n = m_thread[n]) { - if (n == m_final[u]) { - found_final_u = true; - break; - } - } - node phi = find_rev_thread(v); - node delta = found_final_u ? phi : m_final[u]; - - TRACE("network_flow", tout << "Graft T_q and T_r'\n";); - - for (node n = p; n != gamma_p && n != -1; n = m_pred[n]) { - TRACE("network_flow", tout << "1: m_final[" << n << "] |-> " << z << "\n";); - m_final[n] = z; - } - - // - - m_thread[x] = q; - m_thread[z] = y; - - - TRACE("network_flow", tout << "Update T_r'\n";); - - m_thread[phi] = theta; - - for (node n = u; n != gamma_v && n != -1; n = m_pred[n]) { - TRACE("network_flow", tout << "2: m_final[" << n << "] |-> " << delta << "\n";); - m_final[n] = delta; - } - - TRACE("network_flow", tout << pp_vector("Last Successors", m_final, true) << pp_vector("Depths", m_depth);); - - if (v != q) { - TRACE("network_flow", tout << "Reroot T_v at q\n";); - - node alpha1, alpha2; - node prev = q; - for (node n = v; n != q && n != -1; n = m_pred[n]) { - // Find all immediate successors of n - node t1 = m_thread[n]; - node t2 = m_thread[m_final[t1]]; - node t3 = m_thread[m_final[t2]]; - if (t1 == m_pred[n]) { - alpha1 = t2; - alpha2 = t3; - } - else if (t2 == m_pred[n]) { - alpha1 = t1; - alpha2 = t3; - } - else { - alpha1 = t1; - alpha2 = t2; - } - m_thread[n] = alpha1; - m_thread[m_final[alpha1]] = alpha2; - m_thread[m_final[alpha2]] = prev; - prev = n; - } - m_thread[m_final[q]] = prev; - } -#endif diff --git a/src/smt/spanning_tree.cpp b/src/smt/spanning_tree.cpp new file mode 100644 index 000000000..21c3fcfb4 --- /dev/null +++ b/src/smt/spanning_tree.cpp @@ -0,0 +1,356 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + spanning_tree.cpp + +Abstract: + + +Author: + + Anh-Dung Phan (t-anphan) 2013-11-06 + +Notes: + +--*/ +#include +#include "spanning_tree.h" +#include "debug.h" +#include "vector.h" +#include "uint_set.h" +#include "trace.h" + +namespace smt { + + + /** + swap v and q in tree. + - fixup m_thread + - fixup m_pred + + Case 1: final(q) == final(v) + ------- + Old thread: prev -> v -*-> alpha -> q -*-> final(q) -> next + New thread: prev -> q -*-> final(q) -> v -*-> alpha -> next + + Case 2: final(q) != final(v) + ------- + Old thread: prev -> v -*-> alpha -> q -*-> final(q) -> beta -*-> final(v) -> next + New thread: prev -> q -*-> final(q) -> v -*-> alpha -> beta -*-> final(v) -> next + + */ + void thread_spanning_tree::swap_order(node q, node v) { + SASSERT(q != v); + SASSERT(m_pred[q] == v); + SASSERT(is_preorder_traversal(v, get_final(v))); + node prev = find_rev_thread(v); + node final_q = get_final(q); + node final_v = get_final(v); + node next = m_thread[final_v]; + node alpha = find_rev_thread(q); + + if (final_q == final_v) { + m_thread[final_q] = v; + m_thread[alpha] = next; + } + else { + node beta = m_thread[final_q]; + m_thread[final_q] = v; + m_thread[alpha] = beta; + } + m_thread[prev] = q; + m_pred[v] = q; + SASSERT(is_preorder_traversal(q, get_final(q))); + } + + /** + \brief find node that points to 'n' in m_thread + */ + node thread_spanning_tree::find_rev_thread(node n) const { + node ancestor = m_pred[n]; + SASSERT(ancestor != -1); + while (m_thread[ancestor] != n) { + ancestor = m_thread[ancestor]; + } + return ancestor; + } + + void thread_spanning_tree::fix_depth(node start, node end) { + SASSERT(m_pred[start] != -1); + m_depth[start] = m_depth[m_pred[start]]+1; + while (start != end) { + start = m_thread[start]; + m_depth[start] = m_depth[m_pred[start]]+1; + } + } + + node thread_spanning_tree::get_final(int start) { + int n = start; + while (m_depth[m_thread[n]] > m_depth[start]) { + n = m_thread[n]; + } + return n; + } + + bool thread_spanning_tree::is_preorder_traversal(node start, node end) { + // get children of start + uint_set children; + children.insert(start); + node root = m_pred.size()-1; + for (int i = 0; i < root; ++i) { + for (int j = 0; j < root; ++j) { + if (children.contains(m_pred[j])) { + children.insert(j); + } + } + } + // visit children using m_thread + children.remove(start); + do { + start = m_thread[start]; + SASSERT(children.contains(start)); + children.remove(start); + } + while (start != end); + SASSERT(children.empty()); + return true; + } + + bool thread_spanning_tree::is_ancestor_of(node ancestor, node child) { + for (node n = child; n != -1; n = m_pred[n]) { + if (n == ancestor) { + return true; + } + } + return false; + } + + static unsigned find(svector& roots, unsigned x) { + unsigned old_x = x; + while (roots[x] >= 0) { + x = roots[x]; + } + SASSERT(roots[x] < 0); + if (old_x != x) { + roots[old_x] = x; + } + return x; + } + + static void merge(svector& roots, unsigned x, unsigned y) { + x = find(roots, x); + y = find(roots, y); + SASSERT(roots[x] < 0 && roots[y] < 0); + if (x == y) { + return; + } + if (roots[x] > roots[y]) { + std::swap(x, y); + } + SASSERT(roots[x] <= roots[y]); + roots[x] += roots[y]; + roots[y] = x; + } + + void thread_spanning_tree::initialize(svector const & upwards, int num_nodes) { + m_pred.resize(num_nodes + 1); + m_depth.resize(num_nodes + 1); + m_thread.resize(num_nodes + 1); + m_upwards.resize(num_nodes + 1); + + node root = num_nodes; + m_pred[root] = -1; + m_depth[root] = 0; + m_thread[root] = 0; + + // Create artificial edges from/to root node to/from other nodes and initialize the spanning tree + for (int i = 0; i < num_nodes; ++i) { + m_pred[i] = root; + m_depth[i] = 1; + m_thread[i] = i + 1; + m_upwards[i] = upwards[i]; + } + + TRACE("network_flow", { + tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Threads", m_thread); + tout << pp_vector("Depths", m_depth) << pp_vector("Upwards", m_upwards); + }); + } + + node thread_spanning_tree::get_common_ancestor(node u, node v) { + while (u != v) { + if (m_depth[u] > m_depth[v]) + u = m_pred[u]; + else + v = m_pred[v]; + } + return u; + } + + void thread_spanning_tree::get_descendants(node start, svector& descendants) { + descendants.reset(); + node u = start; + while (m_depth[m_thread[u]] > m_depth[start]) { + descendants.push_back(u); + u = m_thread[u]; + } + } + + void thread_spanning_tree::get_ancestors(node start, svector& ancestors) { + ancestors.reset(); + while (m_pred[start] != -1) { + ancestors.push_back(start); + start = m_pred[start]; + } + } + + /** + \brief add entering_edge, remove leaving_edge from spanning tree. + + Old tree: New tree: + root root + / \ / \ + x y x y + / \ / \ / \ / \ + u s u s + | / / + v w v w + / \ \ / \ \ + z p z p + \ \ / + q q + */ + void thread_spanning_tree::update(node p, node q, node u, node v) { + bool q_upwards = false; + + // v is parent of u so T_u does not contain root node + if (m_pred[u] == v) { + std::swap(u, v); + } + SASSERT(m_pred[v] == u); + + if (is_ancestor_of(v, p)) { + std::swap(p, q); + q_upwards = true; + } + SASSERT(is_ancestor_of(v, q)); + + TRACE("network_flow", { + tout << "update_spanning_tree: (" << p << ", " << q << ") enters, ("; + tout << u << ", " << v << ") leaves\n"; + }); + + // Update m_pred (for nodes in the stem from q to v) + // Note: m_pred[v] == u + // Initialize m_upwards[q] = q_upwards + + bool prev_upwards = q_upwards; + node old_pred = m_pred[q]; + if (q != v) { + for (node n = q; n != u; ) { + SASSERT(old_pred != u || n == v); // the last processed node is v + TRACE("network_flow", { + tout << pp_vector("Predecessors", m_pred, true); + }); + SASSERT(-1 != m_pred[old_pred]); + int next_old_pred = m_pred[old_pred]; + swap_order(n, old_pred); + std::swap(m_upwards[n], prev_upwards); + prev_upwards = !prev_upwards; // flip previous version of upwards. + n = old_pred; + old_pred = next_old_pred; + } + } + m_pred[q] = p; + + // m_thread were updated. + // update the depth. + + fix_depth(q, get_final(q)); + + TRACE("network_flow", { + tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Threads", m_thread); + tout << pp_vector("Depths", m_depth) << pp_vector("Upwards", m_upwards); + }); + } + + /** + \brief Check invariants of main data-structures. + + Spanning tree of m_graph + root is represented using: + + svector m_states; edge_id |-> edge_state + svector m_upwards; node |-> bool + svector m_pred; node |-> node + svector m_depth; node |-> int + svector m_thread; node |-> node + + Tree is determined by m_pred: + - m_pred[root] == -1 + - m_pred[n] = m != n for each node n, acyclic until reaching root. + - m_depth[m_pred[n]] + 1 == m_depth[n] for each n != root + + m_thread is a linked list traversing all nodes. + Furthermore, the nodes linked in m_thread follows a + depth-first traversal order. + + m_upwards direction of edge from i to m_pred[i] m_graph + + */ + bool thread_spanning_tree::check_well_formed() { + node root = m_pred.size()-1; + + // Check that m_thread traverses each node. + // This gets checked using union-find as well. + svector found(m_thread.size(), false); + found[root] = true; + for (node x = m_thread[root]; x != root; x = m_thread[x]) { + SASSERT(x != m_thread[x]); + found[x] = true; + } + for (unsigned i = 0; i < found.size(); ++i) { + SASSERT(found[i]); + } + + // m_pred is acyclic, and points to root. + SASSERT(m_pred[root] == -1); + SASSERT(m_depth[root] == 0); + for (node i = 0; i < root; ++i) { + SASSERT(m_depth[m_pred[i]] < m_depth[i]); + } + + // m_depth[x] denotes distance from x to the root node + for (node x = m_thread[root]; x != root; x = m_thread[x]) { + SASSERT(m_depth[x] > 0); + SASSERT(m_depth[x] == m_depth[m_pred[x]] + 1); + } + + // m_thread forms a spanning tree over [0..root] + // Union-find structure + svector roots(m_pred.size(), -1); + + for (node x = m_thread[root]; x != root; x = m_thread[x]) { + node y = m_pred[x]; + // We are now going to check the edge between x and y + SASSERT(find(roots, x) != find(roots, y)); + merge(roots, x, y); + } + + // All nodes belong to the same spanning tree + for (unsigned i = 0; i < roots.size(); ++i) { + SASSERT(roots[i] + roots.size() == 0 || roots[i] >= 0); + } + + return true; + } + + bool thread_spanning_tree::get_arc_direction(node start) const { + return m_upwards[start]; + } + + node thread_spanning_tree::get_parent(node start) { + return m_pred[start]; + } +} \ No newline at end of file diff --git a/src/smt/spanning_tree.h b/src/smt/spanning_tree.h new file mode 100644 index 000000000..6769a6a18 --- /dev/null +++ b/src/smt/spanning_tree.h @@ -0,0 +1,63 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + spanning_tree.h + +Abstract: + + Represent spanning trees with needed operations for Network Simplex + +Author: + + Anh-Dung Phan (t-anphan) 2013-11-06 + +Notes: + +--*/ +#ifndef _SPANNING_TREE_H_ +#define _SPANNING_TREE_H_ + +#include "spanning_tree_base.h" + +namespace smt { + + + class thread_spanning_tree : virtual public spanning_tree_base { + private: + // Store the parent of a node i in the spanning tree + svector m_pred; + // Store the number of edge on the path from node i to the root + svector m_depth; + // Store the pointer from node i to the next node in depth-first search order + svector m_thread; + + // m_upwards[i] is true if the corresponding edge + // (i, m_pred[i]) points upwards (pointing toward the root node) + svector m_upwards; + + void swap_order(node q, node v); + node find_rev_thread(node n) const; + void fix_depth(node start, node end); + node get_final(int start); + bool is_preorder_traversal(node start, node end); + bool is_ancestor_of(node ancestor, node child); + + public: + + void initialize(svector const & upwards, int num_nodes); + void get_descendants(node start, svector& descendants); + void get_ancestors(node start, svector& ancestors); + node get_common_ancestor(node u, node v); + void update(node p, node q, node u, node v); + bool check_well_formed(); + + // TODO: remove these two unnatural functions + bool get_arc_direction(node start) const; + node get_parent(node start); + }; + +} + +#endif diff --git a/src/smt/spanning_tree_base.h b/src/smt/spanning_tree_base.h new file mode 100644 index 000000000..6be090711 --- /dev/null +++ b/src/smt/spanning_tree_base.h @@ -0,0 +1,71 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + spanning_tree_base.h + +Abstract: + + Represent spanning trees with needed operations for Network Simplex + +Author: + + Anh-Dung Phan (t-anphan) 2013-11-06 + +Notes: + +--*/ + +#ifndef _SPANNING_TREE_BASE_H_ +#define _SPANNING_TREE_BASE_H_ + +#include "util.h" +#include "vector.h" + +namespace smt { + typedef int node; + + template + inline std::string pp_vector(std::string const & label, TV v, bool has_header = false) { + std::ostringstream oss; + if (has_header) { + oss << "Index "; + for (unsigned i = 0; i < v.size(); ++i) { + oss << i << " "; + } + oss << std::endl; + } + oss << label << " "; + for (unsigned i = 0; i < v.size(); ++i) { + oss << v[i] << " "; + } + oss << std::endl; + return oss.str(); + } + + class spanning_tree_base { + public: + spanning_tree_base() {}; + virtual ~spanning_tree_base() {}; + + virtual void initialize(svector const & upwards, int num_nodes) = 0; + /** + \brief Get all descendants of a node including itself + */ + virtual void get_descendants(node start, svector& descendants) = 0; + /** + \brief Get all ancestors of a node including itself + */ + virtual void get_ancestors(node start, svector& ancestors) = 0; + virtual node get_common_ancestor(node u, node v) = 0; + virtual void update(node p, node q, node u, node v) = 0; + virtual bool check_well_formed() = 0; + + // TODO: remove these two unnatural functions + virtual bool get_arc_direction(node start) const = 0; + virtual node get_parent(node start) = 0; + }; +} + +#endif \ No newline at end of file From 676e38ad0b07db477f97ea8434a115260a4609c2 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Wed, 6 Nov 2013 18:34:09 -0800 Subject: [PATCH 092/925] Minor updates --- src/smt/network_flow.h | 4 +--- src/smt/network_flow_def.h | 46 +++++++++++++++++++++++++++++--------- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index 489cf351e..3303e2618 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -59,9 +59,6 @@ namespace smt { // Duals of flows which are convenient to compute dual solutions vector m_potentials; - // Keep optimal solution of the min cost flow problem - numeral m_objective_value; - // Basic feasible flows vector m_flows; @@ -100,6 +97,7 @@ namespace smt { bool edge_in_tree(node src, node dst) const; bool check_well_formed(); + bool check_optimal(); public: diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index 834cfc075..d576e3704 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -48,6 +48,7 @@ namespace smt { m_potentials.resize(num_nodes); tree = thread_spanning_tree(); + m_step = 0; } template @@ -79,7 +80,7 @@ namespace smt { m_states[num_edges + i] = BASIS; node src = upwards[i] ? i : root; node tgt = upwards[i] ? root : i; - m_flows[num_edges + i] = upwards[i] ? m_balances[i] : -m_balances[i]; + m_flows[num_edges + i] = upwards[i] ? m_balances[i] : -m_balances[i]; m_graph.add_edge(src, tgt, numeral::one(), explanation()); } @@ -117,7 +118,7 @@ namespace smt { node src = m_graph.get_source(m_entering_edge); node tgt = m_graph.get_target(m_entering_edge); numeral cost = m_graph.get_weight(m_entering_edge); - numeral change = tree.get_arc_direction(src) ? (-cost - m_potentials[src] + m_potentials[tgt]) : (cost + m_potentials[src] - m_potentials[tgt]); + numeral change = m_potentials[tgt] - m_potentials[src] + (tree.get_arc_direction(src) ? -cost : cost); svector descendants; tree.get_descendants(src, descendants); for (unsigned i = 0; i < descendants.size(); ++i) { @@ -142,7 +143,7 @@ namespace smt { } node target = m_graph.get_target(m_entering_edge); - tree.get_ancestors(target,ancestors); + tree.get_ancestors(target, ancestors); for (unsigned i = 0; i < ancestors.size() && ancestors[i] != m_join_node; ++i) { node u = ancestors[i]; edge_id e_id = get_edge_id(u, tree.get_parent(u)); @@ -266,18 +267,20 @@ namespace smt { } } TRACE("network_flow", tout << "Found optimal solution.\n";); + SASSERT(check_optimal()); return true; } // Get the optimal solution template typename network_flow::numeral network_flow::get_optimal_solution(vector & result, bool is_dual) { - m_objective_value = numeral::zero(); + numeral objective_value = numeral::zero(); vector const & es = m_graph.get_all_edges(); for (unsigned i = 0; i < es.size(); ++i) { edge const & e = es[i]; - if (m_states[i] == BASIS) { - m_objective_value += e.get_weight().get_rational() * m_flows[i]; + if (m_states[i] == BASIS) + { + objective_value += e.get_weight().get_rational() * m_flows[i]; } } result.reset(); @@ -287,7 +290,7 @@ namespace smt { else { result.append(m_flows); } - return m_objective_value; + return objective_value; } template @@ -297,7 +300,7 @@ namespace smt { template bool network_flow::edge_in_tree(node src, node dst) const { - return edge_in_tree(get_edge_id(src,dst)); + return edge_in_tree(get_edge_id(src, dst)); } @@ -310,7 +313,6 @@ namespace smt { SASSERT(m_states[i] == BASIS || m_flows[i].is_zero()); } - // m_upwards show correct direction for (unsigned i = 0; i < m_potentials.size(); ++i) { node p = tree.get_parent(i); @@ -322,7 +324,31 @@ namespace smt { } template - std::string network_flow:: display_spanning_tree() { + bool network_flow::check_optimal() { + numeral total_cost = numeral::zero(); + vector const & es = m_graph.get_all_edges(); + for (unsigned i = 0; i < es.size(); ++i) { + edge const & e = es[i]; + if (m_states[i] == BASIS) + { + total_cost += e.get_weight().get_rational() * m_flows[i]; + } + } + + // m_flows are zero on non-basic edges + for (unsigned i = 0; i < m_flows.size(); ++i) { + SASSERT(m_states[i] == BASIS || m_flows[i].is_zero()); + } + numeral total_balance = numeral::zero(); + for (unsigned i = 0; i < m_potentials.size(); ++i) { + total_balance += m_balances[i] * m_potentials[i]; + } + std::cout << "Total balance: " << total_balance << ", total cost: " << total_cost << std::endl; + return total_cost == total_balance; + } + + template + std::string network_flow::display_spanning_tree() { ++m_step;; std::ostringstream oss; std::string prefix = "T"; From bc9bfe7f97060a971eec2b49f599650449d9af0f Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Thu, 7 Nov 2013 07:33:25 +0100 Subject: [PATCH 093/925] Use templates on spanning trees --- src/smt/network_flow.h | 4 +- src/smt/network_flow_def.h | 3 +- src/smt/spanning_tree.h | 15 +++-- src/smt/spanning_tree_base.h | 28 ++++----- ...{spanning_tree.cpp => spanning_tree_def.h} | 59 +++++++++++-------- 5 files changed, 64 insertions(+), 45 deletions(-) rename src/smt/{spanning_tree.cpp => spanning_tree_def.h} (85%) diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index 3303e2618..2d40edbd2 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -32,7 +32,7 @@ Notes: #include"inf_rational.h" #include"diff_logic.h" -#include"spanning_tree.h" +#include"spanning_tree_def.h" namespace smt { @@ -51,7 +51,7 @@ namespace smt { typedef typename Ext::fin_numeral fin_numeral; graph m_graph; - thread_spanning_tree tree; + thread_spanning_tree tree; // Denote supply/demand b_i on node i vector m_balances; diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index d576e3704..f697acaac 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -47,7 +47,7 @@ namespace smt { m_balances.resize(num_nodes); m_potentials.resize(num_nodes); - tree = thread_spanning_tree(); + tree = thread_spanning_tree(); m_step = 0; } @@ -302,7 +302,6 @@ namespace smt { bool network_flow::edge_in_tree(node src, node dst) const { return edge_in_tree(get_edge_id(src, dst)); } - template bool network_flow::check_well_formed() { diff --git a/src/smt/spanning_tree.h b/src/smt/spanning_tree.h index 6769a6a18..41264245e 100644 --- a/src/smt/spanning_tree.h +++ b/src/smt/spanning_tree.h @@ -19,13 +19,20 @@ Notes: #ifndef _SPANNING_TREE_H_ #define _SPANNING_TREE_H_ +#include "diff_logic.h" #include "spanning_tree_base.h" namespace smt { - - class thread_spanning_tree : virtual public spanning_tree_base { + template + class thread_spanning_tree : public spanning_tree_base, private Ext { private: + typedef dl_var node; + typedef dl_edge edge; + typedef dl_graph graph; + typedef typename Ext::numeral numeral; + typedef typename Ext::fin_numeral fin_numeral; + // Store the parent of a node i in the spanning tree svector m_pred; // Store the number of edge on the path from node i to the root @@ -47,8 +54,8 @@ namespace smt { public: void initialize(svector const & upwards, int num_nodes); - void get_descendants(node start, svector& descendants); - void get_ancestors(node start, svector& ancestors); + void get_descendants(node start, svector & descendants); + void get_ancestors(node start, svector & ancestors); node get_common_ancestor(node u, node v); void update(node p, node q, node u, node v); bool check_well_formed(); diff --git a/src/smt/spanning_tree_base.h b/src/smt/spanning_tree_base.h index 6be090711..065a4b042 100644 --- a/src/smt/spanning_tree_base.h +++ b/src/smt/spanning_tree_base.h @@ -24,8 +24,6 @@ Notes: #include "vector.h" namespace smt { - typedef int node; - template inline std::string pp_vector(std::string const & label, TV v, bool has_header = false) { std::ostringstream oss; @@ -44,27 +42,29 @@ namespace smt { return oss.str(); } - class spanning_tree_base { - public: - spanning_tree_base() {}; - virtual ~spanning_tree_base() {}; + class spanning_tree_base { + private: + typedef int node; + + public: + virtual void initialize(svector const & upwards, int num_nodes) {}; - virtual void initialize(svector const & upwards, int num_nodes) = 0; /** \brief Get all descendants of a node including itself */ - virtual void get_descendants(node start, svector& descendants) = 0; + virtual void get_descendants(node start, svector & descendants) {}; /** \brief Get all ancestors of a node including itself */ - virtual void get_ancestors(node start, svector& ancestors) = 0; - virtual node get_common_ancestor(node u, node v) = 0; - virtual void update(node p, node q, node u, node v) = 0; - virtual bool check_well_formed() = 0; + virtual void get_ancestors(node start, svector & ancestors) {}; + + virtual node get_common_ancestor(node u, node v) {UNREACHABLE(); return -1;}; + virtual void update(node p, node q, node u, node v) {}; + virtual bool check_well_formed() {UNREACHABLE(); return false;}; // TODO: remove these two unnatural functions - virtual bool get_arc_direction(node start) const = 0; - virtual node get_parent(node start) = 0; + virtual bool get_arc_direction(node start) const {UNREACHABLE(); return false;}; + virtual node get_parent(node start) {UNREACHABLE(); return -1;}; }; } diff --git a/src/smt/spanning_tree.cpp b/src/smt/spanning_tree_def.h similarity index 85% rename from src/smt/spanning_tree.cpp rename to src/smt/spanning_tree_def.h index 21c3fcfb4..aac40e1b7 100644 --- a/src/smt/spanning_tree.cpp +++ b/src/smt/spanning_tree_def.h @@ -3,7 +3,7 @@ Copyright (c) 2013 Microsoft Corporation Module Name: - spanning_tree.cpp + spanning_tree_def.h Abstract: @@ -15,16 +15,13 @@ Author: Notes: --*/ -#include + +#ifndef _SPANNING_TREE_DEF_H_ +#define _SPANNING_TREE_DEF_H_ + #include "spanning_tree.h" -#include "debug.h" -#include "vector.h" -#include "uint_set.h" -#include "trace.h" namespace smt { - - /** swap v and q in tree. - fixup m_thread @@ -41,7 +38,8 @@ namespace smt { New thread: prev -> q -*-> final(q) -> v -*-> alpha -> beta -*-> final(v) -> next */ - void thread_spanning_tree::swap_order(node q, node v) { + template + void thread_spanning_tree::swap_order(node q, node v) { SASSERT(q != v); SASSERT(m_pred[q] == v); SASSERT(is_preorder_traversal(v, get_final(v))); @@ -68,7 +66,8 @@ namespace smt { /** \brief find node that points to 'n' in m_thread */ - node thread_spanning_tree::find_rev_thread(node n) const { + template + typename thread_spanning_tree::node thread_spanning_tree::find_rev_thread(node n) const { node ancestor = m_pred[n]; SASSERT(ancestor != -1); while (m_thread[ancestor] != n) { @@ -77,7 +76,8 @@ namespace smt { return ancestor; } - void thread_spanning_tree::fix_depth(node start, node end) { + template + void thread_spanning_tree::fix_depth(node start, node end) { SASSERT(m_pred[start] != -1); m_depth[start] = m_depth[m_pred[start]]+1; while (start != end) { @@ -86,7 +86,8 @@ namespace smt { } } - node thread_spanning_tree::get_final(int start) { + template + typename thread_spanning_tree::node thread_spanning_tree::get_final(int start) { int n = start; while (m_depth[m_thread[n]] > m_depth[start]) { n = m_thread[n]; @@ -94,7 +95,8 @@ namespace smt { return n; } - bool thread_spanning_tree::is_preorder_traversal(node start, node end) { + template + bool thread_spanning_tree::is_preorder_traversal(node start, node end) { // get children of start uint_set children; children.insert(start); @@ -118,7 +120,8 @@ namespace smt { return true; } - bool thread_spanning_tree::is_ancestor_of(node ancestor, node child) { + template + bool thread_spanning_tree::is_ancestor_of(node ancestor, node child) { for (node n = child; n != -1; n = m_pred[n]) { if (n == ancestor) { return true; @@ -154,7 +157,8 @@ namespace smt { roots[y] = x; } - void thread_spanning_tree::initialize(svector const & upwards, int num_nodes) { + template + void thread_spanning_tree::initialize(svector const & upwards, int num_nodes) { m_pred.resize(num_nodes + 1); m_depth.resize(num_nodes + 1); m_thread.resize(num_nodes + 1); @@ -179,7 +183,8 @@ namespace smt { }); } - node thread_spanning_tree::get_common_ancestor(node u, node v) { + template + typename thread_spanning_tree::node thread_spanning_tree::get_common_ancestor(node u, node v) { while (u != v) { if (m_depth[u] > m_depth[v]) u = m_pred[u]; @@ -189,7 +194,8 @@ namespace smt { return u; } - void thread_spanning_tree::get_descendants(node start, svector& descendants) { + template + void thread_spanning_tree::get_descendants(node start, svector& descendants) { descendants.reset(); node u = start; while (m_depth[m_thread[u]] > m_depth[start]) { @@ -198,7 +204,8 @@ namespace smt { } } - void thread_spanning_tree::get_ancestors(node start, svector& ancestors) { + template + void thread_spanning_tree::get_ancestors(node start, svector& ancestors) { ancestors.reset(); while (m_pred[start] != -1) { ancestors.push_back(start); @@ -222,7 +229,8 @@ namespace smt { \ \ / q q */ - void thread_spanning_tree::update(node p, node q, node u, node v) { + template + void thread_spanning_tree::update(node p, node q, node u, node v) { bool q_upwards = false; // v is parent of u so T_u does not contain root node @@ -299,7 +307,8 @@ namespace smt { m_upwards direction of edge from i to m_pred[i] m_graph */ - bool thread_spanning_tree::check_well_formed() { + template + bool thread_spanning_tree::check_well_formed() { node root = m_pred.size()-1; // Check that m_thread traverses each node. @@ -346,11 +355,15 @@ namespace smt { return true; } - bool thread_spanning_tree::get_arc_direction(node start) const { + template + bool thread_spanning_tree::get_arc_direction(node start) const { return m_upwards[start]; } - node thread_spanning_tree::get_parent(node start) { + template + typename thread_spanning_tree::node thread_spanning_tree::get_parent(node start) { return m_pred[start]; } -} \ No newline at end of file +} + +#endif \ No newline at end of file From 3ee8c3efb5923795afa672ae3225ebbe89eb8c42 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Nov 2013 00:53:08 -0800 Subject: [PATCH 094/925] pb/car constraints Signed-off-by: Nikolaj Bjorner --- src/smt/theory_card.cpp | 553 ++++++++++++++------------- src/smt/theory_card.h | 29 +- src/tactic/arith/lia2card_tactic.cpp | 50 ++- src/test/main.cpp | 1 + src/test/sorting_network.cpp | 60 +++ src/util/sorting_network.h | 99 +++++ 6 files changed, 494 insertions(+), 298 deletions(-) create mode 100644 src/test/sorting_network.cpp create mode 100644 src/util/sorting_network.h diff --git a/src/smt/theory_card.cpp b/src/smt/theory_card.cpp index edae63108..080cbf55e 100644 --- a/src/smt/theory_card.cpp +++ b/src/smt/theory_card.cpp @@ -97,25 +97,9 @@ namespace smt { ctx.mk_th_axiom(get_id(), 1, &lit); ctx.mark_as_relevant(tmp); } - c->m_args.push_back(bv); - if (0 < k) { - add_watch(bv, c); - } - } - if (0 < k) { - add_card(c); - } - else { - // bv <=> (and (not bv1) ... (not bv_n)) - literal_vector& lits = get_lits(); - lits.push_back(literal(abv)); - for (unsigned i = 0; i < c->m_args.size(); ++i) { - ctx.mk_th_axiom(get_id(), ~literal(abv), ~literal(c->m_args[i])); - lits.push_back(literal(c->m_args[i])); - } - ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); - dealloc(c); + c->m_args.push_back(std::make_pair(bv,1)); } + add_card(c); return true; } @@ -128,6 +112,49 @@ namespace smt { cards->push_back(c); m_watch_trail.push_back(bv); } + + void theory_card::add_card(card* c) { + bool_var abv = c->m_bv; + arg_t& args = c->m_args; + + // sort and coalesce arguments: + std::sort(args.begin(), args.end()); + for (unsigned i = 0; i + 1 < args.size(); ++i) { + if (args[i].first == args[i+1].first) { + args[i].second += args[i+1].second; + for (unsigned j = i+1; j + 1 < args.size(); ++j) { + args[j] = args[j+1]; + } + args.resize(args.size()-1); + } + if (args[i].second == 0) { + for (unsigned j = i; j + 1 < args.size(); ++j) { + args[j] = args[j+1]; + } + args.resize(args.size()-1); + } + } + + int min = 0, max = 0; + for (unsigned i = 0; i < args.size(); ++i) { + // update min and max: + int inc = args[i].second; + if (inc > 0) { + max += inc; + } + else { + SASSERT(inc < 0); + min += inc; + } + // add watch literals: + add_watch(args[i].first, c); + } + c->m_current_min = c->m_abs_min = min; + c->m_current_max = c->m_abs_max = max; + m_cards.insert(abv, c); + m_cards_trail.push_back(abv); + } + void theory_card::reset_eh() { @@ -149,6 +176,172 @@ namespace smt { m_watch_lim.reset(); } + void theory_card::update_min_max(bool_var v, bool is_true, card* c) { + context& ctx = get_context(); + ast_manager& m = get_manager(); + arg_t const& args = c->m_args; + int inc = find_inc(v, args); + int& min = c->m_current_min; + int& max = c->m_current_max; + int k = c->m_k; + // inc > 0 & is_true -> min += inc + // inc < 0 & is_true -> max += inc + // inc > 0 & !is_true -> max -= inc + // inc < 0 & !is_true -> min -= inc + + if (inc > 0 && is_true) { + ctx.push_trail(value_trail(min)); + min += inc; + } + else if (inc < 0 && is_true) { + ctx.push_trail(value_trail(max)); + max += inc; + } + else if (inc > 0 && !is_true) { + ctx.push_trail(value_trail(max)); + max -= inc; + } + else { + ctx.push_trail(value_trail(min)); + min -= inc; + } + // invariant min <= max + SASSERT(min <= max); + } + + void theory_card::assign_use(bool_var v, bool is_true, card* c) { + update_min_max(v, is_true, c); + propagate_assignment(c); + } + + lbool theory_card::inc_min(int inc, lbool val) { + if (inc > 0) { + return val; + } + else if (inc < 0) { + return ~val; + } + else { + return l_undef; + } + } + + lbool theory_card::dec_max(int inc, lbool val) { + if (inc > 0) { + return ~val; + } + else if (inc < 0) { + return val; + } + else { + return l_undef; + } + } + + int theory_card::accumulate_min(literal_vector& lits, card* c) { + context& ctx = get_context(); + int k = c->m_k; + arg_t const& args = c->m_args; + int curr_min = c->m_abs_min; + for (unsigned i = 0; i < args.size() && curr_min <= k; ++i) { + bool_var bv = args[i].first; + int inc = args[i].second; + lbool val = ctx.get_assignment(bv); + if (inc_min(inc, val) == l_true) { + curr_min += abs(inc); + lits.push_back(literal(bv, val != l_true)); + } + } + return curr_min; + } + + int theory_card::accumulate_max(literal_vector& lits, card* c) { + context& ctx = get_context(); + arg_t const& args = c->m_args; + int k = c->m_k; + int curr_max = c->m_abs_max; + for (unsigned i = 0; i < args.size() && k < curr_max; ++i) { + bool_var bv = args[i].first; + int inc = args[i].second; + lbool val = ctx.get_assignment(bv); + if (dec_max(inc, val) == l_true) { + curr_max -= abs(inc); + lits.push_back(literal(bv, val == l_true)); + } + } + return curr_max; + } + + void theory_card::propagate_assignment(card* c) { + context& ctx = get_context(); + arg_t const& args = c->m_args; + bool_var abv = c->m_bv; + int min = c->m_current_min; + int max = c->m_current_max; + int k = c->m_k; + + // + // if min > k && abv != l_false -> force abv false + // if max <= k && abv != l_true -> force abv true + // if min == k && abv == l_true -> force positive unassigned literals false + // if max == k + 1 && abv == l_false -> force negative unassigned literals false + // + lbool aval = ctx.get_assignment(abv); + if (min > k && aval != l_false) { + literal_vector& lits = get_lits(); + lits.push_back(~literal(abv)); + int curr_min = accumulate_min(lits, c); + SASSERT(curr_min > k); + add_clause(lits); + } + else if (max <= k && aval != l_true) { + literal_vector& lits = get_lits(); + lits.push_back(literal(abv)); + int curr_max = accumulate_max(lits, c); + SASSERT(curr_max <= k); + add_clause(lits); + } + else if (min == k && aval == l_true) { + literal_vector& lits = get_lits(); + lits.push_back(~literal(abv)); + int curr_min = accumulate_min(lits, c); + if (curr_min > k) { + add_clause(lits); + } + else { + SASSERT(curr_min == k); + for (unsigned i = 0; i < args.size(); ++i) { + bool_var bv = args[i].first; + int inc = args[i].second; + if (inc_min(inc, ctx.get_assignment(bv)) == l_undef) { + lits.push_back(literal(bv, inc > 0)); // avoid incrementing min. + add_clause(lits); + lits.pop_back(); + } + } + } + } + else if (max == k + 1 && aval == l_false) { + literal_vector& lits = get_lits(); + lits.push_back(literal(abv)); + int curr_max = accumulate_max(lits, c); + if (curr_max <= k) { + add_clause(lits); + } + else if (curr_max == k + 1) { + for (unsigned i = 0; i < args.size(); ++i) { + bool_var bv = args[i].first; + int inc = args[i].second; + if (dec_max(inc, ctx.get_assignment(bv)) == l_undef) { + lits.push_back(literal(bv, inc < 0)); // avoid decrementing max. + add_clause(lits); + lits.pop_back(); + } + } + } + } + } + void theory_card::assign_eh(bool_var v, bool is_true) { context& ctx = get_context(); ast_manager& m = get_manager(); @@ -158,125 +351,33 @@ namespace smt { if (m_watch.find(v, cards)) { for (unsigned i = 0; i < cards->size(); ++i) { - c = (*cards)[i]; - svector const& args = c->m_args; - // - // is_true && m_t + 1 > k -> force false - // !is_true && m_f + 1 >= arity - k -> force true - // - if (is_true && c->m_t >= c->m_k) { - unsigned k = c->m_k; - // force false - switch (ctx.get_assignment(c->m_bv)) { - case l_true: - case l_undef: { - literal_vector& lits = get_lits(); - lits.push_back(~literal(c->m_bv)); - for (unsigned i = 0; i < args.size() && lits.size() < k + 1; ++i) { - if (ctx.get_assignment(args[i]) == l_true) { - lits.push_back(~literal(args[i])); - } - } - SASSERT(lits.size() == k + 1); - add_clause(lits); - break; - } - default: - break; - } - } - else if (!is_true && c->m_k >= args.size() - c->m_f - 1) { - // forced true - switch (ctx.get_assignment(c->m_bv)) { - case l_false: - case l_undef: { - unsigned deficit = args.size() - c->m_k; - literal_vector& lits = get_lits(); - lits.push_back(literal(c->m_bv)); - for (unsigned i = 0; i < args.size() && lits.size() <= deficit; ++i) { - if (ctx.get_assignment(args[i]) == l_false) { - lits.push_back(literal(args[i])); - } - } - add_clause(lits); - break; - } - default: - break; - } - } - else if (is_true) { - ctx.push_trail(value_trail(c->m_t)); - c->m_t++; - } - else { - ctx.push_trail(value_trail(c->m_f)); - c->m_f++; - } + assign_use(v, is_true, (*cards)[i]); } } if (m_cards.find(v, c)) { - svector const& args = c->m_args; - SASSERT(args.size() >= c->m_f + c->m_t); - bool_var bv; + propagate_assignment(c); + } + } - TRACE("card", tout << " t:" << is_true << " k:" << c->m_k << " t:" << c->m_t << " f:" << c->m_f << "\n";); - - // at most k - // propagate false to children that are not yet assigned. - // v & t1 & ... & tk => ~l_j - if (is_true && c->m_k <= c->m_t) { - - literal_vector& lits = get_lits(); - lits.push_back(literal(v)); - bool done = false; - for (unsigned i = 0; !done && i < args.size(); ++i) { - bv = args[i]; - if (ctx.get_assignment(bv) == l_true) { - lits.push_back(literal(bv)); - } - if (lits.size() > c->m_k + 1) { - add_clause(lits); - done = true; - } - } - SASSERT(done || lits.size() == c->m_k + 1); - for (unsigned i = 0; !done && i < args.size(); ++i) { - bv = args[i]; - if (ctx.get_assignment(bv) == l_undef) { - lits.push_back(literal(bv)); - add_clause(lits); - lits.pop_back(); - } - } + int theory_card::find_inc(bool_var bv, svector >const& vars) { + unsigned mid = vars.size()/2; + unsigned lo = 0; + unsigned hi = vars.size()-1; + while (lo < hi) { + if (vars[mid].first == bv) { + return vars[mid].second; } - // at least k+1: - // !v & !f1 & .. & !f_m => l_j - // for m + k + 1 = arity() - if (!is_true && args.size() <= 1 + c->m_f + c->m_k) { - literal_vector& lits = get_lits(); - lits.push_back(literal(v)); - bool done = false; - for (unsigned i = 0; !done && i < args.size(); ++i) { - bv = args[i]; - if (ctx.get_assignment(bv) == l_false) { - lits.push_back(literal(bv)); - } - if (lits.size() > c->m_k + 1) { - add_clause(lits); - done = true; - } - } - for (unsigned i = 0; !done && i < args.size(); ++i) { - bv = args[i]; - if (ctx.get_assignment(bv) != l_false) { - lits.push_back(~literal(bv)); - add_clause(lits); - lits.pop_back(); - } - } + else if (vars[mid].first < bv) { + lo = mid; + mid += (hi-mid)/2; + } + else { + hi = mid; + mid = (mid-lo)/2 + lo; } } + SASSERT(vars[mid].first == bv); + return vars[mid].second; } void theory_card::init_search_eh() { @@ -319,151 +420,79 @@ namespace smt { ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); } + +#if 1 + + +#endif + } + + #if 0 -class sorting_network { - ast_manager& m; - expr_ref_vector m_es; - expr_ref_vector* m_current; - expr_ref_vector* m_next; - - void exchange(unsigned i, unsigned j, expr_ref_vector& es) { - SASSERT(i <= j); - if (i == j) { - return; - } - expr* ei = es[i].get(); - expr* ej = es[j].get(); - es[i] = m.mk_ite(mk_le(ei,ej), ei, ej); - es[j] = m.mk_ite(mk_le(ej,ei), ei, ej); - } - - void sort(unsigned k) { - if (k == 2) { - for (unsigned i = 0; i < m_es.size()/2; ++i) { - exchange(current(2*i), current(2*i+1), m_es); - next(2*i) = current(2*i); - next(2*i+1) = current(2*i+1); + expr_ref_vector merge(expr_ref_vector const& l1, expr_ref_vector const& l2) { + if (l1.empty()) { + return l2; } - std::swap(m_current, m_next); - } - else { - - for (unsigned i = 0; i < m_es.size()/k; ++i) { - for (unsigned j = 0; j < k / 2; ++j) { - next((k * i) + j) = current((k * i) + (2 * j)); - next((k * i) + (k / 2) + j) = current((k * i) + (2 * j) + 1); - } + if (l2.empty()) { + return l1; } - - std::swap(m_current, m_next); - sort(k / 2); - for (unsigned i = 0; i < m_es.size() / k; ++i) { - for (unsigned j = 0; j < k / 2; ++j) { - next((k * i) + (2 * j)) = current((k * i) + j); - next((k * i) + (2 * j) + 1) = current((k * i) + (k / 2) + j); - } - - for (unsigned j = 0; j < (k / 2) - 1; ++j) { - exchange(next((k * i) + (2 * j) + 1), next((k * i) + (2 * (j + 1)))); - } + expr_ref_vector result(m); + if (l1.size() == 1 && l2.size() == 1) { + result.push_back(l1[0]); + result.push_back(l2[0]); + exchange(0, 1, result); + return result; } - std::swap(m_current, m_next); - } - } - - expr_ref_vector merge(expr_ref_vector const& l1, expr_ref_vector& l2) { - if (l1.empty()) { - return l2; - } - if (l2.empty()) { - return l1; - } - expr_ref_vector result(m); - if (l1.size() == 1 && l2.size() == 1) { - result.push_back(l1[0]); - result.push_back(l2[0]); - exchange(0, 1, result); - return result; - } - unsigned l1o = l1.size()/2; - unsigned l2o = l2.size()/2; - unsigned l1e = (l1.size() % 2 == 1) ? l1o + 1 : l1o; - unsigned l2e = (l2.size() % 2 == 1) ? l2o + 1 : l2o; - expr_ref_vector evenl1(m, l1e); - expr_ref_vector oddl1(m, l1o); - expr_ref_vector evenl2(m, l2e); - expr_ref_vector oddl2(m, l2o); - for (unsigned i = 0; i < l1.size(); ++i) { - if (i % 2 == 0) { - evenl1[i/2] = l1[i]; - } - else { - oddl1[i/2] = l1[i]; - } - } - for (unsigned i = 0; i < l2.size(); ++i) { - if (i % 2 == 0) { - evenl2[i/2] = l2[i]; - } - else { - oddl2[i/2] = l2[i]; - } - } - expr_ref_vector even = merge(evenl1, evenl2); - expr_ref_vector odd = merge(oddl1, oddl2); - - result.resize(l1.size() + l2.size()); - for (unsigned i = 0; i < result.size(); ++i) { - if (i % 2 == 0) { - result[i] = even[i/2].get(); - if (i > 0) { - exchange(i - 1, i, result); - } - } - else { - if (i /2 < odd.size()) { - result[i] = odd[i/2].get(); + unsigned l1o = l1.size()/2; + unsigned l2o = l2.size()/2; + unsigned l1e = (l1.size() % 2 == 1) ? l1o + 1 : l1o; + unsigned l2e = (l2.size() % 2 == 1) ? l2o + 1 : l2o; + expr_ref_vector evenl1(m), oddl1(m), evenl2(m), oddl2(m); + evenl1.resize(l1e); + oddl1.resize(l1o); + evenl2.resize(l2e); + oddl2.resize(l2o); + for (unsigned i = 0; i < l1.size(); ++i) { + if (i % 2 == 0) { + evenl1[i/2] = l1[i]; } else { - result[i] = even[(i/2)+1].get(); + oddl1[i/2] = l1[i]; } } - } - return result; - } + for (unsigned i = 0; i < l2.size(); ++i) { + if (i % 2 == 0) { + evenl2[i/2] = l2[i]; + } + else { + oddl2[i/2] = l2[i]; + } + } + expr_ref_vector even = merge(evenl1, evenl2); + expr_ref_vector odd = merge(oddl1, oddl2); -public: - sorting_network(ast_manager& m): - m(m), - m_es(m), - m_current(0), - m_next(0) - {} - - expr_ref_vector operator()(expr_ref_vector const& inputs) { - if (inputs.size() <= 1) { - return inputs; + result.resize(l1.size() + l2.size()); + for (unsigned i = 0; i < result.size(); ++i) { + if (i % 2 == 0) { + result[i] = even[i/2].get(); + if (i > 0) { + exchange(i - 1, i, result); + } + } + else { + if (i /2 < odd.size()) { + result[i] = odd[i/2].get(); + } + else { + result[i] = even[(i/2)+1].get(); + } + } + } + return result; } - m_es.reset(); - m_es.append(inputs); - while (!is_power_of2(m_es.size())) { - m_es.push_back(m.mk_false()); - } - m_es.reverse(); - for (unsigned i = 0; i < m_es.size(); ++i) { - current(i) = i; - } - unsigned k = 2; - while (k <= m_es.size()) { - sort(k); - // TBD - k *= 2; - } - } -}; Sorting networks used in Formula: diff --git a/src/smt/theory_card.h b/src/smt/theory_card.h index ca1d5a061..c53e38e37 100644 --- a/src/smt/theory_card.h +++ b/src/smt/theory_card.h @@ -25,14 +25,19 @@ Notes: namespace smt { class theory_card : public theory { + + typedef svector > arg_t; + struct card { - unsigned m_k; + int m_k; bool_var m_bv; - unsigned m_t; - unsigned m_f; - svector m_args; + int m_current_min; + int m_current_max; + int m_abs_min; + int m_abs_max; + arg_t m_args; card(bool_var bv, unsigned k): - m_k(k), m_bv(bv), m_t(0), m_f(0) + m_k(k), m_bv(bv) {} }; @@ -46,13 +51,19 @@ namespace smt { card_util m_util; void add_watch(bool_var bv, card* c); + void add_card(card* c); - void add_card(card* c) { - m_cards.insert(c->m_bv, c); - m_cards_trail.push_back(c->m_bv); - } void add_clause(literal_vector const& lits); literal_vector& get_lits(); + + int find_inc(bool_var bv, svector >const& vars); + void theory_card::propagate_assignment(card* c); + int theory_card::accumulate_max(literal_vector& lits, card* c); + int theory_card::accumulate_min(literal_vector& lits, card* c); + lbool theory_card::dec_max(int inc, lbool val); + lbool theory_card::inc_min(int inc, lbool val); + void theory_card::assign_use(bool_var v, bool is_true, card* c); + void theory_card::update_min_max(bool_var v, bool is_true, card* c); public: theory_card(ast_manager& m); diff --git a/src/tactic/arith/lia2card_tactic.cpp b/src/tactic/arith/lia2card_tactic.cpp index 7d257d86e..d2be433c6 100644 --- a/src/tactic/arith/lia2card_tactic.cpp +++ b/src/tactic/arith/lia2card_tactic.cpp @@ -175,54 +175,48 @@ class lia2card_tactic : public tactic { if (a.is_le(fml, x, y) || a.is_ge(fml, y, x)) { if (is_01var(x) && a.is_numeral(y, n)) { sub.insert(fml, mk_le(x, n)); - return; } - if (is_01var(y) && a.is_numeral(x, n)) { + else if (is_01var(y) && a.is_numeral(x, n)) { sub.insert(fml, mk_ge(y, n)); - return; } - if (is_add(x, args) && is_unsigned(y, k)) { // x <= k + else if (is_add(x, args) && is_unsigned(y, k)) { // x <= k sub.insert(fml, m_card.mk_at_most_k(args.size(), args.c_ptr(), k)); - return; } - if (is_add(y, args) && is_unsigned(x, k)) { // k <= y <=> not (y <= k-1) + else if (is_add(y, args) && is_unsigned(x, k)) { // k <= y <=> not (y <= k-1) if (k == 0) sub.insert(fml, m.mk_true()); else sub.insert(fml, m.mk_not(m_card.mk_at_most_k(args.size(), args.c_ptr(), k-1))); - return; } - UNREACHABLE(); + else { + UNREACHABLE(); + } } - - if (a.is_lt(fml, x, y) || a.is_gt(fml, y, x)) { + else if (a.is_lt(fml, x, y) || a.is_gt(fml, y, x)) { if (is_01var(x) && a.is_numeral(y, n)) { sub.insert(fml, mk_le(x, n-rational(1))); - return; } - if (is_01var(y) && a.is_numeral(x, n)) { + else if (is_01var(y) && a.is_numeral(x, n)) { sub.insert(fml, mk_ge(y, n+rational(1))); - return; } - if (is_add(x, args) && is_unsigned(y, k)) { // x < k + else if (is_add(x, args) && is_unsigned(y, k)) { // x < k if (k == 0) sub.insert(fml, m.mk_false()); else sub.insert(fml, m_card.mk_at_most_k(args.size(), args.c_ptr(), k-1)); - return; - } - - if (is_add(y, args) && is_unsigned(x, k)) { // k < y <=> not (y <= k) + } + else if (is_add(y, args) && is_unsigned(x, k)) { // k < y <=> not (y <= k) sub.insert(fml, m.mk_not(m_card.mk_at_most_k(args.size(), args.c_ptr(), k))); - return; } - UNREACHABLE(); + else { + UNREACHABLE(); + } } - if (m.is_eq(fml, x, y)) { + else if (m.is_eq(fml, x, y)) { if (!is_01var(x)) { std::swap(x, y); } - if (is_01var(x) && a.is_numeral(y, n)) { + else if (is_01var(x) && a.is_numeral(y, n)) { if (n.is_one()) { sub.insert(fml, mk_01(x)); } @@ -232,19 +226,21 @@ class lia2card_tactic : public tactic { else { sub.insert(fml, m.mk_false()); } - return; } - UNREACHABLE(); + else { + UNREACHABLE(); + } } - if (is_sum(fml)) { + else if (is_sum(fml)) { SASSERT(m_uses.contains(fml)); ptr_vector const& u = m_uses.find(fml); for (unsigned i = 0; i < u.size(); ++i) { convert_01(sub, u[i]); } - return; } - UNREACHABLE(); + else { + UNREACHABLE(); + } } expr_ref mk_01(expr* x) { diff --git a/src/test/main.cpp b/src/test/main.cpp index bc7e04124..94c4feb65 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -216,6 +216,7 @@ int main(int argc, char ** argv) { TST(polynorm); TST(qe_arith); TST(expr_substitution); + TST(sorting_network); } void initialize_mam() {} diff --git a/src/test/sorting_network.cpp b/src/test/sorting_network.cpp new file mode 100644 index 000000000..904bbb970 --- /dev/null +++ b/src/test/sorting_network.cpp @@ -0,0 +1,60 @@ + +#include "sorting_network.h" +#include "vector.h" +#include "ast.h" + +struct ast_ext { + ast_manager& m; + ast_ext(ast_manager& m):m(m) {} + typedef expr* T; + typedef expr_ref_vector vector; + T mk_ite(T a, T b, T c) { + return m.mk_ite(a, b, c); + } + T mk_le(T a, T b) { + if (m.is_bool(a)) { + return m.mk_implies(a, b); + } + UNREACHABLE(); + return 0; + } + T mk_default() { + return m.mk_false(); + } +}; + +struct unsigned_ext { + unsigned_ext() {} + typedef unsigned T; + typedef svector vector; + T mk_ite(T a, T b, T c) { + return (a==1)?b:c; + } + T mk_le(T a, T b) { + return (a <= b)?1:0; + } + T mk_default() { + return 0; + } +}; + +void tst_sorting_network() { + svector vec; + unsigned_ext uext; + sorting_network sn(uext, vec); + + svector in1; + in1.push_back(0); + in1.push_back(1); + in1.push_back(0); + in1.push_back(1); + in1.push_back(1); + in1.push_back(0); + + sn(in1); + + for (unsigned i = 0; i < vec.size(); ++i) { + std::cout << vec[i]; + } + std::cout << "\n"; +} diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h new file mode 100644 index 000000000..d823cf44c --- /dev/null +++ b/src/util/sorting_network.h @@ -0,0 +1,99 @@ + +#include "vector.h" + +#ifndef _SORTING_NETWORK_H_ +#define _SORTING_NETWORK_H_ + + + template + class sorting_network { + typename Ext::vector& m_es; + Ext& m_ext; + svector m_currentv; + svector m_nextv; + svector* m_current; + svector* m_next; + + unsigned& current(unsigned i) { return (*m_current)[i]; } + unsigned& next(unsigned i) { return (*m_next)[i]; } + + void exchange(unsigned i, unsigned j) { + SASSERT(i <= j); + if (i < j) { + Ext::T ei = m_es.get(i); + Ext::T ej = m_es.get(j); + m_es.set(i, m_ext.mk_ite(m_ext.mk_le(ei, ej), ei, ej)); + m_es.set(j, m_ext.mk_ite(m_ext.mk_le(ej, ei), ei, ej)); + } + } + + void sort(unsigned k) { + SASSERT(is_power_of2(k) && k > 0); + if (k == 2) { + for (unsigned i = 0; i < m_es.size()/2; ++i) { + exchange(current(2*i), current(2*i+1)); + next(2*i) = current(2*i); + next(2*i+1) = current(2*i+1); + } + std::swap(m_current, m_next); + } + else { + + for (unsigned i = 0; i < m_es.size()/k; ++i) { + unsigned ki = k * i; + for (unsigned j = 0; j < k / 2; ++j) { + next(ki + j) = current(ki + (2 * j)); + next(ki + (k / 2) + j) = current(ki + (2 * j) + 1); + } + } + + std::swap(m_current, m_next); + sort(k / 2); + for (unsigned i = 0; i < m_es.size() / k; ++i) { + unsigned ki = k * i; + for (unsigned j = 0; j < k / 2; ++j) { + next(ki + (2 * j)) = current(ki + j); + next(ki + (2 * j) + 1) = current(ki + (k / 2) + j); + } + + for (unsigned j = 0; j < (k / 2) - 1; ++j) { + exchange(next(ki + (2 * j) + 1), next(ki + (2 * (j + 1)))); + } + } + std::swap(m_current, m_next); + } + } + + bool is_power_of2(unsigned n) const { + return n != 0 && ((n-1) & n) == 0; + } + + public: + sorting_network(Ext& ext, typename Ext::vector& es): + m_ext(ext), + m_es(es), + m_current(&m_currentv), + m_next(&m_nextv) + {} + + void operator()(typename Ext::vector const& inputs) { + if (inputs.size() <= 1) { + return; + } + m_es.reset(); + m_es.append(inputs); + while (!is_power_of2(m_es.size())) { + m_es.push_back(m_ext.mk_default()); + } + for (unsigned i = 0; i < m_es.size(); ++i) { + current(i) = i; + } + unsigned k = 2; + while (k <= m_es.size()) { + sort(k); + k *= 2; + } + } + }; + +#endif From 220b339e5e87b139cfc9d82d043cdd708482f926 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Nov 2013 01:30:19 -0800 Subject: [PATCH 095/925] add cutting plane Signed-off-by: Nikolaj Bjorner --- src/smt/theory_card.cpp | 156 ++++++---------------------------------- 1 file changed, 23 insertions(+), 133 deletions(-) diff --git a/src/smt/theory_card.cpp b/src/smt/theory_card.cpp index 080cbf55e..acead0dce 100644 --- a/src/smt/theory_card.cpp +++ b/src/smt/theory_card.cpp @@ -134,6 +134,29 @@ namespace smt { args.resize(args.size()-1); } } + // apply cutting plane reduction: + if (!args.empty()) { + unsigned g = abs(args[0].second); + for (unsigned i = 1; g > 1 && i < args.size(); ++i) { + g = gcd(g, args[i].second); + } + if (g > 1) { + unsigned k = c->m_k; + if (k >= 0) { + c->m_k /= g; + } + else { + // watch out for truncation semantcs for k < 0! + k = abs(k); + k += (k % g); + k /= g; + k = -k; + } + for (unsigned i = 0; i < args.size(); ++i) { + args[i].second /= g; + } + } + } int min = 0, max = 0; for (unsigned i = 0; i < args.size(); ++i) { @@ -419,137 +442,4 @@ namespace smt { TRACE("card", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";); ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); } - - -#if 1 - - -#endif - } - - - -#if 0 - - expr_ref_vector merge(expr_ref_vector const& l1, expr_ref_vector const& l2) { - if (l1.empty()) { - return l2; - } - if (l2.empty()) { - return l1; - } - expr_ref_vector result(m); - if (l1.size() == 1 && l2.size() == 1) { - result.push_back(l1[0]); - result.push_back(l2[0]); - exchange(0, 1, result); - return result; - } - unsigned l1o = l1.size()/2; - unsigned l2o = l2.size()/2; - unsigned l1e = (l1.size() % 2 == 1) ? l1o + 1 : l1o; - unsigned l2e = (l2.size() % 2 == 1) ? l2o + 1 : l2o; - expr_ref_vector evenl1(m), oddl1(m), evenl2(m), oddl2(m); - evenl1.resize(l1e); - oddl1.resize(l1o); - evenl2.resize(l2e); - oddl2.resize(l2o); - for (unsigned i = 0; i < l1.size(); ++i) { - if (i % 2 == 0) { - evenl1[i/2] = l1[i]; - } - else { - oddl1[i/2] = l1[i]; - } - } - for (unsigned i = 0; i < l2.size(); ++i) { - if (i % 2 == 0) { - evenl2[i/2] = l2[i]; - } - else { - oddl2[i/2] = l2[i]; - } - } - expr_ref_vector even = merge(evenl1, evenl2); - expr_ref_vector odd = merge(oddl1, oddl2); - - result.resize(l1.size() + l2.size()); - for (unsigned i = 0; i < result.size(); ++i) { - if (i % 2 == 0) { - result[i] = even[i/2].get(); - if (i > 0) { - exchange(i - 1, i, result); - } - } - else { - if (i /2 < odd.size()) { - result[i] = odd[i/2].get(); - } - else { - result[i] = even[(i/2)+1].get(); - } - } - } - return result; - } - -Sorting networks used in Formula: - - public SortingNetwork(SymbolicState owner, Term[] inputs, Sort sortingDomain) - { - Contract.Requires(owner != null && inputs != null && sortingDomain != null); - Contract.Requires(inputs.Length > 0); - - Owner = owner; - Size = (int)Math.Pow(2, (int)Math.Ceiling(Math.Log(inputs.Length, 2))); - - if (Size == 1) - { - elements = new Term[1]; - elements[0] = inputs[0]; - } - else if (Size > 1) - { - var defaultElement = owner.Context.MkNumeral(0, sortingDomain); - - current = new int[Size]; - next = new int[Size]; - elements = new Term[Size]; - for (int i = 0; i < Size; ++i) - { - current[i] = i; - elements[i] = (i < Size - inputs.Length) ? defaultElement : inputs[i - (Size - inputs.Length)]; - } - - int k = 2; - Term xi; - while (k <= Size) - { - Sort(k); - - for (int i = 0; i < Size; ++i) - { - xi = owner.Context.MkFreshConst("x", sortingDomain); - owner.Context.AssertCnstr(owner.Context.MkEq(xi, elements[i])); - elements[i] = xi; - } - - for (int i = 0; i < elements.Length / k; ++i) - { - for (int j = 0; j < k - 1; ++j) - { - owner.Context.AssertCnstr(owner.Context.MkBvUle(elements[(k * i) + j], elements[(k * i) + j + 1])); - } - } - - k *= 2; - } - } - } - - -} - - -#endif From 31e2d823c91309d75e5edfe5f82bf07291c38562 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Nov 2013 01:35:25 -0800 Subject: [PATCH 096/925] add cutting plane Signed-off-by: Nikolaj Bjorner --- src/smt/theory_card.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_card.cpp b/src/smt/theory_card.cpp index acead0dce..6f54fdd4f 100644 --- a/src/smt/theory_card.cpp +++ b/src/smt/theory_card.cpp @@ -113,6 +113,20 @@ namespace smt { m_watch_trail.push_back(bv); } + static unsigned gcd(unsigned a, unsigned b) { + if (a == 0) return b; + if (b == 0) return a; + while (a != b) { + if (a < b) { + b %= a; + } + else { + a %= b; + } + } + return a; + } + void theory_card::add_card(card* c) { bool_var abv = c->m_bv; arg_t& args = c->m_args; @@ -141,7 +155,7 @@ namespace smt { g = gcd(g, args[i].second); } if (g > 1) { - unsigned k = c->m_k; + int k = c->m_k; if (k >= 0) { c->m_k /= g; } From c57594d463eee70d6849687f636318a3473c493a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Nov 2013 10:47:12 -0800 Subject: [PATCH 097/925] tested network sorting Signed-off-by: Nikolaj Bjorner --- src/smt/theory_card.cpp | 26 +++++++-- src/test/sorting_network.cpp | 106 ++++++++++++++++++++++++++++++----- src/util/sorting_network.h | 50 ++++++++--------- 3 files changed, 140 insertions(+), 42 deletions(-) diff --git a/src/smt/theory_card.cpp b/src/smt/theory_card.cpp index 6f54fdd4f..3c4cb21f4 100644 --- a/src/smt/theory_card.cpp +++ b/src/smt/theory_card.cpp @@ -15,11 +15,29 @@ Author: Notes: - - count number of clauses per cardinality constraint. - - when number of conflicts exceeds n^2 or n*log(n), then create a sorting circuit. - where n is the arity of the cardinality constraint. - - extra: do clauses get re-created? keep track of gc status of created clauses. + - Uses cutting plane simplification on 'k' for repeated literals. + In other words, if the gcd of the multiplicity of literals in c3 + is g, then divide through by g and truncate k. + + Example: + ((_ at-most 3) x1 x1 x2 x2) == ((_ at-most 1) x1 x2) + - count number of clauses per cardinality constraint. + + - TBD: when number of conflicts exceeds n^2 or n*log(n), + then create a sorting circuit. + where n is the arity of the cardinality constraint. + + - TBD: do clauses get re-created? keep track of gc + status of created clauses. + + - TBD: add conflict resolution + The idea is that if cardinality constraints c1, c2 + are repeatedly asserted together, then + resolve them into combined cardinality constraint c3 + + c1 /\ c2 -> c3 + --*/ #include "theory_card.h" diff --git a/src/test/sorting_network.cpp b/src/test/sorting_network.cpp index 904bbb970..a6ec9e5e2 100644 --- a/src/test/sorting_network.cpp +++ b/src/test/sorting_network.cpp @@ -2,6 +2,9 @@ #include "sorting_network.h" #include "vector.h" #include "ast.h" +#include "ast_pp.h" +#include "reg_decl_plugins.h" + struct ast_ext { ast_manager& m; @@ -38,23 +41,100 @@ struct unsigned_ext { } }; -void tst_sorting_network() { - svector vec; +static void is_sorted(svector const& v) { + for (unsigned i = 0; i + 1 < v.size(); ++i) { + SASSERT(v[i] <= v[i+1]); + } +} + +static void test_sorting1() { + svector in, out; unsigned_ext uext; - sorting_network sn(uext, vec); + sorting_network sn(uext); - svector in1; - in1.push_back(0); - in1.push_back(1); - in1.push_back(0); - in1.push_back(1); - in1.push_back(1); - in1.push_back(0); + in.push_back(0); + in.push_back(1); + in.push_back(0); + in.push_back(1); + in.push_back(1); + in.push_back(0); - sn(in1); + sn(in, out); - for (unsigned i = 0; i < vec.size(); ++i) { - std::cout << vec[i]; + is_sorted(out); + for (unsigned i = 0; i < out.size(); ++i) { + std::cout << out[i]; } std::cout << "\n"; } + +static void test_sorting2() { + svector in, out; + unsigned_ext uext; + sorting_network sn(uext); + + in.push_back(0); + in.push_back(1); + in.push_back(2); + in.push_back(1); + in.push_back(1); + in.push_back(3); + + sn(in, out); + + is_sorted(out); + + for (unsigned i = 0; i < out.size(); ++i) { + std::cout << out[i]; + } + std::cout << "\n"; +} + +static void test_sorting4_r(unsigned i, svector& in) { + if (i == in.size()) { + svector out; + unsigned_ext uext; + sorting_network sn(uext); + sn(in, out); + is_sorted(out); + std::cout << "sorted\n"; + } + else { + in[i] = 0; + test_sorting4_r(i+1, in); + in[i] = 1; + test_sorting4_r(i+1, in); + } +} + +static void test_sorting4() { + svector in; + in.resize(5); + test_sorting4_r(0, in); +} + +void test_sorting3() { + ast_manager m; + reg_decl_plugins(m); + expr_ref_vector in(m), out(m); + for (unsigned i = 0; i < 7; ++i) { + in.push_back(m.mk_fresh_const("a",m.mk_bool_sort())); + } + for (unsigned i = 0; i < in.size(); ++i) { + std::cout << mk_pp(in[i].get(), m) << "\n"; + } + ast_ext aext(m); + sorting_network sn(aext); + sn(in, out); + std::cout << "size: " << out.size() << "\n"; + for (unsigned i = 0; i < out.size(); ++i) { + std::cout << mk_pp(out[i].get(), m) << "\n"; + } +} + +void tst_sorting_network() { + test_sorting1(); + test_sorting2(); + test_sorting3(); + test_sorting4(); +} diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index d823cf44c..731bda8a9 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -7,7 +7,7 @@ template class sorting_network { - typename Ext::vector& m_es; + typedef typename Ext::vector vect; Ext& m_ext; svector m_currentv; svector m_nextv; @@ -17,21 +17,21 @@ unsigned& current(unsigned i) { return (*m_current)[i]; } unsigned& next(unsigned i) { return (*m_next)[i]; } - void exchange(unsigned i, unsigned j) { + void exchange(unsigned i, unsigned j, vect& out) { SASSERT(i <= j); if (i < j) { - Ext::T ei = m_es.get(i); - Ext::T ej = m_es.get(j); - m_es.set(i, m_ext.mk_ite(m_ext.mk_le(ei, ej), ei, ej)); - m_es.set(j, m_ext.mk_ite(m_ext.mk_le(ej, ei), ei, ej)); + Ext::T ei = out.get(i); + Ext::T ej = out.get(j); + out.set(i, m_ext.mk_ite(m_ext.mk_le(ei, ej), ei, ej)); + out.set(j, m_ext.mk_ite(m_ext.mk_le(ej, ei), ei, ej)); } } - void sort(unsigned k) { + void sort(unsigned k, vect& out) { SASSERT(is_power_of2(k) && k > 0); if (k == 2) { - for (unsigned i = 0; i < m_es.size()/2; ++i) { - exchange(current(2*i), current(2*i+1)); + for (unsigned i = 0; i < out.size()/2; ++i) { + exchange(current(2*i), current(2*i+1), out); next(2*i) = current(2*i); next(2*i+1) = current(2*i+1); } @@ -39,7 +39,7 @@ } else { - for (unsigned i = 0; i < m_es.size()/k; ++i) { + for (unsigned i = 0; i < out.size()/k; ++i) { unsigned ki = k * i; for (unsigned j = 0; j < k / 2; ++j) { next(ki + j) = current(ki + (2 * j)); @@ -48,8 +48,8 @@ } std::swap(m_current, m_next); - sort(k / 2); - for (unsigned i = 0; i < m_es.size() / k; ++i) { + sort(k / 2, out); + for (unsigned i = 0; i < out.size() / k; ++i) { unsigned ki = k * i; for (unsigned j = 0; j < k / 2; ++j) { next(ki + (2 * j)) = current(ki + j); @@ -57,7 +57,7 @@ } for (unsigned j = 0; j < (k / 2) - 1; ++j) { - exchange(next(ki + (2 * j) + 1), next(ki + (2 * (j + 1)))); + exchange(next(ki + (2 * j) + 1), next(ki + (2 * (j + 1))), out); } } std::swap(m_current, m_next); @@ -69,28 +69,28 @@ } public: - sorting_network(Ext& ext, typename Ext::vector& es): + sorting_network(Ext& ext): m_ext(ext), - m_es(es), m_current(&m_currentv), m_next(&m_nextv) {} - void operator()(typename Ext::vector const& inputs) { - if (inputs.size() <= 1) { + void operator()(vect const& in, vect& out) { + if (in.size() <= 1) { return; } - m_es.reset(); - m_es.append(inputs); - while (!is_power_of2(m_es.size())) { - m_es.push_back(m_ext.mk_default()); + out.reset(); + out.append(in); + while (!is_power_of2(out.size())) { + out.push_back(m_ext.mk_default()); } - for (unsigned i = 0; i < m_es.size(); ++i) { - current(i) = i; + for (unsigned i = 0; i < out.size(); ++i) { + m_currentv.push_back(i); + m_nextv.push_back(i); } unsigned k = 2; - while (k <= m_es.size()) { - sort(k); + while (k <= out.size()) { + sort(k, out); k *= 2; } } From 8fb92e6312c5648710679421f0fe78887c46bbed Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Nov 2013 10:49:36 -0800 Subject: [PATCH 098/925] tested network sorting Signed-off-by: Nikolaj Bjorner --- src/util/sorting_network.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index 731bda8a9..c4f6d027c 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -1,3 +1,23 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + sorting_network.h + +Abstract: + + Utility for creating a sorting network. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-11-07 + +Notes: + + Same routine is used in Formula. + +--*/ #include "vector.h" From 759d80dfe37177b9f9c6196624d5ea07027cf9d3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Nov 2013 12:15:51 -0800 Subject: [PATCH 099/925] fix regression Signed-off-by: Nikolaj Bjorner --- src/smt/theory_card.cpp | 4 ++-- src/test/sorting_network.cpp | 2 ++ src/util/sorting_network.h | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/smt/theory_card.cpp b/src/smt/theory_card.cpp index 3c4cb21f4..ebcd52d56 100644 --- a/src/smt/theory_card.cpp +++ b/src/smt/theory_card.cpp @@ -304,7 +304,7 @@ namespace smt { lbool val = ctx.get_assignment(bv); if (inc_min(inc, val) == l_true) { curr_min += abs(inc); - lits.push_back(literal(bv, val != l_true)); + lits.push_back(literal(bv, val == l_true)); } } return curr_min; @@ -424,7 +424,7 @@ namespace smt { } else if (vars[mid].first < bv) { lo = mid; - mid += (hi-mid)/2; + mid += (hi-mid)/2 + 1; } else { hi = mid; diff --git a/src/test/sorting_network.cpp b/src/test/sorting_network.cpp index a6ec9e5e2..5ae6362b1 100644 --- a/src/test/sorting_network.cpp +++ b/src/test/sorting_network.cpp @@ -111,6 +111,8 @@ static void test_sorting4() { svector in; in.resize(5); test_sorting4_r(0, in); + in.resize(8); + test_sorting4_r(0, in); } void test_sorting3() { diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index c4f6d027c..f4eb4b032 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -96,11 +96,11 @@ Notes: {} void operator()(vect const& in, vect& out) { + out.reset(); + out.append(in); if (in.size() <= 1) { return; } - out.reset(); - out.append(in); while (!is_power_of2(out.size())) { out.push_back(m_ext.mk_default()); } From ab4efe2da0eb1139eb78bf9a61512e5390a8b025 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Thu, 7 Nov 2013 15:56:53 -0800 Subject: [PATCH 100/925] Update interface of network flows --- src/smt/network_flow.h | 11 +- src/smt/network_flow_def.h | 194 +++++-------- src/smt/spanning_tree.h | 22 +- src/smt/spanning_tree_base.h | 22 +- src/smt/spanning_tree_def.h | 518 ++++++++++++++++++----------------- 5 files changed, 360 insertions(+), 407 deletions(-) diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index 2d40edbd2..6ac46f0d5 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -51,7 +51,7 @@ namespace smt { typedef typename Ext::fin_numeral fin_numeral; graph m_graph; - thread_spanning_tree tree; + spanning_tree_base m_tree; // Denote supply/demand b_i on node i vector m_balances; @@ -66,17 +66,13 @@ namespace smt { unsigned m_step; - edge_id m_entering_edge; - edge_id m_leaving_edge; - node m_join_node; + edge_id m_enter_id, m_leave_id; optional m_delta; - bool m_in_edge_dir; + bool m_is_swap_enter, m_is_swap_leave; // Initialize the network with a feasible spanning tree void initialize(); - edge_id get_edge_id(dl_var source, dl_var target) const; - void update_potentials(); void update_flows(); @@ -94,7 +90,6 @@ namespace smt { std::string display_spanning_tree(); bool edge_in_tree(edge_id id) const; - bool edge_in_tree(node src, node dst) const; bool check_well_formed(); bool check_optimal(); diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index f697acaac..ca3e6db29 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -40,30 +40,26 @@ namespace smt { m_graph.add_edge(e.get_target(), e.get_source(), e.get_weight(), explanation()); } } - - unsigned num_nodes = m_graph.get_num_nodes() + 1; - unsigned num_edges = m_graph.get_num_edges(); - - m_balances.resize(num_nodes); - m_potentials.resize(num_nodes); - - tree = thread_spanning_tree(); + m_tree = thread_spanning_tree(m_graph); m_step = 0; } template void network_flow::initialize() { TRACE("network_flow", tout << "initialize...\n";); - // Create an artificial root node to construct initial spanning tree + // Create an artificial root node to construct initial spanning m_tree unsigned num_nodes = m_graph.get_num_nodes(); unsigned num_edges = m_graph.get_num_edges(); node root = num_nodes; m_graph.init_var(root); + + m_potentials.resize(num_nodes + 1); m_potentials[root] = numeral::zero(); + m_balances.resize(num_nodes + 1); fin_numeral sum_supply = fin_numeral::zero(); - for (unsigned i = 0; i < m_balances.size(); ++i) { + for (unsigned i = 0; i < num_nodes; ++i) { sum_supply += m_balances[i]; } m_balances[root] = -sum_supply; @@ -73,54 +69,37 @@ namespace smt { m_states.resize(num_nodes + num_edges); m_states.fill(LOWER); - // Create artificial edges from/to root node to/from other nodes and initialize the spanning tree + // Create artificial edges from/to root node to/from other nodes and initialize the spanning m_tree svector upwards(num_nodes, false); for (unsigned i = 0; i < num_nodes; ++i) { upwards[i] = !m_balances[i].is_neg(); m_states[num_edges + i] = BASIS; node src = upwards[i] ? i : root; node tgt = upwards[i] ? root : i; - m_flows[num_edges + i] = upwards[i] ? m_balances[i] : -m_balances[i]; + m_flows[num_edges + i] = upwards[i] ? m_balances[i] : -m_balances[i]; + m_potentials[i] = upwards[i] ? numeral::one() : -numeral::one(); m_graph.add_edge(src, tgt, numeral::one(), explanation()); } - tree.initialize(upwards, num_nodes); - - // Compute initial potentials - svector descendants; - tree.get_descendants(root, descendants); - // Skip root node - for (unsigned i = 1; i < descendants.size(); ++i) { - node u = descendants[i]; - node v = tree.get_parent(u); - edge_id e_id = get_edge_id(u, v); - m_potentials[u] = m_potentials[v] + (tree.get_arc_direction(u) ? - m_graph.get_weight(e_id) : m_graph.get_weight(e_id)); - } + m_tree.initialize(upwards); TRACE("network_flow", { tout << pp_vector("Potentials", m_potentials, true) << pp_vector("Flows", m_flows); }); - TRACE("network_flow", tout << "Spanning tree:\n" << display_spanning_tree();); + TRACE("network_flow", tout << "Spanning m_tree:\n" << display_spanning_tree();); SASSERT(check_well_formed()); } template - edge_id network_flow::get_edge_id(dl_var source, dl_var target) const { - // tree.get_arc_direction(source) decides which node is the real source - edge_id id; - VERIFY(tree.get_arc_direction(source) ? m_graph.get_edge_id(source, target, id) : m_graph.get_edge_id(target, source, id)); - return id; - } - - template - void network_flow::update_potentials() { - TRACE("network_flow", tout << "update_potentials...\n";); - node src = m_graph.get_source(m_entering_edge); - node tgt = m_graph.get_target(m_entering_edge); - numeral cost = m_graph.get_weight(m_entering_edge); - numeral change = m_potentials[tgt] - m_potentials[src] + (tree.get_arc_direction(src) ? -cost : cost); + void network_flow::update_potentials() { + node src = m_graph.get_source(m_enter_id); + node tgt = m_graph.get_target(m_enter_id); + numeral cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(m_enter_id); + numeral change = m_is_swap_leave ? -cost : cost; svector descendants; - tree.get_descendants(src, descendants); + node start = m_is_swap_enter ? src : tgt; + TRACE("network_flow", tout << "update_potentials of T_" << start << " with delta = " << change << "...\n";); + m_tree.get_descendants(start, descendants); for (unsigned i = 0; i < descendants.size(); ++i) { node u = descendants[i]; m_potentials[u] += change; @@ -131,23 +110,16 @@ namespace smt { template void network_flow::update_flows() { TRACE("network_flow", tout << "update_flows...\n";); - numeral val = fin_numeral(m_states[m_entering_edge]) * (*m_delta); - m_flows[m_entering_edge] += val; - node source = m_graph.get_source(m_entering_edge); - svector ancestors; - tree.get_ancestors(source, ancestors); - for (unsigned i = 0; i < ancestors.size() && ancestors[i] != m_join_node; ++i) { - node u = ancestors[i]; - edge_id e_id = get_edge_id(u, tree.get_parent(u)); - m_flows[e_id] += tree.get_arc_direction(u) ? -val : val; - } - - node target = m_graph.get_target(m_entering_edge); - tree.get_ancestors(target, ancestors); - for (unsigned i = 0; i < ancestors.size() && ancestors[i] != m_join_node; ++i) { - node u = ancestors[i]; - edge_id e_id = get_edge_id(u, tree.get_parent(u)); - m_flows[e_id] += tree.get_arc_direction(u) ? val : -val; + numeral val = *m_delta; + m_flows[m_enter_id] += val; + node src = m_graph.get_source(m_enter_id); + node tgt = m_graph.get_target(m_enter_id); + svector path; + svector against; + m_tree.get_path(src, tgt, path, against); + for (unsigned i = 0; i < path.size(); ++i) { + edge_id e_id = path[i]; + m_flows[e_id] += against[i] ? -val : val; } TRACE("network_flow", tout << pp_vector("Flows", m_flows, true);); } @@ -160,11 +132,10 @@ namespace smt { node src = m_graph.get_source(i); node tgt = m_graph.get_target(i); if (m_states[i] != BASIS) { - numeral change = fin_numeral(m_states[i]) * (m_graph.get_weight(i) + m_potentials[src] - m_potentials[tgt]); - // Choose the first negative-cost edge to be the violating edge + numeral cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(i); // TODO: add multiple pivoting strategies - if (change.is_neg()) { - m_entering_edge = i; + if (cost.is_pos()) { + m_enter_id = i; TRACE("network_flow", { tout << "Found entering edge " << i << " between node "; tout << src << " and node " << tgt << "...\n"; @@ -180,52 +151,28 @@ namespace smt { template bool network_flow::choose_leaving_edge() { TRACE("network_flow", tout << "choose_leaving_edge...\n";); - node source = m_graph.get_source(m_entering_edge); - node target = m_graph.get_target(m_entering_edge); - if (m_states[m_entering_edge] == UPPER) { - std::swap(source, target); - } - - m_join_node = tree.get_common_ancestor(source, target); - - TRACE("network_flow", tout << "Found join node " << m_join_node << std::endl;); + node src = m_graph.get_source(m_enter_id); + node tgt = m_graph.get_target(m_enter_id); m_delta.set_invalid(); - node src, tgt; - - // Send flows along the path from source to the ancestor - svector ancestors; - tree.get_ancestors(source, ancestors); - for (unsigned i = 0; i < ancestors.size() && ancestors[i] != m_join_node; ++i) { - node u = ancestors[i]; - edge_id e_id = get_edge_id(u, tree.get_parent(u)); - if (tree.get_arc_direction(u) && (!m_delta || m_flows[e_id] < *m_delta)) { + edge_id leave_id; + svector path; + svector against; + m_tree.get_path(src, tgt, path, against); + for (unsigned i = 0; i < path.size(); ++i) { + edge_id e_id = path[i]; + if (against[i] && (!m_delta || m_flows[e_id] <= *m_delta)) { m_delta = m_flows[e_id]; - src = u; - tgt = tree.get_parent(u); - SASSERT(edge_in_tree(src,tgt)); - m_in_edge_dir = true; - } - } - - // Send flows along the path from target to the ancestor - tree.get_ancestors(target, ancestors); - for (unsigned i = 0; i < ancestors.size() && ancestors[i] != m_join_node; ++i) { - node u = ancestors[i]; - edge_id e_id = get_edge_id(u, tree.get_parent(u)); - if (!tree.get_arc_direction(u) && (!m_delta || m_flows[e_id] <= *m_delta)) { - m_delta = m_flows[e_id]; - src = u; - tgt = tree.get_parent(u); - SASSERT(edge_in_tree(src,tgt)); - m_in_edge_dir = false; + leave_id = e_id; } } if (m_delta) { - m_leaving_edge = get_edge_id(src, tgt); + m_leave_id = leave_id; + TRACE("network_flow", { - tout << "Found leaving edge " << m_leaving_edge; - tout << " between node " << src << " and node " << tgt << "...\n"; + tout << "Found leaving edge " << m_leave_id; + tout << " between node " << m_graph.get_source(m_leave_id); + tout << " and node " << m_graph.get_target(m_leave_id) << " with delta = " << *m_delta << "...\n"; }); return true; } @@ -234,13 +181,8 @@ namespace smt { } template - void network_flow::update_spanning_tree() { - node p = m_graph.get_source(m_entering_edge); - node q = m_graph.get_target(m_entering_edge); - node u = m_graph.get_source(m_leaving_edge); - node v = m_graph.get_target(m_leaving_edge); - - tree.update(p, q, u, v); + void network_flow::update_spanning_tree() { + m_tree.update(m_enter_id, m_leave_id, m_is_swap_enter, m_is_swap_leave); } // Minimize cost flows @@ -252,18 +194,18 @@ namespace smt { bool bounded = choose_leaving_edge(); if (!bounded) return false; update_flows(); - if (m_entering_edge != m_leaving_edge) { - SASSERT(edge_in_tree(m_leaving_edge)); - SASSERT(!edge_in_tree(m_entering_edge)); - m_states[m_entering_edge] = BASIS; - m_states[m_leaving_edge] = (m_flows[m_leaving_edge].is_zero()) ? LOWER : UPPER; + if (m_enter_id != m_leave_id) { + SASSERT(edge_in_tree(m_leave_id)); + SASSERT(!edge_in_tree(m_enter_id)); + m_states[m_enter_id] = BASIS; + m_states[m_leave_id] = (m_flows[m_leave_id].is_zero()) ? LOWER : UPPER; update_spanning_tree(); update_potentials(); - TRACE("network_flow", tout << "Spanning tree:\n" << display_spanning_tree();); + TRACE("network_flow", tout << "Spanning m_tree:\n" << display_spanning_tree();); SASSERT(check_well_formed()); } else { - m_states[m_leaving_edge] = m_states[m_leaving_edge] == LOWER ? UPPER : LOWER; + m_states[m_leave_id] = m_states[m_leave_id] == LOWER ? UPPER : LOWER; } } TRACE("network_flow", tout << "Found optimal solution.\n";); @@ -297,27 +239,24 @@ namespace smt { bool network_flow::edge_in_tree(edge_id id) const { return m_states[id] == BASIS; } - - template - bool network_flow::edge_in_tree(node src, node dst) const { - return edge_in_tree(get_edge_id(src, dst)); - } template bool network_flow::check_well_formed() { - SASSERT(tree.check_well_formed()); + SASSERT(m_tree.check_well_formed()); // m_flows are zero on non-basic edges for (unsigned i = 0; i < m_flows.size(); ++i) { + SASSERT(!m_flows[i].is_neg()); SASSERT(m_states[i] == BASIS || m_flows[i].is_zero()); } - // m_upwards show correct direction - for (unsigned i = 0; i < m_potentials.size(); ++i) { - node p = tree.get_parent(i); - edge_id id; - SASSERT(!tree.get_arc_direction(i) || m_graph.get_edge_id(i, p, id)); - } + vector const & es = m_graph.get_all_edges(); + for (unsigned i = 0; i < es.size(); ++i) { + edge const & e = es[i]; + if (m_states[i] == BASIS) { + SASSERT(m_potentials[e.get_source()] - m_potentials[e.get_target()] == e.get_weight()); + } + } return true; } @@ -328,8 +267,7 @@ namespace smt { vector const & es = m_graph.get_all_edges(); for (unsigned i = 0; i < es.size(); ++i) { edge const & e = es[i]; - if (m_states[i] == BASIS) - { + if (m_states[i] == BASIS) { total_cost += e.get_weight().get_rational() * m_flows[i]; } } diff --git a/src/smt/spanning_tree.h b/src/smt/spanning_tree.h index 41264245e..e085d4542 100644 --- a/src/smt/spanning_tree.h +++ b/src/smt/spanning_tree.h @@ -44,25 +44,27 @@ namespace smt { // (i, m_pred[i]) points upwards (pointing toward the root node) svector m_upwards; + graph & m_graph; + void swap_order(node q, node v); node find_rev_thread(node n) const; void fix_depth(node start, node end); node get_final(int start); - bool is_preorder_traversal(node start, node end); - bool is_ancestor_of(node ancestor, node child); + bool is_preorder_traversal(node start, node end); + edge_id get_edge_to_parent(node start) const; + node get_common_ancestor(node u, node v); public: + thread_spanning_tree(graph & g); - void initialize(svector const & upwards, int num_nodes); + void initialize(svector const & upwards); void get_descendants(node start, svector & descendants); - void get_ancestors(node start, svector & ancestors); - node get_common_ancestor(node u, node v); - void update(node p, node q, node u, node v); + + void update(edge_id enter_id, edge_id leave_id, bool & is_swap_enter, bool & is_swap_leave); bool check_well_formed(); - - // TODO: remove these two unnatural functions - bool get_arc_direction(node start) const; - node get_parent(node start); + void get_path(node start, node end, svector & path, svector & against); + bool is_forward_edge(edge_id e_id) const; + bool is_ancestor_of(node ancestor, node child); }; } diff --git a/src/smt/spanning_tree_base.h b/src/smt/spanning_tree_base.h index 065a4b042..17f49980c 100644 --- a/src/smt/spanning_tree_base.h +++ b/src/smt/spanning_tree_base.h @@ -47,24 +47,14 @@ namespace smt { typedef int node; public: - virtual void initialize(svector const & upwards, int num_nodes) {}; - - /** - \brief Get all descendants of a node including itself - */ + virtual void initialize(svector const & upwards) {}; virtual void get_descendants(node start, svector & descendants) {}; - /** - \brief Get all ancestors of a node including itself - */ - virtual void get_ancestors(node start, svector & ancestors) {}; - - virtual node get_common_ancestor(node u, node v) {UNREACHABLE(); return -1;}; - virtual void update(node p, node q, node u, node v) {}; + + virtual void update(edge_id enter_id, edge_id leave_id, bool & is_swap_enter, bool & is_swap_leave) {}; virtual bool check_well_formed() {UNREACHABLE(); return false;}; - - // TODO: remove these two unnatural functions - virtual bool get_arc_direction(node start) const {UNREACHABLE(); return false;}; - virtual node get_parent(node start) {UNREACHABLE(); return -1;}; + virtual void get_path(node start, node end, svector & path, svector & against) {}; + virtual bool is_forward_edge(edge_id e_id) const {UNREACHABLE(); return false;}; + virtual bool is_ancestor_of(node ancestor, node child) {UNREACHABLE(); return false;}; }; } diff --git a/src/smt/spanning_tree_def.h b/src/smt/spanning_tree_def.h index aac40e1b7..fb2b3c6f3 100644 --- a/src/smt/spanning_tree_def.h +++ b/src/smt/spanning_tree_def.h @@ -22,7 +22,280 @@ Notes: #include "spanning_tree.h" namespace smt { + + template + thread_spanning_tree::thread_spanning_tree(graph & g) : + m_graph(g) { + } + + template + void thread_spanning_tree::initialize(svector const & upwards) { + unsigned num_nodes = m_graph.get_num_nodes(); + m_pred.resize(num_nodes); + m_depth.resize(num_nodes); + m_thread.resize(num_nodes); + m_upwards.resize(num_nodes); + + node root = m_graph.get_num_nodes() - 1; + m_pred[root] = -1; + m_depth[root] = 0; + m_thread[root] = 0; + + // Create artificial edges from/to root node to/from other nodes and initialize the spanning tree + for (int i = 0; i < root; ++i) { + m_pred[i] = root; + m_depth[i] = 1; + m_thread[i] = i + 1; + m_upwards[i] = upwards[i]; + } + + TRACE("network_flow", { + tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Threads", m_thread); + tout << pp_vector("Depths", m_depth) << pp_vector("Upwards", m_upwards); + }); + } + + template + typename thread_spanning_tree::node thread_spanning_tree::get_common_ancestor(node u, node v) { + while (u != v) { + if (m_depth[u] > m_depth[v]) + u = m_pred[u]; + else + v = m_pred[v]; + } + return u; + } + + template + edge_id thread_spanning_tree::get_edge_to_parent(node start) const { + SASSERT(m_pred[start] != -1); + edge_id id; + node end = m_pred[start]; + VERIFY(m_upwards[start] ? m_graph.get_edge_id(start, end, id) : m_graph.get_edge_id(end, start, id)); + return id; + } + + template + void thread_spanning_tree::get_path(node start, node end, svector & path, svector & against) { + node join = get_common_ancestor(start, end); + path.reset(); + while (start != join) { + edge_id e_id = get_edge_to_parent(start); + path.push_back(e_id); + against.push_back(is_forward_edge(e_id)); + start = m_pred[start]; + } + while (end != join) { + edge_id e_id = get_edge_to_parent(end); + path.push_back(e_id); + against.push_back(!is_forward_edge(e_id)); + end = m_pred[end]; + } + } + + template + bool thread_spanning_tree::is_forward_edge(edge_id e_id) const { + node start = m_graph.get_source(e_id); + node end = m_graph.get_target(e_id); + SASSERT(m_pred[start] == end || m_pred[end] == start); + return m_pred[start] == end; + } + + template + void thread_spanning_tree::get_descendants(node start, svector & descendants) { + descendants.reset(); + node u = start; + while (m_depth[m_thread[u]] > m_depth[start]) { + descendants.push_back(u); + u = m_thread[u]; + } + } + + template + bool thread_spanning_tree::is_ancestor_of(node ancestor, node child) { + for (node n = child; n != -1; n = m_pred[n]) { + if (n == ancestor) { + return true; + } + } + return false; + } + /** + \brief add entering_edge, remove leaving_edge from spanning tree. + + Old tree: New tree: + root root + / \ / \ + x y x y + / \ / \ / \ / \ + u s u s + | / / + v w v w + / \ \ / \ \ + z p z p + \ \ / + q q + */ + template + void thread_spanning_tree::update(edge_id enter_id, edge_id leave_id, bool & is_swap_enter, bool & is_swap_leave) { + node p = m_graph.get_source(enter_id); + node q = m_graph.get_target(enter_id); + node u = m_graph.get_source(leave_id); + node v = m_graph.get_target(leave_id); + + if (m_pred[u] == v) { + std::swap(u, v); + is_swap_leave = true; + } + else { + is_swap_leave = false; + } + SASSERT(m_pred[v] == u); + + bool prev_upwards = false; + if (is_ancestor_of(v, p)) { + std::swap(p, q); + prev_upwards = true; + } + + is_swap_enter = prev_upwards; + SASSERT(is_ancestor_of(v, q)); + + TRACE("network_flow", { + tout << "update_spanning_tree: (" << p << ", " << q << ") enters, ("; + tout << u << ", " << v << ") leaves\n"; + }); + + // Update m_pred (for nodes in the stem from q to v) + // Note: m_pred[v] == u + // Initialize m_upwards[q] = q_upwards + + node old_pred = m_pred[q]; + if (q != v) { + for (node n = q; n != u; ) { + SASSERT(old_pred != u || n == v); // the last processed node is v + SASSERT(-1 != m_pred[old_pred]); + int next_old_pred = m_pred[old_pred]; + swap_order(n, old_pred); + std::swap(m_upwards[n], prev_upwards); + prev_upwards = !prev_upwards; // flip previous version of upwards. + n = old_pred; + old_pred = next_old_pred; + } + } + m_pred[q] = p; + + // m_thread were updated. + // update the depth. + + fix_depth(q, get_final(q)); + + TRACE("network_flow", { + tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Threads", m_thread); + tout << pp_vector("Depths", m_depth) << pp_vector("Upwards", m_upwards); + }); + } + + /** + \brief Check invariants of main data-structures. + + Spanning tree of m_graph + root is represented using: + + svector m_states; edge_id |-> edge_state + svector m_upwards; node |-> bool + svector m_pred; node |-> node + svector m_depth; node |-> int + svector m_thread; node |-> node + + Tree is determined by m_pred: + - m_pred[root] == -1 + - m_pred[n] = m != n for each node n, acyclic until reaching root. + - m_depth[m_pred[n]] + 1 == m_depth[n] for each n != root + + m_thread is a linked list traversing all nodes. + Furthermore, the nodes linked in m_thread follows a + depth-first traversal order. + + m_upwards direction of edge from i to m_pred[i] m_graph + + */ + template + bool thread_spanning_tree::check_well_formed() { + node root = m_pred.size()-1; + + // Check that m_thread traverses each node. + // This gets checked using union-find as well. + svector found(m_thread.size(), false); + found[root] = true; + for (node x = m_thread[root]; x != root; x = m_thread[x]) { + SASSERT(x != m_thread[x]); + found[x] = true; + } + for (unsigned i = 0; i < found.size(); ++i) { + SASSERT(found[i]); + } + + // m_pred is acyclic, and points to root. + SASSERT(m_pred[root] == -1); + SASSERT(m_depth[root] == 0); + for (node i = 0; i < root; ++i) { + SASSERT(m_depth[m_pred[i]] < m_depth[i]); + } + + // m_depth[x] denotes distance from x to the root node + for (node x = m_thread[root]; x != root; x = m_thread[x]) { + SASSERT(m_depth[x] > 0); + SASSERT(m_depth[x] == m_depth[m_pred[x]] + 1); + } + + // m_thread forms a spanning tree over [0..root] + // Union-find structure + svector roots(m_pred.size(), -1); + + for (node x = m_thread[root]; x != root; x = m_thread[x]) { + node y = m_pred[x]; + // We are now going to check the edge between x and y + SASSERT(find(roots, x) != find(roots, y)); + merge(roots, x, y); + } + + // All nodes belong to the same spanning tree + for (unsigned i = 0; i < roots.size(); ++i) { + SASSERT(roots[i] + roots.size() == 0 || roots[i] >= 0); + } + + return true; + } + + static unsigned find(svector& roots, unsigned x) { + unsigned old_x = x; + while (roots[x] >= 0) { + x = roots[x]; + } + SASSERT(roots[x] < 0); + if (old_x != x) { + roots[old_x] = x; + } + return x; + } + + static void merge(svector& roots, unsigned x, unsigned y) { + x = find(roots, x); + y = find(roots, y); + SASSERT(roots[x] < 0 && roots[y] < 0); + if (x == y) { + return; + } + if (roots[x] > roots[y]) { + std::swap(x, y); + } + SASSERT(roots[x] <= roots[y]); + roots[x] += roots[y]; + roots[y] = x; + } + + /** swap v and q in tree. - fixup m_thread - fixup m_pred @@ -119,251 +392,6 @@ namespace smt { SASSERT(children.empty()); return true; } - - template - bool thread_spanning_tree::is_ancestor_of(node ancestor, node child) { - for (node n = child; n != -1; n = m_pred[n]) { - if (n == ancestor) { - return true; - } - } - return false; - } - - static unsigned find(svector& roots, unsigned x) { - unsigned old_x = x; - while (roots[x] >= 0) { - x = roots[x]; - } - SASSERT(roots[x] < 0); - if (old_x != x) { - roots[old_x] = x; - } - return x; - } - - static void merge(svector& roots, unsigned x, unsigned y) { - x = find(roots, x); - y = find(roots, y); - SASSERT(roots[x] < 0 && roots[y] < 0); - if (x == y) { - return; - } - if (roots[x] > roots[y]) { - std::swap(x, y); - } - SASSERT(roots[x] <= roots[y]); - roots[x] += roots[y]; - roots[y] = x; - } - - template - void thread_spanning_tree::initialize(svector const & upwards, int num_nodes) { - m_pred.resize(num_nodes + 1); - m_depth.resize(num_nodes + 1); - m_thread.resize(num_nodes + 1); - m_upwards.resize(num_nodes + 1); - - node root = num_nodes; - m_pred[root] = -1; - m_depth[root] = 0; - m_thread[root] = 0; - - // Create artificial edges from/to root node to/from other nodes and initialize the spanning tree - for (int i = 0; i < num_nodes; ++i) { - m_pred[i] = root; - m_depth[i] = 1; - m_thread[i] = i + 1; - m_upwards[i] = upwards[i]; - } - - TRACE("network_flow", { - tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Threads", m_thread); - tout << pp_vector("Depths", m_depth) << pp_vector("Upwards", m_upwards); - }); - } - - template - typename thread_spanning_tree::node thread_spanning_tree::get_common_ancestor(node u, node v) { - while (u != v) { - if (m_depth[u] > m_depth[v]) - u = m_pred[u]; - else - v = m_pred[v]; - } - return u; - } - - template - void thread_spanning_tree::get_descendants(node start, svector& descendants) { - descendants.reset(); - node u = start; - while (m_depth[m_thread[u]] > m_depth[start]) { - descendants.push_back(u); - u = m_thread[u]; - } - } - - template - void thread_spanning_tree::get_ancestors(node start, svector& ancestors) { - ancestors.reset(); - while (m_pred[start] != -1) { - ancestors.push_back(start); - start = m_pred[start]; - } - } - - /** - \brief add entering_edge, remove leaving_edge from spanning tree. - - Old tree: New tree: - root root - / \ / \ - x y x y - / \ / \ / \ / \ - u s u s - | / / - v w v w - / \ \ / \ \ - z p z p - \ \ / - q q - */ - template - void thread_spanning_tree::update(node p, node q, node u, node v) { - bool q_upwards = false; - - // v is parent of u so T_u does not contain root node - if (m_pred[u] == v) { - std::swap(u, v); - } - SASSERT(m_pred[v] == u); - - if (is_ancestor_of(v, p)) { - std::swap(p, q); - q_upwards = true; - } - SASSERT(is_ancestor_of(v, q)); - - TRACE("network_flow", { - tout << "update_spanning_tree: (" << p << ", " << q << ") enters, ("; - tout << u << ", " << v << ") leaves\n"; - }); - - // Update m_pred (for nodes in the stem from q to v) - // Note: m_pred[v] == u - // Initialize m_upwards[q] = q_upwards - - bool prev_upwards = q_upwards; - node old_pred = m_pred[q]; - if (q != v) { - for (node n = q; n != u; ) { - SASSERT(old_pred != u || n == v); // the last processed node is v - TRACE("network_flow", { - tout << pp_vector("Predecessors", m_pred, true); - }); - SASSERT(-1 != m_pred[old_pred]); - int next_old_pred = m_pred[old_pred]; - swap_order(n, old_pred); - std::swap(m_upwards[n], prev_upwards); - prev_upwards = !prev_upwards; // flip previous version of upwards. - n = old_pred; - old_pred = next_old_pred; - } - } - m_pred[q] = p; - - // m_thread were updated. - // update the depth. - - fix_depth(q, get_final(q)); - - TRACE("network_flow", { - tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Threads", m_thread); - tout << pp_vector("Depths", m_depth) << pp_vector("Upwards", m_upwards); - }); - } - - /** - \brief Check invariants of main data-structures. - - Spanning tree of m_graph + root is represented using: - - svector m_states; edge_id |-> edge_state - svector m_upwards; node |-> bool - svector m_pred; node |-> node - svector m_depth; node |-> int - svector m_thread; node |-> node - - Tree is determined by m_pred: - - m_pred[root] == -1 - - m_pred[n] = m != n for each node n, acyclic until reaching root. - - m_depth[m_pred[n]] + 1 == m_depth[n] for each n != root - - m_thread is a linked list traversing all nodes. - Furthermore, the nodes linked in m_thread follows a - depth-first traversal order. - - m_upwards direction of edge from i to m_pred[i] m_graph - - */ - template - bool thread_spanning_tree::check_well_formed() { - node root = m_pred.size()-1; - - // Check that m_thread traverses each node. - // This gets checked using union-find as well. - svector found(m_thread.size(), false); - found[root] = true; - for (node x = m_thread[root]; x != root; x = m_thread[x]) { - SASSERT(x != m_thread[x]); - found[x] = true; - } - for (unsigned i = 0; i < found.size(); ++i) { - SASSERT(found[i]); - } - - // m_pred is acyclic, and points to root. - SASSERT(m_pred[root] == -1); - SASSERT(m_depth[root] == 0); - for (node i = 0; i < root; ++i) { - SASSERT(m_depth[m_pred[i]] < m_depth[i]); - } - - // m_depth[x] denotes distance from x to the root node - for (node x = m_thread[root]; x != root; x = m_thread[x]) { - SASSERT(m_depth[x] > 0); - SASSERT(m_depth[x] == m_depth[m_pred[x]] + 1); - } - - // m_thread forms a spanning tree over [0..root] - // Union-find structure - svector roots(m_pred.size(), -1); - - for (node x = m_thread[root]; x != root; x = m_thread[x]) { - node y = m_pred[x]; - // We are now going to check the edge between x and y - SASSERT(find(roots, x) != find(roots, y)); - merge(roots, x, y); - } - - // All nodes belong to the same spanning tree - for (unsigned i = 0; i < roots.size(); ++i) { - SASSERT(roots[i] + roots.size() == 0 || roots[i] >= 0); - } - - return true; - } - - template - bool thread_spanning_tree::get_arc_direction(node start) const { - return m_upwards[start]; - } - - template - typename thread_spanning_tree::node thread_spanning_tree::get_parent(node start) { - return m_pred[start]; - } } #endif \ No newline at end of file From 401fced4007d5354b52c84f95a64fee03a3a0cbb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Nov 2013 18:09:44 -0800 Subject: [PATCH 101/925] separate out file for objectives Signed-off-by: Nikolaj Bjorner --- src/opt/fu_malik.cpp | 2 + src/opt/opt_context.cpp | 69 +++++++--------------------- src/opt/opt_context.h | 2 + src/opt/opt_maxsmt.cpp | 66 ++++++++++++++++++++++++++ src/opt/opt_maxsmt.h | 52 +++++++++++++++++++++ src/opt/optimize_objectives.cpp | 31 +++++++++++-- src/opt/optimize_objectives.h | 9 +++- src/smt/theory_card.cpp | 19 +++++++- src/smt/theory_card.h | 9 ++++ src/tactic/arith/lia2card_tactic.cpp | 1 + 10 files changed, 199 insertions(+), 61 deletions(-) create mode 100644 src/opt/opt_maxsmt.cpp create mode 100644 src/opt/opt_maxsmt.h diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index 306b3e579..d6e435be9 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -132,6 +132,8 @@ namespace opt { } }; + + // TBD: bug when cancel flag is set, fu_malik returns is_sat == l_true instead of l_undef lbool fu_malik_maxsat(solver& s, expr_ref_vector& soft_constraints) { ast_manager& m = soft_constraints.get_manager(); diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index fbc2981ca..ed971506d 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -21,8 +21,6 @@ Notes: --*/ #include "opt_context.h" -#include "fu_malik.h" -#include "weighted_maxsat.h" #include "ast_pp.h" #include "opt_solver.h" #include "arith_decl_plugin.h" @@ -37,7 +35,8 @@ namespace opt { m_hard_constraints(m), m_soft_constraints(m), m_objectives(m), - m_opt_objectives(m) + m_opt_objectives(m), + m_maxsmt(m) { m_params.set_bool("model", true); m_params.set_bool("unsat_core", true); @@ -45,57 +44,30 @@ namespace opt { void context::optimize() { - expr_ref_vector const& fmls = m_soft_constraints; - if (!m_solver) { symbol logic; set_solver(alloc(opt_solver, m, m_params, logic)); } - solver* s = m_solver.get(); + + // really just works for opt_solver now. + solver* s = m_solver.get(); + opt_solver::scoped_push _sp(get_opt_solver(*s)); for (unsigned i = 0; i < m_hard_constraints.size(); ++i) { s->assert_expr(m_hard_constraints[i].get()); } - - expr_ref_vector fmls_copy(fmls); + lbool is_sat; - if (!fmls.empty()) { - // TBD: bug when cancel flag is set, fu_malik returns is_sat == l_true instead of l_undef - if (is_maxsat_problem()) { - is_sat = opt::fu_malik_maxsat(*s, fmls_copy); - } - else { - is_sat = weighted_maxsat(get_opt_solver(*s), fmls_copy, m_weights); - } - std::cout << "is-sat: " << is_sat << "\n"; - if (is_sat != l_true) { - return; - } - std::cout << "Satisfying soft constraints\n"; - for (unsigned i = 0; i < fmls_copy.size(); ++i) { - std::cout << mk_pp(fmls_copy[i].get(), m) << "\n"; - } + + is_sat = m_maxsmt(get_opt_solver(*s), m_soft_constraints, m_weights); + + for (unsigned i = 0; i < m_soft_constraints.size(); ++i) { + s->assert_expr(m_soft_constraints[i].get()); } - if (!m_objectives.empty()) { - vector > values; - for (unsigned i = 0; i < fmls_copy.size(); ++i) { - s->assert_expr(fmls_copy[i].get()); - } - is_sat = m_opt_objectives(get_opt_solver(*s), m_objectives, values); - std::cout << "is-sat: " << is_sat << std::endl; - - if (is_sat != l_true) { - return; - } - - for (unsigned i = 0; i < values.size(); ++i) { - if (!m_is_max[i]) { - values[i].neg(); - } - std::cout << "objective value: " << mk_pp(m_objectives[i].get(), m) << " -> " << values[i].to_string() << std::endl; - } - } + if (is_sat == l_true) { + is_sat = m_opt_objectives(get_opt_solver(*s), m_objectives); + } if (m_objectives.empty() && m_soft_constraints.empty()) { is_sat = s->check_sat(0,0); @@ -103,15 +75,6 @@ namespace opt { } } - bool context::is_maxsat_problem() const { - vector const& ws = m_weights; - for (unsigned i = 0; i < ws.size(); ++i) { - if (!ws[i].is_one()) { - return false; - } - } - return true; - } opt_solver& context::get_opt_solver(solver& s) { if (typeid(opt_solver) != typeid(s)) { @@ -125,6 +88,7 @@ namespace opt { m_solver->cancel(); } m_opt_objectives.set_cancel(true); + m_maxsmt.set_cancel(true); } void context::reset_cancel() { @@ -132,6 +96,7 @@ namespace opt { m_solver->reset_cancel(); } m_opt_objectives.set_cancel(false); + m_maxsmt.set_cancel(false); } void context::add_objective(app* t, bool is_max) { diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 0aa137748..6a12fa8d6 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -28,6 +28,7 @@ Notes: #include "ast.h" #include "solver.h" #include "optimize_objectives.h" +#include "opt_maxsmt.h" namespace opt { @@ -43,6 +44,7 @@ namespace opt { ref m_solver; params_ref m_params; optimize_objectives m_opt_objectives; + maxsmt m_maxsmt; public: context(ast_manager& m); diff --git a/src/opt/opt_maxsmt.cpp b/src/opt/opt_maxsmt.cpp new file mode 100644 index 000000000..14095252b --- /dev/null +++ b/src/opt/opt_maxsmt.cpp @@ -0,0 +1,66 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + opt_maxsmt.cpp + +Abstract: + + MaxSMT optimization context. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-11-7 + +Notes: + +--*/ + +#include "opt_maxsmt.h" +#include "fu_malik.h" +#include "weighted_maxsat.h" +#include "ast_pp.h" + +namespace opt { + + lbool maxsmt::operator()(opt_solver& s, expr_ref_vector& fmls, vector const& ws) { + lbool is_sat; + + if (fmls.empty()) { + is_sat = s.check_sat(0, 0); + } + else if (is_maxsat_problem(ws)) { + is_sat = opt::fu_malik_maxsat(s, fmls); + } + else { + is_sat = weighted_maxsat(s, fmls, ws); + } + + // Infrastructure for displaying and storing solution is TBD. + std::cout << "is-sat: " << is_sat << "\n"; + if (is_sat == l_true) { + std::cout << "Satisfying soft constraints\n"; + for (unsigned i = 0; i < fmls.size(); ++i) { + std::cout << mk_pp(fmls[i].get(), m) << "\n"; + } + } + return is_sat; + } + + void maxsmt::set_cancel(bool f) { + m_cancel = f; + } + + bool maxsmt::is_maxsat_problem(vector const& ws) const { + for (unsigned i = 0; i < ws.size(); ++i) { + if (!ws[i].is_one()) { + return false; + } + } + return true; + } + + + +}; diff --git a/src/opt/opt_maxsmt.h b/src/opt/opt_maxsmt.h new file mode 100644 index 000000000..d674ff692 --- /dev/null +++ b/src/opt/opt_maxsmt.h @@ -0,0 +1,52 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + opt_maxsmt.h + +Abstract: + + MaxSMT optimization context. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-11-7 + +Notes: + +--*/ +#ifndef _OPT_MAXSMT_H_ +#define _OPT_MAXSMT_H_ + +#include "opt_solver.h" + +namespace opt { + /** + Takes solver with hard constraints added. + Returns modified soft constraints that are maximal assignments. + */ + + class maxsmt { + ast_manager& m; + opt_solver* s; + volatile bool m_cancel; + symbol m_engine; + public: + maxsmt(ast_manager& m): m(m), s(0), m_cancel(false) {} + + lbool operator()(opt_solver& s, expr_ref_vector& soft, vector const& weights); + + void set_cancel(bool f); + + void set_engine(symbol const& e) { m_engine = e; } + + private: + + bool is_maxsat_problem(vector const& ws) const; + + }; + +}; + +#endif diff --git a/src/opt/optimize_objectives.cpp b/src/opt/optimize_objectives.cpp index 9705652fb..ad921934e 100644 --- a/src/opt/optimize_objectives.cpp +++ b/src/opt/optimize_objectives.cpp @@ -204,23 +204,25 @@ namespace opt { Takes solver with hard constraints added. Returns an optimal assignment to objective functions. */ - lbool optimize_objectives::operator()(opt_solver& solver, app_ref_vector& objectives, vector& values) { + lbool optimize_objectives::operator()(opt_solver& solver, app_ref_vector const& objectives) { s = &solver; s->reset_objectives(); m_lower.reset(); m_upper.reset(); + m_objs.reset(); for (unsigned i = 0; i < objectives.size(); ++i) { m_lower.push_back(inf_eps(rational(-1),inf_rational(0))); m_upper.push_back(inf_eps(rational(1), inf_rational(0))); + m_objs.push_back(objectives[i]); } // First check_sat call to initialize theories lbool is_sat = s->check_sat(0, 0); - if (is_sat == l_true) { + if (is_sat == l_true && !objectives.empty()) { opt_solver::scoped_push _push(*s); for (unsigned i = 0; i < objectives.size(); ++i) { - m_vars.push_back(s->add_objective(objectives[i].get())); + m_vars.push_back(s->add_objective(objectives[i])); } if (m_engine == symbol("basic")) { @@ -235,12 +237,31 @@ namespace opt { NOT_IMPLEMENTED_YET(); UNREACHABLE(); } - values.reset(); - values.append(m_lower); } + + std::cout << "is-sat: " << is_sat << std::endl; + display(std::cout); + return is_sat; } + inf_eps optimize_objectives::get_value(bool as_positive, unsigned index) const { + if (as_positive) { + return m_lower[index]; + } + else { + return -m_lower[index]; + } + } + + void optimize_objectives::display(std::ostream& out) const { + unsigned sz = m_objs.size(); + for (unsigned i = 0; i < sz; ++i) { + out << "objective value: " << mk_pp(m_objs[i], m) << " -> " << get_value(true, i).to_string() << std::endl; + } + } + + } #endif diff --git a/src/opt/optimize_objectives.h b/src/opt/optimize_objectives.h index cb9f2241b..c9f5ffc55 100644 --- a/src/opt/optimize_objectives.h +++ b/src/opt/optimize_objectives.h @@ -33,17 +33,22 @@ namespace opt { volatile bool m_cancel; vector m_lower; vector m_upper; + app_ref_vector m_objs; svector m_vars; symbol m_engine; public: - optimize_objectives(ast_manager& m): m(m), s(0), m_cancel(false) {} + optimize_objectives(ast_manager& m): m(m), s(0), m_cancel(false), m_objs(m) {} - lbool operator()(opt_solver& s, app_ref_vector& objectives, vector& values); + lbool operator()(opt_solver& s, app_ref_vector const& objectives); void set_cancel(bool f); void set_engine(symbol const& e) { m_engine = e; } + void display(std::ostream& out) const; + + inf_eps get_value(bool as_positive, unsigned index) const; + private: lbool basic_opt(); diff --git a/src/smt/theory_card.cpp b/src/smt/theory_card.cpp index ebcd52d56..4cd23d225 100644 --- a/src/smt/theory_card.cpp +++ b/src/smt/theory_card.cpp @@ -66,10 +66,13 @@ namespace smt { SASSERT(m_util.is_at_most_k(atom)); unsigned k = m_util.get_k(atom); + if (ctx.b_internalized(atom)) { return false; } + m_stats.m_num_predicates++; + TRACE("card", tout << "internalize: " << mk_pp(atom, m) << "\n";); SASSERT(!ctx.b_internalized(atom)); @@ -210,7 +213,10 @@ namespace smt { m_cards_trail.push_back(abv); } - + void theory_card::collect_statistics(::statistics& st) const { + st.update("pb axioms", m_stats.m_num_axioms); + st.update("pb predicates", m_stats.m_num_predicates); + } void theory_card::reset_eh() { @@ -229,6 +235,7 @@ namespace smt { m_cards_lim.reset(); m_watch_trail.reset(); m_watch_lim.reset(); + m_stats.reset(); } void theory_card::update_min_max(bool_var v, bool is_true, card* c) { @@ -470,8 +477,16 @@ namespace smt { } void theory_card::add_clause(literal_vector const& lits) { + m_stats.m_num_axioms++; context& ctx = get_context(); TRACE("card", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";); - ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); + justification* js = 0; + ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); + IF_VERBOSE(0, + for (unsigned i = 0; i < lits.size(); ++i) { + verbose_stream() << lits[i] << " "; + } + verbose_stream() << "\n";); + // ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); } } diff --git a/src/smt/theory_card.h b/src/smt/theory_card.h index c53e38e37..3c9e3c1f9 100644 --- a/src/smt/theory_card.h +++ b/src/smt/theory_card.h @@ -28,6 +28,13 @@ namespace smt { typedef svector > arg_t; + struct stats { + unsigned m_num_axioms; + unsigned m_num_predicates; + void reset() { memset(this, 0, sizeof(*this)); } + stats() { reset(); } + }; + struct card { int m_k; bool_var m_bv; @@ -49,6 +56,7 @@ namespace smt { unsigned_vector m_watch_lim; literal_vector m_literals; card_util m_util; + stats m_stats; void add_watch(bool_var bv, card* c); void add_card(card* c); @@ -84,6 +92,7 @@ namespace smt { virtual void init_search_eh(); virtual void push_scope_eh(); virtual void pop_scope_eh(unsigned num_scopes); + virtual void collect_statistics(::statistics & st) const; }; }; diff --git a/src/tactic/arith/lia2card_tactic.cpp b/src/tactic/arith/lia2card_tactic.cpp index d2be433c6..5130eea9d 100644 --- a/src/tactic/arith/lia2card_tactic.cpp +++ b/src/tactic/arith/lia2card_tactic.cpp @@ -92,6 +92,7 @@ class lia2card_tactic : public tactic { it = m_01s.begin(), end = m_01s.end(); for (; it != end; ++it) { if (!validate_uses(m_uses.find(*it))) { + std::cout << "did not validate: " << mk_pp(*it, m) << "\n"; m_uses.remove(*it); m_01s.remove(*it); it = m_01s.begin(); From 33be06c6dc3779d9f66947db6072cdfc87a4cca5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Nov 2013 09:00:24 -0800 Subject: [PATCH 102/925] continued re-factoring Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 37 ++++++++----------------------- src/opt/opt_context.h | 39 +++++++++------------------------ src/opt/opt_maxsmt.cpp | 29 +++++++++++++++--------- src/opt/opt_maxsmt.h | 26 +++++++++++++++++----- src/opt/optimize_objectives.cpp | 38 +++++++++++++++++++++++++------- src/opt/optimize_objectives.h | 17 ++++++++------ 6 files changed, 98 insertions(+), 88 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index ed971506d..dbb2b7eb9 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -33,9 +33,7 @@ namespace opt { context::context(ast_manager& m): m(m), m_hard_constraints(m), - m_soft_constraints(m), - m_objectives(m), - m_opt_objectives(m), + m_optsmt(m), m_maxsmt(m) { m_params.set_bool("model", true); @@ -59,19 +57,15 @@ namespace opt { lbool is_sat; - is_sat = m_maxsmt(get_opt_solver(*s), m_soft_constraints, m_weights); + is_sat = m_maxsmt(get_opt_solver(*s)); - for (unsigned i = 0; i < m_soft_constraints.size(); ++i) { - s->assert_expr(m_soft_constraints[i].get()); + expr_ref_vector ans = m_maxsmt.get_assignment(); + for (unsigned i = 0; i < ans.size(); ++i) { + s->assert_expr(ans[i].get()); } if (is_sat == l_true) { - is_sat = m_opt_objectives(get_opt_solver(*s), m_objectives); - } - - if (m_objectives.empty() && m_soft_constraints.empty()) { - is_sat = s->check_sat(0,0); - std::cout << "nothing to optimize: is-sat " << is_sat << std::endl; + is_sat = m_optsmt(get_opt_solver(*s)); } } @@ -87,7 +81,7 @@ namespace opt { if (m_solver) { m_solver->cancel(); } - m_opt_objectives.set_cancel(true); + m_optsmt.set_cancel(true); m_maxsmt.set_cancel(true); } @@ -95,23 +89,10 @@ namespace opt { if (m_solver) { m_solver->reset_cancel(); } - m_opt_objectives.set_cancel(false); + m_optsmt.set_cancel(false); m_maxsmt.set_cancel(false); } - void context::add_objective(app* t, bool is_max) { - expr_ref t1(t, m), t2(m); - th_rewriter rw(m); - if (!is_max) { - arith_util a(m); - t1 = a.mk_uminus(t); - } - rw(t1, t2); - SASSERT(is_app(t2)); - m_objectives.push_back(to_app(t2)); - m_is_max.push_back(is_max); - } - void context::collect_statistics(statistics& stats) { if (m_solver) { m_solver->collect_statistics(stats); @@ -128,7 +109,7 @@ namespace opt { m_solver->updt_params(m_params); } opt_params _p(m_params); - m_opt_objectives.set_engine(_p.engine()); + m_optsmt.set_engine(_p.engine()); } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 6a12fa8d6..fd4e52b17 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -35,43 +35,24 @@ namespace opt { class opt_solver; class context { - ast_manager& m; - expr_ref_vector m_hard_constraints; - expr_ref_vector m_soft_constraints; - vector m_weights; - app_ref_vector m_objectives; - svector m_is_max; - ref m_solver; - params_ref m_params; - optimize_objectives m_opt_objectives; - maxsmt m_maxsmt; + ast_manager& m; + expr_ref_vector m_hard_constraints; + ref m_solver; + params_ref m_params; + optimize_objectives m_optsmt; + maxsmt m_maxsmt; public: context(ast_manager& m); - void add_soft_constraint(expr* f, rational const& w) { - m_soft_constraints.push_back(f); - m_weights.push_back(w); - } - - void add_objective(app* t, bool is_max); - - void add_hard_constraint(expr* f) { - m_hard_constraints.push_back(f); - } - - void set_solver(solver* s) { - m_solver = s; - } - + void add_soft_constraint(expr* f, rational const& w) { m_maxsmt.add(f, w); } + void add_objective(app* t, bool is_max) { m_optsmt.add(t, is_max); } + void add_hard_constraint(expr* f) { m_hard_constraints.push_back(f); } + void set_solver(solver* s) { m_solver = s; } void optimize(); - void cancel(); void reset_cancel(); - void collect_statistics(statistics& stats); - static void collect_param_descrs(param_descrs & r); - void updt_params(params_ref& p); private: diff --git a/src/opt/opt_maxsmt.cpp b/src/opt/opt_maxsmt.cpp index 14095252b..97c73b61f 100644 --- a/src/opt/opt_maxsmt.cpp +++ b/src/opt/opt_maxsmt.cpp @@ -24,29 +24,38 @@ Notes: namespace opt { - lbool maxsmt::operator()(opt_solver& s, expr_ref_vector& fmls, vector const& ws) { + lbool maxsmt::operator()(opt_solver& s) { lbool is_sat; - - if (fmls.empty()) { + m_answer.reset(); + m_answer.append(m_soft_constraints); + if (m_answer.empty()) { is_sat = s.check_sat(0, 0); } - else if (is_maxsat_problem(ws)) { - is_sat = opt::fu_malik_maxsat(s, fmls); + else if (is_maxsat_problem(m_weights)) { + is_sat = opt::fu_malik_maxsat(s, m_answer); } else { - is_sat = weighted_maxsat(s, fmls, ws); + is_sat = weighted_maxsat(s, m_answer, m_weights); } // Infrastructure for displaying and storing solution is TBD. std::cout << "is-sat: " << is_sat << "\n"; if (is_sat == l_true) { std::cout << "Satisfying soft constraints\n"; - for (unsigned i = 0; i < fmls.size(); ++i) { - std::cout << mk_pp(fmls[i].get(), m) << "\n"; - } - } + display_answer(std::cout); + } return is_sat; } + + expr_ref_vector maxsmt::get_assignment() const { + return m_answer; + } + + void maxsmt::display_answer(std::ostream& out) const { + for (unsigned i = 0; i < m_answer.size(); ++i) { + out << mk_pp(m_answer[i], m) << "\n"; + } + } void maxsmt::set_cancel(bool f) { m_cancel = f; diff --git a/src/opt/opt_maxsmt.h b/src/opt/opt_maxsmt.h index d674ff692..0303e4a99 100644 --- a/src/opt/opt_maxsmt.h +++ b/src/opt/opt_maxsmt.h @@ -28,19 +28,33 @@ namespace opt { */ class maxsmt { - ast_manager& m; - opt_solver* s; - volatile bool m_cancel; - symbol m_engine; + ast_manager& m; + opt_solver* s; + volatile bool m_cancel; + expr_ref_vector m_soft_constraints; + expr_ref_vector m_answer; + vector m_weights; + symbol m_engine; public: - maxsmt(ast_manager& m): m(m), s(0), m_cancel(false) {} + maxsmt(ast_manager& m): m(m), s(0), m_cancel(false), m_soft_constraints(m), m_answer(m) {} - lbool operator()(opt_solver& s, expr_ref_vector& soft, vector const& weights); + lbool operator()(opt_solver& s); void set_cancel(bool f); + void add(expr* f, rational const& w) { + m_soft_constraints.push_back(f); + m_weights.push_back(w); + } + void set_engine(symbol const& e) { m_engine = e; } + // TBD: rational get_value() const; + + expr_ref_vector get_assignment() const; + + void display_answer(std::ostream& out) const; + private: bool is_maxsat_problem(vector const& ws) const; diff --git a/src/opt/optimize_objectives.cpp b/src/opt/optimize_objectives.cpp index ad921934e..663f3a52c 100644 --- a/src/opt/optimize_objectives.cpp +++ b/src/opt/optimize_objectives.cpp @@ -46,6 +46,7 @@ Notes: #include "theory_arith.h" #include "ast_pp.h" #include "model_pp.h" +#include "th_rewriter.h" namespace opt { @@ -204,25 +205,24 @@ namespace opt { Takes solver with hard constraints added. Returns an optimal assignment to objective functions. */ - lbool optimize_objectives::operator()(opt_solver& solver, app_ref_vector const& objectives) { + lbool optimize_objectives::operator()(opt_solver& solver) { s = &solver; s->reset_objectives(); m_lower.reset(); m_upper.reset(); - m_objs.reset(); - for (unsigned i = 0; i < objectives.size(); ++i) { + m_vars.reset(); + for (unsigned i = 0; i < m_objs.size(); ++i) { m_lower.push_back(inf_eps(rational(-1),inf_rational(0))); m_upper.push_back(inf_eps(rational(1), inf_rational(0))); - m_objs.push_back(objectives[i]); } // First check_sat call to initialize theories lbool is_sat = s->check_sat(0, 0); - if (is_sat == l_true && !objectives.empty()) { + if (is_sat == l_true && !m_objs.empty()) { opt_solver::scoped_push _push(*s); - for (unsigned i = 0; i < objectives.size(); ++i) { - m_vars.push_back(s->add_objective(objectives[i])); + for (unsigned i = 0; i < m_objs.size(); ++i) { + m_vars.push_back(s->add_objective(m_objs[i].get())); } if (m_engine == symbol("basic")) { @@ -257,10 +257,32 @@ namespace opt { void optimize_objectives::display(std::ostream& out) const { unsigned sz = m_objs.size(); for (unsigned i = 0; i < sz; ++i) { - out << "objective value: " << mk_pp(m_objs[i], m) << " -> " << get_value(true, i).to_string() << std::endl; + bool is_max = m_is_max[i]; + inf_eps val = get_value(is_max, i); + expr_ref obj(m_objs[i], m); + if (!is_max) { + arith_util a(m); + th_rewriter rw(m); + obj = a.mk_uminus(obj); + rw(obj, obj); + } + out << "objective value: " << obj << " |-> " << val << std::endl; } } + void optimize_objectives::add(app* t, bool is_max) { + expr_ref t1(t, m), t2(m); + th_rewriter rw(m); + if (!is_max) { + arith_util a(m); + t1 = a.mk_uminus(t); + } + rw(t1, t2); + SASSERT(is_app(t2)); + m_objs.push_back(to_app(t2)); + m_is_max.push_back(is_max); + } + } diff --git a/src/opt/optimize_objectives.h b/src/opt/optimize_objectives.h index c9f5ffc55..6519bb42f 100644 --- a/src/opt/optimize_objectives.h +++ b/src/opt/optimize_objectives.h @@ -28,18 +28,21 @@ namespace opt { */ class optimize_objectives { - ast_manager& m; - opt_solver* s; - volatile bool m_cancel; - vector m_lower; - vector m_upper; - app_ref_vector m_objs; + ast_manager& m; + opt_solver* s; + volatile bool m_cancel; + vector m_lower; + vector m_upper; + app_ref_vector m_objs; + svector m_is_max; svector m_vars; symbol m_engine; public: optimize_objectives(ast_manager& m): m(m), s(0), m_cancel(false), m_objs(m) {} - lbool operator()(opt_solver& s, app_ref_vector const& objectives); + lbool operator()(opt_solver& s); + + void add(app* t, bool is_max); void set_cancel(bool f); From 29cc9025cbdecaded97f1addd98b5469ce1c051e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Nov 2013 12:41:05 -0800 Subject: [PATCH 103/925] renaming to optsmt Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.h | 4 ++-- .../{optimize_objectives.cpp => optsmt.cpp} | 24 +++++++++---------- src/opt/{optimize_objectives.h => optsmt.h} | 6 ++--- 3 files changed, 17 insertions(+), 17 deletions(-) rename src/opt/{optimize_objectives.cpp => optsmt.cpp} (92%) rename src/opt/{optimize_objectives.h => optsmt.h} (89%) diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index fd4e52b17..beae83fe0 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -27,7 +27,7 @@ Notes: #include "ast.h" #include "solver.h" -#include "optimize_objectives.h" +#include "optsmt.h" #include "opt_maxsmt.h" namespace opt { @@ -39,7 +39,7 @@ namespace opt { expr_ref_vector m_hard_constraints; ref m_solver; params_ref m_params; - optimize_objectives m_optsmt; + optsmt m_optsmt; maxsmt m_maxsmt; public: context(ast_manager& m); diff --git a/src/opt/optimize_objectives.cpp b/src/opt/optsmt.cpp similarity index 92% rename from src/opt/optimize_objectives.cpp rename to src/opt/optsmt.cpp index 663f3a52c..4dcefb577 100644 --- a/src/opt/optimize_objectives.cpp +++ b/src/opt/optsmt.cpp @@ -3,7 +3,7 @@ Copyright (c) 2013 Microsoft Corporation Module Name: - optimize_objectives.cpp + optsmt.cpp Abstract: @@ -40,7 +40,7 @@ Notes: #ifndef _OPT_OBJECTIVE_H_ #define _OPT_OBJECTIVE_H_ -#include "optimize_objectives.h" +#include "optsmt.h" #include "opt_solver.h" #include "arith_decl_plugin.h" #include "theory_arith.h" @@ -51,11 +51,11 @@ Notes: namespace opt { - void optimize_objectives::set_cancel(bool f) { + void optsmt::set_cancel(bool f) { m_cancel = true; } - void optimize_objectives::set_max(vector& dst, vector const& src) { + void optsmt::set_max(vector& dst, vector const& src) { for (unsigned i = 0; i < src.size(); ++i) { if (src[i] > dst[i]) { dst[i] = src[i]; @@ -66,7 +66,7 @@ namespace opt { /* Enumerate locally optimal assignments until fixedpoint. */ - lbool optimize_objectives::basic_opt() { + lbool optsmt::basic_opt() { opt_solver::toggle_objective _t(*s, true); lbool is_sat = l_true; @@ -86,7 +86,7 @@ namespace opt { /* Enumerate locally optimal assignments until fixedpoint. */ - lbool optimize_objectives::farkas_opt() { + lbool optsmt::farkas_opt() { smt::theory_opt& opt = s->get_optimizer(); IF_VERBOSE(1, verbose_stream() << typeid(opt).name() << "\n";); @@ -107,7 +107,7 @@ namespace opt { return l_true; } - void optimize_objectives::update_lower() { + void optsmt::update_lower() { model_ref md; s->get_model(md); set_max(m_lower, s->get_objective_values()); @@ -129,7 +129,7 @@ namespace opt { s->assert_expr(constraint); } - lbool optimize_objectives::update_upper() { + lbool optsmt::update_upper() { smt::theory_opt& opt = s->get_optimizer(); SASSERT(typeid(smt::theory_inf_arith) == typeid(opt)); @@ -205,7 +205,7 @@ namespace opt { Takes solver with hard constraints added. Returns an optimal assignment to objective functions. */ - lbool optimize_objectives::operator()(opt_solver& solver) { + lbool optsmt::operator()(opt_solver& solver) { s = &solver; s->reset_objectives(); m_lower.reset(); @@ -245,7 +245,7 @@ namespace opt { return is_sat; } - inf_eps optimize_objectives::get_value(bool as_positive, unsigned index) const { + inf_eps optsmt::get_value(bool as_positive, unsigned index) const { if (as_positive) { return m_lower[index]; } @@ -254,7 +254,7 @@ namespace opt { } } - void optimize_objectives::display(std::ostream& out) const { + void optsmt::display(std::ostream& out) const { unsigned sz = m_objs.size(); for (unsigned i = 0; i < sz; ++i) { bool is_max = m_is_max[i]; @@ -270,7 +270,7 @@ namespace opt { } } - void optimize_objectives::add(app* t, bool is_max) { + void optsmt::add(app* t, bool is_max) { expr_ref t1(t, m), t2(m); th_rewriter rw(m); if (!is_max) { diff --git a/src/opt/optimize_objectives.h b/src/opt/optsmt.h similarity index 89% rename from src/opt/optimize_objectives.h rename to src/opt/optsmt.h index 6519bb42f..1d51dadfc 100644 --- a/src/opt/optimize_objectives.h +++ b/src/opt/optsmt.h @@ -3,7 +3,7 @@ Copyright (c) 2013 Microsoft Corporation Module Name: - optimize_objectives.h + optsmt.h Abstract: @@ -27,7 +27,7 @@ namespace opt { Returns an optimal assignment to objective functions. */ - class optimize_objectives { + class optsmt { ast_manager& m; opt_solver* s; volatile bool m_cancel; @@ -38,7 +38,7 @@ namespace opt { svector m_vars; symbol m_engine; public: - optimize_objectives(ast_manager& m): m(m), s(0), m_cancel(false), m_objs(m) {} + optsmt(ast_manager& m): m(m), s(0), m_cancel(false), m_objs(m) {} lbool operator()(opt_solver& s); From 6caee5e3ca432ba4ea1cc71803a0ba60545b6e54 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Nov 2013 13:16:10 -0800 Subject: [PATCH 104/925] more refactoring Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 33 +++++------------- src/opt/opt_context.h | 7 ++-- src/opt/opt_maxsmt.cpp | 75 ----------------------------------------- src/opt/opt_maxsmt.h | 66 ------------------------------------ src/opt/opt_solver.cpp | 7 ++++ src/opt/opt_solver.h | 6 ++-- src/opt/optsmt.cpp | 11 ++++-- src/opt/optsmt.h | 6 ++-- 8 files changed, 34 insertions(+), 177 deletions(-) delete mode 100644 src/opt/opt_maxsmt.cpp delete mode 100644 src/opt/opt_maxsmt.h diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index dbb2b7eb9..93f7e1acd 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -27,7 +27,6 @@ Notes: #include "th_rewriter.h" #include "opt_params.hpp" - namespace opt { context::context(ast_manager& m): @@ -49,7 +48,7 @@ namespace opt { // really just works for opt_solver now. solver* s = m_solver.get(); - opt_solver::scoped_push _sp(get_opt_solver(*s)); + opt_solver::scoped_push _sp(*s); for (unsigned i = 0; i < m_hard_constraints.size(); ++i) { s->assert_expr(m_hard_constraints[i].get()); @@ -57,7 +56,7 @@ namespace opt { lbool is_sat; - is_sat = m_maxsmt(get_opt_solver(*s)); + is_sat = m_maxsmt(*s); expr_ref_vector ans = m_maxsmt.get_assignment(); for (unsigned i = 0; i < ans.size(); ++i) { @@ -65,32 +64,17 @@ namespace opt { } if (is_sat == l_true) { - is_sat = m_optsmt(get_opt_solver(*s)); + is_sat = m_optsmt(opt_solver::to_opt(*s)); } } - opt_solver& context::get_opt_solver(solver& s) { - if (typeid(opt_solver) != typeid(s)) { - throw default_exception("BUG: optimization context has not been initialized correctly"); - } - return dynamic_cast(s); - } - - void context::cancel() { + void context::set_cancel(bool f) { if (m_solver) { - m_solver->cancel(); + m_solver->set_cancel(f); } - m_optsmt.set_cancel(true); - m_maxsmt.set_cancel(true); - } - - void context::reset_cancel() { - if (m_solver) { - m_solver->reset_cancel(); - } - m_optsmt.set_cancel(false); - m_maxsmt.set_cancel(false); + m_optsmt.set_cancel(f); + m_maxsmt.set_cancel(f); } void context::collect_statistics(statistics& stats) { @@ -108,8 +92,7 @@ namespace opt { if (m_solver) { m_solver->updt_params(m_params); } - opt_params _p(m_params); - m_optsmt.set_engine(_p.engine()); + m_optsmt.updt_params(m_params); } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index beae83fe0..df2ca8248 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -28,7 +28,7 @@ Notes: #include "ast.h" #include "solver.h" #include "optsmt.h" -#include "opt_maxsmt.h" +#include "maxsmt.h" namespace opt { @@ -49,8 +49,9 @@ namespace opt { void add_hard_constraint(expr* f) { m_hard_constraints.push_back(f); } void set_solver(solver* s) { m_solver = s; } void optimize(); - void cancel(); - void reset_cancel(); + void set_cancel(bool f); + void reset_cancel() { set_cancel(false); } + void cancel() { set_cancel(true); } void collect_statistics(statistics& stats); static void collect_param_descrs(param_descrs & r); void updt_params(params_ref& p); diff --git a/src/opt/opt_maxsmt.cpp b/src/opt/opt_maxsmt.cpp deleted file mode 100644 index 97c73b61f..000000000 --- a/src/opt/opt_maxsmt.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - opt_maxsmt.cpp - -Abstract: - - MaxSMT optimization context. - -Author: - - Nikolaj Bjorner (nbjorner) 2013-11-7 - -Notes: - ---*/ - -#include "opt_maxsmt.h" -#include "fu_malik.h" -#include "weighted_maxsat.h" -#include "ast_pp.h" - -namespace opt { - - lbool maxsmt::operator()(opt_solver& s) { - lbool is_sat; - m_answer.reset(); - m_answer.append(m_soft_constraints); - if (m_answer.empty()) { - is_sat = s.check_sat(0, 0); - } - else if (is_maxsat_problem(m_weights)) { - is_sat = opt::fu_malik_maxsat(s, m_answer); - } - else { - is_sat = weighted_maxsat(s, m_answer, m_weights); - } - - // Infrastructure for displaying and storing solution is TBD. - std::cout << "is-sat: " << is_sat << "\n"; - if (is_sat == l_true) { - std::cout << "Satisfying soft constraints\n"; - display_answer(std::cout); - } - return is_sat; - } - - expr_ref_vector maxsmt::get_assignment() const { - return m_answer; - } - - void maxsmt::display_answer(std::ostream& out) const { - for (unsigned i = 0; i < m_answer.size(); ++i) { - out << mk_pp(m_answer[i], m) << "\n"; - } - } - - void maxsmt::set_cancel(bool f) { - m_cancel = f; - } - - bool maxsmt::is_maxsat_problem(vector const& ws) const { - for (unsigned i = 0; i < ws.size(); ++i) { - if (!ws[i].is_one()) { - return false; - } - } - return true; - } - - - -}; diff --git a/src/opt/opt_maxsmt.h b/src/opt/opt_maxsmt.h deleted file mode 100644 index 0303e4a99..000000000 --- a/src/opt/opt_maxsmt.h +++ /dev/null @@ -1,66 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - opt_maxsmt.h - -Abstract: - - MaxSMT optimization context. - -Author: - - Nikolaj Bjorner (nbjorner) 2013-11-7 - -Notes: - ---*/ -#ifndef _OPT_MAXSMT_H_ -#define _OPT_MAXSMT_H_ - -#include "opt_solver.h" - -namespace opt { - /** - Takes solver with hard constraints added. - Returns modified soft constraints that are maximal assignments. - */ - - class maxsmt { - ast_manager& m; - opt_solver* s; - volatile bool m_cancel; - expr_ref_vector m_soft_constraints; - expr_ref_vector m_answer; - vector m_weights; - symbol m_engine; - public: - maxsmt(ast_manager& m): m(m), s(0), m_cancel(false), m_soft_constraints(m), m_answer(m) {} - - lbool operator()(opt_solver& s); - - void set_cancel(bool f); - - void add(expr* f, rational const& w) { - m_soft_constraints.push_back(f); - m_weights.push_back(w); - } - - void set_engine(symbol const& e) { m_engine = e; } - - // TBD: rational get_value() const; - - expr_ref_vector get_assignment() const; - - void display_answer(std::ostream& out) const; - - private: - - bool is_maxsat_problem(vector const& ws) const; - - }; - -}; - -#endif diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 998214464..cd31e870c 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -187,6 +187,13 @@ namespace opt { m_objective_values.reset(); } + opt_solver& opt_solver::to_opt(solver& s) { + if (typeid(opt_solver) != typeid(s)) { + throw default_exception("BUG: optimization context has not been initialized correctly"); + } + return dynamic_cast(s); + } + opt_solver::toggle_objective::toggle_objective(opt_solver& s, bool new_value): s(s), m_old_value(s.m_objective_enabled) { s.m_objective_enabled = new_value; } diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 4afa65f31..2c96e65ec 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -73,6 +73,8 @@ namespace opt { vector const& get_objective_values(); expr_ref block_lower_bound(unsigned obj_index, inf_eps const& val); + + static opt_solver& to_opt(solver& s); class toggle_objective { opt_solver& s; @@ -83,9 +85,9 @@ namespace opt { }; class scoped_push { - opt_solver& s; + solver& s; public: - scoped_push(opt_solver& s):s(s) { s.push(); } + scoped_push(solver& s):s(s) { s.push(); } ~scoped_push() { s.pop(1); } }; diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 4dcefb577..9c7268913 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -47,6 +47,7 @@ Notes: #include "ast_pp.h" #include "model_pp.h" #include "th_rewriter.h" +#include "opt_params.hpp" namespace opt { @@ -245,8 +246,8 @@ namespace opt { return is_sat; } - inf_eps optsmt::get_value(bool as_positive, unsigned index) const { - if (as_positive) { + inf_eps optsmt::get_value(unsigned index) const { + if (m_is_max[index]) { return m_lower[index]; } else { @@ -258,7 +259,7 @@ namespace opt { unsigned sz = m_objs.size(); for (unsigned i = 0; i < sz; ++i) { bool is_max = m_is_max[i]; - inf_eps val = get_value(is_max, i); + inf_eps val = get_value(i); expr_ref obj(m_objs[i], m); if (!is_max) { arith_util a(m); @@ -283,6 +284,10 @@ namespace opt { m_is_max.push_back(is_max); } + void optsmt::updt_params(params_ref& p) { + opt_params _p(p); + m_engine = _p.engine(); + } } diff --git a/src/opt/optsmt.h b/src/opt/optsmt.h index 1d51dadfc..297f924ae 100644 --- a/src/opt/optsmt.h +++ b/src/opt/optsmt.h @@ -36,7 +36,7 @@ namespace opt { app_ref_vector m_objs; svector m_is_max; svector m_vars; - symbol m_engine; + symbol m_engine; public: optsmt(ast_manager& m): m(m), s(0), m_cancel(false), m_objs(m) {} @@ -46,11 +46,11 @@ namespace opt { void set_cancel(bool f); - void set_engine(symbol const& e) { m_engine = e; } + void updt_params(params_ref& p); void display(std::ostream& out) const; - inf_eps get_value(bool as_positive, unsigned index) const; + inf_eps get_value(unsigned index) const; private: From f350efffc7aad89f622948dac81a56ff3eaa84dc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Nov 2013 13:52:27 -0800 Subject: [PATCH 105/925] working on pareto and upper/lower bound facilities Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 27 +++++++-------------------- src/opt/opt_context.h | 11 ++--------- src/opt/optsmt.cpp | 31 ++++++++++++++++++++++--------- src/opt/optsmt.h | 6 +++++- 4 files changed, 36 insertions(+), 39 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 93f7e1acd..69ec91d85 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -37,38 +37,24 @@ namespace opt { { m_params.set_bool("model", true); m_params.set_bool("unsat_core", true); + m_solver = alloc(opt_solver, m, m_params, symbol()); } void context::optimize() { - if (!m_solver) { - symbol logic; - set_solver(alloc(opt_solver, m, m_params, logic)); - } - - // really just works for opt_solver now. - solver* s = m_solver.get(); - opt_solver::scoped_push _sp(*s); + opt_solver& s = *m_solver.get(); + opt_solver::scoped_push _sp(s); for (unsigned i = 0; i < m_hard_constraints.size(); ++i) { - s->assert_expr(m_hard_constraints[i].get()); + s.assert_expr(m_hard_constraints[i].get()); } - lbool is_sat; - - is_sat = m_maxsmt(*s); - - expr_ref_vector ans = m_maxsmt.get_assignment(); - for (unsigned i = 0; i < ans.size(); ++i) { - s->assert_expr(ans[i].get()); - } - + lbool is_sat = m_maxsmt(s); if (is_sat == l_true) { - is_sat = m_optsmt(opt_solver::to_opt(*s)); + is_sat = m_optsmt(s); } } - void context::set_cancel(bool f) { if (m_solver) { m_solver->set_cancel(f); @@ -93,6 +79,7 @@ namespace opt { m_solver->updt_params(m_params); } m_optsmt.updt_params(m_params); + m_maxsmt.updt_params(m_params); } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index df2ca8248..22fd5fd7a 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -26,7 +26,7 @@ Notes: #define _OPT_CONTEXT_H_ #include "ast.h" -#include "solver.h" +#include "opt_solver.h" #include "optsmt.h" #include "maxsmt.h" @@ -37,7 +37,7 @@ namespace opt { class context { ast_manager& m; expr_ref_vector m_hard_constraints; - ref m_solver; + ref m_solver; params_ref m_params; optsmt m_optsmt; maxsmt m_maxsmt; @@ -47,7 +47,6 @@ namespace opt { void add_soft_constraint(expr* f, rational const& w) { m_maxsmt.add(f, w); } void add_objective(app* t, bool is_max) { m_optsmt.add(t, is_max); } void add_hard_constraint(expr* f) { m_hard_constraints.push_back(f); } - void set_solver(solver* s) { m_solver = s; } void optimize(); void set_cancel(bool f); void reset_cancel() { set_cancel(false); } @@ -55,12 +54,6 @@ namespace opt { void collect_statistics(statistics& stats); static void collect_param_descrs(param_descrs & r); void updt_params(params_ref& p); - - private: - bool is_maxsat_problem() const; - - opt_solver& get_opt_solver(solver& s); - }; } diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 9c7268913..a6dbd30ab 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -132,9 +132,7 @@ namespace opt { lbool optsmt::update_upper() { smt::theory_opt& opt = s->get_optimizer(); - SASSERT(typeid(smt::theory_inf_arith) == typeid(opt)); - smt::theory_inf_arith& th = dynamic_cast(opt); expr_ref bound(m); @@ -246,13 +244,28 @@ namespace opt { return is_sat; } - inf_eps optsmt::get_value(unsigned index) const { - if (m_is_max[index]) { - return m_lower[index]; - } - else { - return -m_lower[index]; - } + inf_eps optsmt::get_value(unsigned i) const { + return m_is_max[i]?m_lower[i]:-m_lower[i]; + } + + inf_eps optsmt::get_lower(unsigned i) const { + return m_is_max[i]?m_lower[i]:-m_upper[i]; + } + + inf_eps optsmt::get_upper(unsigned i) const { + return m_is_max[i]?m_upper[i]:-m_lower[i]; + } + + // force lower_bound(i) <= objective_value(i) + void optsmt::commit_assignment(unsigned i) { + smt::theory_var v = m_vars[i]; + + // TBD: this should be a method on all optimization solvers. + smt::theory_opt& opt = s->get_optimizer(); + SASSERT(typeid(smt::theory_inf_arith) == typeid(opt)); + smt::theory_inf_arith& th = dynamic_cast(opt); + + s->assert_expr(th.block_upper_bound(v, get_lower(i))); } void optsmt::display(std::ostream& out) const { diff --git a/src/opt/optsmt.h b/src/opt/optsmt.h index 297f924ae..b892ef38f 100644 --- a/src/opt/optsmt.h +++ b/src/opt/optsmt.h @@ -44,6 +44,8 @@ namespace opt { void add(app* t, bool is_max); + void commit_assignment(unsigned i); + void set_cancel(bool f); void updt_params(params_ref& p); @@ -51,7 +53,9 @@ namespace opt { void display(std::ostream& out) const; inf_eps get_value(unsigned index) const; - + inf_eps get_lower(unsigned index) const; + inf_eps get_upper(unsigned index) const; + private: lbool basic_opt(); From 9f53a4aa18d7b4c2c51b17f427a3c547ce09f636 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Nov 2013 16:54:34 -0800 Subject: [PATCH 106/925] working on supporting multiple max-sat objectives Signed-off-by: Nikolaj Bjorner --- src/opt/opt_cmds.cpp | 20 ++++++++++++++++--- src/opt/opt_context.cpp | 38 +++++++++++++++++++++++++++++++------ src/opt/opt_context.h | 7 ++++--- src/opt/opt_solver.cpp | 10 +++++++++- src/opt/opt_solver.h | 1 + src/opt/optsmt.cpp | 8 +------- src/opt/weighted_maxsat.cpp | 4 +--- 7 files changed, 65 insertions(+), 23 deletions(-) diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index e08b9652f..ad5985d1c 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -50,6 +50,7 @@ class assert_weighted_cmd : public cmd { unsigned m_idx; expr* m_formula; rational m_weight; + symbol m_id; public: assert_weighted_cmd(cmd_context& ctx, opt_context& opt_ctx): @@ -70,15 +71,22 @@ public: } m_idx = 0; m_formula = 0; + m_id = symbol::null; } virtual char const * get_usage() const { return " "; } virtual char const * get_descr(cmd_context & ctx) const { return "assert soft constraint with weight"; } - virtual unsigned get_arity() const { return 2; } + virtual unsigned get_arity() const { return VAR_ARITY; } // command invocation virtual void prepare(cmd_context & ctx) {} - virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { if (m_idx == 0) return CPK_EXPR; return CPK_NUMERAL; } + virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { + switch(m_idx) { + case 0: return CPK_EXPR; + case 1: return CPK_NUMERAL; + default: return CPK_SYMBOL; + } + } virtual void set_next_arg(cmd_context & ctx, rational const & val) { SASSERT(m_idx == 1); if (!val.is_pos()) { @@ -98,12 +106,18 @@ public: ++m_idx; } + virtual void set_next_arg(cmd_context & ctx, symbol const& s) { + SASSERT(m_idx > 1); + m_id = s; + ++m_idx; + } + virtual void failure_cleanup(cmd_context & ctx) { reset(ctx); } virtual void execute(cmd_context & ctx) { - m_opt_ctx().add_soft_constraint(m_formula, m_weight); + m_opt_ctx().add_soft_constraint(m_formula, m_weight, m_id); reset(ctx); } diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 69ec91d85..ede93b34a 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -32,14 +32,29 @@ namespace opt { context::context(ast_manager& m): m(m), m_hard_constraints(m), - m_optsmt(m), - m_maxsmt(m) + m_optsmt(m) { m_params.set_bool("model", true); m_params.set_bool("unsat_core", true); m_solver = alloc(opt_solver, m, m_params, symbol()); } + context::~context() { + map_t::iterator it = m_maxsmts.begin(), end = m_maxsmts.end(); + for (; it != end; ++it) { + dealloc(it->m_value); + } + } + + void context::add_soft_constraint(expr* f, rational const& w, symbol const& id) { + maxsmt* ms; + if (!m_maxsmts.find(id, ms)) { + ms = alloc(maxsmt, m); + m_maxsmts.insert(id, ms); + } + ms->add(f, w); + } + void context::optimize() { opt_solver& s = *m_solver.get(); @@ -48,8 +63,13 @@ namespace opt { for (unsigned i = 0; i < m_hard_constraints.size(); ++i) { s.assert_expr(m_hard_constraints[i].get()); } - - lbool is_sat = m_maxsmt(s); + + lbool is_sat = l_true; + map_t::iterator it = m_maxsmts.begin(), end = m_maxsmts.end(); + for (; is_sat == l_true && it != end; ++it) { + maxsmt* ms = it->m_value; + is_sat = (*ms)(s); + } if (is_sat == l_true) { is_sat = m_optsmt(s); } @@ -60,7 +80,10 @@ namespace opt { m_solver->set_cancel(f); } m_optsmt.set_cancel(f); - m_maxsmt.set_cancel(f); + map_t::iterator it = m_maxsmts.begin(), end = m_maxsmts.end(); + for (; it != end; ++it) { + it->m_value->set_cancel(f); + } } void context::collect_statistics(statistics& stats) { @@ -79,7 +102,10 @@ namespace opt { m_solver->updt_params(m_params); } m_optsmt.updt_params(m_params); - m_maxsmt.updt_params(m_params); + map_t::iterator it = m_maxsmts.begin(), end = m_maxsmts.end(); + for (; it != end; ++it) { + it->m_value->updt_params(m_params); + } } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 22fd5fd7a..c9388a56a 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -35,16 +35,17 @@ namespace opt { class opt_solver; class context { + typedef map map_t; ast_manager& m; expr_ref_vector m_hard_constraints; ref m_solver; params_ref m_params; optsmt m_optsmt; - maxsmt m_maxsmt; + map_t m_maxsmts; public: context(ast_manager& m); - - void add_soft_constraint(expr* f, rational const& w) { m_maxsmt.add(f, w); } + ~context(); + void add_soft_constraint(expr* f, rational const& w, symbol const& id); void add_objective(app* t, bool is_max) { m_optsmt.add(t, is_max); } void add_hard_constraint(expr* f) { m_hard_constraints.push_back(f); } void optimize(); diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index cd31e870c..750b8d700 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -168,7 +168,15 @@ namespace opt { vector const& opt_solver::get_objective_values() { return m_objective_values; } - + + expr_ref opt_solver::block_upper_bound(unsigned var, inf_eps const& val) { + smt::theory_opt& opt = get_optimizer(); + SASSERT(typeid(smt::theory_inf_arith) == typeid(opt)); + smt::theory_inf_arith& th = dynamic_cast(opt); + smt::theory_var v = m_objective_vars[var]; + return expr_ref(th.block_upper_bound(v, val), m); + } + expr_ref opt_solver::block_lower_bound(unsigned var, inf_eps const& val) { if (val.get_infinity().is_pos()) { return expr_ref(m.mk_false(), m); diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 2c96e65ec..fa9a5e031 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -73,6 +73,7 @@ namespace opt { vector const& get_objective_values(); expr_ref block_lower_bound(unsigned obj_index, inf_eps const& val); + expr_ref block_upper_bound(unsigned obj_index, inf_eps const& val); static opt_solver& to_opt(solver& s); diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index a6dbd30ab..28dd95f67 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -259,13 +259,7 @@ namespace opt { // force lower_bound(i) <= objective_value(i) void optsmt::commit_assignment(unsigned i) { smt::theory_var v = m_vars[i]; - - // TBD: this should be a method on all optimization solvers. - smt::theory_opt& opt = s->get_optimizer(); - SASSERT(typeid(smt::theory_inf_arith) == typeid(opt)); - smt::theory_inf_arith& th = dynamic_cast(opt); - - s->assert_expr(th.block_upper_bound(v, get_lower(i))); + s->assert_expr(s->block_upper_bound(i, get_lower(i))); } void optsmt::display(std::ostream& out) const { diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 204e6d656..b74bb1ab8 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -226,9 +226,7 @@ namespace smt { m_cost_save.append(m_costs); } return !lits.empty(); - } - - + } }; } From 5a27c035e4c544ec48ae86c951e0c37a406db790 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Fri, 8 Nov 2013 18:00:48 -0800 Subject: [PATCH 107/925] Add a vector of edges to handle spanning trees --- src/smt/network_flow.h | 3 +- src/smt/network_flow_def.h | 95 ++++++++++++++++++----------------- src/smt/spanning_tree.h | 34 +++++++------ src/smt/spanning_tree_base.h | 10 ++-- src/smt/spanning_tree_def.h | 96 +++++++++++++++++++++--------------- 5 files changed, 129 insertions(+), 109 deletions(-) diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index 6ac46f0d5..44861575a 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -51,7 +51,7 @@ namespace smt { typedef typename Ext::fin_numeral fin_numeral; graph m_graph; - spanning_tree_base m_tree; + thread_spanning_tree m_tree; // Denote supply/demand b_i on node i vector m_balances; @@ -68,7 +68,6 @@ namespace smt { edge_id m_enter_id, m_leave_id; optional m_delta; - bool m_is_swap_enter, m_is_swap_leave; // Initialize the network with a feasible spanning tree void initialize(); diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index ca3e6db29..d31289dfc 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -27,7 +27,8 @@ namespace smt { template network_flow::network_flow(graph & g, vector const & balances) : - m_balances(balances) { + m_balances(balances), + m_tree(m_graph) { // Network flow graph has the edges in the reversed order compared to constraint graph // We only take enabled edges from the original graph for (unsigned i = 0; i < g.get_num_nodes(); ++i) { @@ -40,14 +41,13 @@ namespace smt { m_graph.add_edge(e.get_target(), e.get_source(), e.get_weight(), explanation()); } } - m_tree = thread_spanning_tree(m_graph); m_step = 0; } template void network_flow::initialize() { TRACE("network_flow", tout << "initialize...\n";); - // Create an artificial root node to construct initial spanning m_tree + // Create an artificial root node to construct initial spanning tree unsigned num_nodes = m_graph.get_num_nodes(); unsigned num_edges = m_graph.get_num_edges(); @@ -69,39 +69,44 @@ namespace smt { m_states.resize(num_nodes + num_edges); m_states.fill(LOWER); - // Create artificial edges from/to root node to/from other nodes and initialize the spanning m_tree - svector upwards(num_nodes, false); + // Create artificial edges from/to root node to/from other nodes and initialize the spanning tree + svector tree; + bool is_forward; for (unsigned i = 0; i < num_nodes; ++i) { - upwards[i] = !m_balances[i].is_neg(); + is_forward = !m_balances[i].is_neg(); m_states[num_edges + i] = BASIS; - node src = upwards[i] ? i : root; - node tgt = upwards[i] ? root : i; - m_flows[num_edges + i] = upwards[i] ? m_balances[i] : -m_balances[i]; - m_potentials[i] = upwards[i] ? numeral::one() : -numeral::one(); - m_graph.add_edge(src, tgt, numeral::one(), explanation()); + node src = is_forward ? i : root; + node tgt = is_forward ? root : i; + m_flows[num_edges + i] = is_forward ? m_balances[i] : -m_balances[i]; + m_potentials[i] = is_forward ? numeral::one() : -numeral::one(); + tree.push_back(m_graph.add_edge(src, tgt, numeral::one(), explanation())); } - m_tree.initialize(upwards); + m_tree.initialize(tree); TRACE("network_flow", { tout << pp_vector("Potentials", m_potentials, true) << pp_vector("Flows", m_flows); }); - TRACE("network_flow", tout << "Spanning m_tree:\n" << display_spanning_tree();); + TRACE("network_flow", tout << "Spanning tree:\n" << display_spanning_tree();); SASSERT(check_well_formed()); } template void network_flow::update_potentials() { node src = m_graph.get_source(m_enter_id); - node tgt = m_graph.get_target(m_enter_id); + node tgt = m_graph.get_target(m_enter_id); numeral cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(m_enter_id); - numeral change = m_is_swap_leave ? -cost : cost; + numeral change = m_tree.in_subtree_t2(tgt) ? cost : -cost; + node start = m_graph.get_source(m_leave_id); + if (!m_tree.in_subtree_t2(start)) { + start = m_graph.get_target(m_leave_id);; + } + TRACE("network_flow", tout << "update_potentials of T_" << start << " with change = " << change << "...\n";); svector descendants; - node start = m_is_swap_enter ? src : tgt; - TRACE("network_flow", tout << "update_potentials of T_" << start << " with delta = " << change << "...\n";); m_tree.get_descendants(start, descendants); + SASSERT(descendants.size() >= 1); for (unsigned i = 0; i < descendants.size(); ++i) { - node u = descendants[i]; + node u = descendants[i]; m_potentials[u] += change; } TRACE("network_flow", tout << pp_vector("Potentials", m_potentials, true);); @@ -110,25 +115,25 @@ namespace smt { template void network_flow::update_flows() { TRACE("network_flow", tout << "update_flows...\n";); - numeral val = *m_delta; - m_flows[m_enter_id] += val; + m_flows[m_enter_id] += *m_delta; node src = m_graph.get_source(m_enter_id); node tgt = m_graph.get_target(m_enter_id); svector path; svector against; m_tree.get_path(src, tgt, path, against); + SASSERT(path.size() >= 1); for (unsigned i = 0; i < path.size(); ++i) { edge_id e_id = path[i]; - m_flows[e_id] += against[i] ? -val : val; + m_flows[e_id] += against[i] ? - *m_delta : *m_delta; } TRACE("network_flow", tout << pp_vector("Flows", m_flows, true);); } template bool network_flow::choose_entering_edge() { - TRACE("network_flow", tout << "choose_entering_edge...\n";); - vector const & es = m_graph.get_all_edges(); - for (unsigned i = 0; i < es.size(); ++i) { + TRACE("network_flow", tout << "choose_entering_edge...\n";); + unsigned num_edges = m_graph.get_num_edges(); + for (unsigned i = 0; i < num_edges; ++i) { node src = m_graph.get_source(i); node tgt = m_graph.get_target(i); if (m_states[i] != BASIS) { @@ -138,7 +143,7 @@ namespace smt { m_enter_id = i; TRACE("network_flow", { tout << "Found entering edge " << i << " between node "; - tout << src << " and node " << tgt << "...\n"; + tout << src << " and node " << tgt << " with reduced cost = " << cost << "...\n"; }); return true; } @@ -158,9 +163,10 @@ namespace smt { svector path; svector against; m_tree.get_path(src, tgt, path, against); + SASSERT(path.size() >= 1); for (unsigned i = 0; i < path.size(); ++i) { edge_id e_id = path[i]; - if (against[i] && (!m_delta || m_flows[e_id] <= *m_delta)) { + if (against[i] && (!m_delta || m_flows[e_id] < *m_delta)) { m_delta = m_flows[e_id]; leave_id = e_id; } @@ -182,7 +188,7 @@ namespace smt { template void network_flow::update_spanning_tree() { - m_tree.update(m_enter_id, m_leave_id, m_is_swap_enter, m_is_swap_leave); + m_tree.update(m_enter_id, m_leave_id); } // Minimize cost flows @@ -201,7 +207,7 @@ namespace smt { m_states[m_leave_id] = (m_flows[m_leave_id].is_zero()) ? LOWER : UPPER; update_spanning_tree(); update_potentials(); - TRACE("network_flow", tout << "Spanning m_tree:\n" << display_spanning_tree();); + TRACE("network_flow", tout << "Spanning tree:\n" << display_spanning_tree();); SASSERT(check_well_formed()); } else { @@ -217,12 +223,11 @@ namespace smt { template typename network_flow::numeral network_flow::get_optimal_solution(vector & result, bool is_dual) { numeral objective_value = numeral::zero(); - vector const & es = m_graph.get_all_edges(); - for (unsigned i = 0; i < es.size(); ++i) { - edge const & e = es[i]; + unsigned num_edges = m_graph.get_num_edges(); + for (unsigned i = 0; i < num_edges; ++i) { if (m_states[i] == BASIS) { - objective_value += e.get_weight().get_rational() * m_flows[i]; + objective_value += m_graph.get_weight(i).get_rational() * m_flows[i]; } } result.reset(); @@ -243,6 +248,7 @@ namespace smt { template bool network_flow::check_well_formed() { SASSERT(m_tree.check_well_formed()); + SASSERT(!m_delta || !(*m_delta).is_neg()); // m_flows are zero on non-basic edges for (unsigned i = 0; i < m_flows.size(); ++i) { @@ -250,11 +256,10 @@ namespace smt { SASSERT(m_states[i] == BASIS || m_flows[i].is_zero()); } - vector const & es = m_graph.get_all_edges(); - for (unsigned i = 0; i < es.size(); ++i) { - edge const & e = es[i]; + unsigned num_edges = m_graph.get_num_edges(); + for (unsigned i = 0; i < num_edges; ++i) { if (m_states[i] == BASIS) { - SASSERT(m_potentials[e.get_source()] - m_potentials[e.get_target()] == e.get_weight()); + SASSERT(m_potentials[m_graph.get_source(i)] - m_potentials[m_graph.get_target(i)] == m_graph.get_weight(i)); } } @@ -264,11 +269,10 @@ namespace smt { template bool network_flow::check_optimal() { numeral total_cost = numeral::zero(); - vector const & es = m_graph.get_all_edges(); - for (unsigned i = 0; i < es.size(); ++i) { - edge const & e = es[i]; + unsigned num_edges = m_graph.get_num_edges(); + for (unsigned i = 0; i < num_edges; ++i) { if (m_states[i] == BASIS) { - total_cost += e.get_weight().get_rational() * m_flows[i]; + total_cost += m_graph.get_weight(i).get_rational() * m_flows[i]; } } @@ -299,15 +303,14 @@ namespace smt { oss << prefix << root << "[shape=doublecircle,label=\"" << prefix << root << " ["; oss << m_potentials[root] << "/" << m_balances[root] << "]\"];\n"; - vector const & es = m_graph.get_all_edges(); - for (unsigned i = 0; i < es.size(); ++i) { - edge const & e = es[i]; - oss << prefix << e.get_source() << " -> " << prefix << e.get_target(); + unsigned num_edges = m_graph.get_num_edges(); + for (unsigned i = 0; i < num_edges; ++i) { + oss << prefix << m_graph.get_source(i) << " -> " << prefix << m_graph.get_target(i); if (m_states[i] == BASIS) { - oss << "[color=red,penwidth=3.0,label=\"" << m_flows[i] << "/" << e.get_weight() << "\"];\n"; + oss << "[color=red,penwidth=3.0,label=\"" << m_flows[i] << "/" << m_graph.get_weight(i) << "\"];\n"; } else { - oss << "[label=\"" << m_flows[i] << "/" << e.get_weight() << "\"];\n"; + oss << "[label=\"" << m_flows[i] << "/" << m_graph.get_weight(i) << "\"];\n"; } } oss << std::endl; diff --git a/src/smt/spanning_tree.h b/src/smt/spanning_tree.h index e085d4542..c591f5485 100644 --- a/src/smt/spanning_tree.h +++ b/src/smt/spanning_tree.h @@ -40,9 +40,10 @@ namespace smt { // Store the pointer from node i to the next node in depth-first search order svector m_thread; - // m_upwards[i] is true if the corresponding edge - // (i, m_pred[i]) points upwards (pointing toward the root node) - svector m_upwards; + // i |-> edge between (i, m_pred[i]) + svector m_tree; + + node m_root_t2; graph & m_graph; @@ -50,21 +51,24 @@ namespace smt { node find_rev_thread(node n) const; void fix_depth(node start, node end); node get_final(int start); - bool is_preorder_traversal(node start, node end); - edge_id get_edge_to_parent(node start) const; + bool is_preorder_traversal(node start, node end); node get_common_ancestor(node u, node v); - - public: - thread_spanning_tree(graph & g); - - void initialize(svector const & upwards); - void get_descendants(node start, svector & descendants); - - void update(edge_id enter_id, edge_id leave_id, bool & is_swap_enter, bool & is_swap_leave); - bool check_well_formed(); - void get_path(node start, node end, svector & path, svector & against); bool is_forward_edge(edge_id e_id) const; bool is_ancestor_of(node ancestor, node child); + + public: + thread_spanning_tree() {}; + thread_spanning_tree(graph & g); + ~thread_spanning_tree() {}; + + void initialize(svector const & tree); + void get_descendants(node start, svector & descendants); + + void update(edge_id enter_id, edge_id leave_id); + void get_path(node start, node end, svector & path, svector & against); + bool in_subtree_t2(node child); + + bool check_well_formed(); }; } diff --git a/src/smt/spanning_tree_base.h b/src/smt/spanning_tree_base.h index 17f49980c..e492f80fa 100644 --- a/src/smt/spanning_tree_base.h +++ b/src/smt/spanning_tree_base.h @@ -47,14 +47,14 @@ namespace smt { typedef int node; public: - virtual void initialize(svector const & upwards) {}; + virtual void initialize(svector const & tree) {}; virtual void get_descendants(node start, svector & descendants) {}; - virtual void update(edge_id enter_id, edge_id leave_id, bool & is_swap_enter, bool & is_swap_leave) {}; - virtual bool check_well_formed() {UNREACHABLE(); return false;}; + virtual void update(edge_id enter_id, edge_id leave_id) {}; virtual void get_path(node start, node end, svector & path, svector & against) {}; - virtual bool is_forward_edge(edge_id e_id) const {UNREACHABLE(); return false;}; - virtual bool is_ancestor_of(node ancestor, node child) {UNREACHABLE(); return false;}; + virtual bool in_subtree_t2(node child) {UNREACHABLE(); return false;}; + + virtual bool check_well_formed() {UNREACHABLE(); return false;}; }; } diff --git a/src/smt/spanning_tree_def.h b/src/smt/spanning_tree_def.h index fb2b3c6f3..2be593842 100644 --- a/src/smt/spanning_tree_def.h +++ b/src/smt/spanning_tree_def.h @@ -29,14 +29,15 @@ namespace smt { } template - void thread_spanning_tree::initialize(svector const & upwards) { + void thread_spanning_tree::initialize(svector const & tree) { + m_tree = tree; + unsigned num_nodes = m_graph.get_num_nodes(); m_pred.resize(num_nodes); m_depth.resize(num_nodes); m_thread.resize(num_nodes); - m_upwards.resize(num_nodes); - - node root = m_graph.get_num_nodes() - 1; + + node root = num_nodes - 1; m_pred[root] = -1; m_depth[root] = 0; m_thread[root] = 0; @@ -46,12 +47,11 @@ namespace smt { m_pred[i] = root; m_depth[i] = 1; m_thread[i] = i + 1; - m_upwards[i] = upwards[i]; } TRACE("network_flow", { tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Threads", m_thread); - tout << pp_vector("Depths", m_depth) << pp_vector("Upwards", m_upwards); + tout << pp_vector("Depths", m_depth) << pp_vector("Tree", m_tree); }); } @@ -66,27 +66,18 @@ namespace smt { return u; } - template - edge_id thread_spanning_tree::get_edge_to_parent(node start) const { - SASSERT(m_pred[start] != -1); - edge_id id; - node end = m_pred[start]; - VERIFY(m_upwards[start] ? m_graph.get_edge_id(start, end, id) : m_graph.get_edge_id(end, start, id)); - return id; - } - template void thread_spanning_tree::get_path(node start, node end, svector & path, svector & against) { node join = get_common_ancestor(start, end); path.reset(); while (start != join) { - edge_id e_id = get_edge_to_parent(start); + edge_id e_id = m_tree[start]; path.push_back(e_id); against.push_back(is_forward_edge(e_id)); start = m_pred[start]; } while (end != join) { - edge_id e_id = get_edge_to_parent(end); + edge_id e_id = m_tree[end]; path.push_back(e_id); against.push_back(!is_forward_edge(e_id)); end = m_pred[end]; @@ -103,12 +94,22 @@ namespace smt { template void thread_spanning_tree::get_descendants(node start, svector & descendants) { - descendants.reset(); - node u = start; - while (m_depth[m_thread[u]] > m_depth[start]) { + descendants.reset(); + descendants.push_back(start); + node u = m_thread[start]; + while (m_depth[u] > m_depth[start]) { descendants.push_back(u); u = m_thread[u]; } + + } + + template + bool thread_spanning_tree::in_subtree_t2(node child) { + if (m_depth[child] < m_depth[m_root_t2]) { + return false; + } + return is_ancestor_of(m_root_t2, child); } template @@ -138,7 +139,7 @@ namespace smt { q q */ template - void thread_spanning_tree::update(edge_id enter_id, edge_id leave_id, bool & is_swap_enter, bool & is_swap_leave) { + void thread_spanning_tree::update(edge_id enter_id, edge_id leave_id) { node p = m_graph.get_source(enter_id); node q = m_graph.get_target(enter_id); node u = m_graph.get_source(leave_id); @@ -146,54 +147,61 @@ namespace smt { if (m_pred[u] == v) { std::swap(u, v); - is_swap_leave = true; - } - else { - is_swap_leave = false; } + SASSERT(m_pred[v] == u); - bool prev_upwards = false; if (is_ancestor_of(v, p)) { - std::swap(p, q); - prev_upwards = true; + std::swap(p, q); } - is_swap_enter = prev_upwards; SASSERT(is_ancestor_of(v, q)); - + TRACE("network_flow", { tout << "update_spanning_tree: (" << p << ", " << q << ") enters, ("; tout << u << ", " << v << ") leaves\n"; }); - // Update m_pred (for nodes in the stem from q to v) - // Note: m_pred[v] == u - // Initialize m_upwards[q] = q_upwards - node old_pred = m_pred[q]; + // Update stem nodes from q to v if (q != v) { for (node n = q; n != u; ) { SASSERT(old_pred != u || n == v); // the last processed node is v SASSERT(-1 != m_pred[old_pred]); int next_old_pred = m_pred[old_pred]; swap_order(n, old_pred); - std::swap(m_upwards[n], prev_upwards); - prev_upwards = !prev_upwards; // flip previous version of upwards. + m_tree[old_pred] = m_tree[n]; n = old_pred; old_pred = next_old_pred; } } - m_pred[q] = p; + else { + node x = get_final(p); + node y = m_thread[x]; + node z = get_final(q); + node t = m_thread[get_final(v)]; + node r = find_rev_thread(v); + m_thread[z] = y; + m_thread[x] = q; + m_thread[r] = t; + } - // m_thread were updated. - // update the depth. + m_pred[q] = p; + m_tree[q] = enter_id; + m_root_t2 = q; + + SASSERT(!in_subtree_t2(p)); + SASSERT(in_subtree_t2(q)); + SASSERT(!in_subtree_t2(u)); + SASSERT(in_subtree_t2(v)); + + // Update the depth. fix_depth(q, get_final(q)); TRACE("network_flow", { tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Threads", m_thread); - tout << pp_vector("Depths", m_depth) << pp_vector("Upwards", m_upwards); + tout << pp_vector("Depths", m_depth) << pp_vector("Tree", m_tree); }); } @@ -263,7 +271,13 @@ namespace smt { // All nodes belong to the same spanning tree for (unsigned i = 0; i < roots.size(); ++i) { SASSERT(roots[i] + roots.size() == 0 || roots[i] >= 0); - } + } + + for (unsigned i = 0; i < m_tree.size(); ++i) { + node src = m_graph.get_source(m_tree[i]); + node tgt = m_graph.get_target(m_tree[i]); + SASSERT(m_pred[src] == tgt || m_pred[tgt] == src); + } return true; } From c6c7093a4cde992e4ec4fc4808873e4749190b6d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Nov 2013 18:22:07 -0800 Subject: [PATCH 108/925] make max-smt solvers generic Signed-off-by: Nikolaj Bjorner --- src/opt/fu_malik.cpp | 102 ++++++++++++++++++----------- src/opt/fu_malik.h | 16 ++++- src/opt/weighted_maxsat.cpp | 127 +++++++++++++++++++++++++++--------- src/opt/weighted_maxsat.h | 16 ++++- 4 files changed, 188 insertions(+), 73 deletions(-) diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index d6e435be9..fe4cdb1f7 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -35,19 +35,20 @@ Notes: */ namespace opt { - class fu_malik { + struct fu_malik::imp { ast_manager& m; solver& s; expr_ref_vector m_soft; expr_ref_vector m_aux; + expr_ref_vector m_assignment; - public: - fu_malik(ast_manager& m, solver& s, expr_ref_vector const& soft): + imp(ast_manager& m, solver& s, expr_ref_vector const& soft): m(m), s(s), m_soft(soft), - m_aux(m) + m_aux(m), + m_assignment(m) { for (unsigned i = 0; i < m_soft.size(); ++i) { m_aux.push_back(m.mk_fresh_const("p", m.mk_bool_sort())); @@ -106,8 +107,6 @@ namespace opt { return l_false; } - private: - void assert_at_most_one(expr_ref_vector const& block_vars) { expr_ref has_one(m), has_zero(m), at_most_one(m); mk_at_most_one(block_vars.size(), block_vars.c_ptr(), has_one, has_zero); @@ -131,46 +130,71 @@ namespace opt { } } - }; - - // TBD: bug when cancel flag is set, fu_malik returns is_sat == l_true instead of l_undef - - lbool fu_malik_maxsat(solver& s, expr_ref_vector& soft_constraints) { - ast_manager& m = soft_constraints.get_manager(); - lbool is_sat = s.check_sat(0,0); - if (!soft_constraints.empty() && is_sat == l_true) { - s.push(); - - fu_malik fm(m, s, soft_constraints); - lbool is_sat = l_true; - do { - is_sat = fm.step(); - } - while (is_sat == l_false); - - if (is_sat == l_true) { - // Get a list of satisfying soft_constraints - model_ref model; - s.get_model(model); + // TBD: bug when cancel flag is set, fu_malik returns is_sat == l_true instead of l_undef + lbool operator()() { + lbool is_sat = s.check_sat(0,0); + if (!m_soft.empty() && is_sat == l_true) { + opt_solver::scoped_push _sp(s); - expr_ref_vector result(m); - for (unsigned i = 0; i < soft_constraints.size(); ++i) { - expr_ref val(m); - VERIFY(model->eval(soft_constraints[i].get(), val)); - if (!m.is_false(val)) { - result.push_back(soft_constraints[i].get()); + lbool is_sat = l_true; + do { + is_sat = step(); + } + while (is_sat == l_false); + + if (is_sat == l_true) { + // Get a list of satisfying m_soft + model_ref model; + s.get_model(model); + + m_assignment.reset(); + for (unsigned i = 0; i < m_soft.size(); ++i) { + expr_ref val(m); + VERIFY(model->eval(m_soft[i].get(), val)); + if (m.is_true(val)) { + m_assignment.push_back(m_soft[i].get()); + } } } - soft_constraints.reset(); - soft_constraints.append(result); } - s.pop(1); + // We are done and soft_constraints has + // been updated with the max-sat assignment. + return is_sat; } - // We are done and soft_constraints has - // been updated with the max-sat assignment. - return is_sat; + }; + + fu_malik::fu_malik(ast_manager& m, solver& s, expr_ref_vector& soft_constraints) { + m_imp = alloc(imp, m, s, soft_constraints); } + fu_malik::~fu_malik() { + dealloc(m_imp); + } + + lbool fu_malik::operator()() { + return (*m_imp)(); + } + rational fu_malik::get_lower() const { + NOT_IMPLEMENTED_YET(); + return rational(0); + } + rational fu_malik::get_upper() const { + NOT_IMPLEMENTED_YET(); + return rational(m_imp->m_soft.size()); + } + rational fu_malik::get_value() const { + NOT_IMPLEMENTED_YET(); + return rational(m_imp->m_assignment.size()); + } + expr_ref_vector fu_malik::get_assignment() const { + return m_imp->m_assignment; + } + void fu_malik::set_cancel(bool f) { + // no-op + } + + + }; diff --git a/src/opt/fu_malik.h b/src/opt/fu_malik.h index 6bfe37f63..48be07316 100644 --- a/src/opt/fu_malik.h +++ b/src/opt/fu_malik.h @@ -20,6 +20,7 @@ Notes: #define _OPT_FU_MALIK_H_ #include "solver.h" +#include "maxsmt.h" namespace opt { /** @@ -27,8 +28,21 @@ namespace opt { Returns a maximal satisfying subset of soft_constraints that are still consistent with the solver state. */ + + class fu_malik : public maxsmt_solver { + struct imp; + imp* m_imp; + public: + fu_malik(ast_manager& m, solver& s, expr_ref_vector& soft_constraints); + virtual ~fu_malik(); + virtual lbool operator()(); + virtual rational get_lower() const; + virtual rational get_upper() const; + virtual rational get_value() const; + virtual expr_ref_vector get_assignment() const; + virtual void set_cancel(bool f); + }; - lbool fu_malik_maxsat(solver& s, expr_ref_vector& soft_constraints); }; #endif diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index b74bb1ab8..0434e3afb 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -151,11 +151,9 @@ namespace smt { virtual final_check_status final_check_eh() { if (block(true)) { - return FC_CONTINUE; - } - else { return FC_DONE; } + return FC_CONTINUE; } virtual bool use_diseqs() const { @@ -203,6 +201,9 @@ namespace smt { }; bool block(bool is_final) { + if (m_vars.empty()) { + return true; + } ast_manager& m = get_manager(); context& ctx = get_context(); literal_vector lits; @@ -218,6 +219,11 @@ namespace smt { lits.push_back(~literal(m_min_cost_bv)); } IF_VERBOSE(2, verbose_stream() << "block: " << m_costs.size() << " " << lits.size() << " " << m_min_cost << "\n";); + IF_VERBOSE(2, for (unsigned i = 0; i < lits.size(); ++i) { + verbose_stream() << lits[i] << " "; + } + verbose_stream() << "\n"; + ); ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); if (is_final && m_cost < m_min_cost) { @@ -225,7 +231,7 @@ namespace smt { m_cost_save.reset(); m_cost_save.append(m_costs); } - return !lits.empty(); + return false; } }; @@ -259,42 +265,101 @@ namespace opt { return result; } + + struct wmaxsmt::imp { + ast_manager& m; + opt_solver& s; + expr_ref_vector m_soft; + expr_ref_vector m_assignment; + rational m_lower; + rational m_upper; + rational m_value; + vector m_weights; + + imp(ast_manager& m, opt_solver& s, expr_ref_vector& soft_constraints, vector const& weights): + m(m), s(s), m_soft(soft_constraints), m_assignment(m), m_weights(weights) + {} + ~imp() {} + + smt::theory_weighted_maxsat& ensure_theory() { + smt::context& ctx = s.get_context(); + smt::theory_id th_id = m.get_family_id("weighted_maxsat"); + smt::theory* th = ctx.get_theory(th_id); + smt::theory_weighted_maxsat* wth; + if (th) { + wth = dynamic_cast(th); + wth->reset(); + } + else { + wth = alloc(smt::theory_weighted_maxsat, m); + ctx.register_plugin(wth); + } + return *wth; + } + /** Takes solver with hard constraints added. Returns a maximal satisfying subset of weighted soft_constraints that are still consistent with the solver state. */ - - lbool weighted_maxsat(opt_solver& s, expr_ref_vector& soft_constraints, vector const& weights) { - ast_manager& m = soft_constraints.get_manager(); - smt::context& ctx = s.get_context(); - smt::theory_id th_id = m.get_family_id("weighted_maxsat"); - smt::theory* th = ctx.get_theory(th_id); - smt::theory_weighted_maxsat* wth; - if (th) { - wth = dynamic_cast(th); - wth->reset(); - } - else { - wth = alloc(smt::theory_weighted_maxsat, m); - ctx.register_plugin(wth); - } - opt_solver::scoped_push _s(s); - for (unsigned i = 0; i < soft_constraints.size(); ++i) { - wth->assert_weighted(soft_constraints[i].get(), weights[i]); - } -#if 0 - lbool result = s.check_sat_core(0,0); + lbool operator()() { + smt::theory_weighted_maxsat& wth = ensure_theory(); + lbool result; + { + opt_solver::scoped_push _s(s); + for (unsigned i = 0; i < m_soft.size(); ++i) { + wth.assert_weighted(m_soft[i].get(), m_weights[i]); + } +#if 1 + result = s.check_sat_core(0,0); #else - lbool result = iterative_weighted_maxsat(s, *wth); + result = iterative_weighted_maxsat(s, *wth); #endif + + wth.get_assignment(m_assignment); + if (!m_assignment.empty() && result == l_false) { + result = l_true; + } + } + wth.reset(); + return result; + } + }; - wth->get_assignment(soft_constraints); - if (!soft_constraints.empty() && result == l_false) { - result = l_true; - } - return result; + wmaxsmt::wmaxsmt(ast_manager& m, opt_solver& s, expr_ref_vector& soft_constraints, vector const& weights) { + m_imp = alloc(imp, m, s, soft_constraints, weights); } + + wmaxsmt::~wmaxsmt() { + dealloc(m_imp); + } + + lbool wmaxsmt::operator()() { + return (*m_imp)(); + } + rational wmaxsmt::get_lower() const { + NOT_IMPLEMENTED_YET(); + return m_imp->m_lower; + } + rational wmaxsmt::get_upper() const { + NOT_IMPLEMENTED_YET(); + return m_imp->m_upper; + } + rational wmaxsmt::get_value() const { + NOT_IMPLEMENTED_YET(); + return m_imp->m_value; + } + expr_ref_vector wmaxsmt::get_assignment() const { + return m_imp->m_assignment; + } + void wmaxsmt::set_cancel(bool f) { + // no-op + } + + + + + }; diff --git a/src/opt/weighted_maxsat.h b/src/opt/weighted_maxsat.h index 120609a8c..3e1cd8529 100644 --- a/src/opt/weighted_maxsat.h +++ b/src/opt/weighted_maxsat.h @@ -19,6 +19,7 @@ Notes: #define _OPT_WEIGHTED_MAX_SAT_H_ #include "opt_solver.h" +#include "maxsmt.h" namespace opt { /** @@ -26,8 +27,19 @@ namespace opt { Returns a maximal satisfying subset of weighted soft_constraints that are still consistent with the solver state. */ - - lbool weighted_maxsat(opt_solver& s, expr_ref_vector& soft_constraints, vector const& weights); + class wmaxsmt : public maxsmt_solver { + struct imp; + imp* m_imp; + public: + wmaxsmt(ast_manager& m, opt_solver& s, expr_ref_vector& soft_constraints, vector const& weights); + ~wmaxsmt(); + virtual lbool operator()(); + virtual rational get_lower() const; + virtual rational get_upper() const; + virtual rational get_value() const; + virtual expr_ref_vector get_assignment() const; + virtual void set_cancel(bool f); + }; }; #endif From 816029c862ab08eef09056e6bc0a15f567636b01 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Nov 2013 20:04:30 -0800 Subject: [PATCH 109/925] missing Signed-off-by: Nikolaj Bjorner --- src/opt/maxsmt.cpp | 114 +++++++++++++++++++++++++++++++++++++++++++++ src/opt/maxsmt.h | 82 ++++++++++++++++++++++++++++++++ 2 files changed, 196 insertions(+) create mode 100644 src/opt/maxsmt.cpp create mode 100644 src/opt/maxsmt.h diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp new file mode 100644 index 000000000..f68e4a50b --- /dev/null +++ b/src/opt/maxsmt.cpp @@ -0,0 +1,114 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + opt_maxsmt.cpp + +Abstract: + + MaxSMT optimization context. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-11-7 + +Notes: + +--*/ + +#include "maxsmt.h" +#include "fu_malik.h" +#include "weighted_maxsat.h" +#include "ast_pp.h" + +namespace opt { + + lbool maxsmt::operator()(solver& s) { + lbool is_sat; + m_answer.reset(); + m_msolver = 0; + if (m_answer.empty()) { + m_msolver = 0; + is_sat = s.check_sat(0, 0); + m_answer.append(m_soft_constraints); + } + else if (is_maxsat_problem(m_weights)) { + m_msolver = alloc(fu_malik, m, s, m_soft_constraints); + } + else { + m_msolver = alloc(wmaxsmt, m, opt_solver::to_opt(s), m_soft_constraints, m_weights); + } + + if (m_msolver) { + is_sat = (*m_msolver)(); + m_answer.append(m_msolver->get_assignment()); + } + + // Infrastructure for displaying and storing solution is TBD. + std::cout << "is-sat: " << is_sat << "\n"; + if (is_sat == l_true) { + std::cout << "Satisfying soft constraints\n"; + display_answer(std::cout); + } + return is_sat; + } + + expr_ref_vector maxsmt::get_assignment() const { + return m_answer; + } + + inf_eps maxsmt::get_value() const { + if (m_msolver) { + return inf_eps(m_msolver->get_value()); + } + return inf_eps(); + } + + inf_eps maxsmt::get_lower() const { + if (m_msolver) { + return inf_eps(m_msolver->get_lower()); + } + return inf_eps(); + } + + inf_eps maxsmt::get_upper() const { + if (m_msolver) { + return inf_eps(m_msolver->get_upper()); + } + return inf_eps(); + } + + void maxsmt::commit_assignment() { + for (unsigned i = 0; i < m_answer.size(); ++i) { + s->assert_expr(m_answer[i].get()); + } + } + + void maxsmt::display_answer(std::ostream& out) const { + for (unsigned i = 0; i < m_answer.size(); ++i) { + out << mk_pp(m_answer[i], m) << "\n"; + } + } + + void maxsmt::set_cancel(bool f) { + m_cancel = f; + if (m_msolver) { + m_msolver->set_cancel(f); + } + } + + bool maxsmt::is_maxsat_problem(vector const& ws) const { + for (unsigned i = 0; i < ws.size(); ++i) { + if (!ws[i].is_one()) { + return false; + } + } + return true; + } + + void maxsmt::updt_params(params_ref& p) { + } + + +}; diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h new file mode 100644 index 000000000..b23d8811e --- /dev/null +++ b/src/opt/maxsmt.h @@ -0,0 +1,82 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + opt_maxsmt.h + +Abstract: + + MaxSMT optimization context. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-11-7 + +Notes: + +--*/ +#ifndef _OPT_MAXSMT_H_ +#define _OPT_MAXSMT_H_ + +#include "solver.h" +#include "opt_solver.h" + +namespace opt { + + class maxsmt_solver { + public: + virtual ~maxsmt_solver() {} + virtual lbool operator()() = 0; + virtual rational get_lower() const = 0; + virtual rational get_upper() const = 0; + virtual rational get_value() const = 0; + virtual expr_ref_vector get_assignment() const = 0; + virtual void set_cancel(bool f) = 0; + }; + /** + Takes solver with hard constraints added. + Returns modified soft constraints that are maximal assignments. + */ + + class maxsmt { + ast_manager& m; + solver* s; + volatile bool m_cancel; + expr_ref_vector m_soft_constraints; + expr_ref_vector m_answer; + vector m_weights; + scoped_ptr m_msolver; + public: + maxsmt(ast_manager& m): m(m), s(0), m_cancel(false), m_soft_constraints(m), m_answer(m) {} + + lbool operator()(solver& s); + + void set_cancel(bool f); + + void updt_params(params_ref& p); + + void add(expr* f, rational const& w) { + m_soft_constraints.push_back(f); + m_weights.push_back(w); + } + + void commit_assignment(); + + inf_eps get_value() const; + inf_eps get_lower() const; + inf_eps get_upper() const; + + expr_ref_vector get_assignment() const; + + void display_answer(std::ostream& out) const; + + private: + + bool is_maxsat_problem(vector const& ws) const; + + }; + +}; + +#endif From 6e1c18601746227da98ed102ccf700c3a268a52c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Nov 2013 20:55:01 -0800 Subject: [PATCH 110/925] enable answer generation Signed-off-by: Nikolaj Bjorner --- src/opt/fu_malik.cpp | 18 ++++++----- src/opt/maxsmt.cpp | 12 ++++---- src/opt/maxsmt.h | 1 - src/opt/opt_cmds.cpp | 16 +++++++++- src/opt/opt_context.cpp | 64 ++++++++++++++++++++++++++++++++++----- src/opt/opt_context.h | 8 +++-- src/opt/optsmt.cpp | 39 ++++++++++++++++-------- src/opt/optsmt.h | 9 ++++-- src/opt/weighted_maxsat.h | 12 ++++---- 9 files changed, 131 insertions(+), 48 deletions(-) diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index fe4cdb1f7..6bfe1d5cc 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -39,14 +39,17 @@ namespace opt { ast_manager& m; solver& s; expr_ref_vector m_soft; + expr_ref_vector m_orig_soft; expr_ref_vector m_aux; expr_ref_vector m_assignment; + unsigned m_upper_size; imp(ast_manager& m, solver& s, expr_ref_vector const& soft): m(m), s(s), m_soft(soft), + m_orig_soft(soft), m_aux(m), m_assignment(m) { @@ -54,6 +57,7 @@ namespace opt { m_aux.push_back(m.mk_fresh_const("p", m.mk_bool_sort())); s.assert_expr(m.mk_or(m_soft[i].get(), m_aux[i].get())); } + m_upper_size = m_soft.size() + 1; } @@ -136,9 +140,10 @@ namespace opt { if (!m_soft.empty() && is_sat == l_true) { opt_solver::scoped_push _sp(s); - lbool is_sat = l_true; + lbool is_sat = l_true; do { is_sat = step(); + --m_upper_size; } while (is_sat == l_false); @@ -148,11 +153,11 @@ namespace opt { s.get_model(model); m_assignment.reset(); - for (unsigned i = 0; i < m_soft.size(); ++i) { + for (unsigned i = 0; i < m_orig_soft.size(); ++i) { expr_ref val(m); - VERIFY(model->eval(m_soft[i].get(), val)); + VERIFY(model->eval(m_orig_soft[i].get(), val)); if (m.is_true(val)) { - m_assignment.push_back(m_soft[i].get()); + m_assignment.push_back(m_orig_soft[i].get()); } } } @@ -175,15 +180,12 @@ namespace opt { return (*m_imp)(); } rational fu_malik::get_lower() const { - NOT_IMPLEMENTED_YET(); return rational(0); } rational fu_malik::get_upper() const { - NOT_IMPLEMENTED_YET(); - return rational(m_imp->m_soft.size()); + return rational(m_imp->m_upper_size); } rational fu_malik::get_value() const { - NOT_IMPLEMENTED_YET(); return rational(m_imp->m_assignment.size()); } expr_ref_vector fu_malik::get_assignment() const { diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index f68e4a50b..1625b6440 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -28,7 +28,7 @@ namespace opt { lbool is_sat; m_answer.reset(); m_msolver = 0; - if (m_answer.empty()) { + if (m_soft_constraints.empty()) { m_msolver = 0; is_sat = s.check_sat(0, 0); m_answer.append(m_soft_constraints); @@ -46,11 +46,11 @@ namespace opt { } // Infrastructure for displaying and storing solution is TBD. - std::cout << "is-sat: " << is_sat << "\n"; - if (is_sat == l_true) { - std::cout << "Satisfying soft constraints\n"; - display_answer(std::cout); - } + IF_VERBOSE(1, verbose_stream() << "is-sat: " << is_sat << "\n"; + if (is_sat == l_true) { + verbose_stream() << "Satisfying soft constraints\n"; + display_answer(verbose_stream()); + }); return is_sat; } diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index b23d8811e..3d67ee7eb 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -62,7 +62,6 @@ namespace opt { } void commit_assignment(); - inf_eps get_value() const; inf_eps get_lower() const; inf_eps get_upper() const; diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index ad5985d1c..35652918b 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -201,13 +201,14 @@ public: for (; it != end; ++it) { opt.add_hard_constraint(*it); } + lbool r = l_undef; cancel_eh eh(opt); { scoped_ctrl_c ctrlc(eh); scoped_timer timer(timeout, &eh); cmd_context::scoped_watch sw(ctx); try { - opt.optimize(); + r = opt.optimize(); } catch (z3_error& ex) { ctx.regular_stream() << "(error: " << ex.msg() << "\")" << std::endl; @@ -216,6 +217,19 @@ public: ctx.regular_stream() << "(error: " << ex.msg() << "\")" << std::endl; } } + switch(r) { + case l_true: + ctx.regular_stream() << "sat\n"; + opt.display_assignment(ctx.regular_stream()); + break; + case l_false: + ctx.regular_stream() << "unsat\n"; + break; + case l_undef: + ctx.regular_stream() << "unknown\n"; + opt.display_range_assignment(ctx.regular_stream()); + break; + } if (p.get_bool("print_statistics", false)) { display_statistics(ctx); } diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index ede93b34a..7808a3d0c 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -6,6 +6,7 @@ Module Name: opt_context.cpp Abstract: + Facility for running optimization problem. Author: @@ -14,17 +15,11 @@ Author: Notes: - TODO: - - - there are race conditions for cancelation. - --*/ #include "opt_context.h" #include "ast_pp.h" #include "opt_solver.h" -#include "arith_decl_plugin.h" -#include "th_rewriter.h" #include "opt_params.hpp" namespace opt { @@ -55,8 +50,12 @@ namespace opt { ms->add(f, w); } - void context::optimize() { + lbool context::optimize() { + // TBD: add configurtion parameter + return optimize_box(); + } + lbool context::optimize_box() { opt_solver& s = *m_solver.get(); opt_solver::scoped_push _sp(s); @@ -73,6 +72,55 @@ namespace opt { if (is_sat == l_true) { is_sat = m_optsmt(s); } + return is_sat; + } + + // finds a random pareto front. + // enumerating more is TBD, e.g., + lbool context::optimize_pareto() { + opt_solver& s = *m_solver.get(); + opt_solver::scoped_push _sp(s); + + for (unsigned i = 0; i < m_hard_constraints.size(); ++i) { + s.assert_expr(m_hard_constraints[i].get()); + } + + lbool is_sat = l_true; + map_t::iterator it = m_maxsmts.begin(), end = m_maxsmts.end(); + for (; is_sat == l_true && it != end; ++it) { + maxsmt* ms = it->m_value; + is_sat = (*ms)(s); + ms->commit_assignment(); + } + for (unsigned i = 0; is_sat == l_true && i < m_optsmt.get_num_objectives(); ++i) { + is_sat = m_optsmt(s); + m_optsmt.commit_assignment(i); + } + return is_sat; + } + + void context::display_assignment(std::ostream& out) { + map_t::iterator it = m_maxsmts.begin(), end = m_maxsmts.end(); + for (; it != end; ++it) { + maxsmt* ms = it->m_value; + if (it->m_key != symbol::null) { + out << it->m_key << " : "; + } + out << ms->get_value() << "\n"; + } + m_optsmt.display_assignment(out); + } + + void context::display_range_assignment(std::ostream& out) { + map_t::iterator it = m_maxsmts.begin(), end = m_maxsmts.end(); + for (; it != end; ++it) { + maxsmt* ms = it->m_value; + if (it->m_key != symbol::null) { + out << it->m_key << " : "; + } + out << "[" << ms->get_lower() << ":" << ms->get_upper() << "]\n"; + } + m_optsmt.display_range_assignment(out); } void context::set_cancel(bool f) { @@ -86,7 +134,7 @@ namespace opt { } } - void context::collect_statistics(statistics& stats) { + void context::collect_statistics(statistics& stats) const { if (m_solver) { m_solver->collect_statistics(stats); } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index c9388a56a..15f59efc8 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -48,11 +48,15 @@ namespace opt { void add_soft_constraint(expr* f, rational const& w, symbol const& id); void add_objective(app* t, bool is_max) { m_optsmt.add(t, is_max); } void add_hard_constraint(expr* f) { m_hard_constraints.push_back(f); } - void optimize(); + lbool optimize(); + lbool optimize_pareto(); + lbool optimize_box(); void set_cancel(bool f); void reset_cancel() { set_cancel(false); } void cancel() { set_cancel(true); } - void collect_statistics(statistics& stats); + void collect_statistics(statistics& stats) const; + void display_assignment(std::ostream& out); + void display_range_assignment(std::ostream& out); static void collect_param_descrs(param_descrs & r); void updt_params(params_ref& p); }; diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 28dd95f67..1d3aa1f77 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -238,8 +238,8 @@ namespace opt { } } - std::cout << "is-sat: " << is_sat << std::endl; - display(std::cout); + IF_VERBOSE(1, verbose_stream() << "is-sat: " << is_sat << std::endl; + display_assignment(verbose_stream());); return is_sat; } @@ -262,22 +262,35 @@ namespace opt { s->assert_expr(s->block_upper_bound(i, get_lower(i))); } - void optsmt::display(std::ostream& out) const { + std::ostream& optsmt::display_objective(std::ostream& out, unsigned i) const { + bool is_max = m_is_max[i]; + inf_eps val = get_value(i); + expr_ref obj(m_objs[i], m); + if (!is_max) { + arith_util a(m); + th_rewriter rw(m); + obj = a.mk_uminus(obj); + rw(obj, obj); + } + return out << obj; + } + + void optsmt::display_assignment(std::ostream& out) const { unsigned sz = m_objs.size(); for (unsigned i = 0; i < sz; ++i) { - bool is_max = m_is_max[i]; - inf_eps val = get_value(i); - expr_ref obj(m_objs[i], m); - if (!is_max) { - arith_util a(m); - th_rewriter rw(m); - obj = a.mk_uminus(obj); - rw(obj, obj); - } - out << "objective value: " << obj << " |-> " << val << std::endl; + display_objective(out, i) << " |-> " << get_value(i) << std::endl; } } + void optsmt::display_range_assignment(std::ostream& out) const { + unsigned sz = m_objs.size(); + for (unsigned i = 0; i < sz; ++i) { + display_objective(out, i) << " |-> [" << get_lower(i) << ":" << get_upper(i) << "]" << std::endl; + } + } + + + void optsmt::add(app* t, bool is_max) { expr_ref t1(t, m), t2(m); th_rewriter rw(m); diff --git a/src/opt/optsmt.h b/src/opt/optsmt.h index b892ef38f..2dae59a4f 100644 --- a/src/opt/optsmt.h +++ b/src/opt/optsmt.h @@ -44,20 +44,23 @@ namespace opt { void add(app* t, bool is_max); - void commit_assignment(unsigned i); - void set_cancel(bool f); void updt_params(params_ref& p); - void display(std::ostream& out) const; + void display_assignment(std::ostream& out) const; + void display_range_assignment(std::ostream& out) const; + unsigned get_num_objectives() const { return m_vars.size(); } + void commit_assignment(unsigned i); inf_eps get_value(unsigned index) const; inf_eps get_lower(unsigned index) const; inf_eps get_upper(unsigned index) const; private: + std::ostream& display_objective(std::ostream& out, unsigned i) const; + lbool basic_opt(); lbool farkas_opt(); diff --git a/src/opt/weighted_maxsat.h b/src/opt/weighted_maxsat.h index 3e1cd8529..8621ff9e1 100644 --- a/src/opt/weighted_maxsat.h +++ b/src/opt/weighted_maxsat.h @@ -6,7 +6,8 @@ Module Name: weighted_maxsat.h Abstract: - Weighted MAXSAT module + + Weighted MAXSAT module Author: @@ -14,6 +15,10 @@ Author: Notes: + Takes solver with hard constraints added. + Returns a maximal satisfying subset of weighted soft_constraints + that are still consistent with the solver state. + --*/ #ifndef _OPT_WEIGHTED_MAX_SAT_H_ #define _OPT_WEIGHTED_MAX_SAT_H_ @@ -22,11 +27,6 @@ Notes: #include "maxsmt.h" namespace opt { - /** - Takes solver with hard constraints added. - Returns a maximal satisfying subset of weighted soft_constraints - that are still consistent with the solver state. - */ class wmaxsmt : public maxsmt_solver { struct imp; imp* m_imp; From 21058c38fd216901272f0d539ce15cef54f2de4e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Nov 2013 21:26:05 -0800 Subject: [PATCH 111/925] fix bounds for weighted maxsmt Signed-off-by: Nikolaj Bjorner --- src/opt/weighted_maxsat.cpp | 58 +++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 0434e3afb..a03d60ae1 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -27,12 +27,12 @@ namespace smt { app_ref_vector m_vars; // Auxiliary variables per soft clause expr_ref_vector m_fmls; // Formulas per soft clause app_ref m_min_cost_atom; // atom tracking modified lower bound - bool_var m_min_cost_bv; // min cost Boolean variable + bool_var m_min_cost_bv; // max cost Boolean variable vector m_weights; // weights of theory variables. svector m_costs; // set of asserted theory variables svector m_cost_save; // set of asserted theory variables rational m_cost; // current sum of asserted costs - rational m_min_cost; // current minimal cost assignment. + rational m_min_cost; // current maximal cost assignment. u_map m_bool2var; // bool_var -> theory_var svector m_var2bool; // theory_var -> bool_var public: @@ -174,9 +174,9 @@ namespace smt { m_fmls.reset(); m_weights.reset(); m_costs.reset(); + m_min_cost.reset(); m_cost.reset(); m_cost_save.reset(); - m_min_cost.reset(); m_bool2var.reset(); m_var2bool.reset(); m_min_cost_atom = 0; @@ -240,8 +240,10 @@ namespace smt { namespace opt { /** - Iteratively increase min-cost until there is an assignment during + Iteratively increase cost until there is an assignment during final_check that satisfies min_cost. + + Takes: log (n / log(n)) iterations */ static lbool iterative_weighted_maxsat(opt_solver& s, smt::theory_weighted_maxsat& wth) { @@ -271,37 +273,43 @@ namespace opt { opt_solver& s; expr_ref_vector m_soft; expr_ref_vector m_assignment; - rational m_lower; - rational m_upper; - rational m_value; vector m_weights; + rational m_upper; imp(ast_manager& m, opt_solver& s, expr_ref_vector& soft_constraints, vector const& weights): m(m), s(s), m_soft(soft_constraints), m_assignment(m), m_weights(weights) {} ~imp() {} - smt::theory_weighted_maxsat& ensure_theory() { + smt::theory_weighted_maxsat* get_theory() const { smt::context& ctx = s.get_context(); smt::theory_id th_id = m.get_family_id("weighted_maxsat"); smt::theory* th = ctx.get_theory(th_id); - smt::theory_weighted_maxsat* wth; if (th) { - wth = dynamic_cast(th); + return dynamic_cast(th); + } + else { + return 0; + } + } + + smt::theory_weighted_maxsat& ensure_theory() { + smt::theory_weighted_maxsat* wth = get_theory(); + if (wth) { wth->reset(); } else { wth = alloc(smt::theory_weighted_maxsat, m); - ctx.register_plugin(wth); + s.get_context().register_plugin(wth); } return *wth; } - /** - Takes solver with hard constraints added. - Returns a maximal satisfying subset of weighted soft_constraints - that are still consistent with the solver state. - */ + /** + Takes solver with hard constraints added. + Returns a maximal satisfying subset of weighted soft_constraints + that are still consistent with the solver state. + */ lbool operator()() { smt::theory_weighted_maxsat& wth = ensure_theory(); @@ -322,9 +330,18 @@ namespace opt { result = l_true; } } + m_upper = wth.get_min_cost(); wth.reset(); return result; } + + rational get_lower() const { + return rational(0); + } + + rational get_upper() const { + return m_upper; + } }; wmaxsmt::wmaxsmt(ast_manager& m, opt_solver& s, expr_ref_vector& soft_constraints, vector const& weights) { @@ -339,16 +356,13 @@ namespace opt { return (*m_imp)(); } rational wmaxsmt::get_lower() const { - NOT_IMPLEMENTED_YET(); - return m_imp->m_lower; + return m_imp->get_lower(); } rational wmaxsmt::get_upper() const { - NOT_IMPLEMENTED_YET(); - return m_imp->m_upper; + return m_imp->get_upper(); } rational wmaxsmt::get_value() const { - NOT_IMPLEMENTED_YET(); - return m_imp->m_value; + return m_imp->get_upper(); } expr_ref_vector wmaxsmt::get_assignment() const { return m_imp->m_assignment; From b573b94f84b0b75560a8c61227794c5692280180 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Nov 2013 21:59:38 -0800 Subject: [PATCH 112/925] nits Signed-off-by: Nikolaj Bjorner --- src/opt/fu_malik.cpp | 2 +- src/opt/opt_context.cpp | 4 ++-- src/opt/opt_context.h | 5 +++-- src/opt/opt_solver.h | 7 ------- src/opt/optsmt.cpp | 10 ++-------- src/opt/optsmt.h | 6 +++--- src/opt/weighted_maxsat.cpp | 2 +- src/solver/solver.h | 8 ++++++++ 8 files changed, 20 insertions(+), 24 deletions(-) diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index 6bfe1d5cc..725fa6072 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -138,7 +138,7 @@ namespace opt { lbool operator()() { lbool is_sat = s.check_sat(0,0); if (!m_soft.empty() && is_sat == l_true) { - opt_solver::scoped_push _sp(s); + solver::scoped_push _sp(s); lbool is_sat = l_true; do { diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 7808a3d0c..2c64f8277 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -51,13 +51,13 @@ namespace opt { } lbool context::optimize() { - // TBD: add configurtion parameter + // TBD: add configuration parameter to select between box and pareto return optimize_box(); } lbool context::optimize_box() { opt_solver& s = *m_solver.get(); - opt_solver::scoped_push _sp(s); + solver::scoped_push _sp(s); for (unsigned i = 0; i < m_hard_constraints.size(); ++i) { s.assert_expr(m_hard_constraints[i].get()); diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 15f59efc8..c54259115 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -49,8 +49,6 @@ namespace opt { void add_objective(app* t, bool is_max) { m_optsmt.add(t, is_max); } void add_hard_constraint(expr* f) { m_hard_constraints.push_back(f); } lbool optimize(); - lbool optimize_pareto(); - lbool optimize_box(); void set_cancel(bool f); void reset_cancel() { set_cancel(false); } void cancel() { set_cancel(true); } @@ -59,6 +57,9 @@ namespace opt { void display_range_assignment(std::ostream& out); static void collect_param_descrs(param_descrs & r); void updt_params(params_ref& p); + private: + lbool optimize_pareto(); + lbool optimize_box(); }; } diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index fa9a5e031..1fffa1b5b 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -85,13 +85,6 @@ namespace opt { ~toggle_objective(); }; - class scoped_push { - solver& s; - public: - scoped_push(solver& s):s(s) { s.push(); } - ~scoped_push() { s.pop(1); } - }; - smt::context& get_context() { return m_context.get_context(); } // used by weighted maxsat. smt::theory_opt& get_optimizer(); diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 1d3aa1f77..e291b76a5 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -37,8 +37,6 @@ Notes: --*/ -#ifndef _OPT_OBJECTIVE_H_ -#define _OPT_OBJECTIVE_H_ #include "optsmt.h" #include "opt_solver.h" @@ -90,7 +88,6 @@ namespace opt { lbool optsmt::farkas_opt() { smt::theory_opt& opt = s->get_optimizer(); - IF_VERBOSE(1, verbose_stream() << typeid(opt).name() << "\n";); if (typeid(smt::theory_inf_arith) != typeid(opt)) { return l_undef; } @@ -138,7 +135,7 @@ namespace opt { expr_ref bound(m); expr_ref_vector bounds(m); - opt_solver::scoped_push _push(*s); + solver::scoped_push _push(*s); // // NB: we have to create all bound expressions before calling check_sat @@ -218,7 +215,7 @@ namespace opt { // First check_sat call to initialize theories lbool is_sat = s->check_sat(0, 0); if (is_sat == l_true && !m_objs.empty()) { - opt_solver::scoped_push _push(*s); + solver::scoped_push _push(*s); for (unsigned i = 0; i < m_objs.size(); ++i) { m_vars.push_back(s->add_objective(m_objs[i].get())); @@ -289,8 +286,6 @@ namespace opt { } } - - void optsmt::add(app* t, bool is_max) { expr_ref t1(t, m), t2(m); th_rewriter rw(m); @@ -311,4 +306,3 @@ namespace opt { } -#endif diff --git a/src/opt/optsmt.h b/src/opt/optsmt.h index 2dae59a4f..189da0e0e 100644 --- a/src/opt/optsmt.h +++ b/src/opt/optsmt.h @@ -16,8 +16,8 @@ Author: Notes: --*/ -#ifndef _OPT_OBJECTIVES_H_ -#define _OPT_OBJECTIVES_H_ +#ifndef _OPTSMT_H_ +#define _OPTSMT_H_ #include "opt_solver.h" @@ -52,7 +52,7 @@ namespace opt { void display_range_assignment(std::ostream& out) const; unsigned get_num_objectives() const { return m_vars.size(); } - void commit_assignment(unsigned i); + void commit_assignment(unsigned index); inf_eps get_value(unsigned index) const; inf_eps get_lower(unsigned index) const; inf_eps get_upper(unsigned index) const; diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index a03d60ae1..206117224 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -315,7 +315,7 @@ namespace opt { smt::theory_weighted_maxsat& wth = ensure_theory(); lbool result; { - opt_solver::scoped_push _s(s); + solver::scoped_push _s(s); for (unsigned i = 0; i < m_soft.size(); ++i) { wth.assert_weighted(m_soft[i].get(), m_weights[i]); } diff --git a/src/solver/solver.h b/src/solver/solver.h index e047bace1..bd1a26adb 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -130,6 +130,14 @@ public: \brief Display the content of this solver. */ virtual void display(std::ostream & out) const; + + class scoped_push { + solver& s; + public: + scoped_push(solver& s):s(s) { s.push(); } + ~scoped_push() { s.pop(1); } + }; + }; #endif From ba05f79415510fba13007d4325ff46e003fc9710 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Nov 2013 22:40:43 -0800 Subject: [PATCH 113/925] bug fixes Signed-off-by: Nikolaj Bjorner --- src/opt/maxsmt.cpp | 4 +++- src/opt/maxsmt.h | 4 ++-- src/opt/opt_context.cpp | 9 +++++++-- src/opt/opt_params.pyg | 1 + src/opt/optsmt.cpp | 8 ++------ src/opt/optsmt.h | 2 +- 6 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 1625b6440..9603286d1 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -28,6 +28,7 @@ namespace opt { lbool is_sat; m_answer.reset(); m_msolver = 0; + m_s = &s; if (m_soft_constraints.empty()) { m_msolver = 0; is_sat = s.check_sat(0, 0); @@ -80,8 +81,9 @@ namespace opt { } void maxsmt::commit_assignment() { + SASSERT(m_s); for (unsigned i = 0; i < m_answer.size(); ++i) { - s->assert_expr(m_answer[i].get()); + m_s->assert_expr(m_answer[i].get()); } } diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 3d67ee7eb..e3105847d 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -41,14 +41,14 @@ namespace opt { class maxsmt { ast_manager& m; - solver* s; + solver* m_s; volatile bool m_cancel; expr_ref_vector m_soft_constraints; expr_ref_vector m_answer; vector m_weights; scoped_ptr m_msolver; public: - maxsmt(ast_manager& m): m(m), s(0), m_cancel(false), m_soft_constraints(m), m_answer(m) {} + maxsmt(ast_manager& m): m(m), m_s(0), m_cancel(false), m_soft_constraints(m), m_answer(m) {} lbool operator()(solver& s); diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 2c64f8277..ebbccdb5d 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -51,8 +51,13 @@ namespace opt { } lbool context::optimize() { - // TBD: add configuration parameter to select between box and pareto - return optimize_box(); + // TBD: does not work... + if (m_params.get_bool("pareto", false)) { + return optimize_pareto(); + } + else { + return optimize_box(); + } } lbool context::optimize_box() { diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index ae6e43aea..3c2381040 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -3,6 +3,7 @@ def_module_params('opt', export=True, params=(('timeout', UINT, UINT_MAX, 'set timeout'), ('engine', SYMBOL, 'basic', "select optimization engine: 'basic', 'farkas', 'symba'"), + ('pareto', BOOL, False, 'return a Pareto front (as opposed to a bounding box)'), )) diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index e291b76a5..15d8f6617 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -204,13 +204,7 @@ namespace opt { lbool optsmt::operator()(opt_solver& solver) { s = &solver; s->reset_objectives(); - m_lower.reset(); - m_upper.reset(); m_vars.reset(); - for (unsigned i = 0; i < m_objs.size(); ++i) { - m_lower.push_back(inf_eps(rational(-1),inf_rational(0))); - m_upper.push_back(inf_eps(rational(1), inf_rational(0))); - } // First check_sat call to initialize theories lbool is_sat = s->check_sat(0, 0); @@ -297,6 +291,8 @@ namespace opt { SASSERT(is_app(t2)); m_objs.push_back(to_app(t2)); m_is_max.push_back(is_max); + m_lower.push_back(inf_eps(rational(-1),inf_rational(0))); + m_upper.push_back(inf_eps(rational(1), inf_rational(0))); } void optsmt::updt_params(params_ref& p) { diff --git a/src/opt/optsmt.h b/src/opt/optsmt.h index 189da0e0e..0fbfeb7b2 100644 --- a/src/opt/optsmt.h +++ b/src/opt/optsmt.h @@ -51,7 +51,7 @@ namespace opt { void display_assignment(std::ostream& out) const; void display_range_assignment(std::ostream& out) const; - unsigned get_num_objectives() const { return m_vars.size(); } + unsigned get_num_objectives() const { return m_objs.size(); } void commit_assignment(unsigned index); inf_eps get_value(unsigned index) const; inf_eps get_lower(unsigned index) const; From dc78da48733d1cebd722af37bf26d49bbe6e6455 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Nov 2013 23:29:31 -0800 Subject: [PATCH 114/925] case analysis for commit Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 3 +-- src/opt/optsmt.cpp | 33 ++++++++++++++++++++++++++++----- src/util/inf_eps_rational.h | 4 ++-- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index ebbccdb5d..7e62605ac 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -51,8 +51,7 @@ namespace opt { } lbool context::optimize() { - // TBD: does not work... - if (m_params.get_bool("pareto", false)) { + if (m_params.get_bool("pareto", false)) { return optimize_pareto(); } else { diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 15d8f6617..1380080ba 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -209,11 +209,11 @@ namespace opt { // First check_sat call to initialize theories lbool is_sat = s->check_sat(0, 0); if (is_sat == l_true && !m_objs.empty()) { - solver::scoped_push _push(*s); - for (unsigned i = 0; i < m_objs.size(); ++i) { m_vars.push_back(s->add_objective(m_objs[i].get())); - } + } + + solver::scoped_push _push(*s); if (m_engine == symbol("basic")) { is_sat = basic_opt(); @@ -249,8 +249,31 @@ namespace opt { // force lower_bound(i) <= objective_value(i) void optsmt::commit_assignment(unsigned i) { - smt::theory_var v = m_vars[i]; - s->assert_expr(s->block_upper_bound(i, get_lower(i))); + inf_eps mid(0); + + // TBD: case analysis should be revisited + rational hi = get_upper(i).get_infinity(); + rational lo = get_lower(i).get_infinity(); + if (hi.is_pos() && !lo.is_neg()) { + mid = get_lower(i); + } + else if (hi.is_pos() && lo.is_neg()) { + mid = inf_eps(0); + } + else if (hi.is_pos() && lo.is_pos()) { + mid = inf_eps(0); // TBD: get a value from a model? + } + else if (hi.is_neg() && lo.is_neg()) { + mid = inf_eps(0); // TBD: get a value from a model? + } + else { + mid = hi; + } + m_lower[i] = mid; + m_upper[i] = mid; + TRACE("opt", tout << "set lower bound of "; display_objective(tout, i) << " to: " << mid << "\n"; + tout << get_lower(i) << ":" << get_upper(i) << "\n";); + s->assert_expr(s->block_upper_bound(i, mid)); } std::ostream& optsmt::display_objective(std::ostream& out, unsigned i) const { diff --git a/src/util/inf_eps_rational.h b/src/util/inf_eps_rational.h index 268bb8109..9f40404ba 100644 --- a/src/util/inf_eps_rational.h +++ b/src/util/inf_eps_rational.h @@ -303,12 +303,12 @@ class inf_eps_rational { } friend inline rational floor(const inf_eps_rational & r) { - SASSERT(r.m_infty.is_zero()); + // SASSERT(r.m_infty.is_zero()); return floor(r.m_r); } friend inline rational ceil(const inf_eps_rational & r) { - SASSERT(r.m_infty.is_zero()); + // SASSERT(r.m_infty.is_zero()); return ceil(r.m_r); } From 2349a0fcddc6599565eee0836cb63e77dd5402b9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Nov 2013 12:35:20 -0800 Subject: [PATCH 115/925] adding core-based max-sat Signed-off-by: Nikolaj Bjorner --- src/opt/core_maxsat.cpp | 127 ++++++++++++++++++++++++++++++++++++++++ src/opt/core_maxsat.h | 51 ++++++++++++++++ src/opt/fu_malik.cpp | 8 +-- 3 files changed, 182 insertions(+), 4 deletions(-) create mode 100644 src/opt/core_maxsat.cpp create mode 100644 src/opt/core_maxsat.h diff --git a/src/opt/core_maxsat.cpp b/src/opt/core_maxsat.cpp new file mode 100644 index 000000000..b0234c6cf --- /dev/null +++ b/src/opt/core_maxsat.cpp @@ -0,0 +1,127 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + core_maxsat.h + +Abstract: + + Core and SAT guided MaxSAT with cardinality constraints. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-11-9 + +Notes: + +--*/ +#include "core_maxsat.h" +#include "card_decl_plugin.h" + +namespace opt { + + + core_maxsat::core_maxsat(ast_manager& m, solver& s, expr_ref_vector& soft_constraints): + m(m), s(s), m_soft(soft_constraints), m_answer(m) { + m_upper = m_soft.size(); + } + + core_maxsat::~core_maxsat() {} + + lbool core_maxsat::operator()() { + expr_ref_vector aux(m); // auxiliary variables to track soft constraints + expr_set core_vars; // variables used so far in some core + expr_set block_vars; // variables that should be blocked. + solver::scoped_push _sp(s); + for (unsigned i = 0; i < m_soft.size(); ++i) { + expr* a = m.mk_fresh_const("p", m.mk_bool_sort()); + aux.push_back(a); + s.assert_expr(m.mk_implies(a, m_soft[i].get())); + block_vars.insert(a); + } + while (m_answer.size() < m_upper) { + ptr_vector vars; + set2vector(block_vars, vars); + lbool is_sat = s.check_sat(vars.size(), vars.c_ptr()); + + switch(is_sat) { + case l_undef: + return l_undef; + case l_true: { + model_ref model; + expr_ref_vector ans(m); + s.get_model(model); + + for (unsigned i = 0; i < aux.size(); ++i) { + expr_ref val(m); + VERIFY(model->eval(m_soft[i].get(), val)); + if (m.is_true(val)) { + ans.push_back(m_soft[i].get()); + } + } + if (ans.size() > m_answer.size()) { + m_answer.reset(); + m_answer.append(ans); + } + unsigned k = m_soft.size()-m_answer.size()-1; // TBD: fix this + expr_ref fml = mk_at_most(core_vars, k); + s.assert_expr(fml); + break; + } + case l_false: { + ptr_vector core; + s.get_unsat_core(core); + for (unsigned i = 0; i < core.size(); ++i) { + core_vars.insert(core[i]); + block_vars.remove(core[i]); + } + if (core.empty()) { + m_upper = m_answer.size(); + return l_true; + } + else { + // at least one core variable is True + expr_ref fml = mk_at_most(core_vars, 0); + fml = m.mk_not(fml); + s.assert_expr(fml); + } + --m_upper; + } + } + } + return l_true; + } + + void core_maxsat::set2vector(expr_set const& set, ptr_vector& es) const { + es.reset(); + expr_set::iterator it = set.begin(), end = set.end(); + for (; it != end; ++it) { + es.push_back(*it); + } + } + + expr_ref core_maxsat::mk_at_most(expr_set const& set, unsigned k) { + card_util card(m); + ptr_vector es; + set2vector(set, es); + return expr_ref(card.mk_at_most_k(es.size(), es.c_ptr(), k), m); + } + + rational core_maxsat::get_lower() const { + return rational(m_answer.size()); + } + rational core_maxsat::get_upper() const { + return rational(m_upper); + } + rational core_maxsat::get_value() const { + return get_lower(); + } + expr_ref_vector core_maxsat::get_assignment() const { + return m_answer; + } + void core_maxsat::set_cancel(bool f) { + + } + +}; diff --git a/src/opt/core_maxsat.h b/src/opt/core_maxsat.h new file mode 100644 index 000000000..eebcf1d91 --- /dev/null +++ b/src/opt/core_maxsat.h @@ -0,0 +1,51 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + core_maxsat.h + +Abstract: + Core and SAT guided MaxSAT with cardinality constraints. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-11-9 + +Notes: + +--*/ +#ifndef _OPT_CORE_MAXSAT_H_ +#define _OPT_CORE_MAXSAT_H_ + +#include "solver.h" +#include "maxsmt.h" + +namespace opt { + + class core_maxsat : public maxsmt_solver { + typedef obj_hashtable expr_set; + + ast_manager& m; + solver& s; + expr_ref_vector m_soft; + expr_ref_vector m_answer; + unsigned m_upper; + public: + core_maxsat(ast_manager& m, solver& s, expr_ref_vector& soft_constraints); + virtual ~core_maxsat(); + virtual lbool operator()(); + virtual rational get_lower() const; + virtual rational get_upper() const; + virtual rational get_value() const; + virtual expr_ref_vector get_assignment() const; + virtual void set_cancel(bool f); + + private: + void set2vector(expr_set const& set, ptr_vector& es) const; + expr_ref mk_at_most(expr_set const& set, unsigned k); + }; + +}; + +#endif diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index 725fa6072..5c5bace02 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -53,10 +53,6 @@ namespace opt { m_aux(m), m_assignment(m) { - for (unsigned i = 0; i < m_soft.size(); ++i) { - m_aux.push_back(m.mk_fresh_const("p", m.mk_bool_sort())); - s.assert_expr(m.mk_or(m_soft[i].get(), m_aux[i].get())); - } m_upper_size = m_soft.size() + 1; } @@ -139,6 +135,10 @@ namespace opt { lbool is_sat = s.check_sat(0,0); if (!m_soft.empty() && is_sat == l_true) { solver::scoped_push _sp(s); + for (unsigned i = 0; i < m_soft.size(); ++i) { + m_aux.push_back(m.mk_fresh_const("p", m.mk_bool_sort())); + s.assert_expr(m.mk_or(m_soft[i].get(), m_aux[i].get())); + } lbool is_sat = l_true; do { From 293a97bdfc962345112065465217a3799bdcc8db Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Nov 2013 15:54:38 -0800 Subject: [PATCH 116/925] working on core-maxsat Signed-off-by: Nikolaj Bjorner --- src/opt/core_maxsat.cpp | 30 ++++++++++++++++++++++++------ src/opt/core_maxsat.h | 1 + src/opt/fu_malik.h | 10 +++++----- src/opt/maxsmt.cpp | 13 +++++++++++-- src/opt/maxsmt.h | 3 ++- src/opt/opt_params.pyg | 1 + src/smt/theory_card.cpp | 16 ++++++++-------- 7 files changed, 52 insertions(+), 22 deletions(-) diff --git a/src/opt/core_maxsat.cpp b/src/opt/core_maxsat.cpp index b0234c6cf..0ea239854 100644 --- a/src/opt/core_maxsat.cpp +++ b/src/opt/core_maxsat.cpp @@ -18,6 +18,7 @@ Notes: --*/ #include "core_maxsat.h" #include "card_decl_plugin.h" +#include "ast_pp.h" namespace opt { @@ -36,9 +37,9 @@ namespace opt { solver::scoped_push _sp(s); for (unsigned i = 0; i < m_soft.size(); ++i) { expr* a = m.mk_fresh_const("p", m.mk_bool_sort()); - aux.push_back(a); - s.assert_expr(m.mk_implies(a, m_soft[i].get())); - block_vars.insert(a); + aux.push_back(m.mk_not(a)); + s.assert_expr(m.mk_or(a, m_soft[i].get())); + block_vars.insert(aux.back()); } while (m_answer.size() < m_upper) { ptr_vector vars; @@ -60,20 +61,30 @@ namespace opt { ans.push_back(m_soft[i].get()); } } + TRACE("opt", tout << "sat\n"; + for (unsigned i = 0; i < ans.size(); ++i) { + tout << mk_pp(ans[i].get(), m) << "\n"; + }); if (ans.size() > m_answer.size()) { m_answer.reset(); m_answer.append(ans); } - unsigned k = m_soft.size()-m_answer.size()-1; // TBD: fix this + unsigned k = m_soft.size()-m_answer.size()-1; expr_ref fml = mk_at_most(core_vars, k); + TRACE("opt", tout << "add: " << fml << "\n";); s.assert_expr(fml); break; } case l_false: { ptr_vector core; s.get_unsat_core(core); + TRACE("opt", tout << "core"; + for (unsigned i = 0; i < core.size(); ++i) { + tout << mk_pp(core[i], m) << " "; + } + tout << "\n";); for (unsigned i = 0; i < core.size(); ++i) { - core_vars.insert(core[i]); + core_vars.insert(get_not(core[i])); block_vars.remove(core[i]); } if (core.empty()) { @@ -84,9 +95,10 @@ namespace opt { // at least one core variable is True expr_ref fml = mk_at_most(core_vars, 0); fml = m.mk_not(fml); + TRACE("opt", tout << "add: " << fml << "\n";); s.assert_expr(fml); } - --m_upper; + --m_upper; } } } @@ -107,6 +119,12 @@ namespace opt { set2vector(set, es); return expr_ref(card.mk_at_most_k(es.size(), es.c_ptr(), k), m); } + + expr* core_maxsat::get_not(expr* e) const { + expr* result = 0; + VERIFY(m.is_not(e, result)); + return result; + } rational core_maxsat::get_lower() const { return rational(m_answer.size()); diff --git a/src/opt/core_maxsat.h b/src/opt/core_maxsat.h index eebcf1d91..b5ee6e422 100644 --- a/src/opt/core_maxsat.h +++ b/src/opt/core_maxsat.h @@ -44,6 +44,7 @@ namespace opt { private: void set2vector(expr_set const& set, ptr_vector& es) const; expr_ref mk_at_most(expr_set const& set, unsigned k); + expr* get_not(expr* e) const; }; }; diff --git a/src/opt/fu_malik.h b/src/opt/fu_malik.h index 48be07316..9375e29c2 100644 --- a/src/opt/fu_malik.h +++ b/src/opt/fu_malik.h @@ -6,6 +6,7 @@ Module Name: fu_malik.h Abstract: + Fu&Malik built-in optimization method. Adapted from sample code in C. @@ -15,6 +16,10 @@ Author: Notes: + Takes solver with hard constraints added. + Returns a maximal satisfying subset of soft_constraints + that are still consistent with the solver state. + --*/ #ifndef _OPT_FU_MALIK_H_ #define _OPT_FU_MALIK_H_ @@ -23,11 +28,6 @@ Notes: #include "maxsmt.h" namespace opt { - /** - Takes solver with hard constraints added. - Returns a maximal satisfying subset of soft_constraints - that are still consistent with the solver state. - */ class fu_malik : public maxsmt_solver { struct imp; diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 9603286d1..b2f09f3c1 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -3,7 +3,7 @@ Copyright (c) 2013 Microsoft Corporation Module Name: - opt_maxsmt.cpp + maxsmt.cpp Abstract: @@ -19,8 +19,10 @@ Notes: #include "maxsmt.h" #include "fu_malik.h" +#include "core_maxsat.h" #include "weighted_maxsat.h" #include "ast_pp.h" +#include "opt_params.hpp" namespace opt { @@ -35,7 +37,12 @@ namespace opt { m_answer.append(m_soft_constraints); } else if (is_maxsat_problem(m_weights)) { - m_msolver = alloc(fu_malik, m, s, m_soft_constraints); + if (m_maxsat_engine == symbol("core_maxsat")) { + m_msolver = alloc(core_maxsat, m, s, m_soft_constraints); + } + else { + m_msolver = alloc(fu_malik, m, s, m_soft_constraints); + } } else { m_msolver = alloc(wmaxsmt, m, opt_solver::to_opt(s), m_soft_constraints, m_weights); @@ -110,6 +117,8 @@ namespace opt { } void maxsmt::updt_params(params_ref& p) { + opt_params _p(p); + m_maxsat_engine = _p.maxsat_engine(); } diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index e3105847d..b6bb15e52 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -3,7 +3,7 @@ Copyright (c) 2013 Microsoft Corporation Module Name: - opt_maxsmt.h + maxsmt.h Abstract: @@ -47,6 +47,7 @@ namespace opt { expr_ref_vector m_answer; vector m_weights; scoped_ptr m_msolver; + symbol m_maxsat_engine; public: maxsmt(ast_manager& m): m(m), m_s(0), m_cancel(false), m_soft_constraints(m), m_answer(m) {} diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index 3c2381040..983c3ed73 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -3,6 +3,7 @@ def_module_params('opt', export=True, params=(('timeout', UINT, UINT_MAX, 'set timeout'), ('engine', SYMBOL, 'basic', "select optimization engine: 'basic', 'farkas', 'symba'"), + ('maxsat_engine', SYMBOL, 'fu_malik', "select engine for non-weighted maxsat: 'fu_malik', 'core_maxsat'"), ('pareto', BOOL, False, 'return a Pareto front (as opposed to a bounding box)'), )) diff --git a/src/smt/theory_card.cpp b/src/smt/theory_card.cpp index 4cd23d225..af8c2cdff 100644 --- a/src/smt/theory_card.cpp +++ b/src/smt/theory_card.cpp @@ -453,19 +453,19 @@ namespace smt { void theory_card::pop_scope_eh(unsigned num_scopes) { unsigned sz = m_watch_lim[m_watch_lim.size()-num_scopes]; - for (unsigned i = m_watch_trail.size(); i > sz; ) { - --i; + while (m_watch_trail.size() > sz) { ptr_vector* cards = 0; - VERIFY(m_watch.find(m_watch_trail[i], cards)); + VERIFY(m_watch.find(m_watch_trail.back(), cards)); SASSERT(cards && !cards->empty()); cards->pop_back(); + m_watch_trail.pop_back(); } m_watch_lim.resize(m_watch_lim.size()-num_scopes); sz = m_cards_lim[m_cards_lim.size()-num_scopes]; - for (unsigned i = m_cards_trail.size(); i > sz; ) { - --i; - SASSERT(m_cards.contains(m_cards_trail[i])); - m_cards.remove(m_cards_trail[i]); + while (m_cards_trail.size() > sz) { + SASSERT(m_cards.contains(m_cards_trail.back())); + m_cards.remove(m_cards_trail.back()); + m_cards_trail.pop_back(); } m_cards_lim.resize(m_cards_lim.size()-num_scopes); } @@ -482,7 +482,7 @@ namespace smt { TRACE("card", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";); justification* js = 0; ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); - IF_VERBOSE(0, + IF_VERBOSE(1, for (unsigned i = 0; i < lits.size(); ++i) { verbose_stream() << lits[i] << " "; } From 3e8c7d85aae4f23e487934bbbe4a373a4eebb040 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Nov 2013 16:13:26 -0800 Subject: [PATCH 117/925] add vocabulary for arbitrary PB inequalities Signed-off-by: Nikolaj Bjorner --- src/ast/card_decl_plugin.cpp | 59 +++++++++++++++++++++++++++++++----- src/ast/card_decl_plugin.h | 14 +++++++-- 2 files changed, 62 insertions(+), 11 deletions(-) diff --git a/src/ast/card_decl_plugin.cpp b/src/ast/card_decl_plugin.cpp index acb6d8adb..16199384b 100644 --- a/src/ast/card_decl_plugin.cpp +++ b/src/ast/card_decl_plugin.cpp @@ -20,7 +20,8 @@ Revision History: #include "card_decl_plugin.h" card_decl_plugin::card_decl_plugin(): - m_at_most_sym("at-most") + m_at_most_sym("at-most"), + m_pble_sym("pble") {} func_decl * card_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, @@ -32,16 +33,36 @@ func_decl * card_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, m.raise_exception("invalid non-Boolean sort applied to 'at-most'"); } } - if (num_parameters != 1 || !parameters[0].is_int() || parameters[0].get_int() < 0) { - m.raise_exception("function 'at-most' expects one non-negative integer parameter"); + switch(k) { + case OP_AT_MOST_K: { + if (num_parameters != 1 || !parameters[0].is_int() || parameters[0].get_int() < 0) { + m.raise_exception("function 'at-most' expects one non-negative integer parameter"); + } + func_decl_info info(m_family_id, OP_AT_MOST_K, 1, parameters); + return m.mk_func_decl(m_at_most_sym, arity, domain, m.mk_bool_sort(), info); + } + case OP_PB_LE: { + if (num_parameters != 1 + arity || !parameters[0].is_int()) { + m.raise_exception("function 'pble' expects arity+1 integer parameters"); + } + for (unsigned i = 1; i < num_parameters; ++i) { + if (!parameters[i].is_int()) { + m.raise_exception("function 'pble' expects arity+1 integer parameters"); + } + } + func_decl_info info(m_family_id, OP_PB_LE, num_parameters, parameters); + return m.mk_func_decl(m_pble_sym, arity, domain, m.mk_bool_sort(), info); + } + default: + UNREACHABLE(); + return 0; } - func_decl_info info(m_family_id, OP_AT_MOST_K, 1, parameters); - return m.mk_func_decl(m_at_most_sym, arity, domain, m.mk_bool_sort(), info); } void card_decl_plugin::get_op_names(svector & op_names, symbol const & logic) { if (logic == symbol::null) { op_names.push_back(builtin_name(m_at_most_sym.bare_str(), OP_AT_MOST_K)); + op_names.push_back(builtin_name(m_pble_sym.bare_str(), OP_PB_LE)); } } @@ -65,8 +86,30 @@ bool card_util::is_at_most_k(app *a, unsigned& k) const { } } -unsigned card_util::get_k(app *a) const { - SASSERT(is_at_most_k(a)); - return static_cast(a->get_decl()->get_parameter(0).get_int()); +int card_util::get_k(app *a) const { + SASSERT(is_at_most_k(a) || is_le(a)); + return a->get_decl()->get_parameter(0).get_int(); } + +bool card_util::is_le(app *a) const { + return is_app_of(a, m_fid, OP_PB_LE); +} + +bool card_util::is_le(app* a, int& k) const { + if (is_le(a)) { + k = get_k(a); + return true; + } + else { + return false; + } +} + +int card_util::get_le_coeff(app* a, unsigned index) { + SASSERT(is_le(a)); + SASSERT(1 + index < a->get_decl()->get_num_parameters()); + return a->get_decl()->get_parameter(index + 1).get_int(); +} + + diff --git a/src/ast/card_decl_plugin.h b/src/ast/card_decl_plugin.h index 3529a1a04..28a22b0be 100644 --- a/src/ast/card_decl_plugin.h +++ b/src/ast/card_decl_plugin.h @@ -30,14 +30,17 @@ hence: #include"ast.h" enum card_op_kind { - OP_AT_MOST_K, + OP_AT_MOST_K, // at most K Booleans are true. + OP_PB_LE, // pseudo-Boolean <= (generalizes at_most_k) LAST_CARD_OP }; class card_decl_plugin : public decl_plugin { symbol m_at_most_sym; + symbol m_pble_sym; func_decl * mk_at_most(unsigned arity, unsigned k); + func_decl * mk_le(unsigned arity, int const* coeffs, int k); public: card_decl_plugin(); virtual ~card_decl_plugin() {} @@ -54,7 +57,8 @@ public: // // Contract for func_decl: // parameters[0] - integer (at most k elements) - // all sorts are Booleans + // all sorts are Booleans + // parameters[1] .. parameters[arity] - coefficients virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range); virtual void get_op_names(svector & op_names, symbol const & logic); @@ -68,9 +72,13 @@ public: card_util(ast_manager& m):m(m), m_fid(m.mk_family_id("card")) {} ast_manager & get_manager() const { return m; } app * mk_at_most_k(unsigned num_args, expr * const * args, unsigned k); + app * mk_le(unsigned num_args, int * const* coeffs, expr * const * args, int k); bool is_at_most_k(app *a) const; bool is_at_most_k(app *a, unsigned& k) const; - unsigned get_k(app *a) const; + int get_k(app *a) const; + bool is_le(app *a) const; + bool is_le(app* a, int& k) const; + int get_le_coeff(app* a, unsigned index); }; From e412d6175d46a550cc598b4c1d6d573d112aa475 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Nov 2013 16:19:49 -0800 Subject: [PATCH 118/925] add pb capabilities Signed-off-by: Nikolaj Bjorner --- src/ast/card_decl_plugin.cpp | 3 +++ src/smt/theory_card.cpp | 21 ++++++++++++++------- src/smt/theory_card.h | 2 +- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/ast/card_decl_plugin.cpp b/src/ast/card_decl_plugin.cpp index 16199384b..d32a2f5f2 100644 --- a/src/ast/card_decl_plugin.cpp +++ b/src/ast/card_decl_plugin.cpp @@ -107,6 +107,9 @@ bool card_util::is_le(app* a, int& k) const { } int card_util::get_le_coeff(app* a, unsigned index) { + if (is_at_most_k(a)) { + return 1; + } SASSERT(is_le(a)); SASSERT(1 + index < a->get_decl()->get_num_parameters()); return a->get_decl()->get_parameter(index + 1).get_int(); diff --git a/src/smt/theory_card.cpp b/src/smt/theory_card.cpp index af8c2cdff..387f156a4 100644 --- a/src/smt/theory_card.cpp +++ b/src/smt/theory_card.cpp @@ -63,8 +63,8 @@ namespace smt { context& ctx = get_context(); ast_manager& m = get_manager(); unsigned num_args = atom->get_num_args(); - SASSERT(m_util.is_at_most_k(atom)); - unsigned k = m_util.get_k(atom); + SASSERT(m_util.is_at_most_k(atom) || m_util.is_le(atom)); + int k = m_util.get_k(atom); if (ctx.b_internalized(atom)) { @@ -78,10 +78,16 @@ namespace smt { SASSERT(!ctx.b_internalized(atom)); bool_var abv = ctx.mk_bool_var(atom); - if (k >= atom->get_num_args()) { - literal lit(abv); - ctx.mk_th_axiom(get_id(), 1, &lit); - return true; + if (k >= static_cast(num_args)) { + bool all_pos = true; + for (unsigned i = 0; all_pos && i < num_args; ++i) { + all_pos = 0 < m_util.get_le_coeff(atom, i); + } + if (all_pos) { + literal lit(abv); + ctx.mk_th_axiom(get_id(), 1, &lit); + return true; + } } card* c = alloc(card, abv, k); @@ -118,7 +124,8 @@ namespace smt { ctx.mk_th_axiom(get_id(), 1, &lit); ctx.mark_as_relevant(tmp); } - c->m_args.push_back(std::make_pair(bv,1)); + int coeff = m_util.get_le_coeff(atom, i); + c->m_args.push_back(std::make_pair(bv, coeff)); } add_card(c); return true; diff --git a/src/smt/theory_card.h b/src/smt/theory_card.h index 3c9e3c1f9..b3739e5b9 100644 --- a/src/smt/theory_card.h +++ b/src/smt/theory_card.h @@ -43,7 +43,7 @@ namespace smt { int m_abs_min; int m_abs_max; arg_t m_args; - card(bool_var bv, unsigned k): + card(bool_var bv, int k): m_k(k), m_bv(bv) {} }; From 0d6ffe6b31faa004f752f47070c414fa03b34f9e Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Mon, 11 Nov 2013 08:51:52 +0100 Subject: [PATCH 119/925] Implement three pivot rules --- src/smt/network_flow.h | 195 ++++++++++++++++++++++++++++++++++-- src/smt/network_flow_def.h | 45 ++++----- src/smt/spanning_tree_def.h | 34 ++++--- 3 files changed, 226 insertions(+), 48 deletions(-) diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index 44861575a..5390f53ea 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -23,8 +23,6 @@ Notes: It remains unclear how to convert DL assignment to a basic feasible solution of Network Simplex. A naive approach is to run an algorithm on max flow in order to get a spanning tree. - - The network_simplex class hasn't had multiple pivoting strategies yet. --*/ #ifndef _NETWORK_FLOW_H_ @@ -36,20 +34,207 @@ Notes: namespace smt { + enum pivot_rule { + // First eligible edge pivot rule + // Edges are traversed in a wraparound fashion + FIRST_ELIGIBLE, + // Best eligible edge pivot rule + // The best edge is selected in every iteration + BEST_ELIGIBLE, + // Candidate list pivot rule + // Major iterations: candidate list is built from eligible edges (in a wraparound way) + // Minor iterations: the best edge is selected from the list + CANDIDATE_LIST + }; + // Solve minimum cost flow problem using Network Simplex algorithm template class network_flow : private Ext { + private: enum edge_state { LOWER = 1, BASIS = 0, UPPER = -1 }; + typedef dl_var node; typedef dl_edge edge; typedef dl_graph graph; typedef typename Ext::numeral numeral; typedef typename Ext::fin_numeral fin_numeral; + class pivot_rule_impl { + protected: + graph & m_graph; + svector & m_states; + vector & m_potentials; + edge_id & m_enter_id; + + public: + pivot_rule_impl() {} + pivot_rule_impl(graph & g, vector & potentials, + svector & states, edge_id & enter_id) + : m_graph(g), + m_potentials(potentials), + m_states(states), + m_enter_id(enter_id) { + } + bool choose_entering_edge() {return false;}; + }; + + class first_eligible_pivot : pivot_rule_impl { + private: + edge_id m_next_edge; + + public: + first_eligible_pivot(graph & g, vector & potentials, + svector & states, edge_id & enter_id) : + pivot_rule_impl(g, potentials, states, enter_id), + m_next_edge(0) { + } + + bool choose_entering_edge() { + TRACE("network_flow", tout << "choose_entering_edge...\n";); + unsigned num_edges = m_graph.get_num_edges(); + for (unsigned i = m_next_edge; i < m_next_edge + num_edges; ++i) { + edge_id id = (i >= num_edges) ? (i - num_edges) : i; + node src = m_graph.get_source(id); + node tgt = m_graph.get_target(id); + if (m_states[id] != BASIS) { + numeral cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(id); + if (cost.is_pos()) { + m_enter_id = id; + TRACE("network_flow", { + tout << "Found entering edge " << id << " between node "; + tout << src << " and node " << tgt << " with reduced cost = " << cost << "...\n"; + }); + return true; + } + } + } + TRACE("network_flow", tout << "Found no entering edge...\n";); + return false; + }; + }; + + class best_eligible_pivot : pivot_rule_impl { + public: + best_eligible_pivot(graph & g, vector & potentials, + svector & states, edge_id & enter_id) : + pivot_rule_impl(g, potentials, states, enter_id) { + } + + bool choose_entering_edge() { + TRACE("network_flow", tout << "choose_entering_edge...\n";); + unsigned num_edges = m_graph.get_num_edges(); + numeral max = numeral::zero(); + for (unsigned i = 0; i < num_edges; ++i) { + node src = m_graph.get_source(i); + node tgt = m_graph.get_target(i); + if (m_states[i] != BASIS) { + numeral cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(i); + if (cost > max) { + max = cost; + m_enter_id = i; + } + } + } + if (max.is_pos()) { + TRACE("network_flow", { + tout << "Found entering edge " << m_enter_id << " between node "; + tout << m_graph.get_source(m_enter_id) << " and node " << m_graph.get_target(m_enter_id); + tout << " with reduced cost = " << max << "...\n"; + }); + return true; + } + TRACE("network_flow", tout << "Found no entering edge...\n";); + return false; + }; + }; + + class candidate_list_pivot : pivot_rule_impl { + private: + edge_id m_next_edge; + svector m_candidates; + unsigned num_candidates; + static const unsigned NUM_CANDIDATES = 10; + + public: + candidate_list_pivot(graph & g, vector & potentials, + svector & states, edge_id & enter_id) : + pivot_rule_impl(g, potentials, states, enter_id), + m_next_edge(0), + num_candidates(NUM_CANDIDATES), + m_candidates(num_candidates) { + } + + bool choose_entering_edge() { + if (m_candidates.empty()) { + // Build the candidate list + unsigned num_edges = m_graph.get_num_edges(); + numeral max = numeral::zero(); + unsigned count = 0; + for (unsigned i = m_next_edge; i < m_next_edge + num_edges; ++i) { + edge_id id = (i >= num_edges) ? i - num_edges : i; + node src = m_graph.get_source(id); + node tgt = m_graph.get_target(id); + if (m_states[id] != BASIS) { + numeral cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(id); + if (cost.is_pos()) { + m_candidates[count++] = id; + if (cost > max) { + max = cost; + m_enter_id = id; + } + } + if (count >= num_candidates) break; + } + } + m_next_edge = m_enter_id; + if (max.is_pos()) { + TRACE("network_flow", { + tout << "Found entering edge " << m_enter_id << " between node "; + tout << m_graph.get_source(m_enter_id) << " and node " << m_graph.get_target(m_enter_id); + tout << " with reduced cost = " << max << "...\n"; + }); + return true; + } + TRACE("network_flow", tout << "Found no entering edge...\n";); + return false; + } + else { + numeral max = numeral::zero(); + unsigned last = m_candidates.size(); + for (unsigned i = 0; i < last; ++i) { + edge_id id = m_candidates[i]; + node src = m_graph.get_source(id); + node tgt = m_graph.get_target(id); + if (m_states[id] != BASIS) { + numeral cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(id); + if (cost > max) { + max = cost; + m_enter_id = id; + } + // Remove stale candidates + if (!cost.is_pos()) { + m_candidates[i] = m_candidates[--last]; + } + } + } + if (max.is_pos()) { + TRACE("network_flow", { + tout << "Found entering edge " << m_enter_id << " between node "; + tout << m_graph.get_source(m_enter_id) << " and node " << m_graph.get_target(m_enter_id); + tout << " with reduced cost = " << max << "...\n"; + }); + return true; + } + TRACE("network_flow", tout << "Found no entering edge...\n";); + return false; + } + }; + }; + graph m_graph; thread_spanning_tree m_tree; @@ -76,9 +261,7 @@ namespace smt { void update_flows(); - // If all reduced costs are non-negative, return false since the current spanning tree is optimal - // Otherwise return true and update m_entering_edge - bool choose_entering_edge(); + bool choose_entering_edge(pivot_rule pr); // Send as much flow as possible around the cycle, the first basic edge with flow 0 will leave // Return false if the problem is unbounded @@ -99,7 +282,7 @@ namespace smt { // Minimize cost flows // Return true if found an optimal solution, and return false if unbounded - bool min_cost(); + bool min_cost(pivot_rule pr = FIRST_ELIGIBLE); // Compute the optimal solution numeral get_optimal_solution(vector & result, bool is_dual); diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index d31289dfc..515d49933 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -129,30 +129,6 @@ namespace smt { TRACE("network_flow", tout << pp_vector("Flows", m_flows, true);); } - template - bool network_flow::choose_entering_edge() { - TRACE("network_flow", tout << "choose_entering_edge...\n";); - unsigned num_edges = m_graph.get_num_edges(); - for (unsigned i = 0; i < num_edges; ++i) { - node src = m_graph.get_source(i); - node tgt = m_graph.get_target(i); - if (m_states[i] != BASIS) { - numeral cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(i); - // TODO: add multiple pivoting strategies - if (cost.is_pos()) { - m_enter_id = i; - TRACE("network_flow", { - tout << "Found entering edge " << i << " between node "; - tout << src << " and node " << tgt << " with reduced cost = " << cost << "...\n"; - }); - return true; - } - } - } - TRACE("network_flow", tout << "Found no entering edge...\n";); - return false; - } - template bool network_flow::choose_leaving_edge() { TRACE("network_flow", tout << "choose_leaving_edge...\n";); @@ -191,12 +167,29 @@ namespace smt { m_tree.update(m_enter_id, m_leave_id); } + // FIXME: should declare pivot as a pivot_rule_impl and refactor + template + bool network_flow::choose_entering_edge(pivot_rule pr) { + if (pr == FIRST_ELIGIBLE) { + first_eligible_pivot pivot(m_graph, m_potentials, m_states, m_enter_id); + return pivot.choose_entering_edge(); + } + else if (pr == BEST_ELIGIBLE) { + best_eligible_pivot pivot(m_graph, m_potentials, m_states, m_enter_id); + return pivot.choose_entering_edge(); + } + else { + candidate_list_pivot pivot(m_graph, m_potentials, m_states, m_enter_id); + return pivot.choose_entering_edge(); + } + } + // Minimize cost flows // Return true if found an optimal solution, and return false if unbounded template - bool network_flow::min_cost() { + bool network_flow::min_cost(pivot_rule pr) { initialize(); - while (choose_entering_edge()) { + while (choose_entering_edge(pr)) { bool bounded = choose_leaving_edge(); if (!bounded) return false; update_flows(); diff --git a/src/smt/spanning_tree_def.h b/src/smt/spanning_tree_def.h index 2be593842..be668d91d 100644 --- a/src/smt/spanning_tree_def.h +++ b/src/smt/spanning_tree_def.h @@ -162,7 +162,7 @@ namespace smt { tout << u << ", " << v << ") leaves\n"; }); - node old_pred = m_pred[q]; + node old_pred = m_pred[q]; // Update stem nodes from q to v if (q != v) { for (node n = q; n != u; ) { @@ -175,18 +175,23 @@ namespace smt { old_pred = next_old_pred; } } - else { - node x = get_final(p); - node y = m_thread[x]; - node z = get_final(q); - node t = m_thread[get_final(v)]; - node r = find_rev_thread(v); - m_thread[z] = y; - m_thread[x] = q; - m_thread[r] = t; - } - m_pred[q] = p; + // Old threads: alpha -> q -*-> f(q) -> beta | p -*-> f(p) -> gamma + // New threads: alpha -> beta | p -*-> f(p) -> q -*-> f(q) -> gamma + + node f_p = get_final(p); + node f_q = get_final(q); + node alpha = find_rev_thread(q); + node beta = m_thread[f_q]; + node gamma = m_thread[f_p]; + + if (q != gamma) { + m_thread[alpha] = beta; + m_thread[f_p] = q; + m_thread[f_q] = gamma; + } + + m_pred[q] = p; m_tree[q] = enter_id; m_root_t2 = q; @@ -211,7 +216,6 @@ namespace smt { Spanning tree of m_graph + root is represented using: svector m_states; edge_id |-> edge_state - svector m_upwards; node |-> bool svector m_pred; node |-> node svector m_depth; node |-> int svector m_thread; node |-> node @@ -224,9 +228,7 @@ namespace smt { m_thread is a linked list traversing all nodes. Furthermore, the nodes linked in m_thread follows a depth-first traversal order. - - m_upwards direction of edge from i to m_pred[i] m_graph - + */ template bool thread_spanning_tree::check_well_formed() { From 66eda866ca6efa54a1e3cea7666e3e7e2bcb5f1f Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Mon, 11 Nov 2013 18:23:21 -0800 Subject: [PATCH 120/925] Fix bugs on candidate list pivot rule --- src/smt/network_flow.h | 76 ++++++++++++++++++++----------------- src/smt/spanning_tree_def.h | 24 +++++++----- 2 files changed, 57 insertions(+), 43 deletions(-) diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index 5390f53ea..461312985 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -156,24 +156,29 @@ namespace smt { private: edge_id m_next_edge; svector m_candidates; - unsigned num_candidates; + unsigned m_num_candidates; + unsigned m_minor_step; + unsigned m_current_length; static const unsigned NUM_CANDIDATES = 10; + static const unsigned MINOR_STEP_LIMIT = 5; public: candidate_list_pivot(graph & g, vector & potentials, svector & states, edge_id & enter_id) : pivot_rule_impl(g, potentials, states, enter_id), m_next_edge(0), - num_candidates(NUM_CANDIDATES), - m_candidates(num_candidates) { + m_minor_step(0), + m_current_length(0), + m_num_candidates(NUM_CANDIDATES), + m_candidates(m_num_candidates) { } bool choose_entering_edge() { - if (m_candidates.empty()) { + if (m_current_length == 0 || m_minor_step == MINOR_STEP_LIMIT) { // Build the candidate list unsigned num_edges = m_graph.get_num_edges(); numeral max = numeral::zero(); - unsigned count = 0; + m_current_length = 0; for (unsigned i = m_next_edge; i < m_next_edge + num_edges; ++i) { edge_id id = (i >= num_edges) ? i - num_edges : i; node src = m_graph.get_source(id); @@ -181,16 +186,18 @@ namespace smt { if (m_states[id] != BASIS) { numeral cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(id); if (cost.is_pos()) { - m_candidates[count++] = id; + m_candidates[m_current_length] = id; + ++m_current_length; if (cost > max) { max = cost; m_enter_id = id; } } - if (count >= num_candidates) break; + if (m_current_length >= m_num_candidates) break; } } m_next_edge = m_enter_id; + m_minor_step = 1; if (max.is_pos()) { TRACE("network_flow", { tout << "Found entering edge " << m_enter_id << " between node "; @@ -202,36 +209,37 @@ namespace smt { TRACE("network_flow", tout << "Found no entering edge...\n";); return false; } - else { - numeral max = numeral::zero(); - unsigned last = m_candidates.size(); - for (unsigned i = 0; i < last; ++i) { - edge_id id = m_candidates[i]; - node src = m_graph.get_source(id); - node tgt = m_graph.get_target(id); - if (m_states[id] != BASIS) { - numeral cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(id); - if (cost > max) { - max = cost; - m_enter_id = id; - } - // Remove stale candidates - if (!cost.is_pos()) { - m_candidates[i] = m_candidates[--last]; - } + + ++m_minor_step; + numeral max = numeral::zero(); + for (unsigned i = 0; i < m_current_length; ++i) { + edge_id id = m_candidates[i]; + node src = m_graph.get_source(id); + node tgt = m_graph.get_target(id); + if (m_states[id] != BASIS) { + numeral cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(id); + if (cost > max) { + max = cost; + m_enter_id = id; + } + // Remove stale candidates + if (!cost.is_pos()) { + --m_current_length; + m_candidates[i] = m_candidates[m_current_length]; + --i; } } - if (max.is_pos()) { - TRACE("network_flow", { - tout << "Found entering edge " << m_enter_id << " between node "; - tout << m_graph.get_source(m_enter_id) << " and node " << m_graph.get_target(m_enter_id); - tout << " with reduced cost = " << max << "...\n"; - }); - return true; - } - TRACE("network_flow", tout << "Found no entering edge...\n";); - return false; } + if (max.is_pos()) { + TRACE("network_flow", { + tout << "Found entering edge " << m_enter_id << " between node "; + tout << m_graph.get_source(m_enter_id) << " and node " << m_graph.get_target(m_enter_id); + tout << " with reduced cost = " << max << "...\n"; + }); + return true; + } + TRACE("network_flow", tout << "Found no entering edge...\n";); + return false; }; }; diff --git a/src/smt/spanning_tree_def.h b/src/smt/spanning_tree_def.h index be668d91d..c1e05ba3b 100644 --- a/src/smt/spanning_tree_def.h +++ b/src/smt/spanning_tree_def.h @@ -333,23 +333,29 @@ namespace smt { SASSERT(m_pred[q] == v); SASSERT(is_preorder_traversal(v, get_final(v))); node prev = find_rev_thread(v); - node final_q = get_final(q); - node final_v = get_final(v); - node next = m_thread[final_v]; + node f_q = get_final(q); + node f_v = get_final(v); + node next = m_thread[f_v]; node alpha = find_rev_thread(q); - if (final_q == final_v) { - m_thread[final_q] = v; + if (f_q == f_v) { + SASSERT(f_q != v && alpha != next); + m_thread[f_q] = v; m_thread[alpha] = next; + f_q = alpha; } - else { - node beta = m_thread[final_q]; - m_thread[final_q] = v; + else { + node beta = m_thread[f_q]; + SASSERT(f_q != v && alpha != beta); + m_thread[f_q] = v; m_thread[alpha] = beta; + f_q = f_v; } + SASSERT(prev != q); m_thread[prev] = q; m_pred[v] = q; - SASSERT(is_preorder_traversal(q, get_final(q))); + // Notes: f_q has to be used since m_depth hasn't been updated yet. + SASSERT(is_preorder_traversal(q, f_q)); } /** From 64daa2977d1a961d387a3ab058850d16ae0c7ccd Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Tue, 12 Nov 2013 16:14:21 -0800 Subject: [PATCH 121/925] Fix termination conditions on core_maxsat --- src/opt/core_maxsat.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/opt/core_maxsat.cpp b/src/opt/core_maxsat.cpp index 0ea239854..e131526cf 100644 --- a/src/opt/core_maxsat.cpp +++ b/src/opt/core_maxsat.cpp @@ -69,6 +69,10 @@ namespace opt { m_answer.reset(); m_answer.append(ans); } + if (m_answer.size() == m_upper) { + return l_true; + } + SASSERT(m_soft.size() >= m_answer.size()+1); unsigned k = m_soft.size()-m_answer.size()-1; expr_ref fml = mk_at_most(core_vars, k); TRACE("opt", tout << "add: " << fml << "\n";); From 133ba2d02a30f44403e70938e7cf268f3d9c58f0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Nov 2013 13:41:14 -0500 Subject: [PATCH 122/925] fixes to pb solver Signed-off-by: Nikolaj Bjorner --- src/muz/transforms/dl_transforms.cpp | 25 ++- src/smt/theory_card.cpp | 319 ++++++++++++++++++++++----- src/smt/theory_card.h | 43 ++-- 3 files changed, 303 insertions(+), 84 deletions(-) diff --git a/src/muz/transforms/dl_transforms.cpp b/src/muz/transforms/dl_transforms.cpp index 2cf48d46b..80634c676 100644 --- a/src/muz/transforms/dl_transforms.cpp +++ b/src/muz/transforms/dl_transforms.cpp @@ -44,6 +44,18 @@ namespace datalog { transf.register_plugin(alloc(datalog::mk_coi_filter, ctx)); transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, ctx)); + if (ctx.get_params().quantify_arrays()) { + transf.register_plugin(alloc(datalog::mk_quantifier_abstraction, ctx, 38000)); + } + transf.register_plugin(alloc(datalog::mk_quantifier_instantiation, ctx, 37000)); + transf.register_plugin(alloc(datalog::mk_scale, ctx, 36030)); + if (ctx.get_params().magic()) { + transf.register_plugin(alloc(datalog::mk_magic_symbolic, ctx, 36020)); + } + transf.register_plugin(alloc(datalog::mk_karr_invariants, ctx, 36010)); + transf.register_plugin(alloc(datalog::mk_array_blast, ctx, 36000)); + transf.register_plugin(alloc(datalog::mk_bit_blast, ctx, 35000)); + transf.register_plugin(alloc(datalog::mk_subsumption_checker, ctx, 35005)); transf.register_plugin(alloc(datalog::mk_rule_inliner, ctx, 35000)); transf.register_plugin(alloc(datalog::mk_coi_filter, ctx, 34990)); @@ -64,19 +76,8 @@ namespace datalog { transf.register_plugin(alloc(datalog::mk_subsumption_checker, ctx, 34880)); - if (ctx.get_params().quantify_arrays()) { - transf.register_plugin(alloc(datalog::mk_quantifier_abstraction, ctx, 33000)); - transf.register_plugin(alloc(datalog::mk_array_blast, ctx, 32500)); - } - transf.register_plugin(alloc(datalog::mk_quantifier_instantiation, ctx, 32000)); - transf.register_plugin(alloc(datalog::mk_bit_blast, ctx, 35000)); - transf.register_plugin(alloc(datalog::mk_array_blast, ctx, 36000)); - transf.register_plugin(alloc(datalog::mk_karr_invariants, ctx, 36010)); - if (ctx.get_params().magic()) { - transf.register_plugin(alloc(datalog::mk_magic_symbolic, ctx, 36020)); - } - transf.register_plugin(alloc(datalog::mk_scale, ctx, 36030)); + ctx.transform_rules(transf); } } diff --git a/src/smt/theory_card.cpp b/src/smt/theory_card.cpp index 387f156a4..c32b600c1 100644 --- a/src/smt/theory_card.cpp +++ b/src/smt/theory_card.cpp @@ -22,15 +22,10 @@ Notes: Example: ((_ at-most 3) x1 x1 x2 x2) == ((_ at-most 1) x1 x2) - - count number of clauses per cardinality constraint. - - - TBD: when number of conflicts exceeds n^2 or n*log(n), + - When number of conflicts exceeds n*log(n), then create a sorting circuit. where n is the arity of the cardinality constraint. - - TBD: do clauses get re-created? keep track of gc - status of created clauses. - - TBD: add conflict resolution The idea is that if cardinality constraints c1, c2 are repeatedly asserted together, then @@ -38,11 +33,18 @@ Notes: c1 /\ c2 -> c3 + That is, during a propagation, assignment or conflict resolution + step track cutting-planes. + + - TBD: profile overhead of (re)creating sorting circuits. + Possibly delay creating them until restart. + --*/ #include "theory_card.h" #include "smt_context.h" #include "ast_pp.h" +#include "sorting_network.h" namespace smt { @@ -78,19 +80,8 @@ namespace smt { SASSERT(!ctx.b_internalized(atom)); bool_var abv = ctx.mk_bool_var(atom); - if (k >= static_cast(num_args)) { - bool all_pos = true; - for (unsigned i = 0; all_pos && i < num_args; ++i) { - all_pos = 0 < m_util.get_le_coeff(atom, i); - } - if (all_pos) { - literal lit(abv); - ctx.mk_th_axiom(get_id(), 1, &lit); - return true; - } - } - - card* c = alloc(card, abv, k); + card* c = alloc(card, m, atom, abv, k, get_compilation_threshold(atom)); + for (unsigned i = 0; i < num_args; ++i) { expr* arg = atom->get_arg(i); if (!ctx.b_internalized(arg)) { @@ -223,6 +214,7 @@ namespace smt { void theory_card::collect_statistics(::statistics& st) const { st.update("pb axioms", m_stats.m_num_axioms); st.update("pb predicates", m_stats.m_num_predicates); + st.update("pb compilations", m_stats.m_num_compiles); } void theory_card::reset_eh() { @@ -245,14 +237,14 @@ namespace smt { m_stats.reset(); } - void theory_card::update_min_max(bool_var v, bool is_true, card* c) { + void theory_card::update_min_max(bool_var v, bool is_true, card& c) { context& ctx = get_context(); ast_manager& m = get_manager(); - arg_t const& args = c->m_args; + arg_t const& args = c.m_args; int inc = find_inc(v, args); - int& min = c->m_current_min; - int& max = c->m_current_max; - int k = c->m_k; + int& min = c.m_current_min; + int& max = c.m_current_max; + int k = c.m_k; // inc > 0 & is_true -> min += inc // inc < 0 & is_true -> max += inc // inc > 0 & !is_true -> max -= inc @@ -278,7 +270,7 @@ namespace smt { SASSERT(min <= max); } - void theory_card::assign_use(bool_var v, bool is_true, card* c) { + void theory_card::assign_use(bool_var v, bool is_true, card& c) { update_min_max(v, is_true, c); propagate_assignment(c); } @@ -307,11 +299,11 @@ namespace smt { } } - int theory_card::accumulate_min(literal_vector& lits, card* c) { + int theory_card::accumulate_min(literal_vector& lits, card& c) { context& ctx = get_context(); - int k = c->m_k; - arg_t const& args = c->m_args; - int curr_min = c->m_abs_min; + int k = c.m_k; + arg_t const& args = c.m_args; + int curr_min = c.m_abs_min; for (unsigned i = 0; i < args.size() && curr_min <= k; ++i) { bool_var bv = args[i].first; int inc = args[i].second; @@ -324,11 +316,11 @@ namespace smt { return curr_min; } - int theory_card::accumulate_max(literal_vector& lits, card* c) { + int theory_card::accumulate_max(literal_vector& lits, card& c) { context& ctx = get_context(); - arg_t const& args = c->m_args; - int k = c->m_k; - int curr_max = c->m_abs_max; + arg_t const& args = c.m_args; + int k = c.m_k; + int curr_max = c.m_abs_max; for (unsigned i = 0; i < args.size() && k < curr_max; ++i) { bool_var bv = args[i].first; int inc = args[i].second; @@ -341,19 +333,33 @@ namespace smt { return curr_max; } - void theory_card::propagate_assignment(card* c) { + void theory_card::propagate_assignment(card& c) { + if (c.m_compiled) { + return; + } + if (should_compile(c)) { + compile_at_most(c); + return; + } context& ctx = get_context(); - arg_t const& args = c->m_args; - bool_var abv = c->m_bv; - int min = c->m_current_min; - int max = c->m_current_max; - int k = c->m_k; + ast_manager& m = get_manager(); + arg_t const& args = c.m_args; + bool_var abv = c.m_bv; + int min = c.m_current_min; + int max = c.m_current_max; + int k = c.m_k; + + TRACE("card", + tout << mk_pp(c.m_app, m) << " min: " + << min << " max: " << max << "\n";); // // if min > k && abv != l_false -> force abv false // if max <= k && abv != l_true -> force abv true - // if min == k && abv == l_true -> force positive unassigned literals false - // if max == k + 1 && abv == l_false -> force negative unassigned literals false + // if min == k && abv == l_true -> force positive + // unassigned literals false + // if max == k + 1 && abv == l_false -> force negative + // unassigned literals false // lbool aval = ctx.get_assignment(abv); if (min > k && aval != l_false) { @@ -361,21 +367,21 @@ namespace smt { lits.push_back(~literal(abv)); int curr_min = accumulate_min(lits, c); SASSERT(curr_min > k); - add_clause(lits); + add_clause(c, lits); } else if (max <= k && aval != l_true) { literal_vector& lits = get_lits(); lits.push_back(literal(abv)); int curr_max = accumulate_max(lits, c); SASSERT(curr_max <= k); - add_clause(lits); + add_clause(c, lits); } else if (min == k && aval == l_true) { literal_vector& lits = get_lits(); lits.push_back(~literal(abv)); int curr_min = accumulate_min(lits, c); if (curr_min > k) { - add_clause(lits); + add_clause(c, lits); } else { SASSERT(curr_min == k); @@ -383,9 +389,9 @@ namespace smt { bool_var bv = args[i].first; int inc = args[i].second; if (inc_min(inc, ctx.get_assignment(bv)) == l_undef) { - lits.push_back(literal(bv, inc > 0)); // avoid incrementing min. - add_clause(lits); - lits.pop_back(); + literal_vector lits_save(lits); // add_clause has a side-effect on literals. + lits_save.push_back(literal(bv, inc > 0)); // avoid incrementing min. + add_clause(c, lits_save); } } } @@ -395,16 +401,16 @@ namespace smt { lits.push_back(literal(abv)); int curr_max = accumulate_max(lits, c); if (curr_max <= k) { - add_clause(lits); + add_clause(c, lits); } else if (curr_max == k + 1) { for (unsigned i = 0; i < args.size(); ++i) { bool_var bv = args[i].first; int inc = args[i].second; if (dec_max(inc, ctx.get_assignment(bv)) == l_undef) { - lits.push_back(literal(bv, inc < 0)); // avoid decrementing max. - add_clause(lits); - lits.pop_back(); + literal_vector lits_save(lits); // add_clause has a side-effect on literals. + lits_save.push_back(literal(bv, inc < 0)); // avoid decrementing max. + add_clause(c, lits_save); } } } @@ -420,11 +426,11 @@ namespace smt { if (m_watch.find(v, cards)) { for (unsigned i = 0; i < cards->size(); ++i) { - assign_use(v, is_true, (*cards)[i]); + assign_use(v, is_true, *(*cards)[i]); } } if (m_cards.find(v, c)) { - propagate_assignment(c); + propagate_assignment(*c); } } @@ -449,6 +455,203 @@ namespace smt { return vars[mid].second; } + struct theory_card::sort_expr { + theory_card& th; + context& ctx; + ast_manager& m; + expr_ref_vector m_trail; + sort_expr(theory_card& th): + th(th), + ctx(th.get_context()), + m(th.get_manager()), + m_trail(m) {} + typedef expr* T; + typedef expr_ref_vector vector; + + T mk_ite(T a, T b, T c) { + if (m.is_true(a)) { + return b; + } + if (m.is_false(a)) { + return c; + } + if (b == c) { + return b; + } + m_trail.push_back(m.mk_ite(a, b, c)); + return m_trail.back(); + } + + T mk_le(T a, T b) { + return mk_ite(b, a, m.mk_true()); + } + + T mk_default() { + return m.mk_false(); + } + + literal internalize(card& ca, expr* e) { + obj_map cache; + for (unsigned i = 0; i < ca.m_args.size(); ++i) { + cache.insert(ca.m_app->get_arg(i), literal(ca.m_args[i].first)); + } + cache.insert(m.mk_false(), false_literal); + cache.insert(m.mk_true(), true_literal); + ptr_vector todo; + todo.push_back(e); + expr *a, *b, *c; + literal la, lb, lc; + while (!todo.empty()) { + expr* t = todo.back(); + if (cache.contains(t)) { + todo.pop_back(); + continue; + } + VERIFY(m.is_ite(t, a, b, c)); + unsigned sz = todo.size(); + if (!cache.find(a, la)) { + todo.push_back(a); + } + if (!cache.find(b, lb)) { + todo.push_back(b); + } + if (!cache.find(c, lc)) { + todo.push_back(c); + } + if (sz != todo.size()) { + continue; + } + todo.pop_back(); + cache.insert(t, mk_ite(ca, t, la, lb, lc)); + } + return cache.find(e); + } + + literal mk_ite(card& ca, expr* t, literal a, literal b, literal c) { + if (a == true_literal) { + return b; + } + else if (a == false_literal) { + return c; + } + else if (b == true_literal && c == false_literal) { + return a; + } + else if (b == false_literal && c == true_literal) { + return ~a; + } + else if (b == c) { + return b; + } + else { + expr_ref p(m); + expr* r; + if (ca.m_replay.find(t, r)) { + p = r; + } + else { + p = m.mk_fresh_const("s", m.mk_bool_sort()); + ca.m_replay.insert(t, p); + ca.m_trail.push_back(p); + } + literal l; + if (ctx.b_internalized(p)) { + l = literal(ctx.get_bool_var(p)); + } + else { + l = literal(ctx.mk_bool_var(p)); + } + add_clause(~l, ~a, b); + add_clause(~l, a, c); + add_clause(l, ~a, ~b); + add_clause(l, a, ~c); + TRACE("card", tout << p << " ::= (if "; + ctx.display_detailed_literal(tout, a); + ctx.display_detailed_literal(tout << " ", b); + ctx.display_detailed_literal(tout << " ", c); + tout << ")\n";); + return l; + } + } + + + // auxiliary clauses don't get garbage collected. + void add_clause(literal a, literal b, literal c) { + literal_vector& lits = th.get_lits(); + if (a != null_literal) lits.push_back(a); + if (b != null_literal) lits.push_back(b); + if (c != null_literal) lits.push_back(c); + justification* js = 0; + TRACE("card", + ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";); + ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX, 0); + } + + void add_clause(literal l1, literal l2) { + add_clause(l1, l2, null_literal); + } + + }; + + unsigned theory_card::get_compilation_threshold(app* a) { + if (!m_util.is_at_most_k(a)) { + return UINT_MAX; + } + unsigned num_args = a->get_num_args(); + unsigned log = 1, n = 1; + while (n <= num_args) { + ++log; + n *= 2; + } + TRACE("card", tout << "threshold:" << (num_args*log) << "\n";); + return num_args*log; + } + + bool theory_card::should_compile(card& c) { + if (!m_util.is_at_most_k(c.m_app)) { + return false; + } + return c.m_num_propagations >= c.m_compilation_threshold; + } + + void theory_card::compile_at_most(card& c) { + ++m_stats.m_num_compiles; + ast_manager& m = get_manager(); + context& ctx = get_context(); + app* a = c.m_app; + SASSERT(m_util.is_at_most_k(a)); + literal atmostk; + int k = m_util.get_k(a); + unsigned num_args = a->get_num_args(); + + sort_expr se(*this); + if (k >= static_cast(num_args)) { + atmostk = true_literal; + } + else if (k < 0) { + atmostk = false_literal; + } + else { + sorting_network sn(se); + expr_ref_vector in(m), out(m); + for (unsigned i = 0; i < num_args; ++i) { + in.push_back(c.m_app->get_arg(i)); + } + sn(in, out); + atmostk = ~se.internalize(c, out[k].get()); // k'th output is 0. + TRACE("card", tout << "~atmost: " << mk_pp(out[k].get(), m) << "\n";); + } + literal thl = literal(c.m_bv); + se.add_clause(~thl, atmostk); + se.add_clause(thl, ~atmostk); + TRACE("card", tout << mk_pp(a, m) << "\n";); + // auxiliary clauses get removed when popping scopes. + // we have to recompile the circuit after back-tracking. + ctx.push_trail(value_trail(c.m_compiled)); + c.m_compiled = true; + } + + void theory_card::init_search_eh() { } @@ -483,16 +686,14 @@ namespace smt { return m_literals; } - void theory_card::add_clause(literal_vector const& lits) { + void theory_card::add_clause(card& c, literal_vector const& lits) { + ++c.m_num_propagations; m_stats.m_num_axioms++; context& ctx = get_context(); - TRACE("card", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";); + TRACE("card", tout << "#prop:" << c.m_num_propagations << " - "; ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";); justification* js = 0; ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); - IF_VERBOSE(1, - for (unsigned i = 0; i < lits.size(); ++i) { - verbose_stream() << lits[i] << " "; - } + IF_VERBOSE(1, ctx.display_literals_verbose(verbose_stream(), lits.size(), lits.c_ptr()); verbose_stream() << "\n";); // ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); } diff --git a/src/smt/theory_card.h b/src/smt/theory_card.h index b3739e5b9..e8eae9232 100644 --- a/src/smt/theory_card.h +++ b/src/smt/theory_card.h @@ -22,20 +22,25 @@ Notes: #include "smt_theory.h" #include "card_decl_plugin.h" +#include "smt_clause.h" namespace smt { class theory_card : public theory { + struct sort_expr; typedef svector > arg_t; struct stats { unsigned m_num_axioms; unsigned m_num_predicates; + unsigned m_num_compiles; void reset() { memset(this, 0, sizeof(*this)); } stats() { reset(); } }; + struct card { + app* m_app; int m_k; bool_var m_bv; int m_current_min; @@ -43,9 +48,17 @@ namespace smt { int m_abs_min; int m_abs_max; arg_t m_args; - card(bool_var bv, int k): - m_k(k), m_bv(bv) - {} + unsigned m_num_propagations; + unsigned m_compilation_threshold; + bool m_compiled; + obj_map m_replay; + expr_ref_vector m_trail; + card(ast_manager& m, app* a, bool_var bv, int k, unsigned threshold): + m_app(a), m_k(k), m_bv(bv), + m_num_propagations(0), m_compilation_threshold(threshold), m_compiled(false), + m_trail(m) + { + } }; u_map*> m_watch; // use-list of literals. @@ -61,18 +74,22 @@ namespace smt { void add_watch(bool_var bv, card* c); void add_card(card* c); - void add_clause(literal_vector const& lits); + void add_clause(card& c, literal_vector const& lits); literal_vector& get_lits(); - int find_inc(bool_var bv, svector >const& vars); - void theory_card::propagate_assignment(card* c); - int theory_card::accumulate_max(literal_vector& lits, card* c); - int theory_card::accumulate_min(literal_vector& lits, card* c); - lbool theory_card::dec_max(int inc, lbool val); - lbool theory_card::inc_min(int inc, lbool val); - void theory_card::assign_use(bool_var v, bool is_true, card* c); - void theory_card::update_min_max(bool_var v, bool is_true, card* c); - + int find_inc(bool_var bv, svector >const& vars); + void propagate_assignment(card& c); + int accumulate_max(literal_vector& lits, card& c); + int accumulate_min(literal_vector& lits, card& c); + lbool dec_max(int inc, lbool val); + lbool inc_min(int inc, lbool val); + void assign_use(bool_var v, bool is_true, card& c); + void update_min_max(bool_var v, bool is_true, card& c); + + void compile_at_most(card& c); + expr_ref nnf(expr* e); + bool should_compile(card& c); + unsigned get_compilation_threshold(app* atom); public: theory_card(ast_manager& m); From d1937b2032fd49bfb0ffa11d590d269b9988b854 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Nov 2013 17:09:10 -0800 Subject: [PATCH 123/925] add PB operators to C-based API Signed-off-by: Nikolaj Bjorner --- scripts/update_api.py | 5 +++++ src/api/z3_api.h | 33 +++++++++++++++++++++++++++++++++ src/api/z3_replayer.cpp | 24 +++++++++++++++++++++++- src/api/z3_replayer.h | 1 + src/ast/card_decl_plugin.cpp | 10 ++++++++++ src/ast/card_decl_plugin.h | 3 ++- src/opt/core_maxsat.cpp | 2 ++ src/opt/fu_malik.cpp | 2 +- 8 files changed, 77 insertions(+), 3 deletions(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index fa6111482..3d8a5dfaf 100644 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -949,6 +949,11 @@ def def_API(name, result, params): log_c.write(" }\n") log_c.write(" Au(a%s);\n" % sz) exe_c.write("in.get_uint_array(%s)" % i) + elif ty == INT: + log_c.write("U(a%s[i]);" % i) + log_c.write(" }\n") + log_c.write(" Au(a%s);\n" % sz) + exe_c.write("in.get_int_array(%s)" % i) else: error ("unsupported parameter for %s, %s" % (name, p)) elif kind == OUT_ARRAY: diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 2b8c74e65..57ab9a1b7 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -874,6 +874,12 @@ typedef enum - Z3_OP_DT_ACCESSOR: datatype accessor. + - Z3_OP_PB_AT_MOST: Cardinality constraint. + E.g., x + y + z <= 2 + + - Z3_OP_PB_LE: Generalized Pseudo-Boolean cardinality constraint. + Example 2*x + 3*y <= 4 + - Z3_OP_UNINTERPRETED: kind used for uninterpreted symbols. */ typedef enum { @@ -1054,6 +1060,10 @@ typedef enum { Z3_OP_DT_RECOGNISER, Z3_OP_DT_ACCESSOR, + // Pseudo Booleans + Z3_OP_PB_AT_MOST=0x900, + Z3_OP_PB_LE, + Z3_OP_UNINTERPRETED } Z3_decl_kind; @@ -3758,6 +3768,29 @@ END_MLAPI_EXCLUDE Z3_sort Z3_API Z3_get_relation_column(__in Z3_context c, __in Z3_sort s, unsigned col); + /** + \brief Pseudo-Boolean relations. + + Encode p1 + p2 + ... + pn <= k + + def_API('Z3_mk_atmost', AST, (_in(CONTEXT), _in(UINT), _in_array(1,AST), _in(UINT))) + */ + + Z3_ast Z3_API Z3_mk_atmost(__in Z3_context c, __in unsigned num_args, + __in_ecount(num_args) Z3_ast const args[], __in unsigned k); + + /** + \brief Pseudo-Boolean relations. + + Encode k1*p1 + k2*p2 + ... + kn*pn <= k + + def_API('Z3_mk_pble', AST, (_in(CONTEXT), _in(UINT), _in_array(1,AST), _in_array(1,INT), _in(INT))) + */ + + Z3_ast Z3_API Z3_mk_pble(__in Z3_context c, __in unsigned num_args, + __in_ecount(num_args) Z3_ast const args[], __in_ecount(num_args) int coeffs[], + __in int k); + /** \mlonly {3 {L Function Declarations}} \endmlonly */ diff --git a/src/api/z3_replayer.cpp b/src/api/z3_replayer.cpp index acdb10bf6..f13b2cbb8 100644 --- a/src/api/z3_replayer.cpp +++ b/src/api/z3_replayer.cpp @@ -44,7 +44,7 @@ struct z3_replayer::imp { size_t_map m_heap; svector m_cmds; - enum value_kind { INT64, UINT64, DOUBLE, STRING, SYMBOL, OBJECT, UINT_ARRAY, SYMBOL_ARRAY, OBJECT_ARRAY }; + enum value_kind { INT64, UINT64, DOUBLE, STRING, SYMBOL, OBJECT, UINT_ARRAY, INT_ARRAY, SYMBOL_ARRAY, OBJECT_ARRAY }; struct value { value_kind m_kind; @@ -68,6 +68,7 @@ struct z3_replayer::imp { vector > m_obj_arrays; vector > m_sym_arrays; vector m_unsigned_arrays; + vector > m_int_arrays; imp(z3_replayer & o, std::istream & in): m_owner(o), @@ -295,6 +296,15 @@ struct z3_replayer::imp { v.push_back(static_cast(m_args[i].m_uint)); } } + if (k == INT64) { + aidx = m_int_arrays.size(); + nk = INT_ARRAY; + m_int_arrays.push_back(svector()); + svector & v = m_int_arrays.back(); + for (unsigned i = asz - sz; i < asz; i++) { + v.push_back(static_cast(m_args[i].m_int)); + } + } else if (k == SYMBOL) { aidx = m_sym_arrays.size(); nk = SYMBOL_ARRAY; @@ -547,6 +557,13 @@ struct z3_replayer::imp { return m_unsigned_arrays[idx].c_ptr(); } + int * get_int_array(unsigned pos) const { + if (pos >= m_args.size() || m_args[pos].m_kind != INT_ARRAY) + throw_invalid_reference(); + unsigned idx = static_cast(m_args[pos].m_uint); + return m_int_arrays[idx].c_ptr(); + } + Z3_symbol * get_symbol_array(unsigned pos) const { if (pos >= m_args.size() || m_args[pos].m_kind != SYMBOL_ARRAY) throw_invalid_reference(); @@ -615,6 +632,7 @@ struct z3_replayer::imp { m_obj_arrays.reset(); m_sym_arrays.reset(); m_unsigned_arrays.reset(); + m_int_arrays.reset(); } @@ -673,6 +691,10 @@ unsigned * z3_replayer::get_uint_array(unsigned pos) const { return m_imp->get_uint_array(pos); } +int * z3_replayer::get_int_array(unsigned pos) const { + return m_imp->get_int_array(pos); +} + Z3_symbol * z3_replayer::get_symbol_array(unsigned pos) const { return m_imp->get_symbol_array(pos); } diff --git a/src/api/z3_replayer.h b/src/api/z3_replayer.h index 6de4bdb39..412032eb7 100644 --- a/src/api/z3_replayer.h +++ b/src/api/z3_replayer.h @@ -49,6 +49,7 @@ public: void * get_obj(unsigned pos) const; unsigned * get_uint_array(unsigned pos) const; + int * get_int_array(unsigned pos) const; Z3_symbol * get_symbol_array(unsigned pos) const; void ** get_obj_array(unsigned pos) const; diff --git a/src/ast/card_decl_plugin.cpp b/src/ast/card_decl_plugin.cpp index d32a2f5f2..6a15792e5 100644 --- a/src/ast/card_decl_plugin.cpp +++ b/src/ast/card_decl_plugin.cpp @@ -72,6 +72,16 @@ app * card_util::mk_at_most_k(unsigned num_args, expr * const * args, unsigned k return m.mk_app(m_fid, OP_AT_MOST_K, 1, ¶m, num_args, args, m.mk_bool_sort()); } +app * card_util::mk_le(unsigned num_args, int const * coeffs, expr * const * args, int k) { + vector params; + params.push_back(parameter(k)); + for (unsigned i = 0; i < num_args; ++i) { + params.push_back(parameter(coeffs[i])); + } + return m.mk_app(m_fid, OP_PB_LE, params.size(), params.c_ptr(), num_args, args, m.mk_bool_sort()); +} + + bool card_util::is_at_most_k(app *a) const { return is_app_of(a, m_fid, OP_AT_MOST_K); } diff --git a/src/ast/card_decl_plugin.h b/src/ast/card_decl_plugin.h index 28a22b0be..3ac681284 100644 --- a/src/ast/card_decl_plugin.h +++ b/src/ast/card_decl_plugin.h @@ -71,8 +71,9 @@ class card_util { public: card_util(ast_manager& m):m(m), m_fid(m.mk_family_id("card")) {} ast_manager & get_manager() const { return m; } + family_id get_family_id() const { return m_fid; } app * mk_at_most_k(unsigned num_args, expr * const * args, unsigned k); - app * mk_le(unsigned num_args, int * const* coeffs, expr * const * args, int k); + app * mk_le(unsigned num_args, int const * coeffs, expr * const * args, int k); bool is_at_most_k(app *a) const; bool is_at_most_k(app *a, unsigned& k) const; int get_k(app *a) const; diff --git a/src/opt/core_maxsat.cpp b/src/opt/core_maxsat.cpp index e131526cf..b4472971e 100644 --- a/src/opt/core_maxsat.cpp +++ b/src/opt/core_maxsat.cpp @@ -65,6 +65,7 @@ namespace opt { for (unsigned i = 0; i < ans.size(); ++i) { tout << mk_pp(ans[i].get(), m) << "\n"; }); + IF_VERBOSE(1, verbose_stream() << "(maxsat.core sat: " << ans.size() << "\n";); if (ans.size() > m_answer.size()) { m_answer.reset(); m_answer.append(ans); @@ -91,6 +92,7 @@ namespace opt { core_vars.insert(get_not(core[i])); block_vars.remove(core[i]); } + IF_VERBOSE(1, verbose_stream() << "(maxsat.core unsat (core size = " << core.size() << ")\n";); if (core.empty()) { m_upper = m_answer.size(); return l_true; diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index 5c5bace02..6ba3bba39 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -73,7 +73,7 @@ namespace opt { */ lbool step() { - IF_VERBOSE(1, verbose_stream() << "(opt.max_sat step)\n";); + IF_VERBOSE(1, verbose_stream() << "(opt.max_sat step)\n";); // add some count, add some information of # of soft constraints still possibly sat. expr_ref_vector assumptions(m), block_vars(m); for (unsigned i = 0; i < m_soft.size(); ++i) { assumptions.push_back(m.mk_not(m_aux[i].get())); From 2d3f6ca71d79cfcb760825050b76b89ec8e1e5d5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Nov 2013 17:15:41 -0800 Subject: [PATCH 124/925] add pb constraints to API Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Context.cs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index ae8b233d1..8ac0c8f98 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -2249,6 +2249,36 @@ namespace Microsoft.Z3 } #endregion + #region Pseudo-Boolean constraints + + /// + /// Create an at-most-k constraint. + /// + public BoolExpr MkAtMost(BoolExpr[] args, uint k) + { + Contract.Requires(args != null); + Contract.Requires(Contract.Result() != null); + CheckContextMatch(args); + return new BoolExpr(this, Native.Z3_mk_atmost(nCtx, (uint) args.Length, + AST.ArrayToNative(args), k)); + } + + /// + /// Create a pseudo-Boolean <= constraint. + /// + public BoolExpr MkPBLe(int[] coeffs, BoolExpr[] args, int k) + { + Contract.Requires(args != null); + Contract.Requires(coeffs != null); + Contract.Requires(args.Length == coeffs.Length); + Contract.Requires(Contract.Result() != null); + CheckContextMatch(args); + return new BoolExpr(this, Native.Z3_mk_pble(nCtx, (uint) args.Length, + AST.ArrayToNative(args), + coeffs, k)); + } + #endregion + #region Numerals #region General Numerals From 5921628f53edda255dc4ae77171cc2f23f83b741 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Wed, 13 Nov 2013 18:46:18 -0800 Subject: [PATCH 125/925] Dump opt_solver checksat calls for profiling --- .gitignore | 1 + src/opt/opt_params.pyg | 3 ++- src/opt/opt_solver.cpp | 32 +++++++++++++++++++++++++++++--- src/opt/opt_solver.h | 6 +++++- 4 files changed, 37 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 77f4d1896..2b3149d04 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ ocamlz3 # Emacs temp files \#*\# # Directories with generated code and documentation +release/* build/* build-dist/* dist/* diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index 983c3ed73..63c4d534a 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -3,8 +3,9 @@ def_module_params('opt', export=True, params=(('timeout', UINT, UINT_MAX, 'set timeout'), ('engine', SYMBOL, 'basic', "select optimization engine: 'basic', 'farkas', 'symba'"), - ('maxsat_engine', SYMBOL, 'fu_malik', "select engine for non-weighted maxsat: 'fu_malik', 'core_maxsat'"), + ('maxsat_engine', SYMBOL, 'fu_malik', "select engine for non-weighted maxsat: 'fu_malik', 'core_maxsat'"), ('pareto', BOOL, False, 'return a Pareto front (as opposed to a bounding box)'), + ('dump_benchmarks', BOOL, False, 'dump benchmarks for profiling'), )) diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 750b8d700..02b01912e 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -24,6 +24,8 @@ Notes: #include"theory_arith.h" #include"theory_diff_logic.h" #include "ast_pp.h" +#include "ast_smt_pp.h" +#include "pp_params.hpp" namespace opt { @@ -32,7 +34,8 @@ namespace opt { m_params(p), m_context(mgr, m_params), m(mgr), - m_objective_enabled(false) { + m_objective_enabled(false), + m_is_dump(false) { m_logic = l; if (m_logic != symbol::null) m_context.set_logic(m_logic); @@ -42,6 +45,7 @@ namespace opt { } void opt_solver::updt_params(params_ref const & p) { + m_is_dump = p.get_bool("dump_benchmarks", false); m_params.updt_params(p); m_context.updt_params(p); } @@ -93,7 +97,8 @@ namespace opt { } } - + static unsigned g_checksat_count = 0; + lbool opt_solver::check_sat_core(unsigned num_assumptions, expr * const * assumptions) { TRACE("opt_solver_na2as", { tout << "opt_opt_solver::check_sat_core: " << m_context.size() << "\n"; @@ -103,6 +108,11 @@ namespace opt { }); lbool r = m_context.check(num_assumptions, assumptions); + if (m_is_dump) { + std::stringstream buffer; + buffer << "opt_solver" << ++g_checksat_count << ".smt2"; + to_smt2_benchmark(buffer.str().c_str(), "benchmark", "QF_BV"); + } if (r == l_true && m_objective_enabled) { m_objective_values.reset(); smt::theory_opt& opt = get_optimizer(); @@ -201,6 +211,23 @@ namespace opt { } return dynamic_cast(s); } + + void opt_solver::to_smt2_benchmark(char const * file_name, char const * name, char const * logic, + char const * status, char const * attributes) { + std::ofstream buffer(file_name); + ast_smt_pp pp(m); + pp.set_benchmark_name(name); + pp.set_logic(logic); + pp.set_status(status); + pp.add_attributes(attributes); + pp_params params; + pp.set_simplify_implies(params.simplify_implies()); + for (unsigned i = 0; i < get_num_assertions(); ++i) { + pp.add_assumption(to_expr(get_assertion(i))); + } + pp.display_smt2(buffer, to_expr(m.mk_true())); + buffer.close(); + } opt_solver::toggle_objective::toggle_objective(opt_solver& s, bool new_value): s(s), m_old_value(s.m_objective_enabled) { s.m_objective_enabled = new_value; @@ -210,5 +237,4 @@ namespace opt { s.m_objective_enabled = m_old_value; } - } diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 1fffa1b5b..90ebe3251 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -45,7 +45,8 @@ namespace opt { symbol m_logic; bool m_objective_enabled; svector m_objective_vars; - vector m_objective_values; + vector m_objective_values; + bool m_is_dump; public: opt_solver(ast_manager & m, params_ref const & p, symbol const & l); virtual ~opt_solver(); @@ -88,6 +89,9 @@ namespace opt { smt::context& get_context() { return m_context.get_context(); } // used by weighted maxsat. smt::theory_opt& get_optimizer(); + + void to_smt2_benchmark(char const * file_name, char const * name = "benchmarks", + char const * logic = "", char const * status = "unknown", char const * attributes = ""); }; } From 34af1988166d012ad9a03c7274489d9bbec9886c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 14 Nov 2013 08:51:01 -0800 Subject: [PATCH 126/925] missing file Signed-off-by: Nikolaj Bjorner --- src/api/api_pb.cpp | 57 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 src/api/api_pb.cpp diff --git a/src/api/api_pb.cpp b/src/api/api_pb.cpp new file mode 100644 index 000000000..52290d28a --- /dev/null +++ b/src/api/api_pb.cpp @@ -0,0 +1,57 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + api_pb.cpp + +Abstract: + API for pb theory + +Author: + + Nikolaj Bjorner (nbjorner) 2013-11-13. + +Revision History: + +--*/ +#include +#include"z3.h" +#include"api_log_macros.h" +#include"api_context.h" +#include"api_util.h" +#include"card_decl_plugin.h" + +extern "C" { + + Z3_ast Z3_API Z3_mk_atmost(Z3_context c, unsigned num_args, + Z3_ast const args[], unsigned k) { + Z3_TRY; + LOG_Z3_mk_atmost(c, num_args, args, k); + RESET_ERROR_CODE(); + parameter param(k); + card_util util(mk_c(c)->m()); + ast* a = util.mk_at_most_k(num_args, to_exprs(args), k); + mk_c(c)->save_ast_trail(a); + check_sorts(c, a); + RETURN_Z3(of_ast(a)); + Z3_CATCH_RETURN(0); + } + + + Z3_ast Z3_API Z3_mk_pble(Z3_context c, unsigned num_args, + Z3_ast const args[], int coeffs[], + int k) { + Z3_TRY; + LOG_Z3_mk_pble(c, num_args, args, coeffs, k); + RESET_ERROR_CODE(); + card_util util(mk_c(c)->m()); + ast* a = util.mk_le(num_args, coeffs, to_exprs(args), k); + mk_c(c)->save_ast_trail(a); + check_sorts(c, a); + RETURN_Z3(of_ast(a)); + Z3_CATCH_RETURN(0); + } + + +}; From d729e89a7b3d05359ba391f978cb3861c9d382a4 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Thu, 14 Nov 2013 12:36:39 -0800 Subject: [PATCH 127/925] Fix a minor bug on cardinality solver --- src/opt/opt_solver.cpp | 16 ++++++++-------- src/opt/opt_solver.h | 4 ++-- src/smt/theory_card.cpp | 5 +++-- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 02b01912e..fee4a8663 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -109,9 +109,11 @@ namespace opt { lbool r = m_context.check(num_assumptions, assumptions); if (m_is_dump) { - std::stringstream buffer; - buffer << "opt_solver" << ++g_checksat_count << ".smt2"; - to_smt2_benchmark(buffer.str().c_str(), "benchmark", "QF_BV"); + std::stringstream file_name; + file_name << "opt_solver" << ++g_checksat_count << ".smt2"; + std::ofstream buffer(file_name.str().c_str()); + to_smt2_benchmark(buffer, "opt_solver", "QF_BV"); + buffer.close(); } if (r == l_true && m_objective_enabled) { m_objective_values.reset(); @@ -212,9 +214,8 @@ namespace opt { return dynamic_cast(s); } - void opt_solver::to_smt2_benchmark(char const * file_name, char const * name, char const * logic, - char const * status, char const * attributes) { - std::ofstream buffer(file_name); + void opt_solver::to_smt2_benchmark(std::ofstream & buffer, char const * name, char const * logic, + char const * status, char const * attributes) { ast_smt_pp pp(m); pp.set_benchmark_name(name); pp.set_logic(logic); @@ -225,8 +226,7 @@ namespace opt { for (unsigned i = 0; i < get_num_assertions(); ++i) { pp.add_assumption(to_expr(get_assertion(i))); } - pp.display_smt2(buffer, to_expr(m.mk_true())); - buffer.close(); + pp.display_smt2(buffer, to_expr(m.mk_true())); } opt_solver::toggle_objective::toggle_objective(opt_solver& s, bool new_value): s(s), m_old_value(s.m_objective_enabled) { diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 90ebe3251..de7ef0b1d 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -90,8 +90,8 @@ namespace opt { smt::theory_opt& get_optimizer(); - void to_smt2_benchmark(char const * file_name, char const * name = "benchmarks", - char const * logic = "", char const * status = "unknown", char const * attributes = ""); + void to_smt2_benchmark(std::ofstream & buffer, char const * name = "benchmarks", + char const * logic = "", char const * status = "unknown", char const * attributes = ""); }; } diff --git a/src/smt/theory_card.cpp b/src/smt/theory_card.cpp index c32b600c1..3aa72baef 100644 --- a/src/smt/theory_card.cpp +++ b/src/smt/theory_card.cpp @@ -133,9 +133,10 @@ namespace smt { } static unsigned gcd(unsigned a, unsigned b) { - if (a == 0) return b; - if (b == 0) return a; while (a != b) { + if (a == 0) return b; + if (b == 0) return a; + SASSERT(a != 0 && b != 0); if (a < b) { b %= a; } From 06ae0db116034afbd00bf206acdf97b703d2c8ef Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 14 Nov 2013 18:04:05 -0800 Subject: [PATCH 128/925] working on pb solver Signed-off-by: Nikolaj Bjorner --- src/ast/ast_smt_pp.cpp | 41 ++++++++------- src/opt/fu_malik.cpp | 38 ++++++++++---- src/smt/theory_card.cpp | 109 +++++++++++++++++++++++++++++++++------- src/smt/theory_card.h | 3 ++ src/util/region.h | 1 + 5 files changed, 144 insertions(+), 48 deletions(-) diff --git a/src/ast/ast_smt_pp.cpp b/src/ast/ast_smt_pp.cpp index f684879ae..66b56d8d4 100644 --- a/src/ast/ast_smt_pp.cpp +++ b/src/ast/ast_smt_pp.cpp @@ -1054,7 +1054,8 @@ void ast_smt_pp::display_ast_smt2(std::ostream& strm, ast* a, unsigned indent, u void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) { ptr_vector ql; - decl_collector decls(m_manager); + ast_manager& m = m_manager; + decl_collector decls(m); smt_renaming rn; for (unsigned i = 0; i < m_assumptions.size(); ++i) { @@ -1065,7 +1066,7 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) { } decls.visit(n); - if (m_manager.is_proof(n)) { + if (m.is_proof(n)) { strm << "("; } if (m_benchmark_name != symbol::null) { @@ -1074,7 +1075,7 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) { if (m_source_info != symbol::null && m_source_info != symbol("")) { strm << "; :source { " << m_source_info << " }\n"; } - if (m_manager.is_bool(n)) { + if (m.is_bool(n)) { strm << "(set-info :status " << m_status << ")\n"; } if (m_category != symbol::null && m_category != symbol("")) { @@ -1091,7 +1092,7 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) { for (unsigned i = 0; i < decls.get_num_sorts(); ++i) { sort* s = decls.get_sorts()[i]; if (!(*m_is_declared)(s)) { - smt_printer p(strm, m_manager, ql, rn, m_logic, true, true, m_simplify_implies, 0); + smt_printer p(strm, m, ql, rn, m_logic, true, true, m_simplify_implies, 0); p.pp_sort_decl(sort_mark, s); } } @@ -1099,7 +1100,7 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) { for (unsigned i = 0; i < decls.get_num_decls(); ++i) { func_decl* d = decls.get_func_decls()[i]; if (!(*m_is_declared)(d)) { - smt_printer p(strm, m_manager, ql, rn, m_logic, true, true, m_simplify_implies, 0); + smt_printer p(strm, m, ql, rn, m_logic, true, true, m_simplify_implies, 0); p(d); strm << "\n"; } @@ -1108,34 +1109,36 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) { for (unsigned i = 0; i < decls.get_num_preds(); ++i) { func_decl* d = decls.get_pred_decls()[i]; if (!(*m_is_declared)(d)) { - smt_printer p(strm, m_manager, ql, rn, m_logic, true, true, m_simplify_implies, 0); + smt_printer p(strm, m, ql, rn, m_logic, true, true, m_simplify_implies, 0); p(d); strm << "\n"; } } for (unsigned i = 0; i < m_assumptions.size(); ++i) { - strm << "(assert\n"; - smt_printer p(strm, m_manager, ql, rn, m_logic, false, true, m_simplify_implies, 0); - p(m_assumptions[i].get()); - strm << ")\n"; + smt_printer p(strm, m, ql, rn, m_logic, false, true, m_simplify_implies, 1); + strm << "(assert\n "; + p(m_assumptions[i].get()); + strm << ")\n"; } for (unsigned i = 0; i < m_assumptions_star.size(); ++i) { - strm << "(assert\n"; - smt_printer p(strm, m_manager, ql, rn, m_logic, false, true, m_simplify_implies, 0); - p(m_assumptions_star[i].get()); + smt_printer p(strm, m, ql, rn, m_logic, false, true, m_simplify_implies, 1); + strm << "(assert\n "; + p(m_assumptions_star[i].get()); strm << ")\n"; } - smt_printer p(strm, m_manager, ql, rn, m_logic, false, true, m_simplify_implies, 0); - if (m_manager.is_bool(n)) { - strm << "(assert\n"; - p(n); - strm << ")\n"; + smt_printer p(strm, m, ql, rn, m_logic, false, true, m_simplify_implies, 0); + if (m.is_bool(n)) { + if (!m.is_true(n)) { + strm << "(assert\n "; + p(n); + strm << ")\n"; + } strm << "(check-sat)\n"; } - else if (m_manager.is_proof(n)) { + else if (m.is_proof(n)) { strm << "(proof\n"; p(n); strm << "))\n"; diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index 6ba3bba39..2d9c25be1 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -18,6 +18,8 @@ Notes: --*/ #include "fu_malik.h" +#include "smtlogics/qfbv_tactic.h" +#include "tactic2solver.h" /** \brief Fu & Malik procedure for MaxSAT. This procedure is based on @@ -37,17 +39,18 @@ namespace opt { struct fu_malik::imp { ast_manager& m; - solver& s; + ref m_s; expr_ref_vector m_soft; expr_ref_vector m_orig_soft; expr_ref_vector m_aux; expr_ref_vector m_assignment; unsigned m_upper_size; + solver& s() { return *m_s; } imp(ast_manager& m, solver& s, expr_ref_vector const& soft): m(m), - s(s), + m_s(&s), m_soft(soft), m_orig_soft(soft), m_aux(m), @@ -78,13 +81,13 @@ namespace opt { for (unsigned i = 0; i < m_soft.size(); ++i) { assumptions.push_back(m.mk_not(m_aux[i].get())); } - lbool is_sat = s.check_sat(assumptions.size(), assumptions.c_ptr()); + lbool is_sat = s().check_sat(assumptions.size(), assumptions.c_ptr()); if (is_sat != l_false) { return is_sat; } ptr_vector core; - s.get_unsat_core(core); + s().get_unsat_core(core); // Update soft-constraints and aux_vars for (unsigned i = 0; i < m_soft.size(); ++i) { @@ -101,7 +104,7 @@ namespace opt { m_aux[i] = m.mk_fresh_const("aux", m.mk_bool_sort()); m_soft[i] = m.mk_or(m_soft[i].get(), block_var); block_vars.push_back(block_var); - s.assert_expr(m.mk_or(m_soft[i].get(), m_aux[i].get())); + s().assert_expr(m.mk_or(m_soft[i].get(), m_aux[i].get())); } assert_at_most_one(block_vars); return l_false; @@ -111,7 +114,7 @@ namespace opt { expr_ref has_one(m), has_zero(m), at_most_one(m); mk_at_most_one(block_vars.size(), block_vars.c_ptr(), has_one, has_zero); at_most_one = m.mk_or(has_one, has_zero); - s.assert_expr(at_most_one); + s().assert_expr(at_most_one); } void mk_at_most_one(unsigned n, expr* const * vars, expr_ref& has_one, expr_ref& has_zero) { @@ -129,15 +132,30 @@ namespace opt { has_zero = m.mk_and(has_zero1, has_zero2); } } + + void set_solver() { + solver& original_solver = s(); + bool all_bv = false; + // retrieve goal from s() + // extract mk_qfbv_probe + // run probe on goals + // if result is "yes", then create teh qfbv_tactic. + + if (all_bv) { + tactic* t = mk_qfbv_tactic(m); + m_s = mk_tactic2solver(m, t); + } + } // TBD: bug when cancel flag is set, fu_malik returns is_sat == l_true instead of l_undef lbool operator()() { - lbool is_sat = s.check_sat(0,0); + set_solver(); + lbool is_sat = s().check_sat(0,0); if (!m_soft.empty() && is_sat == l_true) { - solver::scoped_push _sp(s); + solver::scoped_push _sp(s()); for (unsigned i = 0; i < m_soft.size(); ++i) { m_aux.push_back(m.mk_fresh_const("p", m.mk_bool_sort())); - s.assert_expr(m.mk_or(m_soft[i].get(), m_aux[i].get())); + s().assert_expr(m.mk_or(m_soft[i].get(), m_aux[i].get())); } lbool is_sat = l_true; @@ -150,7 +168,7 @@ namespace opt { if (is_sat == l_true) { // Get a list of satisfying m_soft model_ref model; - s.get_model(model); + s().get_model(model); m_assignment.reset(); for (unsigned i = 0; i < m_orig_soft.size(); ++i) { diff --git a/src/smt/theory_card.cpp b/src/smt/theory_card.cpp index c32b600c1..d593e3742 100644 --- a/src/smt/theory_card.cpp +++ b/src/smt/theory_card.cpp @@ -136,6 +136,12 @@ namespace smt { if (a == 0) return b; if (b == 0) return a; while (a != b) { + if (a == 0) { + return b; + } + if (b == 0) { + return a; + } if (a < b) { b %= a; } @@ -171,7 +177,7 @@ namespace smt { if (!args.empty()) { unsigned g = abs(args[0].second); for (unsigned i = 1; g > 1 && i < args.size(); ++i) { - g = gcd(g, args[i].second); + g = gcd(g, abs(args[i].second)); } if (g > 1) { int k = c->m_k; @@ -183,7 +189,7 @@ namespace smt { k = abs(k); k += (k % g); k /= g; - k = -k; + c->m_k = -k; } for (unsigned i = 0; i < args.size(); ++i) { args[i].second /= g; @@ -213,6 +219,7 @@ namespace smt { void theory_card::collect_statistics(::statistics& st) const { st.update("pb axioms", m_stats.m_num_axioms); + st.update("pb propagations", m_stats.m_num_propagations); st.update("pb predicates", m_stats.m_num_predicates); st.update("pb compilations", m_stats.m_num_compiles); } @@ -316,6 +323,21 @@ namespace smt { return curr_min; } + int theory_card::get_max_delta(card& c) { + if (m_util.is_at_most_k(c.m_app)) { + return 1; + } + int max = 0; + context& ctx = get_context(); + for (unsigned i = 0; i < c.m_args.size(); ++i) { + if (c.m_args[i].second > max && ctx.get_assignment(c.m_args[i].first) == l_undef) { + max = c.m_args[i].second; + } + } + return max; + } + + int theory_card::accumulate_max(literal_vector& lits, card& c) { context& ctx = get_context(); arg_t const& args = c.m_args; @@ -364,19 +386,17 @@ namespace smt { lbool aval = ctx.get_assignment(abv); if (min > k && aval != l_false) { literal_vector& lits = get_lits(); - lits.push_back(~literal(abv)); int curr_min = accumulate_min(lits, c); SASSERT(curr_min > k); - add_clause(c, lits); + add_assign(c, lits, ~literal(abv)); } else if (max <= k && aval != l_true) { literal_vector& lits = get_lits(); - lits.push_back(literal(abv)); int curr_max = accumulate_max(lits, c); SASSERT(curr_max <= k); - add_clause(c, lits); + add_assign(c, lits, literal(abv)); } - else if (min == k && aval == l_true) { + else if (min <= k && k < min + get_max_delta(c) && aval == l_true) { literal_vector& lits = get_lits(); lits.push_back(~literal(abv)); int curr_min = accumulate_min(lits, c); @@ -384,37 +404,70 @@ namespace smt { add_clause(c, lits); } else { - SASSERT(curr_min == k); for (unsigned i = 0; i < args.size(); ++i) { bool_var bv = args[i].first; int inc = args[i].second; - if (inc_min(inc, ctx.get_assignment(bv)) == l_undef) { - literal_vector lits_save(lits); // add_clause has a side-effect on literals. - lits_save.push_back(literal(bv, inc > 0)); // avoid incrementing min. - add_clause(c, lits_save); + if (curr_min + inc > k && inc_min(inc, ctx.get_assignment(bv)) == l_undef) { + add_assign(c, lits, literal(bv, inc > 0)); } } } } - else if (max == k + 1 && aval == l_false) { + else if (max - get_max_delta(c) <= k && k < max && aval == l_false) { literal_vector& lits = get_lits(); lits.push_back(literal(abv)); int curr_max = accumulate_max(lits, c); if (curr_max <= k) { add_clause(c, lits); } - else if (curr_max == k + 1) { + else { for (unsigned i = 0; i < args.size(); ++i) { bool_var bv = args[i].first; int inc = args[i].second; - if (dec_max(inc, ctx.get_assignment(bv)) == l_undef) { - literal_vector lits_save(lits); // add_clause has a side-effect on literals. - lits_save.push_back(literal(bv, inc < 0)); // avoid decrementing max. - add_clause(c, lits_save); + if (curr_max - abs(inc) <= k && dec_max(inc, ctx.get_assignment(bv)) == l_undef) { + add_assign(c, lits, literal(bv, inc < 0)); } } } } +#if 0 + else if (aval == l_true) { + SASSERT(min < k); + literal_vector& lits = get_lits(); + int curr_min = accumulate_min(lits, c); + bool all_inc = curr_min == k; + unsigned num_incs = 0; + for (unsigned i = 0; all_inc && i < args.size(); ++i) { + bool_var bv = args[i].first; + int inc = args[i].second; + if (inc_min(inc, ctx.get_assignment(bv)) == l_undef) { + all_inc = inc + min > k; + num_incs++; + } + } + if (num_incs > 0) { + std::cout << "missed T propgations " << num_incs << "\n"; + } + } + else if (aval == l_false) { + literal_vector& lits = get_lits(); + lits.push_back(literal(abv)); + int curr_max = accumulate_max(lits, c); + bool all_dec = curr_max > k; + unsigned num_decs = 0; + for (unsigned i = 0; all_dec && i < args.size(); ++i) { + bool_var bv = args[i].first; + int inc = args[i].second; + if (dec_max(inc, ctx.get_assignment(bv)) == l_undef) { + all_dec = inc + max <= k; + num_decs++; + } + } + if (num_decs > 0) { + std::cout << "missed F propgations " << num_decs << "\n"; + } + } +#endif } void theory_card::assign_eh(bool_var v, bool is_true) { @@ -608,10 +661,14 @@ namespace smt { } bool theory_card::should_compile(card& c) { +#if 1 + return false; +#else if (!m_util.is_at_most_k(c.m_app)) { return false; } return c.m_num_propagations >= c.m_compilation_threshold; +#endif } void theory_card::compile_at_most(card& c) { @@ -686,6 +743,19 @@ namespace smt { return m_literals; } + void theory_card::add_assign(card& c, literal_vector const& lits, literal l) { + literal_vector ls; + ++c.m_num_propagations; + m_stats.m_num_propagations++; + context& ctx = get_context(); + for (unsigned i = 0; i < lits.size(); ++i) { + ls.push_back(~lits[i]); + } + ctx.assign(l, ctx.mk_justification(theory_propagation_justification(get_id(), ctx.get_region(), ls.size(), ls.c_ptr(), l))); + } + + + void theory_card::add_clause(card& c, literal_vector const& lits) { ++c.m_num_propagations; m_stats.m_num_axioms++; @@ -693,7 +763,8 @@ namespace smt { TRACE("card", tout << "#prop:" << c.m_num_propagations << " - "; ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";); justification* js = 0; ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); - IF_VERBOSE(1, ctx.display_literals_verbose(verbose_stream(), lits.size(), lits.c_ptr()); + IF_VERBOSE(2, ctx.display_literals_verbose(verbose_stream(), + lits.size(), lits.c_ptr()); verbose_stream() << "\n";); // ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); } diff --git a/src/smt/theory_card.h b/src/smt/theory_card.h index e8eae9232..a432ea5a3 100644 --- a/src/smt/theory_card.h +++ b/src/smt/theory_card.h @@ -32,6 +32,7 @@ namespace smt { struct stats { unsigned m_num_axioms; + unsigned m_num_propagations; unsigned m_num_predicates; unsigned m_num_compiles; void reset() { memset(this, 0, sizeof(*this)); } @@ -75,10 +76,12 @@ namespace smt { void add_card(card* c); void add_clause(card& c, literal_vector const& lits); + void add_assign(card& c, literal_vector const& lits, literal l); literal_vector& get_lits(); int find_inc(bool_var bv, svector >const& vars); void propagate_assignment(card& c); + int get_max_delta(card& c); int accumulate_max(literal_vector& lits, card& c); int accumulate_min(literal_vector& lits, card& c); lbool dec_max(int inc, lbool val); diff --git a/src/util/region.h b/src/util/region.h index 7f6bc787e..5be2ae4d3 100644 --- a/src/util/region.h +++ b/src/util/region.h @@ -53,6 +53,7 @@ public: m_scopes.push_back(m_chuncks.size()); } + void pop_scope() { unsigned old_size = m_scopes.back(); m_scopes.pop_back(); From 4be11f24e1a68e9f114c949405678712dc9e4f29 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Thu, 14 Nov 2013 19:02:15 -0800 Subject: [PATCH 129/925] Instrument fu_malik to use the new SAT solver (WIP) --- src/opt/core_maxsat.cpp | 4 +- src/opt/fu_malik.cpp | 74 +++++++++++++++++++++++----- src/tactic/smtlogics/qfbv_tactic.cpp | 14 ++++-- 3 files changed, 73 insertions(+), 19 deletions(-) diff --git a/src/opt/core_maxsat.cpp b/src/opt/core_maxsat.cpp index b4472971e..b386595d3 100644 --- a/src/opt/core_maxsat.cpp +++ b/src/opt/core_maxsat.cpp @@ -65,7 +65,7 @@ namespace opt { for (unsigned i = 0; i < ans.size(); ++i) { tout << mk_pp(ans[i].get(), m) << "\n"; }); - IF_VERBOSE(1, verbose_stream() << "(maxsat.core sat: " << ans.size() << "\n";); + IF_VERBOSE(0, verbose_stream() << "(maxsat.core sat with lower bound: " << ans.size() << "\n";); if (ans.size() > m_answer.size()) { m_answer.reset(); m_answer.append(ans); @@ -92,7 +92,7 @@ namespace opt { core_vars.insert(get_not(core[i])); block_vars.remove(core[i]); } - IF_VERBOSE(1, verbose_stream() << "(maxsat.core unsat (core size = " << core.size() << ")\n";); + IF_VERBOSE(0, verbose_stream() << "(maxsat.core unsat (core size = " << core.size() << ")\n";); if (core.empty()) { m_upper = m_answer.size(); return l_true; diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index 6ba3bba39..42f410761 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -18,6 +18,11 @@ Notes: --*/ #include "fu_malik.h" +#include "smtlogics/qfbv_tactic.h" +#include "tactic2solver.h" +#include "goal.h" +#include "probe.h" +#include "smt_context.h" /** \brief Fu & Malik procedure for MaxSAT. This procedure is based on @@ -37,25 +42,29 @@ namespace opt { struct fu_malik::imp { ast_manager& m; - solver& s; + ref m_s; expr_ref_vector m_soft; expr_ref_vector m_orig_soft; expr_ref_vector m_aux; expr_ref_vector m_assignment; unsigned m_upper_size; - + solver & m_original_solver; + bool m_use_new_bv_solver; imp(ast_manager& m, solver& s, expr_ref_vector const& soft): m(m), - s(s), + m_s(&s), m_soft(soft), m_orig_soft(soft), m_aux(m), - m_assignment(m) + m_assignment(m), + m_original_solver(s), + m_use_new_bv_solver(false) { m_upper_size = m_soft.size() + 1; } + solver& s() { return *m_s; } /** \brief One step of the Fu&Malik algorithm. @@ -73,18 +82,30 @@ namespace opt { */ lbool step() { - IF_VERBOSE(1, verbose_stream() << "(opt.max_sat step)\n";); // add some count, add some information of # of soft constraints still possibly sat. + IF_VERBOSE(0, verbose_stream() << "(opt.max_sat step " << m_soft.size() + 2 - m_upper_size << ")\n";); expr_ref_vector assumptions(m), block_vars(m); for (unsigned i = 0; i < m_soft.size(); ++i) { assumptions.push_back(m.mk_not(m_aux[i].get())); } - lbool is_sat = s.check_sat(assumptions.size(), assumptions.c_ptr()); + lbool is_sat = s().check_sat(assumptions.size(), assumptions.c_ptr()); if (is_sat != l_false) { return is_sat; } ptr_vector core; - s.get_unsat_core(core); + if (m_use_new_bv_solver) { + unsigned i = 0; + while (s().check_sat(core.size(), core.c_ptr()) != l_false) { + IF_VERBOSE(0, verbose_stream() << "(opt.max_sat get-unsat-core round " << i << ")\n";); + core.push_back(assumptions[i].get()); + ++i; + } + } + else { + s().get_unsat_core(core); + } + + SASSERT(!core.empty()); // Update soft-constraints and aux_vars for (unsigned i = 0; i < m_soft.size(); ++i) { @@ -101,9 +122,11 @@ namespace opt { m_aux[i] = m.mk_fresh_const("aux", m.mk_bool_sort()); m_soft[i] = m.mk_or(m_soft[i].get(), block_var); block_vars.push_back(block_var); - s.assert_expr(m.mk_or(m_soft[i].get(), m_aux[i].get())); + s().assert_expr(m.mk_or(m_soft[i].get(), m_aux[i].get())); } + SASSERT (!block_vars.empty()); assert_at_most_one(block_vars); + IF_VERBOSE(0, verbose_stream() << "(opt.max_sat # of non-blocked soft constraints: " << m_soft.size() - block_vars.size() << ")\n";); return l_false; } @@ -111,7 +134,7 @@ namespace opt { expr_ref has_one(m), has_zero(m), at_most_one(m); mk_at_most_one(block_vars.size(), block_vars.c_ptr(), has_one, has_zero); at_most_one = m.mk_or(has_one, has_zero); - s.assert_expr(at_most_one); + s().assert_expr(at_most_one); } void mk_at_most_one(unsigned n, expr* const * vars, expr_ref& has_one, expr_ref& has_zero) { @@ -129,15 +152,40 @@ namespace opt { has_zero = m.mk_and(has_zero1, has_zero2); } } + + void set_solver() { + solver& current_solver = s(); + goal g(m, true, false); + unsigned num_assertions = current_solver.get_num_assertions(); + for (unsigned i = 0; i < num_assertions; ++i) { + g.assert_expr(current_solver.get_assertion(i)); + } + probe *p = mk_is_qfbv_probe(); + bool all_bv = (*p)(g).is_true(); + if (all_bv) { + opt_solver & os = opt_solver::to_opt(m_original_solver); + smt::context & ctx = os.get_context(); + tactic* t = mk_qfbv_tactic(m, ctx.get_params()); + // The new SAT solver hasn't supported unsat core yet + m_s = mk_tactic2solver(m, t); + SASSERT(m_s != &m_original_solver); + for (unsigned i = 0; i < num_assertions; ++i) { + m_s->assert_expr(current_solver.get_assertion(i)); + } + m_use_new_bv_solver = true; + IF_VERBOSE(0, verbose_stream() << "Force to use the new BV solver." << std::endl;); + } + } // TBD: bug when cancel flag is set, fu_malik returns is_sat == l_true instead of l_undef lbool operator()() { - lbool is_sat = s.check_sat(0,0); + set_solver(); + lbool is_sat = s().check_sat(0,0); if (!m_soft.empty() && is_sat == l_true) { - solver::scoped_push _sp(s); + solver::scoped_push _sp(s()); for (unsigned i = 0; i < m_soft.size(); ++i) { m_aux.push_back(m.mk_fresh_const("p", m.mk_bool_sort())); - s.assert_expr(m.mk_or(m_soft[i].get(), m_aux[i].get())); + s().assert_expr(m.mk_or(m_soft[i].get(), m_aux[i].get())); } lbool is_sat = l_true; @@ -150,7 +198,7 @@ namespace opt { if (is_sat == l_true) { // Get a list of satisfying m_soft model_ref model; - s.get_model(model); + s().get_model(model); m_assignment.reset(); for (unsigned i = 0; i < m_orig_soft.size(); ++i) { diff --git a/src/tactic/smtlogics/qfbv_tactic.cpp b/src/tactic/smtlogics/qfbv_tactic.cpp index 51b040332..cdbc6927e 100644 --- a/src/tactic/smtlogics/qfbv_tactic.cpp +++ b/src/tactic/smtlogics/qfbv_tactic.cpp @@ -31,6 +31,15 @@ Notes: #define MEMLIMIT 300 +tactic * mk_new_sat_tactic(ast_manager & m) { + IF_VERBOSE(0, verbose_stream() << "Try to use the new SAT solver." << std::endl;); + tactic * new_sat = cond(mk_or(mk_produce_proofs_probe(), mk_produce_unsat_cores_probe()), + and_then(mk_simplify_tactic(m), + mk_smt_tactic()), + mk_sat_tactic(m)); + return new_sat; +} + tactic * mk_qfbv_tactic(ast_manager & m, params_ref const & p) { params_ref main_p; main_p.set_bool("elim_and", true); @@ -85,10 +94,7 @@ tactic * mk_qfbv_tactic(ast_manager & m, params_ref const & p) { tactic * new_sat = and_then(mk_simplify_tactic(m), mk_smt_tactic()); #else - tactic * new_sat = cond(mk_or(mk_produce_proofs_probe(), mk_produce_unsat_cores_probe()), - and_then(mk_simplify_tactic(m), - mk_smt_tactic()), - mk_sat_tactic(m)); + tactic * new_sat = mk_new_sat_tactic(m); #endif tactic * st = using_params(and_then(preamble_st, From f9164f4cb1d13f1544a36e8fb11fb21280d71e6d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 14 Nov 2013 20:21:33 -0800 Subject: [PATCH 130/925] local updates Signed-off-by: Nikolaj Bjorner --- src/smt/theory_card.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/smt/theory_card.cpp b/src/smt/theory_card.cpp index c32b600c1..4d6df0021 100644 --- a/src/smt/theory_card.cpp +++ b/src/smt/theory_card.cpp @@ -36,8 +36,12 @@ Notes: That is, during a propagation, assignment or conflict resolution step track cutting-planes. - - TBD: profile overhead of (re)creating sorting circuits. - Possibly delay creating them until restart. + - TBD: profile overhead of (re)creating sorting circuits. + Possibly delay creating them until restart. + + - TBD: deal with integer overflows. + + - --*/ @@ -376,6 +380,7 @@ namespace smt { SASSERT(curr_max <= k); add_clause(c, lits); } + // min + min_increment > k else if (min == k && aval == l_true) { literal_vector& lits = get_lits(); lits.push_back(~literal(abv)); @@ -384,6 +389,7 @@ namespace smt { add_clause(c, lits); } else { + // curr_min + min_increment > k SASSERT(curr_min == k); for (unsigned i = 0; i < args.size(); ++i) { bool_var bv = args[i].first; @@ -396,6 +402,7 @@ namespace smt { } } } + // k < max && ... ? else if (max == k + 1 && aval == l_false) { literal_vector& lits = get_lits(); lits.push_back(literal(abv)); @@ -493,7 +500,8 @@ namespace smt { literal internalize(card& ca, expr* e) { obj_map cache; for (unsigned i = 0; i < ca.m_args.size(); ++i) { - cache.insert(ca.m_app->get_arg(i), literal(ca.m_args[i].first)); + bool_var bv = ca.m_args[i].first; + cache.insert(ctx.bool_var2expr(bv), literal(bv)); } cache.insert(m.mk_false(), false_literal); cache.insert(m.mk_true(), true_literal); @@ -622,7 +630,7 @@ namespace smt { SASSERT(m_util.is_at_most_k(a)); literal atmostk; int k = m_util.get_k(a); - unsigned num_args = a->get_num_args(); + unsigned num_args = ca.m_args.size(); sort_expr se(*this); if (k >= static_cast(num_args)) { @@ -635,7 +643,7 @@ namespace smt { sorting_network sn(se); expr_ref_vector in(m), out(m); for (unsigned i = 0; i < num_args; ++i) { - in.push_back(c.m_app->get_arg(i)); + in.push_back(ctx.bool_var2expr(c.m_args[i].first)); } sn(in, out); atmostk = ~se.internalize(c, out[k].get()); // k'th output is 0. From 074e851d4972ff3f2b45ec3e8f53a83575ab6eeb Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Fri, 15 Nov 2013 12:58:11 -0800 Subject: [PATCH 131/925] Display Fu Malik statistics --- src/opt/fu_malik.cpp | 89 ++++++++++++++++++++++++---- src/opt/opt_solver.cpp | 12 +++- src/opt/opt_solver.h | 6 +- src/sat/sat_solver.cpp | 3 +- src/smt/tactic/smt_tactic.cpp | 1 + src/solver/tactic2solver.cpp | 8 ++- src/tactic/smtlogics/qfbv_tactic.cpp | 14 ++--- 7 files changed, 104 insertions(+), 29 deletions(-) diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index 77eb108a9..235fa4205 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -22,6 +22,7 @@ Notes: #include "tactic2solver.h" #include "goal.h" #include "probe.h" +#include "tactic.h" #include "smt_context.h" /** @@ -41,16 +42,16 @@ Notes: namespace opt { struct fu_malik::imp { - ast_manager& m; - ref m_s; + ast_manager& m; expr_ref_vector m_soft; expr_ref_vector m_orig_soft; expr_ref_vector m_aux; expr_ref_vector m_assignment; unsigned m_upper_size; + ref m_s; solver & m_original_solver; - bool m_use_new_bv_solver; + bool m_use_new_bv_solver; imp(ast_manager& m, solver& s, expr_ref_vector const& soft): m(m), @@ -82,6 +83,63 @@ namespace opt { * add at-most-one constraint with blocking */ + typedef obj_hashtable expr_set; + + void set2vector(expr_set const& set, expr_ref_vector & es) const { + es.reset(); + expr_set::iterator it = set.begin(), end = set.end(); + for (; it != end; ++it) { + es.push_back(*it); + } + } + + void set_union(expr_set const& set1, expr_set const& set2, expr_set & set) const { + set.reset(); + expr_set::iterator it = set1.begin(), end = set1.end(); + for (; it != end; ++it) { + set.insert(*it); + } + it = set2.begin(); + end = set2.end(); + for (; it != end; ++it) { + set.insert(*it); + } + } + + void quick_explain(expr_ref_vector const& assumptions, expr_ref_vector & literals, bool has_set, expr_set & core) { + if (has_set && s().check_sat(assumptions.size(), assumptions.c_ptr()) == l_false) { + core.reset(); + return; + } + + SASSERT(!literals.empty()); + if (literals.size() == 1) { + core.reset(); + core.insert(literals[0].get()); + return; + } + + unsigned mid = literals.size()/2; + expr_ref_vector ls1(m), ls2(m); + ls1.append(mid, literals.c_ptr()); + ls2.append(literals.size()-mid, literals.c_ptr() + mid); + + expr_ref_vector as1(m); + as1.append(assumptions); + as1.append(ls1); + expr_set core2; + quick_explain(as1, ls2, !ls1.empty(), core2); + + expr_ref_vector as2(m), cs2(m); + as2.append(assumptions); + set2vector(core2, cs2); + as2.append(cs2); + expr_set core1; + quick_explain(as2, ls1, !core2.empty(), core1); + + set_union(core1, core2, core); + } + lbool step() { IF_VERBOSE(0, verbose_stream() << "(opt.max_sat step " << m_soft.size() + 2 - m_upper_size << ")\n";); expr_ref_vector assumptions(m), block_vars(m); @@ -95,12 +153,14 @@ namespace opt { ptr_vector core; if (m_use_new_bv_solver) { - unsigned i = 0; - while (s().check_sat(core.size(), core.c_ptr()) != l_false) { - IF_VERBOSE(0, verbose_stream() << "(opt.max_sat get-unsat-core round " << i << ")\n";); - core.push_back(assumptions[i].get()); - ++i; + expr_set core_set; + expr_ref_vector empty(m); + quick_explain(empty, assumptions, true, core_set); + expr_set::iterator it = core_set.begin(), end = core_set.end(); + for (; it != end; ++it) { + core.push_back(*it); } + IF_VERBOSE(0, verbose_stream() << "(opt.max_sat unsat-core of size " << core.size() << ")\n";); } else { s().get_unsat_core(core); @@ -164,11 +224,11 @@ namespace opt { probe *p = mk_is_qfbv_probe(); bool all_bv = (*p)(g).is_true(); if (all_bv) { - opt_solver & os = opt_solver::to_opt(m_original_solver); - smt::context & ctx = os.get_context(); - tactic* t = mk_qfbv_tactic(m, ctx.get_params()); + opt_solver & opt_s = opt_solver::to_opt(m_original_solver); + smt::context & ctx = opt_s.get_context(); + tactic_ref t = mk_qfbv_tactic(m, ctx.get_params()); // The new SAT solver hasn't supported unsat core yet - m_s = mk_tactic2solver(m, t); + m_s = mk_tactic2solver(m, t.get()); SASSERT(m_s != &m_original_solver); for (unsigned i = 0; i < num_assertions; ++i) { m_s->assert_expr(current_solver.get_assertion(i)); @@ -211,6 +271,11 @@ namespace opt { } } } + statistics st; + s().collect_statistics(st); + SASSERT(st.size() > 0); + opt_solver & opt_s = opt_solver::to_opt(m_original_solver); + opt_s.set_interim_stats(st); // We are done and soft_constraints has // been updated with the max-sat assignment. return is_sat; diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index fee4a8663..a8e7d8535 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -55,7 +55,13 @@ namespace opt { } void opt_solver::collect_statistics(statistics & st) const { - m_context.collect_statistics(st); + // Hack to display fu_malik statistics + if (m_stats.size() > 0) { + st.copy(m_stats); + } + else { + m_context.collect_statistics(st); + } } void opt_solver::assert_expr(expr * t) { @@ -213,6 +219,10 @@ namespace opt { } return dynamic_cast(s); } + + void opt_solver::set_interim_stats(statistics & st) { + m_stats.copy(st); + } void opt_solver::to_smt2_benchmark(std::ofstream & buffer, char const * name, char const * logic, char const * status, char const * attributes) { diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index de7ef0b1d..e5af48a5c 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -46,7 +46,8 @@ namespace opt { bool m_objective_enabled; svector m_objective_vars; vector m_objective_values; - bool m_is_dump; + bool m_is_dump; + statistics m_stats; public: opt_solver(ast_manager & m, params_ref const & p, symbol const & l); virtual ~opt_solver(); @@ -77,7 +78,8 @@ namespace opt { expr_ref block_upper_bound(unsigned obj_index, inf_eps const& val); static opt_solver& to_opt(solver& s); - + void set_interim_stats(statistics & st); + class toggle_objective { opt_solver& s; bool m_old_value; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 3e9b60260..ec00be897 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -671,6 +671,7 @@ namespace sat { // // ----------------------- lbool solver::check() { + IF_VERBOSE(0, verbose_stream() << "(sat.sat-solver using the new SAT solver)\n";); SASSERT(scope_lvl() == 0); #ifdef CLONE_BEFORE_SOLVING if (m_mc.empty()) { @@ -1970,7 +1971,7 @@ namespace sat { m_cancel = f; } - void solver::collect_statistics(statistics & st) { + void solver::collect_statistics(statistics & st) { m_stats.collect_statistics(st); m_cleaner.collect_statistics(st); m_simplifier.collect_statistics(st); diff --git a/src/smt/tactic/smt_tactic.cpp b/src/smt/tactic/smt_tactic.cpp index 95b150a8c..0fdde612d 100644 --- a/src/smt/tactic/smt_tactic.cpp +++ b/src/smt/tactic/smt_tactic.cpp @@ -135,6 +135,7 @@ public: proof_converter_ref & pc, expr_dependency_ref & core) { try { + IF_VERBOSE(0, verbose_stream() << "(smt.smt-tactic using the old SAT solver)\n";); SASSERT(in->is_well_sorted()); ast_manager & m = in->m(); TRACE("smt_tactic", tout << this << "\nAUTO_CONFIG: " << fparams().m_auto_config << " HIDIV0: " << fparams().m_hi_div0 << " " diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 1268fbcea..dde03f962 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -40,6 +40,7 @@ class tactic2solver : public solver_na2as { bool m_produce_models; bool m_produce_proofs; bool m_produce_unsat_cores; + statistics m_stats; public: tactic2solver(ast_manager & m, tactic * t, params_ref const & p, bool produce_proofs, bool produce_models, bool produce_unsat_cores, symbol const & logic); virtual ~tactic2solver(); @@ -161,6 +162,7 @@ lbool tactic2solver::check_sat_core(unsigned num_assumptions, expr * const * ass m_result->m_unknown = ex.msg(); } m_tactic->collect_statistics(m_result->m_stats); + m_tactic->collect_statistics(m_stats); m_result->m_model = md; m_result->m_proof = pr; if (m_produce_unsat_cores) { @@ -177,9 +179,9 @@ void tactic2solver::set_cancel(bool f) { m_tactic->set_cancel(f); } -void tactic2solver::collect_statistics(statistics & st) const { - if (m_result.get()) - m_result->collect_statistics(st); +void tactic2solver::collect_statistics(statistics & st) const { + st.copy(m_stats); + SASSERT(m_stats.size() > 0); } void tactic2solver::get_unsat_core(ptr_vector & r) { diff --git a/src/tactic/smtlogics/qfbv_tactic.cpp b/src/tactic/smtlogics/qfbv_tactic.cpp index cdbc6927e..51b040332 100644 --- a/src/tactic/smtlogics/qfbv_tactic.cpp +++ b/src/tactic/smtlogics/qfbv_tactic.cpp @@ -31,15 +31,6 @@ Notes: #define MEMLIMIT 300 -tactic * mk_new_sat_tactic(ast_manager & m) { - IF_VERBOSE(0, verbose_stream() << "Try to use the new SAT solver." << std::endl;); - tactic * new_sat = cond(mk_or(mk_produce_proofs_probe(), mk_produce_unsat_cores_probe()), - and_then(mk_simplify_tactic(m), - mk_smt_tactic()), - mk_sat_tactic(m)); - return new_sat; -} - tactic * mk_qfbv_tactic(ast_manager & m, params_ref const & p) { params_ref main_p; main_p.set_bool("elim_and", true); @@ -94,7 +85,10 @@ tactic * mk_qfbv_tactic(ast_manager & m, params_ref const & p) { tactic * new_sat = and_then(mk_simplify_tactic(m), mk_smt_tactic()); #else - tactic * new_sat = mk_new_sat_tactic(m); + tactic * new_sat = cond(mk_or(mk_produce_proofs_probe(), mk_produce_unsat_cores_probe()), + and_then(mk_simplify_tactic(m), + mk_smt_tactic()), + mk_sat_tactic(m)); #endif tactic * st = using_params(and_then(preamble_st, From 314f03c12ca7730d00315d2bf42b8aa5ac4e73ab Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Nov 2013 16:44:08 -0800 Subject: [PATCH 132/925] started new PB solver Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 2 +- src/opt/fu_malik.cpp | 2 +- src/smt/theory_pb.cpp | 703 ++++++++++++++++++++++++++++++++++++++++++ src/smt/theory_pb.h | 117 +++++++ 4 files changed, 822 insertions(+), 2 deletions(-) create mode 100644 src/smt/theory_pb.cpp create mode 100644 src/smt/theory_pb.h diff --git a/scripts/mk_project.py b/scripts/mk_project.py index e92899436..b52934dfe 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -63,11 +63,11 @@ def init_project_def(): add_lib('tab', ['muz', 'transforms'], 'muz/tab') add_lib('bmc', ['muz', 'transforms'], 'muz/bmc') add_lib('fp', ['muz', 'pdr', 'clp', 'tab', 'rel', 'bmc'], 'muz/fp') - add_lib('opt', ['smt'], 'opt') add_lib('smtlogic_tactics', ['arith_tactics', 'bv_tactics', 'nlsat_tactic', 'smt_tactic', 'aig_tactic', 'fp', 'muz','qe'], 'tactic/smtlogics') add_lib('ufbv_tactic', ['normal_forms', 'core_tactics', 'macros', 'smt_tactic', 'rewriter'], 'tactic/ufbv') add_lib('portfolio', ['smtlogic_tactics', 'ufbv_tactic', 'fpa', 'aig_tactic', 'fp', 'qe','sls_tactic', 'subpaving_tactic'], 'tactic/portfolio') add_lib('smtparser', ['portfolio'], 'parsers/smt') + add_lib('opt', ['smt', 'smtlogic_tactics'], 'opt') API_files = ['z3_api.h', 'z3_algebraic.h', 'z3_polynomial.h', 'z3_rcf.h'] add_lib('api', ['portfolio', 'user_plugin', 'smtparser', 'realclosure'], includes2install=['z3.h', 'z3_v1.h', 'z3_macros.h'] + API_files) diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index 77eb108a9..db4cb93d2 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -18,7 +18,7 @@ Notes: --*/ #include "fu_malik.h" -#include "smtlogics/qfbv_tactic.h" +#include "qfbv_tactic.h" #include "tactic2solver.h" #include "goal.h" #include "probe.h" diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp new file mode 100644 index 000000000..171615c95 --- /dev/null +++ b/src/smt/theory_pb.cpp @@ -0,0 +1,703 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + theory_pb.cpp + +Abstract: + + Pseudo-Boolean theory plugin. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-11-05 + +Notes: + + +--*/ + +#include "theory_pb.h" +#include "smt_context.h" +#include "ast_pp.h" +#include "sorting_network.h" + +namespace smt { + + theory_pb::theory_pb(ast_manager& m): + theory(m.mk_family_id("card")), + m_util(m) + {} + + theory_pb::~theory_pb() { + reset_eh(); + } + + theory * theory_pb::mk_fresh(context * new_ctx) { + return alloc(theory_pb, new_ctx->get_manager()); + } + + bool theory_pb::internalize_atom(app * atom, bool gate_ctx) { + context& ctx = get_context(); + ast_manager& m = get_manager(); + unsigned num_args = atom->get_num_args(); + SASSERT(m_util.is_at_most_k(atom) || m_util.is_le(atom)); + + if (ctx.b_internalized(atom)) { + return false; + } + + m_stats.m_num_predicates++; + + SASSERT(!ctx.b_internalized(atom)); + bool_var abv = ctx.mk_bool_var(atom); + + ineq* c = alloc(ineq, atom, literal(abv)); + c->m_k = m_util.get_k(atom); + int& k = c->m_k; + arg_t& args = c->m_args; + + // extract literals and coefficients. + for (unsigned i = 0; i < num_args; ++i) { + expr* arg = atom->get_arg(i); + literal l = compile_arg(arg); + int c = m_util.get_le_coeff(atom, i); + args.push_back(std::make_pair(l, c)); + } + // turn W <= k into -W >= -k + for (unsigned i = 0; i < args.size(); ++i) { + args[i].second = -args[i].second; + } + k = -k; + lbool is_true = normalize_ineq(args, k); + + literal lit(abv); + switch(is_true) { + case l_false: + lit = ~lit; + // fall-through + case l_true: + ctx.mk_th_axiom(get_id(), 1, &lit); + TRACE("card", tout << mk_pp(atom, m) << " := " << lit << "\n";); + dealloc(c); + return true; + case l_undef: + break; + } + + // TBD: special cases: args.size() == 1 + + // maximal coefficient: + int& max_coeff = c->m_max_coeff; + max_coeff = 0; + for (unsigned i = 0; i < args.size(); ++i) { + max_coeff = std::max(max_coeff, args[i].second); + } + + // compute watch literals: + int sum = 0; + unsigned& wsz = c->m_watch_sz; + wsz = 0; + while (sum < k + max_coeff && wsz < args.size()) { + sum += args[wsz].second; + wsz++; + } + + for (unsigned i = 0; i < wsz; ++i) { + add_watch(args[i].first, c); + } + + // pre-compile threshold for cardinality + bool is_cardinality = true; + for (unsigned i = 0; is_cardinality && i < args.size(); ++i) { + is_cardinality = (args[i].second == 1); + } + if (is_cardinality) { + unsigned log = 1, n = 1; + while (n <= args.size()) { + ++log; + n *= 2; + } + c->m_compilation_threshold = args.size()*log; + TRACE("card", tout << "threshold:" << (args.size()*log) << "\n";); + } + else { + c->m_compilation_threshold = UINT_MAX; + } + m_ineqs.insert(abv, c); + m_ineqs_trail.push_back(abv); + + TRACE("card", display(tout, *c);); + + return true; + } + + literal theory_pb::compile_arg(expr* arg) { + context& ctx = get_context(); + ast_manager& m = get_manager(); + if (!ctx.b_internalized(arg)) { + ctx.internalize(arg, false); + } + bool_var bv; + bool has_bv = false; + bool negate = m.is_not(arg, arg); + if (ctx.b_internalized(arg)) { + bv = ctx.get_bool_var(arg); + if (null_theory_var == ctx.get_var_theory(bv)) { + ctx.set_var_theory(bv, get_id()); + } + has_bv = (ctx.get_var_theory(bv) == get_id()); + } + + // pre-processing should better remove negations under cardinality. + // assumes relevancy level = 2 or 0. + if (!has_bv) { + expr_ref tmp(m), fml(m); + tmp = m.mk_fresh_const("card_proxy",m.mk_bool_sort()); + fml = m.mk_iff(tmp, arg); + ctx.internalize(fml, false); + SASSERT(ctx.b_internalized(tmp)); + bv = ctx.get_bool_var(tmp); + SASSERT(null_theory_var == ctx.get_var_theory(bv)); + ctx.set_var_theory(bv, get_id()); + literal lit(ctx.get_bool_var(fml)); + ctx.mk_th_axiom(get_id(), 1, &lit); + ctx.mark_as_relevant(tmp); + } + return negate?~literal(bv):literal(bv); + } + + void theory_pb::add_watch(literal l, ineq* c) { + unsigned idx = l.index(); + ptr_vector* ineqs; + if (!m_watch.find(idx, ineqs)) { + ineqs = alloc(ptr_vector); + m_watch.insert(idx, ineqs); + } + ineqs->push_back(c); + } + + static unsigned gcd(unsigned a, unsigned b) { + while (a != b) { + if (a == 0) return b; + if (b == 0) return a; + SASSERT(a != 0 && b != 0); + if (a < b) { + b %= a; + } + else { + a %= b; + } + } + return a; + } + + lbool theory_pb::normalize_ineq(arg_t& args, int& k) { + + // normalize first all literals to be positive: + // then we can can compare them more easily. + for (unsigned i = 0; i < args.size(); ++i) { + if (args[i].first.sign()) { + args[i].first.neg(); + k -= args[i].second; + args[i].second = -args[i].second; + } + } + // sort and coalesce arguments: + std::sort(args.begin(), args.end()); + for (unsigned i = 0; i + 1 < args.size(); ++i) { + if (args[i].first == args[i+1].first) { + args[i].second += args[i+1].second; + for (unsigned j = i+1; j + 1 < args.size(); ++j) { + args[j] = args[j+1]; + } + args.resize(args.size()-1); + } + if (args[i].second == 0) { + for (unsigned j = i; j + 1 < args.size(); ++j) { + args[j] = args[j+1]; + } + args.resize(args.size()-1); + } + } + // + // Ensure all coefficients are positive: + // c*l + y >= k + // <=> + // c*(1-~l) + y >= k + // <=> + // c - c*~l + y >= k + // <=> + // -c*~l + y >= k - c + // + unsigned sum = 0; + for (unsigned i = 0; i < args.size(); ++i) { + int c = args[i].second; + if (c < 0) { + args[i].second = -c; + args[i].first = ~args[i].first; + k -= c; + } + sum += args[i].second; + } + // detect tautologies: + if (k <= 0) { + args.reset(); + return l_true; + } + // detect infeasible constraints: + if (static_cast(sum) < k) { + args.reset(); + return l_false; + } + // Ensure the largest coefficient is not larger than k: + for (unsigned i = 0; i < args.size(); ++i) { + int c = args[i].second; + if (c > k) { + args[i].second = k; + } + } + SASSERT(!args.empty()); + + // apply cutting plane reduction: + unsigned g = 0; + for (unsigned i = 0; g != 1 && i < args.size(); ++i) { + int c = args[i].second; + if (c != k) { + g = gcd(g, c); + } + } + if (g == 0) { + // all coefficients are equal to k. + for (unsigned i = 0; i < args.size(); ++i) { + SASSERT(args[i].second == k); + args[i].second = 1; + } + k = 1; + } + else if (g > 1) { + // + // Example 5x + 5y + 2z + 2u >= 5 + // becomes 3x + 3y + z + u >= 3 + // + int k_new = k / g; // k_new is the ceiling of k / g. + if (gcd(k, g) != g) { + k_new++; + } + for (unsigned i = 0; i < args.size(); ++i) { + int c = args[i].second; + if (c == k) { + c = k_new; + } + else { + c = c / g; + } + args[i].second = c; + } + k = k_new; + } + + return l_undef; + } + + void theory_pb::collect_statistics(::statistics& st) const { + st.update("pb axioms", m_stats.m_num_axioms); + st.update("pb propagations", m_stats.m_num_propagations); + st.update("pb predicates", m_stats.m_num_predicates); + st.update("pb compilations", m_stats.m_num_compiles); + } + + void theory_pb::reset_eh() { + + // m_watch; + u_map*>::iterator it = m_watch.begin(), end = m_watch.end(); + for (; it != end; ++it) { + dealloc(it->m_value); + } + u_map::iterator itc = m_ineqs.begin(), endc = m_ineqs.end(); + for (; itc != endc; ++itc) { + dealloc(itc->m_value); + } + m_watch.reset(); + m_ineqs.reset(); + m_ineqs_trail.reset(); + m_ineqs_lim.reset(); + m_stats.reset(); + } + + +#if 0 + void theory_pb::propagate_assignment(ineq& c) { + if (c.m_compiled) { + return; + } + if (should_compile(c)) { + compile_ineq(c); + return; + } + context& ctx = get_context(); + ast_manager& m = get_manager(); + arg_t const& args = c.m_args; + bool_var abv = c.m_bv; + int min = c.m_current_min; + int max = c.m_current_max; + int k = c.m_k; + + TRACE("card", + tout << mk_pp(c.m_app, m) << " min: " + << min << " max: " << max << "\n";); + + // + // if min > k && abv != l_false -> force abv false + // if max <= k && abv != l_true -> force abv true + // if min == k && abv == l_true -> force positive + // unassigned literals false + // if max == k + 1 && abv == l_false -> force negative + // unassigned literals false + // + lbool aval = ctx.get_assignment(abv); + if (min > k && aval != l_false) { + literal_vector& lits = get_lits(); + int curr_min = accumulate_min(lits, c); + SASSERT(curr_min > k); + add_assign(c, lits, ~literal(abv)); + } + else if (max <= k && aval != l_true) { + literal_vector& lits = get_lits(); + int curr_max = accumulate_max(lits, c); + SASSERT(curr_max <= k); + add_assign(c, lits, literal(abv)); + } + else if (min <= k && k < min + get_max_delta(c) && aval == l_true) { + literal_vector& lits = get_lits(); + lits.push_back(~literal(abv)); + int curr_min = accumulate_min(lits, c); + if (curr_min > k) { + add_clause(c, lits); + } + else { + for (unsigned i = 0; i < args.size(); ++i) { + bool_var bv = args[i].first; + int inc = args[i].second; + if (curr_min + inc > k && inc_min(inc, ctx.get_assignment(bv)) == l_undef) { + add_assign(c, lits, literal(bv, inc > 0)); + } + } + } + } + else if (max - get_max_delta(c) <= k && k < max && aval == l_false) { + literal_vector& lits = get_lits(); + lits.push_back(literal(abv)); + int curr_max = accumulate_max(lits, c); + if (curr_max <= k) { + add_clause(c, lits); + } + else { + for (unsigned i = 0; i < args.size(); ++i) { + bool_var bv = args[i].first; + int inc = args[i].second; + if (curr_max - abs(inc) <= k && dec_max(inc, ctx.get_assignment(bv)) == l_undef) { + add_assign(c, lits, literal(bv, inc < 0)); + } + } + } + } + else if (aval == l_true) { + SASSERT(min < k); + literal_vector& lits = get_lits(); + int curr_min = accumulate_min(lits, c); + bool all_inc = curr_min == k; + unsigned num_incs = 0; + for (unsigned i = 0; all_inc && i < args.size(); ++i) { + bool_var bv = args[i].first; + int inc = args[i].second; + if (inc_min(inc, ctx.get_assignment(bv)) == l_undef) { + all_inc = inc + min > k; + num_incs++; + } + } + if (num_incs > 0) { + std::cout << "missed T propgations " << num_incs << "\n"; + } + } + else if (aval == l_false) { + literal_vector& lits = get_lits(); + lits.push_back(literal(abv)); + int curr_max = accumulate_max(lits, c); + bool all_dec = curr_max > k; + unsigned num_decs = 0; + for (unsigned i = 0; all_dec && i < args.size(); ++i) { + bool_var bv = args[i].first; + int inc = args[i].second; + if (dec_max(inc, ctx.get_assignment(bv)) == l_undef) { + all_dec = inc + max <= k; + num_decs++; + } + } + if (num_decs > 0) { + std::cout << "missed F propgations " << num_decs << "\n"; + } + } + } +#endif + + void theory_pb::assign_eh(bool_var v, bool is_true) { + context& ctx = get_context(); + ast_manager& m = get_manager(); + ptr_vector* ineqs = 0; + ineq* c = 0; + TRACE("card", tout << "assign: " << mk_pp(ctx.bool_var2expr(v), m) << " <- " << is_true << "\n";); + + if (m_watch.find(v, ineqs)) { + for (unsigned i = 0; i < ineqs->size(); ++i) { + // TBD: assign_use(v, is_true, *(*ineqs)[i]); + } + } + if (m_ineqs.find(v, c)) { + // TBD: propagate_assignment(*c); + } + } + + struct theory_pb::sort_expr { + theory_pb& th; + context& ctx; + ast_manager& m; + expr_ref_vector m_trail; + sort_expr(theory_pb& th): + th(th), + ctx(th.get_context()), + m(th.get_manager()), + m_trail(m) {} + typedef expr* T; + typedef expr_ref_vector vector; + + T mk_ite(T a, T b, T c) { + if (m.is_true(a)) { + return b; + } + if (m.is_false(a)) { + return c; + } + if (b == c) { + return b; + } + m_trail.push_back(m.mk_ite(a, b, c)); + return m_trail.back(); + } + + T mk_le(T a, T b) { + return mk_ite(b, a, m.mk_true()); + } + + T mk_default() { + return m.mk_false(); + } + + literal internalize(ineq& ca, expr* e) { + obj_map cache; + for (unsigned i = 0; i < ca.m_args.size(); ++i) { + cache.insert(ca.m_app->get_arg(i), literal(ca.m_args[i].first)); + } + cache.insert(m.mk_false(), false_literal); + cache.insert(m.mk_true(), true_literal); + ptr_vector todo; + todo.push_back(e); + expr *a, *b, *c; + literal la, lb, lc; + while (!todo.empty()) { + expr* t = todo.back(); + if (cache.contains(t)) { + todo.pop_back(); + continue; + } + VERIFY(m.is_ite(t, a, b, c)); + unsigned sz = todo.size(); + if (!cache.find(a, la)) { + todo.push_back(a); + } + if (!cache.find(b, lb)) { + todo.push_back(b); + } + if (!cache.find(c, lc)) { + todo.push_back(c); + } + if (sz != todo.size()) { + continue; + } + todo.pop_back(); + cache.insert(t, mk_ite(ca, t, la, lb, lc)); + } + return cache.find(e); + } + + literal mk_ite(ineq& ca, expr* t, literal a, literal b, literal c) { + if (a == true_literal) { + return b; + } + else if (a == false_literal) { + return c; + } + else if (b == true_literal && c == false_literal) { + return a; + } + else if (b == false_literal && c == true_literal) { + return ~a; + } + else if (b == c) { + return b; + } + else { + literal l; + if (ctx.b_internalized(t)) { + l = literal(ctx.get_bool_var(t)); + } + else { + l = literal(ctx.mk_bool_var(t)); + } + add_clause(~l, ~a, b); + add_clause(~l, a, c); + add_clause(l, ~a, ~b); + add_clause(l, a, ~c); + TRACE("card", tout << mk_pp(t, m) << " ::= (if "; + ctx.display_detailed_literal(tout, a); + ctx.display_detailed_literal(tout << " ", b); + ctx.display_detailed_literal(tout << " ", c); + tout << ")\n";); + return l; + } + } + + + // auxiliary clauses don't get garbage collected. + void add_clause(literal a, literal b, literal c) { + literal_vector& lits = th.get_lits(); + if (a != null_literal) lits.push_back(a); + if (b != null_literal) lits.push_back(b); + if (c != null_literal) lits.push_back(c); + justification* js = 0; + TRACE("card", + ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";); + ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX, 0); + } + + void add_clause(literal l1, literal l2) { + add_clause(l1, l2, null_literal); + } + + }; + + + bool theory_pb::should_compile(ineq& c) { +#if 1 + return false; +#else + return c.m_num_propagations > c.m_compilation_threshold; +#endif + } + + void theory_pb::compile_ineq(ineq& c) { + ++m_stats.m_num_compiles; + ast_manager& m = get_manager(); + context& ctx = get_context(); + app* a = c.m_app; + SASSERT(m_util.is_at_most_k(a)); + literal atmostk; + int k = m_util.get_k(a); + unsigned num_args = a->get_num_args(); + + sort_expr se(*this); + if (k >= static_cast(num_args)) { + atmostk = true_literal; + } + else if (k < 0) { + atmostk = false_literal; + } + else { + sorting_network sn(se); + expr_ref_vector in(m), out(m); + for (unsigned i = 0; i < num_args; ++i) { + in.push_back(c.m_app->get_arg(i)); + } + sn(in, out); + atmostk = ~se.internalize(c, out[k].get()); // k'th output is 0. + TRACE("card", tout << "~atmost: " << mk_pp(out[k].get(), m) << "\n";); + } + literal thl = c.m_lit; + se.add_clause(~thl, atmostk); + se.add_clause(thl, ~atmostk); + TRACE("card", tout << mk_pp(a, m) << "\n";); + // auxiliary clauses get removed when popping scopes. + // we have to recompile the circuit after back-tracking. + ctx.push_trail(value_trail(c.m_compiled)); + c.m_compiled = true; + } + + + void theory_pb::init_search_eh() { + + } + + void theory_pb::push_scope_eh() { + m_ineqs_lim.push_back(m_ineqs_trail.size()); + } + + void theory_pb::pop_scope_eh(unsigned num_scopes) { + unsigned sz = m_ineqs_lim[m_ineqs_lim.size()-num_scopes]; + while (m_ineqs_trail.size() > sz) { + SASSERT(m_ineqs.contains(m_ineqs_trail.back())); + m_ineqs.remove(m_ineqs_trail.back()); + m_ineqs_trail.pop_back(); + } + m_ineqs_lim.resize(m_ineqs_lim.size()-num_scopes); + } + + std::ostream& theory_pb::display(std::ostream& out, ineq& c) const { + ast_manager& m = get_manager(); + out << mk_pp(c.m_app, m) << "\n"; + for (unsigned i = 0; i < c.m_args.size(); ++i) { + out << c.m_args[i].second << "*" << c.m_args[i].first; + if (i + 1 < c.m_args.size()) { + out << " + "; + } + } + out << " >= " << c.m_k << "\n" + << "propagations: " << c.m_num_propagations + << " max_coeff: " << c.m_max_coeff + << " watch size: " << c.m_watch_sz + << "\n"; + return out; + } + + + literal_vector& theory_pb::get_lits() { + m_literals.reset(); + return m_literals; + } + + void theory_pb::add_assign(ineq& c, literal_vector const& lits, literal l) { + literal_vector ls; + ++c.m_num_propagations; + m_stats.m_num_propagations++; + context& ctx = get_context(); + for (unsigned i = 0; i < lits.size(); ++i) { + ls.push_back(~lits[i]); + } + ctx.assign(l, ctx.mk_justification(theory_propagation_justification(get_id(), ctx.get_region(), ls.size(), ls.c_ptr(), l))); + } + + + + void theory_pb::add_clause(ineq& c, literal_vector const& lits) { + ++c.m_num_propagations; + m_stats.m_num_axioms++; + context& ctx = get_context(); + TRACE("card", tout << "#prop:" << c.m_num_propagations << " - "; ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";); + justification* js = 0; + ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); + IF_VERBOSE(2, ctx.display_literals_verbose(verbose_stream(), + lits.size(), lits.c_ptr()); + verbose_stream() << "\n";); + // ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); + } +} diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h new file mode 100644 index 000000000..432d4e497 --- /dev/null +++ b/src/smt/theory_pb.h @@ -0,0 +1,117 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + theory_pb.h + +Abstract: + + Cardinality theory plugin. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-11-05 + +Notes: + + This custom theory handles cardinality constraints + It performs unit propagation and switches to creating + sorting circuits if it keeps having to propagate (create new clauses). +--*/ + +#include "smt_theory.h" +#include "card_decl_plugin.h" +#include "smt_clause.h" + +namespace smt { + class theory_pb : public theory { + + struct sort_expr; + typedef svector > arg_t; + + struct stats { + unsigned m_num_axioms; + unsigned m_num_propagations; + unsigned m_num_predicates; + unsigned m_num_compiles; + void reset() { memset(this, 0, sizeof(*this)); } + stats() { reset(); } + }; + + + struct ineq { + app* m_app; + literal m_lit; // literal repesenting predicate + arg_t m_args; // encode args[0]*coeffs[0]+...+args[n-1]*coeffs[n-1] >= m_k; + int m_k; // invariants: m_k > 0, coeffs[i] > 0 + + // Watch the first few positions until the sum satisfies: + // sum coeffs[i] >= m_lower + max_coeff + + int m_max_coeff; // maximal coefficient. + unsigned m_watch_sz; // number of literals being watched. + unsigned m_num_propagations; + unsigned m_compilation_threshold; + bool m_compiled; + + ineq(app* a, literal l): + m_app(a), + m_lit(l), + m_num_propagations(0), + m_compilation_threshold(UINT_MAX), + m_compiled(false) + {} + }; + + typedef ptr_vector watch_list; + + u_map m_watch; // per literal. + u_map m_ineqs; // per inequality. + unsigned_vector m_ineqs_trail; + unsigned_vector m_ineqs_lim; + literal_vector m_literals; // temporary vector + card_util m_util; + stats m_stats; + + // internalize_atom: + lbool normalize_ineq(arg_t& args, int& k); + literal compile_arg(expr* arg); + void add_watch(literal l, ineq* c); + + std::ostream& display(std::ostream& out, ineq& c) const; + + void add_clause(ineq& c, literal_vector const& lits); + void add_assign(ineq& c, literal_vector const& lits, literal l); + literal_vector& get_lits(); + + // + // Utilities to compile cardinality + // constraints into a sorting network. + // + void compile_ineq(ineq& c); + bool should_compile(ineq& c); + unsigned get_compilation_threshold(ineq& c); + public: + theory_pb(ast_manager& m); + + virtual ~theory_pb(); + + virtual theory * mk_fresh(context * new_ctx); + virtual bool internalize_atom(app * atom, bool gate_ctx); + virtual bool internalize_term(app * term) { UNREACHABLE(); return false; } + virtual void new_eq_eh(theory_var v1, theory_var v2) { } + virtual void new_diseq_eh(theory_var v1, theory_var v2) { } + virtual bool use_diseqs() const { return false; } + virtual bool build_models() const { return false; } + virtual final_check_status final_check_eh() { return FC_DONE; } + + virtual void reset_eh(); + virtual void assign_eh(bool_var v, bool is_true); + virtual void init_search_eh(); + virtual void push_scope_eh(); + virtual void pop_scope_eh(unsigned num_scopes); + virtual void collect_statistics(::statistics & st) const; + + }; +}; From c837f62863330e7eb908308d45449eda84cb6219 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Fri, 15 Nov 2013 16:58:42 -0800 Subject: [PATCH 133/925] Use quick explain for unsat core in Fu Malik algorithm by default --- src/opt/fu_malik.cpp | 38 ++++++++++++++++++++++++++++++++++---- src/opt/opt_solver.cpp | 4 ++++ src/opt/opt_solver.h | 1 + 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index 235fa4205..a0946dc9f 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -123,7 +123,15 @@ namespace opt { expr_ref_vector ls1(m), ls2(m); ls1.append(mid, literals.c_ptr()); ls2.append(literals.size()-mid, literals.c_ptr() + mid); - +#if Z3DEBUG + expr_ref_vector ls(m); + ls.append(ls1); + ls.append(ls2); + SASSERT(ls.size() == literals.size()); + for (unsigned i = 0; i < literals.size(); ++i) { + SASSERT(ls[i].get() == literals[i].get()); + } +#endif expr_ref_vector as1(m); as1.append(assumptions); as1.append(ls1); @@ -153,6 +161,7 @@ namespace opt { ptr_vector core; if (m_use_new_bv_solver) { + // Binary search for minimal unsat core expr_set core_set; expr_ref_vector empty(m); quick_explain(empty, assumptions, true, core_set); @@ -160,6 +169,24 @@ namespace opt { for (; it != end; ++it) { core.push_back(*it); } + + //// Forward linear search for unsat core + //unsigned i = 0; + //while (s().check_sat(core.size(), core.c_ptr()) != l_false) { + // IF_VERBOSE(0, verbose_stream() << "(opt.max_sat get-unsat-core round " << i << ")\n";); + // core.push_back(assumptions[i].get()); + // ++i; + //} + + //// Backward linear search for unsat core + //unsigned i = 0; + //core.append(assumptions.size(), assumptions.c_ptr()); + //while (!core.empty() && s().check_sat(core.size()-1, core.c_ptr()) == l_false) { + // IF_VERBOSE(0, verbose_stream() << "(opt.max_sat get-unsat-core round " << i << ")\n";); + // core.pop_back(); + // ++i; + //} + IF_VERBOSE(0, verbose_stream() << "(opt.max_sat unsat-core of size " << core.size() << ")\n";); } else { @@ -214,7 +241,11 @@ namespace opt { } } - void set_solver() { + void set_solver() { + opt_solver & opt_s = opt_solver::to_opt(m_original_solver); + if (opt_s.is_dumping_benchmark()) + return; + solver& current_solver = s(); goal g(m, true, false); unsigned num_assertions = current_solver.get_num_assertions(); @@ -223,8 +254,7 @@ namespace opt { } probe *p = mk_is_qfbv_probe(); bool all_bv = (*p)(g).is_true(); - if (all_bv) { - opt_solver & opt_s = opt_solver::to_opt(m_original_solver); + if (all_bv) { smt::context & ctx = opt_s.get_context(); tactic_ref t = mk_qfbv_tactic(m, ctx.get_params()); // The new SAT solver hasn't supported unsat core yet diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index a8e7d8535..88d1cab1f 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -105,6 +105,10 @@ namespace opt { static unsigned g_checksat_count = 0; + bool opt_solver::is_dumping_benchmark() { + return m_is_dump; + } + lbool opt_solver::check_sat_core(unsigned num_assumptions, expr * const * assumptions) { TRACE("opt_solver_na2as", { tout << "opt_opt_solver::check_sat_core: " << m_context.size() << "\n"; diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index e5af48a5c..e946d2131 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -79,6 +79,7 @@ namespace opt { static opt_solver& to_opt(solver& s); void set_interim_stats(statistics & st); + bool is_dumping_benchmark(); class toggle_objective { opt_solver& s; From af8da013b59ce33309b08a33c3f3f9d5b8709e36 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Fri, 15 Nov 2013 17:17:20 -0800 Subject: [PATCH 134/925] Fix a few issues related to thread spanning tree --- src/smt/network_flow.h | 2 +- src/smt/network_flow_def.h | 20 ++--- src/smt/spanning_tree.h | 2 +- src/smt/spanning_tree_base.h | 12 +-- src/smt/spanning_tree_def.h | 146 +++++++++++++++++------------------ 5 files changed, 90 insertions(+), 92 deletions(-) diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index 461312985..d845c671a 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -244,7 +244,7 @@ namespace smt { }; graph m_graph; - thread_spanning_tree m_tree; + spanning_tree_base * m_tree; // Denote supply/demand b_i on node i vector m_balances; diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index 515d49933..0ec7fe0c0 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -27,8 +27,7 @@ namespace smt { template network_flow::network_flow(graph & g, vector const & balances) : - m_balances(balances), - m_tree(m_graph) { + m_balances(balances) { // Network flow graph has the edges in the reversed order compared to constraint graph // We only take enabled edges from the original graph for (unsigned i = 0; i < g.get_num_nodes(); ++i) { @@ -42,6 +41,7 @@ namespace smt { } } m_step = 0; + m_tree = alloc(thread_spanning_tree, m_graph); } template @@ -82,7 +82,7 @@ namespace smt { tree.push_back(m_graph.add_edge(src, tgt, numeral::one(), explanation())); } - m_tree.initialize(tree); + m_tree->initialize(tree); TRACE("network_flow", { tout << pp_vector("Potentials", m_potentials, true) << pp_vector("Flows", m_flows); @@ -96,14 +96,14 @@ namespace smt { node src = m_graph.get_source(m_enter_id); node tgt = m_graph.get_target(m_enter_id); numeral cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(m_enter_id); - numeral change = m_tree.in_subtree_t2(tgt) ? cost : -cost; + numeral change = m_tree->in_subtree_t2(tgt) ? cost : -cost; node start = m_graph.get_source(m_leave_id); - if (!m_tree.in_subtree_t2(start)) { + if (!m_tree->in_subtree_t2(start)) { start = m_graph.get_target(m_leave_id);; } TRACE("network_flow", tout << "update_potentials of T_" << start << " with change = " << change << "...\n";); svector descendants; - m_tree.get_descendants(start, descendants); + m_tree->get_descendants(start, descendants); SASSERT(descendants.size() >= 1); for (unsigned i = 0; i < descendants.size(); ++i) { node u = descendants[i]; @@ -120,7 +120,7 @@ namespace smt { node tgt = m_graph.get_target(m_enter_id); svector path; svector against; - m_tree.get_path(src, tgt, path, against); + m_tree->get_path(src, tgt, path, against); SASSERT(path.size() >= 1); for (unsigned i = 0; i < path.size(); ++i) { edge_id e_id = path[i]; @@ -138,7 +138,7 @@ namespace smt { edge_id leave_id; svector path; svector against; - m_tree.get_path(src, tgt, path, against); + m_tree->get_path(src, tgt, path, against); SASSERT(path.size() >= 1); for (unsigned i = 0; i < path.size(); ++i) { edge_id e_id = path[i]; @@ -164,7 +164,7 @@ namespace smt { template void network_flow::update_spanning_tree() { - m_tree.update(m_enter_id, m_leave_id); + m_tree->update(m_enter_id, m_leave_id); } // FIXME: should declare pivot as a pivot_rule_impl and refactor @@ -240,7 +240,7 @@ namespace smt { template bool network_flow::check_well_formed() { - SASSERT(m_tree.check_well_formed()); + SASSERT(m_tree->check_well_formed()); SASSERT(!m_delta || !(*m_delta).is_neg()); // m_flows are zero on non-basic edges diff --git a/src/smt/spanning_tree.h b/src/smt/spanning_tree.h index c591f5485..f5f6b624f 100644 --- a/src/smt/spanning_tree.h +++ b/src/smt/spanning_tree.h @@ -49,7 +49,7 @@ namespace smt { void swap_order(node q, node v); node find_rev_thread(node n) const; - void fix_depth(node start, node end); + void fix_depth(node start, node after_end); node get_final(int start); bool is_preorder_traversal(node start, node end); node get_common_ancestor(node u, node v); diff --git a/src/smt/spanning_tree_base.h b/src/smt/spanning_tree_base.h index e492f80fa..25384d52e 100644 --- a/src/smt/spanning_tree_base.h +++ b/src/smt/spanning_tree_base.h @@ -47,14 +47,14 @@ namespace smt { typedef int node; public: - virtual void initialize(svector const & tree) {}; - virtual void get_descendants(node start, svector & descendants) {}; + virtual void initialize(svector const & tree) = 0; + virtual void get_descendants(node start, svector & descendants) = 0; - virtual void update(edge_id enter_id, edge_id leave_id) {}; - virtual void get_path(node start, node end, svector & path, svector & against) {}; - virtual bool in_subtree_t2(node child) {UNREACHABLE(); return false;}; + virtual void update(edge_id enter_id, edge_id leave_id) = 0; + virtual void get_path(node start, node end, svector & path, svector & against) = 0; + virtual bool in_subtree_t2(node child) = 0; - virtual bool check_well_formed() {UNREACHABLE(); return false;}; + virtual bool check_well_formed() = 0; }; } diff --git a/src/smt/spanning_tree_def.h b/src/smt/spanning_tree_def.h index c1e05ba3b..281a2cf45 100644 --- a/src/smt/spanning_tree_def.h +++ b/src/smt/spanning_tree_def.h @@ -162,11 +162,26 @@ namespace smt { tout << u << ", " << v << ") leaves\n"; }); + // Old threads: alpha -> v -*-> f(v) -> beta | p -*-> f(p) -> gamma + // New threads: alpha -> beta | p -*-> f(p) -> v -*-> f(v) -> gamma + + node f_p = get_final(p); + node f_v = get_final(v); + node alpha = find_rev_thread(v); + node beta = m_thread[f_v]; + node gamma = m_thread[f_p]; + + if (v != gamma) { + m_thread[alpha] = beta; + m_thread[f_p] = v; + m_thread[f_v] = gamma; + } + node old_pred = m_pred[q]; // Update stem nodes from q to v if (q != v) { - for (node n = q; n != u; ) { - SASSERT(old_pred != u || n == v); // the last processed node is v + for (node n = q; n != v; ) { + SASSERT(old_pred != u); // the last processed node is v SASSERT(-1 != m_pred[old_pred]); int next_old_pred = m_pred[old_pred]; swap_order(n, old_pred); @@ -175,34 +190,18 @@ namespace smt { old_pred = next_old_pred; } } - - // Old threads: alpha -> q -*-> f(q) -> beta | p -*-> f(p) -> gamma - // New threads: alpha -> beta | p -*-> f(p) -> q -*-> f(q) -> gamma - - node f_p = get_final(p); - node f_q = get_final(q); - node alpha = find_rev_thread(q); - node beta = m_thread[f_q]; - node gamma = m_thread[f_p]; - - if (q != gamma) { - m_thread[alpha] = beta; - m_thread[f_p] = q; - m_thread[f_q] = gamma; - } - + m_pred[q] = p; m_tree[q] = enter_id; m_root_t2 = q; + node after_final_q = (v == gamma) ? beta : gamma; + fix_depth(q, after_final_q); + SASSERT(!in_subtree_t2(p)); SASSERT(in_subtree_t2(q)); SASSERT(!in_subtree_t2(u)); SASSERT(in_subtree_t2(v)); - - // Update the depth. - - fix_depth(q, get_final(q)); TRACE("network_flow", { tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Threads", m_thread); @@ -210,6 +209,53 @@ namespace smt { }); } + /** + swap v and q in tree. + - fixup m_thread + - fixup m_pred + + Case 1: final(q) == final(v) + ------- + Old thread: prev -> v -*-> alpha -> q -*-> final(q) -> next + New thread: prev -> q -*-> final(q) -> v -*-> alpha -> next + + Case 2: final(q) != final(v) + ------- + Old thread: prev -> v -*-> alpha -> q -*-> final(q) -> beta -*-> final(v) -> next + New thread: prev -> q -*-> final(q) -> v -*-> alpha -> beta -*-> final(v) -> next + + */ + template + void thread_spanning_tree::swap_order(node q, node v) { + SASSERT(q != v); + SASSERT(m_pred[q] == v); + SASSERT(is_preorder_traversal(v, get_final(v))); + node prev = find_rev_thread(v); + node f_q = get_final(q); + node f_v = get_final(v); + node next = m_thread[f_v]; + node alpha = find_rev_thread(q); + + if (f_q == f_v) { + SASSERT(f_q != v && alpha != next); + m_thread[f_q] = v; + m_thread[alpha] = next; + f_q = alpha; + } + else { + node beta = m_thread[f_q]; + SASSERT(f_q != v && alpha != beta); + m_thread[f_q] = v; + m_thread[alpha] = beta; + f_q = f_v; + } + SASSERT(prev != q); + m_thread[prev] = q; + m_pred[v] = q; + // Notes: f_q has to be used since m_depth hasn't been updated yet. + SASSERT(is_preorder_traversal(q, f_q)); + } + /** \brief Check invariants of main data-structures. @@ -311,53 +357,6 @@ namespace smt { roots[y] = x; } - /** - swap v and q in tree. - - fixup m_thread - - fixup m_pred - - Case 1: final(q) == final(v) - ------- - Old thread: prev -> v -*-> alpha -> q -*-> final(q) -> next - New thread: prev -> q -*-> final(q) -> v -*-> alpha -> next - - Case 2: final(q) != final(v) - ------- - Old thread: prev -> v -*-> alpha -> q -*-> final(q) -> beta -*-> final(v) -> next - New thread: prev -> q -*-> final(q) -> v -*-> alpha -> beta -*-> final(v) -> next - - */ - template - void thread_spanning_tree::swap_order(node q, node v) { - SASSERT(q != v); - SASSERT(m_pred[q] == v); - SASSERT(is_preorder_traversal(v, get_final(v))); - node prev = find_rev_thread(v); - node f_q = get_final(q); - node f_v = get_final(v); - node next = m_thread[f_v]; - node alpha = find_rev_thread(q); - - if (f_q == f_v) { - SASSERT(f_q != v && alpha != next); - m_thread[f_q] = v; - m_thread[alpha] = next; - f_q = alpha; - } - else { - node beta = m_thread[f_q]; - SASSERT(f_q != v && alpha != beta); - m_thread[f_q] = v; - m_thread[alpha] = beta; - f_q = f_v; - } - SASSERT(prev != q); - m_thread[prev] = q; - m_pred[v] = q; - // Notes: f_q has to be used since m_depth hasn't been updated yet. - SASSERT(is_preorder_traversal(q, f_q)); - } - /** \brief find node that points to 'n' in m_thread */ @@ -372,12 +371,11 @@ namespace smt { } template - void thread_spanning_tree::fix_depth(node start, node end) { - SASSERT(m_pred[start] != -1); - m_depth[start] = m_depth[m_pred[start]]+1; - while (start != end) { - start = m_thread[start]; + void thread_spanning_tree::fix_depth(node start, node after_end) { + while (start != after_end) { + SASSERT(m_pred[start] != -1); m_depth[start] = m_depth[m_pred[start]]+1; + start = m_thread[start]; } } From 13c97d12a8f4302a924acf5708ce4f485738f76b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Nov 2013 17:31:31 -0800 Subject: [PATCH 135/925] snapshot Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 34 ++++++++++++++++++++++++++++++++-- src/smt/theory_pb.h | 1 + 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 171615c95..52d525bde 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -196,7 +196,7 @@ namespace smt { lbool theory_pb::normalize_ineq(arg_t& args, int& k) { // normalize first all literals to be positive: - // then we can can compare them more easily. + // then we can compare them more easily. for (unsigned i = 0; i < args.size(); ++i) { if (args[i].first.sign()) { args[i].first.neg(); @@ -451,7 +451,7 @@ namespace smt { if (m_watch.find(v, ineqs)) { for (unsigned i = 0; i < ineqs->size(); ++i) { - // TBD: assign_use(v, is_true, *(*ineqs)[i]); + assign_watch(v, is_true, *ineqs, i); } } if (m_ineqs.find(v, c)) { @@ -459,6 +459,36 @@ namespace smt { } } + void theory_pb::assign_watch(bool_var v, bool is_true, watch_list& watch, unsigned index) { +#if 0 + TBD + ineq& c = *watch[i]; + c.m_sum; + unsigned w; + for (w = 0; w < c.m_watch_sz; ++i) { + if (c.m_args[w].first.var() == v) { + break; + } + } + SASSERT(w < c.m_watch_sz); + literal l = c.m_args[w].first; + int coeff = c.m_args[w].second; + if (is_true == !l.sign()) { + ctx.push_trail(value_trail(c.m_sum)); + c.m_sum += coeff; + // optional propagate + } + else { + unsigned deficit = c.m_max_sum - coeff; + for (unsigned i = c.m_watch_sz; i < c.m_args.size(); ++i) { + if + } + // find a different literal to watch. + ctx.push_trail(value_trail(c.m_watch_sz)); + } +#endif + } + struct theory_pb::sort_expr { theory_pb& th; context& ctx; diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 432d4e497..5fb66f3f4 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -78,6 +78,7 @@ namespace smt { lbool normalize_ineq(arg_t& args, int& k); literal compile_arg(expr* arg); void add_watch(literal l, ineq* c); + void assign_watch(bool_var v, bool is_true, watch_list& watch, unsigned index); std::ostream& display(std::ostream& out, ineq& c) const; From 6ddc8386285cd9c1eff50640cb09b1112e25db0f Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Fri, 15 Nov 2013 18:34:05 -0800 Subject: [PATCH 136/925] Add a basic spanning tree --- src/smt/diff_logic.h | 82 +++++++++++++++++++++++++++++++++++++ src/smt/network_flow_def.h | 2 +- src/smt/spanning_tree.h | 21 +++++++--- src/smt/spanning_tree_def.h | 57 ++++++++++++++++++++++++++ 4 files changed, 155 insertions(+), 7 deletions(-) diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index ff01a4792..fcd4f6309 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -25,6 +25,7 @@ Revision History: #include"trace.h" #include"warning.h" #include"uint_set.h" +#include typedef int dl_var; @@ -953,6 +954,87 @@ public: return m_edges; } + void get_neighbours_undirected(dl_var current, svector & neighbours) { + neighbours.reset(); + edge_id_vector & edges = m_out_edges[current]; + typename edge_id_vector::iterator it = edges.begin(), end = edges.end(); + for (; it != end; ++it) { + edge_id e_id = *it; + edge & e = m_edges[e_id]; + if (!e.is_enabled()) continue; + SASSERT(e.get_source() == current); + dl_var neighbour = e.get_target(); + neighbours.push_back(neighbour); + } + edges = m_in_edges[current]; + it = edges.begin(); + end = edges.end(); + for (; it != end; ++it) { + edge_id e_id = *it; + edge & e = m_edges[e_id]; + if (!e.is_enabled()) continue; + SASSERT(e.get_target() == current); + dl_var neighbour = e.get_source(); + neighbours.push_back(neighbour); + } + } + + void dfs_undirected(dl_var start, svector & threads) { + threads.reset(); + threads.resize(get_num_nodes()); + uint_set visited; + svector nodes; + nodes.push_back(start); + dl_var prev = -1; + while(!nodes.empty()) { + dl_var current = nodes.back(); + nodes.pop_back(); + visited.insert(current); + if (prev != -1) + threads[prev] = current; + prev = current; + svector neighbours; + get_neighbours_undirected(current, neighbours); + for (unsigned i = 0; i < neighbours.size(); ++i) { + edge_id id; + SASSERT(prev == -1 || get_edge_id(prev, current, id) || get_edge_id(current, prev, id)); + if (!visited.contains(neighbours[i])) { + nodes.push_back(neighbours[i]); + } + } + } + threads[prev] = start; + } + + void bfs_undirected(dl_var start, svector & parents, svector & depths) { + parents.reset(); + parents.resize(get_num_nodes()); + depths.reset(); + depths.resize(get_num_nodes()); + uint_set visited; + std::deque nodes; + visited.insert(start); + nodes.push_front(start); + while(!nodes.empty()) { + dl_var current = nodes.back(); + nodes.pop_back(); + SASSERT(visited.contains(current)); + svector neighbours; + get_neighbours_undirected(current, neighbours); + for (unsigned i = 0; i < neighbours.size(); ++i) { + dl_var & next = neighbours[i]; + edge_id id; + SASSERT(get_edge_id(current, next, id) || get_edge_id(next, current, id)); + if (!visited.contains(next)) { + parents[next] = current; + depths[next] = depths[current] + 1; + visited.insert(next); + nodes.push_front(next); + } + } + } + } + template void enumerate_edges(dl_var source, dl_var target, Functor& f) { edge_id_vector & edges = m_out_edges[source]; diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index 0ec7fe0c0..7af1a87ff 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -41,7 +41,7 @@ namespace smt { } } m_step = 0; - m_tree = alloc(thread_spanning_tree, m_graph); + m_tree = alloc(basic_spanning_tree, m_graph); } template diff --git a/src/smt/spanning_tree.h b/src/smt/spanning_tree.h index f5f6b624f..bce910b87 100644 --- a/src/smt/spanning_tree.h +++ b/src/smt/spanning_tree.h @@ -25,8 +25,8 @@ Notes: namespace smt { template - class thread_spanning_tree : public spanning_tree_base, private Ext { - private: + class thread_spanning_tree : public spanning_tree_base, protected Ext { + protected: typedef dl_var node; typedef dl_edge edge; typedef dl_graph graph; @@ -57,20 +57,29 @@ namespace smt { bool is_ancestor_of(node ancestor, node child); public: - thread_spanning_tree() {}; thread_spanning_tree(graph & g); - ~thread_spanning_tree() {}; - void initialize(svector const & tree); + virtual void initialize(svector const & tree); void get_descendants(node start, svector & descendants); - void update(edge_id enter_id, edge_id leave_id); + virtual void update(edge_id enter_id, edge_id leave_id); void get_path(node start, node end, svector & path, svector & against); bool in_subtree_t2(node child); bool check_well_formed(); }; + template + class basic_spanning_tree : public thread_spanning_tree { + private: + graph * m_tree_graph; + + public: + basic_spanning_tree(graph & g); + void initialize(svector const & tree); + void update(edge_id enter_id, edge_id leave_id); + }; + } #endif diff --git a/src/smt/spanning_tree_def.h b/src/smt/spanning_tree_def.h index 281a2cf45..32b971c45 100644 --- a/src/smt/spanning_tree_def.h +++ b/src/smt/spanning_tree_def.h @@ -412,6 +412,63 @@ namespace smt { SASSERT(children.empty()); return true; } + + // Basic spanning tree + template + basic_spanning_tree::basic_spanning_tree(graph & g) : thread_spanning_tree(g) { + } + + template + void basic_spanning_tree::initialize(svector const & tree) { + unsigned num_nodes = m_graph.get_num_nodes(); + m_tree_graph = alloc(graph); + for (unsigned i = 0; i < num_nodes; ++i) { + m_tree_graph->init_var(i); + } + + vector const & es = m_graph.get_all_edges(); + svector::const_iterator it = tree.begin(), end = tree.end(); + for(; it != end; ++it) { + edge const & e = es[*it]; + m_tree_graph->add_edge(e.get_source(), e.get_target(), e.get_weight(), explanation()); + } + + node root = num_nodes - 1; + m_tree_graph->bfs_undirected(root, m_pred, m_depth); + m_tree_graph->dfs_undirected(root, m_thread); + } + + template + void basic_spanning_tree::update(edge_id enter_id, edge_id leave_id) { + if (m_tree_graph) + dealloc(m_tree_graph); + m_tree_graph = alloc(graph); + unsigned num_nodes = m_graph.get_num_nodes(); + for (unsigned i = 0; i < num_nodes; ++i) { + m_tree_graph->init_var(i); + } + + vector const & es = m_graph.get_all_edges(); + svector::const_iterator it = m_tree.begin(), end = m_tree.end(); + for(; it != end; ++it) { + edge const & e = es[*it]; + if (leave_id != *it) { + m_tree_graph->add_edge(e.get_source(), e.get_target(), e.get_weight(), explanation()); + } + } + m_tree_graph->add_edge(m_graph.get_source(enter_id), m_graph.get_target(enter_id), m_graph.get_weight(enter_id), explanation()); + + node root = num_nodes - 1; + m_tree_graph->bfs_undirected(root, m_pred, m_depth); + m_tree_graph->dfs_undirected(root, m_thread); + + for (node x = m_thread[root]; x != root; x = m_thread[x]) { + edge_id id; + VERIFY(m_graph.get_edge_id(x, m_pred[x], id)); + m_tree[x] = id; + } + } + } #endif \ No newline at end of file From 77cdb2bcde9a36ebfd15fcf392edf14706c1ba56 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 16 Nov 2013 17:01:43 -0800 Subject: [PATCH 137/925] working on pb solver Signed-off-by: Nikolaj Bjorner --- src/smt/smt_setup.cpp | 4 +- src/smt/theory_pb.cpp | 504 ++++++++++++++++++++++++------------------ src/smt/theory_pb.h | 56 ++++- 3 files changed, 343 insertions(+), 221 deletions(-) diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 90694b29a..a9fa1766e 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -32,6 +32,7 @@ Revision History: #include"theory_dl.h" #include"theory_seq_empty.h" #include"theory_card.h" +#include"theory_pb.h" namespace smt { @@ -792,7 +793,8 @@ namespace smt { } void setup::setup_card() { - m_context.register_plugin(alloc(theory_card, m_manager)); + // m_context.register_plugin(alloc(theory_card, m_manager)); + m_context.register_plugin(alloc(theory_pb, m_manager)); } void setup::setup_unknown() { diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 52d525bde..5bfc822c5 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -55,14 +55,14 @@ namespace smt { ineq* c = alloc(ineq, atom, literal(abv)); c->m_k = m_util.get_k(atom); - int& k = c->m_k; + numeral& k = c->m_k; arg_t& args = c->m_args; // extract literals and coefficients. for (unsigned i = 0; i < num_args; ++i) { expr* arg = atom->get_arg(i); literal l = compile_arg(arg); - int c = m_util.get_le_coeff(atom, i); + numeral c = m_util.get_le_coeff(atom, i); args.push_back(std::make_pair(l, c)); } // turn W <= k into -W >= -k @@ -89,23 +89,22 @@ namespace smt { // TBD: special cases: args.size() == 1 // maximal coefficient: - int& max_coeff = c->m_max_coeff; + numeral& max_coeff = c->m_max_coeff; max_coeff = 0; for (unsigned i = 0; i < args.size(); ++i) { max_coeff = std::max(max_coeff, args[i].second); } // compute watch literals: - int sum = 0; - unsigned& wsz = c->m_watch_sz; - wsz = 0; + numeral sum = 0; + unsigned wsz = 0; while (sum < k + max_coeff && wsz < args.size()) { sum += args[wsz].second; wsz++; } for (unsigned i = 0; i < wsz; ++i) { - add_watch(args[i].first, c); + add_watch(*c, i); } // pre-compile threshold for cardinality @@ -168,17 +167,40 @@ namespace smt { return negate?~literal(bv):literal(bv); } - void theory_pb::add_watch(literal l, ineq* c) { - unsigned idx = l.index(); - ptr_vector* ineqs; - if (!m_watch.find(idx, ineqs)) { - ineqs = alloc(ptr_vector); - m_watch.insert(idx, ineqs); + void theory_pb::del_watch(watch_list& watch, unsigned index, ineq& c, unsigned ineq_index) { + if (index < watch.size()) { + std::swap(watch[index], watch[watch.size()-1]); } - ineqs->push_back(c); + watch.pop_back(); + + SASSERT(ineq_index < c.watch_size()); + numeral coeff = c.coeff(ineq_index); + if (ineq_index + 1 < c.watch_size()) { + std::swap(c.m_args[ineq_index], c.m_args[c.watch_size()-1]); + } + --c.m_watch_sz; + c.m_max_sum -= coeff; + + // current index of unwatched literal is c.watch_size(). } - static unsigned gcd(unsigned a, unsigned b) { + void theory_pb::add_watch(ineq& c, unsigned i) { + bool_var v = c.lit(i).var(); + c.m_max_sum += c.coeff(i); + SASSERT(i >= c.watch_size()); + if (i > c.watch_size()) { + std::swap(c.m_args[i], c.m_args[c.watch_size()]); + } + ++c.m_watch_sz; + ptr_vector* ineqs; + if (!m_watch.find(v, ineqs)) { + ineqs = alloc(ptr_vector); + m_watch.insert(v, ineqs); + } + ineqs->push_back(&c); + } + + theory_pb::numeral theory_pb::gcd(numeral a, numeral b) { while (a != b) { if (a == 0) return b; if (b == 0) return a; @@ -193,7 +215,8 @@ namespace smt { return a; } - lbool theory_pb::normalize_ineq(arg_t& args, int& k) { + + lbool theory_pb::normalize_ineq(arg_t& args, numeral& k) { // normalize first all literals to be positive: // then we can compare them more easily. @@ -204,6 +227,18 @@ namespace smt { args[i].second = -args[i].second; } } + // remove constants + for (unsigned i = 0; i < args.size(); ++i) { + if (args[i].first == true_literal) { + k += args[i].second; + std::swap(args[i], args[args.size()-1]); + args.pop_back(); + } + else if (args[i].first == false_literal) { + std::swap(args[i], args[args.size()-1]); + args.pop_back(); + } + } // sort and coalesce arguments: std::sort(args.begin(), args.end()); for (unsigned i = 0; i + 1 < args.size(); ++i) { @@ -220,7 +255,7 @@ namespace smt { } args.resize(args.size()-1); } - } + } // // Ensure all coefficients are positive: // c*l + y >= k @@ -231,9 +266,9 @@ namespace smt { // <=> // -c*~l + y >= k - c // - unsigned sum = 0; + numeral sum = 0; for (unsigned i = 0; i < args.size(); ++i) { - int c = args[i].second; + numeral c = args[i].second; if (c < 0) { args[i].second = -c; args[i].first = ~args[i].first; @@ -247,13 +282,13 @@ namespace smt { return l_true; } // detect infeasible constraints: - if (static_cast(sum) < k) { + if (sum < k) { args.reset(); return l_false; } // Ensure the largest coefficient is not larger than k: for (unsigned i = 0; i < args.size(); ++i) { - int c = args[i].second; + numeral c = args[i].second; if (c > k) { args[i].second = k; } @@ -261,9 +296,9 @@ namespace smt { SASSERT(!args.empty()); // apply cutting plane reduction: - unsigned g = 0; + numeral g = 0; for (unsigned i = 0; g != 1 && i < args.size(); ++i) { - int c = args[i].second; + numeral c = args[i].second; if (c != k) { g = gcd(g, c); } @@ -281,12 +316,12 @@ namespace smt { // Example 5x + 5y + 2z + 2u >= 5 // becomes 3x + 3y + z + u >= 3 // - int k_new = k / g; // k_new is the ceiling of k / g. - if (gcd(k, g) != g) { + numeral k_new = k / g; + if ((k % g) != 0) { // k_new is the ceiling of k / g. k_new++; } for (unsigned i = 0; i < args.size(); ++i) { - int c = args[i].second; + numeral c = args[i].second; if (c == k) { c = k_new; } @@ -324,124 +359,9 @@ namespace smt { m_ineqs_trail.reset(); m_ineqs_lim.reset(); m_stats.reset(); + m_to_compile.reset(); } - -#if 0 - void theory_pb::propagate_assignment(ineq& c) { - if (c.m_compiled) { - return; - } - if (should_compile(c)) { - compile_ineq(c); - return; - } - context& ctx = get_context(); - ast_manager& m = get_manager(); - arg_t const& args = c.m_args; - bool_var abv = c.m_bv; - int min = c.m_current_min; - int max = c.m_current_max; - int k = c.m_k; - - TRACE("card", - tout << mk_pp(c.m_app, m) << " min: " - << min << " max: " << max << "\n";); - - // - // if min > k && abv != l_false -> force abv false - // if max <= k && abv != l_true -> force abv true - // if min == k && abv == l_true -> force positive - // unassigned literals false - // if max == k + 1 && abv == l_false -> force negative - // unassigned literals false - // - lbool aval = ctx.get_assignment(abv); - if (min > k && aval != l_false) { - literal_vector& lits = get_lits(); - int curr_min = accumulate_min(lits, c); - SASSERT(curr_min > k); - add_assign(c, lits, ~literal(abv)); - } - else if (max <= k && aval != l_true) { - literal_vector& lits = get_lits(); - int curr_max = accumulate_max(lits, c); - SASSERT(curr_max <= k); - add_assign(c, lits, literal(abv)); - } - else if (min <= k && k < min + get_max_delta(c) && aval == l_true) { - literal_vector& lits = get_lits(); - lits.push_back(~literal(abv)); - int curr_min = accumulate_min(lits, c); - if (curr_min > k) { - add_clause(c, lits); - } - else { - for (unsigned i = 0; i < args.size(); ++i) { - bool_var bv = args[i].first; - int inc = args[i].second; - if (curr_min + inc > k && inc_min(inc, ctx.get_assignment(bv)) == l_undef) { - add_assign(c, lits, literal(bv, inc > 0)); - } - } - } - } - else if (max - get_max_delta(c) <= k && k < max && aval == l_false) { - literal_vector& lits = get_lits(); - lits.push_back(literal(abv)); - int curr_max = accumulate_max(lits, c); - if (curr_max <= k) { - add_clause(c, lits); - } - else { - for (unsigned i = 0; i < args.size(); ++i) { - bool_var bv = args[i].first; - int inc = args[i].second; - if (curr_max - abs(inc) <= k && dec_max(inc, ctx.get_assignment(bv)) == l_undef) { - add_assign(c, lits, literal(bv, inc < 0)); - } - } - } - } - else if (aval == l_true) { - SASSERT(min < k); - literal_vector& lits = get_lits(); - int curr_min = accumulate_min(lits, c); - bool all_inc = curr_min == k; - unsigned num_incs = 0; - for (unsigned i = 0; all_inc && i < args.size(); ++i) { - bool_var bv = args[i].first; - int inc = args[i].second; - if (inc_min(inc, ctx.get_assignment(bv)) == l_undef) { - all_inc = inc + min > k; - num_incs++; - } - } - if (num_incs > 0) { - std::cout << "missed T propgations " << num_incs << "\n"; - } - } - else if (aval == l_false) { - literal_vector& lits = get_lits(); - lits.push_back(literal(abv)); - int curr_max = accumulate_max(lits, c); - bool all_dec = curr_max > k; - unsigned num_decs = 0; - for (unsigned i = 0; all_dec && i < args.size(); ++i) { - bool_var bv = args[i].first; - int inc = args[i].second; - if (dec_max(inc, ctx.get_assignment(bv)) == l_undef) { - all_dec = inc + max <= k; - num_decs++; - } - } - if (num_decs > 0) { - std::cout << "missed F propgations " << num_decs << "\n"; - } - } - } -#endif - void theory_pb::assign_eh(bool_var v, bool is_true) { context& ctx = get_context(); ast_manager& m = get_manager(); @@ -455,38 +375,194 @@ namespace smt { } } if (m_ineqs.find(v, c)) { - // TBD: propagate_assignment(*c); + assign_ineq(*c); } } - void theory_pb::assign_watch(bool_var v, bool is_true, watch_list& watch, unsigned index) { -#if 0 - TBD - ineq& c = *watch[i]; - c.m_sum; - unsigned w; - for (w = 0; w < c.m_watch_sz; ++i) { - if (c.m_args[w].first.var() == v) { + literal_vector& theory_pb::get_helpful_literals(ineq& c, bool negate) { + numeral sum = 0; + context& ctx = get_context(); + literal_vector& lits = get_lits(); + for (unsigned i = 0; sum < c.k() && i < c.size(); ++i) { + literal l = c.lit(i); + if (ctx.get_assignment(l) == l_true) { + sum += c.coeff(i); + if (negate) l = ~l; + lits.push_back(l); + } + } + SASSERT(sum >= c.k()); + return lits; + } + + literal_vector& theory_pb::get_unhelpful_literals(ineq& c, bool negate) { + context& ctx = get_context(); + literal_vector& lits = get_lits(); + for (unsigned i = 0; i < c.size(); ++i) { + literal l = c.lit(i); + if (ctx.get_assignment(l) == l_false) { + if (negate) l = ~l; + lits.push_back(l); + } + } + return lits; + } + + /** + \brief propagate assignment to inequality. + This is a basic, non-optimized implementation based + on the assumption that inequalities are mostly units + and/or relatively few compared to number of argumets. + */ + void theory_pb::assign_ineq(ineq& c) { + context& ctx = get_context(); + numeral sum = 0, maxsum = 0; + for (unsigned i = 0; i < c.size(); ++i) { + switch (ctx.get_assignment(c.lit(i))) { + case l_true: + sum += c.coeff(i); + // falll through + case l_undef: + maxsum += c.coeff(i); + break; + default: break; } } - SASSERT(w < c.m_watch_sz); - literal l = c.m_args[w].first; - int coeff = c.m_args[w].second; - if (is_true == !l.sign()) { - ctx.push_trail(value_trail(c.m_sum)); - c.m_sum += coeff; - // optional propagate + lbool lit_assignment = ctx.get_assignment(c.lit()); + SASSERT(lit_assignment != l_undef); + if (sum >= c.k() && lit_assignment == l_false) { + literal_vector& lits = get_helpful_literals(c, true); + lits.push_back(c.lit()); + add_clause(c, lits); + } + else if (maxsum < c.k() && lit_assignment == l_true) { + literal_vector& lits = get_unhelpful_literals(c, true); + lits.push_back(~c.lit()); + add_clause(c, lits); + } + } + + /** + \brief v is assigned in inequality c. Update current bounds and watch list. + Optimize for case where the c.lit() is True. This covers the case where + inequalities are unit literals and formulas in negation normal form + (inequalities are closed under negation). + + */ + void theory_pb::assign_watch(bool_var v, bool is_true, watch_list& watch, unsigned watch_index) { + context& ctx = get_context(); + ineq& c = *watch[watch_index]; + numeral k = c.m_k; + unsigned w = c.find_lit(v, 0, c.watch_size()); + numeral coeff = c.coeff(w); + if (is_true == c.lit(w).sign()) { + // + // sum is not increased. + // Adjust set of watched literals. + // + del_watch(watch, watch_index, c, w); + + numeral tmp_sum = c.sum(); + for (unsigned i = c.watch_size(); c.max_sum() - coeff < k + c.max_coeff() && i < c.size(); ++i) { + lbool lit_assignment = ctx.get_assignment(c.lit(i)); + switch(lit_assignment) { + case l_true: + tmp_sum += c.coeff(i); + // fall-through + case l_undef: + add_watch(c, i); + break; + case l_false: + break; + } + } + SASSERT(tmp_sum <= c.max_sum()); + if (c.max_sum() < k) { + // + // c.lit() <- false + // we have to add the previously watched literal back. + // such that the sum of watched literals has maximal sum >= k + // + + SASSERT(coeff == c.coeff(w)); + SASSERT(c.max_sum() + coeff >= k); + add_watch(c, c.find_lit(v, c.watch_size(), c.size())); + SASSERT(c.max_sum() >= k); + + switch(ctx.get_assignment(c.lit())) { + case l_false: + break; + case l_true: { + literal_vector& lits = get_unhelpful_literals(c, true); + lits.push_back(~c.lit()); + add_clause(c, lits); + break; + } + case l_undef: { + add_assign(c, get_unhelpful_literals(c, false), ~c.lit()); + break; + } + } + } + else if (tmp_sum >= k) { + // ineq should be true. + // this is handled below + } + else if (c.max_sum() - c.max_coeff() < k) { + // tmp_sum < k <= c.max_sum() + // opportunities for unit propagation for unassigned + // literals whose coefficients satisfy + // c.max_sum() - coeff < k + if (l_true == ctx.get_assignment(c.lit())) { + literal_vector& lits = get_unhelpful_literals(c, false); + for (unsigned i = 0; i < c.size(); ++i) { + if (c.max_sum() - c.coeff(i) < k && ctx.get_assignment(c.lit(i)) == l_undef) { + add_assign(c, lits, c.lit(i)); + } + } + } + } + else { + // tmp_sum < k <= c.max_sum() - c.max_coeff() + // we might miss opportunities for unit propagation if + // max_coeff is not the maximal coefficient + // of the current unassigned literal, but we can + // rely on eventually learning this from propagations. + } + } else { - unsigned deficit = c.m_max_sum - coeff; - for (unsigned i = c.m_watch_sz; i < c.m_args.size(); ++i) { - if - } - // find a different literal to watch. - ctx.push_trail(value_trail(c.m_watch_sz)); + // sum is increased the current set of watch + // literals represent a potentially feasible assignment. + // + ctx.push_trail(value_trail(c.m_sum)); + c.m_sum += coeff; } -#endif + + if (c.sum() >= k) { + lbool ineq_assignment = ctx.get_assignment(c.lit()); + switch(ineq_assignment) { + case l_true: + break; + case l_undef: { + add_assign(c, get_helpful_literals(c, false), c.lit()); + break; + } + case l_false: { + literal_vector& lits = get_helpful_literals(c, true); + lits.push_back(c.lit()); + add_clause(c, lits); + break; + } + } + } + + // else if c.sum() < k and lit(w) was assigned to true: + // Progress was made. + // The watch list contains at least enough + // literals to force the assignment. + } struct theory_pb::sort_expr { @@ -526,8 +602,12 @@ namespace smt { literal internalize(ineq& ca, expr* e) { obj_map cache; - for (unsigned i = 0; i < ca.m_args.size(); ++i) { - cache.insert(ca.m_app->get_arg(i), literal(ca.m_args[i].first)); + expr_ref_vector trail(m); + for (unsigned i = 0; i < ca.size(); ++i) { + expr_ref tmp(m); + ctx.literal2expr(ca.lit(i), tmp); + cache.insert(tmp, ca.lit(i)); + trail.push_back(tmp); } cache.insert(m.mk_false(), false_literal); cache.insert(m.mk_true(), true_literal); @@ -618,49 +698,53 @@ namespace smt { }; - bool theory_pb::should_compile(ineq& c) { -#if 1 - return false; -#else - return c.m_num_propagations > c.m_compilation_threshold; -#endif + void theory_pb::inc_propagations(ineq& c) { + ++c.m_num_propagations; + if (c.m_compiled == l_false && c.m_num_propagations > c.m_compilation_threshold) { + c.m_compiled = l_undef; + m_to_compile.push_back(&c); + } + } + + void theory_pb::restart_eh() { + for (unsigned i = 0; i < m_to_compile.size(); ++i) { + compile_ineq(*m_to_compile[i]); + } + m_to_compile.reset(); } void theory_pb::compile_ineq(ineq& c) { ++m_stats.m_num_compiles; ast_manager& m = get_manager(); context& ctx = get_context(); - app* a = c.m_app; - SASSERT(m_util.is_at_most_k(a)); - literal atmostk; - int k = m_util.get_k(a); - unsigned num_args = a->get_num_args(); + // only cardinality constraints are compiled. + SASSERT(c.m_compilation_threshold < UINT_MAX); + DEBUG_CODE(for (unsigned i = 0; i < c.size(); ++i) SASSERT(c.coeff(i) == 1); ); + unsigned k = static_cast(c.k()); + unsigned num_args = c.size(); + SASSERT(0 <= k && k <= num_args); sort_expr se(*this); - if (k >= static_cast(num_args)) { - atmostk = true_literal; + sorting_network sn(se); + expr_ref_vector in(m), out(m); + expr_ref tmp(m); + for (unsigned i = 0; i < num_args; ++i) { + ctx.literal2expr(c.lit(i), tmp); + in.push_back(tmp); } - else if (k < 0) { - atmostk = false_literal; - } - else { - sorting_network sn(se); - expr_ref_vector in(m), out(m); - for (unsigned i = 0; i < num_args; ++i) { - in.push_back(c.m_app->get_arg(i)); - } - sn(in, out); - atmostk = ~se.internalize(c, out[k].get()); // k'th output is 0. - TRACE("card", tout << "~atmost: " << mk_pp(out[k].get(), m) << "\n";); - } - literal thl = c.m_lit; - se.add_clause(~thl, atmostk); - se.add_clause(thl, ~atmostk); - TRACE("card", tout << mk_pp(a, m) << "\n";); + sn(in, out); + literal at_least_k = se.internalize(c, out[k-1].get()); // first k outputs are 1. + TRACE("card", tout << "at_least: " << mk_pp(out[k-1].get(), m) << "\n";); + + literal thl = c.lit(); + se.add_clause(~thl, at_least_k); + se.add_clause(thl, ~at_least_k); + TRACE("card", tout << mk_pp(c.m_app, m) << "\n";); // auxiliary clauses get removed when popping scopes. // we have to recompile the circuit after back-tracking. - ctx.push_trail(value_trail(c.m_compiled)); - c.m_compiled = true; + c.m_compiled = l_false; + ctx.push_trail(value_trail(c.m_compiled)); + c.m_compiled = l_true; } @@ -685,16 +769,16 @@ namespace smt { std::ostream& theory_pb::display(std::ostream& out, ineq& c) const { ast_manager& m = get_manager(); out << mk_pp(c.m_app, m) << "\n"; - for (unsigned i = 0; i < c.m_args.size(); ++i) { - out << c.m_args[i].second << "*" << c.m_args[i].first; - if (i + 1 < c.m_args.size()) { + for (unsigned i = 0; i < c.size(); ++i) { + out << c.coeff(i) << "*" << c.lit(i); + if (i + 1 < c.size()) { out << " + "; } } out << " >= " << c.m_k << "\n" << "propagations: " << c.m_num_propagations - << " max_coeff: " << c.m_max_coeff - << " watch size: " << c.m_watch_sz + << " max_coeff: " << c.max_coeff() + << " watch size: " << c.watch_size() << "\n"; return out; } @@ -706,20 +790,18 @@ namespace smt { } void theory_pb::add_assign(ineq& c, literal_vector const& lits, literal l) { - literal_vector ls; - ++c.m_num_propagations; + inc_propagations(c); m_stats.m_num_propagations++; context& ctx = get_context(); - for (unsigned i = 0; i < lits.size(); ++i) { - ls.push_back(~lits[i]); - } - ctx.assign(l, ctx.mk_justification(theory_propagation_justification(get_id(), ctx.get_region(), ls.size(), ls.c_ptr(), l))); + ctx.assign(l, ctx.mk_justification( + theory_propagation_justification( + get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), l))); } void theory_pb::add_clause(ineq& c, literal_vector const& lits) { - ++c.m_num_propagations; + inc_propagations(c); m_stats.m_num_axioms++; context& ctx = get_context(); TRACE("card", tout << "#prop:" << c.m_num_propagations << " - "; ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";); diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 5fb66f3f4..d74909e4b 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -28,7 +28,8 @@ namespace smt { class theory_pb : public theory { struct sort_expr; - typedef svector > arg_t; + typedef int64 numeral; + typedef svector > arg_t; struct stats { unsigned m_num_axioms; @@ -44,24 +45,52 @@ namespace smt { app* m_app; literal m_lit; // literal repesenting predicate arg_t m_args; // encode args[0]*coeffs[0]+...+args[n-1]*coeffs[n-1] >= m_k; - int m_k; // invariants: m_k > 0, coeffs[i] > 0 + numeral m_k; // invariants: m_k > 0, coeffs[i] > 0 // Watch the first few positions until the sum satisfies: // sum coeffs[i] >= m_lower + max_coeff - int m_max_coeff; // maximal coefficient. + numeral m_max_coeff; // maximal coefficient. unsigned m_watch_sz; // number of literals being watched. + numeral m_sum; // sum of coefficients so far. + numeral m_max_sum; // maximal sum of watch literals. unsigned m_num_propagations; unsigned m_compilation_threshold; - bool m_compiled; + lbool m_compiled; ineq(app* a, literal l): m_app(a), - m_lit(l), + m_lit(l), + m_max_coeff(0), + m_watch_sz(0), + m_sum(0), + m_max_sum(0), m_num_propagations(0), m_compilation_threshold(UINT_MAX), - m_compiled(false) + m_compiled(l_false) {} + + literal lit() const { return m_lit; } + numeral const & k() const { return m_k; } + + literal lit(unsigned i) const { return m_args[i].first; } + numeral const & coeff(unsigned i) const { return m_args[i].second; } + + unsigned size() const { return m_args.size(); } + + numeral const& sum() const { return m_sum; } + numeral const& max_sum() const { return m_max_sum; } + numeral const& max_coeff() const { return m_max_coeff; } + + unsigned watch_size() const { return m_watch_sz; } + + unsigned find_lit(bool_var v, unsigned begin, unsigned end) { + while (lit(begin).var() != v) { + ++begin; + SASSERT(begin < end); + } + return begin; + } }; typedef ptr_vector watch_list; @@ -73,12 +102,16 @@ namespace smt { literal_vector m_literals; // temporary vector card_util m_util; stats m_stats; + ptr_vector m_to_compile; // inequalities to compile. // internalize_atom: - lbool normalize_ineq(arg_t& args, int& k); + lbool normalize_ineq(arg_t& args, numeral& k); + static numeral gcd(numeral a, numeral b); literal compile_arg(expr* arg); - void add_watch(literal l, ineq* c); + void add_watch(ineq& c, unsigned index); + void del_watch(watch_list& watch, unsigned index, ineq& c, unsigned ineq_index); void assign_watch(bool_var v, bool is_true, watch_list& watch, unsigned index); + void assign_ineq(ineq& c); std::ostream& display(std::ostream& out, ineq& c) const; @@ -86,12 +119,15 @@ namespace smt { void add_assign(ineq& c, literal_vector const& lits, literal l); literal_vector& get_lits(); + literal_vector& get_helpful_literals(ineq& c, bool negate); + literal_vector& get_unhelpful_literals(ineq& c, bool negate); + // // Utilities to compile cardinality // constraints into a sorting network. // void compile_ineq(ineq& c); - bool should_compile(ineq& c); + void inc_propagations(ineq& c); unsigned get_compilation_threshold(ineq& c); public: theory_pb(ast_manager& m); @@ -112,7 +148,9 @@ namespace smt { virtual void init_search_eh(); virtual void push_scope_eh(); virtual void pop_scope_eh(unsigned num_scopes); + virtual void restart_eh(); virtual void collect_statistics(::statistics & st) const; + }; }; From f6c5088cc998d1bdace445c7de8907fbcceef7ea Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 16 Nov 2013 21:05:33 -0800 Subject: [PATCH 138/925] pb theory Signed-off-by: Nikolaj Bjorner --- src/smt/tactic/smt_tactic.cpp | 1 - src/smt/theory_pb.cpp | 140 ++++++++++++++++++++++++++-------- src/smt/theory_pb.h | 5 +- 3 files changed, 112 insertions(+), 34 deletions(-) diff --git a/src/smt/tactic/smt_tactic.cpp b/src/smt/tactic/smt_tactic.cpp index 0fdde612d..95b150a8c 100644 --- a/src/smt/tactic/smt_tactic.cpp +++ b/src/smt/tactic/smt_tactic.cpp @@ -135,7 +135,6 @@ public: proof_converter_ref & pc, expr_dependency_ref & core) { try { - IF_VERBOSE(0, verbose_stream() << "(smt.smt-tactic using the old SAT solver)\n";); SASSERT(in->is_well_sorted()); ast_manager & m = in->m(); TRACE("smt_tactic", tout << this << "\nAUTO_CONFIG: " << fparams().m_auto_config << " HIDIV0: " << fparams().m_hi_div0 << " " diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 5bfc822c5..4fe8e5d2f 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -52,6 +52,7 @@ namespace smt { SASSERT(!ctx.b_internalized(atom)); bool_var abv = ctx.mk_bool_var(atom); + ctx.set_var_theory(abv, get_id()); ineq* c = alloc(ineq, atom, literal(abv)); c->m_k = m_util.get_k(atom); @@ -119,7 +120,7 @@ namespace smt { n *= 2; } c->m_compilation_threshold = args.size()*log; - TRACE("card", tout << "threshold:" << (args.size()*log) << "\n";); + TRACE("card", tout << "compilation threshold: " << (args.size()*log) << "\n";); } else { c->m_compilation_threshold = UINT_MAX; @@ -364,19 +365,22 @@ namespace smt { void theory_pb::assign_eh(bool_var v, bool is_true) { context& ctx = get_context(); - ast_manager& m = get_manager(); ptr_vector* ineqs = 0; - ineq* c = 0; - TRACE("card", tout << "assign: " << mk_pp(ctx.bool_var2expr(v), m) << " <- " << is_true << "\n";); + TRACE("card", tout << "assign: " << literal(v, !is_true) << "\n";); if (m_watch.find(v, ineqs)) { for (unsigned i = 0; i < ineqs->size(); ++i) { - assign_watch(v, is_true, *ineqs, i); + if (assign_watch(v, is_true, *ineqs, i)) { + // i was removed from watch list. + --i; + } } } + ineq* c = 0; if (m_ineqs.find(v, c)) { - assign_ineq(*c); + assign_ineq(*c, is_true); } + TRACE("card", display(tout);); } literal_vector& theory_pb::get_helpful_literals(ineq& c, bool negate) { @@ -414,7 +418,8 @@ namespace smt { on the assumption that inequalities are mostly units and/or relatively few compared to number of argumets. */ - void theory_pb::assign_ineq(ineq& c) { + void theory_pb::assign_ineq(ineq& c, bool is_true) { + context& ctx = get_context(); numeral sum = 0, maxsum = 0; for (unsigned i = 0; i < c.size(); ++i) { @@ -430,13 +435,17 @@ namespace smt { } } lbool lit_assignment = ctx.get_assignment(c.lit()); - SASSERT(lit_assignment != l_undef); - if (sum >= c.k() && lit_assignment == l_false) { + + TRACE("card", + tout << "assign: " << c.lit() << " <- " << is_true << "\n"; + display(tout, c); ); + + if (sum >= c.k() && !is_true) { literal_vector& lits = get_helpful_literals(c, true); lits.push_back(c.lit()); add_clause(c, lits); } - else if (maxsum < c.k() && lit_assignment == l_true) { + else if (maxsum < c.k() && is_true) { literal_vector& lits = get_unhelpful_literals(c, true); lits.push_back(~c.lit()); add_clause(c, lits); @@ -450,21 +459,25 @@ namespace smt { (inequalities are closed under negation). */ - void theory_pb::assign_watch(bool_var v, bool is_true, watch_list& watch, unsigned watch_index) { + bool theory_pb::assign_watch(bool_var v, bool is_true, watch_list& watch, unsigned watch_index) { + bool removed = false; context& ctx = get_context(); ineq& c = *watch[watch_index]; numeral k = c.m_k; unsigned w = c.find_lit(v, 0, c.watch_size()); numeral coeff = c.coeff(w); + TRACE("card", + tout << "assign: " << literal(v) << " <- " << is_true << "\n"; + display(tout, c); ); + if (is_true == c.lit(w).sign()) { // // sum is not increased. // Adjust set of watched literals. // - del_watch(watch, watch_index, c, w); numeral tmp_sum = c.sum(); - for (unsigned i = c.watch_size(); c.max_sum() - coeff < k + c.max_coeff() && i < c.size(); ++i) { + for (unsigned i = c.watch_size(); c.max_sum() < k + c.max_coeff() + coeff && i < c.size(); ++i) { lbool lit_assignment = ctx.get_assignment(c.lit(i)); switch(lit_assignment) { case l_true: @@ -477,19 +490,17 @@ namespace smt { break; } } + if (c.max_sum() >= k + coeff) { + del_watch(watch, watch_index, c, w); + SASSERT(c.max_sum() >= k); + removed = true; + } SASSERT(tmp_sum <= c.max_sum()); + TRACE("card", tout << "tmp_sum: " << tmp_sum << "\n"; display(tout, c); ); if (c.max_sum() < k) { // // c.lit() <- false - // we have to add the previously watched literal back. - // such that the sum of watched literals has maximal sum >= k // - - SASSERT(coeff == c.coeff(w)); - SASSERT(c.max_sum() + coeff >= k); - add_watch(c, c.find_lit(v, c.watch_size(), c.size())); - SASSERT(c.max_sum() >= k); - switch(ctx.get_assignment(c.lit())) { case l_false: break; @@ -506,24 +517,44 @@ namespace smt { } } else if (tmp_sum >= k) { - // ineq should be true. - // this is handled below + // + // c.lit() <- true + // + switch(ctx.get_assignment(c.lit())) { + case l_true: + break; + case l_false: { + literal_vector& lits = get_helpful_literals(c, true); + lits.push_back(c.lit()); + add_clause(c, lits); + break; + } + case l_undef: { + add_assign(c, get_helpful_literals(c, false), c.lit()); + break; + } + } } - else if (c.max_sum() - c.max_coeff() < k) { + else if (c.max_sum() < k + c.max_coeff()) { // tmp_sum < k <= c.max_sum() // opportunities for unit propagation for unassigned // literals whose coefficients satisfy // c.max_sum() - coeff < k + if (l_true == ctx.get_assignment(c.lit())) { - literal_vector& lits = get_unhelpful_literals(c, false); + literal_vector& lits = get_unhelpful_literals(c, true); + lits.push_back(c.lit()); + numeral max_sum = c.max_sum() - coeff; for (unsigned i = 0; i < c.size(); ++i) { - if (c.max_sum() - c.coeff(i) < k && ctx.get_assignment(c.lit(i)) == l_undef) { + if (max_sum - c.coeff(i) < k && ctx.get_assignment(c.lit(i)) == l_undef) { add_assign(c, lits, c.lit(i)); } } } } else { + // c.max_sum() >= k + c.max_coeff() + // tmp_sum < k <= c.max_sum() - c.max_coeff() // we might miss opportunities for unit propagation if // max_coeff is not the maximal coefficient @@ -562,7 +593,8 @@ namespace smt { // Progress was made. // The watch list contains at least enough // literals to force the assignment. - + + return removed; } struct theory_pb::sort_expr { @@ -759,13 +791,45 @@ namespace smt { void theory_pb::pop_scope_eh(unsigned num_scopes) { unsigned sz = m_ineqs_lim[m_ineqs_lim.size()-num_scopes]; while (m_ineqs_trail.size() > sz) { - SASSERT(m_ineqs.contains(m_ineqs_trail.back())); - m_ineqs.remove(m_ineqs_trail.back()); - m_ineqs_trail.pop_back(); + bool_var v = m_ineqs_trail.back(); + ineq* c = 0; + VERIFY(m_ineqs.find(v, c)); + m_ineqs.remove(v); + m_ineqs_trail.pop_back(); + for (unsigned i = 0; i < c->watch_size(); ++i) { + bool_var w = c->lit(i).var(); + ptr_vector* ineqs = 0; + VERIFY(m_watch.find(w, ineqs)); + for (unsigned j = 0; j < ineqs->size(); ++j) { + if ((*ineqs)[j] == c) { + std::swap((*ineqs)[j],(*ineqs)[ineqs->size()-1]); + ineqs->pop_back(); + break; + } + } + } + dealloc(c); } m_ineqs_lim.resize(m_ineqs_lim.size()-num_scopes); } + void theory_pb::display(std::ostream& out) const { + u_map*>::iterator it = m_watch.begin(), end = m_watch.end(); + for (; it != end; ++it) { + out << "watch: " << literal(it->m_key) << " |-> "; + watch_list const& wl = *it->m_value; + for (unsigned i = 0; i < wl.size(); ++i) { + out << wl[i]->lit() << " "; + } + out << "\n"; + } + u_map::iterator itc = m_ineqs.begin(), endc = m_ineqs.end(); + for (; itc != endc; ++itc) { + ineq& c = *itc->m_value; + display(out, c); + } + } + std::ostream& theory_pb::display(std::ostream& out, ineq& c) const { ast_manager& m = get_manager(); out << mk_pp(c.m_app, m) << "\n"; @@ -779,6 +843,8 @@ namespace smt { << "propagations: " << c.m_num_propagations << " max_coeff: " << c.max_coeff() << " watch size: " << c.watch_size() + << " sum: " << c.sum() + << " max-sum: " << c.max_sum() << "\n"; return out; } @@ -793,6 +859,13 @@ namespace smt { inc_propagations(c); m_stats.m_num_propagations++; context& ctx = get_context(); + TRACE("card", tout << "#prop:" << c.m_num_propagations << " - "; + for (unsigned i = 0; i < lits.size(); ++i) { + tout << lits[i] << " "; + } + tout << "=> " << l << "\n"; + display(tout, c);); + ctx.assign(l, ctx.mk_justification( theory_propagation_justification( get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), l))); @@ -804,7 +877,12 @@ namespace smt { inc_propagations(c); m_stats.m_num_axioms++; context& ctx = get_context(); - TRACE("card", tout << "#prop:" << c.m_num_propagations << " - "; ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";); + TRACE("card", tout << "#prop:" << c.m_num_propagations << " - "; + for (unsigned i = 0; i < lits.size(); ++i) { + tout << lits[i] << " "; + } + tout << "\n"; + display(tout, c);); justification* js = 0; ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); IF_VERBOSE(2, ctx.display_literals_verbose(verbose_stream(), diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index d74909e4b..3c992b051 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -110,10 +110,11 @@ namespace smt { literal compile_arg(expr* arg); void add_watch(ineq& c, unsigned index); void del_watch(watch_list& watch, unsigned index, ineq& c, unsigned ineq_index); - void assign_watch(bool_var v, bool is_true, watch_list& watch, unsigned index); - void assign_ineq(ineq& c); + bool assign_watch(bool_var v, bool is_true, watch_list& watch, unsigned index); + void assign_ineq(ineq& c, bool is_true); std::ostream& display(std::ostream& out, ineq& c) const; + virtual void display(std::ostream& out) const; void add_clause(ineq& c, literal_vector const& lits); void add_assign(ineq& c, literal_vector const& lits, literal l); From f3721e5a1546a18f8583e694e52111bbad0e7988 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 17 Nov 2013 10:39:33 -0800 Subject: [PATCH 139/925] pb theory Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 301 +++++++++++++++++++----------------------- src/smt/theory_pb.h | 10 +- 2 files changed, 144 insertions(+), 167 deletions(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 4fe8e5d2f..4af6f1f0f 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -22,8 +22,38 @@ Notes: #include "smt_context.h" #include "ast_pp.h" #include "sorting_network.h" +#include "uint_set.h" namespace smt { + + void theory_pb::ineq::negate() { + m_lit.neg(); + numeral sum = 0; + for (unsigned i = 0; i < size(); ++i) { + m_args[i].first.neg(); + sum += coeff(i); + } + m_k = sum - m_k + 1; + SASSERT(well_formed()); + } + + bool theory_pb::ineq::well_formed() const { + SASSERT(k() > 0); + uint_set vars; + numeral sum = 0; + for (unsigned i = 0; i < size(); ++i) { + SASSERT(coeff(i) <= k()); + SASSERT(1 <= coeff(i)); + SASSERT(lit(i) != true_literal); + SASSERT(lit(i) != false_literal); + SASSERT(lit(i) != null_literal); + SASSERT(!vars.contains(lit(i).var())); + vars.insert(lit(i).var()); + sum += coeff(i); + } + SASSERT(sum >= k()); + return true; + } theory_pb::theory_pb(ast_manager& m): theory(m.mk_family_id("card")), @@ -54,7 +84,7 @@ namespace smt { bool_var abv = ctx.mk_bool_var(atom); ctx.set_var_theory(abv, get_id()); - ineq* c = alloc(ineq, atom, literal(abv)); + ineq* c = alloc(ineq, literal(abv)); c->m_k = m_util.get_k(atom); numeral& k = c->m_k; arg_t& args = c->m_args; @@ -96,17 +126,6 @@ namespace smt { max_coeff = std::max(max_coeff, args[i].second); } - // compute watch literals: - numeral sum = 0; - unsigned wsz = 0; - while (sum < k + max_coeff && wsz < args.size()) { - sum += args[wsz].second; - wsz++; - } - - for (unsigned i = 0; i < wsz; ++i) { - add_watch(*c, i); - } // pre-compile threshold for cardinality bool is_cardinality = true; @@ -359,6 +378,8 @@ namespace smt { m_ineqs.reset(); m_ineqs_trail.reset(); m_ineqs_lim.reset(); + m_assign_ineqs_trail.reset(); + m_assign_ineqs_lim.reset(); m_stats.reset(); m_to_compile.reset(); } @@ -420,36 +441,38 @@ namespace smt { */ void theory_pb::assign_ineq(ineq& c, bool is_true) { + if (c.lit().sign() == is_true) { + c.negate(); + } + context& ctx = get_context(); - numeral sum = 0, maxsum = 0; + numeral maxsum = 0; for (unsigned i = 0; i < c.size(); ++i) { - switch (ctx.get_assignment(c.lit(i))) { - case l_true: - sum += c.coeff(i); - // falll through - case l_undef: + if (ctx.get_assignment(c.lit(i)) != l_false) { maxsum += c.coeff(i); - break; - default: - break; } } - lbool lit_assignment = ctx.get_assignment(c.lit()); TRACE("card", tout << "assign: " << c.lit() << " <- " << is_true << "\n"; display(tout, c); ); - if (sum >= c.k() && !is_true) { - literal_vector& lits = get_helpful_literals(c, true); - lits.push_back(c.lit()); - add_clause(c, lits); - } - else if (maxsum < c.k() && is_true) { + if (maxsum < c.k()) { literal_vector& lits = get_unhelpful_literals(c, true); lits.push_back(~c.lit()); add_clause(c, lits); + return; } + + c.m_max_sum = 0; + c.m_watch_sz = 0; + for (unsigned i = 0; c.max_sum() < c.k() + c.max_coeff() && i < c.size(); ++i) { + if (ctx.get_assignment(c.lit(i)) != l_false) { + add_watch(c, i); + } + } + SASSERT(c.max_sum() >= c.k()); + m_assign_ineqs_trail.push_back(&c); } /** @@ -463,136 +486,70 @@ namespace smt { bool removed = false; context& ctx = get_context(); ineq& c = *watch[watch_index]; - numeral k = c.m_k; unsigned w = c.find_lit(v, 0, c.watch_size()); - numeral coeff = c.coeff(w); + + SASSERT(ctx.get_assignment(c.lit()) == l_true); + + if (is_true == c.lit(w).sign()) { + // + // max_sum is decreased. + // Adjust set of watched literals. + // + + numeral k = c.k(); + del_watch(watch, watch_index, c, w); + removed = true; + + for (unsigned i = c.watch_size(); c.max_sum() < k + c.max_coeff() && i < c.size(); ++i) { + if (ctx.get_assignment(c.lit(i)) != l_false) { + add_watch(c, i); + } + } + + if (c.max_sum() < k) { + // + // L: 3*x1 + 2*x2 + x4 >= 3, but x1 <- 0, x2 <- 0 + // create clause x1 or x2 or ~L + // + literal_vector& lits = get_unhelpful_literals(c, false); + lits.push_back(~c.lit()); + add_clause(c, lits); + } + else if (c.max_sum() < k + c.max_coeff()) { + // + // opportunities for unit propagation for unassigned + // literals whose coefficients satisfy + // c.max_sum() - coeff < k + // + // L: 3*x1 + 2*x2 + x4 >= 3, but x1 <- 0 + // Create clauses x1 or ~L or x2 + // x1 or ~L or x4 + // + + literal_vector& lits = get_unhelpful_literals(c, true); + lits.push_back(c.lit()); + for (unsigned i = 0; i < c.size(); ++i) { + if (c.max_sum() - c.coeff(i) < k && ctx.get_assignment(c.lit(i)) == l_undef) { + add_assign(c, lits, c.lit(i)); + } + } + } + // + // else: c.max_sum() >= k + c.max_coeff() + // we might miss opportunities for unit propagation if + // max_coeff is not the maximal coefficient + // of the current unassigned literal, but we can + // rely on eventually learning this from propagations. + // + } + + // + // else: the current set of watch remain a potentially feasible assignment. + // TRACE("card", tout << "assign: " << literal(v) << " <- " << is_true << "\n"; display(tout, c); ); - if (is_true == c.lit(w).sign()) { - // - // sum is not increased. - // Adjust set of watched literals. - // - - numeral tmp_sum = c.sum(); - for (unsigned i = c.watch_size(); c.max_sum() < k + c.max_coeff() + coeff && i < c.size(); ++i) { - lbool lit_assignment = ctx.get_assignment(c.lit(i)); - switch(lit_assignment) { - case l_true: - tmp_sum += c.coeff(i); - // fall-through - case l_undef: - add_watch(c, i); - break; - case l_false: - break; - } - } - if (c.max_sum() >= k + coeff) { - del_watch(watch, watch_index, c, w); - SASSERT(c.max_sum() >= k); - removed = true; - } - SASSERT(tmp_sum <= c.max_sum()); - TRACE("card", tout << "tmp_sum: " << tmp_sum << "\n"; display(tout, c); ); - if (c.max_sum() < k) { - // - // c.lit() <- false - // - switch(ctx.get_assignment(c.lit())) { - case l_false: - break; - case l_true: { - literal_vector& lits = get_unhelpful_literals(c, true); - lits.push_back(~c.lit()); - add_clause(c, lits); - break; - } - case l_undef: { - add_assign(c, get_unhelpful_literals(c, false), ~c.lit()); - break; - } - } - } - else if (tmp_sum >= k) { - // - // c.lit() <- true - // - switch(ctx.get_assignment(c.lit())) { - case l_true: - break; - case l_false: { - literal_vector& lits = get_helpful_literals(c, true); - lits.push_back(c.lit()); - add_clause(c, lits); - break; - } - case l_undef: { - add_assign(c, get_helpful_literals(c, false), c.lit()); - break; - } - } - } - else if (c.max_sum() < k + c.max_coeff()) { - // tmp_sum < k <= c.max_sum() - // opportunities for unit propagation for unassigned - // literals whose coefficients satisfy - // c.max_sum() - coeff < k - - if (l_true == ctx.get_assignment(c.lit())) { - literal_vector& lits = get_unhelpful_literals(c, true); - lits.push_back(c.lit()); - numeral max_sum = c.max_sum() - coeff; - for (unsigned i = 0; i < c.size(); ++i) { - if (max_sum - c.coeff(i) < k && ctx.get_assignment(c.lit(i)) == l_undef) { - add_assign(c, lits, c.lit(i)); - } - } - } - } - else { - // c.max_sum() >= k + c.max_coeff() - - // tmp_sum < k <= c.max_sum() - c.max_coeff() - // we might miss opportunities for unit propagation if - // max_coeff is not the maximal coefficient - // of the current unassigned literal, but we can - // rely on eventually learning this from propagations. - } - - } - else { - // sum is increased the current set of watch - // literals represent a potentially feasible assignment. - // - ctx.push_trail(value_trail(c.m_sum)); - c.m_sum += coeff; - } - - if (c.sum() >= k) { - lbool ineq_assignment = ctx.get_assignment(c.lit()); - switch(ineq_assignment) { - case l_true: - break; - case l_undef: { - add_assign(c, get_helpful_literals(c, false), c.lit()); - break; - } - case l_false: { - literal_vector& lits = get_helpful_literals(c, true); - lits.push_back(c.lit()); - add_clause(c, lits); - break; - } - } - } - - // else if c.sum() < k and lit(w) was assigned to true: - // Progress was made. - // The watch list contains at least enough - // literals to force the assignment. return removed; } @@ -771,7 +728,7 @@ namespace smt { literal thl = c.lit(); se.add_clause(~thl, at_least_k); se.add_clause(thl, ~at_least_k); - TRACE("card", tout << mk_pp(c.m_app, m) << "\n";); + TRACE("card", tout << c.lit() << "\n";); // auxiliary clauses get removed when popping scopes. // we have to recompile the circuit after back-tracking. c.m_compiled = l_false; @@ -781,21 +738,21 @@ namespace smt { void theory_pb::init_search_eh() { - + m_to_compile.reset(); } void theory_pb::push_scope_eh() { m_ineqs_lim.push_back(m_ineqs_trail.size()); + m_assign_ineqs_lim.push_back(m_assign_ineqs_trail.size()); } void theory_pb::pop_scope_eh(unsigned num_scopes) { - unsigned sz = m_ineqs_lim[m_ineqs_lim.size()-num_scopes]; - while (m_ineqs_trail.size() > sz) { - bool_var v = m_ineqs_trail.back(); - ineq* c = 0; - VERIFY(m_ineqs.find(v, c)); - m_ineqs.remove(v); - m_ineqs_trail.pop_back(); + + // remove watched literals. + unsigned new_lim = m_assign_ineqs_lim.size()-num_scopes; + unsigned sz = m_assign_ineqs_lim[new_lim]; + while (m_assign_ineqs_trail.size() > sz) { + ineq* c = m_assign_ineqs_trail.back(); for (unsigned i = 0; i < c->watch_size(); ++i) { bool_var w = c->lit(i).var(); ptr_vector* ineqs = 0; @@ -808,9 +765,22 @@ namespace smt { } } } + m_assign_ineqs_trail.pop_back(); + } + m_assign_ineqs_lim.resize(new_lim); + + // remove inequalities. + new_lim = m_ineqs_lim.size()-num_scopes; + sz = m_ineqs_lim[new_lim]; + while (m_ineqs_trail.size() > sz) { + bool_var v = m_ineqs_trail.back(); + ineq* c = 0; + VERIFY(m_ineqs.find(v, c)); + m_ineqs.remove(v); + m_ineqs_trail.pop_back(); dealloc(c); } - m_ineqs_lim.resize(m_ineqs_lim.size()-num_scopes); + m_ineqs_lim.resize(new_lim); } void theory_pb::display(std::ostream& out) const { @@ -832,7 +802,10 @@ namespace smt { std::ostream& theory_pb::display(std::ostream& out, ineq& c) const { ast_manager& m = get_manager(); - out << mk_pp(c.m_app, m) << "\n"; + context& ctx = get_context(); + expr_ref tmp(m); + ctx.literal2expr(c.lit(), tmp); + out << tmp << "\n"; for (unsigned i = 0; i < c.size(); ++i) { out << c.coeff(i) << "*" << c.lit(i); if (i + 1 < c.size()) { diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 3c992b051..b27da52ca 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -42,7 +42,6 @@ namespace smt { struct ineq { - app* m_app; literal m_lit; // literal repesenting predicate arg_t m_args; // encode args[0]*coeffs[0]+...+args[n-1]*coeffs[n-1] >= m_k; numeral m_k; // invariants: m_k > 0, coeffs[i] > 0 @@ -58,8 +57,7 @@ namespace smt { unsigned m_compilation_threshold; lbool m_compiled; - ineq(app* a, literal l): - m_app(a), + ineq(literal l): m_lit(l), m_max_coeff(0), m_watch_sz(0), @@ -91,6 +89,10 @@ namespace smt { } return begin; } + + void negate(); + + bool well_formed() const; }; typedef ptr_vector watch_list; @@ -99,6 +101,8 @@ namespace smt { u_map m_ineqs; // per inequality. unsigned_vector m_ineqs_trail; unsigned_vector m_ineqs_lim; + ptr_vector m_assign_ineqs_trail; + unsigned_vector m_assign_ineqs_lim; literal_vector m_literals; // temporary vector card_util m_util; stats m_stats; From 8cb959127f79a860bcfbe3da10ce76a0d1ae3dba Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 17 Nov 2013 10:41:15 -0800 Subject: [PATCH 140/925] pb theory Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 4af6f1f0f..d6fe7e5db 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -444,6 +444,7 @@ namespace smt { if (c.lit().sign() == is_true) { c.negate(); } + SASSERT(c.well_formed()); context& ctx = get_context(); numeral maxsum = 0; From 50cc852112f79b1473062d1eef34584daf6325ac Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 17 Nov 2013 20:15:24 -0800 Subject: [PATCH 141/925] working on pb Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.h | 4 + src/smt/smt_justification.h | 2 + src/smt/theory_pb.cpp | 484 +++++++++++++++++++++++++----------- src/smt/theory_pb.h | 37 +-- 4 files changed, 366 insertions(+), 161 deletions(-) diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 7940b17be..aed164570 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -332,6 +332,10 @@ namespace smt { return get_assignment(literal(v)); } + literal_vector const & assigned_literals() const { + return m_assigned_literals; + } + lbool get_assignment(expr * n) const; // Similar to get_assignment, but returns l_undef if n is not internalized. diff --git a/src/smt/smt_justification.h b/src/smt/smt_justification.h index 4f402daf2..ba306ba73 100644 --- a/src/smt/smt_justification.h +++ b/src/smt/smt_justification.h @@ -225,6 +225,7 @@ namespace smt { virtual proof * mk_proof(conflict_resolution & cr) = 0; virtual char const * get_name() const { return "simple"; } + }; class simple_theory_justification : public simple_justification { @@ -274,6 +275,7 @@ namespace smt { virtual char const * get_name() const { return "theory-propagation"; } + }; class theory_conflict_justification : public simple_theory_justification { diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index d6fe7e5db..c42010a4f 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -37,6 +37,156 @@ namespace smt { SASSERT(well_formed()); } + void theory_pb::ineq::reset() { + m_max_coeff = 0; + m_watch_sz = 0; + m_sum = 0; + m_max_sum = 0; + m_num_propagations = 0; + m_compilation_threshold = UINT_MAX; + m_compiled = l_false; + m_args.reset(); + m_k = 0; + } + + theory_pb::numeral theory_pb::ineq::gcd(numeral a, numeral b) { + while (a != b) { + if (a == 0) return b; + if (b == 0) return a; + SASSERT(a != 0 && b != 0); + if (a < b) { + b %= a; + } + else { + a %= b; + } + } + return a; + } + + lbool theory_pb::ineq::normalize() { + + numeral& k = m_k; + arg_t& args = m_args; + + // normalize first all literals to be positive: + // then we can compare them more easily. + for (unsigned i = 0; i < size(); ++i) { + if (lit(i).sign()) { + args[i].first.neg(); + k -= coeff(i); + args[i].second = -coeff(i); + } + } + // remove constants + for (unsigned i = 0; i < size(); ++i) { + if (lit(i) == true_literal) { + k += coeff(i); + std::swap(args[i], args[size()-1]); + args.pop_back(); + } + else if (lit(i) == false_literal) { + std::swap(args[i], args[size()-1]); + args.pop_back(); + } + } + // sort and coalesce arguments: + std::sort(args.begin(), args.end()); + for (unsigned i = 0; i + 1 < size(); ++i) { + if (lit(i) == args[i+1].first) { + args[i].second += coeff(i+1); + for (unsigned j = i+1; j + 1 < size(); ++j) { + args[j] = args[j+1]; + } + args.pop_back(); + } + if (coeff(i) == 0) { + for (unsigned j = i; j + 1 < size(); ++j) { + args[j] = args[j+1]; + } + args.pop_back(); + } + } + // + // Ensure all coefficients are positive: + // c*l + y >= k + // <=> + // c*(1-~l) + y >= k + // <=> + // c - c*~l + y >= k + // <=> + // -c*~l + y >= k - c + // + numeral sum = 0; + for (unsigned i = 0; i < size(); ++i) { + numeral c = coeff(i); + if (c < 0) { + args[i].second = -c; + args[i].first = ~lit(i); + k -= c; + } + sum += coeff(i); + } + // detect tautologies: + if (k <= 0) { + args.reset(); + return l_true; + } + // detect infeasible constraints: + if (sum < k) { + args.reset(); + return l_false; + } + // Ensure the largest coefficient is not larger than k: + for (unsigned i = 0; i < size(); ++i) { + numeral c = coeff(i); + if (c > k) { + args[i].second = k; + } + } + SASSERT(!args.empty()); + + // apply cutting plane reduction: + numeral g = 0; + for (unsigned i = 0; g != 1 && i < size(); ++i) { + numeral c = coeff(i); + if (c != k) { + g = gcd(g, c); + } + } + if (g == 0) { + // all coefficients are equal to k. + for (unsigned i = 0; i < size(); ++i) { + SASSERT(coeff(i) == k); + args[i].second = 1; + } + k = 1; + } + else if (g > 1) { + // + // Example 5x + 5y + 2z + 2u >= 5 + // becomes 3x + 3y + z + u >= 3 + // + numeral k_new = k / g; + if ((k % g) != 0) { // k_new is the ceiling of k / g. + k_new++; + } + for (unsigned i = 0; i < size(); ++i) { + numeral c = coeff(i); + if (c == k) { + c = k_new; + } + else { + c = c / g; + } + args[i].second = c; + } + k = k_new; + } + SASSERT(well_formed()); + return l_undef; + } + bool theory_pb::ineq::well_formed() const { SASSERT(k() > 0); uint_set vars; @@ -57,7 +207,8 @@ namespace smt { theory_pb::theory_pb(ast_manager& m): theory(m.mk_family_id("card")), - m_util(m) + m_util(m), + m_lemma(null_literal) {} theory_pb::~theory_pb() { @@ -101,7 +252,7 @@ namespace smt { args[i].second = -args[i].second; } k = -k; - lbool is_true = normalize_ineq(args, k); + lbool is_true = c->normalize(); literal lit(abv); switch(is_true) { @@ -138,8 +289,9 @@ namespace smt { ++log; n *= 2; } - c->m_compilation_threshold = args.size()*log; - TRACE("card", tout << "compilation threshold: " << (args.size()*log) << "\n";); + unsigned th = 10*args.size()*log; + c->m_compilation_threshold = th; + TRACE("card", tout << "compilation threshold: " << th << "\n";); } else { c->m_compilation_threshold = UINT_MAX; @@ -167,10 +319,34 @@ namespace smt { ctx.set_var_theory(bv, get_id()); } has_bv = (ctx.get_var_theory(bv) == get_id()); +#if 0 + TBD: + if (!has_bv) { + if (!ctx.e_internalized(arg)) { + ctx.internalize(arg, false); + SASSERT(ctx.e_internalized(arg)); + } + enode* n = ctx.get_enode(arg); + theory_var v = mk_var(n); + ctx.attach_th_var(n, this, v); + } +#endif + } + else if (m.is_true(arg)) { + bv = true_bool_var; + has_bv = true; + } + else if (m.is_false(arg)) { + bv = true_bool_var; + has_bv = true; + negate = !negate; } - // pre-processing should better remove negations under cardinality. + // assumes relevancy level = 2 or 0. + // TBD: should should have been like an uninterpreted + // function intenalize, where enodes for each argument + // is available. if (!has_bv) { expr_ref tmp(m), fml(m); tmp = m.mk_fresh_const("card_proxy",m.mk_bool_sort()); @@ -220,142 +396,8 @@ namespace smt { ineqs->push_back(&c); } - theory_pb::numeral theory_pb::gcd(numeral a, numeral b) { - while (a != b) { - if (a == 0) return b; - if (b == 0) return a; - SASSERT(a != 0 && b != 0); - if (a < b) { - b %= a; - } - else { - a %= b; - } - } - return a; - } - lbool theory_pb::normalize_ineq(arg_t& args, numeral& k) { - - // normalize first all literals to be positive: - // then we can compare them more easily. - for (unsigned i = 0; i < args.size(); ++i) { - if (args[i].first.sign()) { - args[i].first.neg(); - k -= args[i].second; - args[i].second = -args[i].second; - } - } - // remove constants - for (unsigned i = 0; i < args.size(); ++i) { - if (args[i].first == true_literal) { - k += args[i].second; - std::swap(args[i], args[args.size()-1]); - args.pop_back(); - } - else if (args[i].first == false_literal) { - std::swap(args[i], args[args.size()-1]); - args.pop_back(); - } - } - // sort and coalesce arguments: - std::sort(args.begin(), args.end()); - for (unsigned i = 0; i + 1 < args.size(); ++i) { - if (args[i].first == args[i+1].first) { - args[i].second += args[i+1].second; - for (unsigned j = i+1; j + 1 < args.size(); ++j) { - args[j] = args[j+1]; - } - args.resize(args.size()-1); - } - if (args[i].second == 0) { - for (unsigned j = i; j + 1 < args.size(); ++j) { - args[j] = args[j+1]; - } - args.resize(args.size()-1); - } - } - // - // Ensure all coefficients are positive: - // c*l + y >= k - // <=> - // c*(1-~l) + y >= k - // <=> - // c - c*~l + y >= k - // <=> - // -c*~l + y >= k - c - // - numeral sum = 0; - for (unsigned i = 0; i < args.size(); ++i) { - numeral c = args[i].second; - if (c < 0) { - args[i].second = -c; - args[i].first = ~args[i].first; - k -= c; - } - sum += args[i].second; - } - // detect tautologies: - if (k <= 0) { - args.reset(); - return l_true; - } - // detect infeasible constraints: - if (sum < k) { - args.reset(); - return l_false; - } - // Ensure the largest coefficient is not larger than k: - for (unsigned i = 0; i < args.size(); ++i) { - numeral c = args[i].second; - if (c > k) { - args[i].second = k; - } - } - SASSERT(!args.empty()); - - // apply cutting plane reduction: - numeral g = 0; - for (unsigned i = 0; g != 1 && i < args.size(); ++i) { - numeral c = args[i].second; - if (c != k) { - g = gcd(g, c); - } - } - if (g == 0) { - // all coefficients are equal to k. - for (unsigned i = 0; i < args.size(); ++i) { - SASSERT(args[i].second == k); - args[i].second = 1; - } - k = 1; - } - else if (g > 1) { - // - // Example 5x + 5y + 2z + 2u >= 5 - // becomes 3x + 3y + z + u >= 3 - // - numeral k_new = k / g; - if ((k % g) != 0) { // k_new is the ceiling of k / g. - k_new++; - } - for (unsigned i = 0; i < args.size(); ++i) { - numeral c = args[i].second; - if (c == k) { - c = k_new; - } - else { - c = c / g; - } - args[i].second = c; - } - k = k_new; - } - - return l_undef; - } - void theory_pb::collect_statistics(::statistics& st) const { st.update("pb axioms", m_stats.m_num_axioms); st.update("pb propagations", m_stats.m_num_propagations); @@ -384,6 +426,10 @@ namespace smt { m_to_compile.reset(); } + void theory_pb::new_eq_eh(theory_var v1, theory_var v2) { + IF_VERBOSE(0, verbose_stream() << v1 << " = " << v2 << "\n";); + } + void theory_pb::assign_eh(bool_var v, bool is_true) { context& ctx = get_context(); ptr_vector* ineqs = 0; @@ -461,7 +507,7 @@ namespace smt { if (maxsum < c.k()) { literal_vector& lits = get_unhelpful_literals(c, true); lits.push_back(~c.lit()); - add_clause(c, lits); + add_clause(c, c.lit(), lits); return; } @@ -514,7 +560,7 @@ namespace smt { // literal_vector& lits = get_unhelpful_literals(c, false); lits.push_back(~c.lit()); - add_clause(c, lits); + add_clause(c, literal(v, !is_true), lits); } else if (c.max_sum() < k + c.max_coeff()) { // @@ -804,9 +850,14 @@ namespace smt { std::ostream& theory_pb::display(std::ostream& out, ineq& c) const { ast_manager& m = get_manager(); context& ctx = get_context(); - expr_ref tmp(m); - ctx.literal2expr(c.lit(), tmp); - out << tmp << "\n"; + if (c.lit() != null_literal) { + expr_ref tmp(m); + ctx.literal2expr(c.lit(), tmp); + out << tmp << "\n"; + } + else { + out << "null\n"; + } for (unsigned i = 0; i < c.size(); ++i) { out << c.coeff(i) << "*" << c.lit(i); if (i + 1 < c.size()) { @@ -829,6 +880,17 @@ namespace smt { return m_literals; } + class theory_pb::pb_justification : public theory_propagation_justification { + ineq& m_ineq; + public: + pb_justification(ineq& c, family_id fid, region & r, + unsigned num_lits, literal const * lits, literal consequent): + theory_propagation_justification(fid, r, num_lits, lits, consequent), + m_ineq(c) + {} + ineq& get_ineq() { return m_ineq; } + }; + void theory_pb::add_assign(ineq& c, literal_vector const& lits, literal l) { inc_propagations(c); m_stats.m_num_propagations++; @@ -841,13 +903,13 @@ namespace smt { display(tout, c);); ctx.assign(l, ctx.mk_justification( - theory_propagation_justification( - get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), l))); + pb_justification( + c, get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), l))); } - void theory_pb::add_clause(ineq& c, literal_vector const& lits) { + void theory_pb::add_clause(ineq& c, literal conseq, literal_vector const& lits) { inc_propagations(c); m_stats.m_num_axioms++; context& ctx = get_context(); @@ -857,11 +919,139 @@ namespace smt { } tout << "\n"; display(tout, c);); + + // DEBUG_CODE(resolve_conflict(conseq, c);); justification* js = 0; ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); IF_VERBOSE(2, ctx.display_literals_verbose(verbose_stream(), lits.size(), lits.c_ptr()); verbose_stream() << "\n";); // ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); + + } + + void theory_pb::process_antecedent(literal l, numeral coeff) { + context& ctx = get_context(); + bool_var v = l.var(); + unsigned lvl = ctx.get_assign_level(v); + IF_VERBOSE(0, verbose_stream() << l << "*" << coeff << " marked: " << ctx.is_marked(v) << " lvl: " << lvl << "\n";); + if (!ctx.is_marked(v) && lvl > ctx.get_base_level()) { + ctx.set_mark(v); + if (lvl == m_conflict_lvl) { + ++m_num_marks; + } + else { + m_lemma.m_args.push_back(std::make_pair(l, coeff)); + } + } + } + + void theory_pb::process_ineq(ineq& c) { + // TBD: create CUT. + context& ctx = get_context(); + for (unsigned i = 0; i < c.size(); ++i) { + process_antecedent(c.lit(i), c.coeff(i)); + } + process_antecedent(~c.lit(), 1); + } + + // + // modeled after sat_solver/smt_context + // + void theory_pb::resolve_conflict(literal conseq, ineq& c) { + + bool_var v; + context& ctx = get_context(); + unsigned& lvl = m_conflict_lvl = ctx.get_assign_level(c.lit()); + for (unsigned i = 0; i < c.size(); ++i) { + IF_VERBOSE(0, verbose_stream() << "conflict level: " << m_conflict_lvl << "\n";); + v = c.lit(i).var(); + if (ctx.get_assignment(v) != l_undef) { + lvl = std::max(lvl, ctx.get_assign_level(v)); + } + } + + if (lvl == ctx.get_base_level()) { + return; + } + + b_justification js(ctx.mk_justification( + pb_justification(c, get_id(), ctx.get_region(), + 0, 0, c.lit()))); + m_lemma.reset(); + m_num_marks = 0; + + // point into stack of assigned literals + literal_vector const& lits = ctx.assigned_literals(); + SASSERT(!lits.empty()); + unsigned idx = lits.size()-1; + + do { + // + // Resolve selected conseq with antecedents. + // + switch(js.get_kind()) { + case b_justification::CLAUSE: { + clause* cls = js.get_clause(); + unsigned num_lits = cls->get_num_literals(); + for (unsigned i = 0; i < num_lits; ++i) { + process_antecedent(cls->get_literal(i), 1); + } + justification* cjs = cls->get_justification(); + if (cjs) { + // TBD + NOT_IMPLEMENTED_YET(); + } + break; + } + case b_justification::BIN_CLAUSE: + SASSERT(conseq.var() != js.get_literal().var()); + process_antecedent(~js.get_literal(), 1); + break; + case b_justification::AXIOM: + break; + case b_justification::JUSTIFICATION: { + justification& j = *js.get_justification(); + // only process pb justifications. + if (j.get_from_theory() != get_id()) break; + pb_justification& pbj = dynamic_cast(j); + // weaken the lemma and resolve. + process_ineq(pbj.get_ineq()); + break; + } + default: + UNREACHABLE(); + } + // + // find the next marked variable in the assignment stack + // + SASSERT(idx > 0); + SASSERT(m_num_marks > 0); + do { + conseq = lits[idx]; + v = conseq.var(); + --idx; + } + while (!ctx.is_marked(v)); + + js = ctx.get_justification(v); + --m_num_marks; + ctx.unset_mark(v); + IF_VERBOSE(0, verbose_stream() << "unmark: " << v << "\n";); + } + while (m_num_marks > 0); + + // unset the marks on lemmas + for (unsigned i = 0; i < m_lemma.size(); ++i) { + bool_var v = m_lemma.lit(i).var(); + if (ctx.is_marked(v)) { + IF_VERBOSE(0, verbose_stream() << "unmark: " << v << "\n";); + ctx.unset_mark(v); + } + } + + TRACE("card", display(tout, m_lemma);); + + IF_VERBOSE(1, display(verbose_stream(), m_lemma);); } } diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index b27da52ca..28eb0ced6 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -28,6 +28,7 @@ namespace smt { class theory_pb : public theory { struct sort_expr; + class pb_justification; typedef int64 numeral; typedef svector > arg_t; @@ -57,16 +58,9 @@ namespace smt { unsigned m_compilation_threshold; lbool m_compiled; - ineq(literal l): - m_lit(l), - m_max_coeff(0), - m_watch_sz(0), - m_sum(0), - m_max_sum(0), - m_num_propagations(0), - m_compilation_threshold(UINT_MAX), - m_compiled(l_false) - {} + ineq(literal l) : m_lit(l) { + reset(); + } literal lit() const { return m_lit; } numeral const & k() const { return m_k; } @@ -90,9 +84,16 @@ namespace smt { return begin; } + void reset(); + void negate(); + lbool normalize(); + bool well_formed() const; + + static numeral gcd(numeral a, numeral b); + }; typedef ptr_vector watch_list; @@ -109,8 +110,6 @@ namespace smt { ptr_vector m_to_compile; // inequalities to compile. // internalize_atom: - lbool normalize_ineq(arg_t& args, numeral& k); - static numeral gcd(numeral a, numeral b); literal compile_arg(expr* arg); void add_watch(ineq& c, unsigned index); void del_watch(watch_list& watch, unsigned index, ineq& c, unsigned ineq_index); @@ -120,7 +119,7 @@ namespace smt { std::ostream& display(std::ostream& out, ineq& c) const; virtual void display(std::ostream& out) const; - void add_clause(ineq& c, literal_vector const& lits); + void add_clause(ineq& c, literal conseq, literal_vector const& lits); void add_assign(ineq& c, literal_vector const& lits, literal l); literal_vector& get_lits(); @@ -134,6 +133,16 @@ namespace smt { void compile_ineq(ineq& c); void inc_propagations(ineq& c); unsigned get_compilation_threshold(ineq& c); + + // + // Conflict resolution, cutting plane derivation. + // + unsigned m_num_marks; + unsigned m_conflict_lvl; + ineq m_lemma; + void resolve_conflict(literal conseq, ineq& c); + void process_antecedent(literal l, numeral coeff); + void process_ineq(ineq& c); public: theory_pb(ast_manager& m); @@ -142,7 +151,7 @@ namespace smt { virtual theory * mk_fresh(context * new_ctx); virtual bool internalize_atom(app * atom, bool gate_ctx); virtual bool internalize_term(app * term) { UNREACHABLE(); return false; } - virtual void new_eq_eh(theory_var v1, theory_var v2) { } + virtual void new_eq_eh(theory_var v1, theory_var v2); virtual void new_diseq_eh(theory_var v1, theory_var v2) { } virtual bool use_diseqs() const { return false; } virtual bool build_models() const { return false; } From 9734bab2056693a551c5f42a438a4df38f86268e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 17 Nov 2013 21:10:15 -0800 Subject: [PATCH 142/925] pb theory Signed-off-by: Nikolaj Bjorner --- src/opt/opt_params.pyg | 1 + src/smt/theory_pb.cpp | 46 ++++++++++++++++++++++-------------------- src/smt/theory_pb.h | 3 ++- 3 files changed, 27 insertions(+), 23 deletions(-) diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index 63c4d534a..4da07f305 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -6,6 +6,7 @@ def_module_params('opt', ('maxsat_engine', SYMBOL, 'fu_malik', "select engine for non-weighted maxsat: 'fu_malik', 'core_maxsat'"), ('pareto', BOOL, False, 'return a Pareto front (as opposed to a bounding box)'), ('dump_benchmarks', BOOL, False, 'dump benchmarks for profiling'), + ('debug_conflict', BOOL, False, 'debug conflict resolution'), )) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index c42010a4f..72483293e 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -26,6 +26,8 @@ Notes: namespace smt { + bool theory_pb::s_debug_conflict = false; // true; // + void theory_pb::ineq::negate() { m_lit.neg(); numeral sum = 0; @@ -396,8 +398,6 @@ namespace smt { ineqs->push_back(&c); } - - void theory_pb::collect_statistics(::statistics& st) const { st.update("pb axioms", m_stats.m_num_axioms); st.update("pb propagations", m_stats.m_num_propagations); @@ -920,7 +920,9 @@ namespace smt { tout << "\n"; display(tout, c);); - // DEBUG_CODE(resolve_conflict(conseq, c);); + if (s_debug_conflict) { + resolve_conflict(conseq, c); + } justification* js = 0; ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); IF_VERBOSE(2, ctx.display_literals_verbose(verbose_stream(), @@ -934,25 +936,27 @@ namespace smt { context& ctx = get_context(); bool_var v = l.var(); unsigned lvl = ctx.get_assign_level(v); - IF_VERBOSE(0, verbose_stream() << l << "*" << coeff << " marked: " << ctx.is_marked(v) << " lvl: " << lvl << "\n";); if (!ctx.is_marked(v) && lvl > ctx.get_base_level()) { + IF_VERBOSE(0, verbose_stream() << l << "*" << coeff << " marked. lvl: " << lvl << "\n";); ctx.set_mark(v); + m_unmark.push_back(v); if (lvl == m_conflict_lvl) { ++m_num_marks; } - else { - m_lemma.m_args.push_back(std::make_pair(l, coeff)); - } + m_lemma.m_args.push_back(std::make_pair(l, coeff)); } } void theory_pb::process_ineq(ineq& c) { // TBD: create CUT. - context& ctx = get_context(); + // only process literals that were + // assigned below current index 'idx'. + context& ctx = get_context(); for (unsigned i = 0; i < c.size(); ++i) { - process_antecedent(c.lit(i), c.coeff(i)); + process_antecedent(c.lit(i), c.coeff(i)); } process_antecedent(~c.lit(), 1); + m_lemma.m_k += c.k(); } // @@ -984,7 +988,7 @@ namespace smt { // point into stack of assigned literals literal_vector const& lits = ctx.assigned_literals(); SASSERT(!lits.empty()); - unsigned idx = lits.size()-1; + unsigned idx = lits.size()-1; do { // @@ -997,6 +1001,7 @@ namespace smt { for (unsigned i = 0; i < num_lits; ++i) { process_antecedent(cls->get_literal(i), 1); } + m_lemma.m_k += 1; justification* cjs = cls->get_justification(); if (cjs) { // TBD @@ -1005,7 +1010,8 @@ namespace smt { break; } case b_justification::BIN_CLAUSE: - SASSERT(conseq.var() != js.get_literal().var()); + m_lemma.m_k += 1; + process_antecedent(~js.get_literal(), 0); process_antecedent(~js.get_literal(), 1); break; case b_justification::AXIOM: @@ -1025,8 +1031,8 @@ namespace smt { // // find the next marked variable in the assignment stack // - SASSERT(idx > 0); - SASSERT(m_num_marks > 0); + SASSERT(idx > 0); + SASSERT(m_num_marks > 0); do { conseq = lits[idx]; v = conseq.var(); @@ -1036,19 +1042,15 @@ namespace smt { js = ctx.get_justification(v); --m_num_marks; - ctx.unset_mark(v); - IF_VERBOSE(0, verbose_stream() << "unmark: " << v << "\n";); } while (m_num_marks > 0); // unset the marks on lemmas - for (unsigned i = 0; i < m_lemma.size(); ++i) { - bool_var v = m_lemma.lit(i).var(); - if (ctx.is_marked(v)) { - IF_VERBOSE(0, verbose_stream() << "unmark: " << v << "\n";); - ctx.unset_mark(v); - } - } + while (!m_unmark.empty()) { + ctx.unset_mark(m_unmark.back()); + m_unmark.pop_back(); + } + TRACE("card", display(tout, m_lemma);); diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 28eb0ced6..49bd315c0 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -140,6 +140,7 @@ namespace smt { unsigned m_num_marks; unsigned m_conflict_lvl; ineq m_lemma; + svector m_unmark; void resolve_conflict(literal conseq, ineq& c); void process_antecedent(literal l, numeral coeff); void process_ineq(ineq& c); @@ -165,6 +166,6 @@ namespace smt { virtual void restart_eh(); virtual void collect_statistics(::statistics & st) const; - + static bool s_debug_conflict; }; }; From c42f0d60e6d402c97ec95bc618dbbf4aecd865de Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Nov 2013 05:10:30 -0800 Subject: [PATCH 143/925] pb solver Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 54 +++++++++++++++++++++++++++---------------- src/smt/theory_pb.h | 2 +- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 72483293e..68d627748 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -399,7 +399,7 @@ namespace smt { } void theory_pb::collect_statistics(::statistics& st) const { - st.update("pb axioms", m_stats.m_num_axioms); + st.update("pb conflicts", m_stats.m_num_conflicts); st.update("pb propagations", m_stats.m_num_propagations); st.update("pb predicates", m_stats.m_num_predicates); st.update("pb compilations", m_stats.m_num_compiles); @@ -911,7 +911,7 @@ namespace smt { void theory_pb::add_clause(ineq& c, literal conseq, literal_vector const& lits) { inc_propagations(c); - m_stats.m_num_axioms++; + m_stats.m_num_conflicts++; context& ctx = get_context(); TRACE("card", tout << "#prop:" << c.m_num_propagations << " - "; for (unsigned i = 0; i < lits.size(); ++i) { @@ -920,9 +920,11 @@ namespace smt { tout << "\n"; display(tout, c);); - if (s_debug_conflict) { - resolve_conflict(conseq, c); - } + DEBUG_CODE( + IF_VERBOSE(0, verbose_stream() << s_debug_conflict << "\n";); + if (s_debug_conflict) { + resolve_conflict(conseq, c); + }); justification* js = 0; ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); IF_VERBOSE(2, ctx.display_literals_verbose(verbose_stream(), @@ -936,14 +938,20 @@ namespace smt { context& ctx = get_context(); bool_var v = l.var(); unsigned lvl = ctx.get_assign_level(v); - if (!ctx.is_marked(v) && lvl > ctx.get_base_level()) { - IF_VERBOSE(0, verbose_stream() << l << "*" << coeff << " marked. lvl: " << lvl << "\n";); - ctx.set_mark(v); - m_unmark.push_back(v); - if (lvl == m_conflict_lvl) { - ++m_num_marks; + IF_VERBOSE(0, verbose_stream() << "ante: " << l << "*" << coeff << " " << lvl << "\n";); + if (lvl > ctx.get_base_level()) { + if (!ctx.is_marked(v)) { + ctx.set_mark(v); + m_unmark.push_back(v); + if (lvl == m_conflict_lvl) { + IF_VERBOSE(0, verbose_stream() << "new mark\n";); + ++m_num_marks; + } } - m_lemma.m_args.push_back(std::make_pair(l, coeff)); + m_lemma.m_args.push_back(std::make_pair(l, coeff)); + } + else if (ctx.get_assignment(l) == l_true) { + m_lemma.m_k += coeff; } } @@ -953,7 +961,9 @@ namespace smt { // assigned below current index 'idx'. context& ctx = get_context(); for (unsigned i = 0; i < c.size(); ++i) { - process_antecedent(c.lit(i), c.coeff(i)); + if (ctx.get_assignment(c.lit(i)) != l_undef) { + process_antecedent(c.lit(i), c.coeff(i)); + } } process_antecedent(~c.lit(), 1); m_lemma.m_k += c.k(); @@ -963,14 +973,16 @@ namespace smt { // modeled after sat_solver/smt_context // void theory_pb::resolve_conflict(literal conseq, ineq& c) { - + + IF_VERBOSE(0, display(verbose_stream(), c);); + bool_var v; context& ctx = get_context(); unsigned& lvl = m_conflict_lvl = ctx.get_assign_level(c.lit()); for (unsigned i = 0; i < c.size(); ++i) { - IF_VERBOSE(0, verbose_stream() << "conflict level: " << m_conflict_lvl << "\n";); v = c.lit(i).var(); if (ctx.get_assignment(v) != l_undef) { + IF_VERBOSE(0, verbose_stream() << c.lit(i) << " " << ctx.get_assign_level(v) << "\n";); lvl = std::max(lvl, ctx.get_assign_level(v)); } } @@ -994,15 +1006,17 @@ namespace smt { // // Resolve selected conseq with antecedents. // + IF_VERBOSE(0, verbose_stream() << conseq << " " << js.get_kind() << "\n";); switch(js.get_kind()) { + case b_justification::CLAUSE: { - clause* cls = js.get_clause(); - unsigned num_lits = cls->get_num_literals(); + clause& cls = *js.get_clause(); + unsigned num_lits = cls.get_num_literals(); for (unsigned i = 0; i < num_lits; ++i) { - process_antecedent(cls->get_literal(i), 1); + process_antecedent(cls.get_literal(i), 1); } m_lemma.m_k += 1; - justification* cjs = cls->get_justification(); + justification* cjs = cls.get_justification(); if (cjs) { // TBD NOT_IMPLEMENTED_YET(); @@ -1011,7 +1025,7 @@ namespace smt { } case b_justification::BIN_CLAUSE: m_lemma.m_k += 1; - process_antecedent(~js.get_literal(), 0); + process_antecedent(conseq, 1); process_antecedent(~js.get_literal(), 1); break; case b_justification::AXIOM: diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 49bd315c0..e50be1538 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -33,7 +33,7 @@ namespace smt { typedef svector > arg_t; struct stats { - unsigned m_num_axioms; + unsigned m_num_conflicts; unsigned m_num_propagations; unsigned m_num_predicates; unsigned m_num_compiles; From 86e22c11864a77f29271f0ef1795a02c8cb63874 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Nov 2013 09:44:20 -0800 Subject: [PATCH 144/925] add validation option Signed-off-by: Nikolaj Bjorner --- src/opt/maxsmt.cpp | 10 ++++++++++ src/opt/opt_context.cpp | 5 ++--- src/opt/opt_context.h | 2 ++ src/smt/theory_pb.cpp | 1 - 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index b2f09f3c1..2edb28504 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -59,6 +59,16 @@ namespace opt { verbose_stream() << "Satisfying soft constraints\n"; display_answer(verbose_stream()); }); + + DEBUG_CODE(if (is_sat == l_true) { + IF_VERBOSE(0, verbose_stream() << "validating assignment\n";); + m_s->push(); + commit_assignment(); + VERIFY(is_sat == m_s->check_sat(0,0)); + m_s->pop(1); + // TBD: check that all extensions are unsat too + + }); return is_sat; } diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 7e62605ac..6afc7779e 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -70,8 +70,8 @@ namespace opt { lbool is_sat = l_true; map_t::iterator it = m_maxsmts.begin(), end = m_maxsmts.end(); for (; is_sat == l_true && it != end; ++it) { - maxsmt* ms = it->m_value; - is_sat = (*ms)(s); + maxsmt& ms = *it->m_value; + is_sat = ms(s); } if (is_sat == l_true) { is_sat = m_optsmt(s); @@ -160,5 +160,4 @@ namespace opt { } } - } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index c54259115..081bf7c1d 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -60,6 +60,8 @@ namespace opt { private: lbool optimize_pareto(); lbool optimize_box(); + + void validate_feasibility(maxsmt& ms); }; } diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 68d627748..2b42e39f9 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -921,7 +921,6 @@ namespace smt { display(tout, c);); DEBUG_CODE( - IF_VERBOSE(0, verbose_stream() << s_debug_conflict << "\n";); if (s_debug_conflict) { resolve_conflict(conseq, c); }); From 2b2d0e155c02ef64822fb9aa2a4cfa5dd992c770 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Nov 2013 18:03:49 -0800 Subject: [PATCH 145/925] debugged new pb solver Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 9 +++ src/api/api_context.cpp | 1 + src/api/api_context.h | 2 + src/opt/maxsmt.cpp | 6 +- src/smt/diff_logic.h | 6 +- src/smt/theory_pb.cpp | 137 ++++++++++++++++++++++++++-------------- src/smt/theory_pb.h | 5 +- 7 files changed, 114 insertions(+), 52 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index c96328bf8..d8227a152 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -24,6 +24,7 @@ Revision History: #include"bv_decl_plugin.h" #include"datatype_decl_plugin.h" #include"array_decl_plugin.h" +#include"card_decl_plugin.h" #include"ast_translation.h" #include"ast_pp.h" #include"ast_ll_pp.h" @@ -1122,6 +1123,14 @@ extern "C" { } } + if (mk_c(c)->get_pb_fid() == _d->get_family_id()) { + switch(_d->get_decl_kind()) { + case OP_PB_LE: return Z3_OP_PB_LE; + case OP_AT_MOST_K: return Z3_OP_PB_AT_MOST; + default: UNREACHABLE(); + } + } + return Z3_OP_UNINTERPRETED; Z3_CATCH_RETURN(Z3_OP_UNINTERPRETED); } diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index 05e1ca675..49fa1ab99 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -109,6 +109,7 @@ namespace api { m_basic_fid = m().get_basic_family_id(); m_arith_fid = m().mk_family_id("arith"); m_bv_fid = m().mk_family_id("bv"); + m_pb_fid = m().mk_family_id("card"); m_array_fid = m().mk_family_id("array"); m_dt_fid = m().mk_family_id("datatype"); m_datalog_fid = m().mk_family_id("datalog_relation"); diff --git a/src/api/api_context.h b/src/api/api_context.h index e0c95b07b..8b4418c9a 100644 --- a/src/api/api_context.h +++ b/src/api/api_context.h @@ -75,6 +75,7 @@ namespace api { family_id m_bv_fid; family_id m_dt_fid; family_id m_datalog_fid; + family_id m_pb_fid; datatype_decl_plugin * m_dt_plugin; std::string m_string_buffer; // temporary buffer used to cache strings sent to the "external" world. @@ -121,6 +122,7 @@ namespace api { family_id get_bv_fid() const { return m_bv_fid; } family_id get_dt_fid() const { return m_dt_fid; } family_id get_datalog_fid() const { return m_datalog_fid; } + family_id get_pb_fid() const { return m_pb_fid; } datatype_decl_plugin * get_dt_plugin() const { return m_dt_plugin; } Z3_error_code get_error_code() const { return m_error_code; } diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 2edb28504..14233300a 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -34,7 +34,7 @@ namespace opt { if (m_soft_constraints.empty()) { m_msolver = 0; is_sat = s.check_sat(0, 0); - m_answer.append(m_soft_constraints); + m_answer.reset(); } else if (is_maxsat_problem(m_weights)) { if (m_maxsat_engine == symbol("core_maxsat")) { @@ -64,7 +64,7 @@ namespace opt { IF_VERBOSE(0, verbose_stream() << "validating assignment\n";); m_s->push(); commit_assignment(); - VERIFY(is_sat == m_s->check_sat(0,0)); + VERIFY(l_true == m_s->check_sat(0,0)); m_s->pop(1); // TBD: check that all extensions are unsat too @@ -94,7 +94,7 @@ namespace opt { if (m_msolver) { return inf_eps(m_msolver->get_upper()); } - return inf_eps(); + return inf_eps(rational(m_soft_constraints.size())); } void maxsmt::commit_assignment() { diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index fcd4f6309..7bc430244 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -996,8 +996,9 @@ public: svector neighbours; get_neighbours_undirected(current, neighbours); for (unsigned i = 0; i < neighbours.size(); ++i) { + DEBUG_CODE( edge_id id; - SASSERT(prev == -1 || get_edge_id(prev, current, id) || get_edge_id(current, prev, id)); + SASSERT(prev == -1 || get_edge_id(prev, current, id) || get_edge_id(current, prev, id));); if (!visited.contains(neighbours[i])) { nodes.push_back(neighbours[i]); } @@ -1023,8 +1024,9 @@ public: get_neighbours_undirected(current, neighbours); for (unsigned i = 0; i < neighbours.size(); ++i) { dl_var & next = neighbours[i]; + DEBUG_CODE( edge_id id; - SASSERT(get_edge_id(current, next, id) || get_edge_id(next, current, id)); + SASSERT(get_edge_id(current, next, id) || get_edge_id(next, current, id));); if (!visited.contains(next)) { parents[next] = current; depths[next] = depths[current] + 1; diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 2b42e39f9..a52d4b93b 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -429,6 +429,45 @@ namespace smt { void theory_pb::new_eq_eh(theory_var v1, theory_var v2) { IF_VERBOSE(0, verbose_stream() << v1 << " = " << v2 << "\n";); } + + final_check_status theory_pb::final_check_eh() { + TRACE("card", display(tout);); + DEBUG_CODE(validate_final_check();); + return FC_DONE; + } + + void theory_pb::validate_final_check() { + u_map::iterator itc = m_ineqs.begin(), endc = m_ineqs.end(); + for (; itc != endc; ++itc) { + validate_final_check(*itc->m_value); + } + } + + void theory_pb::validate_final_check(ineq& c) { + context& ctx = get_context(); + + if (ctx.get_assignment(c.lit()) == l_undef) { + return; + } + numeral sum = 0, maxsum = 0; + for (unsigned i = 0; i < c.size(); ++i) { + switch(ctx.get_assignment(c.lit(i))) { + case l_true: + sum += c.coeff(i); + case l_undef: + maxsum += c.coeff(i); + break; + } + } + TRACE("card", display(tout << "validate: ", c); + tout << "sum: " << sum << " " << maxsum << " " << ctx.get_assignment(c.lit()) << "\n"; + ); + + SASSERT(sum <= maxsum); + SASSERT((sum >= c.k()) == (ctx.get_assignment(c.lit()) == l_true)); + SASSERT((maxsum < c.k()) == (ctx.get_assignment(c.lit()) == l_false)); + } + void theory_pb::assign_eh(bool_var v, bool is_true) { context& ctx = get_context(); @@ -447,7 +486,6 @@ namespace smt { if (m_ineqs.find(v, c)) { assign_ineq(*c, is_true); } - TRACE("card", display(tout);); } literal_vector& theory_pb::get_helpful_literals(ineq& c, bool negate) { @@ -505,21 +543,21 @@ namespace smt { display(tout, c); ); if (maxsum < c.k()) { - literal_vector& lits = get_unhelpful_literals(c, true); + literal_vector& lits = get_unhelpful_literals(c, false); lits.push_back(~c.lit()); add_clause(c, c.lit(), lits); - return; } - - c.m_max_sum = 0; - c.m_watch_sz = 0; - for (unsigned i = 0; c.max_sum() < c.k() + c.max_coeff() && i < c.size(); ++i) { - if (ctx.get_assignment(c.lit(i)) != l_false) { - add_watch(c, i); - } + else { + c.m_max_sum = 0; + c.m_watch_sz = 0; + for (unsigned i = 0; c.max_sum() < c.k() + c.max_coeff() && i < c.size(); ++i) { + if (ctx.get_assignment(c.lit(i)) != l_false) { + add_watch(c, i); + } + } + SASSERT(c.max_sum() >= c.k()); + m_assign_ineqs_trail.push_back(&c); } - SASSERT(c.max_sum() >= c.k()); - m_assign_ineqs_trail.push_back(&c); } /** @@ -544,16 +582,16 @@ namespace smt { // numeral k = c.k(); - del_watch(watch, watch_index, c, w); - removed = true; + numeral coeff = c.coeff(w); - for (unsigned i = c.watch_size(); c.max_sum() < k + c.max_coeff() && i < c.size(); ++i) { + for (unsigned i = c.watch_size(); c.max_sum() - coeff < k + c.max_coeff() && i < c.size(); ++i) { if (ctx.get_assignment(c.lit(i)) != l_false) { add_watch(c, i); } } - - if (c.max_sum() < k) { + + + if (c.max_sum() - coeff < k) { // // L: 3*x1 + 2*x2 + x4 >= 3, but x1 <- 0, x2 <- 0 // create clause x1 or x2 or ~L @@ -562,32 +600,37 @@ namespace smt { lits.push_back(~c.lit()); add_clause(c, literal(v, !is_true), lits); } - else if (c.max_sum() < k + c.max_coeff()) { - // - // opportunities for unit propagation for unassigned - // literals whose coefficients satisfy - // c.max_sum() - coeff < k - // - // L: 3*x1 + 2*x2 + x4 >= 3, but x1 <- 0 - // Create clauses x1 or ~L or x2 - // x1 or ~L or x4 - // + else { + del_watch(watch, watch_index, c, w); + removed = true; + if (c.max_sum() - coeff < k + c.max_coeff()) { - literal_vector& lits = get_unhelpful_literals(c, true); - lits.push_back(c.lit()); - for (unsigned i = 0; i < c.size(); ++i) { - if (c.max_sum() - c.coeff(i) < k && ctx.get_assignment(c.lit(i)) == l_undef) { - add_assign(c, lits, c.lit(i)); + // + // opportunities for unit propagation for unassigned + // literals whose coefficients satisfy + // c.max_sum() - coeff < k + // + // L: 3*x1 + 2*x2 + x4 >= 3, but x1 <- 0 + // Create clauses x1 or ~L or x2 + // x1 or ~L or x4 + // + + literal_vector& lits = get_unhelpful_literals(c, true); + lits.push_back(c.lit()); + for (unsigned i = 0; i < c.size(); ++i) { + if (c.max_sum() - c.coeff(i) < k && ctx.get_assignment(c.lit(i)) == l_undef) { + add_assign(c, lits, c.lit(i)); + } } } + // + // else: c.max_sum() >= k + c.max_coeff() + // we might miss opportunities for unit propagation if + // max_coeff is not the maximal coefficient + // of the current unassigned literal, but we can + // rely on eventually learning this from propagations. + // } - // - // else: c.max_sum() >= k + c.max_coeff() - // we might miss opportunities for unit propagation if - // max_coeff is not the maximal coefficient - // of the current unassigned literal, but we can - // rely on eventually learning this from propagations. - // } // @@ -736,10 +779,12 @@ namespace smt { void theory_pb::inc_propagations(ineq& c) { ++c.m_num_propagations; +#if 1 if (c.m_compiled == l_false && c.m_num_propagations > c.m_compilation_threshold) { c.m_compiled = l_undef; m_to_compile.push_back(&c); } +#endif } void theory_pb::restart_eh() { @@ -850,14 +895,12 @@ namespace smt { std::ostream& theory_pb::display(std::ostream& out, ineq& c) const { ast_manager& m = get_manager(); context& ctx = get_context(); + out << c.lit() << " "; if (c.lit() != null_literal) { expr_ref tmp(m); ctx.literal2expr(c.lit(), tmp); out << tmp << "\n"; } - else { - out << "null\n"; - } for (unsigned i = 0; i < c.size(); ++i) { out << c.coeff(i) << "*" << c.lit(i); if (i + 1 < c.size()) { @@ -960,7 +1003,7 @@ namespace smt { // assigned below current index 'idx'. context& ctx = get_context(); for (unsigned i = 0; i < c.size(); ++i) { - if (ctx.get_assignment(c.lit(i)) != l_undef) { + if (ctx.get_assignment(c.lit(i)) == l_false) { process_antecedent(c.lit(i), c.coeff(i)); } } @@ -981,7 +1024,8 @@ namespace smt { for (unsigned i = 0; i < c.size(); ++i) { v = c.lit(i).var(); if (ctx.get_assignment(v) != l_undef) { - IF_VERBOSE(0, verbose_stream() << c.lit(i) << " " << ctx.get_assign_level(v) << "\n";); + IF_VERBOSE(0, verbose_stream() << c.lit(i) << " " + << ctx.get_assign_level(v) << "\n";); lvl = std::max(lvl, ctx.get_assign_level(v)); } } @@ -991,8 +1035,9 @@ namespace smt { } b_justification js(ctx.mk_justification( - pb_justification(c, get_id(), ctx.get_region(), - 0, 0, c.lit()))); + pb_justification( + c, get_id(), ctx.get_region(), + 0, 0, c.lit()))); m_lemma.reset(); m_num_marks = 0; diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index e50be1538..2d23b97d6 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -144,6 +144,9 @@ namespace smt { void resolve_conflict(literal conseq, ineq& c); void process_antecedent(literal l, numeral coeff); void process_ineq(ineq& c); + + void validate_final_check(); + void validate_final_check(ineq& c); public: theory_pb(ast_manager& m); @@ -156,7 +159,7 @@ namespace smt { virtual void new_diseq_eh(theory_var v1, theory_var v2) { } virtual bool use_diseqs() const { return false; } virtual bool build_models() const { return false; } - virtual final_check_status final_check_eh() { return FC_DONE; } + virtual final_check_status final_check_eh(); virtual void reset_eh(); virtual void assign_eh(bool_var v, bool is_true); From ee0abfbfe9e9f743eaf7ac9b154b6a4c700876cb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Nov 2013 21:25:02 -0800 Subject: [PATCH 146/925] rename card->pb Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 2 +- src/api/api_context.cpp | 2 +- src/api/api_pb.cpp | 6 ++-- ...ard_decl_plugin.cpp => pb_decl_plugin.cpp} | 26 +++++++-------- .../{card_decl_plugin.h => pb_decl_plugin.h} | 26 +++++++-------- src/ast/reg_decl_plugins.cpp | 6 ++-- src/cmd_context/cmd_context.cpp | 4 +-- src/opt/core_maxsat.cpp | 6 ++-- src/smt/theory_card.cpp | 20 ++++++------ src/smt/theory_card.h | 4 +-- src/smt/theory_pb.cpp | 32 +++++++++---------- src/smt/theory_pb.h | 4 +-- src/tactic/arith/lia2card_tactic.cpp | 20 ++++++------ 13 files changed, 79 insertions(+), 79 deletions(-) rename src/ast/{card_decl_plugin.cpp => pb_decl_plugin.cpp} (78%) rename src/ast/{card_decl_plugin.h => pb_decl_plugin.h} (81%) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index d8227a152..29c492368 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -24,7 +24,7 @@ Revision History: #include"bv_decl_plugin.h" #include"datatype_decl_plugin.h" #include"array_decl_plugin.h" -#include"card_decl_plugin.h" +#include"pb_decl_plugin.h" #include"ast_translation.h" #include"ast_pp.h" #include"ast_ll_pp.h" diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index 49fa1ab99..8c89740ad 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -109,7 +109,7 @@ namespace api { m_basic_fid = m().get_basic_family_id(); m_arith_fid = m().mk_family_id("arith"); m_bv_fid = m().mk_family_id("bv"); - m_pb_fid = m().mk_family_id("card"); + m_pb_fid = m().mk_family_id("pb"); m_array_fid = m().mk_family_id("array"); m_dt_fid = m().mk_family_id("datatype"); m_datalog_fid = m().mk_family_id("datalog_relation"); diff --git a/src/api/api_pb.cpp b/src/api/api_pb.cpp index 52290d28a..17fe2f93e 100644 --- a/src/api/api_pb.cpp +++ b/src/api/api_pb.cpp @@ -20,7 +20,7 @@ Revision History: #include"api_log_macros.h" #include"api_context.h" #include"api_util.h" -#include"card_decl_plugin.h" +#include"pb_decl_plugin.h" extern "C" { @@ -30,7 +30,7 @@ extern "C" { LOG_Z3_mk_atmost(c, num_args, args, k); RESET_ERROR_CODE(); parameter param(k); - card_util util(mk_c(c)->m()); + pb_util util(mk_c(c)->m()); ast* a = util.mk_at_most_k(num_args, to_exprs(args), k); mk_c(c)->save_ast_trail(a); check_sorts(c, a); @@ -45,7 +45,7 @@ extern "C" { Z3_TRY; LOG_Z3_mk_pble(c, num_args, args, coeffs, k); RESET_ERROR_CODE(); - card_util util(mk_c(c)->m()); + pb_util util(mk_c(c)->m()); ast* a = util.mk_le(num_args, coeffs, to_exprs(args), k); mk_c(c)->save_ast_trail(a); check_sorts(c, a); diff --git a/src/ast/card_decl_plugin.cpp b/src/ast/pb_decl_plugin.cpp similarity index 78% rename from src/ast/card_decl_plugin.cpp rename to src/ast/pb_decl_plugin.cpp index 6a15792e5..0f9f479dd 100644 --- a/src/ast/card_decl_plugin.cpp +++ b/src/ast/pb_decl_plugin.cpp @@ -3,7 +3,7 @@ Copyright (c) 2013 Microsoft Corporation Module Name: - card_decl_plugin.cpp + pb_decl_plugin.cpp Abstract: @@ -17,14 +17,14 @@ Revision History: --*/ -#include "card_decl_plugin.h" +#include "pb_decl_plugin.h" -card_decl_plugin::card_decl_plugin(): +pb_decl_plugin::pb_decl_plugin(): m_at_most_sym("at-most"), m_pble_sym("pble") {} -func_decl * card_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, +func_decl * pb_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { SASSERT(m_manager); ast_manager& m = *m_manager; @@ -59,7 +59,7 @@ func_decl * card_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, } } -void card_decl_plugin::get_op_names(svector & op_names, symbol const & logic) { +void pb_decl_plugin::get_op_names(svector & op_names, symbol const & logic) { if (logic == symbol::null) { op_names.push_back(builtin_name(m_at_most_sym.bare_str(), OP_AT_MOST_K)); op_names.push_back(builtin_name(m_pble_sym.bare_str(), OP_PB_LE)); @@ -67,12 +67,12 @@ void card_decl_plugin::get_op_names(svector & op_names, symbol con } -app * card_util::mk_at_most_k(unsigned num_args, expr * const * args, unsigned k) { +app * pb_util::mk_at_most_k(unsigned num_args, expr * const * args, unsigned k) { parameter param(k); return m.mk_app(m_fid, OP_AT_MOST_K, 1, ¶m, num_args, args, m.mk_bool_sort()); } -app * card_util::mk_le(unsigned num_args, int const * coeffs, expr * const * args, int k) { +app * pb_util::mk_le(unsigned num_args, int const * coeffs, expr * const * args, int k) { vector params; params.push_back(parameter(k)); for (unsigned i = 0; i < num_args; ++i) { @@ -82,11 +82,11 @@ app * card_util::mk_le(unsigned num_args, int const * coeffs, expr * const * arg } -bool card_util::is_at_most_k(app *a) const { +bool pb_util::is_at_most_k(app *a) const { return is_app_of(a, m_fid, OP_AT_MOST_K); } -bool card_util::is_at_most_k(app *a, unsigned& k) const { +bool pb_util::is_at_most_k(app *a, unsigned& k) const { if (is_at_most_k(a)) { k = get_k(a); return true; @@ -96,17 +96,17 @@ bool card_util::is_at_most_k(app *a, unsigned& k) const { } } -int card_util::get_k(app *a) const { +int pb_util::get_k(app *a) const { SASSERT(is_at_most_k(a) || is_le(a)); return a->get_decl()->get_parameter(0).get_int(); } -bool card_util::is_le(app *a) const { +bool pb_util::is_le(app *a) const { return is_app_of(a, m_fid, OP_PB_LE); } -bool card_util::is_le(app* a, int& k) const { +bool pb_util::is_le(app* a, int& k) const { if (is_le(a)) { k = get_k(a); return true; @@ -116,7 +116,7 @@ bool card_util::is_le(app* a, int& k) const { } } -int card_util::get_le_coeff(app* a, unsigned index) { +int pb_util::get_le_coeff(app* a, unsigned index) { if (is_at_most_k(a)) { return 1; } diff --git a/src/ast/card_decl_plugin.h b/src/ast/pb_decl_plugin.h similarity index 81% rename from src/ast/card_decl_plugin.h rename to src/ast/pb_decl_plugin.h index 3ac681284..093236218 100644 --- a/src/ast/card_decl_plugin.h +++ b/src/ast/pb_decl_plugin.h @@ -3,11 +3,11 @@ Copyright (c) 2013 Microsoft Corporation Module Name: - card_decl_plugin.h + pb_decl_plugin.h Abstract: - Cardinality Constraints plugin + Pseudo-Boolean and Cardinality Constraints plugin Author: @@ -24,26 +24,26 @@ hence: --*/ -#ifndef _CARD_DECL_PLUGIN_H_ -#define _CARD_DECL_PLUGIN_H_ +#ifndef _PB_DECL_PLUGIN_H_ +#define _PB_DECL_PLUGIN_H_ #include"ast.h" -enum card_op_kind { +enum pb_op_kind { OP_AT_MOST_K, // at most K Booleans are true. OP_PB_LE, // pseudo-Boolean <= (generalizes at_most_k) - LAST_CARD_OP + LAST_PB_OP }; -class card_decl_plugin : public decl_plugin { +class pb_decl_plugin : public decl_plugin { symbol m_at_most_sym; symbol m_pble_sym; func_decl * mk_at_most(unsigned arity, unsigned k); func_decl * mk_le(unsigned arity, int const* coeffs, int k); public: - card_decl_plugin(); - virtual ~card_decl_plugin() {} + pb_decl_plugin(); + virtual ~pb_decl_plugin() {} virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) { UNREACHABLE(); @@ -51,7 +51,7 @@ public: } virtual decl_plugin * mk_fresh() { - return alloc(card_decl_plugin); + return alloc(pb_decl_plugin); } // @@ -65,11 +65,11 @@ public: }; -class card_util { +class pb_util { ast_manager & m; family_id m_fid; public: - card_util(ast_manager& m):m(m), m_fid(m.mk_family_id("card")) {} + pb_util(ast_manager& m):m(m), m_fid(m.mk_family_id("pb")) {} ast_manager & get_manager() const { return m; } family_id get_family_id() const { return m_fid; } app * mk_at_most_k(unsigned num_args, expr * const * args, unsigned k); @@ -83,5 +83,5 @@ public: }; -#endif /* _CARD_DECL_PLUGIN_H_ */ +#endif /* _PB_DECL_PLUGIN_H_ */ diff --git a/src/ast/reg_decl_plugins.cpp b/src/ast/reg_decl_plugins.cpp index 541964038..6a996d288 100644 --- a/src/ast/reg_decl_plugins.cpp +++ b/src/ast/reg_decl_plugins.cpp @@ -25,7 +25,7 @@ Revision History: #include"dl_decl_plugin.h" #include"seq_decl_plugin.h" #include"float_decl_plugin.h" -#include"card_decl_plugin.h" +#include"pb_decl_plugin.h" void reg_decl_plugins(ast_manager & m) { if (!m.get_plugin(m.mk_family_id(symbol("arith")))) { @@ -49,7 +49,7 @@ void reg_decl_plugins(ast_manager & m) { if (!m.get_plugin(m.mk_family_id(symbol("float")))) { m.register_plugin(symbol("float"), alloc(float_decl_plugin)); } - if (!m.get_plugin(m.mk_family_id(symbol("card")))) { - m.register_plugin(symbol("card"), alloc(card_decl_plugin)); + if (!m.get_plugin(m.mk_family_id(symbol("pb")))) { + m.register_plugin(symbol("pb"), alloc(pb_decl_plugin)); } } diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 626272412..976a66664 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -25,7 +25,7 @@ Notes: #include"datatype_decl_plugin.h" #include"seq_decl_plugin.h" #include"float_decl_plugin.h" -#include"card_decl_plugin.h" +#include"pb_decl_plugin.h" #include"ast_pp.h" #include"var_subst.h" #include"pp.h" @@ -573,7 +573,7 @@ void cmd_context::init_manager_core(bool new_manager) { register_plugin(symbol("datatype"), alloc(datatype_decl_plugin), logic_has_datatype()); register_plugin(symbol("seq"), alloc(seq_decl_plugin), logic_has_seq()); register_plugin(symbol("float"), alloc(float_decl_plugin), logic_has_floats()); - register_plugin(symbol("card"), alloc(card_decl_plugin), !has_logic()); + register_plugin(symbol("pb"), alloc(pb_decl_plugin), !has_logic()); } else { // the manager was created by an external module, we must register all plugins available in the manager. diff --git a/src/opt/core_maxsat.cpp b/src/opt/core_maxsat.cpp index b386595d3..b6da58aa0 100644 --- a/src/opt/core_maxsat.cpp +++ b/src/opt/core_maxsat.cpp @@ -17,7 +17,7 @@ Notes: --*/ #include "core_maxsat.h" -#include "card_decl_plugin.h" +#include "pb_decl_plugin.h" #include "ast_pp.h" namespace opt { @@ -120,10 +120,10 @@ namespace opt { } expr_ref core_maxsat::mk_at_most(expr_set const& set, unsigned k) { - card_util card(m); + pb_util pb(m); ptr_vector es; set2vector(set, es); - return expr_ref(card.mk_at_most_k(es.size(), es.c_ptr(), k), m); + return expr_ref(pb.mk_at_most_k(es.size(), es.c_ptr(), k), m); } expr* core_maxsat::get_not(expr* e) const { diff --git a/src/smt/theory_card.cpp b/src/smt/theory_card.cpp index a2706bb4b..f0f156c99 100644 --- a/src/smt/theory_card.cpp +++ b/src/smt/theory_card.cpp @@ -53,7 +53,7 @@ Notes: namespace smt { theory_card::theory_card(ast_manager& m): - theory(m.mk_family_id("card")), + theory(m.mk_family_id("pb")), m_util(m) {} @@ -79,7 +79,7 @@ namespace smt { m_stats.m_num_predicates++; - TRACE("card", tout << "internalize: " << mk_pp(atom, m) << "\n";); + TRACE("pb", tout << "internalize: " << mk_pp(atom, m) << "\n";); SASSERT(!ctx.b_internalized(atom)); bool_var abv = ctx.mk_bool_var(atom); @@ -370,7 +370,7 @@ namespace smt { int max = c.m_current_max; int k = c.m_k; - TRACE("card", + TRACE("pb", tout << mk_pp(c.m_app, m) << " min: " << min << " max: " << max << "\n";); @@ -474,7 +474,7 @@ namespace smt { ast_manager& m = get_manager(); ptr_vector* cards = 0; card* c = 0; - TRACE("card", tout << "assign: " << mk_pp(ctx.bool_var2expr(v), m) << " <- " << is_true << "\n";); + TRACE("pb", tout << "assign: " << mk_pp(ctx.bool_var2expr(v), m) << " <- " << is_true << "\n";); if (m_watch.find(v, cards)) { for (unsigned i = 0; i < cards->size(); ++i) { @@ -618,7 +618,7 @@ namespace smt { add_clause(~l, a, c); add_clause(l, ~a, ~b); add_clause(l, a, ~c); - TRACE("card", tout << p << " ::= (if "; + TRACE("pb", tout << p << " ::= (if "; ctx.display_detailed_literal(tout, a); ctx.display_detailed_literal(tout << " ", b); ctx.display_detailed_literal(tout << " ", c); @@ -635,7 +635,7 @@ namespace smt { if (b != null_literal) lits.push_back(b); if (c != null_literal) lits.push_back(c); justification* js = 0; - TRACE("card", + TRACE("pb", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";); ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX, 0); } @@ -656,7 +656,7 @@ namespace smt { ++log; n *= 2; } - TRACE("card", tout << "threshold:" << (num_args*log) << "\n";); + TRACE("pb", tout << "threshold:" << (num_args*log) << "\n";); return num_args*log; } @@ -696,12 +696,12 @@ namespace smt { } sn(in, out); atmostk = ~se.internalize(c, out[k].get()); // k'th output is 0. - TRACE("card", tout << "~atmost: " << mk_pp(out[k].get(), m) << "\n";); + TRACE("pb", tout << "~atmost: " << mk_pp(out[k].get(), m) << "\n";); } literal thl = literal(c.m_bv); se.add_clause(~thl, atmostk); se.add_clause(thl, ~atmostk); - TRACE("card", tout << mk_pp(a, m) << "\n";); + TRACE("pb", tout << mk_pp(a, m) << "\n";); // auxiliary clauses get removed when popping scopes. // we have to recompile the circuit after back-tracking. ctx.push_trail(value_trail(c.m_compiled)); @@ -760,7 +760,7 @@ namespace smt { ++c.m_num_propagations; m_stats.m_num_axioms++; context& ctx = get_context(); - TRACE("card", tout << "#prop:" << c.m_num_propagations << " - "; ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";); + TRACE("pb", tout << "#prop:" << c.m_num_propagations << " - "; ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";); justification* js = 0; ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); IF_VERBOSE(2, ctx.display_literals_verbose(verbose_stream(), diff --git a/src/smt/theory_card.h b/src/smt/theory_card.h index a432ea5a3..0f425c103 100644 --- a/src/smt/theory_card.h +++ b/src/smt/theory_card.h @@ -21,7 +21,7 @@ Notes: --*/ #include "smt_theory.h" -#include "card_decl_plugin.h" +#include "pb_decl_plugin.h" #include "smt_clause.h" namespace smt { @@ -69,7 +69,7 @@ namespace smt { unsigned_vector m_watch_trail; unsigned_vector m_watch_lim; literal_vector m_literals; - card_util m_util; + pb_util m_util; stats m_stats; void add_watch(bool_var bv, card* c); diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index a52d4b93b..be83d446f 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -208,7 +208,7 @@ namespace smt { } theory_pb::theory_pb(ast_manager& m): - theory(m.mk_family_id("card")), + theory(m.mk_family_id("pb")), m_util(m), m_lemma(null_literal) {} @@ -263,7 +263,7 @@ namespace smt { // fall-through case l_true: ctx.mk_th_axiom(get_id(), 1, &lit); - TRACE("card", tout << mk_pp(atom, m) << " := " << lit << "\n";); + TRACE("pb", tout << mk_pp(atom, m) << " := " << lit << "\n";); dealloc(c); return true; case l_undef: @@ -293,7 +293,7 @@ namespace smt { } unsigned th = 10*args.size()*log; c->m_compilation_threshold = th; - TRACE("card", tout << "compilation threshold: " << th << "\n";); + TRACE("pb", tout << "compilation threshold: " << th << "\n";); } else { c->m_compilation_threshold = UINT_MAX; @@ -301,7 +301,7 @@ namespace smt { m_ineqs.insert(abv, c); m_ineqs_trail.push_back(abv); - TRACE("card", display(tout, *c);); + TRACE("pb", display(tout, *c);); return true; } @@ -431,7 +431,7 @@ namespace smt { } final_check_status theory_pb::final_check_eh() { - TRACE("card", display(tout);); + TRACE("pb", display(tout);); DEBUG_CODE(validate_final_check();); return FC_DONE; } @@ -459,7 +459,7 @@ namespace smt { break; } } - TRACE("card", display(tout << "validate: ", c); + TRACE("pb", display(tout << "validate: ", c); tout << "sum: " << sum << " " << maxsum << " " << ctx.get_assignment(c.lit()) << "\n"; ); @@ -472,7 +472,7 @@ namespace smt { void theory_pb::assign_eh(bool_var v, bool is_true) { context& ctx = get_context(); ptr_vector* ineqs = 0; - TRACE("card", tout << "assign: " << literal(v, !is_true) << "\n";); + TRACE("pb", tout << "assign: " << literal(v, !is_true) << "\n";); if (m_watch.find(v, ineqs)) { for (unsigned i = 0; i < ineqs->size(); ++i) { @@ -538,7 +538,7 @@ namespace smt { } } - TRACE("card", + TRACE("pb", tout << "assign: " << c.lit() << " <- " << is_true << "\n"; display(tout, c); ); @@ -636,7 +636,7 @@ namespace smt { // // else: the current set of watch remain a potentially feasible assignment. // - TRACE("card", + TRACE("pb", tout << "assign: " << literal(v) << " <- " << is_true << "\n"; display(tout, c); ); @@ -748,7 +748,7 @@ namespace smt { add_clause(~l, a, c); add_clause(l, ~a, ~b); add_clause(l, a, ~c); - TRACE("card", tout << mk_pp(t, m) << " ::= (if "; + TRACE("pb", tout << mk_pp(t, m) << " ::= (if "; ctx.display_detailed_literal(tout, a); ctx.display_detailed_literal(tout << " ", b); ctx.display_detailed_literal(tout << " ", c); @@ -765,7 +765,7 @@ namespace smt { if (b != null_literal) lits.push_back(b); if (c != null_literal) lits.push_back(c); justification* js = 0; - TRACE("card", + TRACE("pb", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";); ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX, 0); } @@ -815,12 +815,12 @@ namespace smt { } sn(in, out); literal at_least_k = se.internalize(c, out[k-1].get()); // first k outputs are 1. - TRACE("card", tout << "at_least: " << mk_pp(out[k-1].get(), m) << "\n";); + TRACE("pb", tout << "at_least: " << mk_pp(out[k-1].get(), m) << "\n";); literal thl = c.lit(); se.add_clause(~thl, at_least_k); se.add_clause(thl, ~at_least_k); - TRACE("card", tout << c.lit() << "\n";); + TRACE("pb", tout << c.lit() << "\n";); // auxiliary clauses get removed when popping scopes. // we have to recompile the circuit after back-tracking. c.m_compiled = l_false; @@ -938,7 +938,7 @@ namespace smt { inc_propagations(c); m_stats.m_num_propagations++; context& ctx = get_context(); - TRACE("card", tout << "#prop:" << c.m_num_propagations << " - "; + TRACE("pb", tout << "#prop:" << c.m_num_propagations << " - "; for (unsigned i = 0; i < lits.size(); ++i) { tout << lits[i] << " "; } @@ -956,7 +956,7 @@ namespace smt { inc_propagations(c); m_stats.m_num_conflicts++; context& ctx = get_context(); - TRACE("card", tout << "#prop:" << c.m_num_propagations << " - "; + TRACE("pb", tout << "#prop:" << c.m_num_propagations << " - "; for (unsigned i = 0; i < lits.size(); ++i) { tout << lits[i] << " "; } @@ -1110,7 +1110,7 @@ namespace smt { } - TRACE("card", display(tout, m_lemma);); + TRACE("pb", display(tout, m_lemma);); IF_VERBOSE(1, display(verbose_stream(), m_lemma);); } diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 2d23b97d6..b477e6bb7 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -21,7 +21,7 @@ Notes: --*/ #include "smt_theory.h" -#include "card_decl_plugin.h" +#include "pb_decl_plugin.h" #include "smt_clause.h" namespace smt { @@ -105,7 +105,7 @@ namespace smt { ptr_vector m_assign_ineqs_trail; unsigned_vector m_assign_ineqs_lim; literal_vector m_literals; // temporary vector - card_util m_util; + pb_util m_util; stats m_stats; ptr_vector m_to_compile; // inequalities to compile. diff --git a/src/tactic/arith/lia2card_tactic.cpp b/src/tactic/arith/lia2card_tactic.cpp index 5130eea9d..ec2368ba8 100644 --- a/src/tactic/arith/lia2card_tactic.cpp +++ b/src/tactic/arith/lia2card_tactic.cpp @@ -22,7 +22,7 @@ Notes: #include"ast_pp.h" #include"expr_safe_replace.h" // NB: should use proof-producing expr_substitute in polished version. -#include"card_decl_plugin.h" +#include"pb_decl_plugin.h" #include"arith_decl_plugin.h" class lia2card_tactic : public tactic { @@ -31,7 +31,7 @@ class lia2card_tactic : public tactic { typedef obj_hashtable expr_set; ast_manager & m; arith_util a; - card_util m_card; + pb_util m_pb; obj_map > m_uses; obj_map m_converted; expr_set m_01s; @@ -39,7 +39,7 @@ class lia2card_tactic : public tactic { imp(ast_manager & _m, params_ref const & p): m(_m), a(m), - m_card(m) { + m_pb(m) { } void set_cancel(bool f) { @@ -73,7 +73,7 @@ class lia2card_tactic : public tactic { bounds.has_lower(x, lo, s1) && !s1 && lo.is_zero() && bounds.has_upper(x, hi, s2) && !s2 && hi.is_one()) { m_01s.insert(x); - TRACE("card", tout << "add bound " << mk_pp(x, m) << "\n";); + TRACE("pb", tout << "add bound " << mk_pp(x, m) << "\n";); } } if (m_01s.empty()) { @@ -117,7 +117,7 @@ class lia2card_tactic : public tactic { } g->inc_depth(); result.push_back(g.get()); - TRACE("card", g->display(tout);); + TRACE("pb", g->display(tout);); SASSERT(g->is_well_sorted()); // TBD: convert models for 0-1 variables. @@ -181,13 +181,13 @@ class lia2card_tactic : public tactic { sub.insert(fml, mk_ge(y, n)); } else if (is_add(x, args) && is_unsigned(y, k)) { // x <= k - sub.insert(fml, m_card.mk_at_most_k(args.size(), args.c_ptr(), k)); + sub.insert(fml, m_pb.mk_at_most_k(args.size(), args.c_ptr(), k)); } else if (is_add(y, args) && is_unsigned(x, k)) { // k <= y <=> not (y <= k-1) if (k == 0) sub.insert(fml, m.mk_true()); else - sub.insert(fml, m.mk_not(m_card.mk_at_most_k(args.size(), args.c_ptr(), k-1))); + sub.insert(fml, m.mk_not(m_pb.mk_at_most_k(args.size(), args.c_ptr(), k-1))); } else { UNREACHABLE(); @@ -204,10 +204,10 @@ class lia2card_tactic : public tactic { if (k == 0) sub.insert(fml, m.mk_false()); else - sub.insert(fml, m_card.mk_at_most_k(args.size(), args.c_ptr(), k-1)); + sub.insert(fml, m_pb.mk_at_most_k(args.size(), args.c_ptr(), k-1)); } else if (is_add(y, args) && is_unsigned(x, k)) { // k < y <=> not (y <= k) - sub.insert(fml, m.mk_not(m_card.mk_at_most_k(args.size(), args.c_ptr(), k))); + sub.insert(fml, m.mk_not(m_pb.mk_at_most_k(args.size(), args.c_ptr(), k))); } else { UNREACHABLE(); @@ -304,7 +304,7 @@ class lia2card_tactic : public tactic { } return true; } - TRACE("card", tout << "Use not validated: " << mk_pp(fml, m) << "\n";); + TRACE("pb", tout << "Use not validated: " << mk_pp(fml, m) << "\n";); return false; } From 0ff1b63307c1376f1536d5f5f957f050dd02dac7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Nov 2013 21:26:23 -0800 Subject: [PATCH 147/925] remove theory_card Signed-off-by: Nikolaj Bjorner --- src/smt/smt_setup.cpp | 1 - src/smt/theory_card.cpp | 771 ---------------------------------------- src/smt/theory_card.h | 118 ------ 3 files changed, 890 deletions(-) delete mode 100644 src/smt/theory_card.cpp delete mode 100644 src/smt/theory_card.h diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index a9fa1766e..50173ef5d 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -31,7 +31,6 @@ Revision History: #include"theory_dummy.h" #include"theory_dl.h" #include"theory_seq_empty.h" -#include"theory_card.h" #include"theory_pb.h" namespace smt { diff --git a/src/smt/theory_card.cpp b/src/smt/theory_card.cpp deleted file mode 100644 index f0f156c99..000000000 --- a/src/smt/theory_card.cpp +++ /dev/null @@ -1,771 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - theory_card.cpp - -Abstract: - - Cardinality theory plugin. - -Author: - - Nikolaj Bjorner (nbjorner) 2013-11-05 - -Notes: - - - Uses cutting plane simplification on 'k' for repeated literals. - In other words, if the gcd of the multiplicity of literals in c3 - is g, then divide through by g and truncate k. - - Example: - ((_ at-most 3) x1 x1 x2 x2) == ((_ at-most 1) x1 x2) - - - When number of conflicts exceeds n*log(n), - then create a sorting circuit. - where n is the arity of the cardinality constraint. - - - TBD: add conflict resolution - The idea is that if cardinality constraints c1, c2 - are repeatedly asserted together, then - resolve them into combined cardinality constraint c3 - - c1 /\ c2 -> c3 - - That is, during a propagation, assignment or conflict resolution - step track cutting-planes. - - - TBD: profile overhead of (re)creating sorting circuits. - Possibly delay creating them until restart. - - - TBD: deal with integer overflows. - - - - ---*/ - -#include "theory_card.h" -#include "smt_context.h" -#include "ast_pp.h" -#include "sorting_network.h" - -namespace smt { - - theory_card::theory_card(ast_manager& m): - theory(m.mk_family_id("pb")), - m_util(m) - {} - - theory_card::~theory_card() { - reset_eh(); - } - - theory * theory_card::mk_fresh(context * new_ctx) { - return alloc(theory_card, new_ctx->get_manager()); - } - - bool theory_card::internalize_atom(app * atom, bool gate_ctx) { - context& ctx = get_context(); - ast_manager& m = get_manager(); - unsigned num_args = atom->get_num_args(); - SASSERT(m_util.is_at_most_k(atom) || m_util.is_le(atom)); - int k = m_util.get_k(atom); - - - if (ctx.b_internalized(atom)) { - return false; - } - - m_stats.m_num_predicates++; - - TRACE("pb", tout << "internalize: " << mk_pp(atom, m) << "\n";); - - SASSERT(!ctx.b_internalized(atom)); - bool_var abv = ctx.mk_bool_var(atom); - - card* c = alloc(card, m, atom, abv, k, get_compilation_threshold(atom)); - - for (unsigned i = 0; i < num_args; ++i) { - expr* arg = atom->get_arg(i); - if (!ctx.b_internalized(arg)) { - ctx.internalize(arg, false); - } - bool_var bv; - bool has_bv = false; - if (!m.is_not(arg) && ctx.b_internalized(arg)) { - bv = ctx.get_bool_var(arg); - - if (null_theory_var == ctx.get_var_theory(bv)) { - ctx.set_var_theory(bv, get_id()); - has_bv = true; - } - else if (get_id() == ctx.get_var_theory(bv)) { - has_bv = true; - } - } - // pre-processing should better remove negations under cardinality. - // assumes relevancy level = 2 or 0. - if (!has_bv) { - expr_ref tmp(m), fml(m); - tmp = m.mk_fresh_const("card_proxy",m.mk_bool_sort()); - fml = m.mk_iff(tmp, arg); - ctx.internalize(fml, false); - SASSERT(ctx.b_internalized(tmp)); - bv = ctx.get_bool_var(tmp); - SASSERT(null_theory_var == ctx.get_var_theory(bv)); - ctx.set_var_theory(bv, get_id()); - literal lit(ctx.get_bool_var(fml)); - ctx.mk_th_axiom(get_id(), 1, &lit); - ctx.mark_as_relevant(tmp); - } - int coeff = m_util.get_le_coeff(atom, i); - c->m_args.push_back(std::make_pair(bv, coeff)); - } - add_card(c); - return true; - } - - void theory_card::add_watch(bool_var bv, card* c) { - ptr_vector* cards; - if (!m_watch.find(bv, cards)) { - cards = alloc(ptr_vector); - m_watch.insert(bv, cards); - } - cards->push_back(c); - m_watch_trail.push_back(bv); - } - - static unsigned gcd(unsigned a, unsigned b) { - while (a != b) { - if (a == 0) return b; - if (b == 0) return a; - SASSERT(a != 0 && b != 0); - if (a < b) { - b %= a; - } - else { - a %= b; - } - } - return a; - } - - void theory_card::add_card(card* c) { - bool_var abv = c->m_bv; - arg_t& args = c->m_args; - - // sort and coalesce arguments: - std::sort(args.begin(), args.end()); - for (unsigned i = 0; i + 1 < args.size(); ++i) { - if (args[i].first == args[i+1].first) { - args[i].second += args[i+1].second; - for (unsigned j = i+1; j + 1 < args.size(); ++j) { - args[j] = args[j+1]; - } - args.resize(args.size()-1); - } - if (args[i].second == 0) { - for (unsigned j = i; j + 1 < args.size(); ++j) { - args[j] = args[j+1]; - } - args.resize(args.size()-1); - } - } - // apply cutting plane reduction: - if (!args.empty()) { - unsigned g = abs(args[0].second); - for (unsigned i = 1; g > 1 && i < args.size(); ++i) { - g = gcd(g, abs(args[i].second)); - } - if (g > 1) { - int k = c->m_k; - if (k >= 0) { - c->m_k /= g; - } - else { - // watch out for truncation semantcs for k < 0! - k = abs(k); - k += (k % g); - k /= g; - c->m_k = -k; - } - for (unsigned i = 0; i < args.size(); ++i) { - args[i].second /= g; - } - } - } - - int min = 0, max = 0; - for (unsigned i = 0; i < args.size(); ++i) { - // update min and max: - int inc = args[i].second; - if (inc > 0) { - max += inc; - } - else { - SASSERT(inc < 0); - min += inc; - } - // add watch literals: - add_watch(args[i].first, c); - } - c->m_current_min = c->m_abs_min = min; - c->m_current_max = c->m_abs_max = max; - m_cards.insert(abv, c); - m_cards_trail.push_back(abv); - } - - void theory_card::collect_statistics(::statistics& st) const { - st.update("pb axioms", m_stats.m_num_axioms); - st.update("pb propagations", m_stats.m_num_propagations); - st.update("pb predicates", m_stats.m_num_predicates); - st.update("pb compilations", m_stats.m_num_compiles); - } - - void theory_card::reset_eh() { - - // m_watch; - u_map*>::iterator it = m_watch.begin(), end = m_watch.end(); - for (; it != end; ++it) { - dealloc(it->m_value); - } - u_map::iterator itc = m_cards.begin(), endc = m_cards.end(); - for (; itc != endc; ++itc) { - dealloc(itc->m_value); - } - m_watch.reset(); - m_cards.reset(); - m_cards_trail.reset(); - m_cards_lim.reset(); - m_watch_trail.reset(); - m_watch_lim.reset(); - m_stats.reset(); - } - - void theory_card::update_min_max(bool_var v, bool is_true, card& c) { - context& ctx = get_context(); - ast_manager& m = get_manager(); - arg_t const& args = c.m_args; - int inc = find_inc(v, args); - int& min = c.m_current_min; - int& max = c.m_current_max; - int k = c.m_k; - // inc > 0 & is_true -> min += inc - // inc < 0 & is_true -> max += inc - // inc > 0 & !is_true -> max -= inc - // inc < 0 & !is_true -> min -= inc - - if (inc > 0 && is_true) { - ctx.push_trail(value_trail(min)); - min += inc; - } - else if (inc < 0 && is_true) { - ctx.push_trail(value_trail(max)); - max += inc; - } - else if (inc > 0 && !is_true) { - ctx.push_trail(value_trail(max)); - max -= inc; - } - else { - ctx.push_trail(value_trail(min)); - min -= inc; - } - // invariant min <= max - SASSERT(min <= max); - } - - void theory_card::assign_use(bool_var v, bool is_true, card& c) { - update_min_max(v, is_true, c); - propagate_assignment(c); - } - - lbool theory_card::inc_min(int inc, lbool val) { - if (inc > 0) { - return val; - } - else if (inc < 0) { - return ~val; - } - else { - return l_undef; - } - } - - lbool theory_card::dec_max(int inc, lbool val) { - if (inc > 0) { - return ~val; - } - else if (inc < 0) { - return val; - } - else { - return l_undef; - } - } - - int theory_card::accumulate_min(literal_vector& lits, card& c) { - context& ctx = get_context(); - int k = c.m_k; - arg_t const& args = c.m_args; - int curr_min = c.m_abs_min; - for (unsigned i = 0; i < args.size() && curr_min <= k; ++i) { - bool_var bv = args[i].first; - int inc = args[i].second; - lbool val = ctx.get_assignment(bv); - if (inc_min(inc, val) == l_true) { - curr_min += abs(inc); - lits.push_back(literal(bv, val == l_true)); - } - } - return curr_min; - } - - int theory_card::get_max_delta(card& c) { - if (m_util.is_at_most_k(c.m_app)) { - return 1; - } - int max = 0; - context& ctx = get_context(); - for (unsigned i = 0; i < c.m_args.size(); ++i) { - if (c.m_args[i].second > max && ctx.get_assignment(c.m_args[i].first) == l_undef) { - max = c.m_args[i].second; - } - } - return max; - } - - - int theory_card::accumulate_max(literal_vector& lits, card& c) { - context& ctx = get_context(); - arg_t const& args = c.m_args; - int k = c.m_k; - int curr_max = c.m_abs_max; - for (unsigned i = 0; i < args.size() && k < curr_max; ++i) { - bool_var bv = args[i].first; - int inc = args[i].second; - lbool val = ctx.get_assignment(bv); - if (dec_max(inc, val) == l_true) { - curr_max -= abs(inc); - lits.push_back(literal(bv, val == l_true)); - } - } - return curr_max; - } - - void theory_card::propagate_assignment(card& c) { - if (c.m_compiled) { - return; - } - if (should_compile(c)) { - compile_at_most(c); - return; - } - context& ctx = get_context(); - ast_manager& m = get_manager(); - arg_t const& args = c.m_args; - bool_var abv = c.m_bv; - int min = c.m_current_min; - int max = c.m_current_max; - int k = c.m_k; - - TRACE("pb", - tout << mk_pp(c.m_app, m) << " min: " - << min << " max: " << max << "\n";); - - // - // if min > k && abv != l_false -> force abv false - // if max <= k && abv != l_true -> force abv true - // if min == k && abv == l_true -> force positive - // unassigned literals false - // if max == k + 1 && abv == l_false -> force negative - // unassigned literals false - // - lbool aval = ctx.get_assignment(abv); - if (min > k && aval != l_false) { - literal_vector& lits = get_lits(); - int curr_min = accumulate_min(lits, c); - SASSERT(curr_min > k); - add_assign(c, lits, ~literal(abv)); - } - else if (max <= k && aval != l_true) { - literal_vector& lits = get_lits(); - int curr_max = accumulate_max(lits, c); - SASSERT(curr_max <= k); - add_assign(c, lits, literal(abv)); - } - else if (min <= k && k < min + get_max_delta(c) && aval == l_true) { - literal_vector& lits = get_lits(); - lits.push_back(~literal(abv)); - int curr_min = accumulate_min(lits, c); - if (curr_min > k) { - add_clause(c, lits); - } - else { - for (unsigned i = 0; i < args.size(); ++i) { - bool_var bv = args[i].first; - int inc = args[i].second; - if (curr_min + inc > k && inc_min(inc, ctx.get_assignment(bv)) == l_undef) { - add_assign(c, lits, literal(bv, inc > 0)); - } - } - } - } - else if (max - get_max_delta(c) <= k && k < max && aval == l_false) { - literal_vector& lits = get_lits(); - lits.push_back(literal(abv)); - int curr_max = accumulate_max(lits, c); - if (curr_max <= k) { - add_clause(c, lits); - } - else { - for (unsigned i = 0; i < args.size(); ++i) { - bool_var bv = args[i].first; - int inc = args[i].second; - if (curr_max - abs(inc) <= k && dec_max(inc, ctx.get_assignment(bv)) == l_undef) { - add_assign(c, lits, literal(bv, inc < 0)); - } - } - } - } -#if 0 - else if (aval == l_true) { - SASSERT(min < k); - literal_vector& lits = get_lits(); - int curr_min = accumulate_min(lits, c); - bool all_inc = curr_min == k; - unsigned num_incs = 0; - for (unsigned i = 0; all_inc && i < args.size(); ++i) { - bool_var bv = args[i].first; - int inc = args[i].second; - if (inc_min(inc, ctx.get_assignment(bv)) == l_undef) { - all_inc = inc + min > k; - num_incs++; - } - } - if (num_incs > 0) { - std::cout << "missed T propgations " << num_incs << "\n"; - } - } - else if (aval == l_false) { - literal_vector& lits = get_lits(); - lits.push_back(literal(abv)); - int curr_max = accumulate_max(lits, c); - bool all_dec = curr_max > k; - unsigned num_decs = 0; - for (unsigned i = 0; all_dec && i < args.size(); ++i) { - bool_var bv = args[i].first; - int inc = args[i].second; - if (dec_max(inc, ctx.get_assignment(bv)) == l_undef) { - all_dec = inc + max <= k; - num_decs++; - } - } - if (num_decs > 0) { - std::cout << "missed F propgations " << num_decs << "\n"; - } - } -#endif - } - - void theory_card::assign_eh(bool_var v, bool is_true) { - context& ctx = get_context(); - ast_manager& m = get_manager(); - ptr_vector* cards = 0; - card* c = 0; - TRACE("pb", tout << "assign: " << mk_pp(ctx.bool_var2expr(v), m) << " <- " << is_true << "\n";); - - if (m_watch.find(v, cards)) { - for (unsigned i = 0; i < cards->size(); ++i) { - assign_use(v, is_true, *(*cards)[i]); - } - } - if (m_cards.find(v, c)) { - propagate_assignment(*c); - } - } - - int theory_card::find_inc(bool_var bv, svector >const& vars) { - unsigned mid = vars.size()/2; - unsigned lo = 0; - unsigned hi = vars.size()-1; - while (lo < hi) { - if (vars[mid].first == bv) { - return vars[mid].second; - } - else if (vars[mid].first < bv) { - lo = mid; - mid += (hi-mid)/2 + 1; - } - else { - hi = mid; - mid = (mid-lo)/2 + lo; - } - } - SASSERT(vars[mid].first == bv); - return vars[mid].second; - } - - struct theory_card::sort_expr { - theory_card& th; - context& ctx; - ast_manager& m; - expr_ref_vector m_trail; - sort_expr(theory_card& th): - th(th), - ctx(th.get_context()), - m(th.get_manager()), - m_trail(m) {} - typedef expr* T; - typedef expr_ref_vector vector; - - T mk_ite(T a, T b, T c) { - if (m.is_true(a)) { - return b; - } - if (m.is_false(a)) { - return c; - } - if (b == c) { - return b; - } - m_trail.push_back(m.mk_ite(a, b, c)); - return m_trail.back(); - } - - T mk_le(T a, T b) { - return mk_ite(b, a, m.mk_true()); - } - - T mk_default() { - return m.mk_false(); - } - - literal internalize(card& ca, expr* e) { - obj_map cache; - for (unsigned i = 0; i < ca.m_args.size(); ++i) { - bool_var bv = ca.m_args[i].first; - cache.insert(ctx.bool_var2expr(bv), literal(bv)); - } - cache.insert(m.mk_false(), false_literal); - cache.insert(m.mk_true(), true_literal); - ptr_vector todo; - todo.push_back(e); - expr *a, *b, *c; - literal la, lb, lc; - while (!todo.empty()) { - expr* t = todo.back(); - if (cache.contains(t)) { - todo.pop_back(); - continue; - } - VERIFY(m.is_ite(t, a, b, c)); - unsigned sz = todo.size(); - if (!cache.find(a, la)) { - todo.push_back(a); - } - if (!cache.find(b, lb)) { - todo.push_back(b); - } - if (!cache.find(c, lc)) { - todo.push_back(c); - } - if (sz != todo.size()) { - continue; - } - todo.pop_back(); - cache.insert(t, mk_ite(ca, t, la, lb, lc)); - } - return cache.find(e); - } - - literal mk_ite(card& ca, expr* t, literal a, literal b, literal c) { - if (a == true_literal) { - return b; - } - else if (a == false_literal) { - return c; - } - else if (b == true_literal && c == false_literal) { - return a; - } - else if (b == false_literal && c == true_literal) { - return ~a; - } - else if (b == c) { - return b; - } - else { - expr_ref p(m); - expr* r; - if (ca.m_replay.find(t, r)) { - p = r; - } - else { - p = m.mk_fresh_const("s", m.mk_bool_sort()); - ca.m_replay.insert(t, p); - ca.m_trail.push_back(p); - } - literal l; - if (ctx.b_internalized(p)) { - l = literal(ctx.get_bool_var(p)); - } - else { - l = literal(ctx.mk_bool_var(p)); - } - add_clause(~l, ~a, b); - add_clause(~l, a, c); - add_clause(l, ~a, ~b); - add_clause(l, a, ~c); - TRACE("pb", tout << p << " ::= (if "; - ctx.display_detailed_literal(tout, a); - ctx.display_detailed_literal(tout << " ", b); - ctx.display_detailed_literal(tout << " ", c); - tout << ")\n";); - return l; - } - } - - - // auxiliary clauses don't get garbage collected. - void add_clause(literal a, literal b, literal c) { - literal_vector& lits = th.get_lits(); - if (a != null_literal) lits.push_back(a); - if (b != null_literal) lits.push_back(b); - if (c != null_literal) lits.push_back(c); - justification* js = 0; - TRACE("pb", - ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";); - ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX, 0); - } - - void add_clause(literal l1, literal l2) { - add_clause(l1, l2, null_literal); - } - - }; - - unsigned theory_card::get_compilation_threshold(app* a) { - if (!m_util.is_at_most_k(a)) { - return UINT_MAX; - } - unsigned num_args = a->get_num_args(); - unsigned log = 1, n = 1; - while (n <= num_args) { - ++log; - n *= 2; - } - TRACE("pb", tout << "threshold:" << (num_args*log) << "\n";); - return num_args*log; - } - - bool theory_card::should_compile(card& c) { -#if 1 - return false; -#else - if (!m_util.is_at_most_k(c.m_app)) { - return false; - } - return c.m_num_propagations >= c.m_compilation_threshold; -#endif - } - - void theory_card::compile_at_most(card& c) { - ++m_stats.m_num_compiles; - ast_manager& m = get_manager(); - context& ctx = get_context(); - app* a = c.m_app; - SASSERT(m_util.is_at_most_k(a)); - literal atmostk; - int k = m_util.get_k(a); - unsigned num_args = c.m_args.size(); - - sort_expr se(*this); - if (k >= static_cast(num_args)) { - atmostk = true_literal; - } - else if (k < 0) { - atmostk = false_literal; - } - else { - sorting_network sn(se); - expr_ref_vector in(m), out(m); - for (unsigned i = 0; i < num_args; ++i) { - in.push_back(ctx.bool_var2expr(c.m_args[i].first)); - } - sn(in, out); - atmostk = ~se.internalize(c, out[k].get()); // k'th output is 0. - TRACE("pb", tout << "~atmost: " << mk_pp(out[k].get(), m) << "\n";); - } - literal thl = literal(c.m_bv); - se.add_clause(~thl, atmostk); - se.add_clause(thl, ~atmostk); - TRACE("pb", tout << mk_pp(a, m) << "\n";); - // auxiliary clauses get removed when popping scopes. - // we have to recompile the circuit after back-tracking. - ctx.push_trail(value_trail(c.m_compiled)); - c.m_compiled = true; - } - - - void theory_card::init_search_eh() { - - } - - void theory_card::push_scope_eh() { - m_watch_lim.push_back(m_watch_trail.size()); - m_cards_lim.push_back(m_cards_trail.size()); - } - - void theory_card::pop_scope_eh(unsigned num_scopes) { - unsigned sz = m_watch_lim[m_watch_lim.size()-num_scopes]; - while (m_watch_trail.size() > sz) { - ptr_vector* cards = 0; - VERIFY(m_watch.find(m_watch_trail.back(), cards)); - SASSERT(cards && !cards->empty()); - cards->pop_back(); - m_watch_trail.pop_back(); - } - m_watch_lim.resize(m_watch_lim.size()-num_scopes); - sz = m_cards_lim[m_cards_lim.size()-num_scopes]; - while (m_cards_trail.size() > sz) { - SASSERT(m_cards.contains(m_cards_trail.back())); - m_cards.remove(m_cards_trail.back()); - m_cards_trail.pop_back(); - } - m_cards_lim.resize(m_cards_lim.size()-num_scopes); - } - - - literal_vector& theory_card::get_lits() { - m_literals.reset(); - return m_literals; - } - - void theory_card::add_assign(card& c, literal_vector const& lits, literal l) { - literal_vector ls; - ++c.m_num_propagations; - m_stats.m_num_propagations++; - context& ctx = get_context(); - for (unsigned i = 0; i < lits.size(); ++i) { - ls.push_back(~lits[i]); - } - ctx.assign(l, ctx.mk_justification(theory_propagation_justification(get_id(), ctx.get_region(), ls.size(), ls.c_ptr(), l))); - } - - - - void theory_card::add_clause(card& c, literal_vector const& lits) { - ++c.m_num_propagations; - m_stats.m_num_axioms++; - context& ctx = get_context(); - TRACE("pb", tout << "#prop:" << c.m_num_propagations << " - "; ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";); - justification* js = 0; - ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); - IF_VERBOSE(2, ctx.display_literals_verbose(verbose_stream(), - lits.size(), lits.c_ptr()); - verbose_stream() << "\n";); - // ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); - } -} diff --git a/src/smt/theory_card.h b/src/smt/theory_card.h deleted file mode 100644 index 0f425c103..000000000 --- a/src/smt/theory_card.h +++ /dev/null @@ -1,118 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - theory_card.h - -Abstract: - - Cardinality theory plugin. - -Author: - - Nikolaj Bjorner (nbjorner) 2013-11-05 - -Notes: - - This custom theory handles cardinality constraints - It performs unit propagation and switches to creating - sorting circuits if it keeps having to propagate (create new clauses). ---*/ - -#include "smt_theory.h" -#include "pb_decl_plugin.h" -#include "smt_clause.h" - -namespace smt { - class theory_card : public theory { - - struct sort_expr; - typedef svector > arg_t; - - struct stats { - unsigned m_num_axioms; - unsigned m_num_propagations; - unsigned m_num_predicates; - unsigned m_num_compiles; - void reset() { memset(this, 0, sizeof(*this)); } - stats() { reset(); } - }; - - - struct card { - app* m_app; - int m_k; - bool_var m_bv; - int m_current_min; - int m_current_max; - int m_abs_min; - int m_abs_max; - arg_t m_args; - unsigned m_num_propagations; - unsigned m_compilation_threshold; - bool m_compiled; - obj_map m_replay; - expr_ref_vector m_trail; - card(ast_manager& m, app* a, bool_var bv, int k, unsigned threshold): - m_app(a), m_k(k), m_bv(bv), - m_num_propagations(0), m_compilation_threshold(threshold), m_compiled(false), - m_trail(m) - { - } - }; - - u_map*> m_watch; // use-list of literals. - u_map m_cards; // bool_var |-> card - unsigned_vector m_cards_trail; - unsigned_vector m_cards_lim; - unsigned_vector m_watch_trail; - unsigned_vector m_watch_lim; - literal_vector m_literals; - pb_util m_util; - stats m_stats; - - void add_watch(bool_var bv, card* c); - void add_card(card* c); - - void add_clause(card& c, literal_vector const& lits); - void add_assign(card& c, literal_vector const& lits, literal l); - literal_vector& get_lits(); - - int find_inc(bool_var bv, svector >const& vars); - void propagate_assignment(card& c); - int get_max_delta(card& c); - int accumulate_max(literal_vector& lits, card& c); - int accumulate_min(literal_vector& lits, card& c); - lbool dec_max(int inc, lbool val); - lbool inc_min(int inc, lbool val); - void assign_use(bool_var v, bool is_true, card& c); - void update_min_max(bool_var v, bool is_true, card& c); - - void compile_at_most(card& c); - expr_ref nnf(expr* e); - bool should_compile(card& c); - unsigned get_compilation_threshold(app* atom); - public: - theory_card(ast_manager& m); - - virtual ~theory_card(); - - virtual theory * mk_fresh(context * new_ctx); - virtual bool internalize_atom(app * atom, bool gate_ctx); - virtual bool internalize_term(app * term) { UNREACHABLE(); return false; } - virtual void new_eq_eh(theory_var v1, theory_var v2) { } - virtual void new_diseq_eh(theory_var v1, theory_var v2) { } - virtual bool use_diseqs() const { return false; } - virtual bool build_models() const { return false; } - virtual final_check_status final_check_eh() { return FC_DONE; } - - virtual void reset_eh(); - virtual void assign_eh(bool_var v, bool is_true); - virtual void init_search_eh(); - virtual void push_scope_eh(); - virtual void pop_scope_eh(unsigned num_scopes); - virtual void collect_statistics(::statistics & st) const; - - }; -}; From 475072f5da7c507a2c9421a85ccfdfa5185b277e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Nov 2013 21:27:36 -0800 Subject: [PATCH 148/925] remove theory_card Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index be83d446f..b6fbea01b 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -351,7 +351,7 @@ namespace smt { // is available. if (!has_bv) { expr_ref tmp(m), fml(m); - tmp = m.mk_fresh_const("card_proxy",m.mk_bool_sort()); + tmp = m.mk_fresh_const("pb_proxy",m.mk_bool_sort()); fml = m.mk_iff(tmp, arg); ctx.internalize(fml, false); SASSERT(ctx.b_internalized(tmp)); From efecb9b6c06b06e5c1fcade4aa45e37ffe8da1d4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Nov 2013 21:51:56 -0800 Subject: [PATCH 149/925] working on pb Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 37 ++++++++++++++++++++++++------------- src/smt/theory_pb.h | 2 +- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index b6fbea01b..73586dba5 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -545,7 +545,7 @@ namespace smt { if (maxsum < c.k()) { literal_vector& lits = get_unhelpful_literals(c, false); lits.push_back(~c.lit()); - add_clause(c, c.lit(), lits); + add_clause(c, ~c.lit(), lits); } else { c.m_max_sum = 0; @@ -598,7 +598,7 @@ namespace smt { // literal_vector& lits = get_unhelpful_literals(c, false); lits.push_back(~c.lit()); - add_clause(c, literal(v, !is_true), lits); + add_clause(c, ~literal(v, !is_true), lits); } else { del_watch(watch, watch_index, c, w); @@ -892,7 +892,7 @@ namespace smt { } } - std::ostream& theory_pb::display(std::ostream& out, ineq& c) const { + std::ostream& theory_pb::display(std::ostream& out, ineq& c, bool values) const { ast_manager& m = get_manager(); context& ctx = get_context(); out << c.lit() << " "; @@ -902,7 +902,15 @@ namespace smt { out << tmp << "\n"; } for (unsigned i = 0; i < c.size(); ++i) { - out << c.coeff(i) << "*" << c.lit(i); + literal l(c.lit(i)); + out << c.coeff(i) << "*" << l; + if (values) { + out << "@(" << ctx.get_assignment(l); + if (ctx.get_assignment(l) != l_undef) { + out << ":" << ctx.get_assign_level(l); + } + out << ")"; + } if (i + 1 < c.size()) { out << " + "; } @@ -943,7 +951,7 @@ namespace smt { tout << lits[i] << " "; } tout << "=> " << l << "\n"; - display(tout, c);); + display(tout, c, true);); ctx.assign(l, ctx.mk_justification( pb_justification( @@ -961,7 +969,7 @@ namespace smt { tout << lits[i] << " "; } tout << "\n"; - display(tout, c);); + display(tout, c, true);); DEBUG_CODE( if (s_debug_conflict) { @@ -1016,19 +1024,22 @@ namespace smt { // void theory_pb::resolve_conflict(literal conseq, ineq& c) { - IF_VERBOSE(0, display(verbose_stream(), c);); + IF_VERBOSE(0, verbose_stream() << conseq << "\n"; display(verbose_stream(), c, true);); bool_var v; context& ctx = get_context(); - unsigned& lvl = m_conflict_lvl = ctx.get_assign_level(c.lit()); + unsigned& lvl = m_conflict_lvl = 0; + bool found = false; for (unsigned i = 0; i < c.size(); ++i) { - v = c.lit(i).var(); - if (ctx.get_assignment(v) != l_undef) { - IF_VERBOSE(0, verbose_stream() << c.lit(i) << " " - << ctx.get_assign_level(v) << "\n";); - lvl = std::max(lvl, ctx.get_assign_level(v)); + if (ctx.get_assignment(c.lit(i)) == l_false) { + lvl = std::max(lvl, ctx.get_assign_level(c.lit(i))); } + found = found || (~conseq == c.lit(i)); } + SASSERT(lvl >= ctx.get_assign_level(c.lit())); + SASSERT(ctx.get_assignment(conseq) == l_true); + SASSERT(found); // conseq is negative in c + if (lvl == ctx.get_base_level()) { return; diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index b477e6bb7..432378365 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -116,7 +116,7 @@ namespace smt { bool assign_watch(bool_var v, bool is_true, watch_list& watch, unsigned index); void assign_ineq(ineq& c, bool is_true); - std::ostream& display(std::ostream& out, ineq& c) const; + std::ostream& display(std::ostream& out, ineq& c, bool values = false) const; virtual void display(std::ostream& out) const; void add_clause(ineq& c, literal conseq, literal_vector const& lits); From 1a8ff9cea4ddf9ebde4b4b7906a70b6f9bd63136 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Nov 2013 22:41:06 -0800 Subject: [PATCH 150/925] working on pb Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 120 ++++++++++++++++++++++++++++++++---------- src/smt/theory_pb.h | 12 +++-- 2 files changed, 101 insertions(+), 31 deletions(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 73586dba5..71dbe703e 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -66,6 +66,10 @@ namespace smt { return a; } + theory_pb::numeral theory_pb::ineq::lcm(numeral a, numeral b) { + return (a*b)/gcd(a,b); + } + lbool theory_pb::ineq::normalize() { numeral& k = m_k; @@ -996,27 +1000,76 @@ namespace smt { if (lvl == m_conflict_lvl) { IF_VERBOSE(0, verbose_stream() << "new mark\n";); ++m_num_marks; + if (v >= static_cast(m_conseq_index.size())) { + m_conseq_index.resize(v+1); + } + m_conseq_index[v] = m_lemma_index; } } - m_lemma.m_args.push_back(std::make_pair(l, coeff)); + SASSERT(m_lemma_index <= m_lemma.size()); + if (m_lemma_index == m_lemma.size()) { + m_lemma.m_args.resize(m_lemma_index+1); + } + m_lemma.m_args[m_lemma_index] = std::make_pair(l, coeff); + m_lemma_index = m_lemma.size(); } - else if (ctx.get_assignment(l) == l_true) { + else if (ctx.get_assignment(l) != l_false) { m_lemma.m_k += coeff; } } - void theory_pb::process_ineq(ineq& c) { - // TBD: create CUT. - // only process literals that were + void theory_pb::process_ineq(ineq& c, literal conseq, numeral coeff1) { + + // + // Create CUT. + // TBD only process literals that were // assigned below current index 'idx'. + // and/or relevant to the conflict. + // + + // + // . find coeff2 + // . find lcm of coefficients to conseq. + // . multiply m_lemma by lcm/coeff coefficient to align. + // . create lcm/coeff_2 to multiply on this side. + // . cut resolve constraints. + // + context& ctx = get_context(); + numeral coeff2 = (conseq==null_literal)?1:0; for (unsigned i = 0; i < c.size(); ++i) { - if (ctx.get_assignment(c.lit(i)) == l_false) { - process_antecedent(c.lit(i), c.coeff(i)); + if (c.lit(i) == conseq) { + coeff2 = c.coeff(i); + break; } } - process_antecedent(~c.lit(), 1); - m_lemma.m_k += c.k(); + SASSERT(coeff2 > 0); + numeral lc = ineq::lcm(coeff1, coeff2); + numeral g = lc/coeff1; + if (g > 1) { + for (unsigned i = 0; i < m_lemma.size(); ++i) { + m_lemma.m_args[i].second *= g; + } + m_lemma.m_k *= g; + } + g = lc/coeff2; + for (unsigned i = 0; i < c.size(); ++i) { + if (ctx.get_assignment(c.lit(i)) == l_false) { + process_antecedent(c.lit(i), g*c.coeff(i)); + } + else if (conseq == c.lit(i)) { + // skip this one. + } + else { + m_lemma.m_k += g*c.coeff(i); + } + } + m_lemma.m_k += g*c.k(); + // + // we most likely want c.lit() to be + // an antecedent in a real clause. + // process_antecedent(~c.lit(), 1); + // } // @@ -1029,48 +1082,60 @@ namespace smt { bool_var v; context& ctx = get_context(); unsigned& lvl = m_conflict_lvl = 0; - bool found = false; + unsigned conseq_index = 0; for (unsigned i = 0; i < c.size(); ++i) { if (ctx.get_assignment(c.lit(i)) == l_false) { lvl = std::max(lvl, ctx.get_assign_level(c.lit(i))); } - found = found || (~conseq == c.lit(i)); + if (~conseq == c.lit(i)) { + conseq_index = i; + } } SASSERT(lvl >= ctx.get_assign_level(c.lit())); SASSERT(ctx.get_assignment(conseq) == l_true); - SASSERT(found); // conseq is negative in c - + SASSERT(conseq_index > 0 || ~conseq == c.lit(0)); // conseq is negative in c if (lvl == ctx.get_base_level()) { return; } - b_justification js(ctx.mk_justification( - pb_justification( - c, get_id(), ctx.get_region(), - 0, 0, c.lit()))); - m_lemma.reset(); m_num_marks = 0; + m_lemma.reset(); + m_lemma_index = 0; + process_ineq(c, null_literal, 1); // add consequent to lemma. + + SASSERT(c.lit(conseq_index) == ~conseq); // point into stack of assigned literals literal_vector const& lits = ctx.assigned_literals(); SASSERT(!lits.empty()); unsigned idx = lits.size()-1; + b_justification js = ctx.get_justification(conseq.var()); + do { // // Resolve selected conseq with antecedents. // IF_VERBOSE(0, verbose_stream() << conseq << " " << js.get_kind() << "\n";); + numeral conseq_coeff = m_lemma.coeff(conseq_index); + m_lemma_index = conseq_index; switch(js.get_kind()) { case b_justification::CLAUSE: { clause& cls = *js.get_clause(); unsigned num_lits = cls.get_num_literals(); - for (unsigned i = 0; i < num_lits; ++i) { - process_antecedent(cls.get_literal(i), 1); + if (cls.get_literal(0) == conseq) { + process_antecedent(cls.get_literal(1), conseq_coeff); } - m_lemma.m_k += 1; + else { + SASSERT(cls.get_literal(1) == conseq); + process_antecedent(cls.get_literal(0), conseq_coeff); + } + for (unsigned i = 2; i < num_lits; ++i) { + process_antecedent(cls.get_literal(i), conseq_coeff); + } + m_lemma.m_k += conseq_coeff; justification* cjs = cls.get_justification(); if (cjs) { // TBD @@ -1079,9 +1144,8 @@ namespace smt { break; } case b_justification::BIN_CLAUSE: - m_lemma.m_k += 1; - process_antecedent(conseq, 1); - process_antecedent(~js.get_literal(), 1); + m_lemma.m_k += conseq_coeff; + process_antecedent(~js.get_literal(), conseq_coeff); break; case b_justification::AXIOM: break; @@ -1091,12 +1155,13 @@ namespace smt { if (j.get_from_theory() != get_id()) break; pb_justification& pbj = dynamic_cast(j); // weaken the lemma and resolve. - process_ineq(pbj.get_ineq()); + process_ineq(pbj.get_ineq(), conseq, conseq_coeff); break; } default: UNREACHABLE(); } + m_lemma.normalize(); // // find the next marked variable in the assignment stack // @@ -1109,7 +1174,9 @@ namespace smt { } while (!ctx.is_marked(v)); - js = ctx.get_justification(v); + conseq_index = m_conseq_index[v]; + + js = ctx.get_justification(v); --m_num_marks; } while (m_num_marks > 0); @@ -1120,7 +1187,6 @@ namespace smt { m_unmark.pop_back(); } - TRACE("pb", display(tout, m_lemma);); IF_VERBOSE(1, display(verbose_stream(), m_lemma);); diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 432378365..3ba8ae67f 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -93,6 +93,7 @@ namespace smt { bool well_formed() const; static numeral gcd(numeral a, numeral b); + static numeral lcm(numeral a, numeral b); }; @@ -137,13 +138,16 @@ namespace smt { // // Conflict resolution, cutting plane derivation. // - unsigned m_num_marks; - unsigned m_conflict_lvl; - ineq m_lemma; + unsigned m_num_marks; + unsigned m_conflict_lvl; + ineq m_lemma; + unsigned_vector m_conseq_index; + unsigned m_lemma_index; svector m_unmark; + void set_next_index(unsigned i); void resolve_conflict(literal conseq, ineq& c); void process_antecedent(literal l, numeral coeff); - void process_ineq(ineq& c); + void process_ineq(ineq& c, literal conseq, numeral coeff); void validate_final_check(); void validate_final_check(ineq& c); From 96921355ccca40c88f90941cc46dc7ac553944f3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Nov 2013 00:54:30 -0800 Subject: [PATCH 151/925] pb solver Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 113 ++++++++++++++++++++---------------------- src/smt/theory_pb.h | 2 - 2 files changed, 55 insertions(+), 60 deletions(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 71dbe703e..1248ef6bc 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -42,7 +42,6 @@ namespace smt { void theory_pb::ineq::reset() { m_max_coeff = 0; m_watch_sz = 0; - m_sum = 0; m_max_sum = 0; m_num_propagations = 0; m_compilation_threshold = UINT_MAX; @@ -476,7 +475,6 @@ namespace smt { void theory_pb::assign_eh(bool_var v, bool is_true) { context& ctx = get_context(); ptr_vector* ineqs = 0; - TRACE("pb", tout << "assign: " << literal(v, !is_true) << "\n";); if (m_watch.find(v, ineqs)) { for (unsigned i = 0; i < ineqs->size(); ++i) { @@ -549,7 +547,7 @@ namespace smt { if (maxsum < c.k()) { literal_vector& lits = get_unhelpful_literals(c, false); lits.push_back(~c.lit()); - add_clause(c, ~c.lit(), lits); + add_clause(c, ~lits[0], lits); } else { c.m_max_sum = 0; @@ -602,7 +600,7 @@ namespace smt { // literal_vector& lits = get_unhelpful_literals(c, false); lits.push_back(~c.lit()); - add_clause(c, ~literal(v, !is_true), lits); + add_clause(c, literal(v, !is_true), lits); } else { del_watch(watch, watch_index, c, w); @@ -919,13 +917,12 @@ namespace smt { out << " + "; } } - out << " >= " << c.m_k << "\n" - << "propagations: " << c.m_num_propagations - << " max_coeff: " << c.max_coeff() - << " watch size: " << c.watch_size() - << " sum: " << c.sum() - << " max-sum: " << c.max_sum() - << "\n"; + out << " >= " << c.m_k << "\n"; + if (c.m_num_propagations) out << "propagations: " << c.m_num_propagations << " "; + if (c.max_coeff()) out << "max_coeff: " << c.max_coeff() << " "; + if (c.watch_size()) out << "watch size: " << c.watch_size() << " "; + if (c.max_sum()) out << "max-sum: " << c.max_sum() << " "; + if (c.m_num_propagations || c.max_coeff() || c.watch_size() || c.max_sum()) out << "\n"; return out; } @@ -992,13 +989,16 @@ namespace smt { context& ctx = get_context(); bool_var v = l.var(); unsigned lvl = ctx.get_assign_level(v); - IF_VERBOSE(0, verbose_stream() << "ante: " << l << "*" << coeff << " " << lvl << "\n";); - if (lvl > ctx.get_base_level()) { + IF_VERBOSE(2, verbose_stream() << "ante: " << l << "*" << coeff << " " << lvl << "\n";); + + if (ctx.get_assignment(l) != l_false) { + m_lemma.m_k -= coeff; + } + else if (lvl > ctx.get_base_level()) { if (!ctx.is_marked(v)) { ctx.set_mark(v); m_unmark.push_back(v); if (lvl == m_conflict_lvl) { - IF_VERBOSE(0, verbose_stream() << "new mark\n";); ++m_num_marks; if (v >= static_cast(m_conseq_index.size())) { m_conseq_index.resize(v+1); @@ -1013,9 +1013,6 @@ namespace smt { m_lemma.m_args[m_lemma_index] = std::make_pair(l, coeff); m_lemma_index = m_lemma.size(); } - else if (ctx.get_assignment(l) != l_false) { - m_lemma.m_k += coeff; - } } void theory_pb::process_ineq(ineq& c, literal conseq, numeral coeff1) { @@ -1054,22 +1051,21 @@ namespace smt { } g = lc/coeff2; for (unsigned i = 0; i < c.size(); ++i) { - if (ctx.get_assignment(c.lit(i)) == l_false) { - process_antecedent(c.lit(i), g*c.coeff(i)); - } - else if (conseq == c.lit(i)) { + if (conseq == c.lit(i)) { // skip this one. + SASSERT(ctx.get_assignment(c.lit(i)) == l_true); } - else { - m_lemma.m_k += g*c.coeff(i); + else { + process_antecedent(c.lit(i), g*c.coeff(i)); } } m_lemma.m_k += g*c.k(); // - // we most likely want c.lit() to be + // TBD: we want c.lit() to be // an antecedent in a real clause. - // process_antecedent(~c.lit(), 1); + // The coefficient 'g' is also incorrect. // + // process_antecedent(~c.lit(), g); } // @@ -1077,23 +1073,19 @@ namespace smt { // void theory_pb::resolve_conflict(literal conseq, ineq& c) { - IF_VERBOSE(0, verbose_stream() << conseq << "\n"; display(verbose_stream(), c, true);); + IF_VERBOSE(0, verbose_stream() << "RESOLVE: " << conseq << "\n"; display(verbose_stream(), c, true);); bool_var v; context& ctx = get_context(); unsigned& lvl = m_conflict_lvl = 0; - unsigned conseq_index = 0; for (unsigned i = 0; i < c.size(); ++i) { if (ctx.get_assignment(c.lit(i)) == l_false) { lvl = std::max(lvl, ctx.get_assign_level(c.lit(i))); } - if (~conseq == c.lit(i)) { - conseq_index = i; - } } + SASSERT(lvl >= ctx.get_assign_level(c.lit())); SASSERT(ctx.get_assignment(conseq) == l_true); - SASSERT(conseq_index > 0 || ~conseq == c.lit(0)); // conseq is negative in c if (lvl == ctx.get_base_level()) { return; @@ -1104,22 +1096,39 @@ namespace smt { m_lemma_index = 0; process_ineq(c, null_literal, 1); // add consequent to lemma. - SASSERT(c.lit(conseq_index) == ~conseq); - // point into stack of assigned literals literal_vector const& lits = ctx.assigned_literals(); SASSERT(!lits.empty()); unsigned idx = lits.size()-1; - b_justification js = ctx.get_justification(conseq.var()); - do { + + TRACE("pb", display(tout, m_lemma, true);); + IF_VERBOSE(0, display(verbose_stream(), m_lemma, true);); + + // + // find the next marked variable in the assignment stack + // + do { + conseq = lits[idx]; + v = conseq.var(); + --idx; + } + while (!ctx.is_marked(v)); + + unsigned conseq_index = m_conseq_index[v]; + numeral conseq_coeff = m_lemma.coeff(conseq_index); + m_lemma_index = conseq_index; + + SASSERT(~conseq == m_lemma.lit(conseq_index)); + + --m_num_marks; + b_justification js = ctx.get_justification(v); + // // Resolve selected conseq with antecedents. // - IF_VERBOSE(0, verbose_stream() << conseq << " " << js.get_kind() << "\n";); - numeral conseq_coeff = m_lemma.coeff(conseq_index); - m_lemma_index = conseq_index; + IF_VERBOSE(0, verbose_stream() << "conseq: " << conseq << " at index: " << conseq_index << "\n";); switch(js.get_kind()) { case b_justification::CLAUSE: { @@ -1136,6 +1145,7 @@ namespace smt { process_antecedent(cls.get_literal(i), conseq_coeff); } m_lemma.m_k += conseq_coeff; + TRACE("pb", for (unsigned i = 0; i < num_lits; ++i) tout << cls.get_literal(i) << " "; tout << "\n";); justification* cjs = cls.get_justification(); if (cjs) { // TBD @@ -1146,6 +1156,7 @@ namespace smt { case b_justification::BIN_CLAUSE: m_lemma.m_k += conseq_coeff; process_antecedent(~js.get_literal(), conseq_coeff); + TRACE("pb", tout << "binary: " << js.get_literal() << "\n";); break; case b_justification::AXIOM: break; @@ -1156,39 +1167,25 @@ namespace smt { pb_justification& pbj = dynamic_cast(j); // weaken the lemma and resolve. process_ineq(pbj.get_ineq(), conseq, conseq_coeff); + TRACE("pb", display(tout, pbj.get_ineq());); break; } default: UNREACHABLE(); - } - m_lemma.normalize(); - // - // find the next marked variable in the assignment stack - // - SASSERT(idx > 0); - SASSERT(m_num_marks > 0); - do { - conseq = lits[idx]; - v = conseq.var(); - --idx; - } - while (!ctx.is_marked(v)); - - conseq_index = m_conseq_index[v]; - - js = ctx.get_justification(v); - --m_num_marks; + } } while (m_num_marks > 0); + m_lemma.normalize(); + // unset the marks on lemmas while (!m_unmark.empty()) { ctx.unset_mark(m_unmark.back()); m_unmark.pop_back(); } - TRACE("pb", display(tout, m_lemma);); + TRACE("pb", display(tout << "lemma: ", m_lemma);); - IF_VERBOSE(1, display(verbose_stream(), m_lemma);); + IF_VERBOSE(1, display(verbose_stream() << "lemma: ", m_lemma);); } } diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 3ba8ae67f..252a32096 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -52,7 +52,6 @@ namespace smt { numeral m_max_coeff; // maximal coefficient. unsigned m_watch_sz; // number of literals being watched. - numeral m_sum; // sum of coefficients so far. numeral m_max_sum; // maximal sum of watch literals. unsigned m_num_propagations; unsigned m_compilation_threshold; @@ -70,7 +69,6 @@ namespace smt { unsigned size() const { return m_args.size(); } - numeral const& sum() const { return m_sum; } numeral const& max_sum() const { return m_max_sum; } numeral const& max_coeff() const { return m_max_coeff; } From 696db3a6a49159cd9275a23333c72771a608e9d0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Nov 2013 17:25:19 -0800 Subject: [PATCH 152/925] debug conflict Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 163 ++++++++++++++++++++++++++++-------------- src/smt/theory_pb.h | 12 +++- 2 files changed, 117 insertions(+), 58 deletions(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 1248ef6bc..f32ae390e 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -69,11 +69,9 @@ namespace smt { return (a*b)/gcd(a,b); } - lbool theory_pb::ineq::normalize() { - + void theory_pb::ineq::unique() { numeral& k = m_k; arg_t& args = m_args; - // normalize first all literals to be positive: // then we can compare them more easily. for (unsigned i = 0; i < size(); ++i) { @@ -112,6 +110,13 @@ namespace smt { args.pop_back(); } } + } + + lbool theory_pb::ineq::normalize() { + + numeral& k = m_k; + arg_t& args = m_args; + // // Ensure all coefficients are positive: // c*l + y >= k @@ -143,14 +148,24 @@ namespace smt { return l_false; } // Ensure the largest coefficient is not larger than k: + sum = 0; for (unsigned i = 0; i < size(); ++i) { numeral c = coeff(i); if (c > k) { args[i].second = k; } + sum += coeff(i); } SASSERT(!args.empty()); + // normalize tight inequalities to unit coefficients. + if (sum == k) { + for (unsigned i = 0; i < size(); ++i) { + args[i].second = 1; + } + k = size(); + } + // apply cutting plane reduction: numeral g = 0; for (unsigned i = 0; g != 1 && i < size(); ++i) { @@ -257,6 +272,7 @@ namespace smt { args[i].second = -args[i].second; } k = -k; + c->unique(); lbool is_true = c->normalize(); literal lit(abv); @@ -985,33 +1001,53 @@ namespace smt { } + void theory_pb::set_mark(bool_var v, unsigned idx) { + SASSERT(v != null_bool_var); + if (v >= static_cast(m_conseq_index.size())) { + m_conseq_index.resize(v+1, null_index); + } + SASSERT(!is_marked(v) || m_conseq_index[v] == idx); + if (m_conseq_index[v] == null_index) { + m_conseq_index[v] = idx; + } + } + + bool theory_pb::is_marked(bool_var v) const { + return + (v < static_cast(m_conseq_index.size())) && + (m_conseq_index[v] != null_index); + } + + void theory_pb::unset_mark(literal l) { + bool_var v = l.var(); + SASSERT(v != null_bool_var); + if (v < static_cast(m_conseq_index.size())) { + m_conseq_index[v] = null_index; + } + } + void theory_pb::process_antecedent(literal l, numeral coeff) { context& ctx = get_context(); bool_var v = l.var(); unsigned lvl = ctx.get_assign_level(v); - IF_VERBOSE(2, verbose_stream() << "ante: " << l << "*" << coeff << " " << lvl << "\n";); if (ctx.get_assignment(l) != l_false) { m_lemma.m_k -= coeff; } else if (lvl > ctx.get_base_level()) { - if (!ctx.is_marked(v)) { - ctx.set_mark(v); - m_unmark.push_back(v); + if (is_marked(v)) { + m_lemma.m_args[m_conseq_index[v]].second += coeff; + } + else { if (lvl == m_conflict_lvl) { ++m_num_marks; - if (v >= static_cast(m_conseq_index.size())) { - m_conseq_index.resize(v+1); - } - m_conseq_index[v] = m_lemma_index; } + set_mark(v, m_lemma.size()); + m_lemma.m_args.push_back(std::make_pair(l, coeff)); } - SASSERT(m_lemma_index <= m_lemma.size()); - if (m_lemma_index == m_lemma.size()) { - m_lemma.m_args.resize(m_lemma_index+1); - } - m_lemma.m_args[m_lemma_index] = std::make_pair(l, coeff); - m_lemma_index = m_lemma.size(); + TRACE("pb_verbose", tout + << "ante: " << m_lemma.lit(m_conseq_index[v]) << "*" + << m_lemma.coeff(m_conseq_index[v]) << " " << lvl << "\n";); } } @@ -1019,9 +1055,6 @@ namespace smt { // // Create CUT. - // TBD only process literals that were - // assigned below current index 'idx'. - // and/or relevant to the conflict. // // @@ -1050,30 +1083,24 @@ namespace smt { m_lemma.m_k *= g; } g = lc/coeff2; - for (unsigned i = 0; i < c.size(); ++i) { - if (conseq == c.lit(i)) { - // skip this one. - SASSERT(ctx.get_assignment(c.lit(i)) == l_true); - } - else { - process_antecedent(c.lit(i), g*c.coeff(i)); - } - } m_lemma.m_k += g*c.k(); - // - // TBD: we want c.lit() to be - // an antecedent in a real clause. - // The coefficient 'g' is also incorrect. - // - // process_antecedent(~c.lit(), g); + + for (unsigned i = 0; i < c.size(); ++i) { + process_antecedent(c.lit(i), g*c.coeff(i)); + } + + SASSERT(ctx.get_assignment(c.lit()) == l_true); + if (ctx.get_assign_level(c.lit().var()) > ctx.get_base_level()) { + m_antecedents.push_back(~c.lit()); + } } // // modeled after sat_solver/smt_context // void theory_pb::resolve_conflict(literal conseq, ineq& c) { - - IF_VERBOSE(0, verbose_stream() << "RESOLVE: " << conseq << "\n"; display(verbose_stream(), c, true);); + + TRACE("pb", tout << "RESOLVE: " << conseq << "\n"; display(verbose_stream(), c, true);); bool_var v; context& ctx = get_context(); @@ -1093,7 +1120,7 @@ namespace smt { m_num_marks = 0; m_lemma.reset(); - m_lemma_index = 0; + m_antecedents.reset(); process_ineq(c, null_literal, 1); // add consequent to lemma. // point into stack of assigned literals @@ -1101,10 +1128,10 @@ namespace smt { SASSERT(!lits.empty()); unsigned idx = lits.size()-1; - do { + while (m_num_marks > 0) { - TRACE("pb", display(tout, m_lemma, true);); - IF_VERBOSE(0, display(verbose_stream(), m_lemma, true);); + m_lemma.normalize(); + SASSERT(m_lemma.well_formed()); // // find the next marked variable in the assignment stack @@ -1114,21 +1141,32 @@ namespace smt { v = conseq.var(); --idx; } - while (!ctx.is_marked(v)); + while (!is_marked(v)); unsigned conseq_index = m_conseq_index[v]; numeral conseq_coeff = m_lemma.coeff(conseq_index); - m_lemma_index = conseq_index; + + TRACE("pb", display(tout, m_lemma, true); + tout << "conseq: " << conseq << " at index: " << conseq_index << "\n";); SASSERT(~conseq == m_lemma.lit(conseq_index)); + // Remove conseq from lemma: + unsigned last = m_lemma.size()-1; + if (conseq_index != last) { + m_lemma.m_args[conseq_index] = m_lemma.m_args[last]; + m_conseq_index[m_lemma.lit(conseq_index).var()] = conseq_index; + } + m_lemma.m_args.pop_back(); + unset_mark(conseq); + --m_num_marks; b_justification js = ctx.get_justification(v); // // Resolve selected conseq with antecedents. // - IF_VERBOSE(0, verbose_stream() << "conseq: " << conseq << " at index: " << conseq_index << "\n";); + switch(js.get_kind()) { case b_justification::CLAUSE: { @@ -1144,7 +1182,6 @@ namespace smt { for (unsigned i = 2; i < num_lits; ++i) { process_antecedent(cls.get_literal(i), conseq_coeff); } - m_lemma.m_k += conseq_coeff; TRACE("pb", for (unsigned i = 0; i < num_lits; ++i) tout << cls.get_literal(i) << " "; tout << "\n";); justification* cjs = cls.get_justification(); if (cjs) { @@ -1154,7 +1191,6 @@ namespace smt { break; } case b_justification::BIN_CLAUSE: - m_lemma.m_k += conseq_coeff; process_antecedent(~js.get_literal(), conseq_coeff); TRACE("pb", tout << "binary: " << js.get_literal() << "\n";); break; @@ -1166,26 +1202,43 @@ namespace smt { if (j.get_from_theory() != get_id()) break; pb_justification& pbj = dynamic_cast(j); // weaken the lemma and resolve. + TRACE("pb", display(tout, pbj.get_ineq(), true);); process_ineq(pbj.get_ineq(), conseq, conseq_coeff); - TRACE("pb", display(tout, pbj.get_ineq());); break; } default: UNREACHABLE(); - } + } + m_lemma.normalize(); } - while (m_num_marks > 0); - m_lemma.normalize(); - - // unset the marks on lemmas - while (!m_unmark.empty()) { - ctx.unset_mark(m_unmark.back()); - m_unmark.pop_back(); + for (unsigned i = 0; i < m_lemma.size(); ++i) { + unset_mark(m_lemma.lit(i)); } TRACE("pb", display(tout << "lemma: ", m_lemma);); IF_VERBOSE(1, display(verbose_stream() << "lemma: ", m_lemma);); + + // TBD: + // create clause m_antecedents \/ m_lemma; + // +#if 1 + ast_manager& m = get_manager(); + svector coeffs; + expr_ref_vector args(m); + expr_ref tmp(m); + for (unsigned i = 0; i < m_lemma.size(); ++i) { + ctx.literal2expr(m_lemma.lit(i), tmp); + args.push_back(tmp); + coeffs.push_back(static_cast(m_lemma.coeff(i))); + } + int k = static_cast(m_lemma.k()); + tmp = m_util.mk_le(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), k); + internalize_atom(to_app(tmp), false); + m_antecedents.push_back(literal(ctx.get_bool_var(tmp))); + justification* mjs = 0; + ctx.mk_clause(m_antecedents.size(), m_antecedents.c_ptr(), mjs, CLS_AUX_LEMMA, 0); +#endif } } diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 252a32096..ae7842db3 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -87,6 +87,7 @@ namespace smt { void negate(); lbool normalize(); + void unique(); bool well_formed() const; @@ -139,10 +140,15 @@ namespace smt { unsigned m_num_marks; unsigned m_conflict_lvl; ineq m_lemma; + literal_vector m_antecedents; + + // bool_var |-> index into m_lemma unsigned_vector m_conseq_index; - unsigned m_lemma_index; - svector m_unmark; - void set_next_index(unsigned i); + static const unsigned null_index = UINT_MAX; + bool is_marked(bool_var v) const; + void set_mark(bool_var v, unsigned idx); + void unset_mark(literal l); + void resolve_conflict(literal conseq, ineq& c); void process_antecedent(literal l, numeral coeff); void process_ineq(ineq& c, literal conseq, numeral coeff); From 33895d522b188a4435e9d47d137bd5e9bbacede3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Nov 2013 20:47:16 -0800 Subject: [PATCH 153/925] fix and enable learning Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 1 + src/api/z3_api.h | 4 +++ src/ast/pb_decl_plugin.cpp | 59 +++++++++++++++++++++++++++++++------- src/ast/pb_decl_plugin.h | 10 ++++++- src/smt/theory_pb.cpp | 43 ++++++++++++++++----------- src/smt/theory_pb.h | 2 +- 6 files changed, 91 insertions(+), 28 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 29c492368..f116f6868 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1126,6 +1126,7 @@ extern "C" { if (mk_c(c)->get_pb_fid() == _d->get_family_id()) { switch(_d->get_decl_kind()) { case OP_PB_LE: return Z3_OP_PB_LE; + case OP_PB_GE: return Z3_OP_PB_GE; case OP_AT_MOST_K: return Z3_OP_PB_AT_MOST; default: UNREACHABLE(); } diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 57ab9a1b7..08e645684 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -880,6 +880,9 @@ typedef enum - Z3_OP_PB_LE: Generalized Pseudo-Boolean cardinality constraint. Example 2*x + 3*y <= 4 + - Z3_OP_PB_GE: Generalized Pseudo-Boolean cardinality constraint. + Example 2*x + 3*y + 2*z >= 4 + - Z3_OP_UNINTERPRETED: kind used for uninterpreted symbols. */ typedef enum { @@ -1063,6 +1066,7 @@ typedef enum { // Pseudo Booleans Z3_OP_PB_AT_MOST=0x900, Z3_OP_PB_LE, + Z3_OP_PB_GE, Z3_OP_UNINTERPRETED } Z3_decl_kind; diff --git a/src/ast/pb_decl_plugin.cpp b/src/ast/pb_decl_plugin.cpp index 0f9f479dd..4cc317df3 100644 --- a/src/ast/pb_decl_plugin.cpp +++ b/src/ast/pb_decl_plugin.cpp @@ -21,7 +21,8 @@ Revision History: pb_decl_plugin::pb_decl_plugin(): m_at_most_sym("at-most"), - m_pble_sym("pble") + m_pble_sym("pble"), + m_pbge_sym("pbge") {} func_decl * pb_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, @@ -53,6 +54,18 @@ func_decl * pb_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p func_decl_info info(m_family_id, OP_PB_LE, num_parameters, parameters); return m.mk_func_decl(m_pble_sym, arity, domain, m.mk_bool_sort(), info); } + case OP_PB_GE: { + if (num_parameters != 1 + arity || !parameters[0].is_int()) { + m.raise_exception("function 'pbge' expects arity+1 integer parameters"); + } + for (unsigned i = 1; i < num_parameters; ++i) { + if (!parameters[i].is_int()) { + m.raise_exception("function 'pbge' expects arity+1 integer parameters"); + } + } + func_decl_info info(m_family_id, OP_PB_GE, num_parameters, parameters); + return m.mk_func_decl(m_pbge_sym, arity, domain, m.mk_bool_sort(), info); + } default: UNREACHABLE(); return 0; @@ -63,15 +76,10 @@ void pb_decl_plugin::get_op_names(svector & op_names, symbol const if (logic == symbol::null) { op_names.push_back(builtin_name(m_at_most_sym.bare_str(), OP_AT_MOST_K)); op_names.push_back(builtin_name(m_pble_sym.bare_str(), OP_PB_LE)); + op_names.push_back(builtin_name(m_pbge_sym.bare_str(), OP_PB_GE)); } } - -app * pb_util::mk_at_most_k(unsigned num_args, expr * const * args, unsigned k) { - parameter param(k); - return m.mk_app(m_fid, OP_AT_MOST_K, 1, ¶m, num_args, args, m.mk_bool_sort()); -} - app * pb_util::mk_le(unsigned num_args, int const * coeffs, expr * const * args, int k) { vector params; params.push_back(parameter(k)); @@ -81,6 +89,23 @@ app * pb_util::mk_le(unsigned num_args, int const * coeffs, expr * const * args, return m.mk_app(m_fid, OP_PB_LE, params.size(), params.c_ptr(), num_args, args, m.mk_bool_sort()); } +app * pb_util::mk_ge(unsigned num_args, int const * coeffs, expr * const * args, int k) { + vector params; + params.push_back(parameter(k)); + for (unsigned i = 0; i < num_args; ++i) { + params.push_back(parameter(coeffs[i])); + } + return m.mk_app(m_fid, OP_PB_GE, params.size(), params.c_ptr(), num_args, args, m.mk_bool_sort()); +} + + + +app * pb_util::mk_at_most_k(unsigned num_args, expr * const * args, unsigned k) { + parameter param(k); + return m.mk_app(m_fid, OP_AT_MOST_K, 1, ¶m, num_args, args, m.mk_bool_sort()); +} + + bool pb_util::is_at_most_k(app *a) const { return is_app_of(a, m_fid, OP_AT_MOST_K); @@ -97,7 +122,7 @@ bool pb_util::is_at_most_k(app *a, unsigned& k) const { } int pb_util::get_k(app *a) const { - SASSERT(is_at_most_k(a) || is_le(a)); + SASSERT(is_at_most_k(a) || is_le(a) || is_ge(a)); return a->get_decl()->get_parameter(0).get_int(); } @@ -116,11 +141,25 @@ bool pb_util::is_le(app* a, int& k) const { } } -int pb_util::get_le_coeff(app* a, unsigned index) { +bool pb_util::is_ge(app *a) const { + return is_app_of(a, m_fid, OP_PB_GE); +} + +bool pb_util::is_ge(app* a, int& k) const { + if (is_ge(a)) { + k = get_k(a); + return true; + } + else { + return false; + } +} + +int pb_util::get_coeff(app* a, unsigned index) { if (is_at_most_k(a)) { return 1; } - SASSERT(is_le(a)); + SASSERT(is_le(a) || is_ge(a)); SASSERT(1 + index < a->get_decl()->get_num_parameters()); return a->get_decl()->get_parameter(index + 1).get_int(); } diff --git a/src/ast/pb_decl_plugin.h b/src/ast/pb_decl_plugin.h index 093236218..e7ab3ec25 100644 --- a/src/ast/pb_decl_plugin.h +++ b/src/ast/pb_decl_plugin.h @@ -32,6 +32,7 @@ hence: enum pb_op_kind { OP_AT_MOST_K, // at most K Booleans are true. OP_PB_LE, // pseudo-Boolean <= (generalizes at_most_k) + OP_PB_GE, // pseudo-Boolean >= LAST_PB_OP }; @@ -39,8 +40,10 @@ enum pb_op_kind { class pb_decl_plugin : public decl_plugin { symbol m_at_most_sym; symbol m_pble_sym; + symbol m_pbge_sym; func_decl * mk_at_most(unsigned arity, unsigned k); func_decl * mk_le(unsigned arity, int const* coeffs, int k); + func_decl * mk_ge(unsigned arity, int const* coeffs, int k); public: pb_decl_plugin(); virtual ~pb_decl_plugin() {} @@ -74,14 +77,19 @@ public: family_id get_family_id() const { return m_fid; } app * mk_at_most_k(unsigned num_args, expr * const * args, unsigned k); app * mk_le(unsigned num_args, int const * coeffs, expr * const * args, int k); + app * mk_ge(unsigned num_args, int const * coeffs, expr * const * args, int k); bool is_at_most_k(app *a) const; bool is_at_most_k(app *a, unsigned& k) const; int get_k(app *a) const; bool is_le(app *a) const; bool is_le(app* a, int& k) const; - int get_le_coeff(app* a, unsigned index); + bool is_ge(app* a) const; + bool is_ge(app* a, int& k) const; + int get_coeff(app* a, unsigned index); }; + + #endif /* _PB_DECL_PLUGIN_H_ */ diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index f32ae390e..f18664fbc 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -26,7 +26,7 @@ Notes: namespace smt { - bool theory_pb::s_debug_conflict = false; // true; // + bool theory_pb::s_debug_conflict = true; // false; // true; // void theory_pb::ineq::negate() { m_lit.neg(); @@ -243,7 +243,7 @@ namespace smt { context& ctx = get_context(); ast_manager& m = get_manager(); unsigned num_args = atom->get_num_args(); - SASSERT(m_util.is_at_most_k(atom) || m_util.is_le(atom)); + SASSERT(m_util.is_at_most_k(atom) || m_util.is_le(atom) || m_util.is_ge(atom)); if (ctx.b_internalized(atom)) { return false; @@ -264,14 +264,16 @@ namespace smt { for (unsigned i = 0; i < num_args; ++i) { expr* arg = atom->get_arg(i); literal l = compile_arg(arg); - numeral c = m_util.get_le_coeff(atom, i); + numeral c = m_util.get_coeff(atom, i); args.push_back(std::make_pair(l, c)); } - // turn W <= k into -W >= -k - for (unsigned i = 0; i < args.size(); ++i) { - args[i].second = -args[i].second; + if (m_util.is_at_most_k(atom) || m_util.is_le(atom)) { + // turn W <= k into -W >= -k + for (unsigned i = 0; i < args.size(); ++i) { + args[i].second = -args[i].second; + } + k = -k; } - k = -k; c->unique(); lbool is_true = c->normalize(); @@ -921,7 +923,10 @@ namespace smt { } for (unsigned i = 0; i < c.size(); ++i) { literal l(c.lit(i)); - out << c.coeff(i) << "*" << l; + if (c.coeff(i) != 1) { + out << c.coeff(i) << "*"; + } + out << l; if (values) { out << "@(" << ctx.get_assignment(l); if (ctx.get_assignment(l) != l_undef) { @@ -1091,7 +1096,7 @@ namespace smt { SASSERT(ctx.get_assignment(c.lit()) == l_true); if (ctx.get_assign_level(c.lit().var()) > ctx.get_base_level()) { - m_antecedents.push_back(~c.lit()); + m_ineq_literals.push_back(c.lit()); } } @@ -1100,7 +1105,7 @@ namespace smt { // void theory_pb::resolve_conflict(literal conseq, ineq& c) { - TRACE("pb", tout << "RESOLVE: " << conseq << "\n"; display(verbose_stream(), c, true);); + TRACE("pb", tout << "RESOLVE: " << conseq << "\n"; display(tout, c, true);); bool_var v; context& ctx = get_context(); @@ -1120,7 +1125,7 @@ namespace smt { m_num_marks = 0; m_lemma.reset(); - m_antecedents.reset(); + m_ineq_literals.reset(); process_ineq(c, null_literal, 1); // add consequent to lemma. // point into stack of assigned literals @@ -1221,7 +1226,7 @@ namespace smt { IF_VERBOSE(1, display(verbose_stream() << "lemma: ", m_lemma);); // TBD: - // create clause m_antecedents \/ m_lemma; + // create clause m_literals \/ m_lemma; // #if 1 ast_manager& m = get_manager(); @@ -1234,11 +1239,17 @@ namespace smt { coeffs.push_back(static_cast(m_lemma.coeff(i))); } int k = static_cast(m_lemma.k()); - tmp = m_util.mk_le(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), k); + tmp = m_util.mk_ge(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), k); internalize_atom(to_app(tmp), false); - m_antecedents.push_back(literal(ctx.get_bool_var(tmp))); - justification* mjs = 0; - ctx.mk_clause(m_antecedents.size(), m_antecedents.c_ptr(), mjs, CLS_AUX_LEMMA, 0); + //m_ineq_literals.push_back(literal(ctx.get_bool_var(tmp))); + ctx.mark_as_relevant(tmp); + //justification* mjs = 0; + //ctx.mk_clause(m_ineq_literals.size(), m_ineq_literals.c_ptr(), mjs, CLS_AUX_LEMMA, 0); + literal l(ctx.get_bool_var(tmp)); + ineq* cc = 0; + if (m_ineqs.find(l.var(), cc)) { + add_assign(*cc, m_ineq_literals, l); + } #endif } } diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index ae7842db3..159b709e5 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -140,7 +140,7 @@ namespace smt { unsigned m_num_marks; unsigned m_conflict_lvl; ineq m_lemma; - literal_vector m_antecedents; + literal_vector m_ineq_literals; // bool_var |-> index into m_lemma unsigned_vector m_conseq_index; From e44db06bb76ba7e4c9cb18467db36f0da874aaae Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 20 Nov 2013 16:14:29 -0800 Subject: [PATCH 154/925] update conflict resolution Signed-off-by: Nikolaj Bjorner --- src/smt/smt_internalizer.cpp | 3 ++- src/smt/theory_pb.cpp | 51 ++++++++++++++++++++++++++++-------- src/smt/theory_pb.h | 2 ++ 3 files changed, 44 insertions(+), 12 deletions(-) diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index 42e761b61..bfe1a3bb1 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -814,6 +814,7 @@ namespace smt { */ bool_var context::mk_bool_var(expr * n) { SASSERT(!b_internalized(n)); + SASSERT(!m_manager.is_not(n)); unsigned id = n->get_id(); bool_var v = m_b_internalized_stack.size(); #ifndef _EXTERNAL_RELEASE @@ -828,7 +829,7 @@ namespace smt { } #endif TRACE("mk_bool_var", tout << "creating boolean variable: " << v << " for:\n" << mk_pp(n, m_manager) << "\n";); - TRACE("mk_var_bug", tout << "mk_bool: " << v << "\n";); + TRACE("mk_var_bug", tout << "mk_bool: " << v << "\n";); set_bool_var(id, v); m_bdata.reserve(v+1); m_activity.reserve(v+1); diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index f18664fbc..8cc56926f 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -330,12 +330,14 @@ namespace smt { literal theory_pb::compile_arg(expr* arg) { context& ctx = get_context(); ast_manager& m = get_manager(); - if (!ctx.b_internalized(arg)) { - ctx.internalize(arg, false); - } + bool_var bv; bool has_bv = false; bool negate = m.is_not(arg, arg); + SASSERT(!m.is_not(arg)); + if (!ctx.b_internalized(arg)) { + ctx.internalize(arg, false); + } if (ctx.b_internalized(arg)) { bv = ctx.get_bool_var(arg); if (null_theory_var == ctx.get_var_theory(bv)) { @@ -993,10 +995,14 @@ namespace smt { tout << "\n"; display(tout, c, true);); +#if 0 DEBUG_CODE( if (s_debug_conflict) { resolve_conflict(conseq, c); }); +#else + resolve_conflict(conseq, c); +#endif justification* js = 0; ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); IF_VERBOSE(2, ctx.display_literals_verbose(verbose_stream(), @@ -1176,6 +1182,11 @@ namespace smt { case b_justification::CLAUSE: { clause& cls = *js.get_clause(); + justification* cjs = cls.get_justification(); + if (cjs) { + IF_VERBOSE(0, verbose_stream() << "skipping justification for clause over: " << conseq << "\n";); + break; + } unsigned num_lits = cls.get_num_literals(); if (cls.get_literal(0) == conseq) { process_antecedent(cls.get_literal(1), conseq_coeff); @@ -1188,11 +1199,6 @@ namespace smt { process_antecedent(cls.get_literal(i), conseq_coeff); } TRACE("pb", for (unsigned i = 0; i < num_lits; ++i) tout << cls.get_literal(i) << " "; tout << "\n";); - justification* cjs = cls.get_justification(); - if (cjs) { - // TBD - NOT_IMPLEMENTED_YET(); - } break; } case b_justification::BIN_CLAUSE: @@ -1204,7 +1210,10 @@ namespace smt { case b_justification::JUSTIFICATION: { justification& j = *js.get_justification(); // only process pb justifications. - if (j.get_from_theory() != get_id()) break; + if (j.get_from_theory() != get_id()) { + IF_VERBOSE(0, verbose_stream() << "skipping justification for " << conseq << "\n";); + break; + } pb_justification& pbj = dynamic_cast(j); // weaken the lemma and resolve. TRACE("pb", display(tout, pbj.get_ineq(), true);); @@ -1223,12 +1232,14 @@ namespace smt { TRACE("pb", display(tout << "lemma: ", m_lemma);); - IF_VERBOSE(1, display(verbose_stream() << "lemma: ", m_lemma);); // TBD: - // create clause m_literals \/ m_lemma; + // create clause m_ineq_literals => m_lemma; // #if 1 + hoist_maximal_values(); + IF_VERBOSE(1, display(verbose_stream() << "lemma: ", m_lemma);); + ast_manager& m = get_manager(); svector coeffs; expr_ref_vector args(m); @@ -1250,6 +1261,24 @@ namespace smt { if (m_ineqs.find(l.var(), cc)) { add_assign(*cc, m_ineq_literals, l); } + else { + ctx.assign(l, ctx.mk_justification( + theory_propagation_justification( + get_id(), ctx.get_region(), + m_ineq_literals.size(), m_ineq_literals.c_ptr(), l))); +// IF_VERBOSE(0, verbose_stream() << "Did not compile " << tmp << "\n";); + } #endif } + + void theory_pb::hoist_maximal_values() { + for (unsigned i = 0; i < m_lemma.size(); ++i) { + if (m_lemma.coeff(i) == m_lemma.k()) { + m_ineq_literals.push_back(~m_lemma.lit(i)); + std::swap(m_lemma.m_args[i], m_lemma.m_args[m_lemma.size()-1]); + m_lemma.m_args.pop_back(); + --i; + } + } + } } diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 159b709e5..e205f3f59 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -153,6 +153,8 @@ namespace smt { void process_antecedent(literal l, numeral coeff); void process_ineq(ineq& c, literal conseq, numeral coeff); + void hoist_maximal_values(); + void validate_final_check(); void validate_final_check(ineq& c); public: From 97dfb6d521ddd2c8fedd39cab27278aebe24041e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 21 Nov 2013 15:55:08 -0800 Subject: [PATCH 155/925] moving to rational coefficients Signed-off-by: Nikolaj Bjorner --- src/api/api_pb.cpp | 10 ++- src/ast/pb_decl_plugin.cpp | 102 +++++++++++++++++--------- src/ast/pb_decl_plugin.h | 24 +++--- src/opt/objective_ast.h | 96 ++++++++++++++++++++++++ src/smt/theory_pb.cpp | 138 ++++++++++++++++++----------------- src/smt/theory_pb.h | 8 +- src/solver/tactic2solver.cpp | 2 +- 7 files changed, 261 insertions(+), 119 deletions(-) create mode 100644 src/opt/objective_ast.h diff --git a/src/api/api_pb.cpp b/src/api/api_pb.cpp index 17fe2f93e..6d5a56d2c 100644 --- a/src/api/api_pb.cpp +++ b/src/api/api_pb.cpp @@ -40,13 +40,17 @@ extern "C" { Z3_ast Z3_API Z3_mk_pble(Z3_context c, unsigned num_args, - Z3_ast const args[], int coeffs[], + Z3_ast const args[], int _coeffs[], int k) { Z3_TRY; - LOG_Z3_mk_pble(c, num_args, args, coeffs, k); + LOG_Z3_mk_pble(c, num_args, args, _coeffs, k); RESET_ERROR_CODE(); pb_util util(mk_c(c)->m()); - ast* a = util.mk_le(num_args, coeffs, to_exprs(args), k); + vector coeffs; + for (unsigned i = 0; i < num_args; ++i) { + coeffs.push_back(rational(_coeffs[i])); + } + ast* a = util.mk_le(num_args, coeffs.c_ptr(), to_exprs(args), rational(k)); mk_c(c)->save_ast_trail(a); check_sorts(c, a); RETURN_Z3(of_ast(a)); diff --git a/src/ast/pb_decl_plugin.cpp b/src/ast/pb_decl_plugin.cpp index 4cc317df3..07153e1ac 100644 --- a/src/ast/pb_decl_plugin.cpp +++ b/src/ast/pb_decl_plugin.cpp @@ -21,12 +21,13 @@ Revision History: pb_decl_plugin::pb_decl_plugin(): m_at_most_sym("at-most"), + m_at_least_sym("at-least"), m_pble_sym("pble"), m_pbge_sym("pbge") {} func_decl * pb_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range) { + unsigned arity, sort * const * domain, sort * range) { SASSERT(m_manager); ast_manager& m = *m_manager; for (unsigned i = 0; i < arity; ++i) { @@ -34,37 +35,42 @@ func_decl * pb_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p m.raise_exception("invalid non-Boolean sort applied to 'at-most'"); } } + symbol sym; switch(k) { + case OP_AT_LEAST_K: sym = m_at_least_sym; break; + case OP_AT_MOST_K: sym = m_at_most_sym; break; + case OP_PB_LE: sym = m_pble_sym; break; + case OP_PB_GE: sym = m_pbge_sym; break; + default: break; + } + switch(k) { + case OP_AT_LEAST_K: case OP_AT_MOST_K: { if (num_parameters != 1 || !parameters[0].is_int() || parameters[0].get_int() < 0) { - m.raise_exception("function 'at-most' expects one non-negative integer parameter"); + m.raise_exception("function expects one non-negative integer parameter"); } - func_decl_info info(m_family_id, OP_AT_MOST_K, 1, parameters); - return m.mk_func_decl(m_at_most_sym, arity, domain, m.mk_bool_sort(), info); + func_decl_info info(m_family_id, k, 1, parameters); + return m.mk_func_decl(sym, arity, domain, m.mk_bool_sort(), info); } + case OP_PB_GE: case OP_PB_LE: { - if (num_parameters != 1 + arity || !parameters[0].is_int()) { - m.raise_exception("function 'pble' expects arity+1 integer parameters"); + if (num_parameters != 1 + arity) { + m.raise_exception("function expects arity+1 rational parameters"); } - for (unsigned i = 1; i < num_parameters; ++i) { - if (!parameters[i].is_int()) { + vector params; + for (unsigned i = 0; i < num_parameters; ++i) { + if (parameters[i].is_int()) { + params.push_back(parameter(rational(parameters[i].get_int()))); + } + else if (parameters[i].is_rational()) { + params.push_back(parameter(parameters[i].get_rational())); + } + else { m.raise_exception("function 'pble' expects arity+1 integer parameters"); } } - func_decl_info info(m_family_id, OP_PB_LE, num_parameters, parameters); - return m.mk_func_decl(m_pble_sym, arity, domain, m.mk_bool_sort(), info); - } - case OP_PB_GE: { - if (num_parameters != 1 + arity || !parameters[0].is_int()) { - m.raise_exception("function 'pbge' expects arity+1 integer parameters"); - } - for (unsigned i = 1; i < num_parameters; ++i) { - if (!parameters[i].is_int()) { - m.raise_exception("function 'pbge' expects arity+1 integer parameters"); - } - } - func_decl_info info(m_family_id, OP_PB_GE, num_parameters, parameters); - return m.mk_func_decl(m_pbge_sym, arity, domain, m.mk_bool_sort(), info); + func_decl_info info(m_family_id, k, num_parameters, params.c_ptr()); + return m.mk_func_decl(sym, arity, domain, m.mk_bool_sort(), info); } default: UNREACHABLE(); @@ -80,7 +86,7 @@ void pb_decl_plugin::get_op_names(svector & op_names, symbol const } } -app * pb_util::mk_le(unsigned num_args, int const * coeffs, expr * const * args, int k) { +app * pb_util::mk_le(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k) { vector params; params.push_back(parameter(k)); for (unsigned i = 0; i < num_args; ++i) { @@ -89,7 +95,7 @@ app * pb_util::mk_le(unsigned num_args, int const * coeffs, expr * const * args, return m.mk_app(m_fid, OP_PB_LE, params.size(), params.c_ptr(), num_args, args, m.mk_bool_sort()); } -app * pb_util::mk_ge(unsigned num_args, int const * coeffs, expr * const * args, int k) { +app * pb_util::mk_ge(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k) { vector params; params.push_back(parameter(k)); for (unsigned i = 0; i < num_args; ++i) { @@ -105,13 +111,11 @@ app * pb_util::mk_at_most_k(unsigned num_args, expr * const * args, unsigned k) return m.mk_app(m_fid, OP_AT_MOST_K, 1, ¶m, num_args, args, m.mk_bool_sort()); } - - bool pb_util::is_at_most_k(app *a) const { return is_app_of(a, m_fid, OP_AT_MOST_K); } -bool pb_util::is_at_most_k(app *a, unsigned& k) const { +bool pb_util::is_at_most_k(app *a, rational& k) const { if (is_at_most_k(a)) { k = get_k(a); return true; @@ -121,9 +125,35 @@ bool pb_util::is_at_most_k(app *a, unsigned& k) const { } } -int pb_util::get_k(app *a) const { - SASSERT(is_at_most_k(a) || is_le(a) || is_ge(a)); - return a->get_decl()->get_parameter(0).get_int(); + +app * pb_util::mk_at_least_k(unsigned num_args, expr * const * args, unsigned k) { + parameter param(k); + return m.mk_app(m_fid, OP_AT_LEAST_K, 1, ¶m, num_args, args, m.mk_bool_sort()); +} + +bool pb_util::is_at_least_k(app *a) const { + return is_app_of(a, m_fid, OP_AT_LEAST_K); +} + +bool pb_util::is_at_least_k(app *a, rational& k) const { + if (is_at_least_k(a)) { + k = get_k(a); + return true; + } + else { + return false; + } +} + +rational pb_util::get_k(app *a) const { + parameter const& p = a->get_decl()->get_parameter(0); + if (is_at_most_k(a) || is_at_least_k(a)) { + return rational(p.get_int()); + } + else { + SASSERT(is_le(a) || is_ge(a)); + return p.get_rational(); + } } @@ -131,7 +161,7 @@ bool pb_util::is_le(app *a) const { return is_app_of(a, m_fid, OP_PB_LE); } -bool pb_util::is_le(app* a, int& k) const { +bool pb_util::is_le(app* a, rational& k) const { if (is_le(a)) { k = get_k(a); return true; @@ -145,7 +175,7 @@ bool pb_util::is_ge(app *a) const { return is_app_of(a, m_fid, OP_PB_GE); } -bool pb_util::is_ge(app* a, int& k) const { +bool pb_util::is_ge(app* a, rational& k) const { if (is_ge(a)) { k = get_k(a); return true; @@ -155,13 +185,13 @@ bool pb_util::is_ge(app* a, int& k) const { } } -int pb_util::get_coeff(app* a, unsigned index) { - if (is_at_most_k(a)) { - return 1; +rational pb_util::get_coeff(app* a, unsigned index) { + if (is_at_most_k(a) || is_at_least_k(a)) { + return rational::one(); } SASSERT(is_le(a) || is_ge(a)); SASSERT(1 + index < a->get_decl()->get_num_parameters()); - return a->get_decl()->get_parameter(index + 1).get_int(); + return a->get_decl()->get_parameter(index + 1).get_rational(); } diff --git a/src/ast/pb_decl_plugin.h b/src/ast/pb_decl_plugin.h index e7ab3ec25..4b768ff11 100644 --- a/src/ast/pb_decl_plugin.h +++ b/src/ast/pb_decl_plugin.h @@ -31,6 +31,7 @@ hence: enum pb_op_kind { OP_AT_MOST_K, // at most K Booleans are true. + OP_AT_LEAST_K, // at least K Booleans are true. OP_PB_LE, // pseudo-Boolean <= (generalizes at_most_k) OP_PB_GE, // pseudo-Boolean >= LAST_PB_OP @@ -39,11 +40,13 @@ enum pb_op_kind { class pb_decl_plugin : public decl_plugin { symbol m_at_most_sym; + symbol m_at_least_sym; symbol m_pble_sym; symbol m_pbge_sym; func_decl * mk_at_most(unsigned arity, unsigned k); - func_decl * mk_le(unsigned arity, int const* coeffs, int k); - func_decl * mk_ge(unsigned arity, int const* coeffs, int k); + func_decl * mk_at_least(unsigned arity, unsigned k); + func_decl * mk_le(unsigned arity, rational const* coeffs, int k); + func_decl * mk_ge(unsigned arity, rational const* coeffs, int k); public: pb_decl_plugin(); virtual ~pb_decl_plugin() {} @@ -76,16 +79,19 @@ public: ast_manager & get_manager() const { return m; } family_id get_family_id() const { return m_fid; } app * mk_at_most_k(unsigned num_args, expr * const * args, unsigned k); - app * mk_le(unsigned num_args, int const * coeffs, expr * const * args, int k); - app * mk_ge(unsigned num_args, int const * coeffs, expr * const * args, int k); + app * mk_at_least_k(unsigned num_args, expr * const * args, unsigned k); + app * mk_le(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k); + app * mk_ge(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k); bool is_at_most_k(app *a) const; - bool is_at_most_k(app *a, unsigned& k) const; - int get_k(app *a) const; + bool is_at_most_k(app *a, rational& k) const; + bool is_at_least_k(app *a) const; + bool is_at_least_k(app *a, rational& k) const; + rational get_k(app *a) const; bool is_le(app *a) const; - bool is_le(app* a, int& k) const; + bool is_le(app* a, rational& k) const; bool is_ge(app* a) const; - bool is_ge(app* a, int& k) const; - int get_coeff(app* a, unsigned index); + bool is_ge(app* a, rational& k) const; + rational get_coeff(app* a, unsigned index); }; diff --git a/src/opt/objective_ast.h b/src/opt/objective_ast.h new file mode 100644 index 000000000..b1005b40d --- /dev/null +++ b/src/opt/objective_ast.h @@ -0,0 +1,96 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + objective_ast.h + +Abstract: + Abstract data-type for compound objectives. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-11-21 + +Notes: + +--*/ +#ifndef __OBJECTIVE_AST_H_ +#define __OBJECTIVE_AST_H_ + +namespace opt { + + enum objective_t { + MINIMIZE, + MAXIMIZE, + MAXSAT, + LEX, + BOX, + PARETO + }; + + class compound_objective; + class min_max_objective; + class maxsat_objective; + + class objective { + objective_t m_type; + public: + objective(objective_t ty): + m_type(ty) + {} + virtual ~objective() {} + + objective_t type() const { return m_type; } + + // constructors; + static objective* mk_max(expr_ref& e); + static objective* mk_min(expr_ref& e); + static objective* mk_lex(unsigned sz, objective * const* children); + static objective* mk_box(unsigned sz, objective * const* children); + static objective* mk_pareto(unsigned sz, objective * const* children); + static objective* mk_maxsat(symbol id); + + // accessors (implicit cast operations) + compound_objective& get_compound(); // eg. SASSERT(m_type == LEX/BOX/PARETO); return dynamic_cast(*this); + min_max_objective& get_min_max(); + maxsat_objective& get_maxsat(); + }; + + class compound_objective : public objective { + ptr_vector m_children; + public: + compound_objective(objective_t t): objective(t) {} + virtual ~compound_objective() { + // dealloc vector m_children; + } + + objective *const* children() const { return m_children.c_ptr(); } + + unsigned num_children() const { return m_children.size(); } + } + + class min_max_objective : public objective { + bool m_is_max; + expr_ref m_expr; + public: + min_max_objective(bool is_max, expr_ref& e): m_is_max(is_max), m_expr(e) {} + + virtual ~min_max_objective() {} + + expr* term() { return m_expr; } + bool is_max() const { return m_is_max; } + }; + + class maxsat_objective : public objective { + symbol m_id; + public: + maxsat_objective(symbol const& id): m_id(id) {} + virtual ~maxsat_objective() {} + + symbol const& get_id() const { return m_id; } + }; + +}; + +#endif diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 8cc56926f..b46ad7e0d 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -30,44 +30,26 @@ namespace smt { void theory_pb::ineq::negate() { m_lit.neg(); - numeral sum = 0; + numeral sum(0); for (unsigned i = 0; i < size(); ++i) { m_args[i].first.neg(); sum += coeff(i); } - m_k = sum - m_k + 1; + m_k = sum - m_k + numeral::one(); SASSERT(well_formed()); } void theory_pb::ineq::reset() { - m_max_coeff = 0; + m_max_coeff.reset(); m_watch_sz = 0; - m_max_sum = 0; + m_max_sum.reset(); m_num_propagations = 0; m_compilation_threshold = UINT_MAX; m_compiled = l_false; m_args.reset(); - m_k = 0; + m_k.reset(); } - theory_pb::numeral theory_pb::ineq::gcd(numeral a, numeral b) { - while (a != b) { - if (a == 0) return b; - if (b == 0) return a; - SASSERT(a != 0 && b != 0); - if (a < b) { - b %= a; - } - else { - a %= b; - } - } - return a; - } - - theory_pb::numeral theory_pb::ineq::lcm(numeral a, numeral b) { - return (a*b)/gcd(a,b); - } void theory_pb::ineq::unique() { numeral& k = m_k; @@ -103,7 +85,7 @@ namespace smt { } args.pop_back(); } - if (coeff(i) == 0) { + if (coeff(i).is_zero()) { for (unsigned j = i; j + 1 < size(); ++j) { args[j] = args[j+1]; } @@ -127,10 +109,10 @@ namespace smt { // <=> // -c*~l + y >= k - c // - numeral sum = 0; + numeral sum(0); for (unsigned i = 0; i < size(); ++i) { numeral c = coeff(i); - if (c < 0) { + if (c.is_neg()) { args[i].second = -c; args[i].first = ~lit(i); k -= c; @@ -138,7 +120,7 @@ namespace smt { sum += coeff(i); } // detect tautologies: - if (k <= 0) { + if (k <= numeral::zero()) { args.reset(); return l_true; } @@ -147,8 +129,21 @@ namespace smt { args.reset(); return l_false; } + + // normalize to integers. + numeral d(denominator(k)); + for (unsigned i = 0; i < size(); ++i) { + d = lcm(d, denominator(coeff(i))); + } + if (!d.is_one()) { + k *= d; + for (unsigned i = 0; i < size(); ++i) { + args[i].second *= d; + } + } + // Ensure the largest coefficient is not larger than k: - sum = 0; + sum = numeral::zero(); for (unsigned i = 0; i < size(); ++i) { numeral c = coeff(i); if (c > k) { @@ -161,45 +156,52 @@ namespace smt { // normalize tight inequalities to unit coefficients. if (sum == k) { for (unsigned i = 0; i < size(); ++i) { - args[i].second = 1; + args[i].second = numeral::one(); } - k = size(); + k = numeral(size()); } // apply cutting plane reduction: - numeral g = 0; - for (unsigned i = 0; g != 1 && i < size(); ++i) { + numeral g(0); + for (unsigned i = 0; !g.is_one() && i < size(); ++i) { numeral c = coeff(i); if (c != k) { - g = gcd(g, c); + if (g.is_zero()) { + g = c; + } + else { + g = gcd(g, c); + } } } - if (g == 0) { + if (g.is_zero()) { // all coefficients are equal to k. for (unsigned i = 0; i < size(); ++i) { SASSERT(coeff(i) == k); - args[i].second = 1; + args[i].second = numeral::one(); } - k = 1; + k = numeral::one(); } - else if (g > 1) { + else if (g > numeral::one()) { // // Example 5x + 5y + 2z + 2u >= 5 // becomes 3x + 3y + z + u >= 3 // - numeral k_new = k / g; - if ((k % g) != 0) { // k_new is the ceiling of k / g. + numeral k_new = div(k, g); + if (!(k % g).is_zero()) { // k_new is the ceiling of k / g. k_new++; } for (unsigned i = 0; i < size(); ++i) { + SASSERT(coeff(i).is_pos()); numeral c = coeff(i); if (c == k) { c = k_new; } else { - c = c / g; + c = div(c, g); } args[i].second = c; + SASSERT(coeff(i).is_pos()); } k = k_new; } @@ -208,12 +210,12 @@ namespace smt { } bool theory_pb::ineq::well_formed() const { - SASSERT(k() > 0); + SASSERT(k().is_pos()); uint_set vars; - numeral sum = 0; + numeral sum = numeral::zero(); for (unsigned i = 0; i < size(); ++i) { SASSERT(coeff(i) <= k()); - SASSERT(1 <= coeff(i)); + SASSERT(numeral::one() <= coeff(i)); SASSERT(lit(i) != true_literal); SASSERT(lit(i) != false_literal); SASSERT(lit(i) != null_literal); @@ -274,6 +276,9 @@ namespace smt { } k = -k; } + else { + SASSERT(m_util.is_at_least_k(atom) || m_util.is_ge(atom)); + } c->unique(); lbool is_true = c->normalize(); @@ -295,7 +300,7 @@ namespace smt { // maximal coefficient: numeral& max_coeff = c->m_max_coeff; - max_coeff = 0; + max_coeff = numeral::zero(); for (unsigned i = 0; i < args.size(); ++i) { max_coeff = std::max(max_coeff, args[i].second); } @@ -304,7 +309,7 @@ namespace smt { // pre-compile threshold for cardinality bool is_cardinality = true; for (unsigned i = 0; is_cardinality && i < args.size(); ++i) { - is_cardinality = (args[i].second == 1); + is_cardinality = (args[i].second.is_one()); } if (is_cardinality) { unsigned log = 1, n = 1; @@ -472,7 +477,7 @@ namespace smt { if (ctx.get_assignment(c.lit()) == l_undef) { return; } - numeral sum = 0, maxsum = 0; + numeral sum = numeral::zero(), maxsum = numeral::zero(); for (unsigned i = 0; i < c.size(); ++i) { switch(ctx.get_assignment(c.lit(i))) { case l_true: @@ -511,7 +516,7 @@ namespace smt { } literal_vector& theory_pb::get_helpful_literals(ineq& c, bool negate) { - numeral sum = 0; + numeral sum = numeral::zero(); context& ctx = get_context(); literal_vector& lits = get_lits(); for (unsigned i = 0; sum < c.k() && i < c.size(); ++i) { @@ -553,7 +558,7 @@ namespace smt { SASSERT(c.well_formed()); context& ctx = get_context(); - numeral maxsum = 0; + numeral maxsum = numeral::zero(); for (unsigned i = 0; i < c.size(); ++i) { if (ctx.get_assignment(c.lit(i)) != l_false) { maxsum += c.coeff(i); @@ -570,7 +575,7 @@ namespace smt { add_clause(c, ~lits[0], lits); } else { - c.m_max_sum = 0; + c.m_max_sum = numeral::zero(); c.m_watch_sz = 0; for (unsigned i = 0; c.max_sum() < c.k() + c.max_coeff() && i < c.size(); ++i) { if (ctx.get_assignment(c.lit(i)) != l_false) { @@ -822,10 +827,9 @@ namespace smt { context& ctx = get_context(); // only cardinality constraints are compiled. SASSERT(c.m_compilation_threshold < UINT_MAX); - DEBUG_CODE(for (unsigned i = 0; i < c.size(); ++i) SASSERT(c.coeff(i) == 1); ); - unsigned k = static_cast(c.k()); + DEBUG_CODE(for (unsigned i = 0; i < c.size(); ++i) SASSERT(c.coeff(i).is_one()); ); + unsigned k = c.k().get_unsigned(); unsigned num_args = c.size(); - SASSERT(0 <= k && k <= num_args); sort_expr se(*this); sorting_network sn(se); @@ -925,7 +929,7 @@ namespace smt { } for (unsigned i = 0; i < c.size(); ++i) { literal l(c.lit(i)); - if (c.coeff(i) != 1) { + if (!c.coeff(i).is_one()) { out << c.coeff(i) << "*"; } out << l; @@ -941,11 +945,11 @@ namespace smt { } } out << " >= " << c.m_k << "\n"; - if (c.m_num_propagations) out << "propagations: " << c.m_num_propagations << " "; - if (c.max_coeff()) out << "max_coeff: " << c.max_coeff() << " "; - if (c.watch_size()) out << "watch size: " << c.watch_size() << " "; - if (c.max_sum()) out << "max-sum: " << c.max_sum() << " "; - if (c.m_num_propagations || c.max_coeff() || c.watch_size() || c.max_sum()) out << "\n"; + if (c.m_num_propagations) out << "propagations: " << c.m_num_propagations << " "; + if (c.max_coeff().is_pos()) out << "max_coeff: " << c.max_coeff() << " "; + if (c.watch_size()) out << "watch size: " << c.watch_size() << " "; + if (c.max_sum().is_pos()) out << "max-sum: " << c.max_sum() << " "; + if (c.m_num_propagations || c.max_coeff().is_pos() || c.watch_size() || c.max_sum().is_pos()) out << "\n"; return out; } @@ -1077,23 +1081,25 @@ namespace smt { // context& ctx = get_context(); - numeral coeff2 = (conseq==null_literal)?1:0; + numeral coeff2 = (conseq==null_literal)?numeral::one():numeral::zero(); for (unsigned i = 0; i < c.size(); ++i) { if (c.lit(i) == conseq) { coeff2 = c.coeff(i); break; } } - SASSERT(coeff2 > 0); - numeral lc = ineq::lcm(coeff1, coeff2); + SASSERT(coeff2.is_pos()); + numeral lc = lcm(coeff1, coeff2); numeral g = lc/coeff1; - if (g > 1) { + SASSERT(g.is_int()); + if (g > numeral::one()) { for (unsigned i = 0; i < m_lemma.size(); ++i) { m_lemma.m_args[i].second *= g; } m_lemma.m_k *= g; } g = lc/coeff2; + SASSERT(g.is_int()); m_lemma.m_k += g*c.k(); for (unsigned i = 0; i < c.size(); ++i) { @@ -1132,7 +1138,7 @@ namespace smt { m_num_marks = 0; m_lemma.reset(); m_ineq_literals.reset(); - process_ineq(c, null_literal, 1); // add consequent to lemma. + process_ineq(c, null_literal, numeral::one()); // add consequent to lemma. // point into stack of assigned literals literal_vector const& lits = ctx.assigned_literals(); @@ -1241,15 +1247,15 @@ namespace smt { IF_VERBOSE(1, display(verbose_stream() << "lemma: ", m_lemma);); ast_manager& m = get_manager(); - svector coeffs; + svector coeffs; expr_ref_vector args(m); expr_ref tmp(m); for (unsigned i = 0; i < m_lemma.size(); ++i) { ctx.literal2expr(m_lemma.lit(i), tmp); args.push_back(tmp); - coeffs.push_back(static_cast(m_lemma.coeff(i))); + coeffs.push_back(m_lemma.coeff(i)); } - int k = static_cast(m_lemma.k()); + numeral k = m_lemma.k(); tmp = m_util.mk_ge(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), k); internalize_atom(to_app(tmp), false); //m_ineq_literals.push_back(literal(ctx.get_bool_var(tmp))); diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index e205f3f59..dd0fd41dc 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -29,8 +29,8 @@ namespace smt { struct sort_expr; class pb_justification; - typedef int64 numeral; - typedef svector > arg_t; + typedef rational numeral; + typedef vector > arg_t; struct stats { unsigned m_num_conflicts; @@ -91,8 +91,8 @@ namespace smt { bool well_formed() const; - static numeral gcd(numeral a, numeral b); - static numeral lcm(numeral a, numeral b); + //static numeral gcd(numeral a, numeral b); + //static numeral lcm(numeral a, numeral b); }; diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index dde03f962..5b8e8e107 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -181,7 +181,7 @@ void tactic2solver::set_cancel(bool f) { void tactic2solver::collect_statistics(statistics & st) const { st.copy(m_stats); - SASSERT(m_stats.size() > 0); + //SASSERT(m_stats.size() > 0); } void tactic2solver::get_unsat_core(ptr_vector & r) { From 3b2dd47cd4028d9107eca3048043892eb67df6ff Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Thu, 21 Nov 2013 19:05:17 -0800 Subject: [PATCH 156/925] Refactor pivot rules --- src/smt/diff_logic.h | 36 +++++++++++++++++++++++++----------- src/smt/network_flow.h | 6 +++--- src/smt/network_flow_def.h | 25 ++++++++++++++----------- src/smt/spanning_tree.h | 1 + src/smt/spanning_tree_def.h | 8 ++++---- 5 files changed, 47 insertions(+), 29 deletions(-) diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index 7bc430244..6e58d31bb 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -961,7 +961,6 @@ public: for (; it != end; ++it) { edge_id e_id = *it; edge & e = m_edges[e_id]; - if (!e.is_enabled()) continue; SASSERT(e.get_source() == current); dl_var neighbour = e.get_target(); neighbours.push_back(neighbour); @@ -972,7 +971,6 @@ public: for (; it != end; ++it) { edge_id e_id = *it; edge & e = m_edges[e_id]; - if (!e.is_enabled()) continue; SASSERT(e.get_target() == current); dl_var neighbour = e.get_source(); neighbours.push_back(neighbour); @@ -982,27 +980,41 @@ public: void dfs_undirected(dl_var start, svector & threads) { threads.reset(); threads.resize(get_num_nodes()); - uint_set visited; + uint_set discovered, explored; svector nodes; + discovered.insert(start); nodes.push_back(start); dl_var prev = -1; while(!nodes.empty()) { dl_var current = nodes.back(); - nodes.pop_back(); - visited.insert(current); - if (prev != -1) + SASSERT(discovered.contains(current) && !explored.contains(current)); + std::cout << "thread[" << prev << "] --> " << current << std::endl; + if (prev != -1) { threads[prev] = current; + std::cout << "thread[" << prev << "] --> " << current << std::endl; + } prev = current; svector neighbours; get_neighbours_undirected(current, neighbours); + SASSERT(!neighbours.empty()); + bool found = false; for (unsigned i = 0; i < neighbours.size(); ++i) { + dl_var next = neighbours[i]; DEBUG_CODE( edge_id id; - SASSERT(prev == -1 || get_edge_id(prev, current, id) || get_edge_id(current, prev, id));); - if (!visited.contains(neighbours[i])) { - nodes.push_back(neighbours[i]); + SASSERT(get_edge_id(current, next, id) || get_edge_id(next, current, id));); + if (!discovered.contains(next) && !explored.contains(next)) { + discovered.insert(next); + nodes.push_back(next); + found = true; + break; } - } + } + SASSERT(!nodes.empty()); + if (!found) { + explored.insert(current); + nodes.pop_back(); + } } threads[prev] = start; } @@ -1022,8 +1034,10 @@ public: SASSERT(visited.contains(current)); svector neighbours; get_neighbours_undirected(current, neighbours); + SASSERT(!neighbours.empty()); for (unsigned i = 0; i < neighbours.size(); ++i) { - dl_var & next = neighbours[i]; + dl_var next = neighbours[i]; + std::cout << "parents[" << next << "] --> " << current << std::endl; DEBUG_CODE( edge_id id; SASSERT(get_edge_id(current, next, id) || get_edge_id(next, current, id));); diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index d845c671a..b2a5953ed 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -82,7 +82,7 @@ namespace smt { bool choose_entering_edge() {return false;}; }; - class first_eligible_pivot : pivot_rule_impl { + class first_eligible_pivot : public pivot_rule_impl { private: edge_id m_next_edge; @@ -117,7 +117,7 @@ namespace smt { }; }; - class best_eligible_pivot : pivot_rule_impl { + class best_eligible_pivot : public pivot_rule_impl { public: best_eligible_pivot(graph & g, vector & potentials, svector & states, edge_id & enter_id) : @@ -152,7 +152,7 @@ namespace smt { }; }; - class candidate_list_pivot : pivot_rule_impl { + class candidate_list_pivot : public pivot_rule_impl { private: edge_id m_next_edge; svector m_candidates; diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index 7af1a87ff..383740e4a 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -170,18 +170,21 @@ namespace smt { // FIXME: should declare pivot as a pivot_rule_impl and refactor template bool network_flow::choose_entering_edge(pivot_rule pr) { - if (pr == FIRST_ELIGIBLE) { - first_eligible_pivot pivot(m_graph, m_potentials, m_states, m_enter_id); - return pivot.choose_entering_edge(); + pivot_rule_impl * pivot; + switch (pr) { + case FIRST_ELIGIBLE: + pivot = alloc(first_eligible_pivot, m_graph, m_potentials, m_states, m_enter_id); + break; + case BEST_ELIGIBLE: + pivot = alloc(best_eligible_pivot, m_graph, m_potentials, m_states, m_enter_id); + break; + case CANDIDATE_LIST: + pivot = alloc(best_eligible_pivot, m_graph, m_potentials, m_states, m_enter_id); + break; + default: + UNREACHABLE(); } - else if (pr == BEST_ELIGIBLE) { - best_eligible_pivot pivot(m_graph, m_potentials, m_states, m_enter_id); - return pivot.choose_entering_edge(); - } - else { - candidate_list_pivot pivot(m_graph, m_potentials, m_states, m_enter_id); - return pivot.choose_entering_edge(); - } + return pivot->choose_entering_edge(); } // Minimize cost flows diff --git a/src/smt/spanning_tree.h b/src/smt/spanning_tree.h index bce910b87..e9954c1d9 100644 --- a/src/smt/spanning_tree.h +++ b/src/smt/spanning_tree.h @@ -74,6 +74,7 @@ namespace smt { private: graph * m_tree_graph; + public: basic_spanning_tree(graph & g); void initialize(svector const & tree); diff --git a/src/smt/spanning_tree_def.h b/src/smt/spanning_tree_def.h index 32b971c45..6697c8969 100644 --- a/src/smt/spanning_tree_def.h +++ b/src/smt/spanning_tree_def.h @@ -420,14 +420,15 @@ namespace smt { template void basic_spanning_tree::initialize(svector const & tree) { - unsigned num_nodes = m_graph.get_num_nodes(); m_tree_graph = alloc(graph); + m_tree = tree; + unsigned num_nodes = m_graph.get_num_nodes(); for (unsigned i = 0; i < num_nodes; ++i) { m_tree_graph->init_var(i); } vector const & es = m_graph.get_all_edges(); - svector::const_iterator it = tree.begin(), end = tree.end(); + svector::const_iterator it = m_tree.begin(), end = m_tree.end(); for(; it != end; ++it) { edge const & e = es[*it]; m_tree_graph->add_edge(e.get_source(), e.get_target(), e.get_weight(), explanation()); @@ -440,8 +441,7 @@ namespace smt { template void basic_spanning_tree::update(edge_id enter_id, edge_id leave_id) { - if (m_tree_graph) - dealloc(m_tree_graph); + if (m_tree_graph) dealloc(m_tree_graph); m_tree_graph = alloc(graph); unsigned num_nodes = m_graph.get_num_nodes(); for (unsigned i = 0; i < num_nodes; ++i) { From 7bc7a61a40f1c7c106f50f139c7a8470e264965f Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Fri, 22 Nov 2013 08:58:17 +0100 Subject: [PATCH 157/925] Debug undirected dfs and bfs --- src/smt/diff_logic.h | 57 ++++++++++++++++++------------------- src/smt/spanning_tree_def.h | 6 ++-- 2 files changed, 31 insertions(+), 32 deletions(-) diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index 6e58d31bb..32f8111f0 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -956,8 +956,8 @@ public: void get_neighbours_undirected(dl_var current, svector & neighbours) { neighbours.reset(); - edge_id_vector & edges = m_out_edges[current]; - typename edge_id_vector::iterator it = edges.begin(), end = edges.end(); + edge_id_vector & out_edges = m_out_edges[current]; + typename edge_id_vector::iterator it = out_edges.begin(), end = out_edges.end(); for (; it != end; ++it) { edge_id e_id = *it; edge & e = m_edges[e_id]; @@ -965,11 +965,10 @@ public: dl_var neighbour = e.get_target(); neighbours.push_back(neighbour); } - edges = m_in_edges[current]; - it = edges.begin(); - end = edges.end(); - for (; it != end; ++it) { - edge_id e_id = *it; + edge_id_vector & in_edges = m_in_edges[current]; + typename edge_id_vector::iterator it2 = in_edges.begin(), end2 = in_edges.end(); + for (; it2 != end2; ++it2) { + edge_id e_id = *it2; edge & e = m_edges[e_id]; SASSERT(e.get_target() == current); dl_var neighbour = e.get_source(); @@ -984,31 +983,28 @@ public: svector nodes; discovered.insert(start); nodes.push_back(start); - dl_var prev = -1; + dl_var prev = start; while(!nodes.empty()) { dl_var current = nodes.back(); SASSERT(discovered.contains(current) && !explored.contains(current)); - std::cout << "thread[" << prev << "] --> " << current << std::endl; - if (prev != -1) { - threads[prev] = current; - std::cout << "thread[" << prev << "] --> " << current << std::endl; - } - prev = current; svector neighbours; get_neighbours_undirected(current, neighbours); SASSERT(!neighbours.empty()); bool found = false; for (unsigned i = 0; i < neighbours.size(); ++i) { dl_var next = neighbours[i]; - DEBUG_CODE( - edge_id id; - SASSERT(get_edge_id(current, next, id) || get_edge_id(next, current, id));); - if (!discovered.contains(next) && !explored.contains(next)) { + DEBUG_CODE( + edge_id id; + SASSERT(get_edge_id(current, next, id) || get_edge_id(next, current, id));); + if (!discovered.contains(next) && !explored.contains(next)) { + TRACE("diff_logic", tout << "thread[" << prev << "] --> " << next << std::endl;); + threads[prev] = next; + prev = next; discovered.insert(next); - nodes.push_back(next); + nodes.push_back(next); found = true; break; - } + } } SASSERT(!nodes.empty()); if (!found) { @@ -1022,6 +1018,7 @@ public: void bfs_undirected(dl_var start, svector & parents, svector & depths) { parents.reset(); parents.resize(get_num_nodes()); + parents[start] = -1; depths.reset(); depths.resize(get_num_nodes()); uint_set visited; @@ -1037,16 +1034,16 @@ public: SASSERT(!neighbours.empty()); for (unsigned i = 0; i < neighbours.size(); ++i) { dl_var next = neighbours[i]; - std::cout << "parents[" << next << "] --> " << current << std::endl; - DEBUG_CODE( - edge_id id; - SASSERT(get_edge_id(current, next, id) || get_edge_id(next, current, id));); - if (!visited.contains(next)) { - parents[next] = current; - depths[next] = depths[current] + 1; - visited.insert(next); - nodes.push_front(next); - } + DEBUG_CODE( + edge_id id; + SASSERT(get_edge_id(current, next, id) || get_edge_id(next, current, id));); + if (!visited.contains(next)) { + TRACE("diff_logic", tout << "parents[" << next << "] --> " << current << std::endl;); + parents[next] = current; + depths[next] = depths[current] + 1; + visited.insert(next); + nodes.push_front(next); + } } } } diff --git a/src/smt/spanning_tree_def.h b/src/smt/spanning_tree_def.h index 6697c8969..faf45c383 100644 --- a/src/smt/spanning_tree_def.h +++ b/src/smt/spanning_tree_def.h @@ -421,7 +421,8 @@ namespace smt { template void basic_spanning_tree::initialize(svector const & tree) { m_tree_graph = alloc(graph); - m_tree = tree; + m_tree.reset(); + m_tree.append(tree); unsigned num_nodes = m_graph.get_num_nodes(); for (unsigned i = 0; i < num_nodes; ++i) { m_tree_graph->init_var(i); @@ -456,7 +457,8 @@ namespace smt { m_tree_graph->add_edge(e.get_source(), e.get_target(), e.get_weight(), explanation()); } } - m_tree_graph->add_edge(m_graph.get_source(enter_id), m_graph.get_target(enter_id), m_graph.get_weight(enter_id), explanation()); + edge const & e = es[enter_id]; + m_tree_graph->add_edge(e.get_source(), e.get_target(), e.get_weight(), explanation()); node root = num_nodes - 1; m_tree_graph->bfs_undirected(root, m_pred, m_depth); From 37f562882426cac5909cd1d912fab9b436ab0370 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Fri, 22 Nov 2013 13:44:12 -0800 Subject: [PATCH 158/925] Update basic spanning tree to be on par with threaded one --- src/smt/network_flow.h | 3 +-- src/smt/network_flow_def.h | 28 +++++++++++++++++++++++----- src/smt/spanning_tree.h | 1 - src/smt/spanning_tree_def.h | 23 ++++++++++++++++++----- src/smt/theory_diff_logic.h | 1 - src/smt/theory_diff_logic_def.h | 33 +++++++++++++++++++++------------ 6 files changed, 63 insertions(+), 26 deletions(-) diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index b2a5953ed..b97b9bd40 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -71,7 +71,6 @@ namespace smt { edge_id & m_enter_id; public: - pivot_rule_impl() {} pivot_rule_impl(graph & g, vector & potentials, svector & states, edge_id & enter_id) : m_graph(g), @@ -79,7 +78,7 @@ namespace smt { m_states(states), m_enter_id(enter_id) { } - bool choose_entering_edge() {return false;}; + virtual bool choose_entering_edge() = 0; }; class first_eligible_pivot : public pivot_rule_impl { diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index 383740e4a..86515f432 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -40,6 +40,24 @@ namespace smt { m_graph.add_edge(e.get_target(), e.get_source(), e.get_weight(), explanation()); } } + TRACE("network_flow", { + tout << "Solving different logic optimization problem:" << std::endl; + for (unsigned i = 0; i < m_graph.get_num_nodes(); ++i) { + tout << "(declare-fun v" << i << " () Real)" << std::endl; + } + vector const & es = m_graph.get_all_edges(); + for (unsigned i = 0; i < m_graph.get_num_edges(); ++i) { + edge const & e = es[i]; + tout << "(assert (<= (- v" << e.get_source() << " v" << e.get_target() << ") " << e.get_weight() << "))" << std::endl; + }; + tout << "(maximize (+ "; + for (unsigned i = 0; i < balances.size(); ++i) { + tout << "(* " << balances[i] << " v" << i << ") "; + }; + tout << "))" << std::endl; + tout << "(optimize)" << std::endl; + };); + m_step = 0; m_tree = alloc(basic_spanning_tree, m_graph); } @@ -130,7 +148,7 @@ namespace smt { } template - bool network_flow::choose_leaving_edge() { + bool network_flow::choose_leaving_edge() { TRACE("network_flow", tout << "choose_leaving_edge...\n";); node src = m_graph.get_source(m_enter_id); node tgt = m_graph.get_target(m_enter_id); @@ -155,10 +173,10 @@ namespace smt { tout << "Found leaving edge " << m_leave_id; tout << " between node " << m_graph.get_source(m_leave_id); tout << " and node " << m_graph.get_target(m_leave_id) << " with delta = " << *m_delta << "...\n"; - }); + }); return true; } - TRACE("network_flow", tout << "Can't find a leaving edge... The problem is unbounded.\n";); + TRACE("network_flow", tout << "Can't find a leaving edge... The problem is unbounded.\n";); return false; } @@ -179,7 +197,7 @@ namespace smt { pivot = alloc(best_eligible_pivot, m_graph, m_potentials, m_states, m_enter_id); break; case CANDIDATE_LIST: - pivot = alloc(best_eligible_pivot, m_graph, m_potentials, m_states, m_enter_id); + pivot = alloc(candidate_list_pivot, m_graph, m_potentials, m_states, m_enter_id); break; default: UNREACHABLE(); @@ -208,7 +226,7 @@ namespace smt { } else { m_states[m_leave_id] = m_states[m_leave_id] == LOWER ? UPPER : LOWER; - } + } } TRACE("network_flow", tout << "Found optimal solution.\n";); SASSERT(check_optimal()); diff --git a/src/smt/spanning_tree.h b/src/smt/spanning_tree.h index e9954c1d9..bce910b87 100644 --- a/src/smt/spanning_tree.h +++ b/src/smt/spanning_tree.h @@ -74,7 +74,6 @@ namespace smt { private: graph * m_tree_graph; - public: basic_spanning_tree(graph & g); void initialize(svector const & tree); diff --git a/src/smt/spanning_tree_def.h b/src/smt/spanning_tree_def.h index faf45c383..5127fb2b4 100644 --- a/src/smt/spanning_tree_def.h +++ b/src/smt/spanning_tree_def.h @@ -421,8 +421,7 @@ namespace smt { template void basic_spanning_tree::initialize(svector const & tree) { m_tree_graph = alloc(graph); - m_tree.reset(); - m_tree.append(tree); + m_tree = tree; unsigned num_nodes = m_graph.get_num_nodes(); for (unsigned i = 0; i < num_nodes; ++i) { m_tree_graph->init_var(i); @@ -464,11 +463,25 @@ namespace smt { m_tree_graph->bfs_undirected(root, m_pred, m_depth); m_tree_graph->dfs_undirected(root, m_thread); - for (node x = m_thread[root]; x != root; x = m_thread[x]) { + vector const & tree_edges = m_tree_graph->get_all_edges(); + for (unsigned i = 0; i < tree_edges.size(); ++i) { + edge const & e = tree_edges[i]; + dl_var src = e.get_source(); + dl_var tgt = e.get_target(); edge_id id; - VERIFY(m_graph.get_edge_id(x, m_pred[x], id)); - m_tree[x] = id; + VERIFY(m_graph.get_edge_id(src, tgt, id)); + SASSERT(tgt == m_pred[src] || src == m_pred[tgt]); + if (tgt == m_pred[src]) { + m_tree[src] = id; + } + else { + m_tree[tgt] = id; + } } + + node p = m_graph.get_source(enter_id); + node q = m_graph.get_target(enter_id); + m_root_t2 = p == m_pred[q] ? q : p; } } diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h index 9cc01e260..7f85d854f 100644 --- a/src/smt/theory_diff_logic.h +++ b/src/smt/theory_diff_logic.h @@ -192,7 +192,6 @@ namespace smt { vector m_objectives; vector m_objective_consts; vector > m_objective_assignments; - numeral m_objective_value; // Set a conflict due to a negative cycle. void set_neg_cycle_conflict(); diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index b654d9c31..c45493434 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -1007,9 +1007,9 @@ inf_eps_rational theory_diff_logic::maximize(theory_var v) { IF_VERBOSE(1, for (unsigned i = 0; i < objective.size(); ++i) { - verbose_stream() << "coefficient " << objective[i].second << " of theory_var " << objective[i].first << "\n"; + verbose_stream() << "Coefficient " << objective[i].second << " of theory_var " << objective[i].first << "\n"; } - verbose_stream() << "free coefficient " << m_objective_consts[v] << "\n";); + verbose_stream() << "Free coefficient " << m_objective_consts[v] << "\n";); // Objective coefficients now become balances vector balances(m_graph.get_num_nodes()); @@ -1018,24 +1018,33 @@ inf_eps_rational theory_diff_logic::maximize(theory_var v) { fin_numeral balance(objective[i].second); balances[objective[i].first] = balance; } - + network_flow net_flow(m_graph, balances); bool is_optimal = net_flow.min_cost(); if (is_optimal) { - vector potentials; - m_objective_value = net_flow.get_optimal_solution(potentials, true); - std::cout << "Objective value of var " << v << ": " << m_objective_value << std::endl; - m_objective_assignments[v] = potentials; + numeral objective_value = net_flow.get_optimal_solution(m_objective_assignments[v], true) + numeral(m_objective_consts[v]); + IF_VERBOSE(1, verbose_stream() << "Optimal value of objective " << v << ": " << objective_value << std::endl;); + + DEBUG_CODE( + numeral initial_value = numeral(m_objective_consts[v]); + for (unsigned i = 0; i < objective.size(); ++i) { + initial_value += fin_numeral(objective[i].second) * m_graph.get_assignment(objective[i].first); + } + IF_VERBOSE(1, verbose_stream() << "Initial value of objective " << v << ": " << initial_value << std::endl;); + SASSERT(objective_value >= initial_value);); + + vector & current_assigments = m_objective_assignments[v]; + SASSERT(!current_assigments.empty()); TRACE("network_flow", - for (unsigned i = 0; i < potentials.size(); ++i) { - tout << "v" << i << " -> " << potentials[i] << "\n"; + for (unsigned i = 0; i < current_assigments.size(); ++i) { + tout << "v" << i << " -> " << current_assigments[i] << std::endl; }); - rational r = m_objective_value.get_rational().to_rational(); - rational i = m_objective_value.get_infinitesimal().to_rational(); + rational r = objective_value.get_rational().to_rational(); + rational i = objective_value.get_infinitesimal().to_rational(); return inf_eps_rational(inf_rational(r, i)); } else { - std::cout << "Unbounded objective" << std::endl; + IF_VERBOSE(1, verbose_stream() << "Unbounded objective" << std::endl;); return inf_eps_rational::infinity(); } } From b35088f7e53e2a0f15f4e565e88a68d328d80b27 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Fri, 22 Nov 2013 18:15:34 -0800 Subject: [PATCH 159/925] Update diff logic optimization --- src/smt/network_flow.h | 1 - src/smt/network_flow_def.h | 29 +++++++++++++++++------------ src/smt/theory_diff_logic_def.h | 16 ++++++++++++---- 3 files changed, 29 insertions(+), 17 deletions(-) diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index b97b9bd40..6e6fcaee0 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -54,7 +54,6 @@ namespace smt { enum edge_state { LOWER = 1, BASIS = 0, - UPPER = -1 }; typedef dl_var node; diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index 86515f432..c5038222e 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -114,11 +114,17 @@ namespace smt { node src = m_graph.get_source(m_enter_id); node tgt = m_graph.get_target(m_enter_id); numeral cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(m_enter_id); - numeral change = m_tree->in_subtree_t2(tgt) ? cost : -cost; - node start = m_graph.get_source(m_leave_id); - if (!m_tree->in_subtree_t2(start)) { - start = m_graph.get_target(m_leave_id);; + numeral change; + node start; + if (m_tree->in_subtree_t2(tgt)) { + change = cost; + start = tgt; } + else { + change = -cost; + start = src; + } + SASSERT(m_tree->in_subtree_t2(start)); TRACE("network_flow", tout << "update_potentials of T_" << start << " with change = " << change << "...\n";); svector descendants; m_tree->get_descendants(start, descendants); @@ -185,7 +191,6 @@ namespace smt { m_tree->update(m_enter_id, m_leave_id); } - // FIXME: should declare pivot as a pivot_rule_impl and refactor template bool network_flow::choose_entering_edge(pivot_rule pr) { pivot_rule_impl * pivot; @@ -218,14 +223,11 @@ namespace smt { SASSERT(edge_in_tree(m_leave_id)); SASSERT(!edge_in_tree(m_enter_id)); m_states[m_enter_id] = BASIS; - m_states[m_leave_id] = (m_flows[m_leave_id].is_zero()) ? LOWER : UPPER; + m_states[m_leave_id] = LOWER; update_spanning_tree(); update_potentials(); TRACE("network_flow", tout << "Spanning tree:\n" << display_spanning_tree();); SASSERT(check_well_formed()); - } - else { - m_states[m_leave_id] = m_states[m_leave_id] == LOWER ? UPPER : LOWER; } } TRACE("network_flow", tout << "Found optimal solution.\n";); @@ -241,7 +243,7 @@ namespace smt { for (unsigned i = 0; i < num_edges; ++i) { if (m_states[i] == BASIS) { - objective_value += m_graph.get_weight(i).get_rational() * m_flows[i]; + objective_value += m_flows[i].get_rational() * m_graph.get_weight(i); } } result.reset(); @@ -273,7 +275,10 @@ namespace smt { unsigned num_edges = m_graph.get_num_edges(); for (unsigned i = 0; i < num_edges; ++i) { if (m_states[i] == BASIS) { - SASSERT(m_potentials[m_graph.get_source(i)] - m_potentials[m_graph.get_target(i)] == m_graph.get_weight(i)); + dl_var src = m_graph.get_source(i); + dl_var tgt = m_graph.get_target(i); + numeral weight = m_graph.get_weight(i); + SASSERT(m_potentials[src] - m_potentials[tgt] == weight); } } @@ -286,7 +291,7 @@ namespace smt { unsigned num_edges = m_graph.get_num_edges(); for (unsigned i = 0; i < num_edges; ++i) { if (m_states[i] == BASIS) { - total_cost += m_graph.get_weight(i).get_rational() * m_flows[i]; + total_cost += m_flows[i].get_rational() * m_graph.get_weight(i); } } diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index c45493434..d0cef90cf 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -1031,7 +1031,8 @@ inf_eps_rational theory_diff_logic::maximize(theory_var v) { initial_value += fin_numeral(objective[i].second) * m_graph.get_assignment(objective[i].first); } IF_VERBOSE(1, verbose_stream() << "Initial value of objective " << v << ": " << initial_value << std::endl;); - SASSERT(objective_value >= initial_value);); + // FIXME: Network Simplex lose precisions when handling infinitesimals + SASSERT(objective_value >= initial_value.get_rational());); vector & current_assigments = m_objective_assignments[v]; SASSERT(!current_assigments.empty()); @@ -1092,11 +1093,17 @@ expr* theory_diff_logic::block_lower_bound(theory_var v, inf_rational const vector const & ns = m_objective_assignments[v]; inf_rational val; rational r, s; - for (unsigned i = 0; i < t.size(); ++i) { + rational r0 = ns[0].get_rational().to_rational(); + rational s0 = ns[0].get_infinitesimal().to_rational(); + app * x; + app * x0 = get_enode(t[0].first)->get_owner(); + // Assert improved bounds for x_i - x_0 + for (unsigned i = 1; i < t.size(); ++i) { r = ns[i].get_rational().to_rational(); s = ns[i].get_infinitesimal().to_rational(); - val = inf_rational(r, s); - f = get_enode(t[i].first)->get_owner(); + val = inf_rational(r - r0, s - s0); + x = get_enode(t[i].first)->get_owner(); + f = m_util.mk_sub(x, x0); e = m_util.mk_numeral(val.get_rational(), m.get_sort(f)); if (t[i].second.is_neg() && val.get_infinitesimal().is_pos()) { disj.push_back(m_util.mk_le(f, e)); @@ -1111,6 +1118,7 @@ expr* theory_diff_logic::block_lower_bound(theory_var v, inf_rational const disj.push_back(m_util.mk_gt(f, e)); } else { + UNREACHABLE(); } } return m.mk_or(disj.size(), disj.c_ptr()); From 2ff51e9a6084c88450f1cff7a9c8379fcf23ed0f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 23 Nov 2013 21:33:35 +0100 Subject: [PATCH 160/925] move model_evaluator from pdr to model, call it model_implicant Signed-off-by: Nikolaj Bjorner --- src/model/model_implicant.cpp | 917 +++++++++++++++++++++++++++ src/model/model_implicant.h | 118 ++++ src/muz/pdr/pdr_context.cpp | 3 +- src/muz/pdr/pdr_util.cpp | 873 ------------------------- src/muz/pdr/pdr_util.h | 80 --- src/opt/fu_malik.cpp | 2 +- src/opt/opt_solver.cpp | 19 +- src/opt/opt_solver.h | 5 +- src/smt/theory_pb.cpp | 260 ++++---- src/smt/theory_pb.h | 9 +- src/tactic/arith/lia2card_tactic.cpp | 569 +++++++++-------- 11 files changed, 1514 insertions(+), 1341 deletions(-) create mode 100644 src/model/model_implicant.cpp create mode 100644 src/model/model_implicant.h diff --git a/src/model/model_implicant.cpp b/src/model/model_implicant.cpp new file mode 100644 index 000000000..44c70036c --- /dev/null +++ b/src/model/model_implicant.cpp @@ -0,0 +1,917 @@ +/*++ +Copyright (c) 2011 Microsoft Corporation + +Module Name: + + model_implicant.cpp + +Abstract: + + Facility to extract prime implicant from model. + +Author: + + Krystof Hoder (t-khoder) 2011-8-19. + +Revision History: + + +Notes: + + +--*/ + +#include +#include "array_decl_plugin.h" +#include "ast_pp.h" +#include "bool_rewriter.h" +#include "for_each_expr.h" +#include "model.h" +#include "ref_vector.h" +#include "rewriter.h" +#include "rewriter_def.h" +#include "util.h" +#include "model_implicant.h" +#include "arith_decl_plugin.h" +#include "expr_replacer.h" +#include "model_smt2_pp.h" +#include "poly_rewriter.h" +#include "poly_rewriter_def.h" +#include "arith_rewriter.h" +#include "scoped_proof.h" + + + +///////////////////////// +// model_implicant +// + + +void model_implicant::assign_value(expr* e, expr* val) { + rational r; + if (m.is_true(val)) { + set_true(e); + } + else if (m.is_false(val)) { + set_false(e); + } + else if (m_arith.is_numeral(val, r)) { + set_number(e, r); + } + else if (m.is_value(val)) { + set_value(e, val); + } + else { + IF_VERBOSE(3, verbose_stream() << "Not evaluated " << mk_pp(e, m) << " := " << mk_pp(val, m) << "\n";); + TRACE("pdr", tout << "Variable is not tracked: " << mk_pp(e, m) << " := " << mk_pp(val, m) << "\n";); + set_x(e); + } +} + +void model_implicant::setup_model(model_ref& model) { + m_numbers.reset(); + m_values.reset(); + m_model = model; + rational r; + unsigned sz = model->get_num_constants(); + for (unsigned i = 0; i < sz; i++) { + func_decl * d = model->get_constant(i); + expr* val = model->get_const_interp(d); + expr* e = m.mk_const(d); + m_refs.push_back(e); + assign_value(e, val); + } +} + +void model_implicant::reset() { + m1.reset(); + m2.reset(); + m_values.reset(); + m_visited.reset(); + m_numbers.reset(); + m_refs.reset(); + m_model = 0; +} + +expr_ref_vector model_implicant::minimize_model(ptr_vector const & formulas, model_ref& mdl) { + setup_model(mdl); + + TRACE("pdr_verbose", + tout << "formulas:\n"; + for (unsigned i = 0; i < formulas.size(); ++i) tout << mk_pp(formulas[i], m) << "\n"; + ); + + expr_ref_vector model = prune_by_cone_of_influence(formulas); + TRACE("pdr_verbose", + tout << "pruned model:\n"; + for (unsigned i = 0; i < model.size(); ++i) tout << mk_pp(model[i].get(), m) << "\n";); + + reset(); + + DEBUG_CODE( + setup_model(mdl); + VERIFY(check_model(formulas)); + reset();); + + return model; +} + +expr_ref_vector model_implicant::minimize_literals(ptr_vector const& formulas, model_ref& mdl) { + + TRACE("pdr", + tout << "formulas:\n"; + for (unsigned i = 0; i < formulas.size(); ++i) tout << mk_pp(formulas[i], m) << "\n"; + ); + + expr_ref_vector result(m); + expr_ref tmp(m); + ptr_vector tocollect; + + setup_model(mdl); + collect(formulas, tocollect); + for (unsigned i = 0; i < tocollect.size(); ++i) { + expr* e = tocollect[i]; + expr* e1, *e2; + SASSERT(m.is_bool(e)); + SASSERT(is_true(e) || is_false(e)); + if (is_true(e)) { + result.push_back(e); + } + // hack to break disequalities for arithmetic variables. + else if (m.is_eq(e, e1, e2) && m_arith.is_int_real(e1)) { + if (get_number(e1) < get_number(e2)) { + result.push_back(m_arith.mk_lt(e1,e2)); + } + else { + result.push_back(m_arith.mk_lt(e2,e1)); + } + } + else { + result.push_back(m.mk_not(e)); + } + } + reset(); + TRACE("pdr", + tout << "minimized model:\n"; + for (unsigned i = 0; i < result.size(); ++i) tout << mk_pp(result[i].get(), m) << "\n"; + ); + + return result; +} + +void model_implicant::process_formula(app* e, ptr_vector& todo, ptr_vector& tocollect) { + SASSERT(m.is_bool(e)); + SASSERT(is_true(e) || is_false(e)); + unsigned v = is_true(e); + unsigned sz = e->get_num_args(); + expr* const* args = e->get_args(); + if (e->get_family_id() == m.get_basic_family_id()) { + switch(e->get_decl_kind()) { + case OP_TRUE: + break; + case OP_FALSE: + break; + case OP_EQ: + case OP_IFF: + if (args[0] == args[1]) { + SASSERT(v); + // no-op + } + else if (m.is_bool(args[0])) { + todo.append(sz, args); + } + else { + tocollect.push_back(e); + } + break; + case OP_DISTINCT: + tocollect.push_back(e); + break; + case OP_ITE: + if (args[1] == args[2]) { + tocollect.push_back(args[1]); + } + else if (is_true(args[1]) && is_true(args[2])) { + todo.append(2, args+1); + } + else if (is_false(args[1]) && is_false(args[2])) { + todo.append(2, args+1); + } + else if (is_true(args[0])) { + todo.append(2, args); + } + else { + SASSERT(is_false(args[0])); + todo.push_back(args[0]); + todo.push_back(args[2]); + } + break; + case OP_AND: + if (v) { + todo.append(sz, args); + } + else { + unsigned i = 0; + for (; !is_false(args[i]) && i < sz; ++i); + if (i == sz) { + fatal_error(1); + } + VERIFY(i < sz); + todo.push_back(args[i]); + } + break; + case OP_OR: + if (v) { + unsigned i = 0; + for (; !is_true(args[i]) && i < sz; ++i); + if (i == sz) { + fatal_error(1); + } + VERIFY(i < sz); + todo.push_back(args[i]); + } + else { + todo.append(sz, args); + } + break; + case OP_XOR: + case OP_NOT: + todo.append(sz, args); + break; + case OP_IMPLIES: + if (v) { + if (is_true(args[1])) { + todo.push_back(args[1]); + } + else if (is_false(args[0])) { + todo.push_back(args[0]); + } + else { + IF_VERBOSE(0, verbose_stream() << "Term not handled " << mk_pp(e, m) << "\n";); + UNREACHABLE(); + } + } + else { + todo.append(sz, args); + } + break; + default: + IF_VERBOSE(0, verbose_stream() << "Term not handled " << mk_pp(e, m) << "\n";); + UNREACHABLE(); + } + } + else { + tocollect.push_back(e); + } +} + +void model_implicant::collect(ptr_vector const& formulas, ptr_vector& tocollect) { + ptr_vector todo; + todo.append(formulas); + m_visited.reset(); + + VERIFY(check_model(formulas)); + + while (!todo.empty()) { + app* e = to_app(todo.back()); + todo.pop_back(); + if (!m_visited.is_marked(e)) { + process_formula(e, todo, tocollect); + m_visited.mark(e, true); + } + } + m_visited.reset(); +} + +expr_ref_vector model_implicant::prune_by_cone_of_influence(ptr_vector const & formulas) { + ptr_vector tocollect; + collect(formulas, tocollect); + m1.reset(); + m2.reset(); + for (unsigned i = 0; i < tocollect.size(); ++i) { + TRACE("pdr_verbose", tout << "collect: " << mk_pp(tocollect[i], m) << "\n";); + for_each_expr(*this, m_visited, tocollect[i]); + } + unsigned sz = m_model->get_num_constants(); + expr_ref e(m), eq(m), val(m); + expr_ref_vector model(m); + for (unsigned i = 0; i < sz; i++) { + e = m.mk_const(m_model->get_constant(i)); + if (m_visited.is_marked(e)) { + val = eval(m_model, e); + eq = m.mk_eq(e, val); + model.push_back(eq); + } + } + m_visited.reset(); + TRACE("pdr", tout << sz << " ==> " << model.size() << "\n";); + return model; + +} + +void model_implicant::eval_arith(app* e) { + rational r, r2; + +#define ARG1 e->get_arg(0) +#define ARG2 e->get_arg(1) + + unsigned arity = e->get_num_args(); + for (unsigned i = 0; i < arity; ++i) { + expr* arg = e->get_arg(i); + if (is_x(arg)) { + set_x(e); + return; + } + SASSERT(!is_unknown(arg)); + } + switch(e->get_decl_kind()) { + case OP_NUM: + VERIFY(m_arith.is_numeral(e, r)); + set_number(e, r); + break; + case OP_IRRATIONAL_ALGEBRAIC_NUM: + set_x(e); + break; + case OP_LE: + set_bool(e, get_number(ARG1) <= get_number(ARG2)); + break; + case OP_GE: + set_bool(e, get_number(ARG1) >= get_number(ARG2)); + break; + case OP_LT: + set_bool(e, get_number(ARG1) < get_number(ARG2)); + break; + case OP_GT: + set_bool(e, get_number(ARG1) > get_number(ARG2)); + break; + case OP_ADD: + r = rational::zero(); + for (unsigned i = 0; i < arity; ++i) { + r += get_number(e->get_arg(i)); + } + set_number(e, r); + break; + case OP_SUB: + r = get_number(e->get_arg(0)); + for (unsigned i = 1; i < arity; ++i) { + r -= get_number(e->get_arg(i)); + } + set_number(e, r); + break; + case OP_UMINUS: + SASSERT(arity == 1); + set_number(e, get_number(e->get_arg(0))); + break; + case OP_MUL: + r = rational::one(); + for (unsigned i = 0; i < arity; ++i) { + r *= get_number(e->get_arg(i)); + } + set_number(e, r); + break; + case OP_DIV: + SASSERT(arity == 2); + r = get_number(ARG2); + if (r.is_zero()) { + set_x(e); + } + else { + set_number(e, get_number(ARG1) / r); + } + break; + case OP_IDIV: + SASSERT(arity == 2); + r = get_number(ARG2); + if (r.is_zero()) { + set_x(e); + } + else { + set_number(e, div(get_number(ARG1), r)); + } + break; + case OP_REM: + // rem(v1,v2) = if v2 >= 0 then mod(v1,v2) else -mod(v1,v2) + SASSERT(arity == 2); + r = get_number(ARG2); + if (r.is_zero()) { + set_x(e); + } + else { + r2 = mod(get_number(ARG1), r); + if (r.is_neg()) r2.neg(); + set_number(e, r2); + } + break; + case OP_MOD: + SASSERT(arity == 2); + r = get_number(ARG2); + if (r.is_zero()) { + set_x(e); + } + else { + set_number(e, mod(get_number(ARG1), r)); + } + break; + case OP_TO_REAL: + SASSERT(arity == 1); + set_number(e, get_number(ARG1)); + break; + case OP_TO_INT: + SASSERT(arity == 1); + set_number(e, floor(get_number(ARG1))); + break; + case OP_IS_INT: + SASSERT(arity == 1); + set_bool(e, get_number(ARG1).is_int()); + break; + case OP_POWER: + set_x(e); + break; + default: + IF_VERBOSE(0, verbose_stream() << "Term not handled " << mk_pp(e, m) << "\n";); + UNREACHABLE(); + break; + } +} + +void model_implicant::inherit_value(expr* e, expr* v) { + expr* w; + SASSERT(!is_unknown(v)); + SASSERT(m.get_sort(e) == m.get_sort(v)); + if (is_x(v)) { + set_x(e); + } + else if (m.is_bool(e)) { + SASSERT(m.is_bool(v)); + if (is_true(v)) set_true(e); + else if (is_false(v)) set_false(e); + else { + TRACE("pdr", tout << "not inherited:\n" << mk_pp(e, m) << "\n" << mk_pp(v, m) << "\n";); + set_x(e); + } + } + else if (m_arith.is_int_real(e)) { + set_number(e, get_number(v)); + } + else if (m.is_value(v)) { + set_value(e, v); + } + else if (m_values.find(v, w)) { + set_value(e, w); + } + else { + TRACE("pdr", tout << "not inherited:\n" << mk_pp(e, m) << "\n" << mk_pp(v, m) << "\n";); + set_x(e); + } +} + +void model_implicant::eval_exprs(expr_ref_vector& es) { + model_ref mr(m_model); + for (unsigned j = 0; j < es.size(); ++j) { + if (m_array.is_as_array(es[j].get())) { + es[j] = eval(mr, es[j].get()); + } + } +} + +bool model_implicant::extract_array_func_interp(expr* a, vector& stores, expr_ref& else_case) { + SASSERT(m_array.is_array(a)); + + TRACE("pdr", tout << mk_pp(a, m) << "\n";); + while (m_array.is_store(a)) { + expr_ref_vector store(m); + store.append(to_app(a)->get_num_args()-1, to_app(a)->get_args()+1); + eval_exprs(store); + stores.push_back(store); + a = to_app(a)->get_arg(0); + } + + if (m_array.is_const(a)) { + else_case = to_app(a)->get_arg(0); + return true; + } + + while (m_array.is_as_array(a)) { + func_decl* f = m_array.get_as_array_func_decl(to_app(a)); + func_interp* g = m_model->get_func_interp(f); + unsigned sz = g->num_entries(); + unsigned arity = f->get_arity(); + for (unsigned i = 0; i < sz; ++i) { + expr_ref_vector store(m); + func_entry const* fe = g->get_entry(i); + store.append(arity, fe->get_args()); + store.push_back(fe->get_result()); + for (unsigned j = 0; j < store.size(); ++j) { + if (!is_ground(store[j].get())) { + TRACE("pdr", tout << "could not extract array interpretation: " << mk_pp(a, m) << "\n" << mk_pp(store[j].get(), m) << "\n";); + return false; + } + } + eval_exprs(store); + stores.push_back(store); + } + else_case = g->get_else(); + if (!else_case) { + TRACE("pdr", tout << "no else case " << mk_pp(a, m) << "\n";); + return false; + } + if (!is_ground(else_case)) { + TRACE("pdr", tout << "non-ground else case " << mk_pp(a, m) << "\n" << mk_pp(else_case, m) << "\n";); + return false; + } + if (m_array.is_as_array(else_case)) { + model_ref mr(m_model); + else_case = eval(mr, else_case); + } + TRACE("pdr", tout << "else case: " << mk_pp(else_case, m) << "\n";); + return true; + } + TRACE("pdr", tout << "no translation: " << mk_pp(a, m) << "\n";); + + return false; +} + +/** + best effort evaluator of extensional array equality. +*/ +void model_implicant::eval_array_eq(app* e, expr* arg1, expr* arg2) { + TRACE("pdr", tout << "array equality: " << mk_pp(e, m) << "\n";); + expr_ref v1(m), v2(m); + m_model->eval(arg1, v1); + m_model->eval(arg2, v2); + if (v1 == v2) { + set_true(e); + return; + } + sort* s = m.get_sort(arg1); + sort* r = get_array_range(s); + // give up evaluating finite domain/range arrays + if (!r->is_infinite() && !r->is_very_big() && !s->is_infinite() && !s->is_very_big()) { + TRACE("pdr", tout << "equality is unknown: " << mk_pp(e, m) << "\n";); + set_x(e); + return; + } + vector store; + expr_ref else1(m), else2(m); + if (!extract_array_func_interp(v1, store, else1) || + !extract_array_func_interp(v2, store, else2)) { + TRACE("pdr", tout << "equality is unknown: " << mk_pp(e, m) << "\n";); + set_x(e); + return; + } + + if (else1 != else2) { + if (m.is_value(else1) && m.is_value(else2)) { + TRACE("pdr", tout + << "defaults are different: " << mk_pp(e, m) << " " + << mk_pp(else1, m) << " " << mk_pp(else2, m) << "\n";); + set_false(e); + } + else if (m_array.is_array(else1)) { + eval_array_eq(e, else1, else2); + } + else { + TRACE("pdr", tout << "equality is unknown: " << mk_pp(e, m) << "\n";); + set_x(e); + } + return; + } + + expr_ref s1(m), s2(m), w1(m), w2(m); + expr_ref_vector args1(m), args2(m); + args1.push_back(v1); + args2.push_back(v2); + for (unsigned i = 0; i < store.size(); ++i) { + args1.resize(1); + args2.resize(1); + args1.append(store[i].size()-1, store[i].c_ptr()); + args2.append(store[i].size()-1, store[i].c_ptr()); + s1 = m_array.mk_select(args1.size(), args1.c_ptr()); + s2 = m_array.mk_select(args2.size(), args2.c_ptr()); + m_model->eval(s1, w1); + m_model->eval(s2, w2); + if (w1 == w2) { + continue; + } + if (m.is_value(w1) && m.is_value(w2)) { + TRACE("pdr", tout << "Equality evaluation: " << mk_pp(e, m) << "\n"; + tout << mk_pp(s1, m) << " |-> " << mk_pp(w1, m) << "\n"; + tout << mk_pp(s2, m) << " |-> " << mk_pp(w2, m) << "\n";); + set_false(e); + } + else if (m_array.is_array(w1)) { + eval_array_eq(e, w1, w2); + if (is_true(e)) { + continue; + } + } + else { + TRACE("pdr", tout << "equality is unknown: " << mk_pp(e, m) << "\n";); + set_x(e); + } + return; + } + set_true(e); +} + +void model_implicant::eval_eq(app* e, expr* arg1, expr* arg2) { + if (arg1 == arg2) { + set_true(e); + } + else if (m_array.is_array(arg1)) { + eval_array_eq(e, arg1, arg2); + } + else if (is_x(arg1) || is_x(arg2)) { + expr_ref eq(m), vl(m); + eq = m.mk_eq(arg1, arg2); + m_model->eval(eq, vl); + if (m.is_true(vl)) { + set_bool(e, true); + } + else if (m.is_false(vl)) { + set_bool(e, false); + } + else { + TRACE("pdr", tout << "cannot evaluate: " << mk_pp(vl, m) << "\n";); + set_x(e); + } + } + else if (m.is_bool(arg1)) { + bool val = is_true(arg1) == is_true(arg2); + SASSERT(val == (is_false(arg1) == is_false(arg2))); + if (val) { + set_true(e); + } + else { + set_false(e); + } + } + else if (m_arith.is_int_real(arg1)) { + set_bool(e, get_number(arg1) == get_number(arg2)); + } + else { + expr* e1 = get_value(arg1); + expr* e2 = get_value(arg2); + if (m.is_value(e1) && m.is_value(e2)) { + set_bool(e, e1 == e2); + } + else if (e1 == e2) { + set_bool(e, true); + } + else { + TRACE("pdr", tout << "not value equal:\n" << mk_pp(e1, m) << "\n" << mk_pp(e2, m) << "\n";); + set_x(e); + } + } +} + +void model_implicant::eval_basic(app* e) { + expr* arg1, *arg2; + expr *argCond, *argThen, *argElse, *arg; + bool has_x = false; + unsigned arity = e->get_num_args(); + switch(e->get_decl_kind()) { + case OP_AND: + for (unsigned j = 0; j < arity; ++j) { + expr * arg = e->get_arg(j); + if (is_false(arg)) { + set_false(e); + return; + } + else if (is_x(arg)) { + has_x = true; + } + else { + SASSERT(is_true(arg)); + } + } + if (has_x) { + set_x(e); + } + else { + set_true(e); + } + break; + case OP_OR: + for (unsigned j = 0; j < arity; ++j) { + expr * arg = e->get_arg(j); + if (is_true(arg)) { + set_true(e); + return; + } + else if (is_x(arg)) { + has_x = true; + } + else { + SASSERT(is_false(arg)); + } + } + if (has_x) { + set_x(e); + } + else { + set_false(e); + } + break; + case OP_NOT: + VERIFY(m.is_not(e, arg)); + if (is_true(arg)) { + set_false(e); + } + else if (is_false(arg)) { + set_true(e); + } + else { + SASSERT(is_x(arg)); + set_x(e); + } + break; + case OP_IMPLIES: + VERIFY(m.is_implies(e, arg1, arg2)); + if (is_false(arg1) || is_true(arg2)) { + set_true(e); + } + else if (arg1 == arg2) { + set_true(e); + } + else if (is_true(arg1) && is_false(arg2)) { + set_false(e); + } + else { + SASSERT(is_x(arg1) || is_x(arg2)); + set_x(e); + } + break; + case OP_IFF: + VERIFY(m.is_iff(e, arg1, arg2)); + eval_eq(e, arg1, arg2); + break; + case OP_ITE: + VERIFY(m.is_ite(e, argCond, argThen, argElse)); + if (is_true(argCond)) { + inherit_value(e, argThen); + } + else if (is_false(argCond)) { + inherit_value(e, argElse); + } + else if (argThen == argElse) { + inherit_value(e, argThen); + } + else if (m.is_bool(e)) { + SASSERT(is_x(argCond)); + if (is_x(argThen) || is_x(argElse)) { + set_x(e); + } + else if (is_true(argThen) == is_true(argElse)) { + inherit_value(e, argThen); + } + else { + set_x(e); + } + } + else { + set_x(e); + } + break; + case OP_TRUE: + set_true(e); + break; + case OP_FALSE: + set_false(e); + break; + case OP_EQ: + VERIFY(m.is_eq(e, arg1, arg2)); + eval_eq(e, arg1, arg2); + break; + case OP_DISTINCT: { + vector values; + for (unsigned i = 0; i < arity; ++i) { + expr* arg = e->get_arg(i); + if (is_x(arg)) { + set_x(e); + return; + } + values.push_back(get_number(arg)); + } + std::sort(values.begin(), values.end()); + for (unsigned i = 0; i + 1 < values.size(); ++i) { + if (values[i] == values[i+1]) { + set_false(e); + return; + } + } + set_true(e); + break; + } + default: + IF_VERBOSE(0, verbose_stream() << "Term not handled " << mk_pp(e, m) << "\n";); + UNREACHABLE(); + } +} + +bool model_implicant::check_model(ptr_vector const& formulas) { + ptr_vector todo(formulas); + + while (!todo.empty()) { + expr * curr_e = todo.back(); + + if (!is_app(curr_e)) { + todo.pop_back(); + continue; + } + app * curr = to_app(curr_e); + + if (!is_unknown(curr)) { + todo.pop_back(); + continue; + } + unsigned arity = curr->get_num_args(); + for (unsigned i = 0; i < arity; ++i) { + if (is_unknown(curr->get_arg(i))) { + todo.push_back(curr->get_arg(i)); + } + } + if (todo.back() != curr) { + continue; + } + todo.pop_back(); + if (curr->get_family_id() == m_arith.get_family_id()) { + eval_arith(curr); + } + else if (curr->get_family_id() == m.get_basic_family_id()) { + eval_basic(curr); + } + else { + expr_ref vl(m); + m_model->eval(curr, vl); + assign_value(curr, vl); + } + + IF_VERBOSE(35,verbose_stream() << "assigned "<get_arity() == 0); + expr_ref result(m); + if (m_array.is_array(d->get_range())) { + expr_ref e(m); + e = m.mk_const(d); + result = eval(model, e); + } + else { + result = model->get_const_interp(d); + } + return result; +} + +expr_ref model_implicant::eval(model_ref& model, expr* e) { + expr_ref result(m); + m_model = model; + VERIFY(m_model->eval(e, result, true)); + if (m_array.is_array(e)) { + vector stores; + expr_ref_vector args(m); + expr_ref else_case(m); + if (extract_array_func_interp(result, stores, else_case)) { + result = m_array.mk_const_array(m.get_sort(e), else_case); + while (!stores.empty() && stores.back().back() == else_case) { + stores.pop_back(); + } + for (unsigned i = stores.size(); i > 0; ) { + --i; + args.resize(1); + args[0] = result; + args.append(stores[i]); + result = m_array.mk_store(args.size(), args.c_ptr()); + } + return result; + } + } + return result; +} + + + + diff --git a/src/model/model_implicant.h b/src/model/model_implicant.h new file mode 100644 index 000000000..55b466ca3 --- /dev/null +++ b/src/model/model_implicant.h @@ -0,0 +1,118 @@ +/*++ +Copyright (c) 2011 Microsoft Corporation + +Module Name: + + model_implicant.h + +Abstract: + + Facility to extract prime implicant from model. + +Author: + + Krystof Hoder (t-khoder) 2011-8-19. + +Revision History: + +--*/ + +#ifndef _MODEL_IMPLICANT_H_ +#define _MODEL_IMPLICANT_H_ + +#include "ast.h" +#include "ast_pp.h" +#include "obj_hashtable.h" +#include "ref_vector.h" +#include "trace.h" +#include "vector.h" +#include "arith_decl_plugin.h" +#include "array_decl_plugin.h" + +class model; +class model_core; + +class model_implicant { + ast_manager& m; + arith_util m_arith; + array_util m_array; + obj_map m_numbers; + expr_ref_vector m_refs; + obj_map m_values; + model_ref m_model; + + //00 -- non-visited + //01 -- X + //10 -- false + //11 -- true + expr_mark m1; + expr_mark m2; + expr_mark m_visited; + + + void reset(); + void setup_model(model_ref& model); + void assign_value(expr* e, expr* v); + void collect(ptr_vector const& formulas, ptr_vector& tocollect); + void process_formula(app* e, ptr_vector& todo, ptr_vector& tocollect); + expr_ref_vector prune_by_cone_of_influence(ptr_vector const & formulas); + void eval_arith(app* e); + void eval_basic(app* e); + void eval_eq(app* e, expr* arg1, expr* arg2); + void eval_array_eq(app* e, expr* arg1, expr* arg2); + void inherit_value(expr* e, expr* v); + + inline bool is_unknown(expr* x) { return !m1.is_marked(x) && !m2.is_marked(x); } + inline void set_unknown(expr* x) { m1.mark(x, false); m2.mark(x, false); } + inline bool is_x(expr* x) { return !m1.is_marked(x) && m2.is_marked(x); } + inline bool is_false(expr* x) { return m1.is_marked(x) && !m2.is_marked(x); } + inline bool is_true(expr* x) { return m1.is_marked(x) && m2.is_marked(x); } + inline void set_x(expr* x) { SASSERT(is_unknown(x)); m2.mark(x); } + inline void set_v(expr* x) { SASSERT(is_unknown(x)); m1.mark(x); } + inline void set_false(expr* x) { SASSERT(is_unknown(x)); m1.mark(x); } + inline void set_true(expr* x) { SASSERT(is_unknown(x)); m1.mark(x); m2.mark(x); } + inline void set_bool(expr* x, bool v) { if (v) { set_true(x); } else { set_false(x); } } + inline rational const& get_number(expr* x) const { return m_numbers.find(x); } + inline void set_number(expr* x, rational const& v) { + set_v(x); TRACE("pdr_verbose", tout << mk_pp(x,m) << " " << v << "\n";); m_numbers.insert(x,v); + } + inline expr* get_value(expr* x) { return m_values.find(x); } + inline void set_value(expr* x, expr* v) { set_v(x); m_refs.push_back(v); m_values.insert(x, v); } + + bool check_model(ptr_vector const & formulas); + + bool extract_array_func_interp(expr* a, vector& stores, expr_ref& else_case); + + void eval_exprs(expr_ref_vector& es); + +public: + model_implicant(ast_manager& m) : + m(m), m_arith(m), m_array(m), m_refs(m) {} + + /** + \brief extract equalities from model that suffice to satisfy formula. + + \pre model satisfies formulas + */ + + expr_ref_vector minimize_model(ptr_vector const & formulas, model_ref& mdl); + + /** + \brief extract literals from formulas that satisfy formulas. + + \pre model satisfies formulas + */ + expr_ref_vector minimize_literals(ptr_vector const & formulas, model_ref& mdl); + + /** + for_each_expr visitor. + */ + void operator()(expr* e) {} + + expr_ref eval(model_ref& mdl, expr* e); + + expr_ref eval(model_ref& mdl, func_decl* d); +}; + + +#endif diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index d2ac29689..f530dd7f9 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -48,6 +48,7 @@ Notes: #include "qe_util.h" #include "scoped_proof.h" #include "blast_term_ite_tactic.h" +#include "model_implicant.h" namespace pdr { @@ -1978,7 +1979,7 @@ namespace pdr { tout << "Transition:\n" << mk_pp(T, m) << "\n"; tout << "Phi:\n" << mk_pp(phi, m) << "\n";); - model_evaluator mev(m); + model_implicant mev(m); expr_ref_vector mdl(m), forms(m), Phi(m); forms.push_back(T); forms.push_back(phi); diff --git a/src/muz/pdr/pdr_util.cpp b/src/muz/pdr/pdr_util.cpp index 33c98fae4..18e5b680d 100644 --- a/src/muz/pdr/pdr_util.cpp +++ b/src/muz/pdr/pdr_util.cpp @@ -90,879 +90,6 @@ namespace pdr { return res.str(); } - - - ///////////////////////// - // model_evaluator - // - - - void model_evaluator::assign_value(expr* e, expr* val) { - rational r; - if (m.is_true(val)) { - set_true(e); - } - else if (m.is_false(val)) { - set_false(e); - } - else if (m_arith.is_numeral(val, r)) { - set_number(e, r); - } - else if (m.is_value(val)) { - set_value(e, val); - } - else { - IF_VERBOSE(3, verbose_stream() << "Not evaluated " << mk_pp(e, m) << " := " << mk_pp(val, m) << "\n";); - TRACE("pdr", tout << "Variable is not tracked: " << mk_pp(e, m) << " := " << mk_pp(val, m) << "\n";); - set_x(e); - } - } - - void model_evaluator::setup_model(model_ref& model) { - m_numbers.reset(); - m_values.reset(); - m_model = model; - rational r; - unsigned sz = model->get_num_constants(); - for (unsigned i = 0; i < sz; i++) { - func_decl * d = model->get_constant(i); - expr* val = model->get_const_interp(d); - expr* e = m.mk_const(d); - m_refs.push_back(e); - assign_value(e, val); - } - } - - void model_evaluator::reset() { - m1.reset(); - m2.reset(); - m_values.reset(); - m_visited.reset(); - m_numbers.reset(); - m_refs.reset(); - m_model = 0; - } - - expr_ref_vector model_evaluator::minimize_model(ptr_vector const & formulas, model_ref& mdl) { - setup_model(mdl); - - TRACE("pdr_verbose", - tout << "formulas:\n"; - for (unsigned i = 0; i < formulas.size(); ++i) tout << mk_pp(formulas[i], m) << "\n"; - ); - - expr_ref_vector model = prune_by_cone_of_influence(formulas); - TRACE("pdr_verbose", - tout << "pruned model:\n"; - for (unsigned i = 0; i < model.size(); ++i) tout << mk_pp(model[i].get(), m) << "\n";); - - reset(); - - DEBUG_CODE( - setup_model(mdl); - VERIFY(check_model(formulas)); - reset();); - - return model; - } - - expr_ref_vector model_evaluator::minimize_literals(ptr_vector const& formulas, model_ref& mdl) { - - TRACE("pdr", - tout << "formulas:\n"; - for (unsigned i = 0; i < formulas.size(); ++i) tout << mk_pp(formulas[i], m) << "\n"; - ); - - expr_ref_vector result(m); - expr_ref tmp(m); - ptr_vector tocollect; - - setup_model(mdl); - collect(formulas, tocollect); - for (unsigned i = 0; i < tocollect.size(); ++i) { - expr* e = tocollect[i]; - expr* e1, *e2; - SASSERT(m.is_bool(e)); - SASSERT(is_true(e) || is_false(e)); - if (is_true(e)) { - result.push_back(e); - } - // hack to break disequalities for arithmetic variables. - else if (m.is_eq(e, e1, e2) && m_arith.is_int_real(e1)) { - if (get_number(e1) < get_number(e2)) { - result.push_back(m_arith.mk_lt(e1,e2)); - } - else { - result.push_back(m_arith.mk_lt(e2,e1)); - } - } - else { - result.push_back(m.mk_not(e)); - } - } - reset(); - TRACE("pdr", - tout << "minimized model:\n"; - for (unsigned i = 0; i < result.size(); ++i) tout << mk_pp(result[i].get(), m) << "\n"; - ); - - return result; - } - - void model_evaluator::process_formula(app* e, ptr_vector& todo, ptr_vector& tocollect) { - SASSERT(m.is_bool(e)); - SASSERT(is_true(e) || is_false(e)); - unsigned v = is_true(e); - unsigned sz = e->get_num_args(); - expr* const* args = e->get_args(); - if (e->get_family_id() == m.get_basic_family_id()) { - switch(e->get_decl_kind()) { - case OP_TRUE: - break; - case OP_FALSE: - break; - case OP_EQ: - case OP_IFF: - if (args[0] == args[1]) { - SASSERT(v); - // no-op - } - else if (m.is_bool(args[0])) { - todo.append(sz, args); - } - else { - tocollect.push_back(e); - } - break; - case OP_DISTINCT: - tocollect.push_back(e); - break; - case OP_ITE: - if (args[1] == args[2]) { - tocollect.push_back(args[1]); - } - else if (is_true(args[1]) && is_true(args[2])) { - todo.append(2, args+1); - } - else if (is_false(args[1]) && is_false(args[2])) { - todo.append(2, args+1); - } - else if (is_true(args[0])) { - todo.append(2, args); - } - else { - SASSERT(is_false(args[0])); - todo.push_back(args[0]); - todo.push_back(args[2]); - } - break; - case OP_AND: - if (v) { - todo.append(sz, args); - } - else { - unsigned i = 0; - for (; !is_false(args[i]) && i < sz; ++i); - if (i == sz) { - fatal_error(1); - } - VERIFY(i < sz); - todo.push_back(args[i]); - } - break; - case OP_OR: - if (v) { - unsigned i = 0; - for (; !is_true(args[i]) && i < sz; ++i); - if (i == sz) { - fatal_error(1); - } - VERIFY(i < sz); - todo.push_back(args[i]); - } - else { - todo.append(sz, args); - } - break; - case OP_XOR: - case OP_NOT: - todo.append(sz, args); - break; - case OP_IMPLIES: - if (v) { - if (is_true(args[1])) { - todo.push_back(args[1]); - } - else if (is_false(args[0])) { - todo.push_back(args[0]); - } - else { - IF_VERBOSE(0, verbose_stream() << "Term not handled " << mk_pp(e, m) << "\n";); - UNREACHABLE(); - } - } - else { - todo.append(sz, args); - } - break; - default: - IF_VERBOSE(0, verbose_stream() << "Term not handled " << mk_pp(e, m) << "\n";); - UNREACHABLE(); - } - } - else { - tocollect.push_back(e); - } - } - - void model_evaluator::collect(ptr_vector const& formulas, ptr_vector& tocollect) { - ptr_vector todo; - todo.append(formulas); - m_visited.reset(); - - VERIFY(check_model(formulas)); - - while (!todo.empty()) { - app* e = to_app(todo.back()); - todo.pop_back(); - if (!m_visited.is_marked(e)) { - process_formula(e, todo, tocollect); - m_visited.mark(e, true); - } - } - m_visited.reset(); - } - - expr_ref_vector model_evaluator::prune_by_cone_of_influence(ptr_vector const & formulas) { - ptr_vector tocollect; - collect(formulas, tocollect); - m1.reset(); - m2.reset(); - for (unsigned i = 0; i < tocollect.size(); ++i) { - TRACE("pdr_verbose", tout << "collect: " << mk_pp(tocollect[i], m) << "\n";); - for_each_expr(*this, m_visited, tocollect[i]); - } - unsigned sz = m_model->get_num_constants(); - expr_ref e(m), eq(m), val(m); - expr_ref_vector model(m); - for (unsigned i = 0; i < sz; i++) { - e = m.mk_const(m_model->get_constant(i)); - if (m_visited.is_marked(e)) { - val = eval(m_model, e); - eq = m.mk_eq(e, val); - model.push_back(eq); - } - } - m_visited.reset(); - TRACE("pdr", tout << sz << " ==> " << model.size() << "\n";); - return model; - - } - - void model_evaluator::eval_arith(app* e) { - rational r, r2; - -#define ARG1 e->get_arg(0) -#define ARG2 e->get_arg(1) - - unsigned arity = e->get_num_args(); - for (unsigned i = 0; i < arity; ++i) { - expr* arg = e->get_arg(i); - if (is_x(arg)) { - set_x(e); - return; - } - SASSERT(!is_unknown(arg)); - } - switch(e->get_decl_kind()) { - case OP_NUM: - VERIFY(m_arith.is_numeral(e, r)); - set_number(e, r); - break; - case OP_IRRATIONAL_ALGEBRAIC_NUM: - set_x(e); - break; - case OP_LE: - set_bool(e, get_number(ARG1) <= get_number(ARG2)); - break; - case OP_GE: - set_bool(e, get_number(ARG1) >= get_number(ARG2)); - break; - case OP_LT: - set_bool(e, get_number(ARG1) < get_number(ARG2)); - break; - case OP_GT: - set_bool(e, get_number(ARG1) > get_number(ARG2)); - break; - case OP_ADD: - r = rational::zero(); - for (unsigned i = 0; i < arity; ++i) { - r += get_number(e->get_arg(i)); - } - set_number(e, r); - break; - case OP_SUB: - r = get_number(e->get_arg(0)); - for (unsigned i = 1; i < arity; ++i) { - r -= get_number(e->get_arg(i)); - } - set_number(e, r); - break; - case OP_UMINUS: - SASSERT(arity == 1); - set_number(e, get_number(e->get_arg(0))); - break; - case OP_MUL: - r = rational::one(); - for (unsigned i = 0; i < arity; ++i) { - r *= get_number(e->get_arg(i)); - } - set_number(e, r); - break; - case OP_DIV: - SASSERT(arity == 2); - r = get_number(ARG2); - if (r.is_zero()) { - set_x(e); - } - else { - set_number(e, get_number(ARG1) / r); - } - break; - case OP_IDIV: - SASSERT(arity == 2); - r = get_number(ARG2); - if (r.is_zero()) { - set_x(e); - } - else { - set_number(e, div(get_number(ARG1), r)); - } - break; - case OP_REM: - // rem(v1,v2) = if v2 >= 0 then mod(v1,v2) else -mod(v1,v2) - SASSERT(arity == 2); - r = get_number(ARG2); - if (r.is_zero()) { - set_x(e); - } - else { - r2 = mod(get_number(ARG1), r); - if (r.is_neg()) r2.neg(); - set_number(e, r2); - } - break; - case OP_MOD: - SASSERT(arity == 2); - r = get_number(ARG2); - if (r.is_zero()) { - set_x(e); - } - else { - set_number(e, mod(get_number(ARG1), r)); - } - break; - case OP_TO_REAL: - SASSERT(arity == 1); - set_number(e, get_number(ARG1)); - break; - case OP_TO_INT: - SASSERT(arity == 1); - set_number(e, floor(get_number(ARG1))); - break; - case OP_IS_INT: - SASSERT(arity == 1); - set_bool(e, get_number(ARG1).is_int()); - break; - case OP_POWER: - set_x(e); - break; - default: - IF_VERBOSE(0, verbose_stream() << "Term not handled " << mk_pp(e, m) << "\n";); - UNREACHABLE(); - break; - } - } - - void model_evaluator::inherit_value(expr* e, expr* v) { - expr* w; - SASSERT(!is_unknown(v)); - SASSERT(m.get_sort(e) == m.get_sort(v)); - if (is_x(v)) { - set_x(e); - } - else if (m.is_bool(e)) { - SASSERT(m.is_bool(v)); - if (is_true(v)) set_true(e); - else if (is_false(v)) set_false(e); - else { - TRACE("pdr", tout << "not inherited:\n" << mk_pp(e, m) << "\n" << mk_pp(v, m) << "\n";); - set_x(e); - } - } - else if (m_arith.is_int_real(e)) { - set_number(e, get_number(v)); - } - else if (m.is_value(v)) { - set_value(e, v); - } - else if (m_values.find(v, w)) { - set_value(e, w); - } - else { - TRACE("pdr", tout << "not inherited:\n" << mk_pp(e, m) << "\n" << mk_pp(v, m) << "\n";); - set_x(e); - } - } - - void model_evaluator::eval_exprs(expr_ref_vector& es) { - model_ref mr(m_model); - for (unsigned j = 0; j < es.size(); ++j) { - if (m_array.is_as_array(es[j].get())) { - es[j] = eval(mr, es[j].get()); - } - } - } - - bool model_evaluator::extract_array_func_interp(expr* a, vector& stores, expr_ref& else_case) { - SASSERT(m_array.is_array(a)); - - TRACE("pdr", tout << mk_pp(a, m) << "\n";); - while (m_array.is_store(a)) { - expr_ref_vector store(m); - store.append(to_app(a)->get_num_args()-1, to_app(a)->get_args()+1); - eval_exprs(store); - stores.push_back(store); - a = to_app(a)->get_arg(0); - } - - if (m_array.is_const(a)) { - else_case = to_app(a)->get_arg(0); - return true; - } - - while (m_array.is_as_array(a)) { - func_decl* f = m_array.get_as_array_func_decl(to_app(a)); - func_interp* g = m_model->get_func_interp(f); - unsigned sz = g->num_entries(); - unsigned arity = f->get_arity(); - for (unsigned i = 0; i < sz; ++i) { - expr_ref_vector store(m); - func_entry const* fe = g->get_entry(i); - store.append(arity, fe->get_args()); - store.push_back(fe->get_result()); - for (unsigned j = 0; j < store.size(); ++j) { - if (!is_ground(store[j].get())) { - TRACE("pdr", tout << "could not extract array interpretation: " << mk_pp(a, m) << "\n" << mk_pp(store[j].get(), m) << "\n";); - return false; - } - } - eval_exprs(store); - stores.push_back(store); - } - else_case = g->get_else(); - if (!else_case) { - TRACE("pdr", tout << "no else case " << mk_pp(a, m) << "\n";); - return false; - } - if (!is_ground(else_case)) { - TRACE("pdr", tout << "non-ground else case " << mk_pp(a, m) << "\n" << mk_pp(else_case, m) << "\n";); - return false; - } - if (m_array.is_as_array(else_case)) { - model_ref mr(m_model); - else_case = eval(mr, else_case); - } - TRACE("pdr", tout << "else case: " << mk_pp(else_case, m) << "\n";); - return true; - } - TRACE("pdr", tout << "no translation: " << mk_pp(a, m) << "\n";); - - return false; - } - - /** - best effort evaluator of extensional array equality. - */ - void model_evaluator::eval_array_eq(app* e, expr* arg1, expr* arg2) { - TRACE("pdr", tout << "array equality: " << mk_pp(e, m) << "\n";); - expr_ref v1(m), v2(m); - m_model->eval(arg1, v1); - m_model->eval(arg2, v2); - if (v1 == v2) { - set_true(e); - return; - } - sort* s = m.get_sort(arg1); - sort* r = get_array_range(s); - // give up evaluating finite domain/range arrays - if (!r->is_infinite() && !r->is_very_big() && !s->is_infinite() && !s->is_very_big()) { - TRACE("pdr", tout << "equality is unknown: " << mk_pp(e, m) << "\n";); - set_x(e); - return; - } - vector store; - expr_ref else1(m), else2(m); - if (!extract_array_func_interp(v1, store, else1) || - !extract_array_func_interp(v2, store, else2)) { - TRACE("pdr", tout << "equality is unknown: " << mk_pp(e, m) << "\n";); - set_x(e); - return; - } - - if (else1 != else2) { - if (m.is_value(else1) && m.is_value(else2)) { - TRACE("pdr", tout - << "defaults are different: " << mk_pp(e, m) << " " - << mk_pp(else1, m) << " " << mk_pp(else2, m) << "\n";); - set_false(e); - } - else if (m_array.is_array(else1)) { - eval_array_eq(e, else1, else2); - } - else { - TRACE("pdr", tout << "equality is unknown: " << mk_pp(e, m) << "\n";); - set_x(e); - } - return; - } - - expr_ref s1(m), s2(m), w1(m), w2(m); - expr_ref_vector args1(m), args2(m); - args1.push_back(v1); - args2.push_back(v2); - for (unsigned i = 0; i < store.size(); ++i) { - args1.resize(1); - args2.resize(1); - args1.append(store[i].size()-1, store[i].c_ptr()); - args2.append(store[i].size()-1, store[i].c_ptr()); - s1 = m_array.mk_select(args1.size(), args1.c_ptr()); - s2 = m_array.mk_select(args2.size(), args2.c_ptr()); - m_model->eval(s1, w1); - m_model->eval(s2, w2); - if (w1 == w2) { - continue; - } - if (m.is_value(w1) && m.is_value(w2)) { - TRACE("pdr", tout << "Equality evaluation: " << mk_pp(e, m) << "\n"; - tout << mk_pp(s1, m) << " |-> " << mk_pp(w1, m) << "\n"; - tout << mk_pp(s2, m) << " |-> " << mk_pp(w2, m) << "\n";); - set_false(e); - } - else if (m_array.is_array(w1)) { - eval_array_eq(e, w1, w2); - if (is_true(e)) { - continue; - } - } - else { - TRACE("pdr", tout << "equality is unknown: " << mk_pp(e, m) << "\n";); - set_x(e); - } - return; - } - set_true(e); - } - - void model_evaluator::eval_eq(app* e, expr* arg1, expr* arg2) { - if (arg1 == arg2) { - set_true(e); - } - else if (m_array.is_array(arg1)) { - eval_array_eq(e, arg1, arg2); - } - else if (is_x(arg1) || is_x(arg2)) { - expr_ref eq(m), vl(m); - eq = m.mk_eq(arg1, arg2); - m_model->eval(eq, vl); - if (m.is_true(vl)) { - set_bool(e, true); - } - else if (m.is_false(vl)) { - set_bool(e, false); - } - else { - TRACE("pdr", tout << "cannot evaluate: " << mk_pp(vl, m) << "\n";); - set_x(e); - } - } - else if (m.is_bool(arg1)) { - bool val = is_true(arg1) == is_true(arg2); - SASSERT(val == (is_false(arg1) == is_false(arg2))); - if (val) { - set_true(e); - } - else { - set_false(e); - } - } - else if (m_arith.is_int_real(arg1)) { - set_bool(e, get_number(arg1) == get_number(arg2)); - } - else { - expr* e1 = get_value(arg1); - expr* e2 = get_value(arg2); - if (m.is_value(e1) && m.is_value(e2)) { - set_bool(e, e1 == e2); - } - else if (e1 == e2) { - set_bool(e, true); - } - else { - TRACE("pdr", tout << "not value equal:\n" << mk_pp(e1, m) << "\n" << mk_pp(e2, m) << "\n";); - set_x(e); - } - } - } - - void model_evaluator::eval_basic(app* e) { - expr* arg1, *arg2; - expr *argCond, *argThen, *argElse, *arg; - bool has_x = false; - unsigned arity = e->get_num_args(); - switch(e->get_decl_kind()) { - case OP_AND: - for (unsigned j = 0; j < arity; ++j) { - expr * arg = e->get_arg(j); - if (is_false(arg)) { - set_false(e); - return; - } - else if (is_x(arg)) { - has_x = true; - } - else { - SASSERT(is_true(arg)); - } - } - if (has_x) { - set_x(e); - } - else { - set_true(e); - } - break; - case OP_OR: - for (unsigned j = 0; j < arity; ++j) { - expr * arg = e->get_arg(j); - if (is_true(arg)) { - set_true(e); - return; - } - else if (is_x(arg)) { - has_x = true; - } - else { - SASSERT(is_false(arg)); - } - } - if (has_x) { - set_x(e); - } - else { - set_false(e); - } - break; - case OP_NOT: - VERIFY(m.is_not(e, arg)); - if (is_true(arg)) { - set_false(e); - } - else if (is_false(arg)) { - set_true(e); - } - else { - SASSERT(is_x(arg)); - set_x(e); - } - break; - case OP_IMPLIES: - VERIFY(m.is_implies(e, arg1, arg2)); - if (is_false(arg1) || is_true(arg2)) { - set_true(e); - } - else if (arg1 == arg2) { - set_true(e); - } - else if (is_true(arg1) && is_false(arg2)) { - set_false(e); - } - else { - SASSERT(is_x(arg1) || is_x(arg2)); - set_x(e); - } - break; - case OP_IFF: - VERIFY(m.is_iff(e, arg1, arg2)); - eval_eq(e, arg1, arg2); - break; - case OP_ITE: - VERIFY(m.is_ite(e, argCond, argThen, argElse)); - if (is_true(argCond)) { - inherit_value(e, argThen); - } - else if (is_false(argCond)) { - inherit_value(e, argElse); - } - else if (argThen == argElse) { - inherit_value(e, argThen); - } - else if (m.is_bool(e)) { - SASSERT(is_x(argCond)); - if (is_x(argThen) || is_x(argElse)) { - set_x(e); - } - else if (is_true(argThen) == is_true(argElse)) { - inherit_value(e, argThen); - } - else { - set_x(e); - } - } - else { - set_x(e); - } - break; - case OP_TRUE: - set_true(e); - break; - case OP_FALSE: - set_false(e); - break; - case OP_EQ: - VERIFY(m.is_eq(e, arg1, arg2)); - eval_eq(e, arg1, arg2); - break; - case OP_DISTINCT: { - vector values; - for (unsigned i = 0; i < arity; ++i) { - expr* arg = e->get_arg(i); - if (is_x(arg)) { - set_x(e); - return; - } - values.push_back(get_number(arg)); - } - std::sort(values.begin(), values.end()); - for (unsigned i = 0; i + 1 < values.size(); ++i) { - if (values[i] == values[i+1]) { - set_false(e); - return; - } - } - set_true(e); - break; - } - default: - IF_VERBOSE(0, verbose_stream() << "Term not handled " << mk_pp(e, m) << "\n";); - UNREACHABLE(); - } - } - - bool model_evaluator::check_model(ptr_vector const& formulas) { - ptr_vector todo(formulas); - - while (!todo.empty()) { - expr * curr_e = todo.back(); - - if (!is_app(curr_e)) { - todo.pop_back(); - continue; - } - app * curr = to_app(curr_e); - - if (!is_unknown(curr)) { - todo.pop_back(); - continue; - } - unsigned arity = curr->get_num_args(); - for (unsigned i = 0; i < arity; ++i) { - if (is_unknown(curr->get_arg(i))) { - todo.push_back(curr->get_arg(i)); - } - } - if (todo.back() != curr) { - continue; - } - todo.pop_back(); - if (curr->get_family_id() == m_arith.get_family_id()) { - eval_arith(curr); - } - else if (curr->get_family_id() == m.get_basic_family_id()) { - eval_basic(curr); - } - else { - expr_ref vl(m); - m_model->eval(curr, vl); - assign_value(curr, vl); - } - - IF_VERBOSE(35,verbose_stream() << "assigned "<get_arity() == 0); - expr_ref result(m); - if (m_array.is_array(d->get_range())) { - expr_ref e(m); - e = m.mk_const(d); - result = eval(model, e); - } - else { - result = model->get_const_interp(d); - } - return result; - } - - expr_ref model_evaluator::eval(model_ref& model, expr* e) { - expr_ref result(m); - m_model = model; - VERIFY(m_model->eval(e, result, true)); - if (m_array.is_array(e)) { - vector stores; - expr_ref_vector args(m); - expr_ref else_case(m); - if (extract_array_func_interp(result, stores, else_case)) { - result = m_array.mk_const_array(m.get_sort(e), else_case); - while (!stores.empty() && stores.back().back() == else_case) { - stores.pop_back(); - } - for (unsigned i = stores.size(); i > 0; ) { - --i; - args.resize(1); - args[0] = result; - args.append(stores[i]); - result = m_array.mk_store(args.size(), args.c_ptr()); - } - return result; - } - } - return result; - } - - void reduce_disequalities(model& model, unsigned threshold, expr_ref& fml) { ast_manager& m = fml.get_manager(); expr_ref_vector conjs(m); diff --git a/src/muz/pdr/pdr_util.h b/src/muz/pdr/pdr_util.h index 150cf2bb5..29b640d74 100644 --- a/src/muz/pdr/pdr_util.h +++ b/src/muz/pdr/pdr_util.h @@ -54,86 +54,6 @@ namespace pdr { std::string pp_cube(unsigned sz, app * const * lits, ast_manager& manager); std::string pp_cube(unsigned sz, expr * const * lits, ast_manager& manager); - class model_evaluator { - ast_manager& m; - arith_util m_arith; - array_util m_array; - obj_map m_numbers; - expr_ref_vector m_refs; - obj_map m_values; - model_ref m_model; - - //00 -- non-visited - //01 -- X - //10 -- false - //11 -- true - expr_mark m1; - expr_mark m2; - expr_mark m_visited; - - - void reset(); - void setup_model(model_ref& model); - void assign_value(expr* e, expr* v); - void collect(ptr_vector const& formulas, ptr_vector& tocollect); - void process_formula(app* e, ptr_vector& todo, ptr_vector& tocollect); - expr_ref_vector prune_by_cone_of_influence(ptr_vector const & formulas); - void eval_arith(app* e); - void eval_basic(app* e); - void eval_eq(app* e, expr* arg1, expr* arg2); - void eval_array_eq(app* e, expr* arg1, expr* arg2); - void inherit_value(expr* e, expr* v); - - inline bool is_unknown(expr* x) { return !m1.is_marked(x) && !m2.is_marked(x); } - inline void set_unknown(expr* x) { m1.mark(x, false); m2.mark(x, false); } - inline bool is_x(expr* x) { return !m1.is_marked(x) && m2.is_marked(x); } - inline bool is_false(expr* x) { return m1.is_marked(x) && !m2.is_marked(x); } - inline bool is_true(expr* x) { return m1.is_marked(x) && m2.is_marked(x); } - inline void set_x(expr* x) { SASSERT(is_unknown(x)); m2.mark(x); } - inline void set_v(expr* x) { SASSERT(is_unknown(x)); m1.mark(x); } - inline void set_false(expr* x) { SASSERT(is_unknown(x)); m1.mark(x); } - inline void set_true(expr* x) { SASSERT(is_unknown(x)); m1.mark(x); m2.mark(x); } - inline void set_bool(expr* x, bool v) { if (v) { set_true(x); } else { set_false(x); } } - inline rational const& get_number(expr* x) const { return m_numbers.find(x); } - inline void set_number(expr* x, rational const& v) { - set_v(x); TRACE("pdr_verbose", tout << mk_pp(x,m) << " " << v << "\n";); m_numbers.insert(x,v); - } - inline expr* get_value(expr* x) { return m_values.find(x); } - inline void set_value(expr* x, expr* v) { set_v(x); m_refs.push_back(v); m_values.insert(x, v); } - - bool check_model(ptr_vector const & formulas); - - bool extract_array_func_interp(expr* a, vector& stores, expr_ref& else_case); - - void eval_exprs(expr_ref_vector& es); - - public: - model_evaluator(ast_manager& m) : m(m), m_arith(m), m_array(m), m_refs(m) {} - - /** - \brief extract equalities from model that suffice to satisfy formula. - - \pre model satisfies formulas - */ - - expr_ref_vector minimize_model(ptr_vector const & formulas, model_ref& mdl); - - /** - \brief extract literals from formulas that satisfy formulas. - - \pre model satisfies formulas - */ - expr_ref_vector minimize_literals(ptr_vector const & formulas, model_ref& mdl); - - /** - for_each_expr visitor. - */ - void operator()(expr* e) {} - - expr_ref eval(model_ref& mdl, expr* e); - - expr_ref eval(model_ref& mdl, func_decl* d); - }; /** \brief replace variables that are used in many disequalities by diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index a0395ab84..90420ad72 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -243,7 +243,7 @@ namespace opt { void set_solver() { opt_solver & opt_s = opt_solver::to_opt(m_original_solver); - if (opt_s.is_dumping_benchmark()) + if (opt_s.dump_benchmarks()) return; solver& current_solver = s(); diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 88d1cab1f..754c32d31 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -35,7 +35,8 @@ namespace opt { m_context(mgr, m_params), m(mgr), m_objective_enabled(false), - m_is_dump(false) { + m_dump_benchmarks(false), + m_dump_count(0) { m_logic = l; if (m_logic != symbol::null) m_context.set_logic(m_logic); @@ -45,7 +46,7 @@ namespace opt { } void opt_solver::updt_params(params_ref const & p) { - m_is_dump = p.get_bool("dump_benchmarks", false); + m_dump_benchmarks = p.get_bool("dump_benchmarks", false); m_params.updt_params(p); m_context.updt_params(p); } @@ -105,22 +106,22 @@ namespace opt { static unsigned g_checksat_count = 0; - bool opt_solver::is_dumping_benchmark() { - return m_is_dump; + bool opt_solver::dump_benchmarks() { + return m_dump_benchmarks; } lbool opt_solver::check_sat_core(unsigned num_assumptions, expr * const * assumptions) { - TRACE("opt_solver_na2as", { - tout << "opt_opt_solver::check_sat_core: " << m_context.size() << "\n"; + TRACE("opt", { + tout << "context size: " << m_context.size() << "\n"; for (unsigned i = 0; i < m_context.size(); ++i) { - tout << mk_pp(m_context.get_formulas()[i], m_context.m()) << "\n"; + tout << mk_pp(m_context.get_formulas()[i], m_context.m()) << "\n"; } }); lbool r = m_context.check(num_assumptions, assumptions); - if (m_is_dump) { + if (dump_benchmarks()) { std::stringstream file_name; - file_name << "opt_solver" << ++g_checksat_count << ".smt2"; + file_name << "opt_solver" << ++m_dump_count << ".smt2"; std::ofstream buffer(file_name.str().c_str()); to_smt2_benchmark(buffer, "opt_solver", "QF_BV"); buffer.close(); diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index e946d2131..3be11f4bc 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -46,7 +46,8 @@ namespace opt { bool m_objective_enabled; svector m_objective_vars; vector m_objective_values; - bool m_is_dump; + bool m_dump_benchmarks; + unsigned m_dump_count; statistics m_stats; public: opt_solver(ast_manager & m, params_ref const & p, symbol const & l); @@ -79,7 +80,7 @@ namespace opt { static opt_solver& to_opt(solver& s); void set_interim_stats(statistics & st); - bool is_dumping_benchmark(); + bool dump_benchmarks(); class toggle_objective { opt_solver& s; diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index b46ad7e0d..46a8eb443 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -26,8 +26,6 @@ Notes: namespace smt { - bool theory_pb::s_debug_conflict = true; // false; // true; // - void theory_pb::ineq::negate() { m_lit.neg(); numeral sum(0); @@ -205,10 +203,54 @@ namespace smt { } k = k_new; } + // + // normalize coefficients that fall within a range + // k/n <= ... < k/(n-1) for some n = 1,2,... + // + // e.g, k/n <= min <= max < k/(n-1) + // k/min <= n, n-1 < k/max + // . floor(k/max) = ceil(k/min) - 1 + // . floor(k/max) < k/max + // + // example: k = 5, min = 3, max = 4: 5/3 -> 2 5/4 -> 1, n = 2 + // replace all coefficients by 1, and k by 2. + // + if (!k.is_one()) { + numeral min = coeff(0), max = coeff(0); + for (unsigned i = 1; i < size(); ++i) { + if (coeff(i) < min) min = coeff(i); + if (coeff(i) > max) max = coeff(i); + } + numeral n0 = k/max; + numeral n1 = floor(n0); + numeral n2 = ceil(k/min) - numeral::one(); + if (n1 == n2 && !n0.is_int()) { + for (unsigned i = 0; i < size(); ++i) { + args[i].second = numeral::one(); + } + k = n1 + numeral::one(); + } + } + SASSERT(well_formed()); return l_undef; } + app_ref theory_pb::ineq::to_expr(context& ctx, ast_manager& m) { + expr_ref tmp(m); + app_ref result(m); + svector coeffs; + expr_ref_vector args(m); + for (unsigned i = 0; i < size(); ++i) { + ctx.literal2expr(lit(i), tmp); + args.push_back(tmp); + coeffs.push_back(coeff(i)); + } + pb_util pb(m); + result = pb.mk_ge(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), k()); + return result; + } + bool theory_pb::ineq::well_formed() const { SASSERT(k().is_pos()); uint_set vars; @@ -406,12 +448,20 @@ namespace smt { } --c.m_watch_sz; c.m_max_sum -= coeff; + if (c.max_coeff() == coeff) { + coeff = c.coeff(0); + for (unsigned i = 1; coeff != c.max_coeff() && i < c.m_watch_sz; ++i) { + if (coeff < c.coeff(i)) coeff = c.coeff(i); + } + c.set_max_coeff(coeff); + } // current index of unwatched literal is c.watch_size(). } void theory_pb::add_watch(ineq& c, unsigned i) { - bool_var v = c.lit(i).var(); + literal lit = c.lit(i); + bool_var v = lit.var(); c.m_max_sum += c.coeff(i); SASSERT(i >= c.watch_size()); if (i > c.watch_size()) { @@ -419,9 +469,9 @@ namespace smt { } ++c.m_watch_sz; ptr_vector* ineqs; - if (!m_watch.find(v, ineqs)) { + if (!m_watch.find(lit.index(), ineqs)) { ineqs = alloc(ptr_vector); - m_watch.insert(v, ineqs); + m_watch.insert(lit.index(), ineqs); } ineqs->push_back(&c); } @@ -500,8 +550,8 @@ namespace smt { void theory_pb::assign_eh(bool_var v, bool is_true) { context& ctx = get_context(); ptr_vector* ineqs = 0; - - if (m_watch.find(v, ineqs)) { + literal lit(v, !is_true); + if (m_watch.find(lit.index(), ineqs)) { for (unsigned i = 0; i < ineqs->size(); ++i) { if (assign_watch(v, is_true, *ineqs, i)) { // i was removed from watch list. @@ -572,7 +622,7 @@ namespace smt { if (maxsum < c.k()) { literal_vector& lits = get_unhelpful_literals(c, false); lits.push_back(~c.lit()); - add_clause(c, ~lits[0], lits); + add_clause(c, lits); } else { c.m_max_sum = numeral::zero(); @@ -601,68 +651,63 @@ namespace smt { unsigned w = c.find_lit(v, 0, c.watch_size()); SASSERT(ctx.get_assignment(c.lit()) == l_true); + SASSERT(is_true == c.lit(w).sign()); - if (is_true == c.lit(w).sign()) { - // - // max_sum is decreased. - // Adjust set of watched literals. - // - - numeral k = c.k(); - numeral coeff = c.coeff(w); - - for (unsigned i = c.watch_size(); c.max_sum() - coeff < k + c.max_coeff() && i < c.size(); ++i) { - if (ctx.get_assignment(c.lit(i)) != l_false) { - add_watch(c, i); - } - } - + // + // max_sum is decreased. + // Adjust set of watched literals. + // - if (c.max_sum() - coeff < k) { - // - // L: 3*x1 + 2*x2 + x4 >= 3, but x1 <- 0, x2 <- 0 - // create clause x1 or x2 or ~L - // - literal_vector& lits = get_unhelpful_literals(c, false); - lits.push_back(~c.lit()); - add_clause(c, literal(v, !is_true), lits); + numeral k = c.k(); + numeral coeff = c.coeff(w); + + for (unsigned i = c.watch_size(); c.max_sum() - coeff < k + c.max_coeff() && i < c.size(); ++i) { + if (ctx.get_assignment(c.lit(i)) != l_false) { + add_watch(c, i); } - else { - del_watch(watch, watch_index, c, w); - removed = true; - if (c.max_sum() - coeff < k + c.max_coeff()) { - - // - // opportunities for unit propagation for unassigned - // literals whose coefficients satisfy - // c.max_sum() - coeff < k - // - // L: 3*x1 + 2*x2 + x4 >= 3, but x1 <- 0 - // Create clauses x1 or ~L or x2 - // x1 or ~L or x4 - // - - literal_vector& lits = get_unhelpful_literals(c, true); - lits.push_back(c.lit()); - for (unsigned i = 0; i < c.size(); ++i) { - if (c.max_sum() - c.coeff(i) < k && ctx.get_assignment(c.lit(i)) == l_undef) { - add_assign(c, lits, c.lit(i)); - } + } + + if (c.max_sum() - coeff < k) { + // + // L: 3*x1 + 2*x2 + x4 >= 3, but x1 <- 0, x2 <- 0 + // create clause x1 or x2 or ~L + // + literal_vector& lits = get_unhelpful_literals(c, false); + lits.push_back(~c.lit()); + add_clause(c, lits); + } + else { + del_watch(watch, watch_index, c, w); + removed = true; + if (c.max_sum() - coeff < k + c.max_coeff()) { + + // + // opportunities for unit propagation for unassigned + // literals whose coefficients satisfy + // c.max_sum() - coeff < k + // + // L: 3*x1 + 2*x2 + x4 >= 3, but x1 <- 0 + // Create clauses x1 or ~L or x2 + // x1 or ~L or x4 + // + + literal_vector& lits = get_unhelpful_literals(c, true); + lits.push_back(c.lit()); + for (unsigned i = 0; i < c.size(); ++i) { + if (c.max_sum() - c.coeff(i) < k && ctx.get_assignment(c.lit(i)) == l_undef) { + add_assign(c, lits, c.lit(i)); } } - // - // else: c.max_sum() >= k + c.max_coeff() - // we might miss opportunities for unit propagation if - // max_coeff is not the maximal coefficient - // of the current unassigned literal, but we can - // rely on eventually learning this from propagations. - // } + // + // else: c.max_sum() >= k + c.max_coeff() + // we might miss opportunities for unit propagation if + // max_coeff is not the maximal coefficient + // of the current unassigned literal, but we can + // rely on eventually learning this from propagations. + // } - // - // else: the current set of watch remain a potentially feasible assignment. - // TRACE("pb", tout << "assign: " << literal(v) << " <- " << is_true << "\n"; display(tout, c); ); @@ -872,9 +917,9 @@ namespace smt { while (m_assign_ineqs_trail.size() > sz) { ineq* c = m_assign_ineqs_trail.back(); for (unsigned i = 0; i < c->watch_size(); ++i) { - bool_var w = c->lit(i).var(); + literal w = c->lit(i); ptr_vector* ineqs = 0; - VERIFY(m_watch.find(w, ineqs)); + VERIFY(m_watch.find(w.index(), ineqs)); for (unsigned j = 0; j < ineqs->size(); ++j) { if ((*ineqs)[j] == c) { std::swap((*ineqs)[j],(*ineqs)[ineqs->size()-1]); @@ -904,7 +949,7 @@ namespace smt { void theory_pb::display(std::ostream& out) const { u_map*>::iterator it = m_watch.begin(), end = m_watch.end(); for (; it != end; ++it) { - out << "watch: " << literal(it->m_key) << " |-> "; + out << "watch: " << to_literal(it->m_key) << " |-> "; watch_list const& wl = *it->m_value; for (unsigned i = 0; i < wl.size(); ++i) { out << wl[i]->lit() << " "; @@ -988,7 +1033,7 @@ namespace smt { - void theory_pb::add_clause(ineq& c, literal conseq, literal_vector const& lits) { + void theory_pb::add_clause(ineq& c, literal_vector const& lits) { inc_propagations(c); m_stats.m_num_conflicts++; context& ctx = get_context(); @@ -999,21 +1044,16 @@ namespace smt { tout << "\n"; display(tout, c, true);); -#if 0 - DEBUG_CODE( - if (s_debug_conflict) { - resolve_conflict(conseq, c); - }); -#else - resolve_conflict(conseq, c); -#endif + resolve_conflict(c); + +#if 1 justification* js = 0; ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); IF_VERBOSE(2, ctx.display_literals_verbose(verbose_stream(), lits.size(), lits.c_ptr()); verbose_stream() << "\n";); // ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); - +#endif } void theory_pb::set_mark(bool_var v, unsigned idx) { @@ -1022,9 +1062,7 @@ namespace smt { m_conseq_index.resize(v+1, null_index); } SASSERT(!is_marked(v) || m_conseq_index[v] == idx); - if (m_conseq_index[v] == null_index) { - m_conseq_index[v] = idx; - } + m_conseq_index[v] = idx; } bool theory_pb::is_marked(bool_var v) const { @@ -1115,11 +1153,12 @@ namespace smt { // // modeled after sat_solver/smt_context // - void theory_pb::resolve_conflict(literal conseq, ineq& c) { + bool theory_pb::resolve_conflict(ineq& c) { - TRACE("pb", tout << "RESOLVE: " << conseq << "\n"; display(tout, c, true);); + TRACE("pb", display(tout, c, true);); bool_var v; + literal conseq; context& ctx = get_context(); unsigned& lvl = m_conflict_lvl = 0; for (unsigned i = 0; i < c.size(); ++i) { @@ -1127,12 +1166,8 @@ namespace smt { lvl = std::max(lvl, ctx.get_assign_level(c.lit(i))); } } - - SASSERT(lvl >= ctx.get_assign_level(c.lit())); - SASSERT(ctx.get_assignment(conseq) == l_true); - - if (lvl == ctx.get_base_level()) { - return; + if (lvl < ctx.get_assign_level(c.lit()) || lvl == ctx.get_base_level()) { + return false; } m_num_marks = 0; @@ -1229,52 +1264,37 @@ namespace smt { default: UNREACHABLE(); } - m_lemma.normalize(); } + for (unsigned i = 0; i < m_lemma.size(); ++i) { unset_mark(m_lemma.lit(i)); } TRACE("pb", display(tout << "lemma: ", m_lemma);); - - // TBD: - // create clause m_ineq_literals => m_lemma; - // -#if 1 hoist_maximal_values(); - IF_VERBOSE(1, display(verbose_stream() << "lemma: ", m_lemma);); - ast_manager& m = get_manager(); - svector coeffs; - expr_ref_vector args(m); - expr_ref tmp(m); - for (unsigned i = 0; i < m_lemma.size(); ++i) { - ctx.literal2expr(m_lemma.lit(i), tmp); - args.push_back(tmp); - coeffs.push_back(m_lemma.coeff(i)); + lbool is_true = m_lemma.normalize(); + + IF_VERBOSE(1, display(verbose_stream() << "lemma: ", m_lemma);); + switch(is_true) { + case l_true: + UNREACHABLE(); + return false; + case l_false: + add_assign(c, m_ineq_literals, false_literal); + break; + default: { + app_ref tmp = m_lemma.to_expr(ctx, get_manager()); + internalize_atom(tmp, false); + ctx.mark_as_relevant(tmp); + literal l(ctx.get_bool_var(tmp)); + add_assign(c, m_ineq_literals, l); + break; } - numeral k = m_lemma.k(); - tmp = m_util.mk_ge(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), k); - internalize_atom(to_app(tmp), false); - //m_ineq_literals.push_back(literal(ctx.get_bool_var(tmp))); - ctx.mark_as_relevant(tmp); - //justification* mjs = 0; - //ctx.mk_clause(m_ineq_literals.size(), m_ineq_literals.c_ptr(), mjs, CLS_AUX_LEMMA, 0); - literal l(ctx.get_bool_var(tmp)); - ineq* cc = 0; - if (m_ineqs.find(l.var(), cc)) { - add_assign(*cc, m_ineq_literals, l); } - else { - ctx.assign(l, ctx.mk_justification( - theory_propagation_justification( - get_id(), ctx.get_region(), - m_ineq_literals.size(), m_ineq_literals.c_ptr(), l))); -// IF_VERBOSE(0, verbose_stream() << "Did not compile " << tmp << "\n";); - } -#endif + return true; } void theory_pb::hoist_maximal_values() { diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index dd0fd41dc..17d35c1dd 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -71,6 +71,7 @@ namespace smt { numeral const& max_sum() const { return m_max_sum; } numeral const& max_coeff() const { return m_max_coeff; } + void set_max_coeff(numeral const& n) { m_max_coeff = n; } unsigned watch_size() const { return m_watch_sz; } @@ -91,8 +92,7 @@ namespace smt { bool well_formed() const; - //static numeral gcd(numeral a, numeral b); - //static numeral lcm(numeral a, numeral b); + app_ref to_expr(context& ctx, ast_manager& m); }; @@ -119,7 +119,7 @@ namespace smt { std::ostream& display(std::ostream& out, ineq& c, bool values = false) const; virtual void display(std::ostream& out) const; - void add_clause(ineq& c, literal conseq, literal_vector const& lits); + void add_clause(ineq& c, literal_vector const& lits); void add_assign(ineq& c, literal_vector const& lits, literal l); literal_vector& get_lits(); @@ -149,7 +149,7 @@ namespace smt { void set_mark(bool_var v, unsigned idx); void unset_mark(literal l); - void resolve_conflict(literal conseq, ineq& c); + bool resolve_conflict(ineq& c); void process_antecedent(literal l, numeral coeff); void process_ineq(ineq& c, literal conseq, numeral coeff); @@ -179,6 +179,5 @@ namespace smt { virtual void restart_eh(); virtual void collect_statistics(::statistics & st) const; - static bool s_debug_conflict; }; }; diff --git a/src/tactic/arith/lia2card_tactic.cpp b/src/tactic/arith/lia2card_tactic.cpp index ec2368ba8..c5db50427 100644 --- a/src/tactic/arith/lia2card_tactic.cpp +++ b/src/tactic/arith/lia2card_tactic.cpp @@ -21,7 +21,6 @@ Notes: #include"bound_manager.h" #include"ast_pp.h" #include"expr_safe_replace.h" // NB: should use proof-producing expr_substitute in polished version. - #include"pb_decl_plugin.h" #include"arith_decl_plugin.h" @@ -31,10 +30,10 @@ class lia2card_tactic : public tactic { typedef obj_hashtable expr_set; ast_manager & m; arith_util a; - pb_util m_pb; - obj_map > m_uses; - obj_map m_converted; + pb_util m_pb; + mutable ptr_vector m_todo; expr_set m_01s; + imp(ast_manager & _m, params_ref const & p): m(_m), @@ -56,8 +55,6 @@ class lia2card_tactic : public tactic { SASSERT(g->is_well_sorted()); mc = 0; pc = 0; core = 0; m_01s.reset(); - m_uses.reset(); - m_converted.reset(); tactic_report report("cardinality-intro", *g); @@ -76,36 +73,9 @@ class lia2card_tactic : public tactic { TRACE("pb", tout << "add bound " << mk_pp(x, m) << "\n";); } } - if (m_01s.empty()) { - result.push_back(g.get()); - return; - } - expr_set::iterator it = m_01s.begin(), end = m_01s.end(); - for (; it != end; ++it) { - m_uses.insert(*it, ptr_vector()); - } - for (unsigned j = 0; j < g->size(); ++j) { - ast_mark mark; - collect_uses(mark, g->form(j)); - } - - it = m_01s.begin(), end = m_01s.end(); - for (; it != end; ++it) { - if (!validate_uses(m_uses.find(*it))) { - std::cout << "did not validate: " << mk_pp(*it, m) << "\n"; - m_uses.remove(*it); - m_01s.remove(*it); - it = m_01s.begin(); - end = m_01s.end(); - } - } - if (m_01s.empty()) { - result.push_back(g.get()); - return; - } expr_safe_replace sub(m); - extract_substitution(sub); + extract_pb_substitution(g, sub); expr_ref new_curr(m); proof_ref new_pr(m); @@ -124,248 +94,110 @@ class lia2card_tactic : public tactic { // TBD: support proof conversion (or not..) } - void extract_substitution(expr_safe_replace& sub) { - expr_set::iterator it = m_01s.begin(), end = m_01s.end(); - for (; it != end; ++it) { - extract_substitution(sub, *it); + void extract_pb_substitution(goal_ref const& g, expr_safe_replace& sub) { + ast_mark mark; + for (unsigned i = 0; i < g->size(); i++) { + extract_pb_substitution(mark, g->form(i), sub); } } - void extract_substitution(expr_safe_replace& sub, expr* x) { - ptr_vector const& use_list = m_uses.find(x); - for (unsigned i = 0; i < use_list.size(); ++i) { - expr* u = use_list[i]; - convert_01(sub, u); + void extract_pb_substitution(ast_mark& mark, expr* fml, expr_safe_replace& sub) { + expr_ref tmp(m); + m_todo.reset(); + m_todo.push_back(fml); + while (!m_todo.empty()) { + expr* e = m_todo.back(); + m_todo.pop_back(); + if (mark.is_marked(e) || !is_app(e)) { + continue; + } + mark.mark(e, true); + if (get_pb_relation(sub, e, tmp)) { + sub.insert(e, tmp); + continue; + } + app* ap = to_app(e); + m_todo.append(ap->get_num_args(), ap->get_args()); } } - expr_ref mk_le(expr* x, rational const& bound) { - if (bound.is_pos()) { - return expr_ref(m.mk_true(), m); - } - else if (bound.is_zero()) { - return expr_ref(m.mk_not(mk_01(x)), m); - } - else { - return expr_ref(m.mk_false(), m); - } - } - - expr_ref mk_ge(expr* x, rational const& bound) { - if (bound.is_one()) { - return expr_ref(mk_01(x), m); - } - else if (bound.is_pos()) { - return expr_ref(m.mk_false(), m); - } - else { - return expr_ref(m.mk_true(), m); - } - } bool is_01var(expr* x) const { return m_01s.contains(x); } - void convert_01(expr_safe_replace& sub, expr* fml) { - rational n; - unsigned k; - expr_ref_vector args(m); - expr_ref result(m); - expr* x, *y; - if (a.is_le(fml, x, y) || a.is_ge(fml, y, x)) { - if (is_01var(x) && a.is_numeral(y, n)) { - sub.insert(fml, mk_le(x, n)); - } - else if (is_01var(y) && a.is_numeral(x, n)) { - sub.insert(fml, mk_ge(y, n)); - } - else if (is_add(x, args) && is_unsigned(y, k)) { // x <= k - sub.insert(fml, m_pb.mk_at_most_k(args.size(), args.c_ptr(), k)); - } - else if (is_add(y, args) && is_unsigned(x, k)) { // k <= y <=> not (y <= k-1) - if (k == 0) - sub.insert(fml, m.mk_true()); - else - sub.insert(fml, m.mk_not(m_pb.mk_at_most_k(args.size(), args.c_ptr(), k-1))); - } - else { - UNREACHABLE(); - } - } - else if (a.is_lt(fml, x, y) || a.is_gt(fml, y, x)) { - if (is_01var(x) && a.is_numeral(y, n)) { - sub.insert(fml, mk_le(x, n-rational(1))); - } - else if (is_01var(y) && a.is_numeral(x, n)) { - sub.insert(fml, mk_ge(y, n+rational(1))); - } - else if (is_add(x, args) && is_unsigned(y, k)) { // x < k - if (k == 0) - sub.insert(fml, m.mk_false()); - else - sub.insert(fml, m_pb.mk_at_most_k(args.size(), args.c_ptr(), k-1)); - } - else if (is_add(y, args) && is_unsigned(x, k)) { // k < y <=> not (y <= k) - sub.insert(fml, m.mk_not(m_pb.mk_at_most_k(args.size(), args.c_ptr(), k))); - } - else { - UNREACHABLE(); - } - } - else if (m.is_eq(fml, x, y)) { - if (!is_01var(x)) { - std::swap(x, y); - } - else if (is_01var(x) && a.is_numeral(y, n)) { - if (n.is_one()) { - sub.insert(fml, mk_01(x)); - } - else if (n.is_zero()) { - sub.insert(fml, m.mk_not(mk_01(x))); - } - else { - sub.insert(fml, m.mk_false()); - } - } - else { - UNREACHABLE(); - } - } - else if (is_sum(fml)) { - SASSERT(m_uses.contains(fml)); - ptr_vector const& u = m_uses.find(fml); - for (unsigned i = 0; i < u.size(); ++i) { - convert_01(sub, u[i]); - } - } - else { - UNREACHABLE(); - } - } - expr_ref mk_01(expr* x) { - expr* r; - SASSERT(is_01var(x)); - if (!m_converted.find(x, r)) { - symbol name = to_app(x)->get_decl()->get_name(); - r = m.mk_fresh_const(name.str().c_str(), m.mk_bool_sort()); - m_converted.insert(x, r); - } + expr* r = m.mk_eq(x, a.mk_numeral(rational(1), m.get_sort(x))); return expr_ref(r, m); - } + } - - bool is_add(expr* x, expr_ref_vector& args) { - if (a.is_add(x)) { - app* ap = to_app(x); - for (unsigned i = 0; i < ap->get_num_args(); ++i) { - args.push_back(mk_01(ap->get_arg(i))); - } - return true; - } - else { - return false; - } - } - - bool validate_uses(ptr_vector const& use_list) { - for (unsigned i = 0; i < use_list.size(); ++i) { - if (!validate_use(use_list[i])) { - return false; - } - } - return true; - } - - bool validate_use(expr* fml) { + bool get_pb_relation(expr_safe_replace& sub, expr* fml, expr_ref& result) { expr* x, *y; - if (a.is_le(fml, x, y) || - a.is_ge(fml, x, y) || - a.is_lt(fml, x, y) || - a.is_gt(fml, x, y) || - m.is_eq(fml, x, y)) { - if (a.is_numeral(x)) { - std::swap(x,y); - } - if ((is_one(y) || a.is_zero(y)) && is_01var(x)) - return true; - if (a.is_numeral(y) && is_sum(x) && !m.is_eq(fml)) { - return true; - } - } - if (is_sum(fml)) { - SASSERT(m_uses.contains(fml)); - ptr_vector const& u = m_uses.find(fml); - for (unsigned i = 0; i < u.size(); ++i) { - if (!validate_use(u[i])) { - return false; - } - } + expr_ref_vector args(m); + vector coeffs; + rational coeff; + if ((a.is_le(fml, x, y) || a.is_ge(fml, y, x)) && + get_pb_sum(x, rational::one(), args, coeffs, coeff) && + get_pb_sum(y, -rational::one(), args, coeffs, coeff)) { + result = m_pb.mk_le(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff); return true; } - TRACE("pb", tout << "Use not validated: " << mk_pp(fml, m) << "\n";); - + else if ((a.is_lt(fml, y, x) || a.is_gt(fml, x, y)) && + get_pb_sum(x, rational::one(), args, coeffs, coeff) && + get_pb_sum(y, -rational::one(), args, coeffs, coeff)) { + result = m.mk_not(m_pb.mk_le(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff)); + return true; + } + else if (m.is_eq(fml, x, y) && + get_pb_sum(x, rational::one(), args, coeffs, coeff) && + get_pb_sum(y, -rational::one(), args, coeffs, coeff)) { + result = m.mk_and(m_pb.mk_le(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff), + m_pb.mk_ge(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff)); + return true; + } return false; } - bool is_sum(expr* x) const { + bool get_pb_sum(expr* x, rational const& mul, expr_ref_vector& args, vector& coeffs, rational& coeff) { + expr *y, *z, *u; + rational r, q; + app* f = to_app(x); + bool ok = true; if (a.is_add(x)) { - app* ap = to_app(x); - for (unsigned i = 0; i < ap->get_num_args(); ++i) { - if (!is_01var(ap->get_arg(i))) { - return false; - } + for (unsigned i = 0; ok && i < f->get_num_args(); ++i) { + ok = get_pb_sum(f->get_arg(i), mul, args, coeffs, coeff); } - return true; } - return false; - } - - bool is_unsigned(expr* x, unsigned& k) { - rational r; - if (a.is_numeral(x, r) && r.is_unsigned()) { - k = r.get_unsigned(); - SASSERT(rational(k) == r); - return true; + else if (a.is_sub(x, y, z)) { + ok = get_pb_sum(y, mul, args, coeffs, coeff); + ok = ok && get_pb_sum(z, -mul, args, coeffs, coeff); + } + else if (a.is_uminus(x, y)) { + ok = get_pb_sum(y, -mul, args, coeffs, coeff); + } + else if (a.is_mul(x, y, z) && a.is_numeral(y, r)) { + ok = get_pb_sum(z, r*mul, args, coeffs, coeff); + } + else if (a.is_mul(x, z, y) && a.is_numeral(y, r)) { + ok = get_pb_sum(z, r*mul, args, coeffs, coeff); + } + else if (m.is_ite(x, y, z, u) && a.is_numeral(z, r) && a.is_numeral(u, q)) { + args.push_back(y); + coeffs.push_back(r*mul); + args.push_back(m.mk_not(y)); + coeffs.push_back(q*mul); + } + else if (is_01var(x)) { + args.push_back(mk_01(x)); + coeffs.push_back(mul); + } + else if (a.is_numeral(x, r)) { + coeff += mul*r; } else { - return false; - } - } - - bool is_one(expr* x) { - rational r; - return a.is_numeral(x, r) && r.is_one(); - } - - void collect_uses(ast_mark& mark, expr* f) { - ptr_vector todo; - todo.push_back(f); - while (!todo.empty()) { - f = todo.back(); - todo.pop_back(); - if (mark.is_marked(f)) { - continue; - } - mark.mark(f, true); - if (is_var(f)) { - continue; - } - if (is_quantifier(f)) { - todo.push_back(to_quantifier(f)->get_expr()); - continue; - } - app* a = to_app(f); - for (unsigned i = 0; i < a->get_num_args(); ++i) { - expr* arg = a->get_arg(i); - if (!m_uses.contains(arg)) { - m_uses.insert(arg, ptr_vector()); - } - m_uses.find(arg).push_back(a); - todo.push_back(arg); - } + ok = false; } + return ok; } }; @@ -426,3 +258,240 @@ tactic * mk_lia2card_tactic(ast_manager & m, params_ref const & p) { return clean(alloc(lia2card_tactic, m, p)); } + +#if 0 + void extract_substitution(expr_safe_replace& sub) { + expr_set::iterator it = m_01s.begin(), end = m_01s.end(); + for (; it != end; ++it) { + extract_substitution(sub, *it); + } + } + + void extract_substitution(expr_safe_replace& sub, expr* x) { + ptr_vector const& use_list = m_uses.find(x); + for (unsigned i = 0; i < use_list.size(); ++i) { + expr* u = use_list[i]; + convert_01(sub, u); + } + } + + expr_ref mk_le(expr* x, rational const& bound) { + if (bound.is_pos()) { + return expr_ref(m.mk_true(), m); + } + else if (bound.is_zero()) { + return expr_ref(m.mk_not(mk_01(x)), m); + } + else { + return expr_ref(m.mk_false(), m); + } + } + + expr_ref mk_ge(expr* x, rational const& bound) { + if (bound.is_one()) { + return expr_ref(mk_01(x), m); + } + else if (bound.is_pos()) { + return expr_ref(m.mk_false(), m); + } + else { + return expr_ref(m.mk_true(), m); + } + } + + void convert_01(expr_safe_replace& sub, expr* fml) { + rational n; + unsigned k; + expr_ref_vector args(m); + expr_ref result(m); + expr* x, *y; + if (a.is_le(fml, x, y) || a.is_ge(fml, y, x)) { + if (is_01var(x) && a.is_numeral(y, n)) { + sub.insert(fml, mk_le(x, n)); + } + else if (is_01var(y) && a.is_numeral(x, n)) { + sub.insert(fml, mk_ge(y, n)); + } + else if (is_01_add(x, args) && is_unsigned(y, k)) { // x <= k + sub.insert(fml, m_pb.mk_at_most_k(args.size(), args.c_ptr(), k)); + } + else if (is_01_add(y, args) && is_unsigned(x, k)) { // k <= y <=> not (y <= k-1) + if (k == 0) + sub.insert(fml, m.mk_true()); + else + sub.insert(fml, m.mk_not(m_pb.mk_at_most_k(args.size(), args.c_ptr(), k-1))); + } + else { + UNREACHABLE(); + } + } + else if (a.is_lt(fml, x, y) || a.is_gt(fml, y, x)) { + if (is_01var(x) && a.is_numeral(y, n)) { + sub.insert(fml, mk_le(x, n-rational(1))); + } + else if (is_01var(y) && a.is_numeral(x, n)) { + sub.insert(fml, mk_ge(y, n+rational(1))); + } + else if (is_01_add(x, args) && is_unsigned(y, k)) { // x < k + if (k == 0) + sub.insert(fml, m.mk_false()); + else + sub.insert(fml, m_pb.mk_at_most_k(args.size(), args.c_ptr(), k-1)); + } + else if (is_01_add(y, args) && is_unsigned(x, k)) { // k < y <=> not (y <= k) + sub.insert(fml, m.mk_not(m_pb.mk_at_most_k(args.size(), args.c_ptr(), k))); + } + else { + UNREACHABLE(); + } + } + else if (m.is_eq(fml, x, y)) { + if (!is_01var(x)) { + std::swap(x, y); + } + if (is_01var(x) && a.is_numeral(y, n)) { + if (n.is_one()) { + sub.insert(fml, mk_01(x)); + } + else if (n.is_zero()) { + sub.insert(fml, m.mk_not(mk_01(x))); + } + else { + sub.insert(fml, m.mk_false()); + } + } + else { + UNREACHABLE(); + } + } + else if (is_01_sum(fml)) { + SASSERT(m_uses.contains(fml)); + ptr_vector const& u = m_uses.find(fml); + for (unsigned i = 0; i < u.size(); ++i) { + convert_01(sub, u[i]); + } + } + else { + UNREACHABLE(); + } + } + + bool is_01_add(expr* x, expr_ref_vector& args) { + if (a.is_add(x)) { + app* ap = to_app(x); + for (unsigned i = 0; i < ap->get_num_args(); ++i) { + if (!is_01var(ap->get_arg(i))) { + return false; + } + args.push_back(mk_01(ap->get_arg(i))); + } + return true; + } + else { + return false; + } + } + + bool validate_uses(ptr_vector const& use_list) { + for (unsigned i = 0; i < use_list.size(); ++i) { + if (!validate_use(use_list[i])) { + return false; + } + } + return true; + } + + bool validate_use(expr* fml) { + expr* x, *y; + if (a.is_le(fml, x, y) || + a.is_ge(fml, x, y) || + a.is_lt(fml, x, y) || + a.is_gt(fml, x, y) || + m.is_eq(fml, x, y)) { + if (a.is_numeral(x)) { + std::swap(x,y); + } + if ((is_one(y) || a.is_zero(y)) && is_01var(x)) + return true; + if (a.is_numeral(y) && is_01_sum(x) && !m.is_eq(fml)) { + return true; + } + } + if (is_01_sum(fml)) { + SASSERT(m_uses.contains(fml)); + ptr_vector const& u = m_uses.find(fml); + for (unsigned i = 0; i < u.size(); ++i) { + if (!validate_use(u[i])) { + return false; + } + } + return true; + } + TRACE("pb", tout << "Use not validated: " << mk_pp(fml, m) << "\n";); + + return false; + } + + bool is_01_sum(expr* x) const { + if (a.is_add(x)) { + app* ap = to_app(x); + for (unsigned i = 0; i < ap->get_num_args(); ++i) { + if (!is_01var(ap->get_arg(i))) { + return false; + } + } + return true; + } + return false; + } + + + void collect_uses(ast_mark& mark, expr* f) { + m_todo.reset(); + m_todo.push_back(f); + while (!m_todo.empty()) { + f = m_todo.back(); + m_todo.pop_back(); + if (mark.is_marked(f)) { + continue; + } + mark.mark(f, true); + if (is_var(f)) { + continue; + } + if (is_quantifier(f)) { + m_todo.push_back(to_quantifier(f)->get_expr()); + continue; + } + app* a = to_app(f); + for (unsigned i = 0; i < a->get_num_args(); ++i) { + expr* arg = a->get_arg(i); + if (!m_uses.contains(arg)) { + m_uses.insert(arg, ptr_vector()); + } + m_uses.find(arg).push_back(a); + m_todo.push_back(arg); + } + } + } + + bool is_unsigned(expr* x, unsigned& k) { + rational r; + if (a.is_numeral(x, r) && r.is_unsigned()) { + k = r.get_unsigned(); + SASSERT(rational(k) == r); + return true; + } + else { + return false; + } + } + + bool is_one(expr* x) { + rational r; + return a.is_numeral(x, r) && r.is_one(); + } + + }; + +#endif From cc3d65e544bfdbe9036b62090092acbf155a87da Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Sun, 24 Nov 2013 22:31:52 +0100 Subject: [PATCH 161/925] Add facilities to get optimal assignments --- src/smt/network_flow.h | 8 +++- src/smt/network_flow_def.h | 7 ++++ src/smt/theory_arith.h | 4 +- src/smt/theory_arith_aux.h | 68 ++++++++++++++++++++++++++++----- src/smt/theory_diff_logic.h | 4 +- src/smt/theory_diff_logic_def.h | 25 ++++++++++-- 6 files changed, 98 insertions(+), 18 deletions(-) diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index 6e6fcaee0..3ba733174 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -93,8 +93,8 @@ namespace smt { bool choose_entering_edge() { TRACE("network_flow", tout << "choose_entering_edge...\n";); - unsigned num_edges = m_graph.get_num_edges(); - for (unsigned i = m_next_edge; i < m_next_edge + num_edges; ++i) { + int num_edges = m_graph.get_num_edges(); + for (int i = m_next_edge; i < m_next_edge + num_edges; ++i) { edge_id id = (i >= num_edges) ? (i - num_edges) : i; node src = m_graph.get_source(id); node tgt = m_graph.get_target(id); @@ -106,6 +106,10 @@ namespace smt { tout << "Found entering edge " << id << " between node "; tout << src << " and node " << tgt << " with reduced cost = " << cost << "...\n"; }); + m_next_edge = m_enter_id; + if (m_next_edge >= num_edges) { + m_next_edge -= num_edges; + } return true; } } diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index c5038222e..2b48dadac 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -295,6 +295,13 @@ namespace smt { } } + for (unsigned i = 0; i < num_edges; ++i) { + dl_var src = m_graph.get_source(i); + dl_var tgt = m_graph.get_target(i); + numeral weight = m_graph.get_weight(i); + SASSERT(m_potentials[src] - m_potentials[tgt] <= weight); + } + // m_flows are zero on non-basic edges for (unsigned i = 0; i < m_flows.size(); ++i) { SASSERT(m_states[i] == BASIS || m_flows[i].is_zero()); diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 45e2ffdfa..15fc6e19a 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -37,6 +37,7 @@ Revision History: #include"arith_simplifier_plugin.h" #include"arith_eq_solver.h" #include"theory_opt.h" +#include"uint_set.h" namespace smt { @@ -433,7 +434,7 @@ namespace smt { bool m_eager_gcd; // true if gcd should be applied at every add_row unsigned m_final_check_idx; - inf_eps_rational m_objective_value; + u_map m_objective_vars; // backtracking svector m_bound_trail; @@ -1008,6 +1009,7 @@ namespace smt { private: bool_var m_bound_watch; inf_eps_rational m_upper_bound; + bool get_theory_vars(expr * n, uint_set & vars); public: // ----------------------------------- // diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 430e29358..6948cc8a7 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -966,28 +966,78 @@ namespace smt { return x_i; } + template + bool theory_arith::get_theory_vars(expr * n, uint_set & vars) { + rational r; + expr* x, *y; + if (m_util.is_numeral(n, r)) { + return true; + } + else if (m_util.is_add(n)) { + for (unsigned i = 0; i < to_app(n)->get_num_args(); ++i) { + if (!get_theory_vars(to_app(n)->get_arg(i), vars)) { + return false; + } + } + } + else if (m_util.is_mul(n, x, y) && m_util.is_numeral(x, r)) { + return get_theory_vars(y, vars); + } + else if (m_util.is_mul(n, y, x) && m_util.is_numeral(x, r)) { + return get_theory_vars(y, vars); + } + else if (!is_app(n)) { + return false; + } + else if (to_app(n)->get_family_id() == m_util.get_family_id()) { + return false; + } + else { + context & ctx = get_context(); + SASSERT(ctx.e_internalized(n)); + enode * e = ctx.get_enode(n); + if (is_attached_to_var(e)) { + vars.insert(e->get_th_var(get_id())); + } + return true; + } + return true; + } + // // add_objective(expr* term) internalizes the arithmetic term and creates // a row for it if it is not already internalized. // Then return the variable corresponding to the term. // - template theory_var theory_arith::add_objective(app* term) { - return internalize_term_core(term); + theory_var v = internalize_term_core(term); + uint_set vars; + if (get_theory_vars(term, vars)) { + m_objective_vars.insert(v, vars); + } + return v; } template inf_eps_rational theory_arith::maximize(theory_var v) { bool r = max_min(v, true); - if (at_upper(v)) { - m_objective_value = get_value(v); + if (r || at_upper(v)) { + if (m_objective_vars.contains(v)) { + // FIXME: put this block inside verbose code + uint_set & vars = m_objective_vars[v]; + uint_set::iterator it = vars.begin(), end = vars.end(); + ast_manager& m = get_manager(); + IF_VERBOSE(1, + verbose_stream() << "Optimal assigment:" << std::endl; + for (; it != end; ++it) { + verbose_stream() << mk_pp(get_enode(*it)->get_owner(), m) << " |-> " << get_value(*it) << std::endl; + };); + } + return inf_eps_rational(get_value(v)); } - else if (!r) { - m_objective_value = inf_eps_rational::infinity(); - } - return m_objective_value; + return inf_eps_rational::infinity(); } /** @@ -1414,8 +1464,6 @@ namespace smt { TRACE("maximize", tout << "v" << v << " " << (max ? "max" : "min") << " value is: " << get_value(v) << "\n"; display_row(tout, m_tmp_row, true); display_row_info(tout, m_tmp_row);); - m_objective_value = get_value(v); - mk_bound_from_row(v, get_value(v), max ? B_UPPER : B_LOWER, m_tmp_row); return true; diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h index 7f85d854f..f6b704359 100644 --- a/src/smt/theory_diff_logic.h +++ b/src/smt/theory_diff_logic.h @@ -316,7 +316,9 @@ namespace smt { bool internalize_objective(expr * n, rational const& m, rational& r, objective_term & objective); - private: + private: + + virtual expr* block_objective(theory_var v, inf_rational const& val); virtual void new_eq_eh(theory_var v1, theory_var v2, justification& j); diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index d0cef90cf..e87c34b94 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -29,6 +29,7 @@ Revision History: #include"warning.h" #include"smt_model_generator.h" #include"network_flow_def.h" +#include"model_implicant.h" using namespace smt; @@ -1036,9 +1037,12 @@ inf_eps_rational theory_diff_logic::maximize(theory_var v) { vector & current_assigments = m_objective_assignments[v]; SASSERT(!current_assigments.empty()); - TRACE("network_flow", - for (unsigned i = 0; i < current_assigments.size(); ++i) { - tout << "v" << i << " -> " << current_assigments[i] << std::endl; + ast_manager& m = get_manager(); + IF_VERBOSE(1, + verbose_stream() << "Optimal assigment:" << std::endl; + for (unsigned i = 0; i < objective.size(); ++i) { + theory_var v = objective[i].first; + verbose_stream() << mk_pp(get_enode(v)->get_owner(), m) << " |-> " << current_assigments[v] << std::endl; }); rational r = objective_value.get_rational().to_rational(); rational i = objective_value.get_infinitesimal().to_rational(); @@ -1068,7 +1072,7 @@ theory_var theory_diff_logic::add_objective(app* term) { } template -expr* theory_diff_logic::block_lower_bound(theory_var v, inf_rational const& val) { +expr* theory_diff_logic::block_objective(theory_var v, inf_rational const& val) { ast_manager& m = get_manager(); objective_term const& t = m_objectives[v]; expr_ref e(m), f(m), f2(m); @@ -1135,6 +1139,19 @@ expr* theory_diff_logic::block_lower_bound(theory_var v, inf_rational const } } +template +expr* theory_diff_logic::block_lower_bound(theory_var v, inf_rational const& val) { + expr * o = block_objective(v, val); + context & ctx = get_context(); + model_ref mdl; + ctx.get_model(mdl); + ptr_vector formulas(ctx.get_num_asserted_formulas(), ctx.get_asserted_formulas()); + ast_manager& m = get_manager(); + model_implicant impl_extractor(m); + expr_ref_vector implicants = impl_extractor.minimize_literals(formulas, mdl); + return m.mk_and(o, m.mk_not(m.mk_and(implicants.size(), implicants.c_ptr()))); +} + template bool theory_diff_logic::internalize_objective(expr * n, rational const& m, rational& q, objective_term & objective) { From fff3a1aae5f117975da272fe7b5faec616db15ed Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Mon, 25 Nov 2013 00:30:15 +0100 Subject: [PATCH 162/925] Normalize diff logic's optimal assignments --- src/smt/network_flow_def.h | 5 +++-- src/smt/theory_diff_logic_def.h | 12 +++++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index 2b48dadac..b7e26f436 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -50,9 +50,10 @@ namespace smt { edge const & e = es[i]; tout << "(assert (<= (- v" << e.get_source() << " v" << e.get_target() << ") " << e.get_weight() << "))" << std::endl; }; - tout << "(maximize (+ "; + tout << "(assert (= v0 0))" << std::endl; + tout << "(maximize (+"; for (unsigned i = 0; i < balances.size(); ++i) { - tout << "(* " << balances[i] << " v" << i << ") "; + tout << " (* " << balances[i] << " v" << i << ")"; }; tout << "))" << std::endl; tout << "(optimize)" << std::endl; diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index e87c34b94..79dabbfca 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -1015,10 +1015,16 @@ inf_eps_rational theory_diff_logic::maximize(theory_var v) { // Objective coefficients now become balances vector balances(m_graph.get_num_nodes()); balances.fill(fin_numeral::zero()); + fin_numeral sum = fin_numeral::zero(); for (unsigned i = 0; i < objective.size(); ++i) { fin_numeral balance(objective[i].second); balances[objective[i].first] = balance; + sum += balance; } + // HACK: assume that v0 is always value 0 + if (balances[0].is_zero()) { + balances[0] = -sum; + } network_flow net_flow(m_graph, balances); bool is_optimal = net_flow.min_cost(); @@ -1034,9 +1040,13 @@ inf_eps_rational theory_diff_logic::maximize(theory_var v) { IF_VERBOSE(1, verbose_stream() << "Initial value of objective " << v << ": " << initial_value << std::endl;); // FIXME: Network Simplex lose precisions when handling infinitesimals SASSERT(objective_value >= initial_value.get_rational());); - vector & current_assigments = m_objective_assignments[v]; SASSERT(!current_assigments.empty()); + // Normalize optimal assignments so that v0 is fixed to 0 + for (unsigned i = 1; i < current_assigments.size(); ++i) { + current_assigments[i] -= current_assigments[0]; + } + ast_manager& m = get_manager(); IF_VERBOSE(1, verbose_stream() << "Optimal assigment:" << std::endl; From 8fe50ff2d91a87913a4515fc74fc18a38492baa1 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Mon, 25 Nov 2013 02:15:21 +0100 Subject: [PATCH 163/925] Display diff logic optimization and min cost flow in smt2 format --- src/smt/network_flow.h | 6 +- src/smt/network_flow_def.h | 109 +++++++++++++++++++++++++++---------- 2 files changed, 83 insertions(+), 32 deletions(-) diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index 3ba733174..ea4f32b19 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -279,13 +279,15 @@ namespace smt { void update_spanning_tree(); - std::string display_spanning_tree(); - bool edge_in_tree(edge_id id) const; bool check_well_formed(); bool check_optimal(); + void display(std::ofstream & os); + void display_dual(std::ofstream & os); + void display_spanning_tree(std::ofstream & os); + public: network_flow(graph & g, vector const & balances); diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index b7e26f436..65202d9a9 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -40,29 +40,80 @@ namespace smt { m_graph.add_edge(e.get_target(), e.get_source(), e.get_weight(), explanation()); } } - TRACE("network_flow", { - tout << "Solving different logic optimization problem:" << std::endl; - for (unsigned i = 0; i < m_graph.get_num_nodes(); ++i) { - tout << "(declare-fun v" << i << " () Real)" << std::endl; - } - vector const & es = m_graph.get_all_edges(); - for (unsigned i = 0; i < m_graph.get_num_edges(); ++i) { - edge const & e = es[i]; - tout << "(assert (<= (- v" << e.get_source() << " v" << e.get_target() << ") " << e.get_weight() << "))" << std::endl; - }; - tout << "(assert (= v0 0))" << std::endl; - tout << "(maximize (+"; - for (unsigned i = 0; i < balances.size(); ++i) { - tout << " (* " << balances[i] << " v" << i << ")"; - }; - tout << "))" << std::endl; - tout << "(optimize)" << std::endl; + TRACE("network_flow", { + tout << "Different logic optimization:" << std::endl; + display_dual(tout); + tout << "Minimum cost flow:" << std::endl; + display(tout); };); m_step = 0; m_tree = alloc(basic_spanning_tree, m_graph); } + template + void network_flow::display(std::ofstream & os) { + vector const & es = m_graph.get_all_edges(); + for (unsigned i = 0; i < m_graph.get_num_edges(); ++i) { + edge const & e = es[i]; + os << "(declare-fun y_" << e.get_source() << "_" << e.get_target() << " () Real)" << std::endl; + }; + + for (unsigned i = 0; i < m_graph.get_num_edges(); ++i) { + edge const & e = es[i]; + os << "(assert (>= y_" << e.get_source() << "_" << e.get_target() << " 0))" << std::endl; + }; + + for (unsigned i = 0; i < m_graph.get_num_nodes(); ++i) { + bool initialized = false; + for (unsigned j = 0; j < m_graph.get_num_edges(); ++j) { + edge const & e = es[j]; + if (e.get_target() == i || e.get_source() == i) { + if (!initialized) { + os << "(assert (= (+"; + } + initialized = true; + if (e.get_target() == i) { + os << " y_" << e.get_source() << "_" << e.get_target(); + } + else { + os << " (- y_" << e.get_source() << "_" << e.get_target() << ")"; + } + } + } + if(initialized) { + os << " " << m_balances[i] << ") 0))" << std::endl; + } + } + + os << "(minimize (+"; + for (unsigned i = 0; i < m_graph.get_num_edges(); ++i) { + edge const & e = es[i]; + os << " (* " << e.get_weight() << " y_" << e.get_source() << "_" << e.get_target() << ")"; + }; + os << "))" << std::endl; + os << "(optimize)" << std::endl; + } + + template + void network_flow::display_dual(std::ofstream & os) { + for (unsigned i = 0; i < m_graph.get_num_nodes(); ++i) { + os << "(declare-fun v" << i << " () Real)" << std::endl; + } + vector const & es = m_graph.get_all_edges(); + for (unsigned i = 0; i < m_graph.get_num_edges(); ++i) { + edge const & e = es[i]; + os << "(assert (<= (- v" << e.get_source() << " v" << e.get_target() << ") " << e.get_weight() << "))" << std::endl; + }; + os << "(assert (= v0 0))" << std::endl; + os << "(maximize (+"; + for (unsigned i = 0; i < m_balances.size(); ++i) { + os << " (* " << m_balances[i] << " v" << i << ")"; + }; + os << "))" << std::endl; + os << "(optimize)" << std::endl; + } + template void network_flow::initialize() { TRACE("network_flow", tout << "initialize...\n";); @@ -106,7 +157,7 @@ namespace smt { TRACE("network_flow", { tout << pp_vector("Potentials", m_potentials, true) << pp_vector("Flows", m_flows); }); - TRACE("network_flow", tout << "Spanning tree:\n" << display_spanning_tree();); + TRACE("network_flow", tout << "Spanning tree:\n"; display_spanning_tree(tout);); SASSERT(check_well_formed()); } @@ -227,7 +278,7 @@ namespace smt { m_states[m_leave_id] = LOWER; update_spanning_tree(); update_potentials(); - TRACE("network_flow", tout << "Spanning tree:\n" << display_spanning_tree();); + TRACE("network_flow", tout << "Spanning tree:\n"; display_spanning_tree(tout);); SASSERT(check_well_formed()); } } @@ -316,32 +367,30 @@ namespace smt { } template - std::string network_flow::display_spanning_tree() { + void network_flow::display_spanning_tree(std::ofstream & os) { ++m_step;; - std::ostringstream oss; std::string prefix = "T"; prefix.append(std::to_string(m_step)); prefix.append("_"); unsigned root = m_graph.get_num_nodes() - 1; for (unsigned i = 0; i < root; ++i) { - oss << prefix << i << "[shape=circle,label=\"" << prefix << i << " ["; - oss << m_potentials[i] << "/" << m_balances[i] << "]\"];\n"; + os << prefix << i << "[shape=circle,label=\"" << prefix << i << " ["; + os << m_potentials[i] << "/" << m_balances[i] << "]\"];\n"; } - oss << prefix << root << "[shape=doublecircle,label=\"" << prefix << root << " ["; - oss << m_potentials[root] << "/" << m_balances[root] << "]\"];\n"; + os << prefix << root << "[shape=doublecircle,label=\"" << prefix << root << " ["; + os << m_potentials[root] << "/" << m_balances[root] << "]\"];\n"; unsigned num_edges = m_graph.get_num_edges(); for (unsigned i = 0; i < num_edges; ++i) { - oss << prefix << m_graph.get_source(i) << " -> " << prefix << m_graph.get_target(i); + os << prefix << m_graph.get_source(i) << " -> " << prefix << m_graph.get_target(i); if (m_states[i] == BASIS) { - oss << "[color=red,penwidth=3.0,label=\"" << m_flows[i] << "/" << m_graph.get_weight(i) << "\"];\n"; + os << "[color=red,penwidth=3.0,label=\"" << m_flows[i] << "/" << m_graph.get_weight(i) << "\"];\n"; } else { - oss << "[label=\"" << m_flows[i] << "/" << m_graph.get_weight(i) << "\"];\n"; + os << "[label=\"" << m_flows[i] << "/" << m_graph.get_weight(i) << "\"];\n"; } } - oss << std::endl; - return oss.str(); + os << std::endl; } } From 87a2b990912209da39687d88337cc2a0e6bf8f30 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Mon, 25 Nov 2013 12:16:34 -0800 Subject: [PATCH 164/925] Clean up --- src/model/model_implicant.h | 2 +- src/opt/opt_solver.cpp | 2 -- src/smt/network_flow.h | 14 +++++++++++++- src/smt/network_flow_def.h | 21 +++++++++++++++++---- src/smt/theory_arith.h | 2 +- src/smt/theory_arith_aux.h | 6 +++--- src/smt/theory_arith_core.h | 1 + src/smt/theory_diff_logic_def.h | 4 ++-- 8 files changed, 38 insertions(+), 14 deletions(-) diff --git a/src/model/model_implicant.h b/src/model/model_implicant.h index 55b466ca3..21c91b3cb 100644 --- a/src/model/model_implicant.h +++ b/src/model/model_implicant.h @@ -98,7 +98,7 @@ public: expr_ref_vector minimize_model(ptr_vector const & formulas, model_ref& mdl); /** - \brief extract literals from formulas that satisfy formulas. + \brief extract literals from model that satisfy formulas. \pre model satisfies formulas */ diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 754c32d31..b6a39a949 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -104,8 +104,6 @@ namespace opt { } } - static unsigned g_checksat_count = 0; - bool opt_solver::dump_benchmarks() { return m_dump_benchmarks; } diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index ea4f32b19..db477bc50 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -34,6 +34,17 @@ Notes: namespace smt { + enum min_flow_result { + // Min cost flow problem is infeasible. + // Diff logic optimization could be unbounded or infeasible. + INFEASIBLE, + // Min cost flow and diff logic optimization are both optimal. + OPTIMAL, + // Min cost flow problem is unbounded. + // Diff logic optimization has to be infeasible. + UNBOUNDED, + }; + enum pivot_rule { // First eligible edge pivot rule // Edges are traversed in a wraparound fashion @@ -281,6 +292,7 @@ namespace smt { bool edge_in_tree(edge_id id) const; + bool is_infeasible(); bool check_well_formed(); bool check_optimal(); @@ -294,7 +306,7 @@ namespace smt { // Minimize cost flows // Return true if found an optimal solution, and return false if unbounded - bool min_cost(pivot_rule pr = FIRST_ELIGIBLE); + min_flow_result min_cost(pivot_rule pr = FIRST_ELIGIBLE); // Compute the optimal solution numeral get_optimal_solution(vector & result, bool is_dual); diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index 65202d9a9..1c0e837e3 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -263,13 +263,12 @@ namespace smt { } // Minimize cost flows - // Return true if found an optimal solution, and return false if unbounded template - bool network_flow::min_cost(pivot_rule pr) { + min_flow_result network_flow::min_cost(pivot_rule pr) { initialize(); while (choose_entering_edge(pr)) { bool bounded = choose_leaving_edge(); - if (!bounded) return false; + if (!bounded) return UNBOUNDED; update_flows(); if (m_enter_id != m_leave_id) { SASSERT(edge_in_tree(m_leave_id)); @@ -282,9 +281,23 @@ namespace smt { SASSERT(check_well_formed()); } } + if (is_infeasible()) return INFEASIBLE; TRACE("network_flow", tout << "Found optimal solution.\n";); SASSERT(check_optimal()); - return true; + return OPTIMAL; + } + + template + bool network_flow::is_infeasible() { +#if 0 + // Flows of artificial arcs should be zero + unsigned num_nodes = m_graph.get_num_nodes(); + unsigned num_edges = m_graph.get_num_edges(); + for (unsigned i = 1; i < num_nodes; ++i) { + if (m_flows[num_edges - i].is_pos()) return true; + } +#endif + return false; } // Get the optimal solution diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 15fc6e19a..7979ffc6e 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -434,7 +434,7 @@ namespace smt { bool m_eager_gcd; // true if gcd should be applied at every add_row unsigned m_final_check_idx; - u_map m_objective_vars; + u_map m_objective_theory_vars; // backtracking svector m_bound_trail; diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 6948cc8a7..90a6db250 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -1015,7 +1015,7 @@ namespace smt { theory_var v = internalize_term_core(term); uint_set vars; if (get_theory_vars(term, vars)) { - m_objective_vars.insert(v, vars); + m_objective_theory_vars.insert(v, vars); } return v; } @@ -1024,9 +1024,9 @@ namespace smt { inf_eps_rational theory_arith::maximize(theory_var v) { bool r = max_min(v, true); if (r || at_upper(v)) { - if (m_objective_vars.contains(v)) { + if (m_objective_theory_vars.contains(v)) { // FIXME: put this block inside verbose code - uint_set & vars = m_objective_vars[v]; + uint_set & vars = m_objective_theory_vars[v]; uint_set::iterator it = vars.begin(), end = vars.end(); ast_manager& m = get_manager(); IF_VERBOSE(1, diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 68900cb50..c6d86bdf8 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -1226,6 +1226,7 @@ namespace smt { m_nl_rounds = 0; m_nl_gb_exhausted = false; m_nl_strategy_idx = 0; + m_objective_theory_vars .reset(); theory::reset_eh(); } diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index 79dabbfca..a3f1930c1 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -1027,8 +1027,8 @@ inf_eps_rational theory_diff_logic::maximize(theory_var v) { } network_flow net_flow(m_graph, balances); - bool is_optimal = net_flow.min_cost(); - if (is_optimal) { + min_flow_result result = net_flow.min_cost(); + if (result == OPTIMAL) { numeral objective_value = net_flow.get_optimal_solution(m_objective_assignments[v], true) + numeral(m_objective_consts[v]); IF_VERBOSE(1, verbose_stream() << "Optimal value of objective " << v << ": " << objective_value << std::endl;); From dbc791d385d41e93e66e51dad5dd4991c64a22a0 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Tue, 26 Nov 2013 09:20:11 +0100 Subject: [PATCH 165/925] Reorganize combination of objectives --- src/opt/objective_ast.cpp | 54 ++++++++++++++++ src/opt/objective_ast.h | 30 ++++++--- src/opt/opt_context.cpp | 126 +++++++++++++++++++++++++------------- src/opt/opt_context.h | 16 +++-- src/opt/opt_solver.cpp | 2 +- 5 files changed, 172 insertions(+), 56 deletions(-) create mode 100644 src/opt/objective_ast.cpp diff --git a/src/opt/objective_ast.cpp b/src/opt/objective_ast.cpp new file mode 100644 index 000000000..79d2516d6 --- /dev/null +++ b/src/opt/objective_ast.cpp @@ -0,0 +1,54 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + objective_ast.h + +Abstract: + Abstract data-type for compound objectives. + +Author: + + Anh-Dung Phan (t-anphan) 2013-11-26 + +Notes: + +--*/ + +#include"objective_ast.h" + +namespace opt { + + objective* objective::mk_max(expr_ref& e) { return alloc(min_max_objective, MAXIMIZE, e); }; + objective* objective::mk_min(expr_ref& e) { return alloc(min_max_objective, MINIMIZE, e); }; + objective* objective::mk_maxsat(symbol id) { return alloc(maxsat_objective, id); }; + + objective* objective::mk_lex(unsigned sz, objective * const* children) { + return alloc(compound_objective, LEX, sz, children); + }; + + objective* objective::mk_box(unsigned sz, objective * const* children) { + return alloc(compound_objective, BOX, sz, children); + }; + + objective* objective::mk_pareto(unsigned sz, objective * const* children) { + return alloc(compound_objective, PARETO, sz, children); + }; + + compound_objective& objective::get_compound() { + SASSERT(m_type == LEX || m_type == BOX || m_type == PARETO); + return dynamic_cast(*this); + } + + min_max_objective& objective::get_min_max() { + SASSERT(m_type == MAXIMIZE || m_type == MINIMIZE); + return dynamic_cast(*this); + } + + maxsat_objective& objective::get_maxsat() { + SASSERT(m_type == MAXSAT); + return dynamic_cast(*this); + } + +}; diff --git a/src/opt/objective_ast.h b/src/opt/objective_ast.h index b1005b40d..31a2bf543 100644 --- a/src/opt/objective_ast.h +++ b/src/opt/objective_ast.h @@ -18,6 +18,8 @@ Notes: #ifndef __OBJECTIVE_AST_H_ #define __OBJECTIVE_AST_H_ +#include"ast.h" + namespace opt { enum objective_t { @@ -46,35 +48,45 @@ namespace opt { // constructors; static objective* mk_max(expr_ref& e); static objective* mk_min(expr_ref& e); + static objective* mk_maxsat(symbol id); + static objective* mk_lex(unsigned sz, objective * const* children); static objective* mk_box(unsigned sz, objective * const* children); static objective* mk_pareto(unsigned sz, objective * const* children); - static objective* mk_maxsat(symbol id); // accessors (implicit cast operations) - compound_objective& get_compound(); // eg. SASSERT(m_type == LEX/BOX/PARETO); return dynamic_cast(*this); - min_max_objective& get_min_max(); - maxsat_objective& get_maxsat(); + compound_objective& get_compound(); + min_max_objective& get_min_max(); + maxsat_objective& get_maxsat(); }; class compound_objective : public objective { ptr_vector m_children; public: - compound_objective(objective_t t): objective(t) {} + compound_objective(objective_t t, unsigned sz, objective * const* children): + objective(t), + m_children(sz, children) {} + virtual ~compound_objective() { - // dealloc vector m_children; + ptr_vector::iterator it = m_children.begin(), end = m_children.end(); + for (; it != end; ++it) { + dealloc(*it); + } } objective *const* children() const { return m_children.c_ptr(); } unsigned num_children() const { return m_children.size(); } - } + }; class min_max_objective : public objective { bool m_is_max; expr_ref m_expr; public: - min_max_objective(bool is_max, expr_ref& e): m_is_max(is_max), m_expr(e) {} + min_max_objective(bool is_max, expr_ref& e): + objective(is_max ? MAXIMIZE : MINIMIZE), + m_is_max(is_max), + m_expr(e) {} virtual ~min_max_objective() {} @@ -85,7 +97,7 @@ namespace opt { class maxsat_objective : public objective { symbol m_id; public: - maxsat_objective(symbol const& id): m_id(id) {} + maxsat_objective(symbol const& id): objective(MAXSAT), m_id(id) {} virtual ~maxsat_objective() {} symbol const& get_id() const { return m_id; } diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 6afc7779e..17d829ab9 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -27,7 +27,8 @@ namespace opt { context::context(ast_manager& m): m(m), m_hard_constraints(m), - m_optsmt(m) + m_optsmt(m), + m_objs(m) { m_params.set_bool("model", true); m_params.set_bool("unsat_core", true); @@ -50,57 +51,98 @@ namespace opt { ms->add(f, w); } - lbool context::optimize() { - if (m_params.get_bool("pareto", false)) { - return optimize_pareto(); - } - else { - return optimize_box(); + lbool context::execute(objective & obj, bool committed) { + switch (obj.type()) { + case MINIMIZE: + case MAXIMIZE: + return execute_min_max(obj.get_min_max(), committed); + case MAXSAT: + return execute_maxsat(obj.get_maxsat(), committed); + case LEX: + return execute_lex(obj.get_compound()); + case BOX: + return execute_box(obj.get_compound()); + case PARETO: + return execute_pareto(obj.get_compound()); + default: + UNREACHABLE(); + return l_undef; } } - lbool context::optimize_box() { + lbool context::execute_min_max(min_max_objective & obj, bool committed) { + // HACK: reuse m_optsmt but add only a single objective each round + m_optsmt.add(to_app(obj.term()), obj.is_max()); + opt_solver& s = *m_solver.get(); + lbool result = m_optsmt(s); + if (committed) m_optsmt.commit_assignment(0); + return result; + } + + lbool context::execute_maxsat(maxsat_objective & obj, bool committed) { + maxsmt* ms; + SASSERT(m_maxsmts.find(obj.get_id(), ms)); + opt_solver& s = *m_solver.get(); + lbool result = (*ms)(s); + if (committed) ms->commit_assignment(); + return result; + } + + lbool context::execute_lex(compound_objective & obj) { + ptr_vector children(obj.num_children(), obj.children()); + for (unsigned i = 0; i < children.size(); ++i) { + lbool result = execute(*children[i], true); + if (result != l_true) return result; + } + return l_true; + } + + lbool context::execute_box(compound_objective & obj) { + ptr_vector children(obj.num_children(), obj.children()); + for (unsigned i = 0; i < children.size(); ++i) { + lbool result = execute(*children[i], false); + if (result != l_true) return result; + } + return l_true; + } + + lbool context::execute_pareto(compound_objective & obj) { + // TODO: record a stream of results from pareto front + return execute_lex(obj); + } + + lbool context::optimize() { + // Construct objectives + ptr_vector objectives; + map_t::iterator it = m_maxsmts.begin(), end = m_maxsmts.end(); + for (; it != end; ++it) { + objectives.push_back(objective::mk_maxsat(it->m_key)); + } + + for (unsigned i = 0; i < m_objs.size(); ++i) { + expr_ref e(m_objs[i].get(), m); + objective * o = m_ismaxs[i] ? objective::mk_max(e) : objective::mk_min(e); + objectives.push_back(o); + } + + objective * objective; + if (m_params.get_bool("pareto", false)) { + objective = objective::mk_pareto(objectives.size(), objectives.c_ptr()); + } + else { + objective = objective::mk_box(objectives.size(), objectives.c_ptr()); + } + opt_solver& s = *m_solver.get(); solver::scoped_push _sp(s); for (unsigned i = 0; i < m_hard_constraints.size(); ++i) { s.assert_expr(m_hard_constraints[i].get()); } - - lbool is_sat = l_true; - map_t::iterator it = m_maxsmts.begin(), end = m_maxsmts.end(); - for (; is_sat == l_true && it != end; ++it) { - maxsmt& ms = *it->m_value; - is_sat = ms(s); - } - if (is_sat == l_true) { - is_sat = m_optsmt(s); - } - return is_sat; - } - // finds a random pareto front. - // enumerating more is TBD, e.g., - lbool context::optimize_pareto() { - opt_solver& s = *m_solver.get(); - opt_solver::scoped_push _sp(s); - - for (unsigned i = 0; i < m_hard_constraints.size(); ++i) { - s.assert_expr(m_hard_constraints[i].get()); - } - - lbool is_sat = l_true; - map_t::iterator it = m_maxsmts.begin(), end = m_maxsmts.end(); - for (; is_sat == l_true && it != end; ++it) { - maxsmt* ms = it->m_value; - is_sat = (*ms)(s); - ms->commit_assignment(); - } - for (unsigned i = 0; is_sat == l_true && i < m_optsmt.get_num_objectives(); ++i) { - is_sat = m_optsmt(s); - m_optsmt.commit_assignment(i); - } - return is_sat; + lbool result = execute(*objective, false); + dealloc(objective); + return result; } void context::display_assignment(std::ostream& out) { diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 081bf7c1d..14ef2df0b 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -29,6 +29,7 @@ Notes: #include "opt_solver.h" #include "optsmt.h" #include "maxsmt.h" +#include "objective_ast.h" namespace opt { @@ -42,12 +43,22 @@ namespace opt { params_ref m_params; optsmt m_optsmt; map_t m_maxsmts; + expr_ref_vector m_objs; + svector m_ismaxs; public: context(ast_manager& m); ~context(); void add_soft_constraint(expr* f, rational const& w, symbol const& id); - void add_objective(app* t, bool is_max) { m_optsmt.add(t, is_max); } + void add_objective(app* t, bool is_max) { m_objs.push_back(t); m_ismaxs.push_back(is_max); } void add_hard_constraint(expr* f) { m_hard_constraints.push_back(f); } + + lbool execute(objective & obj, bool committed); + lbool execute_min_max(min_max_objective & obj, bool committed); + lbool execute_maxsat(maxsat_objective & obj, bool committed); + lbool execute_lex(compound_objective & obj); + lbool execute_box(compound_objective & obj); + lbool execute_pareto(compound_objective & obj); + lbool optimize(); void set_cancel(bool f); void reset_cancel() { set_cancel(false); } @@ -58,9 +69,6 @@ namespace opt { static void collect_param_descrs(param_descrs & r); void updt_params(params_ref& p); private: - lbool optimize_pareto(); - lbool optimize_box(); - void validate_feasibility(maxsmt& ms); }; diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index b6a39a949..091adb9b0 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -56,7 +56,7 @@ namespace opt { } void opt_solver::collect_statistics(statistics & st) const { - // Hack to display fu_malik statistics + // HACK: display fu_malik statistics if (m_stats.size() > 0) { st.copy(m_stats); } From 4aa9c742abc10de93612efab2c43b6144390320d Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Tue, 26 Nov 2013 12:54:18 -0800 Subject: [PATCH 166/925] Revise optimize commands --- src/opt/opt_cmds.cpp | 159 +++++++++++++++++++++++++++++++++++++++- src/opt/opt_context.cpp | 20 +++-- src/opt/opt_context.h | 2 + 3 files changed, 169 insertions(+), 12 deletions(-) diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index 35652918b..803d38295 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -29,7 +29,7 @@ Notes: #include "scoped_ctrl_c.h" #include "scoped_timer.h" #include "parametric_cmd.h" - +#include "objective_ast.h" class opt_context { cmd_context& ctx; @@ -248,10 +248,161 @@ private: } }; +static expr* sexpr2expr(cmd_context & ctx, sexpr * s) { + NOT_IMPLEMENTED_YET(); + return 0; +} + +static opt::objective* sexpr2objective(cmd_context & ctx, sexpr * s) { + if (s->is_symbol()) + throw cmd_exception("invalid objective, more arguments expected ", s->get_symbol(), s->get_line(), s->get_pos()); + if (s->is_composite()) { + sexpr * head = s->get_child(0); + if (!head->is_symbol()) + throw cmd_exception("invalid objective, symbol expected", s->get_line(), s->get_pos()); + symbol const & cmd_name = head->get_symbol(); + if (cmd_name == "maximize" || cmd_name == "minimize") { + if (s->get_num_children() != 2) + throw cmd_exception("invalid objective, wrong number of arguments ", s->get_line(), s->get_pos()); + sexpr * arg = s->get_child(1); + expr_ref term(sexpr2expr(ctx, arg), ctx.m()); + if (cmd_name == "maximize") + return opt::objective::mk_max(term); + else + return opt::objective::mk_min(term); + } + else if (cmd_name == "maxsat") { + if (s->get_num_children() != 2) + throw cmd_exception("invalid objective, wrong number of arguments ", s->get_line(), s->get_pos()); + sexpr * arg = s->get_child(1); + if (!arg->is_symbol()) + throw cmd_exception("invalid objective, symbol expected", s->get_line(), s->get_pos()); + symbol const & id = arg->get_symbol(); + // TODO: check whether id is declared via assert-weighted + return opt::objective::mk_maxsat(id); + } + else if (cmd_name == "lex" || cmd_name == "box" || cmd_name == "pareto") { + if (s->get_num_children() <= 2) + throw cmd_exception("invalid objective, wrong number of arguments ", s->get_line(), s->get_pos()); + unsigned num_children = s->get_num_children(); + ptr_vector args; + for (unsigned i = 1; i < num_children; i++) + args.push_back(sexpr2objective(ctx, s->get_child(i))); + if (cmd_name == "lex") + return opt::objective::mk_lex(args.size(), args.c_ptr()); + else if (cmd_name == "box") + return opt::objective::mk_box(args.size(), args.c_ptr()); + else + return opt::objective::mk_pareto(args.size(), args.c_ptr()); + } + else { + throw cmd_exception("invalid objective, unexpected input", s->get_line(), s->get_pos()); + } + } + return 0; +} + +class execute_cmd : public parametric_cmd { +protected: + sexpr * m_objective; + opt_context& m_opt_ctx; +public: + execute_cmd(opt_context& opt_ctx): + parametric_cmd("optimize"), + m_opt_ctx(opt_ctx) + {} + + virtual void init_pdescrs(cmd_context & ctx, param_descrs & p) { + insert_timeout(p); + insert_max_memory(p); + p.insert("print_statistics", CPK_BOOL, "(default: false) print statistics."); + opt::context::collect_param_descrs(p); + } + + virtual char const * get_main_descr() const { return "check sat modulo objective function";} + virtual char const * get_usage() const { return "( )*"; } + virtual void prepare(cmd_context & ctx) { + parametric_cmd::prepare(ctx); + m_objective = 0; + } + virtual void failure_cleanup(cmd_context & ctx) { + reset(ctx); + } + + virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { + if (m_objective == 0) return CPK_SEXPR; + return parametric_cmd::next_arg_kind(ctx); + } + + virtual void set_next_arg(cmd_context & ctx, sexpr * arg) { + m_objective = arg; + } + + virtual void execute(cmd_context & ctx) { + params_ref p = ctx.params().merge_default_params(ps()); + opt::context& opt = m_opt_ctx(); + opt.updt_params(p); + unsigned timeout = p.get_uint("timeout", UINT_MAX); + + ptr_vector::const_iterator it = ctx.begin_assertions(); + ptr_vector::const_iterator end = ctx.end_assertions(); + for (; it != end; ++it) { + opt.add_hard_constraint(*it); + } + lbool r = l_undef; + cancel_eh eh(opt); + { + scoped_ctrl_c ctrlc(eh); + scoped_timer timer(timeout, &eh); + cmd_context::scoped_watch sw(ctx); + try { + opt::objective * o = sexpr2objective(ctx, m_objective); + r = opt.optimize(*o); + dealloc(o); + } + catch (z3_error& ex) { + ctx.regular_stream() << "(error: " << ex.msg() << "\")" << std::endl; + } + catch (z3_exception& ex) { + ctx.regular_stream() << "(error: " << ex.msg() << "\")" << std::endl; + } + } + switch(r) { + case l_true: + ctx.regular_stream() << "sat\n"; + opt.display_assignment(ctx.regular_stream()); + break; + case l_false: + ctx.regular_stream() << "unsat\n"; + break; + case l_undef: + ctx.regular_stream() << "unknown\n"; + opt.display_range_assignment(ctx.regular_stream()); + break; + } + if (p.get_bool("print_statistics", false)) { + display_statistics(ctx); + } + } +private: + + void display_statistics(cmd_context& ctx) { + statistics stats; + unsigned long long max_mem = memory::get_max_used_memory(); + unsigned long long mem = memory::get_allocation_size(); + stats.update("time", ctx.get_seconds()); + stats.update("memory", static_cast(mem)/static_cast(1024*1024)); + stats.update("max memory", static_cast(max_mem)/static_cast(1024*1024)); + m_opt_ctx().collect_statistics(stats); + stats.display_smt2(ctx.regular_stream()); + } +}; + void install_opt_cmds(cmd_context & ctx) { opt_context* opt_ctx = alloc(opt_context, ctx); ctx.insert(alloc(assert_weighted_cmd, ctx, *opt_ctx)); - ctx.insert(alloc(min_maximize_cmd, ctx, *opt_ctx, true)); - ctx.insert(alloc(min_maximize_cmd, ctx, *opt_ctx, false)); - ctx.insert(alloc(optimize_cmd, *opt_ctx)); + ctx.insert(alloc(execute_cmd, *opt_ctx)); + //ctx.insert(alloc(min_maximize_cmd, ctx, *opt_ctx, true)); + //ctx.insert(alloc(min_maximize_cmd, ctx, *opt_ctx, false)); + //ctx.insert(alloc(optimize_cmd, *opt_ctx)); } diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 17d829ab9..13680c16a 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -111,6 +111,17 @@ namespace opt { return execute_lex(obj); } + lbool context::optimize(objective & objective) { + opt_solver& s = *m_solver.get(); + solver::scoped_push _sp(s); + + for (unsigned i = 0; i < m_hard_constraints.size(); ++i) { + s.assert_expr(m_hard_constraints[i].get()); + } + + return execute(objective, false); + } + lbool context::optimize() { // Construct objectives ptr_vector objectives; @@ -133,14 +144,7 @@ namespace opt { objective = objective::mk_box(objectives.size(), objectives.c_ptr()); } - opt_solver& s = *m_solver.get(); - solver::scoped_push _sp(s); - - for (unsigned i = 0; i < m_hard_constraints.size(); ++i) { - s.assert_expr(m_hard_constraints[i].get()); - } - - lbool result = execute(*objective, false); + lbool result = optimize(*objective); dealloc(objective); return result; } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 14ef2df0b..68cf61d80 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -59,7 +59,9 @@ namespace opt { lbool execute_box(compound_objective & obj); lbool execute_pareto(compound_objective & obj); + lbool optimize(objective & objective); lbool optimize(); + void set_cancel(bool f); void reset_cancel() { set_cancel(false); } void cancel() { set_cancel(true); } From 5ed8a48ac2ca8815edaf0926b511772307bc310f Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Tue, 26 Nov 2013 14:16:59 -0800 Subject: [PATCH 167/925] Add push/pop to box optimization --- src/opt/opt_cmds.cpp | 4 ++-- src/opt/opt_context.cpp | 28 +++++++++++++++++++++------- src/opt/opt_context.h | 3 +++ src/smt/theory_diff_logic_def.h | 3 +++ 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index 803d38295..6bf45daee 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -249,8 +249,8 @@ private: }; static expr* sexpr2expr(cmd_context & ctx, sexpr * s) { - NOT_IMPLEMENTED_YET(); - return 0; + NOT_IMPLEMENTED_YET(); + return ctx.m().mk_true(); } static opt::objective* sexpr2objective(cmd_context & ctx, sexpr * s) { diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 13680c16a..198ed918b 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -90,20 +90,24 @@ namespace opt { lbool context::execute_lex(compound_objective & obj) { ptr_vector children(obj.num_children(), obj.children()); + lbool result = l_true; for (unsigned i = 0; i < children.size(); ++i) { - lbool result = execute(*children[i], true); - if (result != l_true) return result; + result = execute(*children[i], true); + if (result != l_true) break; } - return l_true; - } + return result; + } lbool context::execute_box(compound_objective & obj) { ptr_vector children(obj.num_children(), obj.children()); + lbool result = l_true; for (unsigned i = 0; i < children.size(); ++i) { - lbool result = execute(*children[i], false); - if (result != l_true) return result; + push(); + result = execute(*children[i], false); + pop(1); + if (result != l_true) break; } - return l_true; + return result; } lbool context::execute_pareto(compound_objective & obj) { @@ -111,6 +115,16 @@ namespace opt { return execute_lex(obj); } + void context::push() { + opt_solver& s = *m_solver.get(); + s.push(); + } + + void context::pop(unsigned sz) { + opt_solver& s = *m_solver.get(); + s.pop(sz); + } + lbool context::optimize(objective & objective) { opt_solver& s = *m_solver.get(); solver::scoped_push _sp(s); diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 68cf61d80..f70440de6 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -59,6 +59,9 @@ namespace opt { lbool execute_box(compound_objective & obj); lbool execute_pareto(compound_objective & obj); + void push(); + void pop(unsigned sz); + lbool optimize(objective & objective); lbool optimize(); diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index a3f1930c1..7472edd8b 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -1028,6 +1028,7 @@ inf_eps_rational theory_diff_logic::maximize(theory_var v) { network_flow net_flow(m_graph, balances); min_flow_result result = net_flow.min_cost(); + SASSERT(result != UNBOUNDED); if (result == OPTIMAL) { numeral objective_value = net_flow.get_optimal_solution(m_objective_assignments[v], true) + numeral(m_objective_consts[v]); IF_VERBOSE(1, verbose_stream() << "Optimal value of objective " << v << ": " << objective_value << std::endl;); @@ -1059,6 +1060,8 @@ inf_eps_rational theory_diff_logic::maximize(theory_var v) { return inf_eps_rational(inf_rational(r, i)); } else { + // Dual problem is infeasible, primal problem is unbounded + SASSERT(result == INFEASIBLE); IF_VERBOSE(1, verbose_stream() << "Unbounded objective" << std::endl;); return inf_eps_rational::infinity(); } From a016caa5d87a9584648fcfca3a2b60de90b0b355 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 2 Dec 2013 09:47:59 -0800 Subject: [PATCH 168/925] add expression conversion Signed-off-by: Nikolaj Bjorner --- src/opt/opt_cmds.cpp | 147 +++++++++++++++++++++++++++---------------- src/smt/theory_pb.h | 3 +- 2 files changed, 94 insertions(+), 56 deletions(-) diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index 6bf45daee..140afbd56 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -248,59 +248,6 @@ private: } }; -static expr* sexpr2expr(cmd_context & ctx, sexpr * s) { - NOT_IMPLEMENTED_YET(); - return ctx.m().mk_true(); -} - -static opt::objective* sexpr2objective(cmd_context & ctx, sexpr * s) { - if (s->is_symbol()) - throw cmd_exception("invalid objective, more arguments expected ", s->get_symbol(), s->get_line(), s->get_pos()); - if (s->is_composite()) { - sexpr * head = s->get_child(0); - if (!head->is_symbol()) - throw cmd_exception("invalid objective, symbol expected", s->get_line(), s->get_pos()); - symbol const & cmd_name = head->get_symbol(); - if (cmd_name == "maximize" || cmd_name == "minimize") { - if (s->get_num_children() != 2) - throw cmd_exception("invalid objective, wrong number of arguments ", s->get_line(), s->get_pos()); - sexpr * arg = s->get_child(1); - expr_ref term(sexpr2expr(ctx, arg), ctx.m()); - if (cmd_name == "maximize") - return opt::objective::mk_max(term); - else - return opt::objective::mk_min(term); - } - else if (cmd_name == "maxsat") { - if (s->get_num_children() != 2) - throw cmd_exception("invalid objective, wrong number of arguments ", s->get_line(), s->get_pos()); - sexpr * arg = s->get_child(1); - if (!arg->is_symbol()) - throw cmd_exception("invalid objective, symbol expected", s->get_line(), s->get_pos()); - symbol const & id = arg->get_symbol(); - // TODO: check whether id is declared via assert-weighted - return opt::objective::mk_maxsat(id); - } - else if (cmd_name == "lex" || cmd_name == "box" || cmd_name == "pareto") { - if (s->get_num_children() <= 2) - throw cmd_exception("invalid objective, wrong number of arguments ", s->get_line(), s->get_pos()); - unsigned num_children = s->get_num_children(); - ptr_vector args; - for (unsigned i = 1; i < num_children; i++) - args.push_back(sexpr2objective(ctx, s->get_child(i))); - if (cmd_name == "lex") - return opt::objective::mk_lex(args.size(), args.c_ptr()); - else if (cmd_name == "box") - return opt::objective::mk_box(args.size(), args.c_ptr()); - else - return opt::objective::mk_pareto(args.size(), args.c_ptr()); - } - else { - throw cmd_exception("invalid objective, unexpected input", s->get_line(), s->get_pos()); - } - } - return 0; -} class execute_cmd : public parametric_cmd { protected: @@ -356,7 +303,7 @@ public: scoped_timer timer(timeout, &eh); cmd_context::scoped_watch sw(ctx); try { - opt::objective * o = sexpr2objective(ctx, m_objective); + opt::objective * o = sexpr2objective(ctx, *m_objective); r = opt.optimize(*o); dealloc(o); } @@ -396,6 +343,98 @@ private: m_opt_ctx().collect_statistics(stats); stats.display_smt2(ctx.regular_stream()); } + + expr_ref sexpr2expr(cmd_context & ctx, sexpr& s) { + expr_ref result(ctx.m()); + switch(s.get_kind()) { + case sexpr::COMPOSITE: { + sexpr& h = *s.get_child(0); + if (!h.is_symbol()) { + throw cmd_exception("invalid head symbol", s.get_line(), s.get_pos()); + } + symbol sym = h.get_symbol(); + expr_ref_vector args(ctx.m()); + for (unsigned i = 1; i < s.get_num_children(); ++i) { + args.push_back(sexpr2expr(ctx, *s.get_child(i))); + } + ctx.mk_app(sym, args.size(), args.c_ptr(), 0, 0, 0, result); + return result; + } + case sexpr::NUMERAL: + case sexpr::BV_NUMERAL: + // TBD: handle numerals + case sexpr::STRING: + case sexpr::KEYWORD: + throw cmd_exception("non-supported expression", s.get_line(), s.get_pos()); + case sexpr::SYMBOL: + ctx.mk_const(s.get_symbol(), result); + return result; + } + } + + opt::objective_t get_objective_type(sexpr& s) { + if (!s.is_symbol()) + throw cmd_exception("invalid objective, symbol expected", s.get_line(), s.get_pos()); + symbol const & sym = s.get_symbol(); + if (sym == symbol("maximize")) return opt::objective_t::MAXIMIZE; + if (sym == symbol("minimize")) return opt::objective_t::MINIMIZE; + if (sym == symbol("lex")) return opt::objective_t::LEX; + if (sym == symbol("box")) return opt::objective_t::BOX; + if (sym == symbol("pareto")) return opt::objective_t::PARETO; + throw cmd_exception("invalid objective, unexpected input", s.get_line(), s.get_pos()); + } + + opt::objective* sexpr2objective(cmd_context & ctx, sexpr& s) { + if (s.is_symbol()) + throw cmd_exception("invalid objective, more arguments expected ", s.get_symbol(), s.get_line(), s.get_pos()); + if (s.is_composite()) { + sexpr * head = s.get_child(0); + opt::objective_t type = get_objective_type(*head); + switch(type) { + case opt::MAXIMIZE: + case opt::MINIMIZE: { + if (s.get_num_children() != 2) + throw cmd_exception("invalid objective, wrong number of arguments ", s.get_line(), s.get_pos()); + sexpr * arg = s.get_child(1); + expr_ref term(sexpr2expr(ctx, *arg), ctx.m()); + if (type == opt::MAXIMIZE) + return opt::objective::mk_max(term); + else + return opt::objective::mk_min(term); + } + case opt::MAXSAT: { + if (s.get_num_children() != 2) + throw cmd_exception("invalid objective, wrong number of arguments ", s.get_line(), s.get_pos()); + sexpr * arg = s.get_child(1); + if (!arg->is_symbol()) + throw cmd_exception("invalid objective, symbol expected", s.get_line(), s.get_pos()); + symbol const & id = arg->get_symbol(); + // TODO: check whether id is declared via assert-weighted + return opt::objective::mk_maxsat(id); + } + case opt::LEX: + case opt::BOX: + case opt::PARETO: { + if (s.get_num_children() <= 2) + throw cmd_exception("invalid objective, wrong number of arguments ", s.get_line(), s.get_pos()); + unsigned num_children = s.get_num_children(); + ptr_vector args; + for (unsigned i = 1; i < num_children; i++) + args.push_back(sexpr2objective(ctx, *s.get_child(i))); + switch(type) { + case opt::LEX: + return opt::objective::mk_lex(args.size(), args.c_ptr()); + case opt::BOX: + return opt::objective::mk_box(args.size(), args.c_ptr()); + case opt::PARETO: + return opt::objective::mk_pareto(args.size(), args.c_ptr()); + } + } + } + } + return 0; + } + }; void install_opt_cmds(cmd_context & ctx) { diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 17d35c1dd..e72aed879 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -88,12 +88,12 @@ namespace smt { void negate(); lbool normalize(); + void unique(); bool well_formed() const; app_ref to_expr(context& ctx, ast_manager& m); - }; typedef ptr_vector watch_list; @@ -170,7 +170,6 @@ namespace smt { virtual bool use_diseqs() const { return false; } virtual bool build_models() const { return false; } virtual final_check_status final_check_eh(); - virtual void reset_eh(); virtual void assign_eh(bool_var v, bool is_true); virtual void init_search_eh(); From 191efbb72f6f5ae974cd0b1865d29b53aa121f8c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 2 Dec 2013 13:00:51 -0800 Subject: [PATCH 169/925] use expression structure for objectives instead of custom s-expression Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.h | 4 +- src/opt/objective_decl_plugin.cpp | 88 +++++++++++++++++++++++++++++++ src/opt/objective_decl_plugin.h | 71 +++++++++++++++++++++++++ src/opt/opt_cmds.cpp | 59 +++++++++++++-------- src/opt/opt_context.cpp | 83 ++++++++++++++++------------- src/opt/opt_context.h | 17 +++--- 6 files changed, 251 insertions(+), 71 deletions(-) create mode 100644 src/opt/objective_decl_plugin.cpp create mode 100644 src/opt/objective_decl_plugin.h diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index 22b2ea046..11828c4c6 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -211,7 +211,6 @@ protected: void register_builtin_sorts(decl_plugin * p); void register_builtin_ops(decl_plugin * p); - void register_plugin(symbol const & name, decl_plugin * p, bool install_names); void init_manager_core(bool new_manager); void init_manager(); void init_external_manager(); @@ -298,7 +297,8 @@ public: check_sat_result * get_check_sat_result() const { return m_check_sat_result.get(); } check_sat_state cs_state() const; void validate_model(); - + + void register_plugin(symbol const & name, decl_plugin * p, bool install_names); bool is_func_decl(symbol const & s) const; bool is_sort_decl(symbol const& s) const { return m_psort_decls.contains(s); } void insert(cmd * c); diff --git a/src/opt/objective_decl_plugin.cpp b/src/opt/objective_decl_plugin.cpp new file mode 100644 index 000000000..b02ceee27 --- /dev/null +++ b/src/opt/objective_decl_plugin.cpp @@ -0,0 +1,88 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + objective_decl_plugin.cpp + +Abstract: + Abstract data-type for compound objectives. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-11-21 + +Notes: + +--*/ + +#include "objective_decl_plugin.h" + +namespace opt{ + objective_decl_plugin::objective_decl_plugin() {} + + objective_decl_plugin::~objective_decl_plugin() {} + + sort * objective_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) { + SASSERT(k == OBJECTIVE_SORT); + SASSERT(num_parameters == 0); + return m_manager->mk_sort(symbol("objective"), sort_info(get_family_id(), k)); + } + + symbol objective_decl_plugin::get_name(obj_kind k) const { + switch(k) { + case OP_MINIMIZE: return symbol("minimize"); + case OP_MAXIMIZE: return symbol("maximize"); + case OP_LEX: return symbol("lex"); + case OP_BOX: return symbol("box"); + case OP_PARETO: return symbol("pareto"); + default: + UNREACHABLE(); + return symbol(); + } + } + + func_decl * objective_decl_plugin::mk_func_decl( + decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) { + SASSERT(num_parameters == 0); + symbol name = get_name(static_cast(k)); + func_decl_info info(get_family_id(), k, num_parameters, parameters); + return m_manager->mk_func_decl(name, arity, domain, range, info); + } + + void objective_decl_plugin::get_op_names(svector & op_names, symbol const & logic) { + if (logic == symbol::null) { + op_names.push_back(builtin_name(get_name(OP_MAXIMIZE).bare_str(), OP_MAXIMIZE)); + op_names.push_back(builtin_name(get_name(OP_MINIMIZE).bare_str(), OP_MINIMIZE)); + op_names.push_back(builtin_name(get_name(OP_LEX).bare_str(), OP_LEX)); + op_names.push_back(builtin_name(get_name(OP_BOX).bare_str(), OP_BOX)); + op_names.push_back(builtin_name(get_name(OP_PARETO).bare_str(), OP_PARETO)); + } + } + + + objective_util::objective_util(ast_manager& m): m(m), m_fid(m.get_family_id("objective")) {} + + app* objective_util::mk_max(expr_ref& e) { + expr* es[1] = { e }; + return m.mk_app(m_fid, OP_MAXIMIZE, 0, 0, 1, es); + } + app* objective_util::mk_min(expr_ref& e) { + expr* es[1] = { e }; + return m.mk_app(m_fid, OP_MINIMIZE, 0, 0, 1, es); + } + app* objective_util::mk_maxsat(symbol id) { + return m.mk_const(id, m.mk_sort(m_fid, OBJECTIVE_SORT, 0, 0)); + } + app* objective_util::mk_lex(unsigned sz, expr * const * children) { + return m.mk_app(m_fid, OP_LEX, 0, 0, sz, children); + } + app* objective_util::mk_box(unsigned sz, expr * const * children) { + return m.mk_app(m_fid, OP_BOX, 0, 0, sz, children); + } + app* objective_util::mk_pareto(unsigned sz, expr * const * children) { + return m.mk_app(m_fid, OP_PARETO, 0, 0, sz, children); + } + +} diff --git a/src/opt/objective_decl_plugin.h b/src/opt/objective_decl_plugin.h new file mode 100644 index 000000000..40b301ea8 --- /dev/null +++ b/src/opt/objective_decl_plugin.h @@ -0,0 +1,71 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + objective_decl_plugin.h + +Abstract: + Abstract data-type for compound objectives. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-11-21 + +Notes: + +--*/ +#ifndef __OBJECTIVE_DECL_PLUGIN_H_ +#define __OBJECTIVE_DECL_PLUGIN_H_ + +#include"ast.h" + +namespace opt { + + enum obj_kind { + OP_MINIMIZE, + OP_MAXIMIZE, + OP_LEX, + OP_BOX, + OP_PARETO, + LAST_OBJ_OP + }; + + enum objective_sort_kind { + OBJECTIVE_SORT + }; + + class objective_decl_plugin : public decl_plugin { + public: + objective_decl_plugin(); + virtual ~objective_decl_plugin(); + + virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters); + + virtual decl_plugin * mk_fresh() { return alloc(objective_decl_plugin); } + + virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range); + + virtual void get_op_names(svector & op_names, symbol const & logic); + + private: + symbol objective_decl_plugin::get_name(obj_kind k) const; + }; + + class objective_util { + ast_manager& m; + family_id m_fid; + public: + objective_util(ast_manager& m); + family_id get_family_id() const { return m_fid; } + app* mk_max(expr_ref& e); + app* mk_min(expr_ref& e); + app* mk_maxsat(symbol id); + app* mk_lex(unsigned sz, expr * const * children); + app* mk_box(unsigned sz, expr * const * children); + app* mk_pareto(unsigned sz, expr * const * children); + }; +}; + +#endif diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index 140afbd56..7691787ce 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -30,6 +30,7 @@ Notes: #include "scoped_timer.h" #include "parametric_cmd.h" #include "objective_ast.h" +#include "objective_decl_plugin.h" class opt_context { cmd_context& ctx; @@ -39,6 +40,8 @@ public: opt::context& operator()() { if (!m_opt) { m_opt = alloc(opt::context, ctx.m()); + decl_plugin * p = alloc(opt::objective_decl_plugin); + ctx.register_plugin(symbol("objective"), p, true); } return *m_opt; } @@ -251,12 +254,13 @@ private: class execute_cmd : public parametric_cmd { protected: - sexpr * m_objective; + expr * m_objective; opt_context& m_opt_ctx; public: execute_cmd(opt_context& opt_ctx): parametric_cmd("optimize"), - m_opt_ctx(opt_ctx) + m_opt_ctx(opt_ctx), + m_objective(0) {} virtual void init_pdescrs(cmd_context & ctx, param_descrs & p) { @@ -270,19 +274,26 @@ public: virtual char const * get_usage() const { return "( )*"; } virtual void prepare(cmd_context & ctx) { parametric_cmd::prepare(ctx); - m_objective = 0; + reset(ctx); } virtual void failure_cleanup(cmd_context & ctx) { reset(ctx); } + virtual void reset(cmd_context& ctx) { + if (m_objective) { + ctx.m().dec_ref(m_objective); + } + m_objective = 0; + } virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { - if (m_objective == 0) return CPK_SEXPR; + if (m_objective == 0) return CPK_EXPR; return parametric_cmd::next_arg_kind(ctx); } - virtual void set_next_arg(cmd_context & ctx, sexpr * arg) { + virtual void set_next_arg(cmd_context & ctx, expr * arg) { m_objective = arg; + ctx.m().inc_ref(arg); } virtual void execute(cmd_context & ctx) { @@ -303,9 +314,7 @@ public: scoped_timer timer(timeout, &eh); cmd_context::scoped_watch sw(ctx); try { - opt::objective * o = sexpr2objective(ctx, *m_objective); - r = opt.optimize(*o); - dealloc(o); + r = opt.optimize(m_objective); } catch (z3_error& ex) { ctx.regular_stream() << "(error: " << ex.msg() << "\")" << std::endl; @@ -343,6 +352,18 @@ private: m_opt_ctx().collect_statistics(stats); stats.display_smt2(ctx.regular_stream()); } +}; + +void install_opt_cmds(cmd_context & ctx) { + opt_context* opt_ctx = alloc(opt_context, ctx); + ctx.insert(alloc(assert_weighted_cmd, ctx, *opt_ctx)); + ctx.insert(alloc(execute_cmd, *opt_ctx)); + //ctx.insert(alloc(min_maximize_cmd, ctx, *opt_ctx, true)); + //ctx.insert(alloc(min_maximize_cmd, ctx, *opt_ctx, false)); + //ctx.insert(alloc(optimize_cmd, *opt_ctx)); +} + +#if 0 expr_ref sexpr2expr(cmd_context & ctx, sexpr& s) { expr_ref result(ctx.m()); @@ -370,17 +391,18 @@ private: ctx.mk_const(s.get_symbol(), result); return result; } + return result; } opt::objective_t get_objective_type(sexpr& s) { if (!s.is_symbol()) throw cmd_exception("invalid objective, symbol expected", s.get_line(), s.get_pos()); symbol const & sym = s.get_symbol(); - if (sym == symbol("maximize")) return opt::objective_t::MAXIMIZE; - if (sym == symbol("minimize")) return opt::objective_t::MINIMIZE; - if (sym == symbol("lex")) return opt::objective_t::LEX; - if (sym == symbol("box")) return opt::objective_t::BOX; - if (sym == symbol("pareto")) return opt::objective_t::PARETO; + if (sym == symbol("maximize")) return opt::MAXIMIZE; + if (sym == symbol("minimize")) return opt::MINIMIZE; + if (sym == symbol("lex")) return opt::LEX; + if (sym == symbol("box")) return opt::BOX; + if (sym == symbol("pareto")) return opt::PARETO; throw cmd_exception("invalid objective, unexpected input", s.get_line(), s.get_pos()); } @@ -435,13 +457,4 @@ private: return 0; } -}; - -void install_opt_cmds(cmd_context & ctx) { - opt_context* opt_ctx = alloc(opt_context, ctx); - ctx.insert(alloc(assert_weighted_cmd, ctx, *opt_ctx)); - ctx.insert(alloc(execute_cmd, *opt_ctx)); - //ctx.insert(alloc(min_maximize_cmd, ctx, *opt_ctx, true)); - //ctx.insert(alloc(min_maximize_cmd, ctx, *opt_ctx, false)); - //ctx.insert(alloc(optimize_cmd, *opt_ctx)); -} +#endif diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 198ed918b..f9f6def15 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -28,7 +28,8 @@ namespace opt { m(m), m_hard_constraints(m), m_optsmt(m), - m_objs(m) + m_objs(m), + m_obj_util(m) { m_params.set_bool("model", true); m_params.set_bool("unsat_core", true); @@ -51,66 +52,74 @@ namespace opt { ms->add(f, w); } - lbool context::execute(objective & obj, bool committed) { - switch (obj.type()) { - case MINIMIZE: - case MAXIMIZE: - return execute_min_max(obj.get_min_max(), committed); - case MAXSAT: - return execute_maxsat(obj.get_maxsat(), committed); - case LEX: - return execute_lex(obj.get_compound()); - case BOX: - return execute_box(obj.get_compound()); - case PARETO: - return execute_pareto(obj.get_compound()); + lbool context::execute(expr* _obj, bool committed) { + SASSERT(is_app(_obj)); + app* obj = to_app(_obj); + + if (obj->get_family_id() == null_family_id) { + return execute_maxsat(obj, committed); + } + if (obj->get_family_id() != m_obj_util.get_family_id()) { + // error + return l_undef; + } + + switch (obj->get_decl_kind()) { + case OP_MINIMIZE: + case OP_MAXIMIZE: + return execute_min_max(obj, committed); + case OP_LEX: + return execute_lex(obj); + case OP_BOX: + return execute_box(obj); + case OP_PARETO: + return execute_pareto(obj); default: UNREACHABLE(); return l_undef; } } - lbool context::execute_min_max(min_max_objective & obj, bool committed) { + lbool context::execute_min_max(app* obj, bool committed) { // HACK: reuse m_optsmt but add only a single objective each round - m_optsmt.add(to_app(obj.term()), obj.is_max()); + bool is_max = (obj->get_decl_kind() == OP_MAXIMIZE); + m_optsmt.add(to_app(obj->get_arg(0)), is_max); opt_solver& s = *m_solver.get(); lbool result = m_optsmt(s); if (committed) m_optsmt.commit_assignment(0); return result; } - lbool context::execute_maxsat(maxsat_objective & obj, bool committed) { + lbool context::execute_maxsat(app* obj, bool committed) { maxsmt* ms; - SASSERT(m_maxsmts.find(obj.get_id(), ms)); + VERIFY(m_maxsmts.find(obj->get_decl()->get_name(), ms)); opt_solver& s = *m_solver.get(); lbool result = (*ms)(s); if (committed) ms->commit_assignment(); return result; } - lbool context::execute_lex(compound_objective & obj) { - ptr_vector children(obj.num_children(), obj.children()); + lbool context::execute_lex(app* obj) { lbool result = l_true; - for (unsigned i = 0; i < children.size(); ++i) { - result = execute(*children[i], true); + for (unsigned i = 0; i < obj->get_num_args(); ++i) { + result = execute(obj->get_arg(i), true); if (result != l_true) break; } return result; } - lbool context::execute_box(compound_objective & obj) { - ptr_vector children(obj.num_children(), obj.children()); + lbool context::execute_box(app* obj) { lbool result = l_true; - for (unsigned i = 0; i < children.size(); ++i) { + for (unsigned i = 0; i < obj->get_num_args(); ++i) { push(); - result = execute(*children[i], false); + result = execute(obj->get_arg(i), false); pop(1); if (result != l_true) break; } return result; } - lbool context::execute_pareto(compound_objective & obj) { + lbool context::execute_pareto(app* obj) { // TODO: record a stream of results from pareto front return execute_lex(obj); } @@ -125,7 +134,7 @@ namespace opt { s.pop(sz); } - lbool context::optimize(objective & objective) { + lbool context::optimize(expr* objective) { opt_solver& s = *m_solver.get(); solver::scoped_push _sp(s); @@ -138,29 +147,27 @@ namespace opt { lbool context::optimize() { // Construct objectives - ptr_vector objectives; + expr_ref_vector objectives(m); + expr_ref objective(m); + objective_util util(m); map_t::iterator it = m_maxsmts.begin(), end = m_maxsmts.end(); for (; it != end; ++it) { - objectives.push_back(objective::mk_maxsat(it->m_key)); + objectives.push_back(util.mk_maxsat(it->m_key)); } for (unsigned i = 0; i < m_objs.size(); ++i) { expr_ref e(m_objs[i].get(), m); - objective * o = m_ismaxs[i] ? objective::mk_max(e) : objective::mk_min(e); + app * o = m_ismaxs[i] ? util.mk_max(e) : util.mk_min(e); objectives.push_back(o); } - objective * objective; if (m_params.get_bool("pareto", false)) { - objective = objective::mk_pareto(objectives.size(), objectives.c_ptr()); + objective = util.mk_pareto(objectives.size(), objectives.c_ptr()); } else { - objective = objective::mk_box(objectives.size(), objectives.c_ptr()); + objective = util.mk_box(objectives.size(), objectives.c_ptr()); } - - lbool result = optimize(*objective); - dealloc(objective); - return result; + return optimize(objective); } void context::display_assignment(std::ostream& out) { diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index f70440de6..bc2cc713a 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -29,7 +29,7 @@ Notes: #include "opt_solver.h" #include "optsmt.h" #include "maxsmt.h" -#include "objective_ast.h" +#include "objective_decl_plugin.h" namespace opt { @@ -45,6 +45,7 @@ namespace opt { map_t m_maxsmts; expr_ref_vector m_objs; svector m_ismaxs; + objective_util m_obj_util; public: context(ast_manager& m); ~context(); @@ -52,17 +53,17 @@ namespace opt { void add_objective(app* t, bool is_max) { m_objs.push_back(t); m_ismaxs.push_back(is_max); } void add_hard_constraint(expr* f) { m_hard_constraints.push_back(f); } - lbool execute(objective & obj, bool committed); - lbool execute_min_max(min_max_objective & obj, bool committed); - lbool execute_maxsat(maxsat_objective & obj, bool committed); - lbool execute_lex(compound_objective & obj); - lbool execute_box(compound_objective & obj); - lbool execute_pareto(compound_objective & obj); + lbool execute(expr* obj, bool committed); + lbool execute_min_max(app* obj, bool committed); + lbool execute_maxsat(app* obj, bool committed); + lbool execute_lex(app* obj); + lbool execute_box(app* obj); + lbool execute_pareto(app* obj); void push(); void pop(unsigned sz); - lbool optimize(objective & objective); + lbool optimize(expr* objective); lbool optimize(); void set_cancel(bool f); From faa59ba7f90020c06677e705b0c9b237abf40b59 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 2 Dec 2013 14:14:44 -0800 Subject: [PATCH 170/925] debugging multi-objective interface and pb revisions Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.cpp | 2 +- src/opt/opt_cmds.cpp | 32 ++++++++++++++++++++++++++------ src/smt/theory_pb.cpp | 8 ++++---- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 976a66664..47575be7e 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -689,7 +689,7 @@ void cmd_context::insert(symbol const & s, func_decl * f) { if (!m_global_decls) { m_func_decls_stack.push_back(sf_pair(s, f)); } - TRACE("cmd_context", tout << "new sort decl\n" << mk_pp(f, m()) << "\n";); + TRACE("cmd_context", tout << "new function decl\n" << mk_pp(f, m()) << "\n";); } void cmd_context::insert(symbol const & s, psort_decl * p) { diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index 7691787ce..8cf432e7b 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -35,16 +35,27 @@ Notes: class opt_context { cmd_context& ctx; scoped_ptr m_opt; + hashtable m_ids; + public: opt_context(cmd_context& ctx): ctx(ctx) {} opt::context& operator()() { if (!m_opt) { - m_opt = alloc(opt::context, ctx.m()); decl_plugin * p = alloc(opt::objective_decl_plugin); - ctx.register_plugin(symbol("objective"), p, true); + ctx.register_plugin(symbol("objective"), p, true); + m_opt = alloc(opt::context, ctx.m()); } return *m_opt; } + + bool contains(symbol const& s) const { return m_ids.contains(s); } + + void insert(symbol const& s) { m_ids.insert(s); } + + sort* obj_sort(cmd_context& ctx) { + return ctx.m().mk_sort(ctx.m().get_family_id(symbol("objective")), opt::OBJECTIVE_SORT); + } + }; @@ -121,6 +132,10 @@ public: virtual void execute(cmd_context & ctx) { m_opt_ctx().add_soft_constraint(m_formula, m_weight, m_id); + if (!m_opt_ctx.contains(m_id)) { + ctx.insert(m_id, 0, ctx.m().mk_const(m_id, m_opt_ctx.obj_sort(ctx))); + m_opt_ctx.insert(m_id); + } reset(ctx); } @@ -255,12 +270,14 @@ private: class execute_cmd : public parametric_cmd { protected: expr * m_objective; + unsigned m_idx; opt_context& m_opt_ctx; public: execute_cmd(opt_context& opt_ctx): parametric_cmd("optimize"), - m_opt_ctx(opt_ctx), - m_objective(0) + m_objective(0), + m_idx(0), + m_opt_ctx(opt_ctx) {} virtual void init_pdescrs(cmd_context & ctx, param_descrs & p) { @@ -271,10 +288,11 @@ public: } virtual char const * get_main_descr() const { return "check sat modulo objective function";} - virtual char const * get_usage() const { return "( )*"; } + virtual char const * get_usage() const { return " ( )*"; } virtual void prepare(cmd_context & ctx) { parametric_cmd::prepare(ctx); reset(ctx); + m_opt_ctx(); // ensure symbol table is updated. } virtual void failure_cleanup(cmd_context & ctx) { reset(ctx); @@ -284,16 +302,18 @@ public: ctx.m().dec_ref(m_objective); } m_objective = 0; + m_idx = 0; } virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { - if (m_objective == 0) return CPK_EXPR; + if (m_idx == 0) return CPK_EXPR; return parametric_cmd::next_arg_kind(ctx); } virtual void set_next_arg(cmd_context & ctx, expr * arg) { m_objective = arg; ctx.m().inc_ref(arg); + ++m_idx; } virtual void execute(cmd_context & ctx) { diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 46a8eb443..79db388f4 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -550,8 +550,8 @@ namespace smt { void theory_pb::assign_eh(bool_var v, bool is_true) { context& ctx = get_context(); ptr_vector* ineqs = 0; - literal lit(v, !is_true); - if (m_watch.find(lit.index(), ineqs)) { + literal nlit(v, is_true); + if (m_watch.find(nlit.index(), ineqs)) { for (unsigned i = 0; i < ineqs->size(); ++i) { if (assign_watch(v, is_true, *ineqs, i)) { // i was removed from watch list. @@ -1283,8 +1283,8 @@ namespace smt { UNREACHABLE(); return false; case l_false: - add_assign(c, m_ineq_literals, false_literal); - break; + //add_assign(c, m_ineq_literals, false_literal); + //break; default: { app_ref tmp = m_lemma.to_expr(ctx, get_manager()); internalize_atom(tmp, false); From c14c7787353555c733b7dcf644754da6a306c707 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 2 Dec 2013 14:30:17 -0800 Subject: [PATCH 171/925] debugging multi-objective interface and pb revisions Signed-off-by: Nikolaj Bjorner --- src/opt/objective_decl_plugin.cpp | 1 + src/opt/opt_cmds.cpp | 8 -------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/opt/objective_decl_plugin.cpp b/src/opt/objective_decl_plugin.cpp index b02ceee27..9bca883ff 100644 --- a/src/opt/objective_decl_plugin.cpp +++ b/src/opt/objective_decl_plugin.cpp @@ -48,6 +48,7 @@ namespace opt{ SASSERT(num_parameters == 0); symbol name = get_name(static_cast(k)); func_decl_info info(get_family_id(), k, num_parameters, parameters); + range = mk_sort(OBJECTIVE_SORT, 0, 0); return m_manager->mk_func_decl(name, arity, domain, range, info); } diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index 8cf432e7b..35e6ff9f0 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -80,9 +80,6 @@ public: } virtual void reset(cmd_context & ctx) { - if (m_formula) { - ctx.m().dec_ref(m_formula); - } m_idx = 0; m_formula = 0; m_id = symbol::null; @@ -116,7 +113,6 @@ public: throw cmd_exception("Invalid type for expression. Expected Boolean type."); } m_formula = t; - ctx.m().inc_ref(t); ++m_idx; } @@ -298,9 +294,6 @@ public: reset(ctx); } virtual void reset(cmd_context& ctx) { - if (m_objective) { - ctx.m().dec_ref(m_objective); - } m_objective = 0; m_idx = 0; } @@ -312,7 +305,6 @@ public: virtual void set_next_arg(cmd_context & ctx, expr * arg) { m_objective = arg; - ctx.m().inc_ref(arg); ++m_idx; } From af5d989d6c53193b5af5896eadf0f07800ffe37f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 2 Dec 2013 21:51:20 -0800 Subject: [PATCH 172/925] change verbosity level Signed-off-by: Nikolaj Bjorner --- src/opt/core_maxsat.cpp | 4 ++-- src/opt/fu_malik.cpp | 8 ++++---- src/opt/maxsmt.cpp | 1 - src/smt/theory_pb.cpp | 6 +----- 4 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/opt/core_maxsat.cpp b/src/opt/core_maxsat.cpp index b6da58aa0..11756c617 100644 --- a/src/opt/core_maxsat.cpp +++ b/src/opt/core_maxsat.cpp @@ -65,7 +65,7 @@ namespace opt { for (unsigned i = 0; i < ans.size(); ++i) { tout << mk_pp(ans[i].get(), m) << "\n"; }); - IF_VERBOSE(0, verbose_stream() << "(maxsat.core sat with lower bound: " << ans.size() << "\n";); + IF_VERBOSE(1, verbose_stream() << "(maxsat.core sat with lower bound: " << ans.size() << "\n";); if (ans.size() > m_answer.size()) { m_answer.reset(); m_answer.append(ans); @@ -92,7 +92,7 @@ namespace opt { core_vars.insert(get_not(core[i])); block_vars.remove(core[i]); } - IF_VERBOSE(0, verbose_stream() << "(maxsat.core unsat (core size = " << core.size() << ")\n";); + IF_VERBOSE(1, verbose_stream() << "(maxsat.core unsat (core size = " << core.size() << ")\n";); if (core.empty()) { m_upper = m_answer.size(); return l_true; diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index 90420ad72..99ecdf2a5 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -149,7 +149,7 @@ namespace opt { } lbool step() { - IF_VERBOSE(0, verbose_stream() << "(opt.max_sat step " << m_soft.size() + 2 - m_upper_size << ")\n";); + IF_VERBOSE(1, verbose_stream() << "(opt.max_sat step " << m_soft.size() + 2 - m_upper_size << ")\n";); expr_ref_vector assumptions(m), block_vars(m); for (unsigned i = 0; i < m_soft.size(); ++i) { assumptions.push_back(m.mk_not(m_aux[i].get())); @@ -187,7 +187,7 @@ namespace opt { // ++i; //} - IF_VERBOSE(0, verbose_stream() << "(opt.max_sat unsat-core of size " << core.size() << ")\n";); + IF_VERBOSE(1, verbose_stream() << "(opt.max_sat unsat-core of size " << core.size() << ")\n";); } else { s().get_unsat_core(core); @@ -214,7 +214,7 @@ namespace opt { } SASSERT (!block_vars.empty()); assert_at_most_one(block_vars); - IF_VERBOSE(0, verbose_stream() << "(opt.max_sat # of non-blocked soft constraints: " << m_soft.size() - block_vars.size() << ")\n";); + IF_VERBOSE(1, verbose_stream() << "(opt.max_sat # of non-blocked soft constraints: " << m_soft.size() - block_vars.size() << ")\n";); return l_false; } @@ -264,7 +264,7 @@ namespace opt { m_s->assert_expr(current_solver.get_assertion(i)); } m_use_new_bv_solver = true; - IF_VERBOSE(0, verbose_stream() << "Force to use the new BV solver." << std::endl;); + IF_VERBOSE(1, verbose_stream() << "Force to use the new BV solver." << std::endl;); } } diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 14233300a..c6298f2e8 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -61,7 +61,6 @@ namespace opt { }); DEBUG_CODE(if (is_sat == l_true) { - IF_VERBOSE(0, verbose_stream() << "validating assignment\n";); m_s->push(); commit_assignment(); VERIFY(l_true == m_s->check_sat(0,0)); diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 79db388f4..2ef202f76 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1046,14 +1046,10 @@ namespace smt { resolve_conflict(c); -#if 1 justification* js = 0; ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); - IF_VERBOSE(2, ctx.display_literals_verbose(verbose_stream(), - lits.size(), lits.c_ptr()); + IF_VERBOSE(2, ctx.display_literals_verbose(verbose_stream(), lits.size(), lits.c_ptr()); verbose_stream() << "\n";); - // ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); -#endif } void theory_pb::set_mark(bool_var v, unsigned idx) { From 03f5020d0b599e03e2fc8b3ffabc06cb74274c39 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 2 Dec 2013 22:06:15 -0800 Subject: [PATCH 173/925] Nits Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 36 +++++++++++++++++------------------- src/opt/opt_context.h | 21 ++++++++++++--------- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index f9f6def15..710d8a739 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -84,8 +84,7 @@ namespace opt { // HACK: reuse m_optsmt but add only a single objective each round bool is_max = (obj->get_decl_kind() == OP_MAXIMIZE); m_optsmt.add(to_app(obj->get_arg(0)), is_max); - opt_solver& s = *m_solver.get(); - lbool result = m_optsmt(s); + lbool result = m_optsmt(get_solver()); if (committed) m_optsmt.commit_assignment(0); return result; } @@ -93,30 +92,27 @@ namespace opt { lbool context::execute_maxsat(app* obj, bool committed) { maxsmt* ms; VERIFY(m_maxsmts.find(obj->get_decl()->get_name(), ms)); - opt_solver& s = *m_solver.get(); - lbool result = (*ms)(s); + lbool result = (*ms)(get_solver()); if (committed) ms->commit_assignment(); return result; } lbool context::execute_lex(app* obj) { - lbool result = l_true; - for (unsigned i = 0; i < obj->get_num_args(); ++i) { - result = execute(obj->get_arg(i), true); - if (result != l_true) break; + lbool r = l_true; + for (unsigned i = 0; r == l_true && i < obj->get_num_args(); ++i) { + r = execute(obj->get_arg(i), true); } - return result; + return r; } lbool context::execute_box(app* obj) { - lbool result = l_true; - for (unsigned i = 0; i < obj->get_num_args(); ++i) { + lbool r = l_true; + for (unsigned i = 0; r == l_true && i < obj->get_num_args(); ++i) { push(); - result = execute(obj->get_arg(i), false); + r = execute(obj->get_arg(i), false); pop(1); - if (result != l_true) break; } - return result; + return r; } lbool context::execute_pareto(app* obj) { @@ -124,18 +120,20 @@ namespace opt { return execute_lex(obj); } + opt_solver& context::get_solver() { + return *m_solver.get(); + } + void context::push() { - opt_solver& s = *m_solver.get(); - s.push(); + get_solver().push(); } void context::pop(unsigned sz) { - opt_solver& s = *m_solver.get(); - s.pop(sz); + get_solver().pop(sz); } lbool context::optimize(expr* objective) { - opt_solver& s = *m_solver.get(); + opt_solver& s = get_solver(); solver::scoped_push _sp(s); for (unsigned i = 0; i < m_hard_constraints.size(); ++i) { diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index bc2cc713a..30308f0d9 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -53,15 +53,6 @@ namespace opt { void add_objective(app* t, bool is_max) { m_objs.push_back(t); m_ismaxs.push_back(is_max); } void add_hard_constraint(expr* f) { m_hard_constraints.push_back(f); } - lbool execute(expr* obj, bool committed); - lbool execute_min_max(app* obj, bool committed); - lbool execute_maxsat(app* obj, bool committed); - lbool execute_lex(app* obj); - lbool execute_box(app* obj); - lbool execute_pareto(app* obj); - - void push(); - void pop(unsigned sz); lbool optimize(expr* objective); lbool optimize(); @@ -76,6 +67,18 @@ namespace opt { void updt_params(params_ref& p); private: void validate_feasibility(maxsmt& ms); + + lbool execute(expr* obj, bool committed); + lbool execute_min_max(app* obj, bool committed); + lbool execute_maxsat(app* obj, bool committed); + lbool execute_lex(app* obj); + lbool execute_box(app* obj); + lbool execute_pareto(app* obj); + + void push(); + void pop(unsigned sz); + opt_solver& get_solver(); + }; } From 51704b7b95c633ac44e8108e279bfcecd10b2d40 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 3 Dec 2013 08:51:46 -0800 Subject: [PATCH 174/925] tweaking input processing Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 28 +++++++++++++--------------- src/opt/opt_context.h | 2 +- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 710d8a739..6858b3fbc 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -60,14 +60,14 @@ namespace opt { return execute_maxsat(obj, committed); } if (obj->get_family_id() != m_obj_util.get_family_id()) { - // error - return l_undef; + return execute_min_max(obj, committed, true); } switch (obj->get_decl_kind()) { case OP_MINIMIZE: + return execute_min_max(to_app(obj->get_arg(0)), committed, false); case OP_MAXIMIZE: - return execute_min_max(obj, committed); + return execute_min_max(to_app(obj->get_arg(0)), committed, true); case OP_LEX: return execute_lex(obj); case OP_BOX: @@ -80,15 +80,15 @@ namespace opt { } } - lbool context::execute_min_max(app* obj, bool committed) { + lbool context::execute_min_max(app* obj, bool committed, bool is_max) { // HACK: reuse m_optsmt but add only a single objective each round - bool is_max = (obj->get_decl_kind() == OP_MAXIMIZE); - m_optsmt.add(to_app(obj->get_arg(0)), is_max); + m_optsmt.add(obj, is_max); lbool result = m_optsmt(get_solver()); if (committed) m_optsmt.commit_assignment(0); return result; } + lbool context::execute_maxsat(app* obj, bool committed) { maxsmt* ms; VERIFY(m_maxsmts.find(obj->get_decl()->get_name(), ms)); @@ -133,13 +133,14 @@ namespace opt { } lbool context::optimize(expr* objective) { + if (!objective) { + return optimize(); + } opt_solver& s = get_solver(); solver::scoped_push _sp(s); - for (unsigned i = 0; i < m_hard_constraints.size(); ++i) { s.assert_expr(m_hard_constraints[i].get()); } - return execute(objective, false); } @@ -147,23 +148,20 @@ namespace opt { // Construct objectives expr_ref_vector objectives(m); expr_ref objective(m); - objective_util util(m); map_t::iterator it = m_maxsmts.begin(), end = m_maxsmts.end(); for (; it != end; ++it) { - objectives.push_back(util.mk_maxsat(it->m_key)); + objectives.push_back(m_obj_util.mk_maxsat(it->m_key)); } - for (unsigned i = 0; i < m_objs.size(); ++i) { expr_ref e(m_objs[i].get(), m); - app * o = m_ismaxs[i] ? util.mk_max(e) : util.mk_min(e); + app * o = m_ismaxs[i] ? m_obj_util.mk_max(e) : m_obj_util.mk_min(e); objectives.push_back(o); } - if (m_params.get_bool("pareto", false)) { - objective = util.mk_pareto(objectives.size(), objectives.c_ptr()); + objective = m_obj_util.mk_pareto(objectives.size(), objectives.c_ptr()); } else { - objective = util.mk_box(objectives.size(), objectives.c_ptr()); + objective = m_obj_util.mk_box(objectives.size(), objectives.c_ptr()); } return optimize(objective); } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 30308f0d9..473abbb09 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -69,7 +69,7 @@ namespace opt { void validate_feasibility(maxsmt& ms); lbool execute(expr* obj, bool committed); - lbool execute_min_max(app* obj, bool committed); + lbool execute_min_max(app* obj, bool committed, bool is_max); lbool execute_maxsat(app* obj, bool committed); lbool execute_lex(app* obj); lbool execute_box(app* obj); From 18815e3e53317d46443a86d09df20b7befe65a19 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 3 Dec 2013 13:36:25 -0800 Subject: [PATCH 175/925] reorganizing input Signed-off-by: Nikolaj Bjorner --- src/opt/objective_ast.cpp | 54 -------- src/opt/objective_ast.h | 108 --------------- src/opt/objective_decl_plugin.cpp | 89 ------------- src/opt/objective_decl_plugin.h | 71 ---------- src/opt/opt_cmds.cpp | 214 +++++++++++++----------------- src/opt/opt_context.cpp | 152 ++++++++++----------- src/opt/opt_context.h | 41 ++++-- src/opt/opt_params.pyg | 2 +- 8 files changed, 192 insertions(+), 539 deletions(-) delete mode 100644 src/opt/objective_ast.cpp delete mode 100644 src/opt/objective_ast.h delete mode 100644 src/opt/objective_decl_plugin.cpp delete mode 100644 src/opt/objective_decl_plugin.h diff --git a/src/opt/objective_ast.cpp b/src/opt/objective_ast.cpp deleted file mode 100644 index 79d2516d6..000000000 --- a/src/opt/objective_ast.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - objective_ast.h - -Abstract: - Abstract data-type for compound objectives. - -Author: - - Anh-Dung Phan (t-anphan) 2013-11-26 - -Notes: - ---*/ - -#include"objective_ast.h" - -namespace opt { - - objective* objective::mk_max(expr_ref& e) { return alloc(min_max_objective, MAXIMIZE, e); }; - objective* objective::mk_min(expr_ref& e) { return alloc(min_max_objective, MINIMIZE, e); }; - objective* objective::mk_maxsat(symbol id) { return alloc(maxsat_objective, id); }; - - objective* objective::mk_lex(unsigned sz, objective * const* children) { - return alloc(compound_objective, LEX, sz, children); - }; - - objective* objective::mk_box(unsigned sz, objective * const* children) { - return alloc(compound_objective, BOX, sz, children); - }; - - objective* objective::mk_pareto(unsigned sz, objective * const* children) { - return alloc(compound_objective, PARETO, sz, children); - }; - - compound_objective& objective::get_compound() { - SASSERT(m_type == LEX || m_type == BOX || m_type == PARETO); - return dynamic_cast(*this); - } - - min_max_objective& objective::get_min_max() { - SASSERT(m_type == MAXIMIZE || m_type == MINIMIZE); - return dynamic_cast(*this); - } - - maxsat_objective& objective::get_maxsat() { - SASSERT(m_type == MAXSAT); - return dynamic_cast(*this); - } - -}; diff --git a/src/opt/objective_ast.h b/src/opt/objective_ast.h deleted file mode 100644 index 31a2bf543..000000000 --- a/src/opt/objective_ast.h +++ /dev/null @@ -1,108 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - objective_ast.h - -Abstract: - Abstract data-type for compound objectives. - -Author: - - Nikolaj Bjorner (nbjorner) 2013-11-21 - -Notes: - ---*/ -#ifndef __OBJECTIVE_AST_H_ -#define __OBJECTIVE_AST_H_ - -#include"ast.h" - -namespace opt { - - enum objective_t { - MINIMIZE, - MAXIMIZE, - MAXSAT, - LEX, - BOX, - PARETO - }; - - class compound_objective; - class min_max_objective; - class maxsat_objective; - - class objective { - objective_t m_type; - public: - objective(objective_t ty): - m_type(ty) - {} - virtual ~objective() {} - - objective_t type() const { return m_type; } - - // constructors; - static objective* mk_max(expr_ref& e); - static objective* mk_min(expr_ref& e); - static objective* mk_maxsat(symbol id); - - static objective* mk_lex(unsigned sz, objective * const* children); - static objective* mk_box(unsigned sz, objective * const* children); - static objective* mk_pareto(unsigned sz, objective * const* children); - - // accessors (implicit cast operations) - compound_objective& get_compound(); - min_max_objective& get_min_max(); - maxsat_objective& get_maxsat(); - }; - - class compound_objective : public objective { - ptr_vector m_children; - public: - compound_objective(objective_t t, unsigned sz, objective * const* children): - objective(t), - m_children(sz, children) {} - - virtual ~compound_objective() { - ptr_vector::iterator it = m_children.begin(), end = m_children.end(); - for (; it != end; ++it) { - dealloc(*it); - } - } - - objective *const* children() const { return m_children.c_ptr(); } - - unsigned num_children() const { return m_children.size(); } - }; - - class min_max_objective : public objective { - bool m_is_max; - expr_ref m_expr; - public: - min_max_objective(bool is_max, expr_ref& e): - objective(is_max ? MAXIMIZE : MINIMIZE), - m_is_max(is_max), - m_expr(e) {} - - virtual ~min_max_objective() {} - - expr* term() { return m_expr; } - bool is_max() const { return m_is_max; } - }; - - class maxsat_objective : public objective { - symbol m_id; - public: - maxsat_objective(symbol const& id): objective(MAXSAT), m_id(id) {} - virtual ~maxsat_objective() {} - - symbol const& get_id() const { return m_id; } - }; - -}; - -#endif diff --git a/src/opt/objective_decl_plugin.cpp b/src/opt/objective_decl_plugin.cpp deleted file mode 100644 index 9bca883ff..000000000 --- a/src/opt/objective_decl_plugin.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - objective_decl_plugin.cpp - -Abstract: - Abstract data-type for compound objectives. - -Author: - - Nikolaj Bjorner (nbjorner) 2013-11-21 - -Notes: - ---*/ - -#include "objective_decl_plugin.h" - -namespace opt{ - objective_decl_plugin::objective_decl_plugin() {} - - objective_decl_plugin::~objective_decl_plugin() {} - - sort * objective_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) { - SASSERT(k == OBJECTIVE_SORT); - SASSERT(num_parameters == 0); - return m_manager->mk_sort(symbol("objective"), sort_info(get_family_id(), k)); - } - - symbol objective_decl_plugin::get_name(obj_kind k) const { - switch(k) { - case OP_MINIMIZE: return symbol("minimize"); - case OP_MAXIMIZE: return symbol("maximize"); - case OP_LEX: return symbol("lex"); - case OP_BOX: return symbol("box"); - case OP_PARETO: return symbol("pareto"); - default: - UNREACHABLE(); - return symbol(); - } - } - - func_decl * objective_decl_plugin::mk_func_decl( - decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range) { - SASSERT(num_parameters == 0); - symbol name = get_name(static_cast(k)); - func_decl_info info(get_family_id(), k, num_parameters, parameters); - range = mk_sort(OBJECTIVE_SORT, 0, 0); - return m_manager->mk_func_decl(name, arity, domain, range, info); - } - - void objective_decl_plugin::get_op_names(svector & op_names, symbol const & logic) { - if (logic == symbol::null) { - op_names.push_back(builtin_name(get_name(OP_MAXIMIZE).bare_str(), OP_MAXIMIZE)); - op_names.push_back(builtin_name(get_name(OP_MINIMIZE).bare_str(), OP_MINIMIZE)); - op_names.push_back(builtin_name(get_name(OP_LEX).bare_str(), OP_LEX)); - op_names.push_back(builtin_name(get_name(OP_BOX).bare_str(), OP_BOX)); - op_names.push_back(builtin_name(get_name(OP_PARETO).bare_str(), OP_PARETO)); - } - } - - - objective_util::objective_util(ast_manager& m): m(m), m_fid(m.get_family_id("objective")) {} - - app* objective_util::mk_max(expr_ref& e) { - expr* es[1] = { e }; - return m.mk_app(m_fid, OP_MAXIMIZE, 0, 0, 1, es); - } - app* objective_util::mk_min(expr_ref& e) { - expr* es[1] = { e }; - return m.mk_app(m_fid, OP_MINIMIZE, 0, 0, 1, es); - } - app* objective_util::mk_maxsat(symbol id) { - return m.mk_const(id, m.mk_sort(m_fid, OBJECTIVE_SORT, 0, 0)); - } - app* objective_util::mk_lex(unsigned sz, expr * const * children) { - return m.mk_app(m_fid, OP_LEX, 0, 0, sz, children); - } - app* objective_util::mk_box(unsigned sz, expr * const * children) { - return m.mk_app(m_fid, OP_BOX, 0, 0, sz, children); - } - app* objective_util::mk_pareto(unsigned sz, expr * const * children) { - return m.mk_app(m_fid, OP_PARETO, 0, 0, sz, children); - } - -} diff --git a/src/opt/objective_decl_plugin.h b/src/opt/objective_decl_plugin.h deleted file mode 100644 index 40b301ea8..000000000 --- a/src/opt/objective_decl_plugin.h +++ /dev/null @@ -1,71 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - objective_decl_plugin.h - -Abstract: - Abstract data-type for compound objectives. - -Author: - - Nikolaj Bjorner (nbjorner) 2013-11-21 - -Notes: - ---*/ -#ifndef __OBJECTIVE_DECL_PLUGIN_H_ -#define __OBJECTIVE_DECL_PLUGIN_H_ - -#include"ast.h" - -namespace opt { - - enum obj_kind { - OP_MINIMIZE, - OP_MAXIMIZE, - OP_LEX, - OP_BOX, - OP_PARETO, - LAST_OBJ_OP - }; - - enum objective_sort_kind { - OBJECTIVE_SORT - }; - - class objective_decl_plugin : public decl_plugin { - public: - objective_decl_plugin(); - virtual ~objective_decl_plugin(); - - virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters); - - virtual decl_plugin * mk_fresh() { return alloc(objective_decl_plugin); } - - virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); - - virtual void get_op_names(svector & op_names, symbol const & logic); - - private: - symbol objective_decl_plugin::get_name(obj_kind k) const; - }; - - class objective_util { - ast_manager& m; - family_id m_fid; - public: - objective_util(ast_manager& m); - family_id get_family_id() const { return m_fid; } - app* mk_max(expr_ref& e); - app* mk_min(expr_ref& e); - app* mk_maxsat(symbol id); - app* mk_lex(unsigned sz, expr * const * children); - app* mk_box(unsigned sz, expr * const * children); - app* mk_pareto(unsigned sz, expr * const * children); - }; -}; - -#endif diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index 35e6ff9f0..db5906135 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -29,8 +29,6 @@ Notes: #include "scoped_ctrl_c.h" #include "scoped_timer.h" #include "parametric_cmd.h" -#include "objective_ast.h" -#include "objective_decl_plugin.h" class opt_context { cmd_context& ctx; @@ -41,21 +39,10 @@ public: opt_context(cmd_context& ctx): ctx(ctx) {} opt::context& operator()() { if (!m_opt) { - decl_plugin * p = alloc(opt::objective_decl_plugin); - ctx.register_plugin(symbol("objective"), p, true); m_opt = alloc(opt::context, ctx.m()); } return *m_opt; - } - - bool contains(symbol const& s) const { return m_ids.contains(s); } - - void insert(symbol const& s) { m_ids.insert(s); } - - sort* obj_sort(cmd_context& ctx) { - return ctx.m().mk_sort(ctx.m().get_family_id(symbol("objective")), opt::OBJECTIVE_SORT); - } - + } }; @@ -76,7 +63,6 @@ public: {} virtual ~assert_weighted_cmd() { - dealloc(&m_opt_ctx); } virtual void reset(cmd_context & ctx) { @@ -128,10 +114,81 @@ public: virtual void execute(cmd_context & ctx) { m_opt_ctx().add_soft_constraint(m_formula, m_weight, m_id); - if (!m_opt_ctx.contains(m_id)) { - ctx.insert(m_id, 0, ctx.m().mk_const(m_id, m_opt_ctx.obj_sort(ctx))); - m_opt_ctx.insert(m_id); + reset(ctx); + } + + virtual void finalize(cmd_context & ctx) { + } + +}; + + +class assert_soft_cmd : public parametric_cmd { + opt_context& m_opt_ctx; + unsigned m_idx; + expr* m_formula; + +public: + assert_soft_cmd(cmd_context& ctx, opt_context& opt_ctx): + parametric_cmd("assert-soft"), + m_opt_ctx(opt_ctx), + m_idx(0), + m_formula(0) + {} + + virtual ~assert_soft_cmd() { + } + + virtual void reset(cmd_context & ctx) { + m_idx = 0; + m_formula = 0; + } + + virtual char const * get_usage() const { return " [:weight ] [:id ]"; } + virtual char const * get_main_descr() const { return "assert soft constraint with optional weight and identifier"; } + + // command invocation + virtual void prepare(cmd_context & ctx) {} + virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { + if (m_idx == 0) return CPK_EXPR; + return parametric_cmd::next_arg_kind(ctx); + } + + virtual void init_pdescrs(cmd_context & ctx, param_descrs & p) { + p.insert("weight", CPK_UINT, "(default: 1) penalty of not satisfying constraint."); + p.insert("dweight", CPK_DOUBLE, "(default: 1.0) penalty as double of not satisfying constraint."); + p.insert("id", CPK_SYMBOL, "(default: null) partition identifier for soft constraints."); + } + + virtual void set_next_arg(cmd_context & ctx, expr * t) { + SASSERT(m_idx == 0); + if (!ctx.m().is_bool(t)) { + throw cmd_exception("Invalid type for expression. Expected Boolean type."); } + m_formula = t; + ++m_idx; + } + + virtual void failure_cleanup(cmd_context & ctx) { + reset(ctx); + } + + virtual void execute(cmd_context & ctx) { + symbol w("weight"); + rational weight = rational(ps().get_uint(symbol("weight"), 0)); + if (weight.is_zero()) { + double d = ps().get_double(symbol("dweight"), 0.0); + if (d != 0.0) { + std::stringstream strm; + strm << d; + weight = rational(strm.str().c_str()); + } + } + if (weight.is_zero()) { + weight = rational::one(); + } + symbol id = ps().get_sym(symbol("id"), symbol::null); + m_opt_ctx().add_soft_constraint(m_formula, weight, id); reset(ctx); } @@ -183,6 +240,10 @@ public: m_opt_ctx(opt_ctx) {} + virtual ~optimize_cmd() { + dealloc(&m_opt_ctx); + } + virtual void init_pdescrs(cmd_context & ctx, param_descrs & p) { insert_timeout(p); insert_max_memory(p); @@ -263,6 +324,19 @@ private: }; + +void install_opt_cmds(cmd_context & ctx) { + opt_context* opt_ctx = alloc(opt_context, ctx); + ctx.insert(alloc(assert_weighted_cmd, ctx, *opt_ctx)); + ctx.insert(alloc(assert_soft_cmd, ctx, *opt_ctx)); + ctx.insert(alloc(min_maximize_cmd, ctx, *opt_ctx, true)); + ctx.insert(alloc(min_maximize_cmd, ctx, *opt_ctx, false)); + ctx.insert(alloc(optimize_cmd, *opt_ctx)); +} + +#if 0 + ctx.insert(alloc(execute_cmd, *opt_ctx)); + class execute_cmd : public parametric_cmd { protected: expr * m_objective; @@ -365,108 +439,4 @@ private: stats.display_smt2(ctx.regular_stream()); } }; - -void install_opt_cmds(cmd_context & ctx) { - opt_context* opt_ctx = alloc(opt_context, ctx); - ctx.insert(alloc(assert_weighted_cmd, ctx, *opt_ctx)); - ctx.insert(alloc(execute_cmd, *opt_ctx)); - //ctx.insert(alloc(min_maximize_cmd, ctx, *opt_ctx, true)); - //ctx.insert(alloc(min_maximize_cmd, ctx, *opt_ctx, false)); - //ctx.insert(alloc(optimize_cmd, *opt_ctx)); -} - -#if 0 - - expr_ref sexpr2expr(cmd_context & ctx, sexpr& s) { - expr_ref result(ctx.m()); - switch(s.get_kind()) { - case sexpr::COMPOSITE: { - sexpr& h = *s.get_child(0); - if (!h.is_symbol()) { - throw cmd_exception("invalid head symbol", s.get_line(), s.get_pos()); - } - symbol sym = h.get_symbol(); - expr_ref_vector args(ctx.m()); - for (unsigned i = 1; i < s.get_num_children(); ++i) { - args.push_back(sexpr2expr(ctx, *s.get_child(i))); - } - ctx.mk_app(sym, args.size(), args.c_ptr(), 0, 0, 0, result); - return result; - } - case sexpr::NUMERAL: - case sexpr::BV_NUMERAL: - // TBD: handle numerals - case sexpr::STRING: - case sexpr::KEYWORD: - throw cmd_exception("non-supported expression", s.get_line(), s.get_pos()); - case sexpr::SYMBOL: - ctx.mk_const(s.get_symbol(), result); - return result; - } - return result; - } - - opt::objective_t get_objective_type(sexpr& s) { - if (!s.is_symbol()) - throw cmd_exception("invalid objective, symbol expected", s.get_line(), s.get_pos()); - symbol const & sym = s.get_symbol(); - if (sym == symbol("maximize")) return opt::MAXIMIZE; - if (sym == symbol("minimize")) return opt::MINIMIZE; - if (sym == symbol("lex")) return opt::LEX; - if (sym == symbol("box")) return opt::BOX; - if (sym == symbol("pareto")) return opt::PARETO; - throw cmd_exception("invalid objective, unexpected input", s.get_line(), s.get_pos()); - } - - opt::objective* sexpr2objective(cmd_context & ctx, sexpr& s) { - if (s.is_symbol()) - throw cmd_exception("invalid objective, more arguments expected ", s.get_symbol(), s.get_line(), s.get_pos()); - if (s.is_composite()) { - sexpr * head = s.get_child(0); - opt::objective_t type = get_objective_type(*head); - switch(type) { - case opt::MAXIMIZE: - case opt::MINIMIZE: { - if (s.get_num_children() != 2) - throw cmd_exception("invalid objective, wrong number of arguments ", s.get_line(), s.get_pos()); - sexpr * arg = s.get_child(1); - expr_ref term(sexpr2expr(ctx, *arg), ctx.m()); - if (type == opt::MAXIMIZE) - return opt::objective::mk_max(term); - else - return opt::objective::mk_min(term); - } - case opt::MAXSAT: { - if (s.get_num_children() != 2) - throw cmd_exception("invalid objective, wrong number of arguments ", s.get_line(), s.get_pos()); - sexpr * arg = s.get_child(1); - if (!arg->is_symbol()) - throw cmd_exception("invalid objective, symbol expected", s.get_line(), s.get_pos()); - symbol const & id = arg->get_symbol(); - // TODO: check whether id is declared via assert-weighted - return opt::objective::mk_maxsat(id); - } - case opt::LEX: - case opt::BOX: - case opt::PARETO: { - if (s.get_num_children() <= 2) - throw cmd_exception("invalid objective, wrong number of arguments ", s.get_line(), s.get_pos()); - unsigned num_children = s.get_num_children(); - ptr_vector args; - for (unsigned i = 1; i < num_children; i++) - args.push_back(sexpr2objective(ctx, *s.get_child(i))); - switch(type) { - case opt::LEX: - return opt::objective::mk_lex(args.size(), args.c_ptr()); - case opt::BOX: - return opt::objective::mk_box(args.size(), args.c_ptr()); - case opt::PARETO: - return opt::objective::mk_pareto(args.size(), args.c_ptr()); - } - } - } - } - return 0; - } - #endif diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 6858b3fbc..95e2c4f16 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -27,9 +27,7 @@ namespace opt { context::context(ast_manager& m): m(m), m_hard_constraints(m), - m_optsmt(m), - m_objs(m), - m_obj_util(m) + m_optsmt(m) { m_params.set_bool("model", true); m_params.set_bool("unsat_core", true); @@ -48,35 +46,36 @@ namespace opt { if (!m_maxsmts.find(id, ms)) { ms = alloc(maxsmt, m); m_maxsmts.insert(id, ms); + m_objectives.push_back(objective(m, id)); } ms->add(f, w); } - lbool context::execute(expr* _obj, bool committed) { - SASSERT(is_app(_obj)); - app* obj = to_app(_obj); + void context::add_objective(app* t, bool is_max) { + app_ref tr(m); + m_objectives.push_back(objective(is_max, tr)); + } - if (obj->get_family_id() == null_family_id) { - return execute_maxsat(obj, committed); - } - if (obj->get_family_id() != m_obj_util.get_family_id()) { - return execute_min_max(obj, committed, true); + lbool context::optimize() { + opt_solver& s = get_solver(); + solver::scoped_push _sp(s); + for (unsigned i = 0; i < m_hard_constraints.size(); ++i) { + s.assert_expr(m_hard_constraints[i].get()); } - switch (obj->get_decl_kind()) { - case OP_MINIMIZE: - return execute_min_max(to_app(obj->get_arg(0)), committed, false); - case OP_MAXIMIZE: - return execute_min_max(to_app(obj->get_arg(0)), committed, true); - case OP_LEX: - return execute_lex(obj); - case OP_BOX: - return execute_box(obj); - case OP_PARETO: - return execute_pareto(obj); - default: - UNREACHABLE(); - return l_undef; + if (m_objectives.size() == 1) { + return execute(m_objectives[0], false); + } + + symbol pri = m_params.get_sym("priority", symbol("lex")); + if (pri == symbol("pareto")) { + return execute_pareto(); + } + else if (pri == symbol("box")) { + return execute_box(); + } + else { + return execute_lex(); } } @@ -89,35 +88,44 @@ namespace opt { } - lbool context::execute_maxsat(app* obj, bool committed) { + lbool context::execute_maxsat(symbol const& id, bool committed) { maxsmt* ms; - VERIFY(m_maxsmts.find(obj->get_decl()->get_name(), ms)); + VERIFY(m_maxsmts.find(id, ms)); lbool result = (*ms)(get_solver()); if (committed) ms->commit_assignment(); return result; } + + lbool context::execute(objective const& obj, bool committed) { + switch(obj.m_type) { + case O_MAXIMIZE: return execute_min_max(obj.m_term, committed, true); + case O_MINIMIZE: return execute_min_max(obj.m_term, committed, false); + case O_MAXSMT: return execute_maxsat(obj.m_id, committed); + default: UNREACHABLE(); return l_undef; + } + } - lbool context::execute_lex(app* obj) { + lbool context::execute_lex() { lbool r = l_true; - for (unsigned i = 0; r == l_true && i < obj->get_num_args(); ++i) { - r = execute(obj->get_arg(i), true); + for (unsigned i = 0; r == l_true && i < m_objectives.size(); ++i) { + r = execute(m_objectives[i], true); } return r; } - lbool context::execute_box(app* obj) { + lbool context::execute_box() { lbool r = l_true; - for (unsigned i = 0; r == l_true && i < obj->get_num_args(); ++i) { + for (unsigned i = 0; r == l_true && i < m_objectives.size(); ++i) { push(); - r = execute(obj->get_arg(i), false); + r = execute(m_objectives[i], false); pop(1); } return r; } - lbool context::execute_pareto(app* obj) { + lbool context::execute_pareto() { // TODO: record a stream of results from pareto front - return execute_lex(obj); + return execute_lex(); } opt_solver& context::get_solver() { @@ -132,60 +140,42 @@ namespace opt { get_solver().pop(sz); } - lbool context::optimize(expr* objective) { - if (!objective) { - return optimize(); - } - opt_solver& s = get_solver(); - solver::scoped_push _sp(s); - for (unsigned i = 0; i < m_hard_constraints.size(); ++i) { - s.assert_expr(m_hard_constraints[i].get()); - } - return execute(objective, false); - } - - lbool context::optimize() { - // Construct objectives - expr_ref_vector objectives(m); - expr_ref objective(m); - map_t::iterator it = m_maxsmts.begin(), end = m_maxsmts.end(); - for (; it != end; ++it) { - objectives.push_back(m_obj_util.mk_maxsat(it->m_key)); - } - for (unsigned i = 0; i < m_objs.size(); ++i) { - expr_ref e(m_objs[i].get(), m); - app * o = m_ismaxs[i] ? m_obj_util.mk_max(e) : m_obj_util.mk_min(e); - objectives.push_back(o); - } - if (m_params.get_bool("pareto", false)) { - objective = m_obj_util.mk_pareto(objectives.size(), objectives.c_ptr()); - } - else { - objective = m_obj_util.mk_box(objectives.size(), objectives.c_ptr()); - } - return optimize(objective); - } - void context::display_assignment(std::ostream& out) { - map_t::iterator it = m_maxsmts.begin(), end = m_maxsmts.end(); - for (; it != end; ++it) { - maxsmt* ms = it->m_value; - if (it->m_key != symbol::null) { - out << it->m_key << " : "; + for (unsigned i = 0; i < m_objectives.size(); ++i) { + objective const& obj = m_objectives[i]; + switch(obj.m_type) { + case O_MAXSMT: { + symbol s = obj.m_id; + if (s != symbol::null) { + out << s << " : "; + } + maxsmt* ms = m_maxsmts.find(s); + out << ms->get_value() << "\n"; + break; + } + default: + break; } - out << ms->get_value() << "\n"; } m_optsmt.display_assignment(out); } void context::display_range_assignment(std::ostream& out) { - map_t::iterator it = m_maxsmts.begin(), end = m_maxsmts.end(); - for (; it != end; ++it) { - maxsmt* ms = it->m_value; - if (it->m_key != symbol::null) { - out << it->m_key << " : "; + for (unsigned i = 0; i < m_objectives.size(); ++i) { + objective const& obj = m_objectives[i]; + switch(obj.m_type) { + case O_MAXSMT: { + symbol s = obj.m_id; + if (s != symbol::null) { + out << s << " : "; + } + maxsmt* ms = m_maxsmts.find(s); + out << "[" << ms->get_lower() << ":" << ms->get_upper() << "]\n"; + break; + } + default: + break; } - out << "[" << ms->get_lower() << ":" << ms->get_upper() << "]\n"; } m_optsmt.display_range_assignment(out); } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 473abbb09..7bb3f86ed 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -29,7 +29,6 @@ Notes: #include "opt_solver.h" #include "optsmt.h" #include "maxsmt.h" -#include "objective_decl_plugin.h" namespace opt { @@ -37,24 +36,40 @@ namespace opt { class context { typedef map map_t; + enum objective_t { + O_MAXIMIZE, + O_MINIMIZE, + O_MAXSMT + }; + struct objective { + objective_t m_type; + app_ref m_term; // for maximize, minimize + symbol m_id; // for maxsmt + objective(bool is_max, app_ref& t): + m_type(is_max?O_MAXIMIZE:O_MINIMIZE), + m_term(t), + m_id() + {} + objective(ast_manager& m, symbol id): + m_type(O_MAXSMT), + m_term(m), + m_id(id) + {} + }; ast_manager& m; expr_ref_vector m_hard_constraints; ref m_solver; params_ref m_params; - optsmt m_optsmt; + optsmt m_optsmt; map_t m_maxsmts; - expr_ref_vector m_objs; - svector m_ismaxs; - objective_util m_obj_util; + vector m_objectives; public: context(ast_manager& m); ~context(); void add_soft_constraint(expr* f, rational const& w, symbol const& id); - void add_objective(app* t, bool is_max) { m_objs.push_back(t); m_ismaxs.push_back(is_max); } + void add_objective(app* t, bool is_max); void add_hard_constraint(expr* f) { m_hard_constraints.push_back(f); } - - lbool optimize(expr* objective); lbool optimize(); void set_cancel(bool f); @@ -68,12 +83,12 @@ namespace opt { private: void validate_feasibility(maxsmt& ms); - lbool execute(expr* obj, bool committed); + lbool execute(objective const& obj, bool committed); lbool execute_min_max(app* obj, bool committed, bool is_max); - lbool execute_maxsat(app* obj, bool committed); - lbool execute_lex(app* obj); - lbool execute_box(app* obj); - lbool execute_pareto(app* obj); + lbool execute_maxsat(symbol const& s, bool committed); + lbool execute_lex(); + lbool execute_box(); + lbool execute_pareto(); void push(); void pop(unsigned sz); diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index 4da07f305..40ff00a89 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -4,7 +4,7 @@ def_module_params('opt', params=(('timeout', UINT, UINT_MAX, 'set timeout'), ('engine', SYMBOL, 'basic', "select optimization engine: 'basic', 'farkas', 'symba'"), ('maxsat_engine', SYMBOL, 'fu_malik', "select engine for non-weighted maxsat: 'fu_malik', 'core_maxsat'"), - ('pareto', BOOL, False, 'return a Pareto front (as opposed to a bounding box)'), + ('priority', SYMBOL, 'lex', "select how to priortize objectives: 'lex' (lexicographic), 'pareto', or 'box'"), ('dump_benchmarks', BOOL, False, 'dump benchmarks for profiling'), ('debug_conflict', BOOL, False, 'debug conflict resolution'), )) From 838a32206c07658da6ee430a8bef62602d2b9077 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 3 Dec 2013 14:10:07 -0800 Subject: [PATCH 176/925] adjust parsing Signed-off-by: Nikolaj Bjorner --- src/opt/opt_cmds.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index db5906135..d4b28ab2f 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -148,15 +148,18 @@ public: virtual char const * get_main_descr() const { return "assert soft constraint with optional weight and identifier"; } // command invocation - virtual void prepare(cmd_context & ctx) {} + virtual void prepare(cmd_context & ctx) { + reset(ctx); + } + virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { if (m_idx == 0) return CPK_EXPR; return parametric_cmd::next_arg_kind(ctx); } virtual void init_pdescrs(cmd_context & ctx, param_descrs & p) { - p.insert("weight", CPK_UINT, "(default: 1) penalty of not satisfying constraint."); - p.insert("dweight", CPK_DOUBLE, "(default: 1.0) penalty as double of not satisfying constraint."); + p.insert("weight", CPK_NUMERAL, "(default: 1) penalty of not satisfying constraint."); + p.insert("dweight", CPK_DECIMAL, "(default: 1.0) penalty as double of not satisfying constraint."); p.insert("id", CPK_SYMBOL, "(default: null) partition identifier for soft constraints."); } @@ -175,14 +178,9 @@ public: virtual void execute(cmd_context & ctx) { symbol w("weight"); - rational weight = rational(ps().get_uint(symbol("weight"), 0)); + rational weight = ps().get_rat(symbol("weight"), rational(0)); if (weight.is_zero()) { - double d = ps().get_double(symbol("dweight"), 0.0); - if (d != 0.0) { - std::stringstream strm; - strm << d; - weight = rational(strm.str().c_str()); - } + weight = ps().get_rat(symbol("dweight"), rational(0)); } if (weight.is_zero()) { weight = rational::one(); From 222d4a8f01d582de2f8e26487e3d011f2537c941 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 3 Dec 2013 14:47:59 -0800 Subject: [PATCH 177/925] add sketch of C-based API Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 2 +- src/api/api_opt.cpp | 113 ++++++++++++++++++++++++++++++++++++++++++ src/api/z3_api.h | 1 + 3 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 src/api/api_opt.cpp diff --git a/scripts/mk_project.py b/scripts/mk_project.py index b52934dfe..be95032b7 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -69,7 +69,7 @@ def init_project_def(): add_lib('smtparser', ['portfolio'], 'parsers/smt') add_lib('opt', ['smt', 'smtlogic_tactics'], 'opt') API_files = ['z3_api.h', 'z3_algebraic.h', 'z3_polynomial.h', 'z3_rcf.h'] - add_lib('api', ['portfolio', 'user_plugin', 'smtparser', 'realclosure'], + add_lib('api', ['portfolio', 'user_plugin', 'smtparser', 'realclosure','opt'], includes2install=['z3.h', 'z3_v1.h', 'z3_macros.h'] + API_files) add_exe('shell', ['api', 'sat', 'extra_cmds','opt'], exe_name='z3') add_exe('test', ['api', 'fuzzing'], exe_name='test-z3', install=False) diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp new file mode 100644 index 000000000..4f9609840 --- /dev/null +++ b/src/api/api_opt.cpp @@ -0,0 +1,113 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + api_opt.cpp + +Abstract: + API for optimization + +Author: + + Nikolaj Bjorner (nbjorner) 2013-12-3. + +Revision History: + +--*/ +#include +#include"z3.h" +#include"api_log_macros.h" +#include"api_context.h" +#include"api_util.h" +#include"opt_context.h" + +extern "C" { + + struct Z3_optimize_ref : public api::object { + opt::context* m_opt; + Z3_optimize_ref():m_opt(0) {} + virtual ~Z3_optimize_ref() { dealloc(m_opt); } + }; + inline Z3_optimize_ref * to_optimize(Z3_optimize o) { return reinterpret_cast(o); } + inline Z3_optimize of_optimize(Z3_optimize_ref * o) { return reinterpret_cast(o); } + + Z3_optimize Z3_API Z3_mk_optimize(Z3_context c) { + return 0; + } + + void Z3_API Z3_optimize_inc_ref(Z3_context c, Z3_optimize o) { + + } + + void Z3_API Z3_optimize_dec_ref(Z3_context c, Z3_optimize o) { + + } + + void Z3_API Z3_optimize_assert(Z3_context c, Z3_optimize o, Z3_ast a) { + + } + + void Z3_API Z3_optimize_assert_soft(Z3_context c, Z3_optimize o, Z3_ast a, Z3_string weight, Z3_symbol id) { + + } + + void Z3_API Z3_optimize_maximize(Z3_context, Z3_optimize o, Z3_ast t) { + + } + + void Z3_API Z3_optimize_minimize(Z3_context, Z3_optimize o, Z3_ast t) { + + } + + Z3_lbool Z3_API Z3_optimize_check(Z3_context c) { + return Z3_L_UNDEF; + } + + void Z3_API Z3_optimize_set_params(Z3_context c, Z3_optimize o, Z3_params p) { + + } + + Z3_param_descrs Z3_API Z3_optimize_get_param_descrs(Z3_context c, Z3_optimize o) { + return 0; + } + + + // get lower value or current approximation + Z3_ast Z3_API Z3_optimize_get_lower(Z3_context c, Z3_optimize o, unsigned idx) { + return 0; + } + + // get upper or current approximation + Z3_ast Z3_API Z3_optimize_get_upper(Z3_context c, Z3_optimize o, unsigned idx) { + return 0; + } + +#if 0 + + /** + \brief version with assumptions. + + */ + + void check_assumptions; + + /** + \brief retrieve the next answer. There are three modes: + + - the optimization context has been configured to produce partial results. + It returns with L_UNDEF and an partial result and caller can retrieve + the results by querying get_lower and get_upper. + - The full result was produced and it returned L_TRUE. + Retrieve the next result that has the same objective optimal. + - The context was configured to compute a Pareto front. + Search proceeds incrementally identifying feasible boxes. + Every return value is a new sub-box or set of sub-boxes. + */ + void Z3_optimize_get_next(Z3_context c, Z3_optimize o) { + } + + // +#endif + +}; diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 08e645684..d7fea33d7 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -47,6 +47,7 @@ DEFINE_TYPE(Z3_func_interp); #define Z3_func_interp_opt Z3_func_interp DEFINE_TYPE(Z3_func_entry); DEFINE_TYPE(Z3_fixedpoint); +DEFINE_TYPE(Z3_optimize); DEFINE_TYPE(Z3_rcf_num); DEFINE_VOID(Z3_theory_data); #endif From 4719aa11bb15b4e5f7e8ce3fdb0f3353d0c4a2a6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 3 Dec 2013 17:00:34 -0800 Subject: [PATCH 178/925] backfilling API functions Signed-off-by: Nikolaj Bjorner --- src/api/api_opt.cpp | 102 +++++++++++++++++++++++++++++----- src/api/z3_api.h | 132 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 220 insertions(+), 14 deletions(-) diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index 4f9609840..497f988cf 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -21,6 +21,8 @@ Revision History: #include"api_context.h" #include"api_util.h" #include"opt_context.h" +#include"cancel_eh.h" +#include"scoped_timer.h" extern "C" { @@ -31,55 +33,127 @@ extern "C" { }; inline Z3_optimize_ref * to_optimize(Z3_optimize o) { return reinterpret_cast(o); } inline Z3_optimize of_optimize(Z3_optimize_ref * o) { return reinterpret_cast(o); } + inline opt::context& to_optimize_ref(Z3_optimize o) { return *to_optimize(o)->m_opt; } Z3_optimize Z3_API Z3_mk_optimize(Z3_context c) { - return 0; + Z3_TRY; + LOG_Z3_mk_optimize(c); + RESET_ERROR_CODE(); + Z3_optimize_ref * o = alloc(Z3_optimize_ref); + o->m_opt = alloc(opt::context,mk_c(c)->m()); + mk_c(c)->save_object(o); + RETURN_Z3(of_optimize(o)); + Z3_CATCH_RETURN(0); } void Z3_API Z3_optimize_inc_ref(Z3_context c, Z3_optimize o) { - + Z3_TRY; + LOG_Z3_optimize_inc_ref(c, o); + RESET_ERROR_CODE(); + to_optimize(o)->inc_ref(); + Z3_CATCH; } void Z3_API Z3_optimize_dec_ref(Z3_context c, Z3_optimize o) { - + Z3_TRY; + LOG_Z3_optimize_dec_ref(c, o); + RESET_ERROR_CODE(); + to_optimize(o)->dec_ref(); + Z3_CATCH; } void Z3_API Z3_optimize_assert(Z3_context c, Z3_optimize o, Z3_ast a) { - + Z3_TRY; + LOG_Z3_optimize_assert(c, o, a); + RESET_ERROR_CODE(); + CHECK_FORMULA(a,); + to_optimize_ref(o).add_hard_constraint(to_expr(a)); + Z3_CATCH; } void Z3_API Z3_optimize_assert_soft(Z3_context c, Z3_optimize o, Z3_ast a, Z3_string weight, Z3_symbol id) { - + Z3_TRY; + LOG_Z3_optimize_assert_soft(c, o, a, weight, id); + RESET_ERROR_CODE(); + CHECK_FORMULA(a,); + rational w("weight"); + to_optimize_ref(o).add_soft_constraint(to_expr(a), w, to_symbol(id)); + Z3_CATCH; } - void Z3_API Z3_optimize_maximize(Z3_context, Z3_optimize o, Z3_ast t) { - + void Z3_API Z3_optimize_maximize(Z3_context c, Z3_optimize o, Z3_ast t) { + Z3_TRY; + LOG_Z3_optimize_maximize(c, o, t); + RESET_ERROR_CODE(); + CHECK_VALID_AST(t,); + to_optimize_ref(o).add_objective(to_app(t), true); + Z3_CATCH; } - void Z3_API Z3_optimize_minimize(Z3_context, Z3_optimize o, Z3_ast t) { - + void Z3_API Z3_optimize_minimize(Z3_context c, Z3_optimize o, Z3_ast t) { + Z3_TRY; + LOG_Z3_optimize_minimize(c, o, t); + RESET_ERROR_CODE(); + CHECK_VALID_AST(t,); + to_optimize_ref(o).add_objective(to_app(t), false); + Z3_CATCH; } - Z3_lbool Z3_API Z3_optimize_check(Z3_context c) { - return Z3_L_UNDEF; + Z3_lbool Z3_API Z3_optimize_check(Z3_context c, Z3_optimize o) { + Z3_TRY; + LOG_Z3_optimize_check(c, o); + RESET_ERROR_CODE(); + lbool r = l_undef; + cancel_eh eh(to_optimize_ref(o)); + unsigned timeout = 0; // to_optimize(o)->m_params.get_uint("timeout", mk_c(c)->get_timeout()); + api::context::set_interruptable si(*(mk_c(c)), eh); + { + scoped_timer timer(timeout, &eh); + try { + r = to_optimize_ref(o).optimize(); + } + catch (z3_exception& ex) { + mk_c(c)->handle_exception(ex); + r = l_undef; + } + // to_optimize_ref(d).cleanup(); + } + return of_lbool(r); + Z3_CATCH_RETURN(Z3_L_UNDEF); } void Z3_API Z3_optimize_set_params(Z3_context c, Z3_optimize o, Z3_params p) { - + Z3_TRY; + LOG_Z3_optimize_set_params(c, o, p); + RESET_ERROR_CODE(); + param_descrs descrs; + to_optimize_ref(o).collect_param_descrs(descrs); + to_params(p)->m_params.validate(descrs); + to_optimize_ref(o).updt_params(to_param_ref(p)); + Z3_CATCH; } Z3_param_descrs Z3_API Z3_optimize_get_param_descrs(Z3_context c, Z3_optimize o) { - return 0; + Z3_TRY; + LOG_Z3_optimize_get_param_descrs(c, o); + RESET_ERROR_CODE(); + Z3_param_descrs_ref * d = alloc(Z3_param_descrs_ref); + mk_c(c)->save_object(d); + to_optimize_ref(o).collect_param_descrs(d->m_descrs); + Z3_param_descrs r = of_param_descrs(d); + RETURN_Z3(r); + Z3_CATCH_RETURN(0); } - // get lower value or current approximation Z3_ast Z3_API Z3_optimize_get_lower(Z3_context c, Z3_optimize o, unsigned idx) { + NOT_IMPLEMENTED_YET(); return 0; } // get upper or current approximation Z3_ast Z3_API Z3_optimize_get_upper(Z3_context c, Z3_optimize o, unsigned idx) { + NOT_IMPLEMENTED_YET(); return 0; } diff --git a/src/api/z3_api.h b/src/api/z3_api.h index d7fea33d7..f6064d543 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -86,6 +86,7 @@ DEFINE_VOID(Z3_theory_data); - \c Z3_func_interp: interpretation of a function in a model. - \c Z3_func_entry: representation of the value of a \c Z3_func_interp at a particular point. - \c Z3_fixedpoint: context for the recursive predicate solver. + - \c Z3_optimize: context for solving optimization queries. - \c Z3_ast_vector: vector of \c Z3_ast objects. - \c Z3_ast_map: mapping from \c Z3_ast to \c Z3_ast objects. - \c Z3_goal: set of formulas that can be solved and/or transformed using tactics and solvers. @@ -1205,6 +1206,7 @@ typedef enum def_Type('FUNC_INTERP', 'Z3_func_interp', 'FuncInterpObj') def_Type('FUNC_ENTRY', 'Z3_func_entry', 'FuncEntryObj') def_Type('FIXEDPOINT', 'Z3_fixedpoint', 'FixedpointObj') + def_Type('OPTIMIZE', 'Z3_optimize', 'OptimizeObj') def_Type('PARAM_DESCRS', 'Z3_param_descrs', 'ParamDescrs') def_Type('RCF_NUM', 'Z3_rcf_num', 'RCFNumObj') */ @@ -5935,6 +5937,136 @@ END_MLAPI_EXCLUDE #endif #endif + + +#ifdef CorML4 + /** + @name Optimize facilities + */ + /*@{*/ + + /** + \brief Create a new optimize context. + + \conly \remark User must use #Z3_optimize_inc_ref and #Z3_optimize_dec_ref to manage optimize objects. + \conly Even if the context was created using #Z3_mk_context instead of #Z3_mk_context_rc. + + def_API('Z3_mk_optimize', OPTIMIZE, (_in(CONTEXT), )) + */ + Z3_optimize Z3_API Z3_mk_optimize(__in Z3_context c); + +#ifdef Conly + /** + \brief Increment the reference counter of the given optimize context + + def_API('Z3_optimize_inc_ref', VOID, (_in(CONTEXT), _in(OPTIMIZE))) + */ + void Z3_API Z3_optimize_inc_ref(__in Z3_context c,__in Z3_optimize d); + + /** + \brief Decrement the reference counter of the given optimize context. + + def_API('Z3_optimize_dec_ref', VOID, (_in(CONTEXT), _in(OPTIMIZE))) + */ + void Z3_API Z3_optimize_dec_ref(__in Z3_context c,__in Z3_optimize d); +#endif + + /** + \brief Assert hard constraint to the optimization context. + + def_API('Z3_optimize_assert', VOID, (_in(CONTEXT), _in(OPTIMIZE), _in(AST))) + */ + void Z3_API Z3_optimize_assert(Z3_context c, Z3_optimize o, Z3_ast a); + + + /** + \brief Assert soft constraint to the optimization context. + \param c - context + \param o - optimization context + \param a - formula + \param weight - a positive weight, penalty for violating soft constraint + \param id - optional identifier to group soft constraints + + def_API('Z3_optimize_assert_soft', VOID, (_in(CONTEXT), _in(OPTIMIZE), _in(AST), _in(STRING), _in(SYMBOL))) + */ + void Z3_API Z3_optimize_assert_soft(Z3_context c, Z3_optimize o, Z3_ast a, Z3_string weight, Z3_symbol id); + + + /** + \brief Add a maximiztion constraint. + \param c - context + \param o - optimization context + \param a - arithmetical term + def_API('Z3_optimize_maximize', VOID, (_in(CONTEXT), _in(OPTIMIZE), _in(AST))) + */ + void Z3_API Z3_optimize_maximize(Z3_context, Z3_optimize o, Z3_ast t); + + /** + \brief Add a minimiztion constraint. + \param c - context + \param o - optimization context + \param a - arithmetical term + + def_API('Z3_optimize_minimize', VOID, (_in(CONTEXT), _in(OPTIMIZE), _in(AST))) + */ + void Z3_API Z3_optimize_minimize(Z3_context, Z3_optimize o, Z3_ast t); + + /** + \brief Check consistency and produce optimal values. + \param c - context + \param o - optimization context + + def_API('Z3_optimize_check', INT, (_in(CONTEXT), _in(OPTIMIZE))) + */ + Z3_lbool Z3_API Z3_optimize_check(Z3_context c, Z3_optimize o); + + + /** + \brief Set parameters on optimization context. + + \param c - context + \param o - optimization context + \param p - parameters + + def_API('Z3_optimize_set_params', VOID, (_in(CONTEXT), _in(OPTIMIZE), _in(PARAMS))) + */ + void Z3_API Z3_optimize_set_params(Z3_context c, Z3_optimize o, Z3_params p); + + /** + \brief Return the parameter description set for the given optimize object. + + \param c - context + \param o - optimization context + + def_API('Z3_optimize_get_param_descrs', PARAM_DESCRS, (_in(CONTEXT), _in(OPTIMIZE))) + */ + Z3_param_descrs Z3_API Z3_optimize_get_param_descrs(Z3_context c, Z3_optimize o); + + /** + \brief Retrieve lower bound value or approximation for the i'th optimization objective. + + \param c - context + \param o - optimization context + \param idx - index of optimization objective + + def_API('Z3_optimize_get_lower', AST, (_in(CONTEXT), _in(OPTIMIZE), _in(UINT))) + */ + Z3_ast Z3_API Z3_optimize_get_lower(Z3_context c, Z3_optimize o, unsigned idx); + + /** + \brief Retrieve upper bound value or approximation for the i'th optimization objective. + + \param c - context + \param o - optimization context + \param idx - index of optimization objective + + def_API('Z3_optimize_get_upper', AST, (_in(CONTEXT), _in(OPTIMIZE), _in(UINT))) + */ + Z3_ast Z3_API Z3_optimize_get_upper(Z3_context c, Z3_optimize o, unsigned idx); + + +#endif + #ifdef CorML4 /*@}*/ From 9e2908c3f5e02755a0c0b3e1cce7829fbb388827 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 3 Dec 2013 17:46:52 -0800 Subject: [PATCH 179/925] exposing lower/upper Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 27 ++++++++++++++++++++++++++- src/opt/opt_context.h | 4 ++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 95e2c4f16..ff6955b7b 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -108,7 +108,7 @@ namespace opt { lbool context::execute_lex() { lbool r = l_true; for (unsigned i = 0; r == l_true && i < m_objectives.size(); ++i) { - r = execute(m_objectives[i], true); + r = execute(m_objectives[i], i + 1 < m_objectives.size()); } return r; } @@ -179,6 +179,31 @@ namespace opt { } m_optsmt.display_range_assignment(out); } + + expr_ref context::get_lower(unsigned idx) { + NOT_IMPLEMENTED_YET(); + if (idx > m_objectives.size()) { + throw default_exception("index out of bounds"); + } + objective const& obj = m_objectives[idx]; + switch(obj.m_type) { + case O_MAXSMT: { + maxsmt* ms = m_maxsmts.find(obj.m_id); + inf_eps l = ms->get_lower(); + break; + } + case O_MAXIMIZE: + case O_MINIMIZE: + break; + } + + return expr_ref(0,m); + } + + expr_ref context::get_upper(unsigned idx) { + NOT_IMPLEMENTED_YET(); + return expr_ref(0, m); + } void context::set_cancel(bool f) { if (m_solver) { diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 7bb3f86ed..30b7bf77b 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -80,6 +80,10 @@ namespace opt { void display_range_assignment(std::ostream& out); static void collect_param_descrs(param_descrs & r); void updt_params(params_ref& p); + + expr_ref get_lower(unsigned idx); + expr_ref get_upper(unsigned idx); + private: void validate_feasibility(maxsmt& ms); From e3fe80fd4d2e00af1b19ba437a384effa2167ab3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 3 Dec 2013 20:20:24 -0800 Subject: [PATCH 180/925] add .NET interface and finish C interface for optimization Signed-off-by: Nikolaj Bjorner --- src/api/api_opt.cpp | 18 +++- src/api/dotnet/Context.cs | 16 ++++ src/api/dotnet/Optimize.cs | 166 +++++++++++++++++++++++++++++++++++++ src/opt/opt_context.cpp | 81 ++++++++++++------ src/opt/opt_context.h | 12 ++- 5 files changed, 261 insertions(+), 32 deletions(-) create mode 100644 src/api/dotnet/Optimize.cs diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index 497f988cf..afc33e396 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -147,14 +147,24 @@ extern "C" { // get lower value or current approximation Z3_ast Z3_API Z3_optimize_get_lower(Z3_context c, Z3_optimize o, unsigned idx) { - NOT_IMPLEMENTED_YET(); - return 0; + Z3_TRY; + LOG_Z3_optimize_get_lower(c, o, idx); + RESET_ERROR_CODE(); + expr_ref e = to_optimize_ref(o).get_lower(idx); + mk_c(c)->save_ast_trail(e); + RETURN_Z3(of_expr(e)); + Z3_CATCH_RETURN(0); } // get upper or current approximation Z3_ast Z3_API Z3_optimize_get_upper(Z3_context c, Z3_optimize o, unsigned idx) { - NOT_IMPLEMENTED_YET(); - return 0; + Z3_TRY; + LOG_Z3_optimize_get_upper(c, o, idx); + RESET_ERROR_CODE(); + expr_ref e = to_optimize_ref(o).get_upper(idx); + mk_c(c)->save_ast_trail(e); + RETURN_Z3(of_expr(e)); + Z3_CATCH_RETURN(0); } #if 0 diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 8ac0c8f98..5d3e1ad7a 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -3466,6 +3466,18 @@ namespace Microsoft.Z3 } #endregion + #region Optimization + /// + /// Create an Optimization context. + /// + public Optimize MkOptimize() + { + Contract.Ensures(Contract.Result() != null); + + return new Optimize(this); + } + #endregion + #region Miscellaneous /// @@ -3639,6 +3651,7 @@ namespace Microsoft.Z3 Contract.Invariant(m_Statistics_DRQ != null); Contract.Invariant(m_Tactic_DRQ != null); Contract.Invariant(m_Fixedpoint_DRQ != null); + Contract.Invariant(m_Optimize_DRQ != null); } readonly private AST.DecRefQueue m_AST_DRQ = new AST.DecRefQueue(); @@ -3656,6 +3669,7 @@ namespace Microsoft.Z3 readonly private Statistics.DecRefQueue m_Statistics_DRQ = new Statistics.DecRefQueue(); readonly private Tactic.DecRefQueue m_Tactic_DRQ = new Tactic.DecRefQueue(); readonly private Fixedpoint.DecRefQueue m_Fixedpoint_DRQ = new Fixedpoint.DecRefQueue(); + readonly private Optimize.DecRefQueue m_Optimize_DRQ = new Optimize.DecRefQueue(); internal AST.DecRefQueue AST_DRQ { get { Contract.Ensures(Contract.Result() != null); return m_AST_DRQ; } } internal ASTMap.DecRefQueue ASTMap_DRQ { get { Contract.Ensures(Contract.Result() != null); return m_ASTMap_DRQ; } } @@ -3672,6 +3686,7 @@ namespace Microsoft.Z3 internal Statistics.DecRefQueue Statistics_DRQ { get { Contract.Ensures(Contract.Result() != null); return m_Statistics_DRQ; } } internal Tactic.DecRefQueue Tactic_DRQ { get { Contract.Ensures(Contract.Result() != null); return m_Tactic_DRQ; } } internal Fixedpoint.DecRefQueue Fixedpoint_DRQ { get { Contract.Ensures(Contract.Result() != null); return m_Fixedpoint_DRQ; } } + internal Optimize.DecRefQueue Optimize_DRQ { get { Contract.Ensures(Contract.Result() != null); return m_Optimize_DRQ; } } internal uint refCount = 0; @@ -3715,6 +3730,7 @@ namespace Microsoft.Z3 Statistics_DRQ.Clear(this); Tactic_DRQ.Clear(this); Fixedpoint_DRQ.Clear(this); + Optimize_DRQ.Clear(this); m_boolSort = null; m_intSort = null; diff --git a/src/api/dotnet/Optimize.cs b/src/api/dotnet/Optimize.cs new file mode 100644 index 000000000..3b54dca20 --- /dev/null +++ b/src/api/dotnet/Optimize.cs @@ -0,0 +1,166 @@ +/*++ +Copyright (c) 2012 Microsoft Corporation + +Module Name: + + Optimize.cs + +Abstract: + + Z3 Managed API: Optimizes + +Author: + + Nikolaj Bjorner (nbjorner) 2013-12-03 + +Notes: + +--*/ + +using System; +using System.Diagnostics.Contracts; + +namespace Microsoft.Z3 +{ + /// + /// Object for managing optimizization context + /// + [ContractVerification(true)] + public class Optimize : Z3Object + { + +#if false + /// + /// A string that describes all available optimize solver parameters. + /// + public string Help + { + get + { + Contract.Ensures(Contract.Result() != null); + return Native.Z3_optimize_get_help(Context.nCtx, NativeObject); + } + } +#endif + + /// + /// Sets the optimize solver parameters. + /// + public Params Parameters + { + set + { + Contract.Requires(value != null); + Context.CheckContextMatch(value); + Native.Z3_optimize_set_params(Context.nCtx, NativeObject, value.NativeObject); + } + } + + /// + /// Retrieves parameter descriptions for Optimize solver. + /// + public ParamDescrs ParameterDescriptions + { + get { return new ParamDescrs(Context, Native.Z3_optimize_get_param_descrs(Context.nCtx, NativeObject)); } + } + + + /// + /// Assert a constraint (or multiple) into the optimize solver. + /// + public void Assert(params BoolExpr[] constraints) + { + Contract.Requires(constraints != null); + Contract.Requires(Contract.ForAll(constraints, c => c != null)); + + Context.CheckContextMatch(constraints); + foreach (BoolExpr a in constraints) + { + Native.Z3_optimize_assert(Context.nCtx, NativeObject, a.NativeObject); + } + } + + /// + /// Alias for Assert. + /// + public void Add(params BoolExpr[] constraints) + { + Assert(constraints); + } + + /// + /// Assert soft constraint + /// + public void AssertSoft(BoolExpr constraint, uint weight, string group) + { + Context.CheckContextMatch(constraint); + Symbol s = Context.MkSymbol(group); + Native.Z3_optimize_assert_soft(Context.nCtx, NativeObject, constraint.NativeObject, weight.ToString(), s.NativeObject); + } + + + public Status Check() { + Z3_lbool r = (Z3_lbool)Native.Z3_optimize_check(Context.nCtx, NativeObject); + switch (r) + { + case Z3_lbool.Z3_L_TRUE: return Status.SATISFIABLE; + case Z3_lbool.Z3_L_FALSE: return Status.UNSATISFIABLE; + default: return Status.UNKNOWN; + } + } + + public void Maximize(ArithExpr e) { + Native.Z3_optimize_maximize(Context.nCtx, NativeObject, e.NativeObject); + } + + public void Minimize(ArithExpr e) { + Native.Z3_optimize_minimize(Context.nCtx, NativeObject, e.NativeObject); + } + + public ArithExpr GetLower(uint index) { + return new ArithExpr(Context, Native.Z3_optimize_get_lower(Context.nCtx, NativeObject, index)); + } + + public ArithExpr GetUpper(uint index) { + return new ArithExpr(Context, Native.Z3_optimize_get_upper(Context.nCtx, NativeObject, index)); + } + + #region Internal + internal Optimize(Context ctx, IntPtr obj) + : base(ctx, obj) + { + Contract.Requires(ctx != null); + } + internal Optimize(Context ctx) + : base(ctx, Native.Z3_mk_optimize(ctx.nCtx)) + { + Contract.Requires(ctx != null); + } + + internal class DecRefQueue : IDecRefQueue + { + public override void IncRef(Context ctx, IntPtr obj) + { + Native.Z3_optimize_inc_ref(ctx.nCtx, obj); + } + + public override void DecRef(Context ctx, IntPtr obj) + { + Native.Z3_optimize_dec_ref(ctx.nCtx, obj); + } + }; + + internal override void IncRef(IntPtr o) + { + Context.Optimize_DRQ.IncAndClear(Context, o); + base.IncRef(o); + } + + internal override void DecRef(IntPtr o) + { + Context.Optimize_DRQ.Add(o); + base.DecRef(o); + } + #endregion + } +} diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index ff6955b7b..fafd88ecf 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -21,6 +21,7 @@ Notes: #include "ast_pp.h" #include "opt_solver.h" #include "opt_params.hpp" +#include "arith_decl_plugin.h" namespace opt { @@ -52,8 +53,10 @@ namespace opt { } void context::add_objective(app* t, bool is_max) { - app_ref tr(m); - m_objectives.push_back(objective(is_max, tr)); + app_ref tr(t, m); + unsigned index = m_optsmt.get_num_objectives(); + m_optsmt.add(t, is_max); + m_objectives.push_back(objective(is_max, tr, index)); } lbool context::optimize() { @@ -79,27 +82,26 @@ namespace opt { } } - lbool context::execute_min_max(app* obj, bool committed, bool is_max) { - // HACK: reuse m_optsmt but add only a single objective each round - m_optsmt.add(obj, is_max); + lbool context::execute_min_max(unsigned index, bool committed, bool is_max) { + // HACK: reuse m_optsmt without regard for box reuse and not considering + // use-case of lex. lbool result = m_optsmt(get_solver()); - if (committed) m_optsmt.commit_assignment(0); + if (committed) m_optsmt.commit_assignment(index); return result; } lbool context::execute_maxsat(symbol const& id, bool committed) { - maxsmt* ms; - VERIFY(m_maxsmts.find(id, ms)); - lbool result = (*ms)(get_solver()); - if (committed) ms->commit_assignment(); + maxsmt& ms = *m_maxsmts.find(id); + lbool result = ms(get_solver()); + if (committed) ms.commit_assignment(); return result; } lbool context::execute(objective const& obj, bool committed) { switch(obj.m_type) { - case O_MAXIMIZE: return execute_min_max(obj.m_term, committed, true); - case O_MINIMIZE: return execute_min_max(obj.m_term, committed, false); + case O_MAXIMIZE: return execute_min_max(obj.m_index, committed, true); + case O_MINIMIZE: return execute_min_max(obj.m_index, committed, false); case O_MAXSMT: return execute_maxsat(obj.m_id, committed); default: UNREACHABLE(); return l_undef; } @@ -181,28 +183,59 @@ namespace opt { } expr_ref context::get_lower(unsigned idx) { - NOT_IMPLEMENTED_YET(); if (idx > m_objectives.size()) { throw default_exception("index out of bounds"); } objective const& obj = m_objectives[idx]; switch(obj.m_type) { - case O_MAXSMT: { - maxsmt* ms = m_maxsmts.find(obj.m_id); - inf_eps l = ms->get_lower(); - break; - } - case O_MAXIMIZE: + case O_MAXSMT: + return to_expr(m_maxsmts.find(obj.m_id)->get_lower()); case O_MINIMIZE: - break; + case O_MAXIMIZE: + return to_expr(m_optsmt.get_lower(obj.m_index)); + default: + UNREACHABLE(); + return expr_ref(m); } - - return expr_ref(0,m); } expr_ref context::get_upper(unsigned idx) { - NOT_IMPLEMENTED_YET(); - return expr_ref(0, m); + if (idx > m_objectives.size()) { + throw default_exception("index out of bounds"); + } + objective const& obj = m_objectives[idx]; + switch(obj.m_type) { + case O_MAXSMT: + return to_expr(m_maxsmts.find(obj.m_id)->get_upper()); + case O_MINIMIZE: + case O_MAXIMIZE: + return to_expr(m_optsmt.get_upper(obj.m_index)); + default: + UNREACHABLE(); + return expr_ref(m); + } + } + + expr_ref context::to_expr(inf_eps const& n) { + rational inf = n.get_infinity(); + rational r = n.get_rational(); + rational eps = n.get_infinitesimal(); + expr_ref_vector args(m); + arith_util a(m); + if (!inf.is_zero()) { + args.push_back(a.mk_mul(a.mk_numeral(inf, inf.is_int()), m.mk_const(symbol("oo"), a.mk_int()))); + } + if (!r.is_zero()) { + args.push_back(a.mk_numeral(r, r.is_int())); + } + if (!eps.is_zero()) { + args.push_back(a.mk_mul(a.mk_numeral(eps, eps.is_int()), m.mk_const(symbol("epsilon"), a.mk_int()))); + } + switch(args.size()) { + case 0: return expr_ref(a.mk_numeral(rational(0), true), m); + case 1: return expr_ref(args[0].get(), m); + default: return expr_ref(a.mk_add(args.size(), args.c_ptr()), m); + } } void context::set_cancel(bool f) { diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 30b7bf77b..9a0b49541 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -45,15 +45,18 @@ namespace opt { objective_t m_type; app_ref m_term; // for maximize, minimize symbol m_id; // for maxsmt - objective(bool is_max, app_ref& t): + unsigned m_index; + objective(bool is_max, app_ref& t, unsigned idx): m_type(is_max?O_MAXIMIZE:O_MINIMIZE), m_term(t), - m_id() + m_id(), + m_index(idx) {} objective(ast_manager& m, symbol id): m_type(O_MAXSMT), m_term(m), - m_id(id) + m_id(id), + m_index(0) {} }; ast_manager& m; @@ -88,11 +91,12 @@ namespace opt { void validate_feasibility(maxsmt& ms); lbool execute(objective const& obj, bool committed); - lbool execute_min_max(app* obj, bool committed, bool is_max); + lbool execute_min_max(unsigned index, bool committed, bool is_max); lbool execute_maxsat(symbol const& s, bool committed); lbool execute_lex(); lbool execute_box(); lbool execute_pareto(); + expr_ref to_expr(inf_eps const& n); void push(); void pop(unsigned sz); From b9d433e3e5dd75a7e3aeaa51f9fae7953b03f716 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 3 Dec 2013 21:10:54 -0800 Subject: [PATCH 181/925] fix bug in conflict resoltion tracking decision variables Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 2ef202f76..ed451c6fd 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -616,7 +616,7 @@ namespace smt { } TRACE("pb", - tout << "assign: " << c.lit() << " <- " << is_true << "\n"; + tout << "assign: " << c.lit() << "\n"; display(tout, c); ); if (maxsum < c.k()) { @@ -1243,6 +1243,10 @@ namespace smt { TRACE("pb", tout << "binary: " << js.get_literal() << "\n";); break; case b_justification::AXIOM: + if (ctx.get_assign_level(v) > ctx.get_base_level()) { + m_ineq_literals.push_back(conseq); + } + TRACE("pb", tout << "axiom " << conseq << "\n";); break; case b_justification::JUSTIFICATION: { justification& j = *js.get_justification(); @@ -1267,7 +1271,11 @@ namespace smt { unset_mark(m_lemma.lit(i)); } - TRACE("pb", display(tout << "lemma: ", m_lemma);); + TRACE("pb", + for (unsigned i = 0; i < m_ineq_literals.size(); ++i) { + tout << m_ineq_literals[i] << " "; + } + display(tout << "=> ", m_lemma);); hoist_maximal_values(); From 8fa0d6e4f3cfaa92ac12bfeb2669e167ada35f79 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 4 Dec 2013 08:35:27 -0800 Subject: [PATCH 182/925] bug fixes exposed from regression tests Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 45 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index ed451c6fd..abd29c043 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -387,7 +387,7 @@ namespace smt { } if (ctx.b_internalized(arg)) { bv = ctx.get_bool_var(arg); - if (null_theory_var == ctx.get_var_theory(bv)) { + if (is_uninterp(arg) && null_theory_var == ctx.get_var_theory(bv)) { ctx.set_var_theory(bv, get_id()); } has_bv = (ctx.get_var_theory(bv) == get_id()); @@ -423,6 +423,7 @@ namespace smt { expr_ref tmp(m), fml(m); tmp = m.mk_fresh_const("pb_proxy",m.mk_bool_sort()); fml = m.mk_iff(tmp, arg); + TRACE("pb", tout << "create proxy " << fml << "\n";); ctx.internalize(fml, false); SASSERT(ctx.b_internalized(tmp)); bv = ctx.get_bool_var(tmp); @@ -537,8 +538,9 @@ namespace smt { break; } } - TRACE("pb", display(tout << "validate: ", c); - tout << "sum: " << sum << " " << maxsum << " " << ctx.get_assignment(c.lit()) << "\n"; + TRACE("pb", display(tout << "validate: ", c, true); + tout << "sum: " << sum << " " << maxsum << " "; + tout << ctx.get_assignment(c.lit()) << "\n"; ); SASSERT(sum <= maxsum); @@ -551,6 +553,7 @@ namespace smt { context& ctx = get_context(); ptr_vector* ineqs = 0; literal nlit(v, is_true); + TRACE("pb", tout << "assign: " << ~nlit << "\n";); if (m_watch.find(nlit.index(), ineqs)) { for (unsigned i = 0; i < ineqs->size(); ++i) { if (assign_watch(v, is_true, *ineqs, i)) { @@ -609,10 +612,15 @@ namespace smt { context& ctx = get_context(); numeral maxsum = numeral::zero(); + numeral mininc = numeral::zero(); for (unsigned i = 0; i < c.size(); ++i) { - if (ctx.get_assignment(c.lit(i)) != l_false) { + lbool asgn = ctx.get_assignment(c.lit(i)); + if (asgn != l_false) { maxsum += c.coeff(i); } + if (asgn == l_undef && (mininc.is_zero() || mininc > c.coeff(i))) { + mininc = c.coeff(i); + } } TRACE("pb", @@ -635,6 +643,17 @@ namespace smt { SASSERT(c.max_sum() >= c.k()); m_assign_ineqs_trail.push_back(&c); } + + // perform unit propagation + if (false && maxsum >= c.k() && maxsum - mininc < c.k()) { + literal_vector& lits = get_unhelpful_literals(c, true); + lits.push_back(c.lit()); + for (unsigned i = 0; i < c.size(); ++i) { + if (ctx.get_assignment(c.lit(i)) == l_undef) { + add_assign(c, lits, c.lit(i)); + } + } + } } /** @@ -709,7 +728,7 @@ namespace smt { } TRACE("pb", - tout << "assign: " << literal(v) << " <- " << is_true << "\n"; + tout << "assign: " << literal(v,!is_true) << "\n"; display(tout, c); ); @@ -966,11 +985,21 @@ namespace smt { std::ostream& theory_pb::display(std::ostream& out, ineq& c, bool values) const { ast_manager& m = get_manager(); context& ctx = get_context(); - out << c.lit() << " "; + out << c.lit(); if (c.lit() != null_literal) { + if (values) { + out << "@(" << ctx.get_assignment(c.lit()); + if (ctx.get_assignment(c.lit()) != l_undef) { + out << ":" << ctx.get_assign_level(c.lit()); + } + out << ")"; + } expr_ref tmp(m); ctx.literal2expr(c.lit(), tmp); - out << tmp << "\n"; + out << " " << tmp << "\n"; + } + else { + out << " "; } for (unsigned i = 0; i < c.size(); ++i) { literal l(c.lit(i)); @@ -1141,7 +1170,7 @@ namespace smt { } SASSERT(ctx.get_assignment(c.lit()) == l_true); - if (ctx.get_assign_level(c.lit().var()) > ctx.get_base_level()) { + if (ctx.get_assign_level(c.lit()) > ctx.get_base_level()) { m_ineq_literals.push_back(c.lit()); } } From d6f0c13f2a7dc9ba4a4a773f81fcc8e10b5dad7d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 4 Dec 2013 08:35:46 -0800 Subject: [PATCH 183/925] bug fixes exposed from regression tests Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index abd29c043..d8d90b19a 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -645,7 +645,7 @@ namespace smt { } // perform unit propagation - if (false && maxsum >= c.k() && maxsum - mininc < c.k()) { + if (maxsum >= c.k() && maxsum - mininc < c.k()) { literal_vector& lits = get_unhelpful_literals(c, true); lits.push_back(c.lit()); for (unsigned i = 0; i < c.size(); ++i) { From b980a15177515456a7f51eadaca9bf2659f1e295 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 4 Dec 2013 13:02:49 -0800 Subject: [PATCH 184/925] fix leak by commenting out probe experiment Signed-off-by: Nikolaj Bjorner --- src/opt/fu_malik.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index 99ecdf2a5..cf0fefe52 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -205,12 +205,13 @@ namespace opt { if (!found) { continue; } - expr_ref block_var(m); + expr_ref block_var(m), tmp(m); block_var = m.mk_fresh_const("block_var", m.mk_bool_sort()); m_aux[i] = m.mk_fresh_const("aux", m.mk_bool_sort()); m_soft[i] = m.mk_or(m_soft[i].get(), block_var); block_vars.push_back(block_var); - s().assert_expr(m.mk_or(m_soft[i].get(), m_aux[i].get())); + tmp = m.mk_or(m_soft[i].get(), m_aux[i].get()); + s().assert_expr(tmp); } SASSERT (!block_vars.empty()); assert_at_most_one(block_vars); @@ -252,7 +253,9 @@ namespace opt { for (unsigned i = 0; i < num_assertions; ++i) { g.assert_expr(current_solver.get_assertion(i)); } - probe *p = mk_is_qfbv_probe(); +#if 0 + // TBD: this leaks references somehow + probe_ref p = mk_is_qfbv_probe(); bool all_bv = (*p)(g).is_true(); if (all_bv) { smt::context & ctx = opt_s.get_context(); @@ -266,6 +269,7 @@ namespace opt { m_use_new_bv_solver = true; IF_VERBOSE(1, verbose_stream() << "Force to use the new BV solver." << std::endl;); } +#endif } // TBD: bug when cancel flag is set, fu_malik returns is_sat == l_true instead of l_undef @@ -274,9 +278,11 @@ namespace opt { lbool is_sat = s().check_sat(0,0); if (!m_soft.empty() && is_sat == l_true) { solver::scoped_push _sp(s()); + expr_ref tmp(m); for (unsigned i = 0; i < m_soft.size(); ++i) { m_aux.push_back(m.mk_fresh_const("p", m.mk_bool_sort())); - s().assert_expr(m.mk_or(m_soft[i].get(), m_aux[i].get())); + tmp = m.mk_or(m_soft[i].get(), m_aux[i].get()); + s().assert_expr(tmp); } lbool is_sat = l_true; From ead414c4ee8e72c1d9fad7bcdae7aa4a357cf51c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 4 Dec 2013 13:11:58 -0800 Subject: [PATCH 185/925] add back skipped consequences, exposed by fu-malik assertion violation Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index d8d90b19a..e5686e2e2 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1251,6 +1251,7 @@ namespace smt { justification* cjs = cls.get_justification(); if (cjs) { IF_VERBOSE(0, verbose_stream() << "skipping justification for clause over: " << conseq << "\n";); + m_ineq_literals.push_back(conseq); break; } unsigned num_lits = cls.get_num_literals(); @@ -1282,6 +1283,7 @@ namespace smt { // only process pb justifications. if (j.get_from_theory() != get_id()) { IF_VERBOSE(0, verbose_stream() << "skipping justification for " << conseq << "\n";); + m_ineq_literals.push_back(conseq); break; } pb_justification& pbj = dynamic_cast(j); From a1a8aad09b7b42ade1f1a36f43f5c97582ebed17 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 4 Dec 2013 14:38:03 -0800 Subject: [PATCH 186/925] start working on network flow Signed-off-by: Nikolaj Bjorner --- src/smt/network_flow.h | 2 +- src/smt/network_flow_def.h | 1 + src/smt/spanning_tree.h | 31 +++++----- src/smt/spanning_tree_base.h | 13 ++--- src/smt/spanning_tree_def.h | 110 +++++++++++++++++------------------ 5 files changed, 77 insertions(+), 80 deletions(-) diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index db477bc50..0526de965 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -30,7 +30,7 @@ Notes: #include"inf_rational.h" #include"diff_logic.h" -#include"spanning_tree_def.h" +#include"spanning_tree.h" namespace smt { diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index 1c0e837e3..72fedbac9 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -22,6 +22,7 @@ Notes: #include"network_flow.h" #include"uint_set.h" +#include"spanning_tree_def.h" namespace smt { diff --git a/src/smt/spanning_tree.h b/src/smt/spanning_tree.h index bce910b87..5bd5b9fb0 100644 --- a/src/smt/spanning_tree.h +++ b/src/smt/spanning_tree.h @@ -27,44 +27,41 @@ namespace smt { template class thread_spanning_tree : public spanning_tree_base, protected Ext { protected: - typedef dl_var node; typedef dl_edge edge; typedef dl_graph graph; typedef typename Ext::numeral numeral; typedef typename Ext::fin_numeral fin_numeral; // Store the parent of a node i in the spanning tree - svector m_pred; + svector m_pred; // Store the number of edge on the path from node i to the root svector m_depth; - // Store the pointer from node i to the next node in depth-first search order - svector m_thread; + svector m_thread; // Store the pointer from node i to the next node in depth-first search order - // i |-> edge between (i, m_pred[i]) - svector m_tree; + svector m_tree; // i |-> edge between (i, m_pred[i]) - node m_root_t2; + node_id m_root_t2; graph & m_graph; - void swap_order(node q, node v); - node find_rev_thread(node n) const; - void fix_depth(node start, node after_end); - node get_final(int start); - bool is_preorder_traversal(node start, node end); - node get_common_ancestor(node u, node v); + void swap_order(node_id q, node_id v); + node_id find_rev_thread(node_id n) const; + void fix_depth(node_id start, node_id after_end); + node_id get_final(int start); + bool is_preorder_traversal(node_id start, node_id end); + node_id get_common_ancestor(node_id u, node_id v); bool is_forward_edge(edge_id e_id) const; - bool is_ancestor_of(node ancestor, node child); + bool is_ancestor_of(node_id ancestor, node_id child); public: thread_spanning_tree(graph & g); virtual void initialize(svector const & tree); - void get_descendants(node start, svector & descendants); + void get_descendants(node_id start, svector & descendants); virtual void update(edge_id enter_id, edge_id leave_id); - void get_path(node start, node end, svector & path, svector & against); - bool in_subtree_t2(node child); + void get_path(node_id start, node_id end, svector & path, svector & against); + bool in_subtree_t2(node_id child); bool check_well_formed(); }; diff --git a/src/smt/spanning_tree_base.h b/src/smt/spanning_tree_base.h index 25384d52e..f48ce8f4f 100644 --- a/src/smt/spanning_tree_base.h +++ b/src/smt/spanning_tree_base.h @@ -43,19 +43,18 @@ namespace smt { } class spanning_tree_base { - private: - typedef int node; - public: + typedef int node_id; + typedef int edge_id; virtual void initialize(svector const & tree) = 0; - virtual void get_descendants(node start, svector & descendants) = 0; + virtual void get_descendants(node_id start, svector & descendants) = 0; virtual void update(edge_id enter_id, edge_id leave_id) = 0; - virtual void get_path(node start, node end, svector & path, svector & against) = 0; - virtual bool in_subtree_t2(node child) = 0; + virtual void get_path(node_id start, node_id end, svector & path, svector & against) = 0; + virtual bool in_subtree_t2(node_id child) = 0; virtual bool check_well_formed() = 0; }; } -#endif \ No newline at end of file +#endif diff --git a/src/smt/spanning_tree_def.h b/src/smt/spanning_tree_def.h index 5127fb2b4..60bbde291 100644 --- a/src/smt/spanning_tree_def.h +++ b/src/smt/spanning_tree_def.h @@ -37,7 +37,7 @@ namespace smt { m_depth.resize(num_nodes); m_thread.resize(num_nodes); - node root = num_nodes - 1; + node_id root = num_nodes - 1; m_pred[root] = -1; m_depth[root] = 0; m_thread[root] = 0; @@ -56,7 +56,7 @@ namespace smt { } template - typename thread_spanning_tree::node thread_spanning_tree::get_common_ancestor(node u, node v) { + typename thread_spanning_tree::node_id thread_spanning_tree::get_common_ancestor(node_id u, node_id v) { while (u != v) { if (m_depth[u] > m_depth[v]) u = m_pred[u]; @@ -67,8 +67,8 @@ namespace smt { } template - void thread_spanning_tree::get_path(node start, node end, svector & path, svector & against) { - node join = get_common_ancestor(start, end); + void thread_spanning_tree::get_path(node_id start, node_id end, svector & path, svector & against) { + node_id join = get_common_ancestor(start, end); path.reset(); while (start != join) { edge_id e_id = m_tree[start]; @@ -86,17 +86,17 @@ namespace smt { template bool thread_spanning_tree::is_forward_edge(edge_id e_id) const { - node start = m_graph.get_source(e_id); - node end = m_graph.get_target(e_id); + node_id start = m_graph.get_source(e_id); + node_id end = m_graph.get_target(e_id); SASSERT(m_pred[start] == end || m_pred[end] == start); return m_pred[start] == end; } template - void thread_spanning_tree::get_descendants(node start, svector & descendants) { + void thread_spanning_tree::get_descendants(node_id start, svector & descendants) { descendants.reset(); descendants.push_back(start); - node u = m_thread[start]; + node_id u = m_thread[start]; while (m_depth[u] > m_depth[start]) { descendants.push_back(u); u = m_thread[u]; @@ -105,7 +105,7 @@ namespace smt { } template - bool thread_spanning_tree::in_subtree_t2(node child) { + bool thread_spanning_tree::in_subtree_t2(node_id child) { if (m_depth[child] < m_depth[m_root_t2]) { return false; } @@ -113,8 +113,8 @@ namespace smt { } template - bool thread_spanning_tree::is_ancestor_of(node ancestor, node child) { - for (node n = child; n != -1; n = m_pred[n]) { + bool thread_spanning_tree::is_ancestor_of(node_id ancestor, node_id child) { + for (node_id n = child; n != -1; n = m_pred[n]) { if (n == ancestor) { return true; } @@ -140,10 +140,10 @@ namespace smt { */ template void thread_spanning_tree::update(edge_id enter_id, edge_id leave_id) { - node p = m_graph.get_source(enter_id); - node q = m_graph.get_target(enter_id); - node u = m_graph.get_source(leave_id); - node v = m_graph.get_target(leave_id); + node_id p = m_graph.get_source(enter_id); + node_id q = m_graph.get_target(enter_id); + node_id u = m_graph.get_source(leave_id); + node_id v = m_graph.get_target(leave_id); if (m_pred[u] == v) { std::swap(u, v); @@ -165,11 +165,11 @@ namespace smt { // Old threads: alpha -> v -*-> f(v) -> beta | p -*-> f(p) -> gamma // New threads: alpha -> beta | p -*-> f(p) -> v -*-> f(v) -> gamma - node f_p = get_final(p); - node f_v = get_final(v); - node alpha = find_rev_thread(v); - node beta = m_thread[f_v]; - node gamma = m_thread[f_p]; + node_id f_p = get_final(p); + node_id f_v = get_final(v); + node_id alpha = find_rev_thread(v); + node_id beta = m_thread[f_v]; + node_id gamma = m_thread[f_p]; if (v != gamma) { m_thread[alpha] = beta; @@ -177,11 +177,11 @@ namespace smt { m_thread[f_v] = gamma; } - node old_pred = m_pred[q]; + node_id old_pred = m_pred[q]; // Update stem nodes from q to v if (q != v) { - for (node n = q; n != v; ) { - SASSERT(old_pred != u); // the last processed node is v + for (node_id n = q; n != v; ) { + SASSERT(old_pred != u); // the last processed node_id is v SASSERT(-1 != m_pred[old_pred]); int next_old_pred = m_pred[old_pred]; swap_order(n, old_pred); @@ -195,7 +195,7 @@ namespace smt { m_tree[q] = enter_id; m_root_t2 = q; - node after_final_q = (v == gamma) ? beta : gamma; + node_id after_final_q = (v == gamma) ? beta : gamma; fix_depth(q, after_final_q); SASSERT(!in_subtree_t2(p)); @@ -226,15 +226,15 @@ namespace smt { */ template - void thread_spanning_tree::swap_order(node q, node v) { + void thread_spanning_tree::swap_order(node_id q, node_id v) { SASSERT(q != v); SASSERT(m_pred[q] == v); SASSERT(is_preorder_traversal(v, get_final(v))); - node prev = find_rev_thread(v); - node f_q = get_final(q); - node f_v = get_final(v); - node next = m_thread[f_v]; - node alpha = find_rev_thread(q); + node_id prev = find_rev_thread(v); + node_id f_q = get_final(q); + node_id f_v = get_final(v); + node_id next = m_thread[f_v]; + node_id alpha = find_rev_thread(q); if (f_q == f_v) { SASSERT(f_q != v && alpha != next); @@ -243,7 +243,7 @@ namespace smt { f_q = alpha; } else { - node beta = m_thread[f_q]; + node_id beta = m_thread[f_q]; SASSERT(f_q != v && alpha != beta); m_thread[f_q] = v; m_thread[alpha] = beta; @@ -262,13 +262,13 @@ namespace smt { Spanning tree of m_graph + root is represented using: svector m_states; edge_id |-> edge_state - svector m_pred; node |-> node - svector m_depth; node |-> int - svector m_thread; node |-> node + svector m_pred; node_id |-> node + svector m_depth; node_id |-> int + svector m_thread; node_id |-> node Tree is determined by m_pred: - m_pred[root] == -1 - - m_pred[n] = m != n for each node n, acyclic until reaching root. + - m_pred[n] = m != n for each node_id n, acyclic until reaching root. - m_depth[m_pred[n]] + 1 == m_depth[n] for each n != root m_thread is a linked list traversing all nodes. @@ -278,13 +278,13 @@ namespace smt { */ template bool thread_spanning_tree::check_well_formed() { - node root = m_pred.size()-1; + node_id root = m_pred.size()-1; // Check that m_thread traverses each node. // This gets checked using union-find as well. svector found(m_thread.size(), false); found[root] = true; - for (node x = m_thread[root]; x != root; x = m_thread[x]) { + for (node_id x = m_thread[root]; x != root; x = m_thread[x]) { SASSERT(x != m_thread[x]); found[x] = true; } @@ -295,12 +295,12 @@ namespace smt { // m_pred is acyclic, and points to root. SASSERT(m_pred[root] == -1); SASSERT(m_depth[root] == 0); - for (node i = 0; i < root; ++i) { + for (node_id i = 0; i < root; ++i) { SASSERT(m_depth[m_pred[i]] < m_depth[i]); } // m_depth[x] denotes distance from x to the root node - for (node x = m_thread[root]; x != root; x = m_thread[x]) { + for (node_id x = m_thread[root]; x != root; x = m_thread[x]) { SASSERT(m_depth[x] > 0); SASSERT(m_depth[x] == m_depth[m_pred[x]] + 1); } @@ -309,8 +309,8 @@ namespace smt { // Union-find structure svector roots(m_pred.size(), -1); - for (node x = m_thread[root]; x != root; x = m_thread[x]) { - node y = m_pred[x]; + for (node_id x = m_thread[root]; x != root; x = m_thread[x]) { + node_id y = m_pred[x]; // We are now going to check the edge between x and y SASSERT(find(roots, x) != find(roots, y)); merge(roots, x, y); @@ -322,8 +322,8 @@ namespace smt { } for (unsigned i = 0; i < m_tree.size(); ++i) { - node src = m_graph.get_source(m_tree[i]); - node tgt = m_graph.get_target(m_tree[i]); + node_id src = m_graph.get_source(m_tree[i]); + node_id tgt = m_graph.get_target(m_tree[i]); SASSERT(m_pred[src] == tgt || m_pred[tgt] == src); } @@ -358,11 +358,11 @@ namespace smt { } /** - \brief find node that points to 'n' in m_thread + \brief find node_id that points to 'n' in m_thread */ template - typename thread_spanning_tree::node thread_spanning_tree::find_rev_thread(node n) const { - node ancestor = m_pred[n]; + typename thread_spanning_tree::node_id thread_spanning_tree::find_rev_thread(node_id n) const { + node_id ancestor = m_pred[n]; SASSERT(ancestor != -1); while (m_thread[ancestor] != n) { ancestor = m_thread[ancestor]; @@ -371,7 +371,7 @@ namespace smt { } template - void thread_spanning_tree::fix_depth(node start, node after_end) { + void thread_spanning_tree::fix_depth(node_id start, node_id after_end) { while (start != after_end) { SASSERT(m_pred[start] != -1); m_depth[start] = m_depth[m_pred[start]]+1; @@ -380,7 +380,7 @@ namespace smt { } template - typename thread_spanning_tree::node thread_spanning_tree::get_final(int start) { + typename thread_spanning_tree::node_id thread_spanning_tree::get_final(int start) { int n = start; while (m_depth[m_thread[n]] > m_depth[start]) { n = m_thread[n]; @@ -389,11 +389,11 @@ namespace smt { } template - bool thread_spanning_tree::is_preorder_traversal(node start, node end) { + bool thread_spanning_tree::is_preorder_traversal(node_id start, node_id end) { // get children of start uint_set children; children.insert(start); - node root = m_pred.size()-1; + node_id root = m_pred.size()-1; for (int i = 0; i < root; ++i) { for (int j = 0; j < root; ++j) { if (children.contains(m_pred[j])) { @@ -434,7 +434,7 @@ namespace smt { m_tree_graph->add_edge(e.get_source(), e.get_target(), e.get_weight(), explanation()); } - node root = num_nodes - 1; + node_id root = num_nodes - 1; m_tree_graph->bfs_undirected(root, m_pred, m_depth); m_tree_graph->dfs_undirected(root, m_thread); } @@ -459,7 +459,7 @@ namespace smt { edge const & e = es[enter_id]; m_tree_graph->add_edge(e.get_source(), e.get_target(), e.get_weight(), explanation()); - node root = num_nodes - 1; + node_id root = num_nodes - 1; m_tree_graph->bfs_undirected(root, m_pred, m_depth); m_tree_graph->dfs_undirected(root, m_thread); @@ -479,11 +479,11 @@ namespace smt { } } - node p = m_graph.get_source(enter_id); - node q = m_graph.get_target(enter_id); + node_id p = m_graph.get_source(enter_id); + node_id q = m_graph.get_target(enter_id); m_root_t2 = p == m_pred[q] ? q : p; } } -#endif \ No newline at end of file +#endif From 56c4fa8f6d6030f0999f0b055307600255be2098 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 4 Dec 2013 17:39:54 -0800 Subject: [PATCH 187/925] expose models, working on network flow Signed-off-by: Nikolaj Bjorner --- src/api/api_opt.cpp | 18 + src/api/dotnet/Optimize.cs | 20 + src/api/z3_api.h | 11 + src/opt/opt_context.cpp | 4 + src/opt/opt_context.h | 2 + src/smt/network_flow.h | 168 ++------- src/smt/network_flow_def.h | 702 +++++++++++++++++++++-------------- src/smt/spanning_tree_base.h | 9 +- src/smt/spanning_tree_def.h | 4 +- 9 files changed, 497 insertions(+), 441 deletions(-) diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index afc33e396..b1640506e 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -20,6 +20,7 @@ Revision History: #include"api_log_macros.h" #include"api_context.h" #include"api_util.h" +#include"api_model.h" #include"opt_context.h" #include"cancel_eh.h" #include"scoped_timer.h" @@ -122,6 +123,23 @@ extern "C" { Z3_CATCH_RETURN(Z3_L_UNDEF); } + Z3_model Z3_API Z3_optimize_get_model(Z3_context c, Z3_optimize o) { + Z3_TRY; + LOG_Z3_optimize_get_model(c, o); + RESET_ERROR_CODE(); + model_ref _m; + to_optimize_ref(o).get_model(_m); + if (!_m) { + SET_ERROR_CODE(Z3_INVALID_USAGE); + RETURN_Z3(0); + } + Z3_model_ref * m_ref = alloc(Z3_model_ref); + m_ref->m_model = _m; + mk_c(c)->save_object(m_ref); + RETURN_Z3(of_model(m_ref)); + Z3_CATCH_RETURN(0); + } + void Z3_API Z3_optimize_set_params(Z3_context c, Z3_optimize o, Z3_params p) { Z3_TRY; LOG_Z3_optimize_set_params(c, o, p); diff --git a/src/api/dotnet/Optimize.cs b/src/api/dotnet/Optimize.cs index 3b54dca20..4526ead88 100644 --- a/src/api/dotnet/Optimize.cs +++ b/src/api/dotnet/Optimize.cs @@ -108,6 +108,26 @@ namespace Microsoft.Z3 default: return Status.UNKNOWN; } } + + /// + /// The model of the last Check. + /// + /// + /// The result is null if Check was not invoked before, + /// if its results was not SATISFIABLE, or if model production is not enabled. + /// + public Model Model + { + get + { + IntPtr x = Native.Z3_optimize_get_model(Context.nCtx, NativeObject); + if (x == IntPtr.Zero) + return null; + else + return new Model(Context, x); + } + } + public void Maximize(ArithExpr e) { Native.Z3_optimize_maximize(Context.nCtx, NativeObject, e.NativeObject); diff --git a/src/api/z3_api.h b/src/api/z3_api.h index f6064d543..a52ad6106 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -6021,6 +6021,17 @@ END_MLAPI_EXCLUDE Z3_lbool Z3_API Z3_optimize_check(Z3_context c, Z3_optimize o); + /** + \brief Retrieve the model for the last #Z3_optimize_check + + The error handler is invoked if a model is not available because + the commands above were not invoked for the given optimization + solver, or if the result was \c Z3_L_FALSE. + + def_API('Z3_optimize_get_model', MODEL, (_in(CONTEXT), _in(OPTIMIZE))) + */ + Z3_model Z3_API Z3_optimize_get_model(Z3_context c, Z3_optimize o); + /** \brief Set parameters on optimization context. diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index fafd88ecf..31202927c 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -82,6 +82,10 @@ namespace opt { } } + void context::get_model(model_ref& mdl) { + get_solver().get_model(mdl); + } + lbool context::execute_min_max(unsigned index, bool committed, bool is_max) { // HACK: reuse m_optsmt without regard for box reuse and not considering // use-case of lex. diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 9a0b49541..a1f391d1d 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -75,6 +75,8 @@ namespace opt { lbool optimize(); + void get_model(model_ref& m); + void set_cancel(bool f); void reset_cancel() { set_cancel(false); } void cancel() { set_cancel(true); } diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index 0526de965..65575965f 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -77,9 +77,9 @@ namespace smt { protected: graph & m_graph; svector & m_states; - vector & m_potentials; - edge_id & m_enter_id; - + vector & m_potentials; + edge_id & m_enter_id; + bool edge_in_tree(edge_id id) const { return m_states[id] == BASIS; } public: pivot_rule_impl(graph & g, vector & potentials, svector & states, edge_id & enter_id) @@ -88,46 +88,21 @@ namespace smt { m_states(states), m_enter_id(enter_id) { } + virtual ~pivot_rule_impl() {} virtual bool choose_entering_edge() = 0; + virtual pivot_rule rule() const = 0; }; class first_eligible_pivot : public pivot_rule_impl { - private: edge_id m_next_edge; - public: first_eligible_pivot(graph & g, vector & potentials, svector & states, edge_id & enter_id) : pivot_rule_impl(g, potentials, states, enter_id), m_next_edge(0) { } - - bool choose_entering_edge() { - TRACE("network_flow", tout << "choose_entering_edge...\n";); - int num_edges = m_graph.get_num_edges(); - for (int i = m_next_edge; i < m_next_edge + num_edges; ++i) { - edge_id id = (i >= num_edges) ? (i - num_edges) : i; - node src = m_graph.get_source(id); - node tgt = m_graph.get_target(id); - if (m_states[id] != BASIS) { - numeral cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(id); - if (cost.is_pos()) { - m_enter_id = id; - TRACE("network_flow", { - tout << "Found entering edge " << id << " between node "; - tout << src << " and node " << tgt << " with reduced cost = " << cost << "...\n"; - }); - m_next_edge = m_enter_id; - if (m_next_edge >= num_edges) { - m_next_edge -= num_edges; - } - return true; - } - } - } - TRACE("network_flow", tout << "Found no entering edge...\n";); - return false; - }; + virtual bool choose_entering_edge(); + virtual pivot_rule rule() const { return FIRST_ELIGIBLE; } }; class best_eligible_pivot : public pivot_rule_impl { @@ -136,33 +111,8 @@ namespace smt { svector & states, edge_id & enter_id) : pivot_rule_impl(g, potentials, states, enter_id) { } - - bool choose_entering_edge() { - TRACE("network_flow", tout << "choose_entering_edge...\n";); - unsigned num_edges = m_graph.get_num_edges(); - numeral max = numeral::zero(); - for (unsigned i = 0; i < num_edges; ++i) { - node src = m_graph.get_source(i); - node tgt = m_graph.get_target(i); - if (m_states[i] != BASIS) { - numeral cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(i); - if (cost > max) { - max = cost; - m_enter_id = i; - } - } - } - if (max.is_pos()) { - TRACE("network_flow", { - tout << "Found entering edge " << m_enter_id << " between node "; - tout << m_graph.get_source(m_enter_id) << " and node " << m_graph.get_target(m_enter_id); - tout << " with reduced cost = " << max << "...\n"; - }); - return true; - } - TRACE("network_flow", tout << "Found no entering edge...\n";); - return false; - }; + virtual pivot_rule rule() const { return BEST_ELIGIBLE; } + virtual bool choose_entering_edge(); }; class candidate_list_pivot : public pivot_rule_impl { @@ -186,94 +136,22 @@ namespace smt { m_candidates(m_num_candidates) { } - bool choose_entering_edge() { - if (m_current_length == 0 || m_minor_step == MINOR_STEP_LIMIT) { - // Build the candidate list - unsigned num_edges = m_graph.get_num_edges(); - numeral max = numeral::zero(); - m_current_length = 0; - for (unsigned i = m_next_edge; i < m_next_edge + num_edges; ++i) { - edge_id id = (i >= num_edges) ? i - num_edges : i; - node src = m_graph.get_source(id); - node tgt = m_graph.get_target(id); - if (m_states[id] != BASIS) { - numeral cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(id); - if (cost.is_pos()) { - m_candidates[m_current_length] = id; - ++m_current_length; - if (cost > max) { - max = cost; - m_enter_id = id; - } - } - if (m_current_length >= m_num_candidates) break; - } - } - m_next_edge = m_enter_id; - m_minor_step = 1; - if (max.is_pos()) { - TRACE("network_flow", { - tout << "Found entering edge " << m_enter_id << " between node "; - tout << m_graph.get_source(m_enter_id) << " and node " << m_graph.get_target(m_enter_id); - tout << " with reduced cost = " << max << "...\n"; - }); - return true; - } - TRACE("network_flow", tout << "Found no entering edge...\n";); - return false; - } + virtual pivot_rule rule() const { return CANDIDATE_LIST; } - ++m_minor_step; - numeral max = numeral::zero(); - for (unsigned i = 0; i < m_current_length; ++i) { - edge_id id = m_candidates[i]; - node src = m_graph.get_source(id); - node tgt = m_graph.get_target(id); - if (m_states[id] != BASIS) { - numeral cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(id); - if (cost > max) { - max = cost; - m_enter_id = id; - } - // Remove stale candidates - if (!cost.is_pos()) { - --m_current_length; - m_candidates[i] = m_candidates[m_current_length]; - --i; - } - } - } - if (max.is_pos()) { - TRACE("network_flow", { - tout << "Found entering edge " << m_enter_id << " between node "; - tout << m_graph.get_source(m_enter_id) << " and node " << m_graph.get_target(m_enter_id); - tout << " with reduced cost = " << max << "...\n"; - }); - return true; - } - TRACE("network_flow", tout << "Found no entering edge...\n";); - return false; - }; + virtual bool choose_entering_edge(); }; - graph m_graph; - spanning_tree_base * m_tree; - - // Denote supply/demand b_i on node i - vector m_balances; - - // Duals of flows which are convenient to compute dual solutions - vector m_potentials; - - // Basic feasible flows - vector m_flows; - - svector m_states; - - unsigned m_step; - - edge_id m_enter_id, m_leave_id; - optional m_delta; + graph m_graph; + scoped_ptr m_tree; + scoped_ptr m_pivot; + vector m_balances; // Denote supply/demand b_i on node i + vector m_potentials; // Duals of flows which are convenient to compute dual solutions + vector m_flows; // Basic feasible flows + svector m_states; + unsigned m_step; + edge_id m_enter_id; + edge_id m_leave_id; + optional m_delta; // Initialize the network with a feasible spanning tree void initialize(); @@ -290,6 +168,8 @@ namespace smt { void update_spanning_tree(); + numeral get_cost() const; + bool edge_in_tree(edge_id id) const; bool is_infeasible(); diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index 72fedbac9..683ea0b98 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -26,6 +26,128 @@ Notes: namespace smt { + template + bool network_flow::first_eligible_pivot::choose_entering_edge() { + TRACE("network_flow", tout << "choose_entering_edge...\n";); + int num_edges = m_graph.get_num_edges(); + for (int i = m_next_edge; i < m_next_edge + num_edges; ++i) { + edge_id id = i % num_edges; + if (edge_in_tree(id)) { + continue; + } + node src = m_graph.get_source(id); + node tgt = m_graph.get_target(id); + numeral cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(id); + if (cost.is_pos()) { + m_next_edge = m_enter_id = id; + TRACE("network_flow", + tout << "Found entering edge " << id << " between node "; + tout << src << " and node " << tgt << " with reduced cost = " << cost << "...\n";); + return true; + } + } + TRACE("network_flow", tout << "Found no entering edge...\n";); + return false; + }; + + template + bool network_flow::best_eligible_pivot::choose_entering_edge() { + TRACE("network_flow", tout << "choose_entering_edge...\n";); + unsigned num_edges = m_graph.get_num_edges(); + numeral max = numeral::zero(); + for (unsigned i = 0; i < num_edges; ++i) { + node src = m_graph.get_source(i); + node tgt = m_graph.get_target(i); + if (!edge_in_tree(i)) { + numeral cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(i); + if (cost > max) { + max = cost; + m_enter_id = i; + } + } + } + if (max.is_pos()) { + TRACE("network_flow", { + tout << "Found entering edge " << m_enter_id << " between node "; + tout << m_graph.get_source(m_enter_id) << " and node " << m_graph.get_target(m_enter_id); + tout << " with reduced cost = " << max << "...\n"; + }); + return true; + } + TRACE("network_flow", tout << "Found no entering edge...\n";); + return false; + }; + + template + bool network_flow::candidate_list_pivot::choose_entering_edge() { + if (m_current_length == 0 || m_minor_step == MINOR_STEP_LIMIT) { + // Build the candidate list + unsigned num_edges = m_graph.get_num_edges(); + numeral max = numeral::zero(); + m_current_length = 0; + for (unsigned i = m_next_edge; i < m_next_edge + num_edges; ++i) { + edge_id id = (i >= num_edges) ? i - num_edges : i; + node src = m_graph.get_source(id); + node tgt = m_graph.get_target(id); + if (!edge_in_tree(id)) { + numeral cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(id); + if (cost.is_pos()) { + m_candidates[m_current_length] = id; + ++m_current_length; + if (cost > max) { + max = cost; + m_enter_id = id; + } + } + if (m_current_length >= m_num_candidates) break; + } + } + m_next_edge = m_enter_id; + m_minor_step = 1; + if (max.is_pos()) { + TRACE("network_flow", { + tout << "Found entering edge " << m_enter_id << " between node "; + tout << m_graph.get_source(m_enter_id) << " and node " << m_graph.get_target(m_enter_id); + tout << " with reduced cost = " << max << "...\n"; + }); + return true; + } + TRACE("network_flow", tout << "Found no entering edge...\n";); + return false; + } + + ++m_minor_step; + numeral max = numeral::zero(); + for (unsigned i = 0; i < m_current_length; ++i) { + edge_id id = m_candidates[i]; + node src = m_graph.get_source(id); + node tgt = m_graph.get_target(id); + if (!edge_in_tree(id)) { + numeral cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(id); + if (cost > max) { + max = cost; + m_enter_id = id; + } + // Remove stale candidates + if (!cost.is_pos()) { + --m_current_length; + m_candidates[i] = m_candidates[m_current_length]; + --i; + } + } + } + if (max.is_pos()) { + TRACE("network_flow", { + tout << "Found entering edge " << m_enter_id << " between node "; + tout << m_graph.get_source(m_enter_id) << " and node " << m_graph.get_target(m_enter_id); + tout << " with reduced cost = " << max << "...\n"; + }); + return true; + } + TRACE("network_flow", tout << "Found no entering edge...\n";); + return false; + }; + template network_flow::network_flow(graph & g, vector const & balances) : m_balances(balances) { @@ -42,7 +164,7 @@ namespace smt { } } TRACE("network_flow", { - tout << "Different logic optimization:" << std::endl; + tout << "Difference logic optimization:" << std::endl; display_dual(tout); tout << "Minimum cost flow:" << std::endl; display(tout); @@ -52,6 +174,276 @@ namespace smt { m_tree = alloc(basic_spanning_tree, m_graph); } + + template + void network_flow::initialize() { + TRACE("network_flow", tout << "initialize...\n";); + // Create an artificial root node to construct initial spanning tree + unsigned num_nodes = m_graph.get_num_nodes(); + unsigned num_edges = m_graph.get_num_edges(); + + node root = num_nodes; + m_graph.init_var(root); + + m_potentials.resize(num_nodes + 1); + m_potentials[root] = numeral::zero(); + + m_balances.resize(num_nodes + 1); + fin_numeral sum_supply = fin_numeral::zero(); + for (unsigned i = 0; i < num_nodes; ++i) { + sum_supply += m_balances[i]; + } + m_balances[root] = -sum_supply; + + m_flows.resize(num_nodes + num_edges); + m_flows.fill(numeral::zero()); + m_states.resize(num_nodes + num_edges); + m_states.fill(LOWER); + + // Create artificial edges from/to root node to/from other nodes and initialize the spanning tree + svector tree; + for (unsigned i = 0; i < num_nodes; ++i) { + bool is_forward = !m_balances[i].is_neg(); + m_states[num_edges + i] = BASIS; + node src = is_forward ? i : root; + node tgt = is_forward ? root : i; + m_flows[num_edges + i] = is_forward ? m_balances[i] : -m_balances[i]; + m_potentials[i] = is_forward ? numeral::one() : -numeral::one(); + tree.push_back(m_graph.add_edge(src, tgt, numeral::one(), explanation())); + } + + m_tree->initialize(tree); + + TRACE("network_flow", + tout << pp_vector("Potentials", m_potentials); + tout << pp_vector("Flows", m_flows); + tout << "Cost: " << get_cost() << "\n"; + tout << "Spanning tree:\n"; + display_spanning_tree(tout);); + SASSERT(check_well_formed()); + } + + template + void network_flow::update_potentials() { + node src = m_graph.get_source(m_enter_id); + node tgt = m_graph.get_target(m_enter_id); + numeral cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(m_enter_id); + numeral change; + node start; + if (m_tree->in_subtree_t2(tgt)) { + change = cost; + start = tgt; + } + else { + change = -cost; + start = src; + } + SASSERT(m_tree->in_subtree_t2(start)); + TRACE("network_flow", tout << "update_potentials of T_" << start << " with change = " << change << "...\n";); + svector descendants; + m_tree->get_descendants(start, descendants); + SASSERT(descendants.size() >= 1); + for (unsigned i = 0; i < descendants.size(); ++i) { + node u = descendants[i]; + m_potentials[u] += change; + } + TRACE("network_flow", tout << pp_vector("Potentials", m_potentials);); + } + + template + void network_flow::update_flows() { + TRACE("network_flow", tout << "update_flows...\n";); + m_flows[m_enter_id] += *m_delta; + node src = m_graph.get_source(m_enter_id); + node tgt = m_graph.get_target(m_enter_id); + svector path; + svector against; + m_tree->get_path(src, tgt, path, against); + SASSERT(path.size() >= 1); + for (unsigned i = 0; i < path.size(); ++i) { + edge_id e_id = path[i]; + m_flows[e_id] += against[i] ? - *m_delta : *m_delta; + } + TRACE("network_flow", tout << pp_vector("Flows", m_flows);); + } + + template + bool network_flow::choose_leaving_edge() { + TRACE("network_flow", tout << "choose_leaving_edge...\n";); + node src = m_graph.get_source(m_enter_id); + node tgt = m_graph.get_target(m_enter_id); + m_delta.set_invalid(); + edge_id leave_id = null_edge_id; + svector path; + svector against; + m_tree->get_path(src, tgt, path, against); + SASSERT(path.size() >= 1); + for (unsigned i = 0; i < path.size(); ++i) { + edge_id e_id = path[i]; + if (against[i] && (!m_delta || m_flows[e_id] < *m_delta)) { + m_delta = m_flows[e_id]; + leave_id = e_id; + } + } + m_leave_id = leave_id; + + TRACE("network_flow", + tout << "Leaving edge " << m_leave_id; + tout << " between node " << m_graph.get_source(m_leave_id); + tout << " and node " << m_graph.get_target(m_leave_id) ; + if (m_delta) tout << " with delta = " << *m_delta; + tout << "\n";); + + return m_delta; + } + + template + void network_flow::update_spanning_tree() { + m_tree->update(m_enter_id, m_leave_id); + } + + template + bool network_flow::choose_entering_edge(pivot_rule pr) { + if (!m_pivot || pr != m_pivot->rule()) { + switch (pr) { + case FIRST_ELIGIBLE: + m_pivot = alloc(first_eligible_pivot, m_graph, m_potentials, m_states, m_enter_id); + break; + case BEST_ELIGIBLE: + m_pivot = alloc(best_eligible_pivot, m_graph, m_potentials, m_states, m_enter_id); + break; + case CANDIDATE_LIST: + m_pivot = alloc(candidate_list_pivot, m_graph, m_potentials, m_states, m_enter_id); + break; + default: + UNREACHABLE(); + } + } + return m_pivot->choose_entering_edge(); + } + + // Minimize cost flows + template + min_flow_result network_flow::min_cost(pivot_rule pr) { + initialize(); + while (choose_entering_edge(pr)) { + bool bounded = choose_leaving_edge(); + if (!bounded) return UNBOUNDED; + update_flows(); + if (m_enter_id != m_leave_id) { + SASSERT(edge_in_tree(m_leave_id)); + SASSERT(!edge_in_tree(m_enter_id)); + m_states[m_enter_id] = BASIS; + m_states[m_leave_id] = LOWER; + update_spanning_tree(); + update_potentials(); + TRACE("network_flow", + tout << "Spanning tree:\n"; + display_spanning_tree(tout); + tout << "Cost: " << get_cost() << "\n";); + SASSERT(check_well_formed()); + } + } + if (is_infeasible()) return INFEASIBLE; + TRACE("network_flow", tout << "Found optimal solution.\n";); + SASSERT(check_optimal()); + return OPTIMAL; + } + + template + bool network_flow::is_infeasible() { +#if 0 + // Flows of artificial arcs should be zero + unsigned num_nodes = m_graph.get_num_nodes(); + unsigned num_edges = m_graph.get_num_edges(); + for (unsigned i = 1; i < num_nodes; ++i) { + if (m_flows[num_edges - i].is_pos()) return true; + } +#endif + return false; + } + + // Get the optimal solution + template + typename network_flow::numeral network_flow::get_optimal_solution(vector & result, bool is_dual) { + numeral objective_value = get_cost(); + result.reset(); + if (is_dual) { + result.append(m_potentials); + } + else { + result.append(m_flows); + } + return objective_value; + } + + template + typename network_flow::numeral network_flow::get_cost() const { + numeral objective_value = numeral::zero(); + unsigned num_edges = m_graph.get_num_edges(); + for (unsigned i = 0; i < num_edges; ++i) { + if (edge_in_tree(i)) { + objective_value += m_flows[i].get_rational() * m_graph.get_weight(i); + } + } + return objective_value; + } + + template + bool network_flow::edge_in_tree(edge_id id) const { + return m_states[id] == BASIS; + } + + template + bool network_flow::check_well_formed() { + SASSERT(m_tree->check_well_formed()); + SASSERT(!m_delta || !(*m_delta).is_neg()); + + // m_flows are zero on non-basic edges + for (unsigned i = 0; i < m_flows.size(); ++i) { + SASSERT(!m_flows[i].is_neg()); + SASSERT(edge_in_tree(i) || m_flows[i].is_zero()); + } + + unsigned num_edges = m_graph.get_num_edges(); + for (unsigned i = 0; i < num_edges; ++i) { + if (edge_in_tree(i)) { + dl_var src = m_graph.get_source(i); + dl_var tgt = m_graph.get_target(i); + numeral weight = m_graph.get_weight(i); + SASSERT(m_potentials[src] - m_potentials[tgt] == weight); + } + } + + return true; + } + + template + bool network_flow::check_optimal() { + numeral total_cost = get_cost(); + unsigned num_edges = m_graph.get_num_edges(); + + for (unsigned i = 0; i < num_edges; ++i) { + dl_var src = m_graph.get_source(i); + dl_var tgt = m_graph.get_target(i); + numeral weight = m_graph.get_weight(i); + SASSERT(m_potentials[src] - m_potentials[tgt] <= weight); + } + + // m_flows are zero on non-basic edges + for (unsigned i = 0; i < m_flows.size(); ++i) { + SASSERT(edge_in_tree(i) || m_flows[i].is_zero()); + } + numeral total_balance = numeral::zero(); + for (unsigned i = 0; i < m_potentials.size(); ++i) { + total_balance += m_balances[i] * m_potentials[i]; + } + TRACE("network_flow", tout << "Total balance: " << total_balance << ", total cost: " << total_cost << std::endl;); + return total_cost == total_balance; + } + + // display methods + template void network_flow::display(std::ofstream & os) { vector const & es = m_graph.get_all_edges(); @@ -96,6 +488,7 @@ namespace smt { os << "(optimize)" << std::endl; } + template void network_flow::display_dual(std::ofstream & os) { for (unsigned i = 0; i < m_graph.get_num_nodes(); ++i) { @@ -115,296 +508,31 @@ namespace smt { os << "(optimize)" << std::endl; } - template - void network_flow::initialize() { - TRACE("network_flow", tout << "initialize...\n";); - // Create an artificial root node to construct initial spanning tree - unsigned num_nodes = m_graph.get_num_nodes(); - unsigned num_edges = m_graph.get_num_edges(); - - node root = num_nodes; - m_graph.init_var(root); - - m_potentials.resize(num_nodes + 1); - m_potentials[root] = numeral::zero(); - - m_balances.resize(num_nodes + 1); - fin_numeral sum_supply = fin_numeral::zero(); - for (unsigned i = 0; i < num_nodes; ++i) { - sum_supply += m_balances[i]; - } - m_balances[root] = -sum_supply; - - m_flows.resize(num_nodes + num_edges); - m_flows.fill(numeral::zero()); - m_states.resize(num_nodes + num_edges); - m_states.fill(LOWER); - - // Create artificial edges from/to root node to/from other nodes and initialize the spanning tree - svector tree; - bool is_forward; - for (unsigned i = 0; i < num_nodes; ++i) { - is_forward = !m_balances[i].is_neg(); - m_states[num_edges + i] = BASIS; - node src = is_forward ? i : root; - node tgt = is_forward ? root : i; - m_flows[num_edges + i] = is_forward ? m_balances[i] : -m_balances[i]; - m_potentials[i] = is_forward ? numeral::one() : -numeral::one(); - tree.push_back(m_graph.add_edge(src, tgt, numeral::one(), explanation())); - } - - m_tree->initialize(tree); - - TRACE("network_flow", { - tout << pp_vector("Potentials", m_potentials, true) << pp_vector("Flows", m_flows); - }); - TRACE("network_flow", tout << "Spanning tree:\n"; display_spanning_tree(tout);); - SASSERT(check_well_formed()); - } - - template - void network_flow::update_potentials() { - node src = m_graph.get_source(m_enter_id); - node tgt = m_graph.get_target(m_enter_id); - numeral cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(m_enter_id); - numeral change; - node start; - if (m_tree->in_subtree_t2(tgt)) { - change = cost; - start = tgt; - } - else { - change = -cost; - start = src; - } - SASSERT(m_tree->in_subtree_t2(start)); - TRACE("network_flow", tout << "update_potentials of T_" << start << " with change = " << change << "...\n";); - svector descendants; - m_tree->get_descendants(start, descendants); - SASSERT(descendants.size() >= 1); - for (unsigned i = 0; i < descendants.size(); ++i) { - node u = descendants[i]; - m_potentials[u] += change; - } - TRACE("network_flow", tout << pp_vector("Potentials", m_potentials, true);); - } - - template - void network_flow::update_flows() { - TRACE("network_flow", tout << "update_flows...\n";); - m_flows[m_enter_id] += *m_delta; - node src = m_graph.get_source(m_enter_id); - node tgt = m_graph.get_target(m_enter_id); - svector path; - svector against; - m_tree->get_path(src, tgt, path, against); - SASSERT(path.size() >= 1); - for (unsigned i = 0; i < path.size(); ++i) { - edge_id e_id = path[i]; - m_flows[e_id] += against[i] ? - *m_delta : *m_delta; - } - TRACE("network_flow", tout << pp_vector("Flows", m_flows, true);); - } - - template - bool network_flow::choose_leaving_edge() { - TRACE("network_flow", tout << "choose_leaving_edge...\n";); - node src = m_graph.get_source(m_enter_id); - node tgt = m_graph.get_target(m_enter_id); - m_delta.set_invalid(); - edge_id leave_id; - svector path; - svector against; - m_tree->get_path(src, tgt, path, against); - SASSERT(path.size() >= 1); - for (unsigned i = 0; i < path.size(); ++i) { - edge_id e_id = path[i]; - if (against[i] && (!m_delta || m_flows[e_id] < *m_delta)) { - m_delta = m_flows[e_id]; - leave_id = e_id; - } - } - - if (m_delta) { - m_leave_id = leave_id; - - TRACE("network_flow", { - tout << "Found leaving edge " << m_leave_id; - tout << " between node " << m_graph.get_source(m_leave_id); - tout << " and node " << m_graph.get_target(m_leave_id) << " with delta = " << *m_delta << "...\n"; - }); - return true; - } - TRACE("network_flow", tout << "Can't find a leaving edge... The problem is unbounded.\n";); - return false; - } - - template - void network_flow::update_spanning_tree() { - m_tree->update(m_enter_id, m_leave_id); - } - - template - bool network_flow::choose_entering_edge(pivot_rule pr) { - pivot_rule_impl * pivot; - switch (pr) { - case FIRST_ELIGIBLE: - pivot = alloc(first_eligible_pivot, m_graph, m_potentials, m_states, m_enter_id); - break; - case BEST_ELIGIBLE: - pivot = alloc(best_eligible_pivot, m_graph, m_potentials, m_states, m_enter_id); - break; - case CANDIDATE_LIST: - pivot = alloc(candidate_list_pivot, m_graph, m_potentials, m_states, m_enter_id); - break; - default: - UNREACHABLE(); - } - return pivot->choose_entering_edge(); - } - - // Minimize cost flows - template - min_flow_result network_flow::min_cost(pivot_rule pr) { - initialize(); - while (choose_entering_edge(pr)) { - bool bounded = choose_leaving_edge(); - if (!bounded) return UNBOUNDED; - update_flows(); - if (m_enter_id != m_leave_id) { - SASSERT(edge_in_tree(m_leave_id)); - SASSERT(!edge_in_tree(m_enter_id)); - m_states[m_enter_id] = BASIS; - m_states[m_leave_id] = LOWER; - update_spanning_tree(); - update_potentials(); - TRACE("network_flow", tout << "Spanning tree:\n"; display_spanning_tree(tout);); - SASSERT(check_well_formed()); - } - } - if (is_infeasible()) return INFEASIBLE; - TRACE("network_flow", tout << "Found optimal solution.\n";); - SASSERT(check_optimal()); - return OPTIMAL; - } - - template - bool network_flow::is_infeasible() { -#if 0 - // Flows of artificial arcs should be zero - unsigned num_nodes = m_graph.get_num_nodes(); - unsigned num_edges = m_graph.get_num_edges(); - for (unsigned i = 1; i < num_nodes; ++i) { - if (m_flows[num_edges - i].is_pos()) return true; - } -#endif - return false; - } - - // Get the optimal solution - template - typename network_flow::numeral network_flow::get_optimal_solution(vector & result, bool is_dual) { - numeral objective_value = numeral::zero(); - unsigned num_edges = m_graph.get_num_edges(); - for (unsigned i = 0; i < num_edges; ++i) { - if (m_states[i] == BASIS) - { - objective_value += m_flows[i].get_rational() * m_graph.get_weight(i); - } - } - result.reset(); - if (is_dual) { - result.append(m_potentials); - } - else { - result.append(m_flows); - } - return objective_value; - } - - template - bool network_flow::edge_in_tree(edge_id id) const { - return m_states[id] == BASIS; - } - - template - bool network_flow::check_well_formed() { - SASSERT(m_tree->check_well_formed()); - SASSERT(!m_delta || !(*m_delta).is_neg()); - - // m_flows are zero on non-basic edges - for (unsigned i = 0; i < m_flows.size(); ++i) { - SASSERT(!m_flows[i].is_neg()); - SASSERT(m_states[i] == BASIS || m_flows[i].is_zero()); - } - - unsigned num_edges = m_graph.get_num_edges(); - for (unsigned i = 0; i < num_edges; ++i) { - if (m_states[i] == BASIS) { - dl_var src = m_graph.get_source(i); - dl_var tgt = m_graph.get_target(i); - numeral weight = m_graph.get_weight(i); - SASSERT(m_potentials[src] - m_potentials[tgt] == weight); - } - } - - return true; - } - - template - bool network_flow::check_optimal() { - numeral total_cost = numeral::zero(); - unsigned num_edges = m_graph.get_num_edges(); - for (unsigned i = 0; i < num_edges; ++i) { - if (m_states[i] == BASIS) { - total_cost += m_flows[i].get_rational() * m_graph.get_weight(i); - } - } - - for (unsigned i = 0; i < num_edges; ++i) { - dl_var src = m_graph.get_source(i); - dl_var tgt = m_graph.get_target(i); - numeral weight = m_graph.get_weight(i); - SASSERT(m_potentials[src] - m_potentials[tgt] <= weight); - } - - // m_flows are zero on non-basic edges - for (unsigned i = 0; i < m_flows.size(); ++i) { - SASSERT(m_states[i] == BASIS || m_flows[i].is_zero()); - } - numeral total_balance = numeral::zero(); - for (unsigned i = 0; i < m_potentials.size(); ++i) { - total_balance += m_balances[i] * m_potentials[i]; - } - std::cout << "Total balance: " << total_balance << ", total cost: " << total_cost << std::endl; - return total_cost == total_balance; - } - template void network_flow::display_spanning_tree(std::ofstream & os) { - ++m_step;; - std::string prefix = "T"; - prefix.append(std::to_string(m_step)); - prefix.append("_"); - unsigned root = m_graph.get_num_nodes() - 1; - for (unsigned i = 0; i < root; ++i) { - os << prefix << i << "[shape=circle,label=\"" << prefix << i << " ["; - os << m_potentials[i] << "/" << m_balances[i] << "]\"];\n"; - } - os << prefix << root << "[shape=doublecircle,label=\"" << prefix << root << " ["; - os << m_potentials[root] << "/" << m_balances[root] << "]\"];\n"; + ++m_step;; + std::string prefix = "T"; + prefix.append(std::to_string(m_step)); + prefix.append("_"); + unsigned root = m_graph.get_num_nodes() - 1; + for (unsigned i = 0; i < root; ++i) { + os << prefix << i << "[shape=circle,label=\"" << prefix << i << " ["; + os << m_potentials[i] << "/" << m_balances[i] << "]\"];\n"; + } + os << prefix << root << "[shape=doublecircle,label=\"" << prefix << root << " ["; + os << m_potentials[root] << "/" << m_balances[root] << "]\"];\n"; - unsigned num_edges = m_graph.get_num_edges(); - for (unsigned i = 0; i < num_edges; ++i) { - os << prefix << m_graph.get_source(i) << " -> " << prefix << m_graph.get_target(i); - if (m_states[i] == BASIS) { - os << "[color=red,penwidth=3.0,label=\"" << m_flows[i] << "/" << m_graph.get_weight(i) << "\"];\n"; - } - else { - os << "[label=\"" << m_flows[i] << "/" << m_graph.get_weight(i) << "\"];\n"; - } + unsigned num_edges = m_graph.get_num_edges(); + for (unsigned i = 0; i < num_edges; ++i) { + os << prefix << m_graph.get_source(i) << " -> " << prefix << m_graph.get_target(i); + if (edge_in_tree(i)) { + os << "[color=red,penwidth=3.0,label=\"" << m_flows[i] << "/" << m_graph.get_weight(i) << "\"];\n"; } - os << std::endl; + else { + os << "[label=\"" << m_flows[i] << "/" << m_graph.get_weight(i) << "\"];\n"; + } + } + os << std::endl; } } diff --git a/src/smt/spanning_tree_base.h b/src/smt/spanning_tree_base.h index f48ce8f4f..3d3ee7b3a 100644 --- a/src/smt/spanning_tree_base.h +++ b/src/smt/spanning_tree_base.h @@ -25,15 +25,8 @@ Notes: namespace smt { template - inline std::string pp_vector(std::string const & label, TV v, bool has_header = false) { + inline std::string pp_vector(std::string const & label, TV v) { std::ostringstream oss; - if (has_header) { - oss << "Index "; - for (unsigned i = 0; i < v.size(); ++i) { - oss << i << " "; - } - oss << std::endl; - } oss << label << " "; for (unsigned i = 0; i < v.size(); ++i) { oss << v[i] << " "; diff --git a/src/smt/spanning_tree_def.h b/src/smt/spanning_tree_def.h index 60bbde291..5dbcd2b8b 100644 --- a/src/smt/spanning_tree_def.h +++ b/src/smt/spanning_tree_def.h @@ -50,7 +50,7 @@ namespace smt { } TRACE("network_flow", { - tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Threads", m_thread); + tout << pp_vector("Predecessors", m_pred) << pp_vector("Threads", m_thread); tout << pp_vector("Depths", m_depth) << pp_vector("Tree", m_tree); }); } @@ -204,7 +204,7 @@ namespace smt { SASSERT(in_subtree_t2(v)); TRACE("network_flow", { - tout << pp_vector("Predecessors", m_pred, true) << pp_vector("Threads", m_thread); + tout << pp_vector("Predecessors", m_pred) << pp_vector("Threads", m_thread); tout << pp_vector("Depths", m_depth) << pp_vector("Tree", m_tree); }); } From 192ce11ca63a6d475e25a9a022bd3d91a79d5102 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 5 Dec 2013 11:42:04 -0800 Subject: [PATCH 188/925] change model binding time Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 34 ++++++++++++++++++++++------------ src/opt/opt_context.h | 1 + 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 31202927c..49f15f420 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -66,24 +66,34 @@ namespace opt { s.assert_expr(m_hard_constraints[i].get()); } - if (m_objectives.size() == 1) { + lbool is_sat = s.check_sat_core(0,0); + if (is_sat != l_true) { + m_model = 0; + return is_sat; + } + s.get_model(m_model); + switch (m_objectives.size()) { + case 0: + return is_sat; + case 1: return execute(m_objectives[0], false); + default: { + symbol pri = m_params.get_sym("priority", symbol("lex")); + if (pri == symbol("pareto")) { + return execute_pareto(); + } + else if (pri == symbol("box")) { + return execute_box(); + } + else { + return execute_lex(); + } } - - symbol pri = m_params.get_sym("priority", symbol("lex")); - if (pri == symbol("pareto")) { - return execute_pareto(); - } - else if (pri == symbol("box")) { - return execute_box(); - } - else { - return execute_lex(); } } void context::get_model(model_ref& mdl) { - get_solver().get_model(mdl); + mdl = m_model; } lbool context::execute_min_max(unsigned index, bool committed, bool is_max) { diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index a1f391d1d..bce4ad3db 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -66,6 +66,7 @@ namespace opt { optsmt m_optsmt; map_t m_maxsmts; vector m_objectives; + model_ref m_model; public: context(ast_manager& m); ~context(); From 5fc429c50164ca564f40f0e4d394c15d422a9c53 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 5 Dec 2013 16:31:29 -0800 Subject: [PATCH 189/925] debugging network simplex Signed-off-by: Nikolaj Bjorner --- src/smt/network_flow.h | 11 +-- src/smt/network_flow_def.h | 119 ++++++++++++++------------------ src/smt/theory_diff_logic.h | 10 ++- src/smt/theory_diff_logic_def.h | 17 ++--- src/smt/theory_utvpi.h | 5 +- src/smt/theory_utvpi_def.h | 15 ++-- 6 files changed, 75 insertions(+), 102 deletions(-) diff --git a/src/smt/network_flow.h b/src/smt/network_flow.h index 65575965f..e0b415c03 100644 --- a/src/smt/network_flow.h +++ b/src/smt/network_flow.h @@ -144,9 +144,11 @@ namespace smt { graph m_graph; scoped_ptr m_tree; scoped_ptr m_pivot; - vector m_balances; // Denote supply/demand b_i on node i - vector m_potentials; // Duals of flows which are convenient to compute dual solutions - vector m_flows; // Basic feasible flows + vector m_balances; // nodes + 1 |-> [b -1b] Denote supply/demand b_i on node i + vector m_potentials; // nodes + 1 |-> initial: +/- 1 + // Duals of flows which are convenient to compute dual solutions + // become solutions to Dual simplex. + vector m_flows; // edges + nodes |-> assignemnt Basic feasible flows svector m_states; unsigned m_step; edge_id m_enter_id; @@ -176,9 +178,10 @@ namespace smt { bool check_well_formed(); bool check_optimal(); - void display(std::ofstream & os); + void display_primal(std::ofstream & os); void display_dual(std::ofstream & os); void display_spanning_tree(std::ofstream & os); + void display_system(std::ofstream & os); public: diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index 683ea0b98..777bd07a3 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -28,7 +28,7 @@ namespace smt { template bool network_flow::first_eligible_pivot::choose_entering_edge() { - TRACE("network_flow", tout << "choose_entering_edge...\n";); + numeral cost = numeral::zero(); int num_edges = m_graph.get_num_edges(); for (int i = m_next_edge; i < m_next_edge + num_edges; ++i) { edge_id id = i % num_edges; @@ -37,65 +37,51 @@ namespace smt { } node src = m_graph.get_source(id); node tgt = m_graph.get_target(id); - numeral cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(id); + cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(id); if (cost.is_pos()) { m_next_edge = m_enter_id = id; - TRACE("network_flow", - tout << "Found entering edge " << id << " between node "; - tout << src << " and node " << tgt << " with reduced cost = " << cost << "...\n";); return true; } } - TRACE("network_flow", tout << "Found no entering edge...\n";); return false; }; template bool network_flow::best_eligible_pivot::choose_entering_edge() { - TRACE("network_flow", tout << "choose_entering_edge...\n";); unsigned num_edges = m_graph.get_num_edges(); - numeral max = numeral::zero(); + numeral cost = numeral::zero(); for (unsigned i = 0; i < num_edges; ++i) { node src = m_graph.get_source(i); node tgt = m_graph.get_target(i); if (!edge_in_tree(i)) { - numeral cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(i); - if (cost > max) { - max = cost; + numeral new_cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(i); + if (new_cost > cost) { + cost = new_cost; m_enter_id = i; } } } - if (max.is_pos()) { - TRACE("network_flow", { - tout << "Found entering edge " << m_enter_id << " between node "; - tout << m_graph.get_source(m_enter_id) << " and node " << m_graph.get_target(m_enter_id); - tout << " with reduced cost = " << max << "...\n"; - }); - return true; - } - TRACE("network_flow", tout << "Found no entering edge...\n";); - return false; + return cost.is_pos(); }; template bool network_flow::candidate_list_pivot::choose_entering_edge() { + numeral cost = numeral::zero(); if (m_current_length == 0 || m_minor_step == MINOR_STEP_LIMIT) { // Build the candidate list unsigned num_edges = m_graph.get_num_edges(); - numeral max = numeral::zero(); m_current_length = 0; for (unsigned i = m_next_edge; i < m_next_edge + num_edges; ++i) { edge_id id = (i >= num_edges) ? i - num_edges : i; node src = m_graph.get_source(id); node tgt = m_graph.get_target(id); if (!edge_in_tree(id)) { - numeral cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(id); - if (cost.is_pos()) { + numeral new_cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(id); + if (new_cost.is_pos()) { m_candidates[m_current_length] = id; ++m_current_length; - if (cost > max) { - max = cost; + if (new_cost > cost) { + cost = new_cost; m_enter_id = id; } } @@ -104,48 +90,29 @@ namespace smt { } m_next_edge = m_enter_id; m_minor_step = 1; - if (max.is_pos()) { - TRACE("network_flow", { - tout << "Found entering edge " << m_enter_id << " between node "; - tout << m_graph.get_source(m_enter_id) << " and node " << m_graph.get_target(m_enter_id); - tout << " with reduced cost = " << max << "...\n"; - }); - return true; - } - TRACE("network_flow", tout << "Found no entering edge...\n";); - return false; + return cost.is_pos(); } ++m_minor_step; - numeral max = numeral::zero(); for (unsigned i = 0; i < m_current_length; ++i) { edge_id id = m_candidates[i]; node src = m_graph.get_source(id); node tgt = m_graph.get_target(id); if (!edge_in_tree(id)) { - numeral cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(id); - if (cost > max) { - max = cost; + numeral new_cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(id); + if (new_cost > cost) { + cost = new_cost; m_enter_id = id; } // Remove stale candidates - if (!cost.is_pos()) { + if (!new_cost.is_pos()) { --m_current_length; m_candidates[i] = m_candidates[m_current_length]; --i; } } } - if (max.is_pos()) { - TRACE("network_flow", { - tout << "Found entering edge " << m_enter_id << " between node "; - tout << m_graph.get_source(m_enter_id) << " and node " << m_graph.get_target(m_enter_id); - tout << " with reduced cost = " << max << "...\n"; - }); - return true; - } - TRACE("network_flow", tout << "Found no entering edge...\n";); - return false; + return cost.is_pos(); }; template @@ -167,7 +134,7 @@ namespace smt { tout << "Difference logic optimization:" << std::endl; display_dual(tout); tout << "Minimum cost flow:" << std::endl; - display(tout); + display_primal(tout); };); m_step = 0; @@ -219,7 +186,8 @@ namespace smt { tout << pp_vector("Flows", m_flows); tout << "Cost: " << get_cost() << "\n"; tout << "Spanning tree:\n"; - display_spanning_tree(tout);); + display_spanning_tree(tout); + display_primal(tout);); SASSERT(check_well_formed()); } @@ -252,7 +220,6 @@ namespace smt { template void network_flow::update_flows() { - TRACE("network_flow", tout << "update_flows...\n";); m_flows[m_enter_id] += *m_delta; node src = m_graph.get_source(m_enter_id); node tgt = m_graph.get_target(m_enter_id); @@ -269,7 +236,6 @@ namespace smt { template bool network_flow::choose_leaving_edge() { - TRACE("network_flow", tout << "choose_leaving_edge...\n";); node src = m_graph.get_source(m_enter_id); node tgt = m_graph.get_target(m_enter_id); m_delta.set_invalid(); @@ -286,14 +252,7 @@ namespace smt { } } m_leave_id = leave_id; - - TRACE("network_flow", - tout << "Leaving edge " << m_leave_id; - tout << " between node " << m_graph.get_source(m_leave_id); - tout << " and node " << m_graph.get_target(m_leave_id) ; - if (m_delta) tout << " with delta = " << *m_delta; - tout << "\n";); - + return m_delta; } @@ -329,6 +288,19 @@ namespace smt { while (choose_entering_edge(pr)) { bool bounded = choose_leaving_edge(); if (!bounded) return UNBOUNDED; + //TRACE("network_flow", + { + vectorconst& es = m_graph.get_all_edges(); + edge const& e_in = es[m_enter_id]; + edge const& e_out = es[m_leave_id]; + node src_in = e_in.get_source(), tgt_in = e_in.get_target(); + node src_out = e_out.get_source(), tgt_out = e_out.get_target(); + numeral c1 = m_potentials[src_in] - m_potentials[tgt_in] - m_graph.get_weight(m_enter_id); + numeral c2 = m_potentials[src_out] - m_potentials[tgt_out] - m_graph.get_weight(m_leave_id); + tout << "new base: y_" << src_in << "_" << tgt_in << " cost: " << c1 << " delta: " << *m_delta << "\n"; + tout << "old base: y_" << src_out << "_" << tgt_out << " cost: " << c2 << "\n"; + } + // ); update_flows(); if (m_enter_id != m_leave_id) { SASSERT(edge_in_tree(m_leave_id)); @@ -340,10 +312,18 @@ namespace smt { TRACE("network_flow", tout << "Spanning tree:\n"; display_spanning_tree(tout); - tout << "Cost: " << get_cost() << "\n";); + tout << "Cost: " << get_cost() << "\n"; + display_primal(tout); + ); SASSERT(check_well_formed()); } } + TRACE("network_flow", + tout << "Spanning tree:\n"; + display_spanning_tree(tout); + tout << "Cost: " << get_cost() << "\n"; + display_primal(tout); + ); if (is_infeasible()) return INFEASIBLE; TRACE("network_flow", tout << "Found optimal solution.\n";); SASSERT(check_optimal()); @@ -352,14 +332,13 @@ namespace smt { template bool network_flow::is_infeasible() { -#if 0 // Flows of artificial arcs should be zero unsigned num_nodes = m_graph.get_num_nodes(); unsigned num_edges = m_graph.get_num_edges(); + SASSERT(m_flows.size() == num_edges); for (unsigned i = 1; i < num_nodes; ++i) { if (m_flows[num_edges - i].is_pos()) return true; } -#endif return false; } @@ -445,7 +424,7 @@ namespace smt { // display methods template - void network_flow::display(std::ofstream & os) { + void network_flow::display_primal(std::ofstream & os) { vector const & es = m_graph.get_all_edges(); for (unsigned i = 0; i < m_graph.get_num_edges(); ++i) { edge const & e = es[i]; @@ -486,6 +465,12 @@ namespace smt { }; os << "))" << std::endl; os << "(optimize)" << std::endl; + if (!m_flows.empty()) { + for (unsigned i = 0; i < m_graph.get_num_edges(); ++i) { + edge const & e = es[i]; + os << "; y_" << e.get_source() << "_" << e.get_target() << " = " << m_flows[i] << "\n"; + } + } } diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h index f6b704359..015144c2a 100644 --- a/src/smt/theory_diff_logic.h +++ b/src/smt/theory_diff_logic.h @@ -165,8 +165,7 @@ namespace smt { arith_eq_adapter m_arith_eq_adapter; theory_diff_logic_statistics m_stats; dl_graph m_graph; - theory_var m_zero_int; // cache the variable representing the zero variable. - theory_var m_zero_real; // cache the variable representing the zero variable. + theory_var m_zero; // cache the variable representing the zero variable. int_vector m_scc_id; // Cheap equality propagation eq_prop_info_set m_eq_prop_info_set; // set of existing equality prop infos ptr_vector m_eq_prop_infos; @@ -217,8 +216,7 @@ namespace smt { m_params(params), m_util(m), m_arith_eq_adapter(*this, params, m_util), - m_zero_int(null_theory_var), - m_zero_real(null_theory_var), + m_zero(null_theory_var), m_asserted_qhead(0), m_num_core_conflicts(0), m_num_propagation_calls(0), @@ -358,9 +356,9 @@ namespace smt { void get_implied_bound_antecedents(edge_id bridge_edge, edge_id subsumed_edge, conflict_resolution & cr); - theory_var get_zero(sort* s) const { return m_util.is_int(s)?m_zero_int:m_zero_real; } + theory_var get_zero(sort* s) const { return m_zero; } - theory_var get_zero(expr* e) const { return get_zero(get_manager().get_sort(e)); } + theory_var get_zero(expr* e) const { return m_zero; } void inc_conflicts(); diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index 7472edd8b..4202b86a3 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -71,12 +71,7 @@ void theory_diff_logic::init(context * ctx) { zero = m_util.mk_numeral(rational(0), true); e = ctx->mk_enode(zero, false, false, true); SASSERT(!is_attached_to_var(e)); - m_zero_int = mk_var(e); - - zero = m_util.mk_numeral(rational(0), false); - e = ctx->mk_enode(zero, false, false, true); - SASSERT(!is_attached_to_var(e)); - m_zero_real = mk_var(e); + m_zero = mk_var(e); } @@ -356,7 +351,7 @@ final_check_status theory_diff_logic::final_check_eh() { TRACE("arith_final", display(tout); ); // either will already be zero (as we don't do mixed constraints). - m_graph.set_to_zero(m_zero_int, m_zero_real); + m_graph.set_to_zero(m_zero); SASSERT(is_consistent()); if (m_non_diff_logic_exprs) { return FC_GIVEUP; @@ -766,8 +761,7 @@ void theory_diff_logic::reset_eh() { dealloc(m_atoms[i]); } m_graph .reset(); - m_zero_int = null_theory_var; - m_zero_real = null_theory_var; + m_zero = null_theory_var; m_atoms .reset(); m_asserted_atoms .reset(); m_stats .reset(); @@ -1022,10 +1016,9 @@ inf_eps_rational theory_diff_logic::maximize(theory_var v) { sum += balance; } // HACK: assume that v0 is always value 0 - if (balances[0].is_zero()) { - balances[0] = -sum; - } + balances[0] = -sum; + TRACE("arith", display(tout);); network_flow net_flow(m_graph, balances); min_flow_result result = net_flow.min_cost(); SASSERT(result != UNBOUNDED); diff --git a/src/smt/theory_utvpi.h b/src/smt/theory_utvpi.h index 4a5d97d52..5358fb758 100644 --- a/src/smt/theory_utvpi.h +++ b/src/smt/theory_utvpi.h @@ -138,8 +138,7 @@ namespace smt { smt_params m_params; arith_util a; arith_eq_adapter m_arith_eq_adapter; - th_var m_zero_int; // cache the variable representing the zero variable. - th_var m_zero_real; // cache the variable representing the zero variable. + th_var m_zero; //cache the variable representing the zero variable. dl_graph m_graph; nc_functor m_nc_functor; @@ -304,7 +303,7 @@ namespace smt { void new_eq_or_diseq(bool is_eq, th_var v1, th_var v2, justification& eq_just); - th_var get_zero(sort* s) const { return a.is_int(s)?m_zero_int:m_zero_real; } + th_var get_zero(sort* s) const { return m_zero; } th_var get_zero(expr* e) const { return get_zero(get_manager().get_sort(e)); } diff --git a/src/smt/theory_utvpi_def.h b/src/smt/theory_utvpi_def.h index 6039b208a..e6ec7e387 100644 --- a/src/smt/theory_utvpi_def.h +++ b/src/smt/theory_utvpi_def.h @@ -62,8 +62,7 @@ namespace smt { theory(m.mk_family_id("arith")), a(m), m_arith_eq_adapter(*this, m_params, a), - m_zero_int(null_theory_var), - m_zero_real(null_theory_var), + m_zero(null_theory_var), m_nc_functor(*this), m_asserted_qhead(0), m_agility(0.5), @@ -134,8 +133,7 @@ namespace smt { template void theory_utvpi::reset_eh() { m_graph .reset(); - m_zero_int = null_theory_var; - m_zero_real = null_theory_var; + m_zero = null_theory_var; m_atoms .reset(); m_asserted_atoms .reset(); m_stats .reset(); @@ -261,8 +259,7 @@ namespace smt { template void theory_utvpi::init(context* ctx) { theory::init(ctx); - m_zero_int = mk_var(ctx->mk_enode(a.mk_numeral(rational(0), true), false, false, true)); - m_zero_real = mk_var(ctx->mk_enode(a.mk_numeral(rational(0), false), false, false, true)); + m_zero = mk_var(ctx->mk_enode(a.mk_numeral(rational(0), true), false, false, true)); } /** @@ -556,7 +553,7 @@ namespace smt { theory_var v = null_theory_var; context& ctx = get_context(); if (r.is_zero()) { - v = a.is_int(n)?m_zero_int:m_zero_real; + v = m_zero; } else if (ctx.e_internalized(n)) { enode* e = ctx.get_enode(n); @@ -778,9 +775,7 @@ namespace smt { m_factory = alloc(arith_factory, get_manager()); m.register_factory(m_factory); enforce_parity(); - m_graph.set_to_zero(to_var(m_zero_int), to_var(m_zero_real)); - m_graph.set_to_zero(neg(to_var(m_zero_int)), neg(to_var(m_zero_real))); - m_graph.set_to_zero(to_var(m_zero_int), neg(to_var(m_zero_int))); + m_graph.set_to_zero(to_var(m_zero), neg(to_var(m_zero))); compute_delta(); DEBUG_CODE(validate_model();); } From d38e2b9b7899096c00fb42196d2311ccfef707f4 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Thu, 5 Dec 2013 17:30:40 -0800 Subject: [PATCH 190/925] Expose objective indices to .NET API --- src/api/api_opt.cpp | 24 +++++------ src/api/dotnet/Optimize.cs | 82 ++++++++++++++++++++++++++++---------- src/api/z3_api.h | 12 +++--- src/opt/opt_context.cpp | 10 +++-- src/opt/opt_context.h | 6 ++- 5 files changed, 90 insertions(+), 44 deletions(-) diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index b1640506e..7236a7682 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -72,32 +72,32 @@ extern "C" { Z3_CATCH; } - void Z3_API Z3_optimize_assert_soft(Z3_context c, Z3_optimize o, Z3_ast a, Z3_string weight, Z3_symbol id) { + unsigned Z3_API Z3_optimize_assert_soft(Z3_context c, Z3_optimize o, Z3_ast a, Z3_string weight, Z3_symbol id) { Z3_TRY; LOG_Z3_optimize_assert_soft(c, o, a, weight, id); RESET_ERROR_CODE(); - CHECK_FORMULA(a,); + CHECK_FORMULA(a,0); rational w("weight"); - to_optimize_ref(o).add_soft_constraint(to_expr(a), w, to_symbol(id)); - Z3_CATCH; + return to_optimize_ref(o).add_soft_constraint(to_expr(a), w, to_symbol(id)); + Z3_CATCH_RETURN(0); } - void Z3_API Z3_optimize_maximize(Z3_context c, Z3_optimize o, Z3_ast t) { + unsigned Z3_API Z3_optimize_maximize(Z3_context c, Z3_optimize o, Z3_ast t) { Z3_TRY; LOG_Z3_optimize_maximize(c, o, t); RESET_ERROR_CODE(); - CHECK_VALID_AST(t,); - to_optimize_ref(o).add_objective(to_app(t), true); - Z3_CATCH; + CHECK_VALID_AST(t,0); + return to_optimize_ref(o).add_objective(to_app(t), true); + Z3_CATCH_RETURN(0); } - void Z3_API Z3_optimize_minimize(Z3_context c, Z3_optimize o, Z3_ast t) { + unsigned Z3_API Z3_optimize_minimize(Z3_context c, Z3_optimize o, Z3_ast t) { Z3_TRY; LOG_Z3_optimize_minimize(c, o, t); RESET_ERROR_CODE(); - CHECK_VALID_AST(t,); - to_optimize_ref(o).add_objective(to_app(t), false); - Z3_CATCH; + CHECK_VALID_AST(t,0); + return to_optimize_ref(o).add_objective(to_app(t), false); + Z3_CATCH_RETURN(0); } Z3_lbool Z3_API Z3_optimize_check(Z3_context c, Z3_optimize o) { diff --git a/src/api/dotnet/Optimize.cs b/src/api/dotnet/Optimize.cs index 4526ead88..925773fa5 100644 --- a/src/api/dotnet/Optimize.cs +++ b/src/api/dotnet/Optimize.cs @@ -18,6 +18,7 @@ Notes: --*/ using System; +using System.Collections.Generic; using System.Diagnostics.Contracts; namespace Microsoft.Z3 @@ -28,6 +29,7 @@ namespace Microsoft.Z3 [ContractVerification(true)] public class Optimize : Z3Object { + HashSet indices; #if false /// @@ -64,6 +66,26 @@ namespace Microsoft.Z3 get { return new ParamDescrs(Context, Native.Z3_optimize_get_param_descrs(Context.nCtx, NativeObject)); } } + /// + /// Get the number of objectives. + /// + public uint ObjectiveCount + { + get { return (uint)indices.Count; } + } + + /// + /// Get all indices of objectives. + /// + public uint[] Objectives + { + get + { + var objectives = new uint[indices.Count]; + indices.CopyTo(objectives, 0); + return objectives; + } + } /// /// Assert a constraint (or multiple) into the optimize solver. @@ -91,21 +113,28 @@ namespace Microsoft.Z3 /// /// Assert soft constraint /// - public void AssertSoft(BoolExpr constraint, uint weight, string group) + /// + /// Return an objective which associates with the group of constraints. + /// + public uint AssertSoft(BoolExpr constraint, uint weight, string group) { Context.CheckContextMatch(constraint); - Symbol s = Context.MkSymbol(group); - Native.Z3_optimize_assert_soft(Context.nCtx, NativeObject, constraint.NativeObject, weight.ToString(), s.NativeObject); + Symbol s = Context.MkSymbol(group); + uint index = Native.Z3_optimize_assert_soft(Context.nCtx, NativeObject, constraint.NativeObject, weight.ToString(), s.NativeObject); + indices.Add(index); + return index; } - - public Status Check() { - Z3_lbool r = (Z3_lbool)Native.Z3_optimize_check(Context.nCtx, NativeObject); + public Status Check() { + Z3_lbool r = (Z3_lbool)Native.Z3_optimize_check(Context.nCtx, NativeObject); switch (r) { - case Z3_lbool.Z3_L_TRUE: return Status.SATISFIABLE; - case Z3_lbool.Z3_L_FALSE: return Status.UNSATISFIABLE; - default: return Status.UNKNOWN; + case Z3_lbool.Z3_L_TRUE: + return Status.SATISFIABLE; + case Z3_lbool.Z3_L_FALSE: + return Status.UNSATISFIABLE; + default: + return Status.UNKNOWN; } } @@ -127,22 +156,31 @@ namespace Microsoft.Z3 return new Model(Context, x); } } + + public uint MkMaximize(ArithExpr e) + { + uint index = Native.Z3_optimize_maximize(Context.nCtx, NativeObject, e.NativeObject); + indices.Add(index); + return index; + } - - public void Maximize(ArithExpr e) { - Native.Z3_optimize_maximize(Context.nCtx, NativeObject, e.NativeObject); - } + public uint MkMinimize(ArithExpr e) + { + uint index = Native.Z3_optimize_minimize(Context.nCtx, NativeObject, e.NativeObject); + indices.Add(index); + return index; + } - public void Minimize(ArithExpr e) { - Native.Z3_optimize_minimize(Context.nCtx, NativeObject, e.NativeObject); - } - - public ArithExpr GetLower(uint index) { - return new ArithExpr(Context, Native.Z3_optimize_get_lower(Context.nCtx, NativeObject, index)); + public ArithExpr GetLower(uint index) + { + Contract.Requires(indices.Contains(index)); + return new ArithExpr(Context, Native.Z3_optimize_get_lower(Context.nCtx, NativeObject, index)); } - public ArithExpr GetUpper(uint index) { - return new ArithExpr(Context, Native.Z3_optimize_get_upper(Context.nCtx, NativeObject, index)); + public ArithExpr GetUpper(uint index) + { + Contract.Requires(indices.Contains(index)); + return new ArithExpr(Context, Native.Z3_optimize_get_upper(Context.nCtx, NativeObject, index)); } #region Internal @@ -150,11 +188,13 @@ namespace Microsoft.Z3 : base(ctx, obj) { Contract.Requires(ctx != null); + indices = new HashSet(); } internal Optimize(Context ctx) : base(ctx, Native.Z3_mk_optimize(ctx.nCtx)) { Contract.Requires(ctx != null); + indices = new HashSet(); } internal class DecRefQueue : IDecRefQueue diff --git a/src/api/z3_api.h b/src/api/z3_api.h index a52ad6106..9350eb529 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -5987,9 +5987,9 @@ END_MLAPI_EXCLUDE \param weight - a positive weight, penalty for violating soft constraint \param id - optional identifier to group soft constraints - def_API('Z3_optimize_assert_soft', VOID, (_in(CONTEXT), _in(OPTIMIZE), _in(AST), _in(STRING), _in(SYMBOL))) + def_API('Z3_optimize_assert_soft', UINT, (_in(CONTEXT), _in(OPTIMIZE), _in(AST), _in(STRING), _in(SYMBOL))) */ - void Z3_API Z3_optimize_assert_soft(Z3_context c, Z3_optimize o, Z3_ast a, Z3_string weight, Z3_symbol id); + unsigned Z3_API Z3_optimize_assert_soft(Z3_context c, Z3_optimize o, Z3_ast a, Z3_string weight, Z3_symbol id); /** @@ -5997,9 +5997,9 @@ END_MLAPI_EXCLUDE \param c - context \param o - optimization context \param a - arithmetical term - def_API('Z3_optimize_maximize', VOID, (_in(CONTEXT), _in(OPTIMIZE), _in(AST))) + def_API('Z3_optimize_maximize', UINT, (_in(CONTEXT), _in(OPTIMIZE), _in(AST))) */ - void Z3_API Z3_optimize_maximize(Z3_context, Z3_optimize o, Z3_ast t); + unsigned Z3_API Z3_optimize_maximize(Z3_context, Z3_optimize o, Z3_ast t); /** \brief Add a minimiztion constraint. @@ -6007,9 +6007,9 @@ END_MLAPI_EXCLUDE \param o - optimization context \param a - arithmetical term - def_API('Z3_optimize_minimize', VOID, (_in(CONTEXT), _in(OPTIMIZE), _in(AST))) + def_API('Z3_optimize_minimize', UINT, (_in(CONTEXT), _in(OPTIMIZE), _in(AST))) */ - void Z3_API Z3_optimize_minimize(Z3_context, Z3_optimize o, Z3_ast t); + unsigned Z3_API Z3_optimize_minimize(Z3_context, Z3_optimize o, Z3_ast t); /** \brief Check consistency and produce optimal values. diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 49f15f420..78495c928 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -42,21 +42,25 @@ namespace opt { } } - void context::add_soft_constraint(expr* f, rational const& w, symbol const& id) { + unsigned context::add_soft_constraint(expr* f, rational const& w, symbol const& id) { maxsmt* ms; if (!m_maxsmts.find(id, ms)) { ms = alloc(maxsmt, m); m_maxsmts.insert(id, ms); m_objectives.push_back(objective(m, id)); + m_indices.insert(id, m_objectives.size() - 1); } - ms->add(f, w); + ms->add(f, w); + SASSERT(m_indices.contains(id)); + return m_indices[id]; } - void context::add_objective(app* t, bool is_max) { + unsigned context::add_objective(app* t, bool is_max) { app_ref tr(t, m); unsigned index = m_optsmt.get_num_objectives(); m_optsmt.add(t, is_max); m_objectives.push_back(objective(is_max, tr, index)); + return index; } lbool context::optimize() { diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index bce4ad3db..cb46494cd 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -36,6 +36,7 @@ namespace opt { class context { typedef map map_t; + typedef map map_id; enum objective_t { O_MAXIMIZE, O_MINIMIZE, @@ -65,13 +66,14 @@ namespace opt { params_ref m_params; optsmt m_optsmt; map_t m_maxsmts; + map_id m_indices; vector m_objectives; model_ref m_model; public: context(ast_manager& m); ~context(); - void add_soft_constraint(expr* f, rational const& w, symbol const& id); - void add_objective(app* t, bool is_max); + unsigned add_soft_constraint(expr* f, rational const& w, symbol const& id); + unsigned add_objective(app* t, bool is_max); void add_hard_constraint(expr* f) { m_hard_constraints.push_back(f); } lbool optimize(); From 7884b2ab315b58f2f59bf45dec73c0f7c4b41491 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 6 Dec 2013 11:00:49 -0800 Subject: [PATCH 191/925] make lia2card general purpose functions visible Signed-off-by: Nikolaj Bjorner --- src/tactic/arith/lia2card_tactic.cpp | 632 ++++++++------------------- 1 file changed, 182 insertions(+), 450 deletions(-) diff --git a/src/tactic/arith/lia2card_tactic.cpp b/src/tactic/arith/lia2card_tactic.cpp index c5db50427..4212b8e4d 100644 --- a/src/tactic/arith/lia2card_tactic.cpp +++ b/src/tactic/arith/lia2card_tactic.cpp @@ -25,232 +25,198 @@ Notes: #include"arith_decl_plugin.h" class lia2card_tactic : public tactic { - - struct imp { - typedef obj_hashtable expr_set; - ast_manager & m; - arith_util a; - pb_util m_pb; - mutable ptr_vector m_todo; - expr_set m_01s; - - - imp(ast_manager & _m, params_ref const & p): - m(_m), - a(m), - m_pb(m) { - } - - void set_cancel(bool f) { - } - - void updt_params(params_ref const & p) { - } - - void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { - SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; - m_01s.reset(); - - tactic_report report("cardinality-intro", *g); - - bound_manager bounds(m); - bounds(*g); - - bound_manager::iterator bit = bounds.begin(), bend = bounds.end(); - for (; bit != bend; ++bit) { - expr* x = *bit; - bool s1, s2; - rational lo, hi; - if (a.is_int(x) && - bounds.has_lower(x, lo, s1) && !s1 && lo.is_zero() && - bounds.has_upper(x, hi, s2) && !s2 && hi.is_one()) { - m_01s.insert(x); - TRACE("pb", tout << "add bound " << mk_pp(x, m) << "\n";); - } - } - - expr_safe_replace sub(m); - extract_pb_substitution(g, sub); - - expr_ref new_curr(m); - proof_ref new_pr(m); - - for (unsigned i = 0; i < g->size(); i++) { - expr * curr = g->form(i); - sub(curr, new_curr); - g->update(i, new_curr, new_pr, g->dep(i)); - } - g->inc_depth(); - result.push_back(g.get()); - TRACE("pb", g->display(tout);); - SASSERT(g->is_well_sorted()); - - // TBD: convert models for 0-1 variables. - // TBD: support proof conversion (or not..) - } - - void extract_pb_substitution(goal_ref const& g, expr_safe_replace& sub) { - ast_mark mark; - for (unsigned i = 0; i < g->size(); i++) { - extract_pb_substitution(mark, g->form(i), sub); - } - } - - void extract_pb_substitution(ast_mark& mark, expr* fml, expr_safe_replace& sub) { - expr_ref tmp(m); - m_todo.reset(); - m_todo.push_back(fml); - while (!m_todo.empty()) { - expr* e = m_todo.back(); - m_todo.pop_back(); - if (mark.is_marked(e) || !is_app(e)) { - continue; - } - mark.mark(e, true); - if (get_pb_relation(sub, e, tmp)) { - sub.insert(e, tmp); - continue; - } - app* ap = to_app(e); - m_todo.append(ap->get_num_args(), ap->get_args()); - } - } - - - bool is_01var(expr* x) const { - return m_01s.contains(x); - } - - expr_ref mk_01(expr* x) { - expr* r = m.mk_eq(x, a.mk_numeral(rational(1), m.get_sort(x))); - return expr_ref(r, m); - } - - bool get_pb_relation(expr_safe_replace& sub, expr* fml, expr_ref& result) { - expr* x, *y; - expr_ref_vector args(m); - vector coeffs; - rational coeff; - if ((a.is_le(fml, x, y) || a.is_ge(fml, y, x)) && - get_pb_sum(x, rational::one(), args, coeffs, coeff) && - get_pb_sum(y, -rational::one(), args, coeffs, coeff)) { - result = m_pb.mk_le(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff); - return true; - } - else if ((a.is_lt(fml, y, x) || a.is_gt(fml, x, y)) && - get_pb_sum(x, rational::one(), args, coeffs, coeff) && - get_pb_sum(y, -rational::one(), args, coeffs, coeff)) { - result = m.mk_not(m_pb.mk_le(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff)); - return true; - } - else if (m.is_eq(fml, x, y) && - get_pb_sum(x, rational::one(), args, coeffs, coeff) && - get_pb_sum(y, -rational::one(), args, coeffs, coeff)) { - result = m.mk_and(m_pb.mk_le(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff), - m_pb.mk_ge(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff)); - return true; - } - return false; - } - - bool get_pb_sum(expr* x, rational const& mul, expr_ref_vector& args, vector& coeffs, rational& coeff) { - expr *y, *z, *u; - rational r, q; - app* f = to_app(x); - bool ok = true; - if (a.is_add(x)) { - for (unsigned i = 0; ok && i < f->get_num_args(); ++i) { - ok = get_pb_sum(f->get_arg(i), mul, args, coeffs, coeff); - } - } - else if (a.is_sub(x, y, z)) { - ok = get_pb_sum(y, mul, args, coeffs, coeff); - ok = ok && get_pb_sum(z, -mul, args, coeffs, coeff); - } - else if (a.is_uminus(x, y)) { - ok = get_pb_sum(y, -mul, args, coeffs, coeff); - } - else if (a.is_mul(x, y, z) && a.is_numeral(y, r)) { - ok = get_pb_sum(z, r*mul, args, coeffs, coeff); - } - else if (a.is_mul(x, z, y) && a.is_numeral(y, r)) { - ok = get_pb_sum(z, r*mul, args, coeffs, coeff); - } - else if (m.is_ite(x, y, z, u) && a.is_numeral(z, r) && a.is_numeral(u, q)) { - args.push_back(y); - coeffs.push_back(r*mul); - args.push_back(m.mk_not(y)); - coeffs.push_back(q*mul); - } - else if (is_01var(x)) { - args.push_back(mk_01(x)); - coeffs.push_back(mul); - } - else if (a.is_numeral(x, r)) { - coeff += mul*r; - } - else { - ok = false; - } - return ok; - } - }; - - imp * m_imp; - params_ref m_params; public: - lia2card_tactic(ast_manager & m, params_ref const & p): - m_params(p) { - m_imp = alloc(imp, m, p); + typedef obj_hashtable expr_set; + ast_manager & m; + arith_util a; + params_ref m_params; + pb_util m_pb; + mutable ptr_vector m_todo; + expr_set m_01s; + + + lia2card_tactic(ast_manager & _m, params_ref const & p): + m(_m), + a(m), + m_pb(m) { } + virtual ~lia2card_tactic() { + } + + void set_cancel(bool f) { + } + + void updt_params(params_ref const & p) { + m_params = p; + } + + virtual void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) { + SASSERT(g->is_well_sorted()); + mc = 0; pc = 0; core = 0; + m_01s.reset(); + + tactic_report report("cardinality-intro", *g); + + bound_manager bounds(m); + bounds(*g); + + bound_manager::iterator bit = bounds.begin(), bend = bounds.end(); + for (; bit != bend; ++bit) { + expr* x = *bit; + bool s1, s2; + rational lo, hi; + if (a.is_int(x) && + bounds.has_lower(x, lo, s1) && !s1 && lo.is_zero() && + bounds.has_upper(x, hi, s2) && !s2 && hi.is_one()) { + m_01s.insert(x); + TRACE("pb", tout << "add bound " << mk_pp(x, m) << "\n";); + } + } + + expr_safe_replace sub(m); + extract_pb_substitution(g, sub); + + expr_ref new_curr(m); + proof_ref new_pr(m); + + for (unsigned i = 0; i < g->size(); i++) { + expr * curr = g->form(i); + sub(curr, new_curr); + g->update(i, new_curr, new_pr, g->dep(i)); + } + g->inc_depth(); + result.push_back(g.get()); + TRACE("pb", g->display(tout);); + SASSERT(g->is_well_sorted()); + + // TBD: convert models for 0-1 variables. + // TBD: support proof conversion (or not..) + } + + void extract_pb_substitution(goal_ref const& g, expr_safe_replace& sub) { + ast_mark mark; + for (unsigned i = 0; i < g->size(); i++) { + extract_pb_substitution(mark, g->form(i), sub); + } + } + + void extract_pb_substitution(ast_mark& mark, expr* fml, expr_safe_replace& sub) { + expr_ref tmp(m); + m_todo.reset(); + m_todo.push_back(fml); + while (!m_todo.empty()) { + expr* e = m_todo.back(); + m_todo.pop_back(); + if (mark.is_marked(e) || !is_app(e)) { + continue; + } + mark.mark(e, true); + if (get_pb_relation(sub, e, tmp)) { + sub.insert(e, tmp); + continue; + } + app* ap = to_app(e); + m_todo.append(ap->get_num_args(), ap->get_args()); + } + } + + + bool is_01var(expr* x) const { + return m_01s.contains(x); + } + + expr_ref mk_01(expr* x) { + expr* r = m.mk_eq(x, a.mk_numeral(rational(1), m.get_sort(x))); + return expr_ref(r, m); + } + + bool get_pb_relation(expr_safe_replace& sub, expr* fml, expr_ref& result) { + expr* x, *y; + expr_ref_vector args(m); + vector coeffs; + rational coeff; + if ((a.is_le(fml, x, y) || a.is_ge(fml, y, x)) && + get_pb_sum(x, rational::one(), args, coeffs, coeff) && + get_pb_sum(y, -rational::one(), args, coeffs, coeff)) { + result = m_pb.mk_le(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff); + return true; + } + else if ((a.is_lt(fml, y, x) || a.is_gt(fml, x, y)) && + get_pb_sum(x, rational::one(), args, coeffs, coeff) && + get_pb_sum(y, -rational::one(), args, coeffs, coeff)) { + result = m.mk_not(m_pb.mk_le(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff)); + return true; + } + else if (m.is_eq(fml, x, y) && + get_pb_sum(x, rational::one(), args, coeffs, coeff) && + get_pb_sum(y, -rational::one(), args, coeffs, coeff)) { + result = m.mk_and(m_pb.mk_le(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff), + m_pb.mk_ge(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff)); + return true; + } + return false; + } + + bool get_pb_sum(expr* x, rational const& mul, expr_ref_vector& args, vector& coeffs, rational& coeff) { + expr *y, *z, *u; + rational r, q; + app* f = to_app(x); + bool ok = true; + if (a.is_add(x)) { + for (unsigned i = 0; ok && i < f->get_num_args(); ++i) { + ok = get_pb_sum(f->get_arg(i), mul, args, coeffs, coeff); + } + } + else if (a.is_sub(x, y, z)) { + ok = get_pb_sum(y, mul, args, coeffs, coeff); + ok = ok && get_pb_sum(z, -mul, args, coeffs, coeff); + } + else if (a.is_uminus(x, y)) { + ok = get_pb_sum(y, -mul, args, coeffs, coeff); + } + else if (a.is_mul(x, y, z) && a.is_numeral(y, r)) { + ok = get_pb_sum(z, r*mul, args, coeffs, coeff); + } + else if (a.is_mul(x, z, y) && a.is_numeral(y, r)) { + ok = get_pb_sum(z, r*mul, args, coeffs, coeff); + } + else if (m.is_ite(x, y, z, u) && a.is_numeral(z, r) && a.is_numeral(u, q)) { + args.push_back(y); + coeffs.push_back(r*mul); + args.push_back(m.mk_not(y)); + coeffs.push_back(q*mul); + } + else if (is_01var(x)) { + args.push_back(mk_01(x)); + coeffs.push_back(mul); + } + else if (a.is_numeral(x, r)) { + coeff += mul*r; + } + else { + ok = false; + } + return ok; + } + virtual tactic * translate(ast_manager & m) { return alloc(lia2card_tactic, m, m_params); } - virtual ~lia2card_tactic() { - dealloc(m_imp); - } - - virtual void updt_params(params_ref const & p) { - m_params = p; - m_imp->updt_params(p); - } - virtual void collect_param_descrs(param_descrs & r) { } - - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { - (*m_imp)(in, result, mc, pc, core); - } - + virtual void cleanup() { - ast_manager & m = m_imp->m; - imp * d = m_imp; #pragma omp critical (tactic_cancel) { - m_imp = 0; + m_01s.reset(); + m_todo.reset(); } - dealloc(d); - d = alloc(imp, m, m_params); - #pragma omp critical (tactic_cancel) - { - m_imp = d; - } - } - - virtual void set_cancel(bool f) { - if (m_imp) - m_imp->set_cancel(f); } }; @@ -258,240 +224,6 @@ tactic * mk_lia2card_tactic(ast_manager & m, params_ref const & p) { return clean(alloc(lia2card_tactic, m, p)); } - -#if 0 - void extract_substitution(expr_safe_replace& sub) { - expr_set::iterator it = m_01s.begin(), end = m_01s.end(); - for (; it != end; ++it) { - extract_substitution(sub, *it); - } - } - - void extract_substitution(expr_safe_replace& sub, expr* x) { - ptr_vector const& use_list = m_uses.find(x); - for (unsigned i = 0; i < use_list.size(); ++i) { - expr* u = use_list[i]; - convert_01(sub, u); - } - } - - expr_ref mk_le(expr* x, rational const& bound) { - if (bound.is_pos()) { - return expr_ref(m.mk_true(), m); - } - else if (bound.is_zero()) { - return expr_ref(m.mk_not(mk_01(x)), m); - } - else { - return expr_ref(m.mk_false(), m); - } - } - - expr_ref mk_ge(expr* x, rational const& bound) { - if (bound.is_one()) { - return expr_ref(mk_01(x), m); - } - else if (bound.is_pos()) { - return expr_ref(m.mk_false(), m); - } - else { - return expr_ref(m.mk_true(), m); - } - } - - void convert_01(expr_safe_replace& sub, expr* fml) { - rational n; - unsigned k; - expr_ref_vector args(m); - expr_ref result(m); - expr* x, *y; - if (a.is_le(fml, x, y) || a.is_ge(fml, y, x)) { - if (is_01var(x) && a.is_numeral(y, n)) { - sub.insert(fml, mk_le(x, n)); - } - else if (is_01var(y) && a.is_numeral(x, n)) { - sub.insert(fml, mk_ge(y, n)); - } - else if (is_01_add(x, args) && is_unsigned(y, k)) { // x <= k - sub.insert(fml, m_pb.mk_at_most_k(args.size(), args.c_ptr(), k)); - } - else if (is_01_add(y, args) && is_unsigned(x, k)) { // k <= y <=> not (y <= k-1) - if (k == 0) - sub.insert(fml, m.mk_true()); - else - sub.insert(fml, m.mk_not(m_pb.mk_at_most_k(args.size(), args.c_ptr(), k-1))); - } - else { - UNREACHABLE(); - } - } - else if (a.is_lt(fml, x, y) || a.is_gt(fml, y, x)) { - if (is_01var(x) && a.is_numeral(y, n)) { - sub.insert(fml, mk_le(x, n-rational(1))); - } - else if (is_01var(y) && a.is_numeral(x, n)) { - sub.insert(fml, mk_ge(y, n+rational(1))); - } - else if (is_01_add(x, args) && is_unsigned(y, k)) { // x < k - if (k == 0) - sub.insert(fml, m.mk_false()); - else - sub.insert(fml, m_pb.mk_at_most_k(args.size(), args.c_ptr(), k-1)); - } - else if (is_01_add(y, args) && is_unsigned(x, k)) { // k < y <=> not (y <= k) - sub.insert(fml, m.mk_not(m_pb.mk_at_most_k(args.size(), args.c_ptr(), k))); - } - else { - UNREACHABLE(); - } - } - else if (m.is_eq(fml, x, y)) { - if (!is_01var(x)) { - std::swap(x, y); - } - if (is_01var(x) && a.is_numeral(y, n)) { - if (n.is_one()) { - sub.insert(fml, mk_01(x)); - } - else if (n.is_zero()) { - sub.insert(fml, m.mk_not(mk_01(x))); - } - else { - sub.insert(fml, m.mk_false()); - } - } - else { - UNREACHABLE(); - } - } - else if (is_01_sum(fml)) { - SASSERT(m_uses.contains(fml)); - ptr_vector const& u = m_uses.find(fml); - for (unsigned i = 0; i < u.size(); ++i) { - convert_01(sub, u[i]); - } - } - else { - UNREACHABLE(); - } - } - - bool is_01_add(expr* x, expr_ref_vector& args) { - if (a.is_add(x)) { - app* ap = to_app(x); - for (unsigned i = 0; i < ap->get_num_args(); ++i) { - if (!is_01var(ap->get_arg(i))) { - return false; - } - args.push_back(mk_01(ap->get_arg(i))); - } - return true; - } - else { - return false; - } - } - - bool validate_uses(ptr_vector const& use_list) { - for (unsigned i = 0; i < use_list.size(); ++i) { - if (!validate_use(use_list[i])) { - return false; - } - } - return true; - } - - bool validate_use(expr* fml) { - expr* x, *y; - if (a.is_le(fml, x, y) || - a.is_ge(fml, x, y) || - a.is_lt(fml, x, y) || - a.is_gt(fml, x, y) || - m.is_eq(fml, x, y)) { - if (a.is_numeral(x)) { - std::swap(x,y); - } - if ((is_one(y) || a.is_zero(y)) && is_01var(x)) - return true; - if (a.is_numeral(y) && is_01_sum(x) && !m.is_eq(fml)) { - return true; - } - } - if (is_01_sum(fml)) { - SASSERT(m_uses.contains(fml)); - ptr_vector const& u = m_uses.find(fml); - for (unsigned i = 0; i < u.size(); ++i) { - if (!validate_use(u[i])) { - return false; - } - } - return true; - } - TRACE("pb", tout << "Use not validated: " << mk_pp(fml, m) << "\n";); - - return false; - } - - bool is_01_sum(expr* x) const { - if (a.is_add(x)) { - app* ap = to_app(x); - for (unsigned i = 0; i < ap->get_num_args(); ++i) { - if (!is_01var(ap->get_arg(i))) { - return false; - } - } - return true; - } - return false; - } - - - void collect_uses(ast_mark& mark, expr* f) { - m_todo.reset(); - m_todo.push_back(f); - while (!m_todo.empty()) { - f = m_todo.back(); - m_todo.pop_back(); - if (mark.is_marked(f)) { - continue; - } - mark.mark(f, true); - if (is_var(f)) { - continue; - } - if (is_quantifier(f)) { - m_todo.push_back(to_quantifier(f)->get_expr()); - continue; - } - app* a = to_app(f); - for (unsigned i = 0; i < a->get_num_args(); ++i) { - expr* arg = a->get_arg(i); - if (!m_uses.contains(arg)) { - m_uses.insert(arg, ptr_vector()); - } - m_uses.find(arg).push_back(a); - m_todo.push_back(arg); - } - } - } - - bool is_unsigned(expr* x, unsigned& k) { - rational r; - if (a.is_numeral(x, r) && r.is_unsigned()) { - k = r.get_unsigned(); - SASSERT(rational(k) == r); - return true; - } - else { - return false; - } - } - - bool is_one(expr* x) { - rational r; - return a.is_numeral(x, r) && r.is_one(); - } - - }; - -#endif +void convert_objectives() { + +} From 4d6aa1a0f363305c4354d0a50706476e8fa47f34 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 6 Dec 2013 11:34:41 -0800 Subject: [PATCH 192/925] add to_string and get_help methods to optimize API Signed-off-by: Nikolaj Bjorner --- src/api/api_opt.cpp | 22 ++++++++ src/api/dotnet/Optimize.cs | 17 +++--- src/api/z3_api.h | 20 +++++++ src/opt/maxsmt.h | 4 ++ src/opt/opt_context.cpp | 111 +++++++++++++++++++++++++++++++++++++ src/opt/opt_context.h | 3 + 6 files changed, 170 insertions(+), 7 deletions(-) diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index 7236a7682..d4dac1db3 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -185,6 +185,28 @@ extern "C" { Z3_CATCH_RETURN(0); } + Z3_string Z3_API Z3_optimize_to_string(Z3_context c, Z3_optimize o) { + Z3_TRY; + LOG_Z3_optimize_to_string(c, o); + RESET_ERROR_CODE(); + return mk_c(c)->mk_external_string(to_optimize_ref(o).to_string()); + Z3_CATCH_RETURN(""); + } + + Z3_string Z3_API Z3_optimize_get_help(Z3_context c, Z3_optimize d) { + Z3_TRY; + LOG_Z3_optimize_get_help(c, d); + RESET_ERROR_CODE(); + std::ostringstream buffer; + param_descrs descrs; + to_optimize_ref(d).collect_param_descrs(descrs); + descrs.display(buffer); + return mk_c(c)->mk_external_string(buffer.str()); + Z3_CATCH_RETURN(""); + } + + + #if 0 /** diff --git a/src/api/dotnet/Optimize.cs b/src/api/dotnet/Optimize.cs index 925773fa5..fb4af9206 100644 --- a/src/api/dotnet/Optimize.cs +++ b/src/api/dotnet/Optimize.cs @@ -31,7 +31,6 @@ namespace Microsoft.Z3 { HashSet indices; -#if false /// /// A string that describes all available optimize solver parameters. /// @@ -43,7 +42,6 @@ namespace Microsoft.Z3 return Native.Z3_optimize_get_help(Context.nCtx, NativeObject); } } -#endif /// /// Sets the optimize solver parameters. @@ -157,7 +155,7 @@ namespace Microsoft.Z3 } } - public uint MkMaximize(ArithExpr e) + public uint MkMaximize(ArithExpr e) { uint index = Native.Z3_optimize_maximize(Context.nCtx, NativeObject, e.NativeObject); indices.Add(index); @@ -166,15 +164,15 @@ namespace Microsoft.Z3 public uint MkMinimize(ArithExpr e) { - uint index = Native.Z3_optimize_minimize(Context.nCtx, NativeObject, e.NativeObject); + uint index = Native.Z3_optimize_minimize(Context.nCtx, NativeObject, e.NativeObject); indices.Add(index); return index; - } + } - public ArithExpr GetLower(uint index) + public ArithExpr GetLower(uint index) { Contract.Requires(indices.Contains(index)); - return new ArithExpr(Context, Native.Z3_optimize_get_lower(Context.nCtx, NativeObject, index)); + return new ArithExpr(Context, Native.Z3_optimize_get_lower(Context.nCtx, NativeObject, index)); } public ArithExpr GetUpper(uint index) @@ -183,6 +181,11 @@ namespace Microsoft.Z3 return new ArithExpr(Context, Native.Z3_optimize_get_upper(Context.nCtx, NativeObject, index)); } + public override string ToString() + { + return Native.Z3_optimize_to_string(Context.nCtx, NativeObject); + } + #region Internal internal Optimize(Context ctx, IntPtr obj) : base(ctx, obj) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 9350eb529..58bbe0fe9 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -6075,6 +6075,26 @@ END_MLAPI_EXCLUDE */ Z3_ast Z3_API Z3_optimize_get_upper(Z3_context c, Z3_optimize o, unsigned idx); + /** + \brief Print the current context as a string. + \param c - context. + \param o - optimization context. + + def_API('Z3_optimize_to_string', STRING, (_in(CONTEXT), _in(OPTIMIZE))) + */ + Z3_string Z3_API Z3_optimize_to_string( + __in Z3_context c, + __in Z3_optimize o); + + + /** + \brief Return a string containing a description of parameters accepted by optimize. + + def_API('Z3_optimize_get_help', STRING, (_in(CONTEXT), _in(OPTIMIZE))) + */ + Z3_string Z3_API Z3_optimize_get_help(__in Z3_context c, __in Z3_optimize t); + + #endif diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index b6bb15e52..413727b58 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -62,6 +62,10 @@ namespace opt { m_weights.push_back(w); } + unsigned size() const { return m_soft_constraints.size(); } + expr* operator[](unsigned idx) const { return m_soft_constraints[idx]; } + rational weight(unsigned idx) const { return m_weights[idx]; } + void commit_assignment(); inf_eps get_value() const; inf_eps get_lower() const; diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 78495c928..acbd8293d 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -22,6 +22,7 @@ Notes: #include "opt_solver.h" #include "opt_params.hpp" #include "arith_decl_plugin.h" +#include "for_each_expr.h" namespace opt { @@ -289,4 +290,114 @@ namespace opt { } } + typedef obj_hashtable func_decl_set; + + struct context::free_func_visitor { + ast_manager& m; + func_decl_set m_funcs; + obj_hashtable m_sorts; + expr_mark m_visited; + public: + free_func_visitor(ast_manager& m): m(m) {} + void operator()(var * n) { } + void operator()(app * n) { + m_funcs.insert(n->get_decl()); + sort* s = m.get_sort(n); + if (s->get_family_id() == null_family_id) { + m_sorts.insert(s); + } + } + void operator()(quantifier * n) { } + func_decl_set& funcs() { return m_funcs; } + obj_hashtable& sorts() { return m_sorts; } + + void collect(expr* e) { + for_each_expr(*this, m_visited, e); + } + }; + + std::string context::to_string() const { + smt2_pp_environment_dbg env(m); + free_func_visitor visitor(m); + std::ostringstream out; +#define PP(_e_) ast_smt2_pp(out, _e_, env); + for (unsigned i = 0; i < m_hard_constraints.size(); ++i) { + visitor.collect(m_hard_constraints[i]); + } + for (unsigned i = 0; i < m_objectives.size(); ++i) { + objective const& obj = m_objectives[i]; + switch(obj.m_type) { + case O_MAXIMIZE: + case O_MINIMIZE: + visitor.collect(obj.m_term); + break; + case O_MAXSMT: { + maxsmt& ms = *m_maxsmts.find(obj.m_id); + for (unsigned j = 0; j < ms.size(); ++j) { + visitor.collect(ms[j]); + } + break; + } + default: + UNREACHABLE(); + break; + } + } + + obj_hashtable::iterator sit = visitor.sorts().begin(); + obj_hashtable::iterator send = visitor.sorts().end(); + for (; sit != send; ++sit) { + PP(*sit); + } + func_decl_set::iterator it = visitor.funcs().begin(); + func_decl_set::iterator end = visitor.funcs().end(); + for (; it != end; ++it) { + PP(*it); + out << "\n"; + } + for (unsigned i = 0; i < m_hard_constraints.size(); ++i) { + out << "(assert "; + PP(m_hard_constraints[i]); + out << ")\n"; + } + for (unsigned i = 0; i < m_objectives.size(); ++i) { + objective const& obj = m_objectives[i]; + switch(obj.m_type) { + case O_MAXIMIZE: + out << "(maximize "; + PP(obj.m_term); + out << ")\n"; + break; + case O_MINIMIZE: + out << "(minimize "; + PP(obj.m_term); + out << ")\n"; + break; + case O_MAXSMT: { + maxsmt& ms = *m_maxsmts.find(obj.m_id); + for (unsigned j = 0; j < ms.size(); ++j) { + out << "(assert-soft "; + PP(ms[j]); + rational w = ms.weight(j); + if (w.is_int()) { + out << " :weight " << ms.weight(j); + } + else { + out << " :dweight " << ms.weight(j); + } + if (obj.m_id != symbol::null) { + out << " :id " << obj.m_id; + } + out << ")\n"; + } + break; + } + default: + UNREACHABLE(); + break; + } + } + return out.str(); + } + } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index cb46494cd..7ab30ec71 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -35,6 +35,7 @@ namespace opt { class opt_solver; class context { + struct free_func_visitor; typedef map map_t; typedef map map_id; enum objective_t { @@ -92,6 +93,8 @@ namespace opt { expr_ref get_lower(unsigned idx); expr_ref get_upper(unsigned idx); + std::string to_string() const; + private: void validate_feasibility(maxsmt& ms); From 437a545c3b608b86ce0a8c58e55c916305b2672e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 6 Dec 2013 13:12:35 -0800 Subject: [PATCH 193/925] fix pretty printer Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index acbd8293d..e3d4a555e 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -301,7 +301,9 @@ namespace opt { free_func_visitor(ast_manager& m): m(m) {} void operator()(var * n) { } void operator()(app * n) { - m_funcs.insert(n->get_decl()); + if (n->get_family_id() == null_family_id) { + m_funcs.insert(n->get_decl()); + } sort* s = m.get_sort(n); if (s->get_family_id() == null_family_id) { m_sorts.insert(s); @@ -397,6 +399,7 @@ namespace opt { break; } } + out << "(optimize)\n"; return out.str(); } From a617eac0108f47c14258ab58fa4acf9086c0d6c3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 6 Dec 2013 19:36:12 -0800 Subject: [PATCH 194/925] enable bounding for various domains Signed-off-by: Nikolaj Bjorner --- src/opt/opt_solver.cpp | 30 ++++++++++++++++++++++++------ src/opt/opt_solver.h | 4 ++-- src/opt/optsmt.cpp | 6 +++--- src/smt/theory_arith.h | 4 ++-- src/smt/theory_arith_aux.h | 4 ++-- src/smt/theory_diff_logic.h | 3 ++- src/smt/theory_diff_logic_def.h | 2 +- src/smt/theory_opt.h | 5 +++-- 8 files changed, 39 insertions(+), 19 deletions(-) diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 091adb9b0..d6877e5db 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -190,15 +190,33 @@ namespace opt { return m_objective_values; } - expr_ref opt_solver::block_upper_bound(unsigned var, inf_eps const& val) { + expr_ref opt_solver::mk_ge(unsigned var, inf_eps const& val) { smt::theory_opt& opt = get_optimizer(); - SASSERT(typeid(smt::theory_inf_arith) == typeid(opt)); - smt::theory_inf_arith& th = dynamic_cast(opt); smt::theory_var v = m_objective_vars[var]; - return expr_ref(th.block_upper_bound(v, val), m); + + if (typeid(smt::theory_inf_arith) == typeid(opt)) { + smt::theory_inf_arith& th = dynamic_cast(opt); + return expr_ref(th.mk_ge(v, val), m); + } + + if (typeid(smt::theory_mi_arith) == typeid(opt)) { + smt::theory_mi_arith& th = dynamic_cast(opt); + SASSERT(val.get_infinity().is_zero()); + return expr_ref(th.mk_ge(v, val.get_numeral()), m); + } + + if (typeid(smt::theory_i_arith) == typeid(opt)) { + SASSERT(val.get_infinity().is_zero()); + SASSERT(val.get_infinitesimal().is_zero()); + smt::theory_i_arith& th = dynamic_cast(opt); + return expr_ref(th.mk_ge(v, val.get_rational()), m); + } + + // difference logic? + return expr_ref(m.mk_true(), m); } - expr_ref opt_solver::block_lower_bound(unsigned var, inf_eps const& val) { + expr_ref opt_solver::mk_gt(unsigned var, inf_eps const& val) { if (val.get_infinity().is_pos()) { return expr_ref(m.mk_false(), m); } @@ -207,7 +225,7 @@ namespace opt { } else { inf_rational n = val.get_numeral(); - return expr_ref(get_optimizer().block_lower_bound(m_objective_vars[var], n), m); + return expr_ref(get_optimizer().mk_gt(m_objective_vars[var], n), m); } } diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 3be11f4bc..f35a79203 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -75,8 +75,8 @@ namespace opt { void reset_objectives(); vector const& get_objective_values(); - expr_ref block_lower_bound(unsigned obj_index, inf_eps const& val); - expr_ref block_upper_bound(unsigned obj_index, inf_eps const& val); + expr_ref mk_gt(unsigned obj_index, inf_eps const& val); + expr_ref mk_ge(unsigned obj_index, inf_eps const& val); static opt_solver& to_opt(solver& s); void set_interim_stats(statistics & st); diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 1380080ba..ebad310d3 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -121,7 +121,7 @@ namespace opt { for (unsigned i = 0; i < m_lower.size(); ++i) { inf_eps const& v = m_lower[i]; - disj.push_back(s->block_lower_bound(i, v)); + disj.push_back(s->mk_gt(i, v)); } constraint = m.mk_or(disj.size(), disj.c_ptr()); s->assert_expr(constraint); @@ -149,7 +149,7 @@ namespace opt { smt::theory_var v = m_vars[i]; mid.push_back((m_upper[i]+m_lower[i])/rational(2)); //mid.push_back(m_upper[i]); - bound = th.block_upper_bound(v, mid[i]); + bound = th.mk_ge(v, mid[i]); bounds.push_back(bound); } else { @@ -273,7 +273,7 @@ namespace opt { m_upper[i] = mid; TRACE("opt", tout << "set lower bound of "; display_objective(tout, i) << " to: " << mid << "\n"; tout << get_lower(i) << ":" << get_upper(i) << "\n";); - s->assert_expr(s->block_upper_bound(i, mid)); + s->assert_expr(s->mk_ge(i, mid)); } std::ostream& optsmt::display_objective(std::ostream& out, unsigned i) const { diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 7979ffc6e..f0211ca9d 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -999,8 +999,8 @@ namespace smt { // ----------------------------------- virtual inf_eps_rational maximize(theory_var v); virtual theory_var add_objective(app* term); - virtual expr* block_lower_bound(theory_var v, inf_rational const& val); - expr* block_upper_bound(theory_var v, inf_numeral const& val); + virtual expr* mk_gt(theory_var v, inf_rational const& val); + virtual expr* mk_ge(theory_var v, inf_numeral const& val); void enable_record_conflict(expr* bound); void record_conflict(unsigned num_lits, literal const * lits, unsigned num_eqs, enode_pair const * eqs, diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 90a6db250..96245165f 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -1044,7 +1044,7 @@ namespace smt { \brief: assert val < v */ template - expr* theory_arith::block_lower_bound(theory_var v, inf_rational const& val) { + expr* theory_arith::mk_gt(theory_var v, inf_rational const& val) { ast_manager& m = get_manager(); expr* obj = get_enode(v)->get_owner(); expr_ref e(m); @@ -1062,7 +1062,7 @@ namespace smt { \brief assert val <= v */ template - expr* theory_arith::block_upper_bound(theory_var v, inf_numeral const& val) { + expr* theory_arith::mk_ge(theory_var v, inf_numeral const& val) { ast_manager& m = get_manager(); context& ctx = get_context(); std::ostringstream strm; diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h index 015144c2a..ed52b76fc 100644 --- a/src/smt/theory_diff_logic.h +++ b/src/smt/theory_diff_logic.h @@ -310,7 +310,8 @@ namespace smt { virtual inf_eps_rational maximize(theory_var v); virtual theory_var add_objective(app* term); - virtual expr* block_lower_bound(theory_var v, inf_rational const& val); + virtual expr* mk_gt(theory_var v, inf_rational const& val); + virtual expr* mk_ge(theory_var v, inf_rational const& val) { return 0; } bool internalize_objective(expr * n, rational const& m, rational& r, objective_term & objective); diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index 4202b86a3..1982f2eb7 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -1146,7 +1146,7 @@ expr* theory_diff_logic::block_objective(theory_var v, inf_rational const& } template -expr* theory_diff_logic::block_lower_bound(theory_var v, inf_rational const& val) { +expr* theory_diff_logic::mk_gt(theory_var v, inf_rational const& val) { expr * o = block_objective(v, val); context & ctx = get_context(); model_ref mdl; diff --git a/src/smt/theory_opt.h b/src/smt/theory_opt.h index 774e4abd1..208330bfb 100644 --- a/src/smt/theory_opt.h +++ b/src/smt/theory_opt.h @@ -28,9 +28,10 @@ namespace smt { class theory_opt { public: typedef inf_eps_rational inf_eps; - virtual inf_eps_rational maximize(theory_var v) { UNREACHABLE(); return inf_eps::infinity(); } + virtual inf_eps maximize(theory_var v) { UNREACHABLE(); return inf_eps::infinity(); } virtual theory_var add_objective(app* term) { UNREACHABLE(); return null_theory_var; } - virtual expr* block_lower_bound(theory_var v, inf_rational const& val) { return 0; } + virtual expr* mk_gt(theory_var v, inf_rational const& val) { UNREACHABLE(); return 0; } + virtual expr* mk_ge(theory_var v, inf_eps const& val) { UNREACHABLE(); return 0; } }; } From 6300d822241ca1148d49d8e712651813aae29f6e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 7 Dec 2013 08:07:02 -0800 Subject: [PATCH 195/925] fix release build break Signed-off-by: Nikolaj Bjorner --- src/smt/network_flow_def.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/smt/network_flow_def.h b/src/smt/network_flow_def.h index 777bd07a3..93e1ded9a 100644 --- a/src/smt/network_flow_def.h +++ b/src/smt/network_flow_def.h @@ -288,19 +288,21 @@ namespace smt { while (choose_entering_edge(pr)) { bool bounded = choose_leaving_edge(); if (!bounded) return UNBOUNDED; - //TRACE("network_flow", + vectorconst& es = m_graph.get_all_edges(); + TRACE("network_flow", { - vectorconst& es = m_graph.get_all_edges(); edge const& e_in = es[m_enter_id]; edge const& e_out = es[m_leave_id]; - node src_in = e_in.get_source(), tgt_in = e_in.get_target(); - node src_out = e_out.get_source(), tgt_out = e_out.get_target(); + node src_in = e_in.get_source(); + node tgt_in = e_in.get_target(); + node src_out = e_out.get_source(); + node tgt_out = e_out.get_target(); numeral c1 = m_potentials[src_in] - m_potentials[tgt_in] - m_graph.get_weight(m_enter_id); numeral c2 = m_potentials[src_out] - m_potentials[tgt_out] - m_graph.get_weight(m_leave_id); tout << "new base: y_" << src_in << "_" << tgt_in << " cost: " << c1 << " delta: " << *m_delta << "\n"; tout << "old base: y_" << src_out << "_" << tgt_out << " cost: " << c2 << "\n"; } - // ); + ); update_flows(); if (m_enter_id != m_leave_id) { SASSERT(edge_in_tree(m_leave_id)); From da348fe1c091a4b86a3f4279bcf3750b11f0699d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 7 Dec 2013 14:38:09 -0800 Subject: [PATCH 196/925] first pass on normalization Signed-off-by: Nikolaj Bjorner --- src/ast/pb_decl_plugin.cpp | 29 +++- src/ast/pb_decl_plugin.h | 2 + src/opt/opt_context.cpp | 220 ++++++++++++++++++++++++--- src/opt/opt_context.h | 30 +++- src/opt/optsmt.cpp | 3 +- src/smt/theory_arith_aux.h | 38 ++--- src/tactic/arith/elim01_tactic.cpp | 177 +++++++++++++++++++++ src/tactic/arith/elim01_tactic.h | 33 ++++ src/tactic/arith/lia2card_tactic.cpp | 77 ++++++++-- src/tactic/arith/lia2card_tactic.h | 2 + 10 files changed, 539 insertions(+), 72 deletions(-) create mode 100644 src/tactic/arith/elim01_tactic.cpp create mode 100644 src/tactic/arith/elim01_tactic.h diff --git a/src/ast/pb_decl_plugin.cpp b/src/ast/pb_decl_plugin.cpp index 07153e1ac..cb68b2c0b 100644 --- a/src/ast/pb_decl_plugin.cpp +++ b/src/ast/pb_decl_plugin.cpp @@ -59,11 +59,18 @@ func_decl * pb_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p } vector params; for (unsigned i = 0; i < num_parameters; ++i) { - if (parameters[i].is_int()) { - params.push_back(parameter(rational(parameters[i].get_int()))); + parameter const& p = parameters[i]; + if (p.is_int()) { + params.push_back(p); } - else if (parameters[i].is_rational()) { - params.push_back(parameter(parameters[i].get_rational())); + else if (p.is_rational()) { + // HACK: ast pretty printer does not work with rationals. + if (p.get_rational().is_int32()) { + params.push_back(parameter(p.get_rational().get_int32())); + } + else { + params.push_back(p); + } } else { m.raise_exception("function 'pble' expects arity+1 integer parameters"); @@ -148,11 +155,11 @@ bool pb_util::is_at_least_k(app *a, rational& k) const { rational pb_util::get_k(app *a) const { parameter const& p = a->get_decl()->get_parameter(0); if (is_at_most_k(a) || is_at_least_k(a)) { - return rational(p.get_int()); + return to_rational(p); } else { SASSERT(is_le(a) || is_ge(a)); - return p.get_rational(); + return to_rational(p); } } @@ -191,7 +198,13 @@ rational pb_util::get_coeff(app* a, unsigned index) { } SASSERT(is_le(a) || is_ge(a)); SASSERT(1 + index < a->get_decl()->get_num_parameters()); - return a->get_decl()->get_parameter(index + 1).get_rational(); + return to_rational(a->get_decl()->get_parameter(index + 1)); } - +rational pb_util::to_rational(parameter const& p) const { + if (p.is_int()) { + return rational(p.get_int()); + } + SASSERT(p.is_rational()); + return p.get_rational(); +} diff --git a/src/ast/pb_decl_plugin.h b/src/ast/pb_decl_plugin.h index 4b768ff11..103f74115 100644 --- a/src/ast/pb_decl_plugin.h +++ b/src/ast/pb_decl_plugin.h @@ -92,6 +92,8 @@ public: bool is_ge(app* a) const; bool is_ge(app* a, rational& k) const; rational get_coeff(app* a, unsigned index); +private: + rational to_rational(parameter const& p) const; }; diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index e3d4a555e..52ae1e38e 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -23,6 +23,11 @@ Notes: #include "opt_params.hpp" #include "arith_decl_plugin.h" #include "for_each_expr.h" +#include "goal.h" +#include "tactic.h" +#include "lia2card_tactic.h" +#include "elim01_tactic.h" +#include "tactical.h" namespace opt { @@ -51,21 +56,24 @@ namespace opt { m_objectives.push_back(objective(m, id)); m_indices.insert(id, m_objectives.size() - 1); } - ms->add(f, w); SASSERT(m_indices.contains(id)); - return m_indices[id]; + unsigned idx = m_indices[id]; + m_objectives[idx].m_terms.push_back(f); + m_objectives[idx].m_weights.push_back(w); + return idx; } unsigned context::add_objective(app* t, bool is_max) { app_ref tr(t, m); - unsigned index = m_optsmt.get_num_objectives(); - m_optsmt.add(t, is_max); + unsigned index = m_objectives.size(); m_objectives.push_back(objective(is_max, tr, index)); return index; } lbool context::optimize() { - opt_solver& s = get_solver(); + opt_solver& s = get_solver(); + normalize(); + internalize(); solver::scoped_push _sp(s); for (unsigned i = 0; i < m_hard_constraints.size(); ++i) { s.assert_expr(m_hard_constraints[i].get()); @@ -137,9 +145,9 @@ namespace opt { lbool context::execute_box() { lbool r = l_true; for (unsigned i = 0; r == l_true && i < m_objectives.size(); ++i) { - push(); + get_solver().push(); r = execute(m_objectives[i], false); - pop(1); + get_solver().pop(1); } return r; } @@ -153,12 +161,180 @@ namespace opt { return *m_solver.get(); } - void context::push() { - get_solver().push(); + void context::normalize() { + expr_ref_vector fmls(m); + to_fmls(fmls); + simplify_fmls(fmls); + from_fmls(fmls); } - void context::pop(unsigned sz) { - get_solver().pop(sz); + void context::simplify_fmls(expr_ref_vector& fmls) { + goal_ref g(alloc(goal, m, true, false)); + for (unsigned i = 0; i < fmls.size(); ++i) { + g->assert_expr(fmls[i].get()); + } + tactic_ref tac1 = mk_elim01_tactic(m); + tactic_ref tac2 = mk_lia2card_tactic(m); + tactic_ref tac = and_then(tac1.get(), tac2.get()); + model_converter_ref mc; // TBD: expose model converter upwards and apply to returned model. + proof_converter_ref pc; + expr_dependency_ref core(m); + goal_ref_buffer result; + (*tac)(g, result, mc, pc, core); // TBD: have this an attribute so we can cancel. + SASSERT(result.size() == 1); + goal* r = result[0]; + fmls.reset(); + for (unsigned i = 0; i < r->size(); ++i) { + fmls.push_back(r->form(i)); + } + } + + bool context::is_maximize(expr* fml, app_ref& term, unsigned& index) { + if (is_app(fml) && m_objective_fns.find(to_app(fml)->get_decl(), index) && + m_objectives[index].m_type == O_MAXIMIZE) { + term = to_app(to_app(fml)->get_arg(0)); + return true; + } + return false; + } + + bool context::is_minimize(expr* fml, app_ref& term, unsigned& index) { + if (is_app(fml) && m_objective_fns.find(to_app(fml)->get_decl(), index) && + m_objectives[index].m_type == O_MINIMIZE) { + term = to_app(to_app(fml)->get_arg(0)); + return true; + } + return false; + } + + bool context::is_maxsat(expr* fml, expr_ref_vector& terms, + vector& weights, symbol& id, unsigned& index) { + if (!is_app(fml)) return false; + app* a = to_app(fml); + if (m_objective_fns.find(a->get_decl(), index) && m_objectives[index].m_type == O_MAXSMT) { + terms.append(a->get_num_args(), a->get_args()); + weights.append(m_objectives[index].m_weights); + id = m_objectives[index].m_id; + return true; + } + app_ref term(m); + if (is_minimize(fml, term, index)) { + TRACE("opt", tout << "try to convert minimization" << mk_pp(term, m) << "\n";); + rational coeff(0); + return get_pb_sum(term, terms, weights, coeff); + } + return false; + } + + expr* context::mk_objective_fn(unsigned index, objective_t ty, unsigned sz, expr*const* args) { + ptr_vector domain; + for (unsigned i = 0; i < sz; ++i) { + domain.push_back(m.get_sort(args[i])); + } + char const* name = ""; + switch(ty) { + case O_MAXIMIZE: name = "maximize"; break; + case O_MINIMIZE: name = "minimize"; break; + case O_MAXSMT: name = "maxsat"; break; + default: break; + } + func_decl* f = m.mk_fresh_func_decl(name,"", domain.size(), domain.c_ptr(), m.mk_bool_sort()); + m_objective_fns.insert(f, index); + return m.mk_app(f, sz, args); + } + + expr* context::mk_maximize(unsigned index, app* t) { + expr* t_ = t; + return mk_objective_fn(index, O_MAXIMIZE, 1, &t_); + } + + expr* context::mk_minimize(unsigned index, app* t) { + expr* t_ = t; + return mk_objective_fn(index, O_MINIMIZE, 1, &t_); + } + + expr* context::mk_maxsat(unsigned index, unsigned num_fmls, expr* const* fmls) { + return mk_objective_fn(index, O_MAXSMT, num_fmls, fmls); + } + + + void context::from_fmls(expr_ref_vector const& fmls) { + m_hard_constraints.reset(); + for (unsigned i = 0; i < fmls.size(); ++i) { + expr* fml = fmls[i]; + app_ref tr(m); + expr_ref_vector terms(m); + vector weights; + unsigned index; + symbol id; + if (is_maxsat(fml, terms, weights, id, index)) { + objective& obj = m_objectives[index]; + if (obj.m_type != O_MAXSMT) { + // change from maximize/minimize. + obj.m_id = id; + obj.m_type = O_MAXSMT; + obj.m_weights.append(weights); + SASSERT(!m_maxsmts.contains(id)); + maxsmt* ms = alloc(maxsmt, m); + m_maxsmts.insert(id, ms); + m_indices.insert(id, index); + } + SASSERT(obj.m_id == id); + obj.m_terms.reset(); + obj.m_terms.append(terms); + } + else if (is_maximize(fml, tr, index)) { + m_objectives[index].m_term = tr; + } + else if (is_minimize(fml, tr, index)) { + m_objectives[index].m_term = tr; + } + else { + m_hard_constraints.push_back(fml); + } + } + } + + void context::to_fmls(expr_ref_vector& fmls) { + m_objective_fns.reset(); + fmls.append(m_hard_constraints); + for (unsigned i = 0; i < m_objectives.size(); ++i) { + objective const& obj = m_objectives[i]; + switch(obj.m_type) { + case O_MINIMIZE: + fmls.push_back(mk_minimize(i, obj.m_term)); + break; + case O_MAXIMIZE: + fmls.push_back(mk_maximize(i, obj.m_term)); + break; + case O_MAXSMT: + fmls.push_back(mk_maxsat(i, obj.m_terms.size(), obj.m_terms.c_ptr())); + break; + } + } + } + + void context::internalize() { + for (unsigned i = 0; i < m_objectives.size(); ++i) { + objective & obj = m_objectives[i]; + switch(obj.m_type) { + case O_MINIMIZE: + obj.m_index = m_optsmt.get_num_objectives(); + m_optsmt.add(obj.m_term, false); + break; + case O_MAXIMIZE: + obj.m_index = m_optsmt.get_num_objectives(); + m_optsmt.add(obj.m_term, true); + break; + case O_MAXSMT: { + maxsmt& ms = *m_maxsmts.find(obj.m_id); + for (unsigned j = 0; j < obj.m_terms.size(); ++j) { + ms.add(obj.m_terms[j].get(), obj.m_weights[j]); + } + break; + } + } + } } void context::display_assignment(std::ostream& out) { @@ -333,13 +509,11 @@ namespace opt { case O_MINIMIZE: visitor.collect(obj.m_term); break; - case O_MAXSMT: { - maxsmt& ms = *m_maxsmts.find(obj.m_id); - for (unsigned j = 0; j < ms.size(); ++j) { - visitor.collect(ms[j]); + case O_MAXSMT: + for (unsigned j = 0; j < obj.m_terms.size(); ++j) { + visitor.collect(obj.m_terms[j]); } break; - } default: UNREACHABLE(); break; @@ -375,17 +549,16 @@ namespace opt { PP(obj.m_term); out << ")\n"; break; - case O_MAXSMT: { - maxsmt& ms = *m_maxsmts.find(obj.m_id); - for (unsigned j = 0; j < ms.size(); ++j) { + case O_MAXSMT: + for (unsigned j = 0; j < obj.m_terms.size(); ++j) { out << "(assert-soft "; - PP(ms[j]); - rational w = ms.weight(j); + PP(obj.m_terms[j]); + rational w = obj.m_weights[j]; if (w.is_int()) { - out << " :weight " << ms.weight(j); + out << " :weight " << w; } else { - out << " :dweight " << ms.weight(j); + out << " :dweight " << w; } if (obj.m_id != symbol::null) { out << " :id " << obj.m_id; @@ -393,7 +566,6 @@ namespace opt { out << ")\n"; } break; - } default: UNREACHABLE(); break; diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 7ab30ec71..9bc1007de 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -43,20 +43,27 @@ namespace opt { O_MINIMIZE, O_MAXSMT }; + struct objective { objective_t m_type; - app_ref m_term; // for maximize, minimize - symbol m_id; // for maxsmt - unsigned m_index; + app_ref m_term; // for maximize, minimize term + expr_ref_vector m_terms; // for maxsmt + vector m_weights; // for maxsmt + symbol m_id; // for maxsmt + unsigned m_index; // for maximize/minimize index + objective(bool is_max, app_ref& t, unsigned idx): m_type(is_max?O_MAXIMIZE:O_MINIMIZE), m_term(t), + m_terms(t.get_manager()), m_id(), m_index(idx) {} + objective(ast_manager& m, symbol id): m_type(O_MAXSMT), m_term(m), + m_terms(m), m_id(id), m_index(0) {} @@ -70,6 +77,7 @@ namespace opt { map_id m_indices; vector m_objectives; model_ref m_model; + obj_map m_objective_fns; public: context(ast_manager& m); ~context(); @@ -106,8 +114,20 @@ namespace opt { lbool execute_pareto(); expr_ref to_expr(inf_eps const& n); - void push(); - void pop(unsigned sz); + void normalize(); + void internalize(); + bool is_maximize(expr* fml, app_ref& term, unsigned& index); + bool is_minimize(expr* fml, app_ref& term, unsigned& index); + bool is_maxsat(expr* fml, expr_ref_vector& terms, + vector& weights, symbol& id, unsigned& index); + expr* mk_maximize(unsigned index, app* t); + expr* mk_minimize(unsigned index, app* t); + expr* mk_maxsat(unsigned index, unsigned num_fmls, expr* const* fmls); + expr* mk_objective_fn(unsigned index, objective_t ty, unsigned sz, expr*const* args); + void to_fmls(expr_ref_vector& fmls); + void from_fmls(expr_ref_vector const& fmls); + void simplify_fmls(expr_ref_vector& fmls); + opt_solver& get_solver(); }; diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index ebad310d3..91a421adb 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -208,13 +208,12 @@ namespace opt { // First check_sat call to initialize theories lbool is_sat = s->check_sat(0, 0); + solver::scoped_push _push(*s); if (is_sat == l_true && !m_objs.empty()) { for (unsigned i = 0; i < m_objs.size(); ++i) { m_vars.push_back(s->add_objective(m_objs[i].get())); } - solver::scoped_push _push(*s); - if (m_engine == symbol("basic")) { is_sat = basic_opt(); } diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 96245165f..48b4a4583 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -927,7 +927,7 @@ namespace smt { */ template theory_var theory_arith::pick_var_to_leave(theory_var x_j, bool inc, numeral & a_ij, inf_numeral & gain) { - TRACE("maximize", tout << "selecting variable to replace v" << x_j << ", inc: " << inc << "\n";); + TRACE("opt", tout << "selecting variable to replace v" << x_j << ", inc: " << inc << "\n";); theory_var x_i = null_theory_var; inf_numeral curr_gain; column & c = m_columns[x_j]; @@ -951,7 +951,7 @@ namespace smt { x_i = s; a_ij = coeff; gain = curr_gain; - TRACE("maximize", + TRACE("opt", tout << "x_i: v" << x_i << ", gain: " << gain << "\n"; tout << "value(s): (" << get_value(s) << " - " << b->get_value() << ")/" << coeff << "\n"; display_row(tout, r, true); @@ -959,10 +959,10 @@ namespace smt { } } } - TRACE("maximize", tout << "x_i: v" << x_i << ", gain: " << gain << "\n";); + TRACE("opt", tout << "x_i: v" << x_i << ", gain: " << gain << "\n";); } } - TRACE("maximize", tout << "x_i v" << x_i << "\n";); + TRACE("opt", tout << "x_i v" << x_i << "\n";); return x_i; } @@ -1017,11 +1017,15 @@ namespace smt { if (get_theory_vars(term, vars)) { m_objective_theory_vars.insert(v, vars); } + TRACE("opt", tout << mk_pp(term, get_manager()) << " |-> v" << v << "\n";); + TRACE("opt", tout << "data-size: " << m_data.size() << "\n";); + SASSERT(!is_quasi_base(v)); return v; } template inf_eps_rational theory_arith::maximize(theory_var v) { + TRACE("opt", tout << "data-size: " << m_data.size() << "\n";); bool r = max_min(v, true); if (r || at_upper(v)) { if (m_objective_theory_vars.contains(v)) { @@ -1250,7 +1254,7 @@ namespace smt { x_j = null_theory_var; x_i = null_theory_var; gain.reset(); - TRACE("maximize", tout << "i: " << i << ", max: " << max << "\n"; display_row(tout, r, true); tout << "state:\n"; display(tout); i++;); + TRACE("opt", tout << "i: " << i << ", max: " << max << "\n"; display_row(tout, r, true); tout << "state:\n"; display(tout); i++;); typename vector::const_iterator it = r.begin_entries(); typename vector::const_iterator end = r.end_entries(); for (; it != end; ++it) { @@ -1288,10 +1292,10 @@ namespace smt { } } } - TRACE("maximize", tout << "after traversing row:\nx_i: v" << x_i << ", x_j: v" << x_j << ", gain: " << gain << "\n";); + TRACE("opt", tout << "after traversing row:\nx_i: v" << x_i << ", x_j: v" << x_j << ", gain: " << gain << "\n";); if (x_j == null_theory_var) { - TRACE("maximize", tout << "row is " << (max ? "maximized" : "minimized") << "\n";); + TRACE("opt", tout << "row is " << (max ? "maximized" : "minimized") << "\n";); SASSERT(valid_row_assignment()); SASSERT(satisfy_bounds()); return true; @@ -1301,14 +1305,14 @@ namespace smt { // can increase/decrease x_j as much as we want. if (inc && upper(x_j)) { update_value(x_j, upper_bound(x_j) - get_value(x_j)); - TRACE("maximize", tout << "moved v" << x_j << " to upper bound\n";); + TRACE("opt", tout << "moved v" << x_j << " to upper bound\n";); SASSERT(valid_row_assignment()); SASSERT(satisfy_bounds()); continue; } if (!inc && lower(x_j)) { update_value(x_j, lower_bound(x_j) - get_value(x_j)); - TRACE("maximize", tout << "moved v" << x_j << " to lower bound\n";); + TRACE("opt", tout << "moved v" << x_j << " to lower bound\n";); SASSERT(valid_row_assignment()); SASSERT(satisfy_bounds()); continue; @@ -1320,18 +1324,18 @@ namespace smt { // can increase/decrease x_j up to upper/lower bound. if (inc) { update_value(x_j, upper_bound(x_j) - get_value(x_j)); - TRACE("maximize", tout << "moved v" << x_j << " to upper bound\n";); + TRACE("opt", tout << "moved v" << x_j << " to upper bound\n";); } else { update_value(x_j, lower_bound(x_j) - get_value(x_j)); - TRACE("maximize", tout << "moved v" << x_j << " to lower bound\n";); + TRACE("opt", tout << "moved v" << x_j << " to lower bound\n";); } SASSERT(valid_row_assignment()); SASSERT(satisfy_bounds()); continue; } - TRACE("maximize", tout << "max: " << max << ", x_i: v" << x_i << ", x_j: v" << x_j << ", a_ij: " << a_ij << ", coeff: " << coeff << "\n"; + TRACE("opt", tout << "max: " << max << ", x_i: v" << x_i << ", x_j: v" << x_j << ", a_ij: " << a_ij << ", coeff: " << coeff << "\n"; if (upper(x_i)) tout << "upper x_i: " << upper_bound(x_i) << " "; if (lower(x_i)) tout << "lower x_i: " << lower_bound(x_i) << " "; tout << "value x_i: " << get_value(x_i) << "\n"; @@ -1379,7 +1383,7 @@ namespace smt { SASSERT(!delta.is_neg()); } - TRACE("maximize", tout << "Original delta: " << delta << "\n";); + TRACE("opt", tout << "Original delta: " << delta << "\n";); delta_abs = abs(delta); // @@ -1415,7 +1419,7 @@ namespace smt { delta = delta_abs; } - TRACE("maximize", tout << "Safe delta: " << delta << "\n";); + TRACE("opt", tout << "Safe delta: " << delta << "\n";); update_value(x_i, delta); } @@ -1441,7 +1445,7 @@ namespace smt { */ template bool theory_arith::max_min(theory_var v, bool max) { - TRACE("maximize", tout << (max ? "maximizing" : "minimizing") << " v" << v << "...\n";); + TRACE("opt", tout << (max ? "maximizing" : "minimizing") << " v" << v << "...\n";); SASSERT(valid_row_assignment()); SASSERT(satisfy_bounds()); SASSERT(!is_quasi_base(v)); @@ -1461,7 +1465,7 @@ namespace smt { } } if (max_min(m_tmp_row, max)) { - TRACE("maximize", tout << "v" << v << " " << (max ? "max" : "min") << " value is: " << get_value(v) << "\n"; + TRACE("opt", tout << "v" << v << " " << (max ? "max" : "min") << " value is: " << get_value(v) << "\n"; display_row(tout, m_tmp_row, true); display_row_info(tout, m_tmp_row);); mk_bound_from_row(v, get_value(v), max ? B_UPPER : B_LOWER, m_tmp_row); @@ -1489,7 +1493,7 @@ namespace smt { if (succ) { // process new bounds bool r = propagate_core(); - TRACE("maximize", tout << "after max/min round:\n"; display(tout);); + TRACE("opt", tout << "after max/min round:\n"; display(tout);); return r; } return true; diff --git a/src/tactic/arith/elim01_tactic.cpp b/src/tactic/arith/elim01_tactic.cpp new file mode 100644 index 000000000..de76b5e62 --- /dev/null +++ b/src/tactic/arith/elim01_tactic.cpp @@ -0,0 +1,177 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + elim01_tactic.cpp + +Abstract: + + Replace 0-1 integer variables by Booleans. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-12-7 + +Notes: + +--*/ +#include"tactical.h" +#include"cooperate.h" +#include"bound_manager.h" +#include"ast_pp.h" +#include"expr_safe_replace.h" // NB: should use proof-producing expr_substitute in polished version. +#include"arith_decl_plugin.h" +#include"elim01_tactic.h" + +class bool2int_model_converter : public model_converter { + ast_manager& m; + arith_util a; + func_decl_ref_vector m_refs; + obj_map m_bool2int; +public: + + bool2int_model_converter(ast_manager& m): + m(m), + a(m), + m_refs(m) + {} + + virtual void operator()(model_ref & old_model, unsigned goal_idx) { + SASSERT(goal_idx == 0); + model * new_model = alloc(model, m); + unsigned num = old_model->get_num_constants(); + for (unsigned i = 0; i < num; ++i) { + func_decl* f = old_model->get_constant(i); + expr* fi = old_model->get_const_interp(f); + func_decl* f_old; + if (m_bool2int.find(f, f_old)) { + if (!fi) { + // no-op + } + else if (m.is_false(fi)) { + fi = a.mk_numeral(rational(0), true); + } + else if (m.is_true(fi)) { + fi = a.mk_numeral(rational(1), true); + } + else { + fi = 0; + } + new_model->register_decl(f_old, fi); + } + else { + new_model->register_decl(f, fi); + } + num = old_model->get_num_functions(); + for (unsigned i = 0; i < num; i++) { + func_decl * f = old_model->get_function(i); + func_interp * fi = old_model->get_func_interp(f); + new_model->register_decl(f, fi->copy()); + } + new_model->copy_usort_interps(*old_model); + old_model = new_model; + } + } + + void insert(func_decl* x_new, func_decl* x_old) { + m_refs.push_back(x_new); + m_refs.push_back(x_old); + m_bool2int.insert(x_new, x_old); + } + + + virtual model_converter * translate(ast_translation & translator) { + bool2int_model_converter* mc = alloc(bool2int_model_converter, translator.to()); + obj_map::iterator it = m_bool2int.begin(), end = m_bool2int.end(); + for (; it != end; ++it) { + mc->insert(translator(it->m_key), translator(it->m_value)); + } + return mc; + } +}; + + +class elim01_tactic : public tactic { +public: + typedef obj_hashtable expr_set; + ast_manager & m; + arith_util a; + params_ref m_params; + + elim01_tactic(ast_manager & _m, params_ref const & p): + m(_m), + a(m) { + } + + virtual ~elim01_tactic() { + } + + void set_cancel(bool f) { + } + + void updt_params(params_ref const & p) { + m_params = p; + } + + virtual void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) { + SASSERT(g->is_well_sorted()); + mc = 0; pc = 0; core = 0; + + tactic_report report("elim01", *g); + + expr_safe_replace sub(m); + bool2int_model_converter* b2i = alloc(bool2int_model_converter, m); + mc = b2i; + bound_manager bounds(m); + bounds(*g); + + bound_manager::iterator bit = bounds.begin(), bend = bounds.end(); + for (; bit != bend; ++bit) { + if (!is_app(*bit)) continue; + app* x = to_app(*bit); + bool s1, s2; + rational lo, hi; + if (a.is_int(x) && + bounds.has_lower(x, lo, s1) && !s1 && lo.is_zero() && + bounds.has_upper(x, hi, s2) && !s2 && hi.is_one()) { + app* x_new = m.mk_fresh_const(x->get_decl()->get_name().str().c_str(), m.mk_bool_sort()); + sub.insert(x, m.mk_ite(x_new, a.mk_numeral(rational(1), true), + a.mk_numeral(rational(0), true))); + b2i->insert(x_new->get_decl(), x->get_decl()); + } + } + + expr_ref new_curr(m); + proof_ref new_pr(m); + + for (unsigned i = 0; i < g->size(); i++) { + expr * curr = g->form(i); + sub(curr, new_curr); + g->update(i, new_curr, new_pr, g->dep(i)); + } + g->inc_depth(); + result.push_back(g.get()); + TRACE("pb", g->display(tout);); + SASSERT(g->is_well_sorted()); + + // TBD: support proof conversion (or not..) + } + + virtual tactic * translate(ast_manager & m) { + return alloc(elim01_tactic, m, m_params); + } + + virtual void collect_param_descrs(param_descrs & r) {} + + virtual void cleanup() {} +}; + +tactic * mk_elim01_tactic(ast_manager & m, params_ref const & p) { + return clean(alloc(elim01_tactic, m, p)); +} + diff --git a/src/tactic/arith/elim01_tactic.h b/src/tactic/arith/elim01_tactic.h new file mode 100644 index 000000000..867013ed0 --- /dev/null +++ b/src/tactic/arith/elim01_tactic.h @@ -0,0 +1,33 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + elim01_tactic.h + +Abstract: + + Replace 0-1 integer variables by Booleans. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-12-7 + +Notes: + +--*/ +#ifndef _ELIM01_TACTIC_H_ +#define _ELIM01_TACTIC_H_ + +#include"params.h" +class ast_manager; +class tactic; + +tactic * mk_elim01_tactic(ast_manager & m, params_ref const & p = params_ref()); + +/* + ADD_TACTIC("elim01", "eliminate 0-1 integer variables, replace them by Booleans.", "mk_elim01_tactic(m, p)") +*/ + + +#endif diff --git a/src/tactic/arith/lia2card_tactic.cpp b/src/tactic/arith/lia2card_tactic.cpp index 4212b8e4d..347d4749f 100644 --- a/src/tactic/arith/lia2card_tactic.cpp +++ b/src/tactic/arith/lia2card_tactic.cpp @@ -143,24 +143,44 @@ public: if ((a.is_le(fml, x, y) || a.is_ge(fml, y, x)) && get_pb_sum(x, rational::one(), args, coeffs, coeff) && get_pb_sum(y, -rational::one(), args, coeffs, coeff)) { - result = m_pb.mk_le(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff); + result = mk_le(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff); return true; } else if ((a.is_lt(fml, y, x) || a.is_gt(fml, x, y)) && get_pb_sum(x, rational::one(), args, coeffs, coeff) && get_pb_sum(y, -rational::one(), args, coeffs, coeff)) { - result = m.mk_not(m_pb.mk_le(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff)); + result = m.mk_not(mk_le(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff)); return true; } else if (m.is_eq(fml, x, y) && get_pb_sum(x, rational::one(), args, coeffs, coeff) && get_pb_sum(y, -rational::one(), args, coeffs, coeff)) { - result = m.mk_and(m_pb.mk_le(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff), - m_pb.mk_ge(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff)); + result = m.mk_and(mk_le(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff), + mk_ge(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff)); return true; } return false; } + + expr* mk_le(unsigned sz, rational const* weights, expr* const* args, rational const& w) { + if (sz == 1 && weights[0].is_one() && w >= rational::one()) { + return m.mk_true(); + } + if (sz == 1 && weights[0].is_one() && w.is_zero()) { + return m.mk_not(args[0]); + } + return m_pb.mk_le(sz, weights, args, w); + } + + expr* mk_ge(unsigned sz, rational const* weights, expr* const* args, rational const& w) { + if (sz == 1 && weights[0].is_one() && w.is_one()) { + return args[0]; + } + if (sz == 1 && weights[0].is_one() && w.is_zero()) { + return m.mk_not(args[0]); + } + return m_pb.mk_ge(sz, weights, args, w); + } bool get_pb_sum(expr* x, rational const& mul, expr_ref_vector& args, vector& coeffs, rational& coeff) { expr *y, *z, *u; @@ -179,31 +199,53 @@ public: else if (a.is_uminus(x, y)) { ok = get_pb_sum(y, -mul, args, coeffs, coeff); } - else if (a.is_mul(x, y, z) && a.is_numeral(y, r)) { + else if (a.is_mul(x, y, z) && is_numeral(y, r)) { ok = get_pb_sum(z, r*mul, args, coeffs, coeff); } - else if (a.is_mul(x, z, y) && a.is_numeral(y, r)) { + else if (a.is_mul(x, z, y) && is_numeral(y, r)) { ok = get_pb_sum(z, r*mul, args, coeffs, coeff); } - else if (m.is_ite(x, y, z, u) && a.is_numeral(z, r) && a.is_numeral(u, q)) { - args.push_back(y); - coeffs.push_back(r*mul); - args.push_back(m.mk_not(y)); - coeffs.push_back(q*mul); + else if (m.is_ite(x, y, z, u) && is_numeral(z, r) && is_numeral(u, q)) { + insert_arg(r*mul, y, args, coeffs, coeff); + // q*(1-y) = -q*y + q + coeff += q*mul; + insert_arg(-q*mul, y, args, coeffs, coeff); } else if (is_01var(x)) { - args.push_back(mk_01(x)); - coeffs.push_back(mul); + insert_arg(mul, mk_01(x), args, coeffs, coeff); } - else if (a.is_numeral(x, r)) { + else if (is_numeral(x, r)) { coeff += mul*r; } else { + TRACE("pb", tout << "Can't handle " << mk_pp(x, m) << "\n";); ok = false; } return ok; } + + bool is_numeral(expr* e, rational& r) { + if (a.is_uminus(e, e) && is_numeral(e, r)) { + r.neg(); + return true; + } + return a.is_numeral(e, r); + } + void insert_arg(rational const& p, expr* x, + expr_ref_vector& args, vector& coeffs, rational& coeff) { + if (p.is_neg()) { + // p*x = -p*(1-x) + p + args.push_back(m.mk_not(x)); + coeffs.push_back(-p); + coeff += p; + } + else if (p.is_pos()) { + args.push_back(x); + coeffs.push_back(p); + } + } + virtual tactic * translate(ast_manager & m) { return alloc(lia2card_tactic, m, m_params); } @@ -224,6 +266,9 @@ tactic * mk_lia2card_tactic(ast_manager & m, params_ref const & p) { return clean(alloc(lia2card_tactic, m, p)); } -void convert_objectives() { - +bool get_pb_sum(expr* term, expr_ref_vector& args, vector& coeffs, rational& coeff) { + params_ref p; + ast_manager& m = args.get_manager(); + lia2card_tactic tac(m, p); + return tac.get_pb_sum(term, rational::one(), args, coeffs, coeff); } diff --git a/src/tactic/arith/lia2card_tactic.h b/src/tactic/arith/lia2card_tactic.h index 69a5f3f60..de25ce409 100644 --- a/src/tactic/arith/lia2card_tactic.h +++ b/src/tactic/arith/lia2card_tactic.h @@ -30,4 +30,6 @@ tactic * mk_lia2card_tactic(ast_manager & m, params_ref const & p = params_ref() ADD_TACTIC("lia2card", "introduce cardinality constraints from 0-1 integer.", "mk_lia2card_tactic(m, p)") */ +bool get_pb_sum(expr* term, expr_ref_vector& args, vector& coeffs, rational& coeff); + #endif From e307c5fddabe9813c84d4d5086e819cd9ed3655a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 7 Dec 2013 14:47:47 -0800 Subject: [PATCH 197/925] fix minimize->maxsat Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 52ae1e38e..2d1b9c268 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -221,7 +221,18 @@ namespace opt { if (is_minimize(fml, term, index)) { TRACE("opt", tout << "try to convert minimization" << mk_pp(term, m) << "\n";); rational coeff(0); - return get_pb_sum(term, terms, weights, coeff); + // minimize 2*x + 3*y + // <=> + // (assret-soft (not x) 2) + // (assert-soft (not y) 3) + // + if (get_pb_sum(term, terms, weights, coeff) && coeff.is_zero()) { + // TBD: and weights are positive? + for (unsigned i = 0; i < terms.size(); ++i) { + terms[i] = m.mk_not(terms[i].get()); + } + return true; + } } return false; } From 370a4b66de424c428645ad3724af21702fbdce0a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 7 Dec 2013 22:09:57 -0800 Subject: [PATCH 198/925] update lower bounds from feasible solutiosn Signed-off-by: Nikolaj Bjorner --- src/opt/core_maxsat.cpp | 4 ++++ src/opt/core_maxsat.h | 1 + src/opt/fu_malik.cpp | 14 +++++++---- src/opt/fu_malik.h | 1 + src/opt/maxsmt.cpp | 24 +++++++++++++++---- src/opt/maxsmt.h | 12 ++++++++++ src/opt/opt_context.cpp | 47 +++++++++++++++++++++++++++++++++++-- src/opt/opt_context.h | 2 ++ src/opt/opt_solver.cpp | 13 ++-------- src/opt/opt_solver.h | 1 - src/opt/optsmt.cpp | 41 +++++++++++++++++--------------- src/opt/optsmt.h | 2 ++ src/opt/weighted_maxsat.cpp | 4 +++- src/opt/weighted_maxsat.h | 1 + 14 files changed, 123 insertions(+), 44 deletions(-) diff --git a/src/opt/core_maxsat.cpp b/src/opt/core_maxsat.cpp index 11756c617..d283feab8 100644 --- a/src/opt/core_maxsat.cpp +++ b/src/opt/core_maxsat.cpp @@ -147,5 +147,9 @@ namespace opt { void core_maxsat::set_cancel(bool f) { } + void core_maxsat::collect_statistics(statistics& st) const { + // nothing specific + } + }; diff --git a/src/opt/core_maxsat.h b/src/opt/core_maxsat.h index b5ee6e422..63f92cf4a 100644 --- a/src/opt/core_maxsat.h +++ b/src/opt/core_maxsat.h @@ -40,6 +40,7 @@ namespace opt { virtual rational get_value() const; virtual expr_ref_vector get_assignment() const; virtual void set_cancel(bool f); + virtual void collect_statistics(statistics& st) const; private: void set2vector(expr_set const& set, ptr_vector& es) const; diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index cf0fefe52..a83419cb6 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -93,6 +93,12 @@ namespace opt { } } + void collect_statistics(statistics& st) const { + if (m_s != &m_original_solver) { + m_s->collect_statistics(st); + } + } + void set_union(expr_set const& set1, expr_set const& set2, expr_set & set) const { set.reset(); expr_set::iterator it = set1.begin(), end = set1.end(); @@ -307,11 +313,6 @@ namespace opt { } } } - statistics st; - s().collect_statistics(st); - SASSERT(st.size() > 0); - opt_solver & opt_s = opt_solver::to_opt(m_original_solver); - opt_s.set_interim_stats(st); // We are done and soft_constraints has // been updated with the max-sat assignment. return is_sat; @@ -344,6 +345,9 @@ namespace opt { void fu_malik::set_cancel(bool f) { // no-op } + void fu_malik::collect_statistics(statistics& st) const { + m_imp->collect_statistics(st); + } diff --git a/src/opt/fu_malik.h b/src/opt/fu_malik.h index 9375e29c2..980db707b 100644 --- a/src/opt/fu_malik.h +++ b/src/opt/fu_malik.h @@ -41,6 +41,7 @@ namespace opt { virtual rational get_value() const; virtual expr_ref_vector get_assignment() const; virtual void set_cancel(bool f); + virtual void collect_statistics(statistics& st) const; }; }; diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index c6298f2e8..4fc184a13 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -79,21 +79,29 @@ namespace opt { if (m_msolver) { return inf_eps(m_msolver->get_value()); } - return inf_eps(); + return inf_eps(m_upper); } inf_eps maxsmt::get_lower() const { + rational r = m_lower; if (m_msolver) { - return inf_eps(m_msolver->get_lower()); + rational q = m_msolver->get_lower(); + if (r < q) r = q; } - return inf_eps(); + return inf_eps(r); } inf_eps maxsmt::get_upper() const { + rational r = m_upper; if (m_msolver) { - return inf_eps(m_msolver->get_upper()); + rational q = m_msolver->get_upper(); + if (r > q) r = q; } - return inf_eps(rational(m_soft_constraints.size())); + return inf_eps(r); + } + + void maxsmt::update_lower(rational const& r) { + if (m_lower > r) m_lower = r; } void maxsmt::commit_assignment() { @@ -130,5 +138,11 @@ namespace opt { m_maxsat_engine = _p.maxsat_engine(); } + void maxsmt::collect_statistics(statistics& st) const { + if (m_msolver) { + m_msolver->collect_statistics(st); + } + } + }; diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 413727b58..14e8515b7 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -21,6 +21,7 @@ Notes: #include "solver.h" #include "opt_solver.h" +#include "statistics.h" namespace opt { @@ -33,6 +34,7 @@ namespace opt { virtual rational get_value() const = 0; virtual expr_ref_vector get_assignment() const = 0; virtual void set_cancel(bool f) = 0; + virtual void collect_statistics(statistics& st) const = 0; }; /** Takes solver with hard constraints added. @@ -46,6 +48,8 @@ namespace opt { expr_ref_vector m_soft_constraints; expr_ref_vector m_answer; vector m_weights; + rational m_lower; + rational m_upper; scoped_ptr m_msolver; symbol m_maxsat_engine; public: @@ -58,8 +62,11 @@ namespace opt { void updt_params(params_ref& p); void add(expr* f, rational const& w) { + SASSERT(m.is_bool(f)); + SASSERT(w.is_pos()); m_soft_constraints.push_back(f); m_weights.push_back(w); + m_upper += w; } unsigned size() const { return m_soft_constraints.size(); } @@ -70,10 +77,15 @@ namespace opt { inf_eps get_value() const; inf_eps get_lower() const; inf_eps get_upper() const; + void update_lower(rational const& r); + expr_ref_vector get_assignment() const; void display_answer(std::ostream& out) const; + + void collect_statistics(statistics& st) const; + private: diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 2d1b9c268..f38605a61 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -85,6 +85,7 @@ namespace opt { return is_sat; } s.get_model(m_model); + update_lower(); switch (m_objectives.size()) { case 0: return is_sat; @@ -223,11 +224,15 @@ namespace opt { rational coeff(0); // minimize 2*x + 3*y // <=> - // (assret-soft (not x) 2) + // (assert-soft (not x) 2) // (assert-soft (not y) 3) // if (get_pb_sum(term, terms, weights, coeff) && coeff.is_zero()) { - // TBD: and weights are positive? + for (unsigned i = 0; i < weights.size(); ++i) { + if (!weights[i].is_pos()) { + return false; + } + } for (unsigned i = 0; i < terms.size(); ++i) { terms[i] = m.mk_not(terms[i].get()); } @@ -348,6 +353,40 @@ namespace opt { } } + void context::update_lower() { + arith_util a(m); + expr_ref val(m); + rational r(0); + for (unsigned i = 0; i < m_objectives.size(); ++i) { + objective const& obj = m_objectives[i]; + switch(obj.m_type) { + case O_MINIMIZE: + case O_MAXIMIZE: + if (m_model->eval(obj.m_term, val) && a.is_numeral(val, r)) { + m_optsmt.update_lower(obj.m_index, r); + } + break; + case O_MAXSMT: { + bool ok = true; + for (unsigned j = 0; ok && j < obj.m_terms.size(); ++j) { + if (m_model->eval(obj.m_terms[j], val)) { + if (!m.is_true(val)) { + r += obj.m_weights[j]; + } + } + else { + ok = false; + } + } + if (ok) { + m_maxsmts.find(obj.m_id)->update_lower(r); + } + break; + } + } + } + } + void context::display_assignment(std::ostream& out) { for (unsigned i = 0; i < m_objectives.size(); ++i) { objective const& obj = m_objectives[i]; @@ -459,6 +498,10 @@ namespace opt { if (m_solver) { m_solver->collect_statistics(stats); } + map_t::iterator it = m_maxsmts.begin(), end = m_maxsmts.end(); + for (; it != end; ++it) { + it->m_value->collect_statistics(stats); + } } void context::collect_param_descrs(param_descrs & r) { diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 9bc1007de..b1424d165 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -128,6 +128,8 @@ namespace opt { void from_fmls(expr_ref_vector const& fmls); void simplify_fmls(expr_ref_vector& fmls); + void update_lower(); + opt_solver& get_solver(); }; diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index d6877e5db..01d64b6cc 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -55,14 +55,8 @@ namespace opt { m_context.collect_param_descrs(r); } - void opt_solver::collect_statistics(statistics & st) const { - // HACK: display fu_malik statistics - if (m_stats.size() > 0) { - st.copy(m_stats); - } - else { - m_context.collect_statistics(st); - } + void opt_solver::collect_statistics(statistics & st) const { + m_context.collect_statistics(st); } void opt_solver::assert_expr(expr * t) { @@ -241,9 +235,6 @@ namespace opt { return dynamic_cast(s); } - void opt_solver::set_interim_stats(statistics & st) { - m_stats.copy(st); - } void opt_solver::to_smt2_benchmark(std::ofstream & buffer, char const * name, char const * logic, char const * status, char const * attributes) { diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index f35a79203..d5fb58afe 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -79,7 +79,6 @@ namespace opt { expr_ref mk_ge(unsigned obj_index, inf_eps const& val); static opt_solver& to_opt(solver& s); - void set_interim_stats(statistics & st); bool dump_benchmarks(); class toggle_objective { diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 91a421adb..e8df01b5a 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -105,6 +105,13 @@ namespace opt { return l_true; } + void optsmt::update_lower(unsigned idx, rational const& r) { + inf_eps v(r); + if (m_lower[idx] < v) { + m_lower[idx] = v; + } + } + void optsmt::update_lower() { model_ref md; s->get_model(md); @@ -202,30 +209,26 @@ namespace opt { Returns an optimal assignment to objective functions. */ lbool optsmt::operator()(opt_solver& solver) { + if (m_objs.empty()) { + return l_true; + } + lbool is_sat = l_true; s = &solver; - s->reset_objectives(); + solver.reset_objectives(); m_vars.reset(); // First check_sat call to initialize theories - lbool is_sat = s->check_sat(0, 0); - solver::scoped_push _push(*s); - if (is_sat == l_true && !m_objs.empty()) { - for (unsigned i = 0; i < m_objs.size(); ++i) { - m_vars.push_back(s->add_objective(m_objs[i].get())); - } + solver::scoped_push _push(solver); - if (m_engine == symbol("basic")) { - is_sat = basic_opt(); - } - else if (m_engine == symbol("farkas")) { - is_sat = farkas_opt(); - } - else { - // TODO: implement symba engine - // report error on bad configuration. - NOT_IMPLEMENTED_YET(); - UNREACHABLE(); - } + for (unsigned i = 0; i < m_objs.size(); ++i) { + m_vars.push_back(solver.add_objective(m_objs[i].get())); + } + + if (m_engine == symbol("farkas")) { + is_sat = farkas_opt(); + } + else { + is_sat = basic_opt(); } IF_VERBOSE(1, verbose_stream() << "is-sat: " << is_sat << std::endl; diff --git a/src/opt/optsmt.h b/src/opt/optsmt.h index 0fbfeb7b2..c8be7a730 100644 --- a/src/opt/optsmt.h +++ b/src/opt/optsmt.h @@ -56,6 +56,8 @@ namespace opt { inf_eps get_value(unsigned index) const; inf_eps get_lower(unsigned index) const; inf_eps get_upper(unsigned index) const; + + void update_lower(unsigned idx, rational const& r); private: diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 206117224..613ce41d5 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -370,7 +370,9 @@ namespace opt { void wmaxsmt::set_cancel(bool f) { // no-op } - + void wmaxsmt::collect_statistics(statistics& st) const { + // no-op + } diff --git a/src/opt/weighted_maxsat.h b/src/opt/weighted_maxsat.h index 8621ff9e1..3b00e1690 100644 --- a/src/opt/weighted_maxsat.h +++ b/src/opt/weighted_maxsat.h @@ -39,6 +39,7 @@ namespace opt { virtual rational get_value() const; virtual expr_ref_vector get_assignment() const; virtual void set_cancel(bool f); + virtual void collect_statistics(statistics& st) const; }; }; From ddb30c51b53f19398215f9d31059b54077fc2b1a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Dec 2013 12:17:33 -0800 Subject: [PATCH 199/925] debugging lia2maxsat Signed-off-by: Nikolaj Bjorner --- src/opt/maxsmt.cpp | 15 ++--- src/opt/maxsmt.h | 6 +- src/opt/opt_context.cpp | 116 ++++++++++++++++++++++-------------- src/opt/opt_context.h | 11 +++- src/opt/weighted_maxsat.cpp | 21 +++---- 5 files changed, 104 insertions(+), 65 deletions(-) diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 4fc184a13..8232e169e 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -32,6 +32,7 @@ namespace opt { m_msolver = 0; m_s = &s; if (m_soft_constraints.empty()) { + TRACE("opt", tout << "no constraints\n";); m_msolver = 0; is_sat = s.check_sat(0, 0); m_answer.reset(); @@ -75,29 +76,29 @@ namespace opt { return m_answer; } - inf_eps maxsmt::get_value() const { + rational maxsmt::get_value() const { if (m_msolver) { - return inf_eps(m_msolver->get_value()); + return m_msolver->get_value(); } - return inf_eps(m_upper); + return m_upper; } - inf_eps maxsmt::get_lower() const { + rational maxsmt::get_lower() const { rational r = m_lower; if (m_msolver) { rational q = m_msolver->get_lower(); if (r < q) r = q; } - return inf_eps(r); + return r; } - inf_eps maxsmt::get_upper() const { + rational maxsmt::get_upper() const { rational r = m_upper; if (m_msolver) { rational q = m_msolver->get_upper(); if (r > q) r = q; } - return inf_eps(r); + return r; } void maxsmt::update_lower(rational const& r) { diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 14e8515b7..d4eff4334 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -74,9 +74,9 @@ namespace opt { rational weight(unsigned idx) const { return m_weights[idx]; } void commit_assignment(); - inf_eps get_value() const; - inf_eps get_lower() const; - inf_eps get_upper() const; + rational get_value() const; + rational get_lower() const; + rational get_upper() const; void update_lower(rational const& r); diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index f38605a61..1bb34f6dd 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -209,8 +209,10 @@ namespace opt { } bool context::is_maxsat(expr* fml, expr_ref_vector& terms, - vector& weights, symbol& id, unsigned& index) { + vector& weights, rational& offset, + bool& neg, symbol& id, unsigned& index) { if (!is_app(fml)) return false; + neg = false; app* a = to_app(fml); if (m_objective_fns.find(a->get_decl(), index) && m_objectives[index].m_type == O_MAXSMT) { terms.append(a->get_num_args(), a->get_args()); @@ -219,25 +221,46 @@ namespace opt { return true; } app_ref term(m); - if (is_minimize(fml, term, index)) { + offset = rational::zero(); + if (is_minimize(fml, term, index) && + get_pb_sum(term, terms, weights, offset)) { TRACE("opt", tout << "try to convert minimization" << mk_pp(term, m) << "\n";); - rational coeff(0); // minimize 2*x + 3*y // <=> // (assert-soft (not x) 2) // (assert-soft (not y) 3) // - if (get_pb_sum(term, terms, weights, coeff) && coeff.is_zero()) { - for (unsigned i = 0; i < weights.size(); ++i) { - if (!weights[i].is_pos()) { - return false; - } + for (unsigned i = 0; i < weights.size(); ++i) { + if (weights[i].is_neg()) { + offset += weights[i]; + weights[i].neg(); } - for (unsigned i = 0; i < terms.size(); ++i) { + else { terms[i] = m.mk_not(terms[i].get()); } - return true; } + return true; + } + if (is_maximize(fml, term, index) && + get_pb_sum(term, terms, weights, offset)) { + TRACE("opt", tout << "try to convert maximization" << mk_pp(term, m) << "\n";); + // maximize 2*x + 3*y - z + // <=> + // (assert-soft x 2) + // (assert-soft y 3) + // (assert-soft (not z) 1) + // offset := 6 + // maximize = offset - penalty + // + for (unsigned i = 0; i < weights.size(); ++i) { + if (weights[i].is_neg()) { + weights[i].neg(); + terms[i] = m.mk_not(terms[i].get()); + } + offset += weights[i]; + } + neg = true; + return true; } return false; } @@ -281,9 +304,11 @@ namespace opt { app_ref tr(m); expr_ref_vector terms(m); vector weights; + rational offset; unsigned index; symbol id; - if (is_maxsat(fml, terms, weights, id, index)) { + bool neg; + if (is_maxsat(fml, terms, weights, offset, neg, id, index)) { objective& obj = m_objectives[index]; if (obj.m_type != O_MAXSMT) { // change from maximize/minimize. @@ -298,6 +323,9 @@ namespace opt { SASSERT(obj.m_id == id); obj.m_terms.reset(); obj.m_terms.append(terms); + obj.m_offset = offset; + obj.m_neg = neg; + TRACE("opt", tout << "maxsat: " << id << " offset:" << offset << "\n";); } else if (is_maximize(fml, tr, index)) { m_objectives[index].m_term = tr; @@ -390,51 +418,47 @@ namespace opt { void context::display_assignment(std::ostream& out) { for (unsigned i = 0; i < m_objectives.size(); ++i) { objective const& obj = m_objectives[i]; - switch(obj.m_type) { - case O_MAXSMT: { - symbol s = obj.m_id; - if (s != symbol::null) { - out << s << " : "; - } - maxsmt* ms = m_maxsmts.find(s); - out << ms->get_value() << "\n"; - break; - } - default: - break; - } + display_objective(out, obj); + out << get_upper(i) << "\n"; } - m_optsmt.display_assignment(out); } void context::display_range_assignment(std::ostream& out) { - for (unsigned i = 0; i < m_objectives.size(); ++i) { + for (unsigned i = 0; i < m_objectives.size(); ++i) { objective const& obj = m_objectives[i]; - switch(obj.m_type) { - case O_MAXSMT: { - symbol s = obj.m_id; - if (s != symbol::null) { - out << s << " : "; - } - maxsmt* ms = m_maxsmts.find(s); - out << "[" << ms->get_lower() << ":" << ms->get_upper() << "]\n"; - break; - } - default: - break; - } + display_objective(out, obj); + out << " [" << get_lower(i) << ":" << get_upper(i) << "]\n"; } - m_optsmt.display_range_assignment(out); } + void context::display_objective(std::ostream& out, objective const& obj) const { + switch(obj.m_type) { + case O_MAXSMT: { + symbol s = obj.m_id; + if (s != symbol::null) { + out << s << " : "; + } + break; + } + default: + out << obj.m_term << " "; + break; + } + } + + expr_ref context::get_lower(unsigned idx) { if (idx > m_objectives.size()) { throw default_exception("index out of bounds"); } objective const& obj = m_objectives[idx]; switch(obj.m_type) { - case O_MAXSMT: - return to_expr(m_maxsmts.find(obj.m_id)->get_lower()); + case O_MAXSMT: { + rational r = m_maxsmts.find(obj.m_id)->get_lower(); + if (obj.m_neg) r.neg(); + r += obj.m_offset; + return to_expr(inf_eps(r)); + } case O_MINIMIZE: case O_MAXIMIZE: return to_expr(m_optsmt.get_lower(obj.m_index)); @@ -450,8 +474,12 @@ namespace opt { } objective const& obj = m_objectives[idx]; switch(obj.m_type) { - case O_MAXSMT: - return to_expr(m_maxsmts.find(obj.m_id)->get_upper()); + case O_MAXSMT: { + rational r = m_maxsmts.find(obj.m_id)->get_upper(); + if (obj.m_neg) r.neg(); + r += obj.m_offset; + return to_expr(inf_eps(r)); + } case O_MINIMIZE: case O_MAXIMIZE: return to_expr(m_optsmt.get_upper(obj.m_index)); diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index b1424d165..2e19c3cb3 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -49,6 +49,8 @@ namespace opt { app_ref m_term; // for maximize, minimize term expr_ref_vector m_terms; // for maxsmt vector m_weights; // for maxsmt + rational m_offset; // for maxsmt + bool m_neg; // negate symbol m_id; // for maxsmt unsigned m_index; // for maximize/minimize index @@ -56,6 +58,8 @@ namespace opt { m_type(is_max?O_MAXIMIZE:O_MINIMIZE), m_term(t), m_terms(t.get_manager()), + m_offset(0), + m_neg(false), m_id(), m_index(idx) {} @@ -64,6 +68,8 @@ namespace opt { m_type(O_MAXSMT), m_term(m), m_terms(m), + m_offset(0), + m_neg(false), m_id(id), m_index(0) {} @@ -119,7 +125,8 @@ namespace opt { bool is_maximize(expr* fml, app_ref& term, unsigned& index); bool is_minimize(expr* fml, app_ref& term, unsigned& index); bool is_maxsat(expr* fml, expr_ref_vector& terms, - vector& weights, symbol& id, unsigned& index); + vector& weights, rational& offset, bool& neg, + symbol& id, unsigned& index); expr* mk_maximize(unsigned index, app* t); expr* mk_minimize(unsigned index, app* t); expr* mk_maxsat(unsigned index, unsigned num_fmls, expr* const* fmls); @@ -132,6 +139,8 @@ namespace opt { opt_solver& get_solver(); + void display_objective(std::ostream& out, objective const& obj) const; + }; } diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 613ce41d5..dbc943fbd 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -218,12 +218,15 @@ namespace smt { if (m_min_cost_atom) { lits.push_back(~literal(m_min_cost_bv)); } - IF_VERBOSE(2, verbose_stream() << "block: " << m_costs.size() << " " << lits.size() << " " << m_min_cost << "\n";); - IF_VERBOSE(2, for (unsigned i = 0; i < lits.size(); ++i) { - verbose_stream() << lits[i] << " "; - } - verbose_stream() << "\n"; - ); + IF_VERBOSE(2, + verbose_stream() << "block: "; + for (unsigned i = 0; i < lits.size(); ++i) { + expr_ref tmp(m); + ctx.literal2expr(lits[i], tmp); + verbose_stream() << tmp << " "; + } + verbose_stream() << "\n"; + ); ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); if (is_final && m_cost < m_min_cost) { @@ -312,6 +315,7 @@ namespace opt { */ lbool operator()() { + TRACE("opt", tout << "weighted maxsat\n";); smt::theory_weighted_maxsat& wth = ensure_theory(); lbool result; { @@ -319,11 +323,7 @@ namespace opt { for (unsigned i = 0; i < m_soft.size(); ++i) { wth.assert_weighted(m_soft[i].get(), m_weights[i]); } -#if 1 result = s.check_sat_core(0,0); -#else - result = iterative_weighted_maxsat(s, *wth); -#endif wth.get_assignment(m_assignment); if (!m_assignment.empty() && result == l_false) { @@ -331,6 +331,7 @@ namespace opt { } } m_upper = wth.get_min_cost(); + TRACE("opt", tout << "min cost: " << m_upper << "\n";); wth.reset(); return result; } From f0ef339623e9f2738452d7f3e48e4341e2ba9fcf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Dec 2013 12:30:52 -0800 Subject: [PATCH 200/925] fix bug exposed by lia2maxsmt4 Signed-off-by: Nikolaj Bjorner --- src/opt/weighted_maxsat.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index dbc943fbd..48c25e4d5 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -87,6 +87,12 @@ namespace smt { SASSERT(v == m_var2bool.size()); m_var2bool.push_back(bv); SASSERT(ctx.bool_var2enode(bv)); + + lbool asgn = ctx.get_assignment(bv); + if (asgn == l_true) { + assign_eh(bv, true); + } + } if (m_min_cost_atom) { app* var = m_min_cost_atom; From 5566965a5aa99a1880b46ffeaa640fe0da14c66e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Dec 2013 18:19:10 -0800 Subject: [PATCH 201/925] fix bug exposed from relevancy Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index e5686e2e2..e43db8dce 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -528,6 +528,9 @@ namespace smt { if (ctx.get_assignment(c.lit()) == l_undef) { return; } + if (!ctx.is_relevant(c.lit())) { + return; + } numeral sum = numeral::zero(), maxsum = numeral::zero(); for (unsigned i = 0; i < c.size(); ++i) { switch(ctx.get_assignment(c.lit(i))) { From 97b2fc9ee7fef4e2e161f764a235bd602d6d8b11 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Dec 2013 18:34:28 -0800 Subject: [PATCH 202/925] fix bugs exposed by testSolver Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 20 ++++++++++++++++---- src/opt/optsmt.cpp | 12 ++++++++++++ src/tactic/arith/lia2card_tactic.cpp | 6 ++++++ 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 1bb34f6dd..9e6a9fae6 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -419,7 +419,7 @@ namespace opt { for (unsigned i = 0; i < m_objectives.size(); ++i) { objective const& obj = m_objectives[i]; display_objective(out, obj); - out << get_upper(i) << "\n"; + out << "|-> " << get_upper(i) << "\n"; } } @@ -427,7 +427,7 @@ namespace opt { for (unsigned i = 0; i < m_objectives.size(); ++i) { objective const& obj = m_objectives[i]; display_objective(out, obj); - out << " [" << get_lower(i) << ":" << get_upper(i) << "]\n"; + out << " |-> [" << get_lower(i) << ":" << get_upper(i) << "]\n"; } } @@ -496,13 +496,25 @@ namespace opt { expr_ref_vector args(m); arith_util a(m); if (!inf.is_zero()) { - args.push_back(a.mk_mul(a.mk_numeral(inf, inf.is_int()), m.mk_const(symbol("oo"), a.mk_int()))); + expr* oo = m.mk_const(symbol("oo"), a.mk_int()); + if (inf.is_one()) { + args.push_back(oo); + } + else { + args.push_back(a.mk_mul(a.mk_numeral(inf, inf.is_int()), oo)); + } } if (!r.is_zero()) { args.push_back(a.mk_numeral(r, r.is_int())); } if (!eps.is_zero()) { - args.push_back(a.mk_mul(a.mk_numeral(eps, eps.is_int()), m.mk_const(symbol("epsilon"), a.mk_int()))); + expr* ep = m.mk_const(symbol("epsilon"), a.mk_int()); + if (eps.is_one()) { + args.push_back(ep); + } + else { + args.push_back(a.mk_mul(a.mk_numeral(eps, eps.is_int()), ep)); + } } switch(args.size()) { case 0: return expr_ref(a.mk_numeral(rational(0), true), m); diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index e8df01b5a..2f4a35459 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -79,6 +79,12 @@ namespace opt { if (m_cancel || is_sat == l_undef) { return l_undef; } + + // set the solution tight. + for (unsigned i = 0; i < m_lower.size(); ++i) { + m_upper[i] = m_lower[i]; + } + return l_true; } @@ -102,6 +108,12 @@ namespace opt { if (m_cancel || is_sat == l_undef) { return l_undef; } + + // set the solution tight. + for (unsigned i = 0; i < m_lower.size(); ++i) { + m_upper[i] = m_lower[i]; + } + return l_true; } diff --git a/src/tactic/arith/lia2card_tactic.cpp b/src/tactic/arith/lia2card_tactic.cpp index 347d4749f..f5ae23b07 100644 --- a/src/tactic/arith/lia2card_tactic.cpp +++ b/src/tactic/arith/lia2card_tactic.cpp @@ -163,6 +163,9 @@ public: } expr* mk_le(unsigned sz, rational const* weights, expr* const* args, rational const& w) { + if (sz == 0) { + return w.is_neg()?m.mk_false():m.mk_true(); + } if (sz == 1 && weights[0].is_one() && w >= rational::one()) { return m.mk_true(); } @@ -173,6 +176,9 @@ public: } expr* mk_ge(unsigned sz, rational const* weights, expr* const* args, rational const& w) { + if (sz == 0) { + return w.is_pos()?m.mk_false():m.mk_true(); + } if (sz == 1 && weights[0].is_one() && w.is_one()) { return args[0]; } From 0f0397b05f9a10921931d599094d79a3cd0b17d1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Dec 2013 18:58:48 -0800 Subject: [PATCH 203/925] hunt bugs exposed by so.smt2 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 2 ++ src/smt/theory_pb.cpp | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 9e6a9fae6..2142ffae3 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -239,6 +239,7 @@ namespace opt { terms[i] = m.mk_not(terms[i].get()); } } + id = symbol(index); return true; } if (is_maximize(fml, term, index) && @@ -260,6 +261,7 @@ namespace opt { offset += weights[i]; } neg = true; + id = symbol(index); return true; } return false; diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index e43db8dce..eecb1109b 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1121,6 +1121,7 @@ namespace smt { } else { if (lvl == m_conflict_lvl) { + TRACE("pb", tout << "add mark: " << l << " " << coeff << "\n";); ++m_num_marks; } set_mark(v, m_lemma.size()); @@ -1285,7 +1286,8 @@ namespace smt { justification& j = *js.get_justification(); // only process pb justifications. if (j.get_from_theory() != get_id()) { - IF_VERBOSE(0, verbose_stream() << "skipping justification for " << conseq << "\n";); + IF_VERBOSE(0, verbose_stream() << "skipping justification for theory " << conseq << "\n";); + IF_VERBOSE(0, verbose_stream() << j.get_from_theory() << "\n";); m_ineq_literals.push_back(conseq); break; } From ec84d69206e61adbd227dd8e5634e0cd359aca2f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Dec 2013 21:40:53 -0800 Subject: [PATCH 204/925] investigating conflict resolution bug Signed-off-by: Nikolaj Bjorner --- src/smt/smt_b_justification.h | 2 +- src/smt/theory_pb.cpp | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/smt/smt_b_justification.h b/src/smt/smt_b_justification.h index 4798af4b0..5a82e36e8 100644 --- a/src/smt/smt_b_justification.h +++ b/src/smt/smt_b_justification.h @@ -54,7 +54,7 @@ namespace smt { m_data(BOXTAGINT(void*, l.index(), BIN_CLAUSE)) { } - explicit b_justification(justification * js): + explicit b_justification(justification * js): m_data(TAG(void*, js, JUSTIFICATION)) { SASSERT(js); } diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index eecb1109b..355e9a3d5 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1211,7 +1211,7 @@ namespace smt { while (m_num_marks > 0) { - m_lemma.normalize(); + //m_lemma.normalize(); SASSERT(m_lemma.well_formed()); // @@ -1222,7 +1222,11 @@ namespace smt { v = conseq.var(); --idx; } - while (!is_marked(v)); + while (!is_marked(v) && idx > 0); + if (idx == 0) { + IF_VERBOSE(1, verbose_stream() << "BUG?!\n";); + return false; + } unsigned conseq_index = m_conseq_index[v]; numeral conseq_coeff = m_lemma.coeff(conseq_index); @@ -1254,7 +1258,7 @@ namespace smt { clause& cls = *js.get_clause(); justification* cjs = cls.get_justification(); if (cjs) { - IF_VERBOSE(0, verbose_stream() << "skipping justification for clause over: " << conseq << "\n";); + IF_VERBOSE(1, verbose_stream() << "skipping justification for clause over: " << conseq << "\n";); m_ineq_literals.push_back(conseq); break; } @@ -1286,8 +1290,8 @@ namespace smt { justification& j = *js.get_justification(); // only process pb justifications. if (j.get_from_theory() != get_id()) { - IF_VERBOSE(0, verbose_stream() << "skipping justification for theory " << conseq << "\n";); - IF_VERBOSE(0, verbose_stream() << j.get_from_theory() << "\n";); + IF_VERBOSE(1, verbose_stream() << "skipping justification for " << conseq + << " from theory " << j.get_from_theory() << "\n";); m_ineq_literals.push_back(conseq); break; } From d1e86f1d420ba8e73b60386421b0d4beeb7e9b7a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 9 Dec 2013 15:48:15 -0800 Subject: [PATCH 205/925] adding validation code for assignment Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 40 ++++++++++++++++++++++++++++++++++++---- src/smt/theory_pb.h | 3 ++- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 355e9a3d5..d130b0757 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -653,6 +653,7 @@ namespace smt { lits.push_back(c.lit()); for (unsigned i = 0; i < c.size(); ++i) { if (ctx.get_assignment(c.lit(i)) == l_undef) { + SASSERT(validate_assign(c, lits, c.lit(i))); add_assign(c, lits, c.lit(i)); } } @@ -701,12 +702,12 @@ namespace smt { else { del_watch(watch, watch_index, c, w); removed = true; - if (c.max_sum() - coeff < k + c.max_coeff()) { + if (c.max_sum() < k + c.max_coeff()) { // // opportunities for unit propagation for unassigned // literals whose coefficients satisfy - // c.max_sum() - coeff < k + // c.max_sum() < k // // L: 3*x1 + 2*x2 + x4 >= 3, but x1 <- 0 // Create clauses x1 or ~L or x2 @@ -717,6 +718,7 @@ namespace smt { lits.push_back(c.lit()); for (unsigned i = 0; i < c.size(); ++i) { if (c.max_sum() - c.coeff(i) < k && ctx.get_assignment(c.lit(i)) == l_undef) { + SASSERT(validate_assign(c, lits, c.lit(i))); add_assign(c, lits, c.lit(i)); } } @@ -985,7 +987,7 @@ namespace smt { } } - std::ostream& theory_pb::display(std::ostream& out, ineq& c, bool values) const { + std::ostream& theory_pb::display(std::ostream& out, ineq const& c, bool values) const { ast_manager& m = get_manager(); context& ctx = get_context(); out << c.lit(); @@ -1058,6 +1060,7 @@ namespace smt { tout << "=> " << l << "\n"; display(tout, c, true);); + ctx.assign(l, ctx.mk_justification( pb_justification( c, get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), l))); @@ -1084,6 +1087,31 @@ namespace smt { verbose_stream() << "\n";); } + bool theory_pb::validate_assign(ineq const& c, literal_vector const& lits, literal l) const { + uint_set nlits; + for (unsigned i = 0; i < lits.size(); ++i) { + nlits.insert((~lits[i]).index()); + } + nlits.insert(l.index()); + numeral sum = numeral::zero(); + for (unsigned i = 0; i < c.size(); ++i) { + literal lit = c.lit(i); + if (!nlits.contains(lit.index())) { + sum += c.coeff(i); + } + } + if (sum >= c.k()) { + IF_VERBOSE(0, + display(verbose_stream(), c, true); + for (unsigned i = 0; i < lits.size(); ++i) { + verbose_stream() << lits[i] << " "; + } + verbose_stream() << " => " << l << "\n";); + } + SASSERT(sum < c.k()); + return true; + } + void theory_pb::set_mark(bool_var v, unsigned idx) { SASSERT(v != null_bool_var); if (v >= static_cast(m_conseq_index.size())) { @@ -1211,7 +1239,11 @@ namespace smt { while (m_num_marks > 0) { - //m_lemma.normalize(); + lbool is_sat = m_lemma.normalize(); + if (is_sat != l_undef) { + IF_VERBOSE(0, display(verbose_stream() << "created non-tautology lemma: ", m_lemma, true);); + return false; + } SASSERT(m_lemma.well_formed()); // diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index e72aed879..fc1a61186 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -116,7 +116,7 @@ namespace smt { bool assign_watch(bool_var v, bool is_true, watch_list& watch, unsigned index); void assign_ineq(ineq& c, bool is_true); - std::ostream& display(std::ostream& out, ineq& c, bool values = false) const; + std::ostream& display(std::ostream& out, ineq const& c, bool values = false) const; virtual void display(std::ostream& out) const; void add_clause(ineq& c, literal_vector const& lits); @@ -157,6 +157,7 @@ namespace smt { void validate_final_check(); void validate_final_check(ineq& c); + bool validate_assign(ineq const& c, literal_vector const& lits, literal l) const; public: theory_pb(ast_manager& m); From fbf834f4c4dc1bc00b2c97d08eb4bb844827520a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 9 Dec 2013 15:48:58 -0800 Subject: [PATCH 206/925] debugging pb Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 355e9a3d5..00353e4b4 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1211,7 +1211,8 @@ namespace smt { while (m_num_marks > 0) { - //m_lemma.normalize(); + m_lemma.normalize(); + TRACE("pb", display(tout, m_lemma, true);); SASSERT(m_lemma.well_formed()); // From 2c577a304d27fca258aa5a6a702bdc668d925e03 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 10 Dec 2013 15:16:58 -0800 Subject: [PATCH 207/925] bug fixes to pb; working on model extraction Signed-off-by: Nikolaj Bjorner --- src/opt/core_maxsat.cpp | 10 +- src/opt/core_maxsat.h | 3 +- src/opt/fu_malik.cpp | 14 +- src/opt/fu_malik.h | 1 + src/opt/maxsmt.cpp | 7 + src/opt/maxsmt.h | 10 +- src/opt/opt_context.cpp | 8 +- src/opt/opt_context.h | 2 + src/opt/optsmt.cpp | 5 + src/opt/optsmt.h | 2 + src/opt/weighted_maxsat.cpp | 17 ++ src/opt/weighted_maxsat.h | 1 + src/smt/theory_arith_core.h | 11 + src/smt/theory_pb.cpp | 437 +++++++++++++++++++++--------------- src/smt/theory_pb.h | 17 +- 15 files changed, 348 insertions(+), 197 deletions(-) diff --git a/src/opt/core_maxsat.cpp b/src/opt/core_maxsat.cpp index d283feab8..1019465cd 100644 --- a/src/opt/core_maxsat.cpp +++ b/src/opt/core_maxsat.cpp @@ -50,13 +50,13 @@ namespace opt { case l_undef: return l_undef; case l_true: { - model_ref model; + model_ref mdl; expr_ref_vector ans(m); - s.get_model(model); + s.get_model(mdl); for (unsigned i = 0; i < aux.size(); ++i) { expr_ref val(m); - VERIFY(model->eval(m_soft[i].get(), val)); + VERIFY(mdl->eval(m_soft[i].get(), val)); if (m.is_true(val)) { ans.push_back(m_soft[i].get()); } @@ -69,6 +69,7 @@ namespace opt { if (ans.size() > m_answer.size()) { m_answer.reset(); m_answer.append(ans); + m_model = mdl.get(); } if (m_answer.size() == m_upper) { return l_true; @@ -150,6 +151,9 @@ namespace opt { void core_maxsat::collect_statistics(statistics& st) const { // nothing specific } + void core_maxsat::get_model(model_ref& mdl) { + mdl = m_model.get(); + } }; diff --git a/src/opt/core_maxsat.h b/src/opt/core_maxsat.h index 63f92cf4a..cf4ce8d48 100644 --- a/src/opt/core_maxsat.h +++ b/src/opt/core_maxsat.h @@ -31,6 +31,7 @@ namespace opt { expr_ref_vector m_soft; expr_ref_vector m_answer; unsigned m_upper; + model_ref m_model; public: core_maxsat(ast_manager& m, solver& s, expr_ref_vector& soft_constraints); virtual ~core_maxsat(); @@ -41,7 +42,7 @@ namespace opt { virtual expr_ref_vector get_assignment() const; virtual void set_cancel(bool f); virtual void collect_statistics(statistics& st) const; - + virtual void get_model(model_ref& mdl); private: void set2vector(expr_set const& set, ptr_vector& es) const; expr_ref mk_at_most(expr_set const& set, unsigned k); diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index a83419cb6..13dc6e46d 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -48,6 +48,7 @@ namespace opt { expr_ref_vector m_aux; expr_ref_vector m_assignment; unsigned m_upper_size; + model_ref m_model; ref m_s; solver & m_original_solver; @@ -300,13 +301,12 @@ namespace opt { if (is_sat == l_true) { // Get a list of satisfying m_soft - model_ref model; - s().get_model(model); + s().get_model(m_model); m_assignment.reset(); for (unsigned i = 0; i < m_orig_soft.size(); ++i) { expr_ref val(m); - VERIFY(model->eval(m_orig_soft[i].get(), val)); + VERIFY(m_model->eval(m_orig_soft[i].get(), val)); if (m.is_true(val)) { m_assignment.push_back(m_orig_soft[i].get()); } @@ -318,6 +318,10 @@ namespace opt { return is_sat; } + void get_model(model_ref& mdl) { + mdl = m_model.get(); + } + }; fu_malik::fu_malik(ast_manager& m, solver& s, expr_ref_vector& soft_constraints) { @@ -348,6 +352,10 @@ namespace opt { void fu_malik::collect_statistics(statistics& st) const { m_imp->collect_statistics(st); } + void fu_malik::get_model(model_ref& m) { + m_imp->get_model(m); + } + diff --git a/src/opt/fu_malik.h b/src/opt/fu_malik.h index 980db707b..2cd4e146d 100644 --- a/src/opt/fu_malik.h +++ b/src/opt/fu_malik.h @@ -42,6 +42,7 @@ namespace opt { virtual expr_ref_vector get_assignment() const; virtual void set_cancel(bool f); virtual void collect_statistics(statistics& st) const; + virtual void get_model(model_ref& m); }; }; diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 8232e169e..1d1a65e5c 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -52,6 +52,9 @@ namespace opt { if (m_msolver) { is_sat = (*m_msolver)(); m_answer.append(m_msolver->get_assignment()); + if (is_sat == l_true) { + m_msolver->get_model(m_model); + } } // Infrastructure for displaying and storing solution is TBD. @@ -105,6 +108,10 @@ namespace opt { if (m_lower > r) m_lower = r; } + void maxsmt::get_model(model_ref& mdl) { + mdl = m_model.get(); + } + void maxsmt::commit_assignment() { SASSERT(m_s); for (unsigned i = 0; i < m_answer.size(); ++i) { diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index d4eff4334..92744baaf 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -35,6 +35,7 @@ namespace opt { virtual expr_ref_vector get_assignment() const = 0; virtual void set_cancel(bool f) = 0; virtual void collect_statistics(statistics& st) const = 0; + virtual void get_model(model_ref& mdl) = 0; }; /** Takes solver with hard constraints added. @@ -52,6 +53,7 @@ namespace opt { rational m_upper; scoped_ptr m_msolver; symbol m_maxsat_engine; + model_ref m_model; public: maxsmt(ast_manager& m): m(m), m_s(0), m_cancel(false), m_soft_constraints(m), m_answer(m) {} @@ -78,15 +80,11 @@ namespace opt { rational get_lower() const; rational get_upper() const; void update_lower(rational const& r); - - + void get_model(model_ref& mdl); expr_ref_vector get_assignment() const; - - void display_answer(std::ostream& out) const; - + void display_answer(std::ostream& out) const; void collect_statistics(statistics& st) const; - private: bool is_maxsat_problem(vector const& ws) const; diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 2142ffae3..6501ef51b 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -108,12 +108,16 @@ namespace opt { void context::get_model(model_ref& mdl) { mdl = m_model; + if (m_model_converter) { + (*m_model_converter)(mdl, 0); + } } lbool context::execute_min_max(unsigned index, bool committed, bool is_max) { // HACK: reuse m_optsmt without regard for box reuse and not considering // use-case of lex. lbool result = m_optsmt(get_solver()); + if (result == l_true) m_optsmt.get_model(m_model); if (committed) m_optsmt.commit_assignment(index); return result; } @@ -122,6 +126,7 @@ namespace opt { lbool context::execute_maxsat(symbol const& id, bool committed) { maxsmt& ms = *m_maxsmts.find(id); lbool result = ms(get_solver()); + if (result == l_true) ms.get_model(m_model); if (committed) ms.commit_assignment(); return result; } @@ -177,11 +182,10 @@ namespace opt { tactic_ref tac1 = mk_elim01_tactic(m); tactic_ref tac2 = mk_lia2card_tactic(m); tactic_ref tac = and_then(tac1.get(), tac2.get()); - model_converter_ref mc; // TBD: expose model converter upwards and apply to returned model. proof_converter_ref pc; expr_dependency_ref core(m); goal_ref_buffer result; - (*tac)(g, result, mc, pc, core); // TBD: have this an attribute so we can cancel. + (*tac)(g, result, m_model_converter, pc, core); // TBD: have this an attribute so we can cancel. SASSERT(result.size() == 1); goal* r = result[0]; fmls.reset(); diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 2e19c3cb3..bc13795eb 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -29,6 +29,7 @@ Notes: #include "opt_solver.h" #include "optsmt.h" #include "maxsmt.h" +#include "model_converter.h" namespace opt { @@ -83,6 +84,7 @@ namespace opt { map_id m_indices; vector m_objectives; model_ref m_model; + model_converter_ref m_model_converter; obj_map m_objective_fns; public: context(ast_manager& m); diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 2f4a35459..fdf86c534 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -121,6 +121,7 @@ namespace opt { inf_eps v(r); if (m_lower[idx] < v) { m_lower[idx] = v; + s->get_model(m_model); } } @@ -261,6 +262,10 @@ namespace opt { return m_is_max[i]?m_upper[i]:-m_lower[i]; } + void optsmt::get_model(model_ref& mdl) { + mdl = m_model.get(); + } + // force lower_bound(i) <= objective_value(i) void optsmt::commit_assignment(unsigned i) { inf_eps mid(0); diff --git a/src/opt/optsmt.h b/src/opt/optsmt.h index c8be7a730..3379ee310 100644 --- a/src/opt/optsmt.h +++ b/src/opt/optsmt.h @@ -37,6 +37,7 @@ namespace opt { svector m_is_max; svector m_vars; symbol m_engine; + model_ref m_model; public: optsmt(ast_manager& m): m(m), s(0), m_cancel(false), m_objs(m) {} @@ -56,6 +57,7 @@ namespace opt { inf_eps get_value(unsigned index) const; inf_eps get_lower(unsigned index) const; inf_eps get_upper(unsigned index) const; + void get_model(model_ref& mdl); void update_lower(unsigned idx, rational const& r); diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 48c25e4d5..b03b8005a 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -35,6 +35,7 @@ namespace smt { rational m_min_cost; // current maximal cost assignment. u_map m_bool2var; // bool_var -> theory_var svector m_var2bool; // theory_var -> bool_var + model_ref m_model; public: theory_weighted_maxsat(ast_manager& m): theory(m.mk_family_id("weighted_maxsat")), @@ -186,6 +187,7 @@ namespace smt { m_bool2var.reset(); m_var2bool.reset(); m_min_cost_atom = 0; + m_model = 0; } virtual theory * mk_fresh(context * new_ctx) { return alloc(theory_weighted_maxsat, new_ctx->get_manager()); } @@ -194,6 +196,9 @@ namespace smt { virtual void new_eq_eh(theory_var v1, theory_var v2) { } virtual void new_diseq_eh(theory_var v1, theory_var v2) { } + void get_model(model_ref& mdl) { + mdl = m_model.get(); + } private: @@ -239,9 +244,11 @@ namespace smt { m_min_cost = weight; m_cost_save.reset(); m_cost_save.append(m_costs); + ctx.get_model(m_model); } return false; } + }; } @@ -284,6 +291,7 @@ namespace opt { expr_ref_vector m_assignment; vector m_weights; rational m_upper; + model_ref m_model; imp(ast_manager& m, opt_solver& s, expr_ref_vector& soft_constraints, vector const& weights): m(m), s(s), m_soft(soft_constraints), m_assignment(m), m_weights(weights) @@ -337,6 +345,7 @@ namespace opt { } } m_upper = wth.get_min_cost(); + wth.get_model(m_model); TRACE("opt", tout << "min cost: " << m_upper << "\n";); wth.reset(); return result; @@ -349,6 +358,11 @@ namespace opt { rational get_upper() const { return m_upper; } + + void get_model(model_ref& mdl) { + mdl = m_model.get(); + } + }; wmaxsmt::wmaxsmt(ast_manager& m, opt_solver& s, expr_ref_vector& soft_constraints, vector const& weights) { @@ -380,6 +394,9 @@ namespace opt { void wmaxsmt::collect_statistics(statistics& st) const { // no-op } + void wmaxsmt::get_model(model_ref& mdl) { + m_imp->get_model(mdl); + } diff --git a/src/opt/weighted_maxsat.h b/src/opt/weighted_maxsat.h index 3b00e1690..01793b949 100644 --- a/src/opt/weighted_maxsat.h +++ b/src/opt/weighted_maxsat.h @@ -40,6 +40,7 @@ namespace opt { virtual expr_ref_vector get_assignment() const; virtual void set_cancel(bool f); virtual void collect_statistics(statistics& st) const; + virtual void get_model(model_ref& mdl); }; }; diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index c6d86bdf8..944414267 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -348,13 +348,24 @@ namespace smt { context & ctx = get_context(); simplifier & s = ctx.get_simplifier(); expr_ref s_ante(m), s_conseq(m); + expr* s_conseq_n, * s_ante_n; + bool negated; proof_ref pr(m); + s(ante, s_ante, pr); + negated = m.is_not(s_ante, s_ante_n); + if (negated) s_ante = s_ante_n; ctx.internalize(s_ante, false); literal l_ante = ctx.get_literal(s_ante); + if (negated) l_ante.neg(); + s(conseq, s_conseq, pr); + negated = m.is_not(s_conseq, s_conseq_n); + if (negated) s_conseq = s_conseq_n; ctx.internalize(s_conseq, false); literal l_conseq = ctx.get_literal(s_conseq); + if (negated) l_conseq.neg(); + literal lits[2] = {l_ante, l_conseq}; ctx.mk_th_axiom(get_id(), 2, lits); if (ctx.relevancy()) { diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index e2ec2c48a..33cc4105e 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -38,9 +38,9 @@ namespace smt { } void theory_pb::ineq::reset() { - m_max_coeff.reset(); + m_max_watch.reset(); m_watch_sz = 0; - m_max_sum.reset(); + m_watch_sum.reset(); m_num_propagations = 0; m_compilation_threshold = UINT_MAX; m_compiled = l_false; @@ -341,10 +341,10 @@ namespace smt { // TBD: special cases: args.size() == 1 // maximal coefficient: - numeral& max_coeff = c->m_max_coeff; - max_coeff = numeral::zero(); + numeral& max_watch = c->m_max_watch; + max_watch = numeral::zero(); for (unsigned i = 0; i < args.size(); ++i) { - max_coeff = std::max(max_coeff, args[i].second); + max_watch = std::max(max_watch, args[i].second); } @@ -448,13 +448,13 @@ namespace smt { std::swap(c.m_args[ineq_index], c.m_args[c.watch_size()-1]); } --c.m_watch_sz; - c.m_max_sum -= coeff; - if (c.max_coeff() == coeff) { + c.m_watch_sum -= coeff; + if (c.max_watch() == coeff) { coeff = c.coeff(0); - for (unsigned i = 1; coeff != c.max_coeff() && i < c.m_watch_sz; ++i) { + for (unsigned i = 1; coeff != c.max_watch() && i < c.watch_size(); ++i) { if (coeff < c.coeff(i)) coeff = c.coeff(i); } - c.set_max_coeff(coeff); + c.set_max_watch(coeff); } // current index of unwatched literal is c.watch_size(). @@ -463,12 +463,18 @@ namespace smt { void theory_pb::add_watch(ineq& c, unsigned i) { literal lit = c.lit(i); bool_var v = lit.var(); - c.m_max_sum += c.coeff(i); + numeral coeff = c.coeff(i); + c.m_watch_sum += coeff; SASSERT(i >= c.watch_size()); + if (i > c.watch_size()) { std::swap(c.m_args[i], c.m_args[c.watch_size()]); } ++c.m_watch_sz; + if (coeff > c.max_watch()) { + c.set_max_watch(coeff); + } + ptr_vector* ineqs; if (!m_watch.find(lit.index(), ineqs)) { ineqs = alloc(ptr_vector); @@ -515,43 +521,6 @@ namespace smt { return FC_DONE; } - void theory_pb::validate_final_check() { - u_map::iterator itc = m_ineqs.begin(), endc = m_ineqs.end(); - for (; itc != endc; ++itc) { - validate_final_check(*itc->m_value); - } - } - - void theory_pb::validate_final_check(ineq& c) { - context& ctx = get_context(); - - if (ctx.get_assignment(c.lit()) == l_undef) { - return; - } - if (!ctx.is_relevant(c.lit())) { - return; - } - numeral sum = numeral::zero(), maxsum = numeral::zero(); - for (unsigned i = 0; i < c.size(); ++i) { - switch(ctx.get_assignment(c.lit(i))) { - case l_true: - sum += c.coeff(i); - case l_undef: - maxsum += c.coeff(i); - break; - } - } - TRACE("pb", display(tout << "validate: ", c, true); - tout << "sum: " << sum << " " << maxsum << " "; - tout << ctx.get_assignment(c.lit()) << "\n"; - ); - - SASSERT(sum <= maxsum); - SASSERT((sum >= c.k()) == (ctx.get_assignment(c.lit()) == l_true)); - SASSERT((maxsum < c.k()) == (ctx.get_assignment(c.lit()) == l_false)); - } - - void theory_pb::assign_eh(bool_var v, bool is_true) { context& ctx = get_context(); ptr_vector* ineqs = 0; @@ -636,15 +605,17 @@ namespace smt { add_clause(c, lits); } else { - c.m_max_sum = numeral::zero(); + c.m_watch_sum = numeral::zero(); c.m_watch_sz = 0; - for (unsigned i = 0; c.max_sum() < c.k() + c.max_coeff() && i < c.size(); ++i) { + c.m_max_watch = numeral::zero(); + for (unsigned i = 0; c.watch_sum() < c.k() + c.max_watch() && i < c.size(); ++i) { if (ctx.get_assignment(c.lit(i)) != l_false) { add_watch(c, i); } } - SASSERT(c.max_sum() >= c.k()); + SASSERT(c.watch_sum() >= c.k()); m_assign_ineqs_trail.push_back(&c); + DEBUG_CODE(validate_watch(c);); } // perform unit propagation @@ -653,7 +624,7 @@ namespace smt { lits.push_back(c.lit()); for (unsigned i = 0; i < c.size(); ++i) { if (ctx.get_assignment(c.lit(i)) == l_undef) { - SASSERT(validate_assign(c, lits, c.lit(i))); + DEBUG_CODE(validate_assign(c, lits, c.lit(i));); add_assign(c, lits, c.lit(i)); } } @@ -677,20 +648,20 @@ namespace smt { SASSERT(is_true == c.lit(w).sign()); // - // max_sum is decreased. + // watch_sum is decreased. // Adjust set of watched literals. // numeral k = c.k(); numeral coeff = c.coeff(w); - for (unsigned i = c.watch_size(); c.max_sum() - coeff < k + c.max_coeff() && i < c.size(); ++i) { + for (unsigned i = c.watch_size(); c.watch_sum() - coeff < k + c.max_watch() && i < c.size(); ++i) { if (ctx.get_assignment(c.lit(i)) != l_false) { add_watch(c, i); } } - if (c.max_sum() - coeff < k) { + if (c.watch_sum() - coeff < k) { // // L: 3*x1 + 2*x2 + x4 >= 3, but x1 <- 0, x2 <- 0 // create clause x1 or x2 or ~L @@ -702,12 +673,13 @@ namespace smt { else { del_watch(watch, watch_index, c, w); removed = true; - if (c.max_sum() < k + c.max_coeff()) { + SASSERT(c.watch_sum() >= k); + if (c.watch_sum() < k + c.max_watch()) { // // opportunities for unit propagation for unassigned // literals whose coefficients satisfy - // c.max_sum() < k + // c.watch_sum() < k // // L: 3*x1 + 2*x2 + x4 >= 3, but x1 <- 0 // Create clauses x1 or ~L or x2 @@ -717,18 +689,14 @@ namespace smt { literal_vector& lits = get_unhelpful_literals(c, true); lits.push_back(c.lit()); for (unsigned i = 0; i < c.size(); ++i) { - if (c.max_sum() - c.coeff(i) < k && ctx.get_assignment(c.lit(i)) == l_undef) { - SASSERT(validate_assign(c, lits, c.lit(i))); + if (c.watch_sum() - c.coeff(i) < k && ctx.get_assignment(c.lit(i)) == l_undef) { + DEBUG_CODE(validate_assign(c, lits, c.lit(i));); add_assign(c, lits, c.lit(i)); } } } // - // else: c.max_sum() >= k + c.max_coeff() - // we might miss opportunities for unit propagation if - // max_coeff is not the maximal coefficient - // of the current unassigned literal, but we can - // rely on eventually learning this from propagations. + // else: c.watch_sum() >= k + c.max_watch() // } @@ -875,12 +843,10 @@ namespace smt { void theory_pb::inc_propagations(ineq& c) { ++c.m_num_propagations; -#if 1 if (c.m_compiled == l_false && c.m_num_propagations > c.m_compilation_threshold) { c.m_compiled = l_undef; m_to_compile.push_back(&c); } -#endif } void theory_pb::restart_eh() { @@ -970,69 +936,6 @@ namespace smt { m_ineqs_lim.resize(new_lim); } - void theory_pb::display(std::ostream& out) const { - u_map*>::iterator it = m_watch.begin(), end = m_watch.end(); - for (; it != end; ++it) { - out << "watch: " << to_literal(it->m_key) << " |-> "; - watch_list const& wl = *it->m_value; - for (unsigned i = 0; i < wl.size(); ++i) { - out << wl[i]->lit() << " "; - } - out << "\n"; - } - u_map::iterator itc = m_ineqs.begin(), endc = m_ineqs.end(); - for (; itc != endc; ++itc) { - ineq& c = *itc->m_value; - display(out, c); - } - } - - std::ostream& theory_pb::display(std::ostream& out, ineq const& c, bool values) const { - ast_manager& m = get_manager(); - context& ctx = get_context(); - out << c.lit(); - if (c.lit() != null_literal) { - if (values) { - out << "@(" << ctx.get_assignment(c.lit()); - if (ctx.get_assignment(c.lit()) != l_undef) { - out << ":" << ctx.get_assign_level(c.lit()); - } - out << ")"; - } - expr_ref tmp(m); - ctx.literal2expr(c.lit(), tmp); - out << " " << tmp << "\n"; - } - else { - out << " "; - } - for (unsigned i = 0; i < c.size(); ++i) { - literal l(c.lit(i)); - if (!c.coeff(i).is_one()) { - out << c.coeff(i) << "*"; - } - out << l; - if (values) { - out << "@(" << ctx.get_assignment(l); - if (ctx.get_assignment(l) != l_undef) { - out << ":" << ctx.get_assign_level(l); - } - out << ")"; - } - if (i + 1 < c.size()) { - out << " + "; - } - } - out << " >= " << c.m_k << "\n"; - if (c.m_num_propagations) out << "propagations: " << c.m_num_propagations << " "; - if (c.max_coeff().is_pos()) out << "max_coeff: " << c.max_coeff() << " "; - if (c.watch_size()) out << "watch size: " << c.watch_size() << " "; - if (c.max_sum().is_pos()) out << "max-sum: " << c.max_sum() << " "; - if (c.m_num_propagations || c.max_coeff().is_pos() || c.watch_size() || c.max_sum().is_pos()) out << "\n"; - return out; - } - - literal_vector& theory_pb::get_lits() { m_literals.reset(); return m_literals; @@ -1087,34 +990,6 @@ namespace smt { verbose_stream() << "\n";); } - bool theory_pb::validate_assign(ineq const& c, literal_vector const& lits, literal l) const { - uint_set nlits; - context& ctx = get_context(); - for (unsigned i = 0; i < lits.size(); ++i) { - SASSERT(ctx.get_assignment(lits[i]) == l_false); - nlits.insert((~lits[i]).index()); - } - SASSERT(ctx.get_assignment(l) == l_undef); - SASSERT(ctx.get_assignment(c.lit()) == l_true); - nlits.insert(l.index()); - numeral sum = numeral::zero(); - for (unsigned i = 0; i < c.size(); ++i) { - literal lit = c.lit(i); - if (!nlits.contains(lit.index())) { - sum += c.coeff(i); - } - } - if (sum >= c.k()) { - IF_VERBOSE(0, - display(verbose_stream(), c, true); - for (unsigned i = 0; i < lits.size(); ++i) { - verbose_stream() << lits[i] << " "; - } - verbose_stream() << " => " << l << "\n";); - } - SASSERT(sum < c.k()); - return true; - } void theory_pb::set_mark(bool_var v, unsigned idx) { SASSERT(v != null_bool_var); @@ -1149,7 +1024,12 @@ namespace smt { } else if (lvl > ctx.get_base_level()) { if (is_marked(v)) { - m_lemma.m_args[m_conseq_index[v]].second += coeff; + numeral& lcoeff = m_lemma.m_args[m_conseq_index[v]].second; + lcoeff += coeff; + if (lcoeff.is_zero()) { + IF_VERBOSE(1, display(verbose_stream() << "remove 0 consequence", m_lemma, true);); + remove_from_lemma(m_lemma, m_conseq_index[v]); + } } else { if (lvl == m_conflict_lvl) { @@ -1243,10 +1123,9 @@ namespace smt { while (m_num_marks > 0) { - m_lemma.normalize(); lbool is_sat = m_lemma.normalize(); if (is_sat != l_undef) { - IF_VERBOSE(0, display(verbose_stream() << "created non-tautology lemma: ", m_lemma, true);); + IF_VERBOSE(0, display(verbose_stream() << "lemma already evaluated ", m_lemma, true);); return false; } TRACE("pb", display(tout, m_lemma, true);); @@ -1261,11 +1140,22 @@ namespace smt { --idx; } while (!is_marked(v) && idx > 0); - if (idx == 0) { - IF_VERBOSE(1, verbose_stream() << "BUG?!\n";); + if (idx == 0 && !is_marked(v)) { + // + // Yes, this can (currently) happen because + // the decisions for performing unit propagation + // are made asynchronously. + // In other words, PB unit propagation does not follow the + // same order as the assignment stack. + // It is not a correctness bug but causes to miss lemmas. + // + IF_VERBOSE(1, display_resolved_lemma(verbose_stream());); + for (unsigned i = 0; i < m_lemma.size(); ++i) { + unset_mark(m_lemma.lit(i)); + } return false; } - + unsigned conseq_index = m_conseq_index[v]; numeral conseq_coeff = m_lemma.coeff(conseq_index); @@ -1274,16 +1164,8 @@ namespace smt { SASSERT(~conseq == m_lemma.lit(conseq_index)); - // Remove conseq from lemma: - unsigned last = m_lemma.size()-1; - if (conseq_index != last) { - m_lemma.m_args[conseq_index] = m_lemma.m_args[last]; - m_conseq_index[m_lemma.lit(conseq_index).var()] = conseq_index; - } - m_lemma.m_args.pop_back(); - unset_mark(conseq); + remove_from_lemma(m_lemma, conseq_index); - --m_num_marks; b_justification js = ctx.get_justification(v); // @@ -1359,14 +1241,19 @@ namespace smt { lbool is_true = m_lemma.normalize(); - IF_VERBOSE(1, display(verbose_stream() << "lemma: ", m_lemma);); + IF_VERBOSE(2, display(verbose_stream() << "lemma: ", m_lemma);); switch(is_true) { case l_true: UNREACHABLE(); return false; - case l_false: - //add_assign(c, m_ineq_literals, false_literal); - //break; + case l_false: + inc_propagations(c); + m_stats.m_num_conflicts++; + for (unsigned i = 0; i < m_ineq_literals.size(); ++i) { + m_ineq_literals[i].neg(); + } + ctx.mk_clause(m_ineq_literals.size(), m_ineq_literals.c_ptr(), 0, CLS_AUX_LEMMA, 0); + break; default: { app_ref tmp = m_lemma.to_expr(ctx, get_manager()); internalize_atom(tmp, false); @@ -1389,4 +1276,204 @@ namespace smt { } } } + + void theory_pb::remove_from_lemma(ineq& c, unsigned idx) { + // Remove conseq from lemma: + literal lit = c.lit(idx); + unsigned last = c.size()-1; + if (idx != last) { + c.m_args[idx] = c.m_args[last]; + m_conseq_index[c.lit(idx).var()] = idx; + } + c.m_args.pop_back(); + unset_mark(lit); + --m_num_marks; + } + + + // debug methods + + void theory_pb::validate_watch(ineq const& c) const { + context& ctx = get_context(); + numeral sum = numeral::zero(); + numeral max = numeral::zero(); + for (unsigned i = 0; i < c.watch_size(); ++i) { + sum += c.coeff(i); + if (c.coeff(i) > max) { + max = c.coeff(i); + } + } + SASSERT(c.watch_sum() == sum); + SASSERT(sum >= c.k()); + SASSERT(max == c.max_watch()); + } + + void theory_pb::validate_assign(ineq const& c, literal_vector const& lits, literal l) const { + uint_set nlits; + context& ctx = get_context(); + for (unsigned i = 0; i < lits.size(); ++i) { + SASSERT(ctx.get_assignment(lits[i]) == l_true); + nlits.insert((~lits[i]).index()); + } + SASSERT(ctx.get_assignment(l) == l_undef); + SASSERT(ctx.get_assignment(c.lit()) == l_true); + nlits.insert(l.index()); + numeral sum = numeral::zero(); + for (unsigned i = 0; i < c.size(); ++i) { + literal lit = c.lit(i); + if (!nlits.contains(lit.index())) { + sum += c.coeff(i); + } + } + if (sum >= c.k()) { + IF_VERBOSE(0, + display(verbose_stream(), c, true); + for (unsigned i = 0; i < lits.size(); ++i) { + verbose_stream() << lits[i] << " "; + } + verbose_stream() << " => " << l << "\n";); + } + SASSERT(sum < c.k()); + } + + void theory_pb::validate_final_check() { + u_map::iterator itc = m_ineqs.begin(), endc = m_ineqs.end(); + for (; itc != endc; ++itc) { + validate_final_check(*itc->m_value); + } + } + + void theory_pb::validate_final_check(ineq& c) { + context& ctx = get_context(); + + if (ctx.get_assignment(c.lit()) == l_undef) { + return; + } + if (!ctx.is_relevant(c.lit())) { + return; + } + numeral sum = numeral::zero(), maxsum = numeral::zero(); + for (unsigned i = 0; i < c.size(); ++i) { + switch(ctx.get_assignment(c.lit(i))) { + case l_true: + sum += c.coeff(i); + case l_undef: + maxsum += c.coeff(i); + break; + } + } + TRACE("pb", display(tout << "validate: ", c, true); + tout << "sum: " << sum << " " << maxsum << " "; + tout << ctx.get_assignment(c.lit()) << "\n"; + ); + + SASSERT(sum <= maxsum); + SASSERT((sum >= c.k()) == (ctx.get_assignment(c.lit()) == l_true)); + SASSERT((maxsum < c.k()) == (ctx.get_assignment(c.lit()) == l_false)); + } + + // display methods + + void theory_pb::display_resolved_lemma(std::ostream& out) const { + context& ctx = get_context(); + literal_vector const& lits = ctx.assigned_literals(); + bool_var v; + unsigned lvl; + out << "num marks: " << m_num_marks << "\n"; + out << "conflict level: " << m_conflict_lvl << "\n"; + for (unsigned i = 0; i < lits.size(); ++i) { + v = lits[i].var(); + lvl = ctx.get_assign_level(v); + out << lits[i] + << "@ " << lvl + << " " << (is_marked(v)?"m":"u") + << "\n"; + + if (lvl == m_conflict_lvl && is_marked(v)) { + out << "skipped: " << lits[i] << ":"<< i << "\n"; + } + } + display(out, m_lemma, true); + + unsigned nc = 0; + for (unsigned i = 0; i < m_lemma.size(); ++i) { + v = m_lemma.lit(i).var(); + lvl = ctx.get_assign_level(v); + if (lvl == m_conflict_lvl) ++nc; + out << m_lemma.lit(i) + << "@" << lvl + << " " << (is_marked(v)?"m":"u") + << " " << ctx.get_assignment(m_lemma.lit(i)) + << "\n"; + } + out << "num conflicts: " << nc << "\n"; + } + + + std::ostream& theory_pb::display(std::ostream& out, ineq const& c, bool values) const { + ast_manager& m = get_manager(); + context& ctx = get_context(); + out << c.lit(); + if (c.lit() != null_literal) { + if (values) { + out << "@(" << ctx.get_assignment(c.lit()); + if (ctx.get_assignment(c.lit()) != l_undef) { + out << ":" << ctx.get_assign_level(c.lit()); + } + out << ")"; + } + expr_ref tmp(m); + ctx.literal2expr(c.lit(), tmp); + out << " " << tmp << "\n"; + } + else { + out << " "; + } + for (unsigned i = 0; i < c.size(); ++i) { + literal l(c.lit(i)); + if (!c.coeff(i).is_one()) { + out << c.coeff(i) << "*"; + } + out << l; + if (values) { + out << "@(" << ctx.get_assignment(l); + if (ctx.get_assignment(l) != l_undef) { + out << ":" << ctx.get_assign_level(l); + } + out << ")"; + } + if (i + 1 == c.watch_size()) { + out << " .w "; + } + if (i + 1 < c.size()) { + out << " + "; + } + } + out << " >= " << c.m_k << "\n"; + if (c.m_num_propagations) out << "propagations: " << c.m_num_propagations << " "; + if (c.max_watch().is_pos()) out << "max_watch: " << c.max_watch() << " "; + if (c.watch_size()) out << "watch size: " << c.watch_size() << " "; + if (c.watch_sum().is_pos()) out << "watch-sum: " << c.watch_sum() << " "; + if (c.m_num_propagations || c.max_watch().is_pos() || c.watch_size() || c.watch_sum().is_pos()) out << "\n"; + return out; + } + + void theory_pb::display(std::ostream& out) const { + u_map*>::iterator it = m_watch.begin(), end = m_watch.end(); + for (; it != end; ++it) { + out << "watch: " << to_literal(it->m_key) << " |-> "; + watch_list const& wl = *it->m_value; + for (unsigned i = 0; i < wl.size(); ++i) { + out << wl[i]->lit() << " "; + } + out << "\n"; + } + u_map::iterator itc = m_ineqs.begin(), endc = m_ineqs.end(); + for (; itc != endc; ++itc) { + ineq& c = *itc->m_value; + display(out, c); + } + } + + } diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index fc1a61186..34cd479a1 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -48,11 +48,11 @@ namespace smt { numeral m_k; // invariants: m_k > 0, coeffs[i] > 0 // Watch the first few positions until the sum satisfies: - // sum coeffs[i] >= m_lower + max_coeff + // sum coeffs[i] >= m_lower + max_watch - numeral m_max_coeff; // maximal coefficient. + numeral m_max_watch; // maximal coefficient. unsigned m_watch_sz; // number of literals being watched. - numeral m_max_sum; // maximal sum of watch literals. + numeral m_watch_sum; // maximal sum of watch literals. unsigned m_num_propagations; unsigned m_compilation_threshold; lbool m_compiled; @@ -69,9 +69,9 @@ namespace smt { unsigned size() const { return m_args.size(); } - numeral const& max_sum() const { return m_max_sum; } - numeral const& max_coeff() const { return m_max_coeff; } - void set_max_coeff(numeral const& n) { m_max_coeff = n; } + numeral const& watch_sum() const { return m_watch_sum; } + numeral const& max_watch() const { return m_max_watch; } + void set_max_watch(numeral const& n) { m_max_watch = n; } unsigned watch_size() const { return m_watch_sz; } @@ -118,6 +118,7 @@ namespace smt { std::ostream& display(std::ostream& out, ineq const& c, bool values = false) const; virtual void display(std::ostream& out) const; + void display_resolved_lemma(std::ostream& out) const; void add_clause(ineq& c, literal_vector const& lits); void add_assign(ineq& c, literal_vector const& lits, literal l); @@ -152,12 +153,14 @@ namespace smt { bool resolve_conflict(ineq& c); void process_antecedent(literal l, numeral coeff); void process_ineq(ineq& c, literal conseq, numeral coeff); + void remove_from_lemma(ineq& c, unsigned idx); void hoist_maximal_values(); void validate_final_check(); void validate_final_check(ineq& c); - bool validate_assign(ineq const& c, literal_vector const& lits, literal l) const; + void validate_assign(ineq const& c, literal_vector const& lits, literal l) const; + void validate_watch(ineq const& c) const; public: theory_pb(ast_manager& m); From 34c96a8fe0c10363eae2f015fcd3fd0b05bab037 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Tue, 10 Dec 2013 17:10:23 -0800 Subject: [PATCH 208/925] Simple guard in order to not get model before setting solver --- src/opt/optsmt.cpp | 28 ++++++++++++++-------------- src/opt/optsmt.h | 6 +++--- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index fdf86c534..012f8c0e4 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -66,11 +66,11 @@ namespace opt { Enumerate locally optimal assignments until fixedpoint. */ lbool optsmt::basic_opt() { - opt_solver::toggle_objective _t(*s, true); + opt_solver::toggle_objective _t(*m_s, true); lbool is_sat = l_true; while (is_sat == l_true && !m_cancel) { - is_sat = s->check_sat(0, 0); + is_sat = m_s->check_sat(0, 0); if (is_sat == l_true) { update_lower(); } @@ -92,13 +92,13 @@ namespace opt { Enumerate locally optimal assignments until fixedpoint. */ lbool optsmt::farkas_opt() { - smt::theory_opt& opt = s->get_optimizer(); + smt::theory_opt& opt = m_s->get_optimizer(); if (typeid(smt::theory_inf_arith) != typeid(opt)) { return l_undef; } - opt_solver::toggle_objective _t(*s, true); + opt_solver::toggle_objective _t(*m_s, true); lbool is_sat= l_true; while (is_sat == l_true && !m_cancel) { @@ -121,14 +121,14 @@ namespace opt { inf_eps v(r); if (m_lower[idx] < v) { m_lower[idx] = v; - s->get_model(m_model); + if (m_s) m_s->get_model(m_model); } } void optsmt::update_lower() { model_ref md; - s->get_model(md); - set_max(m_lower, s->get_objective_values()); + m_s->get_model(md); + set_max(m_lower, m_s->get_objective_values()); IF_VERBOSE(1, for (unsigned i = 0; i < m_lower.size(); ++i) { verbose_stream() << m_lower[i] << " "; @@ -141,21 +141,21 @@ namespace opt { for (unsigned i = 0; i < m_lower.size(); ++i) { inf_eps const& v = m_lower[i]; - disj.push_back(s->mk_gt(i, v)); + disj.push_back(m_s->mk_gt(i, v)); } constraint = m.mk_or(disj.size(), disj.c_ptr()); - s->assert_expr(constraint); + m_s->assert_expr(constraint); } lbool optsmt::update_upper() { - smt::theory_opt& opt = s->get_optimizer(); + smt::theory_opt& opt = m_s->get_optimizer(); SASSERT(typeid(smt::theory_inf_arith) == typeid(opt)); smt::theory_inf_arith& th = dynamic_cast(opt); expr_ref bound(m); expr_ref_vector bounds(m); - solver::scoped_push _push(*s); + solver::scoped_push _push(*m_s); // // NB: we have to create all bound expressions before calling check_sat @@ -181,7 +181,7 @@ namespace opt { for (unsigned i = 0; i < m_lower.size() && !m_cancel; ++i) { if (m_lower[i] <= mid[i] && mid[i] <= m_upper[i] && m_lower[i] < m_upper[i]) { th.enable_record_conflict(bounds[i].get()); - lbool is_sat = s->check_sat(1, bounds.c_ptr() + i); + lbool is_sat = m_s->check_sat(1, bounds.c_ptr() + i); switch(is_sat) { case l_true: IF_VERBOSE(2, verbose_stream() << "Setting lower bound for v" << m_vars[i] << " to " << m_upper[i] << "\n";); @@ -226,7 +226,7 @@ namespace opt { return l_true; } lbool is_sat = l_true; - s = &solver; + m_s = &solver; solver.reset_objectives(); m_vars.reset(); @@ -292,7 +292,7 @@ namespace opt { m_upper[i] = mid; TRACE("opt", tout << "set lower bound of "; display_objective(tout, i) << " to: " << mid << "\n"; tout << get_lower(i) << ":" << get_upper(i) << "\n";); - s->assert_expr(s->mk_ge(i, mid)); + m_s->assert_expr(m_s->mk_ge(i, mid)); } std::ostream& optsmt::display_objective(std::ostream& out, unsigned i) const { diff --git a/src/opt/optsmt.h b/src/opt/optsmt.h index 3379ee310..9571817f6 100644 --- a/src/opt/optsmt.h +++ b/src/opt/optsmt.h @@ -29,7 +29,7 @@ namespace opt { class optsmt { ast_manager& m; - opt_solver* s; + opt_solver* m_s; volatile bool m_cancel; vector m_lower; vector m_upper; @@ -39,9 +39,9 @@ namespace opt { symbol m_engine; model_ref m_model; public: - optsmt(ast_manager& m): m(m), s(0), m_cancel(false), m_objs(m) {} + optsmt(ast_manager& m): m(m), m_s(0), m_cancel(false), m_objs(m) {} - lbool operator()(opt_solver& s); + lbool operator()(opt_solver& solver); void add(app* t, bool is_max); From caba15d6b3a0cd697eacc1b2285fe697568e12ee Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Tue, 10 Dec 2013 17:15:51 -0800 Subject: [PATCH 209/925] Remove superfluouse indices to make .NET API thinner --- src/api/dotnet/Optimize.cs | 45 +++++--------------------------------- 1 file changed, 6 insertions(+), 39 deletions(-) diff --git a/src/api/dotnet/Optimize.cs b/src/api/dotnet/Optimize.cs index fb4af9206..e892ee70f 100644 --- a/src/api/dotnet/Optimize.cs +++ b/src/api/dotnet/Optimize.cs @@ -29,8 +29,6 @@ namespace Microsoft.Z3 [ContractVerification(true)] public class Optimize : Z3Object { - HashSet indices; - /// /// A string that describes all available optimize solver parameters. /// @@ -64,27 +62,6 @@ namespace Microsoft.Z3 get { return new ParamDescrs(Context, Native.Z3_optimize_get_param_descrs(Context.nCtx, NativeObject)); } } - /// - /// Get the number of objectives. - /// - public uint ObjectiveCount - { - get { return (uint)indices.Count; } - } - - /// - /// Get all indices of objectives. - /// - public uint[] Objectives - { - get - { - var objectives = new uint[indices.Count]; - indices.CopyTo(objectives, 0); - return objectives; - } - } - /// /// Assert a constraint (or multiple) into the optimize solver. /// @@ -118,9 +95,7 @@ namespace Microsoft.Z3 { Context.CheckContextMatch(constraint); Symbol s = Context.MkSymbol(group); - uint index = Native.Z3_optimize_assert_soft(Context.nCtx, NativeObject, constraint.NativeObject, weight.ToString(), s.NativeObject); - indices.Add(index); - return index; + return Native.Z3_optimize_assert_soft(Context.nCtx, NativeObject, constraint.NativeObject, weight.ToString(), s.NativeObject); } public Status Check() { @@ -157,31 +132,25 @@ namespace Microsoft.Z3 public uint MkMaximize(ArithExpr e) { - uint index = Native.Z3_optimize_maximize(Context.nCtx, NativeObject, e.NativeObject); - indices.Add(index); - return index; + return Native.Z3_optimize_maximize(Context.nCtx, NativeObject, e.NativeObject); } public uint MkMinimize(ArithExpr e) { - uint index = Native.Z3_optimize_minimize(Context.nCtx, NativeObject, e.NativeObject); - indices.Add(index); - return index; + return Native.Z3_optimize_minimize(Context.nCtx, NativeObject, e.NativeObject); } public ArithExpr GetLower(uint index) { - Contract.Requires(indices.Contains(index)); - return new ArithExpr(Context, Native.Z3_optimize_get_lower(Context.nCtx, NativeObject, index)); + return new ArithExpr(Context, Native.Z3_optimize_get_lower(Context.nCtx, NativeObject, index)); } public ArithExpr GetUpper(uint index) { - Contract.Requires(indices.Contains(index)); - return new ArithExpr(Context, Native.Z3_optimize_get_upper(Context.nCtx, NativeObject, index)); + return new ArithExpr(Context, Native.Z3_optimize_get_upper(Context.nCtx, NativeObject, index)); } - public override string ToString() + public override string ToString() { return Native.Z3_optimize_to_string(Context.nCtx, NativeObject); } @@ -191,13 +160,11 @@ namespace Microsoft.Z3 : base(ctx, obj) { Contract.Requires(ctx != null); - indices = new HashSet(); } internal Optimize(Context ctx) : base(ctx, Native.Z3_mk_optimize(ctx.nCtx)) { Contract.Requires(ctx != null); - indices = new HashSet(); } internal class DecRefQueue : IDecRefQueue From 1c0442ea313bf1639432b0b32bc050994d350e12 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Wed, 11 Dec 2013 11:49:40 -0800 Subject: [PATCH 210/925] Workaround for theory vars without unassigned atoms --- src/smt/theory_arith_aux.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 48b4a4583..ae69f48e2 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -1067,16 +1067,19 @@ namespace smt { */ template expr* theory_arith::mk_ge(theory_var v, inf_numeral const& val) { + SASSERT(m_objective_theory_vars.contains(v)); ast_manager& m = get_manager(); context& ctx = get_context(); std::ostringstream strm; strm << val << " <= v" << v; expr* b = m.mk_const(symbol(strm.str().c_str()), m.mk_bool_sort()); - if (!ctx.b_internalized(b)) { + // NB: For some reason, v has been internalized however it has no entry in m_unassigned_atoms + SASSERT(m_unassigned_atoms.size() == m_var_occs.size()); + if (!ctx.b_internalized(b) && ((unsigned)v < m_unassigned_atoms.size())) { bool_var bv = ctx.mk_bool_var(b); ctx.set_var_theory(bv, get_id()); // ctx.set_enode_flag(bv, true); - atom* a = alloc(atom, bv, v, val, A_LOWER); + atom* a = alloc(atom, bv, v, val, A_LOWER); m_unassigned_atoms[v]++; m_var_occs[v].push_back(a); m_atoms.push_back(a); From a737639790c1e1881575fdeefe04a1f2f557f711 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Wed, 11 Dec 2013 12:56:48 -0800 Subject: [PATCH 211/925] Skip lower bound assertions for unbounded objectives --- src/opt/optsmt.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 012f8c0e4..0eb9706e0 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -291,8 +291,10 @@ namespace opt { m_lower[i] = mid; m_upper[i] = mid; TRACE("opt", tout << "set lower bound of "; display_objective(tout, i) << " to: " << mid << "\n"; - tout << get_lower(i) << ":" << get_upper(i) << "\n";); - m_s->assert_expr(m_s->mk_ge(i, mid)); + tout << get_lower(i) << ":" << get_upper(i) << "\n";); + // Only assert bounds for bounded objectives + if (mid.get_infinity().is_zero()) + m_s->assert_expr(m_s->mk_ge(i, mid)); } std::ostream& optsmt::display_objective(std::ostream& out, unsigned i) const { From eacb48268c12b52aff28efba0325cbc6e8dc513b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 11 Dec 2013 19:02:36 -0600 Subject: [PATCH 212/925] fixing bugs exposed by msf unit tests Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 10 ++++++++-- src/opt/optsmt.cpp | 6 ++++-- src/smt/theory_arith_aux.h | 37 ++++++++++++++++++++++++++++--------- 3 files changed, 40 insertions(+), 13 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 6501ef51b..2db52795c 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -28,6 +28,7 @@ Notes: #include "lia2card_tactic.h" #include "elim01_tactic.h" #include "tactical.h" +#include "th_rewriter.h" namespace opt { @@ -64,9 +65,14 @@ namespace opt { } unsigned context::add_objective(app* t, bool is_max) { - app_ref tr(t, m); + expr_ref tr(t, m); + app_ref ar(m); + th_rewriter rewrite(m); + rewrite(tr); + SASSERT(is_app(tr)); + ar = to_app(tr); unsigned index = m_objectives.size(); - m_objectives.push_back(objective(is_max, tr, index)); + m_objectives.push_back(objective(is_max, ar, index)); return index; } diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 0eb9706e0..ec16d825d 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -230,8 +230,10 @@ namespace opt { solver.reset_objectives(); m_vars.reset(); - // First check_sat call to initialize theories - solver::scoped_push _push(solver); + { + // force base level + solver::scoped_push _push(solver); + } for (unsigned i = 0; i < m_objs.size(); ++i) { m_vars.push_back(solver.add_objective(m_objs[i].get())); diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index ae69f48e2..448086c6d 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -1045,25 +1045,44 @@ namespace smt { } /** - \brief: assert val < v + \brief: Create an atom that enforces the inequality v > val + The arithmetical expression encoding the inequality suffices + for the theory of aritmetic. */ template expr* theory_arith::mk_gt(theory_var v, inf_rational const& val) { ast_manager& m = get_manager(); expr* obj = get_enode(v)->get_owner(); expr_ref e(m); - e = m_util.mk_numeral(val.get_rational(), m.get_sort(obj)); - - if (val.get_infinitesimal().is_neg()) { + rational r = val.get_rational(); + if (m_util.is_int(m.get_sort(obj))) { + if (r.is_int()) { + r += rational::one(); + } + else { + r = ceil(r); + } + e = m_util.mk_numeral(r, m.get_sort(obj)); return m_util.mk_ge(obj, e); } else { - return m_util.mk_gt(obj, e); + // obj is over the reals. + e = m_util.mk_numeral(r, m.get_sort(obj)); + + if (val.get_infinitesimal().is_neg()) { + return m_util.mk_ge(obj, e); + } + else { + return m_util.mk_gt(obj, e); + } } } /** - \brief assert val <= v + \brief create atom that enforces: val <= v + The atom that enforces the inequality is created directly + as opposed to using arithmetical terms. + This allows to handle inequalities with non-standard numbers. */ template expr* theory_arith::mk_ge(theory_var v, inf_numeral const& val) { @@ -1071,11 +1090,11 @@ namespace smt { ast_manager& m = get_manager(); context& ctx = get_context(); std::ostringstream strm; + expr_ref b(m); strm << val << " <= v" << v; - expr* b = m.mk_const(symbol(strm.str().c_str()), m.mk_bool_sort()); - // NB: For some reason, v has been internalized however it has no entry in m_unassigned_atoms + b = m.mk_const(symbol(strm.str().c_str()), m.mk_bool_sort()); SASSERT(m_unassigned_atoms.size() == m_var_occs.size()); - if (!ctx.b_internalized(b) && ((unsigned)v < m_unassigned_atoms.size())) { + if (!ctx.b_internalized(b)) { bool_var bv = ctx.mk_bool_var(b); ctx.set_var_theory(bv, get_id()); // ctx.set_enode_flag(bv, true); From 56562a725d7591062df279626fdfe5b26797a43d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 11 Dec 2013 19:24:20 -0600 Subject: [PATCH 213/925] fixing bugs Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith_aux.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 448086c6d..26fb655a9 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -1090,10 +1090,8 @@ namespace smt { ast_manager& m = get_manager(); context& ctx = get_context(); std::ostringstream strm; - expr_ref b(m); strm << val << " <= v" << v; - b = m.mk_const(symbol(strm.str().c_str()), m.mk_bool_sort()); - SASSERT(m_unassigned_atoms.size() == m_var_occs.size()); + expr* b = m.mk_const(symbol(strm.str().c_str()), m.mk_bool_sort()); if (!ctx.b_internalized(b)) { bool_var bv = ctx.mk_bool_var(b); ctx.set_var_theory(bv, get_id()); From f41d23bc0fb8a1752bd1bcb32a52f5159b111109 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 12 Dec 2013 12:18:34 -0600 Subject: [PATCH 214/925] debugging model generation Signed-off-by: Nikolaj Bjorner --- src/opt/opt_cmds.cpp | 16 +++++++++++++++- src/opt/opt_context.cpp | 10 ++-------- src/opt/opt_params.pyg | 3 ++- src/opt/optsmt.cpp | 5 ++--- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index d4b28ab2f..5347fa1b2 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -29,6 +29,8 @@ Notes: #include "scoped_ctrl_c.h" #include "scoped_timer.h" #include "parametric_cmd.h" +#include "opt_params.hpp" +#include "model_smt2_pp.h" class opt_context { cmd_context& ctx; @@ -291,10 +293,22 @@ public: } } switch(r) { - case l_true: + case l_true: { ctx.regular_stream() << "sat\n"; opt.display_assignment(ctx.regular_stream()); + opt_params optp(p); + if (optp.print_model()) { + model_ref mdl; + opt.get_model(mdl); + if (mdl) { + ctx.regular_stream() << "(model " << std::endl; + model_smt2_pp(ctx.regular_stream(), ctx, *(mdl.get()), 2); + // m->display(ctx.regular_stream()); + ctx.regular_stream() << ")" << std::endl; + } + } break; + } case l_false: ctx.regular_stream() << "unsat\n"; break; diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 2db52795c..6501ef51b 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -28,7 +28,6 @@ Notes: #include "lia2card_tactic.h" #include "elim01_tactic.h" #include "tactical.h" -#include "th_rewriter.h" namespace opt { @@ -65,14 +64,9 @@ namespace opt { } unsigned context::add_objective(app* t, bool is_max) { - expr_ref tr(t, m); - app_ref ar(m); - th_rewriter rewrite(m); - rewrite(tr); - SASSERT(is_app(tr)); - ar = to_app(tr); + app_ref tr(t, m); unsigned index = m_objectives.size(); - m_objectives.push_back(objective(is_max, ar, index)); + m_objectives.push_back(objective(is_max, tr, index)); return index; } diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index 40ff00a89..868906858 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -3,9 +3,10 @@ def_module_params('opt', export=True, params=(('timeout', UINT, UINT_MAX, 'set timeout'), ('engine', SYMBOL, 'basic', "select optimization engine: 'basic', 'farkas', 'symba'"), - ('maxsat_engine', SYMBOL, 'fu_malik', "select engine for non-weighted maxsat: 'fu_malik', 'core_maxsat'"), + ('maxsat_engine', SYMBOL, 'fu_malik', "select engine for non-weighted maxsat: 'fu_malik', 'core_maxsat'"), ('priority', SYMBOL, 'lex', "select how to priortize objectives: 'lex' (lexicographic), 'pareto', or 'box'"), ('dump_benchmarks', BOOL, False, 'dump benchmarks for profiling'), + ('print_model', BOOL, False, 'display model for satisfiable constraints'), ('debug_conflict', BOOL, False, 'debug conflict resolution'), )) diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index ec16d825d..d870d5675 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -126,15 +126,14 @@ namespace opt { } void optsmt::update_lower() { - model_ref md; - m_s->get_model(md); + m_s->get_model(m_model); set_max(m_lower, m_s->get_objective_values()); IF_VERBOSE(1, for (unsigned i = 0; i < m_lower.size(); ++i) { verbose_stream() << m_lower[i] << " "; } verbose_stream() << "\n"; - model_pp(verbose_stream(), *md); + model_pp(verbose_stream(), *m_model); ); expr_ref_vector disj(m); expr_ref constraint(m); From df5c2adc4e79e32c47aabd1ccfb9cc674507d4f4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 12 Dec 2013 15:39:38 -0600 Subject: [PATCH 215/925] debug opt Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 3 ++- src/tactic/arith/elim01_tactic.cpp | 19 ++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 6501ef51b..6df46e783 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -92,7 +92,8 @@ namespace opt { case 1: return execute(m_objectives[0], false); default: { - symbol pri = m_params.get_sym("priority", symbol("lex")); + opt_params optp(m_params); + symbol pri = optp.priority(); if (pri == symbol("pareto")) { return execute_pareto(); } diff --git a/src/tactic/arith/elim01_tactic.cpp b/src/tactic/arith/elim01_tactic.cpp index de76b5e62..af427ccc5 100644 --- a/src/tactic/arith/elim01_tactic.cpp +++ b/src/tactic/arith/elim01_tactic.cpp @@ -23,6 +23,7 @@ Notes: #include"expr_safe_replace.h" // NB: should use proof-producing expr_substitute in polished version. #include"arith_decl_plugin.h" #include"elim01_tactic.h" +#include"model_smt2_pp.h" class bool2int_model_converter : public model_converter { ast_manager& m; @@ -63,15 +64,15 @@ public: else { new_model->register_decl(f, fi); } - num = old_model->get_num_functions(); - for (unsigned i = 0; i < num; i++) { - func_decl * f = old_model->get_function(i); - func_interp * fi = old_model->get_func_interp(f); - new_model->register_decl(f, fi->copy()); - } - new_model->copy_usort_interps(*old_model); - old_model = new_model; - } + } + num = old_model->get_num_functions(); + for (unsigned i = 0; i < num; i++) { + func_decl * f = old_model->get_function(i); + func_interp * fi = old_model->get_func_interp(f); + new_model->register_decl(f, fi->copy()); + } + new_model->copy_usort_interps(*old_model); + old_model = new_model; } void insert(func_decl* x_new, func_decl* x_old) { From 8c85ee6b7c83eded4b9f1f46975473d827dca9ac Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 13 Dec 2013 23:36:42 +0100 Subject: [PATCH 216/925] fixing lex optimization Signed-off-by: Nikolaj Bjorner --- src/opt/opt_cmds.cpp | 2 +- src/opt/opt_context.cpp | 107 ++++++++++++++++++++--------- src/opt/opt_context.h | 8 ++- src/opt/opt_solver.cpp | 50 +++++++------- src/opt/opt_solver.h | 15 ++--- src/opt/optsmt.cpp | 130 +++++++++++++++++++++--------------- src/opt/optsmt.h | 8 ++- src/smt/smt_context.cpp | 5 ++ src/smt/smt_context.h | 2 + src/smt/theory_arith.h | 2 +- src/smt/theory_arith_aux.h | 8 ++- src/smt/theory_opt.h | 3 +- src/util/inf_eps_rational.h | 4 ++ 13 files changed, 219 insertions(+), 125 deletions(-) diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index 5347fa1b2..88cfd20dd 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -314,7 +314,7 @@ public: break; case l_undef: ctx.regular_stream() << "unknown\n"; - opt.display_range_assignment(ctx.regular_stream()); + opt.display_assignment(ctx.regular_stream()); break; } if (p.get_bool("print_statistics", false)) { diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 6df46e783..8a70683fb 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -28,6 +28,7 @@ Notes: #include "lia2card_tactic.h" #include "elim01_tactic.h" #include "tactical.h" +#include "model_smt2_pp.h" namespace opt { @@ -85,12 +86,13 @@ namespace opt { return is_sat; } s.get_model(m_model); + m_optsmt.setup(s); update_lower(); switch (m_objectives.size()) { case 0: return is_sat; case 1: - return execute(m_objectives[0], false); + return execute(m_objectives[0], true); default: { opt_params optp(m_params); symbol pri = optp.priority(); @@ -111,19 +113,17 @@ namespace opt { mdl = m_model; if (m_model_converter) { (*m_model_converter)(mdl, 0); + get_solver().mc()(mdl, 0); } } - lbool context::execute_min_max(unsigned index, bool committed, bool is_max) { - // HACK: reuse m_optsmt without regard for box reuse and not considering - // use-case of lex. - lbool result = m_optsmt(get_solver()); + lbool context::execute_min_max(unsigned index, bool committed) { + lbool result = m_optsmt.lex(index); if (result == l_true) m_optsmt.get_model(m_model); if (committed) m_optsmt.commit_assignment(index); return result; } - lbool context::execute_maxsat(symbol const& id, bool committed) { maxsmt& ms = *m_maxsmts.find(id); lbool result = ms(get_solver()); @@ -134,8 +134,8 @@ namespace opt { lbool context::execute(objective const& obj, bool committed) { switch(obj.m_type) { - case O_MAXIMIZE: return execute_min_max(obj.m_index, committed, true); - case O_MINIMIZE: return execute_min_max(obj.m_index, committed, false); + case O_MAXIMIZE: return execute_min_max(obj.m_index, committed); + case O_MINIMIZE: return execute_min_max(obj.m_index, committed); case O_MAXSMT: return execute_maxsat(obj.m_id, committed); default: UNREACHABLE(); return l_undef; } @@ -145,16 +145,23 @@ namespace opt { lbool r = l_true; for (unsigned i = 0; r == l_true && i < m_objectives.size(); ++i) { r = execute(m_objectives[i], i + 1 < m_objectives.size()); + if (r == l_true && !get_lower_as_num(i).is_finite()) { + return r; + } } + DEBUG_CODE(if (r == l_true) validate_lex();); return r; } lbool context::execute_box() { - lbool r = l_true; + lbool r = m_optsmt.box(); for (unsigned i = 0; r == l_true && i < m_objectives.size(); ++i) { - get_solver().push(); - r = execute(m_objectives[i], false); - get_solver().pop(1); + objective const& obj = m_objectives[i]; + if (obj.m_type == O_MAXSMT) { + get_solver().push(); + r = execute(obj, false); + get_solver().pop(1); + } } return r; } @@ -244,7 +251,9 @@ namespace opt { terms[i] = m.mk_not(terms[i].get()); } } - id = symbol(index); + std::ostringstream out; + out << term; + id = symbol(out.str().c_str()); return true; } if (is_maximize(fml, term, index) && @@ -266,7 +275,9 @@ namespace opt { offset += weights[i]; } neg = true; - id = symbol(index); + std::ostringstream out; + out << term; + id = symbol(out.str().c_str()); return true; } return false; @@ -426,17 +437,15 @@ namespace opt { for (unsigned i = 0; i < m_objectives.size(); ++i) { objective const& obj = m_objectives[i]; display_objective(out, obj); - out << "|-> " << get_upper(i) << "\n"; + if (get_lower_as_num(i) != get_upper_as_num(i)) { + out << " |-> [" << get_lower(i) << ":" << get_upper(i) << "]\n"; + } + else { + out << "|-> " << get_lower(i) << "\n"; + } } } - void context::display_range_assignment(std::ostream& out) { - for (unsigned i = 0; i < m_objectives.size(); ++i) { - objective const& obj = m_objectives[i]; - display_objective(out, obj); - out << " |-> [" << get_lower(i) << ":" << get_upper(i) << "]\n"; - } - } void context::display_objective(std::ostream& out, objective const& obj) const { switch(obj.m_type) { @@ -453,8 +462,7 @@ namespace opt { } } - - expr_ref context::get_lower(unsigned idx) { + inf_eps context::get_lower_as_num(unsigned idx) { if (idx > m_objectives.size()) { throw default_exception("index out of bounds"); } @@ -464,18 +472,19 @@ namespace opt { rational r = m_maxsmts.find(obj.m_id)->get_lower(); if (obj.m_neg) r.neg(); r += obj.m_offset; - return to_expr(inf_eps(r)); + return inf_eps(r); } case O_MINIMIZE: case O_MAXIMIZE: - return to_expr(m_optsmt.get_lower(obj.m_index)); + return m_optsmt.get_lower(obj.m_index); default: UNREACHABLE(); - return expr_ref(m); - } + return inf_eps(); + } } - expr_ref context::get_upper(unsigned idx) { + + inf_eps context::get_upper_as_num(unsigned idx) { if (idx > m_objectives.size()) { throw default_exception("index out of bounds"); } @@ -485,17 +494,25 @@ namespace opt { rational r = m_maxsmts.find(obj.m_id)->get_upper(); if (obj.m_neg) r.neg(); r += obj.m_offset; - return to_expr(inf_eps(r)); + return inf_eps(r); } case O_MINIMIZE: case O_MAXIMIZE: - return to_expr(m_optsmt.get_upper(obj.m_index)); + return m_optsmt.get_upper(obj.m_index); default: UNREACHABLE(); - return expr_ref(m); + return inf_eps(); } } + expr_ref context::get_lower(unsigned idx) { + return to_expr(get_lower_as_num(idx)); + } + + expr_ref context::get_upper(unsigned idx) { + return to_expr(get_upper_as_num(idx)); + } + expr_ref context::to_expr(inf_eps const& n) { rational inf = n.get_infinity(); rational r = n.get_rational(); @@ -676,4 +693,30 @@ namespace opt { return out.str(); } + void context::validate_lex() { + arith_util a(m); + rational r1; + expr_ref val(m); + for (unsigned i = 0; i < m_objectives.size(); ++i) { + objective const& obj = m_objectives[i]; + switch(obj.m_type) { + case O_MINIMIZE: + case O_MAXIMIZE: { + inf_eps n = m_optsmt.get_lower(obj.m_index); + if (n.get_infinity().is_zero() && + n.get_infinitesimal().is_zero() && + m_model->eval(obj.m_term, val) && + a.is_numeral(val, r1)) { + rational r2 = n.get_rational(); + CTRACE("opt", r1 != r2, tout << obj.m_term << " evaluates to " << r1 << " but has objective " << r2 << "\n";); + CTRACE("opt", r1 != r2, model_smt2_pp(tout, m, *m_model, 0);); + SASSERT(r1 == r2); + } + break; + } + case O_MAXSMT: + break; + } + } + } } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index bc13795eb..50f69d59e 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -115,7 +115,7 @@ namespace opt { void validate_feasibility(maxsmt& ms); lbool execute(objective const& obj, bool committed); - lbool execute_min_max(unsigned index, bool committed, bool is_max); + lbool execute_min_max(unsigned index, bool committed); lbool execute_maxsat(symbol const& s, bool committed); lbool execute_lex(); lbool execute_box(); @@ -139,10 +139,16 @@ namespace opt { void update_lower(); + inf_eps get_lower_as_num(unsigned idx); + inf_eps get_upper_as_num(unsigned idx); + + opt_solver& get_solver(); void display_objective(std::ostream& out, objective const& obj) const; + void validate_lex(); + }; } diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 01d64b6cc..8ed4c863d 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -34,9 +34,9 @@ namespace opt { m_params(p), m_context(mgr, m_params), m(mgr), - m_objective_enabled(false), m_dump_benchmarks(false), - m_dump_count(0) { + m_dump_count(0), + m_fm(m) { m_logic = l; if (m_logic != symbol::null) m_context.set_logic(m_logic); @@ -71,7 +71,6 @@ namespace opt { m_context.pop(n); } - smt::theory_opt& opt_solver::get_optimizer() { smt::context& ctx = m_context.get_context(); smt::theory_id arith_id = m_context.m().get_family_id("arith"); @@ -118,21 +117,26 @@ namespace opt { to_smt2_benchmark(buffer, "opt_solver", "QF_BV"); buffer.close(); } - if (r == l_true && m_objective_enabled) { - m_objective_values.reset(); - smt::theory_opt& opt = get_optimizer(); - for (unsigned i = 0; i < m_objective_vars.size(); ++i) { - smt::theory_var v = m_objective_vars[i]; - m_objective_values.push_back(opt.maximize(v)); - } - } return r; } + + void opt_solver::maximize_objectives() { + for (unsigned i = 0; i < m_objective_vars.size(); ++i) { + maximize_objective(i); + } + } + + void opt_solver::maximize_objective(unsigned i) { + smt::theory_var v = m_objective_vars[i]; + m_objective_values[i] = get_optimizer().maximize(v); + m_context.get_context().update_model(); + } void opt_solver::get_unsat_core(ptr_vector & r) { unsigned sz = m_context.get_unsat_core_size(); - for (unsigned i = 0; i < sz; i++) + for (unsigned i = 0; i < sz; i++) { r.push_back(m_context.get_unsat_core_expr(i)); + } } void opt_solver::get_model(model_ref & m) { @@ -177,6 +181,7 @@ namespace opt { smt::theory_var opt_solver::add_objective(app* term) { m_objective_vars.push_back(get_optimizer().add_objective(term)); + m_objective_values.push_back(inf_eps(rational(-1), inf_rational())); return m_objective_vars.back(); } @@ -184,26 +189,30 @@ namespace opt { return m_objective_values; } + inf_eps const& opt_solver::get_objective_value(unsigned i) { + return m_objective_values[i]; + } + expr_ref opt_solver::mk_ge(unsigned var, inf_eps const& val) { smt::theory_opt& opt = get_optimizer(); smt::theory_var v = m_objective_vars[var]; if (typeid(smt::theory_inf_arith) == typeid(opt)) { smt::theory_inf_arith& th = dynamic_cast(opt); - return expr_ref(th.mk_ge(v, val), m); + return expr_ref(th.mk_ge(m_fm, v, val), m); } if (typeid(smt::theory_mi_arith) == typeid(opt)) { smt::theory_mi_arith& th = dynamic_cast(opt); - SASSERT(val.get_infinity().is_zero()); - return expr_ref(th.mk_ge(v, val.get_numeral()), m); + SASSERT(val.is_finite()); + return expr_ref(th.mk_ge(m_fm, v, val.get_numeral()), m); } if (typeid(smt::theory_i_arith) == typeid(opt)) { - SASSERT(val.get_infinity().is_zero()); + SASSERT(val.is_finite()); SASSERT(val.get_infinitesimal().is_zero()); smt::theory_i_arith& th = dynamic_cast(opt); - return expr_ref(th.mk_ge(v, val.get_rational()), m); + return expr_ref(th.mk_ge(m_fm, v, val.get_rational()), m); } // difference logic? @@ -251,12 +260,5 @@ namespace opt { pp.display_smt2(buffer, to_expr(m.mk_true())); } - opt_solver::toggle_objective::toggle_objective(opt_solver& s, bool new_value): s(s), m_old_value(s.m_objective_enabled) { - s.m_objective_enabled = new_value; - } - - opt_solver::toggle_objective::~toggle_objective() { - s.m_objective_enabled = m_old_value; - } } diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index d5fb58afe..844e276ba 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -30,6 +30,7 @@ Notes: #include"smt_params.h" #include"smt_types.h" #include"theory_opt.h" +#include"filter_model_converter.h" namespace opt { @@ -49,6 +50,7 @@ namespace opt { bool m_dump_benchmarks; unsigned m_dump_count; statistics m_stats; + filter_model_converter m_fm; public: opt_solver(ast_manager & m, params_ref const & p, symbol const & l); virtual ~opt_solver(); @@ -73,22 +75,19 @@ namespace opt { smt::theory_var add_objective(app* term); void reset_objectives(); + void maximize_objective(unsigned i); + void maximize_objectives(); vector const& get_objective_values(); + inf_eps const & get_objective_value(unsigned obj_index); expr_ref mk_gt(unsigned obj_index, inf_eps const& val); expr_ref mk_ge(unsigned obj_index, inf_eps const& val); + model_converter& mc() { return m_fm; } + static opt_solver& to_opt(solver& s); bool dump_benchmarks(); - class toggle_objective { - opt_solver& s; - bool m_old_value; - public: - toggle_objective(opt_solver& s, bool new_value); - ~toggle_objective(); - }; - smt::context& get_context() { return m_context.get_context(); } // used by weighted maxsat. smt::theory_opt& get_optimizer(); diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index d870d5675..3f8f1c939 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -66,7 +66,6 @@ namespace opt { Enumerate locally optimal assignments until fixedpoint. */ lbool optsmt::basic_opt() { - opt_solver::toggle_objective _t(*m_s, true); lbool is_sat = l_true; while (is_sat == l_true && !m_cancel) { @@ -98,8 +97,7 @@ namespace opt { return l_undef; } - opt_solver::toggle_objective _t(*m_s, true); - lbool is_sat= l_true; + lbool is_sat = l_true; while (is_sat == l_true && !m_cancel) { is_sat = update_upper(); @@ -126,6 +124,7 @@ namespace opt { } void optsmt::update_lower() { + m_s->maximize_objectives(); m_s->get_model(m_model); set_max(m_lower, m_s->get_objective_values()); IF_VERBOSE(1, @@ -150,7 +149,6 @@ namespace opt { smt::theory_opt& opt = m_s->get_optimizer(); SASSERT(typeid(smt::theory_inf_arith) == typeid(opt)); smt::theory_inf_arith& th = dynamic_cast(opt); - expr_ref bound(m); expr_ref_vector bounds(m); @@ -165,10 +163,9 @@ namespace opt { for (unsigned i = 0; i < m_lower.size() && !m_cancel; ++i) { if (m_lower[i] < m_upper[i]) { - smt::theory_var v = m_vars[i]; mid.push_back((m_upper[i]+m_lower[i])/rational(2)); //mid.push_back(m_upper[i]); - bound = th.mk_ge(v, mid[i]); + bound = m_s->mk_ge(i, mid[i]); bounds.push_back(bound); } else { @@ -190,7 +187,7 @@ namespace opt { break; case l_false: IF_VERBOSE(2, verbose_stream() << "conflict: " << th.conflict_minimize() << "\n";); - if (!th.conflict_minimize().get_infinity().is_zero()) { + if (!th.conflict_minimize().is_finite()) { // bounds is not in the core. The context is unsat. m_upper[i] = m_lower[i]; return l_false; @@ -216,28 +213,76 @@ namespace opt { return l_true; } - /** - Takes solver with hard constraints added. - Returns an optimal assignment to objective functions. - */ - lbool optsmt::operator()(opt_solver& solver) { - if (m_objs.empty()) { - return l_true; - } - lbool is_sat = l_true; + void optsmt::setup(opt_solver& solver) { m_s = &solver; solver.reset_objectives(); m_vars.reset(); + // force base level { - // force base level solver::scoped_push _push(solver); } for (unsigned i = 0; i < m_objs.size(); ++i) { m_vars.push_back(solver.add_objective(m_objs[i].get())); } + } + lbool optsmt::lex(unsigned obj_index) { + solver::scoped_push _push(*m_s); + SASSERT(obj_index < m_vars.size()); + return basic_lex(obj_index); + } + + lbool optsmt::basic_lex(unsigned obj_index) { + lbool is_sat = l_true; + expr_ref block(m); + + while (is_sat == l_true && !m_cancel) { + is_sat = m_s->check_sat(0, 0); + if (is_sat != l_true) break; + + m_s->maximize_objective(obj_index); + m_s->get_model(m_model); + inf_eps obj = m_s->get_objective_value(obj_index); + if (obj > m_lower[obj_index]) { + m_lower[obj_index] = obj; + for (unsigned i = obj_index+1; i < m_vars.size(); ++i) { + m_s->maximize_objective(i); + m_lower[i] = m_s->get_objective_value(i); + } + } + block = m_s->mk_gt(obj_index, obj); + m_s->assert_expr(block); + + // TBD: only works for simplex + // blocking formula should be extracted based + // on current state. + } + + if (m_cancel || is_sat == l_undef) { + return l_undef; + } + + // set the solution tight. + m_upper[obj_index] = m_lower[obj_index]; + for (unsigned i = obj_index+1; i < m_lower.size(); ++i) { + m_lower[i] = inf_eps(rational(-1), inf_rational(0)); + } + return l_true; + } + + /** + Takes solver with hard constraints added. + Returns an optimal assignment to objective functions. + */ + lbool optsmt::box() { + lbool is_sat = l_true; + if (m_vars.empty()) { + return is_sat; + } + // assertions added during search are temporary. + solver::scoped_push _push(*m_s); if (m_engine == symbol("farkas")) { is_sat = farkas_opt(); } @@ -252,15 +297,15 @@ namespace opt { } inf_eps optsmt::get_value(unsigned i) const { - return m_is_max[i]?m_lower[i]:-m_lower[i]; + return get_lower(i); } inf_eps optsmt::get_lower(unsigned i) const { - return m_is_max[i]?m_lower[i]:-m_upper[i]; + return m_is_max[i]?m_lower[i]:-m_lower[i]; } inf_eps optsmt::get_upper(unsigned i) const { - return m_is_max[i]?m_upper[i]:-m_lower[i]; + return m_is_max[i]?m_upper[i]:-m_upper[i]; } void optsmt::get_model(model_ref& mdl) { @@ -269,33 +314,13 @@ namespace opt { // force lower_bound(i) <= objective_value(i) void optsmt::commit_assignment(unsigned i) { - inf_eps mid(0); - - // TBD: case analysis should be revisited - rational hi = get_upper(i).get_infinity(); - rational lo = get_lower(i).get_infinity(); - if (hi.is_pos() && !lo.is_neg()) { - mid = get_lower(i); - } - else if (hi.is_pos() && lo.is_neg()) { - mid = inf_eps(0); - } - else if (hi.is_pos() && lo.is_pos()) { - mid = inf_eps(0); // TBD: get a value from a model? - } - else if (hi.is_neg() && lo.is_neg()) { - mid = inf_eps(0); // TBD: get a value from a model? - } - else { - mid = hi; - } - m_lower[i] = mid; - m_upper[i] = mid; - TRACE("opt", tout << "set lower bound of "; display_objective(tout, i) << " to: " << mid << "\n"; + inf_eps lo = m_lower[i]; + TRACE("opt", tout << "set lower bound of "; display_objective(tout, i) << " to: " << lo << "\n"; tout << get_lower(i) << ":" << get_upper(i) << "\n";); // Only assert bounds for bounded objectives - if (mid.get_infinity().is_zero()) - m_s->assert_expr(m_s->mk_ge(i, mid)); + if (lo.is_finite()) { + m_s->assert_expr(m_s->mk_ge(i, lo)); + } } std::ostream& optsmt::display_objective(std::ostream& out, unsigned i) const { @@ -314,14 +339,13 @@ namespace opt { void optsmt::display_assignment(std::ostream& out) const { unsigned sz = m_objs.size(); for (unsigned i = 0; i < sz; ++i) { - display_objective(out, i) << " |-> " << get_value(i) << std::endl; - } - } - - void optsmt::display_range_assignment(std::ostream& out) const { - unsigned sz = m_objs.size(); - for (unsigned i = 0; i < sz; ++i) { - display_objective(out, i) << " |-> [" << get_lower(i) << ":" << get_upper(i) << "]" << std::endl; + if (get_lower(i) != get_upper(i)) { + display_objective(out, i) << " |-> [" << get_lower(i) + << ":" << get_upper(i) << "]" << std::endl; + } + else { + display_objective(out, i) << " |-> " << get_value(i) << std::endl; + } } } diff --git a/src/opt/optsmt.h b/src/opt/optsmt.h index 9571817f6..c61599bb2 100644 --- a/src/opt/optsmt.h +++ b/src/opt/optsmt.h @@ -41,7 +41,11 @@ namespace opt { public: optsmt(ast_manager& m): m(m), m_s(0), m_cancel(false), m_objs(m) {} - lbool operator()(opt_solver& solver); + void setup(opt_solver& solver); + + lbool box(); + + lbool lex(unsigned obj_index); void add(app* t, bool is_max); @@ -67,6 +71,8 @@ namespace opt { lbool basic_opt(); + lbool basic_lex(unsigned idx); + lbool farkas_opt(); void set_max(vector& dst, vector const& src); diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 02ee06985..9599eaacb 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3937,6 +3937,11 @@ namespace smt { return th->get_value(n, value); } + void context::update_model() { + mk_proto_model(l_true); + m_model = m_proto_model->mk_model(); + } + void context::mk_proto_model(lbool r) { TRACE("get_model", display(tout); diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index aed164570..42af9738b 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1390,6 +1390,8 @@ namespace smt { void get_model(model_ref & m) const; + void update_model(); + void get_proto_model(proto_model_ref & m) const; unsigned get_num_asserted_formulas() const { return m_asserted_formulas.get_num_formulas(); } diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index f0211ca9d..8bc841ca0 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -1000,7 +1000,7 @@ namespace smt { virtual inf_eps_rational maximize(theory_var v); virtual theory_var add_objective(app* term); virtual expr* mk_gt(theory_var v, inf_rational const& val); - virtual expr* mk_ge(theory_var v, inf_numeral const& val); + virtual expr* mk_ge(filter_model_converter& fm, theory_var v, inf_numeral const& val); void enable_record_conflict(expr* bound); void record_conflict(unsigned num_lits, literal const * lits, unsigned num_eqs, enode_pair const * eqs, diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 26fb655a9..f9f98b867 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -23,6 +23,7 @@ Revision History: #include"theory_arith.h" #include"smt_farkas_util.h" #include"th_rewriter.h" +#include"filter_model_converter.h" namespace smt { @@ -1085,14 +1086,15 @@ namespace smt { This allows to handle inequalities with non-standard numbers. */ template - expr* theory_arith::mk_ge(theory_var v, inf_numeral const& val) { + expr* theory_arith::mk_ge(filter_model_converter& fm, theory_var v, inf_numeral const& val) { SASSERT(m_objective_theory_vars.contains(v)); ast_manager& m = get_manager(); context& ctx = get_context(); std::ostringstream strm; - strm << val << " <= v" << v; - expr* b = m.mk_const(symbol(strm.str().c_str()), m.mk_bool_sort()); + strm << val << " <= " << mk_pp(get_enode(v)->get_owner(), get_manager()); + app* b = m.mk_const(symbol(strm.str().c_str()), m.mk_bool_sort()); if (!ctx.b_internalized(b)) { + fm.insert(b->get_decl()); bool_var bv = ctx.mk_bool_var(b); ctx.set_var_theory(bv, get_id()); // ctx.set_enode_flag(bv, true); diff --git a/src/smt/theory_opt.h b/src/smt/theory_opt.h index 208330bfb..2d4d33e20 100644 --- a/src/smt/theory_opt.h +++ b/src/smt/theory_opt.h @@ -24,6 +24,7 @@ Notes: #ifndef _THEORY_OPT_H_ #define _THEORY_OPT_H_ +class filter_model_converter; namespace smt { class theory_opt { public: @@ -31,7 +32,7 @@ namespace smt { virtual inf_eps maximize(theory_var v) { UNREACHABLE(); return inf_eps::infinity(); } virtual theory_var add_objective(app* term) { UNREACHABLE(); return null_theory_var; } virtual expr* mk_gt(theory_var v, inf_rational const& val) { UNREACHABLE(); return 0; } - virtual expr* mk_ge(theory_var v, inf_eps const& val) { UNREACHABLE(); return 0; } + virtual expr* mk_ge(filter_model_converter& fm, theory_var v, inf_eps const& val) { UNREACHABLE(); return 0; } }; } diff --git a/src/util/inf_eps_rational.h b/src/util/inf_eps_rational.h index 9f40404ba..698075e01 100644 --- a/src/util/inf_eps_rational.h +++ b/src/util/inf_eps_rational.h @@ -143,6 +143,10 @@ class inf_eps_rational { return m_infty; } + bool is_finite() const { + return m_infty.is_zero(); + } + static inf_eps_rational zero() { return inf_eps_rational(Numeral::zero()); } From 5225ea18b7d911d5c0a57caa5dca53c645e1a770 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 14 Dec 2013 09:04:48 +0200 Subject: [PATCH 217/925] fix lower/upper bound updates Signed-off-by: Nikolaj Bjorner --- src/opt/fu_malik.cpp | 23 +++++++++++++---------- src/opt/opt_context.cpp | 6 ++---- src/opt/optsmt.cpp | 3 ++- src/opt/optsmt.h | 2 +- src/opt/weighted_maxsat.cpp | 6 +++++- 5 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index 13dc6e46d..7877ec7b0 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -43,28 +43,31 @@ namespace opt { struct fu_malik::imp { ast_manager& m; + solver & m_original_solver; + ref m_s; expr_ref_vector m_soft; expr_ref_vector m_orig_soft; expr_ref_vector m_aux; expr_ref_vector m_assignment; - unsigned m_upper_size; + unsigned m_upper; + unsigned m_lower; model_ref m_model; - ref m_s; - solver & m_original_solver; bool m_use_new_bv_solver; imp(ast_manager& m, solver& s, expr_ref_vector const& soft): m(m), + m_original_solver(s), m_s(&s), m_soft(soft), m_orig_soft(soft), m_aux(m), m_assignment(m), - m_original_solver(s), + m_upper(0), + m_lower(0), m_use_new_bv_solver(false) { - m_upper_size = m_soft.size() + 1; + m_upper = m_soft.size() + 1; } solver& s() { return *m_s; } @@ -156,7 +159,7 @@ namespace opt { } lbool step() { - IF_VERBOSE(1, verbose_stream() << "(opt.max_sat step " << m_soft.size() + 2 - m_upper_size << ")\n";); + IF_VERBOSE(1, verbose_stream() << "(opt.max_sat step " << m_soft.size() + 2 - m_upper << ")\n";); expr_ref_vector assumptions(m), block_vars(m); for (unsigned i = 0; i < m_soft.size(); ++i) { assumptions.push_back(m.mk_not(m_aux[i].get())); @@ -295,14 +298,14 @@ namespace opt { lbool is_sat = l_true; do { is_sat = step(); - --m_upper_size; + --m_upper; } while (is_sat == l_false); if (is_sat == l_true) { // Get a list of satisfying m_soft s().get_model(m_model); - + m_lower = m_upper; m_assignment.reset(); for (unsigned i = 0; i < m_orig_soft.size(); ++i) { expr_ref val(m); @@ -335,10 +338,10 @@ namespace opt { return (*m_imp)(); } rational fu_malik::get_lower() const { - return rational(0); + return rational(m_imp->m_lower); } rational fu_malik::get_upper() const { - return rational(m_imp->m_upper_size); + return rational(m_imp->m_upper); } rational fu_malik::get_value() const { return rational(m_imp->m_assignment.size()); diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 8a70683fb..453af018e 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -381,12 +381,10 @@ namespace opt { objective & obj = m_objectives[i]; switch(obj.m_type) { case O_MINIMIZE: - obj.m_index = m_optsmt.get_num_objectives(); - m_optsmt.add(obj.m_term, false); + obj.m_index = m_optsmt.add(obj.m_term, false); break; case O_MAXIMIZE: - obj.m_index = m_optsmt.get_num_objectives(); - m_optsmt.add(obj.m_term, true); + obj.m_index = m_optsmt.add(obj.m_term, true); break; case O_MAXSMT: { maxsmt& ms = *m_maxsmts.find(obj.m_id); diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 3f8f1c939..66d46f17c 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -349,7 +349,7 @@ namespace opt { } } - void optsmt::add(app* t, bool is_max) { + unsigned optsmt::add(app* t, bool is_max) { expr_ref t1(t, m), t2(m); th_rewriter rw(m); if (!is_max) { @@ -362,6 +362,7 @@ namespace opt { m_is_max.push_back(is_max); m_lower.push_back(inf_eps(rational(-1),inf_rational(0))); m_upper.push_back(inf_eps(rational(1), inf_rational(0))); + return m_objs.size()-1; } void optsmt::updt_params(params_ref& p) { diff --git a/src/opt/optsmt.h b/src/opt/optsmt.h index c61599bb2..0de1e0319 100644 --- a/src/opt/optsmt.h +++ b/src/opt/optsmt.h @@ -47,7 +47,7 @@ namespace opt { lbool lex(unsigned obj_index); - void add(app* t, bool is_max); + unsigned add(app* t, bool is_max); void set_cancel(bool f); diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index b03b8005a..97de77219 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -291,6 +291,7 @@ namespace opt { expr_ref_vector m_assignment; vector m_weights; rational m_upper; + rational m_lower; model_ref m_model; imp(ast_manager& m, opt_solver& s, expr_ref_vector& soft_constraints, vector const& weights): @@ -345,6 +346,9 @@ namespace opt { } } m_upper = wth.get_min_cost(); + if (result == l_true) { + m_lower = m_upper; + } wth.get_model(m_model); TRACE("opt", tout << "min cost: " << m_upper << "\n";); wth.reset(); @@ -352,7 +356,7 @@ namespace opt { } rational get_lower() const { - return rational(0); + return m_lower; } rational get_upper() const { From 04824d86dfc45988293ca551f01771b79fb5b589 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 14 Dec 2013 09:37:42 +0200 Subject: [PATCH 218/925] fixes to model generation of weighted maxsat Signed-off-by: Nikolaj Bjorner --- src/opt/fu_malik.cpp | 21 +++++++++++---------- src/opt/fu_malik.h | 4 ++-- src/opt/maxsmt.cpp | 2 +- src/opt/maxsmt.h | 5 ++--- src/opt/opt_context.cpp | 31 ++++++++++++++++++++----------- src/opt/opt_context.h | 6 ++++-- src/opt/opt_solver.h | 2 +- src/opt/weighted_maxsat.cpp | 12 ++++-------- 8 files changed, 45 insertions(+), 38 deletions(-) diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index 7877ec7b0..af700168f 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -43,7 +43,7 @@ namespace opt { struct fu_malik::imp { ast_manager& m; - solver & m_original_solver; + opt_solver & m_opt_solver; ref m_s; expr_ref_vector m_soft; expr_ref_vector m_orig_soft; @@ -55,9 +55,9 @@ namespace opt { bool m_use_new_bv_solver; - imp(ast_manager& m, solver& s, expr_ref_vector const& soft): + imp(ast_manager& m, opt_solver& s, expr_ref_vector const& soft): m(m), - m_original_solver(s), + m_opt_solver(s), m_s(&s), m_soft(soft), m_orig_soft(soft), @@ -98,7 +98,7 @@ namespace opt { } void collect_statistics(statistics& st) const { - if (m_s != &m_original_solver) { + if (m_s != &m_opt_solver) { m_s->collect_statistics(st); } } @@ -215,9 +215,11 @@ namespace opt { if (!found) { continue; } - expr_ref block_var(m), tmp(m); + app_ref block_var(m), tmp(m); block_var = m.mk_fresh_const("block_var", m.mk_bool_sort()); m_aux[i] = m.mk_fresh_const("aux", m.mk_bool_sort()); + m_opt_solver.mc().insert(block_var->get_decl()); + m_opt_solver.mc().insert(to_app(m_aux[i].get())->get_decl()); m_soft[i] = m.mk_or(m_soft[i].get(), block_var); block_vars.push_back(block_var); tmp = m.mk_or(m_soft[i].get(), m_aux[i].get()); @@ -253,8 +255,7 @@ namespace opt { } void set_solver() { - opt_solver & opt_s = opt_solver::to_opt(m_original_solver); - if (opt_s.dump_benchmarks()) + if (m_opt_solver.dump_benchmarks()) return; solver& current_solver = s(); @@ -268,11 +269,11 @@ namespace opt { probe_ref p = mk_is_qfbv_probe(); bool all_bv = (*p)(g).is_true(); if (all_bv) { - smt::context & ctx = opt_s.get_context(); + smt::context & ctx = m_opt_solver.get_context(); tactic_ref t = mk_qfbv_tactic(m, ctx.get_params()); // The new SAT solver hasn't supported unsat core yet m_s = mk_tactic2solver(m, t.get()); - SASSERT(m_s != &m_original_solver); + SASSERT(m_s != &m_opt_solver); for (unsigned i = 0; i < num_assertions; ++i) { m_s->assert_expr(current_solver.get_assertion(i)); } @@ -327,7 +328,7 @@ namespace opt { }; - fu_malik::fu_malik(ast_manager& m, solver& s, expr_ref_vector& soft_constraints) { + fu_malik::fu_malik(ast_manager& m, opt_solver& s, expr_ref_vector& soft_constraints) { m_imp = alloc(imp, m, s, soft_constraints); } fu_malik::~fu_malik() { diff --git a/src/opt/fu_malik.h b/src/opt/fu_malik.h index 2cd4e146d..df6c14a55 100644 --- a/src/opt/fu_malik.h +++ b/src/opt/fu_malik.h @@ -24,7 +24,7 @@ Notes: #ifndef _OPT_FU_MALIK_H_ #define _OPT_FU_MALIK_H_ -#include "solver.h" +#include "opt_solver.h" #include "maxsmt.h" namespace opt { @@ -33,7 +33,7 @@ namespace opt { struct imp; imp* m_imp; public: - fu_malik(ast_manager& m, solver& s, expr_ref_vector& soft_constraints); + fu_malik(ast_manager& m, opt_solver& s, expr_ref_vector& soft_constraints); virtual ~fu_malik(); virtual lbool operator()(); virtual rational get_lower() const; diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 1d1a65e5c..369b26782 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -26,7 +26,7 @@ Notes: namespace opt { - lbool maxsmt::operator()(solver& s) { + lbool maxsmt::operator()(opt_solver& s) { lbool is_sat; m_answer.reset(); m_msolver = 0; diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 92744baaf..b6d27f379 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -19,7 +19,6 @@ Notes: #ifndef _OPT_MAXSMT_H_ #define _OPT_MAXSMT_H_ -#include "solver.h" #include "opt_solver.h" #include "statistics.h" @@ -44,7 +43,7 @@ namespace opt { class maxsmt { ast_manager& m; - solver* m_s; + opt_solver* m_s; volatile bool m_cancel; expr_ref_vector m_soft_constraints; expr_ref_vector m_answer; @@ -57,7 +56,7 @@ namespace opt { public: maxsmt(ast_manager& m): m(m), m_s(0), m_cancel(false), m_soft_constraints(m), m_answer(m) {} - lbool operator()(solver& s); + lbool operator()(opt_solver& s); void set_cancel(bool f); diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 453af018e..be0e6010d 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -35,7 +35,8 @@ namespace opt { context::context(ast_manager& m): m(m), m_hard_constraints(m), - m_optsmt(m) + m_optsmt(m), + m_objective_refs(m) { m_params.set_bool("model", true); m_params.set_bool("unsat_core", true); @@ -119,16 +120,16 @@ namespace opt { lbool context::execute_min_max(unsigned index, bool committed) { lbool result = m_optsmt.lex(index); - if (result == l_true) m_optsmt.get_model(m_model); if (committed) m_optsmt.commit_assignment(index); + if (committed && result == l_true) m_optsmt.get_model(m_model); return result; } lbool context::execute_maxsat(symbol const& id, bool committed) { maxsmt& ms = *m_maxsmts.find(id); lbool result = ms(get_solver()); - if (result == l_true) ms.get_model(m_model); if (committed) ms.commit_assignment(); + if (committed && result == l_true) ms.get_model(m_model); return result; } @@ -202,19 +203,21 @@ namespace opt { } } - bool context::is_maximize(expr* fml, app_ref& term, unsigned& index) { + bool context::is_maximize(expr* fml, app_ref& term, expr*& orig_term, unsigned& index) { if (is_app(fml) && m_objective_fns.find(to_app(fml)->get_decl(), index) && m_objectives[index].m_type == O_MAXIMIZE) { term = to_app(to_app(fml)->get_arg(0)); + orig_term = m_objective_orig.find(to_app(fml)->get_decl()); return true; } return false; } - bool context::is_minimize(expr* fml, app_ref& term, unsigned& index) { + bool context::is_minimize(expr* fml, app_ref& term, expr*& orig_term, unsigned& index) { if (is_app(fml) && m_objective_fns.find(to_app(fml)->get_decl(), index) && m_objectives[index].m_type == O_MINIMIZE) { term = to_app(to_app(fml)->get_arg(0)); + orig_term = m_objective_orig.find(to_app(fml)->get_decl()); return true; } return false; @@ -233,8 +236,9 @@ namespace opt { return true; } app_ref term(m); + expr* orig_term; offset = rational::zero(); - if (is_minimize(fml, term, index) && + if (is_minimize(fml, term, orig_term, index) && get_pb_sum(term, terms, weights, offset)) { TRACE("opt", tout << "try to convert minimization" << mk_pp(term, m) << "\n";); // minimize 2*x + 3*y @@ -252,11 +256,11 @@ namespace opt { } } std::ostringstream out; - out << term; + out << mk_pp(orig_term, m); id = symbol(out.str().c_str()); return true; } - if (is_maximize(fml, term, index) && + if (is_maximize(fml, term, orig_term, index) && get_pb_sum(term, terms, weights, offset)) { TRACE("opt", tout << "try to convert maximization" << mk_pp(term, m) << "\n";); // maximize 2*x + 3*y - z @@ -276,7 +280,7 @@ namespace opt { } neg = true; std::ostringstream out; - out << term; + out << mk_pp(orig_term, m); id = symbol(out.str().c_str()); return true; } @@ -297,6 +301,10 @@ namespace opt { } func_decl* f = m.mk_fresh_func_decl(name,"", domain.size(), domain.c_ptr(), m.mk_bool_sort()); m_objective_fns.insert(f, index); + m_objective_refs.push_back(f); + if (sz > 0) { + m_objective_orig.insert(f, args[0]); + } return m.mk_app(f, sz, args); } @@ -317,6 +325,7 @@ namespace opt { void context::from_fmls(expr_ref_vector const& fmls) { m_hard_constraints.reset(); + expr* orig_term; for (unsigned i = 0; i < fmls.size(); ++i) { expr* fml = fmls[i]; app_ref tr(m); @@ -345,10 +354,10 @@ namespace opt { obj.m_neg = neg; TRACE("opt", tout << "maxsat: " << id << " offset:" << offset << "\n";); } - else if (is_maximize(fml, tr, index)) { + else if (is_maximize(fml, tr, orig_term, index)) { m_objectives[index].m_term = tr; } - else if (is_minimize(fml, tr, index)) { + else if (is_minimize(fml, tr, orig_term, index)) { m_objectives[index].m_term = tr; } else { diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 50f69d59e..ebf6eed0a 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -86,6 +86,8 @@ namespace opt { model_ref m_model; model_converter_ref m_model_converter; obj_map m_objective_fns; + obj_map m_objective_orig; + func_decl_ref_vector m_objective_refs; public: context(ast_manager& m); ~context(); @@ -124,8 +126,8 @@ namespace opt { void normalize(); void internalize(); - bool is_maximize(expr* fml, app_ref& term, unsigned& index); - bool is_minimize(expr* fml, app_ref& term, unsigned& index); + bool is_maximize(expr* fml, app_ref& term, expr*& orig_term, unsigned& index); + bool is_minimize(expr* fml, app_ref& term, expr*& orig_term, unsigned& index); bool is_maxsat(expr* fml, expr_ref_vector& terms, vector& weights, rational& offset, bool& neg, symbol& id, unsigned& index); diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 844e276ba..9d452193e 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -83,7 +83,7 @@ namespace opt { expr_ref mk_gt(unsigned obj_index, inf_eps const& val); expr_ref mk_ge(unsigned obj_index, inf_eps const& val); - model_converter& mc() { return m_fm; } + filter_model_converter& mc() { return m_fm; } static opt_solver& to_opt(solver& s); bool dump_benchmarks(); diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 97de77219..787625136 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -35,7 +35,6 @@ namespace smt { rational m_min_cost; // current maximal cost assignment. u_map m_bool2var; // bool_var -> theory_var svector m_var2bool; // theory_var -> bool_var - model_ref m_model; public: theory_weighted_maxsat(ast_manager& m): theory(m.mk_family_id("weighted_maxsat")), @@ -187,7 +186,6 @@ namespace smt { m_bool2var.reset(); m_var2bool.reset(); m_min_cost_atom = 0; - m_model = 0; } virtual theory * mk_fresh(context * new_ctx) { return alloc(theory_weighted_maxsat, new_ctx->get_manager()); } @@ -196,9 +194,6 @@ namespace smt { virtual void new_eq_eh(theory_var v1, theory_var v2) { } virtual void new_diseq_eh(theory_var v1, theory_var v2) { } - void get_model(model_ref& mdl) { - mdl = m_model.get(); - } private: @@ -244,7 +239,6 @@ namespace smt { m_min_cost = weight; m_cost_save.reset(); m_cost_save.append(m_costs); - ctx.get_model(m_model); } return false; } @@ -349,7 +343,6 @@ namespace opt { if (result == l_true) { m_lower = m_upper; } - wth.get_model(m_model); TRACE("opt", tout << "min cost: " << m_upper << "\n";); wth.reset(); return result; @@ -364,7 +357,10 @@ namespace opt { } void get_model(model_ref& mdl) { - mdl = m_model.get(); + lbool is_sat = s.check_sat_core(0,0); + if (is_sat == l_true) { + s.get_model(mdl); + } } }; From 5f72325e9945f7d00e23b89e65f43b0aa2096731 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 14 Dec 2013 10:00:21 +0200 Subject: [PATCH 219/925] working on maxsat Signed-off-by: Nikolaj Bjorner --- src/opt/fu_malik.cpp | 10 +++++++++- src/opt/opt_context.cpp | 15 ++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index af700168f..4c15aedf0 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -24,6 +24,7 @@ Notes: #include "probe.h" #include "tactic.h" #include "smt_context.h" +#include "ast_pp.h" /** \brief Fu & Malik procedure for MaxSAT. This procedure is based on @@ -290,8 +291,14 @@ namespace opt { if (!m_soft.empty() && is_sat == l_true) { solver::scoped_push _sp(s()); expr_ref tmp(m); + TRACE("opt", + tout << "soft constraints:\n"; + for (unsigned i = 0; i < m_soft.size(); ++i) { + tout << mk_pp(m_soft[i].get(), m) << "\n"; + }); for (unsigned i = 0; i < m_soft.size(); ++i) { m_aux.push_back(m.mk_fresh_const("p", m.mk_bool_sort())); + m_opt_solver.mc().insert(to_app(m_aux.back())->get_decl()); tmp = m.mk_or(m_soft[i].get(), m_aux[i].get()); s().assert_expr(tmp); } @@ -304,7 +311,7 @@ namespace opt { while (is_sat == l_false); if (is_sat == l_true) { - // Get a list of satisfying m_soft + // Get a list satisfying m_soft s().get_model(m_model); m_lower = m_upper; m_assignment.reset(); @@ -315,6 +322,7 @@ namespace opt { m_assignment.push_back(m_orig_soft[i].get()); } } + TRACE("opt", tout << "maxsat cost: " << m_upper << "\n";); } } // We are done and soft_constraints has diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index be0e6010d..ce9fedf96 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -255,6 +255,14 @@ namespace opt { terms[i] = m.mk_not(terms[i].get()); } } + TRACE("opt", + tout << "Convert minimization " << mk_pp(orig_term, m) << "\n"; + tout << "to maxsat: " << term << "\n"; + for (unsigned i = 0; i < weights.size(); ++i) { + tout << mk_pp(terms[i].get(), m) << ": " << weights[i] << "\n"; + } + tout << "offset: " << offset << "\n"; + ); std::ostringstream out; out << mk_pp(orig_term, m); id = symbol(out.str().c_str()); @@ -448,7 +456,7 @@ namespace opt { out << " |-> [" << get_lower(i) << ":" << get_upper(i) << "]\n"; } else { - out << "|-> " << get_lower(i) << "\n"; + out << " |-> " << get_lower(i) << "\n"; } } } @@ -459,12 +467,12 @@ namespace opt { case O_MAXSMT: { symbol s = obj.m_id; if (s != symbol::null) { - out << s << " : "; + out << s; } break; } default: - out << obj.m_term << " "; + out << obj.m_term; break; } } @@ -477,6 +485,7 @@ namespace opt { switch(obj.m_type) { case O_MAXSMT: { rational r = m_maxsmts.find(obj.m_id)->get_lower(); + TRACE("opt", tout << "maxsmt: " << r << " negate: " << obj.m_neg << " offset: " << obj.m_offset << "\n";); if (obj.m_neg) r.neg(); r += obj.m_offset; return inf_eps(r); From ac893e907f918bb52ab554538fe09826c3426e5e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 14 Dec 2013 16:06:03 +0200 Subject: [PATCH 220/925] fixes to maxsmt Signed-off-by: Nikolaj Bjorner --- src/opt/core_maxsat.cpp | 50 +++++++++++---------- src/opt/core_maxsat.h | 6 +-- src/opt/fu_malik.cpp | 87 ++++++++++++++++++------------------- src/opt/fu_malik.h | 3 +- src/opt/maxsmt.cpp | 41 ++++++++++------- src/opt/maxsmt.h | 5 +-- src/opt/opt_context.cpp | 10 ++++- src/opt/optsmt.cpp | 7 +-- src/opt/optsmt.h | 1 - src/opt/weighted_maxsat.cpp | 24 +++++----- src/opt/weighted_maxsat.h | 3 +- 11 files changed, 124 insertions(+), 113 deletions(-) diff --git a/src/opt/core_maxsat.cpp b/src/opt/core_maxsat.cpp index 1019465cd..9b4f284a5 100644 --- a/src/opt/core_maxsat.cpp +++ b/src/opt/core_maxsat.cpp @@ -21,11 +21,10 @@ Notes: #include "ast_pp.h" namespace opt { - core_maxsat::core_maxsat(ast_manager& m, solver& s, expr_ref_vector& soft_constraints): - m(m), s(s), m_soft(soft_constraints), m_answer(m) { - m_upper = m_soft.size(); + m(m), s(s), m_lower(0), m_upper(soft_constraints.size()), m_soft(soft_constraints) { + m_answer.resize(m_soft.size(), false); } core_maxsat::~core_maxsat() {} @@ -41,7 +40,7 @@ namespace opt { s.assert_expr(m.mk_or(a, m_soft[i].get())); block_vars.insert(aux.back()); } - while (m_answer.size() < m_upper) { + while (m_lower < m_upper) { ptr_vector vars; set2vector(block_vars, vars); lbool is_sat = s.check_sat(vars.size(), vars.c_ptr()); @@ -51,31 +50,31 @@ namespace opt { return l_undef; case l_true: { model_ref mdl; - expr_ref_vector ans(m); + svector ans; + unsigned new_lower = 0; s.get_model(mdl); - for (unsigned i = 0; i < aux.size(); ++i) { expr_ref val(m); VERIFY(mdl->eval(m_soft[i].get(), val)); - if (m.is_true(val)) { - ans.push_back(m_soft[i].get()); - } + ans.push_back(m.is_true(val)); + if (ans.back()) ++new_lower; } TRACE("opt", tout << "sat\n"; for (unsigned i = 0; i < ans.size(); ++i) { - tout << mk_pp(ans[i].get(), m) << "\n"; + tout << mk_pp(m_soft[i].get(), m) << " |-> " << ans[i] << "\n"; }); - IF_VERBOSE(1, verbose_stream() << "(maxsat.core sat with lower bound: " << ans.size() << "\n";); - if (ans.size() > m_answer.size()) { + IF_VERBOSE(1, verbose_stream() << "(maxsat.core sat with lower bound: " << new_lower << "\n";); + if (new_lower > m_lower) { m_answer.reset(); m_answer.append(ans); m_model = mdl.get(); + m_lower = new_lower; } - if (m_answer.size() == m_upper) { + if (m_lower == m_upper) { return l_true; } - SASSERT(m_soft.size() >= m_answer.size()+1); - unsigned k = m_soft.size()-m_answer.size()-1; + SASSERT(m_soft.size() >= new_lower+1); + unsigned k = m_soft.size()-new_lower-1; expr_ref fml = mk_at_most(core_vars, k); TRACE("opt", tout << "add: " << fml << "\n";); s.assert_expr(fml); @@ -95,7 +94,7 @@ namespace opt { } IF_VERBOSE(1, verbose_stream() << "(maxsat.core unsat (core size = " << core.size() << ")\n";); if (core.empty()) { - m_upper = m_answer.size(); + m_upper = m_lower; return l_true; } else { @@ -134,16 +133,13 @@ namespace opt { } rational core_maxsat::get_lower() const { - return rational(m_answer.size()); + return rational(m_soft.size()-m_upper); } rational core_maxsat::get_upper() const { - return rational(m_upper); + return rational(m_soft.size()-m_lower); } - rational core_maxsat::get_value() const { - return get_lower(); - } - expr_ref_vector core_maxsat::get_assignment() const { - return m_answer; + bool core_maxsat::get_assignment(unsigned idx) const { + return m_answer[idx]; } void core_maxsat::set_cancel(bool f) { @@ -153,6 +149,14 @@ namespace opt { } void core_maxsat::get_model(model_ref& mdl) { mdl = m_model.get(); + if (!mdl) { + SASSERT(m_upper == 0); + lbool is_sat = s.check_sat(0, 0); + if (is_sat == l_true) { + s.get_model(m_model); + } + mdl = m_model; + } } diff --git a/src/opt/core_maxsat.h b/src/opt/core_maxsat.h index cf4ce8d48..623868dc7 100644 --- a/src/opt/core_maxsat.h +++ b/src/opt/core_maxsat.h @@ -29,8 +29,9 @@ namespace opt { ast_manager& m; solver& s; expr_ref_vector m_soft; - expr_ref_vector m_answer; + svector m_answer; unsigned m_upper; + unsigned m_lower; model_ref m_model; public: core_maxsat(ast_manager& m, solver& s, expr_ref_vector& soft_constraints); @@ -38,8 +39,7 @@ namespace opt { virtual lbool operator()(); virtual rational get_lower() const; virtual rational get_upper() const; - virtual rational get_value() const; - virtual expr_ref_vector get_assignment() const; + virtual bool get_assignment(unsigned idx) const; virtual void set_cancel(bool f); virtual void collect_statistics(statistics& st) const; virtual void get_model(model_ref& mdl); diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index 4c15aedf0..4114ac080 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -49,7 +49,7 @@ namespace opt { expr_ref_vector m_soft; expr_ref_vector m_orig_soft; expr_ref_vector m_aux; - expr_ref_vector m_assignment; + svector m_assignment; unsigned m_upper; unsigned m_lower; model_ref m_model; @@ -63,12 +63,12 @@ namespace opt { m_soft(soft), m_orig_soft(soft), m_aux(m), - m_assignment(m), m_upper(0), m_lower(0), m_use_new_bv_solver(false) { m_upper = m_soft.size() + 1; + m_assignment.resize(m_soft.size(), false); } solver& s() { return *m_s; } @@ -286,44 +286,44 @@ namespace opt { // TBD: bug when cancel flag is set, fu_malik returns is_sat == l_true instead of l_undef lbool operator()() { + lbool is_sat = l_true; + if (m_soft.empty()) { + return is_sat; + } set_solver(); - lbool is_sat = s().check_sat(0,0); - if (!m_soft.empty() && is_sat == l_true) { - solver::scoped_push _sp(s()); - expr_ref tmp(m); - TRACE("opt", - tout << "soft constraints:\n"; - for (unsigned i = 0; i < m_soft.size(); ++i) { - tout << mk_pp(m_soft[i].get(), m) << "\n"; - }); - for (unsigned i = 0; i < m_soft.size(); ++i) { - m_aux.push_back(m.mk_fresh_const("p", m.mk_bool_sort())); - m_opt_solver.mc().insert(to_app(m_aux.back())->get_decl()); - tmp = m.mk_or(m_soft[i].get(), m_aux[i].get()); - s().assert_expr(tmp); - } - - lbool is_sat = l_true; - do { - is_sat = step(); - --m_upper; - } - while (is_sat == l_false); - - if (is_sat == l_true) { - // Get a list satisfying m_soft - s().get_model(m_model); - m_lower = m_upper; - m_assignment.reset(); - for (unsigned i = 0; i < m_orig_soft.size(); ++i) { - expr_ref val(m); - VERIFY(m_model->eval(m_orig_soft[i].get(), val)); - if (m.is_true(val)) { - m_assignment.push_back(m_orig_soft[i].get()); - } - } - TRACE("opt", tout << "maxsat cost: " << m_upper << "\n";); + solver::scoped_push _sp(s()); + expr_ref tmp(m); + + TRACE("opt", + tout << "soft constraints:\n"; + for (unsigned i = 0; i < m_soft.size(); ++i) { + tout << mk_pp(m_soft[i].get(), m) << "\n"; + }); + + for (unsigned i = 0; i < m_soft.size(); ++i) { + m_aux.push_back(m.mk_fresh_const("p", m.mk_bool_sort())); + m_opt_solver.mc().insert(to_app(m_aux.back())->get_decl()); + tmp = m.mk_or(m_soft[i].get(), m_aux[i].get()); + s().assert_expr(tmp); + } + + do { + is_sat = step(); + --m_upper; + } + while (is_sat == l_false); + + if (is_sat == l_true) { + // Get a list satisfying m_soft + s().get_model(m_model); + m_lower = m_upper; + m_assignment.reset(); + for (unsigned i = 0; i < m_orig_soft.size(); ++i) { + expr_ref val(m); + VERIFY(m_model->eval(m_orig_soft[i].get(), val)); + m_assignment.push_back(m.is_true(val)); } + TRACE("opt", tout << "maxsat cost: " << m_upper << "\n";); } // We are done and soft_constraints has // been updated with the max-sat assignment. @@ -347,16 +347,13 @@ namespace opt { return (*m_imp)(); } rational fu_malik::get_lower() const { - return rational(m_imp->m_lower); + return rational(m_imp->m_soft.size()-m_imp->m_upper); } rational fu_malik::get_upper() const { - return rational(m_imp->m_upper); + return rational(m_imp->m_soft.size()-m_imp->m_lower); } - rational fu_malik::get_value() const { - return rational(m_imp->m_assignment.size()); - } - expr_ref_vector fu_malik::get_assignment() const { - return m_imp->m_assignment; + bool fu_malik::get_assignment(unsigned idx) const { + return m_imp->m_assignment[idx]; } void fu_malik::set_cancel(bool f) { // no-op diff --git a/src/opt/fu_malik.h b/src/opt/fu_malik.h index df6c14a55..5dd0cbf50 100644 --- a/src/opt/fu_malik.h +++ b/src/opt/fu_malik.h @@ -38,8 +38,7 @@ namespace opt { virtual lbool operator()(); virtual rational get_lower() const; virtual rational get_upper() const; - virtual rational get_value() const; - virtual expr_ref_vector get_assignment() const; + virtual bool get_assignment(unsigned idx) const; virtual void set_cancel(bool f); virtual void collect_statistics(statistics& st) const; virtual void get_model(model_ref& m); diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 369b26782..0d459c44d 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -28,14 +28,12 @@ namespace opt { lbool maxsmt::operator()(opt_solver& s) { lbool is_sat; - m_answer.reset(); m_msolver = 0; m_s = &s; if (m_soft_constraints.empty()) { TRACE("opt", tout << "no constraints\n";); m_msolver = 0; is_sat = s.check_sat(0, 0); - m_answer.reset(); } else if (is_maxsat_problem(m_weights)) { if (m_maxsat_engine == symbol("core_maxsat")) { @@ -51,7 +49,6 @@ namespace opt { if (m_msolver) { is_sat = (*m_msolver)(); - m_answer.append(m_msolver->get_assignment()); if (is_sat == l_true) { m_msolver->get_model(m_model); } @@ -75,16 +72,14 @@ namespace opt { return is_sat; } - expr_ref_vector maxsmt::get_assignment() const { - return m_answer; - } - - rational maxsmt::get_value() const { + bool maxsmt::get_assignment(unsigned idx) const { if (m_msolver) { - return m_msolver->get_value(); + return m_msolver->get_assignment(idx); } - return m_upper; - } + else { + return true; + } + } rational maxsmt::get_lower() const { rational r = m_lower; @@ -114,15 +109,29 @@ namespace opt { void maxsmt::commit_assignment() { SASSERT(m_s); - for (unsigned i = 0; i < m_answer.size(); ++i) { - m_s->assert_expr(m_answer[i].get()); + for (unsigned i = 0; i < m_soft_constraints.size(); ++i) { + expr_ref tmp(m); + tmp = m_soft_constraints[i].get(); + if (get_assignment(i)) { + m_s->assert_expr(tmp); + } + else { + tmp = m.mk_not(tmp); + m_s->assert_expr(tmp); + } } } void maxsmt::display_answer(std::ostream& out) const { - for (unsigned i = 0; i < m_answer.size(); ++i) { - out << mk_pp(m_answer[i], m) << "\n"; - } + for (unsigned i = 0; i < m_soft_constraints.size(); ++i) { + out << mk_pp(m_soft_constraints[i], m); + if (get_assignment(i)) { + out << " |-> true\n"; + } + else { + out << " |-> false\n"; + } + } } void maxsmt::set_cancel(bool f) { diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index b6d27f379..4a2822367 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -30,8 +30,7 @@ namespace opt { virtual lbool operator()() = 0; virtual rational get_lower() const = 0; virtual rational get_upper() const = 0; - virtual rational get_value() const = 0; - virtual expr_ref_vector get_assignment() const = 0; + virtual bool get_assignment(unsigned index) const = 0; virtual void set_cancel(bool f) = 0; virtual void collect_statistics(statistics& st) const = 0; virtual void get_model(model_ref& mdl) = 0; @@ -80,7 +79,7 @@ namespace opt { rational get_upper() const; void update_lower(rational const& r); void get_model(model_ref& mdl); - expr_ref_vector get_assignment() const; + bool get_assignment(unsigned index) const; void display_answer(std::ostream& out) const; void collect_statistics(statistics& st) const; diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index ce9fedf96..749fa071d 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -54,6 +54,7 @@ namespace opt { maxsmt* ms; if (!m_maxsmts.find(id, ms)) { ms = alloc(maxsmt, m); + ms->updt_params(m_params); m_maxsmts.insert(id, ms); m_objectives.push_back(objective(m, id)); m_indices.insert(id, m_objectives.size() - 1); @@ -352,6 +353,7 @@ namespace opt { obj.m_weights.append(weights); SASSERT(!m_maxsmts.contains(id)); maxsmt* ms = alloc(maxsmt, m); + ms->updt_params(m_params); m_maxsmts.insert(id, ms); m_indices.insert(id, index); } @@ -730,8 +732,14 @@ namespace opt { } break; } - case O_MAXSMT: + case O_MAXSMT: { + maxsmt& ms = *m_maxsmts.find(obj.m_id); + for (unsigned i = 0; i < obj.m_terms.size(); ++i) { + VERIFY(m_model->eval(obj.m_terms[i], val)); + SASSERT(ms.get_assignment(i) == (m.mk_true() == val)); + } break; + } } } } diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 66d46f17c..97aec1e8c 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -296,9 +296,6 @@ namespace opt { return is_sat; } - inf_eps optsmt::get_value(unsigned i) const { - return get_lower(i); - } inf_eps optsmt::get_lower(unsigned i) const { return m_is_max[i]?m_lower[i]:-m_lower[i]; @@ -325,7 +322,7 @@ namespace opt { std::ostream& optsmt::display_objective(std::ostream& out, unsigned i) const { bool is_max = m_is_max[i]; - inf_eps val = get_value(i); + inf_eps val = get_lower(i); expr_ref obj(m_objs[i], m); if (!is_max) { arith_util a(m); @@ -344,7 +341,7 @@ namespace opt { << ":" << get_upper(i) << "]" << std::endl; } else { - display_objective(out, i) << " |-> " << get_value(i) << std::endl; + display_objective(out, i) << " |-> " << get_lower(i) << std::endl; } } } diff --git a/src/opt/optsmt.h b/src/opt/optsmt.h index 0de1e0319..1864e2a06 100644 --- a/src/opt/optsmt.h +++ b/src/opt/optsmt.h @@ -58,7 +58,6 @@ namespace opt { unsigned get_num_objectives() const { return m_objs.size(); } void commit_assignment(unsigned index); - inf_eps get_value(unsigned index) const; inf_eps get_lower(unsigned index) const; inf_eps get_upper(unsigned index) const; void get_model(model_ref& mdl); diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 787625136..99d9287a5 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -46,15 +46,16 @@ namespace smt { /** \brief return the complement of variables that are currently assigned. */ - void get_assignment(expr_ref_vector& result) { + void get_assignment(svector& result) { result.reset(); std::sort(m_cost_save.begin(), m_cost_save.end()); for (unsigned i = 0, j = 0; i < m_vars.size(); ++i) { if (j < m_cost_save.size() && m_cost_save[j] == i) { + result.push_back(false); ++j; } else { - result.push_back(m_fmls[i].get()); + result.push_back(true); } } } @@ -282,15 +283,17 @@ namespace opt { ast_manager& m; opt_solver& s; expr_ref_vector m_soft; - expr_ref_vector m_assignment; + svector m_assignment; vector m_weights; rational m_upper; rational m_lower; model_ref m_model; imp(ast_manager& m, opt_solver& s, expr_ref_vector& soft_constraints, vector const& weights): - m(m), s(s), m_soft(soft_constraints), m_assignment(m), m_weights(weights) - {} + m(m), s(s), m_soft(soft_constraints), m_weights(weights) + { + m_assignment.resize(m_soft.size(), false); + } ~imp() {} smt::theory_weighted_maxsat* get_theory() const { @@ -333,9 +336,9 @@ namespace opt { wth.assert_weighted(m_soft[i].get(), m_weights[i]); } result = s.check_sat_core(0,0); - + SASSERT(result != l_true); wth.get_assignment(m_assignment); - if (!m_assignment.empty() && result == l_false) { + if (result == l_false) { result = l_true; } } @@ -382,11 +385,8 @@ namespace opt { rational wmaxsmt::get_upper() const { return m_imp->get_upper(); } - rational wmaxsmt::get_value() const { - return m_imp->get_upper(); - } - expr_ref_vector wmaxsmt::get_assignment() const { - return m_imp->m_assignment; + bool wmaxsmt::get_assignment(unsigned idx) const { + return m_imp->m_assignment[idx]; } void wmaxsmt::set_cancel(bool f) { // no-op diff --git a/src/opt/weighted_maxsat.h b/src/opt/weighted_maxsat.h index 01793b949..deae79893 100644 --- a/src/opt/weighted_maxsat.h +++ b/src/opt/weighted_maxsat.h @@ -36,8 +36,7 @@ namespace opt { virtual lbool operator()(); virtual rational get_lower() const; virtual rational get_upper() const; - virtual rational get_value() const; - virtual expr_ref_vector get_assignment() const; + virtual bool get_assignment(unsigned idx) const; virtual void set_cancel(bool f); virtual void collect_statistics(statistics& st) const; virtual void get_model(model_ref& mdl); From 50f18a77af88b20083bf2116afd71cf6c850c626 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 15 Dec 2013 02:40:52 +0200 Subject: [PATCH 221/925] disable 'optimization' that led to wrong model' Signed-off-by: Nikolaj Bjorner --- src/ast/arith_decl_plugin.cpp | 1 + src/opt/fu_malik.cpp | 4 +++- src/opt/opt_context.cpp | 7 +++++-- src/opt/opt_solver.cpp | 2 ++ 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/ast/arith_decl_plugin.cpp b/src/ast/arith_decl_plugin.cpp index 9d1f4343f..5245b9685 100644 --- a/src/ast/arith_decl_plugin.cpp +++ b/src/ast/arith_decl_plugin.cpp @@ -417,6 +417,7 @@ inline decl_kind arith_decl_plugin::fix_kind(decl_kind k, unsigned arity) { app * arith_decl_plugin::mk_numeral(rational const & val, bool is_int) { if (is_int && !val.is_int()) { + SASSERT(false); m_manager->raise_exception("invalid rational value passed as an integer"); } if (val.is_unsigned()) { diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index 4114ac080..db6a017b2 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -25,6 +25,7 @@ Notes: #include "tactic.h" #include "smt_context.h" #include "ast_pp.h" +#include "model_smt2_pp.h" /** \brief Fu & Malik procedure for MaxSAT. This procedure is based on @@ -323,7 +324,8 @@ namespace opt { VERIFY(m_model->eval(m_orig_soft[i].get(), val)); m_assignment.push_back(m.is_true(val)); } - TRACE("opt", tout << "maxsat cost: " << m_upper << "\n";); + TRACE("opt", tout << "maxsat cost: " << m_upper << "\n"; + model_smt2_pp(tout, m, *m_model, 0);); } // We are done and soft_constraints has // been updated with the max-sat assignment. diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 749fa071d..48274c502 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -122,7 +122,7 @@ namespace opt { lbool context::execute_min_max(unsigned index, bool committed) { lbool result = m_optsmt.lex(index); if (committed) m_optsmt.commit_assignment(index); - if (committed && result == l_true) m_optsmt.get_model(m_model); + if (result == l_true) m_optsmt.get_model(m_model); return result; } @@ -130,7 +130,7 @@ namespace opt { maxsmt& ms = *m_maxsmts.find(id); lbool result = ms(get_solver()); if (committed) ms.commit_assignment(); - if (committed && result == l_true) ms.get_model(m_model); + if (result == l_true) ms.get_model(m_model); return result; } @@ -736,6 +736,9 @@ namespace opt { maxsmt& ms = *m_maxsmts.find(obj.m_id); for (unsigned i = 0; i < obj.m_terms.size(); ++i) { VERIFY(m_model->eval(obj.m_terms[i], val)); + CTRACE("opt",ms.get_assignment(i) != (m.mk_true() == val), + tout << mk_pp(obj.m_terms[i], m) << " evaluates to " << val << "\n"; + model_smt2_pp(tout, m, *m_model, 0);); SASSERT(ms.get_assignment(i) == (m.mk_true() == val)); } break; diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 8ed4c863d..4dbe08697 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -26,6 +26,7 @@ Notes: #include "ast_pp.h" #include "ast_smt_pp.h" #include "pp_params.hpp" +#include "model_smt2_pp.h" namespace opt { @@ -130,6 +131,7 @@ namespace opt { smt::theory_var v = m_objective_vars[i]; m_objective_values[i] = get_optimizer().maximize(v); m_context.get_context().update_model(); + TRACE("opt", { model_ref mdl; get_model(mdl); model_smt2_pp(tout << "update model: ", m, *mdl, 0); }); } void opt_solver::get_unsat_core(ptr_vector & r) { From fe5c42c90f0a3780f58498ef2e9d674e6c3a44e3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 15 Dec 2013 05:23:47 +0200 Subject: [PATCH 222/925] fixes to bugs exposed by regressions Signed-off-by: Nikolaj Bjorner --- src/ast/pb_decl_plugin.cpp | 26 +++--- src/ast/pb_decl_plugin.h | 18 ++-- src/ast/rewriter/pb_rewriter.cpp | 65 +++++++++++++++ src/ast/rewriter/pb_rewriter.h | 45 ++++++++++ src/ast/rewriter/th_rewriter.cpp | 5 ++ src/model/model_evaluator.cpp | 5 ++ src/opt/fu_malik.cpp | 1 + src/opt/maxsmt.cpp | 17 ++-- src/opt/opt_context.cpp | 4 +- src/opt/weighted_maxsat.cpp | 136 +++++++++++++++++++------------ src/smt/theory_pb.cpp | 84 +++++++++++++++++++ src/smt/theory_pb.h | 4 +- 12 files changed, 325 insertions(+), 85 deletions(-) create mode 100644 src/ast/rewriter/pb_rewriter.cpp create mode 100644 src/ast/rewriter/pb_rewriter.h diff --git a/src/ast/pb_decl_plugin.cpp b/src/ast/pb_decl_plugin.cpp index cb68b2c0b..89e2e1e51 100644 --- a/src/ast/pb_decl_plugin.cpp +++ b/src/ast/pb_decl_plugin.cpp @@ -118,8 +118,8 @@ app * pb_util::mk_at_most_k(unsigned num_args, expr * const * args, unsigned k) return m.mk_app(m_fid, OP_AT_MOST_K, 1, ¶m, num_args, args, m.mk_bool_sort()); } -bool pb_util::is_at_most_k(app *a) const { - return is_app_of(a, m_fid, OP_AT_MOST_K); +bool pb_util::is_at_most_k(func_decl *a) const { + return is_decl_of(a, m_fid, OP_AT_MOST_K); } bool pb_util::is_at_most_k(app *a, rational& k) const { @@ -138,8 +138,8 @@ app * pb_util::mk_at_least_k(unsigned num_args, expr * const * args, unsigned k) return m.mk_app(m_fid, OP_AT_LEAST_K, 1, ¶m, num_args, args, m.mk_bool_sort()); } -bool pb_util::is_at_least_k(app *a) const { - return is_app_of(a, m_fid, OP_AT_LEAST_K); +bool pb_util::is_at_least_k(func_decl *a) const { + return is_decl_of(a, m_fid, OP_AT_LEAST_K); } bool pb_util::is_at_least_k(app *a, rational& k) const { @@ -152,8 +152,8 @@ bool pb_util::is_at_least_k(app *a, rational& k) const { } } -rational pb_util::get_k(app *a) const { - parameter const& p = a->get_decl()->get_parameter(0); +rational pb_util::get_k(func_decl *a) const { + parameter const& p = a->get_parameter(0); if (is_at_most_k(a) || is_at_least_k(a)) { return to_rational(p); } @@ -164,8 +164,8 @@ rational pb_util::get_k(app *a) const { } -bool pb_util::is_le(app *a) const { - return is_app_of(a, m_fid, OP_PB_LE); +bool pb_util::is_le(func_decl *a) const { + return is_decl_of(a, m_fid, OP_PB_LE); } bool pb_util::is_le(app* a, rational& k) const { @@ -178,8 +178,8 @@ bool pb_util::is_le(app* a, rational& k) const { } } -bool pb_util::is_ge(app *a) const { - return is_app_of(a, m_fid, OP_PB_GE); +bool pb_util::is_ge(func_decl *a) const { + return is_decl_of(a, m_fid, OP_PB_GE); } bool pb_util::is_ge(app* a, rational& k) const { @@ -192,13 +192,13 @@ bool pb_util::is_ge(app* a, rational& k) const { } } -rational pb_util::get_coeff(app* a, unsigned index) { +rational pb_util::get_coeff(func_decl* a, unsigned index) const { if (is_at_most_k(a) || is_at_least_k(a)) { return rational::one(); } SASSERT(is_le(a) || is_ge(a)); - SASSERT(1 + index < a->get_decl()->get_num_parameters()); - return to_rational(a->get_decl()->get_parameter(index + 1)); + SASSERT(1 + index < a->get_num_parameters()); + return to_rational(a->get_parameter(index + 1)); } rational pb_util::to_rational(parameter const& p) const { diff --git a/src/ast/pb_decl_plugin.h b/src/ast/pb_decl_plugin.h index 103f74115..bc186433e 100644 --- a/src/ast/pb_decl_plugin.h +++ b/src/ast/pb_decl_plugin.h @@ -82,16 +82,22 @@ public: app * mk_at_least_k(unsigned num_args, expr * const * args, unsigned k); app * mk_le(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k); app * mk_ge(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k); - bool is_at_most_k(app *a) const; + bool is_at_most_k(func_decl *a) const; + bool is_at_most_k(app *a) const { return is_at_most_k(a->get_decl()); } bool is_at_most_k(app *a, rational& k) const; - bool is_at_least_k(app *a) const; + bool is_at_least_k(func_decl *a) const; + bool is_at_least_k(app *a) const { return is_at_most_k(a->get_decl()); } bool is_at_least_k(app *a, rational& k) const; - rational get_k(app *a) const; - bool is_le(app *a) const; + rational get_k(func_decl *a) const; + rational get_k(app *a) const { return get_k(a->get_decl()); } + bool is_le(func_decl *a) const; + bool is_le(app *a) const { return is_le(a->get_decl()); } bool is_le(app* a, rational& k) const; - bool is_ge(app* a) const; + bool is_ge(func_decl* a) const; + bool is_ge(app* a) const { return is_ge(a->get_decl()); } bool is_ge(app* a, rational& k) const; - rational get_coeff(app* a, unsigned index); + rational get_coeff(app* a, unsigned index) const { return get_coeff(a->get_decl(), index); } + rational get_coeff(func_decl* a, unsigned index) const; private: rational to_rational(parameter const& p) const; }; diff --git a/src/ast/rewriter/pb_rewriter.cpp b/src/ast/rewriter/pb_rewriter.cpp new file mode 100644 index 000000000..462944943 --- /dev/null +++ b/src/ast/rewriter/pb_rewriter.cpp @@ -0,0 +1,65 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + pb_rewriter.cpp + +Abstract: + + Basic rewriting rules for PB constraints. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-14-12 + +Notes: + +--*/ + +#include "pb_rewriter.h" + +br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { + ast_manager& m = result.get_manager(); + rational sum(0), maxsum(0); + for (unsigned i = 0; i < num_args; ++i) { + if (m.is_true(args[i])) { + sum += m_util.get_coeff(f, i); + maxsum += m_util.get_coeff(f, i); + } + else if (!m.is_false(args[i])) { + maxsum += m_util.get_coeff(f, i); + } + } + rational k = m_util.get_k(f); + + switch(f->get_decl_kind()) { + case OP_AT_MOST_K: + case OP_PB_LE: + if (sum > k) { + result = m.mk_false(); + return BR_DONE; + } + if (maxsum <= k) { + result = m.mk_true(); + return BR_DONE; + } + return BR_FAILED; + case OP_AT_LEAST_K: + case OP_PB_GE: + if (sum >= k) { + result = m.mk_true(); + return BR_DONE; + } + if (maxsum < k) { + result = m.mk_false(); + return BR_DONE; + } + return BR_FAILED; + default: + UNREACHABLE(); + return BR_FAILED; + } +} + + diff --git a/src/ast/rewriter/pb_rewriter.h b/src/ast/rewriter/pb_rewriter.h new file mode 100644 index 000000000..da020cb7c --- /dev/null +++ b/src/ast/rewriter/pb_rewriter.h @@ -0,0 +1,45 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + pb_rewriter.h + +Abstract: + + Basic rewriting rules for PB constraints. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-14-12 + +Notes: + +--*/ +#ifndef _PB_REWRITER_H_ +#define _PB_REWRITER_H_ + +#include"pb_decl_plugin.h" +#include"rewriter_types.h" +#include"params.h" + +/** + \brief Cheap rewrite rules for PB constraints +*/ +class pb_rewriter { + pb_util m_util; +public: + pb_rewriter(ast_manager & m, params_ref const & p = params_ref()): + m_util(m) { + } + ast_manager & m() const { return m_util.get_manager(); } + family_id get_fid() const { return m_util.get_family_id(); } + + void updt_params(params_ref const & p) {} + static void get_param_descrs(param_descrs & r) {} + + br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result); + +}; + +#endif diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index 5d19c53e3..83f88739e 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -25,6 +25,7 @@ Notes: #include"array_rewriter.h" #include"float_rewriter.h" #include"dl_rewriter.h" +#include"pb_rewriter.h" #include"rewriter_def.h" #include"expr_substitution.h" #include"ast_smt2_pp.h" @@ -41,6 +42,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg { datatype_rewriter m_dt_rw; float_rewriter m_f_rw; dl_rewriter m_dl_rw; + pb_rewriter m_pb_rw; arith_util m_a_util; bv_util m_bv_util; unsigned long long m_max_memory; // in bytes @@ -195,6 +197,8 @@ struct th_rewriter_cfg : public default_rewriter_cfg { return m_f_rw.mk_app_core(f, num, args, result); if (fid == m_dl_rw.get_fid()) return m_dl_rw.mk_app_core(f, num, args, result); + if (fid == m_pb_rw.get_fid()) + return m_pb_rw.mk_app_core(f, num, args, result); return BR_FAILED; } @@ -644,6 +648,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg { m_dt_rw(m), m_f_rw(m, p), m_dl_rw(m), + m_pb_rw(m), m_a_util(m), m_bv_util(m), m_used_dependencies(m), diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index 41bca940d..9bb17f730 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -23,6 +23,7 @@ Revision History: #include"bool_rewriter.h" #include"arith_rewriter.h" #include"bv_rewriter.h" +#include"pb_rewriter.h" #include"datatype_rewriter.h" #include"array_rewriter.h" #include"float_rewriter.h" @@ -36,6 +37,7 @@ struct evaluator_cfg : public default_rewriter_cfg { bv_rewriter m_bv_rw; array_rewriter m_ar_rw; datatype_rewriter m_dt_rw; + pb_rewriter m_pb_rw; float_rewriter m_f_rw; unsigned long long m_max_memory; unsigned m_max_steps; @@ -52,6 +54,7 @@ struct evaluator_cfg : public default_rewriter_cfg { // See comment above. We want to allow customers to set :sort-store m_ar_rw(m, p), m_dt_rw(m), + m_pb_rw(m), m_f_rw(m) { m_b_rw.set_flat(false); m_a_rw.set_flat(false); @@ -153,6 +156,8 @@ struct evaluator_cfg : public default_rewriter_cfg { return m_ar_rw.mk_app_core(f, num, args, result); if (fid == m_dt_rw.get_fid()) return m_dt_rw.mk_app_core(f, num, args, result); + if (fid == m_pb_rw.get_fid()) + return m_pb_rw.mk_app_core(f, num, args, result); if (fid == m_f_rw.get_fid()) return m_f_rw.mk_app_core(f, num, args, result); return BR_FAILED; diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index db6a017b2..3769bdd73 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -322,6 +322,7 @@ namespace opt { for (unsigned i = 0; i < m_orig_soft.size(); ++i) { expr_ref val(m); VERIFY(m_model->eval(m_orig_soft[i].get(), val)); + TRACE("opt", tout << val << "\n";); m_assignment.push_back(m.is_true(val)); } TRACE("opt", tout << "maxsat cost: " << m_upper << "\n"; diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 0d459c44d..3b0f684e8 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -112,25 +112,18 @@ namespace opt { for (unsigned i = 0; i < m_soft_constraints.size(); ++i) { expr_ref tmp(m); tmp = m_soft_constraints[i].get(); - if (get_assignment(i)) { - m_s->assert_expr(tmp); - } - else { + if (!get_assignment(i)) { tmp = m.mk_not(tmp); - m_s->assert_expr(tmp); } + TRACE("opt", tout << "asserting: " << tmp << "\n";); + m_s->assert_expr(tmp); } } void maxsmt::display_answer(std::ostream& out) const { for (unsigned i = 0; i < m_soft_constraints.size(); ++i) { - out << mk_pp(m_soft_constraints[i], m); - if (get_assignment(i)) { - out << " |-> true\n"; - } - else { - out << " |-> false\n"; - } + out << mk_pp(m_soft_constraints[i], m) + << (get_assignment(i)?" |-> true\n":" |-> false\n"); } } diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 48274c502..26ce2152b 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -121,7 +121,7 @@ namespace opt { lbool context::execute_min_max(unsigned index, bool committed) { lbool result = m_optsmt.lex(index); - if (committed) m_optsmt.commit_assignment(index); + if (result == l_true && committed) m_optsmt.commit_assignment(index); if (result == l_true) m_optsmt.get_model(m_model); return result; } @@ -129,7 +129,7 @@ namespace opt { lbool context::execute_maxsat(symbol const& id, bool committed) { maxsmt& ms = *m_maxsmts.find(id); lbool result = ms(get_solver()); - if (committed) ms.commit_assignment(); + if (result == l_true && committed) ms.commit_assignment(); if (result == l_true) ms.get_model(m_model); return result; } diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 99d9287a5..45eab4d76 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -48,6 +48,7 @@ namespace smt { */ void get_assignment(svector& result) { result.reset(); + std::sort(m_cost_save.begin(), m_cost_save.end()); for (unsigned i = 0, j = 0; i < m_vars.size(); ++i) { if (j < m_cost_save.size() && m_cost_save[j] == i) { @@ -58,43 +59,58 @@ namespace smt { result.push_back(true); } } + TRACE("opt", + tout << "cost save: "; + for (unsigned i = 0; i < m_cost_save.size(); ++i) { + tout << m_cost_save[i] << " "; + } + tout << "\nvars: "; + for (unsigned i = 0; i < m_vars.size(); ++i) { + tout << mk_pp(m_vars[i].get(), get_manager()) << " "; + } + tout << "\nassignment"; + for (unsigned i = 0; i < result.size(); ++i) { + tout << result[i] << " "; + } + tout << "\n";); + } virtual void init_search_eh() { context & ctx = get_context(); ast_manager& m = get_manager(); - m_var2bool.reset(); - for (unsigned i = 0; i < m_vars.size(); ++i) { + bool initialized = !m_var2bool.empty(); + + for (unsigned i = 0; !initialized && i < m_vars.size(); ++i) { app* var = m_vars[i].get(); bool_var bv; - enode* x; - if (!ctx.e_internalized(var)) { - x = ctx.mk_enode(var, false, true, true); - } - else { - x = ctx.get_enode(var); - } + theory_var v; + SASSERT(!ctx.e_internalized(var)); + enode* x = ctx.mk_enode(var, false, true, true); if (ctx.b_internalized(var)) { bv = ctx.get_bool_var(var); } else { bv = ctx.mk_bool_var(var); } - ctx.set_var_theory(bv, get_id()); + ctx.set_var_theory(bv, get_id()); ctx.set_enode_flag(bv, true); - theory_var v = mk_var(x); + v = mk_var(x); ctx.attach_th_var(x, this, v); m_bool2var.insert(bv, v); SASSERT(v == m_var2bool.size()); m_var2bool.push_back(bv); SASSERT(ctx.bool_var2enode(bv)); - + } + for (unsigned i = 0; i < m_vars.size(); ++i) { + app* var = m_vars[i].get(); + bool_var bv = ctx.get_bool_var(var); lbool asgn = ctx.get_assignment(bv); if (asgn == l_true) { assign_eh(bv, true); } - } + if (m_min_cost_atom) { app* var = m_min_cost_atom; if (!ctx.e_internalized(var)) { @@ -157,10 +173,7 @@ namespace smt { } virtual final_check_status final_check_eh() { - if (block(true)) { - return FC_DONE; - } - return FC_CONTINUE; + return FC_DONE; } virtual bool use_diseqs() const { @@ -171,7 +184,7 @@ namespace smt { return false; } - void reset() { + void reset() { reset_eh(); } @@ -195,17 +208,9 @@ namespace smt { virtual void new_eq_eh(theory_var v1, theory_var v2) { } virtual void new_diseq_eh(theory_var v1, theory_var v2) { } - - private: - - class compare_cost { - theory_weighted_maxsat& m_th; - public: - compare_cost(theory_weighted_maxsat& t):m_th(t) {} - bool operator() (theory_var v, theory_var w) const { - return m_th.m_weights[v] > m_th.m_weights[w]; - } - }; + bool is_optimal() const { + return m_cost < m_min_cost; + } bool block(bool is_final) { if (m_vars.empty()) { @@ -225,18 +230,27 @@ namespace smt { if (m_min_cost_atom) { lits.push_back(~literal(m_min_cost_bv)); } - IF_VERBOSE(2, - verbose_stream() << "block: "; - for (unsigned i = 0; i < lits.size(); ++i) { - expr_ref tmp(m); - ctx.literal2expr(lits[i], tmp); - verbose_stream() << tmp << " "; - } - verbose_stream() << "\n"; - ); + TRACE("opt", + tout << "block" << (is_final?" final: ":": ");; + for (unsigned i = 0; i < lits.size(); ++i) { + expr_ref tmp(m); + ctx.literal2expr(lits[i], tmp); + tout << tmp << " "; + } + tout << "\n"; + if (is_final && is_optimal()) { + tout << "costs: "; + for (unsigned i = 0; i < m_costs.size(); ++i) { + tout << mk_pp(get_enode(m_costs[i])->get_owner(), get_manager()) << " "; + } + tout << "\n"; + ctx.display(tout); + + } + ); ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); - if (is_final && m_cost < m_min_cost) { + if (is_final && is_optimal()) { m_min_cost = weight; m_cost_save.reset(); m_cost_save.append(m_costs); @@ -244,6 +258,19 @@ namespace smt { return false; } + + private: + + class compare_cost { + theory_weighted_maxsat& m_th; + public: + compare_cost(theory_weighted_maxsat& t):m_th(t) {} + bool operator() (theory_var v, theory_var w) const { + return m_th.m_weights[v] > m_th.m_weights[w]; + } + }; + + }; } @@ -329,26 +356,36 @@ namespace opt { lbool operator()() { TRACE("opt", tout << "weighted maxsat\n";); smt::theory_weighted_maxsat& wth = ensure_theory(); - lbool result; + lbool is_sat = l_true; { solver::scoped_push _s(s); for (unsigned i = 0; i < m_soft.size(); ++i) { wth.assert_weighted(m_soft[i].get(), m_weights[i]); } - result = s.check_sat_core(0,0); - SASSERT(result != l_true); - wth.get_assignment(m_assignment); - if (result == l_false) { - result = l_true; + while (l_true == is_sat) { + is_sat = s.check_sat_core(0,0); + if (is_sat == l_true) { + if (wth.is_optimal()) { + s.get_model(m_model); + } + wth.block(true); + if (s.get_context().inconsistent()) { + is_sat = l_false; + } + } + } + if (is_sat == l_false) { + wth.get_assignment(m_assignment); + is_sat = l_true; } } m_upper = wth.get_min_cost(); - if (result == l_true) { + if (is_sat == l_true) { m_lower = m_upper; } TRACE("opt", tout << "min cost: " << m_upper << "\n";); wth.reset(); - return result; + return is_sat; } rational get_lower() const { @@ -360,10 +397,7 @@ namespace opt { } void get_model(model_ref& mdl) { - lbool is_sat = s.check_sat_core(0,0); - if (is_sat == l_true) { - s.get_model(mdl); - } + mdl = m_model.get(); } }; diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 33cc4105e..07e88a3a0 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -23,6 +23,7 @@ Notes: #include "ast_pp.h" #include "sorting_network.h" #include "uint_set.h" +#include "smt_model_generator.h" namespace smt { @@ -1458,6 +1459,89 @@ namespace smt { return out; } + class theory_pb::pb_model_value_proc : public model_value_proc { + app* m_app; + svector m_dependencies; + public: + + pb_model_value_proc(app* a): + m_app(a) {} + + void add(enode* n) { + m_dependencies.push_back(model_value_dependency(n)); + } + + virtual void get_dependencies(buffer & result) { + result.append(m_dependencies.size(), m_dependencies.c_ptr()); + } + + virtual app * mk_value(model_generator & mg, ptr_vector & values) { + ast_manager& m = mg.get_manager(); + SASSERT(values.size() == m_dependencies.size()); + SASSERT(values.size() == m_app->get_num_args()); + pb_util u(m); + rational sum(0); + for (unsigned i = 0; i < m_app->get_num_args(); ++i) { + if (!m.is_true(values[i]) && !m.is_false(values[i])) { + return m_app; + } + if (m.is_true(values[i])) { + sum += u.get_coeff(m_app, i); + } + } + rational k = u.get_k(m_app); + switch(m_app->get_decl_kind()) { + case OP_AT_MOST_K: + return (sum <= k)?m.mk_true():m.mk_false(); + case OP_AT_LEAST_K: + return (sum >= k)?m.mk_true():m.mk_false(); + case OP_PB_LE: + return (sum <= k)?m.mk_true():m.mk_false(); + case OP_PB_GE: + return (sum >= k)?m.mk_true():m.mk_false(); + default: + UNREACHABLE(); + return 0; + } + return 0; + } + }; + + class pb_factory : public value_factory { + public: + pb_factory(ast_manager& m, family_id fid): + value_factory(m, fid) {} + + virtual expr * get_some_value(sort * s) { + return m_manager.mk_true(); + } + virtual bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2) { + v1 = m_manager.mk_true(); + v2 = m_manager.mk_false(); + return true; + } + virtual expr * get_fresh_value(sort * s) { + return 0; + } + virtual void register_value(expr * n) { } + }; + + void theory_pb::init_model(model_generator & m) { + std::cout << "init model\n"; + m.register_factory(alloc(pb_factory, get_manager(), get_id())); + } + + model_value_proc * theory_pb::mk_value(enode * n, model_generator & mg) { + std::cout << "mk-value " << mk_pp(n->get_owner(), get_manager()) << "\n"; + context& ctx = get_context(); + app* a = n->get_owner(); + pb_model_value_proc* p = alloc(pb_model_value_proc, a); + for (unsigned i = 0; i < a->get_num_args(); ++i) { + p->add(ctx.get_enode(a->get_arg(i))); + } + return p; + } + void theory_pb::display(std::ostream& out) const { u_map*>::iterator it = m_watch.begin(), end = m_watch.end(); for (; it != end; ++it) { diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 34cd479a1..c5387471d 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -29,6 +29,7 @@ namespace smt { struct sort_expr; class pb_justification; + class pb_model_value_proc; typedef rational numeral; typedef vector > arg_t; @@ -181,6 +182,7 @@ namespace smt { virtual void pop_scope_eh(unsigned num_scopes); virtual void restart_eh(); virtual void collect_statistics(::statistics & st) const; - + virtual model_value_proc * mk_value(enode * n, model_generator & mg); + virtual void init_model(model_generator & m); }; }; From b764c7bbeefd843480c5a9b877765ab242c50f74 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 15 Dec 2013 05:25:47 +0200 Subject: [PATCH 223/925] fixes to bugs exposed by regressions Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 07e88a3a0..a05fc7270 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1527,12 +1527,10 @@ namespace smt { }; void theory_pb::init_model(model_generator & m) { - std::cout << "init model\n"; m.register_factory(alloc(pb_factory, get_manager(), get_id())); } model_value_proc * theory_pb::mk_value(enode * n, model_generator & mg) { - std::cout << "mk-value " << mk_pp(n->get_owner(), get_manager()) << "\n"; context& ctx = get_context(); app* a = n->get_owner(); pb_model_value_proc* p = alloc(pb_model_value_proc, a); From ddd0bf875d3e7bec6435ef88179c5b586fedced8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 15 Dec 2013 08:46:24 +0200 Subject: [PATCH 224/925] fix bugs in optimization for integers Signed-off-by: Nikolaj Bjorner --- src/opt/weighted_maxsat.cpp | 2 +- src/smt/theory_arith_aux.h | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 45eab4d76..cd4a867a2 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -111,7 +111,7 @@ namespace smt { } } - if (m_min_cost_atom) { + if (!initialized && m_min_cost_atom) { app* var = m_min_cost_atom; if (!ctx.e_internalized(var)) { ctx.mk_enode(var, false, true, true); diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index f9f98b867..7007232b6 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -479,10 +479,11 @@ namespace smt { bool theory_arith::all_coeff_int(row const & r) const { typename vector::const_iterator it = r.begin_entries(); typename vector::const_iterator end = r.end_entries(); - for (; it != end; ++it) { - if (!it->is_dead() && !it->m_coeff.is_int()) + for (; it != end; ++it) { + if (!it->is_dead() && !it->m_coeff.is_int()) { TRACE("gomory_cut", display_row(tout, r, true);); return false; + } } return true; } @@ -949,6 +950,10 @@ namespace smt { if (curr_gain.is_neg()) curr_gain.neg(); if (x_i == null_theory_var || (curr_gain < gain) || (gain.is_zero() && curr_gain.is_zero() && s < x_i)) { + if (is_int(s) && !curr_gain.is_int()) + continue; + if (is_int(x_j) && !curr_gain.is_int()) + continue; x_i = s; a_ij = coeff; gain = curr_gain; From 15b64261dde6d384d8920e79b301ce12349190ad Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 16 Dec 2013 04:55:56 +0200 Subject: [PATCH 225/925] fix wmaxsat Signed-off-by: Nikolaj Bjorner --- src/opt/weighted_maxsat.cpp | 72 +++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 26 deletions(-) diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index cd4a867a2..a595eda89 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -99,6 +99,7 @@ namespace smt { ctx.attach_th_var(x, this, v); m_bool2var.insert(bv, v); SASSERT(v == m_var2bool.size()); + SASSERT(i == v); m_var2bool.push_back(bv); SASSERT(ctx.bool_var2enode(bv)); } @@ -157,7 +158,7 @@ namespace smt { } virtual void assign_eh(bool_var v, bool is_true) { - IF_VERBOSE(3, verbose_stream() << "Assign " << v << " " << is_true << "\n";); + TRACE("opt", tout << "Assign " << mk_pp(m_vars[m_bool2var[v]].get(), get_manager()) << " " << is_true << "\n";); if (is_true) { context& ctx = get_context(); theory_var tv = m_bool2var[v]; @@ -167,7 +168,7 @@ namespace smt { m_cost += w; m_costs.push_back(tv); if (m_cost > m_min_cost) { - block(false); + block(); } } } @@ -212,9 +213,47 @@ namespace smt { return m_cost < m_min_cost; } - bool block(bool is_final) { + expr_ref mk_block() { + ast_manager& m = get_manager(); + expr_ref_vector disj(m); + compare_cost compare_cost(*this); + svector costs(m_costs); + std::sort(costs.begin(), costs.end(), compare_cost); + rational weight(0); + for (unsigned i = 0; i < costs.size() && weight < m_min_cost; ++i) { + weight += m_weights[costs[i]]; + disj.push_back(m.mk_not(m_vars[costs[i]].get())); + } + if (m_min_cost_atom) { + disj.push_back(m.mk_not(m_min_cost_atom)); + } + if (is_optimal()) { + m_min_cost = weight; + m_cost_save.reset(); + m_cost_save.append(m_costs); + } + + expr_ref result(m.mk_or(disj.size(), disj.c_ptr()), m); + + TRACE("opt", + tout << result << "\n"; + if (is_optimal()) { + tout << "costs: "; + for (unsigned i = 0; i < m_costs.size(); ++i) { + tout << mk_pp(get_enode(m_costs[i])->get_owner(), get_manager()) << " "; + } + tout << "\n"; + get_context().display(tout); + }); + return result; + } + + + private: + + void block() { if (m_vars.empty()) { - return true; + return; } ast_manager& m = get_manager(); context& ctx = get_context(); @@ -231,35 +270,18 @@ namespace smt { lits.push_back(~literal(m_min_cost_bv)); } TRACE("opt", - tout << "block" << (is_final?" final: ":": ");; + tout << "block: "; for (unsigned i = 0; i < lits.size(); ++i) { expr_ref tmp(m); ctx.literal2expr(lits[i], tmp); tout << tmp << " "; } tout << "\n"; - if (is_final && is_optimal()) { - tout << "costs: "; - for (unsigned i = 0; i < m_costs.size(); ++i) { - tout << mk_pp(get_enode(m_costs[i])->get_owner(), get_manager()) << " "; - } - tout << "\n"; - ctx.display(tout); - - } ); ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); - if (is_final && is_optimal()) { - m_min_cost = weight; - m_cost_save.reset(); - m_cost_save.append(m_costs); - } - return false; } - - private: class compare_cost { theory_weighted_maxsat& m_th; @@ -368,10 +390,8 @@ namespace opt { if (wth.is_optimal()) { s.get_model(m_model); } - wth.block(true); - if (s.get_context().inconsistent()) { - is_sat = l_false; - } + expr_ref fml = wth.mk_block(); + s.assert_expr(fml); } } if (is_sat == l_false) { From b1caadee49796a6ebb02b904341ef19b6f81b28e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 16 Dec 2013 05:24:05 +0200 Subject: [PATCH 226/925] disabling skip steps to avoid bogus behavior Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index a05fc7270..46fcf3015 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1124,9 +1124,15 @@ namespace smt { while (m_num_marks > 0) { + TRACE("pb_verbose", display(tout << "lemma ", m_lemma, true);); + lbool is_sat = m_lemma.normalize(); if (is_sat != l_undef) { IF_VERBOSE(0, display(verbose_stream() << "lemma already evaluated ", m_lemma, true);); + TRACE("pb", display(tout << "lemma already evaluated ", m_lemma, true);); + for (unsigned i = 0; i < m_lemma.size(); ++i) { + unset_mark(m_lemma.lit(i)); + } return false; } TRACE("pb", display(tout, m_lemma, true);); @@ -1181,6 +1187,11 @@ namespace smt { if (cjs) { IF_VERBOSE(1, verbose_stream() << "skipping justification for clause over: " << conseq << "\n";); m_ineq_literals.push_back(conseq); + m_lemma.m_k -= conseq_coeff; + for (unsigned i = 0; i < m_lemma.size(); ++i) { + unset_mark(m_lemma.lit(i)); + } + return false; break; } unsigned num_lits = cls.get_num_literals(); @@ -1210,16 +1221,22 @@ namespace smt { case b_justification::JUSTIFICATION: { justification& j = *js.get_justification(); // only process pb justifications. - if (j.get_from_theory() != get_id()) { - IF_VERBOSE(1, verbose_stream() << "skipping justification for " << conseq - << " from theory " << j.get_from_theory() << "\n";); + if (j.get_from_theory() != get_id()) { + TRACE("pb", tout << "skipping justification for " << conseq + << " from theory " << j.get_from_theory() << "\n";); m_ineq_literals.push_back(conseq); - break; + m_lemma.m_k -= conseq_coeff; + for (unsigned i = 0; i < m_lemma.size(); ++i) { + unset_mark(m_lemma.lit(i)); + } + return false; + } + else { + pb_justification& pbj = dynamic_cast(j); + // weaken the lemma and resolve. + TRACE("pb", display(tout << "resolve with inequality", pbj.get_ineq(), true);); + process_ineq(pbj.get_ineq(), conseq, conseq_coeff); } - pb_justification& pbj = dynamic_cast(j); - // weaken the lemma and resolve. - TRACE("pb", display(tout, pbj.get_ineq(), true);); - process_ineq(pbj.get_ineq(), conseq, conseq_coeff); break; } default: From e38729a1c698e482f45c3edbf400865e2392528a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 16 Dec 2013 07:50:24 +0200 Subject: [PATCH 227/925] redo marking mechanism as marked literals can disappear from lemma Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 39 +++++++++++++++------------------------ src/smt/theory_pb.h | 4 +++- 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 46fcf3015..bf197ba7f 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -998,6 +998,7 @@ namespace smt { m_conseq_index.resize(v+1, null_index); } SASSERT(!is_marked(v) || m_conseq_index[v] == idx); + m_marked.push_back(v); m_conseq_index[v] = idx; } @@ -1007,14 +1008,20 @@ namespace smt { (m_conseq_index[v] != null_index); } - void theory_pb::unset_mark(literal l) { - bool_var v = l.var(); + void theory_pb::unset_mark(bool_var v) { SASSERT(v != null_bool_var); if (v < static_cast(m_conseq_index.size())) { m_conseq_index[v] = null_index; } } + void theory_pb::unset_marks() { + for (unsigned i = 0; i < m_marked.size(); ++i) { + unset_mark(m_marked[i]); + } + m_marked.reset(); + } + void theory_pb::process_antecedent(literal l, numeral coeff) { context& ctx = get_context(); bool_var v = l.var(); @@ -1112,6 +1119,7 @@ namespace smt { return false; } + unset_marks(); m_num_marks = 0; m_lemma.reset(); m_ineq_literals.reset(); @@ -1128,11 +1136,11 @@ namespace smt { lbool is_sat = m_lemma.normalize(); if (is_sat != l_undef) { + if (is_sat == l_false) { + break; + } IF_VERBOSE(0, display(verbose_stream() << "lemma already evaluated ", m_lemma, true);); TRACE("pb", display(tout << "lemma already evaluated ", m_lemma, true);); - for (unsigned i = 0; i < m_lemma.size(); ++i) { - unset_mark(m_lemma.lit(i)); - } return false; } TRACE("pb", display(tout, m_lemma, true);); @@ -1157,9 +1165,6 @@ namespace smt { // It is not a correctness bug but causes to miss lemmas. // IF_VERBOSE(1, display_resolved_lemma(verbose_stream());); - for (unsigned i = 0; i < m_lemma.size(); ++i) { - unset_mark(m_lemma.lit(i)); - } return false; } @@ -1186,12 +1191,8 @@ namespace smt { justification* cjs = cls.get_justification(); if (cjs) { IF_VERBOSE(1, verbose_stream() << "skipping justification for clause over: " << conseq << "\n";); + TRACE("pb", tout << "skipping justification for clause over: " << conseq << "\n";); m_ineq_literals.push_back(conseq); - m_lemma.m_k -= conseq_coeff; - for (unsigned i = 0; i < m_lemma.size(); ++i) { - unset_mark(m_lemma.lit(i)); - } - return false; break; } unsigned num_lits = cls.get_num_literals(); @@ -1225,11 +1226,6 @@ namespace smt { TRACE("pb", tout << "skipping justification for " << conseq << " from theory " << j.get_from_theory() << "\n";); m_ineq_literals.push_back(conseq); - m_lemma.m_k -= conseq_coeff; - for (unsigned i = 0; i < m_lemma.size(); ++i) { - unset_mark(m_lemma.lit(i)); - } - return false; } else { pb_justification& pbj = dynamic_cast(j); @@ -1244,11 +1240,6 @@ namespace smt { } } - - for (unsigned i = 0; i < m_lemma.size(); ++i) { - unset_mark(m_lemma.lit(i)); - } - TRACE("pb", for (unsigned i = 0; i < m_ineq_literals.size(); ++i) { tout << m_ineq_literals[i] << " "; @@ -1304,7 +1295,7 @@ namespace smt { m_conseq_index[c.lit(idx).var()] = idx; } c.m_args.pop_back(); - unset_mark(lit); + unset_mark(lit.var()); --m_num_marks; } diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index c5387471d..70429ed27 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -143,13 +143,15 @@ namespace smt { unsigned m_conflict_lvl; ineq m_lemma; literal_vector m_ineq_literals; + svector m_marked; // bool_var |-> index into m_lemma unsigned_vector m_conseq_index; static const unsigned null_index = UINT_MAX; bool is_marked(bool_var v) const; void set_mark(bool_var v, unsigned idx); - void unset_mark(literal l); + void unset_mark(bool_var v); + void unset_marks(); bool resolve_conflict(ineq& c); void process_antecedent(literal l, numeral coeff); From 1ca44ed31686774864aaead880c79640ee091b13 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 16 Dec 2013 11:25:50 +0200 Subject: [PATCH 228/925] handle proof-wrapper justifications Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 35 ++++++++++++++++++----------------- src/smt/theory_pb.h | 1 + 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index bf197ba7f..17ef922c8 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1032,12 +1032,8 @@ namespace smt { } else if (lvl > ctx.get_base_level()) { if (is_marked(v)) { - numeral& lcoeff = m_lemma.m_args[m_conseq_index[v]].second; - lcoeff += coeff; - if (lcoeff.is_zero()) { - IF_VERBOSE(1, display(verbose_stream() << "remove 0 consequence", m_lemma, true);); - remove_from_lemma(m_lemma, m_conseq_index[v]); - } + m_lemma.m_args[m_conseq_index[v]].second += coeff; + SASSERT(m_lemma.m_args[m_conseq_index[v]].second.is_pos()); } else { if (lvl == m_conflict_lvl) { @@ -1135,12 +1131,12 @@ namespace smt { TRACE("pb_verbose", display(tout << "lemma ", m_lemma, true);); lbool is_sat = m_lemma.normalize(); - if (is_sat != l_undef) { - if (is_sat == l_false) { - break; - } - IF_VERBOSE(0, display(verbose_stream() << "lemma already evaluated ", m_lemma, true);); - TRACE("pb", display(tout << "lemma already evaluated ", m_lemma, true);); + if (is_sat == l_false) { + break; + } + if (is_sat == l_true) { + IF_VERBOSE(0, verbose_stream() << "lemma already evaluated ";); + TRACE("pb", tout << "lemma already evaluated ";); return false; } TRACE("pb", display(tout, m_lemma, true);); @@ -1189,9 +1185,9 @@ namespace smt { case b_justification::CLAUSE: { clause& cls = *js.get_clause(); justification* cjs = cls.get_justification(); - if (cjs) { - IF_VERBOSE(1, verbose_stream() << "skipping justification for clause over: " << conseq << "\n";); - TRACE("pb", tout << "skipping justification for clause over: " << conseq << "\n";); + if (cjs && !is_proof_justification(*cjs)) { + TRACE("pb", tout << "skipping justification for clause over: " << conseq << " " + << typeid(*cjs).name() << "\n";); m_ineq_literals.push_back(conseq); break; } @@ -1221,10 +1217,10 @@ namespace smt { break; case b_justification::JUSTIFICATION: { justification& j = *js.get_justification(); - // only process pb justifications. if (j.get_from_theory() != get_id()) { TRACE("pb", tout << "skipping justification for " << conseq - << " from theory " << j.get_from_theory() << "\n";); + << " from theory " << j.get_from_theory() << " " + << typeid(j).name() << "\n";); m_ineq_literals.push_back(conseq); } else { @@ -1275,6 +1271,11 @@ namespace smt { return true; } + bool theory_pb::is_proof_justification(justification const& j) const { + return typeid(smt::justification_proof_wrapper) == typeid(j); + } + + void theory_pb::hoist_maximal_values() { for (unsigned i = 0; i < m_lemma.size(); ++i) { if (m_lemma.coeff(i) == m_lemma.k()) { diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 70429ed27..81f3229aa 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -157,6 +157,7 @@ namespace smt { void process_antecedent(literal l, numeral coeff); void process_ineq(ineq& c, literal conseq, numeral coeff); void remove_from_lemma(ineq& c, unsigned idx); + bool is_proof_justification(justification const& j) const; void hoist_maximal_values(); From 1bcf5b8b5f1ec63637efabe398e60d03201f0f58 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 16 Dec 2013 11:42:28 +0200 Subject: [PATCH 229/925] remove auxiliary variables from weighted maxsat Signed-off-by: Nikolaj Bjorner --- src/opt/weighted_maxsat.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index a595eda89..d21e81b70 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -24,6 +24,7 @@ Notes: namespace smt { class theory_weighted_maxsat : public theory { + opt::opt_solver& s; app_ref_vector m_vars; // Auxiliary variables per soft clause expr_ref_vector m_fmls; // Formulas per soft clause app_ref m_min_cost_atom; // atom tracking modified lower bound @@ -35,9 +36,11 @@ namespace smt { rational m_min_cost; // current maximal cost assignment. u_map m_bool2var; // bool_var -> theory_var svector m_var2bool; // theory_var -> bool_var + public: - theory_weighted_maxsat(ast_manager& m): + theory_weighted_maxsat(ast_manager& m, opt::opt_solver& s): theory(m.mk_family_id("weighted_maxsat")), + s(s), m_vars(m), m_fmls(m), m_min_cost_atom(m) @@ -132,6 +135,7 @@ namespace smt { ast_manager& m = get_manager(); app_ref var(m), wfml(m); var = m.mk_fresh_const("w", m.mk_bool_sort()); + s.mc().insert(var->get_decl()); wfml = m.mk_or(var, fml); ctx.assert_expr(wfml); m_weights.push_back(w); @@ -150,6 +154,7 @@ namespace smt { strm << "cost <= " << c; m_min_cost = c; m_min_cost_atom = m.mk_fresh_const(strm.str().c_str(), m.mk_bool_sort()); + s.mc().insert(m_min_cost_atom->get_decl()); return m_min_cost_atom; } @@ -203,7 +208,7 @@ namespace smt { m_min_cost_atom = 0; } - virtual theory * mk_fresh(context * new_ctx) { return alloc(theory_weighted_maxsat, new_ctx->get_manager()); } + virtual theory * mk_fresh(context * new_ctx) { return 0; } virtual bool internalize_atom(app * atom, bool gate_ctx) { return false; } virtual bool internalize_term(app * term) { return false; } virtual void new_eq_eh(theory_var v1, theory_var v2) { } @@ -363,7 +368,7 @@ namespace opt { wth->reset(); } else { - wth = alloc(smt::theory_weighted_maxsat, m); + wth = alloc(smt::theory_weighted_maxsat, m, s); s.get_context().register_plugin(wth); } return *wth; From 56b9c4c8a242ae6582938c9afb0579af8caba12f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 17 Dec 2013 04:20:24 +0200 Subject: [PATCH 230/925] fix bugs reported by phan Signed-off-by: Nikolaj Bjorner --- src/opt/weighted_maxsat.cpp | 46 ++++++++++++++++++++++++++++--------- src/smt/theory_pb.cpp | 14 ++++++++++- 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index d21e81b70..6c4e99d7e 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -36,6 +36,8 @@ namespace smt { rational m_min_cost; // current maximal cost assignment. u_map m_bool2var; // bool_var -> theory_var svector m_var2bool; // theory_var -> bool_var + bool m_propagate; + svector m_assigned; public: theory_weighted_maxsat(ast_manager& m, opt::opt_solver& s): @@ -43,7 +45,8 @@ namespace smt { s(s), m_vars(m), m_fmls(m), - m_min_cost_atom(m) + m_min_cost_atom(m), + m_propagate(false) {} /** @@ -83,7 +86,8 @@ namespace smt { context & ctx = get_context(); ast_manager& m = get_manager(); bool initialized = !m_var2bool.empty(); - + m_propagate = true; + for (unsigned i = 0; !initialized && i < m_vars.size(); ++i) { app* var = m_vars[i].get(); bool_var bv; @@ -106,14 +110,6 @@ namespace smt { m_var2bool.push_back(bv); SASSERT(ctx.bool_var2enode(bv)); } - for (unsigned i = 0; i < m_vars.size(); ++i) { - app* var = m_vars[i].get(); - bool_var bv = ctx.get_bool_var(var); - lbool asgn = ctx.get_assignment(bv); - if (asgn == l_true) { - assign_eh(bv, true); - } - } if (!initialized && m_min_cost_atom) { app* var = m_min_cost_atom; @@ -141,6 +137,7 @@ namespace smt { m_weights.push_back(w); m_vars.push_back(var); m_fmls.push_back(fml); + m_assigned.push_back(false); m_min_cost += w; } @@ -167,11 +164,14 @@ namespace smt { if (is_true) { context& ctx = get_context(); theory_var tv = m_bool2var[v]; + if (m_assigned[tv]) return; rational const& w = m_weights[tv]; ctx.push_trail(value_trail(m_cost)); ctx.push_trail(push_back_vector >(m_costs)); + ctx.push_trail(value_trail(m_assigned[tv])); m_cost += w; m_costs.push_back(tv); + m_assigned[tv] = true; if (m_cost > m_min_cost) { block(); } @@ -206,6 +206,8 @@ namespace smt { m_bool2var.reset(); m_var2bool.reset(); m_min_cost_atom = 0; + m_propagate = false; + m_assigned.reset(); } virtual theory * mk_fresh(context * new_ctx) { return 0; } @@ -214,6 +216,24 @@ namespace smt { virtual void new_eq_eh(theory_var v1, theory_var v2) { } virtual void new_diseq_eh(theory_var v1, theory_var v2) { } + virtual bool can_propagate() { + return m_propagate; + } + + virtual void propagate() { + context& ctx = get_context(); + for (unsigned i = 0; m_propagate && i < m_vars.size(); ++i) { + bool_var bv = m_var2bool[i]; + lbool asgn = ctx.get_assignment(bv); + if (asgn == l_true) { + assign_eh(bv, true); + } + } + m_propagate = false; + } + + + bool is_optimal() const { return m_cost < m_min_cost; } @@ -386,6 +406,7 @@ namespace opt { lbool is_sat = l_true; { solver::scoped_push _s(s); + bool was_sat = false; for (unsigned i = 0; i < m_soft.size(); ++i) { wth.assert_weighted(m_soft[i].get(), m_weights[i]); } @@ -397,10 +418,13 @@ namespace opt { } expr_ref fml = wth.mk_block(); s.assert_expr(fml); + was_sat = true; } } - if (is_sat == l_false) { + if (was_sat) { wth.get_assignment(m_assignment); + } + if (is_sat == l_false && was_sat) { is_sat = l_true; } } diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 17ef922c8..f282b47c3 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -983,7 +983,9 @@ namespace smt { tout << "\n"; display(tout, c, true);); - resolve_conflict(c); + if ((c.m_num_propagations & 0xF) == 0) { + resolve_conflict(c); + } justification* js = 0; ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); @@ -1029,6 +1031,16 @@ namespace smt { if (ctx.get_assignment(l) != l_false) { m_lemma.m_k -= coeff; + if (false && is_marked(v)) { + SASSERT(ctx.get_assignment(l) == l_true); + numeral& lcoeff = m_lemma.m_args[m_conseq_index[v]].second; + lcoeff -= coeff; + if (!lcoeff.is_pos()) { + // perhaps let lemma simplification change coefficient + // when negative? + remove_from_lemma(m_lemma, m_conseq_index[v]); + } + } } else if (lvl > ctx.get_base_level()) { if (is_marked(v)) { From 02f74f102826ab1f529e48e2f144b8a240eb296b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 17 Dec 2013 05:03:20 +0200 Subject: [PATCH 231/925] trying Cezary's example Signed-off-by: Nikolaj Bjorner --- src/opt/maxsmt.cpp | 3 +++ src/opt/weighted_maxsat.cpp | 1 + 2 files changed, 4 insertions(+) diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 3b0f684e8..8f77cdf85 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -39,6 +39,9 @@ namespace opt { if (m_maxsat_engine == symbol("core_maxsat")) { m_msolver = alloc(core_maxsat, m, s, m_soft_constraints); } + else if (m_maxsat_engine == symbol("weighted_maxsat")) { + m_msolver = alloc(wmaxsmt, m, opt_solver::to_opt(s), m_soft_constraints, m_weights); + } else { m_msolver = alloc(fu_malik, m, s, m_soft_constraints); } diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 6c4e99d7e..1d2aa22a6 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -253,6 +253,7 @@ namespace smt { disj.push_back(m.mk_not(m_min_cost_atom)); } if (is_optimal()) { + IF_VERBOSE(1, verbose_stream() << "(wmaxsat with lower bound: " << weight << "\n";); m_min_cost = weight; m_cost_save.reset(); m_cost_save.append(m_costs); From 72130ac7b9c2d2cb5bfa69500fc064b43bccf971 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 18 Dec 2013 05:49:43 +0200 Subject: [PATCH 232/925] fix lower bound update Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 4 ++++ src/opt/optsmt.cpp | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 26ce2152b..599b6d7d2 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -424,6 +424,10 @@ namespace opt { objective const& obj = m_objectives[i]; switch(obj.m_type) { case O_MINIMIZE: + if (m_model->eval(obj.m_term, val) && a.is_numeral(val, r)) { + m_optsmt.update_lower(obj.m_index, -r); + } + break; case O_MAXIMIZE: if (m_model->eval(obj.m_term, val) && a.is_numeral(val, r)) { m_optsmt.update_lower(obj.m_index, r); diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 97aec1e8c..19ea39521 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -117,6 +117,7 @@ namespace opt { void optsmt::update_lower(unsigned idx, rational const& r) { inf_eps v(r); + std::cout << "update lower: " << r << "\n"; if (m_lower[idx] < v) { m_lower[idx] = v; if (m_s) m_s->get_model(m_model); @@ -322,7 +323,6 @@ namespace opt { std::ostream& optsmt::display_objective(std::ostream& out, unsigned i) const { bool is_max = m_is_max[i]; - inf_eps val = get_lower(i); expr_ref obj(m_objs[i], m); if (!is_max) { arith_util a(m); From 22166d0760604436af0bcd21970daee3422f28b1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 18 Dec 2013 05:59:16 +0200 Subject: [PATCH 233/925] remove print Signed-off-by: Nikolaj Bjorner --- src/model/func_interp.cpp | 10 ++++++++-- src/opt/optsmt.cpp | 1 - 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/model/func_interp.cpp b/src/model/func_interp.cpp index ae4c657bd..406f7a89b 100644 --- a/src/model/func_interp.cpp +++ b/src/model/func_interp.cpp @@ -159,11 +159,17 @@ void func_interp::insert_entry(expr * const * args, expr * r) { void func_interp::insert_new_entry(expr * const * args, expr * r) { reset_interp_cache(); CTRACE("func_interp_bug", get_entry(args) != 0, + tout << "Old: " << mk_ismt2_pp(get_entry(args)->m_result, m_manager) << "\n"; + tout << "Args:"; + for (unsigned i = 0; i < m_arity; i++) { + tout << mk_ismt2_pp(get_entry(args)->get_arg(i), m_manager) << "\n"; + } + tout << "New: " << mk_ismt2_pp(r, m_manager) << "\n"; + tout << "Args:"; for (unsigned i = 0; i < m_arity; i++) { tout << mk_ismt2_pp(args[i], m_manager) << "\n"; } - tout << "Old: " << mk_ismt2_pp(get_entry(args)->m_result, m_manager) << "\n"; - tout << "New: " << mk_ismt2_pp(r, m_manager) << "\n";); + ); SASSERT(get_entry(args) == 0); func_entry * new_entry = func_entry::mk(m_manager, m_arity, args, r); if (!new_entry->args_are_values()) diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 19ea39521..668043c03 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -117,7 +117,6 @@ namespace opt { void optsmt::update_lower(unsigned idx, rational const& r) { inf_eps v(r); - std::cout << "update lower: " << r << "\n"; if (m_lower[idx] < v) { m_lower[idx] = v; if (m_s) m_s->get_model(m_model); From eb1b578bfb876b85977f03347a16b40aceb5318c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 18 Dec 2013 08:43:07 +0200 Subject: [PATCH 234/925] fixing optimizaiton bug Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith.h | 7 ++-- src/smt/theory_arith_aux.h | 77 ++++++++++++++++++++++--------------- src/smt/theory_arith_core.h | 1 - 3 files changed, 49 insertions(+), 36 deletions(-) diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 8bc841ca0..2380f8969 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -434,7 +434,6 @@ namespace smt { bool m_eager_gcd; // true if gcd should be applied at every add_row unsigned m_final_check_idx; - u_map m_objective_theory_vars; // backtracking svector m_bound_trail; @@ -857,11 +856,13 @@ namespace smt { void add_tmp_row(row & r1, numeral const & coeff, row const & r2); theory_var pick_var_to_leave(theory_var x_j, bool inc, numeral & a_ij, inf_numeral & gain); + bool is_safe_to_leave(theory_var x); void move_to_bound(theory_var x_i, bool inc); template void add_tmp_row_entry(row & r, numeral const & coeff, theory_var v); - bool max_min(theory_var v, bool max); - bool max_min(row & r, bool max); + enum max_min_t { UNBOUNDED, AT_BOUND, OPTIMIZED, BEST_EFFORT}; + max_min_t max_min(theory_var v, bool max); + max_min_t max_min(row & r, bool max); bool max_min(svector const & vars); // ----------------------------------- diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 7007232b6..515b019eb 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -927,6 +927,26 @@ namespace smt { */ + template + bool theory_arith::is_safe_to_leave(theory_var x) { + + column & c = m_columns[x]; + typename svector::iterator it = c.begin_entries(); + typename svector::iterator end = c.end_entries(); + for (; it != end; ++it) { + if (it->is_dead()) continue; + row const & r = m_rows[it->m_row_id]; + theory_var s = r.get_base_var(); + numeral const & coeff = r[it->m_row_idx].m_coeff; + bool is_unsafe = (s != null_theory_var && is_int(s) && !coeff.is_int()); + TRACE("opt", tout << "is v" << x << " safe to leave for v" << s << "? " << (is_unsafe?"no":"yes") << "\n"; + display_row(tout, r, true);); + if (is_unsafe) return false; + } + + return true; + } + template theory_var theory_arith::pick_var_to_leave(theory_var x_j, bool inc, numeral & a_ij, inf_numeral & gain) { TRACE("opt", tout << "selecting variable to replace v" << x_j << ", inc: " << inc << "\n";); @@ -986,6 +1006,9 @@ namespace smt { } } } + else if (m_util.is_to_real(n, x) || m_util.is_to_int(n, x)) { + return get_theory_vars(x, vars); + } else if (m_util.is_mul(n, x, y) && m_util.is_numeral(x, r)) { return get_theory_vars(y, vars); } @@ -1019,10 +1042,6 @@ namespace smt { template theory_var theory_arith::add_objective(app* term) { theory_var v = internalize_term_core(term); - uint_set vars; - if (get_theory_vars(term, vars)) { - m_objective_theory_vars.insert(v, vars); - } TRACE("opt", tout << mk_pp(term, get_manager()) << " |-> v" << v << "\n";); TRACE("opt", tout << "data-size: " << m_data.size() << "\n";); SASSERT(!is_quasi_base(v)); @@ -1032,22 +1051,12 @@ namespace smt { template inf_eps_rational theory_arith::maximize(theory_var v) { TRACE("opt", tout << "data-size: " << m_data.size() << "\n";); - bool r = max_min(v, true); - if (r || at_upper(v)) { - if (m_objective_theory_vars.contains(v)) { - // FIXME: put this block inside verbose code - uint_set & vars = m_objective_theory_vars[v]; - uint_set::iterator it = vars.begin(), end = vars.end(); - ast_manager& m = get_manager(); - IF_VERBOSE(1, - verbose_stream() << "Optimal assigment:" << std::endl; - for (; it != end; ++it) { - verbose_stream() << mk_pp(get_enode(*it)->get_owner(), m) << " |-> " << get_value(*it) << std::endl; - };); - } - return inf_eps_rational(get_value(v)); + max_min_t r = max_min(v, true); + if (r == UNBOUNDED) { + return inf_eps_rational::infinity(); } - return inf_eps_rational::infinity(); + return inf_eps_rational(get_value(v)); + } /** @@ -1092,7 +1101,6 @@ namespace smt { */ template expr* theory_arith::mk_ge(filter_model_converter& fm, theory_var v, inf_numeral const& val) { - SASSERT(m_objective_theory_vars.contains(v)); ast_manager& m = get_manager(); context& ctx = get_context(); std::ostringstream strm; @@ -1262,9 +1270,10 @@ namespace smt { Return true if succeeded. */ template - bool theory_arith::max_min(row & r, bool max) { + typename theory_arith::max_min_t theory_arith::max_min(row & r, bool max) { TRACE("max_min", tout << "max_min...\n";); m_stats.m_max_min++; + bool skipped_row = false; SASSERT(valid_row_assignment()); SASSERT(satisfy_bounds()); @@ -1292,6 +1301,10 @@ namespace smt { bool curr_inc = curr_coeff.is_pos() ? max : !max; if ((curr_inc && at_upper(curr_x_j)) || (!curr_inc && at_lower(curr_x_j))) continue; // variable cannot be used for max/min. + if (!is_safe_to_leave(curr_x_j)) { + skipped_row = true; + continue; + } theory_var curr_x_i = pick_var_to_leave(curr_x_j, curr_inc, curr_a_ij, curr_gain); if (curr_x_i == null_theory_var) { // we can increase/decrease curr_x_j as much as we want. @@ -1325,7 +1338,7 @@ namespace smt { TRACE("opt", tout << "row is " << (max ? "maximized" : "minimized") << "\n";); SASSERT(valid_row_assignment()); SASSERT(satisfy_bounds()); - return true; + return skipped_row?BEST_EFFORT:OPTIMIZED; } if (x_i == null_theory_var) { @@ -1344,7 +1357,7 @@ namespace smt { SASSERT(satisfy_bounds()); continue; } - return false; // unbounded. + return UNBOUNDED; } if (!is_fixed(x_j) && is_bounded(x_j) && (upper_bound(x_j) - lower_bound(x_j) <= gain)) { @@ -1471,13 +1484,13 @@ namespace smt { \brief Maximize/Minimize the given variable. The bounds of v are update if procedure succeeds. */ template - bool theory_arith::max_min(theory_var v, bool max) { + typename theory_arith::max_min_t theory_arith::max_min(theory_var v, bool max) { TRACE("opt", tout << (max ? "maximizing" : "minimizing") << " v" << v << "...\n";); SASSERT(valid_row_assignment()); SASSERT(satisfy_bounds()); SASSERT(!is_quasi_base(v)); if ((max && at_upper(v)) || (!max && at_lower(v))) - return false; // nothing to be done... + return AT_BOUND; // nothing to be done... m_tmp_row.reset(); if (is_non_base(v)) { add_tmp_row_entry(m_tmp_row, numeral(1), v); @@ -1491,15 +1504,15 @@ namespace smt { add_tmp_row_entry(m_tmp_row, it->m_coeff, it->m_var); } } - if (max_min(m_tmp_row, max)) { + max_min_t r = max_min(m_tmp_row, max); + if (r == OPTIMIZED) { TRACE("opt", tout << "v" << v << " " << (max ? "max" : "min") << " value is: " << get_value(v) << "\n"; display_row(tout, m_tmp_row, true); display_row_info(tout, m_tmp_row);); mk_bound_from_row(v, get_value(v), max ? B_UPPER : B_LOWER, m_tmp_row); - return true; } - return false; + return r; } /** @@ -1512,9 +1525,9 @@ namespace smt { svector::const_iterator it = vars.begin(); svector::const_iterator end = vars.end(); for (; it != end; ++it) { - if (max_min(*it, true)) + if (max_min(*it, true) == OPTIMIZED) succ = true; - if (max_min(*it, false)) + if (max_min(*it, false) == OPTIMIZED) succ = true; } if (succ) { @@ -1688,9 +1701,9 @@ namespace smt { m_tmp_lit_set.reset(); m_tmp_eq_set.reset(); - if (max_min(m_tmp_row, true) && + if ((OPTIMIZED == max_min(m_tmp_row, true)) && is_zero_row(m_tmp_row, true, m_tmp_acc_lits, m_tmp_acc_eqs, m_tmp_lit_set, m_tmp_eq_set) && - max_min(m_tmp_row, false) && + (OPTIMIZED == max_min(m_tmp_row, false)) && is_zero_row(m_tmp_row, false, m_tmp_acc_lits, m_tmp_acc_eqs, m_tmp_lit_set, m_tmp_eq_set)) { // v1 == v2 TRACE("imply_eq", tout << "found new implied equality:\n"; diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 944414267..49032bdc8 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -1237,7 +1237,6 @@ namespace smt { m_nl_rounds = 0; m_nl_gb_exhausted = false; m_nl_strategy_idx = 0; - m_objective_theory_vars .reset(); theory::reset_eh(); } From 392b4193672bbdc96861eba6cb407bec1710f76b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 18 Dec 2013 09:14:10 +0200 Subject: [PATCH 235/925] debug min_max Signed-off-by: Nikolaj Bjorner --- src/opt/optsmt.cpp | 4 ++-- src/smt/theory_arith_aux.h | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 668043c03..6da9771fb 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -298,11 +298,11 @@ namespace opt { inf_eps optsmt::get_lower(unsigned i) const { - return m_is_max[i]?m_lower[i]:-m_lower[i]; + return m_is_max[i]?m_lower[i]:-m_upper[i]; } inf_eps optsmt::get_upper(unsigned i) const { - return m_is_max[i]?m_upper[i]:-m_upper[i]; + return m_is_max[i]?m_upper[i]:-m_lower[i]; } void optsmt::get_model(model_ref& mdl) { diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 515b019eb..bb8e8ef77 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -930,6 +930,9 @@ namespace smt { template bool theory_arith::is_safe_to_leave(theory_var x) { + if (get_context().is_shared(get_enode(x))) { + return false; + } column & c = m_columns[x]; typename svector::iterator it = c.begin_entries(); typename svector::iterator end = c.end_entries(); @@ -939,6 +942,7 @@ namespace smt { theory_var s = r.get_base_var(); numeral const & coeff = r[it->m_row_idx].m_coeff; bool is_unsafe = (s != null_theory_var && is_int(s) && !coeff.is_int()); + is_unsafe = is_unsafe || (s != null_theory_var && get_context().is_shared(get_enode(s))); TRACE("opt", tout << "is v" << x << " safe to leave for v" << s << "? " << (is_unsafe?"no":"yes") << "\n"; display_row(tout, r, true);); if (is_unsafe) return false; From cff0e0fc6c28071fd7ae4398bc34e8bbd9f9d121 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 18 Dec 2013 09:18:06 +0200 Subject: [PATCH 236/925] debug min_max Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith.h | 2 +- src/smt/theory_arith_aux.h | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 2380f8969..a7d58080e 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -855,7 +855,7 @@ namespace smt { row m_tmp_row; void add_tmp_row(row & r1, numeral const & coeff, row const & r2); - theory_var pick_var_to_leave(theory_var x_j, bool inc, numeral & a_ij, inf_numeral & gain); + theory_var pick_var_to_leave(theory_var x_j, bool inc, numeral & a_ij, inf_numeral & gain, bool& skiped_row); bool is_safe_to_leave(theory_var x); void move_to_bound(theory_var x_i, bool inc); template diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index bb8e8ef77..b0d983bca 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -952,7 +952,7 @@ namespace smt { } template - theory_var theory_arith::pick_var_to_leave(theory_var x_j, bool inc, numeral & a_ij, inf_numeral & gain) { + theory_var theory_arith::pick_var_to_leave(theory_var x_j, bool inc, numeral & a_ij, inf_numeral & gain, bool& skipped_row) { TRACE("opt", tout << "selecting variable to replace v" << x_j << ", inc: " << inc << "\n";); theory_var x_i = null_theory_var; inf_numeral curr_gain; @@ -974,10 +974,14 @@ namespace smt { if (curr_gain.is_neg()) curr_gain.neg(); if (x_i == null_theory_var || (curr_gain < gain) || (gain.is_zero() && curr_gain.is_zero() && s < x_i)) { - if (is_int(s) && !curr_gain.is_int()) + if (is_int(s) && !curr_gain.is_int()) { + skipped_row = true; continue; - if (is_int(x_j) && !curr_gain.is_int()) + } + if (is_int(x_j) && !curr_gain.is_int()) { + skipped_row = true; continue; + } x_i = s; a_ij = coeff; gain = curr_gain; @@ -1309,7 +1313,7 @@ namespace smt { skipped_row = true; continue; } - theory_var curr_x_i = pick_var_to_leave(curr_x_j, curr_inc, curr_a_ij, curr_gain); + theory_var curr_x_i = pick_var_to_leave(curr_x_j, curr_inc, curr_a_ij, curr_gain, skipped_row); if (curr_x_i == null_theory_var) { // we can increase/decrease curr_x_j as much as we want. x_i = null_theory_var; // unbounded From 26237a37272169deac6dfb333fddc6a5e6afd4d6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 19 Dec 2013 07:40:18 +0200 Subject: [PATCH 237/925] debug benchmarks, theory_pb Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 4 +- src/opt/weighted_maxsat.cpp | 10 ++- src/smt/theory_pb.cpp | 116 +++++++++++++++++++++------ src/smt/theory_pb.h | 2 + src/tactic/arith/lia2card_tactic.cpp | 6 ++ 5 files changed, 108 insertions(+), 30 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 599b6d7d2..3cbc3d3a1 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -27,6 +27,7 @@ Notes: #include "tactic.h" #include "lia2card_tactic.h" #include "elim01_tactic.h" +#include "simplify_tactic.h" #include "tactical.h" #include "model_smt2_pp.h" @@ -189,9 +190,10 @@ namespace opt { for (unsigned i = 0; i < fmls.size(); ++i) { g->assert_expr(fmls[i].get()); } + tactic_ref tac0 = mk_simplify_tactic(m); tactic_ref tac1 = mk_elim01_tactic(m); tactic_ref tac2 = mk_lia2card_tactic(m); - tactic_ref tac = and_then(tac1.get(), tac2.get()); + tactic_ref tac = and_then(tac0.get(), tac1.get(), tac2.get()); proof_converter_ref pc; expr_dependency_ref core(m); goal_ref_buffer result; diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 1d2aa22a6..427725fbe 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -253,7 +253,7 @@ namespace smt { disj.push_back(m.mk_not(m_min_cost_atom)); } if (is_optimal()) { - IF_VERBOSE(1, verbose_stream() << "(wmaxsat with lower bound: " << weight << "\n";); + IF_VERBOSE(1, verbose_stream() << "(wmaxsat with lower bound: " << weight << ")\n";); m_min_cost = weight; m_cost_save.reset(); m_cost_save.append(m_costs); @@ -363,9 +363,10 @@ namespace opt { rational m_upper; rational m_lower; model_ref m_model; + volatile bool m_cancel; imp(ast_manager& m, opt_solver& s, expr_ref_vector& soft_constraints, vector const& weights): - m(m), s(s), m_soft(soft_constraints), m_weights(weights) + m(m), s(s), m_soft(soft_constraints), m_weights(weights), m_cancel(false) { m_assignment.resize(m_soft.size(), false); } @@ -413,6 +414,9 @@ namespace opt { } while (l_true == is_sat) { is_sat = s.check_sat_core(0,0); + if (m_cancel) { + is_sat = l_undef; + } if (is_sat == l_true) { if (wth.is_optimal()) { s.get_model(m_model); @@ -473,7 +477,7 @@ namespace opt { return m_imp->m_assignment[idx]; } void wmaxsmt::set_cancel(bool f) { - // no-op + m_imp->m_cancel = f; } void wmaxsmt::collect_statistics(statistics& st) const { // no-op diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index f282b47c3..3b9ed85cc 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -76,21 +76,54 @@ namespace smt { } // sort and coalesce arguments: std::sort(args.begin(), args.end()); - for (unsigned i = 0; i + 1 < size(); ++i) { - if (lit(i) == args[i+1].first) { - args[i].second += coeff(i+1); - for (unsigned j = i+1; j + 1 < size(); ++j) { - args[j] = args[j+1]; - } - args.pop_back(); + + unsigned i = 0, j = 1; + for (; j < size(); ++i) { + SASSERT(j > i); + literal l = lit(i); + for (; j < size() && lit(j) == lit(i); ++j) { + args[i].second += coeff(j); } - if (coeff(i).is_zero()) { - for (unsigned j = i; j + 1 < size(); ++j) { - args[j] = args[j+1]; - } - args.pop_back(); + if (j < size()) { + args[i+1].first = lit(j); + args[i+1].second = coeff(j); + ++j; } - } + } + if (i + 1 < size()) { + args.resize(i+1); + } + } + + void theory_pb::ineq::prune() { + numeral& k = m_k; + arg_t& args = m_args; + numeral nlt(0); + unsigned occ = 0; + for (unsigned i = 0; nlt < k && i < size(); ++i) { + if (coeff(i) < k) { + nlt += coeff(i); + ++occ; + } + } + if (0 < occ && nlt < k) { + IF_VERBOSE(2, verbose_stream() << "prune\n"; + for (unsigned i = 0; i < size(); ++i) { + verbose_stream() << coeff(i) << "*" << lit(i) << " "; + } + verbose_stream() << " >= " << k << "\n"; + ); + + for (unsigned i = 0; i < size(); ++i) { + if (coeff(i) < k) { + args[i] = args.back(); + args.pop_back(); + --i; + } + } + normalize(); + + } } lbool theory_pb::ineq::normalize() { @@ -121,20 +154,28 @@ namespace smt { // detect tautologies: if (k <= numeral::zero()) { args.reset(); + k = numeral::zero(); return l_true; } // detect infeasible constraints: if (sum < k) { args.reset(); + k = numeral::one(); return l_false; } - // normalize to integers. - numeral d(denominator(k)); - for (unsigned i = 0; i < size(); ++i) { - d = lcm(d, denominator(coeff(i))); + bool all_int = true; + for (unsigned i = 0; all_int && i < size(); ++i) { + all_int = coeff(i).is_int(); } - if (!d.is_one()) { + + if (!all_int) { + // normalize to integers. + numeral d(denominator(k)); + for (unsigned i = 0; i < size(); ++i) { + d = lcm(d, denominator(coeff(i))); + } + SASSERT(!d.is_one()); k *= d; for (unsigned i = 0; i < size(); ++i) { args[i].second *= d; @@ -182,6 +223,13 @@ namespace smt { k = numeral::one(); } else if (g > numeral::one()) { + IF_VERBOSE(2, verbose_stream() << "cut " << g << "\n"; + for (unsigned i = 0; i < size(); ++i) { + verbose_stream() << coeff(i) << "*" << lit(i) << " "; + } + verbose_stream() << " >= " << k << "\n"; + ); + // // Example 5x + 5y + 2z + 2u >= 5 // becomes 3x + 3y + z + u >= 3 @@ -226,6 +274,13 @@ namespace smt { numeral n1 = floor(n0); numeral n2 = ceil(k/min) - numeral::one(); if (n1 == n2 && !n0.is_int()) { + IF_VERBOSE(2, verbose_stream() << "set cardinality\n"; + for (unsigned i = 0; i < size(); ++i) { + verbose_stream() << coeff(i) << "*" << lit(i) << " "; + } + verbose_stream() << " >= " << k << "\n"; + ); + for (unsigned i = 0; i < size(); ++i) { args[i].second = numeral::one(); } @@ -300,6 +355,8 @@ namespace smt { bool_var abv = ctx.mk_bool_var(atom); ctx.set_var_theory(abv, get_id()); + IF_VERBOSE(3, verbose_stream() << mk_pp(atom, m) << "\n";); + ineq* c = alloc(ineq, literal(abv)); c->m_k = m_util.get_k(atom); numeral& k = c->m_k; @@ -324,7 +381,9 @@ namespace smt { } c->unique(); lbool is_true = c->normalize(); + c->prune(); + literal lit(abv); switch(is_true) { case l_false: @@ -339,7 +398,9 @@ namespace smt { break; } - // TBD: special cases: args.size() == 1 + // TBD: special cases: k == 1, or args.size() == 1 + + // maximal coefficient: numeral& max_watch = c->m_max_watch; @@ -983,14 +1044,12 @@ namespace smt { tout << "\n"; display(tout, c, true);); - if ((c.m_num_propagations & 0xF) == 0) { + if (true || (c.m_num_propagations & 0xF) == 0) { resolve_conflict(c); } justification* js = 0; ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); - IF_VERBOSE(2, ctx.display_literals_verbose(verbose_stream(), lits.size(), lits.c_ptr()); - verbose_stream() << "\n";); } @@ -1031,7 +1090,7 @@ namespace smt { if (ctx.get_assignment(l) != l_false) { m_lemma.m_k -= coeff; - if (false && is_marked(v)) { + if (true && false && is_marked(v)) { SASSERT(ctx.get_assignment(l) == l_true); numeral& lcoeff = m_lemma.m_args[m_conseq_index[v]].second; lcoeff -= coeff; @@ -1173,6 +1232,7 @@ namespace smt { // It is not a correctness bug but causes to miss lemmas. // IF_VERBOSE(1, display_resolved_lemma(verbose_stream());); + TRACE("pb", display_resolved_lemma(tout);); return false; } @@ -1254,11 +1314,15 @@ namespace smt { } display(tout << "=> ", m_lemma);); + // 3x + 3y + z + u >= 4 + // ~x /\ ~y => z + u >= + + IF_VERBOSE(2, display(verbose_stream() << "lemma1: ", m_lemma);); hoist_maximal_values(); - lbool is_true = m_lemma.normalize(); + m_lemma.prune(); - IF_VERBOSE(2, display(verbose_stream() << "lemma: ", m_lemma);); + IF_VERBOSE(2, display(verbose_stream() << "lemma2: ", m_lemma);); switch(is_true) { case l_true: UNREACHABLE(); @@ -1290,7 +1354,7 @@ namespace smt { void theory_pb::hoist_maximal_values() { for (unsigned i = 0; i < m_lemma.size(); ++i) { - if (m_lemma.coeff(i) == m_lemma.k()) { + if (m_lemma.coeff(i) >= m_lemma.k()) { m_ineq_literals.push_back(~m_lemma.lit(i)); std::swap(m_lemma.m_args[i], m_lemma.m_args[m_lemma.size()-1]); m_lemma.m_args.pop_back(); diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 81f3229aa..9a4c18ed4 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -92,6 +92,8 @@ namespace smt { void unique(); + void prune(); + bool well_formed() const; app_ref to_expr(context& ctx, ast_manager& m); diff --git a/src/tactic/arith/lia2card_tactic.cpp b/src/tactic/arith/lia2card_tactic.cpp index f5ae23b07..c6c49ec5b 100644 --- a/src/tactic/arith/lia2card_tactic.cpp +++ b/src/tactic/arith/lia2card_tactic.cpp @@ -211,6 +211,9 @@ public: else if (a.is_mul(x, z, y) && is_numeral(y, r)) { ok = get_pb_sum(z, r*mul, args, coeffs, coeff); } + else if (a.is_to_real(x, y)) { + ok = get_pb_sum(y, mul, args, coeffs, coeff); + } else if (m.is_ite(x, y, z, u) && is_numeral(z, r) && is_numeral(u, q)) { insert_arg(r*mul, y, args, coeffs, coeff); // q*(1-y) = -q*y + q @@ -235,6 +238,9 @@ public: r.neg(); return true; } + if (a.is_to_real(e, e)) { + return is_numeral(e, r); + } return a.is_numeral(e, r); } From 0deb9518730caf4bd1c73b6fa3da6e6ceafeabf8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 20 Dec 2013 12:04:17 +0100 Subject: [PATCH 238/925] different strategies for weighted Signed-off-by: Nikolaj Bjorner --- src/opt/core_maxsat.cpp | 3 + src/opt/core_maxsat.h | 1 + src/opt/fu_malik.cpp | 4 + src/opt/fu_malik.h | 1 + src/opt/maxsmt.cpp | 5 + src/opt/maxsmt.h | 3 + src/opt/opt_context.cpp | 9 +- src/opt/opt_params.pyg | 5 + src/opt/opt_solver.cpp | 28 ++- src/opt/opt_solver.h | 2 +- src/opt/weighted_maxsat.cpp | 383 ++++++++++++++++++++++++++---------- src/opt/weighted_maxsat.h | 1 + src/smt/smt_context.cpp | 1 + src/smt/theory_pb.cpp | 24 ++- src/smt/theory_pb.h | 5 + 15 files changed, 352 insertions(+), 123 deletions(-) diff --git a/src/opt/core_maxsat.cpp b/src/opt/core_maxsat.cpp index 9b4f284a5..053f4dc5a 100644 --- a/src/opt/core_maxsat.cpp +++ b/src/opt/core_maxsat.cpp @@ -147,6 +147,9 @@ namespace opt { void core_maxsat::collect_statistics(statistics& st) const { // nothing specific } + void core_maxsat::updt_params(params_ref& p) { + // no-op + } void core_maxsat::get_model(model_ref& mdl) { mdl = m_model.get(); if (!mdl) { diff --git a/src/opt/core_maxsat.h b/src/opt/core_maxsat.h index 623868dc7..f5a1a9bb3 100644 --- a/src/opt/core_maxsat.h +++ b/src/opt/core_maxsat.h @@ -43,6 +43,7 @@ namespace opt { virtual void set_cancel(bool f); virtual void collect_statistics(statistics& st) const; virtual void get_model(model_ref& mdl); + virtual void updt_params(params_ref& p); private: void set2vector(expr_set const& set, ptr_vector& es) const; expr_ref mk_at_most(expr_set const& set, unsigned k); diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index 3769bdd73..feb82eb2c 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -368,6 +368,10 @@ namespace opt { m_imp->get_model(m); } + void fu_malik::updt_params(params_ref& p) { + // no-op + } + diff --git a/src/opt/fu_malik.h b/src/opt/fu_malik.h index 5dd0cbf50..e9c994faf 100644 --- a/src/opt/fu_malik.h +++ b/src/opt/fu_malik.h @@ -42,6 +42,7 @@ namespace opt { virtual void set_cancel(bool f); virtual void collect_statistics(statistics& st) const; virtual void get_model(model_ref& m); + virtual void updt_params(params_ref& p); }; }; diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 8f77cdf85..f8a26d687 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -51,6 +51,7 @@ namespace opt { } if (m_msolver) { + m_msolver->updt_params(m_params); is_sat = (*m_msolver)(); if (is_sat == l_true) { m_msolver->get_model(m_model); @@ -149,6 +150,10 @@ namespace opt { void maxsmt::updt_params(params_ref& p) { opt_params _p(p); m_maxsat_engine = _p.maxsat_engine(); + m_params = p; + if (m_msolver) { + m_msolver->updt_params(p); + } } void maxsmt::collect_statistics(statistics& st) const { diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 4a2822367..9eb1f66f5 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -34,6 +34,8 @@ namespace opt { virtual void set_cancel(bool f) = 0; virtual void collect_statistics(statistics& st) const = 0; virtual void get_model(model_ref& mdl) = 0; + virtual void updt_params(params_ref& p) = 0; + }; /** Takes solver with hard constraints added. @@ -52,6 +54,7 @@ namespace opt { scoped_ptr m_msolver; symbol m_maxsat_engine; model_ref m_model; + params_ref m_params; public: maxsmt(ast_manager& m): m(m), m_s(0), m_cancel(false), m_soft_constraints(m), m_answer(m) {} diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 3cbc3d3a1..87895b33b 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -193,7 +193,14 @@ namespace opt { tactic_ref tac0 = mk_simplify_tactic(m); tactic_ref tac1 = mk_elim01_tactic(m); tactic_ref tac2 = mk_lia2card_tactic(m); - tactic_ref tac = and_then(tac0.get(), tac1.get(), tac2.get()); + tactic_ref tac; + opt_params optp(m_params); + if (optp.elim_01()) { + tac = and_then(tac0.get(), tac1.get(), tac2.get()); + } + else { + tac = tac0; + } proof_converter_ref pc; expr_dependency_ref core(m); goal_ref_buffer result; diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index 868906858..0dd01d358 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -8,6 +8,11 @@ def_module_params('opt', ('dump_benchmarks', BOOL, False, 'dump benchmarks for profiling'), ('print_model', BOOL, False, 'display model for satisfiable constraints'), ('debug_conflict', BOOL, False, 'debug conflict resolution'), + ('wmaxsat_engine', SYMBOL, 'wmax', "weighted maxsat engine: 'wmax', 'iwmax' (iterative), 'bwmax' (bisection)"), + ('pb_conflict_freq', UINT, 0, 'conflict frequency for pb theory'), + ('pb_learn_comp', BOOL, True, 'learn complement literals'), + ('elim_01', BOOL, True, 'eliminate 01 variables') + )) diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 4dbe08697..eb97d49b0 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -18,14 +18,16 @@ Notes: Based directly on smt_solver. --*/ -#include"reg_decl_plugins.h" -#include"opt_solver.h" -#include"smt_context.h" -#include"theory_arith.h" -#include"theory_diff_logic.h" +#include "reg_decl_plugins.h" +#include "opt_solver.h" +#include "smt_context.h" +#include "theory_arith.h" +#include "theory_diff_logic.h" +#include "theory_pb.h" #include "ast_pp.h" #include "ast_smt_pp.h" #include "pp_params.hpp" +#include "opt_params.hpp" #include "model_smt2_pp.h" namespace opt { @@ -46,10 +48,18 @@ namespace opt { opt_solver::~opt_solver() { } - void opt_solver::updt_params(params_ref const & p) { - m_dump_benchmarks = p.get_bool("dump_benchmarks", false); - m_params.updt_params(p); - m_context.updt_params(p); + void opt_solver::updt_params(params_ref & _p) { + opt_params p(_p); + m_dump_benchmarks = p.dump_benchmarks(); + m_params.updt_params(_p); + m_context.updt_params(_p); + smt::theory_id th_id = m.get_family_id("pb"); + smt::theory* _th = get_context().get_theory(th_id); + if (_th) { + smt::theory_pb* th = dynamic_cast(_th); + th->set_conflict_frequency(p.pb_conflict_freq()); + th->set_learn_complements(p.pb_learn_comp()); + } } void opt_solver::collect_param_descrs(param_descrs & r) { diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 9d452193e..141108d0a 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -55,7 +55,7 @@ namespace opt { opt_solver(ast_manager & m, params_ref const & p, symbol const & l); virtual ~opt_solver(); - virtual void updt_params(params_ref const & p); + virtual void updt_params(params_ref & p); virtual void collect_param_descrs(param_descrs & r); virtual void collect_statistics(statistics & st) const; virtual void assert_expr(expr * t); diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 427725fbe..1b25ba688 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -20,14 +20,23 @@ Notes: #include "smt_theory.h" #include "smt_context.h" #include "ast_pp.h" +#include "opt_params.hpp" +#include "pb_decl_plugin.h" namespace smt { class theory_weighted_maxsat : public theory { + struct stats { + unsigned m_num_blocks; + void reset() { memset(this, 0, sizeof(*this)); } + stats() { reset(); } + }; + opt::opt_solver& s; app_ref_vector m_vars; // Auxiliary variables per soft clause expr_ref_vector m_fmls; // Formulas per soft clause app_ref m_min_cost_atom; // atom tracking modified lower bound + app_ref_vector m_min_cost_atoms; bool_var m_min_cost_bv; // max cost Boolean variable vector m_weights; // weights of theory variables. svector m_costs; // set of asserted theory variables @@ -38,6 +47,7 @@ namespace smt { svector m_var2bool; // theory_var -> bool_var bool m_propagate; svector m_assigned; + stats m_stats; public: theory_weighted_maxsat(ast_manager& m, opt::opt_solver& s): @@ -46,6 +56,7 @@ namespace smt { m_vars(m), m_fmls(m), m_min_cost_atom(m), + m_min_cost_atoms(m), m_propagate(false) {} @@ -88,41 +99,8 @@ namespace smt { bool initialized = !m_var2bool.empty(); m_propagate = true; - for (unsigned i = 0; !initialized && i < m_vars.size(); ++i) { - app* var = m_vars[i].get(); - bool_var bv; - theory_var v; - SASSERT(!ctx.e_internalized(var)); - enode* x = ctx.mk_enode(var, false, true, true); - if (ctx.b_internalized(var)) { - bv = ctx.get_bool_var(var); - } - else { - bv = ctx.mk_bool_var(var); - } - ctx.set_var_theory(bv, get_id()); - ctx.set_enode_flag(bv, true); - v = mk_var(x); - ctx.attach_th_var(x, this, v); - m_bool2var.insert(bv, v); - SASSERT(v == m_var2bool.size()); - SASSERT(i == v); - m_var2bool.push_back(bv); - SASSERT(ctx.bool_var2enode(bv)); - } - - if (!initialized && m_min_cost_atom) { - app* var = m_min_cost_atom; - if (!ctx.e_internalized(var)) { - ctx.mk_enode(var, false, true, true); - } - if (ctx.b_internalized(var)) { - m_min_cost_bv = ctx.get_bool_var(var); - } - else { - m_min_cost_bv = ctx.mk_bool_var(var); - } - ctx.set_enode_flag(m_min_cost_bv, true); + for (unsigned i = 0; i < m_min_cost_atoms.size(); ++i) { + app* var = m_min_cost_atoms[i].get(); } } @@ -139,6 +117,33 @@ namespace smt { m_fmls.push_back(fml); m_assigned.push_back(false); m_min_cost += w; + + register_var(var, true); + } + + bool_var register_var(app* var, bool attach) { + context & ctx = get_context(); + ast_manager& m = get_manager(); + bool_var bv; + SASSERT(!ctx.e_internalized(var)); + enode* x = ctx.mk_enode(var, false, true, true); + if (ctx.b_internalized(var)) { + bv = ctx.get_bool_var(var); + } + else { + bv = ctx.mk_bool_var(var); + } + ctx.set_enode_flag(bv, true); + if (attach) { + ctx.set_var_theory(bv, get_id()); + theory_var v = mk_var(x); + ctx.attach_th_var(x, this, v); + m_bool2var.insert(bv, v); + SASSERT(v == m_var2bool.size()); + m_var2bool.push_back(bv); + SASSERT(ctx.bool_var2enode(bv)); + } + return bv; } rational const& get_min_cost() const { @@ -151,7 +156,11 @@ namespace smt { strm << "cost <= " << c; m_min_cost = c; m_min_cost_atom = m.mk_fresh_const(strm.str().c_str(), m.mk_bool_sort()); + m_min_cost_atoms.push_back(m_min_cost_atom); s.mc().insert(m_min_cost_atom->get_decl()); + + m_min_cost_bv = register_var(m_min_cost_atom, false); + return m_min_cost_atom; } @@ -206,8 +215,10 @@ namespace smt { m_bool2var.reset(); m_var2bool.reset(); m_min_cost_atom = 0; + m_min_cost_atoms.reset(); m_propagate = false; m_assigned.reset(); + m_stats.reset(); } virtual theory * mk_fresh(context * new_ctx) { return 0; } @@ -216,6 +227,10 @@ namespace smt { virtual void new_eq_eh(theory_var v1, theory_var v2) { } virtual void new_diseq_eh(theory_var v1, theory_var v2) { } + virtual void collect_statistics(::statistics & st) const { + st.update("wmaxsat num blocks", m_stats.m_num_blocks); + } + virtual bool can_propagate() { return m_propagate; } @@ -253,7 +268,7 @@ namespace smt { disj.push_back(m.mk_not(m_min_cost_atom)); } if (is_optimal()) { - IF_VERBOSE(1, verbose_stream() << "(wmaxsat with lower bound: " << weight << ")\n";); + IF_VERBOSE(1, verbose_stream() << "(wmaxsat with upper bound: " << weight << ")\n";); m_min_cost = weight; m_cost_save.reset(); m_cost_save.append(m_costs); @@ -281,6 +296,7 @@ namespace smt { if (m_vars.empty()) { return; } + ++m_stats.m_num_blocks; ast_manager& m = get_manager(); context& ctx = get_context(); literal_vector lits; @@ -317,43 +333,12 @@ namespace smt { return m_th.m_weights[v] > m_th.m_weights[w]; } }; - - }; } namespace opt { - /** - Iteratively increase cost until there is an assignment during - final_check that satisfies min_cost. - - Takes: log (n / log(n)) iterations - */ - - static lbool iterative_weighted_maxsat(opt_solver& s, smt::theory_weighted_maxsat& wth) { - ast_manager& m = s.get_context().get_manager(); - rational cost = wth.get_min_cost(); - rational log_cost(1), tmp(1); - while (tmp < cost) { - ++log_cost; - tmp *= rational(2); - } - expr_ref_vector bounds(m); - expr_ref bound(m); - lbool result = l_false; - while (log_cost <= cost && !wth.found_solution() && result != l_undef) { - std::cout << "cost: " << log_cost << "\n"; - bound = wth.set_min_cost(log_cost); - bounds.push_back(bound); - result = s.check_sat_core(1,bounds.c_ptr()+bounds.size()-1); - log_cost *= rational(2); - } - return result; - } - - struct wmaxsmt::imp { ast_manager& m; opt_solver& s; @@ -363,6 +348,7 @@ namespace opt { rational m_upper; rational m_lower; model_ref m_model; + symbol m_engine; volatile bool m_cancel; imp(ast_manager& m, opt_solver& s, expr_ref_vector& soft_constraints, vector const& weights): @@ -403,44 +389,17 @@ namespace opt { */ lbool operator()() { - TRACE("opt", tout << "weighted maxsat\n";); - smt::theory_weighted_maxsat& wth = ensure_theory(); - lbool is_sat = l_true; - { - solver::scoped_push _s(s); - bool was_sat = false; - for (unsigned i = 0; i < m_soft.size(); ++i) { - wth.assert_weighted(m_soft[i].get(), m_weights[i]); - } - while (l_true == is_sat) { - is_sat = s.check_sat_core(0,0); - if (m_cancel) { - is_sat = l_undef; - } - if (is_sat == l_true) { - if (wth.is_optimal()) { - s.get_model(m_model); - } - expr_ref fml = wth.mk_block(); - s.assert_expr(fml); - was_sat = true; - } - } - if (was_sat) { - wth.get_assignment(m_assignment); - } - if (is_sat == l_false && was_sat) { - is_sat = l_true; - } + if (m_engine == symbol("iwmax")) { + return iterative_solve(); } - m_upper = wth.get_min_cost(); - if (is_sat == l_true) { - m_lower = m_upper; + if (m_engine == symbol("bwmax")) { + return bisection_solve(); } - TRACE("opt", tout << "min cost: " << m_upper << "\n";); - wth.reset(); - return is_sat; - } + if (m_engine == symbol("pwmax")) { + return pb_solve(); + } + return incremental_solve(); + } rational get_lower() const { return m_lower; @@ -454,6 +413,219 @@ namespace opt { mdl = m_model.get(); } + + + lbool incremental_solve() { + TRACE("opt", tout << "weighted maxsat\n";); + smt::theory_weighted_maxsat& wth = ensure_theory(); + solver::scoped_push _s(s); + lbool is_sat = l_true; + bool was_sat = false; + for (unsigned i = 0; i < m_soft.size(); ++i) { + wth.assert_weighted(m_soft[i].get(), m_weights[i]); + } + solver::scoped_push __s(s); + while (l_true == is_sat) { + is_sat = s.check_sat_core(0,0); + if (m_cancel) { + is_sat = l_undef; + } + if (is_sat == l_true) { + if (wth.is_optimal()) { + s.get_model(m_model); + } + expr_ref fml = wth.mk_block(); + s.assert_expr(fml); + was_sat = true; + } + } + if (was_sat) { + wth.get_assignment(m_assignment); + } + if (is_sat == l_false && was_sat) { + is_sat = l_true; + } + m_upper = wth.get_min_cost(); + if (is_sat == l_true) { + m_lower = m_upper; + } + TRACE("opt", tout << "min cost: " << m_upper << "\n";); + return is_sat; + } + + /** + Iteratively increase cost until there is an assignment during + final_check that satisfies min_cost. + + Takes: log (n / log(n)) iterations + */ + + lbool iterative_solve() { + smt::theory_weighted_maxsat& wth = ensure_theory(); + solver::scoped_push _s(s); + for (unsigned i = 0; i < m_soft.size(); ++i) { + wth.assert_weighted(m_soft[i].get(), m_weights[i]); + } + solver::scoped_push __s(s); + rational cost = wth.get_min_cost(); + rational log_cost(1), tmp(1); + while (tmp < cost) { + ++log_cost; + tmp *= rational(2); + } + expr_ref_vector bounds(m); + expr_ref bound(m); + lbool result = l_false; + unsigned nsc = 0; + m_upper = cost; + while (log_cost <= cost && result == l_false) { + bound = wth.set_min_cost(log_cost); + s.push_core(); + ++nsc; + IF_VERBOSE(1, verbose_stream() << "(wmaxsat.iwmax min cost: " << log_cost << ")\n";); + TRACE("opt", tout << "cost: " << log_cost << " " << bound << "\n";); + bounds.push_back(bound); + result = conditional_solve(bound); + if (result == l_false) { + m_lower = log_cost; + } + log_cost *= rational(2); + if (m_cancel) { + result = l_undef; + } + } + s.pop_core(nsc); + return result; + } + + lbool conditional_solve(expr* cond) { + smt::theory_weighted_maxsat& wth = *get_theory(); + bool was_sat = false; + lbool is_sat = l_true; + while (l_true == is_sat) { + is_sat = s.check_sat_core(1,&cond); + if (m_cancel) { + is_sat = l_undef; + } + if (is_sat == l_true) { + if (wth.is_optimal()) { + s.get_model(m_model); + was_sat = true; + } + expr_ref fml = wth.mk_block(); + s.assert_expr(fml); + } + } + if (was_sat) { + wth.get_assignment(m_assignment); + } + if (is_sat == l_false && was_sat) { + is_sat = l_true; + } + if (is_sat == l_true) { + m_lower = m_upper = wth.get_min_cost(); + } + TRACE("opt", tout << "min cost: " << m_upper << "\n";); + return is_sat; + } + + lbool bisection_solve() { + TRACE("opt", tout << "weighted maxsat\n";); + smt::theory_weighted_maxsat& wth = ensure_theory(); + solver::scoped_push _s(s); + lbool is_sat = l_true; + bool was_sat = false; + expr_ref_vector bounds(m); + for (unsigned i = 0; i < m_soft.size(); ++i) { + wth.assert_weighted(m_soft[i].get(), m_weights[i]); + } + solver::scoped_push __s(s); + m_lower = rational::zero(); + m_upper = wth.get_min_cost(); + while (m_lower < m_upper) { + rational cost = div(m_upper + m_lower, rational(2)); + bounds.push_back(wth.set_min_cost(cost)); + is_sat = s.check_sat_core(1,bounds.c_ptr()+bounds.size()-1); + if (m_cancel) { + is_sat = l_undef; + } + switch(is_sat) { + case l_true: { + if (wth.is_optimal()) { + s.get_model(m_model); + } + expr_ref fml = wth.mk_block(); + s.assert_expr(fml); + m_upper = wth.get_min_cost(); + break; + } + case l_false: { + m_lower = cost; + IF_VERBOSE(1, verbose_stream() << "(wmaxsat.bwmax min cost: " << m_lower << ")\n";); + break; + } + case l_undef: + return l_undef; + } + } + if (was_sat) { + is_sat = l_true; + } + return is_sat; + } + + // convert bounds constraint into pseudo-Boolean + + lbool pb_solve() { + pb_util u(m); + expr_ref fml(m), val(m); + expr_ref_vector nsoft(m); + m_lower = m_upper = rational::zero(); + rational minw(0); + for (unsigned i = 0; i < m_soft.size(); ++i) { + m_upper += m_weights[i]; + if (m_weights[i] < minw || minw.is_zero()) { + minw = m_weights[i]; + } + nsoft.push_back(m.mk_not(m_soft[i].get())); + } + solver::scoped_push __s(s); + lbool is_sat = l_true; + bool was_sat = false; + while (l_true == is_sat) { + is_sat = s.check_sat_core(0,0); + if (m_cancel) { + is_sat = l_undef; + } + if (is_sat == l_true) { + s.get_model(m_model); + m_upper = rational::zero(); + for (unsigned i = 0; i < m_soft.size(); ++i) { + VERIFY(m_model->eval(m_soft[i].get(), val)); + m_assignment[i] = !m.is_false(val); + if (!m_assignment[i]) { + m_upper += m_weights[i]; + } + } + + IF_VERBOSE(1, verbose_stream() << "(wmaxsat.pb with upper bound: " << m_upper << ")\n";); + fml = u.mk_le(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper - minw); + s.assert_expr(fml); + was_sat = true; + } + } + if (is_sat == l_false && was_sat) { + is_sat = l_true; + m_lower = m_upper; + } + return is_sat; + } + + void updt_params(params_ref& p) { + opt_params _p(p); + m_engine = _p.wmaxsat_engine(); + } + }; wmaxsmt::wmaxsmt(ast_manager& m, opt_solver& s, expr_ref_vector& soft_constraints, vector const& weights) { @@ -486,8 +658,9 @@ namespace opt { m_imp->get_model(mdl); } - - + void wmaxsmt::updt_params(params_ref& p) { + m_imp->updt_params(p); + } }; diff --git a/src/opt/weighted_maxsat.h b/src/opt/weighted_maxsat.h index deae79893..9a407ba56 100644 --- a/src/opt/weighted_maxsat.h +++ b/src/opt/weighted_maxsat.h @@ -40,6 +40,7 @@ namespace opt { virtual void set_cancel(bool f); virtual void collect_statistics(statistics& st) const; virtual void get_model(model_ref& mdl); + virtual void updt_params(params_ref& p); }; }; diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 9599eaacb..84d26e40b 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -1334,6 +1334,7 @@ namespace smt { TRACE("propagate_bool_var_enode_bug", tout << "var: " << v << " #" << bool_var2expr(v)->get_id() << "\n";); SASSERT(v < static_cast(m_b_internalized_stack.size())); enode * n = bool_var2enode(v); + CTRACE("mk_bool_var", !n, tout << "No enode for " << v << "\n";); bool sign = val == l_false; if (n->merge_tf()) add_eq(n, sign ? m_false_enode : m_true_enode, eq_justification(literal(v, sign))); diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 3b9ed85cc..0777edf10 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -328,7 +328,9 @@ namespace smt { theory_pb::theory_pb(ast_manager& m): theory(m.mk_family_id("pb")), m_util(m), - m_lemma(null_literal) + m_lemma(null_literal), + m_learn_complements(false), + m_conflict_frequency(0xF) {} theory_pb::~theory_pb() { @@ -716,10 +718,11 @@ namespace smt { numeral k = c.k(); numeral coeff = c.coeff(w); - - for (unsigned i = c.watch_size(); c.watch_sum() - coeff < k + c.max_watch() && i < c.size(); ++i) { + bool add_more = c.watch_sum() - coeff < k + c.max_watch(); + for (unsigned i = c.watch_size(); add_more && i < c.size(); ++i) { if (ctx.get_assignment(c.lit(i)) != l_false) { add_watch(c, i); + add_more = c.watch_sum() - coeff < k + c.max_watch(); } } @@ -750,8 +753,9 @@ namespace smt { literal_vector& lits = get_unhelpful_literals(c, true); lits.push_back(c.lit()); + numeral deficit = c.watch_sum() - k; for (unsigned i = 0; i < c.size(); ++i) { - if (c.watch_sum() - c.coeff(i) < k && ctx.get_assignment(c.lit(i)) == l_undef) { + if (ctx.get_assignment(c.lit(i)) == l_undef && deficit < c.coeff(i)) { DEBUG_CODE(validate_assign(c, lits, c.lit(i));); add_assign(c, lits, c.lit(i)); } @@ -1044,12 +1048,18 @@ namespace smt { tout << "\n"; display(tout, c, true);); - if (true || (c.m_num_propagations & 0xF) == 0) { + justification* js = 0; + + if (m_conflict_frequency == 0 || (0 == (c.m_num_propagations % m_conflict_frequency))) { resolve_conflict(c); } - justification* js = 0; ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); + + // if (true || (c.m_num_propagations & 0xF) == 0) { + // resolve_conflict(c); + //} + } @@ -1090,7 +1100,7 @@ namespace smt { if (ctx.get_assignment(l) != l_false) { m_lemma.m_k -= coeff; - if (true && false && is_marked(v)) { + if (m_learn_complements && is_marked(v)) { SASSERT(ctx.get_assignment(l) == l_true); numeral& lcoeff = m_lemma.m_args[m_conseq_index[v]].second; lcoeff -= coeff; diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 9a4c18ed4..66a8eccba 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -111,6 +111,8 @@ namespace smt { pb_util m_util; stats m_stats; ptr_vector m_to_compile; // inequalities to compile. + unsigned m_conflict_frequency; + bool m_learn_complements; // internalize_atom: literal compile_arg(expr* arg); @@ -189,5 +191,8 @@ namespace smt { virtual void collect_statistics(::statistics & st) const; virtual model_value_proc * mk_value(enode * n, model_generator & mg); virtual void init_model(model_generator & m); + + void set_conflict_frequency(unsigned f) { m_conflict_frequency = f; } + void set_learn_complements(bool l) { m_learn_complements = l; } }; }; From 6aa00869690d7c9234f11236419624d5b7223f69 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 20 Dec 2013 16:46:23 -0800 Subject: [PATCH 239/925] adding wpm2 algorithm Signed-off-by: Nikolaj Bjorner --- src/opt/weighted_maxsat.cpp | 197 ++++++++++++++++++++++++++++++++++-- src/smt/smt_context.cpp | 6 +- src/smt/theory_pb.cpp | 3 + 3 files changed, 197 insertions(+), 9 deletions(-) diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 1b25ba688..0619953b9 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -22,6 +22,7 @@ Notes: #include "ast_pp.h" #include "opt_params.hpp" #include "pb_decl_plugin.h" +#include "uint_set.h" namespace smt { @@ -85,7 +86,7 @@ namespace smt { for (unsigned i = 0; i < m_vars.size(); ++i) { tout << mk_pp(m_vars[i].get(), get_manager()) << " "; } - tout << "\nassignment"; + tout << "\nassignment: "; for (unsigned i = 0; i < result.size(); ++i) { tout << result[i] << " "; } @@ -350,12 +351,17 @@ namespace opt { model_ref m_model; symbol m_engine; volatile bool m_cancel; + params_ref m_params; + opt_solver m_solver; + scoped_ptr m_imp; - imp(ast_manager& m, opt_solver& s, expr_ref_vector& soft_constraints, vector const& weights): - m(m), s(s), m_soft(soft_constraints), m_weights(weights), m_cancel(false) + imp(ast_manager& m, opt_solver& s, expr_ref_vector const& soft_constraints, vector const& weights): + m(m), s(s), m_soft(soft_constraints), m_weights(weights), m_cancel(false), + m_solver(m, m_params, symbol("bound")) { m_assignment.resize(m_soft.size(), false); } + ~imp() {} smt::theory_weighted_maxsat* get_theory() const { @@ -398,6 +404,9 @@ namespace opt { if (m_engine == symbol("pwmax")) { return pb_solve(); } + if (m_engine == symbol("wpm2")) { + return wpm2_solve(); + } return incremental_solve(); } @@ -606,8 +615,7 @@ namespace opt { if (!m_assignment[i]) { m_upper += m_weights[i]; } - } - + } IF_VERBOSE(1, verbose_stream() << "(wmaxsat.pb with upper bound: " << m_upper << ")\n";); fml = u.mk_le(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper - minw); s.assert_expr(fml); @@ -621,6 +629,178 @@ namespace opt { return is_sat; } + lbool wpm2_solve() { + solver::scoped_push _s(s); + pb_util u(m); + app_ref fml(m), a(m), b(m), c(m); + expr_ref val(m); + expr_ref_vector block(m), ans(m), al(m), am(m); + m_lower = m_upper = rational::zero(); + obj_map ans_index; + vector amk; + vector sc; + for (unsigned i = 0; i < m_soft.size(); ++i) { + rational w = m_weights[i]; + m_upper += w; + + b = m.mk_fresh_const("b", m.mk_bool_sort()); + s.mc().insert(b->get_decl()); + block.push_back(b); + expr* bb = b; + + a = m.mk_fresh_const("a", m.mk_bool_sort()); + s.mc().insert(a->get_decl()); + ans.push_back(a); + ans_index.insert(a, i); + fml = m.mk_or(m_soft[i].get(), b, m.mk_not(a)); + s.assert_expr(fml); + + c = m.mk_fresh_const("c", m.mk_bool_sort()); + s.mc().insert(c->get_decl()); + fml = m.mk_implies(c, u.mk_le(1,&w,&bb,rational(0))); + s.assert_expr(fml); + + sc.push_back(uint_set()); + sc.back().insert(i); + am.push_back(c); + amk.push_back(rational(0)); + } + + while (true) { + expr_ref_vector asms(m); + ptr_vector core; + asms.append(ans); + asms.append(am); + lbool is_sat = s.check_sat(asms.size(), asms.c_ptr()); + if (m_cancel && is_sat != l_false) { + is_sat = l_undef; + } + if (is_sat == l_true) { + s.get_model(m_model); + m_upper = m_lower; + for (unsigned i = 0; i < block.size(); ++i) { + VERIFY(m_model->eval(block[i].get(), val)); + m_assignment[i] = m.is_false(val); + } + } + if (is_sat != l_false) { + return is_sat; + } + s.get_unsat_core(core); + if (core.empty()) { + return l_false; + } + uint_set A; + for (unsigned i = 0; i < core.size(); ++i) { + unsigned j; + if (ans_index.find(core[i], j)) { + A.insert(j); + } + } + if (A.empty()) { + return l_false; + } + uint_set B; + for (unsigned i = 0; i < sc.size(); ++i) { + uint_set t(sc[i]); + t &= A; + if (!t.empty()) { + B |= sc[i]; + m_lower -= amk[i]; + sc[i] = sc.back(); + sc.pop_back(); + am[i] = am.back(); + am.pop_back(); + amk[i] = amk.back(); + amk.pop_back(); + --i; + } + } + vector ws; + expr_ref_vector bs(m); + for (unsigned i = 0; i < m_soft.size(); ++i) { + if (B.contains(i)) { + ws.push_back(m_weights[i]); + bs.push_back(block[i].get()); + } + } + rational k; + is_sat = new_bound(al, ws, bs, k); + if (is_sat != l_true) { + return is_sat; + } + m_lower += k; + expr_ref B_le_k(m), B_ge_k(m); + B_le_k = u.mk_le(ws.size(), ws.c_ptr(), bs.c_ptr(), k); + B_ge_k = u.mk_ge(ws.size(), ws.c_ptr(), bs.c_ptr(), k); + s.assert_expr(B_ge_k); + al.push_back(B_ge_k); + IF_VERBOSE(1, verbose_stream() << "(wmaxsat.wpm2 lower bound: " << m_lower << ")\n";); + IF_VERBOSE(2, verbose_stream() << "New lower bound: " << B_ge_k << "\n";); + + c = m.mk_fresh_const("c", m.mk_bool_sort()); + s.mc().insert(c->get_decl()); + fml = m.mk_implies(c, B_le_k); + s.assert_expr(fml); + sc.push_back(B); + am.push_back(c); + amk.push_back(k); + } + } + + lbool new_bound(expr_ref_vector const& al, + vector const& ws, + expr_ref_vector const& bs, + rational& k) { + pb_util u(m); + lbool is_sat = bound(al, ws, bs, k); + if (is_sat != l_true) return is_sat; +#if 1 + rational mininc(0); + for (unsigned i = 0; i < ws.size(); ++i) { + if (mininc.is_zero() || mininc > ws[i]) { + mininc = ws[i]; + } + } + k += mininc; +#else + expr_ref_vector al2(m); + al2.append(al); + // w_j*b_j > k + rational k0 = k; + al2.push_back(m.mk_not(u.mk_le(ws.size(), ws.c_ptr(), bs.c_ptr(), k))); + is_sat = bound(al2, ws, bs, k); + if (is_sat == l_true) { + SASSERT(k > k0); + } +#endif + return is_sat; + } + + // + // minimal k, such that al & w_j*b_j >= k is sat + // minimal k, such that al & 3*x + 4*y >= k is sat + // minimal k, such that al & (or (not x) w3) & (or (not y) w4) + // + lbool bound(expr_ref_vector const& al, + vector const& ws, + expr_ref_vector const& bs, + rational& k) { + expr_ref_vector nbs(m); + m_solver.push_core(); + for (unsigned i = 0; i < al.size(); ++i) { + m_solver.assert_expr(al[i]); + } + for (unsigned i = 0; i < bs.size(); ++i) { + nbs.push_back(m.mk_not(bs[i])); + } + m_imp = alloc(imp, m, m_solver, nbs, ws); // race condition. + lbool is_sat = m_imp->pb_solve(); + k = m_imp->m_lower; + m_solver.pop_core(1); + return is_sat; + } + void updt_params(params_ref& p) { opt_params _p(p); m_engine = _p.wmaxsat_engine(); @@ -650,9 +830,14 @@ namespace opt { } void wmaxsmt::set_cancel(bool f) { m_imp->m_cancel = f; + m_imp->m_solver.set_cancel(f); + // TBD race + if (m_imp->m_imp) { + m_imp->m_imp->m_cancel = f; + } } void wmaxsmt::collect_statistics(statistics& st) const { - // no-op + m_imp->m_solver.collect_statistics(st); } void wmaxsmt::get_model(model_ref& mdl) { m_imp->get_model(mdl); diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 84d26e40b..2cce3931e 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -199,6 +199,9 @@ namespace smt { bool context::bcp() { SASSERT(!inconsistent()); while (m_qhead < m_assigned_literals.size()) { + if (m_cancel_flag) { + return true; + } literal l = m_assigned_literals[m_qhead]; SASSERT(get_assignment(l) == l_true); m_qhead++; @@ -225,9 +228,6 @@ namespace smt { case l_true: break; } - if (m_cancel_flag) { - return true; - } } } diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 0777edf10..755bc4c2c 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -35,6 +35,7 @@ namespace smt { sum += coeff(i); } m_k = sum - m_k + numeral::one(); + VERIFY(l_undef == normalize()); SASSERT(well_formed()); } @@ -381,9 +382,11 @@ namespace smt { else { SASSERT(m_util.is_at_least_k(atom) || m_util.is_ge(atom)); } + TRACE("pb", display(tout, *c);); c->unique(); lbool is_true = c->normalize(); c->prune(); + TRACE("pb", display(tout, *c);); literal lit(abv); From 670f56e5e4fad8990f00ab7878a450cb08a9a746 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 21 Dec 2013 07:09:39 -0800 Subject: [PATCH 240/925] adjust benchmark generation Signed-off-by: Nikolaj Bjorner --- src/opt/opt_solver.cpp | 8 ++++---- src/opt/opt_solver.h | 2 +- src/opt/weighted_maxsat.cpp | 11 +++++++---- src/smt/theory_pb.cpp | 13 ++++++++++++- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index eb97d49b0..c437e48f1 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -38,12 +38,13 @@ namespace opt { m_context(mgr, m_params), m(mgr), m_dump_benchmarks(false), - m_dump_count(0), m_fm(m) { m_logic = l; if (m_logic != symbol::null) m_context.set_logic(m_logic); } + + unsigned opt_solver::m_dump_count = 0; opt_solver::~opt_solver() { } @@ -119,15 +120,14 @@ namespace opt { tout << mk_pp(m_context.get_formulas()[i], m_context.m()) << "\n"; } }); - - lbool r = m_context.check(num_assumptions, assumptions); if (dump_benchmarks()) { std::stringstream file_name; file_name << "opt_solver" << ++m_dump_count << ".smt2"; std::ofstream buffer(file_name.str().c_str()); - to_smt2_benchmark(buffer, "opt_solver", "QF_BV"); + to_smt2_benchmark(buffer, "opt_solver", ""); buffer.close(); } + lbool r = m_context.check(num_assumptions, assumptions); return r; } diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 141108d0a..eb5812317 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -48,7 +48,7 @@ namespace opt { svector m_objective_vars; vector m_objective_values; bool m_dump_benchmarks; - unsigned m_dump_count; + static unsigned m_dump_count; statistics m_stats; filter_model_converter m_fm; public: diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 0619953b9..b9a9cfbcc 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -246,9 +246,7 @@ namespace smt { } } m_propagate = false; - } - - + } bool is_optimal() const { return m_cost < m_min_cost; @@ -755,7 +753,7 @@ namespace opt { pb_util u(m); lbool is_sat = bound(al, ws, bs, k); if (is_sat != l_true) return is_sat; -#if 1 +#if 0 rational mininc(0); for (unsigned i = 0; i < ws.size(); ++i) { if (mininc.is_zero() || mininc > ws[i]) { @@ -795,6 +793,7 @@ namespace opt { nbs.push_back(m.mk_not(bs[i])); } m_imp = alloc(imp, m, m_solver, nbs, ws); // race condition. + m_imp->updt_params(m_params); lbool is_sat = m_imp->pb_solve(); k = m_imp->m_lower; m_solver.pop_core(1); @@ -804,6 +803,10 @@ namespace opt { void updt_params(params_ref& p) { opt_params _p(p); m_engine = _p.wmaxsat_engine(); + m_solver.updt_params(p); + if (m_imp) { + m_imp->updt_params(p); + } } }; diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 755bc4c2c..df71ce969 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -388,8 +388,8 @@ namespace smt { c->prune(); TRACE("pb", display(tout, *c);); - literal lit(abv); + switch(is_true) { case l_false: lit = ~lit; @@ -405,6 +405,17 @@ namespace smt { // TBD: special cases: k == 1, or args.size() == 1 + if (c->k().is_one()) { + literal_vector& lits = get_lits(); + lits.push_back(~lit); + for (unsigned i = 0; i < c->size(); ++i) { + lits.push_back(c->lit(i)); + SASSERT(c->coeff(i).is_one()); + ctx.mk_th_axiom(get_id(), lit, ~c->lit(i)); + } + ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); + return true; + } // maximal coefficient: From 24f2fd380c6fdb75a2933adcf06d243a072e88e7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 23 Dec 2013 01:33:24 -0800 Subject: [PATCH 241/925] adding pre-processing of BP constraints Signed-off-by: Nikolaj Bjorner --- src/ast/pb_decl_plugin.h | 8 +- src/ast/rewriter/pb_rewriter.cpp | 113 +++++++-- src/ast/rewriter/pb_rewriter.h | 15 ++ src/ast/rewriter/pb_rewriter_def.h | 263 +++++++++++++++++++++ src/opt/weighted_maxsat.cpp | 60 +++-- src/smt/theory_arith_int.h | 3 +- src/smt/theory_pb.cpp | 279 ++++------------------- src/tactic/core/pb_preprocess_tactic.cpp | 185 +++++++++++++++ src/tactic/core/pb_preprocess_tactic.h | 34 +++ 9 files changed, 679 insertions(+), 281 deletions(-) create mode 100644 src/ast/rewriter/pb_rewriter_def.h create mode 100644 src/tactic/core/pb_preprocess_tactic.cpp create mode 100644 src/tactic/core/pb_preprocess_tactic.h diff --git a/src/ast/pb_decl_plugin.h b/src/ast/pb_decl_plugin.h index bc186433e..c590f8320 100644 --- a/src/ast/pb_decl_plugin.h +++ b/src/ast/pb_decl_plugin.h @@ -83,18 +83,18 @@ public: app * mk_le(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k); app * mk_ge(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k); bool is_at_most_k(func_decl *a) const; - bool is_at_most_k(app *a) const { return is_at_most_k(a->get_decl()); } + bool is_at_most_k(expr *a) const { return is_app(a) && is_at_most_k(to_app(a)->get_decl()); } bool is_at_most_k(app *a, rational& k) const; bool is_at_least_k(func_decl *a) const; - bool is_at_least_k(app *a) const { return is_at_most_k(a->get_decl()); } + bool is_at_least_k(expr *a) const { return is_app(a) && is_at_least_k(to_app(a)->get_decl()); } bool is_at_least_k(app *a, rational& k) const; rational get_k(func_decl *a) const; rational get_k(app *a) const { return get_k(a->get_decl()); } bool is_le(func_decl *a) const; - bool is_le(app *a) const { return is_le(a->get_decl()); } + bool is_le(expr *a) const { return is_app(a) && is_le(to_app(a)->get_decl()); } bool is_le(app* a, rational& k) const; bool is_ge(func_decl* a) const; - bool is_ge(app* a) const { return is_ge(a->get_decl()); } + bool is_ge(expr* a) const { return is_app(a) && is_ge(to_app(a)->get_decl()); } bool is_ge(app* a, rational& k) const; rational get_coeff(app* a, unsigned index) const { return get_coeff(a->get_decl(), index); } rational get_coeff(func_decl* a, unsigned index) const; diff --git a/src/ast/rewriter/pb_rewriter.cpp b/src/ast/rewriter/pb_rewriter.cpp index 462944943..5b1b37120 100644 --- a/src/ast/rewriter/pb_rewriter.cpp +++ b/src/ast/rewriter/pb_rewriter.cpp @@ -18,6 +18,60 @@ Notes: --*/ #include "pb_rewriter.h" +#include "pb_rewriter_def.h" +#include "ast_pp.h" + + +class pb_ast_rewriter_util { + ast_manager& m; + expr_ref_vector m_refs; +public: + + typedef std::pair arg_t; + typedef vector args_t; + typedef rational numeral; + + pb_ast_rewriter_util(ast_manager& m): m(m), m_refs(m) {} + + expr* negate(expr* e) { + if (m.is_true(e)) { + return m.mk_false(); + } + if (m.is_false(e)) { + return m.mk_true(); + } + if (m.is_not(e, e)) { + return e; + } + m_refs.push_back(m.mk_not(e)); + return m_refs.back(); + } + + void display(std::ostream& out, expr* e) { + out << mk_pp(e, m); + } + + bool is_negated(expr* e) const { + return m.is_not(e); + } + + bool is_true(expr* e) const { + return m.is_true(e); + } + + bool is_false(expr* e) const { + return m.is_false(e); + } + + struct compare { + bool operator()(std::pair const& a, + std::pair const& b) { + return a.first->get_id() < b.first->get_id(); + } + + }; +}; + br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { ast_manager& m = result.get_manager(); @@ -32,34 +86,59 @@ br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons } } rational k = m_util.get_k(f); + + vector > vec; + for (unsigned i = 0; i < num_args; ++i) { + vec.push_back(std::make_pair(args[i], m_util.get_coeff(f, i))); + } switch(f->get_decl_kind()) { case OP_AT_MOST_K: case OP_PB_LE: - if (sum > k) { - result = m.mk_false(); - return BR_DONE; + for (unsigned i = 0; i < num_args; ++i) { + vec[i].second.neg(); } - if (maxsum <= k) { - result = m.mk_true(); - return BR_DONE; - } - return BR_FAILED; + k.neg(); + break; case OP_AT_LEAST_K: case OP_PB_GE: - if (sum >= k) { - result = m.mk_true(); - return BR_DONE; - } - if (maxsum < k) { - result = m.mk_false(); - return BR_DONE; - } - return BR_FAILED; + break; default: UNREACHABLE(); return BR_FAILED; } + + + pb_ast_rewriter_util pbu(m); + pb_rewriter_util util(pbu); + + util.unique(vec, k); + lbool is_sat = util.normalize(vec, k); + util.prune(vec, k); + switch (is_sat) { + case l_true: + result = m.mk_true(); + break; + case l_false: + result = m.mk_false(); + break; + default: + m_args.reset(); + m_coeffs.reset(); + for (unsigned i = 0; i < vec.size(); ++i) { + m_args.push_back(vec[i].first); + m_coeffs.push_back(vec[i].second); + } + result = m_util.mk_ge(vec.size(), m_coeffs.c_ptr(), m_args.c_ptr(), k); + break; + } + TRACE("pb", + expr_ref tmp(m); + tmp = m.mk_app(f, num_args, args); + tout << tmp << "\n"; + tout << result << "\n";); + + return BR_DONE; } diff --git a/src/ast/rewriter/pb_rewriter.h b/src/ast/rewriter/pb_rewriter.h index da020cb7c..8ea41b668 100644 --- a/src/ast/rewriter/pb_rewriter.h +++ b/src/ast/rewriter/pb_rewriter.h @@ -22,12 +22,27 @@ Notes: #include"pb_decl_plugin.h" #include"rewriter_types.h" #include"params.h" +#include"lbool.h" + + +template +class pb_rewriter_util { + PBU& m_util; + void display(std::ostream& out, typename PBU::args_t& args, typename PBU::numeral& k); +public: + pb_rewriter_util(PBU& u) : m_util(u) {} + void unique(typename PBU::args_t& args, typename PBU::numeral& k); + lbool normalize(typename PBU::args_t& args, typename PBU::numeral& k); + void prune(typename PBU::args_t& args, typename PBU::numeral& k); +}; /** \brief Cheap rewrite rules for PB constraints */ class pb_rewriter { pb_util m_util; + vector m_coeffs; + ptr_vector m_args; public: pb_rewriter(ast_manager & m, params_ref const & p = params_ref()): m_util(m) { diff --git a/src/ast/rewriter/pb_rewriter_def.h b/src/ast/rewriter/pb_rewriter_def.h new file mode 100644 index 000000000..a6a37f73d --- /dev/null +++ b/src/ast/rewriter/pb_rewriter_def.h @@ -0,0 +1,263 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + pb_rewriter_def.h + +Abstract: + + Basic rewriting rules for PB constraints. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-14-12 + +Notes: + +--*/ +#ifndef _PB_REWRITER_DEF_H_ +#define _PB_REWRITER_DEF_H_ + +#include"pb_rewriter.h" + + +template +void pb_rewriter_util::display(std::ostream& out, typename PBU::args_t& args, typename PBU::numeral& k) { + for (unsigned i = 0; i < args.size(); ++i) { + out << args[i].second << " * "; + m_util.display(out, args[i].first); + out << " "; + if (i+1 < args.size()) out << "+ "; + } + out << " >= " << k << "\n"; +} + +template +void pb_rewriter_util::unique(typename PBU::args_t& args, typename PBU::numeral& k) { + + TRACE("pb", display(tout << "pre-unique:", args, k);); + for (unsigned i = 0; i < args.size(); ++i) { + if (m_util.is_negated(args[i].first)) { + args[i].first = m_util.negate(args[i].first); + k -= args[i].second; + args[i].second = -args[i].second; + } + } + // remove constants + for (unsigned i = 0; i < args.size(); ++i) { + if (m_util.is_true(args[i].first)) { + k -= args[i].second; + std::swap(args[i], args[args.size()-1]); + args.pop_back(); + --i; + } + else if (m_util.is_false(args[i].first)) { + std::swap(args[i], args[args.size()-1]); + args.pop_back(); + --i; + } + } + // sort and coalesce arguments: + PBU::compare cmp; + std::sort(args.begin(), args.end(), cmp); + + unsigned i = 0, j = 1; + for (; j < args.size(); ++i) { + SASSERT(j > i); + for (; j < args.size() && args[j].first == args[i].first; ++j) { + args[i].second += args[j].second; + } + if (j < args.size()) { + args[i+1].first = args[j].first; + args[i+1].second = args[j].second; + ++j; + } + } + if (i + 1 < args.size()) { + args.resize(i+1); + } + TRACE("pb", display(tout << "post-unique:", args, k);); +} + +template +lbool pb_rewriter_util::normalize(typename PBU::args_t& args, typename PBU::numeral& k) { + TRACE("pb", display(tout << "pre-normalize:", args, k);); + + // + // Ensure all coefficients are positive: + // c*l + y >= k + // <=> + // c*(1-~l) + y >= k + // <=> + // c - c*~l + y >= k + // <=> + // -c*~l + y >= k - c + // + PBU::numeral sum(0); + for (unsigned i = 0; i < args.size(); ++i) { + PBU::numeral c = args[i].second; + if (c.is_neg()) { + args[i].second = -c; + args[i].first = m_util.negate(args[i].first); + k -= c; + } + sum += args[i].second; + } + // detect tautologies: + if (k <= PBU::numeral::zero()) { + args.reset(); + k = PBU::numeral::zero(); + return l_true; + } + // detect infeasible constraints: + if (sum < k) { + args.reset(); + k = PBU::numeral::one(); + return l_false; + } + + bool all_int = true; + for (unsigned i = 0; all_int && i < args.size(); ++i) { + all_int = args[i].second.is_int(); + } + + if (!all_int) { + // normalize to integers. + PBU::numeral d(denominator(k)); + for (unsigned i = 0; i < args.size(); ++i) { + d = lcm(d, denominator(args[i].second)); + } + SASSERT(!d.is_one()); + k *= d; + for (unsigned i = 0; i < args.size(); ++i) { + args[i].second *= d; + } + } + + // Ensure the largest coefficient is not larger than k: + sum = PBU::numeral::zero(); + for (unsigned i = 0; i < args.size(); ++i) { + PBU::numeral c = args[i].second; + if (c > k) { + args[i].second = k; + } + sum += args[i].second; + } + SASSERT(!args.empty()); + + // normalize tight inequalities to unit coefficients. + if (sum == k) { + for (unsigned i = 0; i < args.size(); ++i) { + args[i].second = PBU::numeral::one(); + } + k = PBU::numeral(args.size()); + } + + // apply cutting plane reduction: + PBU::numeral g(0); + for (unsigned i = 0; !g.is_one() && i < args.size(); ++i) { + PBU::numeral c = args[i].second; + if (c != k) { + if (g.is_zero()) { + g = c; + } + else { + g = gcd(g, c); + } + } + } + if (g.is_zero()) { + // all coefficients are equal to k. + for (unsigned i = 0; i < args.size(); ++i) { + SASSERT(args[i].second == k); + args[i].second = PBU::numeral::one(); + } + k = PBU::numeral::one(); + } + else if (g > PBU::numeral::one()) { + IF_VERBOSE(3, verbose_stream() << "cut " << g << "\n"; + display(verbose_stream(), args, k); + ); + + // + // Example 5x + 5y + 2z + 2u >= 5 + // becomes 3x + 3y + z + u >= 3 + // + PBU::numeral k_new = div(k, g); + if (!(k % g).is_zero()) { // k_new is the ceiling of k / g. + k_new++; + } + for (unsigned i = 0; i < args.size(); ++i) { + SASSERT(args[i].second.is_pos()); + PBU::numeral c = args[i].second; + if (c == k) { + c = k_new; + } + else { + c = div(c, g); + } + args[i].second = c; + SASSERT(args[i].second.is_pos()); + } + k = k_new; + } + // + // normalize coefficients that fall within a range + // k/n <= ... < k/(n-1) for some n = 1,2,... + // + // e.g, k/n <= min <= max < k/(n-1) + // k/min <= n, n-1 < k/max + // . floor(k/max) = ceil(k/min) - 1 + // . floor(k/max) < k/max + // + // example: k = 5, min = 3, max = 4: 5/3 -> 2 5/4 -> 1, n = 2 + // replace all coefficients by 1, and k by 2. + // + if (!k.is_one()) { + PBU::numeral min = args[0].second, max = args[0].second; + for (unsigned i = 1; i < args.size(); ++i) { + if (args[i].second < min) min = args[i].second; + if (args[i].second > max) max = args[i].second; + } + PBU::numeral n0 = k/max; + PBU::numeral n1 = floor(n0); + PBU::numeral n2 = ceil(k/min) - PBU::numeral::one(); + if (n1 == n2 && !n0.is_int()) { + IF_VERBOSE(3, display(verbose_stream() << "set cardinality\n", args, k);); + + for (unsigned i = 0; i < args.size(); ++i) { + args[i].second = PBU::numeral::one(); + } + k = n1 + PBU::numeral::one(); + } + } + return l_undef; +} + + +template +void pb_rewriter_util::prune(typename PBU::args_t& args, typename PBU::numeral& k) { + + PBU::numeral nlt(0); + unsigned occ = 0; + for (unsigned i = 0; nlt < k && i < args.size(); ++i) { + if (args[i].second < k) { + nlt += args[i].second; + ++occ; + } + } + if (0 < occ && nlt < k) { + + for (unsigned i = 0; i < args.size(); ++i) { + if (args[i].second < k) { + args[i] = args.back(); + args.pop_back(); + --i; + } + } + normalize(args, k); + } +} + +#endif diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index b9a9cfbcc..6fae39bad 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -374,7 +374,7 @@ namespace opt { } } - smt::theory_weighted_maxsat& ensure_theory() { + smt::theory_weighted_maxsat* ensure_theory() { smt::theory_weighted_maxsat* wth = get_theory(); if (wth) { wth->reset(); @@ -383,7 +383,7 @@ namespace opt { wth = alloc(smt::theory_weighted_maxsat, m, s); s.get_context().register_plugin(wth); } - return *wth; + return wth; } /** @@ -420,16 +420,26 @@ namespace opt { mdl = m_model.get(); } - + class scoped_ensure_theory { + smt::theory_weighted_maxsat* m_wth; + public: + scoped_ensure_theory(imp& i) { + m_wth = i.ensure_theory(); + } + ~scoped_ensure_theory() { + m_wth->reset(); + } + smt::theory_weighted_maxsat& operator()() { return *m_wth; } + }; lbool incremental_solve() { TRACE("opt", tout << "weighted maxsat\n";); - smt::theory_weighted_maxsat& wth = ensure_theory(); + scoped_ensure_theory wth(*this); solver::scoped_push _s(s); lbool is_sat = l_true; bool was_sat = false; for (unsigned i = 0; i < m_soft.size(); ++i) { - wth.assert_weighted(m_soft[i].get(), m_weights[i]); + wth().assert_weighted(m_soft[i].get(), m_weights[i]); } solver::scoped_push __s(s); while (l_true == is_sat) { @@ -438,27 +448,27 @@ namespace opt { is_sat = l_undef; } if (is_sat == l_true) { - if (wth.is_optimal()) { + if (wth().is_optimal()) { s.get_model(m_model); } - expr_ref fml = wth.mk_block(); + expr_ref fml = wth().mk_block(); s.assert_expr(fml); was_sat = true; } } if (was_sat) { - wth.get_assignment(m_assignment); + wth().get_assignment(m_assignment); } if (is_sat == l_false && was_sat) { is_sat = l_true; } - m_upper = wth.get_min_cost(); + m_upper = wth().get_min_cost(); if (is_sat == l_true) { m_lower = m_upper; } TRACE("opt", tout << "min cost: " << m_upper << "\n";); - return is_sat; - } + return is_sat; + } /** Iteratively increase cost until there is an assignment during @@ -468,13 +478,13 @@ namespace opt { */ lbool iterative_solve() { - smt::theory_weighted_maxsat& wth = ensure_theory(); + scoped_ensure_theory wth(*this); solver::scoped_push _s(s); for (unsigned i = 0; i < m_soft.size(); ++i) { - wth.assert_weighted(m_soft[i].get(), m_weights[i]); + wth().assert_weighted(m_soft[i].get(), m_weights[i]); } solver::scoped_push __s(s); - rational cost = wth.get_min_cost(); + rational cost = wth().get_min_cost(); rational log_cost(1), tmp(1); while (tmp < cost) { ++log_cost; @@ -486,7 +496,7 @@ namespace opt { unsigned nsc = 0; m_upper = cost; while (log_cost <= cost && result == l_false) { - bound = wth.set_min_cost(log_cost); + bound = wth().set_min_cost(log_cost); s.push_core(); ++nsc; IF_VERBOSE(1, verbose_stream() << "(wmaxsat.iwmax min cost: " << log_cost << ")\n";); @@ -538,32 +548,32 @@ namespace opt { lbool bisection_solve() { TRACE("opt", tout << "weighted maxsat\n";); - smt::theory_weighted_maxsat& wth = ensure_theory(); + scoped_ensure_theory wth(*this); solver::scoped_push _s(s); lbool is_sat = l_true; bool was_sat = false; expr_ref_vector bounds(m); for (unsigned i = 0; i < m_soft.size(); ++i) { - wth.assert_weighted(m_soft[i].get(), m_weights[i]); + wth().assert_weighted(m_soft[i].get(), m_weights[i]); } solver::scoped_push __s(s); m_lower = rational::zero(); - m_upper = wth.get_min_cost(); - while (m_lower < m_upper) { + m_upper = wth().get_min_cost(); + while (m_lower < m_upper && is_sat != l_undef) { rational cost = div(m_upper + m_lower, rational(2)); - bounds.push_back(wth.set_min_cost(cost)); + bounds.push_back(wth().set_min_cost(cost)); is_sat = s.check_sat_core(1,bounds.c_ptr()+bounds.size()-1); if (m_cancel) { is_sat = l_undef; } switch(is_sat) { case l_true: { - if (wth.is_optimal()) { + if (wth().is_optimal()) { s.get_model(m_model); } - expr_ref fml = wth.mk_block(); + expr_ref fml = wth().mk_block(); s.assert_expr(fml); - m_upper = wth.get_min_cost(); + m_upper = wth().get_min_cost(); break; } case l_false: { @@ -572,8 +582,8 @@ namespace opt { break; } case l_undef: - return l_undef; - } + break; + } } if (was_sat) { is_sat = l_true; diff --git a/src/smt/theory_arith_int.h b/src/smt/theory_arith_int.h index a80f55de8..4fa9e75c7 100644 --- a/src/smt/theory_arith_int.h +++ b/src/smt/theory_arith_int.h @@ -473,7 +473,8 @@ namespace smt { */ template bool theory_arith::mk_gomory_cut(row const & r) { - SASSERT(!all_coeff_int(r)); + // The following assertion is wrong. It may be violated in mixed-integer problems. + // SASSERT(!all_coeff_int(r)); theory_var x_i = r.get_base_var(); SASSERT(is_int(x_i)); diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index df71ce969..8c9be4659 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -24,9 +24,43 @@ Notes: #include "sorting_network.h" #include "uint_set.h" #include "smt_model_generator.h" +#include "pb_rewriter_def.h" namespace smt { + class pb_lit_rewriter_util { + public: + typedef std::pair arg_t; + typedef vector args_t; + typedef rational numeral; + + literal negate(literal l) { + return ~l; + } + + void display(std::ostream& out, literal l) { + out << l; + } + + bool is_negated(literal l) const { + return l.sign(); + } + + bool is_true(literal l) const { + return l == true_literal; + } + + bool is_false(literal l) const { + return l == false_literal; + } + + struct compare { + bool operator()(arg_t const& a, arg_t const& b) { + return a.first < b.first; + } + }; + }; + void theory_pb::ineq::negate() { m_lit.neg(); numeral sum(0); @@ -52,245 +86,21 @@ namespace smt { void theory_pb::ineq::unique() { - numeral& k = m_k; - arg_t& args = m_args; - // normalize first all literals to be positive: - // then we can compare them more easily. - for (unsigned i = 0; i < size(); ++i) { - if (lit(i).sign()) { - args[i].first.neg(); - k -= coeff(i); - args[i].second = -coeff(i); - } - } - // remove constants - for (unsigned i = 0; i < size(); ++i) { - if (lit(i) == true_literal) { - k += coeff(i); - std::swap(args[i], args[size()-1]); - args.pop_back(); - } - else if (lit(i) == false_literal) { - std::swap(args[i], args[size()-1]); - args.pop_back(); - } - } - // sort and coalesce arguments: - std::sort(args.begin(), args.end()); - - unsigned i = 0, j = 1; - for (; j < size(); ++i) { - SASSERT(j > i); - literal l = lit(i); - for (; j < size() && lit(j) == lit(i); ++j) { - args[i].second += coeff(j); - } - if (j < size()) { - args[i+1].first = lit(j); - args[i+1].second = coeff(j); - ++j; - } - } - if (i + 1 < size()) { - args.resize(i+1); - } + pb_lit_rewriter_util pbu; + pb_rewriter_util util(pbu); + util.unique(m_args, m_k); } void theory_pb::ineq::prune() { - numeral& k = m_k; - arg_t& args = m_args; - numeral nlt(0); - unsigned occ = 0; - for (unsigned i = 0; nlt < k && i < size(); ++i) { - if (coeff(i) < k) { - nlt += coeff(i); - ++occ; - } - } - if (0 < occ && nlt < k) { - IF_VERBOSE(2, verbose_stream() << "prune\n"; - for (unsigned i = 0; i < size(); ++i) { - verbose_stream() << coeff(i) << "*" << lit(i) << " "; - } - verbose_stream() << " >= " << k << "\n"; - ); - - for (unsigned i = 0; i < size(); ++i) { - if (coeff(i) < k) { - args[i] = args.back(); - args.pop_back(); - --i; - } - } - normalize(); - - } + pb_lit_rewriter_util pbu; + pb_rewriter_util util(pbu); + util.prune(m_args, m_k); } lbool theory_pb::ineq::normalize() { - - numeral& k = m_k; - arg_t& args = m_args; - - // - // Ensure all coefficients are positive: - // c*l + y >= k - // <=> - // c*(1-~l) + y >= k - // <=> - // c - c*~l + y >= k - // <=> - // -c*~l + y >= k - c - // - numeral sum(0); - for (unsigned i = 0; i < size(); ++i) { - numeral c = coeff(i); - if (c.is_neg()) { - args[i].second = -c; - args[i].first = ~lit(i); - k -= c; - } - sum += coeff(i); - } - // detect tautologies: - if (k <= numeral::zero()) { - args.reset(); - k = numeral::zero(); - return l_true; - } - // detect infeasible constraints: - if (sum < k) { - args.reset(); - k = numeral::one(); - return l_false; - } - - bool all_int = true; - for (unsigned i = 0; all_int && i < size(); ++i) { - all_int = coeff(i).is_int(); - } - - if (!all_int) { - // normalize to integers. - numeral d(denominator(k)); - for (unsigned i = 0; i < size(); ++i) { - d = lcm(d, denominator(coeff(i))); - } - SASSERT(!d.is_one()); - k *= d; - for (unsigned i = 0; i < size(); ++i) { - args[i].second *= d; - } - } - - // Ensure the largest coefficient is not larger than k: - sum = numeral::zero(); - for (unsigned i = 0; i < size(); ++i) { - numeral c = coeff(i); - if (c > k) { - args[i].second = k; - } - sum += coeff(i); - } - SASSERT(!args.empty()); - - // normalize tight inequalities to unit coefficients. - if (sum == k) { - for (unsigned i = 0; i < size(); ++i) { - args[i].second = numeral::one(); - } - k = numeral(size()); - } - - // apply cutting plane reduction: - numeral g(0); - for (unsigned i = 0; !g.is_one() && i < size(); ++i) { - numeral c = coeff(i); - if (c != k) { - if (g.is_zero()) { - g = c; - } - else { - g = gcd(g, c); - } - } - } - if (g.is_zero()) { - // all coefficients are equal to k. - for (unsigned i = 0; i < size(); ++i) { - SASSERT(coeff(i) == k); - args[i].second = numeral::one(); - } - k = numeral::one(); - } - else if (g > numeral::one()) { - IF_VERBOSE(2, verbose_stream() << "cut " << g << "\n"; - for (unsigned i = 0; i < size(); ++i) { - verbose_stream() << coeff(i) << "*" << lit(i) << " "; - } - verbose_stream() << " >= " << k << "\n"; - ); - - // - // Example 5x + 5y + 2z + 2u >= 5 - // becomes 3x + 3y + z + u >= 3 - // - numeral k_new = div(k, g); - if (!(k % g).is_zero()) { // k_new is the ceiling of k / g. - k_new++; - } - for (unsigned i = 0; i < size(); ++i) { - SASSERT(coeff(i).is_pos()); - numeral c = coeff(i); - if (c == k) { - c = k_new; - } - else { - c = div(c, g); - } - args[i].second = c; - SASSERT(coeff(i).is_pos()); - } - k = k_new; - } - // - // normalize coefficients that fall within a range - // k/n <= ... < k/(n-1) for some n = 1,2,... - // - // e.g, k/n <= min <= max < k/(n-1) - // k/min <= n, n-1 < k/max - // . floor(k/max) = ceil(k/min) - 1 - // . floor(k/max) < k/max - // - // example: k = 5, min = 3, max = 4: 5/3 -> 2 5/4 -> 1, n = 2 - // replace all coefficients by 1, and k by 2. - // - if (!k.is_one()) { - numeral min = coeff(0), max = coeff(0); - for (unsigned i = 1; i < size(); ++i) { - if (coeff(i) < min) min = coeff(i); - if (coeff(i) > max) max = coeff(i); - } - numeral n0 = k/max; - numeral n1 = floor(n0); - numeral n2 = ceil(k/min) - numeral::one(); - if (n1 == n2 && !n0.is_int()) { - IF_VERBOSE(2, verbose_stream() << "set cardinality\n"; - for (unsigned i = 0; i < size(); ++i) { - verbose_stream() << coeff(i) << "*" << lit(i) << " "; - } - verbose_stream() << " >= " << k << "\n"; - ); - - for (unsigned i = 0; i < size(); ++i) { - args[i].second = numeral::one(); - } - k = n1 + numeral::one(); - } - } - - SASSERT(well_formed()); - return l_undef; + pb_lit_rewriter_util pbu; + pb_rewriter_util util(pbu); + return util.normalize(m_args, m_k); } app_ref theory_pb::ineq::to_expr(context& ctx, ast_manager& m) { @@ -403,6 +213,7 @@ namespace smt { break; } +#if 0 // TBD: special cases: k == 1, or args.size() == 1 if (c->k().is_one()) { @@ -416,7 +227,7 @@ namespace smt { ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); return true; } - +#endif // maximal coefficient: numeral& max_watch = c->m_max_watch; diff --git a/src/tactic/core/pb_preprocess_tactic.cpp b/src/tactic/core/pb_preprocess_tactic.cpp new file mode 100644 index 000000000..60bda3c18 --- /dev/null +++ b/src/tactic/core/pb_preprocess_tactic.cpp @@ -0,0 +1,185 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + pb_preprocess_tactic.cpp + +Abstract: + + Pre-process pseudo-Boolean inequalities using + generalized Davis Putnam (resolution) to eliminate variables. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-12-23 + +Notes: + +--*/ +#include "pb_preprocess_tactic.h" +#include "tactical.h" +#include "for_each_expr.h" +#include "pb_decl_plugin.h" + +class pb_preprocess_tactic : public tactic { + struct rec { unsigned pos, neg; rec() { pos = neg = 0; } }; + typedef obj_map var_map; + ast_manager& m; + pb_util pb; + var_map m_vars; + ptr_vector m_ge; + ptr_vector m_other; + + struct declassifier { + obj_map& m_vars; + declassifier(obj_map& v): m_vars(v) {} + + void operator()(app* e) { + if (m_vars.contains(e)) { + m_vars.remove(e); + } + } + void operator()(var* e) {} + void operator()(quantifier* q) {} + }; + +public: + pb_preprocess_tactic(ast_manager& m, params_ref const& p = params_ref()): + m(m), pb(m) {} + + virtual ~pb_preprocess_tactic() {} + + virtual tactic * translate(ast_manager & m) { + return alloc(pb_preprocess_tactic, m); + } + + virtual void operator()( + goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) { + SASSERT(g->is_well_sorted()); + mc = 0; pc = 0; core = 0; + + reset(); + for (unsigned i = 0; i < g->size(); i++) { + process_vars(g->form(i)); + } + + if (m_ge.empty()) { + result.push_back(g.get()); + return; + } + + for (unsigned i = 0; i < m_ge.size(); ++i) { + classify_vars(m_ge[i]); + } + + declassifier dcl(m_vars); + expr_mark visited; + for (unsigned i = 0; !m_vars.empty() && i < m_other.size(); ++i) { + for_each_expr(dcl, visited, m_other[i]); + } + + if (m_vars.empty()) { + result.push_back(g.get()); + return; + } + + var_map::iterator it = next_resolvent(m_vars.begin()); + while (it != m_vars.end()) { + expr * e = it->m_key; + it->m_value.pos; + it->m_value.neg; + + it = next_resolvent(it); + } + + g->inc_depth(); + result.push_back(g.get()); + } + + virtual void set_cancel(bool f) { + } + + virtual void updt_params(params_ref const & p) { + } + + virtual void cleanup() { + } + +private: + + void reset() { + m_ge.reset(); + m_other.reset(); + m_vars.reset(); + } + + void process_vars(expr* e) { + if (pb.is_ge(e) && pure_args(to_app(e))) { + m_ge.push_back(to_app(e)); + } + else if (m.is_or(e) && pure_args(to_app(e))) { + m_ge.push_back(to_app(e)); + } + else { + m_other.push_back(e); + } + } + + void classify_vars(app* e) { + expr* r; + for (unsigned i = 0; i < e->get_num_args(); ++i) { + if (m.is_true(e) || m.is_false(e)) { + // no-op + } + else if (m.is_not(e, r)) { + insert(r, false); + } + else { + insert(e, true); + } + } + } + + void insert(expr* e, bool pos) { + if (!m_vars.contains(e)) { + m_vars.insert(e, rec()); + } + if (pos) { + m_vars.find(e).pos++; + } + else { + m_vars.find(e).neg++; + } + } + + bool pure_args(app* a) const { + for (unsigned i = 0; i < a->get_num_args(); ++i) { + expr* e = a->get_arg(i); + m.is_not(e, e); + if (!is_uninterp_const(e) && !m.is_true(e) && !m.is_false(e)) { + return false; + } + } + return true; + } + + var_map::iterator next_resolvent(var_map::iterator it) { + if (it == m_vars.end()) { + return it; + } + while (it != m_vars.end() && it->m_value.pos != 1 && it->m_value.neg != 1) { + ++it; + } + return it; + } +}; + + +tactic * mk_pb_preprocess_tactic(ast_manager & m, params_ref const & p) { + return alloc(pb_preprocess_tactic, m); +} diff --git a/src/tactic/core/pb_preprocess_tactic.h b/src/tactic/core/pb_preprocess_tactic.h new file mode 100644 index 000000000..5746779b7 --- /dev/null +++ b/src/tactic/core/pb_preprocess_tactic.h @@ -0,0 +1,34 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + pb_preprocess_tactic.h + +Abstract: + + Pre-process pseudo-Boolean inequalities using + generalized Davis Putnam (resolution) to eliminate variables. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-12-23 + +Notes: + +--*/ +#ifndef _PB_PREPROCESS_TACTIC_H_ +#define _PB_PREPROCESS_TACTIC_H_ + +#include"params.h" +class ast_manager; +class tactic; + +tactic * mk_pb_preprocess_tactic(ast_manager & m, params_ref const & p = params_ref()); + +/* + ADD_TACTIC("pb-preprocess", "pre-process pseudo-Boolean constraints a la Davis Putnam.", "mk_pb_preprocess_tactic(m, p)") +*/ + + +#endif From 0c2ec6951adb5e1654364bc9751314b3da29ae86 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 23 Dec 2013 03:25:22 -0800 Subject: [PATCH 242/925] working on pre-processing Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb_rewriter_def.h | 3 + src/tactic/core/pb_preprocess_tactic.cpp | 189 ++++++++++++++++++++--- 2 files changed, 170 insertions(+), 22 deletions(-) diff --git a/src/ast/rewriter/pb_rewriter_def.h b/src/ast/rewriter/pb_rewriter_def.h index a6a37f73d..c6570b5fa 100644 --- a/src/ast/rewriter/pb_rewriter_def.h +++ b/src/ast/rewriter/pb_rewriter_def.h @@ -68,6 +68,9 @@ void pb_rewriter_util::unique(typename PBU::args_t& args, typename PBU::num for (; j < args.size() && args[j].first == args[i].first; ++j) { args[i].second += args[j].second; } + if (args[i].second.is_zero()) { + --i; + } if (j < args.size()) { args[i+1].first = args[j].first; args[i+1].second = args[j].second; diff --git a/src/tactic/core/pb_preprocess_tactic.cpp b/src/tactic/core/pb_preprocess_tactic.cpp index 60bda3c18..44b74cc20 100644 --- a/src/tactic/core/pb_preprocess_tactic.cpp +++ b/src/tactic/core/pb_preprocess_tactic.cpp @@ -21,15 +21,20 @@ Notes: #include "tactical.h" #include "for_each_expr.h" #include "pb_decl_plugin.h" +#include "th_rewriter.h" +#include "expr_substitution.h" +#include "ast_pp.h" class pb_preprocess_tactic : public tactic { - struct rec { unsigned pos, neg; rec() { pos = neg = 0; } }; + struct rec { unsigned_vector pos, neg; rec() { } }; typedef obj_map var_map; ast_manager& m; pb_util pb; var_map m_vars; - ptr_vector m_ge; - ptr_vector m_other; + app_ref_vector m_ge; + expr_ref_vector m_other; + th_rewriter m_r; + struct declassifier { obj_map& m_vars; @@ -46,7 +51,7 @@ class pb_preprocess_tactic : public tactic { public: pb_preprocess_tactic(ast_manager& m, params_ref const& p = params_ref()): - m(m), pb(m) {} + m(m), pb(m), m_ge(m), m_other(m), m_r(m) {} virtual ~pb_preprocess_tactic() {} @@ -64,7 +69,7 @@ public: mc = 0; pc = 0; core = 0; reset(); - for (unsigned i = 0; i < g->size(); i++) { + for (unsigned i = 0; i < g->size(); ++i) { process_vars(g->form(i)); } @@ -73,31 +78,56 @@ public: return; } + for (unsigned i = 0; i < m_ge.size(); ++i) { - classify_vars(m_ge[i]); + classify_vars(i, m_ge[i].get()); } declassifier dcl(m_vars); expr_mark visited; for (unsigned i = 0; !m_vars.empty() && i < m_other.size(); ++i) { - for_each_expr(dcl, visited, m_other[i]); + for_each_expr(dcl, visited, m_other[i].get()); } if (m_vars.empty()) { result.push_back(g.get()); return; } - + + g->inc_depth(); var_map::iterator it = next_resolvent(m_vars.begin()); while (it != m_vars.end()) { expr * e = it->m_key; - it->m_value.pos; - it->m_value.neg; - + if (it->m_value.pos.empty()) { + replace(it->m_value.neg, e, m.mk_false()); + } + else if (it->m_value.neg.empty()) { + replace(it->m_value.pos, e, m.mk_true()); + } + else if (it->m_value.pos.size() == 1) { + resolve(it->m_value.pos[0], it->m_value.neg, e, true); + } + else if (it->m_value.neg.size() == 1) { + resolve(it->m_value.neg[0], it->m_value.pos, e, false); + } + else { + + } + ++it; it = next_resolvent(it); + // FIXME: some but not all indices are invalidated. } - g->inc_depth(); + g->reset(); + for (unsigned i = 0; i < m_ge.size(); ++i) { + g->assert_expr(m_ge[i].get()); + } + + for (unsigned i = 0; i < m_other.size(); ++i) { + g->assert_expr(m_other[i].get()); + } + + result.push_back(g.get()); } @@ -119,41 +149,57 @@ private: } void process_vars(expr* e) { - if (pb.is_ge(e) && pure_args(to_app(e))) { + expr* r; + if (is_uninterp_const(e)) { + m_ge.push_back(to_app(e)); + } + else if (pb.is_ge(e) && pure_args(to_app(e))) { m_ge.push_back(to_app(e)); } else if (m.is_or(e) && pure_args(to_app(e))) { m_ge.push_back(to_app(e)); } + else if (m.is_not(e, r) && is_uninterp_const(r)) { + m_ge.push_back(to_app(e)); + } else { m_other.push_back(e); } } - void classify_vars(app* e) { + void classify_vars(unsigned idx, app* e) { expr* r; + if (m.is_not(e, r)) { + insert(idx, r, false); + return; + } + if (is_uninterp_const(e)) { + insert(idx, e, true); + return; + } for (unsigned i = 0; i < e->get_num_args(); ++i) { - if (m.is_true(e) || m.is_false(e)) { + expr* arg = e->get_arg(i); + if (m.is_true(arg) || m.is_false(arg)) { // no-op } - else if (m.is_not(e, r)) { - insert(r, false); + else if (m.is_not(arg, r)) { + insert(idx, r, false); } else { - insert(e, true); + insert(idx, arg, true); } } } - void insert(expr* e, bool pos) { + void insert(unsigned i, expr* e, bool pos) { if (!m_vars.contains(e)) { m_vars.insert(e, rec()); } if (pos) { - m_vars.find(e).pos++; + m_vars.find(e).pos.push_back(i); } else { - m_vars.find(e).neg++; + m_vars.find(e).neg.push_back(i); } } @@ -172,11 +218,110 @@ private: if (it == m_vars.end()) { return it; } - while (it != m_vars.end() && it->m_value.pos != 1 && it->m_value.neg != 1) { + while (it != m_vars.end() && it->m_value.pos.size() > 1 && it->m_value.neg.size() > 1) { ++it; } return it; } + + rational get_coeff(unsigned num_args, expr* const* args, rational const* coeffs, expr* e) { + for (unsigned i = 0; i < num_args; ++i) { + if (args[i] == e) return coeffs[i]; + } + return rational::zero(); + } + + void resolve(unsigned idx, unsigned_vector const& positions, expr* e, bool pos) { + app* fml = m_ge[idx].get(); + if (m.is_true(fml)) { + return; + } + m_r.set_substitution(0); + expr_ref tmp1(m), tmp2(m), e1(m), e2(m); + ptr_vector args; + vector coeffs; + rational k1, k2, c1, c2; + if (pos) { + e1 = e; + e2 = m.mk_not(e); + } + else { + e1 = m.mk_not(e); + e2 = e; + } + VERIFY(to_ge(fml, args, coeffs, k1)); + c1 = get_coeff(args.size(), args.c_ptr(), coeffs.c_ptr(), e1); + unsigned sz = coeffs.size(); + for (unsigned i = 0; i < positions.size(); ++i) { + SASSERT(positions[i] != idx); // rely on simplification + app* fml2 = m_ge[positions[i]].get(); + if (m.is_true(fml2)) continue; + VERIFY(to_ge(fml2, args, coeffs, k2)); + c2 = get_coeff(args.size()-sz, args.c_ptr()+sz, coeffs.c_ptr()+sz, e2); + std::cout << "coeffs: " << c1 << " " << c2 << "\n"; + tmp1 = pb.mk_ge(args.size(), coeffs.c_ptr(), args.c_ptr(), k1 + k2); + m_r(tmp1, tmp2); + TRACE("pb", tout << mk_pp(fml2, m) << " -> " << tmp2 << "\n";); + IF_VERBOSE(1, verbose_stream() << mk_pp(fml2, m) << " -> " << tmp2 << "\n";); +#if 0 + m_ge[positions[i]] = tmp2; +#endif + args.resize(sz); + coeffs.resize(sz); + } + + // m_ge[idx] = m.mk_true(); + } + + bool to_ge(app* e, ptr_vector& args, vector& coeffs, rational& k) { + expr* r; + if (is_uninterp_const(e)) { + args.push_back(e); + coeffs.push_back(rational::one()); + k = rational::one(); + } + else if (m.is_not(e, r) && is_uninterp_const(r)) { + args.push_back(e); + coeffs.push_back(rational::one()); + k = rational::one(); + } + else if (pb.is_ge(e)) { + SASSERT(pure_args(e)); + for (unsigned i = 0; i < e->get_num_args(); ++i) { + args.push_back(e->get_arg(i)); + coeffs.push_back(pb.get_coeff(e, i)); + } + k = pb.get_k(e); + } + else if (m.is_or(e)) { + SASSERT(pure_args(e)); + for (unsigned i = 0; i < e->get_num_args(); ++i) { + args.push_back(e->get_arg(i)); + coeffs.push_back(rational::one()); + } + k = rational::one(); + } + else { + return false; + } + return true; + } + + void replace(unsigned_vector const& positions, expr* e, expr* v) { + expr_substitution sub(m); + sub.insert(e, v); + expr_ref tmp(m); + m_r.set_substitution(&sub); + for (unsigned i = 0; i < positions.size(); ++i) { + unsigned idx = positions[i]; + if (!m.is_true(m_ge[idx].get())) { + m_r(m_ge[idx].get(), tmp); + TRACE("pb", tout << mk_pp(m_ge[idx].get(), m) << " -> " << tmp + << " by " << mk_pp(e, m) << " |-> " << mk_pp(v, m) << "\n";); + m_ge[idx] = to_app(tmp); + } + } + } }; From 70c4432bb4347b5c3b104f22357c1513e3afd1b5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 23 Dec 2013 13:22:21 -0800 Subject: [PATCH 243/925] working on pb pre-processing Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb_rewriter_def.h | 41 ++++-- src/tactic/core/pb_preprocess_tactic.cpp | 164 +++++++++++++++-------- 2 files changed, 139 insertions(+), 66 deletions(-) diff --git a/src/ast/rewriter/pb_rewriter_def.h b/src/ast/rewriter/pb_rewriter_def.h index c6570b5fa..3ffedb020 100644 --- a/src/ast/rewriter/pb_rewriter_def.h +++ b/src/ast/rewriter/pb_rewriter_def.h @@ -61,25 +61,34 @@ void pb_rewriter_util::unique(typename PBU::args_t& args, typename PBU::num // sort and coalesce arguments: PBU::compare cmp; std::sort(args.begin(), args.end(), cmp); - - unsigned i = 0, j = 1; - for (; j < args.size(); ++i) { - SASSERT(j > i); - for (; j < args.size() && args[j].first == args[i].first; ++j) { + + // coallesce + unsigned i, j; + for (i = 0, j = 1; j < args.size(); ++j) { + if (args[i].first == args[j].first) { args[i].second += args[j].second; } - if (args[i].second.is_zero()) { - --i; - } - if (j < args.size()) { - args[i+1].first = args[j].first; - args[i+1].second = args[j].second; - ++j; + else { + ++i; + args[i] = args[j]; } } if (i + 1 < args.size()) { args.resize(i+1); } + + // remove 0s. + for (i = 0, j = 0; j < args.size(); ++j) { + if (!args[j].second.is_zero()) { + if (i != j) { + args[i] = args[j]; + } + ++i; + } + } + if (i < args.size()) { + args.resize(i); + } TRACE("pb", display(tout << "post-unique:", args, k);); } @@ -87,6 +96,12 @@ template lbool pb_rewriter_util::normalize(typename PBU::args_t& args, typename PBU::numeral& k) { TRACE("pb", display(tout << "pre-normalize:", args, k);); + bool found = false; + for (unsigned i = 0; !found && i < args.size(); ++i) { + found = args[i].second.is_zero(); + } + if (found) display(std::cout, args, k); + SASSERT(!found); // // Ensure all coefficients are positive: // c*l + y >= k @@ -223,6 +238,7 @@ lbool pb_rewriter_util::normalize(typename PBU::args_t& args, typename PBU: if (args[i].second < min) min = args[i].second; if (args[i].second > max) max = args[i].second; } + SASSERT(min.is_pos()); PBU::numeral n0 = k/max; PBU::numeral n1 = floor(n0); PBU::numeral n2 = ceil(k/min) - PBU::numeral::one(); @@ -259,6 +275,7 @@ void pb_rewriter_util::prune(typename PBU::args_t& args, typename PBU::nume --i; } } + unique(args, k); normalize(args, k); } } diff --git a/src/tactic/core/pb_preprocess_tactic.cpp b/src/tactic/core/pb_preprocess_tactic.cpp index 44b74cc20..dd1033d54 100644 --- a/src/tactic/core/pb_preprocess_tactic.cpp +++ b/src/tactic/core/pb_preprocess_tactic.cpp @@ -31,8 +31,8 @@ class pb_preprocess_tactic : public tactic { ast_manager& m; pb_util pb; var_map m_vars; - app_ref_vector m_ge; - expr_ref_vector m_other; + unsigned_vector m_ge; + unsigned_vector m_other; th_rewriter m_r; @@ -51,7 +51,7 @@ class pb_preprocess_tactic : public tactic { public: pb_preprocess_tactic(ast_manager& m, params_ref const& p = params_ref()): - m(m), pb(m), m_ge(m), m_other(m), m_r(m) {} + m(m), pb(m), m_r(m) {} virtual ~pb_preprocess_tactic() {} @@ -70,7 +70,7 @@ public: reset(); for (unsigned i = 0; i < g->size(); ++i) { - process_vars(g->form(i)); + process_vars(i, g->form(i)); } if (m_ge.empty()) { @@ -78,15 +78,14 @@ public: return; } - for (unsigned i = 0; i < m_ge.size(); ++i) { - classify_vars(i, m_ge[i].get()); + classify_vars(i, to_app(g->form(m_ge[i]))); } declassifier dcl(m_vars); expr_mark visited; for (unsigned i = 0; !m_vars.empty() && i < m_other.size(); ++i) { - for_each_expr(dcl, visited, m_other[i].get()); + for_each_expr(dcl, visited, g->form(m_other[i])); } if (m_vars.empty()) { @@ -95,38 +94,37 @@ public: } g->inc_depth(); + // first eliminate variables var_map::iterator it = next_resolvent(m_vars.begin()); while (it != m_vars.end()) { expr * e = it->m_key; - if (it->m_value.pos.empty()) { - replace(it->m_value.neg, e, m.mk_false()); + rec const& r = it->m_value; + if (r.pos.empty()) { + replace(r.neg, e, m.mk_false(), g); } - else if (it->m_value.neg.empty()) { - replace(it->m_value.pos, e, m.mk_true()); - } - else if (it->m_value.pos.size() == 1) { - resolve(it->m_value.pos[0], it->m_value.neg, e, true); - } - else if (it->m_value.neg.size() == 1) { - resolve(it->m_value.neg[0], it->m_value.pos, e, false); - } - else { - + else if (r.neg.empty()) { + replace(r.pos, e, m.mk_true(), g); } ++it; it = next_resolvent(it); - // FIXME: some but not all indices are invalidated. } - - g->reset(); - for (unsigned i = 0; i < m_ge.size(); ++i) { - g->assert_expr(m_ge[i].get()); + // now resolve clauses. + it = next_resolvent(m_vars.begin()); + while (it != m_vars.end()) { + expr * e = it->m_key; + rec const& r = it->m_value; + if (r.pos.size() == 1) { + resolve(r.pos[0], r.neg, e, true, g); + } + else if (r.neg.size() == 1) { + resolve(r.neg[0], r.pos, e, false, g); + } + ++it; + it = next_resolvent(it); } - for (unsigned i = 0; i < m_other.size(); ++i) { - g->assert_expr(m_other[i].get()); - } + g->elim_true(); result.push_back(g.get()); } @@ -148,22 +146,23 @@ private: m_vars.reset(); } - void process_vars(expr* e) { + + void process_vars(unsigned i, expr* e) { expr* r; if (is_uninterp_const(e)) { - m_ge.push_back(to_app(e)); + m_ge.push_back(i); } else if (pb.is_ge(e) && pure_args(to_app(e))) { - m_ge.push_back(to_app(e)); + m_ge.push_back(i); } else if (m.is_or(e) && pure_args(to_app(e))) { - m_ge.push_back(to_app(e)); + m_ge.push_back(i); } else if (m.is_not(e, r) && is_uninterp_const(r)) { - m_ge.push_back(to_app(e)); + m_ge.push_back(i); } else { - m_other.push_back(e); + m_other.push_back(i); } } @@ -231,11 +230,43 @@ private: return rational::zero(); } - void resolve(unsigned idx, unsigned_vector const& positions, expr* e, bool pos) { - app* fml = m_ge[idx].get(); + // + // one of the formulas are replaced by T after resolution + // so if there is a pointer into that formula, we can no + // longer assume variables have unique occurrences. + // + bool is_valid(unsigned_vector const& positions, goal_ref const& g) const { + for (unsigned i = 0; i < positions.size(); ++i) { + unsigned idx = positions[i]; + if (m.is_true(g->form(idx))) return false; + } + return true; + } + + bool is_reduction(unsigned_vector const& pos, app* fml, goal_ref const& g) { + unsigned sz = fml->get_num_args(); + for (unsigned i = 0; i < pos.size(); ++i) { + if (!is_app(g->form(pos[i]))) return false; + if (to_app(g->form(pos[i]))->get_num_args() < sz) return false; + } + return true; + } + + void resolve(unsigned idx1, unsigned_vector const& positions, expr* e, bool pos, goal_ref const& g) { + if (!is_app(g->form(idx1))) { + return; + } + app* fml = to_app(g->form(idx1)); if (m.is_true(fml)) { return; } + if (!is_valid(positions, g)) { + return; + } + if (positions.size() > 1 && !is_reduction(positions, fml, g)) { + return; + } + IF_VERBOSE(1, verbose_stream() << "resolving: " << mk_pp(fml, m) << "\n";); m_r.set_substitution(0); expr_ref tmp1(m), tmp2(m), e1(m), e2(m); ptr_vector args; @@ -251,26 +282,49 @@ private: } VERIFY(to_ge(fml, args, coeffs, k1)); c1 = get_coeff(args.size(), args.c_ptr(), coeffs.c_ptr(), e1); + if (c1.is_zero()) { + return; + } unsigned sz = coeffs.size(); for (unsigned i = 0; i < positions.size(); ++i) { - SASSERT(positions[i] != idx); // rely on simplification - app* fml2 = m_ge[positions[i]].get(); + unsigned idx2 = positions[i]; + if (idx2 == idx1) { + continue; + } + app* fml2 = to_app(g->form(idx2)); if (m.is_true(fml2)) continue; VERIFY(to_ge(fml2, args, coeffs, k2)); c2 = get_coeff(args.size()-sz, args.c_ptr()+sz, coeffs.c_ptr()+sz, e2); - std::cout << "coeffs: " << c1 << " " << c2 << "\n"; - tmp1 = pb.mk_ge(args.size(), coeffs.c_ptr(), args.c_ptr(), k1 + k2); - m_r(tmp1, tmp2); - TRACE("pb", tout << mk_pp(fml2, m) << " -> " << tmp2 << "\n";); - IF_VERBOSE(1, verbose_stream() << mk_pp(fml2, m) << " -> " << tmp2 << "\n";); -#if 0 - m_ge[positions[i]] = tmp2; -#endif + if (!c2.is_zero()) { + rational m1(1), m2(1); + if (c1 != c2) { + rational lc = lcm(c1, c2); + m1 = lc/c1; + m2 = lc/c2; + for (unsigned j = 0; j < sz; ++j) { + coeffs[j] *= m1; + } + for (unsigned j = sz; j < args.size(); ++j) { + coeffs[j] *= m2; + } + } + tmp1 = pb.mk_ge(args.size(), coeffs.c_ptr(), args.c_ptr(), m1*k1 + m2*k2); + m_r(tmp1, tmp2); + TRACE("pb", tout << "to\n" << mk_pp(fml2, m) << " -> " << tmp2 << "\n";); + IF_VERBOSE(1, verbose_stream() << mk_pp(fml2, m) << " -> " << tmp2 << "\n";); + + g->update(idx2, tmp2); // proof & dependencies + + if (!m1.is_one()) { + for (unsigned j = 0; j < sz; ++j) { + coeffs[j] /= m1; + } + } + } args.resize(sz); coeffs.resize(sz); } - - // m_ge[idx] = m.mk_true(); + g->update(idx1, m.mk_true()); // proof & dependencies } bool to_ge(app* e, ptr_vector& args, vector& coeffs, rational& k) { @@ -307,18 +361,20 @@ private: return true; } - void replace(unsigned_vector const& positions, expr* e, expr* v) { + void replace(unsigned_vector const& positions, expr* e, expr* v, goal_ref const& g) { + if (!is_valid(positions, g)) return; expr_substitution sub(m); sub.insert(e, v); expr_ref tmp(m); - m_r.set_substitution(&sub); + m_r.set_substitution(&sub); for (unsigned i = 0; i < positions.size(); ++i) { unsigned idx = positions[i]; - if (!m.is_true(m_ge[idx].get())) { - m_r(m_ge[idx].get(), tmp); - TRACE("pb", tout << mk_pp(m_ge[idx].get(), m) << " -> " << tmp + expr* f = g->form(idx); + if (!m.is_true(f)) { + m_r(f, tmp); + TRACE("pb", tout << mk_pp(f, m) << " -> " << tmp << " by " << mk_pp(e, m) << " |-> " << mk_pp(v, m) << "\n";); - m_ge[idx] = to_app(tmp); + g->update(idx, tmp); // proof & dependencies. } } } From 0641c4f69447c7c4f123bf76e22015eb0f81082c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 26 Dec 2013 09:53:33 -0800 Subject: [PATCH 244/925] working on pre-processing Signed-off-by: Nikolaj Bjorner --- src/ast/pb_decl_plugin.h | 4 +- src/ast/rewriter/pb_rewriter_def.h | 28 +- src/opt/opt_context.cpp | 2 +- src/opt/opt_solver.cpp | 19 +- src/opt/opt_solver.h | 4 +- src/opt/weighted_maxsat.cpp | 98 ++++- src/smt/theory_pb.cpp | 22 +- src/tactic/core/pb_preprocess_tactic.cpp | 441 +++++++++++++++++------ 8 files changed, 467 insertions(+), 151 deletions(-) diff --git a/src/ast/pb_decl_plugin.h b/src/ast/pb_decl_plugin.h index c590f8320..9ee74dfaf 100644 --- a/src/ast/pb_decl_plugin.h +++ b/src/ast/pb_decl_plugin.h @@ -89,14 +89,14 @@ public: bool is_at_least_k(expr *a) const { return is_app(a) && is_at_least_k(to_app(a)->get_decl()); } bool is_at_least_k(app *a, rational& k) const; rational get_k(func_decl *a) const; - rational get_k(app *a) const { return get_k(a->get_decl()); } + rational get_k(expr *a) const { return get_k(to_app(a)->get_decl()); } bool is_le(func_decl *a) const; bool is_le(expr *a) const { return is_app(a) && is_le(to_app(a)->get_decl()); } bool is_le(app* a, rational& k) const; bool is_ge(func_decl* a) const; bool is_ge(expr* a) const { return is_app(a) && is_ge(to_app(a)->get_decl()); } bool is_ge(app* a, rational& k) const; - rational get_coeff(app* a, unsigned index) const { return get_coeff(a->get_decl(), index); } + rational get_coeff(expr* a, unsigned index) const { return get_coeff(to_app(a)->get_decl(), index); } rational get_coeff(func_decl* a, unsigned index) const; private: rational to_rational(parameter const& p) const; diff --git a/src/ast/rewriter/pb_rewriter_def.h b/src/ast/rewriter/pb_rewriter_def.h index 3ffedb020..c6e21b6ce 100644 --- a/src/ast/rewriter/pb_rewriter_def.h +++ b/src/ast/rewriter/pb_rewriter_def.h @@ -36,7 +36,7 @@ void pb_rewriter_util::display(std::ostream& out, typename PBU::args_t& arg template void pb_rewriter_util::unique(typename PBU::args_t& args, typename PBU::numeral& k) { - TRACE("pb", display(tout << "pre-unique:", args, k);); + TRACE("pb_verbose", display(tout << "pre-unique:", args, k);); for (unsigned i = 0; i < args.size(); ++i) { if (m_util.is_negated(args[i].first)) { args[i].first = m_util.negate(args[i].first); @@ -73,9 +73,7 @@ void pb_rewriter_util::unique(typename PBU::args_t& args, typename PBU::num args[i] = args[j]; } } - if (i + 1 < args.size()) { - args.resize(i+1); - } + args.resize(i+1); // remove 0s. for (i = 0, j = 0; j < args.size(); ++j) { @@ -86,22 +84,22 @@ void pb_rewriter_util::unique(typename PBU::args_t& args, typename PBU::num ++i; } } - if (i < args.size()) { - args.resize(i); - } - TRACE("pb", display(tout << "post-unique:", args, k);); + args.resize(i); + TRACE("pb_verbose", display(tout << "post-unique:", args, k);); } template lbool pb_rewriter_util::normalize(typename PBU::args_t& args, typename PBU::numeral& k) { - TRACE("pb", display(tout << "pre-normalize:", args, k);); + TRACE("pb_verbose", display(tout << "pre-normalize:", args, k);); + + DEBUG_CODE( + bool found = false; + for (unsigned i = 0; !found && i < args.size(); ++i) { + found = args[i].second.is_zero(); + } + if (found) display(verbose_stream(), args, k); + SASSERT(!found);); - bool found = false; - for (unsigned i = 0; !found && i < args.size(); ++i) { - found = args[i].second.is_zero(); - } - if (found) display(std::cout, args, k); - SASSERT(!found); // // Ensure all coefficients are positive: // c*l + y >= k diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 87895b33b..0695abc6d 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -116,8 +116,8 @@ namespace opt { mdl = m_model; if (m_model_converter) { (*m_model_converter)(mdl, 0); - get_solver().mc()(mdl, 0); } + get_solver().mc()(mdl, 0); } lbool context::execute_min_max(unsigned index, bool committed) { diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index c437e48f1..18285d37b 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -124,11 +124,10 @@ namespace opt { std::stringstream file_name; file_name << "opt_solver" << ++m_dump_count << ".smt2"; std::ofstream buffer(file_name.str().c_str()); - to_smt2_benchmark(buffer, "opt_solver", ""); + to_smt2_benchmark(buffer, num_assumptions, assumptions, "opt_solver", ""); buffer.close(); } - lbool r = m_context.check(num_assumptions, assumptions); - return r; + return m_context.check(num_assumptions, assumptions); } void opt_solver::maximize_objectives() { @@ -257,7 +256,9 @@ namespace opt { } - void opt_solver::to_smt2_benchmark(std::ofstream & buffer, char const * name, char const * logic, + void opt_solver::to_smt2_benchmark(std::ofstream & buffer, + unsigned num_assumptions, expr * const * assumptions, + char const * name, char const * logic, char const * status, char const * attributes) { ast_smt_pp pp(m); pp.set_benchmark_name(name); @@ -266,10 +267,14 @@ namespace opt { pp.add_attributes(attributes); pp_params params; pp.set_simplify_implies(params.simplify_implies()); - for (unsigned i = 0; i < get_num_assertions(); ++i) { - pp.add_assumption(to_expr(get_assertion(i))); + + for (unsigned i = 0; i < num_assumptions; ++i) { + pp.add_assumption(assumptions[i]); } - pp.display_smt2(buffer, to_expr(m.mk_true())); + for (unsigned i = 0; i < get_num_assertions(); ++i) { + pp.add_assumption(get_assertion(i)); + } + pp.display_smt2(buffer, m.mk_true()); } diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index eb5812317..0f62642d4 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -92,7 +92,9 @@ namespace opt { smt::theory_opt& get_optimizer(); - void to_smt2_benchmark(std::ofstream & buffer, char const * name = "benchmarks", + void to_smt2_benchmark(std::ofstream & buffer, + unsigned num_assumptions, expr * const * assumptions, + char const * name = "benchmarks", char const * logic = "", char const * status = "unknown", char const * attributes = ""); }; } diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 6fae39bad..863cab7ef 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -23,6 +23,11 @@ Notes: #include "opt_params.hpp" #include "pb_decl_plugin.h" #include "uint_set.h" +#include "pb_preprocess_tactic.h" +#include "simplify_tactic.h" +#include "tactical.h" +#include "tactic.h" +#include "model_smt2_pp.h" namespace smt { @@ -637,6 +642,53 @@ namespace opt { return is_sat; } + lbool pb_simplify_solve() { + pb_util u(m); + expr_ref fml(m), val(m); + expr_ref_vector nsoft(m); + m_lower = m_upper = rational::zero(); + rational minw(0); + for (unsigned i = 0; i < m_soft.size(); ++i) { + m_upper += m_weights[i]; + if (m_weights[i] < minw || minw.is_zero()) { + minw = m_weights[i]; + } + nsoft.push_back(m.mk_not(m_soft[i].get())); + } + solver::scoped_push _s1(s); + lbool is_sat = l_true; + bool was_sat = false; + fml = m.mk_true(); + while (l_true == is_sat) { + solver::scoped_push _s2(s); + s.assert_expr(fml); + is_sat = simplify_and_check_sat(0,0); + if (m_cancel) { + is_sat = l_undef; + } + if (is_sat == l_true) { + rational old_upper = m_upper; + m_upper = rational::zero(); + for (unsigned i = 0; i < m_soft.size(); ++i) { + VERIFY(m_model->eval(m_soft[i].get(), val)); + m_assignment[i] = !m.is_false(val); + if (!m_assignment[i]) { + m_upper += m_weights[i]; + } + } + IF_VERBOSE(1, verbose_stream() << "(wmaxsat.pb with upper bound: " << m_upper << ")\n";); + fml = u.mk_le(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper - minw); + was_sat = true; + } + } + if (is_sat == l_false && was_sat) { + is_sat = l_true; + m_lower = m_upper; + } + return is_sat; + } + + lbool wpm2_solve() { solver::scoped_push _s(s); pb_util u(m); @@ -645,6 +697,7 @@ namespace opt { expr_ref_vector block(m), ans(m), al(m), am(m); m_lower = m_upper = rational::zero(); obj_map ans_index; + vector amk; vector sc; for (unsigned i = 0; i < m_soft.size(); ++i) { @@ -804,7 +857,7 @@ namespace opt { } m_imp = alloc(imp, m, m_solver, nbs, ws); // race condition. m_imp->updt_params(m_params); - lbool is_sat = m_imp->pb_solve(); + lbool is_sat = m_imp->pb_simplify_solve(); k = m_imp->m_lower; m_solver.pop_core(1); return is_sat; @@ -819,6 +872,49 @@ namespace opt { } } + lbool simplify_and_check_sat(unsigned n, expr* const* assumptions) { + lbool is_sat = l_true; + tactic_ref tac1 = mk_simplify_tactic(m); + tactic_ref tac2 = mk_pb_preprocess_tactic(m); + tactic_ref tac = and_then(tac1.get(), tac2.get()); // TBD: make attribute for cancelation. + proof_converter_ref pc; + expr_dependency_ref core(m); + model_converter_ref mc; + goal_ref_buffer result; + goal_ref g(alloc(goal, m, true, false)); + for (unsigned i = 0; i < s.get_num_assertions(); ++i) { + g->assert_expr(s.get_assertion(i)); + } + for (unsigned i = 0; i < n; ++i) { + NOT_IMPLEMENTED_YET(); + // add assumption in a wrapper. + } + (*tac)(g, result, mc, pc, core); + if (result.empty()) { + is_sat = l_false; + } + else { + SASSERT(result.size() == 1); + goal* r = result[0]; + solver::scoped_push _s(m_solver); + // TBD ptr_vector asms; + for (unsigned i = 0; i < r->size(); ++i) { + // TBD collect assumptions from r + m_solver.assert_expr(r->form(i)); + } + is_sat = m_solver.check_sat_core(0, 0); + if (l_true == is_sat) { + m_solver.get_model(m_model); + if (mc) (*mc)(m_model, 0); + IF_VERBOSE(2, + g->display(verbose_stream() << "goal:\n"); + r->display(verbose_stream() << "reduced:\n"); + model_smt2_pp(verbose_stream(), m, *m_model, 0);); + } + } + return is_sat; + } + }; wmaxsmt::wmaxsmt(ast_manager& m, opt_solver& s, expr_ref_vector& soft_constraints, vector const& weights) { diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 8c9be4659..c04390ea8 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -168,8 +168,6 @@ namespace smt { bool_var abv = ctx.mk_bool_var(atom); ctx.set_var_theory(abv, get_id()); - IF_VERBOSE(3, verbose_stream() << mk_pp(atom, m) << "\n";); - ineq* c = alloc(ineq, literal(abv)); c->m_k = m_util.get_k(atom); numeral& k = c->m_k; @@ -192,21 +190,19 @@ namespace smt { else { SASSERT(m_util.is_at_least_k(atom) || m_util.is_ge(atom)); } - TRACE("pb", display(tout, *c);); c->unique(); lbool is_true = c->normalize(); c->prune(); - TRACE("pb", display(tout, *c);); literal lit(abv); - + + TRACE("pb", display(tout << mk_pp(atom, m), *c); tout << " := " << lit << "\n";); switch(is_true) { case l_false: lit = ~lit; // fall-through case l_true: ctx.mk_th_axiom(get_id(), 1, &lit); - TRACE("pb", tout << mk_pp(atom, m) << " := " << lit << "\n";); dealloc(c); return true; case l_undef: @@ -1246,14 +1242,12 @@ namespace smt { sum += c.coeff(i); } } - if (sum >= c.k()) { - IF_VERBOSE(0, - display(verbose_stream(), c, true); - for (unsigned i = 0; i < lits.size(); ++i) { - verbose_stream() << lits[i] << " "; - } - verbose_stream() << " => " << l << "\n";); - } + CTRACE("pb", (sum >= c.k()), + display(tout << "invalid assign" , c, true); + for (unsigned i = 0; i < lits.size(); ++i) { + tout << lits[i] << " "; + } + tout << " => " << l << "\n";); SASSERT(sum < c.k()); } diff --git a/src/tactic/core/pb_preprocess_tactic.cpp b/src/tactic/core/pb_preprocess_tactic.cpp index dd1033d54..28aa96e56 100644 --- a/src/tactic/core/pb_preprocess_tactic.cpp +++ b/src/tactic/core/pb_preprocess_tactic.cpp @@ -16,6 +16,20 @@ Author: Notes: + Resolution for PB constraints require the implicit + inequalities that each variable ranges over [0,1] + so not all resolvents produce smaller sets of clauses. + + We here implement subsumption resolution. + + x + y >= 1 + A~x + B~y + Cz >= k + --------------------- + Cz >= k - B + + where A <= B, x, y do not occur elsewhere. + + --*/ #include "pb_preprocess_tactic.h" #include "tactical.h" @@ -25,30 +39,100 @@ Notes: #include "expr_substitution.h" #include "ast_pp.h" +class pb_preproc_model_converter : public model_converter { + ast_manager& m; + pb_util pb; + expr_ref_vector m_refs; + svector > m_const; + +public: + pb_preproc_model_converter(ast_manager& m):m(m), pb(m), m_refs(m) {} + + virtual void operator()(model_ref & mdl, unsigned goal_idx) { + SASSERT(goal_idx == 0); + for (unsigned i = 0; i < m_const.size(); ++i) { + mdl->register_decl(m_const[i].first->get_decl(), m_const[i].second); + } + } + + void set_value(app* e, expr* v) { + SASSERT(e->get_num_args() == 0); + SASSERT(is_uninterp_const(e)); + m_const.push_back(std::make_pair(e, v)); + m_refs.push_back(e); + m_refs.push_back(v); + } + + void set_value(expr* e, bool p) { + if (m.is_not(e, e)) { + set_value(e, !p); + } + else { + SASSERT(is_app(e)); + set_value(to_app(e), p?m.mk_true():m.mk_false()); + } + } + + virtual model_converter * translate(ast_translation & translator) { + pb_preproc_model_converter* mc = alloc(pb_preproc_model_converter, translator.to()); + for (unsigned i = 0; i < m_const.size(); ++i) { + mc->set_value(translator(m_const[i].first), translator(m_const[i].second)); + } + return mc; + } + +}; + class pb_preprocess_tactic : public tactic { struct rec { unsigned_vector pos, neg; rec() { } }; - typedef obj_map var_map; + typedef obj_map var_map; ast_manager& m; pb_util pb; var_map m_vars; unsigned_vector m_ge; unsigned_vector m_other; + bool m_progress; th_rewriter m_r; struct declassifier { - obj_map& m_vars; - declassifier(obj_map& v): m_vars(v) {} + var_map& m_vars; + declassifier(var_map& v): m_vars(v) {} void operator()(app* e) { if (m_vars.contains(e)) { m_vars.remove(e); } } - void operator()(var* e) {} - void operator()(quantifier* q) {} + void operator()(var*) {} + void operator()(quantifier*) {} }; + void display_annotation(std::ostream& out, goal_ref const& g) { + for (unsigned i = 0; i < m_ge.size(); ++i) { + out << "ge " << m_ge[i] << ": " << mk_pp(g->form(m_ge[i]), m) << "\n"; + } + for (unsigned i = 0; i < m_other.size(); ++i) { + out << "ot " << m_other[i] << ": " << mk_pp(g->form(m_other[i]), m) << "\n"; + } + + var_map::iterator it = m_vars.begin(); + var_map::iterator end = m_vars.end(); + for (; it != end; ++it) { + app* e = it->m_key; + unsigned_vector const& pos = it->m_value.pos; + unsigned_vector const& neg = it->m_value.neg; + out << mk_pp(e, m) << ": "; + for (unsigned i = 0; i < pos.size(); ++i) { + out << "p: " << pos[i] << " "; + } + for (unsigned i = 0; i < neg.size(); ++i) { + out << "n: " << neg[i] << " "; + } + out << "\n"; + } + } + public: pb_preprocess_tactic(ast_manager& m, params_ref const& p = params_ref()): m(m), pb(m), m_r(m) {} @@ -68,65 +152,84 @@ public: SASSERT(g->is_well_sorted()); mc = 0; pc = 0; core = 0; + // TBD: bail out if cores are enabled. + // TBD: bail out if proofs are enabled/add proofs. + // TBD: model construction by back-filling solutions. + + pb_preproc_model_converter* pp = alloc(pb_preproc_model_converter, m); + mc = pp; + + g->inc_depth(); + result.push_back(g.get()); + while (simplify(g, *pp)); + + } + + bool simplify(goal_ref const& g, pb_preproc_model_converter& mc) { reset(); + normalize(g); + if (g->inconsistent()) { + return false; + } for (unsigned i = 0; i < g->size(); ++i) { - process_vars(i, g->form(i)); + process_vars(i, g); } - + if (m_ge.empty()) { - result.push_back(g.get()); - return; + return false; } - + for (unsigned i = 0; i < m_ge.size(); ++i) { classify_vars(i, to_app(g->form(m_ge[i]))); } - + declassifier dcl(m_vars); expr_mark visited; for (unsigned i = 0; !m_vars.empty() && i < m_other.size(); ++i) { for_each_expr(dcl, visited, g->form(m_other[i])); } - + if (m_vars.empty()) { - result.push_back(g.get()); - return; + return false; } - - g->inc_depth(); + + // display_annotation(tout, g); + m_progress = false; // first eliminate variables var_map::iterator it = next_resolvent(m_vars.begin()); - while (it != m_vars.end()) { - expr * e = it->m_key; + while (it != m_vars.end()) { + app * e = it->m_key; rec const& r = it->m_value; if (r.pos.empty()) { replace(r.neg, e, m.mk_false(), g); + mc.set_value(e, m.mk_false()); } else if (r.neg.empty()) { replace(r.pos, e, m.mk_true(), g); + mc.set_value(e, m.mk_true()); } + if (g->inconsistent()) return false; ++it; it = next_resolvent(it); } // now resolve clauses. it = next_resolvent(m_vars.begin()); while (it != m_vars.end()) { - expr * e = it->m_key; + + app * e = it->m_key; rec const& r = it->m_value; - if (r.pos.size() == 1) { - resolve(r.pos[0], r.neg, e, true, g); + if (r.pos.size() == 1 && !r.neg.empty()) { + resolve(mc, r.pos[0], r.neg, e, true, g); } - else if (r.neg.size() == 1) { - resolve(r.neg[0], r.pos, e, false, g); + else if (r.neg.size() == 1 && !r.pos.empty()) { + resolve(mc, r.neg[0], r.pos, e, false, g); } + if (g->inconsistent()) return false; ++it; it = next_resolvent(it); } - - g->elim_true(); - - result.push_back(g.get()); + return m_progress; } virtual void set_cancel(bool f) { @@ -146,9 +249,37 @@ private: m_vars.reset(); } + expr* negate(expr* e) { + if (m.is_not(e, e)) return e; + return m.mk_not(e); + } - void process_vars(unsigned i, expr* e) { + void normalize(goal_ref const& g) { expr* r; + expr_ref tmp(m); + for (unsigned i = 0; !g->inconsistent() && i < g->size(); ++i) { + expr* e = g->form(i); + if (m.is_not(e, r) && pb.is_ge(r)) { + rational k = pb.get_k(r); + rational sum(0); + expr_ref_vector args(m); + vector coeffs; + for (unsigned j = 0; j < to_app(r)->get_num_args(); ++j) { + sum += pb.get_coeff(r, j); + coeffs.push_back(pb.get_coeff(r, j)); + args.push_back(negate(to_app(r)->get_arg(j))); + } + tmp = pb.mk_ge(args.size(), coeffs.c_ptr(), args.c_ptr(), sum - k + rational::one()); + g->update(i, tmp); + } + } + } + + + void process_vars(unsigned i, goal_ref const& g) { + expr* r, *e; + e = g->form(i); + if (is_uninterp_const(e)) { m_ge.push_back(i); } @@ -168,8 +299,8 @@ private: void classify_vars(unsigned idx, app* e) { expr* r; - if (m.is_not(e, r)) { - insert(idx, r, false); + if (m.is_not(e, r) && is_uninterp_const(r)) { + insert(idx, e, false); return; } if (is_uninterp_const(e)) { @@ -182,15 +313,17 @@ private: // no-op } else if (m.is_not(arg, r)) { - insert(idx, r, false); + SASSERT(is_uninterp_const(r)); + insert(idx, to_app(r), false); } else { - insert(idx, arg, true); + SASSERT(is_uninterp_const(arg)); + insert(idx, to_app(arg), true); } } } - void insert(unsigned i, expr* e, bool pos) { + void insert(unsigned i, app* e, bool pos) { if (!m_vars.contains(e)) { m_vars.insert(e, rec()); } @@ -252,82 +385,86 @@ private: return true; } - void resolve(unsigned idx1, unsigned_vector const& positions, expr* e, bool pos, goal_ref const& g) { - if (!is_app(g->form(idx1))) { - return; - } - app* fml = to_app(g->form(idx1)); - if (m.is_true(fml)) { - return; - } - if (!is_valid(positions, g)) { - return; - } - if (positions.size() > 1 && !is_reduction(positions, fml, g)) { - return; - } - IF_VERBOSE(1, verbose_stream() << "resolving: " << mk_pp(fml, m) << "\n";); - m_r.set_substitution(0); - expr_ref tmp1(m), tmp2(m), e1(m), e2(m); - ptr_vector args; - vector coeffs; - rational k1, k2, c1, c2; - if (pos) { - e1 = e; - e2 = m.mk_not(e); - } - else { - e1 = m.mk_not(e); - e2 = e; - } - VERIFY(to_ge(fml, args, coeffs, k1)); - c1 = get_coeff(args.size(), args.c_ptr(), coeffs.c_ptr(), e1); - if (c1.is_zero()) { - return; - } - unsigned sz = coeffs.size(); - for (unsigned i = 0; i < positions.size(); ++i) { - unsigned idx2 = positions[i]; - if (idx2 == idx1) { - continue; + // Implement very special case of resolution. + + void resolve(pb_preproc_model_converter& mc, unsigned idx1, + unsigned_vector const& positions, app* e, bool pos, goal_ref const& g) { + if (positions.size() != 1) return; + unsigned idx2 = positions[0]; + expr_ref tmp1(m), tmp2(m); + expr* fml1 = g->form(idx1); + expr* fml2 = g->form(idx2); + expr_ref_vector args1(m), args2(m); + vector coeffs1, coeffs2; + rational k1, k2; + if (!to_ge(fml1, args1, coeffs1, k1)) return; + if (!k1.is_one()) return; + if (!to_ge(g->form(idx2), args2, coeffs2, k2)) return; + // check that each variable in idx1 occurs only in idx2 + unsigned min_index = 0; + rational min_coeff(0); + unsigned_vector indices; + for (unsigned i = 0; i < args1.size(); ++i) { + expr* x = args1[i].get(); + m.is_not(x, x); + if (!is_app(x)) return; + if (!m_vars.contains(to_app(x))) return; + rec const& r = m_vars.find(to_app(x)); + if (r.pos.size() != 1 || r.neg.size() != 1) return; + if (r.pos[0] != idx2 && r.neg[0] != idx2) return; + for (unsigned j = 0; j < args2.size(); ++j) { + if (is_complement(args1[i].get(), args2[j].get())) { + if (i == 0) { + min_coeff = coeffs2[j]; + } + else if (min_coeff > coeffs2[j]) { + min_coeff = coeffs2[j]; + min_index = j; + } + indices.push_back(j); + } } - app* fml2 = to_app(g->form(idx2)); - if (m.is_true(fml2)) continue; - VERIFY(to_ge(fml2, args, coeffs, k2)); - c2 = get_coeff(args.size()-sz, args.c_ptr()+sz, coeffs.c_ptr()+sz, e2); - if (!c2.is_zero()) { - rational m1(1), m2(1); - if (c1 != c2) { - rational lc = lcm(c1, c2); - m1 = lc/c1; - m2 = lc/c2; - for (unsigned j = 0; j < sz; ++j) { - coeffs[j] *= m1; - } - for (unsigned j = sz; j < args.size(); ++j) { - coeffs[j] *= m2; - } - } - tmp1 = pb.mk_ge(args.size(), coeffs.c_ptr(), args.c_ptr(), m1*k1 + m2*k2); - m_r(tmp1, tmp2); - TRACE("pb", tout << "to\n" << mk_pp(fml2, m) << " -> " << tmp2 << "\n";); - IF_VERBOSE(1, verbose_stream() << mk_pp(fml2, m) << " -> " << tmp2 << "\n";); - - g->update(idx2, tmp2); // proof & dependencies - - if (!m1.is_one()) { - for (unsigned j = 0; j < sz; ++j) { - coeffs[j] /= m1; - } - } - } - args.resize(sz); - coeffs.resize(sz); } + for (unsigned i = 0; i < indices.size(); ++i) { + unsigned j = indices[i]; + expr* arg = args2[j].get(); + if (j == min_index) { + args2[j] = m.mk_false(); + } + else { + args2[j] = m.mk_true(); + } + mc.set_value(arg, j != min_index); + } + + tmp1 = pb.mk_ge(args2.size(), coeffs2.c_ptr(), args2.c_ptr(), k2); + IF_VERBOSE(3, verbose_stream() << " " << tmp1 << "\n"; + for (unsigned i = 0; i < args2.size(); ++i) { + verbose_stream() << mk_pp(args2[i].get(), m) << " "; + } + verbose_stream() << "\n"; + ); + m_r(tmp1, tmp2); + if (pb.is_ge(tmp2) && pb.get_k(to_app(tmp2)).is_one()) { + tmp2 = m.mk_or(to_app(tmp2)->get_num_args(), to_app(tmp2)->get_args()); + } + IF_VERBOSE(3, + verbose_stream() << "resolve: " << mk_pp(fml1, m) << "\n" << mk_pp(fml2, m) << "\n" << tmp1 << "\n"; + verbose_stream() << "to\n" << mk_pp(fml2, m) << " -> " << tmp2 << "\n";); + g->update(idx1, m.mk_true()); // proof & dependencies + g->update(idx2, tmp2); // proof & dependencies + m_progress = true; + //IF_VERBOSE(0, if (!g->inconsistent()) display_annotation(verbose_stream(), g);); } - bool to_ge(app* e, ptr_vector& args, vector& coeffs, rational& k) { + bool is_complement(expr* x, expr* y) const { + if (m.is_not(x,x)) return x == y; + if (m.is_not(y,y)) return x == y; + return false; + } + + bool to_ge(expr* e, expr_ref_vector& args, vector& coeffs, rational& k) { expr* r; if (is_uninterp_const(e)) { args.push_back(e); @@ -340,17 +477,19 @@ private: k = rational::one(); } else if (pb.is_ge(e)) { - SASSERT(pure_args(e)); - for (unsigned i = 0; i < e->get_num_args(); ++i) { - args.push_back(e->get_arg(i)); - coeffs.push_back(pb.get_coeff(e, i)); + app* a = to_app(e); + SASSERT(pure_args(a)); + for (unsigned i = 0; i < a->get_num_args(); ++i) { + args.push_back(a->get_arg(i)); + coeffs.push_back(pb.get_coeff(a, i)); } k = pb.get_k(e); } else if (m.is_or(e)) { + app* a = to_app(e); SASSERT(pure_args(e)); - for (unsigned i = 0; i < e->get_num_args(); ++i) { - args.push_back(e->get_arg(i)); + for (unsigned i = 0; i < a->get_num_args(); ++i) { + args.push_back(a->get_arg(i)); coeffs.push_back(rational::one()); } k = rational::one(); @@ -375,8 +514,10 @@ private: TRACE("pb", tout << mk_pp(f, m) << " -> " << tmp << " by " << mk_pp(e, m) << " |-> " << mk_pp(v, m) << "\n";); g->update(idx, tmp); // proof & dependencies. + m_progress = true; } } + m_r.set_substitution(0); } }; @@ -384,3 +525,83 @@ private: tactic * mk_pb_preprocess_tactic(ast_manager & m, params_ref const & p) { return alloc(pb_preprocess_tactic, m); } + +#if 0 + + struct resolve_t { + app* e; + expr* lhs; + expr* rhs; + expr* res; + resolve_t(app* e, expr* lhs, expr* rhs, expr* res): + e(e), lhs(lhs), rhs(rhs), res(res) + {} + }; + + svector m_resolve; + + void satisfy(model_ref& mdl, expr* e) { + if (m.is_true(e)) { + return; + } + if (pb.is_ge(e)) { + rational k = pb.get_k(e); + rational c(0); + app* a = to_app(e); + for (unsigned i = 0; c < k && i < a->get_num_args(); ++i) { + expr* arg = a->get_arg(i); + if (is_uninterp_const(arg)) { + mdl->register_decl(to_app(arg)->get_decl(), m.mk_true()); + std::cout << mk_pp(arg, m) << " |-> true\n"; + c += pb.get_coeff(a, i); + } + else if (m.is_not(arg, arg) && is_uninterp_const(arg)) { + mdl->register_decl(to_app(arg)->get_decl(), m.mk_false()); + std::cout << mk_pp(arg, m) << " |-> false\n"; + c += pb.get_coeff(a, i); + } + } + SASSERT(c >= k); + return; + } + UNREACHABLE(); + } + + for (unsigned i = m_resolve.size(); i > 0; ) { + --i; + resolve_t const& r = m_resolve[i]; + expr_ref tmp1(m), tmp2(m), tmp3(m), tmp4(m); + VERIFY(mdl->eval(r.rhs, tmp2)); + satisfy(mdl, tmp2); + + VERIFY(mdl->eval(r.lhs, tmp1)); + satisfy(mdl, tmp1); + + if (m.is_false(tmp2) || m.is_false(tmp1)) { + VERIFY(mdl->eval(r.res, tmp3)); + th_rewriter rw(m); + rw(r.res, tmp4); + std::cout << "L:" << mk_pp(r.lhs,m) << " " << tmp1 << "\n"; + std::cout << "R:" << mk_pp(r.rhs,m) << " " << tmp2 << "\n"; + std::cout << "LR:" << mk_pp(r.res,m) << "\n" << tmp4 << "\n" << tmp3 << "\n"; + exit(0); + } + VERIFY(mdl->eval(r.e, tmp3)); + if (r.e == tmp3) { + mdl->register_decl(r.e->get_decl(), m.mk_true()); + } + // evaluate lhs, rhs + // determine how to + // assign e based on residue. + } + + void resolve(app* e, expr* lhs, expr* rhs, expr* res) { + m_refs.push_back(e); + m_refs.push_back(lhs); + m_refs.push_back(rhs); + m_refs.push_back(res); + m_resolve.push_back(resolve_t(e, lhs, rhs, res)); + } + + +#endif From a0e98ca39bf12bb320c728be759eefb28a9c4436 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 26 Dec 2013 10:14:05 -0800 Subject: [PATCH 245/925] working on pb pre-processing/subsumption Signed-off-by: Nikolaj Bjorner --- src/tactic/core/pb_preprocess_tactic.cpp | 51 ++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/src/tactic/core/pb_preprocess_tactic.cpp b/src/tactic/core/pb_preprocess_tactic.cpp index 28aa96e56..7297d767b 100644 --- a/src/tactic/core/pb_preprocess_tactic.cpp +++ b/src/tactic/core/pb_preprocess_tactic.cpp @@ -150,11 +150,10 @@ public: proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + pc = 0; core = 0; // TBD: bail out if cores are enabled. // TBD: bail out if proofs are enabled/add proofs. - // TBD: model construction by back-filling solutions. pb_preproc_model_converter* pp = alloc(pb_preproc_model_converter, m); mc = pp; @@ -162,7 +161,6 @@ public: g->inc_depth(); result.push_back(g.get()); while (simplify(g, *pp)); - } bool simplify(goal_ref const& g, pb_preproc_model_converter& mc) { @@ -228,7 +226,34 @@ public: ++it; it = next_resolvent(it); } + + // now check for subsumption. + for (unsigned i = 0; i < m_ge.size(); ++i) { + + expr_ref_vector args1(m), args2(m); + vector coeffs1, coeffs2; + rational k1, k2; + expr* fml = g->form(m_ge[i]); + if (!to_ge(fml, args1, coeffs1, k1)) continue; + if (args1.empty()) continue; + expr* arg = args1[0].get(); + bool neg = m.is_not(arg, arg); + if (!is_uninterp_const(arg)) continue; + rec const& r = m_vars.find(to_app(arg)); + unsigned_vector const& pos = neg?r.neg:r.pos; + for (unsigned j = 0; j < pos.size(); ++j) { + unsigned k = pos[j]; + if (k == i) continue; + if (!to_ge(g->form(k), args2, coeffs2, k2)) continue; + if (subsumes(args1, coeffs1, k1, args2, coeffs2, k2)) { + g->update(k, m.mk_true()); + m_progress = true; + } + } + } + g->elim_true(); + return m_progress; } @@ -487,7 +512,7 @@ private: } else if (m.is_or(e)) { app* a = to_app(e); - SASSERT(pure_args(e)); + SASSERT(pure_args(a)); for (unsigned i = 0; i < a->get_num_args(); ++i) { args.push_back(a->get_arg(i)); coeffs.push_back(rational::one()); @@ -519,6 +544,24 @@ private: } m_r.set_substitution(0); } + + bool subsumes(expr_ref_vector const& args1, + vector const& coeffs1, rational const& k1, + expr_ref_vector const& args2, + vector const& coeffs2, rational const& k2) { + if (k2 > k1) return false; + for (unsigned i = 0; i < args1.size(); ++i) { + bool found = false; + for (unsigned j = 0; !found && j < args2.size(); ++j) { + if (args1[i] == args2[j]) { + if (coeffs1[1] > coeffs2[j]) return false; + found = true; + } + } + if (!found) return false; + } + return true; + } }; From 58f8181a7443a53521edc0040f2aa56eee380572 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 26 Dec 2013 17:14:29 -0800 Subject: [PATCH 246/925] fixes to dotnet interface Signed-off-by: Nikolaj Bjorner --- src/api/api_opt.cpp | 11 ++++++----- src/api/dotnet/Optimize.cs | 4 ++-- src/opt/opt_context.cpp | 8 +++++--- src/smt/theory_arith_aux.h | 4 +++- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index d4dac1db3..d38b5e38c 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -129,12 +129,13 @@ extern "C" { RESET_ERROR_CODE(); model_ref _m; to_optimize_ref(o).get_model(_m); - if (!_m) { - SET_ERROR_CODE(Z3_INVALID_USAGE); - RETURN_Z3(0); - } Z3_model_ref * m_ref = alloc(Z3_model_ref); - m_ref->m_model = _m; + if (_m) { + m_ref->m_model = _m; + } + else { + m_ref->m_model = alloc(model, mk_c(c)->m()); + } mk_c(c)->save_object(m_ref); RETURN_Z3(of_model(m_ref)); Z3_CATCH_RETURN(0); diff --git a/src/api/dotnet/Optimize.cs b/src/api/dotnet/Optimize.cs index e892ee70f..8284125d5 100644 --- a/src/api/dotnet/Optimize.cs +++ b/src/api/dotnet/Optimize.cs @@ -142,12 +142,12 @@ namespace Microsoft.Z3 public ArithExpr GetLower(uint index) { - return new ArithExpr(Context, Native.Z3_optimize_get_lower(Context.nCtx, NativeObject, index)); + return (ArithExpr)Expr.Create(Context, Native.Z3_optimize_get_lower(Context.nCtx, NativeObject, index)); } public ArithExpr GetUpper(uint index) { - return new ArithExpr(Context, Native.Z3_optimize_get_upper(Context.nCtx, NativeObject, index)); + return (ArithExpr)Expr.Create(Context, Native.Z3_optimize_get_upper(Context.nCtx, NativeObject, index)); } public override string ToString() diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 0695abc6d..c3dd32ab8 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -114,10 +114,12 @@ namespace opt { void context::get_model(model_ref& mdl) { mdl = m_model; - if (m_model_converter) { - (*m_model_converter)(mdl, 0); + if (mdl) { + if (m_model_converter) { + (*m_model_converter)(mdl, 0); + } + get_solver().mc()(mdl, 0); } - get_solver().mc()(mdl, 0); } lbool context::execute_min_max(unsigned index, bool committed) { diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index b0d983bca..485b68e2a 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -1315,6 +1315,7 @@ namespace smt { } theory_var curr_x_i = pick_var_to_leave(curr_x_j, curr_inc, curr_a_ij, curr_gain, skipped_row); if (curr_x_i == null_theory_var) { + TRACE("opt", tout << "unbounded\n";); // we can increase/decrease curr_x_j as much as we want. x_i = null_theory_var; // unbounded x_j = curr_x_j; @@ -1340,7 +1341,8 @@ namespace smt { } } } - TRACE("opt", tout << "after traversing row:\nx_i: v" << x_i << ", x_j: v" << x_j << ", gain: " << gain << "\n";); + TRACE("opt", tout << "after traversing row:\nx_i: v" << x_i << ", x_j: v" << x_j << ", gain: " << gain << "\n"; + tout << "skipped row: " << (skipped_row?"yes":"no") << "\n";); if (x_j == null_theory_var) { TRACE("opt", tout << "row is " << (max ? "maximized" : "minimized") << "\n";); From 32762b54a74f22113084bcb0269546df3a212297 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 27 Dec 2013 07:50:25 -0800 Subject: [PATCH 247/925] debug looping behavior Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith.h | 4 ++-- src/smt/theory_arith_aux.h | 28 +++++++++++++++++++++------- src/smt/theory_arith_int.h | 15 +++++++++++---- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index a7d58080e..ee2ce349d 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -855,8 +855,8 @@ namespace smt { row m_tmp_row; void add_tmp_row(row & r1, numeral const & coeff, row const & r2); - theory_var pick_var_to_leave(theory_var x_j, bool inc, numeral & a_ij, inf_numeral & gain, bool& skiped_row); - bool is_safe_to_leave(theory_var x); + theory_var pick_var_to_leave(bool has_int, theory_var x_j, bool inc, numeral & a_ij, inf_numeral & gain, bool& skiped_row); + bool is_safe_to_leave(theory_var x, bool& has_int); void move_to_bound(theory_var x_i, bool inc); template void add_tmp_row_entry(row & r, numeral const & coeff, theory_var v); diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 485b68e2a..77845fee6 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -928,7 +928,7 @@ namespace smt { */ template - bool theory_arith::is_safe_to_leave(theory_var x) { + bool theory_arith::is_safe_to_leave(theory_var x, bool& has_int) { if (get_context().is_shared(get_enode(x))) { return false; @@ -936,14 +936,16 @@ namespace smt { column & c = m_columns[x]; typename svector::iterator it = c.begin_entries(); typename svector::iterator end = c.end_entries(); + has_int = false; for (; it != end; ++it) { if (it->is_dead()) continue; row const & r = m_rows[it->m_row_id]; theory_var s = r.get_base_var(); numeral const & coeff = r[it->m_row_idx].m_coeff; + if (s != null_theory_var && is_int(s)) has_int = true; bool is_unsafe = (s != null_theory_var && is_int(s) && !coeff.is_int()); is_unsafe = is_unsafe || (s != null_theory_var && get_context().is_shared(get_enode(s))); - TRACE("opt", tout << "is v" << x << " safe to leave for v" << s << "? " << (is_unsafe?"no":"yes") << "\n"; + TRACE("opt", tout << "is v" << x << " safe to leave for v" << s << "? " << (is_unsafe?"no":"yes") << " " << (has_int?"int":"real") << "\n"; display_row(tout, r, true);); if (is_unsafe) return false; } @@ -952,7 +954,9 @@ namespace smt { } template - theory_var theory_arith::pick_var_to_leave(theory_var x_j, bool inc, numeral & a_ij, inf_numeral & gain, bool& skipped_row) { + theory_var theory_arith::pick_var_to_leave( + bool has_int, theory_var x_j, bool inc, + numeral & a_ij, inf_numeral & gain, bool& skipped_row) { TRACE("opt", tout << "selecting variable to replace v" << x_j << ", inc: " << inc << "\n";); theory_var x_i = null_theory_var; inf_numeral curr_gain; @@ -982,6 +986,10 @@ namespace smt { skipped_row = true; continue; } + if (!curr_gain.is_int() && has_int) { + skipped_row = true; + continue; + } x_i = s; a_ij = coeff; gain = curr_gain; @@ -1294,6 +1302,7 @@ namespace smt { #ifdef _TRACE unsigned i = 0; #endif + max_min_t result; while (true) { x_j = null_theory_var; x_i = null_theory_var; @@ -1307,13 +1316,14 @@ namespace smt { SASSERT(is_non_base(curr_x_j)); curr_coeff = it->m_coeff; bool curr_inc = curr_coeff.is_pos() ? max : !max; + bool has_int = false; if ((curr_inc && at_upper(curr_x_j)) || (!curr_inc && at_lower(curr_x_j))) continue; // variable cannot be used for max/min. - if (!is_safe_to_leave(curr_x_j)) { + if (!is_safe_to_leave(curr_x_j, has_int)) { skipped_row = true; continue; } - theory_var curr_x_i = pick_var_to_leave(curr_x_j, curr_inc, curr_a_ij, curr_gain, skipped_row); + theory_var curr_x_i = pick_var_to_leave(has_int, curr_x_j, curr_inc, curr_a_ij, curr_gain, skipped_row); if (curr_x_i == null_theory_var) { TRACE("opt", tout << "unbounded\n";); // we can increase/decrease curr_x_j as much as we want. @@ -1348,7 +1358,8 @@ namespace smt { TRACE("opt", tout << "row is " << (max ? "maximized" : "minimized") << "\n";); SASSERT(valid_row_assignment()); SASSERT(satisfy_bounds()); - return skipped_row?BEST_EFFORT:OPTIMIZED; + result = skipped_row?BEST_EFFORT:OPTIMIZED; + break; } if (x_i == null_theory_var) { @@ -1367,7 +1378,8 @@ namespace smt { SASSERT(satisfy_bounds()); continue; } - return UNBOUNDED; + result = skipped_row?BEST_EFFORT:UNBOUNDED; + break; } if (!is_fixed(x_j) && is_bounded(x_j) && (upper_bound(x_j) - lower_bound(x_j) <= gain)) { @@ -1413,6 +1425,8 @@ namespace smt { SASSERT(valid_row_assignment()); SASSERT(satisfy_bounds()); } + TRACE("opt", display(tout);); + return result; } /** diff --git a/src/smt/theory_arith_int.h b/src/smt/theory_arith_int.h index 4fa9e75c7..4b5388062 100644 --- a/src/smt/theory_arith_int.h +++ b/src/smt/theory_arith_int.h @@ -33,11 +33,15 @@ namespace smt { // Integrality // // ----------------------------------- + /** \brief Move non base variables to one of its bounds. If the variable does not have bounds, it is integer, but it is not assigned to an integer value, then the variable is set to an integer value. + In mixed integer/real problems moving a real variable to a bound could cause an integer value to + have an infinitesimal. Such an assignment would disable mk_gomory_cut, and Z3 would loop. + */ template void theory_arith::move_non_base_vars_to_bounds() { @@ -413,10 +417,10 @@ namespace smt { for (; it != end; ++it) { // All non base variables must be at their bounds and assigned to rationals (that is, infinitesimals are not allowed). if (!it->is_dead() && it->m_var != b && (!at_bound(it->m_var) || !get_value(it->m_var).is_rational())) { - TRACE("gomory_cut", tout << "row is gomory cut target:\n"; + TRACE("gomory_cut", tout << "row is not gomory cut target:\n"; display_var(tout, it->m_var); tout << "at_bound: " << at_bound(it->m_var) << "\n"; - tout << "infinitesimal: " << get_value(it->m_var).is_rational() << "\n";); + tout << "infinitesimal: " << !get_value(it->m_var).is_rational() << "\n";); return false; } } @@ -1378,6 +1382,7 @@ namespace smt { m_branch_cut_counter++; // TODO: add giveup code if (m_branch_cut_counter % m_params.m_arith_branch_cut_ratio == 0) { + TRACE("opt", display(tout);); move_non_base_vars_to_bounds(); if (!make_feasible()) { TRACE("arith_int", tout << "failed to move variables to bounds.\n";); @@ -1389,7 +1394,9 @@ namespace smt { TRACE("arith_int", tout << "v" << int_var << " does not have an integer assignment: " << get_value(int_var) << "\n";); SASSERT(is_base(int_var)); row const & r = m_rows[get_var_row(int_var)]; - mk_gomory_cut(r); + if (!mk_gomory_cut(r)) { + // silent failure + } return FC_CONTINUE; } } @@ -1399,7 +1406,7 @@ namespace smt { } theory_var int_var = find_infeasible_int_base_var(); if (int_var != null_theory_var) { - TRACE("arith_int", tout << "v" << int_var << " does not have and integer assignment: " << get_value(int_var) << "\n";); + TRACE("arith_int", tout << "v" << int_var << " does not have an integer assignment: " << get_value(int_var) << "\n";); // apply branching branch_infeasible_int_var(int_var); return FC_CONTINUE; From 5cc4cc82264790b2bfd60068cbf1107e0f25a693 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Fri, 27 Dec 2013 11:18:10 -0800 Subject: [PATCH 248/925] Add MSF plugins --- .../App.config | 60 +++ .../Properties/AssemblyInfo.cs | 36 ++ .../ServiceTests.cs | 86 ++++ .../SolverFoundation.Plugin.Z3.Tests.csproj | 70 ++++ .../SolverTests.cs | 132 ++++++ .../SolverFoundation.Plugin.Z3/AbortWorker.cs | 92 +++++ .../Properties/AssemblyInfo.cs | 36 ++ .../SolverFoundation.Plugin.Z3.csproj | 185 +++++++++ .../msf/SolverFoundation.Plugin.Z3/Utils.cs | 124 ++++++ .../Z3BaseDirective.cs | 101 +++++ .../Z3BaseParams.cs | 103 +++++ .../Z3BaseSolver.cs | 381 +++++++++++++++++ .../Z3MILPDirective.cs | 9 + .../Z3MILPParams.cs | 19 + .../Z3MILPSolver.cs | 230 +++++++++++ .../Z3TermDirective.cs | 9 + .../Z3TermParams.cs | 17 + .../Z3TermSolver.cs | 382 ++++++++++++++++++ examples/msf/Validator/App.config | 60 +++ ...crosoftSolverFoundationForExcel.dll.config | 58 +++ examples/msf/Validator/Program.cs | 194 +++++++++ .../msf/Validator/Properties/AssemblyInfo.cs | 36 ++ examples/msf/Validator/Validator.csproj | 143 +++++++ examples/msf/Z3MSFPlugin.sln | 120 ++++++ 24 files changed, 2683 insertions(+) create mode 100644 examples/msf/SolverFoundation.Plugin.Z3.Tests/App.config create mode 100644 examples/msf/SolverFoundation.Plugin.Z3.Tests/Properties/AssemblyInfo.cs create mode 100644 examples/msf/SolverFoundation.Plugin.Z3.Tests/ServiceTests.cs create mode 100644 examples/msf/SolverFoundation.Plugin.Z3.Tests/SolverFoundation.Plugin.Z3.Tests.csproj create mode 100644 examples/msf/SolverFoundation.Plugin.Z3.Tests/SolverTests.cs create mode 100644 examples/msf/SolverFoundation.Plugin.Z3/AbortWorker.cs create mode 100644 examples/msf/SolverFoundation.Plugin.Z3/Properties/AssemblyInfo.cs create mode 100644 examples/msf/SolverFoundation.Plugin.Z3/SolverFoundation.Plugin.Z3.csproj create mode 100644 examples/msf/SolverFoundation.Plugin.Z3/Utils.cs create mode 100644 examples/msf/SolverFoundation.Plugin.Z3/Z3BaseDirective.cs create mode 100644 examples/msf/SolverFoundation.Plugin.Z3/Z3BaseParams.cs create mode 100644 examples/msf/SolverFoundation.Plugin.Z3/Z3BaseSolver.cs create mode 100644 examples/msf/SolverFoundation.Plugin.Z3/Z3MILPDirective.cs create mode 100644 examples/msf/SolverFoundation.Plugin.Z3/Z3MILPParams.cs create mode 100644 examples/msf/SolverFoundation.Plugin.Z3/Z3MILPSolver.cs create mode 100644 examples/msf/SolverFoundation.Plugin.Z3/Z3TermDirective.cs create mode 100644 examples/msf/SolverFoundation.Plugin.Z3/Z3TermParams.cs create mode 100644 examples/msf/SolverFoundation.Plugin.Z3/Z3TermSolver.cs create mode 100644 examples/msf/Validator/App.config create mode 100644 examples/msf/Validator/MicrosoftSolverFoundationForExcel.dll.config create mode 100644 examples/msf/Validator/Program.cs create mode 100644 examples/msf/Validator/Properties/AssemblyInfo.cs create mode 100644 examples/msf/Validator/Validator.csproj create mode 100644 examples/msf/Z3MSFPlugin.sln diff --git a/examples/msf/SolverFoundation.Plugin.Z3.Tests/App.config b/examples/msf/SolverFoundation.Plugin.Z3.Tests/App.config new file mode 100644 index 000000000..75e2872f1 --- /dev/null +++ b/examples/msf/SolverFoundation.Plugin.Z3.Tests/App.config @@ -0,0 +1,60 @@ + + + +
+ + + + + + + + + + + + + + + + diff --git a/examples/msf/SolverFoundation.Plugin.Z3.Tests/Properties/AssemblyInfo.cs b/examples/msf/SolverFoundation.Plugin.Z3.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..b58f97eda --- /dev/null +++ b/examples/msf/SolverFoundation.Plugin.Z3.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SolverFoundation.Plugin.Z3.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SolverFoundation.Plugin.Z3.Tests")] +[assembly: AssemblyCopyright("Copyright © 2013")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("27657eee-ca7b-4996-a905-86a3f4584988")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/examples/msf/SolverFoundation.Plugin.Z3.Tests/ServiceTests.cs b/examples/msf/SolverFoundation.Plugin.Z3.Tests/ServiceTests.cs new file mode 100644 index 000000000..25a8e2d26 --- /dev/null +++ b/examples/msf/SolverFoundation.Plugin.Z3.Tests/ServiceTests.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using Microsoft.SolverFoundation.Common; +using Microsoft.SolverFoundation.Solvers; +using Microsoft.SolverFoundation.Services; +using Microsoft.SolverFoundation.Plugin.Z3; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Microsoft.SolverFoundation.Plugin.Z3.Tests +{ + [TestClass] + public class ServiceTests + { + [TestInitialize] + public void SetUp() + { + SolverContext context = SolverContext.GetContext(); + context.ClearModel(); + } + + private void TestService1(Directive directive) + { + SolverContext context = SolverContext.GetContext(); + Model model = context.CreateModel(); + + Decision x1 = new Decision(Domain.RealRange(0, 2), "x1"); + Decision x2 = new Decision(Domain.RealRange(0, 2), "x2"); + + Decision z = new Decision(Domain.IntegerRange(0, 1), "z"); + + model.AddDecisions(x1, x2, z); + + model.AddConstraint("Row0", x1 - z <= 1); + model.AddConstraint("Row1", x2 + z <= 2); + + Goal goal = model.AddGoal("Goal0", GoalKind.Maximize, x1 + x2); + + Solution solution = context.Solve(directive); + Assert.IsTrue(goal.ToInt32() == 3); + context.ClearModel(); + } + + private void TestService2(Directive directive) + { + SolverContext context = SolverContext.GetContext(); + Model model = context.CreateModel(); + + Decision x1 = new Decision(Domain.RealNonnegative, "x1"); + Decision x2 = new Decision(Domain.RealNonnegative, "x2"); + + Decision z = new Decision(Domain.IntegerRange(0, 1), "z"); + + Rational M = 100; + + model.AddDecisions(x1, x2, z); + + model.AddConstraint("Row0", x1 + x2 >= 1); + model.AddConstraint("Row1", x1 - z * 100 <= 0); + model.AddConstraint("Row2", x2 + z * 100 <= 100); + + Goal goal = model.AddGoal("Goal0", GoalKind.Maximize, x1 + x2); + + Solution solution = context.Solve(directive); + Assert.IsTrue(goal.ToInt32() == 100); + context.ClearModel(); + } + + [TestMethod] + public void TestService1() + { + TestService1(new Z3MILPDirective()); + TestService1(new Z3TermDirective()); + } + + [TestMethod] + public void TestService2() + { + TestService2(new Z3MILPDirective()); + TestService2(new Z3TermDirective()); + } + + } +} diff --git a/examples/msf/SolverFoundation.Plugin.Z3.Tests/SolverFoundation.Plugin.Z3.Tests.csproj b/examples/msf/SolverFoundation.Plugin.Z3.Tests/SolverFoundation.Plugin.Z3.Tests.csproj new file mode 100644 index 000000000..24cecfa10 --- /dev/null +++ b/examples/msf/SolverFoundation.Plugin.Z3.Tests/SolverFoundation.Plugin.Z3.Tests.csproj @@ -0,0 +1,70 @@ + + + + + Debug + AnyCPU + {280AEE2F-1FDB-4A27-BE37-14DC154C873B} + Library + Properties + Microsoft.SolverFoundation.Plugin.Z3.Tests + SolverFoundation.Plugin.Z3.Tests + v4.0 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + x86 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + x86 + + + + ..\Microsoft.Solver.Foundation.dll + + + + + + + + + + + + + + + + + + + + + {7340e664-f648-4ff7-89b2-f4da424996d3} + SolverFoundation.Plugin.Z3 + + + + + \ No newline at end of file diff --git a/examples/msf/SolverFoundation.Plugin.Z3.Tests/SolverTests.cs b/examples/msf/SolverFoundation.Plugin.Z3.Tests/SolverTests.cs new file mode 100644 index 000000000..c2cd0c270 --- /dev/null +++ b/examples/msf/SolverFoundation.Plugin.Z3.Tests/SolverTests.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using Microsoft.SolverFoundation.Common; +using Microsoft.SolverFoundation.Solvers; +using Microsoft.SolverFoundation.Services; +using Microsoft.SolverFoundation.Plugin.Z3; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Microsoft.SolverFoundation.Plugin.Z3.Tests +{ + [TestClass] + public class SolverTests + { + [TestMethod] + public void TestMILPSolver1() + { + var solver = new Z3MILPSolver(); + int goal; + + solver.AddRow("goal", out goal); + int x1, x2, z; + + // 0 <= x1 <= 2 + solver.AddVariable("x1", out x1); + solver.SetBounds(x1, 0, 2); + + // 0 <= x2 <= 2 + solver.AddVariable("x2", out x2); + solver.SetBounds(x2, 0, 2); + + // z is an integer in [0,1] + solver.AddVariable("z", out z); + solver.SetIntegrality(z, true); + solver.SetBounds(z, 0, 1); + + //max x1 + x2 + solver.SetCoefficient(goal, x1, 1); + solver.SetCoefficient(goal, x2, 1); + solver.AddGoal(goal, 1, false); + + // 0 <= x1 -z <= 1 + int row1; + solver.AddRow("rowI1", out row1); + solver.SetBounds(row1, 0, 1); + solver.SetCoefficient(row1, x1, 1); + solver.SetCoefficient(row1, z, -1); + + // 0 <= x2 + z <= 2 + int row2; + solver.AddRow("rowI2", out row2); + solver.SetBounds(row2, 0, 2); + solver.SetCoefficient(row2, x2, 1); + solver.SetCoefficient(row2, z, 1); + + var p = new Z3MILPParams(); + solver.Solve(p); + + Assert.IsTrue(solver.Result == LinearResult.Optimal); + Assert.AreEqual(solver.GetValue(x1), 2 * Rational.One); + Assert.AreEqual(solver.GetValue(x2), Rational.One); + Assert.AreEqual(solver.GetValue(z), Rational.One); + Assert.AreEqual(solver.GetValue(goal), 3 * Rational.One); + } + + [TestMethod] + public void TestMILPSolver2() + { + var solver = new Z3MILPSolver(); + int goal, extraGoal; + + Rational M = 100; + solver.AddRow("goal", out goal); + int x1, x2, z; + + // 0 <= x1 <= 100 + solver.AddVariable("x1", out x1); + solver.SetBounds(x1, 0, M); + + // 0 <= x2 <= 100 + solver.AddVariable("x2", out x2); + solver.SetBounds(x2, 0, M); + + // z is an integer in [0,1] + solver.AddVariable("z", out z); + solver.SetIntegrality(z, true); + solver.SetBounds(z, 0, 1); + + solver.SetCoefficient(goal, x1, 1); + solver.SetCoefficient(goal, x2, 2); + solver.AddGoal(goal, 1, false); + + solver.AddRow("extraGoal", out extraGoal); + + solver.SetCoefficient(extraGoal, x1, 2); + solver.SetCoefficient(extraGoal, x2, 1); + solver.AddGoal(extraGoal, 2, false); + + // x1 + x2 >= 1 + int row; + solver.AddRow("row", out row); + solver.SetBounds(row, 1, Rational.PositiveInfinity); + solver.SetCoefficient(row, x1, 1); + solver.SetCoefficient(row, x2, 1); + + + // x1 - M*z <= 0 + int row1; + solver.AddRow("rowI1", out row1); + solver.SetBounds(row1, Rational.NegativeInfinity, 0); + solver.SetCoefficient(row1, x1, 1); + solver.SetCoefficient(row1, z, -M); + + // x2 - M* (1-z) <= 0 + int row2; + solver.AddRow("rowI2", out row2); + solver.SetBounds(row2, Rational.NegativeInfinity, M); + solver.SetCoefficient(row2, x2, 1); + solver.SetCoefficient(row2, z, M); + + var p = new Z3MILPParams(); + p.OptKind = OptimizationKind.BoundingBox; + + solver.Solve(p); + Assert.IsTrue(solver.Result == LinearResult.Optimal); + Assert.AreEqual(solver.GetValue(goal), 200 * Rational.One); + Assert.AreEqual(solver.GetValue(extraGoal), 200 * Rational.One); + } + } +} diff --git a/examples/msf/SolverFoundation.Plugin.Z3/AbortWorker.cs b/examples/msf/SolverFoundation.Plugin.Z3/AbortWorker.cs new file mode 100644 index 000000000..99d6fe17a --- /dev/null +++ b/examples/msf/SolverFoundation.Plugin.Z3/AbortWorker.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using Microsoft.Z3; + +namespace Microsoft.SolverFoundation.Plugin.Z3 +{ + /// + /// Thread that will wait until the query abort function returns true or + /// the stop method is called. If the abort function returns true at some + /// point it will issue a softCancel() call to Z3. + /// + internal class AbortWorker + { + #region Private Members + + /// The Z3 solver + private Microsoft.Z3.Context _context; + /// The abort function to use to check if we are aborted + private Func _QueryAbortFunction; + /// Flag indicating that worker should stop + private bool _stop = false; + /// Flag indicating that we have been sent an abort signal + private bool _aborted = false; + + #endregion Private Members + + #region Construction + + /// + /// Worker constructor taking a Z3 instance and a function to periodically + /// check for aborts. + /// + /// Z3 instance + /// method to call to check for aborts + public AbortWorker(Context context, Func queryAbortFunction) + { + _context = context; + _QueryAbortFunction = queryAbortFunction; + } + + #endregion Construction + + #region Public Methods + + /// + /// Stop the abort worker. + /// + public void Stop() + { + _stop = true; + } + + /// + /// Is true if we have been aborted. + /// + public bool Aborted + { + get + { + return _aborted; + } + } + + /// + /// Starts the abort worker. The worker checks the abort method + /// periodically until either it is stopped by a call to the Stop() + /// method or it gets an abort signal. In the latter case it will + /// issue a soft abort signal to Z3. + /// + public void Start() + { + // We go until someone stops us + _stop = false; + while (!_stop && !_QueryAbortFunction()) + { + // Wait for a while + Thread.Sleep(10); + } + // If we were stopped on abort, cancel z3 + if (!_stop) + { + _context.Interrupt(); + _aborted = true; + } + } + + #endregion Public Methods + } +} diff --git a/examples/msf/SolverFoundation.Plugin.Z3/Properties/AssemblyInfo.cs b/examples/msf/SolverFoundation.Plugin.Z3/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..b30c01ab4 --- /dev/null +++ b/examples/msf/SolverFoundation.Plugin.Z3/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SolverFoundation.Plugin.Z3")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("SolverFoundation.Plugin.Z3")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2013")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("ed1476c0-96de-4d2c-983d-3888b140c3ad")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/examples/msf/SolverFoundation.Plugin.Z3/SolverFoundation.Plugin.Z3.csproj b/examples/msf/SolverFoundation.Plugin.Z3/SolverFoundation.Plugin.Z3.csproj new file mode 100644 index 000000000..6a4a22aec --- /dev/null +++ b/examples/msf/SolverFoundation.Plugin.Z3/SolverFoundation.Plugin.Z3.csproj @@ -0,0 +1,185 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {7340E664-F648-4FF7-89B2-F4DA424996D3} + Library + Properties + Microsoft.SolverFoundation.Plugin.Z3 + SolverFoundation.Plugin.Z3 + v4.0 + 512 + false + + + + + 3.5 + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + AllRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AllRules.ruleset + + + bin\commercial\ + TRACE + true + pdbonly + AnyCPU + bin\Release\Z3Solver.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + AllRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + + + bin\commercial_64\ + TRACE + true + pdbonly + AnyCPU + bin\Release\Z3Solver.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + AllRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + false + false + + + true + bin\x86\Debug\ + DEBUG;TRACE + full + x86 + prompt + AllRules.ruleset + + + bin\x86\Release\ + TRACE + true + pdbonly + x86 + prompt + AllRules.ruleset + + + bin\x86\commercial\ + TRACE + true + pdbonly + x86 + prompt + AllRules.ruleset + + + bin\x86\commercial_64\ + TRACE + true + pdbonly + x86 + prompt + AllRules.ruleset + false + + + + ..\Microsoft.Solver.Foundation.dll + + + ..\Microsoft.Z3.dll + + + + 3.5 + + + + 3.5 + + + 3.5 + + + + + + + + + + + + + + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + \ No newline at end of file diff --git a/examples/msf/SolverFoundation.Plugin.Z3/Utils.cs b/examples/msf/SolverFoundation.Plugin.Z3/Utils.cs new file mode 100644 index 000000000..71c8647a1 --- /dev/null +++ b/examples/msf/SolverFoundation.Plugin.Z3/Utils.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Diagnostics; +using Microsoft.Z3; +using Microsoft.SolverFoundation.Common; + +namespace Microsoft.SolverFoundation.Plugin.Z3 +{ + public class Utils + { + /// + /// Returns the Z3 term corresponding to the MSF rational number. + /// + /// The MSF rational + /// The Z3 term + public static ArithExpr GetNumeral(Context context, Rational rational, Sort sort = null) + { + try + { + sort = rational.IsInteger() ? ((Sort)context.IntSort) : (sort == null ? (Sort)context.RealSort : sort); + return (ArithExpr)context.MkNumeral(rational.ToString(), sort); + } + catch (Z3Exception e) + { + Console.Error.WriteLine("Conversion of {0} failed:\n {1}", rational, e); + throw new NotSupportedException(); + } + } + + private static long BASE = 10 ^ 18; + + private static Rational ToRational(System.Numerics.BigInteger bi) + { + if (System.Numerics.BigInteger.Abs(bi) <= BASE) + { + return (Rational)((long)bi); + } + return BASE * ToRational(bi / BASE) + ToRational(bi % BASE); + } + + public static Rational ToRational(IntNum i) + { + return ToRational(i.BigInteger); + } + + public static Rational ToRational(RatNum r) + { + return ToRational(r.BigIntNumerator) / ToRational(r.BigIntDenominator); + } + + public static Rational ToRational(Expr expr) + { + Debug.Assert(expr is ArithExpr, "Only accept ArithExpr for now."); + var e = expr as ArithExpr; + + if (e is IntNum) + { + Debug.Assert(expr.IsIntNum, "Number should be an integer."); + return ToRational(expr as IntNum); + } + + if (e is RatNum) + { + Debug.Assert(expr.IsRatNum, "Number should be a rational."); + return ToRational(expr as RatNum); + } + + if (e.IsAdd) + { + Rational r = Rational.Zero; + foreach (var arg in e.Args) + { + r += ToRational(arg); + } + return r; + } + + if (e.IsMul) + { + Rational r = Rational.One; + foreach (var arg in e.Args) + { + r *= ToRational(arg); + } + return r; + } + + if (e.IsUMinus) + { + return -ToRational(e.Args[0]); + } + + if (e.IsDiv) + { + return ToRational(e.Args[0]) / ToRational(e.Args[1]); + } + + if (e.IsSub) + { + Rational r = ToRational(e.Args[0]); + for (int i = 1; i < e.Args.Length; ++i) + { + r -= ToRational(e.Args[i]); + } + return r; + } + + if (e.IsConst && e.FuncDecl.Name.ToString() == "oo") + { + return Rational.PositiveInfinity; + } + + if (e.IsConst && e.FuncDecl.Name.ToString() == "epsilon") + { + return Rational.One/Rational.PositiveInfinity; + } + + Debug.Assert(false, "Should not happen"); + return Rational.One; + } + } +} diff --git a/examples/msf/SolverFoundation.Plugin.Z3/Z3BaseDirective.cs b/examples/msf/SolverFoundation.Plugin.Z3/Z3BaseDirective.cs new file mode 100644 index 000000000..e1403f698 --- /dev/null +++ b/examples/msf/SolverFoundation.Plugin.Z3/Z3BaseDirective.cs @@ -0,0 +1,101 @@ +using System; +using System.Text; +using Microsoft.SolverFoundation.Services; + +namespace Microsoft.SolverFoundation.Plugin.Z3 +{ + /// + /// Combining objective functions + /// + public enum OptimizationKind + { + Lexicographic, + BoundingBox, + ParetoOptimal + }; + + /// + /// Algorithm for solving cardinality constraints + /// + public enum CardinalityAlgorithm + { + FuMalik, + CoreMaxSAT + } + + /// + /// Algorithm for solving pseudo-boolean constraints + /// + public enum PseudoBooleanAlgorithm + { + WeightedMaxSAT, + IterativeWeightedMaxSAT, + BisectionWeightedMaxSAT, + WeightedPartialMaxSAT2 + } + + /// + /// Strategy for solving arithmetic optimization + /// + public enum ArithmeticStrategy + { + Basic, + Farkas + } + + public abstract class Z3BaseDirective : Directive + { + protected OptimizationKind _optKind; + protected CardinalityAlgorithm _cardAlgorithm; + protected PseudoBooleanAlgorithm _pboAlgorithm; + protected ArithmeticStrategy _arithStrategy; + + protected string _smt2LogFile; + + public Z3BaseDirective() + { + Arithmetic = Arithmetic.Exact; + } + + public OptimizationKind OptKind + { + get { return _optKind; } + set { _optKind = value; } + } + + public CardinalityAlgorithm CardinalityAlgorithm + { + get { return _cardAlgorithm; } + set { _cardAlgorithm = value; } + } + + public PseudoBooleanAlgorithm PseudoBooleanAlgorithm + { + get { return _pboAlgorithm; } + set { _pboAlgorithm = value; } + } + + public ArithmeticStrategy ArithmeticStrategy + { + get { return _arithStrategy; } + set { _arithStrategy = value; } + } + + public string SMT2LogFile + { + get { return _smt2LogFile; } + set { _smt2LogFile = value; } + } + + public override string ToString() + { + var sb = new StringBuilder(); + sb.Append(this.GetType().Name); + sb.Append("("); + sb.AppendFormat("OptKind: {0}, ", _optKind); + sb.AppendFormat("SMT2LogFile: {0}", _smt2LogFile); + sb.Append(")"); + return sb.ToString(); + } + } +} diff --git a/examples/msf/SolverFoundation.Plugin.Z3/Z3BaseParams.cs b/examples/msf/SolverFoundation.Plugin.Z3/Z3BaseParams.cs new file mode 100644 index 000000000..6585181ec --- /dev/null +++ b/examples/msf/SolverFoundation.Plugin.Z3/Z3BaseParams.cs @@ -0,0 +1,103 @@ +using Microsoft.SolverFoundation.Services; +using System; + +namespace Microsoft.SolverFoundation.Plugin.Z3 +{ + /// + /// Implementation of the solver parameters for Z3 + /// + public class Z3BaseParams : ISolverParameters + { + #region Private Members + + /// The abort method we can call (defaults to always false) + protected Func _queryAbortFunction = delegate() { return false; }; + + /// The directive to use + protected Directive _directive = null; + + protected OptimizationKind _optKind; + protected CardinalityAlgorithm _cardAlgorithm; + protected PseudoBooleanAlgorithm _pboAlgorithm; + protected ArithmeticStrategy _arithStrategy; + + protected string _smt2LogFile; + + #endregion Private Members + + #region Construction + + public Z3BaseParams() { } + + public Z3BaseParams(Directive directive) + { + _directive = directive; + + var z3Directive = directive as Z3BaseDirective; + if (z3Directive != null) + { + _optKind = z3Directive.OptKind; + _cardAlgorithm = z3Directive.CardinalityAlgorithm; + _pboAlgorithm = z3Directive.PseudoBooleanAlgorithm; + _arithStrategy = z3Directive.ArithmeticStrategy; + _smt2LogFile = z3Directive.SMT2LogFile; + } + } + + public Z3BaseParams(Func queryAbortFunction) + { + _queryAbortFunction = queryAbortFunction; + } + + public Z3BaseParams(Z3BaseParams z3Parameters) + { + _queryAbortFunction = z3Parameters._queryAbortFunction; + } + + #endregion Construction + + #region ISolverParameters Members + + /// + /// Getter for the abort method + /// + public Func QueryAbort + { + get { return _queryAbortFunction; } + set { _queryAbortFunction = value; } + } + + public OptimizationKind OptKind + { + get { return _optKind; } + set { _optKind = value; } + } + + public CardinalityAlgorithm CardinalityAlgorithm + { + get { return _cardAlgorithm; } + set { _cardAlgorithm = value; } + } + + public PseudoBooleanAlgorithm PseudoBooleanAlgorithm + { + get { return _pboAlgorithm; } + set { _pboAlgorithm = value; } + } + + public ArithmeticStrategy ArithmeticStrategy + { + get { return _arithStrategy; } + set { _arithStrategy = value; } + } + + public string SMT2LogFile + { + get { return _smt2LogFile; } + set { _smt2LogFile = value; } + } + + #endregion + } + +} \ No newline at end of file diff --git a/examples/msf/SolverFoundation.Plugin.Z3/Z3BaseSolver.cs b/examples/msf/SolverFoundation.Plugin.Z3/Z3BaseSolver.cs new file mode 100644 index 000000000..54e3893f0 --- /dev/null +++ b/examples/msf/SolverFoundation.Plugin.Z3/Z3BaseSolver.cs @@ -0,0 +1,381 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.IO; +using System.Linq; +using System.Text; +using System.Diagnostics; +using Microsoft.Z3; +using Microsoft.SolverFoundation.Common; +using Microsoft.SolverFoundation.Services; + +namespace Microsoft.SolverFoundation.Plugin.Z3 +{ + internal enum Z3Result + { + Optimal, + LocalOptimal, + Feasible, + Interrupted, + Infeasible + } + + /// + /// The basic solver class to take care of transformation from an MSF instance to an Z3 instance + /// + internal class Z3BaseSolver + { + /// Representing MSF model + private IRowVariableModel _model; + + /// The Z3 solver we are currently using + private Context _context = null; + + /// Default optimization solver + private Optimize _optSolver = null; + + /// Marks when we are inside the Solve() method + private bool _isSolving = false; + + /// A map from MSF variable ids to Z3 variables + private Dictionary _variables = new Dictionary(); + + /// A map from MSF variable ids to Z3 goal ids + private Dictionary _goals = new Dictionary(); + + internal Z3BaseSolver(IRowVariableModel model) + { + _model = model; + } + + internal Context Context + { + get { return _context; } + } + + internal Dictionary Variables + { + get { return _variables; } + } + + internal Dictionary Goals + { + get { return _goals; } + } + + /// + /// Destructs a currently active Z3 solver and the associated data. + /// + internal void DestructSolver(bool checkInSolve) + { + if (_context != null) + { + if (checkInSolve && !_isSolving) + { + _variables.Clear(); + if (!_isSolving) + { + _optSolver.Dispose(); + _context.Dispose(); + } + } + else + { + Console.Error.WriteLine("Z3 destruction is invoked while in Solving phase."); + } + } + } + + /// + /// Constructs a Z3 solver to be used. + /// + internal void ConstructSolver(Z3BaseParams parameters) + { + // If Z3 is there already, kill it + if (_context != null) + { + DestructSolver(false); + } + + _context = new Context(); + _optSolver = _context.MkOptimize(); + var p = _context.MkParams(); + + switch (parameters.OptKind) + { + case OptimizationKind.BoundingBox: + p.Add("priority", _context.MkSymbol("box")); + break; + case OptimizationKind.Lexicographic: + p.Add("priority", _context.MkSymbol("lex")); + break; + case OptimizationKind.ParetoOptimal: + p.Add("priority", _context.MkSymbol("pareto")); + break; + default: + Debug.Assert(false, String.Format("Unknown optimization option {0}", parameters.OptKind)); + break; + } + + switch (parameters.CardinalityAlgorithm) + { + case CardinalityAlgorithm.FuMalik: + p.Add("maxsat_engine", _context.MkSymbol("fu_malik")); + break; + case CardinalityAlgorithm.CoreMaxSAT: + p.Add("maxsat_engine", _context.MkSymbol("core_maxsat")); + break; + default: + Debug.Assert(false, String.Format("Unknown cardinality algorithm option {0}", parameters.CardinalityAlgorithm)); + break; + } + + switch (parameters.PseudoBooleanAlgorithm) + { + case PseudoBooleanAlgorithm.WeightedMaxSAT: + p.Add("wmaxsat_engine", _context.MkSymbol("wmax")); + break; + case PseudoBooleanAlgorithm.IterativeWeightedMaxSAT: + p.Add("wmaxsat_engine", _context.MkSymbol("iwmax")); + break; + case PseudoBooleanAlgorithm.BisectionWeightedMaxSAT: + p.Add("wmaxsat_engine", _context.MkSymbol("bwmax")); + break; + case PseudoBooleanAlgorithm.WeightedPartialMaxSAT2: + p.Add("wmaxsat_engine", _context.MkSymbol("wpm2")); + break; + default: + Debug.Assert(false, String.Format("Unknown pseudo-boolean algorithm option {0}", parameters.PseudoBooleanAlgorithm)); + break; + } + + switch (parameters.ArithmeticStrategy) + { + case ArithmeticStrategy.Basic: + p.Add("engine", _context.MkSymbol("basic")); + break; + case ArithmeticStrategy.Farkas: + p.Add("engine", _context.MkSymbol("farkas")); + break; + default: + Debug.Assert(false, String.Format("Unknown arithmetic strategy option {0}", parameters.ArithmeticStrategy)); + break; + } + + _optSolver.Parameters = p; + } + + internal ArithExpr GetVariable(int vid) + { + Expr variable; + if (!_variables.TryGetValue(vid, out variable)) + { + AddVariable(vid); + variable = _variables[vid]; + } + return (ArithExpr)variable; + } + + internal void AssertBool(BoolExpr row) + { + _optSolver.Assert(row); + } + + internal void AssertArith(int vid, ArithExpr variable) + { + // Get the bounds on the row + Rational lower, upper; + _model.GetBounds(vid, out lower, out upper); + + // Case of equality + if (lower == upper) + { + // Create the equality term + Expr eqConst = GetNumeral(lower, variable.Sort); + BoolExpr constraint = _context.MkEq(eqConst, variable); + // Assert the constraint + _optSolver.Assert(constraint); + } + else + { + // If upper bound is finite assert the upper bound constraint + if (lower.IsFinite) + { + // Create the lower Bound constraint + ArithExpr lowerTerm = GetNumeral(lower, variable.Sort); + BoolExpr constraint = _context.MkLe(lowerTerm, variable); + // Assert the constraint + _optSolver.Assert(constraint); + } + // If lower bound is finite assert the lower bound constraint + if (upper.IsFinite) + { + // Create the upper bound constraint + ArithExpr upperTerm = GetNumeral(upper, variable.Sort); + BoolExpr constraint = _context.MkGe(upperTerm, variable); + // Assert the constraint + _optSolver.Assert(constraint); + } + } + } + + /// + /// Adds a MSF variable with the coresponding assertion to the Z3 variables. + /// + /// The MSF id of the variable + internal void AddVariable(int vid) + { + // Is the variable an integer + bool isInteger = _model.GetIntegrality(vid); + + // Construct the sort we will be using + Sort sort = isInteger ? (Sort)_context.IntSort : (Sort)_context.RealSort; + + // Get the variable key + object key = _model.GetKeyFromIndex(vid); + + // Try to construct the name + string name; + if (key != null) name = String.Format("x_{0}_{1}", key, vid); + else name = String.Format("x_{0}", vid); + ArithExpr variable = (ArithExpr)_context.MkConst(name, sort); + + // Create the variable and add it to the map + Debug.Assert(!_variables.ContainsKey(vid), "Variable names should be unique."); + _variables.Add(vid, variable); + + AssertArith(vid, variable); + } + + internal ArithExpr GetNumeral(Rational rational, Sort sort = null) + { + return Utils.GetNumeral(_context, rational, sort); + } + + internal void Solve(Z3BaseParams parameters, IEnumerable modelGoals, + Action addRow, Func mkGoalRow, Action setResult) + { + _variables.Clear(); + _goals.Clear(); + + try + { + // Mark that we are in solving phase + _isSolving = true; + + // Construct Z3 + ConstructSolver(parameters); + + // Add all the variables + foreach (int vid in _model.VariableIndices) + { + AddVariable(vid); + } + + // Add all the rows + foreach (int rid in _model.RowIndices) + { + addRow(rid); + } + + // Add enabled goals to optimization problem + foreach (IGoal g in modelGoals) + { + if (!g.Enabled) continue; + + ArithExpr gr = mkGoalRow(g.Index); + if (g.Minimize) + _goals.Add(g, _optSolver.MkMinimize(gr)); + else + _goals.Add(g, _optSolver.MkMaximize(gr)); + } + + if (_goals.Any() && parameters.SMT2LogFile != null) + { + Debug.WriteLine("Dumping SMT2 benchmark to log file..."); + File.WriteAllText(parameters.SMT2LogFile, _optSolver.ToString()); + } + + bool aborted = parameters.QueryAbort(); + + if (!aborted) + { + // Start the abort thread + AbortWorker abortWorker = new AbortWorker(_context, parameters.QueryAbort); + Thread abortThread = new Thread(abortWorker.Start); + abortThread.Start(); + + // Now solve the problem + Status status = _optSolver.Check(); + + // Stop the abort thread + abortWorker.Stop(); + abortThread.Join(); + + switch (status) + { + case Status.SATISFIABLE: + Microsoft.Z3.Model model = _optSolver.Model; + Debug.Assert(model != null, "Should be able to get Z3 model."); + // Remember the solution values + foreach (KeyValuePair pair in _variables) + { + var value = Utils.ToRational(model.Eval(pair.Value, true)); + _model.SetValue(pair.Key, value); + } + // Remember all objective values + foreach (var pair in _goals) + { + var optimalValue = Utils.ToRational(_optSolver.GetUpper(pair.Value)); + _model.SetValue(pair.Key.Index, optimalValue); + } + model.Dispose(); + setResult(_goals.Any() ? Z3Result.Optimal : Z3Result.Feasible); + break; + case Status.UNSATISFIABLE: + setResult(Z3Result.Infeasible); + break; + case Status.UNKNOWN: + if (abortWorker.Aborted) + { + Microsoft.Z3.Model subOptimalModel = _optSolver.Model; + if (subOptimalModel != null && subOptimalModel.NumConsts != 0) + { + // Remember the solution values + foreach (KeyValuePair pair in _variables) + { + var value = Utils.ToRational(subOptimalModel.Eval(pair.Value, true)); + _model.SetValue(pair.Key, value); + } + // Remember all objective values + foreach (var pair in _goals) + { + var optimalValue = Utils.ToRational(_optSolver.GetUpper(pair.Value)); + _model.SetValue(pair.Key.Index, optimalValue); + } + subOptimalModel.Dispose(); + + setResult(Z3Result.LocalOptimal); + } + else + setResult(Z3Result.Infeasible); + } + else + setResult(Z3Result.Interrupted); + break; + default: + Debug.Assert(false, "Unrecognized Z3 Status"); + break; + } + } + } + finally + { + _isSolving = false; + } + + // Now kill Z3 + DestructSolver(true); + } + } +} diff --git a/examples/msf/SolverFoundation.Plugin.Z3/Z3MILPDirective.cs b/examples/msf/SolverFoundation.Plugin.Z3/Z3MILPDirective.cs new file mode 100644 index 000000000..69f9ff6c1 --- /dev/null +++ b/examples/msf/SolverFoundation.Plugin.Z3/Z3MILPDirective.cs @@ -0,0 +1,9 @@ +using Microsoft.SolverFoundation.Services; +using System; + +namespace Microsoft.SolverFoundation.Plugin.Z3 +{ + public class Z3MILPDirective : Z3BaseDirective + { + } +} diff --git a/examples/msf/SolverFoundation.Plugin.Z3/Z3MILPParams.cs b/examples/msf/SolverFoundation.Plugin.Z3/Z3MILPParams.cs new file mode 100644 index 000000000..38bd9040a --- /dev/null +++ b/examples/msf/SolverFoundation.Plugin.Z3/Z3MILPParams.cs @@ -0,0 +1,19 @@ +using Microsoft.SolverFoundation.Services; +using System; + +namespace Microsoft.SolverFoundation.Plugin.Z3 +{ + public class Z3MILPParams : Z3BaseParams + { + // Need these constructors for reflection done by plugin model + + public Z3MILPParams() : base() { } + + public Z3MILPParams(Directive directive) : base(directive) { } + + public Z3MILPParams(Func queryAbortFunction) : base(queryAbortFunction) { } + + public Z3MILPParams(Z3BaseParams z3Parameters) : base (z3Parameters) { } + } + +} \ No newline at end of file diff --git a/examples/msf/SolverFoundation.Plugin.Z3/Z3MILPSolver.cs b/examples/msf/SolverFoundation.Plugin.Z3/Z3MILPSolver.cs new file mode 100644 index 000000000..b31f6de97 --- /dev/null +++ b/examples/msf/SolverFoundation.Plugin.Z3/Z3MILPSolver.cs @@ -0,0 +1,230 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.IO; + +using Microsoft.Z3; +using Microsoft.SolverFoundation.Common; +using Microsoft.SolverFoundation.Services; +using Microsoft.SolverFoundation.Plugin; + +namespace Microsoft.SolverFoundation.Plugin.Z3 +{ + /// + /// The class is implementation of the MSF mixed linear programming solver + /// using the Microsoft Z3 solver as the backend. + /// + public class Z3MILPSolver : LinearModel, ILinearSolver, ILinearSolution, IReportProvider + { + #region Private members + + private LinearResult _result; + private LinearSolutionQuality _solutionQuality; + private Z3BaseSolver _solver; + + #endregion Private members + + #region Solver construction and destruction + + /// Constructor that initializes the base clases + public Z3MILPSolver() : base(null) + { + _result = LinearResult.Feasible; + _solver = new Z3BaseSolver(this); + } + + /// Constructor that initializes the base clases + public Z3MILPSolver(ISolverEnvironment context) : this() { } + + /// + /// Shutdown can be called when when the solver is not active, i.e. + /// when it is done with Solve() or it has gracefully returns from Solve() + /// after an abort. + /// + public void Shutdown() { _solver.DestructSolver(true); } + + #endregion Solver construction and destruction + + #region Obtaining information about the solution + + public ILinearSolverReport GetReport(LinearSolverReportType reportType) + { + // We don't support sensitivity report + return null; + } + + #endregion Obtaining information about the solution + + #region Construction of the problem + + /// + /// Get corresponding Z3 formula of a MSF row. + /// + /// The MSF row id + private ArithExpr MkGoalRow(int rid) + { + // Start with the 0 term + List row = new List(); + + // Now, add all the entries of this row + foreach (LinearEntry entry in GetRowEntries(rid)) + { + // Get the variable and constant in the row + ArithExpr e = _solver.GetVariable(entry.Index); + if (!entry.Value.IsOne) + { + e = _solver.Context.MkMul(_solver.GetNumeral(entry.Value, e.Sort), e); + } + row.Add(e); + } + switch (row.Count) + { + case 0: return _solver.GetNumeral(new Rational()); + case 1: return row[0]; + default: return _solver.Context.MkAdd(row.ToArray()); + } + } + + /// + /// Adds a MSF row to the Z3 assertions. + /// + /// The MSF row id + private void AddRow(int rid) + { + // Start with the 0 term + ArithExpr row = MkGoalRow(rid); + _solver.AssertArith(rid, row); + } + + /// + /// Set results based on internal solver status + /// + private void SetResult(Z3Result status) + { + switch (status) + { + case Z3Result.Optimal: + _result = LinearResult.Optimal; + _solutionQuality = LinearSolutionQuality.Exact; + break; + case Z3Result.LocalOptimal: + _result = LinearResult.Feasible; + _solutionQuality = LinearSolutionQuality.Approximate; + break; + case Z3Result.Feasible: + _result = LinearResult.Feasible; + _solutionQuality = LinearSolutionQuality.Exact; + break; + case Z3Result.Infeasible: + _result = LinearResult.InfeasiblePrimal; + _solutionQuality = LinearSolutionQuality.None; + break; + case Z3Result.Interrupted: + _result = LinearResult.Interrupted; + _solutionQuality = LinearSolutionQuality.None; + break; + default: + Debug.Assert(false, "Unrecognized Z3 Result"); + break; + } + } + + #endregion Construction of the problem + + #region Solving the problem + + /// + /// Starts solving the problem using the Z3 solver. + /// + /// Parameters to the solver + /// The solution to the problem + public ILinearSolution Solve(ISolverParameters parameters) + { + // Get the Z3 parameters + var z3Params = parameters as Z3BaseParams; + Debug.Assert(z3Params != null, "Parameters should be an instance of Z3BaseParams."); + + _solver.Solve(z3Params, Goals, AddRow, MkGoalRow, SetResult); + + return this; + } + + #endregion Solving the problem + + #region ILinearSolution Members + + public Rational GetSolutionValue(int goalIndex) + { + var goal = Goals.ElementAt(goalIndex); + Debug.Assert(goal != null, "Goal should be an element of the goal list."); + return GetValue(goal.Index); + } + + public void GetSolvedGoal(int goalIndex, out object key, out int vid, out bool minimize, out bool optimal) + { + var goal = Goals.ElementAt(goalIndex); + Debug.Assert(goal != null, "Goal should be an element of the goal list."); + key = goal.Key; + vid = goal.Index; + minimize = goal.Minimize; + optimal = _result == LinearResult.Optimal; + } + + // LpResult is LP relaxation assignment. + + public LinearResult LpResult + { + get { return _result; } + } + + public Rational MipBestBound + { + get + { + Debug.Assert(GoalCount > 0, "MipBestBound is only applicable for optimization instances."); + return GetSolutionValue(0); + } + } + + public LinearResult MipResult + { + get { return _result; } + } + + public LinearResult Result + { + get { return _result; } + } + + public LinearSolutionQuality SolutionQuality + { + get { return _solutionQuality; } + } + + public int SolvedGoalCount + { + get { return GoalCount; } + } + + #endregion + + public Report GetReport(SolverContext context, Solution solution, SolutionMapping solutionMapping) + { + LinearSolutionMapping lpSolutionMapping = solutionMapping as LinearSolutionMapping; + if (lpSolutionMapping == null && solutionMapping != null) + throw new ArgumentException("solutionMapping is not a LinearSolutionMapping", "solutionMapping"); + return new Z3LinearSolverReport(context, this, solution, lpSolutionMapping); + } + } + + /// + /// Class implementing the LinearReport. + /// + public class Z3LinearSolverReport : LinearReport + { + public Z3LinearSolverReport(SolverContext context, ISolver solver, Solution solution, LinearSolutionMapping solutionMapping) + : base(context, solver, solution, solutionMapping) { + } + } +} diff --git a/examples/msf/SolverFoundation.Plugin.Z3/Z3TermDirective.cs b/examples/msf/SolverFoundation.Plugin.Z3/Z3TermDirective.cs new file mode 100644 index 000000000..12dcb6e84 --- /dev/null +++ b/examples/msf/SolverFoundation.Plugin.Z3/Z3TermDirective.cs @@ -0,0 +1,9 @@ +using Microsoft.SolverFoundation.Services; +using System; + +namespace Microsoft.SolverFoundation.Plugin.Z3 +{ + public class Z3TermDirective : Z3BaseDirective + { + } +} diff --git a/examples/msf/SolverFoundation.Plugin.Z3/Z3TermParams.cs b/examples/msf/SolverFoundation.Plugin.Z3/Z3TermParams.cs new file mode 100644 index 000000000..48a90afe1 --- /dev/null +++ b/examples/msf/SolverFoundation.Plugin.Z3/Z3TermParams.cs @@ -0,0 +1,17 @@ +using Microsoft.SolverFoundation.Services; +using System; + +namespace Microsoft.SolverFoundation.Plugin.Z3 +{ + public class Z3TermParams : Z3BaseParams + { + public Z3TermParams() : base() { } + + public Z3TermParams(Directive directive) : base(directive) { } + + public Z3TermParams(Func queryAbortFunction) : base(queryAbortFunction) { } + + public Z3TermParams(Z3BaseParams z3Parameters) : base(z3Parameters) { } + } + +} \ No newline at end of file diff --git a/examples/msf/SolverFoundation.Plugin.Z3/Z3TermSolver.cs b/examples/msf/SolverFoundation.Plugin.Z3/Z3TermSolver.cs new file mode 100644 index 000000000..3317b9a4d --- /dev/null +++ b/examples/msf/SolverFoundation.Plugin.Z3/Z3TermSolver.cs @@ -0,0 +1,382 @@ +using System; +using System.Threading; +using System.Globalization; +using System.Collections.Generic; +using Microsoft.SolverFoundation.Common; +using Microsoft.SolverFoundation.Properties; +using Microsoft.SolverFoundation.Solvers; +using Microsoft.SolverFoundation.Services; +using Microsoft.Z3; +using System.Linq; +using System.Diagnostics; +using System.IO; + +namespace Microsoft.SolverFoundation.Plugin.Z3 +{ + /// + /// The class is implementation of the MSF constraint solver + /// using the Microsoft Z3 solver as the backend. + /// This solver supports Int, Real constraints and their arbitrary boolean combinations. + /// + public class Z3TermSolver : TermModel, ITermSolver, INonlinearSolution, IReportProvider + { + private NonlinearResult _result; + private Z3BaseSolver _solver; + + /// Constructor that initializes the base clases + public Z3TermSolver() : base(null) + { + _solver = new Z3BaseSolver(this); + } + + /// Constructor that initializes the base clases + public Z3TermSolver(ISolverEnvironment context) : this() { } + + /// + /// Shutdown can be called when when the solver is not active, i.e. + /// when it is done with Solve() or it has gracefully returns from Solve() + /// after an abort. + /// + public void Shutdown() { _solver.DestructSolver(true); } + + private BoolExpr MkBool(int rid) + { + var context = _solver.Context; + + if (IsConstant(rid)) + { + Rational lower, upper; + GetBounds(rid, out lower, out upper); + Debug.Assert(lower == upper); + if (lower.IsZero) return context.MkFalse(); + return context.MkTrue(); + } + if (IsOperation(rid)) + { + BoolExpr[] children; + ArithExpr[] operands; + TermModelOperation op = GetOperation(rid); + switch(op) { + case TermModelOperation.And: + Debug.Assert(GetOperandCount(rid) >= 2, "Conjunction requires at least two operands."); + children = (GetOperands(rid)).Select(x => MkBool(x)).ToArray(); + return context.MkAnd(children); + case TermModelOperation.Or: + Debug.Assert(GetOperandCount(rid) >= 2, "Disjunction requires at least two operands."); + children = (GetOperands(rid)).Select(x => MkBool(x)).ToArray(); + return context.MkOr(children); + case TermModelOperation.Not: + Debug.Assert(GetOperandCount(rid) == 1, "Negation is unary."); + return context.MkNot(MkBool(GetOperand(rid, 0))); + case TermModelOperation.If: + Debug.Assert(GetOperandCount(rid) == 3, "If is ternary."); + BoolExpr b = MkBool(GetOperand(rid, 0)); + Expr x1 = MkBool(GetOperand(rid, 1)); + Expr x2 = MkBool(GetOperand(rid, 2)); + return (BoolExpr)context.MkITE(b, x1, x2); + case TermModelOperation.Unequal: + Debug.Assert(GetOperandCount(rid) >= 2, "Distinct should have at least two operands."); + return context.MkDistinct((GetOperands(rid)).Select(x => MkTerm(x)).ToArray()); + case TermModelOperation.Greater: + case TermModelOperation.Less: + case TermModelOperation.GreaterEqual: + case TermModelOperation.LessEqual: + case TermModelOperation.Equal: + Debug.Assert(GetOperandCount(rid) >= 2, "Comparison should have at least two operands."); + operands = (GetOperands(rid)).Select(x => MkTerm(x)).ToArray(); + return ReduceComparison(GetOperation(rid), operands); + case TermModelOperation.Identity: + Debug.Assert(GetOperandCount(rid) == 1, "Identity takes exactly one operand."); + return MkBool(GetOperand(rid, 0)); + default: + return context.MkEq(MkTerm(rid), _solver.GetNumeral(Rational.One)); + } + } + return context.MkEq(MkTerm(rid), _solver.GetNumeral(Rational.One)); + } + + private ArithExpr MkBoolToArith(BoolExpr e) + { + var context = _solver.Context; + return (ArithExpr)context.MkITE(e, _solver.GetNumeral(Rational.One), _solver.GetNumeral(Rational.Zero)); + } + + private ArithExpr MkTerm(int rid) + { + var context = _solver.Context; + + if (IsConstant(rid)) + { + Rational lower, upper; + GetBounds(rid, out lower, out upper); + Debug.Assert(lower == upper); + return _solver.GetNumeral(lower); + } + else if (IsOperation(rid)) + { + ArithExpr[] operands; + TermModelOperation op = GetOperation(rid); + switch(op) + { + case TermModelOperation.And: + case TermModelOperation.Or: + case TermModelOperation.Not: + case TermModelOperation.Unequal: + case TermModelOperation.Greater: + case TermModelOperation.Less: + case TermModelOperation.GreaterEqual: + case TermModelOperation.LessEqual: + case TermModelOperation.Equal: + return MkBoolToArith(MkBool(rid)); + case TermModelOperation.If: + Debug.Assert(GetOperandCount(rid) == 3, "If is ternary."); + BoolExpr b = MkBool(GetOperand(rid, 0)); + Expr x1 = MkTerm(GetOperand(rid, 1)); + Expr x2 = MkTerm(GetOperand(rid, 2)); + return (ArithExpr)context.MkITE(b, x1, x2); + case TermModelOperation.Plus: + Debug.Assert(GetOperandCount(rid) >= 2, "Plus takes at least two operands."); + operands = (GetOperands(rid)).Select(x => MkTerm(x)).ToArray(); + return context.MkAdd(operands); + case TermModelOperation.Minus: + Debug.Assert(GetOperandCount(rid) == 1, "Minus takes exactly one operand."); + return context.MkUnaryMinus(MkTerm(GetOperand(rid, 0))); + case TermModelOperation.Times: + Debug.Assert(GetOperandCount(rid) >= 2, "Times requires at least two operands."); + operands = (GetOperands(rid)).Select(x => MkTerm(x)).ToArray(); + return context.MkMul(operands); + case TermModelOperation.Identity: + Debug.Assert(GetOperandCount(rid) == 1, "Identity takes exactly one operand."); + return MkTerm(GetOperand(rid, 0)); + case TermModelOperation.Abs: + Debug.Assert(GetOperandCount(rid) == 1, "Abs takes exactly one operand."); + ArithExpr e = MkTerm(GetOperand(rid, 0)); + ArithExpr minusE = context.MkUnaryMinus(e); + ArithExpr zero = _solver.GetNumeral(Rational.Zero); + return (ArithExpr)context.MkITE(context.MkGe(e, zero), e, minusE); + default: + Console.Error.WriteLine("{0} operation isn't supported.", op); + throw new NotSupportedException(); + } + } + else + { + return _solver.GetVariable(rid); + } + } + + private BoolExpr ReduceComparison(TermModelOperation type, ArithExpr[] operands) + { + var context = _solver.Context; + Debug.Assert(operands.Length >= 2); + Func mkComparison; + switch (type) + { + case TermModelOperation.Greater: + mkComparison = (x, y) => context.MkGt(x, y); + break; + case TermModelOperation.Less: + mkComparison = (x, y) => context.MkLt(x, y); + break; + case TermModelOperation.GreaterEqual: + mkComparison = (x, y) => context.MkGe(x, y); + break; + case TermModelOperation.LessEqual: + mkComparison = (x, y) => context.MkLe(x, y); + break; + case TermModelOperation.Equal: + mkComparison = (x, y) => context.MkEq(x, y); + break; + default: + throw new NotSupportedException(); + } + + BoolExpr current = mkComparison(operands[0], operands[1]); + for (int i = 1; i < operands.Length - 1; ++i) + current = context.MkAnd(current, mkComparison(operands[i], operands[i + 1])); + return current; + } + + private bool IsBoolRow(int rid) + { + Rational lower, upper; + GetBounds(rid, out lower, out upper); + + return lower == upper && lower.IsOne && IsBoolTerm(rid); + } + + private bool IsBoolTerm(int rid) + { + if (IsConstant(rid)) + { + Rational lower, upper; + GetBounds(rid, out lower, out upper); + Debug.Assert(lower == upper); + return lower.IsOne || lower.IsZero; + } + if (IsOperation(rid)) + { + TermModelOperation op = GetOperation(rid); + switch (op) + { + case TermModelOperation.And: + case TermModelOperation.Or: + case TermModelOperation.Not: + case TermModelOperation.LessEqual: + case TermModelOperation.Less: + case TermModelOperation.Greater: + case TermModelOperation.GreaterEqual: + case TermModelOperation.Unequal: + case TermModelOperation.Equal: + return true; + case TermModelOperation.If: + return IsBoolTerm(GetOperand(rid, 1)) && + IsBoolTerm(GetOperand(rid, 2)); + case TermModelOperation.Identity: + return IsBoolTerm(GetOperand(rid, 0)); + default: + return false; + } + } + return false; + } + + /// + /// Adds a MSF row to the Z3 assertions. + /// + /// The MSF row id + private void AddRow(int rid) + { + if (IsConstant(rid)) + return; + + if (IsBoolRow(rid)) + { + _solver.AssertBool(MkBool(rid)); + return; + } + // Start with the 0 term + ArithExpr row = MkTerm(rid); + _solver.AssertArith(rid, row); + } + + private TermModelOperation[] _supportedOperations = + { TermModelOperation.And, + TermModelOperation.Or, + TermModelOperation.Not, + TermModelOperation.Unequal, + TermModelOperation.Greater, + TermModelOperation.Less, + TermModelOperation.GreaterEqual, + TermModelOperation.LessEqual, + TermModelOperation.Equal, + TermModelOperation.If, + TermModelOperation.Plus, + TermModelOperation.Minus, + TermModelOperation.Times, + TermModelOperation.Identity, + TermModelOperation.Abs }; + + /// + /// Gets the operations supported by the solver. + /// + /// All the TermModelOperations supported by the solver. + public IEnumerable SupportedOperations + { + get { return _supportedOperations; } + } + + /// + /// Set results based on internal solver status + /// + private void SetResult(Z3Result status) + { + switch (status) + { + case Z3Result.Optimal: + _result = NonlinearResult.Optimal; + break; + case Z3Result.LocalOptimal: + _result = NonlinearResult.LocalOptimal; + break; + case Z3Result.Feasible: + _result = NonlinearResult.Feasible; + break; + case Z3Result.Infeasible: + _result = NonlinearResult.Infeasible; + break; + case Z3Result.Interrupted: + _result = NonlinearResult.Interrupted; + break; + default: + Debug.Assert(false, "Unrecognized Z3 Result"); + break; + } + } + + /// + /// Starts solving the problem using the Z3 solver. + /// + /// Parameters to the solver + /// The solution to the problem + public INonlinearSolution Solve(ISolverParameters parameters) + { + // Get the Z3 parameters + var z3Params = parameters as Z3BaseParams; + Debug.Assert(z3Params != null, "Parameters should be an instance of Z3BaseParams."); + + _solver.Solve(z3Params, Goals, AddRow, MkTerm, SetResult); + + return this; + } + + double INonlinearSolution.GetValue(int vid) + { + Debug.Assert(_solver.Variables.ContainsKey(vid), "This index should correspond to a variable."); + return GetValue(vid).ToDouble(); + } + + public int SolvedGoalCount + { + get { return GoalCount; } + } + + public double GetSolutionValue(int goalIndex) + { + var goal = Goals.ElementAt(goalIndex); + Debug.Assert(goal != null, "Goal should be an element of the goal list."); + return GetValue(goal.Index).ToDouble(); + } + + public void GetSolvedGoal(int goalIndex, out object key, out int vid, out bool minimize, out bool optimal) + { + var goal = Goals.ElementAt(goalIndex); + Debug.Assert(goal != null, "Goal should be an element of the goal list."); + key = goal.Key; + vid = goal.Index; + minimize = goal.Minimize; + optimal = _result == NonlinearResult.Optimal; + } + + public NonlinearResult Result + { + get { return _result; } + } + + public Report GetReport(SolverContext context, Solution solution, SolutionMapping solutionMapping) + { + PluginSolutionMapping pluginSolutionMapping = solutionMapping as PluginSolutionMapping; + if (pluginSolutionMapping == null && solutionMapping != null) + throw new ArgumentException("solutionMapping is not a LinearSolutionMapping", "solutionMapping"); + return new Z3TermSolverReport(context, this, solution, pluginSolutionMapping); + } + } + + public class Z3TermSolverReport : Report + { + public Z3TermSolverReport(SolverContext context, ISolver solver, Solution solution, PluginSolutionMapping pluginSolutionMapping) + : base(context, solver, solution, pluginSolutionMapping) + { + } + } +} diff --git a/examples/msf/Validator/App.config b/examples/msf/Validator/App.config new file mode 100644 index 000000000..75e2872f1 --- /dev/null +++ b/examples/msf/Validator/App.config @@ -0,0 +1,60 @@ + + + +
+ + + + + + + + + + + + + + + + diff --git a/examples/msf/Validator/MicrosoftSolverFoundationForExcel.dll.config b/examples/msf/Validator/MicrosoftSolverFoundationForExcel.dll.config new file mode 100644 index 000000000..cd9dcad25 --- /dev/null +++ b/examples/msf/Validator/MicrosoftSolverFoundationForExcel.dll.config @@ -0,0 +1,58 @@ + + + +
+ + + + + + + + + + + + + diff --git a/examples/msf/Validator/Program.cs b/examples/msf/Validator/Program.cs new file mode 100644 index 000000000..758c65c78 --- /dev/null +++ b/examples/msf/Validator/Program.cs @@ -0,0 +1,194 @@ +using System; +using System.IO; +using System.Linq; +using System.Collections.Generic; +using Microsoft.SolverFoundation.Common; +using Microsoft.SolverFoundation.Solvers; +using Microsoft.SolverFoundation.Plugin.Z3; +using Microsoft.SolverFoundation.Services; +using System.Text; + +namespace Validator +{ + class Program + { + static void LoadModel(SolverContext context, string fileName) + { + string ext = Path.GetExtension(fileName).ToLower(); + + if (ext == ".mps") + { + context.LoadModel(FileFormat.MPS, Path.GetFullPath(fileName)); + } + else if (ext == ".smps") + { + context.LoadModel(FileFormat.SMPS, Path.GetFullPath(fileName)); + } + else if (ext == ".oml") + { + context.LoadModel(FileFormat.OML, Path.GetFullPath(fileName)); + } + else + { + throw new NotSupportedException("This file format hasn't been supported."); + } + } + + static void ExecuteZ3(string fileName, Z3BaseDirective directive) + { + SolverContext context = SolverContext.GetContext(); + try + { + LoadModel(context, fileName); + + Solution solution = context.Solve(directive); + Report report = solution.GetReport(); + Console.Write("{0}", report); + } + catch (Exception e) + { + Console.WriteLine("Skipping unsolvable instance in {0} with error message '{1}'.", fileName, e.Message); + } + finally + { + context.ClearModel(); + } + } + + static void ConvertToSMT2(string fileName, Z3BaseDirective directive) + { + SolverContext context = SolverContext.GetContext(); + try + { + LoadModel(context, fileName); + + if (context.CurrentModel.Goals.Any()) + { + directive.SMT2LogFile = Path.ChangeExtension(fileName, ".smt2"); + context.Solve(() => true, directive); + } + } + catch (Exception e) + { + Console.WriteLine("Skipping unconvertable instance in {0} with error message '{1}'.", fileName, e.Message); + } + finally + { + context.ClearModel(); + } + } + + static void ValidateZ3(string fileName, Z3BaseDirective directive) + { + SolverContext context = SolverContext.GetContext(); + try + { + LoadModel(context, fileName); + + if (context.CurrentModel.Goals.Any()) + { + var msfDirective = (directive is Z3MILPDirective) ? (Directive)new MixedIntegerProgrammingDirective() { TimeLimit = 10000 } + : (Directive)new Directive() { TimeLimit = 10000 }; + var sol1 = context.Solve(msfDirective); + + Console.WriteLine("Solved the model using MSF."); + Console.Write("{0}", sol1.GetReport()); + var expectedGoals = sol1.Goals.Select(x => x.ToDouble()); + context.ClearModel(); + + context.LoadModel(FileFormat.OML, Path.GetFullPath(fileName)); + directive.SMT2LogFile = Path.ChangeExtension(fileName, ".smt2"); + var sol2 = context.Solve(directive); + //Console.Write("{0}", sol2.GetReport()); + var actualGoals = sol2.Goals.Select(x => x.ToDouble()); + + Console.WriteLine("Solved the model using Z3."); + var goalPairs = expectedGoals.Zip(actualGoals, (expected, actual) => new { expected, actual }).ToArray(); + bool validated = goalPairs.All(p => Math.Abs(p.expected - p.actual) <= 0.0001); + if (validated) + { + Console.WriteLine("INFO: Two solvers give approximately the same results."); + } + else + { + Console.Error.WriteLine("ERROR: Discrepancy found between results."); + if (!validated && File.Exists(directive.SMT2LogFile)) + { + var sb = new StringBuilder(); + for(int i = 0; i < goalPairs.Length; i++) + { + sb.AppendFormat("\n(echo \"Goal {0}: actual |-> {1:0.0000}, expected |-> {2:0.0000}\")", + i + 1, goalPairs[i].actual, goalPairs[i].expected); + } + Console.Error.WriteLine(sb.ToString()); + File.AppendAllText(directive.SMT2LogFile, sb.ToString()); + } + } + } + else + { + Console.WriteLine("Ignoring this instance without having any goal."); + } + } + catch (Exception e) + { + Console.WriteLine("Skipping unsolvable instance in {0} with error message '{1}'.", + fileName, e.Message); + } + finally + { + context.ClearModel(); + } + } + + static void Main(string[] args) + { + Z3BaseDirective directive = new Z3MILPDirective(); + + for (int i = 0; i < args.Length; ++i) { + if (args[i] == "-s" || args[i] == "-solve") + { + ExecuteZ3(args[i + 1], directive); + return; + } + if (args[i] == "-c" || args[i] == "-convert") + { + ConvertToSMT2(args[i + 1], directive); + return; + } + if (args[i] == "-v" || args[i] == "-validate") + { + ValidateZ3(args[i + 1], directive); + return; + } + if (args[i] == "-t" || args[i] == "-term") + { + directive = new Z3TermDirective(); + } + } + + if (args.Length > 0) + { + ExecuteZ3(args[0], directive); + return; + } + + Console.WriteLine(@" +Validator is a simple command line to migrate benchmarks from OML, MPS and SMPS to SMT2 formats. + +Commands: + -solve : solving the model using Z3 + -convert : converting the model into SMT2 format + -validate : validating by comparing results between Z3 and MSF solvers + -term : change the default Z3 MILP solver to Z3 Term solver + + where is any file with OML, MPS or SMPS extension. + +Examples: + Validator.exe -convert model.mps + Validator.exe -term -solve model.oml + +"); + } + } +} diff --git a/examples/msf/Validator/Properties/AssemblyInfo.cs b/examples/msf/Validator/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..eb2f8ed71 --- /dev/null +++ b/examples/msf/Validator/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("testSolver")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("testSolver")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2009")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("c03c1084-d119-483f-80fe-c639eae75959")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/examples/msf/Validator/Validator.csproj b/examples/msf/Validator/Validator.csproj new file mode 100644 index 000000000..97d00331d --- /dev/null +++ b/examples/msf/Validator/Validator.csproj @@ -0,0 +1,143 @@ + + + + Debug + AnyCPU + 9.0.21022 + 2.0 + {54835857-129F-44C9-B529-A42158647B36} + Exe + Properties + Validator + Validator + v4.0 + 512 + + + + + 3.5 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + bin\x64\Debug\ + DEBUG;TRACE + full + x86 + true + GlobalSuppressions.cs + prompt + + + bin\x64\Release\ + TRACE + true + pdbonly + x64 + true + GlobalSuppressions.cs + prompt + + + true + bin\x86\Debug\ + DEBUG;TRACE + full + x86 + prompt + MinimumRecommendedRules.ruleset + + + bin\x86\Release\ + TRACE + true + pdbonly + x86 + prompt + MinimumRecommendedRules.ruleset + + + + ..\Microsoft.Solver.Foundation.dll + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + + + + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + + + {7340e664-f648-4ff7-89b2-f4da424996d3} + SolverFoundation.Plugin.Z3 + + + + + \ No newline at end of file diff --git a/examples/msf/Z3MSFPlugin.sln b/examples/msf/Z3MSFPlugin.sln new file mode 100644 index 000000000..0554e16dd --- /dev/null +++ b/examples/msf/Z3MSFPlugin.sln @@ -0,0 +1,120 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SolverFoundation.Plugin.Z3", "SolverFoundation.Plugin.Z3\SolverFoundation.Plugin.Z3.csproj", "{7340E664-F648-4FF7-89B2-F4DA424996D3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SolverFoundation.Plugin.Z3.Tests", "SolverFoundation.Plugin.Z3.Tests\SolverFoundation.Plugin.Z3.Tests.csproj", "{280AEE2F-1FDB-4A27-BE37-14DC154C873B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Validator", "Validator\Validator.csproj", "{54835857-129F-44C9-B529-A42158647B36}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + commercial_64|Any CPU = commercial_64|Any CPU + commercial_64|Mixed Platforms = commercial_64|Mixed Platforms + commercial_64|x64 = commercial_64|x64 + commercial_64|x86 = commercial_64|x86 + commercial|Any CPU = commercial|Any CPU + commercial|Mixed Platforms = commercial|Mixed Platforms + commercial|x64 = commercial|x64 + commercial|x86 = commercial|x86 + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7340E664-F648-4FF7-89B2-F4DA424996D3}.commercial_64|Any CPU.ActiveCfg = commercial_64|Any CPU + {7340E664-F648-4FF7-89B2-F4DA424996D3}.commercial_64|Any CPU.Build.0 = commercial_64|Any CPU + {7340E664-F648-4FF7-89B2-F4DA424996D3}.commercial_64|Mixed Platforms.ActiveCfg = commercial_64|x86 + {7340E664-F648-4FF7-89B2-F4DA424996D3}.commercial_64|Mixed Platforms.Build.0 = commercial_64|x86 + {7340E664-F648-4FF7-89B2-F4DA424996D3}.commercial_64|x64.ActiveCfg = commercial_64|Any CPU + {7340E664-F648-4FF7-89B2-F4DA424996D3}.commercial_64|x86.ActiveCfg = commercial_64|x86 + {7340E664-F648-4FF7-89B2-F4DA424996D3}.commercial_64|x86.Build.0 = commercial_64|x86 + {7340E664-F648-4FF7-89B2-F4DA424996D3}.commercial|Any CPU.ActiveCfg = commercial|Any CPU + {7340E664-F648-4FF7-89B2-F4DA424996D3}.commercial|Any CPU.Build.0 = commercial|Any CPU + {7340E664-F648-4FF7-89B2-F4DA424996D3}.commercial|Mixed Platforms.ActiveCfg = commercial|x86 + {7340E664-F648-4FF7-89B2-F4DA424996D3}.commercial|Mixed Platforms.Build.0 = commercial|x86 + {7340E664-F648-4FF7-89B2-F4DA424996D3}.commercial|x64.ActiveCfg = commercial|Any CPU + {7340E664-F648-4FF7-89B2-F4DA424996D3}.commercial|x86.ActiveCfg = commercial|x86 + {7340E664-F648-4FF7-89B2-F4DA424996D3}.commercial|x86.Build.0 = commercial|x86 + {7340E664-F648-4FF7-89B2-F4DA424996D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7340E664-F648-4FF7-89B2-F4DA424996D3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7340E664-F648-4FF7-89B2-F4DA424996D3}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {7340E664-F648-4FF7-89B2-F4DA424996D3}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {7340E664-F648-4FF7-89B2-F4DA424996D3}.Debug|x64.ActiveCfg = Debug|Any CPU + {7340E664-F648-4FF7-89B2-F4DA424996D3}.Debug|x86.ActiveCfg = Debug|x86 + {7340E664-F648-4FF7-89B2-F4DA424996D3}.Debug|x86.Build.0 = Debug|x86 + {7340E664-F648-4FF7-89B2-F4DA424996D3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7340E664-F648-4FF7-89B2-F4DA424996D3}.Release|Any CPU.Build.0 = Release|Any CPU + {7340E664-F648-4FF7-89B2-F4DA424996D3}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {7340E664-F648-4FF7-89B2-F4DA424996D3}.Release|Mixed Platforms.Build.0 = Release|x86 + {7340E664-F648-4FF7-89B2-F4DA424996D3}.Release|x64.ActiveCfg = Release|Any CPU + {7340E664-F648-4FF7-89B2-F4DA424996D3}.Release|x86.ActiveCfg = Release|x86 + {7340E664-F648-4FF7-89B2-F4DA424996D3}.Release|x86.Build.0 = Release|x86 + {280AEE2F-1FDB-4A27-BE37-14DC154C873B}.commercial_64|Any CPU.ActiveCfg = Release|Any CPU + {280AEE2F-1FDB-4A27-BE37-14DC154C873B}.commercial_64|Any CPU.Build.0 = Release|Any CPU + {280AEE2F-1FDB-4A27-BE37-14DC154C873B}.commercial_64|Mixed Platforms.ActiveCfg = Release|Any CPU + {280AEE2F-1FDB-4A27-BE37-14DC154C873B}.commercial_64|Mixed Platforms.Build.0 = Release|Any CPU + {280AEE2F-1FDB-4A27-BE37-14DC154C873B}.commercial_64|x64.ActiveCfg = Release|Any CPU + {280AEE2F-1FDB-4A27-BE37-14DC154C873B}.commercial_64|x86.ActiveCfg = Release|Any CPU + {280AEE2F-1FDB-4A27-BE37-14DC154C873B}.commercial|Any CPU.ActiveCfg = Release|Any CPU + {280AEE2F-1FDB-4A27-BE37-14DC154C873B}.commercial|Any CPU.Build.0 = Release|Any CPU + {280AEE2F-1FDB-4A27-BE37-14DC154C873B}.commercial|Mixed Platforms.ActiveCfg = Release|Any CPU + {280AEE2F-1FDB-4A27-BE37-14DC154C873B}.commercial|Mixed Platforms.Build.0 = Release|Any CPU + {280AEE2F-1FDB-4A27-BE37-14DC154C873B}.commercial|x64.ActiveCfg = Release|Any CPU + {280AEE2F-1FDB-4A27-BE37-14DC154C873B}.commercial|x86.ActiveCfg = Release|Any CPU + {280AEE2F-1FDB-4A27-BE37-14DC154C873B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {280AEE2F-1FDB-4A27-BE37-14DC154C873B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {280AEE2F-1FDB-4A27-BE37-14DC154C873B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {280AEE2F-1FDB-4A27-BE37-14DC154C873B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {280AEE2F-1FDB-4A27-BE37-14DC154C873B}.Debug|x64.ActiveCfg = Debug|Any CPU + {280AEE2F-1FDB-4A27-BE37-14DC154C873B}.Debug|x86.ActiveCfg = Debug|Any CPU + {280AEE2F-1FDB-4A27-BE37-14DC154C873B}.Debug|x86.Build.0 = Debug|Any CPU + {280AEE2F-1FDB-4A27-BE37-14DC154C873B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {280AEE2F-1FDB-4A27-BE37-14DC154C873B}.Release|Any CPU.Build.0 = Release|Any CPU + {280AEE2F-1FDB-4A27-BE37-14DC154C873B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {280AEE2F-1FDB-4A27-BE37-14DC154C873B}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {280AEE2F-1FDB-4A27-BE37-14DC154C873B}.Release|x64.ActiveCfg = Release|Any CPU + {280AEE2F-1FDB-4A27-BE37-14DC154C873B}.Release|x86.ActiveCfg = Release|Any CPU + {280AEE2F-1FDB-4A27-BE37-14DC154C873B}.Release|x86.Build.0 = Release|Any CPU + {54835857-129F-44C9-B529-A42158647B36}.commercial_64|Any CPU.ActiveCfg = Release|Any CPU + {54835857-129F-44C9-B529-A42158647B36}.commercial_64|Any CPU.Build.0 = Release|Any CPU + {54835857-129F-44C9-B529-A42158647B36}.commercial_64|Mixed Platforms.ActiveCfg = Release|x86 + {54835857-129F-44C9-B529-A42158647B36}.commercial_64|Mixed Platforms.Build.0 = Release|x86 + {54835857-129F-44C9-B529-A42158647B36}.commercial_64|x64.ActiveCfg = Release|x64 + {54835857-129F-44C9-B529-A42158647B36}.commercial_64|x64.Build.0 = Release|x64 + {54835857-129F-44C9-B529-A42158647B36}.commercial_64|x86.ActiveCfg = Release|x86 + {54835857-129F-44C9-B529-A42158647B36}.commercial_64|x86.Build.0 = Release|x86 + {54835857-129F-44C9-B529-A42158647B36}.commercial|Any CPU.ActiveCfg = Release|Any CPU + {54835857-129F-44C9-B529-A42158647B36}.commercial|Any CPU.Build.0 = Release|Any CPU + {54835857-129F-44C9-B529-A42158647B36}.commercial|Mixed Platforms.ActiveCfg = Release|x86 + {54835857-129F-44C9-B529-A42158647B36}.commercial|Mixed Platforms.Build.0 = Release|x86 + {54835857-129F-44C9-B529-A42158647B36}.commercial|x64.ActiveCfg = Release|x64 + {54835857-129F-44C9-B529-A42158647B36}.commercial|x64.Build.0 = Release|x64 + {54835857-129F-44C9-B529-A42158647B36}.commercial|x86.ActiveCfg = Release|x86 + {54835857-129F-44C9-B529-A42158647B36}.commercial|x86.Build.0 = Release|x86 + {54835857-129F-44C9-B529-A42158647B36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {54835857-129F-44C9-B529-A42158647B36}.Debug|Any CPU.Build.0 = Debug|Any CPU + {54835857-129F-44C9-B529-A42158647B36}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {54835857-129F-44C9-B529-A42158647B36}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {54835857-129F-44C9-B529-A42158647B36}.Debug|x64.ActiveCfg = Debug|x64 + {54835857-129F-44C9-B529-A42158647B36}.Debug|x64.Build.0 = Debug|x64 + {54835857-129F-44C9-B529-A42158647B36}.Debug|x86.ActiveCfg = Debug|x86 + {54835857-129F-44C9-B529-A42158647B36}.Debug|x86.Build.0 = Debug|x86 + {54835857-129F-44C9-B529-A42158647B36}.Release|Any CPU.ActiveCfg = Release|Any CPU + {54835857-129F-44C9-B529-A42158647B36}.Release|Any CPU.Build.0 = Release|Any CPU + {54835857-129F-44C9-B529-A42158647B36}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {54835857-129F-44C9-B529-A42158647B36}.Release|Mixed Platforms.Build.0 = Release|x86 + {54835857-129F-44C9-B529-A42158647B36}.Release|x64.ActiveCfg = Release|x64 + {54835857-129F-44C9-B529-A42158647B36}.Release|x64.Build.0 = Release|x64 + {54835857-129F-44C9-B529-A42158647B36}.Release|x86.ActiveCfg = Release|x86 + {54835857-129F-44C9-B529-A42158647B36}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal From 8accc49386be42c1ef7ecd1a8df044d8f2ed60a9 Mon Sep 17 00:00:00 2001 From: Anh-Dung Phan Date: Fri, 27 Dec 2013 11:39:50 -0800 Subject: [PATCH 249/925] Add a README for MSF plugin --- examples/msf/README | 20 ++++++++ .../SolverFoundation.Plugin.Z3.csproj | 50 ++----------------- examples/msf/Validator/Validator.csproj | 30 ++--------- 3 files changed, 30 insertions(+), 70 deletions(-) create mode 100644 examples/msf/README diff --git a/examples/msf/README b/examples/msf/README new file mode 100644 index 000000000..ab69fb0fe --- /dev/null +++ b/examples/msf/README @@ -0,0 +1,20 @@ +In order to use Z3 MSF plugin, follow the following steps: +1. Compile latest Z3 .NET API (from any branch consisting of opt features) and copy 'libz3.dll' and 'Microsoft.Z3.dll' to the folder of 'Z3MSFPlugin.sln'. +2. Retrieve 'Microsoft.Solver.Foundation.dll' from http://archive.msdn.microsoft.com/solverfoundation/Release/ProjectReleases.aspx?ReleaseId=1799, + preferably using DLL only version. Copy 'Microsoft.Solver.Foundation.dll' to the folder of 'Z3MSFPlugin.sln' +3. Build 'Z3MSFPlugin.sln' + +The solution consists of a plugin project, a test project with a few simple test cases and a command line projects for external OML, MPS and SMPS models. +To retrieve SMT2 models which are native to Z3, set the logging file in corresponding directives or solver params e.g. + + var p = new Z3MILPParams(); + p.SMT2LogFile = "model.smt2"; + +For more details, check out the commands in 'Validator\Program.cs'. + +Enjoy! + + + + + \ No newline at end of file diff --git a/examples/msf/SolverFoundation.Plugin.Z3/SolverFoundation.Plugin.Z3.csproj b/examples/msf/SolverFoundation.Plugin.Z3/SolverFoundation.Plugin.Z3.csproj index 6a4a22aec..9f6b71f34 100644 --- a/examples/msf/SolverFoundation.Plugin.Z3/SolverFoundation.Plugin.Z3.csproj +++ b/examples/msf/SolverFoundation.Plugin.Z3/SolverFoundation.Plugin.Z3.csproj @@ -14,11 +14,7 @@ 512 false - - - - 3.5 - + publish\ true Disk @@ -61,13 +57,7 @@ true pdbonly AnyCPU - bin\Release\Z3Solver.dll.CodeAnalysisLog.xml - true - GlobalSuppressions.cs prompt - AllRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules bin\commercial_64\ @@ -75,15 +65,7 @@ true pdbonly AnyCPU - bin\Release\Z3Solver.dll.CodeAnalysisLog.xml - true - GlobalSuppressions.cs prompt - AllRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - false - false true @@ -119,8 +101,6 @@ pdbonly x86 prompt - AllRules.ruleset - false @@ -130,15 +110,12 @@ ..\Microsoft.Z3.dll - - 3.5 + - - 3.5 + - - 3.5 + @@ -156,24 +133,7 @@ - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - + " << r << "; score=" << m_mpz_manager.to_string(cur_best) << std::endl;); + + if (m_mpz_manager.gt(cur_best, best_score)) { + m_mpz_manager.set(best_score, cur_best); + best_const = fd_inx; + m_mpz_manager.set(best_value, temp); + return true; + } + } + + return false; +} + +mpz bvsls_opt_engine::find_best_move( + ptr_vector & to_evaluate, + mpz score, + unsigned & best_const, + mpz & best_value, + unsigned & new_bit, + move_type & move, + mpz const & max_score, + expr * objective) +{ + mpz old_value, temp; +#if _USE_MUL3_ || _USE_UNARY_MINUS_ + mpz temp2; +#endif + unsigned bv_sz; + mpz new_score = score; + + for (unsigned i = 0; i < to_evaluate.size() && m_mpz_manager.lt(new_score, max_score); i++) { + func_decl * fd = to_evaluate[i]; + sort * srt = fd->get_range(); + bv_sz = (m_manager.is_bool(srt)) ? 1 : m_bv_util.get_bv_size(srt); + m_mpz_manager.set(old_value, m_tracker.get_value(fd)); + + // first try to flip every bit + for (unsigned j = 0; j < bv_sz && m_mpz_manager.lt(new_score, max_score); j++) { + // What would happen if we flipped bit #i ? + mk_flip(srt, old_value, j, temp); + + if (what_if(fd, i, temp, new_score, best_const, best_value)) { + new_bit = j; + move = MV_FLIP; + } + } + + if (m_bv_util.is_bv_sort(srt) && bv_sz > 1) { +#if _USE_ADDSUB_ + if (!m_mpz_manager.is_even(old_value)) { + // for odd values, try +1 + mk_inc(bv_sz, old_value, temp); + if (what_if(fd, i, temp, new_score, best_const, best_value)) + move = MV_INC; + } + else { + // for even values, try -1 + mk_dec(bv_sz, old_value, temp); + if (what_if(fd, i, temp, new_score, best_const, best_value)) + move = MV_DEC; + } +#endif + // try inverting + mk_inv(bv_sz, old_value, temp); + if (what_if(fd, i, temp, new_score, best_const, best_value)) + move = MV_INV; + +#if _USE_UNARY_MINUS_ + mk_inc(bv_sz, temp, temp2); + if (what_if(fd, i, temp2, new_score, best_const, best_value)) + move = MV_UMIN; +#endif + +#if _USE_MUL2DIV2_ + // try multiplication by 2 + mk_mul2(bv_sz, old_value, temp); + if (what_if(fd, i, temp, new_score, best_const, best_value)) + move = MV_MUL2; + +#if _USE_MUL3_ + // try multiplication by 3 + mk_add(bv_sz, old_value, temp, temp2); + if (what_if(fd, i, temp2, new_score, best_const, best_value)) + move = MV_MUL3; +#endif + + // try division by 2 + mk_div2(bv_sz, old_value, temp); + if (what_if(fd, i, temp, new_score, best_const, best_value)) + move = MV_DIV2; +#endif + } + + // reset to what it was before + double check = incremental_score(fd, old_value); + } + + m_mpz_manager.del(old_value); + m_mpz_manager.del(temp); +#if _USE_MUL3_ + m_mpz_manager.del(temp2); +#endif + + return new_score; +} + +bool bvsls_opt_engine::randomize_wrt_hard() { + ptr_vector consts = m_obj_tracker.get_constants(); + unsigned csz = consts.size(); + unsigned retry_count = csz; + + while (retry_count-- > 0) + { + + unsigned ri = (m_tracker.get_random_uint((csz < 16) ? 4 : (csz < 256) ? 8 : (csz < 4096) ? 12 : (csz < 65536) ? 16 : 32)) % csz; + func_decl * random_fd = consts[ri]; // Random constant + + mpz random_val; // random value. + m_mpz_manager.set(random_val, m_tracker.get_random(random_fd->get_range())); + + mpz old_value; + m_mpz_manager.set(old_value, m_tracker.get_value(random_fd)); + + if (!m_mpz_manager.eq(random_val, old_value)) { + m_evaluator.update(random_fd, random_val); + + if (m_hard_tracker.is_sat()) { + TRACE("sls_opt", tout << "Randomizing " << random_fd->get_name() << " to " << + m_mpz_manager.to_string(random_val) << std::endl;); + m_obj_evaluator.update(random_fd, random_val); + return true; + } + else + m_evaluator.update(random_fd, old_value); + } + } + + return false; } \ No newline at end of file diff --git a/src/tactic/sls/bvsls_opt_engine.h b/src/tactic/sls/bvsls_opt_engine.h index 326e51df4..befd00353 100644 --- a/src/tactic/sls/bvsls_opt_engine.h +++ b/src/tactic/sls/bvsls_opt_engine.h @@ -22,6 +22,12 @@ Notes: #include "sls_engine.h" class bvsls_opt_engine : public sls_engine { + sls_tracker & m_hard_tracker; + sls_tracker m_obj_tracker; + sls_evaluator m_obj_evaluator; + model_ref m_best_model; + mpz m_best_model_score; + public: bvsls_opt_engine(ast_manager & m, params_ref const & p); ~bvsls_opt_engine(); @@ -33,10 +39,33 @@ public: optimization_result(ast_manager & m) : is_sat(l_undef), optimum(m) {} }; - optimization_result optimize(expr_ref const & objective); + optimization_result optimize(expr_ref const & objective, model_ref initial_model = model_ref(), bool maximize=true); + + void get_model(model_ref & result) { result = m_best_model; } protected: expr_ref maximize(expr_ref const & objective); + expr_ref minimize(expr_ref const & objective); + + bool what_if(func_decl * fd, const unsigned & fd_inx, const mpz & temp, + mpz & best_score, unsigned & best_const, mpz & best_value); + + mpz find_best_move(ptr_vector & to_evaluate, mpz score, + unsigned & best_const, mpz & best_value, unsigned & new_bit, move_type & move, + mpz const & max_score, expr * objective); + + mpz top_score(void) { + mpz res(0); + obj_hashtable const & top_exprs = m_obj_tracker.get_top_exprs(); + for (obj_hashtable::iterator it = top_exprs.begin(); + it != top_exprs.end(); + it++) + m_mpz_manager.add(res, m_obj_tracker.get_value(*it), res); + return res; + } + + void save_model(mpz const & score); + bool randomize_wrt_hard(); }; #endif \ No newline at end of file diff --git a/src/tactic/sls/sls_evaluator.h b/src/tactic/sls/sls_evaluator.h index 0053763bb..5e8b10488 100644 --- a/src/tactic/sls/sls_evaluator.h +++ b/src/tactic/sls/sls_evaluator.h @@ -138,6 +138,14 @@ public: } break; } + case OP_ITE: { + SASSERT(n_args = 3); + if (m_mpz_manager.is_one(m_tracker.get_value(args[0]))) + m_mpz_manager.set(result, m_tracker.get_value(args[1])); + else + m_mpz_manager.set(result, m_tracker.get_value(args[2])); + break; + } default: NOT_IMPLEMENTED_YET(); } diff --git a/src/tactic/sls/sls_tracker.h b/src/tactic/sls/sls_tracker.h index 50d0e4188..188df66b1 100644 --- a/src/tactic/sls/sls_tracker.h +++ b/src/tactic/sls/sls_tracker.h @@ -133,6 +133,19 @@ public: } #endif + inline obj_hashtable const & get_top_exprs() { + return m_top_expr; + } + + inline bool is_sat() { + for (obj_hashtable::iterator it = m_top_expr.begin(); + it != m_top_expr.end(); + it++) + if (!m_mpz_manager.is_one(get_value(*it))) + return false; + return true; + } + inline void set_value(expr * n, const mpz & r) { SASSERT(m_scores.contains(n)); m_mpz_manager.set(m_scores.find(n).value, r); @@ -522,6 +535,28 @@ public: } } + void set_model(model_ref const & mdl) { + for (unsigned i = 0; i < mdl->get_num_constants(); i++) { + func_decl * fd = mdl->get_constant(i); + expr * val = mdl->get_const_interp(fd); + if (m_entry_points.contains(fd)) { + if (m_manager.is_bool(val)) { + set_value(fd, m_manager.is_true(val) ? m_mpz_manager.mk_z(1) : m_mpz_manager.mk_z(0)); + } + else if (m_bv_util.is_numeral(val)) { + rational r_val; + unsigned bv_sz; + m_bv_util.is_numeral(val, r_val, bv_sz); + mpq q = r_val.to_mpq(); + SASSERT(m_mpz_manager.is_one(q.denominator())); + set_value(fd, q.numerator()); + } + else + NOT_IMPLEMENTED_YET(); + } + } + } + model_ref get_model() { model_ref res = alloc(model, m_manager); unsigned sz = get_num_constants(); @@ -674,6 +709,9 @@ public: m_scores.find(n).has_pos_occ = 1; } } + else if (m_bv_util.is_bv(n)) { + /* CMW: I need this for optimization. Safe to ignore? */ + } else NOT_IMPLEMENTED_YET(); } From 7d896e5a9a21039a66cba34b4c5c78e6cbe645c8 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 31 Mar 2014 17:58:19 +0100 Subject: [PATCH 353/925] bvsls_opt_engine bugfix Signed-off-by: Christoph M. Wintersteiger --- src/tactic/sls/bvsls_opt_engine.cpp | 30 ++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/tactic/sls/bvsls_opt_engine.cpp b/src/tactic/sls/bvsls_opt_engine.cpp index cad496fd0..37587428c 100644 --- a/src/tactic/sls/bvsls_opt_engine.cpp +++ b/src/tactic/sls/bvsls_opt_engine.cpp @@ -86,9 +86,9 @@ expr_ref bvsls_opt_engine::maximize(expr_ref const & objective) unsigned obj_bv_sz = m_bv_util.get_bv_size(obj_e); ptr_vector objs; objs.push_back(obj_e); - m_obj_tracker.initialize(objs); - m_obj_evaluator.update_all(); + m_obj_tracker.initialize(objs); m_obj_tracker.set_model(m_hard_tracker.get_model()); + m_obj_evaluator.update_all(); TRACE("sls_opt", tout << "Initial opt model:" << std::endl; m_obj_tracker.show_model(tout);); IF_VERBOSE(1, verbose_stream() << "Maximizing... restarts left:" << (m_max_restarts - m_stats.m_restarts) << std::endl;); @@ -97,10 +97,10 @@ expr_ref bvsls_opt_engine::maximize(expr_ref const & objective) unsigned new_const = (unsigned)-1, new_bit = 0; ptr_vector consts = m_obj_tracker.get_constants(); move_type move; - m_mpz_manager.set(score, m_obj_tracker.get_value(obj_e)); + m_mpz_manager.set(score, top_score()); m_mpz_manager.set(max_score, m_powers(obj_bv_sz)); m_mpz_manager.dec(max_score); - save_model(score); + save_model(score); while (check_restart((unsigned)m_stats.m_stopwatch.get_current_seconds()) && m_stats.m_stopwatch.get_current_seconds() < _TIMELIMIT_ && @@ -129,6 +129,7 @@ expr_ref bvsls_opt_engine::maximize(expr_ref const & objective) TRACE("sls_opt", tout << "New best: " << m_mpz_manager.to_string(score) << std::endl;); func_decl * fd = consts[new_const]; incremental_score(fd, new_value); + m_obj_evaluator.update(fd, new_value); m_mpz_manager.set(score, top_score()); } } @@ -184,7 +185,7 @@ bool bvsls_opt_engine::what_if( double r = incremental_score(fd, temp); #endif - if (r >= 1.0 && m_tracker.is_sat()) { + if (r >= 1.0 && m_hard_tracker.is_sat()) { m_obj_evaluator.update(fd, temp); mpz cur_best(0); m_mpz_manager.set(cur_best, top_score()); @@ -199,6 +200,11 @@ bool bvsls_opt_engine::what_if( return true; } } + else + { + TRACE("sls_whatif_failed", tout << "WHAT IF " << fd->get_name() << " WERE " << m_mpz_manager.to_string(temp) << + " --> unsatisfied hard constraints" << std::endl;); + } return false; } @@ -218,13 +224,14 @@ mpz bvsls_opt_engine::find_best_move( mpz temp2; #endif unsigned bv_sz; - mpz new_score = score; + mpz new_score; + m_mpz_manager.set(new_score, score); for (unsigned i = 0; i < to_evaluate.size() && m_mpz_manager.lt(new_score, max_score); i++) { func_decl * fd = to_evaluate[i]; sort * srt = fd->get_range(); bv_sz = (m_manager.is_bool(srt)) ? 1 : m_bv_util.get_bv_size(srt); - m_mpz_manager.set(old_value, m_tracker.get_value(fd)); + m_mpz_manager.set(old_value, m_obj_tracker.get_value(fd)); // first try to flip every bit for (unsigned j = 0; j < bv_sz && m_mpz_manager.lt(new_score, max_score); j++) { @@ -285,6 +292,7 @@ mpz bvsls_opt_engine::find_best_move( // reset to what it was before double check = incremental_score(fd, old_value); + m_obj_evaluator.update(fd, old_value); } m_mpz_manager.del(old_value); @@ -304,21 +312,21 @@ bool bvsls_opt_engine::randomize_wrt_hard() { while (retry_count-- > 0) { - unsigned ri = (m_tracker.get_random_uint((csz < 16) ? 4 : (csz < 256) ? 8 : (csz < 4096) ? 12 : (csz < 65536) ? 16 : 32)) % csz; + unsigned ri = (m_obj_tracker.get_random_uint((csz < 16) ? 4 : (csz < 256) ? 8 : (csz < 4096) ? 12 : (csz < 65536) ? 16 : 32)) % csz; func_decl * random_fd = consts[ri]; // Random constant mpz random_val; // random value. - m_mpz_manager.set(random_val, m_tracker.get_random(random_fd->get_range())); + m_mpz_manager.set(random_val, m_obj_tracker.get_random(random_fd->get_range())); mpz old_value; - m_mpz_manager.set(old_value, m_tracker.get_value(random_fd)); + m_mpz_manager.set(old_value, m_obj_tracker.get_value(random_fd)); if (!m_mpz_manager.eq(random_val, old_value)) { m_evaluator.update(random_fd, random_val); if (m_hard_tracker.is_sat()) { TRACE("sls_opt", tout << "Randomizing " << random_fd->get_name() << " to " << - m_mpz_manager.to_string(random_val) << std::endl;); + m_mpz_manager.to_string(random_val) << std::endl;); m_obj_evaluator.update(random_fd, random_val); return true; } From f321f19b206c5479e089d8312aef8f955a1cccda Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 31 Mar 2014 23:30:59 +0200 Subject: [PATCH 354/925] adding bcd2 Signed-off-by: Nikolaj Bjorner --- src/opt/weighted_maxsat.cpp | 85 ++++++++++++++++++++++++++++++++----- 1 file changed, 74 insertions(+), 11 deletions(-) diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 5cf69b16b..8a1a07693 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -605,38 +605,101 @@ namespace opt { struct wcore { unsigned_vector m_R; - rational m_lambda; - rational m_nu; - rational m_epsilon; + rational m_lower; + rational m_mid; + rational m_upper; }; lbool bcd2_solve() { return l_undef; #if 0 - expr_ref fml(m); + expr_ref fml(m), val(m); + app_ref r(m); vector cores; + obj_map ans2core; // answer literal to core index lbool is_sat = l_undef; - expr_ref_vector nsoft(m); + expr_ref_vector soft(m), rs(m); m_lower = m_upper = rational::zero(); + bool first = true; for (unsigned i = 0; i < m_soft.size(); ++i) { m_upper += m_weights[i]; + r = m.mk_fresh_const("r", m.mk_bool_sort()); + s.mc().insert(r->get_decl()); + fml = m.mk_or(m_soft[i].get(), r); + s.assert_expr(fml); + rs.push_back(r); + asms.push_back(m.mk_not(r)); } + m_upper += rational(1); solver::scoped_push _s(s); while (m_lower < m_upper) { solver::scoped_push _s(s); - + if (m_cancel) { + return l_undef; + } for (unsigned i = 0; i < cores.size(); ++i) { assert_core(cores[i]); + // need assumptions here as well. } - is_sat = check_sat(0, 0); + is_sat = check_sat(asms.size(), asms.c_ptr()); switch(is_sat) { - case l_undef: return l_undef; + case l_undef: + return l_undef; case l_true: { - + updt_model(s); + m_upper.reset(); + for (unsigned i = 0; i < cores.size(); ++i) { + wcore& c_i = cores[i]; + unsigned_vector const& R = c_i.m_R; + c_i.m_upper.reset(); + for (unsigned j = 0; j < R.size(); ++j) { + unsigned r_j = R[j]; + VERIFY(m_model->eval(m_soft[r_j].get(), val)); + if (m.is_false(val)) { + c_i.m_upper += m_weights[r_j]; + } + } + c_i.m_mid = div(c_i.m_lower + c_i.m_upper, rational(2)); + m_upper += c_i.m_upper; + } + first = false; break; } case l_false: { - + ptr_vector core; + s.get_unsat_core(core); + uint_set subC; + unsigned_vector soft; + rational delta(0); + for (unsigned i = 0; i < core.size(); ++i) { + unsigned j; + if (ans2core.find(core[i], j)) { + subC.insert(j); + rational new_delta = rational(1) + cores[j].m_upper - cores[j].m_mid; + SASSERT(new_delta.is_pos()); + if (delta.is_zero() || delta > new_delta) { + delta = new_delta; + } + } + else { + soft.push_back(i); + } + } + if (soft.empty() && subC.num_elems() == 1) { + SASSERT(core.size() == 1); + unsigned s = *subS.begin(); + wcore& c_s = cores[s]; + m_lower -= c_s.m_lower; + c_s.m_lower = refine(c_s, c_s.m_mid); + m_lower += c_s.m_lower; + } + else { + wcore c_s; + relax(subC, soft, c_s.m_R); + for (unsigned i = 0; i < subC.size(); ++i) { + + } + } break; } } @@ -654,7 +717,7 @@ namespace opt { ws.push_back(m_weights[idx]); rs.push_back(m_soft[idx].get()); // TBD: check } - // TBD: fml = pb.mk_le(ws.size(), ws.c_ptr(), rs.c_ptr(), core.m_nu); + // TBD: fml = pb.mk_le(ws.size(), ws.c_ptr(), rs.c_ptr(), core.m_mid); s.assert_expr(fml); } From 7fd6549a4053e9c3961c0e608560aed6f118d1d9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 31 Mar 2014 23:32:31 +0200 Subject: [PATCH 355/925] another sls example Signed-off-by: Nikolaj Bjorner --- tests/sls1.smt2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/sls1.smt2 b/tests/sls1.smt2 index 2218993a2..5f38a9418 100644 --- a/tests/sls1.smt2 +++ b/tests/sls1.smt2 @@ -5840,5 +5840,5 @@ (* 100 x_1604) (* 100 x_1001))) (optimize :print_statistics true - :wmaxsat_engine sls + :wmaxsat_engine bvsls :maxsat_engine weighted_maxsat) From 1db7e0a149fee3313c70fd0ac38027021f67a0c0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 2 Apr 2014 15:54:28 +0200 Subject: [PATCH 356/925] fix compiler warnings reported by Robert White Signed-off-by: Nikolaj Bjorner --- src/api/api_interp.cpp | 2 +- src/api/api_opt.cpp | 34 +++++++++++++++++----------------- src/ast/scoped_proof.h | 2 +- src/interp/iz3hash.h | 2 +- src/smt/theory_arith_eq.h | 2 +- src/tactic/sls/sls_tracker.h | 3 ++- src/util/sorting_network.h | 4 ++-- 7 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/api/api_interp.cpp b/src/api/api_interp.cpp index 2c88a1978..48e13d571 100644 --- a/src/api/api_interp.cpp +++ b/src/api/api_interp.cpp @@ -317,7 +317,7 @@ static void get_file_params(const char *filename, hash_map= 0 && eqpos < tok.size()){ + if(eqpos < tok.size()){ std::string left = tok.substr(0,eqpos); std::string right = tok.substr(eqpos+1,tok.size()-eqpos-1); params[left] = right; diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index b1e4b9203..e40d690fc 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -36,7 +36,7 @@ extern "C" { }; inline Z3_optimize_ref * to_optimize(Z3_optimize o) { return reinterpret_cast(o); } inline Z3_optimize of_optimize(Z3_optimize_ref * o) { return reinterpret_cast(o); } - inline opt::context& to_optimize_ref(Z3_optimize o) { return *to_optimize(o)->m_opt; } + inline opt::context* to_optimize_ref(Z3_optimize o) { return to_optimize(o)->m_opt; } Z3_optimize Z3_API Z3_mk_optimize(Z3_context c) { Z3_TRY; @@ -70,7 +70,7 @@ extern "C" { LOG_Z3_optimize_assert(c, o, a); RESET_ERROR_CODE(); CHECK_FORMULA(a,); - to_optimize_ref(o).add_hard_constraint(to_expr(a)); + to_optimize_ref(o)->add_hard_constraint(to_expr(a)); Z3_CATCH; } @@ -80,7 +80,7 @@ extern "C" { RESET_ERROR_CODE(); CHECK_FORMULA(a,0); rational w(weight); - return to_optimize_ref(o).add_soft_constraint(to_expr(a), w, to_symbol(id)); + return to_optimize_ref(o)->add_soft_constraint(to_expr(a), w, to_symbol(id)); Z3_CATCH_RETURN(0); } @@ -89,7 +89,7 @@ extern "C" { LOG_Z3_optimize_maximize(c, o, t); RESET_ERROR_CODE(); CHECK_VALID_AST(t,0); - return to_optimize_ref(o).add_objective(to_app(t), true); + return to_optimize_ref(o)->add_objective(to_app(t), true); Z3_CATCH_RETURN(0); } @@ -98,7 +98,7 @@ extern "C" { LOG_Z3_optimize_minimize(c, o, t); RESET_ERROR_CODE(); CHECK_VALID_AST(t,0); - return to_optimize_ref(o).add_objective(to_app(t), false); + return to_optimize_ref(o)->add_objective(to_app(t), false); Z3_CATCH_RETURN(0); } @@ -107,19 +107,19 @@ extern "C" { LOG_Z3_optimize_check(c, o); RESET_ERROR_CODE(); lbool r = l_undef; - cancel_eh eh(to_optimize_ref(o)); + cancel_eh eh(*to_optimize_ref(o)); unsigned timeout = 0; // to_optimize(o)->m_params.get_uint("timeout", mk_c(c)->get_timeout()); api::context::set_interruptable si(*(mk_c(c)), eh); { scoped_timer timer(timeout, &eh); try { - r = to_optimize_ref(o).optimize(); + r = to_optimize_ref(o)->optimize(); } catch (z3_exception& ex) { mk_c(c)->handle_exception(ex); r = l_undef; } - // to_optimize_ref(d).cleanup(); + // to_optimize_ref(d)->cleanup(); } return of_lbool(r); Z3_CATCH_RETURN(Z3_L_UNDEF); @@ -130,7 +130,7 @@ extern "C" { LOG_Z3_optimize_get_model(c, o); RESET_ERROR_CODE(); model_ref _m; - to_optimize_ref(o).get_model(_m); + to_optimize_ref(o)->get_model(_m); Z3_model_ref * m_ref = alloc(Z3_model_ref); if (_m) { m_ref->m_model = _m; @@ -148,10 +148,10 @@ extern "C" { LOG_Z3_optimize_set_params(c, o, p); RESET_ERROR_CODE(); param_descrs descrs; - to_optimize_ref(o).collect_param_descrs(descrs); + to_optimize_ref(o)->collect_param_descrs(descrs); to_params(p)->m_params.validate(descrs); params_ref pr = to_param_ref(p); - to_optimize_ref(o).updt_params(pr); + to_optimize_ref(o)->updt_params(pr); Z3_CATCH; } @@ -161,7 +161,7 @@ extern "C" { RESET_ERROR_CODE(); Z3_param_descrs_ref * d = alloc(Z3_param_descrs_ref); mk_c(c)->save_object(d); - to_optimize_ref(o).collect_param_descrs(d->m_descrs); + to_optimize_ref(o)->collect_param_descrs(d->m_descrs); Z3_param_descrs r = of_param_descrs(d); RETURN_Z3(r); Z3_CATCH_RETURN(0); @@ -172,7 +172,7 @@ extern "C" { Z3_TRY; LOG_Z3_optimize_get_lower(c, o, idx); RESET_ERROR_CODE(); - expr_ref e = to_optimize_ref(o).get_lower(idx); + expr_ref e = to_optimize_ref(o)->get_lower(idx); mk_c(c)->save_ast_trail(e); RETURN_Z3(of_expr(e)); Z3_CATCH_RETURN(0); @@ -183,7 +183,7 @@ extern "C" { Z3_TRY; LOG_Z3_optimize_get_upper(c, o, idx); RESET_ERROR_CODE(); - expr_ref e = to_optimize_ref(o).get_upper(idx); + expr_ref e = to_optimize_ref(o)->get_upper(idx); mk_c(c)->save_ast_trail(e); RETURN_Z3(of_expr(e)); Z3_CATCH_RETURN(0); @@ -193,7 +193,7 @@ extern "C" { Z3_TRY; LOG_Z3_optimize_to_string(c, o); RESET_ERROR_CODE(); - return mk_c(c)->mk_external_string(to_optimize_ref(o).to_string()); + return mk_c(c)->mk_external_string(to_optimize_ref(o)->to_string()); Z3_CATCH_RETURN(""); } @@ -203,7 +203,7 @@ extern "C" { RESET_ERROR_CODE(); std::ostringstream buffer; param_descrs descrs; - to_optimize_ref(d).collect_param_descrs(descrs); + to_optimize_ref(d)->collect_param_descrs(descrs); descrs.display(buffer); return mk_c(c)->mk_external_string(buffer.str()); Z3_CATCH_RETURN(""); @@ -214,7 +214,7 @@ extern "C" { LOG_Z3_optimize_get_statistics(c, d); RESET_ERROR_CODE(); Z3_stats_ref * st = alloc(Z3_stats_ref); - to_optimize_ref(d).collect_statistics(st->m_stats); + to_optimize_ref(d)->collect_statistics(st->m_stats); mk_c(c)->save_object(st); Z3_stats r = of_stats(st); RETURN_Z3(r); diff --git a/src/ast/scoped_proof.h b/src/ast/scoped_proof.h index e37290c03..68c186e85 100644 --- a/src/ast/scoped_proof.h +++ b/src/ast/scoped_proof.h @@ -16,7 +16,7 @@ Author: Revision History: --*/ -#ifndef _SCOPED_PROOF__H_ +#ifndef _SCOPED_PROOF_H_ #define _SCOPED_PROOF_H_ #include "ast.h" diff --git a/src/interp/iz3hash.h b/src/interp/iz3hash.h index 2b364bc1b..d1bfd9f7b 100644 --- a/src/interp/iz3hash.h +++ b/src/interp/iz3hash.h @@ -464,7 +464,7 @@ namespace hash_space { Value &operator[](const Key& key) { std::pair kvp(key,Value()); - return lookup(kvp,true)->val.second; + return this->lookup(kvp,true)->val.second; } }; diff --git a/src/smt/theory_arith_eq.h b/src/smt/theory_arith_eq.h index 04e16e778..368ccb87d 100644 --- a/src/smt/theory_arith_eq.h +++ b/src/smt/theory_arith_eq.h @@ -193,7 +193,7 @@ namespace smt { return true; } - if (!r.get_base_var() == x && x > y) { + if (r.get_base_var() != x && x > y) { std::swap(x, y); k.neg(); } diff --git a/src/tactic/sls/sls_tracker.h b/src/tactic/sls/sls_tracker.h index 188df66b1..a074af2f8 100644 --- a/src/tactic/sls/sls_tracker.h +++ b/src/tactic/sls/sls_tracker.h @@ -20,6 +20,7 @@ Notes: #ifndef _SLS_TRACKER_H_ #define _SLS_TRACKER_H_ +#include #include"for_each_expr.h" #include"ast_smt2_pp.h" #include"bv_decl_plugin.h" @@ -1482,4 +1483,4 @@ public: } }; -#endif \ No newline at end of file +#endif diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index a1f58a3a7..b9cf86433 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -380,7 +380,7 @@ Notes: literal y2 = min(as[0], bs[0]); out.push_back(y1); out.push_back(y2); - cmp(as[0], bs[0], y1, y2); + psort_nw::cmp(as[0], bs[0], y1, y2); } else if (a == 0) { out.append(b, bs); @@ -455,7 +455,7 @@ Notes: for (unsigned i = 0; i < sz; ++i) { literal y1 = max(as[i+1],bs[i]); literal y2 = min(as[i+1],bs[i]); - cmp(as[i+1], bs[i], y1, y2); + psort_nw::cmp(as[i+1], bs[i], y1, y2); out.push_back(y1); out.push_back(y2); } From 71af72eed45bd7770578fd8aa1dcaee84b7f9993 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 14 Apr 2014 15:24:47 +0100 Subject: [PATCH 357/925] bugfix for bvsls_opt_engine Signed-off-by: Christoph M. Wintersteiger --- src/opt/weighted_maxsat.cpp | 5 +++++ src/tactic/sls/bvsls_opt_engine.cpp | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 2d2d67320..b7b906ca6 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -347,6 +347,11 @@ namespace opt { unsigned bv_size = 0; m_bvsls.get_model(m_model); VERIFY(bv.is_numeral(res.optimum, m_lower, bv_size)); + for (unsigned i = 0; i < m_soft.size(); ++i) { + expr_ref tmp(m); + m_model->eval(m_soft[i].get(), tmp, true); + m_assignment[i] = m.is_true(tmp); + } break; } case l_false: diff --git a/src/tactic/sls/bvsls_opt_engine.cpp b/src/tactic/sls/bvsls_opt_engine.cpp index 37587428c..ff17ced2b 100644 --- a/src/tactic/sls/bvsls_opt_engine.cpp +++ b/src/tactic/sls/bvsls_opt_engine.cpp @@ -100,6 +100,8 @@ expr_ref bvsls_opt_engine::maximize(expr_ref const & objective) m_mpz_manager.set(score, top_score()); m_mpz_manager.set(max_score, m_powers(obj_bv_sz)); m_mpz_manager.dec(max_score); + IF_IVERBOSE(10, verbose_stream() << "Initial score: " << m_mpz_manager.to_string(score) << std::endl;); + save_model(score); while (check_restart((unsigned)m_stats.m_stopwatch.get_current_seconds()) && @@ -126,7 +128,8 @@ expr_ref bvsls_opt_engine::maximize(expr_ref const & objective) m_mpz_manager.set(score, top_score()); } else { - TRACE("sls_opt", tout << "New best: " << m_mpz_manager.to_string(score) << std::endl;); + TRACE("sls_opt", tout << "New optimum: " << m_mpz_manager.to_string(score) << std::endl;); + IF_IVERBOSE(10, verbose_stream() << "New optimum: " << m_mpz_manager.to_string(score) << std::endl;); func_decl * fd = consts[new_const]; incremental_score(fd, new_value); m_obj_evaluator.update(fd, new_value); From 64106af5ec8107d659a73f9ef4d36697e826d65a Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 14 Apr 2014 17:48:09 +0100 Subject: [PATCH 358/925] bvsls_opt_engine fixes Signed-off-by: Christoph M. Wintersteiger --- src/opt/weighted_maxsat.cpp | 5 +- src/tactic/sls/bvsls_opt_engine.cpp | 121 +++++++++++++--------- src/tactic/sls/bvsls_opt_engine.h | 8 +- src/tactic/sls/sls_compilation_settings.h | 2 +- 4 files changed, 82 insertions(+), 54 deletions(-) diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index b7b906ca6..2e7e2f4aa 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -339,8 +339,11 @@ namespace opt { lbool is_sat = s.check_sat_core(0, 0); if (is_sat == l_true) { updt_model(s); + params_ref p; + p.set_uint("restarts", 20); + m_bvsls.updt_params(p); // TBD: can we set an initial model on m_bvsls? - // CMW: Yes, see next line. + // CMW: Yes, see next line. bvsls_opt_engine::optimization_result res = m_bvsls.optimize(objective, m_model, true); switch (res.is_sat) { case l_true: { diff --git a/src/tactic/sls/bvsls_opt_engine.cpp b/src/tactic/sls/bvsls_opt_engine.cpp index ff17ced2b..12a0cf631 100644 --- a/src/tactic/sls/bvsls_opt_engine.cpp +++ b/src/tactic/sls/bvsls_opt_engine.cpp @@ -16,6 +16,7 @@ Author: Notes: --*/ +#include "sls_compilation_settings.h" #include "nnf.h" #include "bvsls_opt_engine.h" @@ -41,7 +42,8 @@ bvsls_opt_engine::optimization_result bvsls_opt_engine::optimize( TRACE("sls_opt", tout << "objective: " << (_maximize?"maximize":"minimize") << " " << mk_ismt2_pp(objective, m()) << std::endl;); m_hard_tracker.initialize(m_assertions); - m_restart_limit = _RESTART_LIMIT_; + m_restart_limit = _RESTART_LIMIT_; + setup_opt_tracker(objective, _maximize); if (initial_model.get() != 0) { TRACE("sls_opt", tout << "Initial model provided: " << std::endl; @@ -51,62 +53,88 @@ bvsls_opt_engine::optimization_result bvsls_opt_engine::optimize( tout << fd->get_name() << " := " << mk_ismt2_pp(val, m()) << std::endl; }); m_hard_tracker.set_model(initial_model); - } - - optimization_result res(m_manager); - - res.is_sat = m_hard_tracker.is_sat() ? l_true : l_undef; - - if (!res.is_sat) { - do { - checkpoint(); - - IF_VERBOSE(1, verbose_stream() << "Satisfying... restarts left:" << (m_max_restarts - m_stats.m_restarts) << std::endl;); - res.is_sat = search(); - - if (res.is_sat == l_undef) - m_hard_tracker.randomize(m_assertions); - } while (m_stats.m_stopwatch.get_current_seconds() < _TIMELIMIT_ && - res.is_sat != l_true && m_stats.m_restarts++ < m_max_restarts); } + + optimization_result res(m_manager); + lbool is_sat = m_hard_tracker.is_sat() ? l_true : l_undef; - if (res.is_sat) - res.optimum = _maximize ? maximize(objective) : minimize(objective); + for (m_stats.m_restarts = 0; + m_stats.m_restarts < m_max_restarts; + m_stats.m_restarts++) + { + mpz old_best; + m_mpz_manager.set(old_best, m_best_model_score); + + if (!is_sat) { + do { + checkpoint(); + + IF_VERBOSE(1, verbose_stream() << "Satisfying... restarts left:" << (m_max_restarts - m_stats.m_restarts) << std::endl;); + is_sat = search(); + + if (is_sat == l_undef) + m_hard_tracker.randomize(m_assertions); + } + while (is_sat != l_true && + m_stats.m_restarts++ < m_max_restarts); + } + + if (is_sat == l_true) { + IF_VERBOSE(1, verbose_stream() << "Optimizing... restarts left:" << (m_max_restarts - m_stats.m_restarts) << std::endl;); + res.is_sat = l_true; + m_obj_tracker.set_model(m_hard_tracker.get_model()); + m_obj_evaluator.update_all(); + expr_ref local_best = maximize(); + if ((_maximize && m_mpz_manager.gt(m_best_model_score, old_best)) || + (!_maximize && m_mpz_manager.lt(m_best_model_score, old_best))) + { + res.optimum = local_best; + } + } + + m_hard_tracker.randomize(m_assertions); + m_evaluator.update_all(); + is_sat = m_hard_tracker.is_sat() ? l_true : l_undef; + } TRACE("sls_opt", tout << "sat: " << res.is_sat << "; optimum: " << mk_ismt2_pp(res.optimum, m()) << std::endl;); return res; } -expr_ref bvsls_opt_engine::maximize(expr_ref const & objective) +void bvsls_opt_engine::setup_opt_tracker(expr_ref const & objective, bool _max) +{ + expr_ref obj(m_manager); + obj = objective; + if (!_max) + obj = m_bv_util.mk_bv_neg(objective); + + m_obj_e = obj.get(); + m_obj_bv_sz = m_bv_util.get_bv_size(m_obj_e); + ptr_vector objs; + objs.push_back(m_obj_e); + m_obj_tracker.initialize(objs); +} + +expr_ref bvsls_opt_engine::maximize() { SASSERT(m_hard_tracker.is_sat()); - expr * obj_e = objective.get(); - unsigned obj_bv_sz = m_bv_util.get_bv_size(obj_e); - ptr_vector objs; - objs.push_back(obj_e); - m_obj_tracker.initialize(objs); - m_obj_tracker.set_model(m_hard_tracker.get_model()); - m_obj_evaluator.update_all(); - - TRACE("sls_opt", tout << "Initial opt model:" << std::endl; m_obj_tracker.show_model(tout);); - IF_VERBOSE(1, verbose_stream() << "Maximizing... restarts left:" << (m_max_restarts - m_stats.m_restarts) << std::endl;); + TRACE("sls_opt", tout << "Initial opt model:" << std::endl; m_obj_tracker.show_model(tout);); mpz score, old_score, max_score, new_value; unsigned new_const = (unsigned)-1, new_bit = 0; ptr_vector consts = m_obj_tracker.get_constants(); move_type move; m_mpz_manager.set(score, top_score()); - m_mpz_manager.set(max_score, m_powers(obj_bv_sz)); m_mpz_manager.dec(max_score); + m_mpz_manager.set(max_score, m_powers(m_obj_bv_sz)); m_mpz_manager.dec(max_score); - IF_IVERBOSE(10, verbose_stream() << "Initial score: " << m_mpz_manager.to_string(score) << std::endl;); + IF_VERBOSE(10, verbose_stream() << "Initial score: " << m_mpz_manager.to_string(score) << std::endl;); save_model(score); - while (check_restart((unsigned)m_stats.m_stopwatch.get_current_seconds()) && - m_stats.m_stopwatch.get_current_seconds() < _TIMELIMIT_ && - m_mpz_manager.lt(score, max_score)) { + while (m_mpz_manager.lt(score, max_score) && check_restart(m_stats.m_moves)) + { checkpoint(); m_stats.m_moves++; m_mpz_manager.set(old_score, score); @@ -114,22 +142,24 @@ expr_ref bvsls_opt_engine::maximize(expr_ref const & objective) mpz score(0); m_mpz_manager.set(score, - find_best_move(consts, score, new_const, new_value, new_bit, move, max_score, obj_e)); + find_best_move(consts, score, new_const, new_value, new_bit, move, max_score, m_obj_e)); if (new_const == static_cast(-1)) { m_mpz_manager.set(score, old_score); if (m_mpz_manager.gt(score, m_best_model_score)) - save_model(score); + save_model(score); if (!randomize_wrt_hard()) { // Can't improve and can't randomize; can't do anything other than bail out. TRACE("sls_opt", tout << "Got stuck; bailing out." << std::endl;); + IF_VERBOSE(10, verbose_stream() << "No local improvements possible." << std::endl;); goto bailout; - } - m_mpz_manager.set(score, top_score()); + } + m_mpz_manager.set(score, top_score()); } else { + m_stats.m_moves++; TRACE("sls_opt", tout << "New optimum: " << m_mpz_manager.to_string(score) << std::endl;); - IF_IVERBOSE(10, verbose_stream() << "New optimum: " << m_mpz_manager.to_string(score) << std::endl;); + IF_VERBOSE(10, verbose_stream() << "New optimum: " << m_mpz_manager.to_string(score) << std::endl;); func_decl * fd = consts[new_const]; incremental_score(fd, new_value); m_obj_evaluator.update(fd, new_value); @@ -141,17 +171,10 @@ bailout: m_mpz_manager.del(new_value); expr_ref res(m_manager); - res = m_bv_util.mk_numeral(m_best_model_score, obj_bv_sz); + res = m_bv_util.mk_numeral(m_best_model_score, m_obj_bv_sz); return res; } -expr_ref bvsls_opt_engine::minimize(expr_ref const & objective) -{ - expr_ref n_obj(m_manager); - n_obj = m_bv_util.mk_bv_neg(objective); - return maximize(n_obj); -} - void bvsls_opt_engine::save_model(mpz const & score) { model_ref mdl = m_hard_tracker.get_model(); model_ref obj_mdl = m_obj_tracker.get_model(); diff --git a/src/tactic/sls/bvsls_opt_engine.h b/src/tactic/sls/bvsls_opt_engine.h index befd00353..75216c49e 100644 --- a/src/tactic/sls/bvsls_opt_engine.h +++ b/src/tactic/sls/bvsls_opt_engine.h @@ -27,7 +27,9 @@ class bvsls_opt_engine : public sls_engine { sls_evaluator m_obj_evaluator; model_ref m_best_model; mpz m_best_model_score; - + unsigned m_obj_bv_sz; + expr * m_obj_e; + public: bvsls_opt_engine(ast_manager & m, params_ref const & p); ~bvsls_opt_engine(); @@ -44,8 +46,8 @@ public: void get_model(model_ref & result) { result = m_best_model; } protected: - expr_ref maximize(expr_ref const & objective); - expr_ref minimize(expr_ref const & objective); + void setup_opt_tracker(expr_ref const & objective, bool _max); + expr_ref maximize(); bool what_if(func_decl * fd, const unsigned & fd_inx, const mpz & temp, mpz & best_score, unsigned & best_const, mpz & best_value); diff --git a/src/tactic/sls/sls_compilation_settings.h b/src/tactic/sls/sls_compilation_settings.h index 4d8c83599..321320c39 100644 --- a/src/tactic/sls/sls_compilation_settings.h +++ b/src/tactic/sls/sls_compilation_settings.h @@ -38,7 +38,7 @@ Notes: // do we use restarts? // 0 = no, 1 = use #moves, 2 = use #plateaus, 3 = use time -#define _RESTARTS_ 3 +#define _RESTARTS_ 1 // limit of moves/plateaus/seconds until first restart occurs #define _RESTART_LIMIT_ 10 // 0 = initialize with all zero, 1 initialize with random value From 00f45579cc222a06b3e4a8a94ef12e0ef9dfeb09 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 14 Apr 2014 16:24:23 -0700 Subject: [PATCH 359/925] refactor weighted maxsmt Signed-off-by: Nikolaj Bjorner --- src/opt/maxsmt.cpp | 14 +- src/opt/maxsmt.h | 4 +- src/opt/opt_context.cpp | 4 +- src/opt/weighted_maxsat.cpp | 1709 +++++++++++++++++++---------------- src/opt/weighted_maxsat.h | 5 +- 5 files changed, 940 insertions(+), 796 deletions(-) diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index cc926484c..d2f308488 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -27,29 +27,29 @@ Notes: namespace opt { - lbool maxsmt::operator()(opt_solver& s) { + lbool maxsmt::operator()(opt_solver* s) { lbool is_sat; m_msolver = 0; - m_s = &s; + m_s = s; IF_VERBOSE(1, verbose_stream() << "(maxsmt)\n";); if (m_soft_constraints.empty()) { TRACE("opt", tout << "no constraints\n";); m_msolver = 0; - is_sat = s.check_sat(0, 0); + is_sat = m_s->check_sat(0, 0); } else if (is_maxsat_problem(m_weights)) { if (m_maxsat_engine == symbol("core_maxsat")) { - m_msolver = alloc(core_maxsat, m, s, m_soft_constraints); + m_msolver = alloc(core_maxsat, m, *m_s, m_soft_constraints); } else if (m_maxsat_engine == symbol("weighted_maxsat")) { - m_msolver = alloc(wmaxsmt, m, opt_solver::to_opt(s), m_soft_constraints, m_weights); + m_msolver = alloc(wmaxsmt, m, m_s.get(), m_soft_constraints, m_weights); } else { - m_msolver = alloc(fu_malik, m, s, m_soft_constraints); + m_msolver = alloc(fu_malik, m, *m_s, m_soft_constraints); } } else { - m_msolver = alloc(wmaxsmt, m, opt_solver::to_opt(s), m_soft_constraints, m_weights); + m_msolver = alloc(wmaxsmt, m, m_s.get(), m_soft_constraints, m_weights); } if (m_msolver) { diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 9eb1f66f5..ffcfcab63 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -44,7 +44,7 @@ namespace opt { class maxsmt { ast_manager& m; - opt_solver* m_s; + ref m_s; volatile bool m_cancel; expr_ref_vector m_soft_constraints; expr_ref_vector m_answer; @@ -58,7 +58,7 @@ namespace opt { public: maxsmt(ast_manager& m): m(m), m_s(0), m_cancel(false), m_soft_constraints(m), m_answer(m) {} - lbool operator()(opt_solver& s); + lbool operator()(opt_solver* s); void set_cancel(bool f); diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 45b828b5f..36775aab3 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -194,7 +194,7 @@ namespace opt { lbool context::execute_maxsat(symbol const& id, bool committed) { model_ref tmp; maxsmt& ms = *m_maxsmts.find(id); - lbool result = ms(get_solver()); + lbool result = ms(m_solver.get()); if (result == l_true && committed) ms.commit_assignment(); if (result != l_false && (ms.get_model(tmp), tmp.get())) ms.get_model(m_model); return result; @@ -381,7 +381,7 @@ namespace opt { params_ref lia_p; lia_p.set_bool("compile_equality", optp.pb_compile_equality()); tac3->updt_params(lia_p); - m_simplify = and_then(tac0.get(), tac2.get(), tac3.get(), mk_nnf_tactic(m)); + m_simplify = and_then(tac0.get(), tac2.get(), tac3.get()); } else { m_simplify = tac0.get(); diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 2d2d67320..2fe441f53 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -39,37 +39,48 @@ Notes: namespace opt { - struct wmaxsmt::imp { + + // --------------------------------------------- + // base class with common utilities used + // by maxsmt solvers + // + class maxsmt_solver_base : public maxsmt_solver { + protected: + ref m_s; ast_manager& m; - opt_solver& s; // solver state that contains hard constraints - expr_ref_vector m_soft; // set of soft constraints - vector m_weights; // their weights - svector m_assignment; // truth assignment to soft constrsaints - rational m_upper; // current upper bound for wmaxsmt - rational m_lower; // current lower bound for wmaxsmt - model_ref m_model; // current best model is stored here. - symbol m_engine; // config - bool m_print_all_models; // config - params_ref m_params; // config volatile bool m_cancel; - opt_solver m_solver; // used for recursively calling maxsmt - scoped_ptr m_imp; // - ref m_sat_solver; // used for maxsmt over QF_BV - smt::pb_sls m_sls; // used for sls improvement of assignment - bvsls_opt_engine m_bvsls; // used for bvsls improvements of assignment - + expr_ref_vector m_soft; + vector m_weights; + rational m_lower; + rational m_upper; + model_ref m_model; + ref m_mc; // model converter to remove fresh variables + svector m_assignment; // truth assignment to soft constraints + params_ref m_params; // config + public: + maxsmt_solver_base(solver* s, ast_manager& m): + m_s(s), m(m), m_cancel(false), m_soft(m) {} - imp(ast_manager& m, opt_solver& s, expr_ref_vector const& soft_constraints, vector const& weights): - m(m), s(s), m_soft(soft_constraints), - m_weights(weights), m_print_all_models(false), m_cancel(false), - m_solver(m, m_params, symbol("bound")), - m_sls(m), - m_bvsls(m, m_params) - { - m_assignment.resize(m_soft.size(), false); + virtual ~maxsmt_solver_base() {} + virtual rational get_lower() const { return m_lower; } + virtual rational get_upper() const { return m_upper; } + virtual bool get_assignment(unsigned index) const { return m_assignment[index]; } + virtual void set_cancel(bool f) { m_cancel = f; } + virtual void collect_statistics(statistics& st) const { } + virtual void get_model(model_ref& mdl) { mdl = m_model.get(); } + virtual void updt_params(params_ref& p) { + m_params = p; + s().updt_params(p); + } + void add_soft( + vector const& weights, + expr_ref_vector const& soft) { + m_weights.append(weights); + m_soft.append(soft); } - - ~imp() {} + void add_hard(expr* e){ s().assert_expr(e); } + solver& s() { return *m_s; } + void set_converter(filter_model_converter* mc) { m_mc = mc; } void re_init(expr_ref_vector const& soft, vector const& weights) { m_soft.reset(); @@ -81,474 +92,6 @@ namespace opt { m_lower.reset(); m_upper.reset(); } - - smt::theory_wmaxsat* get_theory() const { - smt::context& ctx = s.get_context(); - smt::theory_id th_id = m.get_family_id("weighted_maxsat"); - smt::theory* th = ctx.get_theory(th_id); - if (th) { - return dynamic_cast(th); - } - else { - return 0; - } - } - - smt::theory_wmaxsat* ensure_theory() { - smt::theory_wmaxsat* wth = get_theory(); - if (wth) { - wth->reset(); - } - else { - wth = alloc(smt::theory_wmaxsat, m, s.mc_ref()); - s.get_context().register_plugin(wth); - } - return wth; - } - - /** - Takes solver with hard constraints added. - Returns a maximal satisfying subset of weighted soft_constraints - that are still consistent with the solver state. - */ - - lbool operator()() { - if (m_engine == symbol("iwmax")) { - return iterative_solve(); - } - if (m_engine == symbol("pwmax")) { - return pb_solve(); - } - if (m_engine == symbol("bvmax")) { - return pb2sat_solve(); - } - if (m_engine == symbol("wpm2")) { - return wpm2_solve(); - } - if (m_engine == symbol("wpm2b")) { - return wpm2b_solve(); - } - if (m_engine == symbol("sls")) { - return sls_solve(); - } - if (m_engine == symbol("bvsls")) { - return bvsls_solve(); - } - if (m_engine == symbol::null || m_engine == symbol("wmax")) { - return incremental_solve(); - } - IF_VERBOSE(0, verbose_stream() << "(unknown engine " << m_engine << " using default 'wmax')\n";); - return incremental_solve(); - } - - rational get_lower() const { - return m_lower; - } - - rational get_upper() const { - return m_upper; - } - - void get_model(model_ref& mdl) { - mdl = m_model.get(); - } - - void set_cancel(bool f) { - if (m_sat_solver) { - m_sat_solver->set_cancel(f); - } - m_sls.set_cancel(f); - m_bvsls.set_cancel(f); - m_cancel = f; - m_solver.set_cancel(f); - m_imp->m_cancel = f; - m_imp->m_solver.set_cancel(f); - } - - void collect_statistics(statistics& st) const { - m_solver.collect_statistics(st); - if (m_sat_solver) { - m_sat_solver->collect_statistics(st); - } - } - - - class scoped_ensure_theory { - smt::theory_wmaxsat* m_wth; - public: - scoped_ensure_theory(imp& i) { - m_wth = i.ensure_theory(); - } - ~scoped_ensure_theory() { - m_wth->reset(); - } - smt::theory_wmaxsat& operator()() { return *m_wth; } - }; - - lbool incremental_solve() { - IF_VERBOSE(3, verbose_stream() << "(incremental solve)\n";); - TRACE("opt", tout << "weighted maxsat\n";); - scoped_ensure_theory wth(*this); - solver::scoped_push _s(s); - lbool is_sat = l_true; - bool was_sat = false; - for (unsigned i = 0; i < m_soft.size(); ++i) { - wth().assert_weighted(m_soft[i].get(), m_weights[i]); - } - - solver::scoped_push __s(s); - while (l_true == is_sat) { - is_sat = s.check_sat_core(0,0); - if (m_cancel) { - is_sat = l_undef; - } - if (is_sat == l_true) { - if (wth().is_optimal()) { - m_upper = wth().get_min_cost(); - updt_model(s); - } - expr_ref fml = wth().mk_block(); - s.assert_expr(fml); - was_sat = true; - } - IF_VERBOSE(3, verbose_stream() << "(incremental bound)\n";); - } - if (was_sat) { - wth().get_assignment(m_assignment); - } - if (is_sat == l_false && was_sat) { - is_sat = l_true; - } - m_upper = wth().get_min_cost(); - if (is_sat == l_true) { - m_lower = m_upper; - } - TRACE("opt", tout << "min cost: " << m_upper << "\n";); - return is_sat; - } - - lbool sls_solve() { - IF_VERBOSE(1, verbose_stream() << "(sls solve)\n";); - for (unsigned i = 0; i < s.get_num_assertions(); ++i) { - m_sls.add(s.get_assertion(i)); - } - pb_util u(m); - expr_ref fml(m), val(m); - app_ref b(m); - expr_ref_vector nsoft(m); - m_lower = m_upper = rational::zero(); - solver::scoped_push __s(s); - for (unsigned i = 0; i < m_soft.size(); ++i) { - m_upper += m_weights[i]; - b = m.mk_fresh_const("b", m.mk_bool_sort()); - s.mc().insert(b->get_decl()); - fml = m.mk_or(m_soft[i].get(), b); - s.assert_expr(fml); - nsoft.push_back(b); - m_sls.add(m_soft[i].get(), m_weights[i]); - } - lbool is_sat = l_true; - bool was_sat = false; - while (l_true == is_sat) { - is_sat = s.check_sat_core(0,0); - if (m_cancel) { - is_sat = l_undef; - } - if (is_sat == l_true) { - updt_model(s); - m_sls.set_model(m_model); - m_upper = rational::zero(); - if (l_true == m_sls()) { - m_sls.get_model(m_model); - for (unsigned i = 0; i < m_soft.size(); ++i) { - m_assignment[i] = m_sls.soft_holds(i); - } - } - else { - for (unsigned i = 0; i < m_soft.size(); ++i) { - VERIFY(m_model->eval(nsoft[i].get(), val)); - m_assignment[i] = !m.is_true(val); - } - } - for (unsigned i = 0; i < m_soft.size(); ++i) { - if (!m_assignment[i]) { - m_upper += m_weights[i]; - } - } - IF_VERBOSE(1, verbose_stream() << "(sls.pb with upper bound: " << m_upper << ")\n";); - fml = m.mk_not(u.mk_ge(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper)); - s.assert_expr(fml); - was_sat = true; - } - } - if (is_sat == l_false && was_sat) { - is_sat = l_true; - m_lower = m_upper; - } - return is_sat; - } - - lbool bvsls_solve() { - IF_VERBOSE(1, verbose_stream() << "(bvsls solve)\n";); - - bv_util bv(m); - pb::card_pb_rewriter pb_rewriter(m); - expr_ref tmp(m), objective(m), zero(m); - expr_ref_vector es(m); - - goal_ref g(alloc(goal, m, true, false)); - for (unsigned i = 0; i < s.get_num_assertions(); ++i) { - pb_rewriter(s.get_assertion(i), tmp); - g->assert_expr(tmp); - } - tactic_ref simplify = mk_nnf_tactic(m); - proof_converter_ref pc; - expr_dependency_ref core(m); - goal_ref_buffer result; - model_converter_ref model_converter; - (*simplify)(g, result, model_converter, pc, core); - SASSERT(result.size() == 1); - goal* r = result[0]; - for (unsigned i = 0; i < r->size(); ++i) { - m_bvsls.assert_expr(r->form(i)); - } - - m_lower = m_upper = rational::zero(); - - for (unsigned i = 0; i < m_soft.size(); ++i) { - m_upper += m_weights[i]; - } - rational num = numerator(m_upper); - rational den = denominator(m_upper); - rational maxval = num*den; - unsigned bv_size = maxval.get_num_bits(); - zero = bv.mk_numeral(rational(0), bv_size); - for (unsigned i = 0; i < m_soft.size(); ++i) { - pb_rewriter(m_soft[i].get(), tmp); - es.push_back(m.mk_ite(tmp, bv.mk_numeral(den*m_weights[i], bv_size), zero)); - } - if (es.empty()) { - objective = bv.mk_numeral(0, bv_size); - } - else { - objective = es[0].get(); - for (unsigned i = 1; i < es.size(); ++i) { - objective = bv.mk_bv_add(objective, es[i].get()); - } - } - lbool is_sat = s.check_sat_core(0, 0); - if (is_sat == l_true) { - updt_model(s); - // TBD: can we set an initial model on m_bvsls? - // CMW: Yes, see next line. - bvsls_opt_engine::optimization_result res = m_bvsls.optimize(objective, m_model, true); - switch (res.is_sat) { - case l_true: { - unsigned bv_size = 0; - m_bvsls.get_model(m_model); - VERIFY(bv.is_numeral(res.optimum, m_lower, bv_size)); - break; - } - case l_false: - case l_undef: - break; - } - return res.is_sat; - } - else - return is_sat; - - } - - /** - Iteratively increase cost until there is an assignment during - final_check that satisfies min_cost. - - Takes: log (n / log(n)) iterations - */ - - lbool iterative_solve() { - scoped_ensure_theory wth(*this); - solver::scoped_push _s(s); - for (unsigned i = 0; i < m_soft.size(); ++i) { - wth().assert_weighted(m_soft[i].get(), m_weights[i]); - } - solver::scoped_push __s(s); - rational cost = wth().get_min_cost(); - rational log_cost(1), tmp(1); - while (tmp < cost) { - ++log_cost; - tmp *= rational(2); - } - expr_ref_vector bounds(m); - expr_ref bound(m); - lbool result = l_false; - unsigned nsc = 0; - m_upper = cost; - while (result == l_false) { - bound = wth().set_min_cost(log_cost); - s.push_core(); - ++nsc; - IF_VERBOSE(1, verbose_stream() << "(wmaxsat.iwmax min cost: " << log_cost << ")\n";); - TRACE("opt", tout << "cost: " << log_cost << " " << bound << "\n";); - bounds.push_back(bound); - result = conditional_solve(bound); - if (result == l_false) { - m_lower = log_cost; - } - if (log_cost > cost) { - break; - } - log_cost *= rational(2); - if (m_cancel) { - result = l_undef; - } - } - s.pop_core(nsc); - return result; - } - - lbool conditional_solve(expr* cond) { - IF_VERBOSE(1, verbose_stream() << "(wmaxsat.conditional solve)\n";); - smt::theory_wmaxsat& wth = *get_theory(); - bool was_sat = false; - lbool is_sat = l_true; - while (l_true == is_sat) { - is_sat = s.check_sat_core(1,&cond); - if (m_cancel) { - is_sat = l_undef; - } - if (is_sat == l_true) { - if (wth.is_optimal()) { - s.get_model(m_model); - was_sat = true; - } - expr_ref fml = wth.mk_block(); - s.assert_expr(fml); - } - } - if (was_sat) { - wth.get_assignment(m_assignment); - } - if (is_sat == l_false && was_sat) { - is_sat = l_true; - } - if (is_sat == l_true) { - m_lower = m_upper = wth.get_min_cost(); - } - TRACE("opt", tout << "min cost: " << m_upper << "\n";); - return is_sat; - } - - - // convert bounds constraint into pseudo-Boolean - lbool pb_solve() { - pb_util u(m); - expr_ref fml(m), val(m); - app_ref b(m); - expr_ref_vector nsoft(m); - m_lower = m_upper = rational::zero(); - solver::scoped_push __s(s); - for (unsigned i = 0; i < m_soft.size(); ++i) { - m_upper += m_weights[i]; - b = m.mk_fresh_const("b", m.mk_bool_sort()); - s.mc().insert(b->get_decl()); - fml = m.mk_or(m_soft[i].get(), b); - s.assert_expr(fml); - nsoft.push_back(b); - } - lbool is_sat = l_true; - bool was_sat = false; - fml = m.mk_true(); - while (l_true == is_sat) { - solver::scoped_push _s(s); - s.assert_expr(fml); - is_sat = s.check_sat_core(0,0); - if (m_cancel) { - is_sat = l_undef; - } - if (is_sat == l_true) { - s.get_model(m_model); - m_upper = rational::zero(); - for (unsigned i = 0; i < m_soft.size(); ++i) { - VERIFY(m_model->eval(nsoft[i].get(), val)); - m_assignment[i] = !m.is_true(val); - if (!m_assignment[i]) { - m_upper += m_weights[i]; - } - } - IF_VERBOSE(1, verbose_stream() << "(wmaxsat.pb with upper bound: " << m_upper << ")\n";); - fml = m.mk_not(u.mk_ge(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper)); - was_sat = true; - } - } - if (is_sat == l_false && was_sat) { - is_sat = l_true; - m_lower = m_upper; - } - return is_sat; - } - - // - // convert bounds constraint into pseudo-Boolean, - // then treat pseudo-Booleans as bit-vectors and - // sorting circuits. - // - lbool pb2sat_solve() { - IF_VERBOSE(1, verbose_stream() << "(wmaxsat.bv solve)\n";); - pb_util u(m); - expr_ref fml(m), val(m); - app_ref b(m); - expr_ref_vector nsoft(m); - m_lower = m_upper = rational::zero(); - tactic_ref pb2bv = mk_card2bv_tactic(m, m_params); - tactic_ref bv2sat = mk_qfbv_tactic(m, m_params); - tactic_ref tac = and_then(pb2bv.get(), bv2sat.get()); - m_sat_solver = mk_tactic2solver(m, tac.get(), m_params); - unsigned sz = s.get_num_assertions(); - for (unsigned i = 0; i < sz; ++i) { - m_sat_solver->assert_expr(s.get_assertion(i)); - } - for (unsigned i = 0; i < m_soft.size(); ++i) { - m_upper += m_weights[i]; - b = m.mk_fresh_const("b", m.mk_bool_sort()); - // TODO: s.mc().insert(b->get_decl()); - fml = m.mk_or(m_soft[i].get(), b); - m_sat_solver->assert_expr(fml); - nsoft.push_back(b); - } - lbool is_sat = l_true; - bool was_sat = false; - fml = m.mk_true(); - while (l_true == is_sat) { - solver::scoped_push __s(*(m_sat_solver)); - m_sat_solver->assert_expr(fml); - is_sat = m_sat_solver->check_sat(0,0); - if (m_cancel) { - is_sat = l_undef; - } - if (is_sat == l_true) { - m_sat_solver->get_model(m_model); - m_upper = rational::zero(); - for (unsigned i = 0; i < m_soft.size(); ++i) { - VERIFY(m_model->eval(nsoft[i].get(), val)); - m_assignment[i] = !m.is_true(val); - if (!m_assignment[i]) { - m_upper += m_weights[i]; - } - } - IF_VERBOSE(1, verbose_stream() << "(wmaxsat.bv with upper bound: " << m_upper << ")\n";); - fml = m.mk_not(u.mk_ge(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper)); - was_sat = true; - } - } - if (is_sat == l_false && was_sat) { - is_sat = l_true; - m_lower = m_upper; - } - return is_sat; - } - expr* mk_not(expr* e) { if (m.is_not(e, e)) { return e; @@ -557,9 +100,206 @@ namespace opt { return m.mk_not(e); } } + }; - lbool pb_simplify_solve() { - TRACE("opt", s.display(tout); tout << "\n"; + // ------------------------------------------------------ + // Morgado, Heras, Marques-Silva 2013 + // (initial version without model-based optimizations) + // + class bcd2 : public maxsmt_solver_base { + struct wcore { + unsigned_vector m_R; + rational m_lower; + rational m_mid; + rational m_upper; + }; + public: + bcd2(solver* s, ast_manager& m): + maxsmt_solver_base(s, m) {} + + virtual ~bcd2() {} + + + virtual lbool operator()() { + expr_ref fml(m), val(m); + app_ref r(m); + vector cores; + obj_map ans2core; // answer literal to core index + lbool is_sat = l_undef; + expr_ref_vector rs(m), asms(m); + m_lower = m_upper = rational::zero(); // current upper and lower bounds + vector sigmas; // sigma_j := w_j if soft clause has not been satisfied + bool first = true; + for (unsigned i = 0; i < m_soft.size(); ++i) { + m_upper += m_weights[i]; + r = m.mk_fresh_const("r", m.mk_bool_sort()); + if (m_mc) { + m_mc->insert(r->get_decl()); + } + fml = m.mk_or(m_soft[i].get(), r); + s().assert_expr(fml); // does not get asserted in model-based mode. + rs.push_back(r); + asms.push_back(m.mk_not(r)); + sigmas.push_back(m_weights[i]); + m_assignment.push_back(false); + } + m_upper += rational(1); + solver::scoped_push _s(s()); + while (m_lower < m_upper) { + solver::scoped_push __s(s()); + if (m_cancel) { + return l_undef; + } + for (unsigned i = 0; i < cores.size(); ++i) { + assert_core(cores[i]); + NOT_IMPLEMENTED_YET(); + // need assumptions here as well. + } + is_sat = s().check_sat(asms.size(), asms.c_ptr()); + switch(is_sat) { + case l_undef: + return l_undef; + case l_true: { + s().get_model(m_model); + m_upper.reset(); + for (unsigned i = 0; i < m_soft.size(); ++i) { + VERIFY(m_model->eval(m_soft[i].get(), val)); + m_assignment[i] = m.is_true(val); + } + for (unsigned i = 0; i < cores.size(); ++i) { + wcore& c_i = cores[i]; + unsigned_vector const& R = c_i.m_R; + c_i.m_upper.reset(); + for (unsigned j = 0; j core; + uint_set subC, soft; + rational delta(0), lower(0); + wcore c_s; + s().get_unsat_core(core); + core2indices(core, ans2core, subC, soft); + for (uint_set::iterator it = subC.begin(); it != subC.end(); ++it) { + unsigned j = *it; + c_s.m_R.push_back(j); + lower += cores[j].m_lower; + rational new_delta = rational(1) + cores[j].m_upper - cores[j].m_mid; + SASSERT(new_delta.is_pos()); + if (delta.is_zero() || delta > new_delta) { + delta = new_delta; + } + } + if (soft.num_elems() == 0 && subC.num_elems() == 1) { + SASSERT(core.size() == 1); + unsigned s = *subC.begin(); + wcore& c_s = cores[s]; + c_s.m_lower = refine(c_s.m_R, c_s.m_mid); + } + else { + relax(subC, soft, c_s.m_R, delta); + c_s.m_lower = refine(c_s.m_R, lower + delta - rational(1)); + c_s.m_upper = rational(first?0:1); + for (unsigned i = 0; i < c_s.m_R.size(); ++i) { + c_s.m_upper += sigmas[c_s.m_R[i]]; + } + c_s.m_mid = div(c_s.m_lower + c_s.m_upper, rational(2)); + subtract(cores, subC); + cores.push_back(c_s); + } + break; + } + } + m_lower = compute_lower(cores); + } + return is_sat; + } + + + private: + rational compute_lower(vector const& cores) { + rational result(0); + for (unsigned i = 0; i < cores.size(); ++i) { + result += cores[i].m_lower; + } + return result; + } + + void subtract(vector& cores, uint_set const& subC) { + unsigned j = 0; + for (unsigned i = 0; i < cores.size(); ++i) { + if (!subC.contains(i)) { + if (j != i) { + cores[j] = cores[i]; + } + ++j; + } + } + cores.resize(j); + } + + void core2indices( + ptr_vector const& core, + obj_map const& ans2core, + uint_set& subC, + uint_set& soft) + { + for (unsigned i = 0; i < core.size(); ++i) { + unsigned j; + if (ans2core.find(core[i], j)) { + subC.insert(j); + } + else { + soft.insert(i); + } + } + } + + rational refine(unsigned_vector const& idx, rational v) { + return v + rational(1); + } + + void relax(uint_set& subC, uint_set& soft, unsigned_vector& R, rational& delta) { + NOT_IMPLEMENTED_YET(); + } + + void assert_core(wcore const& core) { + expr_ref fml(m); + vector ws; + ptr_vector rs; + for (unsigned j = 0; j < core.m_R.size(); ++j) { + unsigned idx = core.m_R[j]; + ws.push_back(m_weights[idx]); + rs.push_back(m_soft[idx].get()); // TBD: check + } + // TBD: fml = pb.mk_le(ws.size(), ws.c_ptr(), rs.c_ptr(), core.m_mid); + NOT_IMPLEMENTED_YET(); + s().assert_expr(fml); + } + }; + + class pb_simplify_solve : public maxsmt_solver_base { + public: + pb_simplify_solve(solver* s, ast_manager& m): + maxsmt_solver_base(s, m) {} + + virtual ~pb_simplify_solve() {} + + lbool operator()() { + TRACE("opt", s().display(tout); tout << "\n"; for (unsigned i = 0; i < m_soft.size(); ++i) { tout << mk_pp(m_soft[i].get(), m) << " " << m_weights[i] << "\n"; } @@ -572,14 +312,14 @@ namespace opt { m_upper += m_weights[i]; nsoft.push_back(mk_not(m_soft[i].get())); } - solver::scoped_push _s1(s); + solver::scoped_push _s1(s()); lbool is_sat = l_true; bool was_sat = false; fml = m.mk_true(); while (l_true == is_sat) { - TRACE("opt", s.display(tout<<"looping\n");); - solver::scoped_push _s2(s); - s.assert_expr(fml); + TRACE("opt", s().display(tout<<"looping\n");); + solver::scoped_push _s2(s()); + s().assert_expr(fml); is_sat = simplify_and_check_sat(0,0); if (m_cancel) { is_sat = l_undef; @@ -608,132 +348,64 @@ namespace opt { return is_sat; } - // ------------------------------------------------------ - // Morgado, Heras, Marques-Silva 2013 - - struct wcore { - unsigned_vector m_R; - rational m_lower; - rational m_mid; - rational m_upper; - }; - - lbool bcd2_solve() { - return l_undef; -#if 0 - expr_ref fml(m), val(m); - app_ref r(m); - vector cores; - obj_map ans2core; // answer literal to core index - lbool is_sat = l_undef; - expr_ref_vector soft(m), rs(m); - m_lower = m_upper = rational::zero(); - bool first = true; - for (unsigned i = 0; i < m_soft.size(); ++i) { - m_upper += m_weights[i]; - r = m.mk_fresh_const("r", m.mk_bool_sort()); - s.mc().insert(r->get_decl()); - fml = m.mk_or(m_soft[i].get(), r); - s.assert_expr(fml); - rs.push_back(r); - asms.push_back(m.mk_not(r)); + private: + lbool simplify_and_check_sat(unsigned n, expr* const* assumptions) { + lbool is_sat = l_true; + tactic_ref tac1 = mk_simplify_tactic(m); + // tactic_ref tac2 = mk_pb_preprocess_tactic(m); + tactic_ref tac = tac1; // and_then(tac1.get(), tac2.get()); // TBD: make attribute for cancelation. + proof_converter_ref pc; + expr_dependency_ref core(m); + model_converter_ref mc; + goal_ref_buffer result; + goal_ref g(alloc(goal, m, true, false)); + for (unsigned i = 0; i < s().get_num_assertions(); ++i) { + g->assert_expr(s().get_assertion(i)); } - m_upper += rational(1); - solver::scoped_push _s(s); - while (m_lower < m_upper) { - solver::scoped_push _s(s); - if (m_cancel) { - return l_undef; - } - for (unsigned i = 0; i < cores.size(); ++i) { - assert_core(cores[i]); - // need assumptions here as well. - } - is_sat = check_sat(asms.size(), asms.c_ptr()); - switch(is_sat) { - case l_undef: - return l_undef; - case l_true: { - updt_model(s); - m_upper.reset(); - for (unsigned i = 0; i < cores.size(); ++i) { - wcore& c_i = cores[i]; - unsigned_vector const& R = c_i.m_R; - c_i.m_upper.reset(); - for (unsigned j = 0; j < R.size(); ++j) { - unsigned r_j = R[j]; - VERIFY(m_model->eval(m_soft[r_j].get(), val)); - if (m.is_false(val)) { - c_i.m_upper += m_weights[r_j]; - } - } - c_i.m_mid = div(c_i.m_lower + c_i.m_upper, rational(2)); - m_upper += c_i.m_upper; - } - first = false; - break; - } - case l_false: { - ptr_vector core; - s.get_unsat_core(core); - uint_set subC; - unsigned_vector soft; - rational delta(0); - for (unsigned i = 0; i < core.size(); ++i) { - unsigned j; - if (ans2core.find(core[i], j)) { - subC.insert(j); - rational new_delta = rational(1) + cores[j].m_upper - cores[j].m_mid; - SASSERT(new_delta.is_pos()); - if (delta.is_zero() || delta > new_delta) { - delta = new_delta; - } - } - else { - soft.push_back(i); - } - } - if (soft.empty() && subC.num_elems() == 1) { - SASSERT(core.size() == 1); - unsigned s = *subS.begin(); - wcore& c_s = cores[s]; - m_lower -= c_s.m_lower; - c_s.m_lower = refine(c_s, c_s.m_mid); - m_lower += c_s.m_lower; - } - else { - wcore c_s; - relax(subC, soft, c_s.m_R); - for (unsigned i = 0; i < subC.size(); ++i) { - - } - } - break; + for (unsigned i = 0; i < n; ++i) { + NOT_IMPLEMENTED_YET(); + // add assumption in a wrapper. + } + (*tac)(g, result, mc, pc, core); + if (result.empty()) { + is_sat = l_false; + } + else { + SASSERT(result.size() == 1); + goal_ref r = result[0]; + solver::scoped_push _s(s()); + // TBD ptr_vector asms; + for (unsigned i = 0; i < r->size(); ++i) { + // TBD collect assumptions from r + s().assert_expr(r->form(i)); } + is_sat = s().check_sat(0, 0); + if (l_true == is_sat && !m_cancel) { + s().get_model(m_model); + if (mc && m_model) (*mc)(m_model, 0); + IF_VERBOSE(2, + g->display(verbose_stream() << "goal:\n"); + r->display(verbose_stream() << "reduced:\n"); + model_smt2_pp(verbose_stream(), m, *m_model, 0);); } } return is_sat; -#endif } + }; - void assert_core(wcore const& core) { - expr_ref fml(m); - vector ws; - ptr_vector rs; - for (unsigned j = 0; j < core.m_R.size(); ++j) { - unsigned idx = core.m_R[j]; - ws.push_back(m_weights[idx]); - rs.push_back(m_soft[idx].get()); // TBD: check - } - // TBD: fml = pb.mk_le(ws.size(), ws.c_ptr(), rs.c_ptr(), core.m_mid); - s.assert_expr(fml); - } + // ------------------------------------------------------ + // AAAI 2010 + class wpm2 : public maxsmt_solver_base { + scoped_ptr maxs; + public: + wpm2(solver* s, ast_manager& m, maxsmt_solver_base* maxs): + maxsmt_solver_base(s, m), maxs(maxs) {} - // ------------------------------------------------------ - // AAAI 2010 - lbool wpm2_solve() { + virtual ~wpm2() {} + + lbool operator()() { IF_VERBOSE(1, verbose_stream() << "(wmaxsat.wpm2 solve)\n";); - solver::scoped_push _s(s); + solver::scoped_push _s(s()); pb_util u(m); app_ref fml(m), a(m), b(m), c(m); expr_ref val(m); @@ -748,21 +420,21 @@ namespace opt { m_upper += w; b = m.mk_fresh_const("b", m.mk_bool_sort()); - s.mc().insert(b->get_decl()); + m_mc->insert(b->get_decl()); block.push_back(b); expr* bb = b; a = m.mk_fresh_const("a", m.mk_bool_sort()); - s.mc().insert(a->get_decl()); + m_mc->insert(a->get_decl()); ans.push_back(a); ans_index.insert(a, i); fml = m.mk_or(m_soft[i].get(), b, m.mk_not(a)); - s.assert_expr(fml); + s().assert_expr(fml); c = m.mk_fresh_const("c", m.mk_bool_sort()); - s.mc().insert(c->get_decl()); + m_mc->insert(c->get_decl()); fml = m.mk_implies(c, u.mk_le(1,&w,&bb,rational(0))); - s.assert_expr(fml); + s().assert_expr(fml); sc.push_back(uint_set()); sc.back().insert(i); @@ -775,7 +447,7 @@ namespace opt { ptr_vector core; asms.append(ans); asms.append(am); - lbool is_sat = s.check_sat(asms.size(), asms.c_ptr()); + lbool is_sat = s().check_sat(asms.size(), asms.c_ptr()); TRACE("opt", tout << "\nassumptions: "; for (unsigned i = 0; i < asms.size(); ++i) { @@ -786,7 +458,7 @@ namespace opt { tout << "lower: " << m_lower << "\n"; if (is_sat == l_true) { model_ref mdl; - s.get_model(mdl); + s().get_model(mdl); model_smt2_pp(tout, m, *(mdl.get()), 0); }); @@ -795,7 +467,7 @@ namespace opt { } if (is_sat == l_true) { m_upper = m_lower; - updt_model(s); + s().get_model(m_model); for (unsigned i = 0; i < block.size(); ++i) { VERIFY(m_model->eval(m_soft[i].get(), val)); TRACE("opt", tout << mk_pp(block[i].get(), m) << " " << val << "\n";); @@ -805,7 +477,7 @@ namespace opt { if (is_sat != l_false) { return is_sat; } - s.get_unsat_core(core); + s().get_unsat_core(core); if (core.empty()) { return l_false; } @@ -863,21 +535,643 @@ namespace opt { expr_ref B_le_k(m), B_ge_k(m); B_le_k = u.mk_le(ws.size(), ws.c_ptr(), bs.c_ptr(), k); B_ge_k = u.mk_ge(ws.size(), ws.c_ptr(), bs.c_ptr(), k); - s.assert_expr(B_ge_k); + s().assert_expr(B_ge_k); al.push_back(B_ge_k); IF_VERBOSE(1, verbose_stream() << "(wmaxsat.wpm2 lower bound: " << m_lower << ")\n";); IF_VERBOSE(2, verbose_stream() << "New lower bound: " << B_ge_k << "\n";); c = m.mk_fresh_const("c", m.mk_bool_sort()); - s.mc().insert(c->get_decl()); + m_mc->insert(c->get_decl()); fml = m.mk_implies(c, B_le_k); - s.assert_expr(fml); + s().assert_expr(fml); sc.push_back(B); am.push_back(c); amk.push_back(k); } } + private: + lbool new_bound(expr_ref_vector const& al, + vector const& ws, + expr_ref_vector const& bs, + rational& k) { + pb_util u(m); + expr_ref_vector al2(m); + al2.append(al); + // w_j*b_j > k + al2.push_back(m.mk_not(u.mk_le(ws.size(), ws.c_ptr(), bs.c_ptr(), k))); + return bound(al2, ws, bs, k); + } + + // + // minimal k, such that al & w_j*b_j >= k is sat + // minimal k, such that al & 3*x + 4*y >= k is sat + // minimal k, such that al & (or (not x) w3) & (or (not y) w4) + // + lbool bound(expr_ref_vector const& al, + vector const& ws, + expr_ref_vector const& bs, + rational& k) { + expr_ref_vector nbs(m); + opt_solver::scoped_push _sc(maxs->s()); + for (unsigned i = 0; i < al.size(); ++i) { + maxs->add_hard(al[i]); + } + for (unsigned i = 0; i < bs.size(); ++i) { + nbs.push_back(mk_not(bs[i])); + } + TRACE("opt", + maxs->s().display(tout); + tout << "\n"; + for (unsigned i = 0; i < bs.size(); ++i) { + tout << mk_pp(bs[i], m) << " " << ws[i] << "\n"; + }); + maxs->re_init(nbs, ws); + lbool is_sat = (*maxs)(); + SASSERT(maxs->get_lower() > k); + k = maxs->get_lower(); + return is_sat; + } + }; + + class sls : public maxsmt_solver_base { + smt::pb_sls m_sls; // used for sls improvement of assignment + public: + sls(solver* s, ast_manager& m): maxsmt_solver_base(s, m), m_sls(m) {} + virtual ~sls() {} + lbool operator()() { + IF_VERBOSE(1, verbose_stream() << "(sls solve)\n";); + for (unsigned i = 0; i < s().get_num_assertions(); ++i) { + m_sls.add(s().get_assertion(i)); + } + pb_util u(m); + expr_ref fml(m), val(m); + app_ref b(m); + expr_ref_vector nsoft(m); + m_lower = m_upper = rational::zero(); + solver::scoped_push __s(s()); + for (unsigned i = 0; i < m_soft.size(); ++i) { + m_upper += m_weights[i]; + b = m.mk_fresh_const("b", m.mk_bool_sort()); + m_mc->insert(b->get_decl()); + fml = m.mk_or(m_soft[i].get(), b); + s().assert_expr(fml); + nsoft.push_back(b); + m_sls.add(m_soft[i].get(), m_weights[i]); + } + lbool is_sat = l_true; + bool was_sat = false; + while (l_true == is_sat) { + is_sat = s().check_sat(0,0); + if (m_cancel) { + is_sat = l_undef; + } + if (is_sat == l_true) { + s().get_model(m_model); + m_sls.set_model(m_model); + m_upper = rational::zero(); + if (l_true == m_sls()) { + m_sls.get_model(m_model); + for (unsigned i = 0; i < m_soft.size(); ++i) { + m_assignment[i] = m_sls.soft_holds(i); + } + } + else { + for (unsigned i = 0; i < m_soft.size(); ++i) { + VERIFY(m_model->eval(nsoft[i].get(), val)); + m_assignment[i] = !m.is_true(val); + } + } + for (unsigned i = 0; i < m_soft.size(); ++i) { + if (!m_assignment[i]) { + m_upper += m_weights[i]; + } + } + IF_VERBOSE(1, verbose_stream() << "(sls.pb with upper bound: " << m_upper << ")\n";); + fml = m.mk_not(u.mk_ge(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper)); + s().assert_expr(fml); + was_sat = true; + } + } + if (is_sat == l_false && was_sat) { + is_sat = l_true; + m_lower = m_upper; + } + return is_sat; + } + + virtual void set_cancel(bool f) { + m_sls.set_cancel(f); + } + }; + + class bvsls : public maxsmt_solver_base { + bvsls_opt_engine m_bvsls; // used for bvsls improvements of assignment + public: + bvsls(solver* s, ast_manager& m): + maxsmt_solver_base(s, m), + m_bvsls(m, m_params) {} + virtual ~bvsls() {} + lbool operator()() { + IF_VERBOSE(1, verbose_stream() << "(bvsls solve)\n";); + + bv_util bv(m); + pb::card_pb_rewriter pb_rewriter(m); + expr_ref tmp(m), objective(m), zero(m); + expr_ref_vector es(m); + + goal_ref g(alloc(goal, m, true, false)); + for (unsigned i = 0; i < s().get_num_assertions(); ++i) { + pb_rewriter(s().get_assertion(i), tmp); + g->assert_expr(tmp); + } + tactic_ref simplify = mk_nnf_tactic(m); + proof_converter_ref pc; + expr_dependency_ref core(m); + goal_ref_buffer result; + model_converter_ref model_converter; + (*simplify)(g, result, model_converter, pc, core); + SASSERT(result.size() == 1); + goal* r = result[0]; + for (unsigned i = 0; i < r->size(); ++i) { + m_bvsls.assert_expr(r->form(i)); + } + + m_lower = m_upper = rational::zero(); + + for (unsigned i = 0; i < m_soft.size(); ++i) { + m_upper += m_weights[i]; + } + rational num = numerator(m_upper); + rational den = denominator(m_upper); + rational maxval = num*den; + unsigned bv_size = maxval.get_num_bits(); + zero = bv.mk_numeral(rational(0), bv_size); + for (unsigned i = 0; i < m_soft.size(); ++i) { + pb_rewriter(m_soft[i].get(), tmp); + es.push_back(m.mk_ite(tmp, bv.mk_numeral(den*m_weights[i], bv_size), zero)); + } + if (es.empty()) { + objective = bv.mk_numeral(0, bv_size); + } + else { + objective = es[0].get(); + for (unsigned i = 1; i < es.size(); ++i) { + objective = bv.mk_bv_add(objective, es[i].get()); + } + } + lbool is_sat = s().check_sat(0, 0); + if (is_sat == l_true) { + s().get_model(m_model); + bvsls_opt_engine::optimization_result res = m_bvsls.optimize(objective, m_model, true); + switch (res.is_sat) { + case l_true: { + unsigned bv_size = 0; + m_bvsls.get_model(m_model); + VERIFY(bv.is_numeral(res.optimum, m_lower, bv_size)); + break; + } + case l_false: + case l_undef: + break; + } + return res.is_sat; + } + else { + return is_sat; + } + } + virtual void set_cancel(bool f) { + m_bvsls.set_cancel(f); + } + + }; + + + class maxsmt_solver_wbase : public maxsmt_solver_base { + smt::context& ctx; + public: + maxsmt_solver_wbase(solver* s, ast_manager& m, smt::context& ctx): + maxsmt_solver_base(s, m), ctx(ctx) {} + ~maxsmt_solver_wbase() {} + + class scoped_ensure_theory { + smt::theory_wmaxsat* m_wth; + public: + scoped_ensure_theory(maxsmt_solver_wbase& s) { + m_wth = s.ensure_theory(); + } + ~scoped_ensure_theory() { + m_wth->reset(); + } + smt::theory_wmaxsat& operator()() { return *m_wth; } + }; + smt::theory_wmaxsat* ensure_theory() { + smt::theory_wmaxsat* wth = get_theory(); + if (wth) { + wth->reset(); + } + else { + wth = alloc(smt::theory_wmaxsat, m, m_mc); + ctx.register_plugin(wth); + } + return wth; + } + smt::theory_wmaxsat* get_theory() const { + smt::theory_id th_id = m.get_family_id("weighted_maxsat"); + smt::theory* th = ctx.get_theory(th_id); + if (th) { + return dynamic_cast(th); + } + else { + return 0; + } + } + }; + /** + Iteratively increase cost until there is an assignment during + final_check that satisfies min_cost. + + Takes: log (n / log(n)) iterations + */ + + class iwmax : public maxsmt_solver_wbase { + public: + + iwmax(solver* s, ast_manager& m, smt::context& ctx): maxsmt_solver_wbase(s, m, ctx) {} + virtual ~iwmax() {} + + lbool operator()() { + scoped_ensure_theory wth(*this); + solver::scoped_push _s(s()); + for (unsigned i = 0; i < m_soft.size(); ++i) { + wth().assert_weighted(m_soft[i].get(), m_weights[i]); + } + solver::scoped_push __s(s()); + rational cost = wth().get_min_cost(); + rational log_cost(1), tmp(1); + while (tmp < cost) { + ++log_cost; + tmp *= rational(2); + } + expr_ref_vector bounds(m); + expr_ref bound(m); + lbool result = l_false; + unsigned nsc = 0; + m_upper = cost; + while (result == l_false) { + bound = wth().set_min_cost(log_cost); + s().push(); + ++nsc; + IF_VERBOSE(1, verbose_stream() << "(wmaxsat.iwmax min cost: " << log_cost << ")\n";); + TRACE("opt", tout << "cost: " << log_cost << " " << bound << "\n";); + bounds.push_back(bound); + result = conditional_solve(bound); + if (result == l_false) { + m_lower = log_cost; + } + if (log_cost > cost) { + break; + } + log_cost *= rational(2); + if (m_cancel) { + result = l_undef; + } + } + s().pop(nsc); + return result; + } + private: + lbool conditional_solve(expr* cond) { + IF_VERBOSE(1, verbose_stream() << "(wmaxsat.conditional solve)\n";); + smt::theory_wmaxsat& wth = *get_theory(); + bool was_sat = false; + lbool is_sat = l_true; + while (l_true == is_sat) { + is_sat = s().check_sat(1,&cond); + if (m_cancel) { + is_sat = l_undef; + } + if (is_sat == l_true) { + if (wth.is_optimal()) { + s().get_model(m_model); + was_sat = true; + } + expr_ref fml = wth.mk_block(); + s().assert_expr(fml); + } + } + if (was_sat) { + wth.get_assignment(m_assignment); + } + if (is_sat == l_false && was_sat) { + is_sat = l_true; + } + if (is_sat == l_true) { + m_lower = m_upper = wth.get_min_cost(); + } + TRACE("opt", tout << "min cost: " << m_upper << "\n";); + return is_sat; + } + + }; + + class wmax : public maxsmt_solver_wbase { + public: + wmax(solver* s, ast_manager& m, smt::context& ctx): maxsmt_solver_wbase(s, m, ctx) {} + virtual ~wmax() {} + + lbool operator()() { + IF_VERBOSE(3, verbose_stream() << "(incremental solve)\n";); + TRACE("opt", tout << "weighted maxsat\n";); + scoped_ensure_theory wth(*this); + solver::scoped_push _s(s()); + lbool is_sat = l_true; + bool was_sat = false; + for (unsigned i = 0; i < m_soft.size(); ++i) { + wth().assert_weighted(m_soft[i].get(), m_weights[i]); + } + + solver::scoped_push __s(s()); + while (l_true == is_sat) { + is_sat = s().check_sat(0,0); + if (m_cancel) { + is_sat = l_undef; + } + if (is_sat == l_true) { + if (wth().is_optimal()) { + m_upper = wth().get_min_cost(); + s().get_model(m_model); + } + expr_ref fml = wth().mk_block(); + s().assert_expr(fml); + was_sat = true; + } + IF_VERBOSE(3, verbose_stream() << "(incremental bound)\n";); + } + if (was_sat) { + wth().get_assignment(m_assignment); + } + if (is_sat == l_false && was_sat) { + is_sat = l_true; + } + m_upper = wth().get_min_cost(); + if (is_sat == l_true) { + m_lower = m_upper; + } + TRACE("opt", tout << "min cost: " << m_upper << "\n";); + return is_sat; + } + }; + + class bvmax : public maxsmt_solver_base { + solver* mk_sat_solver(solver* s) { + tactic_ref pb2bv = mk_card2bv_tactic(m, m_params); + tactic_ref bv2sat = mk_qfbv_tactic(m, m_params); + tactic_ref tac = and_then(pb2bv.get(), bv2sat.get()); + solver* sat_solver = mk_tactic2solver(m, tac.get(), m_params); + unsigned sz = s->get_num_assertions(); + for (unsigned i = 0; i < sz; ++i) { + sat_solver->assert_expr(s->get_assertion(i)); + } + return sat_solver; + } + public: + bvmax(solver* s, ast_manager& m): maxsmt_solver_base(mk_sat_solver(s), m) {} + virtual ~bvmax() {} + + // + // convert bounds constraint into pseudo-Boolean, + // then treat pseudo-Booleans as bit-vectors and + // sorting circuits. + // + lbool operator()() { + IF_VERBOSE(1, verbose_stream() << "(wmaxsat.bv solve)\n";); + pb_util u(m); + expr_ref fml(m), val(m); + app_ref b(m); + expr_ref_vector nsoft(m); + m_lower = m_upper = rational::zero(); + for (unsigned i = 0; i < m_soft.size(); ++i) { + m_upper += m_weights[i]; + b = m.mk_fresh_const("b", m.mk_bool_sort()); + m_mc->insert(b->get_decl()); + fml = m.mk_or(m_soft[i].get(), b); + s().assert_expr(fml); + nsoft.push_back(b); + } + lbool is_sat = l_true; + bool was_sat = false; + fml = m.mk_true(); + while (l_true == is_sat) { + solver::scoped_push __s(s()); + s().assert_expr(fml); + is_sat = s().check_sat(0,0); + if (m_cancel) { + is_sat = l_undef; + } + if (is_sat == l_true) { + s().get_model(m_model); + m_upper = rational::zero(); + for (unsigned i = 0; i < m_soft.size(); ++i) { + VERIFY(m_model->eval(nsoft[i].get(), val)); + m_assignment[i] = !m.is_true(val); + if (!m_assignment[i]) { + m_upper += m_weights[i]; + } + } + IF_VERBOSE(1, verbose_stream() << "(wmaxsat.bv with upper bound: " << m_upper << ")\n";); + fml = m.mk_not(u.mk_ge(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper)); + was_sat = true; + } + } + if (is_sat == l_false && was_sat) { + is_sat = l_true; + m_lower = m_upper; + } + return is_sat; + } + + }; + + class pwmax : public maxsmt_solver_base { + public: + pwmax(solver* s, ast_manager& m): maxsmt_solver_base(s, m) {} + virtual ~pwmax() {} + lbool operator()() { + pb_util u(m); + expr_ref fml(m), val(m); + app_ref b(m); + expr_ref_vector nsoft(m); + m_lower = m_upper = rational::zero(); + solver::scoped_push __s(s()); + for (unsigned i = 0; i < m_soft.size(); ++i) { + m_upper += m_weights[i]; + b = m.mk_fresh_const("b", m.mk_bool_sort()); + m_mc->insert(b->get_decl()); + fml = m.mk_or(m_soft[i].get(), b); + s().assert_expr(fml); + nsoft.push_back(b); + } + lbool is_sat = l_true; + bool was_sat = false; + fml = m.mk_true(); + while (l_true == is_sat) { + solver::scoped_push _s(s()); + s().assert_expr(fml); + is_sat = s().check_sat(0,0); + if (m_cancel) { + is_sat = l_undef; + } + if (is_sat == l_true) { + s().get_model(m_model); + m_upper = rational::zero(); + for (unsigned i = 0; i < m_soft.size(); ++i) { + VERIFY(m_model->eval(nsoft[i].get(), val)); + m_assignment[i] = !m.is_true(val); + if (!m_assignment[i]) { + m_upper += m_weights[i]; + } + } + IF_VERBOSE(1, verbose_stream() << "(wmaxsat.pb with upper bound: " << m_upper << ")\n";); + fml = m.mk_not(u.mk_ge(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper)); + was_sat = true; + } + } + if (is_sat == l_false && was_sat) { + is_sat = l_true; + m_lower = m_upper; + } + return is_sat; + } + + }; + + struct wmaxsmt::imp { + ast_manager& m; + ref s; // solver state that contains hard constraints + expr_ref_vector m_soft; // set of soft constraints + vector m_weights; // their weights + symbol m_engine; // config + mutable params_ref m_params; // config + mutable scoped_ptr m_maxsmt; // underlying maxsmt solver + + imp(ast_manager& m, + opt_solver* s, + expr_ref_vector const& soft_constraints, + vector const& weights): + m(m), + s(s), + m_soft(soft_constraints), + m_weights(weights) + { + } + + maxsmt_solver_base& maxsmt() const { + if (m_maxsmt) { + return *m_maxsmt; + } + if (m_engine == symbol("iwmax")) { + m_maxsmt = alloc(iwmax, s.get(), m, s->get_context()); + } + else if (m_engine == symbol("pwmax")) { + m_maxsmt = alloc(pwmax, s.get(), m); + } + else if (m_engine == symbol("bvmax")) { + m_maxsmt = alloc(bvmax, s.get(), m); + } + else if (m_engine == symbol("wpm2")) { + maxsmt_solver_base* s2 = alloc(pb_simplify_solve, s.get(), m); + m_maxsmt = alloc(wpm2, s.get(), m, s2); + } + else if (m_engine == symbol("bvsls")) { + m_maxsmt = alloc(bvsls, s.get(), m); + } + else if (m_engine == symbol::null || m_engine == symbol("wmax")) { + m_maxsmt = alloc(wmax, s.get(), m, s->get_context()); + } + else { + IF_VERBOSE(0, verbose_stream() << "(unknown engine " << m_engine << " using default 'wmax')\n";); + m_maxsmt = alloc(wmax, s.get(), m, s->get_context()); + } + m_maxsmt->updt_params(m_params); + m_maxsmt->add_soft(m_weights, m_soft); + m_maxsmt->set_converter(s->mc_ref().get()); + return *m_maxsmt; + } + + ~imp() {} + + /** + Takes solver with hard constraints added. + Returns a maximal satisfying subset of weighted soft_constraints + that are still consistent with the solver state. + */ + lbool operator()() { + return maxsmt()(); + } + rational get_lower() const { + return maxsmt().get_lower(); + } + rational get_upper() const { + return maxsmt().get_upper(); + } + void get_model(model_ref& mdl) { + if (m_maxsmt) m_maxsmt->get_model(mdl); + } + void set_cancel(bool f) { + if (m_maxsmt) m_maxsmt->set_cancel(f); + } + bool get_assignment(unsigned index) const { + return maxsmt().get_assignment(index); + } + void collect_statistics(statistics& st) const { + if (m_maxsmt) m_maxsmt->collect_statistics(st); + } + void updt_params(params_ref& p) { + opt_params _p(p); + m_engine = _p.wmaxsat_engine(); + m_maxsmt = 0; + } + }; + + wmaxsmt::wmaxsmt(ast_manager& m, + opt_solver* s, + expr_ref_vector& soft_constraints, + vector const& weights) { + m_imp = alloc(imp, m, s, soft_constraints, weights); + } + wmaxsmt::~wmaxsmt() { + dealloc(m_imp); + } + lbool wmaxsmt::operator()() { + return (*m_imp)(); + } + rational wmaxsmt::get_lower() const { + return m_imp->get_lower(); + } + rational wmaxsmt::get_upper() const { + return m_imp->get_upper(); + } + bool wmaxsmt::get_assignment(unsigned idx) const { + return m_imp->get_assignment(idx); + } + void wmaxsmt::set_cancel(bool f) { + m_imp->set_cancel(f); + } + void wmaxsmt::collect_statistics(statistics& st) const { + m_imp->collect_statistics(st); + } + void wmaxsmt::get_model(model_ref& mdl) { + m_imp->get_model(mdl); + } + void wmaxsmt::updt_params(params_ref& p) { + m_imp->updt_params(p); + } +}; + + +#if 0 // ------------------------------------------------------ // Version from CP'13 lbool wpm2b_solve() { @@ -929,7 +1223,7 @@ namespace opt { expr_ref_vector asms(m); asms.append(ans); asms.append(am); - lbool is_sat = s.check_sat(asms.size(), asms.c_ptr()); + lbool is_sat = s().check_sat(asms.size(), asms.c_ptr()); if (m_cancel && is_sat != l_false) { is_sat = l_undef; } @@ -1052,159 +1346,6 @@ namespace opt { } } - lbool new_bound(expr_ref_vector const& al, - vector const& ws, - expr_ref_vector const& bs, - rational& k) { - pb_util u(m); - expr_ref_vector al2(m); - al2.append(al); - // w_j*b_j > k - al2.push_back(m.mk_not(u.mk_le(ws.size(), ws.c_ptr(), bs.c_ptr(), k))); - return bound(al2, ws, bs, k); - } - // - // minimal k, such that al & w_j*b_j >= k is sat - // minimal k, such that al & 3*x + 4*y >= k is sat - // minimal k, such that al & (or (not x) w3) & (or (not y) w4) - // - lbool bound(expr_ref_vector const& al, - vector const& ws, - expr_ref_vector const& bs, - rational& k) { - expr_ref_vector nbs(m); - opt_solver::scoped_push _sc(m_solver); - for (unsigned i = 0; i < al.size(); ++i) { - m_solver.assert_expr(al[i]); - } - for (unsigned i = 0; i < bs.size(); ++i) { - nbs.push_back(mk_not(bs[i])); - } - TRACE("opt", - m_solver.display(tout); - tout << "\n"; - for (unsigned i = 0; i < bs.size(); ++i) { - tout << mk_pp(bs[i], m) << " " << ws[i] << "\n"; - }); - m_imp->re_init(nbs, ws); - lbool is_sat = m_imp->pb_simplify_solve(); - SASSERT(m_imp->m_lower > k); - k = m_imp->m_lower; - return is_sat; - } - void updt_params(params_ref& p) { - opt_params _p(p); - m_engine = _p.wmaxsat_engine(); - m_print_all_models = _p.print_all_models(); - m_solver.updt_params(p); - if (m_imp) { - m_imp->updt_params(p); - } - } - - void updt_model(solver& s) { - s.get_model(m_model); - if (m_print_all_models) { - std::cout << "[" << m_lower << ":" << m_upper << "]\n"; - std::cout << "(model " << std::endl; - model_smt2_pp(std::cout, m, *(m_model.get()), 2); - std::cout << ")" << std::endl; - } - } - - lbool simplify_and_check_sat(unsigned n, expr* const* assumptions) { - lbool is_sat = l_true; - tactic_ref tac1 = mk_simplify_tactic(m); - // tactic_ref tac2 = mk_pb_preprocess_tactic(m); - tactic_ref tac = tac1; // and_then(tac1.get(), tac2.get()); // TBD: make attribute for cancelation. - proof_converter_ref pc; - expr_dependency_ref core(m); - model_converter_ref mc; - goal_ref_buffer result; - goal_ref g(alloc(goal, m, true, false)); - for (unsigned i = 0; i < s.get_num_assertions(); ++i) { - g->assert_expr(s.get_assertion(i)); - } - for (unsigned i = 0; i < n; ++i) { - NOT_IMPLEMENTED_YET(); - // add assumption in a wrapper. - } - (*tac)(g, result, mc, pc, core); - if (result.empty()) { - is_sat = l_false; - } - else { - SASSERT(result.size() == 1); - goal_ref r = result[0]; - solver::scoped_push _s(m_solver); - // TBD ptr_vector asms; - for (unsigned i = 0; i < r->size(); ++i) { - // TBD collect assumptions from r - m_solver.assert_expr(r->form(i)); - } - is_sat = m_solver.check_sat_core(0, 0); - if (l_true == is_sat && !m_cancel) { - updt_model(m_solver); - if (mc && m_model) (*mc)(m_model, 0); - IF_VERBOSE(2, - g->display(verbose_stream() << "goal:\n"); - r->display(verbose_stream() << "reduced:\n"); - model_smt2_pp(verbose_stream(), m, *m_model, 0);); - } - } - return is_sat; - } - - }; - - wmaxsmt::wmaxsmt(ast_manager& m, opt_solver& s, expr_ref_vector& soft_constraints, vector const& weights) { - m_imp = alloc(imp, m, s, soft_constraints, weights); - m_imp->m_imp = alloc(imp, m, m_imp->m_solver, soft_constraints, weights); - } - - wmaxsmt::~wmaxsmt() { - dealloc(m_imp); - } - - lbool wmaxsmt::operator()() { - return (*m_imp)(); - } - rational wmaxsmt::get_lower() const { - return m_imp->get_lower(); - } - rational wmaxsmt::get_upper() const { - return m_imp->get_upper(); - } - bool wmaxsmt::get_assignment(unsigned idx) const { - return m_imp->m_assignment[idx]; - } - void wmaxsmt::set_cancel(bool f) { - m_imp->set_cancel(f); - } - void wmaxsmt::collect_statistics(statistics& st) const { - m_imp->collect_statistics(st); - } - void wmaxsmt::get_model(model_ref& mdl) { - m_imp->get_model(mdl); - } - - void wmaxsmt::updt_params(params_ref& p) { - m_imp->updt_params(p); - } - -}; - -#if 0 - class base_solver { - opt_solver& s; - public: - base_solver(opt_solver& s): s(s) {} - virutal void assert_soft(expr* e, rational const& w) = 0; - virtual void get_model(model_ref& m) = 0; - virtual void block() = 0; - virtual lbool check() = 0; - virtual void get_core(ptr_vector& core) { UNREACHABLE(); } - }; #endif diff --git a/src/opt/weighted_maxsat.h b/src/opt/weighted_maxsat.h index 9a407ba56..c3b75cd32 100644 --- a/src/opt/weighted_maxsat.h +++ b/src/opt/weighted_maxsat.h @@ -31,7 +31,10 @@ namespace opt { struct imp; imp* m_imp; public: - wmaxsmt(ast_manager& m, opt_solver& s, expr_ref_vector& soft_constraints, vector const& weights); + wmaxsmt(ast_manager& m, + opt_solver* s, + expr_ref_vector& soft_constraints, + vector const& weights); ~wmaxsmt(); virtual lbool operator()(); virtual rational get_lower() const; From 91dc527635a385b382115f4dadb51d97e77a4c8b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 14 Apr 2014 21:18:18 -0700 Subject: [PATCH 360/925] tidy Signed-off-by: Nikolaj Bjorner --- src/opt/weighted_maxsat.cpp | 54 +++++++++++++------------------------ 1 file changed, 19 insertions(+), 35 deletions(-) diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 942a1ab55..a4c587a2e 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -89,8 +89,14 @@ namespace opt { m_weights.append(weights); m_assignment.reset(); m_assignment.resize(m_soft.size(), false); + init(); + } + void init() { m_lower.reset(); m_upper.reset(); + for (unsigned i = 0; i < m_weights.size(); ++i) { + m_upper += m_weights[i]; + } } expr* mk_not(expr* e) { if (m.is_not(e, e)) { @@ -127,15 +133,12 @@ namespace opt { obj_map ans2core; // answer literal to core index lbool is_sat = l_undef; expr_ref_vector rs(m), asms(m); - m_lower = m_upper = rational::zero(); // current upper and lower bounds vector sigmas; // sigma_j := w_j if soft clause has not been satisfied bool first = true; + init(); for (unsigned i = 0; i < m_soft.size(); ++i) { - m_upper += m_weights[i]; r = m.mk_fresh_const("r", m.mk_bool_sort()); - if (m_mc) { - m_mc->insert(r->get_decl()); - } + m_mc->insert(r->get_decl()); fml = m.mk_or(m_soft[i].get(), r); s().assert_expr(fml); // does not get asserted in model-based mode. rs.push_back(r); @@ -307,9 +310,8 @@ namespace opt { pb_util u(m); expr_ref fml(m), val(m); expr_ref_vector nsoft(m); - m_lower = m_upper = rational::zero(); + init(); for (unsigned i = 0; i < m_soft.size(); ++i) { - m_upper += m_weights[i]; nsoft.push_back(mk_not(m_soft[i].get())); } solver::scoped_push _s1(s()); @@ -320,7 +322,7 @@ namespace opt { TRACE("opt", s().display(tout<<"looping\n");); solver::scoped_push _s2(s()); s().assert_expr(fml); - is_sat = simplify_and_check_sat(0,0); + is_sat = simplify_and_check_sat(); if (m_cancel) { is_sat = l_undef; } @@ -349,11 +351,10 @@ namespace opt { } private: - lbool simplify_and_check_sat(unsigned n, expr* const* assumptions) { + lbool simplify_and_check_sat() { lbool is_sat = l_true; - tactic_ref tac1 = mk_simplify_tactic(m); - // tactic_ref tac2 = mk_pb_preprocess_tactic(m); - tactic_ref tac = tac1; // and_then(tac1.get(), tac2.get()); // TBD: make attribute for cancelation. + tactic_ref tac = mk_simplify_tactic(m); + // TBD: make tac attribute for cancelation. proof_converter_ref pc; expr_dependency_ref core(m); model_converter_ref mc; @@ -362,10 +363,6 @@ namespace opt { for (unsigned i = 0; i < s().get_num_assertions(); ++i) { g->assert_expr(s().get_assertion(i)); } - for (unsigned i = 0; i < n; ++i) { - NOT_IMPLEMENTED_YET(); - // add assumption in a wrapper. - } (*tac)(g, result, mc, pc, core); if (result.empty()) { is_sat = l_false; @@ -374,9 +371,7 @@ namespace opt { SASSERT(result.size() == 1); goal_ref r = result[0]; solver::scoped_push _s(s()); - // TBD ptr_vector asms; for (unsigned i = 0; i < r->size(); ++i) { - // TBD collect assumptions from r s().assert_expr(r->form(i)); } is_sat = s().check_sat(0, 0); @@ -410,14 +405,12 @@ namespace opt { app_ref fml(m), a(m), b(m), c(m); expr_ref val(m); expr_ref_vector block(m), ans(m), al(m), am(m); - m_lower = m_upper = rational::zero(); obj_map ans_index; - vector amk; vector sc; + init(); for (unsigned i = 0; i < m_soft.size(); ++i) { rational w = m_weights[i]; - m_upper += w; b = m.mk_fresh_const("b", m.mk_bool_sort()); m_mc->insert(b->get_decl()); @@ -607,10 +600,9 @@ namespace opt { expr_ref fml(m), val(m); app_ref b(m); expr_ref_vector nsoft(m); - m_lower = m_upper = rational::zero(); + init(); solver::scoped_push __s(s()); for (unsigned i = 0; i < m_soft.size(); ++i) { - m_upper += m_weights[i]; b = m.mk_fresh_const("b", m.mk_bool_sort()); m_mc->insert(b->get_decl()); fml = m.mk_or(m_soft[i].get(), b); @@ -696,11 +688,7 @@ namespace opt { m_bvsls.assert_expr(r->form(i)); } - m_lower = m_upper = rational::zero(); - - for (unsigned i = 0; i < m_soft.size(); ++i) { - m_upper += m_weights[i]; - } + init(); rational num = numerator(m_upper); rational den = denominator(m_upper); rational maxval = num*den; @@ -959,9 +947,8 @@ namespace opt { expr_ref fml(m), val(m); app_ref b(m); expr_ref_vector nsoft(m); - m_lower = m_upper = rational::zero(); + init(); for (unsigned i = 0; i < m_soft.size(); ++i) { - m_upper += m_weights[i]; b = m.mk_fresh_const("b", m.mk_bool_sort()); m_mc->insert(b->get_decl()); fml = m.mk_or(m_soft[i].get(), b); @@ -1011,10 +998,9 @@ namespace opt { expr_ref fml(m), val(m); app_ref b(m); expr_ref_vector nsoft(m); - m_lower = m_upper = rational::zero(); solver::scoped_push __s(s()); + init(); for (unsigned i = 0; i < m_soft.size(); ++i) { - m_upper += m_weights[i]; b = m.mk_fresh_const("b", m.mk_bool_sort()); m_mc->insert(b->get_decl()); fml = m.mk_or(m_soft[i].get(), b); @@ -1189,16 +1175,14 @@ namespace opt { app_ref fml(m), a(m), b(m), c(m); expr_ref val(m); expr_ref_vector block(m), ans(m), am(m), soft(m); - m_lower = m_upper = rational::zero(); obj_map ans_index; - vector amk; vector sc; // vector of indices used in at last constraints expr_ref_vector al(m); // vector of at least constraints. rational wmax; + init(); for (unsigned i = 0; i < m_soft.size(); ++i) { rational w = m_weights[i]; - m_upper += w; if (wmax < w) wmax = w; b = m.mk_fresh_const("b", m.mk_bool_sort()); block.push_back(b); From e32666927b145691a5437f74c01a31de799d07e3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 14 Apr 2014 21:59:39 -0700 Subject: [PATCH 361/925] tidy Signed-off-by: Nikolaj Bjorner --- src/opt/weighted_maxsat.cpp | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index a4c587a2e..af97c57a0 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -72,9 +72,9 @@ namespace opt { m_params = p; s().updt_params(p); } - void add_soft( - vector const& weights, - expr_ref_vector const& soft) { + void init_soft(vector const& weights, expr_ref_vector const& soft) { + m_weights.reset(); + m_soft.reset(); m_weights.append(weights); m_soft.append(soft); } @@ -82,20 +82,13 @@ namespace opt { solver& s() { return *m_s; } void set_converter(filter_model_converter* mc) { m_mc = mc; } - void re_init(expr_ref_vector const& soft, vector const& weights) { - m_soft.reset(); - m_soft.append(soft); - m_weights.reset(); - m_weights.append(weights); - m_assignment.reset(); - m_assignment.resize(m_soft.size(), false); - init(); - } void init() { m_lower.reset(); m_upper.reset(); + m_assignment.reset(); for (unsigned i = 0; i < m_weights.size(); ++i) { m_upper += m_weights[i]; + m_assignment.push_back(false); } } expr* mk_not(expr* e) { @@ -130,10 +123,10 @@ namespace opt { expr_ref fml(m), val(m); app_ref r(m); vector cores; - obj_map ans2core; // answer literal to core index + obj_map ans2core; // answer literal to core index lbool is_sat = l_undef; expr_ref_vector rs(m), asms(m); - vector sigmas; // sigma_j := w_j if soft clause has not been satisfied + vector sigmas; // sigma_j := w_j if soft clause has not been satisfied bool first = true; init(); for (unsigned i = 0; i < m_soft.size(); ++i) { @@ -144,7 +137,6 @@ namespace opt { rs.push_back(r); asms.push_back(m.mk_not(r)); sigmas.push_back(m_weights[i]); - m_assignment.push_back(false); } m_upper += rational(1); solver::scoped_push _s(s()); @@ -578,7 +570,7 @@ namespace opt { for (unsigned i = 0; i < bs.size(); ++i) { tout << mk_pp(bs[i], m) << " " << ws[i] << "\n"; }); - maxs->re_init(nbs, ws); + maxs->init_soft(ws, nbs); lbool is_sat = (*maxs)(); SASSERT(maxs->get_lower() > k); k = maxs->get_lower(); @@ -652,6 +644,7 @@ namespace opt { } virtual void set_cancel(bool f) { + maxsmt_solver_base::set_cancel(f); m_sls.set_cancel(f); } }; @@ -737,6 +730,7 @@ namespace opt { } } virtual void set_cancel(bool f) { + maxsmt_solver_base::set_cancel(f); m_bvsls.set_cancel(f); } @@ -1089,7 +1083,7 @@ namespace opt { m_maxsmt = alloc(wmax, s.get(), m, s->get_context()); } m_maxsmt->updt_params(m_params); - m_maxsmt->add_soft(m_weights, m_soft); + m_maxsmt->init_soft(m_weights, m_soft); m_maxsmt->set_converter(s->mc_ref().get()); return *m_maxsmt; } From c84ab2fc017a169299cd5d2e855fcc2cf84c6e31 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 14 Apr 2014 22:12:22 -0700 Subject: [PATCH 362/925] tidy Signed-off-by: Nikolaj Bjorner --- src/opt/weighted_maxsat.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index af97c57a0..36242543d 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -126,7 +126,7 @@ namespace opt { obj_map ans2core; // answer literal to core index lbool is_sat = l_undef; expr_ref_vector rs(m), asms(m); - vector sigmas; // sigma_j := w_j if soft clause has not been satisfied + vector sigmas(m_weights); // sigma_j := w_j if soft clause has not been satisfied bool first = true; init(); for (unsigned i = 0; i < m_soft.size(); ++i) { @@ -136,9 +136,9 @@ namespace opt { s().assert_expr(fml); // does not get asserted in model-based mode. rs.push_back(r); asms.push_back(m.mk_not(r)); - sigmas.push_back(m_weights[i]); + SASSERT(m_weights[i].is_int()); // TBD: re-normalize weights if non-integral. } - m_upper += rational(1); + m_upper += rational(1); // TBD: assuming integral weights solver::scoped_push _s(s()); while (m_lower < m_upper) { solver::scoped_push __s(s()); @@ -783,8 +783,7 @@ namespace opt { final_check that satisfies min_cost. Takes: log (n / log(n)) iterations - */ - + */ class iwmax : public maxsmt_solver_wbase { public: From 7237be768bf8ecd99735f97bd7c3c3b17b7f8b22 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 17 Apr 2014 11:06:43 -0700 Subject: [PATCH 363/925] fixing bugs in refactored code exposed from White's example Signed-off-by: Nikolaj Bjorner --- src/opt/maxsmt.cpp | 9 ++ src/opt/maxsmt.h | 9 +- src/opt/opt_context.cpp | 13 +++ src/opt/opt_context.h | 1 + src/opt/weighted_maxsat.cpp | 184 ++++++++++++++++++------------------ src/smt/theory_wmaxsat.cpp | 28 ------ src/smt/theory_wmaxsat.h | 4 - 7 files changed, 117 insertions(+), 131 deletions(-) diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index d2f308488..d27d17790 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -126,6 +126,15 @@ namespace opt { } } + void maxsmt::add(expr* f, rational const& w) { + TRACE("opt", tout << mk_pp(f, m) << " weight: " << w << "\n";); + SASSERT(m.is_bool(f)); + SASSERT(w.is_pos()); + m_soft_constraints.push_back(f); + m_weights.push_back(w); + m_upper += w; + } + void maxsmt::display_answer(std::ostream& out) const { for (unsigned i = 0; i < m_soft_constraints.size(); ++i) { out << mk_pp(m_soft_constraints[i], m) diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index ffcfcab63..c4cf33cac 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -64,14 +64,7 @@ namespace opt { void updt_params(params_ref& p); - void add(expr* f, rational const& w) { - SASSERT(m.is_bool(f)); - SASSERT(w.is_pos()); - m_soft_constraints.push_back(f); - m_weights.push_back(w); - m_upper += w; - } - + void add(expr* f, rational const& w); unsigned size() const { return m_soft_constraints.size(); } expr* operator[](unsigned idx) const { return m_soft_constraints[idx]; } rational weight(unsigned idx) const { return m_weights[idx]; } diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 36775aab3..bf6faa005 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -547,6 +547,10 @@ namespace opt { void context::from_fmls(expr_ref_vector const& fmls) { + TRACE("opt", + for (unsigned i = 0; i < fmls.size(); ++i) { + tout << mk_pp(fmls[i], m) << "\n"; + }); m_hard_constraints.reset(); expr* orig_term; for (unsigned i = 0; i < fmls.size(); ++i) { @@ -607,6 +611,10 @@ namespace opt { break; } } + TRACE("opt", + for (unsigned i = 0; i < fmls.size(); ++i) { + tout << mk_pp(fmls[i].get(), m) << "\n"; + }); } void context::internalize() { @@ -670,6 +678,11 @@ namespace opt { } } + void context::display(std::ostream& out) { + + } + + void context::display_assignment(std::ostream& out) { for (unsigned i = 0; i < m_objectives.size(); ++i) { objective const& obj = m_objectives[i]; diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index fe5f91406..3fad9a59d 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -123,6 +123,7 @@ namespace opt { virtual std::string reason_unknown() const { return std::string("unknown"); } virtual void display_assignment(std::ostream& out); + void display(std::ostream& out); static void collect_param_descrs(param_descrs & r); void updt_params(params_ref& p); diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 36242543d..36c7911c3 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -778,92 +778,8 @@ namespace opt { } } }; - /** - Iteratively increase cost until there is an assignment during - final_check that satisfies min_cost. - - Takes: log (n / log(n)) iterations - */ - class iwmax : public maxsmt_solver_wbase { - public: - iwmax(solver* s, ast_manager& m, smt::context& ctx): maxsmt_solver_wbase(s, m, ctx) {} - virtual ~iwmax() {} - lbool operator()() { - scoped_ensure_theory wth(*this); - solver::scoped_push _s(s()); - for (unsigned i = 0; i < m_soft.size(); ++i) { - wth().assert_weighted(m_soft[i].get(), m_weights[i]); - } - solver::scoped_push __s(s()); - rational cost = wth().get_min_cost(); - rational log_cost(1), tmp(1); - while (tmp < cost) { - ++log_cost; - tmp *= rational(2); - } - expr_ref_vector bounds(m); - expr_ref bound(m); - lbool result = l_false; - unsigned nsc = 0; - m_upper = cost; - while (result == l_false) { - bound = wth().set_min_cost(log_cost); - s().push(); - ++nsc; - IF_VERBOSE(1, verbose_stream() << "(wmaxsat.iwmax min cost: " << log_cost << ")\n";); - TRACE("opt", tout << "cost: " << log_cost << " " << bound << "\n";); - bounds.push_back(bound); - result = conditional_solve(bound); - if (result == l_false) { - m_lower = log_cost; - } - if (log_cost > cost) { - break; - } - log_cost *= rational(2); - if (m_cancel) { - result = l_undef; - } - } - s().pop(nsc); - return result; - } - private: - lbool conditional_solve(expr* cond) { - IF_VERBOSE(1, verbose_stream() << "(wmaxsat.conditional solve)\n";); - smt::theory_wmaxsat& wth = *get_theory(); - bool was_sat = false; - lbool is_sat = l_true; - while (l_true == is_sat) { - is_sat = s().check_sat(1,&cond); - if (m_cancel) { - is_sat = l_undef; - } - if (is_sat == l_true) { - if (wth.is_optimal()) { - s().get_model(m_model); - was_sat = true; - } - expr_ref fml = wth.mk_block(); - s().assert_expr(fml); - } - } - if (was_sat) { - wth.get_assignment(m_assignment); - } - if (is_sat == l_false && was_sat) { - is_sat = l_true; - } - if (is_sat == l_true) { - m_lower = m_upper = wth.get_min_cost(); - } - TRACE("opt", tout << "min cost: " << m_upper << "\n";); - return is_sat; - } - - }; class wmax : public maxsmt_solver_wbase { public: @@ -914,19 +830,21 @@ namespace opt { }; class bvmax : public maxsmt_solver_base { - solver* mk_sat_solver(solver* s) { + solver* mk_sat_solver() { tactic_ref pb2bv = mk_card2bv_tactic(m, m_params); tactic_ref bv2sat = mk_qfbv_tactic(m, m_params); tactic_ref tac = and_then(pb2bv.get(), bv2sat.get()); solver* sat_solver = mk_tactic2solver(m, tac.get(), m_params); - unsigned sz = s->get_num_assertions(); + unsigned sz = s().get_num_assertions(); for (unsigned i = 0; i < sz; ++i) { - sat_solver->assert_expr(s->get_assertion(i)); + sat_solver->assert_expr(s().get_assertion(i)); } return sat_solver; } public: - bvmax(solver* s, ast_manager& m): maxsmt_solver_base(mk_sat_solver(s), m) {} + bvmax(solver* s, ast_manager& m): maxsmt_solver_base(s, m) { + m_s = mk_sat_solver(); + } virtual ~bvmax() {} // @@ -1058,9 +976,6 @@ namespace opt { if (m_maxsmt) { return *m_maxsmt; } - if (m_engine == symbol("iwmax")) { - m_maxsmt = alloc(iwmax, s.get(), m, s->get_context()); - } else if (m_engine == symbol("pwmax")) { m_maxsmt = alloc(pwmax, s.get(), m); } @@ -1118,6 +1033,7 @@ namespace opt { void updt_params(params_ref& p) { opt_params _p(p); m_engine = _p.wmaxsat_engine(); + std::cout << m_engine << "\n"; m_maxsmt = 0; } }; @@ -1159,6 +1075,92 @@ namespace opt { #if 0 + + /** + Iteratively increase cost until there is an assignment during + final_check that satisfies min_cost. + + Takes: log (n / log(n)) iterations + */ + class iwmax : public maxsmt_solver_wbase { + public: + + iwmax(solver* s, ast_manager& m, smt::context& ctx): maxsmt_solver_wbase(s, m, ctx) {} + virtual ~iwmax() {} + + lbool operator()() { + pb_util + solver::scoped_push _s(s()); + for (unsigned i = 0; i < m_soft.size(); ++i) { + wth().assert_weighted(m_soft[i].get(), m_weights[i]); + } + solver::scoped_push __s(s()); + rational cost = wth().get_min_cost(); + rational log_cost(1), tmp(1); + while (tmp < cost) { + ++log_cost; + tmp *= rational(2); + } + expr_ref_vector bounds(m); + expr_ref bound(m); + lbool result = l_false; + unsigned nsc = 0; + m_upper = cost; + while (result == l_false) { + bound = wth().set_min_cost(log_cost); + s().push(); + ++nsc; + IF_VERBOSE(1, verbose_stream() << "(wmaxsat.iwmax min cost: " << log_cost << ")\n";); + TRACE("opt", tout << "cost: " << log_cost << " " << bound << "\n";); + bounds.push_back(bound); + result = conditional_solve(wth(), bound); + if (result == l_false) { + m_lower = log_cost; + } + if (log_cost > cost) { + break; + } + log_cost *= rational(2); + if (m_cancel) { + result = l_undef; + } + } + s().pop(nsc); + return result; + } + private: + lbool conditional_solve(smt::theory_wmaxsat& wth, expr* cond) { + bool was_sat = false; + lbool is_sat = l_true; + while (l_true == is_sat) { + is_sat = s().check_sat(1,&cond); + if (m_cancel) { + is_sat = l_undef; + } + if (is_sat == l_true) { + if (wth.is_optimal()) { + s().get_model(m_model); + was_sat = true; + } + expr_ref fml = wth.mk_block(); + s().assert_expr(fml); + } + } + if (was_sat) { + wth.get_assignment(m_assignment); + } + if (is_sat == l_false && was_sat) { + is_sat = l_true; + } + if (is_sat == l_true) { + m_lower = m_upper = wth.get_min_cost(); + } + TRACE("opt", tout << "min cost: " << m_upper << " sat: " << is_sat << "\n";); + return is_sat; + } + + }; + // ------------------------------------------------------ // Version from CP'13 lbool wpm2b_solve() { diff --git a/src/smt/theory_wmaxsat.cpp b/src/smt/theory_wmaxsat.cpp index 92b1b4626..556f5047a 100644 --- a/src/smt/theory_wmaxsat.cpp +++ b/src/smt/theory_wmaxsat.cpp @@ -29,8 +29,6 @@ theory_wmaxsat::theory_wmaxsat(ast_manager& m, ref& mc): m_mc(mc), m_vars(m), m_fmls(m), - m_min_cost_atom(m), - m_min_cost_atoms(m), m_zweights(m_mpz), m_old_values(m_mpz), m_zcost(m_mpz), @@ -138,21 +136,6 @@ rational const& theory_wmaxsat::get_min_cost() { return m_rmin_cost; } -expr* theory_wmaxsat::set_min_cost(rational const& c) { - m_normalize = true; - ast_manager& m = get_manager(); - std::ostringstream strm; - strm << "cost <= " << c; - m_rmin_cost = c; - m_min_cost_atom = m.mk_fresh_const(strm.str().c_str(), m.mk_bool_sort()); - m_min_cost_atoms.push_back(m_min_cost_atom); - m_mc->insert(m_min_cost_atom->get_decl()); - - m_min_cost_bv = register_var(m_min_cost_atom, false); - - return m_min_cost_atom; -} - void theory_wmaxsat::assign_eh(bool_var v, bool is_true) { TRACE("opt", tout << "Assign " << mk_pp(m_vars[m_bool2var[v]].get(), get_manager()) << " " << is_true << "\n";); if (is_true) { @@ -194,8 +177,6 @@ void theory_wmaxsat::reset_eh() { m_cost_save.reset(); m_bool2var.reset(); m_var2bool.reset(); - m_min_cost_atom = 0; - m_min_cost_atoms.reset(); m_propagate = false; m_found_optimal = false; m_assigned.reset(); @@ -231,9 +212,6 @@ expr_ref theory_wmaxsat::mk_block() { weight += m_zweights[costs[i]]; disj.push_back(m.mk_not(m_vars[costs[i]].get())); } - if (m_min_cost_atom) { - disj.push_back(m.mk_not(m_min_cost_atom)); - } if (is_optimal()) { unsynch_mpq_manager mgr; scoped_mpq q(mgr); @@ -272,9 +250,6 @@ expr_ref theory_wmaxsat::mk_optimal_block(svector const& ws, rational m_cost_save.push_back(v); disj.push_back(m.mk_not(m_vars[v].get())); } - if (m_min_cost_atom) { - disj.push_back(m.mk_not(m_min_cost_atom)); - } expr_ref result(m.mk_or(disj.size(), disj.c_ptr()), m); return result; } @@ -297,9 +272,6 @@ void theory_wmaxsat::block() { weight += m_zweights[costs[i]]; lits.push_back(~literal(m_var2bool[costs[i]])); } - if (m_min_cost_atom) { - lits.push_back(~literal(m_min_cost_bv)); - } TRACE("opt", tout << "block: "; for (unsigned i = 0; i < lits.size(); ++i) { diff --git a/src/smt/theory_wmaxsat.h b/src/smt/theory_wmaxsat.h index 21f7fd907..b6974957c 100644 --- a/src/smt/theory_wmaxsat.h +++ b/src/smt/theory_wmaxsat.h @@ -32,9 +32,6 @@ namespace smt { mutable unsynch_mpz_manager m_mpz; app_ref_vector m_vars; // Auxiliary variables per soft clause expr_ref_vector m_fmls; // Formulas per soft clause - app_ref m_min_cost_atom; // atom tracking modified lower bound - app_ref_vector m_min_cost_atoms; - bool_var m_min_cost_bv; // max cost Boolean variable vector m_rweights; // weights of theory variables. scoped_mpz_vector m_zweights; scoped_mpz_vector m_old_values; @@ -60,7 +57,6 @@ namespace smt { bool_var assert_weighted(expr* fml, rational const& w); bool_var register_var(app* var, bool attach); rational const& get_min_cost(); - expr* set_min_cost(rational const& c); class numeral_trail : public trail { typedef scoped_mpz T; T & m_value; From ae1656a92ce64a7f8c55bee63030546b12004ca0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 17 Apr 2014 15:37:03 -0700 Subject: [PATCH 364/925] working on bcd2 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 15 ++- src/opt/weighted_maxsat.cpp | 244 +++++++++++++++++++++++++----------- src/opt/weighted_maxsat.h | 2 +- 3 files changed, 183 insertions(+), 78 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index bf6faa005..5252d60b6 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -426,8 +426,19 @@ namespace opt { neg = false; app* a = to_app(fml); if (m_objective_fns.find(a->get_decl(), index) && m_objectives[index].m_type == O_MAXSMT) { - terms.append(a->get_num_args(), a->get_args()); - weights.append(m_objectives[index].m_weights); + for (unsigned i = 0; i < a->get_num_args(); ++i) { + expr* arg = a->get_arg(i); + if (m.is_true(arg)) { + + } + else if (false && m.is_false(arg)) { + offset += m_objectives[index].m_weights[i]; + } + else { + terms.push_back(arg); + weights.push_back(m_objectives[index].m_weights[i]); + } + } id = m_objectives[index].m_id; return true; } diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 36c7911c3..e253621f9 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -6,11 +6,12 @@ Module Name: weighted_maxsat.cpp Abstract: + Weighted MAXSAT module Author: - Anh-Dung Phan (t-anphan) 2013-10-16 + Nikolaj Bjorner (nbjorner) 2014-4-17 Notes: @@ -107,49 +108,77 @@ namespace opt { // class bcd2 : public maxsmt_solver_base { struct wcore { + expr* m_r; unsigned_vector m_R; rational m_lower; rational m_mid; rational m_upper; }; + typedef obj_hashtable expr_set; + + pb_util pb; + expr_ref_vector m_relax; // index |-> expr + obj_map m_relax2index; // expr |-> index + expr_ref_vector m_trail; + expr_set m_asm_set; + vector m_cores; + vector m_sigmas; + + + + void set2vector(expr_set const& set, expr_ref_vector & es) const { + es.reset(); + expr_set::iterator it = set.begin(), end = set.end(); + for (; it != end; ++it) { + es.push_back(*it); + } + } + + void init() { + m_relax.reset(); + m_trail.reset(); + m_asm_set.reset(); + m_cores.reset(); + m_sigmas.reset(); + for (unsigned i = 0; i < m_soft.size(); ++i) { + m_relax.push_back(mk_fresh()); + m_relax2index.insert(m_relax.back(), i); + m_sigmas.push_back(m_weights[i]); + } + } + public: bcd2(solver* s, ast_manager& m): - maxsmt_solver_base(s, m) {} + maxsmt_solver_base(s, m), + pb(m), + m_relax(m), + m_trail(m) {} virtual ~bcd2() {} virtual lbool operator()() { - expr_ref fml(m), val(m); - app_ref r(m); - vector cores; - obj_map ans2core; // answer literal to core index + expr_ref fml(m), r(m); + init(); lbool is_sat = l_undef; - expr_ref_vector rs(m), asms(m); - vector sigmas(m_weights); // sigma_j := w_j if soft clause has not been satisfied + expr_ref_vector asms(m); bool first = true; init(); for (unsigned i = 0; i < m_soft.size(); ++i) { - r = m.mk_fresh_const("r", m.mk_bool_sort()); - m_mc->insert(r->get_decl()); - fml = m.mk_or(m_soft[i].get(), r); + fml = m.mk_implies(m_relax[i].get(), m_soft[i].get()); s().assert_expr(fml); // does not get asserted in model-based mode. - rs.push_back(r); - asms.push_back(m.mk_not(r)); + m_asm_set.insert(m_relax[i].get()); SASSERT(m_weights[i].is_int()); // TBD: re-normalize weights if non-integral. } m_upper += rational(1); // TBD: assuming integral weights - solver::scoped_push _s(s()); + solver::scoped_push _scope1(s()); while (m_lower < m_upper) { - solver::scoped_push __s(s()); + solver::scoped_push _scope2(s()); + assert_cores(); + set2vector(m_asm_set, asms); if (m_cancel) { return l_undef; } - for (unsigned i = 0; i < cores.size(); ++i) { - assert_core(cores[i]); - NOT_IMPLEMENTED_YET(); - // need assumptions here as well. - } is_sat = s().check_sat(asms.size(), asms.c_ptr()); switch(is_sat) { case l_undef: @@ -157,78 +186,133 @@ namespace opt { case l_true: { s().get_model(m_model); m_upper.reset(); - for (unsigned i = 0; i < m_soft.size(); ++i) { - VERIFY(m_model->eval(m_soft[i].get(), val)); - m_assignment[i] = m.is_true(val); - } - for (unsigned i = 0; i < cores.size(); ++i) { - wcore& c_i = cores[i]; - unsigned_vector const& R = c_i.m_R; - c_i.m_upper.reset(); - for (unsigned j = 0; j core; + ptr_vector unsat_core; uint_set subC, soft; - rational delta(0), lower(0); - wcore c_s; - s().get_unsat_core(core); - core2indices(core, ans2core, subC, soft); - for (uint_set::iterator it = subC.begin(); it != subC.end(); ++it) { - unsigned j = *it; - c_s.m_R.push_back(j); - lower += cores[j].m_lower; - rational new_delta = rational(1) + cores[j].m_upper - cores[j].m_mid; - SASSERT(new_delta.is_pos()); - if (delta.is_zero() || delta > new_delta) { - delta = new_delta; - } - } + s().get_unsat_core(unsat_core); + core2indices(unsat_core, subC, soft); + SASSERT(unsat_core.size() == subC.num_elems() + soft.num_elems()); if (soft.num_elems() == 0 && subC.num_elems() == 1) { - SASSERT(core.size() == 1); unsigned s = *subC.begin(); - wcore& c_s = cores[s]; + wcore& c_s = m_cores[s]; c_s.m_lower = refine(c_s.m_R, c_s.m_mid); } else { + wcore c_s; + rational delta = min_of_delta(subC); + rational lower = sum_of_lower(subC); + union_Rs(subC, c_s.m_R); + r = mk_fresh(); relax(subC, soft, c_s.m_R, delta); c_s.m_lower = refine(c_s.m_R, lower + delta - rational(1)); - c_s.m_upper = rational(first?0:1); - for (unsigned i = 0; i < c_s.m_R.size(); ++i) { - c_s.m_upper += sigmas[c_s.m_R[i]]; - } - c_s.m_mid = div(c_s.m_lower + c_s.m_upper, rational(2)); - subtract(cores, subC); - cores.push_back(c_s); + c_s.m_upper = rational(first?1:0); + c_s.m_upper += sum_of_sigmas(c_s.m_R); + c_s.m_mid = div(c_s.m_lower + c_s.m_upper, rational(2)); + c_s.m_r = r; + m_asm_set.insert(r); + subtract(m_cores, subC); + m_cores.push_back(c_s); } break; } } - m_lower = compute_lower(cores); + m_lower = compute_lower(); } return is_sat; } private: - rational compute_lower(vector const& cores) { + + expr* mk_fresh() { + app_ref r(m); + r = m.mk_fresh_const("r", m.mk_bool_sort()); + m_trail.push_back(r); + m_mc->insert(r->get_decl()); + return r; + } + + void update_assignment() { + expr_ref val(m); + for (unsigned i = 0; i < m_soft.size(); ++i) { + VERIFY(m_model->eval(m_soft[i].get(), val)); + m_assignment[i] = m.is_true(val); + } + } + + void update_sigmas() { + for (unsigned i = 0; i < m_cores.size(); ++i) { + wcore& c_i = m_cores[i]; + unsigned_vector const& R = c_i.m_R; + c_i.m_upper.reset(); + for (unsigned j = 0; j < R.size(); ++j) { + unsigned r_j = R[j]; + if (!m_assignment[r_j]) { + c_i.m_upper += m_weights[r_j]; + m_sigmas[r_j] = m_weights[r_j]; + } + else { + m_sigmas[r_j].reset(); + } + } + c_i.m_mid = div(c_i.m_lower + c_i.m_upper, rational(2)); + m_upper += c_i.m_upper; + } + } + + /** + * Minimum of two (positive) numbers. Zero is treated as +infinity. + */ + rational min_z(rational const& a, rational const& b) { + if (a.is_zero()) return b; + if (b.is_zero()) return a; + if (a < b) return a; + return b; + } + + rational min_of_delta(uint_set const& subC) { + rational delta(0); + for (uint_set::iterator it = subC.begin(); it != subC.end(); ++it) { + unsigned j = *it; + wcore const& core = m_cores[j]; + rational new_delta = rational(1) + core.m_upper - core.m_mid; + SASSERT(new_delta.is_pos()); + delta = min_z(delta, new_delta); + } + return delta; + } + + rational sum_of_lower(uint_set const& subC) { + rational lower(0); + for (uint_set::iterator it = subC.begin(); it != subC.end(); ++it) { + lower += m_cores[*it].m_lower; + } + return lower; + } + + rational sum_of_sigmas(unsigned_vector const& R) { + rational sum(0); + for (unsigned i = 0; i < R.size(); ++i) { + sum += m_sigmas[R[i]]; + } + return sum; + } + + void union_Rs(uint_set const& subC, unsigned_vector& R) { + for (uint_set::iterator it = subC.begin(); it != subC.end(); ++it) { + R.append(m_cores[*it].m_R); + } + } + + rational compute_lower() { rational result(0); - for (unsigned i = 0; i < cores.size(); ++i) { - result += cores[i].m_lower; + for (unsigned i = 0; i < m_cores.size(); ++i) { + result += m_cores[i].m_lower; } return result; } @@ -242,19 +326,21 @@ namespace opt { } ++j; } + else { + m_asm_set.remove(cores[i].m_r); + } } cores.resize(j); } void core2indices( ptr_vector const& core, - obj_map const& ans2core, uint_set& subC, uint_set& soft) { for (unsigned i = 0; i < core.size(); ++i) { unsigned j; - if (ans2core.find(core[i], j)) { + if (m_relax2index.find(core[i], j)) { subC.insert(j); } else { @@ -268,9 +354,18 @@ namespace opt { } void relax(uint_set& subC, uint_set& soft, unsigned_vector& R, rational& delta) { - NOT_IMPLEMENTED_YET(); + for (uint_set::iterator it = soft.begin(); it != soft.end(); ++it) { + R.push_back(*it); + delta = min_z(delta, m_weights[*it]); + m_asm_set.remove(m_relax[*it].get()); + } } + void assert_cores() { + for (unsigned i = 0; i < m_cores.size(); ++i) { + assert_core(m_cores[i]); + } + } void assert_core(wcore const& core) { expr_ref fml(m); vector ws; @@ -280,8 +375,8 @@ namespace opt { ws.push_back(m_weights[idx]); rs.push_back(m_soft[idx].get()); // TBD: check } - // TBD: fml = pb.mk_le(ws.size(), ws.c_ptr(), rs.c_ptr(), core.m_mid); - NOT_IMPLEMENTED_YET(); + fml = pb.mk_le(ws.size(), ws.c_ptr(), rs.c_ptr(), core.m_mid); + fml = m.mk_implies(core.m_r, fml); s().assert_expr(fml); } }; @@ -1033,7 +1128,6 @@ namespace opt { void updt_params(params_ref& p) { opt_params _p(p); m_engine = _p.wmaxsat_engine(); - std::cout << m_engine << "\n"; m_maxsmt = 0; } }; diff --git a/src/opt/weighted_maxsat.h b/src/opt/weighted_maxsat.h index c3b75cd32..d84f96f0a 100644 --- a/src/opt/weighted_maxsat.h +++ b/src/opt/weighted_maxsat.h @@ -11,7 +11,7 @@ Abstract: Author: - Anh-Dung Phan (t-anphan) 2013-10-16 + Nikolaj Bjorner (nbjorner) 2014-4-17 Notes: From e3b346df6fbac35a098af2609df392d6d4f967e3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 18 Apr 2014 08:04:18 -0700 Subject: [PATCH 365/925] working on bcd2 Signed-off-by: Nikolaj Bjorner --- src/api/python/z3.py | 2 +- src/opt/opt_context.cpp | 2 +- src/opt/weighted_maxsat.cpp | 111 ++++++++++++++++++++++++------------ 3 files changed, 77 insertions(+), 38 deletions(-) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index f513fd4bd..3145dc75a 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -6333,7 +6333,7 @@ class Optimize(Z3PPObject): if not isinstance(weight, str): raise Z3Exception("weight should be a string or an integer") if id == None: - id = 0 + id = "" id = to_symbol(id, self.ctx) v = Z3_optimize_assert_soft(self.ctx.ref(), self.optimize, arg.as_ast(), weight, id) return OptimizeObjective(v) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 5252d60b6..547f90bd7 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -431,7 +431,7 @@ namespace opt { if (m.is_true(arg)) { } - else if (false && m.is_false(arg)) { + else if (m.is_false(arg)) { offset += m_objectives[index].m_weights[i]; } else { diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index e253621f9..4c56cce4e 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -73,7 +73,7 @@ namespace opt { m_params = p; s().updt_params(p); } - void init_soft(vector const& weights, expr_ref_vector const& soft) { + virtual void init_soft(vector const& weights, expr_ref_vector const& soft) { m_weights.reset(); m_soft.reset(); m_weights.append(weights); @@ -117,14 +117,14 @@ namespace opt { typedef obj_hashtable expr_set; pb_util pb; - expr_ref_vector m_relax; // index |-> expr + expr_ref_vector m_soft_aux; obj_map m_relax2index; // expr |-> index + obj_map m_soft2index; // expr |-> index expr_ref_vector m_trail; expr_set m_asm_set; vector m_cores; vector m_sigmas; - - + rational m_den; // least common multiplier of original denominators void set2vector(expr_set const& set, expr_ref_vector & es) const { es.reset(); @@ -133,16 +133,27 @@ namespace opt { es.push_back(*it); } } + virtual void init_soft(vector const& weights, expr_ref_vector const& soft) { + maxsmt_solver_base::init_soft(weights, soft); - void init() { - m_relax.reset(); + // normalize weights to be integral: + m_den = rational::one(); + for (unsigned i = 0; i < m_weights.size(); ++i) { + m_den = lcm(m_den, denominator(m_weights[i])); + } + if (!m_den.is_one()) { + for (unsigned i = 0; i < m_weights.size(); ++i) { + m_weights[i] = m_den*m_weights[i]; + SASSERT(m_weights[i].is_int()); + } + } + } + void init_bcd() { m_trail.reset(); m_asm_set.reset(); m_cores.reset(); m_sigmas.reset(); for (unsigned i = 0; i < m_soft.size(); ++i) { - m_relax.push_back(mk_fresh()); - m_relax2index.insert(m_relax.back(), i); m_sigmas.push_back(m_weights[i]); } } @@ -151,8 +162,9 @@ namespace opt { bcd2(solver* s, ast_manager& m): maxsmt_solver_base(s, m), pb(m), - m_relax(m), - m_trail(m) {} + m_soft_aux(m), + m_trail(m) { + } virtual ~bcd2() {} @@ -160,28 +172,34 @@ namespace opt { virtual lbool operator()() { expr_ref fml(m), r(m); init(); + init_bcd(); lbool is_sat = l_undef; expr_ref_vector asms(m); bool first = true; - init(); for (unsigned i = 0; i < m_soft.size(); ++i) { - fml = m.mk_implies(m_relax[i].get(), m_soft[i].get()); + r = mk_fresh(); + m_soft2index.insert(r, m_soft_aux.size()); + m_soft_aux.push_back(r); + fml = m.mk_implies(r, m_soft[i].get()); s().assert_expr(fml); // does not get asserted in model-based mode. - m_asm_set.insert(m_relax[i].get()); - SASSERT(m_weights[i].is_int()); // TBD: re-normalize weights if non-integral. + m_asm_set.insert(r); + SASSERT(m_weights[i].is_int()); } - m_upper += rational(1); // TBD: assuming integral weights + m_upper += rational(1); solver::scoped_push _scope1(s()); while (m_lower < m_upper) { solver::scoped_push _scope2(s()); + TRACE("opt", display(tout);); assert_cores(); set2vector(m_asm_set, asms); if (m_cancel) { + normalize_bounds(); return l_undef; } is_sat = s().check_sat(asms.size(), asms.c_ptr()); switch(is_sat) { case l_undef: + normalize_bounds(); return l_undef; case l_true: { s().get_model(m_model); @@ -216,6 +234,7 @@ namespace opt { c_s.m_r = r; m_asm_set.insert(r); subtract(m_cores, subC); + m_relax2index.insert(r, m_cores.size()); m_cores.push_back(c_s); } break; @@ -223,12 +242,23 @@ namespace opt { } m_lower = compute_lower(); } - return is_sat; + normalize_bounds(); + if (first) { + return is_sat; + } + else { + return l_true; + } } private: + void normalize_bounds() { + m_lower /= m_den; + m_upper /= m_den; + } + expr* mk_fresh() { app_ref r(m); r = m.mk_fresh_const("r", m.mk_bool_sort()); @@ -302,13 +332,11 @@ namespace opt { } return sum; } - void union_Rs(uint_set const& subC, unsigned_vector& R) { for (uint_set::iterator it = subC.begin(); it != subC.end(); ++it) { R.append(m_cores[*it].m_R); } } - rational compute_lower() { rational result(0); for (unsigned i = 0; i < m_cores.size(); ++i) { @@ -316,51 +344,43 @@ namespace opt { } return result; } - void subtract(vector& cores, uint_set const& subC) { unsigned j = 0; for (unsigned i = 0; i < cores.size(); ++i) { - if (!subC.contains(i)) { + if (subC.contains(i)) { + m_asm_set.remove(cores[i].m_r); + } + else { if (j != i) { cores[j] = cores[i]; } ++j; } - else { - m_asm_set.remove(cores[i].m_r); - } } cores.resize(j); } - - void core2indices( - ptr_vector const& core, - uint_set& subC, - uint_set& soft) - { + void core2indices(ptr_vector const& core, uint_set& subC, uint_set& soft) { for (unsigned i = 0; i < core.size(); ++i) { unsigned j; if (m_relax2index.find(core[i], j)) { subC.insert(j); } else { - soft.insert(i); + VERIFY(m_soft2index.find(core[i], j)); + soft.insert(j); } } - } - + } rational refine(unsigned_vector const& idx, rational v) { return v + rational(1); } - void relax(uint_set& subC, uint_set& soft, unsigned_vector& R, rational& delta) { - for (uint_set::iterator it = soft.begin(); it != soft.end(); ++it) { + for (uint_set::iterator it = soft.begin(); it != soft.end(); ++it) { R.push_back(*it); delta = min_z(delta, m_weights[*it]); - m_asm_set.remove(m_relax[*it].get()); + m_asm_set.remove(m_soft_aux[*it].get()); } } - void assert_cores() { for (unsigned i = 0; i < m_cores.size(); ++i) { assert_core(m_cores[i]); @@ -379,6 +399,22 @@ namespace opt { fml = m.mk_implies(core.m_r, fml); s().assert_expr(fml); } + void display(std::ostream& out) { + out << "[" << m_lower << ":" << m_upper << "]\n"; + s().display(out); + out << "\n"; + for (unsigned i = 0; i < m_cores.size(); ++i) { + wcore const& c = m_cores[i]; + out << mk_pp(c.m_r, m) << ": "; + for (unsigned j = 0; j < c.m_R.size(); ++j) { + out << c.m_R[j] << " (" << m_sigmas[c.m_R[j]] << ") "; + } + out << "[" << c.m_lower << ":" << c.m_mid << ":" << c.m_upper << "]\n"; + } + for (unsigned i = 0; i < m_soft.size(); ++i) { + out << mk_pp(m_soft[i].get(), m) << " " << m_weights[i] << "\n"; + } + } }; class pb_simplify_solve : public maxsmt_solver_base { @@ -1081,6 +1117,9 @@ namespace opt { maxsmt_solver_base* s2 = alloc(pb_simplify_solve, s.get(), m); m_maxsmt = alloc(wpm2, s.get(), m, s2); } + else if (m_engine == symbol("bcd2")) { + m_maxsmt = alloc(bcd2, s.get(), m); + } else if (m_engine == symbol("bvsls")) { m_maxsmt = alloc(bvsls, s.get(), m); } From 5ead06bcef5f974fbb4dc5b099a3333001f1a8c5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 18 Apr 2014 10:29:52 -0700 Subject: [PATCH 366/925] adding SLS solver layer Signed-off-by: Nikolaj Bjorner --- src/opt/opt_sls_solver.h | 114 ++++++++++++++++++++++++++++++++++++ src/opt/weighted_maxsat.cpp | 105 ++++++++++++++++++++++++--------- 2 files changed, 190 insertions(+), 29 deletions(-) create mode 100644 src/opt/opt_sls_solver.h diff --git a/src/opt/opt_sls_solver.h b/src/opt/opt_sls_solver.h new file mode 100644 index 000000000..bfeaad822 --- /dev/null +++ b/src/opt/opt_sls_solver.h @@ -0,0 +1,114 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + opt_sls_solver.h + +Abstract: + + Wraps a solver with SLS for improving a solution using an objective function. + +Author: + + Nikolaj Bjorner (nbjorner) 2014-4-18 + +Notes: + + +--*/ +#ifndef _OPT_SLS_SOLVER_H_ +#define _OPT_SLS_SOLVER_H_ + +#include "solver_na2as.h" + +namespace opt { + + class sls_solver : public solver_na2as { + ast_manager& m; + ref m_solver; + bvsls_opt_engine m_sls; + model_ref m_model; + expr_ref m_objective; + public: + sls_solver(ast_manager & m, solver* s, expr* to_maximize, params_ref const& p): + solver_na2as(m), + m(m), + m_solver(s), + m_sls(m, p), + m_objective(to_maximize,m) + { + } + virtual ~sls_solver() {} + + virtual void updt_params(params_ref & p) { + m_solver->updt_params(p); + } + virtual void collect_param_descrs(param_descrs & r) { + m_solver->collect_param_descrs(r); + } + virtual void collect_statistics(statistics & st) const { + m_solver->collect_statistics(st); + // TBD: m_sls.get_stats(); + } + virtual void assert_expr(expr * t) { + m_solver->assert_expr(t); + m_sls.assert_expr(t); + } + virtual void get_unsat_core(ptr_vector & r) { + m_solver->get_unsat_core(r); + } + virtual void get_model(model_ref & m) { + m = m_model; + } + virtual proof * get_proof() { + return m_solver->get_proof(); + } + virtual std::string reason_unknown() const { + return m_solver->reason_unknown(); + } + virtual void get_labels(svector & r) { + m_solver->get_labels(r); + } + virtual void set_cancel(bool f) { + m_solver->set_cancel(f); + m_sls.set_cancel(f); + } + virtual void set_progress_callback(progress_callback * callback) { + m_solver->set_progress_callback(callback); + } + virtual unsigned get_num_assertions() const { + return m_solver->get_num_assertions(); + } + virtual expr * get_assertion(unsigned idx) const { + return m_solver->get_assertion(idx); + } + virtual void display(std::ostream & out) const { + m_solver->display(out); + // m_sls.display(out); + } + + protected: + virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) { + lbool r = m_solver->check_sat(num_assumptions, assumptions); + if (r == l_true) { + m_solver->get_model(m_model); + bvsls_opt_engine::optimization_result or(m); + or = m_sls.optimize(m_objective, m_model, true); + SASSERT(or.is_sat == l_true); + m_sls.get_model(m_model); + or.optimum; + } + return r; + } + virtual void push_core() { + m_solver->push(); + } + virtual void pop_core(unsigned n) { + m_solver->pop(n); + } + + }; +} + +#endif diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 4c56cce4e..dc65ec09d 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -37,6 +37,7 @@ Notes: #include "tactic2solver.h" #include "bvsls_opt_engine.h" #include "nnf_tactic.h" +#include "opt_sls_solver.h" namespace opt { @@ -125,12 +126,14 @@ namespace opt { vector m_cores; vector m_sigmas; rational m_den; // least common multiplier of original denominators + bool m_enable_lazy; // enable adding soft constraints lazily (called 'mgbcd2') + unsigned_vector m_lazy_soft; // soft constraints to add lazily. - void set2vector(expr_set const& set, expr_ref_vector & es) const { + void set2asms(expr_set const& set, expr_ref_vector & es) const { es.reset(); expr_set::iterator it = set.begin(), end = set.end(); for (; it != end; ++it) { - es.push_back(*it); + es.push_back(m.mk_not(*it)); } } virtual void init_soft(vector const& weights, expr_ref_vector const& soft) { @@ -153,9 +156,18 @@ namespace opt { m_asm_set.reset(); m_cores.reset(); m_sigmas.reset(); + m_lazy_soft.reset(); for (unsigned i = 0; i < m_soft.size(); ++i) { m_sigmas.push_back(m_weights[i]); - } + m_soft_aux.push_back(mk_fresh()); + if (m_enable_lazy) { + m_lazy_soft.push_back(i); + } + else { + enable_soft_constraint(i); + } + } + m_upper += rational(1); } public: @@ -163,7 +175,8 @@ namespace opt { maxsmt_solver_base(s, m), pb(m), m_soft_aux(m), - m_trail(m) { + m_trail(m), + m_enable_lazy(false) { } virtual ~bcd2() {} @@ -171,27 +184,18 @@ namespace opt { virtual lbool operator()() { expr_ref fml(m), r(m); - init(); - init_bcd(); lbool is_sat = l_undef; expr_ref_vector asms(m); bool first = true; - for (unsigned i = 0; i < m_soft.size(); ++i) { - r = mk_fresh(); - m_soft2index.insert(r, m_soft_aux.size()); - m_soft_aux.push_back(r); - fml = m.mk_implies(r, m_soft[i].get()); - s().assert_expr(fml); // does not get asserted in model-based mode. - m_asm_set.insert(r); - SASSERT(m_weights[i].is_int()); - } - m_upper += rational(1); solver::scoped_push _scope1(s()); + init(); + init_bcd(); while (m_lower < m_upper) { + IF_VERBOSE(1, verbose_stream() << "(wmaxsat.bcd2 [" << m_lower << ":" << m_upper << "])\n";); solver::scoped_push _scope2(s()); TRACE("opt", display(tout);); assert_cores(); - set2vector(m_asm_set, asms); + set2asms(m_asm_set, asms); if (m_cancel) { normalize_bounds(); return l_undef; @@ -202,11 +206,12 @@ namespace opt { normalize_bounds(); return l_undef; case l_true: { - s().get_model(m_model); - m_upper.reset(); - update_assignment(); - update_sigmas(); + svector assignment; + update_assignment(assignment); first = false; + if (check_lazy_soft(assignment)) { + update_sigmas(); + } break; } case l_false: { @@ -254,6 +259,31 @@ namespace opt { private: + void enable_soft_constraint(unsigned i) { + expr_ref fml(m); + expr* r = m_soft_aux[i].get(); + m_soft2index.insert(r, i); + fml = m.mk_or(r, m_soft[i].get()); + s().assert_expr(fml); + m_asm_set.insert(r); + SASSERT(m_weights[i].is_int()); + } + + bool check_lazy_soft(svector const& assignment) { + bool all_satisfied = true; + for (unsigned i = 0; i < m_lazy_soft.size(); ++i) { + unsigned j = m_lazy_soft[i]; + if (!assignment[j]) { + enable_soft_constraint(j); + m_lazy_soft[i] = m_lazy_soft.back(); + m_lazy_soft.pop_back(); + --i; + all_satisfied = false; + } + } + return all_satisfied; + } + void normalize_bounds() { m_lower /= m_den; m_upper /= m_den; @@ -267,11 +297,24 @@ namespace opt { return r; } - void update_assignment() { + void update_assignment(svector& new_assignment) { expr_ref val(m); + rational new_upper(0); + model_ref model; + new_assignment.reset(); + s().get_model(model); for (unsigned i = 0; i < m_soft.size(); ++i) { - VERIFY(m_model->eval(m_soft[i].get(), val)); - m_assignment[i] = m.is_true(val); + VERIFY(model->eval(m_soft[i].get(), val)); + new_assignment.push_back(m.is_true(val)); + if (!new_assignment[i]) { + new_upper += m_weights[i]; + } + } + if (new_upper < m_upper) { + m_upper = new_upper; + m_model = model; + m_assignment.reset(); + m_assignment.append(new_assignment); } } @@ -291,7 +334,6 @@ namespace opt { } } c_i.m_mid = div(c_i.m_lower + c_i.m_upper, rational(2)); - m_upper += c_i.m_upper; } } @@ -362,11 +404,13 @@ namespace opt { void core2indices(ptr_vector const& core, uint_set& subC, uint_set& soft) { for (unsigned i = 0; i < core.size(); ++i) { unsigned j; - if (m_relax2index.find(core[i], j)) { + expr* a; + VERIFY(m.is_not(core[i], a)); + if (m_relax2index.find(a, j)) { subC.insert(j); } else { - VERIFY(m_soft2index.find(core[i], j)); + VERIFY(m_soft2index.find(a, j)); soft.insert(j); } } @@ -393,10 +437,10 @@ namespace opt { for (unsigned j = 0; j < core.m_R.size(); ++j) { unsigned idx = core.m_R[j]; ws.push_back(m_weights[idx]); - rs.push_back(m_soft[idx].get()); // TBD: check + rs.push_back(m_soft_aux[idx].get()); // TBD: check } fml = pb.mk_le(ws.size(), ws.c_ptr(), rs.c_ptr(), core.m_mid); - fml = m.mk_implies(core.m_r, fml); + fml = m.mk_or(core.m_r, fml); s().assert_expr(fml); } void display(std::ostream& out) { @@ -1113,6 +1157,9 @@ namespace opt { else if (m_engine == symbol("bvmax")) { m_maxsmt = alloc(bvmax, s.get(), m); } + else if (m_engine == symbol("pb")) { + m_maxsmt = alloc(pb_simplify_solve, s.get(), m); + } else if (m_engine == symbol("wpm2")) { maxsmt_solver_base* s2 = alloc(pb_simplify_solve, s.get(), m); m_maxsmt = alloc(wpm2, s.get(), m, s2); From 032e2618f66d3dd2a5c198ed1eb832b34c98c100 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Apr 2014 11:58:57 -0700 Subject: [PATCH 367/925] refactor Signed-off-by: Nikolaj Bjorner --- src/opt/opt_params.pyg | 4 +- src/opt/opt_sls_solver.h | 42 +++++- src/opt/weighted_maxsat.cpp | 285 ++++++++++++++++-------------------- 3 files changed, 166 insertions(+), 165 deletions(-) diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index 7d6e55a82..eb0a02752 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -9,7 +9,9 @@ def_module_params('opt', ('print_model', BOOL, False, 'display model for satisfiable constraints'), ('print_all_models', BOOL, False, 'display all intermediary models for satisfiable constraints'), ('debug_conflict', BOOL, False, 'debug conflict resolution'), - ('wmaxsat_engine', SYMBOL, 'wmax', "weighted maxsat engine: 'wmax', 'iwmax' (iterative), 'bwmax' (bisection)"), + ('wmaxsat_engine', SYMBOL, 'wmax', "weighted maxsat engine: 'wmax', 'pbmax', 'bcd2', 'wpm2', 'bvsls', 'sls'"), + ('enable_sls', BOOL, False, 'enable SLS tuning during weighted maxsast'), + ('enable_sat', BOOL, False, 'enable the new SAT core for propositional constraints'), ('elim_01', BOOL, True, 'eliminate 01 variables'), ('pb.compile_equality', BOOL, False, 'compile arithmetical equalities into pseudo-Boolean equality (instead of two inequalites)') diff --git a/src/opt/opt_sls_solver.h b/src/opt/opt_sls_solver.h index bfeaad822..60a95b215 100644 --- a/src/opt/opt_sls_solver.h +++ b/src/opt/opt_sls_solver.h @@ -21,6 +21,7 @@ Notes: #define _OPT_SLS_SOLVER_H_ #include "solver_na2as.h" +#include "card2bv_tactic.h" namespace opt { @@ -28,15 +29,17 @@ namespace opt { ast_manager& m; ref m_solver; bvsls_opt_engine m_sls; + pb::card_pb_rewriter m_pb2bv; model_ref m_model; - expr_ref m_objective; + expr_ref m_objective; public: sls_solver(ast_manager & m, solver* s, expr* to_maximize, params_ref const& p): solver_na2as(m), m(m), m_solver(s), m_sls(m, p), - m_objective(to_maximize,m) + m_pb2bv(m), + m_objective(to_maximize, m) { } virtual ~sls_solver() {} @@ -52,8 +55,10 @@ namespace opt { // TBD: m_sls.get_stats(); } virtual void assert_expr(expr * t) { + expr_ref tmp(m); m_solver->assert_expr(t); - m_sls.assert_expr(t); + m_pb2bv(t, tmp); + m_sls.assert_expr(tmp); } virtual void get_unsat_core(ptr_vector & r) { m_solver->get_unsat_core(r); @@ -89,15 +94,16 @@ namespace opt { } protected: - virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) { + typedef bvsls_opt_engine::optimization_result opt_result; + + virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) { lbool r = m_solver->check_sat(num_assumptions, assumptions); if (r == l_true) { m_solver->get_model(m_model); - bvsls_opt_engine::optimization_result or(m); - or = m_sls.optimize(m_objective, m_model, true); - SASSERT(or.is_sat == l_true); + assertions2sls(); + opt_result or = m_sls.optimize(m_objective, m_model, true); + SASSERT(or.is_sat == l_true || or.is_sat == l_undef); m_sls.get_model(m_model); - or.optimum; } return r; } @@ -107,6 +113,26 @@ namespace opt { virtual void pop_core(unsigned n) { m_solver->pop(n); } + private: + void assertions2sls() { + expr_ref tmp(m); + goal_ref g(alloc(goal, m, true, false)); + for (unsigned i = 0; i < m_solver->get_num_assertions(); ++i) { + m_pb2bv(m_solver->get_assertion(i), tmp); + g->assert_expr(tmp); + } + tactic_ref simplify = mk_nnf_tactic(m); + proof_converter_ref pc; + expr_dependency_ref core(m); + goal_ref_buffer result; + model_converter_ref model_converter; + (*simplify)(g, result, model_converter, pc, core); + SASSERT(result.size() == 1); + goal* r = result[0]; + for (unsigned i = 0; i < r->size(); ++i) { + m_sls.assert_expr(r->form(i)); + } + } }; } diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index dc65ec09d..42a037b7d 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -50,6 +50,7 @@ namespace opt { protected: ref m_s; ast_manager& m; + pb::card_pb_rewriter pb_rewriter; volatile bool m_cancel; expr_ref_vector m_soft; vector m_weights; @@ -59,9 +60,12 @@ namespace opt { ref m_mc; // model converter to remove fresh variables svector m_assignment; // truth assignment to soft constraints params_ref m_params; // config + bool m_enable_sls; // config + bool m_enable_sat; // config public: maxsmt_solver_base(solver* s, ast_manager& m): - m_s(s), m(m), m_cancel(false), m_soft(m) {} + m_s(s), m(m), pb_rewriter(m), m_cancel(false), m_soft(m), + m_enable_sls(false), m_enable_sat(false) {} virtual ~maxsmt_solver_base() {} virtual rational get_lower() const { return m_lower; } @@ -73,6 +77,9 @@ namespace opt { virtual void updt_params(params_ref& p) { m_params = p; s().updt_params(p); + opt_params _p(p); + m_enable_sat = _p.enable_sat(); + m_enable_sls = _p.enable_sls(); } virtual void init_soft(vector const& weights, expr_ref_vector const& soft) { m_weights.reset(); @@ -101,6 +108,99 @@ namespace opt { return m.mk_not(e); } } + + struct is_bv { + struct found {}; + ast_manager& m; + pb_util pb; + bv_util bv; + is_bv(ast_manager& m): m(m), pb(m), bv(m) {} + void operator()(var *) { throw found(); } + void operator()(quantifier *) { throw found(); } + void operator()(app *n) { + family_id fid = n->get_family_id(); + if (fid != m.get_basic_family_id() && + fid != pb.get_family_id() && + fid != bv.get_family_id() && + !is_uninterp_const(n)) { + throw found(); + } + } + }; + + bool probe_bv() { + if (!m_enable_sat) return false; + expr_fast_mark1 visited; + is_bv proc(m); + try { + unsigned sz = s().get_num_assertions(); + for (unsigned i = 0; i < sz; i++) { + quick_for_each_expr(proc, visited, s().get_assertion(i)); + } + sz = m_soft.size(); + for (unsigned i = 0; i < sz; ++i) { + quick_for_each_expr(proc, visited, m_soft[i].get()); + } + } + catch (is_bv::found) { + return false; + } + return true; + } + + void enable_bvsat() { + if (probe_bv()) { + tactic_ref pb2bv = mk_card2bv_tactic(m, m_params); + tactic_ref bv2sat = mk_qfbv_tactic(m, m_params); + tactic_ref tac = and_then(pb2bv.get(), bv2sat.get()); + solver* sat_solver = mk_tactic2solver(m, tac.get(), m_params); + unsigned sz = s().get_num_assertions(); + for (unsigned i = 0; i < sz; ++i) { + sat_solver->assert_expr(s().get_assertion(i)); + } + m_s = sat_solver; + } + } + + void enable_sls() { + if (m_enable_sls && probe_bv()) { + expr_ref objective = soft2bv(); + m_params.set_uint("restarts", 20); + m_s = alloc(sls_solver, m, m_s.get(), objective, m_params); + } + } + + // convert soft constraints to bit-vector objective. + expr_ref soft2bv() { + rational upper(1); + expr_ref objective(m); + for (unsigned i = 0; i < m_weights.size(); ++i) { + upper += m_weights[i]; + } + expr_ref zero(m), tmp(m); + bv_util bv(m); + expr_ref_vector es(m); + rational num = numerator(upper); + rational den = denominator(upper); + rational maxval = num*den; + unsigned bv_size = maxval.get_num_bits(); + zero = bv.mk_numeral(rational(0), bv_size); + for (unsigned i = 0; i < m_soft.size(); ++i) { + pb_rewriter(m_soft[i].get(), tmp); + es.push_back(m.mk_ite(tmp, bv.mk_numeral(den*m_weights[i], bv_size), zero)); + } + if (es.empty()) { + objective = bv.mk_numeral(0, bv_size); + } + else { + objective = es[0].get(); + for (unsigned i = 1; i < es.size(); ++i) { + objective = bv.mk_bv_add(objective, es[i].get()); + } + } + return objective; + } + }; // ------------------------------------------------------ @@ -187,6 +287,7 @@ namespace opt { lbool is_sat = l_undef; expr_ref_vector asms(m); bool first = true; + enable_sls(); solver::scoped_push _scope1(s()); init(); init_bcd(); @@ -461,14 +562,16 @@ namespace opt { } }; - class pb_simplify_solve : public maxsmt_solver_base { + class pbmax : public maxsmt_solver_base { public: - pb_simplify_solve(solver* s, ast_manager& m): + pbmax(solver* s, ast_manager& m): maxsmt_solver_base(s, m) {} - virtual ~pb_simplify_solve() {} + virtual ~pbmax() {} lbool operator()() { + enable_bvsat(); + enable_sls(); TRACE("opt", s().display(tout); tout << "\n"; for (unsigned i = 0; i < m_soft.size(); ++i) { tout << mk_pp(m_soft[i].get(), m) << " " << m_weights[i] << "\n"; @@ -567,6 +670,7 @@ namespace opt { lbool operator()() { IF_VERBOSE(1, verbose_stream() << "(wmaxsat.wpm2 solve)\n";); + enable_sls(); solver::scoped_push _s(s()); pb_util u(m); app_ref fml(m), a(m), b(m), c(m); @@ -825,88 +929,28 @@ namespace opt { }; class bvsls : public maxsmt_solver_base { - bvsls_opt_engine m_bvsls; // used for bvsls improvements of assignment public: bvsls(solver* s, ast_manager& m): - maxsmt_solver_base(s, m), - m_bvsls(m, m_params) {} + maxsmt_solver_base(s, m) {} virtual ~bvsls() {} lbool operator()() { IF_VERBOSE(1, verbose_stream() << "(bvsls solve)\n";); - - bv_util bv(m); - pb::card_pb_rewriter pb_rewriter(m); - expr_ref tmp(m), objective(m), zero(m); - expr_ref_vector es(m); - - goal_ref g(alloc(goal, m, true, false)); - for (unsigned i = 0; i < s().get_num_assertions(); ++i) { - pb_rewriter(s().get_assertion(i), tmp); - g->assert_expr(tmp); - } - tactic_ref simplify = mk_nnf_tactic(m); - proof_converter_ref pc; - expr_dependency_ref core(m); - goal_ref_buffer result; - model_converter_ref model_converter; - (*simplify)(g, result, model_converter, pc, core); - SASSERT(result.size() == 1); - goal* r = result[0]; - for (unsigned i = 0; i < r->size(); ++i) { - m_bvsls.assert_expr(r->form(i)); - } - + enable_bvsat(); + enable_sls(); init(); - rational num = numerator(m_upper); - rational den = denominator(m_upper); - rational maxval = num*den; - unsigned bv_size = maxval.get_num_bits(); - zero = bv.mk_numeral(rational(0), bv_size); - for (unsigned i = 0; i < m_soft.size(); ++i) { - pb_rewriter(m_soft[i].get(), tmp); - es.push_back(m.mk_ite(tmp, bv.mk_numeral(den*m_weights[i], bv_size), zero)); - } - if (es.empty()) { - objective = bv.mk_numeral(0, bv_size); - } - else { - objective = es[0].get(); - for (unsigned i = 1; i < es.size(); ++i) { - objective = bv.mk_bv_add(objective, es[i].get()); - } - } lbool is_sat = s().check_sat(0, 0); if (is_sat == l_true) { s().get_model(m_model); - params_ref p; - p.set_uint("restarts", 20); - m_bvsls.updt_params(p); - bvsls_opt_engine::optimization_result res = m_bvsls.optimize(objective, m_model, true); - switch (res.is_sat) { - case l_true: { - unsigned bv_size = 0; - m_bvsls.get_model(m_model); - VERIFY(bv.is_numeral(res.optimum, m_lower, bv_size)); - for (unsigned i = 0; i < m_soft.size(); ++i) { - expr_ref tmp(m); - m_model->eval(m_soft[i].get(), tmp, true); - m_assignment[i] = m.is_true(tmp); + for (unsigned i = 0; i < m_soft.size(); ++i) { + expr_ref tmp(m); + m_model->eval(m_soft[i].get(), tmp, true); + m_assignment[i] = m.is_true(tmp); + if (!m_assignment[i]) { + m_upper += m_weights[i]; } - break; } - case l_false: - case l_undef: - break; - } - return res.is_sat; } - else { - return is_sat; - } - } - virtual void set_cancel(bool f) { - maxsmt_solver_base::set_cancel(f); - m_bvsls.set_cancel(f); + return is_sat; } }; @@ -962,7 +1006,6 @@ namespace opt { virtual ~wmax() {} lbool operator()() { - IF_VERBOSE(3, verbose_stream() << "(incremental solve)\n";); TRACE("opt", tout << "weighted maxsat\n";); scoped_ensure_theory wth(*this); solver::scoped_push _s(s()); @@ -971,9 +1014,9 @@ namespace opt { for (unsigned i = 0; i < m_soft.size(); ++i) { wth().assert_weighted(m_soft[i].get(), m_weights[i]); } - solver::scoped_push __s(s()); while (l_true == is_sat) { + IF_VERBOSE(1, verbose_stream() << "(wmax " << m_upper << ")\n";); is_sat = s().check_sat(0,0); if (m_cancel) { is_sat = l_undef; @@ -987,7 +1030,6 @@ namespace opt { s().assert_expr(fml); was_sat = true; } - IF_VERBOSE(3, verbose_stream() << "(incremental bound)\n";); } if (was_sat) { wth().get_assignment(m_assignment); @@ -1004,82 +1046,13 @@ namespace opt { } }; - class bvmax : public maxsmt_solver_base { - solver* mk_sat_solver() { - tactic_ref pb2bv = mk_card2bv_tactic(m, m_params); - tactic_ref bv2sat = mk_qfbv_tactic(m, m_params); - tactic_ref tac = and_then(pb2bv.get(), bv2sat.get()); - solver* sat_solver = mk_tactic2solver(m, tac.get(), m_params); - unsigned sz = s().get_num_assertions(); - for (unsigned i = 0; i < sz; ++i) { - sat_solver->assert_expr(s().get_assertion(i)); - } - return sat_solver; - } - public: - bvmax(solver* s, ast_manager& m): maxsmt_solver_base(s, m) { - m_s = mk_sat_solver(); - } - virtual ~bvmax() {} - - // - // convert bounds constraint into pseudo-Boolean, - // then treat pseudo-Booleans as bit-vectors and - // sorting circuits. - // - lbool operator()() { - IF_VERBOSE(1, verbose_stream() << "(wmaxsat.bv solve)\n";); - pb_util u(m); - expr_ref fml(m), val(m); - app_ref b(m); - expr_ref_vector nsoft(m); - init(); - for (unsigned i = 0; i < m_soft.size(); ++i) { - b = m.mk_fresh_const("b", m.mk_bool_sort()); - m_mc->insert(b->get_decl()); - fml = m.mk_or(m_soft[i].get(), b); - s().assert_expr(fml); - nsoft.push_back(b); - } - lbool is_sat = l_true; - bool was_sat = false; - fml = m.mk_true(); - while (l_true == is_sat) { - solver::scoped_push __s(s()); - s().assert_expr(fml); - is_sat = s().check_sat(0,0); - if (m_cancel) { - is_sat = l_undef; - } - if (is_sat == l_true) { - s().get_model(m_model); - m_upper = rational::zero(); - for (unsigned i = 0; i < m_soft.size(); ++i) { - VERIFY(m_model->eval(nsoft[i].get(), val)); - m_assignment[i] = !m.is_true(val); - if (!m_assignment[i]) { - m_upper += m_weights[i]; - } - } - IF_VERBOSE(1, verbose_stream() << "(wmaxsat.bv with upper bound: " << m_upper << ")\n";); - fml = m.mk_not(u.mk_ge(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper)); - was_sat = true; - } - } - if (is_sat == l_false && was_sat) { - is_sat = l_true; - m_lower = m_upper; - } - return is_sat; - } - - }; - class pwmax : public maxsmt_solver_base { public: pwmax(solver* s, ast_manager& m): maxsmt_solver_base(s, m) {} virtual ~pwmax() {} lbool operator()() { + enable_bvsat(); + enable_sls(); pb_util u(m); expr_ref fml(m), val(m); app_ref b(m); @@ -1151,17 +1124,14 @@ namespace opt { if (m_maxsmt) { return *m_maxsmt; } - else if (m_engine == symbol("pwmax")) { + if (m_engine == symbol("pwmax")) { m_maxsmt = alloc(pwmax, s.get(), m); } - else if (m_engine == symbol("bvmax")) { - m_maxsmt = alloc(bvmax, s.get(), m); - } - else if (m_engine == symbol("pb")) { - m_maxsmt = alloc(pb_simplify_solve, s.get(), m); + else if (m_engine == symbol("pbmax")) { + m_maxsmt = alloc(pbmax, s.get(), m); } else if (m_engine == symbol("wpm2")) { - maxsmt_solver_base* s2 = alloc(pb_simplify_solve, s.get(), m); + maxsmt_solver_base* s2 = alloc(pbmax, s.get(), m); m_maxsmt = alloc(wpm2, s.get(), m, s2); } else if (m_engine == symbol("bcd2")) { @@ -1170,6 +1140,9 @@ namespace opt { else if (m_engine == symbol("bvsls")) { m_maxsmt = alloc(bvsls, s.get(), m); } + else if (m_engine == symbol("sls")) { + m_maxsmt = alloc(sls, s.get(), m); + } else if (m_engine == symbol::null || m_engine == symbol("wmax")) { m_maxsmt = alloc(wmax, s.get(), m, s->get_context()); } @@ -1345,7 +1318,7 @@ namespace opt { // Version from CP'13 lbool wpm2b_solve() { IF_VERBOSE(1, verbose_stream() << "(wmaxsat.wpm2b solve)\n";); - solver::scoped_push _s(s); + solver::scoped_push _s(s()); pb_util u(m); app_ref fml(m), a(m), b(m), c(m); expr_ref val(m); From ff154a09b3fdcf649753c505ddb903a9877acfd4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Apr 2014 12:12:51 -0700 Subject: [PATCH 368/925] sls Signed-off-by: Nikolaj Bjorner --- src/opt/opt_sls_solver.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/opt/opt_sls_solver.h b/src/opt/opt_sls_solver.h index 60a95b215..0873b4f01 100644 --- a/src/opt/opt_sls_solver.h +++ b/src/opt/opt_sls_solver.h @@ -55,10 +55,7 @@ namespace opt { // TBD: m_sls.get_stats(); } virtual void assert_expr(expr * t) { - expr_ref tmp(m); m_solver->assert_expr(t); - m_pb2bv(t, tmp); - m_sls.assert_expr(tmp); } virtual void get_unsat_core(ptr_vector & r) { m_solver->get_unsat_core(r); From b30004107572257e37ebacd536a9255cc2e1d932 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Apr 2014 16:52:57 -0700 Subject: [PATCH 369/925] resetting SLS engine between calls, moved statistics collection to engine Signed-off-by: Nikolaj Bjorner --- src/opt/opt_sls_solver.h | 30 ++++++++++++++++++++++-------- src/opt/weighted_maxsat.cpp | 2 +- src/tactic/sls/sls_engine.cpp | 14 ++++++++++++++ src/tactic/sls/sls_engine.h | 4 +++- src/tactic/sls/sls_tactic.cpp | 13 +------------ 5 files changed, 41 insertions(+), 22 deletions(-) diff --git a/src/opt/opt_sls_solver.h b/src/opt/opt_sls_solver.h index 0873b4f01..542728cc4 100644 --- a/src/opt/opt_sls_solver.h +++ b/src/opt/opt_sls_solver.h @@ -28,16 +28,17 @@ namespace opt { class sls_solver : public solver_na2as { ast_manager& m; ref m_solver; - bvsls_opt_engine m_sls; + scoped_ptr m_sls; pb::card_pb_rewriter m_pb2bv; model_ref m_model; expr_ref m_objective; + params_ref m_params; public: sls_solver(ast_manager & m, solver* s, expr* to_maximize, params_ref const& p): solver_na2as(m), m(m), m_solver(s), - m_sls(m, p), + m_sls(0), m_pb2bv(m), m_objective(to_maximize, m) { @@ -46,13 +47,14 @@ namespace opt { virtual void updt_params(params_ref & p) { m_solver->updt_params(p); + m_params.copy(p); } virtual void collect_param_descrs(param_descrs & r) { m_solver->collect_param_descrs(r); } virtual void collect_statistics(statistics & st) const { m_solver->collect_statistics(st); - // TBD: m_sls.get_stats(); + // TBD: m_sls->get_stats(); } virtual void assert_expr(expr * t) { m_solver->assert_expr(t); @@ -74,7 +76,13 @@ namespace opt { } virtual void set_cancel(bool f) { m_solver->set_cancel(f); - m_sls.set_cancel(f); + m_pb2bv.set_cancel(f); + #pragma omp critical (this) + { + if (m_sls) { + m_sls->set_cancel(f); + } + } } virtual void set_progress_callback(progress_callback * callback) { m_solver->set_progress_callback(callback); @@ -87,7 +95,7 @@ namespace opt { } virtual void display(std::ostream & out) const { m_solver->display(out); - // m_sls.display(out); + // if (m_sls) m_sls->display(out); } protected: @@ -97,10 +105,16 @@ namespace opt { lbool r = m_solver->check_sat(num_assumptions, assumptions); if (r == l_true) { m_solver->get_model(m_model); + #pragma omp critical (this) + { + m_sls = alloc(bvsls_opt_engine, m, m_params); + } assertions2sls(); - opt_result or = m_sls.optimize(m_objective, m_model, true); + opt_result or = m_sls->optimize(m_objective, m_model, true); SASSERT(or.is_sat == l_true || or.is_sat == l_undef); - m_sls.get_model(m_model); + if (or.is_sat == l_true) { + m_sls->get_model(m_model); + } } return r; } @@ -127,7 +141,7 @@ namespace opt { SASSERT(result.size() == 1); goal* r = result[0]; for (unsigned i = 0; i < r->size(); ++i) { - m_sls.assert_expr(r->form(i)); + m_sls->assert_expr(r->form(i)); } } diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 42a037b7d..ea3515ec7 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -75,7 +75,7 @@ namespace opt { virtual void collect_statistics(statistics& st) const { } virtual void get_model(model_ref& mdl) { mdl = m_model.get(); } virtual void updt_params(params_ref& p) { - m_params = p; + m_params.copy(p); s().updt_params(p); opt_params _p(p); m_enable_sat = _p.enable_sat(); diff --git a/src/tactic/sls/sls_engine.cpp b/src/tactic/sls/sls_engine.cpp index dc4451bb5..7c85f3bd6 100644 --- a/src/tactic/sls/sls_engine.cpp +++ b/src/tactic/sls/sls_engine.cpp @@ -68,6 +68,20 @@ void sls_engine::updt_params(params_ref const & _p) { m_plateau_limit = p.plateau_limit(); } +void sls_engine::collect_statistics(statistics& st) const { + double seconds = m_stats.m_stopwatch.get_current_seconds(); + st.update("sls restarts", m_stats.m_restarts); + st.update("sls full evals", m_stats.m_full_evals); + st.update("sls incr evals", m_stats.m_incr_evals); + st.update("sls incr evals/sec", m_stats.m_incr_evals / seconds); + st.update("sls FLIP moves", m_stats.m_flips); + st.update("sls INC moves", m_stats.m_incs); + st.update("sls DEC moves", m_stats.m_decs); + st.update("sls INV moves", m_stats.m_invs); + st.update("sls moves", m_stats.m_moves); + st.update("sls moves/sec", m_stats.m_moves / seconds); +} + void sls_engine::checkpoint() { if (m_cancel) throw tactic_exception(TACTIC_CANCELED_MSG); diff --git a/src/tactic/sls/sls_engine.h b/src/tactic/sls/sls_engine.h index c6e3af155..9a5e905b3 100644 --- a/src/tactic/sls/sls_engine.h +++ b/src/tactic/sls/sls_engine.h @@ -27,6 +27,7 @@ Notes: #include"sls_compilation_settings.h" #include"sls_tracker.h" #include"sls_evaluator.h" +#include"statistics.h" class sls_engine { public: @@ -96,7 +97,8 @@ public: void assert_expr(expr * e) { m_assertions.push_back(e); } - stats const & get_stats(void) { return m_stats; } + // stats const & get_stats(void) { return m_stats; } + void collect_statistics(statistics & st) const; void reset_statistics(void) { m_stats.reset(); } bool full_eval(model & mdl); diff --git a/src/tactic/sls/sls_tactic.cpp b/src/tactic/sls/sls_tactic.cpp index a9b110224..464a0925c 100644 --- a/src/tactic/sls/sls_tactic.cpp +++ b/src/tactic/sls/sls_tactic.cpp @@ -93,18 +93,7 @@ public: } virtual void collect_statistics(statistics & st) const { - sls_engine::stats const & stats = m_engine->get_stats(); - double seconds = stats.m_stopwatch.get_current_seconds(); - st.update("sls restarts", stats.m_restarts); - st.update("sls full evals", stats.m_full_evals); - st.update("sls incr evals", stats.m_incr_evals); - st.update("sls incr evals/sec", stats.m_incr_evals / seconds); - st.update("sls FLIP moves", stats.m_flips); - st.update("sls INC moves", stats.m_incs); - st.update("sls DEC moves", stats.m_decs); - st.update("sls INV moves", stats.m_invs); - st.update("sls moves", stats.m_moves); - st.update("sls moves/sec", stats.m_moves / seconds); + m_engine->collect_statistics(st); } virtual void reset_statistics() { From 3f5ed8ff1109754a2972da626dbd1d6e0c7e3265 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Apr 2014 20:27:39 -0700 Subject: [PATCH 370/925] coallesce common code Signed-off-by: Nikolaj Bjorner --- src/opt/opt_params.pyg | 1 + src/opt/opt_sls_solver.h | 73 +++++++++++++++---- src/opt/pb_sls.cpp | 2 +- src/opt/pb_sls.h | 2 +- src/opt/weighted_maxsat.cpp | 140 ++++++++++-------------------------- 5 files changed, 97 insertions(+), 121 deletions(-) diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index eb0a02752..201a1601b 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -12,6 +12,7 @@ def_module_params('opt', ('wmaxsat_engine', SYMBOL, 'wmax', "weighted maxsat engine: 'wmax', 'pbmax', 'bcd2', 'wpm2', 'bvsls', 'sls'"), ('enable_sls', BOOL, False, 'enable SLS tuning during weighted maxsast'), ('enable_sat', BOOL, False, 'enable the new SAT core for propositional constraints'), + ('sls_engine', SYMBOL, 'bv', "SLS engine. Either 'bv' or 'pb'"), ('elim_01', BOOL, True, 'eliminate 01 variables'), ('pb.compile_equality', BOOL, False, 'compile arithmetical equalities into pseudo-Boolean equality (instead of two inequalites)') diff --git a/src/opt/opt_sls_solver.h b/src/opt/opt_sls_solver.h index 542728cc4..63810e974 100644 --- a/src/opt/opt_sls_solver.h +++ b/src/opt/opt_sls_solver.h @@ -22,23 +22,27 @@ Notes: #include "solver_na2as.h" #include "card2bv_tactic.h" +#include "pb_sls.h" namespace opt { class sls_solver : public solver_na2as { ast_manager& m; ref m_solver; - scoped_ptr m_sls; + scoped_ptr m_bvsls; + scoped_ptr m_pbsls; pb::card_pb_rewriter m_pb2bv; model_ref m_model; expr_ref m_objective; params_ref m_params; + symbol m_engine; public: sls_solver(ast_manager & m, solver* s, expr* to_maximize, params_ref const& p): solver_na2as(m), m(m), m_solver(s), - m_sls(0), + m_bvsls(0), + m_pbsls(0), m_pb2bv(m), m_objective(to_maximize, m) { @@ -48,13 +52,16 @@ namespace opt { virtual void updt_params(params_ref & p) { m_solver->updt_params(p); m_params.copy(p); + opt_params _p(p); + m_engine = _p.sls_engine(); } virtual void collect_param_descrs(param_descrs & r) { m_solver->collect_param_descrs(r); } virtual void collect_statistics(statistics & st) const { m_solver->collect_statistics(st); - // TBD: m_sls->get_stats(); + if (m_bvsls) m_bvsls->collect_statistics(st); + if (m_pbsls) m_pbsls->collect_statistics(st); } virtual void assert_expr(expr * t) { m_solver->assert_expr(t); @@ -79,8 +86,11 @@ namespace opt { m_pb2bv.set_cancel(f); #pragma omp critical (this) { - if (m_sls) { - m_sls->set_cancel(f); + if (m_bvsls) { + m_bvsls->set_cancel(f); + } + if (m_pbsls) { + m_pbsls->set_cancel(f); } } } @@ -95,7 +105,7 @@ namespace opt { } virtual void display(std::ostream & out) const { m_solver->display(out); - // if (m_sls) m_sls->display(out); + // if (m_bvsls) m_bvsls->display(out); } protected: @@ -105,15 +115,11 @@ namespace opt { lbool r = m_solver->check_sat(num_assumptions, assumptions); if (r == l_true) { m_solver->get_model(m_model); - #pragma omp critical (this) - { - m_sls = alloc(bvsls_opt_engine, m, m_params); + if (m_engine == symbol("pb")) { + } - assertions2sls(); - opt_result or = m_sls->optimize(m_objective, m_model, true); - SASSERT(or.is_sat == l_true || or.is_sat == l_undef); - if (or.is_sat == l_true) { - m_sls->get_model(m_model); + else { + bvsls_opt(); } } return r; @@ -124,6 +130,7 @@ namespace opt { virtual void pop_core(unsigned n) { m_solver->pop(n); } + private: void assertions2sls() { expr_ref tmp(m); @@ -141,7 +148,43 @@ namespace opt { SASSERT(result.size() == 1); goal* r = result[0]; for (unsigned i = 0; i < r->size(); ++i) { - m_sls->assert_expr(r->form(i)); + m_bvsls->assert_expr(r->form(i)); + } + } + + void pbsls_opt() { + #pragma omp critical (this) + { + m_pbsls = alloc(smt::pb_sls, m); + } + m_pbsls->set_model(m_model); + m_pbsls->updt_params(m_params); + for (unsigned i = 0; i < m_solver->get_num_assertions(); ++i) { + m_pbsls->add(m_solver->get_assertion(i)); + } +#if 0 + TBD: + for (unsigned i = 0; i < m_num_soft; ++i) { + m_pbsls->add(m_soft[i].get(), m_weights[i].get()); + } +#endif + + lbool is_sat = (*m_pbsls.get())(); + if (is_sat == l_true) { + m_bvsls->get_model(m_model); + } + } + + void bvsls_opt() { + #pragma omp critical (this) + { + m_bvsls = alloc(bvsls_opt_engine, m, m_params); + } + assertions2sls(); + opt_result or = m_bvsls->optimize(m_objective, m_model, true); + SASSERT(or.is_sat == l_true || or.is_sat == l_undef); + if (or.is_sat == l_true) { + m_bvsls->get_model(m_model); } } diff --git a/src/opt/pb_sls.cpp b/src/opt/pb_sls.cpp index c7c0c1032..d000350e5 100644 --- a/src/opt/pb_sls.cpp +++ b/src/opt/pb_sls.cpp @@ -233,7 +233,7 @@ namespace smt { } } - void collect_statistics(statistics& st) const { + void collect_statistics(::statistics& st) const { } void updt_params(params_ref& p) { diff --git a/src/opt/pb_sls.h b/src/opt/pb_sls.h index a65ed83bf..c8d2c60c2 100644 --- a/src/opt/pb_sls.h +++ b/src/opt/pb_sls.h @@ -39,7 +39,7 @@ namespace smt { void set_model(model_ref& mdl); lbool operator()(); void set_cancel(bool f); - void collect_statistics(statistics& st) const; + void collect_statistics(::statistics& st) const; void get_model(model_ref& mdl); void updt_params(params_ref& p); }; diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index ea3515ec7..d9a5eae11 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -562,10 +562,15 @@ namespace opt { } }; + // ---------------------------------- + // incrementally add pseudo-boolean + // lower bounds. + class pbmax : public maxsmt_solver_base { + bool m_use_aux; public: - pbmax(solver* s, ast_manager& m): - maxsmt_solver_base(s, m) {} + pbmax(solver* s, ast_manager& m, bool use_aux): + maxsmt_solver_base(s, m), m_use_aux(use_aux) {} virtual ~pbmax() {} @@ -579,29 +584,41 @@ namespace opt { ); pb_util u(m); expr_ref fml(m), val(m); + app_ref b(m); expr_ref_vector nsoft(m); init(); - for (unsigned i = 0; i < m_soft.size(); ++i) { - nsoft.push_back(mk_not(m_soft[i].get())); + if (m_use_aux) { + s().push(); + } + for (unsigned i = 0; i < m_soft.size(); ++i) { + if (m_use_aux) { + b = m.mk_fresh_const("b", m.mk_bool_sort()); + m_mc->insert(b->get_decl()); + fml = m.mk_or(m_soft[i].get(), b); + s().assert_expr(fml); + nsoft.push_back(b); + } + else { + nsoft.push_back(mk_not(m_soft[i].get())); + } } - solver::scoped_push _s1(s()); lbool is_sat = l_true; bool was_sat = false; fml = m.mk_true(); while (l_true == is_sat) { TRACE("opt", s().display(tout<<"looping\n");); - solver::scoped_push _s2(s()); + solver::scoped_push _scope2(s()); s().assert_expr(fml); - is_sat = simplify_and_check_sat(); + is_sat = s().check_sat(0,0); if (m_cancel) { is_sat = l_undef; } if (is_sat == l_true) { - m_upper = rational::zero(); + m_upper.reset(); for (unsigned i = 0; i < m_soft.size(); ++i) { - VERIFY(m_model->eval(m_soft[i].get(), val)); + VERIFY(m_model->eval(nsoft[i].get(), val)); TRACE("opt", tout << "eval " << mk_pp(m_soft[i].get(), m) << " " << val << "\n";); - m_assignment[i] = m.is_true(val); + m_assignment[i] = !m.is_true(val); if (!m_assignment[i]) { m_upper += m_weights[i]; } @@ -616,46 +633,12 @@ namespace opt { is_sat = l_true; m_lower = m_upper; } + if (m_use_aux) { + s().pop(1); + } TRACE("opt", tout << "lower: " << m_lower << "\n";); return is_sat; } - - private: - lbool simplify_and_check_sat() { - lbool is_sat = l_true; - tactic_ref tac = mk_simplify_tactic(m); - // TBD: make tac attribute for cancelation. - proof_converter_ref pc; - expr_dependency_ref core(m); - model_converter_ref mc; - goal_ref_buffer result; - goal_ref g(alloc(goal, m, true, false)); - for (unsigned i = 0; i < s().get_num_assertions(); ++i) { - g->assert_expr(s().get_assertion(i)); - } - (*tac)(g, result, mc, pc, core); - if (result.empty()) { - is_sat = l_false; - } - else { - SASSERT(result.size() == 1); - goal_ref r = result[0]; - solver::scoped_push _s(s()); - for (unsigned i = 0; i < r->size(); ++i) { - s().assert_expr(r->form(i)); - } - is_sat = s().check_sat(0, 0); - if (l_true == is_sat && !m_cancel) { - s().get_model(m_model); - if (mc && m_model) (*mc)(m_model, 0); - IF_VERBOSE(2, - g->display(verbose_stream() << "goal:\n"); - r->display(verbose_stream() << "reduced:\n"); - model_smt2_pp(verbose_stream(), m, *m_model, 0);); - } - } - return is_sat; - } }; // ------------------------------------------------------ @@ -998,6 +981,9 @@ namespace opt { } }; + // ---------------------------------------------------------- + // weighted max-sat using a custom theory solver for max-sat. + // NB. it is quite similar to pseudo-Boolean propagation. class wmax : public maxsmt_solver_wbase { @@ -1046,60 +1032,6 @@ namespace opt { } }; - class pwmax : public maxsmt_solver_base { - public: - pwmax(solver* s, ast_manager& m): maxsmt_solver_base(s, m) {} - virtual ~pwmax() {} - lbool operator()() { - enable_bvsat(); - enable_sls(); - pb_util u(m); - expr_ref fml(m), val(m); - app_ref b(m); - expr_ref_vector nsoft(m); - solver::scoped_push __s(s()); - init(); - for (unsigned i = 0; i < m_soft.size(); ++i) { - b = m.mk_fresh_const("b", m.mk_bool_sort()); - m_mc->insert(b->get_decl()); - fml = m.mk_or(m_soft[i].get(), b); - s().assert_expr(fml); - nsoft.push_back(b); - } - lbool is_sat = l_true; - bool was_sat = false; - fml = m.mk_true(); - while (l_true == is_sat) { - solver::scoped_push _s(s()); - s().assert_expr(fml); - is_sat = s().check_sat(0,0); - if (m_cancel) { - is_sat = l_undef; - } - if (is_sat == l_true) { - s().get_model(m_model); - m_upper = rational::zero(); - for (unsigned i = 0; i < m_soft.size(); ++i) { - VERIFY(m_model->eval(nsoft[i].get(), val)); - m_assignment[i] = !m.is_true(val); - if (!m_assignment[i]) { - m_upper += m_weights[i]; - } - } - IF_VERBOSE(1, verbose_stream() << "(wmaxsat.pb with upper bound: " << m_upper << ")\n";); - fml = m.mk_not(u.mk_ge(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper)); - was_sat = true; - } - } - if (is_sat == l_false && was_sat) { - is_sat = l_true; - m_lower = m_upper; - } - return is_sat; - } - - }; - struct wmaxsmt::imp { ast_manager& m; ref s; // solver state that contains hard constraints @@ -1125,13 +1057,13 @@ namespace opt { return *m_maxsmt; } if (m_engine == symbol("pwmax")) { - m_maxsmt = alloc(pwmax, s.get(), m); + m_maxsmt = alloc(pbmax, s.get(), m, true); } else if (m_engine == symbol("pbmax")) { - m_maxsmt = alloc(pbmax, s.get(), m); + m_maxsmt = alloc(pbmax, s.get(), m, false); } else if (m_engine == symbol("wpm2")) { - maxsmt_solver_base* s2 = alloc(pbmax, s.get(), m); + maxsmt_solver_base* s2 = alloc(pbmax, s.get(), m, false); m_maxsmt = alloc(wpm2, s.get(), m, s2); } else if (m_engine == symbol("bcd2")) { From 1f66e46c671a972b9da9663b84edcb08f82eada5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Apr 2014 20:50:44 -0700 Subject: [PATCH 371/925] move sls functionality to solver Signed-off-by: Nikolaj Bjorner --- src/opt/opt_sls_solver.h | 57 ++++++++++++++---- src/opt/weighted_maxsat.cpp | 116 ++---------------------------------- 2 files changed, 51 insertions(+), 122 deletions(-) diff --git a/src/opt/opt_sls_solver.h b/src/opt/opt_sls_solver.h index 63810e974..f33282fa2 100644 --- a/src/opt/opt_sls_solver.h +++ b/src/opt/opt_sls_solver.h @@ -23,6 +23,8 @@ Notes: #include "solver_na2as.h" #include "card2bv_tactic.h" #include "pb_sls.h" +#include "bvsls_opt_engine.h" + namespace opt { @@ -32,19 +34,24 @@ namespace opt { scoped_ptr m_bvsls; scoped_ptr m_pbsls; pb::card_pb_rewriter m_pb2bv; + vector m_weights; + expr_ref_vector m_soft; model_ref m_model; - expr_ref m_objective; params_ref m_params; symbol m_engine; public: - sls_solver(ast_manager & m, solver* s, expr* to_maximize, params_ref const& p): + sls_solver(ast_manager & m, solver* s, + expr_ref_vector const& soft, + vector const& weights, + params_ref const& p): solver_na2as(m), m(m), m_solver(s), m_bvsls(0), m_pbsls(0), m_pb2bv(m), - m_objective(to_maximize, m) + m_weights(weights), + m_soft(soft) { } virtual ~sls_solver() {} @@ -116,7 +123,7 @@ namespace opt { if (r == l_true) { m_solver->get_model(m_model); if (m_engine == symbol("pb")) { - + pbsls_opt(); } else { bvsls_opt(); @@ -132,6 +139,37 @@ namespace opt { } private: + // convert soft constraints to bit-vector objective. + expr_ref soft2bv() { + rational upper(1); + expr_ref objective(m); + for (unsigned i = 0; i < m_weights.size(); ++i) { + upper += m_weights[i]; + } + expr_ref zero(m), tmp(m); + bv_util bv(m); + expr_ref_vector es(m); + rational num = numerator(upper); + rational den = denominator(upper); + rational maxval = num*den; + unsigned bv_size = maxval.get_num_bits(); + zero = bv.mk_numeral(rational(0), bv_size); + for (unsigned i = 0; i < m_soft.size(); ++i) { + m_pb2bv(m_soft[i].get(), tmp); + es.push_back(m.mk_ite(tmp, bv.mk_numeral(den*m_weights[i], bv_size), zero)); + } + if (es.empty()) { + objective = bv.mk_numeral(0, bv_size); + } + else { + objective = es[0].get(); + for (unsigned i = 1; i < es.size(); ++i) { + objective = bv.mk_bv_add(objective, es[i].get()); + } + } + return objective; + } + void assertions2sls() { expr_ref tmp(m); goal_ref g(alloc(goal, m, true, false)); @@ -162,13 +200,9 @@ namespace opt { for (unsigned i = 0; i < m_solver->get_num_assertions(); ++i) { m_pbsls->add(m_solver->get_assertion(i)); } -#if 0 - TBD: - for (unsigned i = 0; i < m_num_soft; ++i) { - m_pbsls->add(m_soft[i].get(), m_weights[i].get()); + for (unsigned i = 0; i < m_soft.size(); ++i) { + m_pbsls->add(m_soft[i].get(), m_weights[i]); } -#endif - lbool is_sat = (*m_pbsls.get())(); if (is_sat == l_true) { m_bvsls->get_model(m_model); @@ -181,7 +215,8 @@ namespace opt { m_bvsls = alloc(bvsls_opt_engine, m, m_params); } assertions2sls(); - opt_result or = m_bvsls->optimize(m_objective, m_model, true); + expr_ref objective = soft2bv(); + opt_result or = m_bvsls->optimize(objective, m_model, true); SASSERT(or.is_sat == l_true || or.is_sat == l_undef); if (or.is_sat == l_true) { m_bvsls->get_model(m_model); diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index d9a5eae11..9862c2b28 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -35,7 +35,6 @@ Notes: #include "qfbv_tactic.h" #include "card2bv_tactic.h" #include "tactic2solver.h" -#include "bvsls_opt_engine.h" #include "nnf_tactic.h" #include "opt_sls_solver.h" @@ -50,7 +49,6 @@ namespace opt { protected: ref m_s; ast_manager& m; - pb::card_pb_rewriter pb_rewriter; volatile bool m_cancel; expr_ref_vector m_soft; vector m_weights; @@ -64,7 +62,7 @@ namespace opt { bool m_enable_sat; // config public: maxsmt_solver_base(solver* s, ast_manager& m): - m_s(s), m(m), pb_rewriter(m), m_cancel(false), m_soft(m), + m_s(s), m(m), m_cancel(false), m_soft(m), m_enable_sls(false), m_enable_sat(false) {} virtual ~maxsmt_solver_base() {} @@ -164,42 +162,11 @@ namespace opt { void enable_sls() { if (m_enable_sls && probe_bv()) { - expr_ref objective = soft2bv(); m_params.set_uint("restarts", 20); - m_s = alloc(sls_solver, m, m_s.get(), objective, m_params); + m_s = alloc(sls_solver, m, m_s.get(), m_soft, m_weights, m_params); } } - // convert soft constraints to bit-vector objective. - expr_ref soft2bv() { - rational upper(1); - expr_ref objective(m); - for (unsigned i = 0; i < m_weights.size(); ++i) { - upper += m_weights[i]; - } - expr_ref zero(m), tmp(m); - bv_util bv(m); - expr_ref_vector es(m); - rational num = numerator(upper); - rational den = denominator(upper); - rational maxval = num*den; - unsigned bv_size = maxval.get_num_bits(); - zero = bv.mk_numeral(rational(0), bv_size); - for (unsigned i = 0; i < m_soft.size(); ++i) { - pb_rewriter(m_soft[i].get(), tmp); - es.push_back(m.mk_ite(tmp, bv.mk_numeral(den*m_weights[i], bv_size), zero)); - } - if (es.empty()) { - objective = bv.mk_numeral(0, bv_size); - } - else { - objective = es[0].get(); - for (unsigned i = 1; i < es.size(); ++i) { - objective = bv.mk_bv_add(objective, es[i].get()); - } - } - return objective; - } }; @@ -841,83 +808,12 @@ namespace opt { }; class sls : public maxsmt_solver_base { - smt::pb_sls m_sls; // used for sls improvement of assignment public: - sls(solver* s, ast_manager& m): maxsmt_solver_base(s, m), m_sls(m) {} + sls(solver* s, ast_manager& m): + maxsmt_solver_base(s, m) {} virtual ~sls() {} lbool operator()() { IF_VERBOSE(1, verbose_stream() << "(sls solve)\n";); - for (unsigned i = 0; i < s().get_num_assertions(); ++i) { - m_sls.add(s().get_assertion(i)); - } - pb_util u(m); - expr_ref fml(m), val(m); - app_ref b(m); - expr_ref_vector nsoft(m); - init(); - solver::scoped_push __s(s()); - for (unsigned i = 0; i < m_soft.size(); ++i) { - b = m.mk_fresh_const("b", m.mk_bool_sort()); - m_mc->insert(b->get_decl()); - fml = m.mk_or(m_soft[i].get(), b); - s().assert_expr(fml); - nsoft.push_back(b); - m_sls.add(m_soft[i].get(), m_weights[i]); - } - lbool is_sat = l_true; - bool was_sat = false; - while (l_true == is_sat) { - is_sat = s().check_sat(0,0); - if (m_cancel) { - is_sat = l_undef; - } - if (is_sat == l_true) { - s().get_model(m_model); - m_sls.set_model(m_model); - m_upper = rational::zero(); - if (l_true == m_sls()) { - m_sls.get_model(m_model); - for (unsigned i = 0; i < m_soft.size(); ++i) { - m_assignment[i] = m_sls.soft_holds(i); - } - } - else { - for (unsigned i = 0; i < m_soft.size(); ++i) { - VERIFY(m_model->eval(nsoft[i].get(), val)); - m_assignment[i] = !m.is_true(val); - } - } - for (unsigned i = 0; i < m_soft.size(); ++i) { - if (!m_assignment[i]) { - m_upper += m_weights[i]; - } - } - IF_VERBOSE(1, verbose_stream() << "(sls.pb with upper bound: " << m_upper << ")\n";); - fml = m.mk_not(u.mk_ge(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper)); - s().assert_expr(fml); - was_sat = true; - } - } - if (is_sat == l_false && was_sat) { - is_sat = l_true; - m_lower = m_upper; - } - return is_sat; - } - - virtual void set_cancel(bool f) { - maxsmt_solver_base::set_cancel(f); - m_sls.set_cancel(f); - } - }; - - class bvsls : public maxsmt_solver_base { - public: - bvsls(solver* s, ast_manager& m): - maxsmt_solver_base(s, m) {} - virtual ~bvsls() {} - lbool operator()() { - IF_VERBOSE(1, verbose_stream() << "(bvsls solve)\n";); enable_bvsat(); enable_sls(); init(); @@ -1069,9 +965,7 @@ namespace opt { else if (m_engine == symbol("bcd2")) { m_maxsmt = alloc(bcd2, s.get(), m); } - else if (m_engine == symbol("bvsls")) { - m_maxsmt = alloc(bvsls, s.get(), m); - } + // TBD: this is experimental one-round version of SLS else if (m_engine == symbol("sls")) { m_maxsmt = alloc(sls, s.get(), m); } From beaa50e0d803fb4ad1f0581efc2bbdea5488cbef Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 21 Apr 2014 18:07:02 +0200 Subject: [PATCH 372/925] fixing sls Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 2 +- src/opt/opt_sls_solver.h | 14 ++- src/opt/pb_sls.cpp | 172 ++++++++++++++++++++++++++++-------- src/opt/weighted_maxsat.cpp | 7 +- tests/chat1.smt2 | 2 +- 5 files changed, 150 insertions(+), 47 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 547f90bd7..a16654614 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -957,7 +957,7 @@ namespace opt { break; } } - out << "(optimize)\n"; + out << "(check-sat)\n"; return out.str(); } diff --git a/src/opt/opt_sls_solver.h b/src/opt/opt_sls_solver.h index f33282fa2..001a33ed4 100644 --- a/src/opt/opt_sls_solver.h +++ b/src/opt/opt_sls_solver.h @@ -43,7 +43,7 @@ namespace opt { sls_solver(ast_manager & m, solver* s, expr_ref_vector const& soft, vector const& weights, - params_ref const& p): + params_ref & p): solver_na2as(m), m(m), m_solver(s), @@ -53,6 +53,7 @@ namespace opt { m_weights(weights), m_soft(soft) { + updt_params(p); } virtual ~sls_solver() {} @@ -89,6 +90,7 @@ namespace opt { m_solver->get_labels(r); } virtual void set_cancel(bool f) { + std::cout << "set cancel\n"; m_solver->set_cancel(f); m_pb2bv.set_cancel(f); #pragma omp critical (this) @@ -205,7 +207,7 @@ namespace opt { } lbool is_sat = (*m_pbsls.get())(); if (is_sat == l_true) { - m_bvsls->get_model(m_model); + m_pbsls->get_model(m_model); } } @@ -216,7 +218,13 @@ namespace opt { } assertions2sls(); expr_ref objective = soft2bv(); - opt_result or = m_bvsls->optimize(objective, m_model, true); + opt_result or(m); + try { + or = m_bvsls->optimize(objective, m_model, true); + } + catch (...) { + + } SASSERT(or.is_sat == l_true || or.is_sat == l_undef); if (or.is_sat == l_true) { m_bvsls->get_model(m_model); diff --git a/src/opt/pb_sls.cpp b/src/opt/pb_sls.cpp index d000350e5..2d7586300 100644 --- a/src/opt/pb_sls.cpp +++ b/src/opt/pb_sls.cpp @@ -107,28 +107,33 @@ namespace smt { vector m_hard_occ, m_soft_occ; // variable occurrence svector m_assignment; // current assignment. svector m_best_assignment; - obj_map m_decl2var; // map declarations to Boolean variables. - ptr_vector m_var2decl; // reverse map + expr_ref_vector m_trail; + obj_map m_decl2var; // map declarations to Boolean variables. + ptr_vector m_var2decl; // reverse map index_set m_hard_false; // list of hard clauses that are false. index_set m_soft_false; // list of soft clauses that are false. unsigned m_max_flips; // maximal number of flips unsigned m_non_greedy_percent; // percent of moves to do non-greedy style random_gen m_rng; + scoped_mpz one; imp(ast_manager& m): m(m), pb(m), m_rewrite(m), m_cancel(false), - m_orig_clauses(m) + m_orig_clauses(m), + m_trail(m), + one(mgr) { init_max_flips(); m_non_greedy_percent = 30; - m_decl2var.insert(m.mk_true()->get_decl(), 0); - m_var2decl.push_back(m.mk_true()->get_decl()); + m_decl2var.insert(m.mk_true(), 0); + m_var2decl.push_back(m.mk_true()); m_assignment.push_back(true); m_hard_occ.push_back(unsigned_vector()); m_soft_occ.push_back(unsigned_vector()); + one = mpz(1); } ~imp() { @@ -155,14 +160,10 @@ namespace smt { void set_model(model_ref & mdl) { m_orig_model = mdl; - unsigned sz = mdl->get_num_constants(); - for (unsigned i = 0; i < sz; ++i) { - func_decl* f = mdl->get_constant(i); - if (m.is_bool(f->get_range())) { - literal lit = mk_literal(f); - SASSERT(!lit.sign()); - m_assignment[lit.var()] = m.is_true(mdl->get_const_interp(f)); - } + for (unsigned i = 0; i < m_var2decl.size(); ++i) { + expr_ref tmp(m); + VERIFY(mdl->eval(m_var2decl[i], tmp)); + m_assignment[i] = m.is_true(tmp); } } @@ -229,7 +230,10 @@ namespace smt { void get_model(model_ref& mdl) { mdl = alloc(model, m); for (unsigned i = 1; i < m_var2decl.size(); ++i) { - mdl->register_decl(m_var2decl[i], m_assignment[i]?m.mk_true():m.mk_false()); + expr* d = m_var2decl[i]; + if (is_uninterp_const(d)) { + mdl->register_decl(to_app(d)->get_decl(), m_assignment[i] ? m.mk_true() : m.mk_false()); + } } } @@ -248,6 +252,7 @@ namespace smt { for (unsigned i = 0; i < cls.m_lits.size(); ++i) { w = cls.m_weights[i]; out << w << "*" << cls.m_lits[i] << " "; + out << "(" << mk_pp(m_var2decl[cls.m_lits[i].var()], m) << ") "; if (i + 1 < cls.m_lits.size()) { out << "+ "; } @@ -271,7 +276,7 @@ namespace smt { display(out << m_weights[i] << ": ", m_soft[i]); } for (unsigned i = 0; i < m_assignment.size(); ++i) { - out << literal(i) << ": " << m_var2decl[i]->get_name() << " |-> " << (m_assignment[i]?"true":"false") << "\n"; + out << literal(i) << ": " << mk_pp(m_var2decl[i], m) << " |-> " << (m_assignment[i]?"true":"false") << "\n"; } } @@ -319,8 +324,11 @@ namespace smt { if (!eval(m_clauses[i])) { m_hard_false.insert(i); expr_ref tmp(m); - VERIFY(m_orig_model->eval(m_orig_clauses[i].get(), tmp)); - std::cout << "original evaluation: " << tmp << "\n"; + VERIFY(m_orig_model->eval(m_orig_clauses[i].get(), tmp)); + IF_VERBOSE(0, + verbose_stream() << "original evaluation: " << tmp << "\n"; + verbose_stream() << mk_pp(m_orig_clauses[i].get(), m) << "\n"; + display(verbose_stream(), m_clauses[i]);); } } for (unsigned i = 0; i < m_soft.size(); ++i) { @@ -482,45 +490,131 @@ namespace smt { return break_count; } - literal mk_literal(func_decl* f) { - SASSERT(f->get_family_id() == null_family_id); + literal mk_aux_literal(expr* f) { unsigned var; + expr_ref tmp(m); if (!m_decl2var.find(f, var)) { var = m_hard_occ.size(); SASSERT(m_var2decl.size() == var); SASSERT(m_soft_occ.size() == var); m_hard_occ.push_back(unsigned_vector()); m_soft_occ.push_back(unsigned_vector()); - m_assignment.push_back(false); + VERIFY(m_orig_model->eval(f, tmp)); + m_assignment.push_back(m.is_true(tmp)); m_decl2var.insert(f, var); m_var2decl.push_back(f); } return literal(var); } - + void pad(scoped_mpz_vector& vec, unsigned sz, mpz& val) { + for (unsigned i = 0; i < sz; ++i) { + vec.push_back(val); + } + } literal mk_literal(expr* f) { - literal result; - bool sign = false; - while (m.is_not(f, f)) { - sign = !sign; + if (m.is_not(f, f)) { + literal result = mk_literal(f); + if (result != null_literal) { + result.neg(); + } + return result; } - if (m.is_true(f)) { - result = true_literal; + if (is_uninterp_const(f)) + return mk_aux_literal(to_app(f)); + if (m.is_true(f)) + return true_literal; + if (m.is_false(f)) + return false_literal; + if (m.is_and(f)) { + literal_vector lits; + app* g = to_app(f); + for (unsigned i = 0; i < g->get_num_args(); ++i) { + lits.push_back(mk_literal(g->get_arg(i))); + } + literal result = mk_aux_literal(f); + for (unsigned i = 0; i < lits.size(); ++i) { + clause cls(mgr); + cls.m_lits.push_back(~result); + cls.m_weights.push_back(one); + cls.m_lits.push_back(lits[i]); + cls.m_weights.push_back(one); + cls.m_k = one; + cls.m_eq = false; + m_clauses.push_back(cls); + m_orig_clauses.push_back(f); + lits[i].neg(); + } + lits.push_back(result); + clause cls(mgr); + cls.m_lits.append(lits); + pad(cls.m_weights, lits.size(), one); + cls.m_k = one; + cls.m_eq = false; + m_clauses.push_back(cls); + m_orig_clauses.push_back(f); + return result; } - else if (m.is_false(f)) { - result = false_literal; + if (m.is_or(f)) { + literal_vector lits; + app* g = to_app(f); + for (unsigned i = 0; i < g->get_num_args(); ++i) { + lits.push_back(mk_literal(g->get_arg(i))); + } + literal result = mk_aux_literal(f); + for (unsigned i = 0; i < lits.size(); ++i) { + clause cls(mgr); + cls.m_lits.push_back(result); + cls.m_weights.push_back(one); + cls.m_lits.push_back(~lits[i]); + cls.m_weights.push_back(one); + cls.m_k = one; + cls.m_eq = false; + m_clauses.push_back(cls); + m_orig_clauses.push_back(f); + } + lits.push_back(~result); + clause cls(mgr); + cls.m_lits.append(lits); + pad(cls.m_weights, lits.size(), one); + cls.m_k = one; + cls.m_eq = false; + m_clauses.push_back(cls); + m_orig_clauses.push_back(f); + return result; } - else if (is_uninterp_const(f)) { - result = mk_literal(to_app(f)->get_decl()); + expr* x, *y; + if (m.is_eq(f, x, y) || m.is_iff(f, x, y)) { + literal a = mk_literal(x); + literal b = mk_literal(y); + literal result = mk_aux_literal(f); + clause cls(mgr); + cls.m_lits.push_back(~result); + cls.m_lits.push_back(~a); + cls.m_lits.push_back(b); + pad(cls.m_weights, 3, one); + cls.m_k = one; + cls.m_eq = false; + m_clauses.push_back(cls); + m_orig_clauses.push_back(f); // actually, the clause that defines f + cls.m_lits[0] = ~result; + cls.m_lits[1] = a; + cls.m_lits[2] = ~b; + m_clauses.push_back(cls); + m_orig_clauses.push_back(f); + cls.m_lits[0] = result; + cls.m_lits[1] = a; + cls.m_lits[2] = b; + m_clauses.push_back(cls); + m_orig_clauses.push_back(f); + cls.m_lits[0] = result; + cls.m_lits[1] = ~a; + cls.m_lits[2] = ~b; + m_clauses.push_back(cls); + m_orig_clauses.push_back(f); + return result; } - else { - IF_VERBOSE(0, verbose_stream() << "not handled: " << mk_pp(f, m) << "\n";); - result = null_literal; - } - if (sign) { - result.neg(); - } - return result; + IF_VERBOSE(0, verbose_stream() << "not handled: " << mk_pp(f, m) << "\n";); + return null_literal; } bool compile_clause(expr* _f, clause& cls) { diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 9862c2b28..141bf49c7 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -69,7 +69,7 @@ namespace opt { virtual rational get_lower() const { return m_lower; } virtual rational get_upper() const { return m_upper; } virtual bool get_assignment(unsigned index) const { return m_assignment[index]; } - virtual void set_cancel(bool f) { m_cancel = f; } + virtual void set_cancel(bool f) { m_cancel = f; m_s->set_cancel(f); } virtual void collect_statistics(statistics& st) const { } virtual void get_model(model_ref& mdl) { mdl = m_model.get(); } virtual void updt_params(params_ref& p) { @@ -127,7 +127,6 @@ namespace opt { }; bool probe_bv() { - if (!m_enable_sat) return false; expr_fast_mark1 visited; is_bv proc(m); try { @@ -553,7 +552,7 @@ namespace opt { expr_ref fml(m), val(m); app_ref b(m); expr_ref_vector nsoft(m); - init(); + init(); if (m_use_aux) { s().push(); } @@ -582,6 +581,7 @@ namespace opt { } if (is_sat == l_true) { m_upper.reset(); + s().get_model(m_model); for (unsigned i = 0; i < m_soft.size(); ++i) { VERIFY(m_model->eval(nsoft[i].get(), val)); TRACE("opt", tout << "eval " << mk_pp(m_soft[i].get(), m) << " " << val << "\n";); @@ -820,6 +820,7 @@ namespace opt { lbool is_sat = s().check_sat(0, 0); if (is_sat == l_true) { s().get_model(m_model); + m_upper.reset(); for (unsigned i = 0; i < m_soft.size(); ++i) { expr_ref tmp(m); m_model->eval(m_soft[i].get(), tmp, true); diff --git a/tests/chat1.smt2 b/tests/chat1.smt2 index 0b489e192..e6e11076b 100644 --- a/tests/chat1.smt2 +++ b/tests/chat1.smt2 @@ -3374,7 +3374,7 @@ (optimize ; :wmaxsat_engine wpm2 ; :wmaxsat_engine pwmax - :wmaxsat_engine bvmax +; :wmaxsat_engine bvmax :print_statistics true :timeout 1200000 ) From d118f07e3765ceebf50d41e6515006645d5f29cb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 22 Apr 2014 14:48:05 +0200 Subject: [PATCH 373/925] fix maximize name in C++ API Signed-off-by: Nikolaj Bjorner --- examples/c++/example.cpp | 2 ++ src/api/c++/z3++.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/c++/example.cpp b/examples/c++/example.cpp index 77f7702f2..7ffa04709 100644 --- a/examples/c++/example.cpp +++ b/examples/c++/example.cpp @@ -972,6 +972,8 @@ void substitute_example() { std::cout << new_f << std::endl; } + + int main() { try { demorgan(); std::cout << "\n"; diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 9941e5082..b4e90f4f4 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1505,7 +1505,7 @@ namespace z3 { assert(e.is_bool()); return handle(Z3_optimize_assert_soft(ctx(), m_opt, e, weight, 0)); } - handle maximzie(expr const& e) { + handle maximize(expr const& e) { return handle(Z3_optimize_maximize(ctx(), m_opt, e)); } handle minimize(expr const& e) { From 3003049df8f8b3deeaf33f81415620311237a65e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 22 Apr 2014 15:41:11 +0200 Subject: [PATCH 374/925] fix bug in bcd2 Signed-off-by: Nikolaj Bjorner --- src/opt/weighted_maxsat.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 141bf49c7..7087e795d 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -121,6 +121,7 @@ namespace opt { fid != pb.get_family_id() && fid != bv.get_family_id() && !is_uninterp_const(n)) { + std::cout << mk_pp(n, m) << "\n"; throw found(); } } @@ -161,6 +162,7 @@ namespace opt { void enable_sls() { if (m_enable_sls && probe_bv()) { + std::cout << "SLS enabled\n"; m_params.set_uint("restarts", 20); m_s = alloc(sls_solver, m, m_s.get(), m_soft, m_weights, m_params); } @@ -188,6 +190,7 @@ namespace opt { obj_map m_relax2index; // expr |-> index obj_map m_soft2index; // expr |-> index expr_ref_vector m_trail; + expr_ref_vector m_soft_constraints; expr_set m_asm_set; vector m_cores; vector m_sigmas; @@ -242,7 +245,9 @@ namespace opt { pb(m), m_soft_aux(m), m_trail(m), + m_soft_constraints(m), m_enable_lazy(false) { + m_enable_lazy = true; } virtual ~bcd2() {} @@ -259,6 +264,7 @@ namespace opt { init_bcd(); while (m_lower < m_upper) { IF_VERBOSE(1, verbose_stream() << "(wmaxsat.bcd2 [" << m_lower << ":" << m_upper << "])\n";); + assert_soft(); solver::scoped_push _scope2(s()); TRACE("opt", display(tout);); assert_cores(); @@ -331,11 +337,18 @@ namespace opt { expr* r = m_soft_aux[i].get(); m_soft2index.insert(r, i); fml = m.mk_or(r, m_soft[i].get()); - s().assert_expr(fml); + m_soft_constraints.push_back(fml); m_asm_set.insert(r); SASSERT(m_weights[i].is_int()); } + void assert_soft() { + for (unsigned i = 0; i < m_soft_constraints.size(); ++i) { + s().assert_expr(m_soft_constraints[i].get()); + } + m_soft_constraints.reset(); + } + bool check_lazy_soft(svector const& assignment) { bool all_satisfied = true; for (unsigned i = 0; i < m_lazy_soft.size(); ++i) { @@ -467,6 +480,9 @@ namespace opt { } } cores.resize(j); + for (unsigned i = 0; i < cores.size(); ++i) { + m_relax2index.insert(cores[i].m_r, i); + } } void core2indices(ptr_vector const& core, uint_set& subC, uint_set& soft) { for (unsigned i = 0; i < core.size(); ++i) { From d67b5226f013323ba337b0eba7c96ad618d1f138 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 22 Apr 2014 16:59:40 +0200 Subject: [PATCH 375/925] fix compiler errors reported by Robert White Signed-off-by: Nikolaj Bjorner --- src/opt/opt_sls_solver.h | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/opt/opt_sls_solver.h b/src/opt/opt_sls_solver.h index 001a33ed4..7ed4c40a6 100644 --- a/src/opt/opt_sls_solver.h +++ b/src/opt/opt_sls_solver.h @@ -93,7 +93,7 @@ namespace opt { std::cout << "set cancel\n"; m_solver->set_cancel(f); m_pb2bv.set_cancel(f); - #pragma omp critical (this) + #pragma omp critical (sls_solver) { if (m_bvsls) { m_bvsls->set_cancel(f); @@ -193,7 +193,7 @@ namespace opt { } void pbsls_opt() { - #pragma omp critical (this) + #pragma omp critical (sls_solver) { m_pbsls = alloc(smt::pb_sls, m); } @@ -212,21 +212,22 @@ namespace opt { } void bvsls_opt() { - #pragma omp critical (this) + #pragma omp critical (sls_solver) { m_bvsls = alloc(bvsls_opt_engine, m, m_params); } assertions2sls(); expr_ref objective = soft2bv(); - opt_result or(m); + opt_result res(m); + res.is_sat = l_undef; try { - or = m_bvsls->optimize(objective, m_model, true); + res = m_bvsls->optimize(objective, m_model, true); } catch (...) { } - SASSERT(or.is_sat == l_true || or.is_sat == l_undef); - if (or.is_sat == l_true) { + SASSERT(res.is_sat == l_true || res.is_sat == l_undef); + if (res.is_sat == l_true) { m_bvsls->get_model(m_model); } } From 859013e9c939c7de7080b66790a656ce066c49d8 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 22 Apr 2014 19:13:43 +0100 Subject: [PATCH 376/925] bvsls opt engine bugfix/debugging Signed-off-by: Christoph M. Wintersteiger --- src/tactic/sls/bvsls_opt_engine.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/tactic/sls/bvsls_opt_engine.cpp b/src/tactic/sls/bvsls_opt_engine.cpp index 12a0cf631..95a9389fc 100644 --- a/src/tactic/sls/bvsls_opt_engine.cpp +++ b/src/tactic/sls/bvsls_opt_engine.cpp @@ -53,11 +53,14 @@ bvsls_opt_engine::optimization_result bvsls_opt_engine::optimize( tout << fd->get_name() << " := " << mk_ismt2_pp(val, m()) << std::endl; }); m_hard_tracker.set_model(initial_model); - } + m_evaluator.update_all(); + } optimization_result res(m_manager); lbool is_sat = m_hard_tracker.is_sat() ? l_true : l_undef; + TRACE("sls_opt", tout << "initial model is sat? " << is_sat << std::endl;); + for (m_stats.m_restarts = 0; m_stats.m_restarts < m_max_restarts; m_stats.m_restarts++) @@ -65,7 +68,7 @@ bvsls_opt_engine::optimization_result bvsls_opt_engine::optimize( mpz old_best; m_mpz_manager.set(old_best, m_best_model_score); - if (!is_sat) { + if (is_sat != l_true) { do { checkpoint(); From 23a74b3c265d2ea5be7c1d9067c908cce386d0f0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 Apr 2014 08:07:37 +0200 Subject: [PATCH 377/925] fix assertions reported by Christoph Signed-off-by: Nikolaj Bjorner --- src/api/python/z3.py | 16 ++++++++++++++++ src/opt/opt_sls_solver.h | 1 - src/opt/pb_sls.cpp | 7 +++++-- src/opt/weighted_maxsat.cpp | 1 - 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index 3145dc75a..d31bcb729 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -6010,6 +6010,22 @@ class Solver(Z3PPObject): """ return Z3_solver_to_string(self.ctx.ref(), self.solver) + def to_smt2(self): + """return SMTLIB2 formatted benchmark for solver's assertions""" + es = self.assertions() + sz = len(es) + sz1 = sz + if sz1 > 0: + sz1 -= 1 + v = (Ast * sz1)() + for i in range(sz1): + v[i] = es[i].as_ast() + if sz > 0: + e = es[sz1].as_ast() + else: + e = BoolVal(True, self.ctx).as_ast() + return Z3_benchmark_to_smtlib_string(self.ctx.ref(), "benchmark generated from python API", "", "unknown", "", sz1, v, e) + def SolverFor(logic, ctx=None): """Create a solver customized for the given logic. diff --git a/src/opt/opt_sls_solver.h b/src/opt/opt_sls_solver.h index 7ed4c40a6..cd634e728 100644 --- a/src/opt/opt_sls_solver.h +++ b/src/opt/opt_sls_solver.h @@ -90,7 +90,6 @@ namespace opt { m_solver->get_labels(r); } virtual void set_cancel(bool f) { - std::cout << "set cancel\n"; m_solver->set_cancel(f); m_pb2bv.set_cancel(f); #pragma omp critical (sls_solver) diff --git a/src/opt/pb_sls.cpp b/src/opt/pb_sls.cpp index 2d7586300..0fe17a29a 100644 --- a/src/opt/pb_sls.cpp +++ b/src/opt/pb_sls.cpp @@ -301,6 +301,7 @@ namespace smt { clause const& cls = clauses[i]; for (unsigned j = 0; j < cls.m_lits.size(); ++j) { literal lit = cls.m_lits[j]; + if (occ.size() <= static_cast(lit.var())) occ.resize(lit.var() + 1); occ[lit.var()].push_back(i); } } @@ -314,6 +315,10 @@ namespace smt { m_soft_false.reset(); m_soft_occ.reset(); m_penalty.reset(); + for (unsigned i = 0; i <= m_var2decl.size(); ++i) { + m_soft_occ.push_back(unsigned_vector()); + m_hard_occ.push_back(unsigned_vector()); + } // initialize the occurs vectors. init_occ(m_clauses, m_hard_occ); @@ -443,7 +448,6 @@ namespace smt { } int flip(literal l) { - SASSERT(get_value(l)); m_assignment[l.var()] = !m_assignment[l.var()]; int break_count = 0; unsigned_vector const& occh = m_hard_occ[l.var()]; @@ -484,7 +488,6 @@ namespace smt { } } - SASSERT(get_value(~l)); TRACE("opt", tout << "flip: " << l << " num false: " << m_hard_false.num_elems() << " penalty: " << m_penalty << " break count: " << break_count << "\n";); return break_count; diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 7087e795d..774147b91 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -162,7 +162,6 @@ namespace opt { void enable_sls() { if (m_enable_sls && probe_bv()) { - std::cout << "SLS enabled\n"; m_params.set_uint("restarts", 20); m_s = alloc(sls_solver, m, m_s.get(), m_soft, m_weights, m_params); } From 27fa7077a62091937c5bd98f99fcddaf693f2f14 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 Apr 2014 09:22:31 +0200 Subject: [PATCH 378/925] fix compiler warnings/errors reported by Robert White Signed-off-by: Nikolaj Bjorner --- src/opt/pb_sls.cpp | 6 +++--- src/tactic/sls/bvsls_opt_engine.h | 11 ++++++++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/opt/pb_sls.cpp b/src/opt/pb_sls.cpp index 0fe17a29a..c62c79c6a 100644 --- a/src/opt/pb_sls.cpp +++ b/src/opt/pb_sls.cpp @@ -586,7 +586,7 @@ namespace smt { return result; } expr* x, *y; - if (m.is_eq(f, x, y) || m.is_iff(f, x, y)) { + if ((m.is_eq(f, x, y) && m.is_bool(x)) || m.is_iff(f, x, y)) { literal a = mk_literal(x); literal b = mk_literal(y); literal result = mk_aux_literal(f); @@ -615,9 +615,9 @@ namespace smt { m_clauses.push_back(cls); m_orig_clauses.push_back(f); return result; - } + } IF_VERBOSE(0, verbose_stream() << "not handled: " << mk_pp(f, m) << "\n";); - return null_literal; + return mk_aux_literal(f); } bool compile_clause(expr* _f, clause& cls) { diff --git a/src/tactic/sls/bvsls_opt_engine.h b/src/tactic/sls/bvsls_opt_engine.h index 75216c49e..64a366d73 100644 --- a/src/tactic/sls/bvsls_opt_engine.h +++ b/src/tactic/sls/bvsls_opt_engine.h @@ -39,6 +39,15 @@ public: lbool is_sat; expr_ref optimum; optimization_result(ast_manager & m) : is_sat(l_undef), optimum(m) {} + optimization_result& operator=(optimization_result const& other) { + is_sat = other.is_sat; + optimum = other.optimum; + return *this; + } + optimization_result(optimization_result const& other): + is_sat(other.is_sat), + optimum(other.optimum) { + } }; optimization_result optimize(expr_ref const & objective, model_ref initial_model = model_ref(), bool maximize=true); @@ -70,4 +79,4 @@ protected: bool randomize_wrt_hard(); }; -#endif \ No newline at end of file +#endif From 55863b4bb5097c4da60c5db9f34ec089d13b697f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 Apr 2014 14:05:59 +0200 Subject: [PATCH 379/925] fix build problems, fix scoping Signed-off-by: Nikolaj Bjorner --- src/api/python/z3printer.py | 2 +- src/opt/opt_sls_solver.h | 6 ++---- src/opt/weighted_maxsat.cpp | 33 ++++++++++++++++++++--------- src/tactic/arith/card2bv_tactic.cpp | 3 ++- 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/api/python/z3printer.py b/src/api/python/z3printer.py index d3dc43d3e..d1d85d30e 100644 --- a/src/api/python/z3printer.py +++ b/src/api/python/z3printer.py @@ -386,7 +386,7 @@ def seq3(args, lp='(', rp=')'): else: return group(indent(len(lp), compose(to_format(lp), seq(args), to_format(rp)))) -class StopPPException: +class StopPPException(Exception): def __str__(self): return 'pp-interrupted' diff --git a/src/opt/opt_sls_solver.h b/src/opt/opt_sls_solver.h index cd634e728..7578502b0 100644 --- a/src/opt/opt_sls_solver.h +++ b/src/opt/opt_sls_solver.h @@ -204,10 +204,8 @@ namespace opt { for (unsigned i = 0; i < m_soft.size(); ++i) { m_pbsls->add(m_soft[i].get(), m_weights[i]); } - lbool is_sat = (*m_pbsls.get())(); - if (is_sat == l_true) { - m_pbsls->get_model(m_model); - } + (*m_pbsls.get())(); + m_pbsls->get_model(m_model); } void bvsls_opt() { diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 774147b91..593e87e7f 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -156,6 +156,8 @@ namespace opt { for (unsigned i = 0; i < sz; ++i) { sat_solver->assert_expr(s().get_assertion(i)); } + unsigned lvl = m_s->get_scope_level(); + while (lvl > 0) { sat_solver->push(); --lvl; } m_s = sat_solver; } } @@ -163,7 +165,9 @@ namespace opt { void enable_sls() { if (m_enable_sls && probe_bv()) { m_params.set_uint("restarts", 20); + unsigned lvl = m_s->get_scope_level(); m_s = alloc(sls_solver, m, m_s.get(), m_soft, m_weights, m_params); + while (lvl > 0) { m_s->push(); --lvl; } } } @@ -247,6 +251,7 @@ namespace opt { m_soft_constraints(m), m_enable_lazy(false) { m_enable_lazy = true; + enable_sls(); } virtual ~bcd2() {} @@ -257,7 +262,6 @@ namespace opt { lbool is_sat = l_undef; expr_ref_vector asms(m); bool first = true; - enable_sls(); solver::scoped_push _scope1(s()); init(); init_bcd(); @@ -551,13 +555,14 @@ namespace opt { bool m_use_aux; public: pbmax(solver* s, ast_manager& m, bool use_aux): - maxsmt_solver_base(s, m), m_use_aux(use_aux) {} + maxsmt_solver_base(s, m), m_use_aux(use_aux) { + enable_bvsat(); + enable_sls(); + } virtual ~pbmax() {} lbool operator()() { - enable_bvsat(); - enable_sls(); TRACE("opt", s().display(tout); tout << "\n"; for (unsigned i = 0; i < m_soft.size(); ++i) { tout << mk_pp(m_soft[i].get(), m) << " " << m_weights[i] << "\n"; @@ -628,14 +633,15 @@ namespace opt { class wpm2 : public maxsmt_solver_base { scoped_ptr maxs; public: - wpm2(solver* s, ast_manager& m, maxsmt_solver_base* maxs): - maxsmt_solver_base(s, m), maxs(maxs) {} + wpm2(solver* s, ast_manager& m, maxsmt_solver_base* _maxs): + maxsmt_solver_base(s, m), maxs(_maxs) { + enable_sls(); + } virtual ~wpm2() {} lbool operator()() { IF_VERBOSE(1, verbose_stream() << "(wmaxsat.wpm2 solve)\n";); - enable_sls(); solver::scoped_push _s(s()); pb_util u(m); app_ref fml(m), a(m), b(m), c(m); @@ -778,6 +784,12 @@ namespace opt { amk.push_back(k); } } + + virtual void set_cancel(bool f) { + maxsmt_solver_base::set_cancel(f); + maxs->set_cancel(f); + } + private: lbool new_bound(expr_ref_vector const& al, vector const& ws, @@ -825,12 +837,13 @@ namespace opt { class sls : public maxsmt_solver_base { public: sls(solver* s, ast_manager& m): - maxsmt_solver_base(s, m) {} + maxsmt_solver_base(s, m) { + enable_bvsat(); + enable_sls(); + } virtual ~sls() {} lbool operator()() { IF_VERBOSE(1, verbose_stream() << "(sls solve)\n";); - enable_bvsat(); - enable_sls(); init(); lbool is_sat = s().check_sat(0, 0); if (is_sat == l_true) { diff --git a/src/tactic/arith/card2bv_tactic.cpp b/src/tactic/arith/card2bv_tactic.cpp index ca40d8a47..bba8705e0 100644 --- a/src/tactic/arith/card2bv_tactic.cpp +++ b/src/tactic/arith/card2bv_tactic.cpp @@ -137,9 +137,10 @@ namespace pb { return BR_FAILED; } - template class rewriter_tpl; }; +template class rewriter_tpl; + class card2bv_tactic : public tactic { ast_manager & m; params_ref m_params; From 20cb8a3092d59d0dc3a51ca454bcdcd25e5de11d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 Apr 2014 03:00:31 +0200 Subject: [PATCH 380/925] added pareto utility Signed-off-by: Nikolaj Bjorner --- src/opt/maxsmt.cpp | 9 +- src/opt/maxsmt.h | 3 +- src/opt/opt_context.cpp | 235 +++++++++++++++++++++++++--------------- src/opt/opt_context.h | 13 +-- src/opt/opt_pareto.cpp | 197 +++++++++++++++++++++++++++++++++ src/opt/opt_pareto.h | 109 +++++++++++++++++++ src/opt/optsmt.cpp | 12 +- src/opt/optsmt.h | 3 +- 8 files changed, 477 insertions(+), 104 deletions(-) create mode 100644 src/opt/opt_pareto.cpp create mode 100644 src/opt/opt_pareto.h diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index d27d17790..cc1b1ba42 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -105,10 +105,15 @@ namespace opt { return r; } - void maxsmt::update_lower(rational const& r) { - if (m_lower > r) m_lower = r; + void maxsmt::update_lower(rational const& r, bool override) { + if (m_lower > r || override) m_lower = r; } + void maxsmt::update_upper(rational const& r, bool override) { + if (m_upper < r || override) m_upper = r; + } + + void maxsmt::get_model(model_ref& mdl) { mdl = m_model.get(); } diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index c4cf33cac..cd26c40e5 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -73,7 +73,8 @@ namespace opt { rational get_value() const; rational get_lower() const; rational get_upper() const; - void update_lower(rational const& r); + void update_lower(rational const& r, bool override); + void update_upper(rational const& r, bool override); void get_model(model_ref& mdl); bool get_assignment(unsigned index) const; void display_answer(std::ostream& out) const; diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index a16654614..4f2a5eba2 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -152,7 +152,7 @@ namespace opt { IF_VERBOSE(1, verbose_stream() << "(optimize:sat)\n";); s.get_model(m_model); m_optsmt.setup(s); - update_lower(); + update_lower(true); switch (m_objectives.size()) { case 0: return is_sat; @@ -234,91 +234,147 @@ namespace opt { return r; } + class context::pareto : public pareto_callback { + context& ctx; + ast_manager& m; + expr_ref mk_ge(expr* t, expr* s) { + expr_ref result(m); + if (ctx.m_bv.is_bv(t)) { + result = ctx.m_bv.mk_ule(s, t); + } + else { + result = ctx.m_arith.mk_ge(t, s); + } + return result; + } + public: + pareto(context& ctx):ctx(ctx),m(ctx.m) {} + + + virtual void yield(model_ref& mdl) { + ctx.m_model = mdl; + ctx.update_lower(true); + for (unsigned i = 0; i < ctx.m_objectives.size(); ++i) { + objective const& obj = ctx.m_objectives[i]; + switch(obj.m_type) { + case O_MINIMIZE: + case O_MAXIMIZE: + ctx.m_optsmt.update_upper(obj.m_index, ctx.m_optsmt.get_lower(obj.m_index), true); + break; + case O_MAXSMT: { + rational r = ctx.m_maxsmts.find(obj.m_id)->get_lower(); + ctx.m_maxsmts.find(obj.m_id)->update_upper(r, true); + break; + } + } + } + + IF_VERBOSE(1, ctx.display_assignment(verbose_stream());); + } + virtual unsigned num_objectives() { + return ctx.m_objectives.size(); + } + virtual expr_ref mk_le(unsigned i, model_ref& mdl) { + objective const& obj = ctx.m_objectives[i]; + expr_ref val(m), result(m), term(m); + mk_term_val(mdl, obj, term, val); + switch (obj.m_type) { + case O_MINIMIZE: + result = mk_ge(term, val); + break; + case O_MAXSMT: + result = mk_ge(term, val); + break; + case O_MAXIMIZE: + result = mk_ge(val, term); + break; + } + return result; + } + virtual expr_ref mk_ge(unsigned i, model_ref& mdl) { + objective const& obj = ctx.m_objectives[i]; + expr_ref val(m), result(m), term(m); + mk_term_val(mdl, obj, term, val); + switch (obj.m_type) { + case O_MINIMIZE: + result = mk_ge(val, term); + break; + case O_MAXSMT: + result = mk_ge(val, term); + break; + case O_MAXIMIZE: + result = mk_ge(term, val); + break; + } + return result; + } + + virtual expr_ref mk_gt(unsigned i, model_ref& mdl) { + expr_ref result = mk_le(i, mdl); + result = m.mk_not(result); + return result; + } + private: + void mk_term_val(model_ref& mdl, objective const& obj, expr_ref& term, expr_ref& val) { + rational r; + switch (obj.m_type) { + case O_MINIMIZE: + case O_MAXIMIZE: + term = obj.m_term; + break; + case O_MAXSMT: { + unsigned sz = obj.m_terms.size(); + expr_ref_vector sum(m); + expr_ref zero(m); + zero = ctx.m_arith.mk_numeral(rational(0), false); + for (unsigned i = 0; i < sz; ++i) { + expr* t = obj.m_terms[i]; + rational const& w = obj.m_weights[i]; + sum.push_back(m.mk_ite(t, ctx.m_arith.mk_numeral(w, false), zero)); + } + if (sum.empty()) { + term = zero; + } + else { + term = ctx.m_arith.mk_add(sum.size(), sum.c_ptr()); + } + break; + } + } + VERIFY(mdl->eval(term, val) && ctx.is_numeral(val, r)); + } + +#if 0 + // use PB + expr_ref mk_pb_cmp(objective const& obj, model_ref& mdl, bool is_ge) { + rational r, sum(0); + expr_ref val(m), result(m); + unsigned sz = obj.m_terms.size(); + pb_util pb(m); + + for (unsigned i = 0; i < sz; ++i) { + expr* t = obj.m_terms[i]; + VERIFY(mdl->eval(t, val)); + if (m.is_true(val)) { + sum += r; + } + } + if (is_ge) { + result = pb.mk_ge(obj.m_terms.size(), obj.m_weights.c_ptr(), obj.m_terms.c_ptr(), r); + } + else { + result = pb.mk_le(obj.m_terms.size(), obj.m_weights.c_ptr(), obj.m_terms.c_ptr(), r); + } + } +#endif + }; lbool context::execute_pareto() { - opt_solver& s = get_solver(); - expr_ref val(m); - rational r; - lbool is_sat = l_true; - vector bounds; - for (unsigned i = 0; i < m_objectives.size(); ++i) { - objective const& obj = m_objectives[i]; - if (obj.m_type == O_MAXSMT) { - IF_VERBOSE(0, verbose_stream() << "Pareto optimization is not supported for MAXSMT\n";); - return l_undef; - } - solver::scoped_push _sp(s); - is_sat = m_optsmt.pareto(obj.m_index); - if (is_sat != l_true) { - return is_sat; - } - if (!m_optsmt.get_upper(obj.m_index).is_finite()) { - return l_undef; - } - bounds_t bound; - for (unsigned j = 0; j < m_objectives.size(); ++j) { - objective const& obj_j = m_objectives[j]; - inf_eps lo = m_optsmt.get_lower(obj_j.m_index); - inf_eps hi = m_optsmt.get_upper(obj_j.m_index); - bound.push_back(std::make_pair(lo, hi)); - } - bounds.push_back(bound); - } - for (unsigned i = 0; i < bounds.size(); ++i) { - for (unsigned j = 0; j < bounds.size(); ++j) { - objective const& obj = m_objectives[j]; - bounds[i][j].second = bounds[j][j].second; - } - IF_VERBOSE(0, display_bounds(verbose_stream() << "new bound\n", bounds[i]);); - } - - for (unsigned i = 0; i < bounds.size(); ++i) { - bounds_t b = bounds[i]; - vector mids; - solver::scoped_push _sp(s); - for (unsigned j = 0; j < b.size(); ++j) { - objective const& obj = m_objectives[j]; - inf_eps mid = (b[j].second - b[j].first)/rational(2); - mids.push_back(mid); - expr_ref ge = s.mk_ge(obj.m_index, mid); - s.assert_expr(ge); - } - is_sat = execute_box(); - switch(is_sat) { - case l_undef: - return is_sat; - case l_true: { - bool at_bound = true; - for (unsigned j = 0; j < b.size(); ++j) { - objective const& obj = m_objectives[j]; - if (m_model->eval(obj.m_term, val) && is_numeral(val, r)) { - mids[j] = inf_eps(r); - } - at_bound = at_bound && mids[j] == b[j].second; - b[j].second = mids[j]; - } - IF_VERBOSE(0, display_bounds(verbose_stream() << "new bound\n", b);); - if (!at_bound) { - bounds.push_back(b); - } - break; - } - case l_false: { - bounds_t b2(b); - for (unsigned j = 0; j < b.size(); ++j) { - b2[j].second = mids[j]; - if (j > 0) { - b2[j-1].second = b[j-1].second; - } - IF_VERBOSE(0, display_bounds(verbose_stream() << "refined bound\n", b2);); - bounds.push_back(b2); - } - break; - } - } - } - - return is_sat; + pareto cb(*this); + m_pareto = alloc(gia_pareto, m, cb, m_solver.get(), m_params); + return (*(m_pareto.get()))(); + // NB. stack reference cb is out of scope after return. + // NB. fix race condition for set_cancel } void context::display_bounds(std::ostream& out, bounds_t const& b) const { @@ -652,7 +708,7 @@ namespace opt { } } - void context::update_lower() { + void context::update_lower(bool override) { expr_ref val(m); rational r(0); for (unsigned i = 0; i < m_objectives.size(); ++i) { @@ -660,12 +716,12 @@ namespace opt { switch(obj.m_type) { case O_MINIMIZE: if (m_model->eval(obj.m_term, val) && is_numeral(val, r)) { - m_optsmt.update_lower(obj.m_index, -r); + m_optsmt.update_lower(obj.m_index, inf_eps(-r), override); } break; case O_MAXIMIZE: if (m_model->eval(obj.m_term, val) && is_numeral(val, r)) { - m_optsmt.update_lower(obj.m_index, r); + m_optsmt.update_lower(obj.m_index, inf_eps(r), override); } break; case O_MAXSMT: { @@ -681,7 +737,7 @@ namespace opt { } } if (ok) { - m_maxsmts.find(obj.m_id)->update_lower(r); + m_maxsmts.find(obj.m_id)->update_lower(r, override); } break; } @@ -816,6 +872,9 @@ namespace opt { if (m_simplify) { m_simplify->set_cancel(f); } + if (m_pareto) { + m_pareto->set_cancel(f); + } m_optsmt.set_cancel(f); map_t::iterator it = m_maxsmts.begin(), end = m_maxsmts.end(); for (; it != end; ++it) { diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 3fad9a59d..1912dac0d 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -14,19 +14,13 @@ Author: Notes: - TODO: - - - type check objective term and assertions. It should pass basic sanity being - integer, real (, bit-vector) or other supported objective function type. - - - add appropriate statistics tracking to opt::context - --*/ #ifndef _OPT_CONTEXT_H_ #define _OPT_CONTEXT_H_ #include "ast.h" #include "opt_solver.h" +#include "opt_pareto.h" #include "optsmt.h" #include "maxsmt.h" #include "model_converter.h" @@ -86,6 +80,7 @@ namespace opt { bv_util m_bv; expr_ref_vector m_hard_constraints; ref m_solver; + scoped_ptr m_pareto; params_ref m_params; optsmt m_optsmt; map_t m_maxsmts; @@ -158,7 +153,7 @@ namespace opt { void from_fmls(expr_ref_vector const& fmls); void simplify_fmls(expr_ref_vector& fmls); - void update_lower(); + void update_lower(bool override); inf_eps get_lower_as_num(unsigned idx); inf_eps get_upper_as_num(unsigned idx); @@ -174,6 +169,8 @@ namespace opt { void validate_lex(); + class pareto; + }; } diff --git a/src/opt/opt_pareto.cpp b/src/opt/opt_pareto.cpp new file mode 100644 index 000000000..6bffd19ef --- /dev/null +++ b/src/opt/opt_pareto.cpp @@ -0,0 +1,197 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + opt_pareto.cpp + +Abstract: + + Pareto front utilities + +Author: + + Nikolaj Bjorner (nbjorner) 2014-4-24 + +Notes: + + +--*/ + +#include "opt_pareto.h" +#include "ast_pp.h" + +namespace opt { + + // --------------------- + // GIA pareto algorithm + + lbool gia_pareto::operator()() { + model_ref model; + expr_ref fml(m); + lbool is_sat = m_solver->check_sat(0, 0); + while (is_sat == l_true) { + { + solver::scoped_push _s(*m_solver.get()); + while (is_sat == l_true) { + if (m_cancel) { + return l_undef; + } + m_solver->get_model(model); + // TBD: we can also use local search to tune solution coordinate-wise. + mk_dominates(model); + is_sat = m_solver->check_sat(0, 0); + } + if (is_sat == l_undef) { + return l_undef; + } + is_sat = l_true; + } + cb.yield(model); + mk_not_dominated_by(model); + is_sat = m_solver->check_sat(0, 0); + } + if (is_sat == l_undef) { + return l_undef; + } + return l_true; + } + + void pareto_base::mk_dominates(model_ref& model) { + unsigned sz = cb.num_objectives(); + expr_ref fml(m); + expr_ref_vector gt(m), fmls(m); + for (unsigned i = 0; i < sz; ++i) { + fmls.push_back(cb.mk_ge(i, model)); + gt.push_back(cb.mk_gt(i, model)); + } + fmls.push_back(m.mk_or(gt.size(), gt.c_ptr())); + fml = m.mk_and(fmls.size(), fmls.c_ptr()); + IF_VERBOSE(10, verbose_stream() << "dominates: " << fml << "\n";); + m_solver->assert_expr(fml); + } + + void pareto_base::mk_not_dominated_by(model_ref& model) { + unsigned sz = cb.num_objectives(); + expr_ref fml(m); + expr_ref_vector le(m); + for (unsigned i = 0; i < sz; ++i) { + le.push_back(cb.mk_le(i, model)); + } + fml = m.mk_not(m.mk_and(le.size(), le.c_ptr())); + IF_VERBOSE(10, verbose_stream() << "not dominated by: " << fml << "\n";); + m_solver->assert_expr(fml); + } + + // --------------------------------- + // OIA algorithm (without filtering) + + lbool oia_pareto::operator()() { + model_ref model; + solver::scoped_push _s(*m_solver.get()); + lbool is_sat = m_solver->check_sat(0, 0); + if (is_sat != l_true) { + return is_sat; + } + while (is_sat == l_true) { + if (m_cancel) { + return l_undef; + } + m_solver->get_model(model); + cb.yield(model); + mk_not_dominated_by(model); + is_sat = m_solver->check_sat(0, 0); + } + if (m_cancel) { + return l_undef; + } + return l_true; + } + +} + +#if 0 + opt_solver& s = get_solver(); + expr_ref val(m); + rational r; + lbool is_sat = l_true; + vector bounds; + for (unsigned i = 0; i < m_objectives.size(); ++i) { + objective const& obj = m_objectives[i]; + if (obj.m_type == O_MAXSMT) { + IF_VERBOSE(0, verbose_stream() << "Pareto optimization is not supported for MAXSMT\n";); + return l_undef; + } + solver::scoped_push _sp(s); + is_sat = m_optsmt.pareto(obj.m_index); + if (is_sat != l_true) { + return is_sat; + } + if (!m_optsmt.get_upper(obj.m_index).is_finite()) { + return l_undef; + } + bounds_t bound; + for (unsigned j = 0; j < m_objectives.size(); ++j) { + objective const& obj_j = m_objectives[j]; + inf_eps lo = m_optsmt.get_lower(obj_j.m_index); + inf_eps hi = m_optsmt.get_upper(obj_j.m_index); + bound.push_back(std::make_pair(lo, hi)); + } + bounds.push_back(bound); + } + for (unsigned i = 0; i < bounds.size(); ++i) { + for (unsigned j = 0; j < bounds.size(); ++j) { + objective const& obj = m_objectives[j]; + bounds[i][j].second = bounds[j][j].second; + } + IF_VERBOSE(0, display_bounds(verbose_stream() << "new bound\n", bounds[i]);); + } + + for (unsigned i = 0; i < bounds.size(); ++i) { + bounds_t b = bounds[i]; + vector mids; + solver::scoped_push _sp(s); + for (unsigned j = 0; j < b.size(); ++j) { + objective const& obj = m_objectives[j]; + inf_eps mid = (b[j].second - b[j].first)/rational(2); + mids.push_back(mid); + expr_ref ge = s.mk_ge(obj.m_index, mid); + s.assert_expr(ge); + } + is_sat = execute_box(); + switch(is_sat) { + case l_undef: + return is_sat; + case l_true: { + bool at_bound = true; + for (unsigned j = 0; j < b.size(); ++j) { + objective const& obj = m_objectives[j]; + if (m_model->eval(obj.m_term, val) && is_numeral(val, r)) { + mids[j] = inf_eps(r); + } + at_bound = at_bound && mids[j] == b[j].second; + b[j].second = mids[j]; + } + IF_VERBOSE(0, display_bounds(verbose_stream() << "new bound\n", b);); + if (!at_bound) { + bounds.push_back(b); + } + break; + } + case l_false: { + bounds_t b2(b); + for (unsigned j = 0; j < b.size(); ++j) { + b2[j].second = mids[j]; + if (j > 0) { + b2[j-1].second = b[j-1].second; + } + IF_VERBOSE(0, display_bounds(verbose_stream() << "refined bound\n", b2);); + bounds.push_back(b2); + } + break; + } + } + } + + return is_sat; +#endif diff --git a/src/opt/opt_pareto.h b/src/opt/opt_pareto.h new file mode 100644 index 000000000..fa0243807 --- /dev/null +++ b/src/opt/opt_pareto.h @@ -0,0 +1,109 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + opt_pareto.h + +Abstract: + + Pareto front utilities + +Author: + + Nikolaj Bjorner (nbjorner) 2014-4-24 + +Notes: + + +--*/ +#ifndef _OPT_PARETO_H_ +#define _OPT_PARETO_H_ + +#include "solver.h" +#include "model.h" + +namespace opt { + + class pareto_callback { + public: + virtual void yield(model_ref& model) = 0; + virtual unsigned num_objectives() = 0; + virtual expr_ref mk_gt(unsigned i, model_ref& model) = 0; + virtual expr_ref mk_ge(unsigned i, model_ref& model) = 0; + virtual expr_ref mk_le(unsigned i, model_ref& model) = 0; + }; + class pareto_base { + protected: + ast_manager& m; + pareto_callback& cb; + volatile bool m_cancel; + ref m_solver; + params_ref m_params; + public: + pareto_base( + ast_manager & m, + pareto_callback& cb, + solver* s, + params_ref & p): + m(m), + cb(cb), + m_cancel(false), + m_solver(s), + m_params(p) { + } + virtual ~pareto_base() {} + virtual void updt_params(params_ref & p) { + m_solver->updt_params(p); + m_params.copy(p); + } + virtual void collect_param_descrs(param_descrs & r) { + m_solver->collect_param_descrs(r); + } + virtual void collect_statistics(statistics & st) const { + m_solver->collect_statistics(st); + } + virtual void set_cancel(bool f) { + m_solver->set_cancel(f); + m_cancel = f; + } + virtual void display(std::ostream & out) const { + m_solver->display(out); + } + virtual lbool operator()() = 0; + + protected: + + void mk_dominates(model_ref& model); + + void mk_not_dominated_by(model_ref& model); + }; + class gia_pareto : public pareto_base { + public: + gia_pareto(ast_manager & m, + pareto_callback& cb, + solver* s, + params_ref & p): + pareto_base(m, cb, s, p) { + } + virtual ~gia_pareto() {} + + virtual lbool operator()(); + }; + + // opportunistic improvement algorithm. + class oia_pareto : public pareto_base { + public: + oia_pareto(ast_manager & m, + pareto_callback& cb, + solver* s, + params_ref & p): + pareto_base(m, cb, s, p) { + } + virtual ~oia_pareto() {} + + virtual lbool operator()(); + }; +} + +#endif diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 14e133a70..e5370e82d 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -115,11 +115,15 @@ namespace opt { return l_true; } - void optsmt::update_lower(unsigned idx, rational const& r) { - inf_eps v(r); - if (m_lower[idx] < v) { + void optsmt::update_lower(unsigned idx, inf_eps const& v, bool override) { + if (m_lower[idx] < v || override) { m_lower[idx] = v; - if (m_s) m_s->get_model(m_model); + } + } + + void optsmt::update_upper(unsigned idx, inf_eps const& v, bool override) { + if (m_upper[idx] > v || override) { + m_upper[idx] = v; } } diff --git a/src/opt/optsmt.h b/src/opt/optsmt.h index 060ae9aaa..5f4a2988f 100644 --- a/src/opt/optsmt.h +++ b/src/opt/optsmt.h @@ -60,7 +60,8 @@ namespace opt { inf_eps get_upper(unsigned index) const; void get_model(model_ref& mdl); - void update_lower(unsigned idx, rational const& r); + void update_lower(unsigned idx, inf_eps const& r, bool override); + void update_upper(unsigned idx, inf_eps const& r, bool override); void reset(); From 5fab191c6c1aa710231522b137c40a91f71caf5b Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 25 Apr 2014 18:58:19 +0100 Subject: [PATCH 381/925] compilation fix Signed-off-by: Christoph M. Wintersteiger --- src/tactic/sls/bvsls_opt_engine.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/tactic/sls/bvsls_opt_engine.cpp b/src/tactic/sls/bvsls_opt_engine.cpp index 95a9389fc..a674e8a25 100644 --- a/src/tactic/sls/bvsls_opt_engine.cpp +++ b/src/tactic/sls/bvsls_opt_engine.cpp @@ -16,7 +16,6 @@ Author: Notes: --*/ -#include "sls_compilation_settings.h" #include "nnf.h" #include "bvsls_opt_engine.h" @@ -42,7 +41,6 @@ bvsls_opt_engine::optimization_result bvsls_opt_engine::optimize( TRACE("sls_opt", tout << "objective: " << (_maximize?"maximize":"minimize") << " " << mk_ismt2_pp(objective, m()) << std::endl;); m_hard_tracker.initialize(m_assertions); - m_restart_limit = _RESTART_LIMIT_; setup_opt_tracker(objective, _maximize); if (initial_model.get() != 0) { @@ -53,7 +51,7 @@ bvsls_opt_engine::optimization_result bvsls_opt_engine::optimize( tout << fd->get_name() << " := " << mk_ismt2_pp(val, m()) << std::endl; }); m_hard_tracker.set_model(initial_model); - m_evaluator.update_all(); + m_evaluator.update_all(); } optimization_result res(m_manager); From 182fea2d7ba77c8ceec8b974d5e3729ef3bd84fe Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 5 May 2014 10:21:16 -0700 Subject: [PATCH 382/925] fix bcd2 Signed-off-by: Nikolaj Bjorner --- src/opt/maxsmt.cpp | 4 ++-- src/opt/opt_context.cpp | 7 ++----- src/opt/weighted_maxsat.cpp | 1 + 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index cc1b1ba42..1f43bbe36 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -91,7 +91,7 @@ namespace opt { rational r = m_lower; if (m_msolver) { rational q = m_msolver->get_lower(); - if (r < q) r = q; + if (q > r) r = q; } return r; } @@ -100,7 +100,7 @@ namespace opt { rational r = m_upper; if (m_msolver) { rational q = m_msolver->get_upper(); - if (r > q) r = q; + if (q < r) r = q; } return r; } diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 4f2a5eba2..7b9ca0a8d 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -612,7 +612,6 @@ namespace opt { return mk_objective_fn(index, O_MAXSMT, num_fmls, fmls); } - void context::from_fmls(expr_ref_vector const& fmls) { TRACE("opt", for (unsigned i = 0; i < fmls.size(); ++i) { @@ -625,7 +624,7 @@ namespace opt { app_ref tr(m); expr_ref_vector terms(m); vector weights; - rational offset; + rational offset(0); unsigned index; symbol id; bool neg; @@ -737,7 +736,7 @@ namespace opt { } } if (ok) { - m_maxsmts.find(obj.m_id)->update_lower(r, override); + m_maxsmts.find(obj.m_id)->update_upper(r, override); } break; } @@ -749,7 +748,6 @@ namespace opt { } - void context::display_assignment(std::ostream& out) { for (unsigned i = 0; i < m_objectives.size(); ++i) { objective const& obj = m_objectives[i]; @@ -763,7 +761,6 @@ namespace opt { } } - void context::display_objective(std::ostream& out, objective const& obj) const { switch(obj.m_type) { case O_MAXSMT: { diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 593e87e7f..7a19e00af 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -300,6 +300,7 @@ namespace opt { unsigned s = *subC.begin(); wcore& c_s = m_cores[s]; c_s.m_lower = refine(c_s.m_R, c_s.m_mid); + c_s.m_mid = div(c_s.m_lower + c_s.m_upper, rational(2)); } else { wcore c_s; From 25ad9d2ee126b7ad262d8e3505485e151fcb9f5f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 5 May 2014 14:43:06 -0700 Subject: [PATCH 383/925] tuning based on benchmarks from Robert White Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/expr_safe_replace.cpp | 52 +++++++++++++------------- src/ast/rewriter/expr_safe_replace.h | 7 +++- src/opt/pb_sls.cpp | 7 ++++ src/opt/weighted_maxsat.cpp | 34 ++++++++++------- src/tactic/arith/elim01_tactic.cpp | 5 +++ 5 files changed, 65 insertions(+), 40 deletions(-) diff --git a/src/ast/rewriter/expr_safe_replace.cpp b/src/ast/rewriter/expr_safe_replace.cpp index a4886ad1a..37fcdfe6a 100644 --- a/src/ast/rewriter/expr_safe_replace.cpp +++ b/src/ast/rewriter/expr_safe_replace.cpp @@ -29,43 +29,39 @@ void expr_safe_replace::insert(expr* src, expr* dst) { } void expr_safe_replace::operator()(expr* e, expr_ref& res) { - obj_map cache; - ptr_vector todo, args; - expr_ref_vector refs(m); - todo.push_back(e); + m_todo.push_back(e); expr* a, *b, *d; - todo.push_back(e); - while (!todo.empty()) { - a = todo.back(); - if (cache.contains(a)) { - todo.pop_back(); + while (!m_todo.empty()) { + a = m_todo.back(); + if (m_cache.contains(a)) { + m_todo.pop_back(); } else if (m_subst.find(a, b)) { - cache.insert(a, b); - todo.pop_back(); + m_cache.insert(a, b); + m_todo.pop_back(); } else if (is_var(a)) { - cache.insert(a, a); - todo.pop_back(); + m_cache.insert(a, a); + m_todo.pop_back(); } else if (is_app(a)) { app* c = to_app(a); unsigned n = c->get_num_args(); - args.reset(); + m_args.reset(); for (unsigned i = 0; i < n; ++i) { - if (cache.find(c->get_arg(i), d)) { - args.push_back(d); + if (m_cache.find(c->get_arg(i), d)) { + m_args.push_back(d); } else { - todo.push_back(c->get_arg(i)); + m_todo.push_back(c->get_arg(i)); } } - if (args.size() == n) { - b = m.mk_app(c->get_decl(), args.size(), args.c_ptr()); - refs.push_back(b); - cache.insert(a, b); - todo.pop_back(); + if (m_args.size() == n) { + b = m.mk_app(c->get_decl(), m_args.size(), m_args.c_ptr()); + m_refs.push_back(b); + m_cache.insert(a, b); + m_todo.pop_back(); } } else { @@ -93,12 +89,16 @@ void expr_safe_replace::operator()(expr* e, expr_ref& res) { } replace(q->get_expr(), new_body); b = m.update_quantifier(q, pats.size(), pats.c_ptr(), nopats.size(), nopats.c_ptr(), new_body); - refs.push_back(b); - cache.insert(a, b); - todo.pop_back(); + m_refs.push_back(b); + m_cache.insert(a, b); + m_todo.pop_back(); } } - res = cache.find(e); + res = m_cache.find(e); + m_cache.reset(); + m_todo.reset(); + m_args.reset(); + m_refs.reset(); } void expr_safe_replace::reset() { diff --git a/src/ast/rewriter/expr_safe_replace.h b/src/ast/rewriter/expr_safe_replace.h index ad626d18f..1f21d35e9 100644 --- a/src/ast/rewriter/expr_safe_replace.h +++ b/src/ast/rewriter/expr_safe_replace.h @@ -29,9 +29,12 @@ class expr_safe_replace { expr_ref_vector m_src; expr_ref_vector m_dst; obj_map m_subst; + obj_map m_cache; + ptr_vector m_todo, m_args; + expr_ref_vector m_refs; public: - expr_safe_replace(ast_manager& m): m(m), m_src(m), m_dst(m) {} + expr_safe_replace(ast_manager& m): m(m), m_src(m), m_dst(m), m_refs(m) {} void insert(expr* src, expr* dst); @@ -42,6 +45,8 @@ public: void apply_substitution(expr* s, expr* def, expr_ref& t); void reset(); + + bool empty() const { return m_subst.empty(); } }; #endif /* __EXPR_SAFE_REPLACE_H__ */ diff --git a/src/opt/pb_sls.cpp b/src/opt/pb_sls.cpp index c62c79c6a..f04301c06 100644 --- a/src/opt/pb_sls.cpp +++ b/src/opt/pb_sls.cpp @@ -90,6 +90,8 @@ namespace smt { struct stats { stats() { reset(); } void reset() { memset(this, 0, sizeof(*this)); } + unsigned m_num_flips; + unsigned m_num_improvements; }; ast_manager& m; @@ -116,6 +118,7 @@ namespace smt { unsigned m_non_greedy_percent; // percent of moves to do non-greedy style random_gen m_rng; scoped_mpz one; + stats m_stats; imp(ast_manager& m): m(m), @@ -238,6 +241,8 @@ namespace smt { } void collect_statistics(::statistics& st) const { + st.update("sls.num_flips", m_stats.m_num_flips); + st.update("sls.num_improvements", m_stats.m_num_improvements); } void updt_params(params_ref& p) { @@ -347,6 +352,7 @@ namespace smt { } literal flip() { + m_stats.m_num_flips++; literal result; if (m_hard_false.empty()) { result = flip_soft(); @@ -359,6 +365,7 @@ namespace smt { m_best_assignment.reset(); m_best_assignment.append(m_assignment); m_best_penalty = m_penalty; + m_stats.m_num_improvements++; init_max_flips(); } if (!m_assignment[result.var()]) { diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 7a19e00af..42a1c8ce3 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -60,17 +60,24 @@ namespace opt { params_ref m_params; // config bool m_enable_sls; // config bool m_enable_sat; // config + bool m_sls_enabled; + bool m_sat_enabled; public: maxsmt_solver_base(solver* s, ast_manager& m): m_s(s), m(m), m_cancel(false), m_soft(m), - m_enable_sls(false), m_enable_sat(false) {} + m_enable_sls(false), m_enable_sat(false), + m_sls_enabled(false), m_sat_enabled(false) {} virtual ~maxsmt_solver_base() {} virtual rational get_lower() const { return m_lower; } virtual rational get_upper() const { return m_upper; } virtual bool get_assignment(unsigned index) const { return m_assignment[index]; } virtual void set_cancel(bool f) { m_cancel = f; m_s->set_cancel(f); } - virtual void collect_statistics(statistics& st) const { } + virtual void collect_statistics(statistics& st) const { + if (m_sls_enabled || m_sat_enabled) { + m_s->collect_statistics(st); + } + } virtual void get_model(model_ref& mdl) { mdl = m_model.get(); } virtual void updt_params(params_ref& p) { m_params.copy(p); @@ -121,7 +128,6 @@ namespace opt { fid != pb.get_family_id() && fid != bv.get_family_id() && !is_uninterp_const(n)) { - std::cout << mk_pp(n, m) << "\n"; throw found(); } } @@ -147,7 +153,7 @@ namespace opt { } void enable_bvsat() { - if (probe_bv()) { + if (m_enable_sat && !m_sat_enabled && probe_bv()) { tactic_ref pb2bv = mk_card2bv_tactic(m, m_params); tactic_ref bv2sat = mk_qfbv_tactic(m, m_params); tactic_ref tac = and_then(pb2bv.get(), bv2sat.get()); @@ -159,15 +165,17 @@ namespace opt { unsigned lvl = m_s->get_scope_level(); while (lvl > 0) { sat_solver->push(); --lvl; } m_s = sat_solver; + m_sat_enabled = true; } } void enable_sls() { - if (m_enable_sls && probe_bv()) { + if (m_enable_sls && !m_sls_enabled && probe_bv()) { m_params.set_uint("restarts", 20); unsigned lvl = m_s->get_scope_level(); m_s = alloc(sls_solver, m, m_s.get(), m_soft, m_weights, m_params); while (lvl > 0) { m_s->push(); --lvl; } + m_sls_enabled = true; } } @@ -249,19 +257,18 @@ namespace opt { m_soft_aux(m), m_trail(m), m_soft_constraints(m), - m_enable_lazy(false) { + m_enable_lazy(true) { m_enable_lazy = true; - enable_sls(); } virtual ~bcd2() {} - virtual lbool operator()() { expr_ref fml(m), r(m); lbool is_sat = l_undef; expr_ref_vector asms(m); bool first = true; + enable_sls(); solver::scoped_push _scope1(s()); init(); init_bcd(); @@ -557,13 +564,14 @@ namespace opt { public: pbmax(solver* s, ast_manager& m, bool use_aux): maxsmt_solver_base(s, m), m_use_aux(use_aux) { - enable_bvsat(); - enable_sls(); } virtual ~pbmax() {} lbool operator()() { + enable_bvsat(); + enable_sls(); + TRACE("opt", s().display(tout); tout << "\n"; for (unsigned i = 0; i < m_soft.size(); ++i) { tout << mk_pp(m_soft[i].get(), m) << " " << m_weights[i] << "\n"; @@ -636,12 +644,12 @@ namespace opt { public: wpm2(solver* s, ast_manager& m, maxsmt_solver_base* _maxs): maxsmt_solver_base(s, m), maxs(_maxs) { - enable_sls(); } virtual ~wpm2() {} lbool operator()() { + enable_sls(); IF_VERBOSE(1, verbose_stream() << "(wmaxsat.wpm2 solve)\n";); solver::scoped_push _s(s()); pb_util u(m); @@ -839,12 +847,12 @@ namespace opt { public: sls(solver* s, ast_manager& m): maxsmt_solver_base(s, m) { - enable_bvsat(); - enable_sls(); } virtual ~sls() {} lbool operator()() { IF_VERBOSE(1, verbose_stream() << "(sls solve)\n";); + enable_bvsat(); + enable_sls(); init(); lbool is_sat = s().check_sat(0, 0); if (is_sat == l_true) { diff --git a/src/tactic/arith/elim01_tactic.cpp b/src/tactic/arith/elim01_tactic.cpp index 300291cb2..53fa948ce 100644 --- a/src/tactic/arith/elim01_tactic.cpp +++ b/src/tactic/arith/elim01_tactic.cpp @@ -185,6 +185,11 @@ public: << bounds.has_upper(x, hi, s2) << " " << hi << "\n";); } } + + if (sub.empty()) { + result.push_back(g.get()); + return; + } expr_ref new_curr(m), tmp_curr(m); proof_ref new_pr(m); From f1ebf2002ade0bb141bddf01d5c918ec986a4b44 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 5 May 2014 16:40:54 -0700 Subject: [PATCH 384/925] tuning sls Signed-off-by: Nikolaj Bjorner --- src/duality/duality.h | 2 +- src/duality/duality_solver.cpp | 2 +- src/opt/pb_sls.cpp | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/duality/duality.h b/src/duality/duality.h index fc70ffa70..4005adc1a 100644 --- a/src/duality/duality.h +++ b/src/duality/duality.h @@ -29,7 +29,7 @@ using namespace stl_ext; namespace Duality { - class implicant_solver; + struct implicant_solver; /* Generic operations on Z3 formulas */ diff --git a/src/duality/duality_solver.cpp b/src/duality/duality_solver.cpp index ff3bc190b..c10d83603 100644 --- a/src/duality/duality_solver.cpp +++ b/src/duality/duality_solver.cpp @@ -2201,7 +2201,7 @@ namespace Duality { #endif int expand_max = 1; if(0&&duality->BatchExpand){ - int thing = stack.size() * 0.1; + int thing = static_cast(stack.size() * 0.1); expand_max = std::max(1,thing); if(expand_max > 1) std::cout << "foo!\n"; diff --git a/src/opt/pb_sls.cpp b/src/opt/pb_sls.cpp index f04301c06..29d814a43 100644 --- a/src/opt/pb_sls.cpp +++ b/src/opt/pb_sls.cpp @@ -623,6 +623,9 @@ namespace smt { m_orig_clauses.push_back(f); return result; } + if (pb.is_ge(f)) { + + } IF_VERBOSE(0, verbose_stream() << "not handled: " << mk_pp(f, m) << "\n";); return mk_aux_literal(f); } From 7ade3f2c04556d9ee33dc03d83f0b982525ede31 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 5 May 2014 19:22:34 -0700 Subject: [PATCH 385/925] fix sls based on pkb120 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_sls_solver.h | 7 +++++- src/opt/pb_sls.cpp | 50 ++++++++++++++++++++++++++++++++++--- src/opt/pb_sls.h | 1 + src/opt/weighted_maxsat.cpp | 1 + 4 files changed, 54 insertions(+), 5 deletions(-) diff --git a/src/opt/opt_sls_solver.h b/src/opt/opt_sls_solver.h index 7578502b0..282cc03e5 100644 --- a/src/opt/opt_sls_solver.h +++ b/src/opt/opt_sls_solver.h @@ -194,7 +194,12 @@ namespace opt { void pbsls_opt() { #pragma omp critical (sls_solver) { - m_pbsls = alloc(smt::pb_sls, m); + if (m_pbsls) { + m_pbsls->reset(); + } + else { + m_pbsls = alloc(smt::pb_sls, m); + } } m_pbsls->set_model(m_model); m_pbsls->updt_params(m_params); diff --git a/src/opt/pb_sls.cpp b/src/opt/pb_sls.cpp index 29d814a43..1052e44b6 100644 --- a/src/opt/pb_sls.cpp +++ b/src/opt/pb_sls.cpp @@ -130,7 +130,24 @@ namespace smt { one(mgr) { init_max_flips(); + } + + ~imp() { + } + + void reset() { + init_max_flips(); m_non_greedy_percent = 30; + m_decl2var.reset(); + m_var2decl.reset(); + m_assignment.reset(); + m_hard_occ.reset(); + m_soft_occ.reset(); + m_clauses.reset(); + m_orig_clauses.reset(); + m_soft.reset(); + m_weights.reset(); + m_trail.reset(); m_decl2var.insert(m.mk_true(), 0); m_var2decl.push_back(m.mk_true()); m_assignment.push_back(true); @@ -139,9 +156,6 @@ namespace smt { one = mpz(1); } - ~imp() { - } - void init_max_flips() { m_max_flips = 200; } @@ -635,11 +649,36 @@ namespace smt { m_rewrite(_f, tmp); if (!is_app(tmp)) return false; app* f = to_app(tmp); + expr* f2; unsigned sz = f->get_num_args(); expr* const* args = f->get_args(); literal lit; rational coeff, k; - if (pb.is_ge(f) || pb.is_eq(f)) { + if (m.is_not(f, f2) && pb.is_ge(f2)) { + // ~(ax+by >= k) + // <=> + // ax + by < k + // <=> + // -ax - by >= -k + 1 + // <=> + // a(1-x) + b(1-y) >= -k + a + b + 1 + sz = to_app(f2)->get_num_args(); + args = to_app(f2)->get_args(); + k = pb.get_k(f2); + SASSERT(k.is_int()); + k.neg(); + k += rational::one(); + expr_ref_vector args(m); + vector coeffs; + for (unsigned i = 0; i < sz; ++i) { + args.push_back(m.mk_not(to_app(f2)->get_arg(i))); + coeffs.push_back(pb.get_coeff(f2, i)); + k += pb.get_coeff(f2, i); + } + tmp = pb.mk_ge(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), k); + return compile_clause(tmp, cls); + } + else if (pb.is_ge(f) || pb.is_eq(f)) { k = pb.get_k(f); SASSERT(k.is_int()); cls.m_k = k.to_mpq().numerator(); @@ -720,6 +759,9 @@ namespace smt { void pb_sls::get_model(model_ref& mdl) { m_imp->get_model(mdl); } + void pb_sls::reset() { + m_imp->reset(); + } bool pb_sls::soft_holds(unsigned index) { return m_imp->soft_holds(index); } diff --git a/src/opt/pb_sls.h b/src/opt/pb_sls.h index c8d2c60c2..d3993dc49 100644 --- a/src/opt/pb_sls.h +++ b/src/opt/pb_sls.h @@ -42,6 +42,7 @@ namespace smt { void collect_statistics(::statistics& st) const; void get_model(model_ref& mdl); void updt_params(params_ref& p); + void reset(); }; diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 42a1c8ce3..b56e28579 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -621,6 +621,7 @@ namespace opt { } TRACE("opt", tout << "new upper: " << m_upper << "\n";); IF_VERBOSE(1, verbose_stream() << "(wmaxsat.pb solve with upper bound: " << m_upper << ")\n";); + fml = m.mk_not(u.mk_ge(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper)); was_sat = true; } From d2db8007d8dfb211addf9ee72f25320f48180420 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 6 May 2014 04:01:10 -0700 Subject: [PATCH 386/925] tuning pb/max Signed-off-by: Nikolaj Bjorner --- src/ast/pb_decl_plugin.cpp | 34 +++++++++++++++++++++++ src/ast/pb_decl_plugin.h | 3 ++ src/opt/opt_sls_solver.h | 24 +++++++++------- src/opt/opt_solver.cpp | 4 ++- src/opt/weighted_maxsat.cpp | 41 +++++++++++++++------------- src/smt/params/smt_params_helper.pyg | 2 +- src/smt/params/theory_pb_params.h | 2 +- src/smt/smt_setup.cpp | 1 - src/smt/theory_pb.cpp | 7 +---- 9 files changed, 79 insertions(+), 39 deletions(-) diff --git a/src/ast/pb_decl_plugin.cpp b/src/ast/pb_decl_plugin.cpp index 808f4e3dc..c04ed5e8c 100644 --- a/src/ast/pb_decl_plugin.cpp +++ b/src/ast/pb_decl_plugin.cpp @@ -126,6 +126,40 @@ app * pb_util::mk_eq(unsigned num_args, rational const * coeffs, expr * const * return m.mk_app(m_fid, OP_PB_EQ, params.size(), params.c_ptr(), num_args, args, m.mk_bool_sort()); } +// ax + by < k +// <=> +// -ax - by >= -k + 1 +// <=> +// a(1-x) + b(1-y) >= -k + a + b + 1 +app * pb_util::mk_lt(unsigned num_args, rational const * _coeffs, expr * const * _args, rational const& _k) { + vector coeffs; + rational k(_k); + expr_ref_vector args(m); + expr* f; + rational d(denominator(k)); + for (unsigned i = 0; i < num_args; ++i) { + coeffs.push_back(_coeffs[i]); + d = lcm(d, denominator(coeffs[i])); + if (m.is_not(_args[i], f)) { + args.push_back(f); + } + else { + args.push_back(m.mk_not(f)); + } + } + if (!d.is_one()) { + k *= d; + for (unsigned i = 0; i < num_args; ++i) { + coeffs[i] *= d; + } + } + k.neg(); + k += rational::one(); + for (unsigned i = 0; i < num_args; ++i) { + k += coeffs[i]; + } + return mk_ge(num_args, coeffs.c_ptr(), args.c_ptr(), k); +} app * pb_util::mk_at_most_k(unsigned num_args, expr * const * args, unsigned k) { diff --git a/src/ast/pb_decl_plugin.h b/src/ast/pb_decl_plugin.h index 54da51775..8ecf0f259 100644 --- a/src/ast/pb_decl_plugin.h +++ b/src/ast/pb_decl_plugin.h @@ -86,6 +86,7 @@ public: app * mk_le(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k); app * mk_ge(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k); app * mk_eq(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k); + app * mk_lt(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k); bool is_at_most_k(func_decl *a) const; bool is_at_most_k(expr *a) const { return is_app(a) && is_at_most_k(to_app(a)->get_decl()); } bool is_at_most_k(expr *a, rational& k) const; @@ -106,6 +107,8 @@ public: bool is_eq(func_decl* f) const; bool is_eq(expr* e) const { return is_app(e) && is_eq(to_app(e)->get_decl()); } bool is_eq(expr* e, rational& k) const; + + private: rational to_rational(parameter const& p) const; }; diff --git a/src/opt/opt_sls_solver.h b/src/opt/opt_sls_solver.h index 282cc03e5..e2cac1d89 100644 --- a/src/opt/opt_sls_solver.h +++ b/src/opt/opt_sls_solver.h @@ -116,6 +116,15 @@ namespace opt { // if (m_bvsls) m_bvsls->display(out); } + void opt(model_ref& mdl) { + if (m_engine == symbol("pb")) { + pbsls_opt(mdl); + } + else { + bvsls_opt(mdl); + } + } + protected: typedef bvsls_opt_engine::optimization_result opt_result; @@ -123,12 +132,7 @@ namespace opt { lbool r = m_solver->check_sat(num_assumptions, assumptions); if (r == l_true) { m_solver->get_model(m_model); - if (m_engine == symbol("pb")) { - pbsls_opt(); - } - else { - bvsls_opt(); - } + opt(m_model); } return r; } @@ -191,7 +195,7 @@ namespace opt { } } - void pbsls_opt() { + void pbsls_opt(model_ref& mdl) { #pragma omp critical (sls_solver) { if (m_pbsls) { @@ -201,7 +205,7 @@ namespace opt { m_pbsls = alloc(smt::pb_sls, m); } } - m_pbsls->set_model(m_model); + m_pbsls->set_model(mdl); m_pbsls->updt_params(m_params); for (unsigned i = 0; i < m_solver->get_num_assertions(); ++i) { m_pbsls->add(m_solver->get_assertion(i)); @@ -213,7 +217,7 @@ namespace opt { m_pbsls->get_model(m_model); } - void bvsls_opt() { + void bvsls_opt(model_ref& mdl) { #pragma omp critical (sls_solver) { m_bvsls = alloc(bvsls_opt_engine, m, m_params); @@ -223,7 +227,7 @@ namespace opt { opt_result res(m); res.is_sat = l_undef; try { - res = m_bvsls->optimize(objective, m_model, true); + res = m_bvsls->optimize(objective, mdl, true); } catch (...) { diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index cd4e167dc..23c1a59b2 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -43,8 +43,10 @@ namespace opt { m_dump_benchmarks(false), m_fm(alloc(filter_model_converter, m)) { m_logic = l; - if (m_logic != symbol::null) + if (m_logic != symbol::null) { m_context.set_logic(m_logic); + } + m_params.updt_params(p); m_params.m_relevancy_lvl = 0; } diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index b56e28579..fbd028338 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -66,7 +66,10 @@ namespace opt { maxsmt_solver_base(solver* s, ast_manager& m): m_s(s), m(m), m_cancel(false), m_soft(m), m_enable_sls(false), m_enable_sat(false), - m_sls_enabled(false), m_sat_enabled(false) {} + m_sls_enabled(false), m_sat_enabled(false) { + m_s->get_model(m_model); + SASSERT(m_model); + } virtual ~maxsmt_solver_base() {} virtual rational get_lower() const { return m_lower; } @@ -173,9 +176,11 @@ namespace opt { if (m_enable_sls && !m_sls_enabled && probe_bv()) { m_params.set_uint("restarts", 20); unsigned lvl = m_s->get_scope_level(); - m_s = alloc(sls_solver, m, m_s.get(), m_soft, m_weights, m_params); + sls_solver* sls = alloc(sls_solver, m, m_s.get(), m_soft, m_weights, m_params); + m_s = sls; while (lvl > 0) { m_s->push(); --lvl; } m_sls_enabled = true; + sls->opt(m_model); } } @@ -598,9 +603,21 @@ namespace opt { } } lbool is_sat = l_true; - bool was_sat = false; - fml = m.mk_true(); while (l_true == is_sat) { + IF_VERBOSE(1, verbose_stream() << "(wmaxsat.pb solve with upper bound: " << m_upper << ")\n";); + m_upper.reset(); + for (unsigned i = 0; i < m_soft.size(); ++i) { + VERIFY(m_model->eval(nsoft[i].get(), val)); + TRACE("opt", tout << "eval " << mk_pp(m_soft[i].get(), m) << " " << val << "\n";); + m_assignment[i] = !m.is_true(val); + if (!m_assignment[i]) { + m_upper += m_weights[i]; + } + } + TRACE("opt", tout << "new upper: " << m_upper << "\n";); + + fml = u.mk_lt(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper); + TRACE("opt", s().display(tout<<"looping\n");); solver::scoped_push _scope2(s()); s().assert_expr(fml); @@ -609,24 +626,10 @@ namespace opt { is_sat = l_undef; } if (is_sat == l_true) { - m_upper.reset(); s().get_model(m_model); - for (unsigned i = 0; i < m_soft.size(); ++i) { - VERIFY(m_model->eval(nsoft[i].get(), val)); - TRACE("opt", tout << "eval " << mk_pp(m_soft[i].get(), m) << " " << val << "\n";); - m_assignment[i] = !m.is_true(val); - if (!m_assignment[i]) { - m_upper += m_weights[i]; - } - } - TRACE("opt", tout << "new upper: " << m_upper << "\n";); - IF_VERBOSE(1, verbose_stream() << "(wmaxsat.pb solve with upper bound: " << m_upper << ")\n";); - - fml = m.mk_not(u.mk_ge(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper)); - was_sat = true; } } - if (is_sat == l_false && was_sat) { + if (is_sat == l_false) { is_sat = l_true; m_lower = m_upper; } diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 96ee7f5fc..3dec59d29 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -44,7 +44,7 @@ def_module_params(module_name='smt', ('arith.int_eq_branch', BOOL, False, 'branching using derived integer equations'), ('arith.ignore_int', BOOL, False, 'treat integer variables as real'), ('arith.dump_lemmas', BOOL, False, 'dump arithmetic theory lemmas to files'), - ('pb.conflict_frequency', UINT, 0, 'conflict frequency for Pseudo-Boolean theory'), + ('pb.conflict_frequency', UINT, 1000, 'conflict frequency for Pseudo-Boolean theory'), ('pb.learn_complements', BOOL, True, 'learn complement literals for Pseudo-Boolean theory'), ('pb.enable_compilation', BOOL, True, 'enable compilation into sorting circuits for Pseudo-Boolean'), ('pb.enable_simplex', BOOL, False, 'enable simplex to check rational feasibility'), diff --git a/src/smt/params/theory_pb_params.h b/src/smt/params/theory_pb_params.h index f6debea8a..0432ac633 100644 --- a/src/smt/params/theory_pb_params.h +++ b/src/smt/params/theory_pb_params.h @@ -28,7 +28,7 @@ struct theory_pb_params { bool m_pb_enable_compilation; bool m_pb_enable_simplex; theory_pb_params(params_ref const & p = params_ref()): - m_pb_conflict_frequency(0), + m_pb_conflict_frequency(1000), m_pb_learn_complements(true), m_pb_enable_compilation(true), m_pb_enable_simplex(false) diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index f836a31c4..d933a5f43 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -790,7 +790,6 @@ namespace smt { } void setup::setup_card() { - // m_context.register_plugin(alloc(theory_card, m_manager)); m_context.register_plugin(alloc(theory_pb, m_manager, m_params)); } diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index fa9810fc5..495c757fa 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -187,8 +187,6 @@ namespace smt { m_args[1].append(m_args[0]); m_args[1].negate(); - //m_args[0].display(std::cout); - //m_args[1].display(std::cout); SASSERT(m_args[0].size() == m_args[1].size()); SASSERT(m_args[0].well_formed()); SASSERT(m_args[1].well_formed()); @@ -284,8 +282,6 @@ namespace smt { m_last_explain(last_explain) {} virtual void undo(context& ctx) { - //std::cout << "undo bound: " << m_v << " " << m_last_explain; - //std::cout << (m_is_lower?" lower ":" upper ") << pb.m_mpq_inf_mgr.to_string(m_last_bound) << "\n"; if (m_is_lower) { if (m_last_bound_valid) { pb.m_simplex.set_lower(m_v, m_last_bound); @@ -318,7 +314,6 @@ namespace smt { } bool theory_pb::update_bound(bool_var v, literal explain, bool is_lower, mpq_inf const& bound) { - // std::cout << v << " " << explain << (is_lower?" lower ":" upper ") << m_mpq_inf_mgr.to_string(bound) << "\n"; if (is_lower) { if (m_simplex.above_lower(v, bound)) { scoped_eps_numeral last_bound(m_mpq_inf_mgr); @@ -411,6 +406,7 @@ namespace smt { } bool theory_pb::internalize_atom(app * atom, bool gate_ctx) { + ast_manager& m = get_manager(); SASSERT(m_util.is_at_most_k(atom) || m_util.is_le(atom) || m_util.is_ge(atom) || m_util.is_at_least_k(atom) || m_util.is_eq(atom)); @@ -423,7 +419,6 @@ namespace smt { SASSERT(!ctx.b_internalized(atom)); m_stats.m_num_predicates++; - ast_manager& m = get_manager(); unsigned num_args = atom->get_num_args(); bool_var abv = ctx.mk_bool_var(atom); ctx.set_var_theory(abv, get_id()); From 05a39cb2cfea64d834da636f61d6a8181dabf1ab Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 May 2014 08:51:07 -0700 Subject: [PATCH 387/925] fix wrong simplex backtracking Signed-off-by: Nikolaj Bjorner --- src/ast/pb_decl_plugin.cpp | 2 +- src/math/simplex/simplex.h | 3 +- src/math/simplex/simplex_def.h | 64 ++++++++++++++++++++-- src/opt/opt_sls_solver.h | 2 + src/opt/pb_sls.cpp | 21 +++++--- src/opt/weighted_maxsat.cpp | 67 +++++++++++++---------- src/smt/theory_pb.cpp | 12 ++--- src/smt/theory_pb.h | 5 +- src/test/simplex.cpp | 2 - src/test/theory_pb.cpp | 99 ++++++++++++++++++++++++++++++++++ src/util/sorting_network.h | 10 ++-- 11 files changed, 231 insertions(+), 56 deletions(-) diff --git a/src/ast/pb_decl_plugin.cpp b/src/ast/pb_decl_plugin.cpp index c04ed5e8c..0cfe1c096 100644 --- a/src/ast/pb_decl_plugin.cpp +++ b/src/ast/pb_decl_plugin.cpp @@ -144,7 +144,7 @@ app * pb_util::mk_lt(unsigned num_args, rational const * _coeffs, expr * const * args.push_back(f); } else { - args.push_back(m.mk_not(f)); + args.push_back(m.mk_not(_args[i])); } } if (!d.is_one()) { diff --git a/src/math/simplex/simplex.h b/src/math/simplex/simplex.h index 7a5ba2d70..3f164f275 100644 --- a/src/math/simplex/simplex.h +++ b/src/math/simplex/simplex.h @@ -126,7 +126,7 @@ namespace simplex { row get_infeasible_row(); var_t get_base_var(row const& r) const { return m_row2base[r.id()]; } numeral const& get_base_coeff(row const& r) const { return m_vars[m_row2base[r.id()]].m_base_coeff; } - void del_row(row const& r); + void del_row(var_t base_var); void set_lower(var_t var, eps_numeral const& b); void set_upper(var_t var, eps_numeral const& b); void get_lower(var_t var, scoped_eps_numeral& b) const { b = m_vars[var].m_lower; } @@ -157,6 +157,7 @@ namespace simplex { private: + void del_row(row const& r); var_t select_var_to_fix(); pivot_strategy_t pivot_strategy(); var_t select_smallest_var() { return m_to_patch.empty()?null_var:m_to_patch.erase_min(); } diff --git a/src/math/simplex/simplex_def.h b/src/math/simplex/simplex_def.h index c3a2bef95..c1a4ec36e 100644 --- a/src/math/simplex/simplex_def.h +++ b/src/math/simplex/simplex_def.h @@ -114,6 +114,7 @@ namespace simplex { em.set(m_vars[base_var].m_value, value); add_patch(base_var); SASSERT(well_formed_row(r)); + SASSERT(well_formed()); return r; } @@ -135,10 +136,51 @@ namespace simplex { template void simplex::del_row(row const& r) { - TRACE("simplex", tout << r.id() << "\n";); - m_vars[m_row2base[r.id()]].m_is_base = false; + var_t var = m_row2base[r.id()]; + m_vars[var].m_is_base = false; + m_vars[var].m_lower_valid = false; + m_vars[var].m_upper_valid = false; m_row2base[r.id()] = null_var; M.del(r); + SASSERT(M.col_begin(var) == M.col_end(var)); + SASSERT(well_formed()); + } + + template + void simplex::del_row(var_t var) { + TRACE("simplex", tout << var << "\n";); + row r; + if (is_base(var)) { + r = row(m_vars[var].m_base2row); + } + else { + col_iterator it = M.col_begin(var), end = M.col_end(var); + if (it == end) { + return; + } + typename matrix::row_entry const& re = it.get_row_entry(); + r = it.get_row(); + var_t old_base = m_row2base[r.id()]; + scoped_eps_numeral new_value(em); + var_info& vi = m_vars[old_base]; + if (below_lower(old_base)) { + new_value = vi.m_lower; + } + else if (above_upper(old_base)) { + new_value = vi.m_upper; + } + else { + new_value = vi.m_value; + } + // need to move var such that old_base comes in bound. + update_and_pivot(old_base, var, re.m_coeff, new_value); + SASSERT(is_base(var)); + SASSERT(m_vars[var].m_base2row == r.id()); + SASSERT(!below_lower(old_base) && !above_upper(old_base)); + } + del_row(r); + TRACE("simplex", display(tout);); + SASSERT(well_formed()); } template @@ -164,6 +206,7 @@ namespace simplex { em.sub(b, vi.m_value, delta); update_value(var, delta); } + SASSERT(well_formed()); } template @@ -177,6 +220,7 @@ namespace simplex { em.sub(b, vi.m_value, delta); update_value(var, delta); } + SASSERT(well_formed()); } template @@ -194,6 +238,7 @@ namespace simplex { scoped_eps_numeral delta(em); em.sub(b, m_vars[var].m_value, delta); update_value(var, delta); + SASSERT(well_formed()); } template @@ -345,6 +390,7 @@ namespace simplex { SASSERT(well_formed_row(row(r_k))); } } + SASSERT(well_formed()); } template @@ -883,7 +929,13 @@ namespace simplex { var_t s = m_row2base[i]; if (s == null_var) continue; SASSERT(i == m_vars[s].m_base2row); - SASSERT(well_formed_row(row(i))); + VERIFY(well_formed_row(row(i))); + } + for (unsigned i = 0; i < m_vars.size(); ++i) { + if (!is_base(i)) { + SASSERT(!above_upper(i)); + SASSERT(!below_lower(i)); + } } return true; } @@ -909,7 +961,11 @@ namespace simplex { sum += tmp; SASSERT(s != it->m_var || m.eq(m_vars[s].m_base_coeff, it->m_coeff)); } - SASSERT(em.is_zero(sum)); + if (!em.is_zero(sum)) { + IF_VERBOSE(0, M.display_row(verbose_stream(), r);); + TRACE("pb", display(tout << "non-well formed row\n"); M.display_row(tout << "row: ", r);); + throw default_exception("non-well formed row"); + } return true; } diff --git a/src/opt/opt_sls_solver.h b/src/opt/opt_sls_solver.h index e2cac1d89..817537a75 100644 --- a/src/opt/opt_sls_solver.h +++ b/src/opt/opt_sls_solver.h @@ -215,6 +215,7 @@ namespace opt { } (*m_pbsls.get())(); m_pbsls->get_model(m_model); + mdl = m_model.get(); } void bvsls_opt(model_ref& mdl) { @@ -235,6 +236,7 @@ namespace opt { SASSERT(res.is_sat == l_true || res.is_sat == l_undef); if (res.is_sat == l_true) { m_bvsls->get_model(m_model); + mdl = m_model.get(); } } diff --git a/src/opt/pb_sls.cpp b/src/opt/pb_sls.cpp index 1052e44b6..a702b6b7b 100644 --- a/src/opt/pb_sls.cpp +++ b/src/opt/pb_sls.cpp @@ -129,7 +129,8 @@ namespace smt { m_trail(m), one(mgr) { - init_max_flips(); + reset(); + one = mpz(1); } ~imp() { @@ -153,7 +154,6 @@ namespace smt { m_assignment.push_back(true); m_hard_occ.push_back(unsigned_vector()); m_soft_occ.push_back(unsigned_vector()); - one = mpz(1); } void init_max_flips() { @@ -406,7 +406,14 @@ namespace smt { else if (break_count == min_bc && m_rng(5) == 1) { min_bc_index = i; } - VERIFY(-break_count == flip(~lit)); + int new_break_count = flip(~lit); + if (-break_count != new_break_count) { + verbose_stream() << lit << "\n"; + IF_VERBOSE(0, display(verbose_stream(), cls);); + display(verbose_stream()); + exit(0); + } + // VERIFY(-break_count == flip(~lit)); } if (m_rng(100) <= m_non_greedy_percent) { lit = cls.m_lits[m_rng(cls.m_lits.size())]; @@ -472,11 +479,12 @@ namespace smt { m_assignment[l.var()] = !m_assignment[l.var()]; int break_count = 0; unsigned_vector const& occh = m_hard_occ[l.var()]; - scoped_mpz value(mgr); + scoped_mpz value(mgr); for (unsigned i = 0; i < occh.size(); ++i) { unsigned j = occh[i]; - value = m_clauses[j].m_value; - if (eval(m_clauses[j])) { + clause& cls = m_clauses[j]; + value = cls.m_value; + if (eval(cls)) { if (m_hard_false.contains(j)) { break_count--; m_hard_false.remove(j); @@ -488,7 +496,6 @@ namespace smt { m_hard_false.insert(j); } else if (value < m_clauses[j].m_value) { - break_count++; } } } diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index fbd028338..112b0522a 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -82,6 +82,7 @@ namespace opt { } } virtual void get_model(model_ref& mdl) { mdl = m_model.get(); } + void set_model() { s().get_model(m_model); } virtual void updt_params(params_ref& p) { m_params.copy(p); s().updt_params(p); @@ -104,8 +105,12 @@ namespace opt { m_upper.reset(); m_assignment.reset(); for (unsigned i = 0; i < m_weights.size(); ++i) { - m_upper += m_weights[i]; - m_assignment.push_back(false); + expr_ref val(m); + VERIFY(m_model->eval(m_soft[i].get(), val)); + m_assignment.push_back(m.is_true(val)); + if (!m_assignment.back()) { + m_upper += m_weights[i]; + } } } expr* mk_not(expr* e) { @@ -255,6 +260,14 @@ namespace opt { m_upper += rational(1); } + void process_sat() { + svector assignment; + update_assignment(assignment); + if (check_lazy_soft(assignment)) { + update_sigmas(); + } + } + public: bcd2(solver* s, ast_manager& m): maxsmt_solver_base(s, m), @@ -263,7 +276,6 @@ namespace opt { m_trail(m), m_soft_constraints(m), m_enable_lazy(true) { - m_enable_lazy = true; } virtual ~bcd2() {} @@ -272,11 +284,15 @@ namespace opt { expr_ref fml(m), r(m); lbool is_sat = l_undef; expr_ref_vector asms(m); - bool first = true; enable_sls(); solver::scoped_push _scope1(s()); init(); init_bcd(); + if (m_cancel) { + normalize_bounds(); + return l_undef; + } + process_sat(); while (m_lower < m_upper) { IF_VERBOSE(1, verbose_stream() << "(wmaxsat.bcd2 [" << m_lower << ":" << m_upper << "])\n";); assert_soft(); @@ -293,15 +309,9 @@ namespace opt { case l_undef: normalize_bounds(); return l_undef; - case l_true: { - svector assignment; - update_assignment(assignment); - first = false; - if (check_lazy_soft(assignment)) { - update_sigmas(); - } - break; - } + case l_true: + process_sat(); + break; case l_false: { ptr_vector unsat_core; uint_set subC, soft; @@ -322,7 +332,7 @@ namespace opt { r = mk_fresh(); relax(subC, soft, c_s.m_R, delta); c_s.m_lower = refine(c_s.m_R, lower + delta - rational(1)); - c_s.m_upper = rational(first?1:0); + c_s.m_upper = rational::one(); c_s.m_upper += sum_of_sigmas(c_s.m_R); c_s.m_mid = div(c_s.m_lower + c_s.m_upper, rational(2)); c_s.m_r = r; @@ -337,12 +347,7 @@ namespace opt { m_lower = compute_lower(); } normalize_bounds(); - if (first) { - return is_sat; - } - else { - return l_true; - } + return l_true; } @@ -533,13 +538,18 @@ namespace opt { expr_ref fml(m); vector ws; ptr_vector rs; + rational w(0); for (unsigned j = 0; j < core.m_R.size(); ++j) { unsigned idx = core.m_R[j]; ws.push_back(m_weights[idx]); - rs.push_back(m_soft_aux[idx].get()); // TBD: check + w += ws.back(); + rs.push_back(m_soft_aux[idx].get()); } + w.neg(); + w += core.m_mid; + ws.push_back(w); + rs.push_back(core.m_r); fml = pb.mk_le(ws.size(), ws.c_ptr(), rs.c_ptr(), core.m_mid); - fml = m.mk_or(core.m_r, fml); s().assert_expr(fml); } void display(std::ostream& out) { @@ -604,7 +614,7 @@ namespace opt { } lbool is_sat = l_true; while (l_true == is_sat) { - IF_VERBOSE(1, verbose_stream() << "(wmaxsat.pb solve with upper bound: " << m_upper << ")\n";); + TRACE("opt", s().display(tout<<"looping\n");); m_upper.reset(); for (unsigned i = 0; i < m_soft.size(); ++i) { VERIFY(m_model->eval(nsoft[i].get(), val)); @@ -614,11 +624,10 @@ namespace opt { m_upper += m_weights[i]; } } + IF_VERBOSE(1, verbose_stream() << "(wmaxsat.pb solve with upper bound: " << m_upper << ")\n";); TRACE("opt", tout << "new upper: " << m_upper << "\n";); - fml = u.mk_lt(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper); - - TRACE("opt", s().display(tout<<"looping\n");); + fml = m.mk_not(u.mk_ge(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper)); solver::scoped_push _scope2(s()); s().assert_expr(fml); is_sat = s().check_sat(0,0); @@ -840,7 +849,11 @@ namespace opt { tout << mk_pp(bs[i], m) << " " << ws[i] << "\n"; }); maxs->init_soft(ws, nbs); - lbool is_sat = (*maxs)(); + lbool is_sat = maxs->s().check_sat(0,0); + if (is_sat == l_true) { + maxs->set_model(); + is_sat = (*maxs)(); + } SASSERT(maxs->get_lower() > k); k = maxs->get_lower(); return is_sat; diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 495c757fa..f19eb706c 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -529,11 +529,9 @@ namespace smt { numeral k = rep.k(); theory_var slack; bool_var abv2; - row r; TRACE("pb", display(tout << abv <<"\n", rep);); if (m_ineq_rep.find(rep, abv2)) { slack = abv2; - r = m_ineq_row_info.find(abv2).m_row; TRACE("pb", tout << "Old row: " << abv << " |-> " << slack << " "; tout << m_ineq_row_info.find(abv2).m_bound << " vs. " << k << "\n"; @@ -572,10 +570,10 @@ namespace smt { m_simplex.ensure_var(slack); vars.push_back(slack); coeffs.push_back(mpz(-1)); - r = m_simplex.add_row(slack, vars.size(), vars.c_ptr(), coeffs.c_ptr()); + m_simplex.add_row(slack, vars.size(), vars.c_ptr(), coeffs.c_ptr()); TRACE("pb", tout << "New row: " << abv << " " << k << "\n"; display(tout, rep);); } - m_ineq_row_info.insert(abv, row_info(slack, k, rep, r)); + m_ineq_row_info.insert(abv, row_info(slack, k, rep)); } TRACE("pb", display(tout, *c);); @@ -1310,7 +1308,7 @@ namespace smt { m_ineq_row_info.erase(v); bool_var v2 = m_ineq_rep.find(r_info.m_rep); if (v == v2) { - m_simplex.del_row(r_info.m_row); + m_simplex.del_row(r_info.m_slack); m_ineq_rep.erase(r_info.m_rep); } } @@ -1433,7 +1431,7 @@ namespace smt { justification* js = 0; - if (m_conflict_frequency == 0 || (0 == (c.m_num_propagations % m_conflict_frequency))) { + if (m_conflict_frequency == 0 || (m_conflict_frequency -1 == (c.m_num_propagations % m_conflict_frequency))) { resolve_conflict(c); } @@ -1854,6 +1852,8 @@ namespace smt { case l_undef: maxsum += c.coeff(i); break; + case l_false: + break; } } TRACE("pb", display(tout << "validate: ", c, true); diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 595cf5e6e..b7922fbd0 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -185,9 +185,8 @@ namespace smt { unsigned m_slack; // slack variable in simplex tableau numeral m_bound; // bound arg_t m_rep; // representative - row m_row; - row_info(theory_var slack, numeral const& b, arg_t const& r, row const& ro): - m_slack(slack), m_bound(b), m_rep(r), m_row(ro) {} + row_info(theory_var slack, numeral const& b, arg_t const& r): + m_slack(slack), m_bound(b), m_rep(r) {} row_info(): m_slack(0) {} }; diff --git a/src/test/simplex.cpp b/src/test/simplex.cpp index 37d4501f7..a70d0d8cf 100644 --- a/src/test/simplex.cpp +++ b/src/test/simplex.cpp @@ -124,8 +124,6 @@ static void test4() { feas(S); } - - void tst_simplex() { Simplex S; diff --git a/src/test/theory_pb.cpp b/src/test/theory_pb.cpp index 8c9ef405b..ee1ec126a 100644 --- a/src/test/theory_pb.cpp +++ b/src/test/theory_pb.cpp @@ -3,6 +3,7 @@ #include "model_v2_pp.h" #include "reg_decl_plugins.h" #include "theory_pb.h" +#include "th_rewriter.h" unsigned populate_literals(unsigned k, smt::literal_vector& lits) { SASSERT(k < (1u << lits.size())); @@ -19,7 +20,105 @@ unsigned populate_literals(unsigned k, smt::literal_vector& lits) { return t; } +class pb_fuzzer { + ast_manager& m; + random_gen rand; + smt_params params; + smt::context ctx; + expr_ref_vector vars; + +public: + pb_fuzzer(ast_manager& m): m(m), rand(0), ctx(m, params), vars(m) { + params.m_model = true; + params.m_pb_enable_simplex = true; + unsigned N = 3; + for (unsigned i = 0; i < N; ++i) { + std::stringstream strm; + strm << "b" << i; + vars.push_back(m.mk_const(symbol(strm.str().c_str()), m.mk_bool_sort())); + std::cout << "(declare-const " << strm.str() << " Bool)\n"; + } + } + + void fuzz() { + enable_trace("pb"); + enable_trace("simplex"); + unsigned nr = 0; + for (unsigned i = 0; i < 100000; ++i) { + fuzz_round(nr, 2); + } + } + +private: + + void add_ineq() { + pb_util pb(m); + expr_ref fml(m), tmp(m); + th_rewriter rw(m); + vector coeffs(vars.size()); + expr_ref_vector args(vars); + while (true) { + rational k(rand(6)); + for (unsigned i = 0; i < coeffs.size(); ++i) { + int v = 3 - rand(5); + coeffs[i] = rational(v); + if (coeffs[i].is_neg()) { + args[i] = m.mk_not(args[i].get()); + coeffs[i].neg(); + k += coeffs[i]; + } + } + fml = pb.mk_ge(args.size(), coeffs.c_ptr(), args.c_ptr(), k); + rw(fml, tmp); + rw(tmp, tmp); + if (pb.is_ge(tmp)) { + fml = tmp; + break; + } + } + std::cout << "(assert " << fml << ")\n"; + ctx.assert_expr(fml); + } + + + + void fuzz_round(unsigned& num_rounds, unsigned lvl) { + unsigned num_rounds2 = 0; + lbool is_sat = l_true; + std::cout << "(push)\n"; + ctx.push(); + unsigned r = 0; + while (is_sat == l_true && r <= num_rounds + 1) { + add_ineq(); + std::cout << "(check-sat)\n"; + is_sat = ctx.check(); + if (lvl > 0 && is_sat == l_true) { + fuzz_round(num_rounds2, lvl-1); + } + ++r; + } + num_rounds = r; + std::cout << "; number of rounds: " << num_rounds << " level: " << lvl << "\n"; + ctx.pop(1); + std::cout << "(pop)\n"; + } + +}; + + + +static void fuzz_pb() +{ + ast_manager m; + reg_decl_plugins(m); + pb_fuzzer fuzzer(m); + fuzzer.fuzz(); +} + void tst_theory_pb() { + + fuzz_pb(); + ast_manager m; smt_params params; params.m_model = true; diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index b9cf86433..f403f9e16 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -187,7 +187,7 @@ Notes: else { SASSERT(2*k <= n); m_t = full?GE_FULL:GE; - card(k, n, xs, out); + psort_nw::card(k, n, xs, out); return out[k-1]; } } @@ -322,8 +322,8 @@ Notes: void cmp(literal x1, literal x2, literal y1, literal y2) { switch(m_t) { - case LE: cmp_le(x1, x2, y1, y2); break; - case GE: cmp_ge(x1, x2, y1, y2); break; + case LE: case LE_FULL: cmp_le(x1, x2, y1, y2); break; + case GE: case GE_FULL: cmp_ge(x1, x2, y1, y2); break; case EQ: cmp_eq(x1, x2, y1, y2); break; } } @@ -334,7 +334,7 @@ Notes: void card(unsigned k, unsigned n, literal const* xs, literal_vector& out) { TRACE("pb", tout << "card k:" << k << " n: " << n << "\n";); if (n <= k) { - sorting(n, xs, out); + psort_nw::sorting(n, xs, out); } else if (use_dcard(k, n)) { dsorting(k, n, xs, out); @@ -485,7 +485,7 @@ Notes: out.push_back(xs[0]); break; case 2: - merge(1, xs, 1, xs+1, out); + psort_nw::merge(1, xs, 1, xs+1, out); break; default: if (use_dsorting(n)) { From 9c1f85e564feff0ef93f0d7fed6a1b86fed8987a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 May 2014 11:03:11 -0700 Subject: [PATCH 388/925] addressing compiler warnings Signed-off-by: Nikolaj Bjorner --- src/interp/iz3base.h | 2 +- src/math/simplex/sparse_matrix_def.h | 1 - src/smt/theory_pb.cpp | 6 ------ src/smt/theory_wmaxsat.cpp | 1 - src/tactic/arith/card2bv_tactic.cpp | 1 - 5 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/interp/iz3base.h b/src/interp/iz3base.h index d82e721ae..550c563af 100755 --- a/src/interp/iz3base.h +++ b/src/interp/iz3base.h @@ -161,7 +161,7 @@ class iz3base : public iz3mgr, public scopes { stl_ext::hash_map simplify_memo; stl_ext::hash_map frame_map; // map assertions to frames - int frames; // number of frames + // int frames; // number of frames protected: void add_frame_range(int frame, ast t); diff --git a/src/math/simplex/sparse_matrix_def.h b/src/math/simplex/sparse_matrix_def.h index 277165138..f4c25658e 100644 --- a/src/math/simplex/sparse_matrix_def.h +++ b/src/math/simplex/sparse_matrix_def.h @@ -325,7 +325,6 @@ namespace simplex { void sparse_matrix::add(row row1, numeral const& n, row row2) { m_stats.m_add_rows++; _row & r1 = m_rows[row1.id()]; - _row & r2 = m_rows[row2.id()]; r1.save_var_pos(m_var_pos, m_var_pos_idx); diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index f19eb706c..1ae3634aa 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -406,7 +406,6 @@ namespace smt { } bool theory_pb::internalize_atom(app * atom, bool gate_ctx) { - ast_manager& m = get_manager(); SASSERT(m_util.is_at_most_k(atom) || m_util.is_le(atom) || m_util.is_ge(atom) || m_util.is_at_least_k(atom) || m_util.is_eq(atom)); @@ -707,7 +706,6 @@ namespace smt { } void theory_pb::remove(ptr_vector& ineqs, ineq* c) { - context& ctx = get_context(); for (unsigned j = 0; j < ineqs.size(); ++j) { if (ineqs[j] == c) { std::swap(ineqs[j], ineqs[ineqs.size()-1]); @@ -1217,7 +1215,6 @@ namespace smt { void theory_pb::compile_ineq(ineq& c) { ++m_stats.m_num_compiles; - ast_manager& m = get_manager(); context& ctx = get_context(); // only cardinality constraints are compiled. SASSERT(c.m_compilation_threshold < UINT_MAX); @@ -1551,8 +1548,6 @@ namespace smt { m_ineq_literals.push_back(c.lit()); } } - - static unsigned s_min_l_size = UINT_MAX; // // modeled after sat_solver/smt_context @@ -1789,7 +1784,6 @@ namespace smt { // debug methods void theory_pb::validate_watch(ineq const& c) const { - context& ctx = get_context(); scoped_mpz sum(m_mpz_mgr), max(m_mpz_mgr); for (unsigned i = 0; i < c.watch_size(); ++i) { sum += c.ncoeff(i); diff --git a/src/smt/theory_wmaxsat.cpp b/src/smt/theory_wmaxsat.cpp index 556f5047a..2c33d28da 100644 --- a/src/smt/theory_wmaxsat.cpp +++ b/src/smt/theory_wmaxsat.cpp @@ -105,7 +105,6 @@ bool_var theory_wmaxsat::assert_weighted(expr* fml, rational const& w) { bool_var theory_wmaxsat::register_var(app* var, bool attach) { context & ctx = get_context(); - ast_manager& m = get_manager(); bool_var bv; SASSERT(!ctx.e_internalized(var)); enode* x = ctx.mk_enode(var, false, true, true); diff --git a/src/tactic/arith/card2bv_tactic.cpp b/src/tactic/arith/card2bv_tactic.cpp index bba8705e0..26bea6343 100644 --- a/src/tactic/arith/card2bv_tactic.cpp +++ b/src/tactic/arith/card2bv_tactic.cpp @@ -102,7 +102,6 @@ namespace pb { // else if (f->get_family_id() == au.get_family_id()) { if (f->get_decl_kind() == OP_ADD) { - bool all_ite_01 = true; unsigned bits = 0; for (unsigned i = 0; i < sz; i++) { rational val1, val2; From 1e235659c7fac37a6a1b575619ad384d0de47c00 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 May 2014 11:05:22 -0700 Subject: [PATCH 389/925] unreferenced variable Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 1ae3634aa..cb52f0e79 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -760,7 +760,6 @@ namespace smt { } void theory_pb::assign_eh(bool_var v, bool is_true) { - context& ctx = get_context(); ptr_vector* ineqs = 0; literal nlit(v, is_true); TRACE("pb", tout << "assign: " << ~nlit << "\n";); From a0359c3035b235d44b21d7243bc208a0438ca331 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 May 2014 11:24:36 -0700 Subject: [PATCH 390/925] add logging Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 8c8d7040d..d2634106a 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -2951,7 +2951,7 @@ namespace smt { \brief Execute some finalization code after performing the search. */ void context::check_finalize(lbool r) { - TRACE("after_search", display(tout);); + TRACE("after_search", display(tout << "result: " << r << "\n");); display_profile(verbose_stream()); } From 4dc71acde0493aa4462b96ca5be0a650e6ba35aa Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 May 2014 11:31:54 -0700 Subject: [PATCH 391/925] add logging Signed-off-by: Nikolaj Bjorner --- src/opt/maxsmt.cpp | 1 + src/opt/opt_context.cpp | 1 + src/opt/optsmt.cpp | 1 + 3 files changed, 3 insertions(+) diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 1f43bbe36..dd0171c6a 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -32,6 +32,7 @@ namespace opt { m_msolver = 0; m_s = s; IF_VERBOSE(1, verbose_stream() << "(maxsmt)\n";); + TRACE("opt", tout << "maxsmt\n";); if (m_soft_constraints.empty()) { TRACE("opt", tout << "no constraints\n";); m_msolver = 0; diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 7b9ca0a8d..ceab047b7 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -145,6 +145,7 @@ namespace opt { IF_VERBOSE(1, verbose_stream() << "(optimize:check-sat)\n";); lbool is_sat = s.check_sat_core(0,0); + TRACE("opt", tout << "initial search result: " << is_sat << "\n";); if (is_sat != l_true) { m_model = 0; return is_sat; diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index e5370e82d..980ad7037 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -235,6 +235,7 @@ namespace opt { lbool optsmt::lex(unsigned obj_index) { IF_VERBOSE(1, verbose_stream() << "(optsmt:lex)\n";); + TRACE("opt", tout << "optsmt:lex\n";); solver::scoped_push _push(*m_s); SASSERT(obj_index < m_vars.size()); return basic_lex(obj_index); From f1194ffeaaa59d7bf355502f9bca1ce76d197aa6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 May 2014 11:34:15 -0700 Subject: [PATCH 392/925] add logging Signed-off-by: Nikolaj Bjorner --- src/opt/optsmt.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 980ad7037..4686910c8 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -268,6 +268,7 @@ namespace opt { } if (m_cancel || is_sat == l_undef) { + TRACE("opt", tout << "undef: " << m_cancel << " " << is_sat << "\n";); return l_undef; } From 02b419c939b44429f2b79a181d6c05c3de3261b4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 May 2014 11:36:08 -0700 Subject: [PATCH 393/925] add logging Signed-off-by: Nikolaj Bjorner --- src/opt/optsmt.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 4686910c8..8428f03ab 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -51,6 +51,7 @@ namespace opt { void optsmt::set_cancel(bool f) { + TRACE("opt", tout << "set cancel: " << f << "\n";); m_cancel = f; } From 9c4409a8fee924c5883137282595f7303a2bf591 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 May 2014 11:48:28 -0700 Subject: [PATCH 394/925] set timout to max Signed-off-by: Nikolaj Bjorner --- src/api/api_opt.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index e40d690fc..6ded13ee5 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -108,7 +108,8 @@ extern "C" { RESET_ERROR_CODE(); lbool r = l_undef; cancel_eh eh(*to_optimize_ref(o)); - unsigned timeout = 0; // to_optimize(o)->m_params.get_uint("timeout", mk_c(c)->get_timeout()); + unsigned timeout = 0xFFFFFFF; + // to_optimize(o)->m_params.get_uint("timeout", mk_c(c)->get_timeout()); api::context::set_interruptable si(*(mk_c(c)), eh); { scoped_timer timer(timeout, &eh); From 252b9e8819fa6c158f326d83541bdea6c8c249e5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 May 2014 16:32:17 -0700 Subject: [PATCH 395/925] fix lower/upper bound estimate with respect to offset Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 5 ++++- src/opt/weighted_maxsat.cpp | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index ceab047b7..f227d3c04 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -710,22 +710,25 @@ namespace opt { void context::update_lower(bool override) { expr_ref val(m); - rational r(0); for (unsigned i = 0; i < m_objectives.size(); ++i) { objective const& obj = m_objectives[i]; + rational r; switch(obj.m_type) { case O_MINIMIZE: if (m_model->eval(obj.m_term, val) && is_numeral(val, r)) { + r += obj.m_offset; m_optsmt.update_lower(obj.m_index, inf_eps(-r), override); } break; case O_MAXIMIZE: if (m_model->eval(obj.m_term, val) && is_numeral(val, r)) { + r += obj.m_offset; m_optsmt.update_lower(obj.m_index, inf_eps(r), override); } break; case O_MAXSMT: { bool ok = true; + r = obj.m_offset; for (unsigned j = 0; ok && j < obj.m_terms.size(); ++j) { if (m_model->eval(obj.m_terms[j], val)) { if (!m.is_true(val)) { diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 112b0522a..f19c5c77e 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -111,6 +111,7 @@ namespace opt { if (!m_assignment.back()) { m_upper += m_weights[i]; } + TRACE("opt", tout << "evaluate: " << val << "\n";); } } expr* mk_not(expr* e) { From cf55854d2208674dd8005d44d98bda3f648e90e1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 May 2014 17:21:16 -0700 Subject: [PATCH 396/925] adding scoped state Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 160 ++++++++++++++++++++++++++-------------- src/opt/opt_context.h | 47 +++++++++--- 2 files changed, 141 insertions(+), 66 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index f227d3c04..5d0632c1c 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -39,65 +39,44 @@ Notes: namespace opt { - context::context(ast_manager& m): - m(m), - m_arith(m), - m_bv(m), - m_hard_constraints(m), - m_optsmt(m), - m_objective_refs(m) - { - m_params.set_bool("model", true); - m_params.set_bool("unsat_core", true); - m_solver = alloc(opt_solver, m, m_params, symbol()); + void context::scoped_state::push() { + m_hard_lim.push_back(m_hard.size()); + m_objectives_lim.push_back(m_objectives.size()); } - context::~context() { - map_t::iterator it = m_maxsmts.begin(), end = m_maxsmts.end(); - for (; it != end; ++it) { - dealloc(it->m_value); + void context::scoped_state::pop() { + m_hard.resize(m_hard_lim.back()); + unsigned k = m_objectives_term_trail_lim.back(); + while (m_objectives_term_trail.size() > k) { + unsigned idx = m_objectives_term_trail.back(); + m_objectives[idx].m_terms.pop_back(); + m_objectives[idx].m_weights.pop_back(); + m_objectives_term_trail.pop_back(); } - } - - void context::push() { - m_objectives_lim.push_back(m_objectives.size()); - m_objectives_term_trail_lim.push_back(m_objectives_term_trail.size()); - m_solver->push(); - } - - void context::pop(unsigned n) { - m_solver->pop(n); - while (n > 0) { - --n; - unsigned k = m_objectives_term_trail_lim.back(); - while (m_objectives_term_trail.size() > k) { - unsigned idx = m_objectives_term_trail.back(); - m_objectives[idx].m_terms.pop_back(); - m_objectives[idx].m_weights.pop_back(); - m_objectives_term_trail.pop_back(); + m_objectives_term_trail_lim.pop_back(); + k = m_objectives_lim.back(); + while (m_objectives.size() > k) { + objective& obj = m_objectives.back(); + if (obj.m_type == O_MAXSMT) { + m_indices.erase(obj.m_id); } - m_objectives_term_trail_lim.pop_back(); - k = m_objectives_lim.back(); - while (m_objectives.size() > k) { - objective& obj = m_objectives.back(); - if (obj.m_type == O_MAXSMT) { - dealloc(m_maxsmts[obj.m_id]); - m_maxsmts.erase(obj.m_id); - m_indices.erase(obj.m_id); - } - m_objectives.pop_back(); - } - m_objectives_lim.pop_back(); + m_objectives.pop_back(); } + m_objectives_lim.pop_back(); + m_hard_lim.pop_back(); } - void context::set_hard_constraints(ptr_vector& fmls) { - m_hard_constraints.reset(); - m_hard_constraints.append(fmls.size(), fmls.c_ptr()); + + void context::scoped_state::add(expr* hard) { + m_hard.push_back(hard); } - unsigned context::add_soft_constraint(expr* f, rational const& w, symbol const& id) { - maxsmt* ms; + void context::scoped_state::set(ptr_vector & hard) { + m_hard.reset(); + m_hard.append(hard.size(), hard.c_ptr()); + } + + unsigned context::scoped_state::add(expr* f, rational const& w, symbol const& id) { if (w.is_neg()) { throw default_exception("Negative weight supplied. Weight should be positive"); } @@ -107,10 +86,7 @@ namespace opt { if (!m.is_bool(f)) { throw default_exception("Soft constraint should be Boolean"); } - if (!m_maxsmts.find(id, ms)) { - ms = alloc(maxsmt, m); - ms->updt_params(m_params); - m_maxsmts.insert(id, ms); + if (!m_indices.contains(id)) { m_objectives.push_back(objective(m, id)); m_indices.insert(id, m_objectives.size() - 1); } @@ -122,7 +98,7 @@ namespace opt { return idx; } - unsigned context::add_objective(app* t, bool is_max) { + unsigned context::scoped_state::add(app* t, bool is_max) { app_ref tr(t, m); if (!m_bv.is_bv(t) && !m_arith.is_int_real(t)) { throw default_exception("Objective must be bit-vector, integer or real"); @@ -132,8 +108,79 @@ namespace opt { return index; } - lbool context::optimize() { + context::context(ast_manager& m): + m(m), + m_arith(m), + m_bv(m), + m_hard_constraints(m), + m_optsmt(m), + m_scoped_state(m), + m_objective_refs(m) + { + m_params.set_bool("model", true); + m_params.set_bool("unsat_core", true); + m_solver = alloc(opt_solver, m, m_params, symbol()); + } + + context::~context() { + reset_maxsmts(); + } + + void context::reset_maxsmts() { + map_t::iterator it = m_maxsmts.begin(), end = m_maxsmts.end(); + for (; it != end; ++it) { + dealloc(it->m_value); + } + } + + void context::push() { + m_scoped_state.push(); + m_solver->push(); + } + + void context::pop(unsigned n) { + m_solver->pop(n); + for (unsigned i = 0; i < n; ++i) { + m_scoped_state.pop(); + } + } + + void context::set_hard_constraints(ptr_vector& fmls) { + m_scoped_state.set(fmls); + } + + void context::add_hard_constraint(expr* f) { + m_scoped_state.add(f); + } + + unsigned context::add_soft_constraint(expr* f, rational const& w, symbol const& id) { + return m_scoped_state.add(f, w, id); + } + + unsigned context::add_objective(app* t, bool is_max) { + return m_scoped_state.add(t, is_max); + } + + void context::import_scoped_state() { m_optsmt.reset(); + reset_maxsmts(); + m_objectives.reset(); + m_hard_constraints.reset(); + scoped_state& s = m_scoped_state; + for (unsigned i = 0; i < s.m_objectives.size(); ++i) { + objective& obj = s.m_objectives[i]; + m_objectives.push_back(obj); + if (obj.m_type == O_MAXSMT) { + maxsmt* ms = alloc(maxsmt, m); + ms->updt_params(m_params); + m_maxsmts.insert(obj.m_id, ms); + } + } + m_hard_constraints.append(s.m_hard); + } + + lbool context::optimize() { + import_scoped_state(); normalize(); internalize(); opt_solver& s = get_solver(); @@ -640,7 +687,6 @@ namespace opt { maxsmt* ms = alloc(maxsmt, m); ms->updt_params(m_params); m_maxsmts.insert(id, ms); - m_indices.insert(id, index); } SASSERT(obj.m_id == id); obj.m_terms.reset(); diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 1912dac0d..bf3dd7499 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -75,6 +75,35 @@ namespace opt { m_index(0) {} }; + + class scoped_state { + ast_manager& m; + arith_util m_arith; + bv_util m_bv; + unsigned_vector m_hard_lim; + unsigned_vector m_objectives_lim; + unsigned_vector m_objectives_term_trail; + unsigned_vector m_objectives_term_trail_lim; + map_id m_indices; + + public: + expr_ref_vector m_hard; + vector m_objectives; + + scoped_state(ast_manager& m): + m(m), + m_arith(m), + m_bv(m), + m_hard(m) + {} + void push(); + void pop(); + void add(expr* hard); + void set(ptr_vector & hard); + unsigned add(expr* soft, rational const& weight, symbol const& id); + unsigned add(app* obj, bool is_max); + }; + ast_manager& m; arith_util m_arith; bv_util m_bv; @@ -82,25 +111,23 @@ namespace opt { ref m_solver; scoped_ptr m_pareto; params_ref m_params; - optsmt m_optsmt; + optsmt m_optsmt; map_t m_maxsmts; - map_id m_indices; + scoped_state m_scoped_state; vector m_objectives; - unsigned_vector m_objectives_lim; - unsigned_vector m_objectives_term_trail; - unsigned_vector m_objectives_term_trail_lim; model_ref m_model; model_converter_ref m_model_converter; obj_map m_objective_fns; - obj_map m_objective_orig; - func_decl_ref_vector m_objective_refs; - tactic_ref m_simplify; + obj_map m_objective_orig; + func_decl_ref_vector m_objective_refs; + tactic_ref m_simplify; public: context(ast_manager& m); virtual ~context(); unsigned add_soft_constraint(expr* f, rational const& w, symbol const& id); unsigned add_objective(app* t, bool is_max); - void add_hard_constraint(expr* f) { m_hard_constraints.push_back(f); } + void add_hard_constraint(expr* f); + virtual void push(); virtual void pop(unsigned n); @@ -138,6 +165,8 @@ namespace opt { lbool execute_pareto(); expr_ref to_expr(inf_eps const& n); + void reset_maxsmts(); + void import_scoped_state(); void normalize(); void internalize(); bool is_maximize(expr* fml, app_ref& term, expr*& orig_term, unsigned& index); From fb0305d5ecfb9fdc30947d2e1d0217144e1ad321 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 May 2014 22:27:35 -0700 Subject: [PATCH 397/925] update timeout logic Signed-off-by: Nikolaj Bjorner --- src/api/api_opt.cpp | 38 +++++++++++++++++++------------------- src/opt/opt_context.h | 1 + 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index 6ded13ee5..a0f9e3d87 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -36,7 +36,8 @@ extern "C" { }; inline Z3_optimize_ref * to_optimize(Z3_optimize o) { return reinterpret_cast(o); } inline Z3_optimize of_optimize(Z3_optimize_ref * o) { return reinterpret_cast(o); } - inline opt::context* to_optimize_ref(Z3_optimize o) { return to_optimize(o)->m_opt; } + inline opt::context* to_optimize_ptr(Z3_optimize o) { return to_optimize(o)->m_opt; } + inline opt::context& to_optimize_ref(Z3_optimize o) { return *(to_optimize(o)->m_opt); } Z3_optimize Z3_API Z3_mk_optimize(Z3_context c) { Z3_TRY; @@ -70,7 +71,7 @@ extern "C" { LOG_Z3_optimize_assert(c, o, a); RESET_ERROR_CODE(); CHECK_FORMULA(a,); - to_optimize_ref(o)->add_hard_constraint(to_expr(a)); + to_optimize_ref(o).add_hard_constraint(to_expr(a)); Z3_CATCH; } @@ -80,7 +81,7 @@ extern "C" { RESET_ERROR_CODE(); CHECK_FORMULA(a,0); rational w(weight); - return to_optimize_ref(o)->add_soft_constraint(to_expr(a), w, to_symbol(id)); + return to_optimize_ref(o).add_soft_constraint(to_expr(a), w, to_symbol(id)); Z3_CATCH_RETURN(0); } @@ -89,7 +90,7 @@ extern "C" { LOG_Z3_optimize_maximize(c, o, t); RESET_ERROR_CODE(); CHECK_VALID_AST(t,0); - return to_optimize_ref(o)->add_objective(to_app(t), true); + return to_optimize_ref(o).add_objective(to_app(t), true); Z3_CATCH_RETURN(0); } @@ -98,7 +99,7 @@ extern "C" { LOG_Z3_optimize_minimize(c, o, t); RESET_ERROR_CODE(); CHECK_VALID_AST(t,0); - return to_optimize_ref(o)->add_objective(to_app(t), false); + return to_optimize_ref(o).add_objective(to_app(t), false); Z3_CATCH_RETURN(0); } @@ -107,20 +108,19 @@ extern "C" { LOG_Z3_optimize_check(c, o); RESET_ERROR_CODE(); lbool r = l_undef; - cancel_eh eh(*to_optimize_ref(o)); - unsigned timeout = 0xFFFFFFF; - // to_optimize(o)->m_params.get_uint("timeout", mk_c(c)->get_timeout()); + cancel_eh eh(to_optimize_ref(o)); + unsigned timeout = to_optimize_ref(o).get_params().get_uint("timeout", mk_c(c)->get_timeout()); api::context::set_interruptable si(*(mk_c(c)), eh); { scoped_timer timer(timeout, &eh); try { - r = to_optimize_ref(o)->optimize(); + r = to_optimize_ref(o).optimize(); } catch (z3_exception& ex) { mk_c(c)->handle_exception(ex); r = l_undef; } - // to_optimize_ref(d)->cleanup(); + // to_optimize_ref(d).cleanup(); } return of_lbool(r); Z3_CATCH_RETURN(Z3_L_UNDEF); @@ -131,7 +131,7 @@ extern "C" { LOG_Z3_optimize_get_model(c, o); RESET_ERROR_CODE(); model_ref _m; - to_optimize_ref(o)->get_model(_m); + to_optimize_ref(o).get_model(_m); Z3_model_ref * m_ref = alloc(Z3_model_ref); if (_m) { m_ref->m_model = _m; @@ -149,10 +149,10 @@ extern "C" { LOG_Z3_optimize_set_params(c, o, p); RESET_ERROR_CODE(); param_descrs descrs; - to_optimize_ref(o)->collect_param_descrs(descrs); + to_optimize_ref(o).collect_param_descrs(descrs); to_params(p)->m_params.validate(descrs); params_ref pr = to_param_ref(p); - to_optimize_ref(o)->updt_params(pr); + to_optimize_ref(o).updt_params(pr); Z3_CATCH; } @@ -162,7 +162,7 @@ extern "C" { RESET_ERROR_CODE(); Z3_param_descrs_ref * d = alloc(Z3_param_descrs_ref); mk_c(c)->save_object(d); - to_optimize_ref(o)->collect_param_descrs(d->m_descrs); + to_optimize_ref(o).collect_param_descrs(d->m_descrs); Z3_param_descrs r = of_param_descrs(d); RETURN_Z3(r); Z3_CATCH_RETURN(0); @@ -173,7 +173,7 @@ extern "C" { Z3_TRY; LOG_Z3_optimize_get_lower(c, o, idx); RESET_ERROR_CODE(); - expr_ref e = to_optimize_ref(o)->get_lower(idx); + expr_ref e = to_optimize_ref(o).get_lower(idx); mk_c(c)->save_ast_trail(e); RETURN_Z3(of_expr(e)); Z3_CATCH_RETURN(0); @@ -184,7 +184,7 @@ extern "C" { Z3_TRY; LOG_Z3_optimize_get_upper(c, o, idx); RESET_ERROR_CODE(); - expr_ref e = to_optimize_ref(o)->get_upper(idx); + expr_ref e = to_optimize_ref(o).get_upper(idx); mk_c(c)->save_ast_trail(e); RETURN_Z3(of_expr(e)); Z3_CATCH_RETURN(0); @@ -194,7 +194,7 @@ extern "C" { Z3_TRY; LOG_Z3_optimize_to_string(c, o); RESET_ERROR_CODE(); - return mk_c(c)->mk_external_string(to_optimize_ref(o)->to_string()); + return mk_c(c)->mk_external_string(to_optimize_ref(o).to_string()); Z3_CATCH_RETURN(""); } @@ -204,7 +204,7 @@ extern "C" { RESET_ERROR_CODE(); std::ostringstream buffer; param_descrs descrs; - to_optimize_ref(d)->collect_param_descrs(descrs); + to_optimize_ref(d).collect_param_descrs(descrs); descrs.display(buffer); return mk_c(c)->mk_external_string(buffer.str()); Z3_CATCH_RETURN(""); @@ -215,7 +215,7 @@ extern "C" { LOG_Z3_optimize_get_statistics(c, d); RESET_ERROR_CODE(); Z3_stats_ref * st = alloc(Z3_stats_ref); - to_optimize_ref(d)->collect_statistics(st->m_stats); + to_optimize_ref(d).collect_statistics(st->m_stats); mk_c(c)->save_object(st); Z3_stats r = of_stats(st); RETURN_Z3(r); diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index bf3dd7499..f38d87cd8 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -148,6 +148,7 @@ namespace opt { void display(std::ostream& out); static void collect_param_descrs(param_descrs & r); void updt_params(params_ref& p); + params_ref& get_params() { return m_params; } expr_ref get_lower(unsigned idx); expr_ref get_upper(unsigned idx); From d8ad75e3f41c5eefe1f2ea4b6bb0d531d5d4c706 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 May 2014 22:30:59 -0700 Subject: [PATCH 398/925] ptr/ref Signed-off-by: Nikolaj Bjorner --- src/api/api_opt.cpp | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index a0f9e3d87..3c4089a34 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -37,7 +37,6 @@ extern "C" { inline Z3_optimize_ref * to_optimize(Z3_optimize o) { return reinterpret_cast(o); } inline Z3_optimize of_optimize(Z3_optimize_ref * o) { return reinterpret_cast(o); } inline opt::context* to_optimize_ptr(Z3_optimize o) { return to_optimize(o)->m_opt; } - inline opt::context& to_optimize_ref(Z3_optimize o) { return *(to_optimize(o)->m_opt); } Z3_optimize Z3_API Z3_mk_optimize(Z3_context c) { Z3_TRY; @@ -71,7 +70,7 @@ extern "C" { LOG_Z3_optimize_assert(c, o, a); RESET_ERROR_CODE(); CHECK_FORMULA(a,); - to_optimize_ref(o).add_hard_constraint(to_expr(a)); + to_optimize_ptr(o)->add_hard_constraint(to_expr(a)); Z3_CATCH; } @@ -81,7 +80,7 @@ extern "C" { RESET_ERROR_CODE(); CHECK_FORMULA(a,0); rational w(weight); - return to_optimize_ref(o).add_soft_constraint(to_expr(a), w, to_symbol(id)); + return to_optimize_ptr(o)->add_soft_constraint(to_expr(a), w, to_symbol(id)); Z3_CATCH_RETURN(0); } @@ -90,7 +89,7 @@ extern "C" { LOG_Z3_optimize_maximize(c, o, t); RESET_ERROR_CODE(); CHECK_VALID_AST(t,0); - return to_optimize_ref(o).add_objective(to_app(t), true); + return to_optimize_ptr(o)->add_objective(to_app(t), true); Z3_CATCH_RETURN(0); } @@ -99,7 +98,7 @@ extern "C" { LOG_Z3_optimize_minimize(c, o, t); RESET_ERROR_CODE(); CHECK_VALID_AST(t,0); - return to_optimize_ref(o).add_objective(to_app(t), false); + return to_optimize_ptr(o)->add_objective(to_app(t), false); Z3_CATCH_RETURN(0); } @@ -108,13 +107,13 @@ extern "C" { LOG_Z3_optimize_check(c, o); RESET_ERROR_CODE(); lbool r = l_undef; - cancel_eh eh(to_optimize_ref(o)); - unsigned timeout = to_optimize_ref(o).get_params().get_uint("timeout", mk_c(c)->get_timeout()); + cancel_eh eh(*to_optimize_ptr(o)); + unsigned timeout = to_optimize_ptr(o)->get_params().get_uint("timeout", mk_c(c)->get_timeout()); api::context::set_interruptable si(*(mk_c(c)), eh); { scoped_timer timer(timeout, &eh); try { - r = to_optimize_ref(o).optimize(); + r = to_optimize_ptr(o)->optimize(); } catch (z3_exception& ex) { mk_c(c)->handle_exception(ex); @@ -131,7 +130,7 @@ extern "C" { LOG_Z3_optimize_get_model(c, o); RESET_ERROR_CODE(); model_ref _m; - to_optimize_ref(o).get_model(_m); + to_optimize_ptr(o)->get_model(_m); Z3_model_ref * m_ref = alloc(Z3_model_ref); if (_m) { m_ref->m_model = _m; @@ -149,10 +148,10 @@ extern "C" { LOG_Z3_optimize_set_params(c, o, p); RESET_ERROR_CODE(); param_descrs descrs; - to_optimize_ref(o).collect_param_descrs(descrs); + to_optimize_ptr(o)->collect_param_descrs(descrs); to_params(p)->m_params.validate(descrs); params_ref pr = to_param_ref(p); - to_optimize_ref(o).updt_params(pr); + to_optimize_ptr(o)->updt_params(pr); Z3_CATCH; } @@ -162,7 +161,7 @@ extern "C" { RESET_ERROR_CODE(); Z3_param_descrs_ref * d = alloc(Z3_param_descrs_ref); mk_c(c)->save_object(d); - to_optimize_ref(o).collect_param_descrs(d->m_descrs); + to_optimize_ptr(o)->collect_param_descrs(d->m_descrs); Z3_param_descrs r = of_param_descrs(d); RETURN_Z3(r); Z3_CATCH_RETURN(0); @@ -173,7 +172,7 @@ extern "C" { Z3_TRY; LOG_Z3_optimize_get_lower(c, o, idx); RESET_ERROR_CODE(); - expr_ref e = to_optimize_ref(o).get_lower(idx); + expr_ref e = to_optimize_ptr(o)->get_lower(idx); mk_c(c)->save_ast_trail(e); RETURN_Z3(of_expr(e)); Z3_CATCH_RETURN(0); @@ -184,7 +183,7 @@ extern "C" { Z3_TRY; LOG_Z3_optimize_get_upper(c, o, idx); RESET_ERROR_CODE(); - expr_ref e = to_optimize_ref(o).get_upper(idx); + expr_ref e = to_optimize_ptr(o)->get_upper(idx); mk_c(c)->save_ast_trail(e); RETURN_Z3(of_expr(e)); Z3_CATCH_RETURN(0); @@ -194,7 +193,7 @@ extern "C" { Z3_TRY; LOG_Z3_optimize_to_string(c, o); RESET_ERROR_CODE(); - return mk_c(c)->mk_external_string(to_optimize_ref(o).to_string()); + return mk_c(c)->mk_external_string(to_optimize_ptr(o)->to_string()); Z3_CATCH_RETURN(""); } @@ -204,7 +203,7 @@ extern "C" { RESET_ERROR_CODE(); std::ostringstream buffer; param_descrs descrs; - to_optimize_ref(d).collect_param_descrs(descrs); + to_optimize_ptr(d)->collect_param_descrs(descrs); descrs.display(buffer); return mk_c(c)->mk_external_string(buffer.str()); Z3_CATCH_RETURN(""); @@ -215,7 +214,7 @@ extern "C" { LOG_Z3_optimize_get_statistics(c, d); RESET_ERROR_CODE(); Z3_stats_ref * st = alloc(Z3_stats_ref); - to_optimize_ref(d).collect_statistics(st->m_stats); + to_optimize_ptr(d)->collect_statistics(st->m_stats); mk_c(c)->save_object(st); Z3_stats r = of_stats(st); RETURN_Z3(r); From e9a11bd93b79a4ac5246bfd516f63348e0f57c12 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 10 May 2014 17:43:42 -0700 Subject: [PATCH 399/925] fix emptines check Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index f38d87cd8..a09872e85 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -131,7 +131,7 @@ namespace opt { virtual void push(); virtual void pop(unsigned n); - virtual bool empty() { return m_objectives.empty(); } + virtual bool empty() { return m_scoped_state.m_objectives.empty(); } virtual void set_cancel(bool f); virtual void reset_cancel() { set_cancel(false); } virtual void cancel() { set_cancel(true); } From cad1e5cab39992b5c0d30da7fcc45a91a69e5b72 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 11 May 2014 18:39:36 -0700 Subject: [PATCH 400/925] move to scoped state, change default parameter for sls until bv is debugged Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 16 ++++++++-------- src/opt/opt_params.pyg | 2 +- src/opt/weighted_maxsat.cpp | 31 ++++++------------------------- 3 files changed, 15 insertions(+), 34 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 5d0632c1c..3a88ff904 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -991,11 +991,11 @@ namespace opt { free_func_visitor visitor(m); std::ostringstream out; #define PP(_e_) ast_smt2_pp(out, _e_, env); - for (unsigned i = 0; i < m_hard_constraints.size(); ++i) { - visitor.collect(m_hard_constraints[i]); + for (unsigned i = 0; i < m_scoped_state.m_hard.size(); ++i) { + visitor.collect(m_scoped_state.m_hard[i]); } - for (unsigned i = 0; i < m_objectives.size(); ++i) { - objective const& obj = m_objectives[i]; + for (unsigned i = 0; i < m_scoped_state.m_objectives.size(); ++i) { + objective const& obj = m_scoped_state.m_objectives[i]; switch(obj.m_type) { case O_MAXIMIZE: case O_MINIMIZE: @@ -1023,13 +1023,13 @@ namespace opt { PP(*it); out << "\n"; } - for (unsigned i = 0; i < m_hard_constraints.size(); ++i) { + for (unsigned i = 0; i < m_scoped_state.m_hard.size(); ++i) { out << "(assert "; - PP(m_hard_constraints[i]); + PP(m_scoped_state.m_hard[i]); out << ")\n"; } - for (unsigned i = 0; i < m_objectives.size(); ++i) { - objective const& obj = m_objectives[i]; + for (unsigned i = 0; i < m_scoped_state.m_objectives.size(); ++i) { + objective const& obj = m_scoped_state.m_objectives[i]; switch(obj.m_type) { case O_MAXIMIZE: out << "(maximize "; diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index 201a1601b..2e6f67219 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -12,7 +12,7 @@ def_module_params('opt', ('wmaxsat_engine', SYMBOL, 'wmax', "weighted maxsat engine: 'wmax', 'pbmax', 'bcd2', 'wpm2', 'bvsls', 'sls'"), ('enable_sls', BOOL, False, 'enable SLS tuning during weighted maxsast'), ('enable_sat', BOOL, False, 'enable the new SAT core for propositional constraints'), - ('sls_engine', SYMBOL, 'bv', "SLS engine. Either 'bv' or 'pb'"), + ('sls_engine', SYMBOL, 'pb', "SLS engine. Either 'bv' or 'pb'"), ('elim_01', BOOL, True, 'eliminate 01 variables'), ('pb.compile_equality', BOOL, False, 'compile arithmetical equalities into pseudo-Boolean equality (instead of two inequalites)') diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index f19c5c77e..075b89a76 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -576,10 +576,9 @@ namespace opt { // lower bounds. class pbmax : public maxsmt_solver_base { - bool m_use_aux; public: - pbmax(solver* s, ast_manager& m, bool use_aux): - maxsmt_solver_base(s, m), m_use_aux(use_aux) { + pbmax(solver* s, ast_manager& m): + maxsmt_solver_base(s, m) { } virtual ~pbmax() {} @@ -598,20 +597,8 @@ namespace opt { app_ref b(m); expr_ref_vector nsoft(m); init(); - if (m_use_aux) { - s().push(); - } for (unsigned i = 0; i < m_soft.size(); ++i) { - if (m_use_aux) { - b = m.mk_fresh_const("b", m.mk_bool_sort()); - m_mc->insert(b->get_decl()); - fml = m.mk_or(m_soft[i].get(), b); - s().assert_expr(fml); - nsoft.push_back(b); - } - else { - nsoft.push_back(mk_not(m_soft[i].get())); - } + nsoft.push_back(mk_not(m_soft[i].get())); } lbool is_sat = l_true; while (l_true == is_sat) { @@ -643,9 +630,6 @@ namespace opt { is_sat = l_true; m_lower = m_upper; } - if (m_use_aux) { - s().pop(1); - } TRACE("opt", tout << "lower: " << m_lower << "\n";); return is_sat; } @@ -1008,14 +992,11 @@ namespace opt { if (m_maxsmt) { return *m_maxsmt; } - if (m_engine == symbol("pwmax")) { - m_maxsmt = alloc(pbmax, s.get(), m, true); - } - else if (m_engine == symbol("pbmax")) { - m_maxsmt = alloc(pbmax, s.get(), m, false); + if (m_engine == symbol("pbmax")) { + m_maxsmt = alloc(pbmax, s.get(), m); } else if (m_engine == symbol("wpm2")) { - maxsmt_solver_base* s2 = alloc(pbmax, s.get(), m, false); + maxsmt_solver_base* s2 = alloc(pbmax, s.get(), m); m_maxsmt = alloc(wpm2, s.get(), m, s2); } else if (m_engine == symbol("bcd2")) { From 1ea376e31046cba3198ec2b9ab61875f1e764d37 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 13 May 2014 10:33:09 -0700 Subject: [PATCH 401/925] edits Signed-off-by: Nikolaj Bjorner --- src/opt/opt_pareto.cpp | 85 ------------------------------------------ 1 file changed, 85 deletions(-) diff --git a/src/opt/opt_pareto.cpp b/src/opt/opt_pareto.cpp index 6bffd19ef..d901da0e9 100644 --- a/src/opt/opt_pareto.cpp +++ b/src/opt/opt_pareto.cpp @@ -110,88 +110,3 @@ namespace opt { } -#if 0 - opt_solver& s = get_solver(); - expr_ref val(m); - rational r; - lbool is_sat = l_true; - vector bounds; - for (unsigned i = 0; i < m_objectives.size(); ++i) { - objective const& obj = m_objectives[i]; - if (obj.m_type == O_MAXSMT) { - IF_VERBOSE(0, verbose_stream() << "Pareto optimization is not supported for MAXSMT\n";); - return l_undef; - } - solver::scoped_push _sp(s); - is_sat = m_optsmt.pareto(obj.m_index); - if (is_sat != l_true) { - return is_sat; - } - if (!m_optsmt.get_upper(obj.m_index).is_finite()) { - return l_undef; - } - bounds_t bound; - for (unsigned j = 0; j < m_objectives.size(); ++j) { - objective const& obj_j = m_objectives[j]; - inf_eps lo = m_optsmt.get_lower(obj_j.m_index); - inf_eps hi = m_optsmt.get_upper(obj_j.m_index); - bound.push_back(std::make_pair(lo, hi)); - } - bounds.push_back(bound); - } - for (unsigned i = 0; i < bounds.size(); ++i) { - for (unsigned j = 0; j < bounds.size(); ++j) { - objective const& obj = m_objectives[j]; - bounds[i][j].second = bounds[j][j].second; - } - IF_VERBOSE(0, display_bounds(verbose_stream() << "new bound\n", bounds[i]);); - } - - for (unsigned i = 0; i < bounds.size(); ++i) { - bounds_t b = bounds[i]; - vector mids; - solver::scoped_push _sp(s); - for (unsigned j = 0; j < b.size(); ++j) { - objective const& obj = m_objectives[j]; - inf_eps mid = (b[j].second - b[j].first)/rational(2); - mids.push_back(mid); - expr_ref ge = s.mk_ge(obj.m_index, mid); - s.assert_expr(ge); - } - is_sat = execute_box(); - switch(is_sat) { - case l_undef: - return is_sat; - case l_true: { - bool at_bound = true; - for (unsigned j = 0; j < b.size(); ++j) { - objective const& obj = m_objectives[j]; - if (m_model->eval(obj.m_term, val) && is_numeral(val, r)) { - mids[j] = inf_eps(r); - } - at_bound = at_bound && mids[j] == b[j].second; - b[j].second = mids[j]; - } - IF_VERBOSE(0, display_bounds(verbose_stream() << "new bound\n", b);); - if (!at_bound) { - bounds.push_back(b); - } - break; - } - case l_false: { - bounds_t b2(b); - for (unsigned j = 0; j < b.size(); ++j) { - b2[j].second = mids[j]; - if (j > 0) { - b2[j-1].second = b[j-1].second; - } - IF_VERBOSE(0, display_bounds(verbose_stream() << "refined bound\n", b2);); - bounds.push_back(b2); - } - break; - } - } - } - - return is_sat; -#endif From 03979fd58024e734677f6577aa6b04692d38db22 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 13 May 2014 12:48:17 -0700 Subject: [PATCH 402/925] fix up pareto callback mechanism Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.cpp | 11 +- src/cmd_context/cmd_context.h | 1 + src/opt/opt_cmds.cpp | 10 ++ src/opt/opt_context.cpp | 209 +++++++++++++++++--------------- src/opt/opt_context.h | 17 ++- src/opt/opt_pareto.cpp | 58 ++++----- src/opt/opt_pareto.h | 10 +- src/solver/solver.h | 6 +- 8 files changed, 178 insertions(+), 144 deletions(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index ca9e90430..4373ee33a 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1359,6 +1359,7 @@ void cmd_context::check_sat(unsigned num_assumptions, expr * const * assumptions lbool r; if (m_opt && !m_opt->empty()) { + bool was_pareto = false; m_check_sat_result = get_opt(); cancel_eh eh(*get_opt()); scoped_ctrl_c ctrlc(eh); @@ -1368,6 +1369,11 @@ void cmd_context::check_sat(unsigned num_assumptions, expr * const * assumptions get_opt()->set_hard_constraints(cnstr); try { r = get_opt()->optimize(); + while (r == l_true && get_opt()->is_pareto()) { + was_pareto = true; + get_opt()->display_assignment(regular_stream()); + r = get_opt()->optimize(); + } } catch (z3_error & ex) { throw ex; @@ -1375,8 +1381,11 @@ void cmd_context::check_sat(unsigned num_assumptions, expr * const * assumptions catch (z3_exception & ex) { throw cmd_exception(ex.msg()); } + if (was_pareto && r == l_false) { + r = l_true; + } get_opt()->set_status(r); - if (r != l_false) { + if (r != l_false && !was_pareto) { get_opt()->display_assignment(regular_stream()); } } diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index 8f7fc3228..0dfea0441 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -122,6 +122,7 @@ public: virtual lbool optimize() = 0; virtual void set_hard_constraints(ptr_vector & hard) = 0; virtual void display_assignment(std::ostream& out) = 0; + virtual bool is_pareto() = 0; }; class cmd_context : public progress_callback, public tactic_manager, public ast_printer_context { diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index 857a3c585..42d749cb6 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -266,6 +266,16 @@ public: cmd_context::scoped_watch sw(ctx); try { r = opt.optimize(); + if (r == l_true && opt.is_pareto()) { + while (r == l_true) { + display_result(ctx); + r = opt.optimize(); + } + if (p.get_bool("print_statistics", false)) { + display_statistics(ctx); + } + return; + } } catch (z3_error& ex) { ctx.regular_stream() << "(error: " << ex.msg() << "\")" << std::endl; diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 3a88ff904..fda90006c 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -180,10 +180,13 @@ namespace opt { } lbool context::optimize() { + if (m_pareto) { + return execute_pareto(); + } import_scoped_state(); normalize(); internalize(); - opt_solver& s = get_solver(); + opt_solver& s = get_solver(); solver::scoped_push _sp(s); for (unsigned i = 0; i < m_hard_constraints.size(); ++i) { TRACE("opt", tout << "Hard constraint: " << mk_ismt2_pp(m_hard_constraints[i].get(), m) << std::endl;); @@ -210,6 +213,7 @@ namespace opt { opt_params optp(m_params); symbol pri = optp.priority(); if (pri == symbol("pareto")) { + _sp.disable_pop(); return execute_pareto(); } else if (pri == symbol("box")) { @@ -282,115 +286,109 @@ namespace opt { return r; } - class context::pareto : public pareto_callback { - context& ctx; - ast_manager& m; - expr_ref mk_ge(expr* t, expr* s) { - expr_ref result(m); - if (ctx.m_bv.is_bv(t)) { - result = ctx.m_bv.mk_ule(s, t); + + expr_ref context::mk_le(unsigned i, model_ref& mdl) { + objective const& obj = m_objectives[i]; + expr_ref val(m), result(m), term(m); + mk_term_val(mdl, obj, term, val); + switch (obj.m_type) { + case O_MINIMIZE: + result = mk_ge(term, val); + break; + case O_MAXSMT: + result = mk_ge(term, val); + break; + case O_MAXIMIZE: + result = mk_ge(val, term); + break; + } + return result; + } + + expr_ref context::mk_ge(unsigned i, model_ref& mdl) { + objective const& obj = m_objectives[i]; + expr_ref val(m), result(m), term(m); + mk_term_val(mdl, obj, term, val); + switch (obj.m_type) { + case O_MINIMIZE: + result = mk_ge(val, term); + break; + case O_MAXSMT: + result = mk_ge(val, term); + break; + case O_MAXIMIZE: + result = mk_ge(term, val); + break; + } + return result; + } + + expr_ref context::mk_gt(unsigned i, model_ref& mdl) { + expr_ref result = mk_le(i, mdl); + result = m.mk_not(result); + return result; + } + + void context::mk_term_val(model_ref& mdl, objective const& obj, expr_ref& term, expr_ref& val) { + rational r; + switch (obj.m_type) { + case O_MINIMIZE: + case O_MAXIMIZE: + term = obj.m_term; + break; + case O_MAXSMT: { + unsigned sz = obj.m_terms.size(); + expr_ref_vector sum(m); + expr_ref zero(m); + zero = m_arith.mk_numeral(rational(0), false); + for (unsigned i = 0; i < sz; ++i) { + expr* t = obj.m_terms[i]; + rational const& w = obj.m_weights[i]; + sum.push_back(m.mk_ite(t, m_arith.mk_numeral(w, false), zero)); + } + if (sum.empty()) { + term = zero; } else { - result = ctx.m_arith.mk_ge(t, s); - } - return result; + term = m_arith.mk_add(sum.size(), sum.c_ptr()); + } + break; } - public: - pareto(context& ctx):ctx(ctx),m(ctx.m) {} + } + VERIFY(mdl->eval(term, val) && is_numeral(val, r)); + } - virtual void yield(model_ref& mdl) { - ctx.m_model = mdl; - ctx.update_lower(true); - for (unsigned i = 0; i < ctx.m_objectives.size(); ++i) { - objective const& obj = ctx.m_objectives[i]; - switch(obj.m_type) { - case O_MINIMIZE: - case O_MAXIMIZE: - ctx.m_optsmt.update_upper(obj.m_index, ctx.m_optsmt.get_lower(obj.m_index), true); - break; - case O_MAXSMT: { - rational r = ctx.m_maxsmts.find(obj.m_id)->get_lower(); - ctx.m_maxsmts.find(obj.m_id)->update_upper(r, true); - break; - } - } - } + expr_ref context::mk_ge(expr* t, expr* s) { + expr_ref result(m); + if (m_bv.is_bv(t)) { + result = m_bv.mk_ule(s, t); + } + else { + result = m_arith.mk_ge(t, s); + } + return result; + } - IF_VERBOSE(1, ctx.display_assignment(verbose_stream());); - } - virtual unsigned num_objectives() { - return ctx.m_objectives.size(); - } - virtual expr_ref mk_le(unsigned i, model_ref& mdl) { - objective const& obj = ctx.m_objectives[i]; - expr_ref val(m), result(m), term(m); - mk_term_val(mdl, obj, term, val); - switch (obj.m_type) { - case O_MINIMIZE: - result = mk_ge(term, val); - break; - case O_MAXSMT: - result = mk_ge(term, val); - break; - case O_MAXIMIZE: - result = mk_ge(val, term); - break; - } - return result; - } - virtual expr_ref mk_ge(unsigned i, model_ref& mdl) { - objective const& obj = ctx.m_objectives[i]; - expr_ref val(m), result(m), term(m); - mk_term_val(mdl, obj, term, val); - switch (obj.m_type) { - case O_MINIMIZE: - result = mk_ge(val, term); - break; - case O_MAXSMT: - result = mk_ge(val, term); - break; - case O_MAXIMIZE: - result = mk_ge(term, val); - break; - } - return result; - } - - virtual expr_ref mk_gt(unsigned i, model_ref& mdl) { - expr_ref result = mk_le(i, mdl); - result = m.mk_not(result); - return result; - } - private: - void mk_term_val(model_ref& mdl, objective const& obj, expr_ref& term, expr_ref& val) { - rational r; - switch (obj.m_type) { + void context::yield() { + m_pareto->get_model(m_model); + update_lower(true); + for (unsigned i = 0; i < m_objectives.size(); ++i) { + objective const& obj = m_objectives[i]; + switch(obj.m_type) { case O_MINIMIZE: case O_MAXIMIZE: - term = obj.m_term; + m_optsmt.update_upper(obj.m_index, m_optsmt.get_lower(obj.m_index), true); break; case O_MAXSMT: { - unsigned sz = obj.m_terms.size(); - expr_ref_vector sum(m); - expr_ref zero(m); - zero = ctx.m_arith.mk_numeral(rational(0), false); - for (unsigned i = 0; i < sz; ++i) { - expr* t = obj.m_terms[i]; - rational const& w = obj.m_weights[i]; - sum.push_back(m.mk_ite(t, ctx.m_arith.mk_numeral(w, false), zero)); - } - if (sum.empty()) { - term = zero; - } - else { - term = ctx.m_arith.mk_add(sum.size(), sum.c_ptr()); - } + rational r = m_maxsmts.find(obj.m_id)->get_lower(); + m_maxsmts.find(obj.m_id)->update_upper(r, true); break; } } - VERIFY(mdl->eval(term, val) && ctx.is_numeral(val, r)); } + } + #if 0 // use PB @@ -415,13 +413,22 @@ namespace opt { } } #endif - }; lbool context::execute_pareto() { - pareto cb(*this); - m_pareto = alloc(gia_pareto, m, cb, m_solver.get(), m_params); - return (*(m_pareto.get()))(); - // NB. stack reference cb is out of scope after return. + if (!m_pareto) { + m_pareto = alloc(gia_pareto, m, *this, m_solver.get(), m_params); + } + lbool is_sat = (*(m_pareto.get()))(); + if (is_sat != l_true) { + m_pareto = 0; + } + if (is_sat == l_true) { + yield(); + } + else { + m_solver->pop(1); + } + return is_sat; // NB. fix race condition for set_cancel } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index a09872e85..18d6d3745 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -34,7 +34,7 @@ namespace opt { class opt_solver; - class context : public opt_wrapper { + class context : public opt_wrapper, public pareto_callback { struct free_func_visitor; typedef map map_t; typedef map map_id; @@ -145,6 +145,8 @@ namespace opt { virtual std::string reason_unknown() const { return std::string("unknown"); } virtual void display_assignment(std::ostream& out); + virtual bool is_pareto() { return m_pareto.get() != 0; } + void display(std::ostream& out); static void collect_param_descrs(param_descrs & r); void updt_params(params_ref& p); @@ -155,6 +157,13 @@ namespace opt { std::string to_string() const; + + virtual unsigned num_objectives() { return m_objectives.size(); } + virtual expr_ref mk_gt(unsigned i, model_ref& model); + virtual expr_ref mk_ge(unsigned i, model_ref& model); + virtual expr_ref mk_le(unsigned i, model_ref& model); + + private: void validate_feasibility(maxsmt& ms); @@ -199,7 +208,11 @@ namespace opt { void validate_lex(); - class pareto; + + // pareto + void yield(); + expr_ref mk_ge(expr* t, expr* s); + void mk_term_val(model_ref& mdl, objective const& obj, expr_ref& term, expr_ref& val); }; diff --git a/src/opt/opt_pareto.cpp b/src/opt/opt_pareto.cpp index d901da0e9..2e0286945 100644 --- a/src/opt/opt_pareto.cpp +++ b/src/opt/opt_pareto.cpp @@ -20,6 +20,7 @@ Notes: #include "opt_pareto.h" #include "ast_pp.h" +#include "model_smt2_pp.h" namespace opt { @@ -27,43 +28,39 @@ namespace opt { // GIA pareto algorithm lbool gia_pareto::operator()() { - model_ref model; expr_ref fml(m); lbool is_sat = m_solver->check_sat(0, 0); - while (is_sat == l_true) { + if (is_sat == l_true) { { solver::scoped_push _s(*m_solver.get()); while (is_sat == l_true) { if (m_cancel) { return l_undef; } - m_solver->get_model(model); + m_solver->get_model(m_model); + IF_VERBOSE(1, model_smt2_pp(verbose_stream() << "new model:\n", m, *m_model, 0);); // TBD: we can also use local search to tune solution coordinate-wise. - mk_dominates(model); + mk_dominates(); is_sat = m_solver->check_sat(0, 0); } - if (is_sat == l_undef) { - return l_undef; - } - is_sat = l_true; } - cb.yield(model); - mk_not_dominated_by(model); - is_sat = m_solver->check_sat(0, 0); + if (is_sat == l_undef) { + return l_undef; + } + SASSERT(is_sat == l_false); + is_sat = l_true; + mk_not_dominated_by(); } - if (is_sat == l_undef) { - return l_undef; - } - return l_true; + return is_sat; } - void pareto_base::mk_dominates(model_ref& model) { + void pareto_base::mk_dominates() { unsigned sz = cb.num_objectives(); expr_ref fml(m); expr_ref_vector gt(m), fmls(m); for (unsigned i = 0; i < sz; ++i) { - fmls.push_back(cb.mk_ge(i, model)); - gt.push_back(cb.mk_gt(i, model)); + fmls.push_back(cb.mk_ge(i, m_model)); + gt.push_back(cb.mk_gt(i, m_model)); } fmls.push_back(m.mk_or(gt.size(), gt.c_ptr())); fml = m.mk_and(fmls.size(), fmls.c_ptr()); @@ -71,12 +68,12 @@ namespace opt { m_solver->assert_expr(fml); } - void pareto_base::mk_not_dominated_by(model_ref& model) { + void pareto_base::mk_not_dominated_by() { unsigned sz = cb.num_objectives(); expr_ref fml(m); expr_ref_vector le(m); for (unsigned i = 0; i < sz; ++i) { - le.push_back(cb.mk_le(i, model)); + le.push_back(cb.mk_le(i, m_model)); } fml = m.mk_not(m.mk_and(le.size(), le.c_ptr())); IF_VERBOSE(10, verbose_stream() << "not dominated by: " << fml << "\n";); @@ -87,25 +84,16 @@ namespace opt { // OIA algorithm (without filtering) lbool oia_pareto::operator()() { - model_ref model; solver::scoped_push _s(*m_solver.get()); lbool is_sat = m_solver->check_sat(0, 0); - if (is_sat != l_true) { - return is_sat; - } - while (is_sat == l_true) { - if (m_cancel) { - return l_undef; - } - m_solver->get_model(model); - cb.yield(model); - mk_not_dominated_by(model); - is_sat = m_solver->check_sat(0, 0); - } if (m_cancel) { - return l_undef; + is_sat = l_undef; } - return l_true; + if (is_sat == l_true) { + m_solver->get_model(m_model); + mk_not_dominated_by(); + } + return is_sat; } } diff --git a/src/opt/opt_pareto.h b/src/opt/opt_pareto.h index fa0243807..8a2378ae9 100644 --- a/src/opt/opt_pareto.h +++ b/src/opt/opt_pareto.h @@ -27,7 +27,6 @@ namespace opt { class pareto_callback { public: - virtual void yield(model_ref& model) = 0; virtual unsigned num_objectives() = 0; virtual expr_ref mk_gt(unsigned i, model_ref& model) = 0; virtual expr_ref mk_ge(unsigned i, model_ref& model) = 0; @@ -40,6 +39,7 @@ namespace opt { volatile bool m_cancel; ref m_solver; params_ref m_params; + model_ref m_model; public: pareto_base( ast_manager & m, @@ -72,11 +72,15 @@ namespace opt { } virtual lbool operator()() = 0; + virtual void get_model(model_ref& mdl) { + mdl = m_model; + } + protected: - void mk_dominates(model_ref& model); + void mk_dominates(); - void mk_not_dominated_by(model_ref& model); + void mk_not_dominated_by(); }; class gia_pareto : public pareto_base { public: diff --git a/src/solver/solver.h b/src/solver/solver.h index bd1a26adb..e0d3d30e2 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -133,9 +133,11 @@ public: class scoped_push { solver& s; + bool m_nopop; public: - scoped_push(solver& s):s(s) { s.push(); } - ~scoped_push() { s.pop(1); } + scoped_push(solver& s):s(s), m_nopop(false) { s.push(); } + ~scoped_push() { if (!m_nopop) s.pop(1); } + void disable_pop() { m_nopop = true; } }; }; From 6821d61ac4d85b4bf95d20e1baa18b0590b4c62c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 13 May 2014 17:19:19 -0700 Subject: [PATCH 403/925] working on incremental sat solver Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 6 +- src/opt/weighted_maxsat.cpp | 140 ++++++++++++++++++++++++ src/tactic/smtlogics/qfbv_tactic.cpp | 152 +++++++++++++-------------- src/tactic/smtlogics/qfbv_tactic.h | 3 + 4 files changed, 221 insertions(+), 80 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index fda90006c..1ad9909ad 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -802,12 +802,12 @@ namespace opt { } void context::display(std::ostream& out) { - + display_assignment(out); } void context::display_assignment(std::ostream& out) { - for (unsigned i = 0; i < m_objectives.size(); ++i) { - objective const& obj = m_objectives[i]; + for (unsigned i = 0; i < m_scoped_state.m_objectives.size(); ++i) { + objective const& obj = m_scoped_state.m_objectives[i]; display_objective(out, obj); if (get_lower_as_num(i) != get_upper_as_num(i)) { out << " |-> [" << get_lower(i) << ":" << get_upper(i) << "]\n"; diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 075b89a76..7f571301d 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -37,9 +37,145 @@ Notes: #include "tactic2solver.h" #include "nnf_tactic.h" #include "opt_sls_solver.h" +#include "sat_solver.h" +#include "goal2sat.h" namespace opt { + // incremental SAT solver. + class inc_sat_solver : public solver { + ast_manager& m; + sat::solver m_solver; + goal2sat m_goal2sat; + params_ref m_params; + expr_ref_vector m_fmls; + atom2bool_var m_map; + model_ref m_model; + tactic_ref m_preprocess; + public: + inc_sat_solver(ast_manager& m, params_ref const& p): + m(m), m_solver(p,0), m_params(p), + m_fmls(m), m_map(m) { + tactic_ref pb2bv = mk_card2bv_tactic(m, m_params); + tactic_ref bv2sat = mk_qfbv_tactic(m, p, mk_skip_tactic(), mk_fail_tactic()); + m_preprocess = and_then(pb2bv.get(), bv2sat.get()); + } + + virtual ~inc_sat_solver() {} + + virtual void set_progress_callback(progress_callback * callback) { + } + virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions) { + SASSERT(num_assumptions == 0); + + goal_ref_buffer result; + model_converter_ref mc; // TODO make model convertion work between checks + proof_converter_ref pc; + expr_dependency_ref core(m); + + if (!m_fmls.empty()) { + goal_ref g = alloc(goal, m); + for (unsigned i = 0; i < m_fmls.size(); ++i) { + g->assert_expr(m_fmls[i].get()); + } + m_fmls.reset(); + try { + (*m_preprocess)(g, result, mc, pc, core); + } + catch (tactic_exception &) { + IF_VERBOSE(0, verbose_stream() << "exception in tactic\n";); + return l_undef; + } + // TODO: check that result is a singleton. + if (result.size() != 1) { + IF_VERBOSE(0, verbose_stream() << "size of result is not 1, it is: " << result.size() << "\n";); + return l_undef; + } + m_goal2sat(*result[0], m_params, m_solver, m_map); + } + + lbool r = m_solver.check(); + if (r == l_true) { + model_ref md = alloc(model, m); + sat::model const & ll_m = m_solver.get_model(); + atom2bool_var::iterator it = m_map.begin(); + atom2bool_var::iterator end = m_map.end(); + for (; it != end; ++it) { + expr * n = it->m_key; + sat::bool_var v = it->m_value; + switch (sat::value_at(v, ll_m)) { + case l_true: + md->register_decl(to_app(n)->get_decl(), m.mk_true()); + break; + case l_false: + md->register_decl(to_app(n)->get_decl(), m.mk_false()); + break; + default: + break; + } + } + TRACE("sat_tactic", model_v2_pp(tout, *md);); + m_model = md; + if (mc) { + (*mc)(m_model); + } + } + m_solver.pop(m_solver.scope_lvl()); + return r; + } + virtual void set_cancel(bool f) { + m_goal2sat.set_cancel(f); + m_solver.set_cancel(f); + m_preprocess->set_cancel(f); + } + virtual void push() { + IF_VERBOSE(0, verbose_stream() << "push ignored\n";); + } + virtual void pop(unsigned n) { + IF_VERBOSE(0, verbose_stream() << "pop ignored\n";); + } + virtual unsigned get_scope_level() const { + return 0; + } + virtual void assert_expr(expr * t, expr * a) { + if (a) { + m_fmls.push_back(m.mk_implies(a, t)); + } + else { + m_fmls.push_back(t); + } + } + virtual void assert_expr(expr * t) { + m_fmls.push_back(t); + } + virtual void set_produce_models(bool f) {} + virtual void collect_param_descrs(param_descrs & r) { + goal2sat::collect_param_descrs(r); + sat::solver::collect_param_descrs(r); + } + virtual void updt_params(params_ref const & p) { + m_params = p; + } + + virtual void collect_statistics(statistics & st) const {} + virtual void get_unsat_core(ptr_vector & r) { + UNREACHABLE(); + } + virtual void get_model(model_ref & m) { + m = m_model; + } + virtual proof * get_proof() { + UNREACHABLE(); + return 0; + } + virtual std::string reason_unknown() const { + return "no reason given"; + } + virtual void get_labels(svector & r) { + UNREACHABLE(); + } + + }; // --------------------------------------------- // base class with common utilities used @@ -163,10 +299,14 @@ namespace opt { void enable_bvsat() { if (m_enable_sat && !m_sat_enabled && probe_bv()) { +#if 1 tactic_ref pb2bv = mk_card2bv_tactic(m, m_params); tactic_ref bv2sat = mk_qfbv_tactic(m, m_params); tactic_ref tac = and_then(pb2bv.get(), bv2sat.get()); solver* sat_solver = mk_tactic2solver(m, tac.get(), m_params); +#else + solver* sat_solver = alloc(inc_sat_solver, m, m_params); +#endif unsigned sz = s().get_num_assertions(); for (unsigned i = 0; i < sz; ++i) { sat_solver->assert_expr(s().get_assertion(i)); diff --git a/src/tactic/smtlogics/qfbv_tactic.cpp b/src/tactic/smtlogics/qfbv_tactic.cpp index 38dd631cc..db1c7b762 100644 --- a/src/tactic/smtlogics/qfbv_tactic.cpp +++ b/src/tactic/smtlogics/qfbv_tactic.cpp @@ -31,13 +31,12 @@ Notes: #define MEMLIMIT 300 -tactic * mk_qfbv_tactic(ast_manager & m, params_ref const & p) { - - params_ref main_p; - main_p.set_bool("elim_and", true); - main_p.set_bool("push_ite_bv", true); - main_p.set_bool("blast_distinct", true); +static tactic * mk_qfbv_preamble(ast_manager& m, params_ref const& p) { + params_ref solve_eq_p; + // conservative guassian elimination. + solve_eq_p.set_uint("solve_eqs_max_occs", 2); + params_ref simp2_p = p; simp2_p.set_bool("som", true); simp2_p.set_bool("pull_cheap_ite", true); @@ -47,6 +46,38 @@ tactic * mk_qfbv_tactic(ast_manager & m, params_ref const & p) { simp2_p.set_bool("flat", true); // required by som simp2_p.set_bool("hoist_mul", false); // required by som + + params_ref hoist_p; + hoist_p.set_bool("hoist_mul", true); + hoist_p.set_bool("som", false); + + return + and_then( + and_then(mk_simplify_tactic(m), + mk_propagate_values_tactic(m), + using_params(mk_solve_eqs_tactic(m), solve_eq_p), + mk_elim_uncnstr_tactic(m), + if_no_proofs(if_no_unsat_cores(mk_bv_size_reduction_tactic(m))), + using_params(mk_simplify_tactic(m), simp2_p)), + // Z3 can solve a couple of extra benchmarks by using hoist_mul + // but the timeout in SMT-COMP is too small. + // Moreover, it impacted negatively some easy benchmarks. + // We should decide later, if we keep it or not. + using_params(mk_simplify_tactic(m), hoist_p), + mk_max_bv_sharing_tactic(m)); +} + +static tactic * main_p(tactic* t) { + params_ref p; + p.set_bool("elim_and", true); + p.set_bool("push_ite_bv", true); + p.set_bool("blast_distinct", true); + return using_params(t, p); +} + + +tactic * mk_qfbv_tactic(ast_manager& m, params_ref const & p, tactic* sat, tactic* smt) { + params_ref local_ctx_p = p; local_ctx_p.set_bool("local_ctx", true); @@ -60,88 +91,55 @@ tactic * mk_qfbv_tactic(ast_manager & m, params_ref const & p) { ctx_simp_p.set_uint("max_depth", 32); ctx_simp_p.set_uint("max_steps", 50000000); - params_ref hoist_p; - hoist_p.set_bool("hoist_mul", true); - hoist_p.set_bool("som", false); - - params_ref solve_eq_p; - // conservative guassian elimination. - solve_eq_p.set_uint("solve_eqs_max_occs", 2); params_ref big_aig_p; big_aig_p.set_bool("aig_per_assertion", false); + + tactic* preamble_st = mk_qfbv_preamble(m, p); + + tactic * st = main_p(and_then(preamble_st, + // If the user sets HI_DIV0=false, then the formula may contain uninterpreted function + // symbols. In this case, we should not use + cond(mk_is_qfbv_probe(), + cond(mk_is_qfbv_eq_probe(), + and_then(mk_bv1_blaster_tactic(m), + using_params(smt, solver_p)), + and_then(mk_bit_blaster_tactic(m), + when(mk_lt(mk_memory_probe(), mk_const_probe(MEMLIMIT)), + and_then(using_params(and_then(mk_simplify_tactic(m), + mk_solve_eqs_tactic(m)), + local_ctx_p), + if_no_proofs(cond(mk_produce_unsat_cores_probe(), + mk_aig_tactic(), + using_params(mk_aig_tactic(), + big_aig_p))))), + sat)), + smt))); + + st->updt_params(p); + return st; + +} + + +tactic * mk_qfbv_tactic(ast_manager & m, params_ref const & p) { - tactic * preamble_st = and_then(and_then(mk_simplify_tactic(m), - mk_propagate_values_tactic(m), - using_params(mk_solve_eqs_tactic(m), solve_eq_p), - mk_elim_uncnstr_tactic(m), - if_no_proofs(if_no_unsat_cores(mk_bv_size_reduction_tactic(m))), - using_params(mk_simplify_tactic(m), simp2_p)), - // Z3 can solve a couple of extra benchmarks by using hoist_mul - // but the timeout in SMT-COMP is too small. - // Moreover, it impacted negatively some easy benchmarks. - // We should decide later, if we keep it or not. - using_params(mk_simplify_tactic(m), hoist_p), - mk_max_bv_sharing_tactic(m)); - -#ifdef USE_OLD_SAT_SOLVER - tactic * new_sat = and_then(mk_simplify_tactic(m), - mk_smt_tactic()); -#else tactic * new_sat = cond(mk_or(mk_produce_proofs_probe(), mk_produce_unsat_cores_probe()), - and_then(mk_simplify_tactic(m), - mk_smt_tactic()), + and_then(mk_simplify_tactic(m), mk_smt_tactic()), mk_sat_tactic(m)); -#endif - /* use full sls - tactic * st = using_params(and_then(preamble_st, + return mk_qfbv_tactic(m, p, new_sat, mk_smt_tactic()); + +} + +/* use full sls + tactic * st = main_p(and_then(preamble_st, cond(mk_is_qfbv_probe(), cond(mk_is_qfbv_eq_probe(), and_then(mk_bv1_blaster_tactic(m), using_params(mk_smt_tactic(), solver_p)), and_then(mk_nnf_tactic(m, p), mk_sls_tactic(m))), - mk_smt_tactic())), - main_p);*/ - - /* use pure dpll - tactic * st = using_params(and_then(mk_simplify_tactic(m), - cond(mk_is_qfbv_probe(), - and_then(mk_bit_blaster_tactic(m), - when(mk_lt(mk_memory_probe(), mk_const_probe(MEMLIMIT)), - and_then(using_params(and_then(mk_simplify_tactic(m), - mk_solve_eqs_tactic(m)), - local_ctx_p), - if_no_proofs(cond(mk_produce_unsat_cores_probe(), - mk_aig_tactic(), - using_params(mk_aig_tactic(), - big_aig_p))))), - new_sat), - mk_smt_tactic())), - main_p);*/ - - tactic * st = using_params(and_then(preamble_st, - // If the user sets HI_DIV0=false, then the formula may contain uninterpreted function - // symbols. In this case, we should not use - cond(mk_is_qfbv_probe(), - cond(mk_is_qfbv_eq_probe(), - and_then(mk_bv1_blaster_tactic(m), - using_params(mk_smt_tactic(), solver_p)), - and_then(mk_bit_blaster_tactic(m), - when(mk_lt(mk_memory_probe(), mk_const_probe(MEMLIMIT)), - and_then(using_params(and_then(mk_simplify_tactic(m), - mk_solve_eqs_tactic(m)), - local_ctx_p), - if_no_proofs(cond(mk_produce_unsat_cores_probe(), - mk_aig_tactic(), - using_params(mk_aig_tactic(), - big_aig_p))))), - new_sat)), - mk_smt_tactic())), - main_p); - - st->updt_params(p); - return st; -} + mk_smt_tactic()))); +*/ diff --git a/src/tactic/smtlogics/qfbv_tactic.h b/src/tactic/smtlogics/qfbv_tactic.h index 7210f6f25..c20a4443a 100644 --- a/src/tactic/smtlogics/qfbv_tactic.h +++ b/src/tactic/smtlogics/qfbv_tactic.h @@ -24,8 +24,11 @@ class ast_manager; class tactic; tactic * mk_qfbv_tactic(ast_manager & m, params_ref const & p = params_ref()); + /* ADD_TACTIC("qfbv", "builtin strategy for solving QF_BV problems.", "mk_qfbv_tactic(m, p)") */ +tactic * mk_qfbv_tactic(ast_manager & m, params_ref const & p, tactic* sat, tactic* smt); + #endif From 6d6abb4dde6bcb28dd1aa437bd9362eddb3c5652 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 14 May 2014 09:27:47 -0700 Subject: [PATCH 404/925] experimenting with inc_sat Signed-off-by: Nikolaj Bjorner --- src/opt/weighted_maxsat.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 7f571301d..484159719 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -51,7 +51,9 @@ namespace opt { expr_ref_vector m_fmls; atom2bool_var m_map; model_ref m_model; + model_converter_ref m_mc; tactic_ref m_preprocess; + statistics m_stats; public: inc_sat_solver(ast_manager& m, params_ref const& p): m(m), m_solver(p,0), m_params(p), @@ -68,9 +70,10 @@ namespace opt { virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions) { SASSERT(num_assumptions == 0); + m_solver.pop(m_solver.scope_lvl()); goal_ref_buffer result; - model_converter_ref mc; // TODO make model convertion work between checks proof_converter_ref pc; + model_converter_ref mc; expr_dependency_ref core(m); if (!m_fmls.empty()) { @@ -84,8 +87,10 @@ namespace opt { } catch (tactic_exception &) { IF_VERBOSE(0, verbose_stream() << "exception in tactic\n";); + m_preprocess->collect_statistics(m_stats); return l_undef; } + m_mc = concat(m_mc.get(), mc.get()); // TODO: check that result is a singleton. if (result.size() != 1) { IF_VERBOSE(0, verbose_stream() << "size of result is not 1, it is: " << result.size() << "\n";); @@ -114,13 +119,13 @@ namespace opt { break; } } - TRACE("sat_tactic", model_v2_pp(tout, *md);); m_model = md; - if (mc) { - (*mc)(m_model); + if (m_mc) { + (*m_mc)(m_model); } + // IF_VERBOSE(0, model_smt2_pp(verbose_stream(), m, *(m_model.get()), 0);); } - m_solver.pop(m_solver.scope_lvl()); + m_solver.collect_statistics(m_stats); return r; } virtual void set_cancel(bool f) { @@ -157,7 +162,9 @@ namespace opt { m_params = p; } - virtual void collect_statistics(statistics & st) const {} + virtual void collect_statistics(statistics & st) const { + st.copy(m_stats); + } virtual void get_unsat_core(ptr_vector & r) { UNREACHABLE(); } From 81c2560854a504481d0c6a3da836c02245b97d3e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 14 May 2014 15:13:26 -0700 Subject: [PATCH 405/925] experimenting with inc-sat Signed-off-by: Nikolaj Bjorner --- src/opt/weighted_maxsat.cpp | 37 +++++++++++++++++++++------- src/tactic/smtlogics/qfbv_tactic.cpp | 16 ++++++------ src/tactic/smtlogics/qfbv_tactic.h | 2 ++ 3 files changed, 39 insertions(+), 16 deletions(-) diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 484159719..18707bf67 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -27,6 +27,7 @@ Notes: #include "pb_decl_plugin.h" #include "uint_set.h" #include "pb_preprocess_tactic.h" +#include "aig_tactic.h" #include "simplify_tactic.h" #include "tactical.h" #include "tactic.h" @@ -34,6 +35,7 @@ Notes: #include "pb_sls.h" #include "qfbv_tactic.h" #include "card2bv_tactic.h" +#include "bit_blaster_tactic.h" #include "tactic2solver.h" #include "nnf_tactic.h" #include "opt_sls_solver.h" @@ -54,13 +56,19 @@ namespace opt { model_converter_ref m_mc; tactic_ref m_preprocess; statistics m_stats; + app_ref m_soft; public: - inc_sat_solver(ast_manager& m, params_ref const& p): + inc_sat_solver(ast_manager& m, params_ref const& p, expr_ref_vector const& soft): m(m), m_solver(p,0), m_params(p), - m_fmls(m), m_map(m) { + m_fmls(m), m_map(m), m_soft(m) { tactic_ref pb2bv = mk_card2bv_tactic(m, m_params); - tactic_ref bv2sat = mk_qfbv_tactic(m, p, mk_skip_tactic(), mk_fail_tactic()); - m_preprocess = and_then(pb2bv.get(), bv2sat.get()); + tactic_ref preamble_st = mk_qfbv_preamble(m, m_params); + m_preprocess = and_then(pb2bv.get(), preamble_st.get(), mk_bit_blaster_tactic(m), mk_aig_tactic()); + + ptr_vector sorts; + sorts.resize(soft.size(), m.mk_bool_sort()); + func_decl_ref fn(m.mk_func_decl(symbol("Soft"), sorts.size(), sorts.c_ptr(), m.mk_bool_sort()), m); + m_soft = m.mk_app(fn, soft.size(), soft.c_ptr()); } virtual ~inc_sat_solver() {} @@ -81,12 +89,15 @@ namespace opt { for (unsigned i = 0; i < m_fmls.size(); ++i) { g->assert_expr(m_fmls[i].get()); } + g->assert_expr(m_soft); + TRACE("opt", g->display(tout);); m_fmls.reset(); - try { + try { (*m_preprocess)(g, result, mc, pc, core); + TRACE("opt", result[0]->display(tout);); } - catch (tactic_exception &) { - IF_VERBOSE(0, verbose_stream() << "exception in tactic\n";); + catch (tactic_exception & ex) { + IF_VERBOSE(0, verbose_stream() << "exception in tactic " << ex.msg() << "\n";); m_preprocess->collect_statistics(m_stats); return l_undef; } @@ -96,7 +107,15 @@ namespace opt { IF_VERBOSE(0, verbose_stream() << "size of result is not 1, it is: " << result.size() << "\n";); return l_undef; } - m_goal2sat(*result[0], m_params, m_solver, m_map); + g = result[0]; + for (unsigned i = 0; i < g->size(); ++i) { + expr* f = g->form(i); + if (is_app_of(f, m_soft->get_decl())) { + g->update(i, m.mk_true()); + } + } + TRACE("opt", g->display(tout);); + m_goal2sat(*g, m_params, m_solver, m_map); } lbool r = m_solver.check(); @@ -312,7 +331,7 @@ namespace opt { tactic_ref tac = and_then(pb2bv.get(), bv2sat.get()); solver* sat_solver = mk_tactic2solver(m, tac.get(), m_params); #else - solver* sat_solver = alloc(inc_sat_solver, m, m_params); + solver* sat_solver = alloc(inc_sat_solver, m, m_params, m_soft); #endif unsigned sz = s().get_num_assertions(); for (unsigned i = 0; i < sz; ++i) { diff --git a/src/tactic/smtlogics/qfbv_tactic.cpp b/src/tactic/smtlogics/qfbv_tactic.cpp index db1c7b762..3b5c352bb 100644 --- a/src/tactic/smtlogics/qfbv_tactic.cpp +++ b/src/tactic/smtlogics/qfbv_tactic.cpp @@ -31,7 +31,7 @@ Notes: #define MEMLIMIT 300 -static tactic * mk_qfbv_preamble(ast_manager& m, params_ref const& p) { +tactic * mk_qfbv_preamble(ast_manager& m, params_ref const& p) { params_ref solve_eq_p; // conservative guassian elimination. @@ -53,16 +53,18 @@ static tactic * mk_qfbv_preamble(ast_manager& m, params_ref const& p) { return and_then( - and_then(mk_simplify_tactic(m), - mk_propagate_values_tactic(m), - using_params(mk_solve_eqs_tactic(m), solve_eq_p), - mk_elim_uncnstr_tactic(m), - if_no_proofs(if_no_unsat_cores(mk_bv_size_reduction_tactic(m))), - using_params(mk_simplify_tactic(m), simp2_p)), + mk_simplify_tactic(m), + mk_propagate_values_tactic(m), + using_params(mk_solve_eqs_tactic(m), solve_eq_p), + mk_elim_uncnstr_tactic(m), + if_no_proofs(if_no_unsat_cores(mk_bv_size_reduction_tactic(m))), + using_params(mk_simplify_tactic(m), simp2_p), + // // Z3 can solve a couple of extra benchmarks by using hoist_mul // but the timeout in SMT-COMP is too small. // Moreover, it impacted negatively some easy benchmarks. // We should decide later, if we keep it or not. + // using_params(mk_simplify_tactic(m), hoist_p), mk_max_bv_sharing_tactic(m)); } diff --git a/src/tactic/smtlogics/qfbv_tactic.h b/src/tactic/smtlogics/qfbv_tactic.h index c20a4443a..98b3e2289 100644 --- a/src/tactic/smtlogics/qfbv_tactic.h +++ b/src/tactic/smtlogics/qfbv_tactic.h @@ -29,6 +29,8 @@ tactic * mk_qfbv_tactic(ast_manager & m, params_ref const & p = params_ref()); ADD_TACTIC("qfbv", "builtin strategy for solving QF_BV problems.", "mk_qfbv_tactic(m, p)") */ +tactic * mk_qfbv_preamble(ast_manager& m, params_ref const& p); + tactic * mk_qfbv_tactic(ast_manager & m, params_ref const & p, tactic* sat, tactic* smt); #endif From d849b5c637d4624c5f1263b45c479640ceae4b2a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 14 May 2014 19:40:58 -0700 Subject: [PATCH 406/925] experiment with sat solver Signed-off-by: Nikolaj Bjorner --- src/opt/opt_sls_solver.h | 64 +++++++------- src/opt/weighted_maxsat.cpp | 133 ++++++++++++++++++++++++------ src/sat/sat_simplifier.cpp | 3 + src/sat/sat_simplifier.h | 1 + src/sat/sat_simplifier_params.pyg | 1 + 5 files changed, 149 insertions(+), 53 deletions(-) diff --git a/src/opt/opt_sls_solver.h b/src/opt/opt_sls_solver.h index 817537a75..13f9e99f1 100644 --- a/src/opt/opt_sls_solver.h +++ b/src/opt/opt_sls_solver.h @@ -125,6 +125,38 @@ namespace opt { } } + static expr_ref soft2bv(expr_ref_vector const& soft, vector const& weights) { + ast_manager& m = soft.get_manager(); + pb::card_pb_rewriter pb2bv(m); + rational upper(1); + expr_ref objective(m); + for (unsigned i = 0; i < weights.size(); ++i) { + upper += weights[i]; + } + expr_ref zero(m), tmp(m); + bv_util bv(m); + expr_ref_vector es(m); + rational num = numerator(upper); + rational den = denominator(upper); + rational maxval = num*den; + unsigned bv_size = maxval.get_num_bits(); + zero = bv.mk_numeral(rational(0), bv_size); + for (unsigned i = 0; i < soft.size(); ++i) { + pb2bv(soft[i], tmp); + es.push_back(m.mk_ite(tmp, bv.mk_numeral(den*weights[i], bv_size), zero)); + } + if (es.empty()) { + objective = bv.mk_numeral(0, bv_size); + } + else { + objective = es[0].get(); + for (unsigned i = 1; i < es.size(); ++i) { + objective = bv.mk_bv_add(objective, es[i].get()); + } + } + return objective; + } + protected: typedef bvsls_opt_engine::optimization_result opt_result; @@ -143,37 +175,9 @@ namespace opt { m_solver->pop(n); } + private: // convert soft constraints to bit-vector objective. - expr_ref soft2bv() { - rational upper(1); - expr_ref objective(m); - for (unsigned i = 0; i < m_weights.size(); ++i) { - upper += m_weights[i]; - } - expr_ref zero(m), tmp(m); - bv_util bv(m); - expr_ref_vector es(m); - rational num = numerator(upper); - rational den = denominator(upper); - rational maxval = num*den; - unsigned bv_size = maxval.get_num_bits(); - zero = bv.mk_numeral(rational(0), bv_size); - for (unsigned i = 0; i < m_soft.size(); ++i) { - m_pb2bv(m_soft[i].get(), tmp); - es.push_back(m.mk_ite(tmp, bv.mk_numeral(den*m_weights[i], bv_size), zero)); - } - if (es.empty()) { - objective = bv.mk_numeral(0, bv_size); - } - else { - objective = es[0].get(); - for (unsigned i = 1; i < es.size(); ++i) { - objective = bv.mk_bv_add(objective, es[i].get()); - } - } - return objective; - } void assertions2sls() { expr_ref tmp(m); @@ -224,7 +228,7 @@ namespace opt { m_bvsls = alloc(bvsls_opt_engine, m, m_params); } assertions2sls(); - expr_ref objective = soft2bv(); + expr_ref objective = soft2bv(m_soft, m_weights); opt_result res(m); res.is_sat = l_undef; try { diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 18707bf67..6e529bdad 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -26,24 +26,39 @@ Notes: #include "opt_params.hpp" #include "pb_decl_plugin.h" #include "uint_set.h" -#include "pb_preprocess_tactic.h" -#include "aig_tactic.h" -#include "simplify_tactic.h" #include "tactical.h" #include "tactic.h" #include "model_smt2_pp.h" #include "pb_sls.h" +#include "tactic2solver.h" +#include "pb_preprocess_tactic.h" +#include "aig_tactic.h" +#include "simplify_tactic.h" +#include "nnf_tactic.h" +#include "propagate_values_tactic.h" +#include "max_bv_sharing_tactic.h" #include "qfbv_tactic.h" #include "card2bv_tactic.h" #include "bit_blaster_tactic.h" -#include "tactic2solver.h" -#include "nnf_tactic.h" + #include "opt_sls_solver.h" #include "sat_solver.h" #include "goal2sat.h" namespace opt { + static app_ref mk_bv_vec(ast_manager& m, sort* s) { + bv_util bv(m); + expr_ref_vector vars(m); + unsigned sz = bv.get_bv_size(s); + for (unsigned i = 0; i < sz; ++i) { + std::stringstream strm; + strm << "soft_v" << i; + vars.push_back(m.mk_const(symbol(strm.str().c_str()), m.mk_bool_sort())); + } + return app_ref(bv.mk_bv(vars.size(), vars.c_ptr()), m); + } + // incremental SAT solver. class inc_sat_solver : public solver { ast_manager& m; @@ -58,17 +73,29 @@ namespace opt { statistics m_stats; app_ref m_soft; public: - inc_sat_solver(ast_manager& m, params_ref const& p, expr_ref_vector const& soft): + inc_sat_solver(ast_manager& m, params_ref const& p, expr_ref_vector const& soft, vector const& weights): m(m), m_solver(p,0), m_params(p), m_fmls(m), m_map(m), m_soft(m) { - tactic_ref pb2bv = mk_card2bv_tactic(m, m_params); - tactic_ref preamble_st = mk_qfbv_preamble(m, m_params); - m_preprocess = and_then(pb2bv.get(), preamble_st.get(), mk_bit_blaster_tactic(m), mk_aig_tactic()); + // m_params.set_bool("elim_vars", false); + m_solver.updt_params(m_params); + params_ref simp2_p = p; + simp2_p.set_bool("som", true); + simp2_p.set_bool("pull_cheap_ite", true); + simp2_p.set_bool("push_ite_bv", false); + simp2_p.set_bool("local_ctx", true); + simp2_p.set_uint("local_ctx_limit", 10000000); + simp2_p.set_bool("flat", true); // required by som + simp2_p.set_bool("hoist_mul", false); // required by som + m_preprocess = + and_then(mk_card2bv_tactic(m, m_params), + mk_simplify_tactic(m), + mk_propagate_values_tactic(m), + using_params(mk_simplify_tactic(m), simp2_p), + mk_max_bv_sharing_tactic(m), + mk_bit_blaster_tactic(m), + mk_aig_tactic()); + - ptr_vector sorts; - sorts.resize(soft.size(), m.mk_bool_sort()); - func_decl_ref fn(m.mk_func_decl(symbol("Soft"), sorts.size(), sorts.c_ptr(), m.mk_bool_sort()), m); - m_soft = m.mk_app(fn, soft.size(), soft.c_ptr()); } virtual ~inc_sat_solver() {} @@ -89,7 +116,7 @@ namespace opt { for (unsigned i = 0; i < m_fmls.size(); ++i) { g->assert_expr(m_fmls[i].get()); } - g->assert_expr(m_soft); + //g->assert_expr(m_soft); TRACE("opt", g->display(tout);); m_fmls.reset(); try { @@ -102,18 +129,11 @@ namespace opt { return l_undef; } m_mc = concat(m_mc.get(), mc.get()); - // TODO: check that result is a singleton. if (result.size() != 1) { IF_VERBOSE(0, verbose_stream() << "size of result is not 1, it is: " << result.size() << "\n";); return l_undef; } g = result[0]; - for (unsigned i = 0; i < g->size(); ++i) { - expr* f = g->form(i); - if (is_app_of(f, m_soft->get_decl())) { - g->update(i, m.mk_true()); - } - } TRACE("opt", g->display(tout);); m_goal2sat(*g, m_params, m_solver, m_map); } @@ -126,6 +146,7 @@ namespace opt { atom2bool_var::iterator end = m_map.end(); for (; it != end; ++it) { expr * n = it->m_key; + if (is_app(n) && to_app(n)->get_num_args() > 0) continue; sat::bool_var v = it->m_value; switch (sat::value_at(v, ll_m)) { case l_true: @@ -179,6 +200,8 @@ namespace opt { } virtual void updt_params(params_ref const & p) { m_params = p; + //m_params.set_bool("elim_vars", false); + m_solver.updt_params(m_params); } virtual void collect_statistics(statistics & st) const { @@ -325,13 +348,13 @@ namespace opt { void enable_bvsat() { if (m_enable_sat && !m_sat_enabled && probe_bv()) { -#if 1 +#if 0 tactic_ref pb2bv = mk_card2bv_tactic(m, m_params); tactic_ref bv2sat = mk_qfbv_tactic(m, m_params); tactic_ref tac = and_then(pb2bv.get(), bv2sat.get()); solver* sat_solver = mk_tactic2solver(m, tac.get(), m_params); #else - solver* sat_solver = alloc(inc_sat_solver, m, m_params, m_soft); + solver* sat_solver = alloc(inc_sat_solver, m, m_params, m_soft, m_weights); #endif unsigned sz = s().get_num_assertions(); for (unsigned i = 0; i < sz; ++i) { @@ -749,6 +772,69 @@ namespace opt { virtual ~pbmax() {} + lbool operator()() { + enable_bvsat(); + enable_sls(); + + TRACE("opt", s().display(tout); tout << "\n"; + for (unsigned i = 0; i < m_soft.size(); ++i) { + tout << mk_pp(m_soft[i].get(), m) << " " << m_weights[i] << "\n"; + } + ); + pb_util u(m); + bv_util bv(m); + expr_ref bsoft = sls_solver::soft2bv(m_soft, m_weights); + app_ref var(m); + expr_ref fml(m), val(m), soft(m); + app_ref b(m); + sort* srt = m.get_sort(bsoft); + var = mk_bv_vec(m, srt); + fml = m.mk_eq(bsoft, var); + ptr_vector sorts; + sorts.resize(var->get_num_args(), m.mk_bool_sort()); + func_decl_ref fn(m.mk_func_decl(symbol("Soft"), sorts.size(), sorts.c_ptr(), m.mk_bool_sort()), m); + soft = m.mk_app(fn, var->get_num_args(), var->get_args()); + s().assert_expr(fml); + s().assert_expr(soft); + expr_ref_vector nsoft(m); + init(); + for (unsigned i = 0; i < m_soft.size(); ++i) { + nsoft.push_back(mk_not(m_soft[i].get())); + } + fml = m.mk_not(bv.mk_ule(bv.mk_numeral(m_upper, m.get_sort(var)), var)); + s().assert_expr(fml); + + lbool is_sat = s().check_sat(0,0); + while (l_true == is_sat) { + TRACE("opt", s().display(tout<<"looping\n");); + m_model->eval(var, val); + unsigned bv_size; + if (bv.is_numeral(val, m_upper, bv_size)) { + IF_VERBOSE(1, verbose_stream() << "(wmaxsat.pb solve with upper bound: " << m_upper << ")\n";); + TRACE("opt", tout << "new upper: " << m_upper << "\n";); + + fml = m.mk_not(bv.mk_ule(bv.mk_numeral(m_upper, m.get_sort(var)), var)); + // fml = m.mk_not(u.mk_ge(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper)); + // solver::scoped_push _scope2(s()); + s().assert_expr(fml); + } + is_sat = s().check_sat(0,0); + if (m_cancel) { + is_sat = l_undef; + } + if (is_sat == l_true) { + s().get_model(m_model); + } + } + if (is_sat == l_false) { + is_sat = l_true; + m_lower = m_upper; + } + TRACE("opt", tout << "lower: " << m_lower << "\n";); + return is_sat; + } + +#if 0 lbool operator()() { enable_bvsat(); enable_sls(); @@ -799,6 +885,7 @@ namespace opt { TRACE("opt", tout << "lower: " << m_lower << "\n";); return is_sat; } +#endif }; // ------------------------------------------------------ diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index f20ffa7c7..3553a9031 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1421,6 +1421,8 @@ namespace sat { }; void simplifier::elim_vars() { + if (!m_elim_vars) return; + elim_var_report rpt(*this); bool_var_vector vars; order_vars_for_elim(vars); @@ -1460,6 +1462,7 @@ namespace sat { m_res_cls_cutoff2 = p.resolution_cls_cutoff2(); m_subsumption = p.subsumption(); m_subsumption_limit = p.subsumption_limit(); + m_elim_vars = p.elim_vars(); } void simplifier::collect_param_descrs(param_descrs & r) { diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h index 96d346598..263354a4a 100644 --- a/src/sat/sat_simplifier.h +++ b/src/sat/sat_simplifier.h @@ -82,6 +82,7 @@ namespace sat { bool m_subsumption; unsigned m_subsumption_limit; + bool m_elim_vars; // stats unsigned m_num_blocked_clauses; diff --git a/src/sat/sat_simplifier_params.pyg b/src/sat/sat_simplifier_params.pyg index 6165e7e62..ff2944987 100644 --- a/src/sat/sat_simplifier_params.pyg +++ b/src/sat/sat_simplifier_params.pyg @@ -15,5 +15,6 @@ def_module_params(module_name='sat', ('resolution.lit_cutoff_range3', UINT, 300, 'second cutoff (total number of literals) for Boolean variable elimination, for problems containing more than res_cls_cutoff2'), ('resolution.cls_cutoff1', UINT, 100000000, 'limit1 - total number of problems clauses for the second cutoff of Boolean variable elimination'), ('resolution.cls_cutoff2', UINT, 700000000, 'limit2 - total number of problems clauses for the second cutoff of Boolean variable elimination'), + ('elim_vars', BOOL, True, 'enable variable elimination during simplification'), ('subsumption', BOOL, True, 'eliminate subsumed clauses'), ('subsumption.limit', UINT, 100000000, 'approx. maximum number of literals visited during subsumption (and subsumption resolution)'))) From 33e2f2012db969318325a67455f4cdb6e8a9fe7d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 15 May 2014 08:46:20 -0700 Subject: [PATCH 407/925] inc sat experiment Signed-off-by: Nikolaj Bjorner --- src/opt/weighted_maxsat.cpp | 52 +++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 6e529bdad..7282fdf63 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -45,6 +45,9 @@ Notes: #include "sat_solver.h" #include "goal2sat.h" + +#define _INC_SAT 0 + namespace opt { static app_ref mk_bv_vec(ast_manager& m, sort* s) { @@ -76,7 +79,7 @@ namespace opt { inc_sat_solver(ast_manager& m, params_ref const& p, expr_ref_vector const& soft, vector const& weights): m(m), m_solver(p,0), m_params(p), m_fmls(m), m_map(m), m_soft(m) { - // m_params.set_bool("elim_vars", false); + m_params.set_bool("elim_vars", false); m_solver.updt_params(m_params); params_ref simp2_p = p; simp2_p.set_bool("som", true); @@ -116,7 +119,6 @@ namespace opt { for (unsigned i = 0; i < m_fmls.size(); ++i) { g->assert_expr(m_fmls[i].get()); } - //g->assert_expr(m_soft); TRACE("opt", g->display(tout);); m_fmls.reset(); try { @@ -146,23 +148,29 @@ namespace opt { atom2bool_var::iterator end = m_map.end(); for (; it != end; ++it) { expr * n = it->m_key; - if (is_app(n) && to_app(n)->get_num_args() > 0) continue; + if (is_app(n) && to_app(n)->get_num_args() > 0) { + IF_VERBOSE(0, verbose_stream() << "skip: " << mk_pp(n, m) << "\n";); + continue; + } sat::bool_var v = it->m_value; switch (sat::value_at(v, ll_m)) { case l_true: + IF_VERBOSE(0, verbose_stream() << "true: " << mk_pp(n, m) << "\n";); md->register_decl(to_app(n)->get_decl(), m.mk_true()); break; case l_false: + IF_VERBOSE(0, verbose_stream() << "false: " << mk_pp(n, m) << "\n";); md->register_decl(to_app(n)->get_decl(), m.mk_false()); break; default: + IF_VERBOSE(0, verbose_stream() << "undef: " << mk_pp(n, m) << "\n";); break; } } m_model = md; - if (m_mc) { - (*m_mc)(m_model); - } + //if (m_mc) { + // (*m_mc)(m_model); + //} // IF_VERBOSE(0, model_smt2_pp(verbose_stream(), m, *(m_model.get()), 0);); } m_solver.collect_statistics(m_stats); @@ -200,7 +208,7 @@ namespace opt { } virtual void updt_params(params_ref const & p) { m_params = p; - //m_params.set_bool("elim_vars", false); + m_params.set_bool("elim_vars", false); m_solver.updt_params(m_params); } @@ -348,13 +356,13 @@ namespace opt { void enable_bvsat() { if (m_enable_sat && !m_sat_enabled && probe_bv()) { -#if 0 +#if _INC_SAT + solver* sat_solver = alloc(inc_sat_solver, m, m_params, m_soft, m_weights); +#else tactic_ref pb2bv = mk_card2bv_tactic(m, m_params); tactic_ref bv2sat = mk_qfbv_tactic(m, m_params); tactic_ref tac = and_then(pb2bv.get(), bv2sat.get()); solver* sat_solver = mk_tactic2solver(m, tac.get(), m_params); -#else - solver* sat_solver = alloc(inc_sat_solver, m, m_params, m_soft, m_weights); #endif unsigned sz = s().get_num_assertions(); for (unsigned i = 0; i < sz; ++i) { @@ -772,6 +780,7 @@ namespace opt { virtual ~pbmax() {} +#if _INC_SAT lbool operator()() { enable_bvsat(); enable_sls(); @@ -806,18 +815,21 @@ namespace opt { lbool is_sat = s().check_sat(0,0); while (l_true == is_sat) { - TRACE("opt", s().display(tout<<"looping\n");); + s().get_model(m_model); + TRACE("opt", s().display(tout<<"looping\n"); + model_smt2_pp(tout, m, *(m_model.get()), 0);); + m_model->eval(var, val); unsigned bv_size; - if (bv.is_numeral(val, m_upper, bv_size)) { - IF_VERBOSE(1, verbose_stream() << "(wmaxsat.pb solve with upper bound: " << m_upper << ")\n";); - TRACE("opt", tout << "new upper: " << m_upper << "\n";); + VERIFY(bv.is_numeral(val, m_upper, bv_size)); + IF_VERBOSE(1, verbose_stream() << "(wmaxsat.pb solve with upper bound: " << m_upper << ")\n";); + TRACE("opt", tout << "new upper: " << m_upper << "\n";); + + fml = m.mk_not(bv.mk_ule(bv.mk_numeral(m_upper, m.get_sort(var)), var)); + // fml = m.mk_not(u.mk_ge(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper)); + // solver::scoped_push _scope2(s()); + s().assert_expr(fml); - fml = m.mk_not(bv.mk_ule(bv.mk_numeral(m_upper, m.get_sort(var)), var)); - // fml = m.mk_not(u.mk_ge(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper)); - // solver::scoped_push _scope2(s()); - s().assert_expr(fml); - } is_sat = s().check_sat(0,0); if (m_cancel) { is_sat = l_undef; @@ -834,7 +846,7 @@ namespace opt { return is_sat; } -#if 0 +#else lbool operator()() { enable_bvsat(); enable_sls(); From 61dcdcb9d1105328123e548a6373ed97c1e4dbb7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 15 May 2014 11:25:05 -0700 Subject: [PATCH 408/925] separate inc sat solver for now Signed-off-by: Nikolaj Bjorner --- src/opt/inc_sat_solver.cpp | 184 +++++++++++++++++++++++++++ src/opt/opt_sls_solver.h | 1 + src/opt/weighted_maxsat.cpp | 240 +++++------------------------------- 3 files changed, 213 insertions(+), 212 deletions(-) create mode 100644 src/opt/inc_sat_solver.cpp diff --git a/src/opt/inc_sat_solver.cpp b/src/opt/inc_sat_solver.cpp new file mode 100644 index 000000000..afd7ae905 --- /dev/null +++ b/src/opt/inc_sat_solver.cpp @@ -0,0 +1,184 @@ + +#include "solver.h" +#include "tactical.h" +#include "sat_solver.h" +#include "tactic2solver.h" +#include "nnf_tactic.h" +#include "aig_tactic.h" +#include "propagate_values_tactic.h" +#include "max_bv_sharing_tactic.h" +#include "card2bv_tactic.h" +#include "bit_blaster_tactic.h" +#include "simplify_tactic.h" +#include "goal2sat.h" + +// incremental SAT solver. +class inc_sat_solver : public solver { + ast_manager& m; + sat::solver m_solver; + goal2sat m_goal2sat; + params_ref m_params; + expr_ref_vector m_fmls; + atom2bool_var m_map; + model_ref m_model; + model_converter_ref m_mc; + tactic_ref m_preprocess; + statistics m_stats; +public: + inc_sat_solver(ast_manager& m, params_ref const& p): + m(m), m_solver(p,0), m_params(p), + m_fmls(m), m_map(m) { + m_params.set_bool("elim_vars", false); + m_solver.updt_params(m_params); + params_ref simp2_p = p; + simp2_p.set_bool("som", true); + simp2_p.set_bool("pull_cheap_ite", true); + simp2_p.set_bool("push_ite_bv", false); + simp2_p.set_bool("local_ctx", true); + simp2_p.set_uint("local_ctx_limit", 10000000); + simp2_p.set_bool("flat", true); // required by som + simp2_p.set_bool("hoist_mul", false); // required by som + m_preprocess = + and_then(mk_card2bv_tactic(m, m_params), + mk_simplify_tactic(m), + mk_propagate_values_tactic(m), + using_params(mk_simplify_tactic(m), simp2_p), + mk_max_bv_sharing_tactic(m), + mk_bit_blaster_tactic(m), + mk_aig_tactic()); + + + } + + virtual ~inc_sat_solver() {} + + virtual void set_progress_callback(progress_callback * callback) { + } + virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions) { + SASSERT(num_assumptions == 0); + + m_solver.pop(m_solver.scope_lvl()); + goal_ref_buffer result; + proof_converter_ref pc; + model_converter_ref mc; + expr_dependency_ref core(m); + + if (!m_fmls.empty()) { + goal_ref g = alloc(goal, m); + for (unsigned i = 0; i < m_fmls.size(); ++i) { + g->assert_expr(m_fmls[i].get()); + } + TRACE("opt", g->display(tout);); + m_fmls.reset(); + try { + (*m_preprocess)(g, result, mc, pc, core); + TRACE("opt", result[0]->display(tout);); + } + catch (tactic_exception & ex) { + IF_VERBOSE(0, verbose_stream() << "exception in tactic " << ex.msg() << "\n";); + m_preprocess->collect_statistics(m_stats); + return l_undef; + } + m_mc = concat(m_mc.get(), mc.get()); + if (result.size() != 1) { + IF_VERBOSE(0, verbose_stream() << "size of result is not 1, it is: " << result.size() << "\n";); + return l_undef; + } + g = result[0]; + TRACE("opt", g->display(tout);); + m_goal2sat(*g, m_params, m_solver, m_map); + } + + lbool r = m_solver.check(); + if (r == l_true) { + model_ref md = alloc(model, m); + sat::model const & ll_m = m_solver.get_model(); + atom2bool_var::iterator it = m_map.begin(); + atom2bool_var::iterator end = m_map.end(); + for (; it != end; ++it) { + expr * n = it->m_key; + if (is_app(n) && to_app(n)->get_num_args() > 0) { + continue; + } + sat::bool_var v = it->m_value; + switch (sat::value_at(v, ll_m)) { + case l_true: + md->register_decl(to_app(n)->get_decl(), m.mk_true()); + break; + case l_false: + md->register_decl(to_app(n)->get_decl(), m.mk_false()); + break; + default: + break; + } + } + m_model = md; + if (m_mc) { + (*m_mc)(m_model); + } + // IF_VERBOSE(0, model_smt2_pp(verbose_stream(), m, *(m_model.get()), 0);); + } + m_solver.collect_statistics(m_stats); + return r; + } + virtual void set_cancel(bool f) { + m_goal2sat.set_cancel(f); + m_solver.set_cancel(f); + m_preprocess->set_cancel(f); + } + virtual void push() { + IF_VERBOSE(0, verbose_stream() << "push ignored\n";); + } + virtual void pop(unsigned n) { + IF_VERBOSE(0, verbose_stream() << "pop ignored\n";); + } + virtual unsigned get_scope_level() const { + return 0; + } + virtual void assert_expr(expr * t, expr * a) { + if (a) { + m_fmls.push_back(m.mk_implies(a, t)); + } + else { + m_fmls.push_back(t); + } + } + virtual void assert_expr(expr * t) { + m_fmls.push_back(t); + } + virtual void set_produce_models(bool f) {} + virtual void collect_param_descrs(param_descrs & r) { + goal2sat::collect_param_descrs(r); + sat::solver::collect_param_descrs(r); + } + virtual void updt_params(params_ref const & p) { + m_params = p; + m_params.set_bool("elim_vars", false); + m_solver.updt_params(m_params); + } + + virtual void collect_statistics(statistics & st) const { + st.copy(m_stats); + } + virtual void get_unsat_core(ptr_vector & r) { + UNREACHABLE(); + } + virtual void get_model(model_ref & m) { + m = m_model; + } + virtual proof * get_proof() { + UNREACHABLE(); + return 0; + } + virtual std::string reason_unknown() const { + return "no reason given"; + } + virtual void get_labels(svector & r) { + UNREACHABLE(); + } + +}; + +solver* mk_inc_sat_solver(ast_manager& m, params_ref& p) { + return alloc(inc_sat_solver, m, p); +} diff --git a/src/opt/opt_sls_solver.h b/src/opt/opt_sls_solver.h index 13f9e99f1..007ade793 100644 --- a/src/opt/opt_sls_solver.h +++ b/src/opt/opt_sls_solver.h @@ -22,6 +22,7 @@ Notes: #include "solver_na2as.h" #include "card2bv_tactic.h" +#include "nnf_tactic.h" #include "pb_sls.h" #include "bvsls_opt_engine.h" diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 7282fdf63..bda19cc8e 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -32,208 +32,15 @@ Notes: #include "pb_sls.h" #include "tactic2solver.h" #include "pb_preprocess_tactic.h" -#include "aig_tactic.h" -#include "simplify_tactic.h" -#include "nnf_tactic.h" -#include "propagate_values_tactic.h" -#include "max_bv_sharing_tactic.h" #include "qfbv_tactic.h" #include "card2bv_tactic.h" -#include "bit_blaster_tactic.h" - #include "opt_sls_solver.h" -#include "sat_solver.h" -#include "goal2sat.h" #define _INC_SAT 0 namespace opt { - static app_ref mk_bv_vec(ast_manager& m, sort* s) { - bv_util bv(m); - expr_ref_vector vars(m); - unsigned sz = bv.get_bv_size(s); - for (unsigned i = 0; i < sz; ++i) { - std::stringstream strm; - strm << "soft_v" << i; - vars.push_back(m.mk_const(symbol(strm.str().c_str()), m.mk_bool_sort())); - } - return app_ref(bv.mk_bv(vars.size(), vars.c_ptr()), m); - } - - // incremental SAT solver. - class inc_sat_solver : public solver { - ast_manager& m; - sat::solver m_solver; - goal2sat m_goal2sat; - params_ref m_params; - expr_ref_vector m_fmls; - atom2bool_var m_map; - model_ref m_model; - model_converter_ref m_mc; - tactic_ref m_preprocess; - statistics m_stats; - app_ref m_soft; - public: - inc_sat_solver(ast_manager& m, params_ref const& p, expr_ref_vector const& soft, vector const& weights): - m(m), m_solver(p,0), m_params(p), - m_fmls(m), m_map(m), m_soft(m) { - m_params.set_bool("elim_vars", false); - m_solver.updt_params(m_params); - params_ref simp2_p = p; - simp2_p.set_bool("som", true); - simp2_p.set_bool("pull_cheap_ite", true); - simp2_p.set_bool("push_ite_bv", false); - simp2_p.set_bool("local_ctx", true); - simp2_p.set_uint("local_ctx_limit", 10000000); - simp2_p.set_bool("flat", true); // required by som - simp2_p.set_bool("hoist_mul", false); // required by som - m_preprocess = - and_then(mk_card2bv_tactic(m, m_params), - mk_simplify_tactic(m), - mk_propagate_values_tactic(m), - using_params(mk_simplify_tactic(m), simp2_p), - mk_max_bv_sharing_tactic(m), - mk_bit_blaster_tactic(m), - mk_aig_tactic()); - - - } - - virtual ~inc_sat_solver() {} - - virtual void set_progress_callback(progress_callback * callback) { - } - virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions) { - SASSERT(num_assumptions == 0); - - m_solver.pop(m_solver.scope_lvl()); - goal_ref_buffer result; - proof_converter_ref pc; - model_converter_ref mc; - expr_dependency_ref core(m); - - if (!m_fmls.empty()) { - goal_ref g = alloc(goal, m); - for (unsigned i = 0; i < m_fmls.size(); ++i) { - g->assert_expr(m_fmls[i].get()); - } - TRACE("opt", g->display(tout);); - m_fmls.reset(); - try { - (*m_preprocess)(g, result, mc, pc, core); - TRACE("opt", result[0]->display(tout);); - } - catch (tactic_exception & ex) { - IF_VERBOSE(0, verbose_stream() << "exception in tactic " << ex.msg() << "\n";); - m_preprocess->collect_statistics(m_stats); - return l_undef; - } - m_mc = concat(m_mc.get(), mc.get()); - if (result.size() != 1) { - IF_VERBOSE(0, verbose_stream() << "size of result is not 1, it is: " << result.size() << "\n";); - return l_undef; - } - g = result[0]; - TRACE("opt", g->display(tout);); - m_goal2sat(*g, m_params, m_solver, m_map); - } - - lbool r = m_solver.check(); - if (r == l_true) { - model_ref md = alloc(model, m); - sat::model const & ll_m = m_solver.get_model(); - atom2bool_var::iterator it = m_map.begin(); - atom2bool_var::iterator end = m_map.end(); - for (; it != end; ++it) { - expr * n = it->m_key; - if (is_app(n) && to_app(n)->get_num_args() > 0) { - IF_VERBOSE(0, verbose_stream() << "skip: " << mk_pp(n, m) << "\n";); - continue; - } - sat::bool_var v = it->m_value; - switch (sat::value_at(v, ll_m)) { - case l_true: - IF_VERBOSE(0, verbose_stream() << "true: " << mk_pp(n, m) << "\n";); - md->register_decl(to_app(n)->get_decl(), m.mk_true()); - break; - case l_false: - IF_VERBOSE(0, verbose_stream() << "false: " << mk_pp(n, m) << "\n";); - md->register_decl(to_app(n)->get_decl(), m.mk_false()); - break; - default: - IF_VERBOSE(0, verbose_stream() << "undef: " << mk_pp(n, m) << "\n";); - break; - } - } - m_model = md; - //if (m_mc) { - // (*m_mc)(m_model); - //} - // IF_VERBOSE(0, model_smt2_pp(verbose_stream(), m, *(m_model.get()), 0);); - } - m_solver.collect_statistics(m_stats); - return r; - } - virtual void set_cancel(bool f) { - m_goal2sat.set_cancel(f); - m_solver.set_cancel(f); - m_preprocess->set_cancel(f); - } - virtual void push() { - IF_VERBOSE(0, verbose_stream() << "push ignored\n";); - } - virtual void pop(unsigned n) { - IF_VERBOSE(0, verbose_stream() << "pop ignored\n";); - } - virtual unsigned get_scope_level() const { - return 0; - } - virtual void assert_expr(expr * t, expr * a) { - if (a) { - m_fmls.push_back(m.mk_implies(a, t)); - } - else { - m_fmls.push_back(t); - } - } - virtual void assert_expr(expr * t) { - m_fmls.push_back(t); - } - virtual void set_produce_models(bool f) {} - virtual void collect_param_descrs(param_descrs & r) { - goal2sat::collect_param_descrs(r); - sat::solver::collect_param_descrs(r); - } - virtual void updt_params(params_ref const & p) { - m_params = p; - m_params.set_bool("elim_vars", false); - m_solver.updt_params(m_params); - } - - virtual void collect_statistics(statistics & st) const { - st.copy(m_stats); - } - virtual void get_unsat_core(ptr_vector & r) { - UNREACHABLE(); - } - virtual void get_model(model_ref & m) { - m = m_model; - } - virtual proof * get_proof() { - UNREACHABLE(); - return 0; - } - virtual std::string reason_unknown() const { - return "no reason given"; - } - virtual void get_labels(svector & r) { - UNREACHABLE(); - } - - }; - // --------------------------------------------- // base class with common utilities used // by maxsmt solvers @@ -357,7 +164,7 @@ namespace opt { void enable_bvsat() { if (m_enable_sat && !m_sat_enabled && probe_bv()) { #if _INC_SAT - solver* sat_solver = alloc(inc_sat_solver, m, m_params, m_soft, m_weights); + solver* sat_solver = mk_inc_sat_solver(m, m_params); #else tactic_ref pb2bv = mk_card2bv_tactic(m, m_params); tactic_ref bv2sat = mk_qfbv_tactic(m, m_params); @@ -781,6 +588,19 @@ namespace opt { virtual ~pbmax() {} #if _INC_SAT + + app_ref mk_bv_vec(sort* s) { + bv_util bv(m); + expr_ref_vector vars(m); + unsigned sz = bv.get_bv_size(s); + for (unsigned i = 0; i < sz; ++i) { + std::stringstream strm; + strm << "soft_v" << i; + vars.push_back(m.mk_const(symbol(strm.str().c_str()), m.mk_bool_sort())); + } + return app_ref(bv.mk_bv(vars.size(), vars.c_ptr()), m); + } + lbool operator()() { enable_bvsat(); enable_sls(); @@ -792,42 +612,38 @@ namespace opt { ); pb_util u(m); bv_util bv(m); - expr_ref bsoft = sls_solver::soft2bv(m_soft, m_weights); - app_ref var(m); - expr_ref fml(m), val(m), soft(m); - app_ref b(m); + expr_ref_vector nsoft(m); + for (unsigned i = 0; i < m_soft.size(); ++i) { + nsoft.push_back(m.mk_not(m_soft[i].get())); + } + expr_ref bsoft = sls_solver::soft2bv(nsoft, m_weights); sort* srt = m.get_sort(bsoft); - var = mk_bv_vec(m, srt); - fml = m.mk_eq(bsoft, var); + app_ref var(m); + expr_ref fml(m), val(m); + var = mk_bv_vec(srt); + unsigned bv_size; ptr_vector sorts; sorts.resize(var->get_num_args(), m.mk_bool_sort()); func_decl_ref fn(m.mk_func_decl(symbol("Soft"), sorts.size(), sorts.c_ptr(), m.mk_bool_sort()), m); - soft = m.mk_app(fn, var->get_num_args(), var->get_args()); - s().assert_expr(fml); - s().assert_expr(soft); - expr_ref_vector nsoft(m); init(); - for (unsigned i = 0; i < m_soft.size(); ++i) { - nsoft.push_back(mk_not(m_soft[i].get())); - } + fml = m.mk_eq(bsoft, var); + s().assert_expr(fml); + fml = m.mk_app(fn, var->get_num_args(), var->get_args()); + s().assert_expr(fml); fml = m.mk_not(bv.mk_ule(bv.mk_numeral(m_upper, m.get_sort(var)), var)); s().assert_expr(fml); lbool is_sat = s().check_sat(0,0); while (l_true == is_sat) { s().get_model(m_model); - TRACE("opt", s().display(tout<<"looping\n"); - model_smt2_pp(tout, m, *(m_model.get()), 0);); + TRACE("opt", model_smt2_pp(tout, m, *(m_model.get()), 0);); m_model->eval(var, val); - unsigned bv_size; VERIFY(bv.is_numeral(val, m_upper, bv_size)); IF_VERBOSE(1, verbose_stream() << "(wmaxsat.pb solve with upper bound: " << m_upper << ")\n";); TRACE("opt", tout << "new upper: " << m_upper << "\n";); fml = m.mk_not(bv.mk_ule(bv.mk_numeral(m_upper, m.get_sort(var)), var)); - // fml = m.mk_not(u.mk_ge(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper)); - // solver::scoped_push _scope2(s()); s().assert_expr(fml); is_sat = s().check_sat(0,0); From 3e1b9876dbbe186add43c6c0fbb29536e71dcb6d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 15 May 2014 17:54:54 -0700 Subject: [PATCH 409/925] fix bug in model generation for COI filter Signed-off-by: Nikolaj Bjorner --- src/muz/transforms/dl_mk_coi_filter.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/muz/transforms/dl_mk_coi_filter.cpp b/src/muz/transforms/dl_mk_coi_filter.cpp index 31af7a53f..c7a8d5aa0 100644 --- a/src/muz/transforms/dl_mk_coi_filter.cpp +++ b/src/muz/transforms/dl_mk_coi_filter.cpp @@ -200,7 +200,23 @@ namespace datalog { func_decl_set::iterator it = pruned_preds.begin(); extension_model_converter* mc0 = alloc(extension_model_converter, m); for (; it != end; ++it) { - mc0->insert(*it, m.mk_true()); + const rule_vector& rules = source.get_predicate_rules(*it); + expr_ref_vector fmls(m); + for (unsigned i = 0; i < rules.size(); ++i) { + app* head = rules[i]->get_head(); + expr_ref_vector conj(m); + unsigned n = head->get_num_args()-1; + for (unsigned j = 0; j < head->get_num_args(); ++j) { + expr* arg = head->get_arg(j); + if (!is_var(arg)) { + conj.push_back(m.mk_eq(m.mk_var(j, m.get_sort(arg)), arg)); + } + } + fmls.push_back(m.mk_and(conj.size(), conj.c_ptr())); + } + expr_ref fml(m); + fml = m.mk_or(fmls.size(), fmls.c_ptr()); + mc0->insert(*it, fml); } m_context.add_model_converter(mc0); } From 698705b7fa9df96a1074638ae3ee9255b88c4280 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 24 May 2014 18:39:43 -0700 Subject: [PATCH 410/925] initial version of HS maxsat Signed-off-by: Nikolaj Bjorner --- src/opt/maxsmt.cpp | 2 +- src/opt/weighted_maxsat.cpp | 841 +++++++++++++++++++++--------------- 2 files changed, 485 insertions(+), 358 deletions(-) diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index dd0171c6a..9da9f9f2e 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -127,7 +127,7 @@ namespace opt { if (!get_assignment(i)) { tmp = m.mk_not(tmp); } - TRACE("opt", tout << "asserting: " << tmp << "\n";); + TRACE("opt", tout << "committing: " << tmp << "\n";); m_s->assert_expr(tmp); } } diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index bda19cc8e..46a5e81fb 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -35,12 +35,24 @@ Notes: #include "qfbv_tactic.h" #include "card2bv_tactic.h" #include "opt_sls_solver.h" - - -#define _INC_SAT 0 +#include "cancel_eh.h" +#include "scoped_timer.h" namespace opt { + class scoped_stopwatch { + double& m_time; + stopwatch m_watch; + public: + scoped_stopwatch(double& time): m_time(time) { + m_watch.start(); + } + ~scoped_stopwatch() { + m_watch.stop(); + m_time += m_watch.get_seconds(); + } + }; + // --------------------------------------------- // base class with common utilities used // by maxsmt solvers @@ -111,9 +123,16 @@ namespace opt { if (!m_assignment.back()) { m_upper += m_weights[i]; } - TRACE("opt", tout << "evaluate: " << val << "\n";); } + + TRACE("opt", + tout << m_upper << ": "; + for (unsigned i = 0; i < m_weights.size(); ++i) { + tout << (m_assignment[i]?"1":"0"); + } + tout << "\n";); } + expr* mk_not(expr* e) { if (m.is_not(e, e)) { return e; @@ -163,14 +182,10 @@ namespace opt { void enable_bvsat() { if (m_enable_sat && !m_sat_enabled && probe_bv()) { -#if _INC_SAT - solver* sat_solver = mk_inc_sat_solver(m, m_params); -#else tactic_ref pb2bv = mk_card2bv_tactic(m, m_params); tactic_ref bv2sat = mk_qfbv_tactic(m, m_params); tactic_ref tac = and_then(pb2bv.get(), bv2sat.get()); solver* sat_solver = mk_tactic2solver(m, tac.get(), m_params); -#endif unsigned sz = s().get_num_assertions(); for (unsigned i = 0; i < sz; ++i) { sat_solver->assert_expr(s().get_assertion(i)); @@ -192,9 +207,7 @@ namespace opt { m_sls_enabled = true; sls->opt(m_model); } - } - - + } }; // ------------------------------------------------------ @@ -575,6 +588,447 @@ namespace opt { } }; + // ---------------------------------- + // MaxSatHS+MSS + // variant of MaxSAT-HS that also refines + // upper bound. Lower-bounds are also + // refined in a partial way + + class hsmax : public maxsmt_solver_base { + struct stats { + stats() { reset(); } + void reset() { memset(this, 0, sizeof(*this)); } + unsigned m_num_iterations; + unsigned m_num_core_reductions_success; + unsigned m_num_core_reductions_failure; + unsigned m_num_model_expansions_success; + unsigned m_num_model_expansions_failure; + double m_core_reduction_time; + double m_model_expansion_time; + double m_aux_sat_time; + }; + + scoped_ptr maxs; + expr_ref_vector m_aux; // auxiliary (indicator) variables. + expr_ref_vector m_naux; // negation of auxiliary variables. + obj_map m_aux2index; // expr |-> index + svector m_seed; // clause selected in current model. + svector m_aux_active; // active soft clauses. + ptr_vector m_asms; // assumptions (over aux) + bool m_partial_check; // last check was partial. + pb_util pb; + stats m_stats; + + + public: + hsmax(solver* s, ast_manager& m, maxsmt_solver_base* maxs): + maxsmt_solver_base(s, m), + maxs(maxs), + m_aux(m), + m_naux(m), + m_partial_check(false), + pb(m) { + } + virtual ~hsmax() {} + + virtual void set_cancel(bool f) { + maxsmt_solver_base::set_cancel(f); + maxs->set_cancel(f); + } + + virtual void collect_statistics(statistics& st) const { + maxsmt_solver_base::collect_statistics(st); + maxs->collect_statistics(st); + st.update("hsmax-num-iterations", m_stats.m_num_iterations); + st.update("hsmax-num-core-reductions-n", m_stats.m_num_core_reductions_failure); + st.update("hsmax-num-core-reductions-y", m_stats.m_num_core_reductions_success); + st.update("hsmax-num-model-expansions-n", m_stats.m_num_model_expansions_failure); + st.update("hsmax-num-model-expansions-y", m_stats.m_num_model_expansions_success); + st.update("hsmax-core-reduction-time", m_stats.m_core_reduction_time); + st.update("hsmax-model-expansion-time", m_stats.m_model_expansion_time); + st.update("hsmax-aux-sat-time", m_stats.m_aux_sat_time); + } + + lbool operator()() { + init(); + init_local(); + lbool is_sat = l_true; + bool is_first = true; + while (is_sat != l_false && m_lower < m_upper) { + ++m_stats.m_num_iterations; + IF_VERBOSE(1, verbose_stream() << + "(wmaxsat.hsmax [" << m_lower << ":" << m_upper << "])\n";); + if (m_cancel) + return l_undef; + switch(is_sat) { + case l_undef: + return l_undef; + case l_false: + m_lower = m_upper; + return l_true; + case l_true: + TRACE("opt", tout << "is_first: " << is_first << "\n";); + if (!is_first) { + is_sat = check_subset(); + } + is_first = false; + switch(is_sat) { + case l_undef: + return l_undef; + case l_true: + if (grow()) + block_down(); + else + return l_undef; + break; + case l_false: + if (shrink()) + block_up(); + else + return l_undef; + break; + } + } + is_sat = next_seed(); + } + m_lower = m_upper; + return l_true; + } + + private: + + unsigned num_soft() const { return m_soft.size(); } + + void init_local() { + unsigned sz = num_soft(); + m_seed.reset(); + m_aux.reset(); + m_naux.reset(); + m_aux_active.reset(); + m_aux2index.reset(); + for (unsigned i = 0; i < sz; ++i) { + bool tt = is_true(m_model, m_soft[i].get()); + m_seed.push_back(tt); + m_aux. push_back(mk_fresh()); + m_naux.push_back(m.mk_not(m_aux.back())); + m_aux_active.push_back(false); + m_aux2index.insert(m_aux[i].get(), i); + if (tt) { + m_asms.push_back(m_aux.back()); + ensure_active(i); + } + } + maxs->init_soft(m_weights, m_aux); + TRACE("opt", print_seed(tout);); + } + + // + // retrieve the next seed that satisfies state of maxs. + // state of maxs must be satisfiable before optimization is called. + // + struct cancel_maxs { + hsmax& hs; + cancel_maxs(hsmax& hs):hs(hs) {} + void reset_cancel() { + hs.maxs->set_cancel(false); + } + void cancel() { + hs.maxs->set_cancel(true); + } + }; + + // + // find some satisfying assignment to maxs state. + // improve it towards lower bound within some resource + // limits (or skip improvement steps all-together, + // to enable improving upper bound more often). + // This is the next satisfying assignment. + // + lbool next_seed() { + scoped_stopwatch _sw(m_stats.m_aux_sat_time); + lbool is_sat = maxs->s().check_sat(0,0); + m_partial_check = true; + if (is_sat == l_true) { + maxs->set_model(); + } + else { + return is_sat; + } + if (false) { + unsigned timeout = 1000; // fixme, make adaptive + cancel_maxs ch(*this); + cancel_eh eh(ch); + { + scoped_timer timer(timeout, &eh); + is_sat = (*maxs)(); + + // revert timeout. + if (is_sat == l_undef && !m_cancel) { + IF_VERBOSE(1, verbose_stream() << "(wmaxsat.opt-timeout)\n";); + TRACE("opt", tout << "(wmaxsat.opt-timeout)\n";); + maxs->set_cancel(false); + is_sat = l_true; + } + else { + m_partial_check = false; + } + } + } + if (is_sat == l_true) { + model_ref mdl; + maxs->get_model(mdl); + for (unsigned i = 0; i < num_soft(); ++i) { + if (is_active(i)) { + m_seed[i] = is_true(mdl, m_aux[i].get()); + } + else { + m_seed[i] = false; + } + } + TRACE("opt", print_seed(tout);); + } + return is_sat; + } + + // + // check assignment returned by maxs with the original + // hard constraints. + // If the assignment is consistent with the hard constraints + // update the current model, otherwise, update the current lower + // bound. + // + lbool check_subset() { + TRACE("opt", tout << "\n";); + m_asms.reset(); + for (unsigned i = 0; i < num_soft(); ++i) { + if (m_seed[i]) { + m_asms.push_back(m_aux[i].get()); + ensure_active(i); + } + } + lbool is_sat = s().check_sat(m_asms.size(), m_asms.c_ptr()); + switch (is_sat) { + case l_true: + update_model(); + break; + case l_false: + if (m_lower < maxs->get_lower()) { + m_lower = maxs->get_lower(); + } + break; + default: + break; + } + TRACE("opt", tout << is_sat << "\n";); + + return is_sat; + } + + // + // extend the current assignment to one that + // satisfies as many soft constraints as possible. + // update the upper bound based on this assignment + // (because maxs has the constraint that the new + // assignment improves the previous m_upper). + // + bool grow() { + m_upper.reset(); + scoped_stopwatch _sw(m_stats.m_model_expansion_time); + for (unsigned i = 0; i < num_soft(); ++i) { + if (!m_seed[i]) { + if (is_true(m_model, m_soft[i].get())) { + m_seed[i] = true; + } + else { + ensure_active(i); + m_asms.push_back(m_aux[i].get()); + lbool is_sat = s().check_sat(m_asms.size(), m_asms.c_ptr()); + IF_VERBOSE(1, verbose_stream() + << "check: " << mk_pp(m_asms.back(), m) + << ":" << is_sat << "\n";); + TRACE("opt", tout + << "check: " << mk_pp(m_asms.back(), m) + << ":" << is_sat << "\n";); + switch(is_sat) { + case l_undef: + return false; + case l_false: + ++m_stats.m_num_model_expansions_failure; + m_upper += m_weights[i]; + m_asms.pop_back(); + break; + case l_true: + ++m_stats.m_num_model_expansions_success; + update_model(); + TRACE("opt", model_smt2_pp(tout << mk_pp(m_aux[i].get(), m) << "\n", + m, *(m_model.get()), 0);); + m_seed[i] = true; + break; + } + } + } + } + //rational old_upper = m_upper; + m_upper.reset(); + for (unsigned i = 0; i < num_soft(); ++i) { + if (!m_seed[i]) { + m_upper += m_weights[i]; + } + } + //SASSERT(old_upper > m_upper); + TRACE("opt", tout << "new upper: " << m_upper << "\n";); + return true; + } + + // remove soft constraints from the current core. + // + bool shrink() { + scoped_stopwatch _sw(m_stats.m_core_reduction_time); + m_asms.reset(); + s().get_unsat_core(m_asms); + return true; // disabled pending configuration experiment. + TRACE("opt", print_asms(tout);); + obj_map asm2index; + for (unsigned i = 0; i < m_asms.size(); ++i) { + asm2index.insert(m_asms[i], i); + } + obj_map::iterator it = asm2index.begin(), end = asm2index.end(); + for (; it != end; ++it) { + unsigned i = it->m_value; + if (i < m_asms.size()) { + expr* tmp = m_asms[i]; + expr* back = m_asms.back(); + m_asms[i] = back; + m_asms.pop_back(); + lbool is_sat = s().check_sat(m_asms.size(), m_asms.c_ptr()); + TRACE("opt", tout << "checking: " << mk_pp(tmp, m) << ": " << is_sat << "\n";); + switch(is_sat) { + case l_true: + ++m_stats.m_num_core_reductions_failure; + // put back literal into core + m_asms.push_back(back); + m_asms[i] = tmp; + break; + case l_false: + // update the core + m_asms.reset(); + ++m_stats.m_num_core_reductions_success; + s().get_unsat_core(m_asms); + TRACE("opt", print_asms(tout);); + update_index(asm2index); + break; + case l_undef: + return false; + } + } + } + return true; + } + + void update_model() { + s().get_model(m_model); + for (unsigned i = 0; i < num_soft(); ++i) { + m_assignment[i] = is_true(m_model, m_soft[i].get()); + } + } + + void print_asms(std::ostream& out) { + for (unsigned j = 0; j < m_asms.size(); ++j) { + out << mk_pp(m_asms[j], m) << " "; + } + out << "\n"; + } + + void print_seed(std::ostream& out) { + for (unsigned i = 0; i < num_soft(); ++i) { + out << (m_seed[i]?"1":"0"); + } + out << "\n"; + } + + // + // must include some literal not from asms. + // furthermore, update upper bound constraint in maxs + // + void block_down() { + uint_set indices; + for (unsigned i = 0; i < m_asms.size(); ++i) { + unsigned index = m_aux2index.find(m_asms[i]); + indices.insert(index); + } + expr_ref_vector fmls(m); + expr_ref fml(m); + for (unsigned i = 0; i < num_soft(); ++i) { + if (!indices.contains(i)) { + fmls.push_back(m_aux[i].get()); + } + } + fml = m.mk_or(fmls.size(), fmls.c_ptr()); + maxs->add_hard(fml); + TRACE("opt", tout << fml << "\n";); + set_upper(); + } + + // constrain the upper bound. + // w1*(not r1) + w2*(not r2) + ... + w_n*(not r_n) < m_upper + void set_upper() { + expr_ref fml(m); + fml = pb.mk_lt(num_soft(), m_weights.c_ptr(), m_naux.c_ptr(), m_upper); + maxs->add_hard(fml); + } + + // should exclude some literal from core. + void block_up() { + expr_ref_vector fmls(m); + expr_ref fml(m); + for (unsigned i = 0; i < m_asms.size(); ++i) { + fmls.push_back(m.mk_not(m_asms[i])); + } + fml = m.mk_or(fmls.size(), fmls.c_ptr()); + TRACE("opt", tout << fml << "\n";); + maxs->add_hard(fml); + } + + + void update_index(obj_map& asm2index) { + obj_map::iterator it = asm2index.begin(), end = asm2index.end(); + for (; it != end; ++it) { + it->m_value = UINT_MAX; + } + for (unsigned i = 0; i < m_asms.size(); ++i) { + asm2index.find(m_asms[i]) = i; + } + } + + app_ref mk_fresh() { + app_ref r(m); + r = m.mk_fresh_const("r", m.mk_bool_sort()); + m_mc->insert(r->get_decl()); + return r; + } + + bool is_true(model_ref& mdl, expr* e) { + expr_ref val(m); + VERIFY(mdl->eval(e, val)); + return m.is_true(val); + } + + bool is_active(unsigned i) const { + return m_aux_active[i]; + } + + void ensure_active(unsigned i) { + if (!is_active(i)) { + expr_ref fml(m); + fml = m.mk_implies(m_aux[i].get(), m_soft[i].get()); + s().assert_expr(fml); + m_aux_active[i] = true; + } + } + + }; + + // ---------------------------------- // incrementally add pseudo-boolean // lower bounds. @@ -587,82 +1041,6 @@ namespace opt { virtual ~pbmax() {} -#if _INC_SAT - - app_ref mk_bv_vec(sort* s) { - bv_util bv(m); - expr_ref_vector vars(m); - unsigned sz = bv.get_bv_size(s); - for (unsigned i = 0; i < sz; ++i) { - std::stringstream strm; - strm << "soft_v" << i; - vars.push_back(m.mk_const(symbol(strm.str().c_str()), m.mk_bool_sort())); - } - return app_ref(bv.mk_bv(vars.size(), vars.c_ptr()), m); - } - - lbool operator()() { - enable_bvsat(); - enable_sls(); - - TRACE("opt", s().display(tout); tout << "\n"; - for (unsigned i = 0; i < m_soft.size(); ++i) { - tout << mk_pp(m_soft[i].get(), m) << " " << m_weights[i] << "\n"; - } - ); - pb_util u(m); - bv_util bv(m); - expr_ref_vector nsoft(m); - for (unsigned i = 0; i < m_soft.size(); ++i) { - nsoft.push_back(m.mk_not(m_soft[i].get())); - } - expr_ref bsoft = sls_solver::soft2bv(nsoft, m_weights); - sort* srt = m.get_sort(bsoft); - app_ref var(m); - expr_ref fml(m), val(m); - var = mk_bv_vec(srt); - unsigned bv_size; - ptr_vector sorts; - sorts.resize(var->get_num_args(), m.mk_bool_sort()); - func_decl_ref fn(m.mk_func_decl(symbol("Soft"), sorts.size(), sorts.c_ptr(), m.mk_bool_sort()), m); - init(); - fml = m.mk_eq(bsoft, var); - s().assert_expr(fml); - fml = m.mk_app(fn, var->get_num_args(), var->get_args()); - s().assert_expr(fml); - fml = m.mk_not(bv.mk_ule(bv.mk_numeral(m_upper, m.get_sort(var)), var)); - s().assert_expr(fml); - - lbool is_sat = s().check_sat(0,0); - while (l_true == is_sat) { - s().get_model(m_model); - TRACE("opt", model_smt2_pp(tout, m, *(m_model.get()), 0);); - - m_model->eval(var, val); - VERIFY(bv.is_numeral(val, m_upper, bv_size)); - IF_VERBOSE(1, verbose_stream() << "(wmaxsat.pb solve with upper bound: " << m_upper << ")\n";); - TRACE("opt", tout << "new upper: " << m_upper << "\n";); - - fml = m.mk_not(bv.mk_ule(bv.mk_numeral(m_upper, m.get_sort(var)), var)); - s().assert_expr(fml); - - is_sat = s().check_sat(0,0); - if (m_cancel) { - is_sat = l_undef; - } - if (is_sat == l_true) { - s().get_model(m_model); - } - } - if (is_sat == l_false) { - is_sat = l_true; - m_lower = m_upper; - } - TRACE("opt", tout << "lower: " << m_lower << "\n";); - return is_sat; - } - -#else lbool operator()() { enable_bvsat(); enable_sls(); @@ -682,11 +1060,11 @@ namespace opt { } lbool is_sat = l_true; while (l_true == is_sat) { - TRACE("opt", s().display(tout<<"looping\n");); + TRACE("opt", s().display(tout<<"looping\n"); + model_smt2_pp(tout << "\n", m, *(m_model.get()), 0);); m_upper.reset(); for (unsigned i = 0; i < m_soft.size(); ++i) { VERIFY(m_model->eval(nsoft[i].get(), val)); - TRACE("opt", tout << "eval " << mk_pp(m_soft[i].get(), m) << " " << val << "\n";); m_assignment[i] = !m.is_true(val); if (!m_assignment[i]) { m_upper += m_weights[i]; @@ -695,7 +1073,7 @@ namespace opt { IF_VERBOSE(1, verbose_stream() << "(wmaxsat.pb solve with upper bound: " << m_upper << ")\n";); TRACE("opt", tout << "new upper: " << m_upper << "\n";); - fml = m.mk_not(u.mk_ge(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper)); + fml = u.mk_lt(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper); solver::scoped_push _scope2(s()); s().assert_expr(fml); is_sat = s().check_sat(0,0); @@ -713,7 +1091,6 @@ namespace opt { TRACE("opt", tout << "lower: " << m_lower << "\n";); return is_sat; } -#endif }; // ------------------------------------------------------ @@ -878,6 +1255,11 @@ namespace opt { maxs->set_cancel(f); } + virtual void collect_statistics(statistics& st) const { + maxsmt_solver_base::collect_statistics(st); + maxs->collect_statistics(st); + } + private: lbool new_bound(expr_ref_vector const& al, vector const& ws, @@ -1077,13 +1459,22 @@ namespace opt { m_maxsmt = alloc(pbmax, s.get(), m); } else if (m_engine == symbol("wpm2")) { - maxsmt_solver_base* s2 = alloc(pbmax, s.get(), m); + ref s0 = alloc(opt_solver, m, m_params, symbol()); + // initialize model. + s0->check_sat(0,0); + maxsmt_solver_base* s2 = alloc(pbmax, s0.get(), m); m_maxsmt = alloc(wpm2, s.get(), m, s2); } else if (m_engine == symbol("bcd2")) { m_maxsmt = alloc(bcd2, s.get(), m); } - // TBD: this is experimental one-round version of SLS + else if (m_engine == symbol("hsmax")) { + ref s0 = alloc(opt_solver, m, m_params, symbol()); + s0->check_sat(0,0); + maxsmt_solver_base* s2 = alloc(pbmax, s0.get(), m); + m_maxsmt = alloc(hsmax, s.get(), m, s2); + } + // NB: this is experimental one-round version of SLS else if (m_engine == symbol("sls")) { m_maxsmt = alloc(sls, s.get(), m); } @@ -1169,267 +1560,3 @@ namespace opt { m_imp->updt_params(p); } }; - - -#if 0 - - /** - Iteratively increase cost until there is an assignment during - final_check that satisfies min_cost. - - Takes: log (n / log(n)) iterations - */ - class iwmax : public maxsmt_solver_wbase { - public: - - iwmax(solver* s, ast_manager& m, smt::context& ctx): maxsmt_solver_wbase(s, m, ctx) {} - virtual ~iwmax() {} - - lbool operator()() { - pb_util - solver::scoped_push _s(s()); - for (unsigned i = 0; i < m_soft.size(); ++i) { - wth().assert_weighted(m_soft[i].get(), m_weights[i]); - } - solver::scoped_push __s(s()); - rational cost = wth().get_min_cost(); - rational log_cost(1), tmp(1); - while (tmp < cost) { - ++log_cost; - tmp *= rational(2); - } - expr_ref_vector bounds(m); - expr_ref bound(m); - lbool result = l_false; - unsigned nsc = 0; - m_upper = cost; - while (result == l_false) { - bound = wth().set_min_cost(log_cost); - s().push(); - ++nsc; - IF_VERBOSE(1, verbose_stream() << "(wmaxsat.iwmax min cost: " << log_cost << ")\n";); - TRACE("opt", tout << "cost: " << log_cost << " " << bound << "\n";); - bounds.push_back(bound); - result = conditional_solve(wth(), bound); - if (result == l_false) { - m_lower = log_cost; - } - if (log_cost > cost) { - break; - } - log_cost *= rational(2); - if (m_cancel) { - result = l_undef; - } - } - s().pop(nsc); - return result; - } - private: - lbool conditional_solve(smt::theory_wmaxsat& wth, expr* cond) { - bool was_sat = false; - lbool is_sat = l_true; - while (l_true == is_sat) { - is_sat = s().check_sat(1,&cond); - if (m_cancel) { - is_sat = l_undef; - } - if (is_sat == l_true) { - if (wth.is_optimal()) { - s().get_model(m_model); - was_sat = true; - } - expr_ref fml = wth.mk_block(); - s().assert_expr(fml); - } - } - if (was_sat) { - wth.get_assignment(m_assignment); - } - if (is_sat == l_false && was_sat) { - is_sat = l_true; - } - if (is_sat == l_true) { - m_lower = m_upper = wth.get_min_cost(); - } - TRACE("opt", tout << "min cost: " << m_upper << " sat: " << is_sat << "\n";); - return is_sat; - } - - }; - - // ------------------------------------------------------ - // Version from CP'13 - lbool wpm2b_solve() { - IF_VERBOSE(1, verbose_stream() << "(wmaxsat.wpm2b solve)\n";); - solver::scoped_push _s(s()); - pb_util u(m); - app_ref fml(m), a(m), b(m), c(m); - expr_ref val(m); - expr_ref_vector block(m), ans(m), am(m), soft(m); - obj_map ans_index; - vector amk; - vector sc; // vector of indices used in at last constraints - expr_ref_vector al(m); // vector of at least constraints. - rational wmax; - init(); - for (unsigned i = 0; i < m_soft.size(); ++i) { - rational w = m_weights[i]; - if (wmax < w) wmax = w; - b = m.mk_fresh_const("b", m.mk_bool_sort()); - block.push_back(b); - expr* bb = b; - s.mc().insert(b->get_decl()); - a = m.mk_fresh_const("a", m.mk_bool_sort()); - s.mc().insert(a->get_decl()); - ans.push_back(a); - ans_index.insert(a, i); - soft.push_back(0); // assert soft constraints lazily. - - c = m.mk_fresh_const("c", m.mk_bool_sort()); - s.mc().insert(c->get_decl()); - fml = m.mk_implies(c, u.mk_le(1,&w,&bb,rational(0))); - s.assert_expr(fml); - - sc.push_back(uint_set()); - sc.back().insert(i); - am.push_back(c); - - al.push_back(u.mk_ge(1,&w,&bb,rational(0))); - s.assert_expr(al.back()); - - amk.push_back(rational(0)); - } - ++wmax; - - while (true) { - enable_soft(soft, block, ans, wmax); - expr_ref_vector asms(m); - asms.append(ans); - asms.append(am); - lbool is_sat = s().check_sat(asms.size(), asms.c_ptr()); - if (m_cancel && is_sat != l_false) { - is_sat = l_undef; - } - if (is_sat == l_undef) { - return l_undef; - } - if (is_sat == l_true && wmax.is_zero()) { - m_upper = m_lower; - updt_model(s); - for (unsigned i = 0; i < block.size(); ++i) { - VERIFY(m_model->eval(block[i].get(), val)); - m_assignment[i] = m.is_false(val); - } - return l_true; - } - if (is_sat == l_true) { - rational W(0); - for (unsigned i = 0; i < m_weights.size(); ++i) { - if (m_weights[i] < wmax) W += m_weights[i]; - } - harden(am, W); - wmax = decrease(wmax); - continue; - } - SASSERT(is_sat == l_false); - ptr_vector core; - s.get_unsat_core(core); - if (core.empty()) { - return l_false; - } - uint_set A; - for (unsigned i = 0; i < core.size(); ++i) { - unsigned j; - if (ans_index.find(core[i], j) && soft[j].get()) { - A.insert(j); - } - } - if (A.empty()) { - return l_false; - } - uint_set B; - rational k; - for (unsigned i = 0; i < sc.size(); ++i) { - uint_set t(sc[i]); - t &= A; - if (!t.empty()) { - B |= sc[i]; - m_lower -= amk[i]; - k += amk[i]; - sc[i] = sc.back(); - sc.pop_back(); - am[i] = am.back(); - am.pop_back(); - amk[i] = amk.back(); - amk.pop_back(); - --i; - } - } - vector ws; - expr_ref_vector bs(m); - for (unsigned i = 0; i < m_soft.size(); ++i) { - if (B.contains(i)) { - ws.push_back(m_weights[i]); - bs.push_back(block[i].get()); - } - } - - expr_ref_vector al2(al); - for (unsigned i = 0; i < s.get_num_assertions(); ++i) { - al2.push_back(s.get_assertion(i)); - } - is_sat = new_bound(al2, ws, bs, k); - if (is_sat != l_true) { - return is_sat; - } - m_lower += k; - expr_ref B_le_k(m), B_ge_k(m); - B_le_k = u.mk_le(ws.size(), ws.c_ptr(), bs.c_ptr(), k); - B_ge_k = u.mk_ge(ws.size(), ws.c_ptr(), bs.c_ptr(), k); - s.assert_expr(B_ge_k); - al.push_back(B_ge_k); - IF_VERBOSE(1, verbose_stream() << "(wmaxsat.wpm2 lower bound: " << m_lower << ")\n";); - IF_VERBOSE(2, verbose_stream() << "New lower bound: " << B_ge_k << "\n";); - - c = m.mk_fresh_const("c", m.mk_bool_sort()); - s.mc().insert(c->get_decl()); - fml = m.mk_implies(c, B_le_k); - s.assert_expr(fml); - sc.push_back(B); - am.push_back(c); - amk.push_back(k); - } - } - - void harden(expr_ref_vector& am, rational const& W) { - // TBD - } - - rational decrease(rational const& wmax) { - rational wmin(0); - for (unsigned i = 0; i < m_weights.size(); ++i) { - rational w = m_weights[i]; - if (w < wmax && wmin < w) wmin = w; - } - return wmin; - } - - - // enable soft constraints that have reached wmax. - void enable_soft(expr_ref_vector& soft, - expr_ref_vector const& block, - expr_ref_vector const& ans, - rational wmax) { - for (unsigned i = 0; i < m_soft.size(); ++i) { - rational w = m_weights[i]; - if (w >= wmax && !soft[i].get()) { - soft[i] = m.mk_or(m_soft[i].get(), block[i], m.mk_not(ans[i])); - s.assert_expr(soft[i].get()); - } - } - } - - - -#endif From e370fbb7eded5087895f5332bcded3b534e8cec8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 27 May 2014 11:38:43 -0700 Subject: [PATCH 411/925] updated maxhs Signed-off-by: Nikolaj Bjorner --- src/opt/weighted_maxsat.cpp | 238 ++++++++++++++++++++++++++---------- 1 file changed, 171 insertions(+), 67 deletions(-) diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 46a5e81fb..b28f36129 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -590,9 +590,10 @@ namespace opt { // ---------------------------------- // MaxSatHS+MSS - // variant of MaxSAT-HS that also refines - // upper bound. Lower-bounds are also - // refined in a partial way + // variant of MaxSAT-HS (Algorithm 9) + // that also refines upper bound during progressive calls + // to the underlying optimization solver for the soft constraints. + // class hsmax : public maxsmt_solver_base { struct stats { @@ -605,17 +606,18 @@ namespace opt { unsigned m_num_model_expansions_failure; double m_core_reduction_time; double m_model_expansion_time; - double m_aux_sat_time; + double m_aux_sat_time; + double m_disjoint_cores_time; }; scoped_ptr maxs; expr_ref_vector m_aux; // auxiliary (indicator) variables. expr_ref_vector m_naux; // negation of auxiliary variables. obj_map m_aux2index; // expr |-> index + unsigned_vector m_core_activity; // number of times soft constraint is used in a core. svector m_seed; // clause selected in current model. svector m_aux_active; // active soft clauses. ptr_vector m_asms; // assumptions (over aux) - bool m_partial_check; // last check was partial. pb_util pb; stats m_stats; @@ -626,7 +628,6 @@ namespace opt { maxs(maxs), m_aux(m), m_naux(m), - m_partial_check(false), pb(m) { } virtual ~hsmax() {} @@ -647,51 +648,50 @@ namespace opt { st.update("hsmax-core-reduction-time", m_stats.m_core_reduction_time); st.update("hsmax-model-expansion-time", m_stats.m_model_expansion_time); st.update("hsmax-aux-sat-time", m_stats.m_aux_sat_time); + st.update("hsmax-disj-core-time", m_stats.m_disjoint_cores_time); } lbool operator()() { + ptr_vector hs; init(); init_local(); - lbool is_sat = l_true; - bool is_first = true; - while (is_sat != l_false && m_lower < m_upper) { + if (!disjoint_cores(hs)) { + return l_undef; + } + seed2assumptions(); + while (m_lower < m_upper) { ++m_stats.m_num_iterations; IF_VERBOSE(1, verbose_stream() << "(wmaxsat.hsmax [" << m_lower << ":" << m_upper << "])\n";); - if (m_cancel) + if (m_cancel) { return l_undef; - switch(is_sat) { + } + lbool core_found = generate_cores(hs); + + switch(core_found) { case l_undef: return l_undef; - case l_false: - m_lower = m_upper; - return l_true; - case l_true: - TRACE("opt", tout << "is_first: " << is_first << "\n";); - if (!is_first) { - is_sat = check_subset(); - } - is_first = false; + case l_true: { + lbool is_sat = next_seed(); switch(is_sat) { - case l_undef: - return l_undef; - case l_true: - if (grow()) - block_down(); - else - return l_undef; + case l_true: + seed2hs(hs); break; case l_false: - if (shrink()) - block_up(); - else - return l_undef; - break; + TRACE("opt", tout << "no more seeds\n";); + m_lower = m_upper; + return l_true; + case l_undef: + return l_undef; } + break; + } + case l_false: + TRACE("opt", tout << "no more cores\n";); + m_lower = m_upper; + return l_true; } - is_sat = next_seed(); } - m_lower = m_upper; return l_true; } @@ -701,17 +701,20 @@ namespace opt { void init_local() { unsigned sz = num_soft(); + m_asms.reset(); m_seed.reset(); m_aux.reset(); m_naux.reset(); m_aux_active.reset(); m_aux2index.reset(); + m_core_activity.reset(); for (unsigned i = 0; i < sz; ++i) { bool tt = is_true(m_model, m_soft[i].get()); m_seed.push_back(tt); m_aux. push_back(mk_fresh()); m_naux.push_back(m.mk_not(m_aux.back())); m_aux_active.push_back(false); + m_core_activity.push_back(0); m_aux2index.insert(m_aux[i].get(), i); if (tt) { m_asms.push_back(m_aux.back()); @@ -722,10 +725,132 @@ namespace opt { TRACE("opt", print_seed(tout);); } + void seed2assumptions() { + m_asms.reset(); + for (unsigned i = 0; i < num_soft(); ++i) { + if (m_seed[i]) { + m_asms.push_back(m_aux[i].get()); + } + } + } + + void hs2seed(ptr_vector const& hs) { + for (unsigned i = 0; i < num_soft(); ++i) { + m_seed[i] = true; + } + for (unsigned i = 0; i < hs.size(); ++i) { + m_seed[m_aux2index.find(hs[i])] = false; + } + } + + void seed2hs(ptr_vector& hs) { + hs.reset(); + for (unsigned i = 0; i < num_soft(); ++i) { + if (!m_seed[i]) { + hs.push_back(m_aux[i].get()); + } + } + } + // - // retrieve the next seed that satisfies state of maxs. - // state of maxs must be satisfiable before optimization is called. + // Find disjoint cores for soft constraints. + // + bool disjoint_cores(ptr_vector& hs) { + scoped_stopwatch _sw(m_stats.m_disjoint_cores_time); + m_asms.reset(); + svector active(num_soft(), true); + rational lower(0); + update_assumptions(active, lower, hs); + SASSERT(lower.is_zero()); + while (true) { + lbool is_sat = s().check_sat(m_asms.size(), m_asms.c_ptr()); + switch (is_sat) { + case l_true: + if (lower > m_lower) { + m_lower = lower; + } + return true; + case l_false: + if (!shrink()) return false; + block_up(); + update_assumptions(active, lower, hs); + break; + case l_undef: + return false; + } + } + } + + void update_assumptions(svector& active, rational& lower, ptr_vector& hs) { + rational arg_min(0); + expr* e = 0; + for (unsigned i = 0; i < m_asms.size(); ++i) { + unsigned index = m_aux2index.find(m_asms[i]); + active[index] = false; + if (arg_min.is_zero() || arg_min > m_weights[index]) { + arg_min = m_weights[index]; + e = m_asms[i]; + } + } + if (e) { + hs.push_back(e); + lower += arg_min; + } + m_asms.reset(); + for (unsigned i = 0; i < num_soft(); ++i) { + if (active[i]) { + m_asms.push_back(m_aux[i].get()); + ensure_active(i); + } + } + } + + // + // Auxiliary Algorithm 10 for producing cores. // + lbool generate_cores(ptr_vector& hs) { + bool core = false; + while (true) { + hs2seed(hs); + lbool is_sat = check_subset(); + switch(is_sat) { + case l_undef: + return l_undef; + case l_true: + if (!grow()) return l_undef; + block_down(); + return core?l_true:l_false; + case l_false: + if (!shrink()) return l_undef; + find_non_optimal_hitting_set(hs); + break; + } + } + } + + struct lt_activity { + hsmax& hs; + lt_activity(hsmax& hs):hs(hs) {} + bool operator()(expr* a, expr* b) const { + unsigned w1 = hs.m_core_activity[hs.m_aux2index.find(a)]; + unsigned w2 = hs.m_core_activity[hs.m_aux2index.find(b)]; + return w1 < w2; + } + }; + + // + // produce the non-optimal hitting set by using the 10% heuristic. + // of most active cores constraints. + // + void find_non_optimal_hitting_set(ptr_vector& hs) { + // m_asms contains the current core. + std::sort(m_asms.begin(), m_asms.end(), lt_activity(*this)); + for (unsigned i = m_asms.size(); i > 9*m_asms.size()/10;) { + --i; + hs.push_back(m_asms[i]); + } + } + struct cancel_maxs { hsmax& hs; cancel_maxs(hsmax& hs):hs(hs) {} @@ -737,43 +862,26 @@ namespace opt { } }; + // - // find some satisfying assignment to maxs state. - // improve it towards lower bound within some resource - // limits (or skip improvement steps all-together, - // to enable improving upper bound more often). - // This is the next satisfying assignment. + // retrieve the next seed that satisfies state of maxs. + // state of maxs must be satisfiable before optimization is called. + // + // + // find a satisfying assignment to maxs state, that + // minimizes objective function. // lbool next_seed() { scoped_stopwatch _sw(m_stats.m_aux_sat_time); lbool is_sat = maxs->s().check_sat(0,0); - m_partial_check = true; if (is_sat == l_true) { maxs->set_model(); } else { return is_sat; } - if (false) { - unsigned timeout = 1000; // fixme, make adaptive - cancel_maxs ch(*this); - cancel_eh eh(ch); - { - scoped_timer timer(timeout, &eh); - is_sat = (*maxs)(); + is_sat = (*maxs)(); - // revert timeout. - if (is_sat == l_undef && !m_cancel) { - IF_VERBOSE(1, verbose_stream() << "(wmaxsat.opt-timeout)\n";); - TRACE("opt", tout << "(wmaxsat.opt-timeout)\n";); - maxs->set_cancel(false); - is_sat = l_true; - } - else { - m_partial_check = false; - } - } - } if (is_sat == l_true) { model_ref mdl; maxs->get_model(mdl); @@ -812,9 +920,6 @@ namespace opt { update_model(); break; case l_false: - if (m_lower < maxs->get_lower()) { - m_lower = maxs->get_lower(); - } break; default: break; @@ -832,7 +937,6 @@ namespace opt { // assignment improves the previous m_upper). // bool grow() { - m_upper.reset(); scoped_stopwatch _sw(m_stats.m_model_expansion_time); for (unsigned i = 0; i < num_soft(); ++i) { if (!m_seed[i]) { @@ -854,7 +958,6 @@ namespace opt { return false; case l_false: ++m_stats.m_num_model_expansions_failure; - m_upper += m_weights[i]; m_asms.pop_back(); break; case l_true: @@ -880,13 +983,13 @@ namespace opt { return true; } + // // remove soft constraints from the current core. // bool shrink() { scoped_stopwatch _sw(m_stats.m_core_reduction_time); m_asms.reset(); s().get_unsat_core(m_asms); - return true; // disabled pending configuration experiment. TRACE("opt", print_asms(tout);); obj_map asm2index; for (unsigned i = 0; i < m_asms.size(); ++i) { @@ -983,6 +1086,7 @@ namespace opt { expr_ref fml(m); for (unsigned i = 0; i < m_asms.size(); ++i) { fmls.push_back(m.mk_not(m_asms[i])); + m_core_activity[m_aux2index.find(m_asms[i])]++; } fml = m.mk_or(fmls.size(), fmls.c_ptr()); TRACE("opt", tout << fml << "\n";); From 2071029bb3b3e990bce8ea88b83e0aa1f79f8250 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 27 May 2014 15:45:33 -0700 Subject: [PATCH 412/925] hsmax Signed-off-by: Nikolaj Bjorner --- src/opt/weighted_maxsat.cpp | 48 ++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index b28f36129..d3816bdaf 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -663,6 +663,7 @@ namespace opt { ++m_stats.m_num_iterations; IF_VERBOSE(1, verbose_stream() << "(wmaxsat.hsmax [" << m_lower << ":" << m_upper << "])\n";); + TRACE("opt", tout << "(wmaxsat.hsmax [" << m_lower << ":" << m_upper << "])\n";); if (m_cancel) { return l_undef; } @@ -675,7 +676,7 @@ namespace opt { lbool is_sat = next_seed(); switch(is_sat) { case l_true: - seed2hs(hs); + seed2hs(false, hs); break; case l_false: TRACE("opt", tout << "no more seeds\n";); @@ -725,14 +726,6 @@ namespace opt { TRACE("opt", print_seed(tout);); } - void seed2assumptions() { - m_asms.reset(); - for (unsigned i = 0; i < num_soft(); ++i) { - if (m_seed[i]) { - m_asms.push_back(m_aux[i].get()); - } - } - } void hs2seed(ptr_vector const& hs) { for (unsigned i = 0; i < num_soft(); ++i) { @@ -741,17 +734,29 @@ namespace opt { for (unsigned i = 0; i < hs.size(); ++i) { m_seed[m_aux2index.find(hs[i])] = false; } + TRACE("opt", + print_asms(tout << "hitting set: ", hs); + print_seed(tout);); } - void seed2hs(ptr_vector& hs) { + void seed2hs(bool pos, ptr_vector& hs) { hs.reset(); for (unsigned i = 0; i < num_soft(); ++i) { - if (!m_seed[i]) { + if (pos == m_seed[i]) { hs.push_back(m_aux[i].get()); } } + TRACE("opt", + print_asms(tout << "hitting set: ", hs); + print_seed(tout);); + } + void seed2assumptions() { + seed2hs(true, m_asms); + } + + // // Find disjoint cores for soft constraints. // @@ -821,7 +826,9 @@ namespace opt { block_down(); return core?l_true:l_false; case l_false: + core = true; if (!shrink()) return l_undef; + block_up(); find_non_optimal_hitting_set(hs); break; } @@ -873,6 +880,7 @@ namespace opt { // lbool next_seed() { scoped_stopwatch _sw(m_stats.m_aux_sat_time); + TRACE("opt", tout << "\n";); lbool is_sat = maxs->s().check_sat(0,0); if (is_sat == l_true) { maxs->set_model(); @@ -990,7 +998,7 @@ namespace opt { scoped_stopwatch _sw(m_stats.m_core_reduction_time); m_asms.reset(); s().get_unsat_core(m_asms); - TRACE("opt", print_asms(tout);); + TRACE("opt", print_asms(tout, m_asms);); obj_map asm2index; for (unsigned i = 0; i < m_asms.size(); ++i) { asm2index.insert(m_asms[i], i); @@ -1017,7 +1025,7 @@ namespace opt { m_asms.reset(); ++m_stats.m_num_core_reductions_success; s().get_unsat_core(m_asms); - TRACE("opt", print_asms(tout);); + TRACE("opt", print_asms(tout, m_asms);); update_index(asm2index); break; case l_undef: @@ -1035,14 +1043,15 @@ namespace opt { } } - void print_asms(std::ostream& out) { - for (unsigned j = 0; j < m_asms.size(); ++j) { - out << mk_pp(m_asms[j], m) << " "; + void print_asms(std::ostream& out, ptr_vector const& asms) { + for (unsigned j = 0; j < asms.size(); ++j) { + out << mk_pp(asms[j], m) << " "; } out << "\n"; } void print_seed(std::ostream& out) { + out << "seed: "; for (unsigned i = 0; i < num_soft(); ++i) { out << (m_seed[i]?"1":"0"); } @@ -1573,9 +1582,10 @@ namespace opt { m_maxsmt = alloc(bcd2, s.get(), m); } else if (m_engine == symbol("hsmax")) { - ref s0 = alloc(opt_solver, m, m_params, symbol()); - s0->check_sat(0,0); - maxsmt_solver_base* s2 = alloc(pbmax, s0.get(), m); + ref s0 = alloc(opt_solver, m, m_params, symbol()); + s0->check_sat(0,0); + maxsmt_solver_base* s2 = alloc(pbmax, s0.get(), m); // , s0->get_context(); + s2->set_converter(s0->mc_ref().get()); m_maxsmt = alloc(hsmax, s.get(), m, s2); } // NB: this is experimental one-round version of SLS From 57fc0f3f552e8a8440cee405bf191b999be69927 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 28 May 2014 15:44:39 -0700 Subject: [PATCH 413/925] bug fixes to min-max, and experiments with hsmax Signed-off-by: Nikolaj Bjorner --- src/opt/weighted_maxsat.cpp | 115 +++++++++++++++++++++++++++++------- src/smt/theory_arith.h | 3 +- src/smt/theory_arith_aux.h | 23 ++++++-- src/smt/theory_arith_inv.h | 12 ++++ 4 files changed, 124 insertions(+), 29 deletions(-) diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index d3816bdaf..c1b22f075 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -37,6 +37,7 @@ Notes: #include "opt_sls_solver.h" #include "cancel_eh.h" #include "scoped_timer.h" +#include "optsmt.h" namespace opt { @@ -611,7 +612,11 @@ namespace opt { }; scoped_ptr maxs; + optsmt m_optsmt; // hitting set optimizer based on simplex. + opt_solver m_solver; + unsigned m_objective; // index of objective expr_ref_vector m_aux; // auxiliary (indicator) variables. + expr_ref_vector m_iaux; // auxiliary integer (indicator) variables. expr_ref_vector m_naux; // negation of auxiliary variables. obj_map m_aux2index; // expr |-> index unsigned_vector m_core_activity; // number of times soft constraint is used in a core. @@ -619,6 +624,7 @@ namespace opt { svector m_aux_active; // active soft clauses. ptr_vector m_asms; // assumptions (over aux) pb_util pb; + arith_util a; stats m_stats; @@ -626,20 +632,30 @@ namespace opt { hsmax(solver* s, ast_manager& m, maxsmt_solver_base* maxs): maxsmt_solver_base(s, m), maxs(maxs), + m_optsmt(m), + m_solver(m, m_params, symbol()), m_aux(m), + m_iaux(m), m_naux(m), - pb(m) { + pb(m), + a(m) { } virtual ~hsmax() {} virtual void set_cancel(bool f) { maxsmt_solver_base::set_cancel(f); - maxs->set_cancel(f); + // maxs->set_cancel(f); + m_optsmt.set_cancel(f); + } + + virtual void updt_params(params_ref& p) { + maxsmt_solver_base::updt_params(p); + m_solver.updt_params(p); } virtual void collect_statistics(statistics& st) const { maxsmt_solver_base::collect_statistics(st); - maxs->collect_statistics(st); + // maxs->s().collect_statistics(st); st.update("hsmax-num-iterations", m_stats.m_num_iterations); st.update("hsmax-num-core-reductions-n", m_stats.m_num_core_reductions_failure); st.update("hsmax-num-core-reductions-y", m_stats.m_num_core_reductions_success); @@ -702,9 +718,12 @@ namespace opt { void init_local() { unsigned sz = num_soft(); + app_ref fml(m), obj(m); + expr_ref_vector sum(m); m_asms.reset(); m_seed.reset(); m_aux.reset(); + m_iaux.reset(); m_naux.reset(); m_aux_active.reset(); m_aux2index.reset(); @@ -712,17 +731,28 @@ namespace opt { for (unsigned i = 0; i < sz; ++i) { bool tt = is_true(m_model, m_soft[i].get()); m_seed.push_back(tt); - m_aux. push_back(mk_fresh()); + m_aux. push_back(mk_fresh(m.mk_bool_sort())); + m_iaux.push_back(mk_fresh(a.mk_int())); + expr* iaux = m_iaux.back(); m_naux.push_back(m.mk_not(m_aux.back())); m_aux_active.push_back(false); m_core_activity.push_back(0); - m_aux2index.insert(m_aux[i].get(), i); + m_aux2index.insert(m_aux.back(), i); + m_aux2index.insert(m_iaux.back(), i); + fml = m.mk_and(a.mk_le(a.mk_numeral(rational::zero(), true), iaux), + a.mk_le(iaux, a.mk_numeral(rational::one(), true))); + rational const& w = m_weights[i]; + sum.push_back(a.mk_mul(a.mk_numeral(w, w.is_int()), iaux)); + m_solver.assert_expr(fml); if (tt) { m_asms.push_back(m_aux.back()); ensure_active(i); } } - maxs->init_soft(m_weights, m_aux); + obj = a.mk_add(sum.size(), sum.c_ptr()); + m_objective = m_optsmt.add(obj); + m_optsmt.setup(m_solver); + // maxs->init_soft(m_weights, m_aux); TRACE("opt", print_seed(tout);); } @@ -858,18 +888,6 @@ namespace opt { } } - struct cancel_maxs { - hsmax& hs; - cancel_maxs(hsmax& hs):hs(hs) {} - void reset_cancel() { - hs.maxs->set_cancel(false); - } - void cancel() { - hs.maxs->set_cancel(true); - } - }; - - // // retrieve the next seed that satisfies state of maxs. // state of maxs must be satisfiable before optimization is called. @@ -881,6 +899,26 @@ namespace opt { lbool next_seed() { scoped_stopwatch _sw(m_stats.m_aux_sat_time); TRACE("opt", tout << "\n";); +#if 1 + m_solver.display(std::cout); + lbool is_sat = m_optsmt.lex(m_objective); + if (is_sat == l_true) { + model_ref mdl; + m_optsmt.get_model(mdl); + + for (unsigned i = 0; i < num_soft(); ++i) { + if (is_active(i)) { + m_seed[i] = is_one(mdl, m_iaux[i].get()); + } + else { + m_seed[i] = false; + } + } + print_seed(std::cout); + TRACE("opt", print_seed(tout);); + } + +#else lbool is_sat = maxs->s().check_sat(0,0); if (is_sat == l_true) { maxs->set_model(); @@ -903,6 +941,7 @@ namespace opt { } TRACE("opt", print_seed(tout);); } +#endif return is_sat; } @@ -1070,6 +1109,16 @@ namespace opt { } expr_ref_vector fmls(m); expr_ref fml(m); +#if 1 + for (unsigned i = 0; i < num_soft(); ++i) { + if (!indices.contains(i)) { + fmls.push_back(m_iaux[i].get()); + } + } + fml = a.mk_ge(a.mk_add(fmls.size(), fmls.c_ptr()), a.mk_numeral(rational::one(), true)); + m_solver.assert_expr(fml); + +#else for (unsigned i = 0; i < num_soft(); ++i) { if (!indices.contains(i)) { fmls.push_back(m_aux[i].get()); @@ -1077,8 +1126,9 @@ namespace opt { } fml = m.mk_or(fmls.size(), fmls.c_ptr()); maxs->add_hard(fml); +#endif TRACE("opt", tout << fml << "\n";); - set_upper(); + // set_upper(); } // constrain the upper bound. @@ -1093,13 +1143,25 @@ namespace opt { void block_up() { expr_ref_vector fmls(m); expr_ref fml(m); +#if 1 for (unsigned i = 0; i < m_asms.size(); ++i) { + unsigned index = m_aux2index.find(m_asms[i]); + m_core_activity[index]++; + fmls.push_back(m_iaux[index].get()); + } + fml = a.mk_lt(a.mk_add(fmls.size(), fmls.c_ptr()), a.mk_numeral(rational(fmls.size()), true)); + TRACE("opt", tout << fml << "\n";); + m_solver.assert_expr(fml); +#else + for (unsigned i = 0; i < m_asms.size(); ++i) { + unsigned index = m_aux2index.find(m_asms[i]); fmls.push_back(m.mk_not(m_asms[i])); - m_core_activity[m_aux2index.find(m_asms[i])]++; + m_core_activity[index]++; } fml = m.mk_or(fmls.size(), fmls.c_ptr()); TRACE("opt", tout << fml << "\n";); maxs->add_hard(fml); +#endif } @@ -1113,19 +1175,28 @@ namespace opt { } } - app_ref mk_fresh() { + app_ref mk_fresh(sort* s) { app_ref r(m); - r = m.mk_fresh_const("r", m.mk_bool_sort()); + r = m.mk_fresh_const("r", s); m_mc->insert(r->get_decl()); return r; } + bool is_true(model_ref& mdl, expr* e) { expr_ref val(m); VERIFY(mdl->eval(e, val)); return m.is_true(val); } + bool is_one(model_ref& mdl, expr* e) { + rational r; + expr_ref val(m); + VERIFY(mdl->eval(e, val)); + std::cout << mk_pp(e, m) << " |-> " << val << "\n"; + return a.is_numeral(val, r) && r.is_one(); + } + bool is_active(unsigned i) const { return m_aux_active[i]; } diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 2e8c62393..0ddaf67d9 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -857,7 +857,7 @@ namespace smt { void add_tmp_row(row & r1, numeral const & coeff, row const & r2); theory_var pick_var_to_leave(bool has_int, theory_var x_j, bool inc, numeral & a_ij, inf_numeral & gain, bool& skiped_row); bool is_safe_to_leave(theory_var x, bool& has_int); - void move_to_bound(theory_var x_i, bool inc); + bool move_to_bound(theory_var x_i, bool inc); template void add_tmp_row_entry(row & r, numeral const & coeff, theory_var v); enum max_min_t { UNBOUNDED, AT_BOUND, OPTIMIZED, BEST_EFFORT}; @@ -1061,6 +1061,7 @@ namespace smt { bool valid_row_assignment() const; bool valid_row_assignment(row const & r) const; bool satisfy_bounds() const; + bool satisfy_integrality() const; #endif }; diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 7a84b3a8b..1e2a6c238 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -1069,7 +1069,7 @@ namespace smt { template inf_eps_rational theory_arith::maximize(theory_var v, expr_ref& blocker) { - TRACE("opt", tout << "data-size: " << m_data.size() << "\n";); + TRACE("bound_bug", display_var(tout, v); display(tout);); max_min_t r = max_min(v, true); if (r == UNBOUNDED) { blocker = get_manager().mk_false(); @@ -1361,7 +1361,8 @@ namespace smt { } } TRACE("opt", tout << "after traversing row:\nx_i: v" << x_i << ", x_j: v" << x_j << ", gain: " << gain << "\n"; - tout << "skipped row: " << (skipped_row?"yes":"no") << "\n";); + tout << "skipped row: " << (skipped_row?"yes":"no") << "\n"; + display(tout);); if (x_j == null_theory_var) { TRACE("opt", tout << "row is " << (max ? "maximized" : "minimized") << "\n";); @@ -1378,6 +1379,7 @@ namespace smt { TRACE("opt", tout << "moved v" << x_j << " to upper bound\n";); SASSERT(valid_row_assignment()); SASSERT(satisfy_bounds()); + SASSERT(satisfy_integrality()); continue; } if (!inc && lower(x_j)) { @@ -1385,13 +1387,14 @@ namespace smt { TRACE("opt", tout << "moved v" << x_j << " to lower bound\n";); SASSERT(valid_row_assignment()); SASSERT(satisfy_bounds()); + SASSERT(satisfy_integrality()); continue; } result = skipped_row?BEST_EFFORT:UNBOUNDED; break; } - if (!is_fixed(x_j) && is_bounded(x_j) && (upper_bound(x_j) - lower_bound(x_j) <= gain)) { + if (!is_fixed(x_j) && is_bounded(x_j) && !skipped_row && (upper_bound(x_j) - lower_bound(x_j) <= gain)) { // can increase/decrease x_j up to upper/lower bound. if (inc) { update_value(x_j, upper_bound(x_j) - get_value(x_j)); @@ -1403,6 +1406,7 @@ namespace smt { } SASSERT(valid_row_assignment()); SASSERT(satisfy_bounds()); + SASSERT(satisfy_integrality()); continue; } @@ -1425,7 +1429,10 @@ namespace smt { move_xi_to_lower = a_ij.is_pos(); else move_xi_to_lower = a_ij.is_neg(); - move_to_bound(x_i, move_xi_to_lower); + if (!move_to_bound(x_i, move_xi_to_lower)) { + result = BEST_EFFORT; + break; + } row & r2 = m_rows[get_var_row(x_j)]; coeff.neg(); @@ -1433,6 +1440,7 @@ namespace smt { SASSERT(r.get_idx_of(x_j) == -1); SASSERT(valid_row_assignment()); SASSERT(satisfy_bounds()); + SASSERT(satisfy_integrality()); } TRACE("opt", display(tout);); return result; @@ -1444,7 +1452,7 @@ namespace smt { */ template - void theory_arith::move_to_bound(theory_var x_i, bool move_to_lower) { + bool theory_arith::move_to_bound(theory_var x_i, bool move_to_lower) { inf_numeral delta, delta_abs; if (move_to_lower) { @@ -1484,6 +1492,9 @@ namespace smt { } } + if (is_int(x_i)) { + delta_abs = floor(delta_abs); + } if (move_to_lower) { delta = -delta_abs; @@ -1493,8 +1504,8 @@ namespace smt { } TRACE("opt", tout << "Safe delta: " << delta << "\n";); - update_value(x_i, delta); + return !delta.is_zero(); } /** diff --git a/src/smt/theory_arith_inv.h b/src/smt/theory_arith_inv.h index 80bb9307f..f6270e664 100644 --- a/src/smt/theory_arith_inv.h +++ b/src/smt/theory_arith_inv.h @@ -199,6 +199,18 @@ namespace smt { } return true; } + + template + bool theory_arith::satisfy_integrality() const { + int num = get_num_vars(); + for (theory_var v = 0; v < num; v++) { + if (!(is_int(v) && get_value(v).is_int())) { + TRACE("bound_bug", display_var(tout, v); display(tout);); + return false; + } + } + return true; + } #endif }; From 4415df3fcf7dcf7108f03a27035b8f4e6a0b8b10 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 2 Jun 2014 19:10:20 +0530 Subject: [PATCH 414/925] various fixes Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.cpp | 1 + src/muz/rel/dl_product_relation.cpp | 6 +- src/opt/opt_cmds.cpp | 2 +- src/opt/opt_context.cpp | 67 ++++++++-------------- src/opt/opt_context.h | 3 +- src/opt/weighted_maxsat.cpp | 87 +++++++++++++++++++---------- 6 files changed, 89 insertions(+), 77 deletions(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 4373ee33a..a76933912 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1372,6 +1372,7 @@ void cmd_context::check_sat(unsigned num_assumptions, expr * const * assumptions while (r == l_true && get_opt()->is_pareto()) { was_pareto = true; get_opt()->display_assignment(regular_stream()); + regular_stream() << "\n"; r = get_opt()->optimize(); } } diff --git a/src/muz/rel/dl_product_relation.cpp b/src/muz/rel/dl_product_relation.cpp index 48cd666e6..b66e4d47d 100644 --- a/src/muz/rel/dl_product_relation.cpp +++ b/src/muz/rel/dl_product_relation.cpp @@ -184,8 +184,10 @@ namespace datalog { } relation_base * product_relation_plugin::mk_full(func_decl* p, const relation_signature & s, family_id kind) { - if (kind == null_family_id) { - return alloc(product_relation, *this, s); + if (kind == null_family_id || !m_spec_store.contains_signature(s)) { + product_relation* result = alloc(product_relation, *this, s); + result->m_default_empty = false; + return result; } rel_spec spec; m_spec_store.get_relation_spec(s, kind, spec); diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index 42d749cb6..537f4bf22 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -269,6 +269,7 @@ public: if (r == l_true && opt.is_pareto()) { while (r == l_true) { display_result(ctx); + ctx.regular_stream() << "\n"; r = opt.optimize(); } if (p.get_bool("print_statistics", false)) { @@ -314,7 +315,6 @@ public: if (mdl) { ctx.regular_stream() << "(model " << std::endl; model_smt2_pp(ctx.regular_stream(), ctx, *(mdl.get()), 2); - // m->display(ctx.regular_stream()); ctx.regular_stream() << ")" << std::endl; } } diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 1ad9909ad..b8eeb0d09 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -42,6 +42,7 @@ namespace opt { void context::scoped_state::push() { m_hard_lim.push_back(m_hard.size()); m_objectives_lim.push_back(m_objectives.size()); + m_objectives_term_trail_lim.push_back(m_objectives_term_trail.size()); } void context::scoped_state::pop() { @@ -372,48 +373,10 @@ namespace opt { void context::yield() { m_pareto->get_model(m_model); - update_lower(true); - for (unsigned i = 0; i < m_objectives.size(); ++i) { - objective const& obj = m_objectives[i]; - switch(obj.m_type) { - case O_MINIMIZE: - case O_MAXIMIZE: - m_optsmt.update_upper(obj.m_index, m_optsmt.get_lower(obj.m_index), true); - break; - case O_MAXSMT: { - rational r = m_maxsmts.find(obj.m_id)->get_lower(); - m_maxsmts.find(obj.m_id)->update_upper(r, true); - break; - } - } - } + update_bound(true, true); + update_bound(true, false); } - -#if 0 - // use PB - expr_ref mk_pb_cmp(objective const& obj, model_ref& mdl, bool is_ge) { - rational r, sum(0); - expr_ref val(m), result(m); - unsigned sz = obj.m_terms.size(); - pb_util pb(m); - - for (unsigned i = 0; i < sz; ++i) { - expr* t = obj.m_terms[i]; - VERIFY(mdl->eval(t, val)); - if (m.is_true(val)) { - sum += r; - } - } - if (is_ge) { - result = pb.mk_ge(obj.m_terms.size(), obj.m_weights.c_ptr(), obj.m_terms.c_ptr(), r); - } - else { - result = pb.mk_le(obj.m_terms.size(), obj.m_weights.c_ptr(), obj.m_terms.c_ptr(), r); - } - } -#endif - lbool context::execute_pareto() { if (!m_pareto) { m_pareto = alloc(gia_pareto, m, *this, m_solver.get(), m_params); @@ -761,7 +724,7 @@ namespace opt { } } - void context::update_lower(bool override) { + void context::update_bound(bool override, bool is_lower) { expr_ref val(m); for (unsigned i = 0; i < m_objectives.size(); ++i) { objective const& obj = m_objectives[i]; @@ -770,18 +733,27 @@ namespace opt { case O_MINIMIZE: if (m_model->eval(obj.m_term, val) && is_numeral(val, r)) { r += obj.m_offset; - m_optsmt.update_lower(obj.m_index, inf_eps(-r), override); + if (is_lower) { + m_optsmt.update_lower(obj.m_index, inf_eps(-r), override); + } + else { + m_optsmt.update_upper(obj.m_index, inf_eps(-r), override); + } } break; case O_MAXIMIZE: if (m_model->eval(obj.m_term, val) && is_numeral(val, r)) { r += obj.m_offset; - m_optsmt.update_lower(obj.m_index, inf_eps(r), override); + if (is_lower) { + m_optsmt.update_lower(obj.m_index, inf_eps(r), override); + } + else { + m_optsmt.update_upper(obj.m_index, inf_eps(r), override); + } } break; case O_MAXSMT: { bool ok = true; - r = obj.m_offset; for (unsigned j = 0; ok && j < obj.m_terms.size(); ++j) { if (m_model->eval(obj.m_terms[j], val)) { if (!m.is_true(val)) { @@ -793,7 +765,12 @@ namespace opt { } } if (ok) { - m_maxsmts.find(obj.m_id)->update_upper(r, override); + if (is_lower) { + m_maxsmts.find(obj.m_id)->update_upper(r, override); + } + else { + m_maxsmts.find(obj.m_id)->update_lower(r, override); + } } break; } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 18d6d3745..1f7eb55af 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -192,7 +192,8 @@ namespace opt { void from_fmls(expr_ref_vector const& fmls); void simplify_fmls(expr_ref_vector& fmls); - void update_lower(bool override); + void update_lower(bool override) { update_bound(override, true); } + void update_bound(bool override, bool is_lower); inf_eps get_lower_as_num(unsigned idx); inf_eps get_upper_as_num(unsigned idx); diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index c1b22f075..6c4bbc1b4 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -39,6 +39,8 @@ Notes: #include "scoped_timer.h" #include "optsmt.h" +#define USE_SIMPLEX 0 + namespace opt { class scoped_stopwatch { @@ -644,7 +646,7 @@ namespace opt { virtual void set_cancel(bool f) { maxsmt_solver_base::set_cancel(f); - // maxs->set_cancel(f); + maxs->set_cancel(f); m_optsmt.set_cancel(f); } @@ -655,7 +657,7 @@ namespace opt { virtual void collect_statistics(statistics& st) const { maxsmt_solver_base::collect_statistics(st); - // maxs->s().collect_statistics(st); + maxs->s().collect_statistics(st); st.update("hsmax-num-iterations", m_stats.m_num_iterations); st.update("hsmax-num-core-reductions-n", m_stats.m_num_core_reductions_failure); st.update("hsmax-num-core-reductions-y", m_stats.m_num_core_reductions_success); @@ -738,21 +740,26 @@ namespace opt { m_aux_active.push_back(false); m_core_activity.push_back(0); m_aux2index.insert(m_aux.back(), i); +#if USE_SIMPLEX m_aux2index.insert(m_iaux.back(), i); fml = m.mk_and(a.mk_le(a.mk_numeral(rational::zero(), true), iaux), a.mk_le(iaux, a.mk_numeral(rational::one(), true))); rational const& w = m_weights[i]; sum.push_back(a.mk_mul(a.mk_numeral(w, w.is_int()), iaux)); m_solver.assert_expr(fml); +#endif if (tt) { m_asms.push_back(m_aux.back()); ensure_active(i); } } +#if USE_SIMPLEX obj = a.mk_add(sum.size(), sum.c_ptr()); m_objective = m_optsmt.add(obj); m_optsmt.setup(m_solver); - // maxs->init_soft(m_weights, m_aux); +#else + maxs->init_soft(m_weights, m_aux); +#endif TRACE("opt", print_seed(tout);); } @@ -878,9 +885,9 @@ namespace opt { // // produce the non-optimal hitting set by using the 10% heuristic. // of most active cores constraints. + // m_asms contains the current core. // void find_non_optimal_hitting_set(ptr_vector& hs) { - // m_asms contains the current core. std::sort(m_asms.begin(), m_asms.end(), lt_activity(*this)); for (unsigned i = m_asms.size(); i > 9*m_asms.size()/10;) { --i; @@ -899,7 +906,7 @@ namespace opt { lbool next_seed() { scoped_stopwatch _sw(m_stats.m_aux_sat_time); TRACE("opt", tout << "\n";); -#if 1 +#if USE_SIMPLEX m_solver.display(std::cout); lbool is_sat = m_optsmt.lex(m_objective); if (is_sat == l_true) { @@ -919,7 +926,27 @@ namespace opt { } #else - lbool is_sat = maxs->s().check_sat(0,0); + + // min c_i*(not x_i) for x_i are soft clauses. + // max c_i*x_i for x_i are soft clauses + + lbool is_sat = l_true; + if (m_lower.is_pos()) { + expr_ref fml(m); + solver::scoped_push _scope(maxs->s()); + fml = pb.mk_le(num_soft(), m_weights.c_ptr(), m_naux.c_ptr(), m_lower); + maxs->add_hard(fml); + //fml = pb.mk_ge(num_soft(), m_weights.c_ptr(), m_naux.c_ptr(), m_lower); + //maxs->add_hard(fml); + std::cout << fml << "\n"; + is_sat = maxs->s().check_sat(0,0); + if (is_sat == l_true) { + maxs->set_model(); + extract_seed(); + return l_true; + } + } + is_sat = maxs->s().check_sat(0,0); if (is_sat == l_true) { maxs->set_model(); } @@ -927,24 +954,27 @@ namespace opt { return is_sat; } is_sat = (*maxs)(); - + if (is_sat == l_true) { - model_ref mdl; - maxs->get_model(mdl); - for (unsigned i = 0; i < num_soft(); ++i) { - if (is_active(i)) { - m_seed[i] = is_true(mdl, m_aux[i].get()); - } - else { - m_seed[i] = false; - } - } - TRACE("opt", print_seed(tout);); + extract_seed(); } #endif return is_sat; } + void extract_seed() { + model_ref mdl; + maxs->get_model(mdl); + m_lower.reset(); + for (unsigned i = 0; i < num_soft(); ++i) { + m_seed[i] = is_active(i) && is_true(mdl, m_aux[i].get()); + if (!m_seed[i]) { + m_lower += m_weights[i]; + } + } + TRACE("opt", print_seed(tout);); + } + // // check assignment returned by maxs with the original // hard constraints. @@ -1018,15 +1048,16 @@ namespace opt { } } } - //rational old_upper = m_upper; - m_upper.reset(); + rational upper(0); for (unsigned i = 0; i < num_soft(); ++i) { if (!m_seed[i]) { - m_upper += m_weights[i]; + upper += m_weights[i]; } - } - //SASSERT(old_upper > m_upper); - TRACE("opt", tout << "new upper: " << m_upper << "\n";); + } + if (upper < m_upper) { + m_upper = upper; + TRACE("opt", tout << "new upper: " << m_upper << "\n";); + } return true; } @@ -1109,7 +1140,7 @@ namespace opt { } expr_ref_vector fmls(m); expr_ref fml(m); -#if 1 +#if USE_SIMPLEX for (unsigned i = 0; i < num_soft(); ++i) { if (!indices.contains(i)) { fmls.push_back(m_iaux[i].get()); @@ -1126,9 +1157,9 @@ namespace opt { } fml = m.mk_or(fmls.size(), fmls.c_ptr()); maxs->add_hard(fml); + set_upper(); #endif TRACE("opt", tout << fml << "\n";); - // set_upper(); } // constrain the upper bound. @@ -1143,7 +1174,7 @@ namespace opt { void block_up() { expr_ref_vector fmls(m); expr_ref fml(m); -#if 1 +#if USE_SIMPLEX for (unsigned i = 0; i < m_asms.size(); ++i) { unsigned index = m_aux2index.find(m_asms[i]); m_core_activity[index]++; @@ -1655,7 +1686,7 @@ namespace opt { else if (m_engine == symbol("hsmax")) { ref s0 = alloc(opt_solver, m, m_params, symbol()); s0->check_sat(0,0); - maxsmt_solver_base* s2 = alloc(pbmax, s0.get(), m); // , s0->get_context(); + maxsmt_solver_base* s2 = alloc(pbmax, s0.get(), m); // , s0->get_context()); s2->set_converter(s0->mc_ref().get()); m_maxsmt = alloc(hsmax, s.get(), m, s2); } From 5427964c54ced9c3b4dfd0eff854005ee9be5bb3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 14 Jun 2014 14:08:55 -0700 Subject: [PATCH 415/925] use approximate hitting set implementation Signed-off-by: Nikolaj Bjorner --- src/opt/hitting_sets.cpp | 250 +++++++++++++++++++++++++++++++---- src/opt/hitting_sets.h | 10 +- src/opt/weighted_maxsat.cpp | 145 +++++--------------- src/sat/sat_asymm_branch.cpp | 2 +- src/sat/sat_asymm_branch.h | 2 +- src/sat/sat_cleaner.cpp | 2 +- src/sat/sat_cleaner.h | 2 +- src/sat/sat_probing.cpp | 2 +- src/sat/sat_probing.h | 2 +- src/sat/sat_scc.cpp | 2 +- src/sat/sat_scc.h | 2 +- src/sat/sat_simplifier.cpp | 2 +- src/sat/sat_simplifier.h | 2 +- src/sat/sat_solver.cpp | 2 +- src/sat/sat_solver.h | 2 +- 15 files changed, 273 insertions(+), 156 deletions(-) diff --git a/src/opt/hitting_sets.cpp b/src/opt/hitting_sets.cpp index 7ef2eadc6..62b36961b 100644 --- a/src/opt/hitting_sets.cpp +++ b/src/opt/hitting_sets.cpp @@ -22,6 +22,7 @@ Notes: #include "simplex.h" #include "sparse_matrix_def.h" #include "simplex_def.h" +#include "sat_solver.h" typedef simplex::simplex Simplex; typedef simplex::sparse_matrix sparse_matrix; @@ -38,15 +39,26 @@ namespace opt { rational m_max_weight; rational m_denominator; vector m_S; + vector m_T; svector m_value; + svector m_value_saved; unsigned_vector m_value_trail; unsigned_vector m_value_lim; - vector m_use_list; + vector m_tuse_list; + vector m_fuse_list; unsynch_mpz_manager m; Simplex m_simplex; unsigned m_weights_var; - imp():m_cancel(false) {} + params_ref m_params; + sat::solver m_solver; + svector m_vars; + + imp(): + m_cancel(false), + m_max_weight(0), + m_weights_var(0), + m_solver(m_params,0) {} ~imp() {} void add_weight(rational const& w) { @@ -57,28 +69,56 @@ namespace opt { m_simplex.set_upper(var, mpq_inf(mpq(1),mpq(0))); m_weights.push_back(w); m_value.push_back(l_undef); - m_use_list.push_back(unsigned_vector()); + m_tuse_list.push_back(unsigned_vector()); + m_fuse_list.push_back(unsigned_vector()); m_max_weight += w; + m_vars.push_back(m_solver.mk_var()); } - void add_set(unsigned sz, unsigned const* S) { - if (sz == 0) { - return; - } + void add_exists_false(unsigned sz, unsigned const* S) { + SASSERT(sz > 0); for (unsigned i = 0; i < sz; ++i) { - m_use_list[S[i]].push_back(m_S.size()); + m_fuse_list[S[i]].push_back(m_T.size()); + } + init_weights(); + m_T.push_back(unsigned_vector(sz, S)); + add_simplex_row(false, sz, S); + // Add clause to SAT solver: + svector lits; + for (unsigned i = 0; i < sz; ++i) { + lits.push_back(sat::literal(m_vars[S[i]], true)); + } + m_solver.mk_clause(lits.size(), lits.c_ptr()); + } + + void add_exists_true(unsigned sz, unsigned const* S) { + SASSERT(sz > 0); + for (unsigned i = 0; i < sz; ++i) { + m_tuse_list[S[i]].push_back(m_S.size()); } init_weights(); m_S.push_back(unsigned_vector(sz, S)); - add_simplex_row(sz, S); + add_simplex_row(true, sz, S); + + // Add clause to SAT solver + svector lits; + for (unsigned i = 0; i < sz; ++i) { + lits.push_back(sat::literal(m_vars[S[i]], false)); + } + m_solver.mk_clause(lits.size(), lits.c_ptr()); } - bool compute_lower() { + lbool compute_lower() { m_lower.reset(); - return L1() && L2() && L3(); + if (L1() && L2() && L3()) { + return l_true; + } + else { + return l_undef; + } } - bool compute_upper() { + lbool compute_upper() { m_upper = m_max_weight; return U1(); } @@ -91,18 +131,30 @@ namespace opt { return m_upper/m_denominator; } + void set_upper(rational const& r) { + m_max_weight = r; + } + + bool get_value(unsigned idx) { + return + idx < m_value_saved.size() && + m_value_saved[idx] == l_true; + } + void set_cancel(bool f) { m_cancel = f; m_simplex.set_cancel(f); + m_solver.set_cancel(f); } void collect_statistics(::statistics& st) const { m_simplex.collect_statistics(st); + m_solver.collect_statistics(st); } void reset() { m_lower.reset(); - m_upper = m_max_weight; + m_upper = m_max_weight; } void init_weights() { @@ -135,6 +187,25 @@ namespace opt { m_simplex.add_row(m_weights_var, coeffs.size(), vars.c_ptr(), coeffs.c_ptr()); } + void display(std::ostream& out) const { + for (unsigned i = 0; i < m_weights.size(); ++i) { + out << i << ": " << m_value_saved[i]<< " " << m_weights[i] << "\n"; + } + for (unsigned i = 0; i < m_S.size(); ++i) { + display(out << "+ ", m_S[i]); + } + for (unsigned i = 0; i < m_T.size(); ++i) { + display(out << "- ", m_T[i]); + } + } + + void display(std::ostream& out, set const& S) const { + for (unsigned i = 0; i < S.size(); ++i) { + out << S[i] << " "; + } + out << "\n"; + } + struct scoped_select { imp& s; unsigned sz; @@ -164,9 +235,67 @@ namespace opt { } }; + lbool U1() { + scoped_select _sc(*this); + while (true) { + if (!compute_U1()) return l_undef; + unsigned i = 0, j = 0; + set_undef_to_false(); + if (values_satisfy_Ts(i)) { + return l_true; + } + + // + // pick some unsatisfied clause from m_T, + // and set the value of the most expensive + // literal to true. + // + + IF_VERBOSE(1, verbose_stream() << "(hs.refining exclusion set " << i << "\n";); + set const& T = m_T[i]; + rational max_value(0); + j = 0; + for (i = 0; i < T.size(); ++i) { + SASSERT(m_value_saved[T[i]] == l_true); + if (max_value < m_weights[T[i]]) { + max_value = m_weights[T[i]]; + j = T[i]; + } + } + IF_VERBOSE(1, verbose_stream() << "(hs.unselect " << j << ")\n";); + unselect(j); + for (i = 0; i < m_S.size(); ++i) { + set const& S = m_S[i]; + for (j = 0; j < S.size(); ++j) { + if (l_false != selected(S[j])) break; + } + if (j == S.size()) { + IF_VERBOSE(1, verbose_stream() << "approximation failed, fall back to SAT\n";); + return compute_U2(); + } + } + TRACE("opt", display(tout);); + } + } + + lbool compute_U2() { + lbool is_sat = m_solver.check(); + if (is_sat == l_true) { + sat::model const& model = m_solver.get_model(); + m_value_saved.reset(); + m_upper.reset(); + for (unsigned i = 0; i < m_vars.size(); ++i) { + m_value_saved.push_back(model[m_vars[i]]); + if (model[m_vars[i]] == l_true) { + m_upper += m_weights[i]; + } + } + } + return is_sat; + } // compute upper bound for hitting set. - bool U1() { + bool compute_U1() { rational w(0); scoped_select _sc(*this); @@ -177,7 +306,7 @@ namespace opt { // // Sort indices. - // The least literals are those where -score/w is minimized. + // The least literals are those where score/w is maximized. // unsigned_vector indices; for (unsigned i = 0; i < m_value.size(); ++i) { @@ -194,8 +323,11 @@ namespace opt { select(idx); w += m_weights[idx]; } - if (w < m_upper) { - m_upper = w; + m_upper = w; + m_value_saved.reset(); + m_value_saved.append(m_value); + if (m_upper > m_max_weight) { + IF_VERBOSE(0, verbose_stream() << "got worse upper bound\n";); } return !m_cancel; } @@ -209,19 +341,23 @@ namespace opt { set const& S = m_S[i]; if (!has_selected(S)) { for (unsigned j = 0; j < S.size(); ++j) { - scores[S[j]]++; + if (selected(S[j]) != l_false) { + scores[S[j]]++; + } } } } } void update_scores(unsigned_vector& scores, unsigned v) { - unsigned_vector const& v_uses = m_use_list[v]; + unsigned_vector const& v_uses = m_tuse_list[v]; for (unsigned i = 0; i < v_uses.size(); ++i) { set const& S = m_S[v_uses[i]]; if (!has_selected(S)) { for (unsigned j = 0; j < S.size(); ++j) { - --scores[S[j]]; + if (selected(S[j]) != l_false) { + --scores[S[j]]; + } } } } @@ -300,20 +436,26 @@ namespace opt { return true; } - void add_simplex_row(unsigned sz, unsigned const* S) { + void add_simplex_row(bool is_some_true, unsigned sz, unsigned const* S) { unsigned_vector vars; scoped_mpz_vector coeffs(m); for (unsigned i = 0; i < sz; ++i) { vars.push_back(S[i]); coeffs.push_back(mpz(1)); } - unsigned base_var = m_S.size() + m_weights.size(); + unsigned base_var = m_T.size() + m_S.size() + m_weights.size(); m_simplex.ensure_var(base_var); vars.push_back(base_var); coeffs.push_back(mpz(-1)); // S - base_var = 0 - // base_var >= 1 - m_simplex.set_lower(base_var, mpq_inf(mpq(1),mpq(0))); + if (is_some_true) { + // base_var >= 1 + m_simplex.set_lower(base_var, mpq_inf(mpq(1),mpq(0))); + } + else { + // base_var <= sz-1 + m_simplex.set_upper(base_var, mpq_inf(mpq(sz-1),mpq(0))); + } m_simplex.add_row(base_var, coeffs.size(), vars.c_ptr(), coeffs.c_ptr()); } @@ -334,7 +476,6 @@ namespace opt { return result; } - lbool selected(unsigned j) const { return m_value[j]; } @@ -343,10 +484,58 @@ namespace opt { m_value[j] = l_true; m_value_trail.push_back(j); } + + void unselect(unsigned j) { + m_value[j] = l_false; + m_value_trail.push_back(j); + } + + bool have_selected(lbool val, vector const& Sets, unsigned& i) { + for (i = 0; i < Sets.size(); ++i) { + if (!has_selected(val, Sets[i])) return false; + } + return true; + } + + void set_undef_to_false() { + for (unsigned i = 0; i < m_value_saved.size(); ++i) { + if (m_value_saved[i] == l_undef) { + m_value_saved[i] = l_false; + } + } + } + + bool values_satisfy_Ts(unsigned& i) { + unsigned j = 0; + for (i = 0; i < m_T.size(); ++i) { + set const& T = m_T[i]; + for (j = 0; j < T.size(); ++j) { + if (m_value_saved[T[j]] == l_false) { + break; + } + } + if (T.size() == j) { + break; + } + } + return i == m_T.size(); + } bool has_selected(set const& S) { + return has_selected(l_true, S); + } + + bool has_unselected(set const& S) { + return has_selected(l_false, S); + } + + bool has_unset(set const& S) { + return has_selected(l_undef, S); + } + + bool has_selected(lbool val, set const& S) { for (unsigned i = 0; i < S.size(); ++i) { - if (l_true == selected(S[i])) { + if (val == selected(S[i])) { return true; } } @@ -357,11 +546,14 @@ namespace opt { hitting_sets::hitting_sets() { m_imp = alloc(imp); } hitting_sets::~hitting_sets() { dealloc(m_imp); } void hitting_sets::add_weight(rational const& w) { m_imp->add_weight(w); } - void hitting_sets::add_set(unsigned sz, unsigned const* elems) { m_imp->add_set(sz, elems); } - bool hitting_sets::compute_lower() { return m_imp->compute_lower(); } - bool hitting_sets::compute_upper() { return m_imp->compute_upper(); } + void hitting_sets::add_exists_true(unsigned sz, unsigned const* elems) { m_imp->add_exists_true(sz, elems); } + void hitting_sets::add_exists_false(unsigned sz, unsigned const* elems) { m_imp->add_exists_false(sz, elems); } + lbool hitting_sets::compute_lower() { return m_imp->compute_lower(); } + lbool hitting_sets::compute_upper() { return m_imp->compute_upper(); } rational hitting_sets::get_lower() { return m_imp->get_lower(); } rational hitting_sets::get_upper() { return m_imp->get_upper(); } + void hitting_sets::set_upper(rational const& r) { return m_imp->set_upper(r); } + bool hitting_sets::get_value(unsigned idx) { return m_imp->get_value(idx); } void hitting_sets::set_cancel(bool f) { m_imp->set_cancel(f); } void hitting_sets::collect_statistics(::statistics& st) const { m_imp->collect_statistics(st); } void hitting_sets::reset() { m_imp->reset(); } diff --git a/src/opt/hitting_sets.h b/src/opt/hitting_sets.h index bea5559f9..58de8c518 100644 --- a/src/opt/hitting_sets.h +++ b/src/opt/hitting_sets.h @@ -21,6 +21,7 @@ Notes: #include "rational.h" #include "statistics.h" +#include "lbool.h" namespace opt { @@ -31,11 +32,14 @@ namespace opt { hitting_sets(); ~hitting_sets(); void add_weight(rational const& w); - void add_set(unsigned sz, unsigned const* elems); - bool compute_lower(); - bool compute_upper(); + void add_exists_true(unsigned sz, unsigned const* elems); + void add_exists_false(unsigned sz, unsigned const* elems); + lbool compute_lower(); + lbool compute_upper(); + void set_upper(rational const& r); rational get_lower(); rational get_upper(); + bool get_value(unsigned idx); void set_cancel(bool f); void collect_statistics(::statistics& st) const; void reset(); diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 12a922b01..bdac382f9 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -613,11 +613,8 @@ namespace opt { double m_disjoint_cores_time; }; - scoped_ptr maxs; - hitting_sets m_hs; + hitting_sets m_hs; expr_ref_vector m_aux; // auxiliary (indicator) variables. - expr_ref_vector m_iaux; // auxiliary integer (indicator) variables. - expr_ref_vector m_naux; // negation of auxiliary variables. obj_map m_aux2index; // expr |-> index unsigned_vector m_core_activity; // number of times soft constraint is used in a core. svector m_seed; // clause selected in current model. @@ -630,12 +627,9 @@ namespace opt { public: - hsmax(solver* s, ast_manager& m, maxsmt_solver_base* maxs): + hsmax(solver* s, ast_manager& m): maxsmt_solver_base(s, m), - maxs(maxs), m_aux(m), - m_iaux(m), - m_naux(m), pb(m), a(m), m_at_lower_bound(false) { @@ -644,7 +638,7 @@ namespace opt { virtual void set_cancel(bool f) { maxsmt_solver_base::set_cancel(f); - maxs->set_cancel(f); + m_hs.set_cancel(f); } virtual void updt_params(params_ref& p) { @@ -653,7 +647,7 @@ namespace opt { virtual void collect_statistics(statistics& st) const { maxsmt_solver_base::collect_statistics(st); - maxs->s().collect_statistics(st); + m_hs.collect_statistics(st); st.update("hsmax-num-iterations", m_stats.m_num_iterations); st.update("hsmax-num-core-reductions-n", m_stats.m_num_core_reductions_failure); st.update("hsmax-num-core-reductions-y", m_stats.m_num_core_reductions_success); @@ -694,14 +688,14 @@ namespace opt { break; case l_false: TRACE("opt", tout << "no more seeds\n";); - m_lower = m_upper; - return l_true; + m_lower = m_upper; + return l_true; case l_undef: return l_undef; } break; } - case l_false: + case l_false: TRACE("opt", tout << "no more cores\n";); m_lower = m_upper; return l_true; @@ -721,8 +715,6 @@ namespace opt { m_asms.reset(); m_seed.reset(); m_aux.reset(); - m_iaux.reset(); - m_naux.reset(); m_aux_active.reset(); m_aux2index.reset(); m_core_activity.reset(); @@ -730,9 +722,6 @@ namespace opt { bool tt = is_true(m_model, m_soft[i].get()); m_seed.push_back(tt); m_aux. push_back(mk_fresh(m.mk_bool_sort())); - m_iaux.push_back(mk_fresh(a.mk_int())); - expr* iaux = m_iaux.back(); - m_naux.push_back(m.mk_not(m_aux.back())); m_aux_active.push_back(false); m_core_activity.push_back(0); m_aux2index.insert(m_aux.back(), i); @@ -741,7 +730,6 @@ namespace opt { ensure_active(i); } } - maxs->init_soft(m_weights, m_aux); for (unsigned i = 0; i < m_weights.size(); ++i) { m_hs.add_weight(m_weights[i]); @@ -901,11 +889,8 @@ namespace opt { } // - // retrieve the next seed that satisfies state of maxs. - // state of maxs must be satisfiable before optimization is called. - // - // find a satisfying assignment to maxs state, that - // minimizes objective function. + // retrieve the next seed that satisfies state of hs. + // state of hs must be satisfiable before optimization is called. // lbool next_seed() { scoped_stopwatch _sw(m_stats.m_aux_sat_time); @@ -914,67 +899,28 @@ namespace opt { // min c_i*(not x_i) for x_i are soft clauses. // max c_i*x_i for x_i are soft clauses - lbool is_sat = l_true; m_at_lower_bound = false; - expr_ref fml(m); - if (m_lower.is_pos()) { - solver::scoped_push _scope(maxs->s()); - fml = pb.mk_le(num_soft(), m_weights.c_ptr(), m_naux.c_ptr(), m_lower); - maxs->add_hard(fml); - is_sat = maxs->s().check_sat(0,0); - if (is_sat == l_true) { - maxs->set_model(); - extract_seed(); - m_at_lower_bound = true; - return l_true; - } - } - is_sat = maxs->s().check_sat(0,0); - if (is_sat == l_true) { - maxs->set_model(); - } - else { - m_at_lower_bound = true; - return is_sat; - } - is_sat = (*maxs)(); + + lbool is_sat = m_hs.compute_upper(); if (is_sat == l_true) { - extract_seed(); + is_sat = m_hs.compute_lower(); + } + if (is_sat == l_true) { + m_at_lower_bound = m_hs.get_upper() == m_hs.get_lower(); + if (m_hs.get_lower() > m_lower) { + m_lower = m_hs.get_lower(); + } + for (unsigned i = 0; i < num_soft(); ++i) { + m_seed[i] = is_active(i) && !m_hs.get_value(i); + } + TRACE("opt", print_seed(tout);); } return is_sat; } -#if 0 - if (!m_hs.compute_upper()) { - return l_undef; - } - solver::scoped_push _scope(maxs->s()); - fml = pb.mk_le(num_soft(), m_weights.c_ptr(), m_naux.c_ptr(), m_hs.get_upper()); - IF_VERBOSE(0, verbose_stream() << "upper: " << m_hs.get_upper() << " " << m_upper << "\n";); - maxs->add_hard(fml); - TRACE("opt", tout << "checking with upper bound: " << m_hs.get_upper() << "\n";); - is_sat = maxs->s().check_sat(0,0); - std::cout << is_sat << "\n"; - - // TBD: uper bound estimate does not include the negative constraints. -#endif - - void extract_seed() { - model_ref mdl; - maxs->get_model(mdl); - m_lower.reset(); - for (unsigned i = 0; i < num_soft(); ++i) { - m_seed[i] = is_active(i) && is_true(mdl, m_aux[i].get()); - if (!m_seed[i]) { - m_lower += m_weights[i]; - } - } - TRACE("opt", print_seed(tout);); - } - // - // check assignment returned by maxs with the original + // check assignment returned by HS with the original // hard constraints. // If the assignment is consistent with the hard constraints // update the current model, otherwise, update the current lower @@ -1008,9 +954,7 @@ namespace opt { // extend the current assignment to one that // satisfies as many soft constraints as possible. // update the upper bound based on this assignment - // (because maxs has the constraint that the new - // assignment improves the previous m_upper). - // + // bool grow() { scoped_stopwatch _sw(m_stats.m_model_expansion_time); for (unsigned i = 0; i < num_soft(); ++i) { @@ -1022,7 +966,7 @@ namespace opt { ensure_active(i); m_asms.push_back(m_aux[i].get()); lbool is_sat = s().check_sat(m_asms.size(), m_asms.c_ptr()); - IF_VERBOSE(1, verbose_stream() + IF_VERBOSE(3, verbose_stream() << "check: " << mk_pp(m_asms.back(), m) << ":" << is_sat << "\n";); TRACE("opt", tout @@ -1054,6 +998,7 @@ namespace opt { } if (upper < m_upper) { m_upper = upper; + m_hs.set_upper(upper); TRACE("opt", tout << "new upper: " << m_upper << "\n";); } return true; @@ -1128,50 +1073,32 @@ namespace opt { // // must include some literal not from asms. - // furthermore, update upper bound constraint in maxs + // (furthermore, update upper bound constraint in HS) // void block_down() { uint_set indices; + unsigned_vector c_indices; for (unsigned i = 0; i < m_asms.size(); ++i) { unsigned index = m_aux2index.find(m_asms[i]); indices.insert(index); } - expr_ref_vector fmls(m); - expr_ref fml(m); for (unsigned i = 0; i < num_soft(); ++i) { if (!indices.contains(i)) { - fmls.push_back(m_aux[i].get()); + c_indices.push_back(i); } } - fml = m.mk_or(fmls.size(), fmls.c_ptr()); - maxs->add_hard(fml); - set_upper(); - TRACE("opt", tout << fml << "\n";); - } - - // constrain the upper bound. - // w1*(not r1) + w2*(not r2) + ... + w_n*(not r_n) < m_upper - void set_upper() { - expr_ref fml(m); - fml = pb.mk_lt(num_soft(), m_weights.c_ptr(), m_naux.c_ptr(), m_upper); - maxs->add_hard(fml); + m_hs.add_exists_false(c_indices.size(), c_indices.c_ptr()); } // should exclude some literal from core. void block_up() { - expr_ref_vector fmls(m); - expr_ref fml(m); unsigned_vector indices; for (unsigned i = 0; i < m_asms.size(); ++i) { unsigned index = m_aux2index.find(m_asms[i]); - fmls.push_back(m.mk_not(m_asms[i])); m_core_activity[index]++; indices.push_back(index); } - fml = m.mk_or(fmls.size(), fmls.c_ptr()); - TRACE("opt", tout << fml << "\n";); - m_hs.add_set(indices.size(), indices.c_ptr()); - maxs->add_hard(fml); + m_hs.add_exists_true(indices.size(), indices.c_ptr()); } @@ -1661,14 +1588,8 @@ namespace opt { else if (m_engine == symbol("bcd2")) { m_maxsmt = alloc(bcd2, s.get(), m); } - else if (m_engine == symbol("hsmax")) { - //m_params.set_bool("pb.enable_simplex", true); - ref s0 = alloc(opt_solver, m, m_params, symbol()); - s0->check_sat(0,0); - maxsmt_solver_base* s2 = alloc(pbmax, s0.get(), m); // , s0->get_context()); - s2->set_converter(s0->mc_ref().get()); - - m_maxsmt = alloc(hsmax, s.get(), m, s2); + else if (m_engine == symbol("hsmax")) { + m_maxsmt = alloc(hsmax, s.get(), m); } // NB: this is experimental one-round version of SLS else if (m_engine == symbol("sls")) { diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index b8ac520b2..193bf59f2 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -215,7 +215,7 @@ namespace sat { sat_asymm_branch_params::collect_param_descrs(d); } - void asymm_branch::collect_statistics(statistics & st) { + void asymm_branch::collect_statistics(statistics & st) const { st.update("elim literals", m_elim_literals); } diff --git a/src/sat/sat_asymm_branch.h b/src/sat/sat_asymm_branch.h index 6ffd239eb..f10522fab 100644 --- a/src/sat/sat_asymm_branch.h +++ b/src/sat/sat_asymm_branch.h @@ -49,7 +49,7 @@ namespace sat { void updt_params(params_ref const & p); static void collect_param_descrs(param_descrs & d); - void collect_statistics(statistics & st); + void collect_statistics(statistics & st) const; void reset_statistics(); void dec(unsigned c) { m_counter -= c; } diff --git a/src/sat/sat_cleaner.cpp b/src/sat/sat_cleaner.cpp index 4b1ac2c92..959f5e94f 100644 --- a/src/sat/sat_cleaner.cpp +++ b/src/sat/sat_cleaner.cpp @@ -206,7 +206,7 @@ namespace sat { m_elim_literals = 0; } - void cleaner::collect_statistics(statistics & st) { + void cleaner::collect_statistics(statistics & st) const { st.update("elim clauses", m_elim_clauses); st.update("elim literals", m_elim_literals); } diff --git a/src/sat/sat_cleaner.h b/src/sat/sat_cleaner.h index d4306afcd..d22408926 100644 --- a/src/sat/sat_cleaner.h +++ b/src/sat/sat_cleaner.h @@ -42,7 +42,7 @@ namespace sat { bool operator()(bool force = false); - void collect_statistics(statistics & st); + void collect_statistics(statistics & st) const; void reset_statistics(); void dec() { m_cleanup_counter--; } diff --git a/src/sat/sat_probing.cpp b/src/sat/sat_probing.cpp index f9741cd7b..e9710c2d4 100644 --- a/src/sat/sat_probing.cpp +++ b/src/sat/sat_probing.cpp @@ -259,7 +259,7 @@ namespace sat { m_to_assert.finalize(); } - void probing::collect_statistics(statistics & st) { + void probing::collect_statistics(statistics & st) const { st.update("probing assigned", m_num_assigned); } diff --git a/src/sat/sat_probing.h b/src/sat/sat_probing.h index 9f3c1ae87..2061b74bd 100644 --- a/src/sat/sat_probing.h +++ b/src/sat/sat_probing.h @@ -71,7 +71,7 @@ namespace sat { void free_memory(); - void collect_statistics(statistics & st); + void collect_statistics(statistics & st) const; void reset_statistics(); // return the literals implied by l. diff --git a/src/sat/sat_scc.cpp b/src/sat/sat_scc.cpp index 29f3f006f..ffbdb31c6 100644 --- a/src/sat/sat_scc.cpp +++ b/src/sat/sat_scc.cpp @@ -223,7 +223,7 @@ namespace sat { return to_elim.size(); } - void scc::collect_statistics(statistics & st) { + void scc::collect_statistics(statistics & st) const { st.update("elim bool vars", m_num_elim); } diff --git a/src/sat/sat_scc.h b/src/sat/sat_scc.h index c85cc7d42..5f69e11c6 100644 --- a/src/sat/sat_scc.h +++ b/src/sat/sat_scc.h @@ -40,7 +40,7 @@ namespace sat { void updt_params(params_ref const & p); static void collect_param_descrs(param_descrs & d); - void collect_statistics(statistics & st); + void collect_statistics(statistics & st) const; void reset_statistics(); }; }; diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 3553a9031..969a6c37a 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1469,7 +1469,7 @@ namespace sat { sat_simplifier_params::collect_param_descrs(r); } - void simplifier::collect_statistics(statistics & st) { + void simplifier::collect_statistics(statistics & st) const { st.update("subsumed", m_num_subsumed); st.update("subsumption resolution", m_num_sub_res); st.update("elim literals", m_num_elim_lits); diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h index 263354a4a..521990ea0 100644 --- a/src/sat/sat_simplifier.h +++ b/src/sat/sat_simplifier.h @@ -181,7 +181,7 @@ namespace sat { void free_memory(); - void collect_statistics(statistics & st); + void collect_statistics(statistics & st) const; void reset_statistics(); }; }; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index e807915c4..0e9f50828 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1988,7 +1988,7 @@ namespace sat { m_cancel = f; } - void solver::collect_statistics(statistics & st) { + void solver::collect_statistics(statistics & st) const { m_stats.collect_statistics(st); m_cleaner.collect_statistics(st); m_simplifier.collect_statistics(st); diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 2a64c9cd5..0738f0118 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -143,7 +143,7 @@ namespace sat { static void collect_param_descrs(param_descrs & d); void set_cancel(bool f); - void collect_statistics(statistics & st); + void collect_statistics(statistics & st) const; void reset_statistics(); void display_status(std::ostream & out) const; From 7fbe7124f9426faafa447ef5cd7a1342fd19989e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 14 Jun 2014 17:29:53 -0700 Subject: [PATCH 416/925] bugfixes to hsmax Signed-off-by: Nikolaj Bjorner --- src/muz/pdr/pdr_smt_context_manager.h | 17 ------- src/opt/hitting_sets.cpp | 13 ++++-- src/opt/weighted_maxsat.cpp | 67 ++++++--------------------- src/sat/sat_solver.h | 2 +- 4 files changed, 24 insertions(+), 75 deletions(-) diff --git a/src/muz/pdr/pdr_smt_context_manager.h b/src/muz/pdr/pdr_smt_context_manager.h index 4775dc58f..ea8947ea1 100644 --- a/src/muz/pdr/pdr_smt_context_manager.h +++ b/src/muz/pdr/pdr_smt_context_manager.h @@ -71,23 +71,6 @@ namespace pdr { virtual expr* get_unsat_core_expr(unsigned i) { return m_context.get_unsat_core_expr(i); } }; - // TBD: - class sat_context : public smt_context { - sat::solver m_solver; - public: - sat_context(smt::kernel & ctx, smt_context_manager& p, app* pred); - virtual ~sat_context() {} - virtual void assert_expr(expr* e); - virtual lbool check(expr_ref_vector& assumptions); - virtual void get_model(model_ref& model); - virtual proof* get_proof(); - virtual void pop() { m_solver.pop(1); } - virtual void push() { m_solver.push(); } - // TBD: add unsat core extraction with sat::solver. - virtual unsigned get_unsat_core_size(); - virtual expr* get_unsat_core_expr(unsigned i); - }; - class smt_context_manager { smt_params& m_fparams; ast_manager& m; diff --git a/src/opt/hitting_sets.cpp b/src/opt/hitting_sets.cpp index 62b36961b..6cad9a8c2 100644 --- a/src/opt/hitting_sets.cpp +++ b/src/opt/hitting_sets.cpp @@ -110,7 +110,8 @@ namespace opt { lbool compute_lower() { m_lower.reset(); - if (L1() && L2() && L3()) { + // L3() disabled: mostly a waste of time. + if (L1() && L2()) { return l_true; } else { @@ -238,7 +239,9 @@ namespace opt { lbool U1() { scoped_select _sc(*this); while (true) { - if (!compute_U1()) return l_undef; + if (!compute_U1()) { + return l_undef; + } unsigned i = 0, j = 0; set_undef_to_false(); if (values_satisfy_Ts(i)) { @@ -251,7 +254,7 @@ namespace opt { // literal to true. // - IF_VERBOSE(1, verbose_stream() << "(hs.refining exclusion set " << i << "\n";); + IF_VERBOSE(1, verbose_stream() << "(hs.refining exclusion set " << i << ")\n";); set const& T = m_T[i]; rational max_value(0); j = 0; @@ -270,7 +273,7 @@ namespace opt { if (l_false != selected(S[j])) break; } if (j == S.size()) { - IF_VERBOSE(1, verbose_stream() << "approximation failed, fall back to SAT\n";); + IF_VERBOSE(1, verbose_stream() << "(hs.fallback-to-SAT)\n";); return compute_U2(); } } @@ -327,7 +330,7 @@ namespace opt { m_value_saved.reset(); m_value_saved.append(m_value); if (m_upper > m_max_weight) { - IF_VERBOSE(0, verbose_stream() << "got worse upper bound\n";); + IF_VERBOSE(1, verbose_stream() << "(hs.bound_degradation " << m_upper << " )\n";); } return !m_cancel; } diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index bdac382f9..cd7540317 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -686,8 +686,9 @@ namespace opt { case l_true: seed2hs(false, hs); break; - case l_false: + case l_false: TRACE("opt", tout << "no more seeds\n";); + IF_VERBOSE(1, verbose_stream() << "(wmaxsat.maxhs.no-more-seeds)\n";); m_lower = m_upper; return l_true; case l_undef: @@ -696,6 +697,7 @@ namespace opt { break; } case l_false: + IF_VERBOSE(1, verbose_stream() << "(wmaxsat.maxhs.no-more-cores)\n";); TRACE("opt", tout << "no more cores\n";); m_lower = m_upper; return l_true; @@ -825,7 +827,7 @@ namespace opt { // Auxiliary Algorithm 10 for producing cores. // lbool generate_cores(ptr_vector& hs) { - bool core = false; + bool core = !m_at_lower_bound; while (true) { hs2seed(hs); lbool is_sat = check_subset(); @@ -869,25 +871,6 @@ namespace opt { } } - lbool next_seed(ptr_vector& hs, lbool core_found) { - - if (core_found == l_false && m_at_lower_bound) { - return l_true; - } - lbool is_sat = next_seed(); - switch(is_sat) { - case l_true: - seed2hs(false, hs); - return m_at_lower_bound?l_true:l_false; - case l_false: - TRACE("opt", tout << "no more seeds\n";); - return l_true; - case l_undef: - return l_undef; - } - return l_undef; - } - // // retrieve the next seed that satisfies state of hs. // state of hs must be satisfiable before optimization is called. @@ -922,9 +905,6 @@ namespace opt { // // check assignment returned by HS with the original // hard constraints. - // If the assignment is consistent with the hard constraints - // update the current model, otherwise, update the current lower - // bound. // lbool check_subset() { TRACE("opt", tout << "\n";); @@ -935,19 +915,7 @@ namespace opt { ensure_active(i); } } - lbool is_sat = s().check_sat(m_asms.size(), m_asms.c_ptr()); - switch (is_sat) { - case l_true: - update_model(); - break; - case l_false: - break; - default: - break; - } - TRACE("opt", tout << is_sat << "\n";); - - return is_sat; + return s().check_sat(m_asms.size(), m_asms.c_ptr()); } // @@ -957,18 +925,17 @@ namespace opt { // bool grow() { scoped_stopwatch _sw(m_stats.m_model_expansion_time); + model_ref mdl; + s().get_model(mdl); for (unsigned i = 0; i < num_soft(); ++i) { if (!m_seed[i]) { - if (is_true(m_model, m_soft[i].get())) { + if (is_true(mdl, m_soft[i].get())) { m_seed[i] = true; } else { ensure_active(i); m_asms.push_back(m_aux[i].get()); lbool is_sat = s().check_sat(m_asms.size(), m_asms.c_ptr()); - IF_VERBOSE(3, verbose_stream() - << "check: " << mk_pp(m_asms.back(), m) - << ":" << is_sat << "\n";); TRACE("opt", tout << "check: " << mk_pp(m_asms.back(), m) << ":" << is_sat << "\n";); @@ -981,9 +948,7 @@ namespace opt { break; case l_true: ++m_stats.m_num_model_expansions_success; - update_model(); - TRACE("opt", model_smt2_pp(tout << mk_pp(m_aux[i].get(), m) << "\n", - m, *(m_model.get()), 0);); + s().get_model(mdl); m_seed[i] = true; break; } @@ -999,7 +964,12 @@ namespace opt { if (upper < m_upper) { m_upper = upper; m_hs.set_upper(upper); - TRACE("opt", tout << "new upper: " << m_upper << "\n";); + m_model = mdl; + m_assignment.reset(); + m_assignment.append(m_seed); + TRACE("opt", + tout << "new upper: " << m_upper << "\n"; + model_smt2_pp(tout, m, *(mdl.get()), 0);); } return true; } @@ -1049,13 +1019,6 @@ namespace opt { return true; } - void update_model() { - s().get_model(m_model); - for (unsigned i = 0; i < num_soft(); ++i) { - m_assignment[i] = is_true(m_model, m_soft[i].get()); - } - } - void print_asms(std::ostream& out, ptr_vector const& asms) { for (unsigned j = 0; j < asms.size(); ++j) { out << mk_pp(asms[j], m) << " "; diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 0738f0118..b18bae06a 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -339,8 +339,8 @@ namespace sat { // Backtracking // // ----------------------- - public: void push(); + public: void pop(unsigned num_scopes); protected: From ef62a52fff8a1cb0e47d024141a88e8e37d8d574 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 14 Jun 2014 18:45:16 -0700 Subject: [PATCH 417/925] cleanup Signed-off-by: Nikolaj Bjorner --- src/opt/weighted_maxsat.cpp | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index cd7540317..1c07b05c8 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -1042,8 +1042,7 @@ namespace opt { uint_set indices; unsigned_vector c_indices; for (unsigned i = 0; i < m_asms.size(); ++i) { - unsigned index = m_aux2index.find(m_asms[i]); - indices.insert(index); + indices.insert(m_aux2index.find(m_asms[i])); } for (unsigned i = 0; i < num_soft(); ++i) { if (!indices.contains(i)) { @@ -1064,7 +1063,6 @@ namespace opt { m_hs.add_exists_true(indices.size(), indices.c_ptr()); } - void update_index(obj_map& asm2index) { obj_map::iterator it = asm2index.begin(), end = asm2index.end(); for (; it != end; ++it) { @@ -1082,20 +1080,12 @@ namespace opt { return r; } - bool is_true(model_ref& mdl, expr* e) { expr_ref val(m); VERIFY(mdl->eval(e, val)); return m.is_true(val); } - bool is_one(model_ref& mdl, expr* e) { - rational r; - expr_ref val(m); - VERIFY(mdl->eval(e, val)); - return a.is_numeral(val, r) && r.is_one(); - } - bool is_active(unsigned i) const { return m_aux_active[i]; } From 63550d8a1a886ecc8b4695db0f6b00f38b901201 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 15 Jun 2014 05:44:03 -0700 Subject: [PATCH 418/925] bug fixes in hsmax Signed-off-by: Nikolaj Bjorner --- src/opt/hitting_sets.cpp | 52 ++++++++++++++++++++++++-------- src/opt/opt_solver.cpp | 2 +- src/opt/weighted_maxsat.cpp | 59 ++++++++++++++++++++++--------------- 3 files changed, 75 insertions(+), 38 deletions(-) diff --git a/src/opt/hitting_sets.cpp b/src/opt/hitting_sets.cpp index 6cad9a8c2..2e3d59a36 100644 --- a/src/opt/hitting_sets.cpp +++ b/src/opt/hitting_sets.cpp @@ -58,7 +58,10 @@ namespace opt { m_cancel(false), m_max_weight(0), m_weights_var(0), - m_solver(m_params,0) {} + m_solver(m_params,0) { + m_params.set_bool("elim_vars", false); + m_solver.updt_params(m_params); + } ~imp() {} void add_weight(rational const& w) { @@ -245,6 +248,9 @@ namespace opt { unsigned i = 0, j = 0; set_undef_to_false(); if (values_satisfy_Ts(i)) { + if (m_upper > m_max_weight) { + IF_VERBOSE(1, verbose_stream() << "(hs.bound_degradation " << m_upper << " )\n";); + } return l_true; } @@ -282,21 +288,44 @@ namespace opt { } lbool compute_U2() { - lbool is_sat = m_solver.check(); - if (is_sat == l_true) { - sat::model const& model = m_solver.get_model(); - m_value_saved.reset(); - m_upper.reset(); - for (unsigned i = 0; i < m_vars.size(); ++i) { - m_value_saved.push_back(model[m_vars[i]]); - if (model[m_vars[i]] == l_true) { - m_upper += m_weights[i]; + lbool is_sat = l_true; + while (true) { + is_sat = m_solver.check(); + if (is_sat == l_true) { + sat::model const& model = m_solver.get_model(); + m_value_saved.reset(); + m_upper.reset(); + for (unsigned i = 0; i < m_vars.size(); ++i) { + m_value_saved.push_back(model[m_vars[i]]); + if (model[m_vars[i]] == l_true) { + m_upper += m_weights[i]; + } } + IF_VERBOSE(1, verbose_stream() << "(hs.upper " << m_upper << ")\n";); + m_solver.pop(m_solver.scope_lvl()); + } + break; } return is_sat; } + bool block_model(sat::model const& model) { + rational value(0); + svector lits; + for (unsigned i = 0; i < m_vars.size(); ++i) { + if (value >= m_max_weight) { + m_solver.mk_clause(lits.size(), lits.c_ptr()); + return true; + } + if (model[m_vars[i]] == l_true) { + value += m_weights[i]; + lits.push_back(sat::literal(m_vars[i], true)); + } + } + return false; + } + // compute upper bound for hitting set. bool compute_U1() { rational w(0); @@ -329,9 +358,6 @@ namespace opt { m_upper = w; m_value_saved.reset(); m_value_saved.append(m_value); - if (m_upper > m_max_weight) { - IF_VERBOSE(1, verbose_stream() << "(hs.bound_degradation " << m_upper << " )\n";); - } return !m_cancel; } diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 23c1a59b2..21667e5f8 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -125,7 +125,7 @@ namespace opt { } lbool opt_solver::check_sat_core(unsigned num_assumptions, expr * const * assumptions) { - TRACE("opt", { + TRACE("opt_verbose", { tout << "context size: " << m_context.size() << "\n"; for (unsigned i = 0; i < m_context.size(); ++i) { tout << mk_pp(m_context.get_formulas()[i], m_context.m()) << "\n"; diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 1c07b05c8..00c445402 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -928,30 +928,36 @@ namespace opt { model_ref mdl; s().get_model(mdl); for (unsigned i = 0; i < num_soft(); ++i) { - if (!m_seed[i]) { - if (is_true(mdl, m_soft[i].get())) { - m_seed[i] = true; - } - else { - ensure_active(i); - m_asms.push_back(m_aux[i].get()); - lbool is_sat = s().check_sat(m_asms.size(), m_asms.c_ptr()); - TRACE("opt", tout - << "check: " << mk_pp(m_asms.back(), m) - << ":" << is_sat << "\n";); - switch(is_sat) { - case l_undef: - return false; - case l_false: - ++m_stats.m_num_model_expansions_failure; - m_asms.pop_back(); - break; - case l_true: - ++m_stats.m_num_model_expansions_success; - s().get_model(mdl); - m_seed[i] = true; - break; - } + ensure_active(i); + m_seed[i] = false; + } + for (unsigned i = 0; i < m_asms.size(); ++i) { + m_seed[m_aux2index.find(m_asms[i])] = true; + } + + for (unsigned i = 0; i < num_soft(); ++i) { + if (m_seed[i]) { + // already an assumption + } + else if (is_true(mdl, m_soft[i].get())) { + m_seed[i] = true; + m_asms.push_back(m_aux[i].get()); + } + else { + m_asms.push_back(m_aux[i].get()); + lbool is_sat = s().check_sat(m_asms.size(), m_asms.c_ptr()); + switch(is_sat) { + case l_undef: + return false; + case l_false: + ++m_stats.m_num_model_expansions_failure; + m_asms.pop_back(); + break; + case l_true: + ++m_stats.m_num_model_expansions_success; + s().get_model(mdl); + m_seed[i] = true; + break; } } } @@ -971,6 +977,11 @@ namespace opt { tout << "new upper: " << m_upper << "\n"; model_smt2_pp(tout, m, *(mdl.get()), 0);); } + DEBUG_CODE( + for (unsigned i = 0; i < num_soft(); ++i) { + SASSERT(is_true(mdl, m_soft[i].get()) == m_seed[i]); + }); + return true; } From bad03822b4f450fee541bdc196b1b9cccf256113 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 16 Jun 2014 16:55:48 -0700 Subject: [PATCH 419/925] working on HS Signed-off-by: Nikolaj Bjorner --- src/opt/hitting_sets.cpp | 244 ++++++++++++++++++++++++++------------- 1 file changed, 164 insertions(+), 80 deletions(-) diff --git a/src/opt/hitting_sets.cpp b/src/opt/hitting_sets.cpp index 2e3d59a36..fc6491cde 100644 --- a/src/opt/hitting_sets.cpp +++ b/src/opt/hitting_sets.cpp @@ -38,26 +38,37 @@ namespace opt { vector m_weights; rational m_max_weight; rational m_denominator; - vector m_S; vector m_T; - svector m_value; + vector m_F; + svector m_value; svector m_value_saved; - unsigned_vector m_value_trail; - unsigned_vector m_value_lim; + unsigned_vector m_justification; vector m_tuse_list; vector m_fuse_list; + vector m_twatch; + vector m_fwatch; + unsigned_vector m_trail; // trail of assigned literals + unsigned m_qhead; // queue head + + // simplex unsynch_mpz_manager m; Simplex m_simplex; unsigned m_weights_var; + // sat solver params_ref m_params; sat::solver m_solver; svector m_vars; + static unsigned const null_clause = UINT_MAX; + static unsigned const axiom = UINT_MAX-1; + imp(): m_cancel(false), m_max_weight(0), + m_denominator(1), m_weights_var(0), + m_qhead(0), m_solver(m_params,0) { m_params.set_bool("elim_vars", false); m_solver.updt_params(m_params); @@ -72,43 +83,48 @@ namespace opt { m_simplex.set_upper(var, mpq_inf(mpq(1),mpq(0))); m_weights.push_back(w); m_value.push_back(l_undef); + m_justification.push_back(null_clause); m_tuse_list.push_back(unsigned_vector()); m_fuse_list.push_back(unsigned_vector()); + m_twatch.push_back(unsigned_vector()); + m_fwatch.push_back(unsigned_vector()); m_max_weight += w; m_vars.push_back(m_solver.mk_var()); } void add_exists_false(unsigned sz, unsigned const* S) { - SASSERT(sz > 0); - for (unsigned i = 0; i < sz; ++i) { - m_fuse_list[S[i]].push_back(m_T.size()); - } - init_weights(); - m_T.push_back(unsigned_vector(sz, S)); - add_simplex_row(false, sz, S); - // Add clause to SAT solver: - svector lits; - for (unsigned i = 0; i < sz; ++i) { - lits.push_back(sat::literal(m_vars[S[i]], true)); - } - m_solver.mk_clause(lits.size(), lits.c_ptr()); + add_exists(sz, S, true); } void add_exists_true(unsigned sz, unsigned const* S) { + add_exists(sz, S, false); + } + + void add_exists(unsigned sz, unsigned const* S, bool sign) { + vector& use_list = sign?m_fuse_list:m_tuse_list; + lbool val = sign?l_false:l_true; + vector& Sets = sign?m_F:m_T; + vector& watch = sign?m_fwatch:m_twatch; SASSERT(sz > 0); for (unsigned i = 0; i < sz; ++i) { - m_tuse_list[S[i]].push_back(m_S.size()); + use_list[S[i]].push_back(Sets.size()); } init_weights(); - m_S.push_back(unsigned_vector(sz, S)); - add_simplex_row(true, sz, S); - - // Add clause to SAT solver + if (sz == 1) { + assign(S[0], val, axiom); + } + else { + watch[S[0]].push_back(Sets.size()); + watch[S[1]].push_back(Sets.size()); + Sets.push_back(unsigned_vector(sz, S)); + } + add_simplex_row(!sign, sz, S); + // Add clause to SAT solver: svector lits; for (unsigned i = 0; i < sz; ++i) { - lits.push_back(sat::literal(m_vars[S[i]], false)); + lits.push_back(sat::literal(m_vars[S[i]], sign)); } - m_solver.mk_clause(lits.size(), lits.c_ptr()); + m_solver.mk_clause(lits.size(), lits.c_ptr()); } lbool compute_lower() { @@ -136,7 +152,7 @@ namespace opt { } void set_upper(rational const& r) { - m_max_weight = r; + m_max_weight = r*m_denominator; } bool get_value(unsigned idx) { @@ -195,11 +211,11 @@ namespace opt { for (unsigned i = 0; i < m_weights.size(); ++i) { out << i << ": " << m_value_saved[i]<< " " << m_weights[i] << "\n"; } - for (unsigned i = 0; i < m_S.size(); ++i) { - display(out << "+ ", m_S[i]); - } for (unsigned i = 0; i < m_T.size(); ++i) { - display(out << "- ", m_T[i]); + display(out << "+ ", m_T[i]); + } + for (unsigned i = 0; i < m_F.size(); ++i) { + display(out << "- ", m_F[i]); } } @@ -213,7 +229,7 @@ namespace opt { struct scoped_select { imp& s; unsigned sz; - scoped_select(imp& s):s(s), sz(s.m_value_trail.size()) { + scoped_select(imp& s):s(s), sz(s.m_trail.size()) { } ~scoped_select() { s.undo_select(sz); @@ -241,13 +257,14 @@ namespace opt { lbool U1() { scoped_select _sc(*this); - while (true) { - if (!compute_U1()) { - return l_undef; + while (true) { + lbool is_sat = compute_U1(); + if (is_sat != l_true) { + return is_sat; } unsigned i = 0, j = 0; set_undef_to_false(); - if (values_satisfy_Ts(i)) { + if (values_satisfy_Fs(i)) { if (m_upper > m_max_weight) { IF_VERBOSE(1, verbose_stream() << "(hs.bound_degradation " << m_upper << " )\n";); } @@ -255,26 +272,26 @@ namespace opt { } // - // pick some unsatisfied clause from m_T, + // pick some unsatisfied clause from m_F, // and set the value of the most expensive // literal to true. // IF_VERBOSE(1, verbose_stream() << "(hs.refining exclusion set " << i << ")\n";); - set const& T = m_T[i]; + set const& F = m_F[i]; rational max_value(0); j = 0; - for (i = 0; i < T.size(); ++i) { - SASSERT(m_value_saved[T[i]] == l_true); - if (max_value < m_weights[T[i]]) { - max_value = m_weights[T[i]]; - j = T[i]; + for (i = 0; i < F.size(); ++i) { + SASSERT(m_value_saved[F[i]] == l_true); + if (max_value < m_weights[F[i]]) { + max_value = m_weights[F[i]]; + j = F[i]; } } IF_VERBOSE(1, verbose_stream() << "(hs.unselect " << j << ")\n";); - unselect(j); - for (i = 0; i < m_S.size(); ++i) { - set const& S = m_S[i]; + assign(j, l_false, null_clause); + for (i = 0; i < m_T.size(); ++i) { + set const& S = m_T[i]; for (j = 0; j < S.size(); ++j) { if (l_false != selected(S[j])) break; } @@ -327,7 +344,7 @@ namespace opt { } // compute upper bound for hitting set. - bool compute_U1() { + lbool compute_U1() { rational w(0); scoped_select _sc(*this); @@ -345,20 +362,23 @@ namespace opt { indices.push_back(i); } value_lt lt(m_weights, scores); - while (!m_cancel) { + while (true) { + if (m_cancel) { + return l_undef; + } std::sort(indices.begin(), indices.end(), lt); unsigned idx = indices[0]; if (scores[idx] == 0) { break; } update_scores(scores, idx); - select(idx); + assign(idx, l_true, null_clause); w += m_weights[idx]; } m_upper = w; m_value_saved.reset(); m_value_saved.append(m_value); - return !m_cancel; + return l_true; } void init_scores(unsigned_vector & scores) { @@ -366,12 +386,12 @@ namespace opt { for (unsigned i = 0; i < m_value.size(); ++i) { scores.push_back(0); } - for (unsigned i = 0; i < m_S.size(); ++i) { - set const& S = m_S[i]; + for (unsigned i = 0; i < m_T.size(); ++i) { + set const& S = m_T[i]; if (!has_selected(S)) { for (unsigned j = 0; j < S.size(); ++j) { if (selected(S[j]) != l_false) { - scores[S[j]]++; + ++scores[S[j]]; } } } @@ -379,9 +399,9 @@ namespace opt { } void update_scores(unsigned_vector& scores, unsigned v) { - unsigned_vector const& v_uses = m_tuse_list[v]; - for (unsigned i = 0; i < v_uses.size(); ++i) { - set const& S = m_S[v_uses[i]]; + unsigned_vector const& uses = m_tuse_list[v]; + for (unsigned i = 0; i < uses.size(); ++i) { + set const& S = m_T[uses[i]]; if (!has_selected(S)) { for (unsigned j = 0; j < S.size(); ++j) { if (selected(S[j]) != l_false) { @@ -392,16 +412,17 @@ namespace opt { } } + bool L1() { rational w(0); scoped_select _sc(*this); - for (unsigned i = 0; !m_cancel && i < m_S.size(); ++i) { - set const& S = m_S[i]; + for (unsigned i = 0; !m_cancel && i < m_T.size(); ++i) { + set const& S = m_T[i]; SASSERT(!S.empty()); if (!has_selected(S)) { w += m_weights[select_min(S)]; for (unsigned j = 0; j < S.size(); ++j) { - select(S[j]); + assign(S[j], l_true, null_clause); } } } @@ -415,8 +436,8 @@ namespace opt { rational w(0); scoped_select _sc(*this); int n = 0; - for (unsigned i = 0; i < m_S.size(); ++i) { - if (!has_selected(m_S[i])) ++n; + for (unsigned i = 0; i < m_T.size(); ++i) { + if (!has_selected(m_T[i])) ++n; } unsigned_vector scores; init_scores(scores); @@ -472,7 +493,7 @@ namespace opt { vars.push_back(S[i]); coeffs.push_back(mpz(1)); } - unsigned base_var = m_T.size() + m_S.size() + m_weights.size(); + unsigned base_var = m_F.size() + m_T.size() + m_weights.size(); m_simplex.ensure_var(base_var); vars.push_back(base_var); coeffs.push_back(mpz(-1)); @@ -489,10 +510,10 @@ namespace opt { } void undo_select(unsigned sz) { - for (unsigned j = sz; j < m_value_trail.size(); ++j) { - m_value[m_value_trail[j]] = l_undef; + for (unsigned j = sz; j < m_trail.size(); ++j) { + m_value[m_trail[j]] = l_undef; } - m_value_trail.resize(sz); + m_trail.resize(sz); } unsigned select_min(set const& S) { @@ -508,17 +529,13 @@ namespace opt { lbool selected(unsigned j) const { return m_value[j]; } + + void assign(unsigned j, lbool val, unsigned clause_id = null_clause) { + m_value[j] = val; + m_justification[j] = clause_id; + m_trail.push_back(j); + } - void select(unsigned j) { - m_value[j] = l_true; - m_value_trail.push_back(j); - } - - void unselect(unsigned j) { - m_value[j] = l_false; - m_value_trail.push_back(j); - } - bool have_selected(lbool val, vector const& Sets, unsigned& i) { for (i = 0; i < Sets.size(); ++i) { if (!has_selected(val, Sets[i])) return false; @@ -534,20 +551,20 @@ namespace opt { } } - bool values_satisfy_Ts(unsigned& i) { + bool values_satisfy_Fs(unsigned& i) { unsigned j = 0; - for (i = 0; i < m_T.size(); ++i) { - set const& T = m_T[i]; - for (j = 0; j < T.size(); ++j) { - if (m_value_saved[T[j]] == l_false) { + for (i = 0; i < m_F.size(); ++i) { + set const& F = m_F[i]; + for (j = 0; j < F.size(); ++j) { + if (m_value_saved[F[j]] == l_false) { break; } } - if (T.size() == j) { + if (F.size() == j) { break; } } - return i == m_T.size(); + return i == m_F.size(); } bool has_selected(set const& S) { @@ -570,6 +587,73 @@ namespace opt { } return false; } + + // (simple, greedy) CDCL learner for hitting sets. + + lbool search() { + return l_undef; + } + + lbool propagate() { + lbool is_sat = l_true; + while (m_qhead < m_trail.size() && is_sat == l_true) { + unsigned idx = m_trail[m_qhead]; + ++m_qhead; + switch (m_value[idx]) { + case l_undef: + UNREACHABLE(); + break; + case l_true: + is_sat = propagate(idx, l_false, m_fwatch, m_F); + break; + case l_false: + is_sat = propagate(idx, l_true, m_twatch, m_T); + break; + } + } + return is_sat; + } + + lbool propagate(unsigned idx, lbool good_val, vector& watch, vector& Fs) + { + unsigned sz = watch[idx].size(); + lbool bad_val = ~good_val; + for (unsigned i = 0; i < sz; ++i) { + if (m_cancel) return l_undef; + unsigned clause_id = watch[idx][i]; + set& F = Fs[clause_id]; + SASSERT(F.size() >= 2); + unsigned k1 = (F[0] == idx)?0:1; + unsigned k2 = 1 - k1; + SASSERT(F[k1] == idx); + SASSERT(m_value[F[k1]] == bad_val); + if (m_value[F[k2]] == good_val) { + continue; + } + bool found = false; + for (unsigned j = 2; !found && j < F.size(); ++j) { + unsigned idx2 = F[j]; + if (m_value[idx2] != bad_val) { + found = true; + std::swap(F[k1], F[j]); + watch[idx][i] = watch[idx].back(); + watch[idx].pop_back(); + --i; + --sz; + watch[idx2].push_back(clause_id); + } + } + if (!found) { + if (m_value[F[k2]] == bad_val) { + return l_false; + } + SASSERT(m_value[F[k2]] == l_undef); + assign(F[k2], good_val, clause_id); + } + } + return l_true; + } + }; hitting_sets::hitting_sets() { m_imp = alloc(imp); } From b64b12cae3d6191a3912659caa9b03c96a12e271 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 17 Jun 2014 12:54:50 -0700 Subject: [PATCH 420/925] working on HS Signed-off-by: Nikolaj Bjorner --- src/opt/hitting_sets.cpp | 451 +++++++++++++++++++++++++++++---------- 1 file changed, 339 insertions(+), 112 deletions(-) diff --git a/src/opt/hitting_sets.cpp b/src/opt/hitting_sets.cpp index fc6491cde..96661dd75 100644 --- a/src/opt/hitting_sets.cpp +++ b/src/opt/hitting_sets.cpp @@ -32,6 +32,21 @@ namespace opt { struct hitting_sets::imp { typedef unsigned_vector set; + class justification { + public: + enum kind_t { AXIOM, DECISION, CLAUSE }; + private: + kind_t m_kind; + unsigned m_value; + public: + justification(kind_t k):m_kind(k), m_value(0) {} + justification(unsigned v):m_kind(CLAUSE), m_value(v) {} + unsigned clause() const { return m_value; } + bool is_axiom() const { return m_kind == AXIOM; } + bool is_decision() const { return m_kind == DECISION; } + bool is_clause() const { return m_kind == CLAUSE; } + kind_t kind() const { return m_kind; } + }; volatile bool m_cancel; rational m_lower; rational m_upper; @@ -41,14 +56,31 @@ namespace opt { vector m_T; vector m_F; svector m_value; - svector m_value_saved; - unsigned_vector m_justification; + svector m_model; vector m_tuse_list; vector m_fuse_list; + + // Custom CDCL solver. + svector m_justification; vector m_twatch; vector m_fwatch; - unsigned_vector m_trail; // trail of assigned literals - unsigned m_qhead; // queue head + unsigned_vector m_level; + unsigned_vector m_trail; // trail of assigned literals + unsigned m_qhead; // queue head + justification m_conflict_j; // conflict justification + unsigned m_conflict_l; // conflict literal + bool m_inconsistent; + unsigned m_scope_lvl; + rational m_weight; // current weight of assignment. + unsigned_vector m_indices; + unsigned_vector m_scores; + svector m_mark; + struct scope { + unsigned m_trail_lim; + }; + vector m_scopes; + unsigned_vector m_lemma; + unsigned m_conflict_lvl; // simplex unsynch_mpz_manager m; @@ -62,6 +94,7 @@ namespace opt { static unsigned const null_clause = UINT_MAX; static unsigned const axiom = UINT_MAX-1; + static unsigned const decision = UINT_MAX-2; imp(): m_cancel(false), @@ -69,6 +102,8 @@ namespace opt { m_denominator(1), m_weights_var(0), m_qhead(0), + m_conflict_j(justification(justification::AXIOM)), + m_inconsistent(false), m_solver(m_params,0) { m_params.set_bool("elim_vars", false); m_solver.updt_params(m_params); @@ -88,6 +123,10 @@ namespace opt { m_fuse_list.push_back(unsigned_vector()); m_twatch.push_back(unsigned_vector()); m_fwatch.push_back(unsigned_vector()); + m_level.push_back(0); + m_indices.push_back(var); + m_mark.push_back(false); + m_scores.push_back(0); m_max_weight += w; m_vars.push_back(m_solver.mk_var()); } @@ -157,8 +196,8 @@ namespace opt { bool get_value(unsigned idx) { return - idx < m_value_saved.size() && - m_value_saved[idx] == l_true; + idx < m_model.size() && + m_model[idx] == l_true; } void set_cancel(bool f) { @@ -209,7 +248,7 @@ namespace opt { void display(std::ostream& out) const { for (unsigned i = 0; i < m_weights.size(); ++i) { - out << i << ": " << m_value_saved[i]<< " " << m_weights[i] << "\n"; + out << i << ": " << m_model[i]<< " " << m_weights[i] << "\n"; } for (unsigned i = 0; i < m_T.size(); ++i) { display(out << "+ ", m_T[i]); @@ -217,6 +256,24 @@ namespace opt { for (unsigned i = 0; i < m_F.size(); ++i) { display(out << "- ", m_F[i]); } + out << "inconsistent: " << m_inconsistent << "\n"; + out << "weight: " << m_weight << "\n"; + out << "use lists:\n"; + for (unsigned i = 0; i < m_fwatch.size(); ++i) { + out << i << ": "; + for (unsigned j = 0; j < m_twatch[i].size(); ++j) { + out << "+" << m_twatch[i][j] << " "; + } + for (unsigned j = 0; j < m_fwatch[i].size(); ++j) { + out << "-" << m_fwatch[i][j] << " "; + } + out << "\n"; + } + out << "trail\n"; + for (unsigned i = 0; i < m_trail.size(); ++i) { + out << m_trail[i] << " "; + } + out << "\n"; } void display(std::ostream& out, set const& S) const { @@ -232,7 +289,7 @@ namespace opt { scoped_select(imp& s):s(s), sz(s.m_trail.size()) { } ~scoped_select() { - s.undo_select(sz); + s.unassign(sz); } }; @@ -282,18 +339,18 @@ namespace opt { rational max_value(0); j = 0; for (i = 0; i < F.size(); ++i) { - SASSERT(m_value_saved[F[i]] == l_true); + SASSERT(m_model[F[i]] == l_true); if (max_value < m_weights[F[i]]) { max_value = m_weights[F[i]]; j = F[i]; } } IF_VERBOSE(1, verbose_stream() << "(hs.unselect " << j << ")\n";); - assign(j, l_false, null_clause); + assign(j, l_false, decision); for (i = 0; i < m_T.size(); ++i) { set const& S = m_T[i]; for (j = 0; j < S.size(); ++j) { - if (l_false != selected(S[j])) break; + if (l_false != value(S[j])) break; } if (j == S.size()) { IF_VERBOSE(1, verbose_stream() << "(hs.fallback-to-SAT)\n";); @@ -310,10 +367,10 @@ namespace opt { is_sat = m_solver.check(); if (is_sat == l_true) { sat::model const& model = m_solver.get_model(); - m_value_saved.reset(); + m_model.reset(); m_upper.reset(); for (unsigned i = 0; i < m_vars.size(); ++i) { - m_value_saved.push_back(model[m_vars[i]]); + m_model.push_back(model[m_vars[i]]); if (model[m_vars[i]] == l_true) { m_upper += m_weights[i]; } @@ -350,38 +407,32 @@ namespace opt { // score each variable by the number of // unassigned sets they occur in. - unsigned_vector scores; - init_scores(scores); // // Sort indices. // The least literals are those where score/w is maximized. // - unsigned_vector indices; - for (unsigned i = 0; i < m_value.size(); ++i) { - indices.push_back(i); - } - value_lt lt(m_weights, scores); + value_lt lt(m_weights, m_scores); while (true) { - if (m_cancel) { + if (canceled()) { return l_undef; } - std::sort(indices.begin(), indices.end(), lt); - unsigned idx = indices[0]; - if (scores[idx] == 0) { + init_scores(); + std::sort(m_indices.begin(), m_indices.end(), lt); + unsigned idx = m_indices[0]; + if (m_scores[idx] == 0) { break; } - update_scores(scores, idx); - assign(idx, l_true, null_clause); - w += m_weights[idx]; + assign(idx, l_true, decision); } - m_upper = w; - m_value_saved.reset(); - m_value_saved.append(m_value); + m_upper = m_weight; + m_model.reset(); + m_model.append(m_value); return l_true; } - void init_scores(unsigned_vector & scores) { + void init_scores() { + unsigned_vector & scores = m_scores; scores.reset(); for (unsigned i = 0; i < m_value.size(); ++i) { scores.push_back(0); @@ -390,7 +441,7 @@ namespace opt { set const& S = m_T[i]; if (!has_selected(S)) { for (unsigned j = 0; j < S.size(); ++j) { - if (selected(S[j]) != l_false) { + if (value(S[j]) != l_false) { ++scores[S[j]]; } } @@ -398,38 +449,23 @@ namespace opt { } } - void update_scores(unsigned_vector& scores, unsigned v) { - unsigned_vector const& uses = m_tuse_list[v]; - for (unsigned i = 0; i < uses.size(); ++i) { - set const& S = m_T[uses[i]]; - if (!has_selected(S)) { - for (unsigned j = 0; j < S.size(); ++j) { - if (selected(S[j]) != l_false) { - --scores[S[j]]; - } - } - } - } - } - - bool L1() { rational w(0); scoped_select _sc(*this); - for (unsigned i = 0; !m_cancel && i < m_T.size(); ++i) { + for (unsigned i = 0; !canceled() && i < m_T.size(); ++i) { set const& S = m_T[i]; SASSERT(!S.empty()); if (!has_selected(S)) { w += m_weights[select_min(S)]; for (unsigned j = 0; j < S.size(); ++j) { - assign(S[j], l_true, null_clause); + assign(S[j], l_true, decision); } } } if (m_lower < w) { m_lower = w; } - return !m_cancel; + return !canceled(); } bool L2() { @@ -439,34 +475,29 @@ namespace opt { for (unsigned i = 0; i < m_T.size(); ++i) { if (!has_selected(m_T[i])) ++n; } - unsigned_vector scores; - init_scores(scores); - unsigned_vector indices; - for (unsigned i = 0; i < m_value.size(); ++i) { - indices.push_back(i); - } - value_lt lt(m_weights, scores); + init_scores(); + value_lt lt(m_weights, m_scores); - std::sort(indices.begin(), indices.end(), lt); - for(unsigned i = 0; i < indices.size() && n > 0; ++i) { + std::sort(m_indices.begin(), m_indices.end(), lt); + for(unsigned i = 0; i < m_indices.size() && n > 0; ++i) { // deg(c) = score(c) // wt(c) = m_weights[c] - unsigned idx = indices[i]; - if (scores[idx] == 0) { + unsigned idx = m_indices[i]; + if (m_scores[idx] == 0) { break; } - if (scores[idx] < static_cast(n) || m_weights[idx].is_one()) { + if (m_scores[idx] < static_cast(n) || m_weights[idx].is_one()) { w += m_weights[idx]; } else { - w += div((rational(n)*m_weights[idx]), rational(scores[idx])); + w += div((rational(n)*m_weights[idx]), rational(m_scores[idx])); } - n -= scores[idx]; + n -= m_scores[idx]; } if (m_lower < w) { m_lower = w; } - return !m_cancel; + return !canceled(); } bool L3() { @@ -508,13 +539,6 @@ namespace opt { } m_simplex.add_row(base_var, coeffs.size(), vars.c_ptr(), coeffs.c_ptr()); } - - void undo_select(unsigned sz) { - for (unsigned j = sz; j < m_trail.size(); ++j) { - m_value[m_trail[j]] = l_undef; - } - m_trail.resize(sz); - } unsigned select_min(set const& S) { unsigned result = S[0]; @@ -525,17 +549,7 @@ namespace opt { } return result; } - - lbool selected(unsigned j) const { - return m_value[j]; - } - - void assign(unsigned j, lbool val, unsigned clause_id = null_clause) { - m_value[j] = val; - m_justification[j] = clause_id; - m_trail.push_back(j); - } - + bool have_selected(lbool val, vector const& Sets, unsigned& i) { for (i = 0; i < Sets.size(); ++i) { if (!has_selected(val, Sets[i])) return false; @@ -544,9 +558,9 @@ namespace opt { } void set_undef_to_false() { - for (unsigned i = 0; i < m_value_saved.size(); ++i) { - if (m_value_saved[i] == l_undef) { - m_value_saved[i] = l_false; + for (unsigned i = 0; i < m_model.size(); ++i) { + if (m_model[i] == l_undef) { + m_model[i] = l_false; } } } @@ -556,7 +570,7 @@ namespace opt { for (i = 0; i < m_F.size(); ++i) { set const& F = m_F[i]; for (j = 0; j < F.size(); ++j) { - if (m_value_saved[F[j]] == l_false) { + if (m_model[F[j]] == l_false) { break; } } @@ -581,77 +595,290 @@ namespace opt { bool has_selected(lbool val, set const& S) { for (unsigned i = 0; i < S.size(); ++i) { - if (val == selected(S[i])) { + if (val == value(S[i])) { return true; } } return false; } - // (simple, greedy) CDCL learner for hitting sets. + // (greedy) CDCL learner for hitting sets. - lbool search() { - return l_undef; + inline unsigned scope_lvl() const { return m_scope_lvl; } + inline bool inconsistent() const { return m_inconsistent; } + inline bool canceled() const { return m_cancel; } + inline unsigned lvl(unsigned idx) const { return m_level[idx]; } + inline lbool value(unsigned idx) const { return m_value[idx]; } + + inline bool is_marked(unsigned v) const { return m_mark[v] != 0; } + inline void mark(unsigned v) { SASSERT(!is_marked(v)); m_mark[v] = true; } + inline void reset_mark(unsigned v) { SASSERT(is_marked(v)); m_mark[v] = false; } + + void push() { + SASSERT(!inconsistent()); + ++m_scope_lvl; + m_scopes.push_back(scope()); + scope& s = m_scopes.back(); + s.m_trail_lim = m_trail.size(); } - lbool propagate() { - lbool is_sat = l_true; - while (m_qhead < m_trail.size() && is_sat == l_true) { + void pop(unsigned n) { + if (n > 0) { + m_inconsistent = false; + m_scope_lvl = scope_lvl() - n; + unassign(m_scopes[scope_lvl()].m_trail_lim); + m_scopes.shrink(scope_lvl()); + } + } + + void assign(unsigned j, lbool val, unsigned justification) { + if (val == l_true) { + m_weight += m_weights[j]; + } + m_value[j] = val; + m_justification[j] = justification; + m_trail.push_back(j); + m_level[j] = scope_lvl(); + TRACE("opt", tout << j << " := " << val << " scope: " << scope_lvl() << " w: " << m_weight << "\n";); + } + + void unassign(unsigned sz) { + for (unsigned j = sz; j < m_trail.size(); ++j) { + unsigned idx = m_trail[j]; + if (value(idx) == l_true) { + m_weight -= m_weights[idx]; + } + m_value[idx] = l_undef; + } + TRACE("opt", tout << m_weight << "\n";); + m_trail.shrink(sz); + } + + + lbool search() { + TRACE("opt", display(tout);); + pop(scope_lvl()); + while (true) { + while (true) { + propagate(); + if (canceled()) return l_undef; + if (!inconsistent()) break; + if (!resolve_conflict()) return l_false; + SASSERT(!inconsistent()); + } + if (!decide()) { + m_model.reset(); + m_model.append(m_value); + m_upper = m_weight; + SASSERT(m_weight < m_max_weight); + return l_true; + } + } + } + + bool resolve_conflict() { + while (true) { + if (!resolve_conflict_core()) return false; + if (!inconsistent()) return true; + } + } + + unsigned get_max_lvl(unsigned conflict_l, justification const& conflict_j) { + if (scope_lvl() == 0) return 0; + unsigned r = lvl(conflict_l); + if (conflict_j.is_clause()) { + unsigned clause = conflict_j.clause(); + vector const& S = (value(clause) == l_true)?m_F:m_T; + r = std::max(r, lvl(S[clause][0])); + r = std::max(r, lvl(S[clause][1])); + } + return r; + } + + bool resolve_conflict_core() { + SASSERT(inconsistent()); + TRACE("opt", display(tout);); + unsigned conflict_l = m_conflict_l; + justification conflict_j = m_conflict_j; + m_conflict_lvl = get_max_lvl(conflict_l, conflict_j); + if (m_conflict_lvl == 0) { + return false; + } + unsigned idx = skip_above_conflict_level(); + unsigned num_marks = 0; + m_lemma.reset(); + m_lemma.push_back(0); + process_antecedent(conflict_l, num_marks); + do { + if (conflict_j.is_clause()) { + lbool val = value(conflict_l); + unsigned cl = conflict_j.clause(); + unsigned i = 0; + SASSERT(val != l_undef); + set const& T = (val == l_true)?m_T[cl]:m_F[cl]; + if (T[0] == conflict_l) { + i = 1; + } + else { + SASSERT(T[1] == conflict_l); + process_antecedent(T[0], num_marks); + i = 2; + } + unsigned sz = T.size(); + for (; i < sz; ++i) { + process_antecedent(T[i], num_marks); + } + } + while (true) { + unsigned l = m_trail[idx]; + if (is_marked(l)) break; + SASSERT(idx > 0); + --idx; + } + conflict_l = m_trail[idx]; + conflict_j = m_justification[conflict_l]; + --idx; + --num_marks; + reset_mark(conflict_l); + } + while (num_marks > 0); + m_lemma[0] = conflict_l; + + unsigned new_scope_lvl = 0; + for (unsigned i = 0; i < m_lemma.size(); ++i) { + SASSERT(l_true == value(m_lemma[i])); + new_scope_lvl = std::max(new_scope_lvl, lvl(m_lemma[i])); + reset_mark(m_lemma[i]); + } + pop(scope_lvl() - new_scope_lvl); + add_exists_false(m_lemma.size(), m_lemma.c_ptr()); + return true; + } + + void process_antecedent(unsigned antecedent, unsigned& num_marks) { + unsigned alvl = lvl(antecedent); + if (!is_marked(antecedent) && alvl > 0) { + mark(antecedent); + if (alvl <= m_conflict_lvl && value(antecedent) == l_true) { + m_lemma.push_back(antecedent); + } + else { + ++num_marks; + } + } + } + + unsigned skip_above_conflict_level() { + unsigned idx = m_trail.size(); + if (idx == 0) { + return idx; + } + idx--; + // skip literals from levels above the conflict level + while (lvl(m_trail[idx]) > m_conflict_lvl) { + SASSERT(idx > 0); + idx--; + } + return idx; + } + + void set_conflict(unsigned idx, unsigned justification) { + if (!inconsistent()) { + m_inconsistent = true; + m_conflict_j = justification; + m_conflict_l = idx; + } + } + + unsigned next_var() { + value_lt lt(m_weights, m_scores); + init_scores(); + std::sort(m_indices.begin(), m_indices.end(), lt); + unsigned idx = m_indices[0]; + if (m_scores[idx] == 0) { + idx = UINT_MAX; + } + return idx; + } + + bool decide() { + unsigned idx = next_var(); + if (idx == UINT_MAX) { + return false; + } + else { + push(); + TRACE("opt", tout << "decide " << idx << "\n";); + assign(idx, l_true, decision); + return true; + } + } + + void propagate() { + while (m_qhead < m_trail.size() && !inconsistent() && !canceled()) { unsigned idx = m_trail[m_qhead]; ++m_qhead; - switch (m_value[idx]) { + switch (value(idx)) { case l_undef: UNREACHABLE(); break; case l_true: - is_sat = propagate(idx, l_false, m_fwatch, m_F); + propagate(idx, l_false, m_fwatch, m_F); break; case l_false: - is_sat = propagate(idx, l_true, m_twatch, m_T); + propagate(idx, l_true, m_twatch, m_T); break; } } - return is_sat; + prune_branch(); } - lbool propagate(unsigned idx, lbool good_val, vector& watch, vector& Fs) + void propagate(unsigned idx, lbool good_val, vector& watch, vector& Fs) { unsigned sz = watch[idx].size(); lbool bad_val = ~good_val; - for (unsigned i = 0; i < sz; ++i) { - if (m_cancel) return l_undef; + unsigned l = 0; + for (unsigned i = 0; i < sz && !canceled(); ++i, ++l) { unsigned clause_id = watch[idx][i]; set& F = Fs[clause_id]; SASSERT(F.size() >= 2); unsigned k1 = (F[0] == idx)?0:1; unsigned k2 = 1 - k1; SASSERT(F[k1] == idx); - SASSERT(m_value[F[k1]] == bad_val); - if (m_value[F[k2]] == good_val) { + SASSERT(value(F[k1]) == bad_val); + if (value(F[k2]) == good_val) { + watch[idx][l] = watch[idx][i]; continue; } bool found = false; for (unsigned j = 2; !found && j < F.size(); ++j) { unsigned idx2 = F[j]; - if (m_value[idx2] != bad_val) { + if (value(idx2) != bad_val) { found = true; std::swap(F[k1], F[j]); - watch[idx][i] = watch[idx].back(); - watch[idx].pop_back(); - --i; - --sz; + --l; watch[idx2].push_back(clause_id); } } if (!found) { - if (m_value[F[k2]] == bad_val) { - return l_false; + if (value(F[k2]) == bad_val) { + set_conflict(F[k2], clause_id); + return; } - SASSERT(m_value[F[k2]] == l_undef); + SASSERT(value(F[k2]) == l_undef); assign(F[k2], good_val, clause_id); + watch[idx][l] = watch[idx][i]; } } - return l_true; + watch[idx].shrink(l); + } + + void prune_branch() { + // TBD: make this more powerful + // by using L1, L2, L3 pruning criteria. + if (m_weight >= m_max_weight) { + m_inconsistent = true; + } } From 84d971b69ac742541605f2cb0ca539f1f31269be Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 17 Jun 2014 17:05:05 -0700 Subject: [PATCH 421/925] working on HS Signed-off-by: Nikolaj Bjorner --- src/opt/hitting_sets.cpp | 122 +++++++++++++++++++++++++++++-------- src/qe/qe_arith_plugin.cpp | 3 + 2 files changed, 99 insertions(+), 26 deletions(-) diff --git a/src/opt/hitting_sets.cpp b/src/opt/hitting_sets.cpp index 96661dd75..0b7613400 100644 --- a/src/opt/hitting_sets.cpp +++ b/src/opt/hitting_sets.cpp @@ -38,14 +38,23 @@ namespace opt { private: kind_t m_kind; unsigned m_value; + bool m_pos; public: - justification(kind_t k):m_kind(k), m_value(0) {} - justification(unsigned v):m_kind(CLAUSE), m_value(v) {} + explicit justification(kind_t k):m_kind(k), m_value(0), m_pos(false) {} + explicit justification(unsigned v, bool pos):m_kind(CLAUSE), m_value(v), m_pos(pos) {} + explicit justification(justification const& other): m_kind(other.m_kind), m_value(other.m_value), m_pos(other.m_pos) {} + justification& operator=(justification const& other) { + m_kind = other.m_kind; + m_value = other.m_value; + m_pos = other.m_pos; + return *this; + } unsigned clause() const { return m_value; } bool is_axiom() const { return m_kind == AXIOM; } bool is_decision() const { return m_kind == DECISION; } bool is_clause() const { return m_kind == CLAUSE; } kind_t kind() const { return m_kind; } + bool pos() const { return m_pos; } }; volatile bool m_cancel; rational m_lower; @@ -92,9 +101,7 @@ namespace opt { sat::solver m_solver; svector m_vars; - static unsigned const null_clause = UINT_MAX; - static unsigned const axiom = UINT_MAX-1; - static unsigned const decision = UINT_MAX-2; + static unsigned const null_idx = UINT_MAX; imp(): m_cancel(false), @@ -102,6 +109,7 @@ namespace opt { m_denominator(1), m_weights_var(0), m_qhead(0), + m_scope_lvl(0), m_conflict_j(justification(justification::AXIOM)), m_inconsistent(false), m_solver(m_params,0) { @@ -118,13 +126,14 @@ namespace opt { m_simplex.set_upper(var, mpq_inf(mpq(1),mpq(0))); m_weights.push_back(w); m_value.push_back(l_undef); - m_justification.push_back(null_clause); + m_justification.push_back(justification(justification::DECISION)); m_tuse_list.push_back(unsigned_vector()); m_fuse_list.push_back(unsigned_vector()); m_twatch.push_back(unsigned_vector()); m_fwatch.push_back(unsigned_vector()); m_level.push_back(0); m_indices.push_back(var); + m_model.push_back(l_undef); m_mark.push_back(false); m_scores.push_back(0); m_max_weight += w; @@ -150,7 +159,7 @@ namespace opt { } init_weights(); if (sz == 1) { - assign(S[0], val, axiom); + assign(S[0], val, justification(justification::AXIOM)); } else { watch[S[0]].push_back(Sets.size()); @@ -179,7 +188,8 @@ namespace opt { lbool compute_upper() { m_upper = m_max_weight; - return U1(); + return search(); + // return U1(); } rational get_lower() { @@ -283,6 +293,25 @@ namespace opt { out << "\n"; } + void display(std::ostream& out, justification const& j) const { + switch(j.kind()) { + case justification::AXIOM: + out << "axiom\n"; + break; + case justification::DECISION: + out << "decision\n"; + break; + case justification::CLAUSE: { + out << "clause: "; + set const& S = j.pos()?m_T[j.clause()]:m_F[j.clause()]; + for (unsigned i = 0; i < S.size(); ++i) { + out << S[i] << " "; + } + out << "\n"; + } + } + } + struct scoped_select { imp& s; unsigned sz; @@ -346,7 +375,7 @@ namespace opt { } } IF_VERBOSE(1, verbose_stream() << "(hs.unselect " << j << ")\n";); - assign(j, l_false, decision); + assign(j, l_false, justification(justification::DECISION)); for (i = 0; i < m_T.size(); ++i) { set const& S = m_T[i]; for (j = 0; j < S.size(); ++j) { @@ -423,7 +452,7 @@ namespace opt { if (m_scores[idx] == 0) { break; } - assign(idx, l_true, decision); + assign(idx, l_true, justification(justification::DECISION)); } m_upper = m_weight; m_model.reset(); @@ -458,7 +487,7 @@ namespace opt { if (!has_selected(S)) { w += m_weights[select_min(S)]; for (unsigned j = 0; j < S.size(); ++j) { - assign(S[j], l_true, decision); + assign(S[j], l_true, justification(justification::DECISION)); } } } @@ -631,7 +660,7 @@ namespace opt { } } - void assign(unsigned j, lbool val, unsigned justification) { + void assign(unsigned j, lbool val, justification const& justification) { if (val == l_true) { m_weight += m_weights[j]; } @@ -652,6 +681,7 @@ namespace opt { } TRACE("opt", tout << m_weight << "\n";); m_trail.shrink(sz); + m_qhead = sz; } @@ -669,13 +699,36 @@ namespace opt { if (!decide()) { m_model.reset(); m_model.append(m_value); + SASSERT(validate_model()); m_upper = m_weight; - SASSERT(m_weight < m_max_weight); + // SASSERT(m_weight < m_max_weight); return l_true; } } } + bool validate_model() { + for (unsigned i = 0; i < m_T.size(); ++i) { + set const& S = m_T[i]; + bool found = false; + for (unsigned j = 0; !found && j < S.size(); ++j) { + found = value(S[j]) == l_true; + } + SASSERT(found); + } + for (unsigned i = 0; i < m_F.size(); ++i) { + set const& S = m_F[i]; + bool found = false; + for (unsigned j = 0; !found && j < S.size(); ++j) { + found = value(S[j]) != l_true; + } + CTRACE("opt", !found, display(tout << "not found: " << i << "\n", S);); + SASSERT(found); + } + + return true; + } + bool resolve_conflict() { while (true) { if (!resolve_conflict_core()) return false; @@ -688,7 +741,7 @@ namespace opt { unsigned r = lvl(conflict_l); if (conflict_j.is_clause()) { unsigned clause = conflict_j.clause(); - vector const& S = (value(clause) == l_true)?m_F:m_T; + vector const& S = conflict_j.pos()?m_T:m_F; r = std::max(r, lvl(S[clause][0])); r = std::max(r, lvl(S[clause][1])); } @@ -699,7 +752,7 @@ namespace opt { SASSERT(inconsistent()); TRACE("opt", display(tout);); unsigned conflict_l = m_conflict_l; - justification conflict_j = m_conflict_j; + justification conflict_j(m_conflict_j); m_conflict_lvl = get_max_lvl(conflict_l, conflict_j); if (m_conflict_lvl == 0) { return false; @@ -710,12 +763,13 @@ namespace opt { m_lemma.push_back(0); process_antecedent(conflict_l, num_marks); do { + TRACE("opt", tout << "conflict literal: " << conflict_l << "\n"; + display(tout, conflict_j);); if (conflict_j.is_clause()) { - lbool val = value(conflict_l); unsigned cl = conflict_j.clause(); unsigned i = 0; - SASSERT(val != l_undef); - set const& T = (val == l_true)?m_T[cl]:m_F[cl]; + SASSERT(value(conflict_l) != l_undef); + set const& T = conflict_j.pos()?m_T[cl]:m_F[cl]; if (T[0] == conflict_l) { i = 1; } @@ -745,6 +799,11 @@ namespace opt { m_lemma[0] = conflict_l; unsigned new_scope_lvl = 0; + TRACE("opt", + for (unsigned i = 0; i < m_lemma.size(); ++i) { + tout << m_lemma[i] << " "; + } + tout << "\n";); for (unsigned i = 0; i < m_lemma.size(); ++i) { SASSERT(l_true == value(m_lemma[i])); new_scope_lvl = std::max(new_scope_lvl, lvl(m_lemma[i])); @@ -757,13 +816,14 @@ namespace opt { void process_antecedent(unsigned antecedent, unsigned& num_marks) { unsigned alvl = lvl(antecedent); + SASSERT(alvl <= m_conflict_lvl); if (!is_marked(antecedent) && alvl > 0) { mark(antecedent); - if (alvl <= m_conflict_lvl && value(antecedent) == l_true) { - m_lemma.push_back(antecedent); + if (alvl == m_conflict_lvl) { + ++num_marks; } else { - ++num_marks; + m_lemma.push_back(antecedent); } } } @@ -782,8 +842,9 @@ namespace opt { return idx; } - void set_conflict(unsigned idx, unsigned justification) { + void set_conflict(unsigned idx, justification const& justification) { if (!inconsistent()) { + TRACE("opt", tout << "conflict: " << idx << "\n";); m_inconsistent = true; m_conflict_j = justification; m_conflict_l = idx; @@ -809,7 +870,7 @@ namespace opt { else { push(); TRACE("opt", tout << "decide " << idx << "\n";); - assign(idx, l_true, decision); + assign(idx, l_true, justification(justification::DECISION)); return true; } } @@ -830,11 +891,12 @@ namespace opt { break; } } - prune_branch(); + //prune_branch(); } void propagate(unsigned idx, lbool good_val, vector& watch, vector& Fs) { + TRACE("opt", tout << idx << "\n";); unsigned sz = watch[idx].size(); lbool bad_val = ~good_val; unsigned l = 0; @@ -862,11 +924,11 @@ namespace opt { } if (!found) { if (value(F[k2]) == bad_val) { - set_conflict(F[k2], clause_id); + set_conflict(F[k2], justification(clause_id, good_val == l_true)); return; } SASSERT(value(F[k2]) == l_undef); - assign(F[k2], good_val, clause_id); + assign(F[k2], good_val, justification(clause_id, good_val == l_true)); watch[idx][l] = watch[idx][i]; } } @@ -878,6 +940,14 @@ namespace opt { // by using L1, L2, L3 pruning criteria. if (m_weight >= m_max_weight) { m_inconsistent = true; + for (unsigned i = m_trail.size(); i > 0; ) { + --i; + if (value(m_trail[i]) == l_true) { + m_conflict_l = m_trail[i]; + m_conflict_j = m_justification[m_conflict_l]; + break; + } + } } } diff --git a/src/qe/qe_arith_plugin.cpp b/src/qe/qe_arith_plugin.cpp index 7bf0978f6..5a2866ba5 100644 --- a/src/qe/qe_arith_plugin.cpp +++ b/src/qe/qe_arith_plugin.cpp @@ -2043,6 +2043,7 @@ public: // z < d expr* z_lt_d = m_util.m_arith.mk_le(z, m_util.m_arith.mk_numeral(d-rational(1), true)); m_ctx.add_constraint(false, z_lt_d); + TRACE("qe", tout << mk_pp(z_lt_d, m) << "\n";); // result <- result & z <= d - 1 SASSERT(!abs(d).is_one()); @@ -2056,9 +2057,11 @@ public: t1 = m_util.mk_sub(x, z); m_util.mk_divides(d, t1, new_atom); m_ctx.add_constraint(false, new_atom); + TRACE("qe", tout << mk_pp(new_atom, m) << "\n";); // (c | ax + t <-> c | az + t) for each divisor. mk_div_equivs(bounds, z, result); + TRACE("qe", tout << mk_pp(result, m) << "\n";); // update x_t to map x |-> dx + z x_t.set_term(z); From d7d85aa18aa87919f6fceb15a9fcb0199c69d1c6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 17 Jun 2014 22:32:32 -0700 Subject: [PATCH 422/925] working on HS Signed-off-by: Nikolaj Bjorner --- src/opt/hitting_sets.cpp | 112 +++++++++++++++++++++++++++------------ 1 file changed, 79 insertions(+), 33 deletions(-) diff --git a/src/opt/hitting_sets.cpp b/src/opt/hitting_sets.cpp index 0b7613400..7695850a9 100644 --- a/src/opt/hitting_sets.cpp +++ b/src/opt/hitting_sets.cpp @@ -140,30 +140,33 @@ namespace opt { m_vars.push_back(m_solver.mk_var()); } - void add_exists_false(unsigned sz, unsigned const* S) { - add_exists(sz, S, true); + unsigned add_exists_false(unsigned sz, unsigned const* S) { + return add_exists(sz, S, true); } - void add_exists_true(unsigned sz, unsigned const* S) { - add_exists(sz, S, false); + unsigned add_exists_true(unsigned sz, unsigned const* S) { + return add_exists(sz, S, false); } - void add_exists(unsigned sz, unsigned const* S, bool sign) { + unsigned add_exists(unsigned sz, unsigned const* S, bool sign) { vector& use_list = sign?m_fuse_list:m_tuse_list; lbool val = sign?l_false:l_true; + unsigned clause_id; vector& Sets = sign?m_F:m_T; vector& watch = sign?m_fwatch:m_twatch; SASSERT(sz > 0); for (unsigned i = 0; i < sz; ++i) { use_list[S[i]].push_back(Sets.size()); } - init_weights(); + init_weights(); if (sz == 1) { + clause_id = UINT_MAX; assign(S[0], val, justification(justification::AXIOM)); } else { - watch[S[0]].push_back(Sets.size()); - watch[S[1]].push_back(Sets.size()); + clause_id = Sets.size(); + watch[S[0]].push_back(clause_id); + watch[S[1]].push_back(clause_id); Sets.push_back(unsigned_vector(sz, S)); } add_simplex_row(!sign, sz, S); @@ -173,6 +176,7 @@ namespace opt { lits.push_back(sat::literal(m_vars[S[i]], sign)); } m_solver.mk_clause(lits.size(), lits.c_ptr()); + return clause_id; } lbool compute_lower() { @@ -257,18 +261,18 @@ namespace opt { } void display(std::ostream& out) const { - for (unsigned i = 0; i < m_weights.size(); ++i) { - out << i << ": " << m_model[i]<< " " << m_weights[i] << "\n"; - } - for (unsigned i = 0; i < m_T.size(); ++i) { - display(out << "+ ", m_T[i]); - } - for (unsigned i = 0; i < m_F.size(); ++i) { - display(out << "- ", m_F[i]); - } out << "inconsistent: " << m_inconsistent << "\n"; out << "weight: " << m_weight << "\n"; - out << "use lists:\n"; + for (unsigned i = 0; i < m_weights.size(); ++i) { + out << i << ": " << value(i) << " " << m_weights[i] << "\n"; + } + for (unsigned i = 0; i < m_T.size(); ++i) { + display(out << "+" << i << ": ", m_T[i]); + } + for (unsigned i = 0; i < m_F.size(); ++i) { + display(out << "-" << i << ": ", m_F[i]); + } + out << "watch lists:\n"; for (unsigned i = 0; i < m_fwatch.size(); ++i) { out << i << ": "; for (unsigned j = 0; j < m_twatch[i].size(); ++j) { @@ -697,9 +701,9 @@ namespace opt { SASSERT(!inconsistent()); } if (!decide()) { + SASSERT(validate_model()); m_model.reset(); m_model.append(m_value); - SASSERT(validate_model()); m_upper = m_weight; // SASSERT(m_weight < m_max_weight); return l_true; @@ -714,6 +718,9 @@ namespace opt { for (unsigned j = 0; !found && j < S.size(); ++j) { found = value(S[j]) == l_true; } + CTRACE("opt", !found, + display(tout << "not found: " << i << "\n", S); + display(tout);); SASSERT(found); } for (unsigned i = 0; i < m_F.size(); ++i) { @@ -722,13 +729,31 @@ namespace opt { for (unsigned j = 0; !found && j < S.size(); ++j) { found = value(S[j]) != l_true; } - CTRACE("opt", !found, display(tout << "not found: " << i << "\n", S);); + CTRACE("opt", !found, + display(tout << "not found: " << i << "\n", S); + display(tout);); SASSERT(found); } return true; } + bool invariant() { + for (unsigned i = 0; i < m_fwatch.size(); ++i) { + for (unsigned j = 0; j < m_fwatch[i].size(); ++j) { + set const& S = m_F[m_fwatch[i][j]]; + SASSERT(S[0] == i || S[1] == i); + } + } + for (unsigned i = 0; i < m_twatch.size(); ++i) { + for (unsigned j = 0; j < m_twatch[i].size(); ++j) { + set const& S = m_T[m_twatch[i][j]]; + SASSERT(S[0] == i || S[1] == i); + } + } + return true; + } + bool resolve_conflict() { while (true) { if (!resolve_conflict_core()) return false; @@ -798,19 +823,23 @@ namespace opt { while (num_marks > 0); m_lemma[0] = conflict_l; - unsigned new_scope_lvl = 0; TRACE("opt", for (unsigned i = 0; i < m_lemma.size(); ++i) { - tout << m_lemma[i] << " "; + tout << m_lemma[i] << " " << value(m_lemma[i]) << " "; } tout << "\n";); - for (unsigned i = 0; i < m_lemma.size(); ++i) { + unsigned new_scope_lvl = 0; + for (unsigned i = 1; i < m_lemma.size(); ++i) { SASSERT(l_true == value(m_lemma[i])); new_scope_lvl = std::max(new_scope_lvl, lvl(m_lemma[i])); reset_mark(m_lemma[i]); } pop(scope_lvl() - new_scope_lvl); - add_exists_false(m_lemma.size(), m_lemma.c_ptr()); + SASSERT(l_undef == value(conflict_l)); + unsigned clause_id = add_exists_false(m_lemma.size(), m_lemma.c_ptr()); + if (clause_id != UINT_MAX) { + assign(conflict_l, l_false, justification(clause_id, false)); + } return true; } @@ -819,7 +848,7 @@ namespace opt { SASSERT(alvl <= m_conflict_lvl); if (!is_marked(antecedent) && alvl > 0) { mark(antecedent); - if (alvl == m_conflict_lvl) { + if (alvl == m_conflict_lvl || value(antecedent) == l_false) { ++num_marks; } else { @@ -876,6 +905,8 @@ namespace opt { } void propagate() { + TRACE("opt", display(tout);); + SASSERT(invariant()); while (m_qhead < m_trail.size() && !inconsistent() && !canceled()) { unsigned idx = m_trail[m_qhead]; ++m_qhead; @@ -896,9 +927,10 @@ namespace opt { void propagate(unsigned idx, lbool good_val, vector& watch, vector& Fs) { - TRACE("opt", tout << idx << "\n";); + TRACE("opt", tout << idx << " " << value(idx) << "\n";); unsigned sz = watch[idx].size(); lbool bad_val = ~good_val; + SASSERT(value(idx) == bad_val); unsigned l = 0; for (unsigned i = 0; i < sz && !canceled(); ++i, ++l) { unsigned clause_id = watch[idx][i]; @@ -925,20 +957,32 @@ namespace opt { if (!found) { if (value(F[k2]) == bad_val) { set_conflict(F[k2], justification(clause_id, good_val == l_true)); - return; + for (; l <= i && i < sz; ++i, ++l) { + watch[idx][l] = watch[idx][i]; + } + break; + } + else { + SASSERT(value(F[k2]) == l_undef); + assign(F[k2], good_val, justification(clause_id, good_val == l_true)); + watch[idx][l] = watch[idx][i]; } - SASSERT(value(F[k2]) == l_undef); - assign(F[k2], good_val, justification(clause_id, good_val == l_true)); - watch[idx][l] = watch[idx][i]; } } watch[idx].shrink(l); + SASSERT(invariant()); + TRACE("opt", tout << idx << " " << value(idx) << "\n";); + SASSERT(value(idx) == bad_val); + } + + bool infeasible_lookahead() { + // TBD: make this more powerful + // by using L1, L2, L3 pruning criteria. + return (m_weight >= m_max_weight); } void prune_branch() { - // TBD: make this more powerful - // by using L1, L2, L3 pruning criteria. - if (m_weight >= m_max_weight) { + if (infeasible_lookahead()) { m_inconsistent = true; for (unsigned i = m_trail.size(); i > 0; ) { --i; @@ -951,6 +995,8 @@ namespace opt { } } + // TBD: derive strong inequalities and add them to Simplex. + // x_i1 + .. + x_ik >= k-1 for each subset k from set n: x_1 + .. + x_n >= k }; hitting_sets::hitting_sets() { m_imp = alloc(imp); } From 04407938bee9e715138d9288a69283e391aeca11 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 18 Jun 2014 17:31:00 -0700 Subject: [PATCH 423/925] custom HS solver Signed-off-by: Nikolaj Bjorner --- src/opt/hitting_sets.cpp | 342 +++++++++++++++++---------------------- 1 file changed, 147 insertions(+), 195 deletions(-) diff --git a/src/opt/hitting_sets.cpp b/src/opt/hitting_sets.cpp index 7695850a9..3d815ddc6 100644 --- a/src/opt/hitting_sets.cpp +++ b/src/opt/hitting_sets.cpp @@ -22,7 +22,6 @@ Notes: #include "simplex.h" #include "sparse_matrix_def.h" #include "simplex_def.h" -#include "sat_solver.h" typedef simplex::simplex Simplex; typedef simplex::sparse_matrix sparse_matrix; @@ -42,7 +41,7 @@ namespace opt { public: explicit justification(kind_t k):m_kind(k), m_value(0), m_pos(false) {} explicit justification(unsigned v, bool pos):m_kind(CLAUSE), m_value(v), m_pos(pos) {} - explicit justification(justification const& other): m_kind(other.m_kind), m_value(other.m_value), m_pos(other.m_pos) {} + justification(justification const& other): m_kind(other.m_kind), m_value(other.m_value), m_pos(other.m_pos) {} justification& operator=(justification const& other) { m_kind = other.m_kind; m_value = other.m_value; @@ -96,11 +95,6 @@ namespace opt { Simplex m_simplex; unsigned m_weights_var; - // sat solver - params_ref m_params; - sat::solver m_solver; - svector m_vars; - static unsigned const null_idx = UINT_MAX; imp(): @@ -111,10 +105,7 @@ namespace opt { m_qhead(0), m_scope_lvl(0), m_conflict_j(justification(justification::AXIOM)), - m_inconsistent(false), - m_solver(m_params,0) { - m_params.set_bool("elim_vars", false); - m_solver.updt_params(m_params); + m_inconsistent(false) { } ~imp() {} @@ -137,46 +128,49 @@ namespace opt { m_mark.push_back(false); m_scores.push_back(0); m_max_weight += w; - m_vars.push_back(m_solver.mk_var()); } - unsigned add_exists_false(unsigned sz, unsigned const* S) { + justification add_exists_false(unsigned sz, unsigned const* S) { return add_exists(sz, S, true); } - unsigned add_exists_true(unsigned sz, unsigned const* S) { + justification add_exists_true(unsigned sz, unsigned const* S) { return add_exists(sz, S, false); } - unsigned add_exists(unsigned sz, unsigned const* S, bool sign) { + justification add_exists(unsigned sz, unsigned const* S, bool sign) { vector& use_list = sign?m_fuse_list:m_tuse_list; lbool val = sign?l_false:l_true; - unsigned clause_id; + justification j(justification::AXIOM); vector& Sets = sign?m_F:m_T; vector& watch = sign?m_fwatch:m_twatch; - SASSERT(sz > 0); - for (unsigned i = 0; i < sz; ++i) { - use_list[S[i]].push_back(Sets.size()); - } init_weights(); - if (sz == 1) { - clause_id = UINT_MAX; + if (sz == 0) { + // TBD + IF_VERBOSE(0, verbose_stream() << "empty clause\n";); + set_conflict(0, justification(justification::AXIOM)); + } + else if (sz == 1) { + IF_VERBOSE(1, verbose_stream() << "unit literal : " << S[0] << " " << val << "\n";); assign(S[0], val, justification(justification::AXIOM)); } else { - clause_id = Sets.size(); + unsigned clause_id = Sets.size(); + for (unsigned i = 0; i < sz; ++i) { + use_list[S[i]].push_back(clause_id); + } + j = justification(clause_id, !sign); watch[S[0]].push_back(clause_id); watch[S[1]].push_back(clause_id); Sets.push_back(unsigned_vector(sz, S)); + if (!sign) { + pop(scope_lvl()); + inc_score(clause_id); + } + TRACE("opt", display(tout, j);); + // add_simplex_row(!sign, sz, S); } - add_simplex_row(!sign, sz, S); - // Add clause to SAT solver: - svector lits; - for (unsigned i = 0; i < sz; ++i) { - lits.push_back(sat::literal(m_vars[S[i]], sign)); - } - m_solver.mk_clause(lits.size(), lits.c_ptr()); - return clause_id; + return j; } lbool compute_lower() { @@ -192,8 +186,30 @@ namespace opt { lbool compute_upper() { m_upper = m_max_weight; - return search(); - // return U1(); + unsigned fsz = m_F.size(); + lbool r = search(); + pop(scope_lvl()); + + std::cout << m_T.size() << " " << m_F.size() << "\n"; + + // garbage collect agressively on exit. + // all learned clases for negative branches are + // pruned. + m_F.resize(fsz); + for (unsigned i = 0; i < m_fuse_list.size(); ++i) { + unsigned_vector & uses = m_fuse_list[i]; + while (!uses.empty() && uses.back() >= fsz) uses.pop_back(); + unsigned_vector & watch = m_fwatch[i]; + unsigned j = 0, k = 0; + for (; j < watch.size(); ++j) { + if (watch[j] < fsz) { + watch[k] = watch[j]; + ++k; + } + } + watch.resize(k); + } + return r; } rational get_lower() { @@ -217,12 +233,10 @@ namespace opt { void set_cancel(bool f) { m_cancel = f; m_simplex.set_cancel(f); - m_solver.set_cancel(f); } void collect_statistics(::statistics& st) const { m_simplex.collect_statistics(st); - m_solver.collect_statistics(st); } void reset() { @@ -264,7 +278,7 @@ namespace opt { out << "inconsistent: " << m_inconsistent << "\n"; out << "weight: " << m_weight << "\n"; for (unsigned i = 0; i < m_weights.size(); ++i) { - out << i << ": " << value(i) << " " << m_weights[i] << "\n"; + out << i << ": " << value(i) << " w: " << m_weights[i] << " s: " << m_scores[i] << "\n"; } for (unsigned i = 0; i < m_T.size(); ++i) { display(out << "+" << i << ": ", m_T[i]); @@ -345,139 +359,33 @@ namespace opt { } }; - lbool U1() { - scoped_select _sc(*this); - while (true) { - lbool is_sat = compute_U1(); - if (is_sat != l_true) { - return is_sat; + void inc_score(unsigned clause_id) { + set const& S = m_T[clause_id]; + if (!has_selected(S)) { + for (unsigned j = 0; j < S.size(); ++j) { + ++m_scores[S[j]]; } - unsigned i = 0, j = 0; - set_undef_to_false(); - if (values_satisfy_Fs(i)) { - if (m_upper > m_max_weight) { - IF_VERBOSE(1, verbose_stream() << "(hs.bound_degradation " << m_upper << " )\n";); - } - return l_true; - } - - // - // pick some unsatisfied clause from m_F, - // and set the value of the most expensive - // literal to true. - // - - IF_VERBOSE(1, verbose_stream() << "(hs.refining exclusion set " << i << ")\n";); - set const& F = m_F[i]; - rational max_value(0); - j = 0; - for (i = 0; i < F.size(); ++i) { - SASSERT(m_model[F[i]] == l_true); - if (max_value < m_weights[F[i]]) { - max_value = m_weights[F[i]]; - j = F[i]; - } - } - IF_VERBOSE(1, verbose_stream() << "(hs.unselect " << j << ")\n";); - assign(j, l_false, justification(justification::DECISION)); - for (i = 0; i < m_T.size(); ++i) { - set const& S = m_T[i]; - for (j = 0; j < S.size(); ++j) { - if (l_false != value(S[j])) break; - } - if (j == S.size()) { - IF_VERBOSE(1, verbose_stream() << "(hs.fallback-to-SAT)\n";); - return compute_U2(); - } - } - TRACE("opt", display(tout);); } } - lbool compute_U2() { - lbool is_sat = l_true; - while (true) { - is_sat = m_solver.check(); - if (is_sat == l_true) { - sat::model const& model = m_solver.get_model(); - m_model.reset(); - m_upper.reset(); - for (unsigned i = 0; i < m_vars.size(); ++i) { - m_model.push_back(model[m_vars[i]]); - if (model[m_vars[i]] == l_true) { - m_upper += m_weights[i]; - } - } - IF_VERBOSE(1, verbose_stream() << "(hs.upper " << m_upper << ")\n";); - m_solver.pop(m_solver.scope_lvl()); - + void dec_score(unsigned clause_id) { + set const& S = m_T[clause_id]; + if (!has_selected(S)) { + for (unsigned j = 0; j < S.size(); ++j) { + SASSERT(m_scores[S[j]] > 0); + --m_scores[S[j]]; } - break; } - return is_sat; } - bool block_model(sat::model const& model) { - rational value(0); - svector lits; - for (unsigned i = 0; i < m_vars.size(); ++i) { - if (value >= m_max_weight) { - m_solver.mk_clause(lits.size(), lits.c_ptr()); - return true; + void update_score(unsigned idx, bool inc) { + unsigned_vector const& uses = m_tuse_list[idx]; + for (unsigned i = 0; i < uses.size(); ++i) { + if (inc) { + inc_score(uses[i]); } - if (model[m_vars[i]] == l_true) { - value += m_weights[i]; - lits.push_back(sat::literal(m_vars[i], true)); - } - } - return false; - } - - // compute upper bound for hitting set. - lbool compute_U1() { - rational w(0); - scoped_select _sc(*this); - - // score each variable by the number of - // unassigned sets they occur in. - - // - // Sort indices. - // The least literals are those where score/w is maximized. - // - value_lt lt(m_weights, m_scores); - while (true) { - if (canceled()) { - return l_undef; - } - init_scores(); - std::sort(m_indices.begin(), m_indices.end(), lt); - unsigned idx = m_indices[0]; - if (m_scores[idx] == 0) { - break; - } - assign(idx, l_true, justification(justification::DECISION)); - } - m_upper = m_weight; - m_model.reset(); - m_model.append(m_value); - return l_true; - } - - void init_scores() { - unsigned_vector & scores = m_scores; - scores.reset(); - for (unsigned i = 0; i < m_value.size(); ++i) { - scores.push_back(0); - } - for (unsigned i = 0; i < m_T.size(); ++i) { - set const& S = m_T[i]; - if (!has_selected(S)) { - for (unsigned j = 0; j < S.size(); ++j) { - if (value(S[j]) != l_false) { - ++scores[S[j]]; - } - } + else { + dec_score(uses[i]); } } } @@ -508,7 +416,6 @@ namespace opt { for (unsigned i = 0; i < m_T.size(); ++i) { if (!has_selected(m_T[i])) ++n; } - init_scores(); value_lt lt(m_weights, m_scores); std::sort(m_indices.begin(), m_indices.end(), lt); @@ -664,28 +571,47 @@ namespace opt { } } - void assign(unsigned j, lbool val, justification const& justification) { + void assign(unsigned idx, lbool val, justification const& justification) { if (val == l_true) { - m_weight += m_weights[j]; + m_weight += m_weights[idx]; + update_score(idx, false); } - m_value[j] = val; - m_justification[j] = justification; - m_trail.push_back(j); - m_level[j] = scope_lvl(); - TRACE("opt", tout << j << " := " << val << " scope: " << scope_lvl() << " w: " << m_weight << "\n";); + SASSERT(val != l_true || m_scores[idx] == 0); + m_value[idx] = val; + m_justification[idx] = justification; + m_trail.push_back(idx); + m_level[idx] = scope_lvl(); + TRACE("opt", tout << idx << " := " << val << " scope: " << scope_lvl() << " w: " << m_weight << "\n";); } + + svector m_replay_idx; + svector m_replay_val; void unassign(unsigned sz) { for (unsigned j = sz; j < m_trail.size(); ++j) { - unsigned idx = m_trail[j]; - if (value(idx) == l_true) { - m_weight -= m_weights[idx]; - } + unsigned idx = m_trail[j]; + lbool val = value(idx); m_value[idx] = l_undef; + if (val == l_true) { + m_weight -= m_weights[idx]; + update_score(idx, true); + } + if (m_justification[idx].is_axiom()) { + m_replay_idx.push_back(idx); + m_replay_val.push_back(val); + } } TRACE("opt", tout << m_weight << "\n";); m_trail.shrink(sz); m_qhead = sz; + for (unsigned i = m_replay_idx.size(); i > 0; ) { + --i; + unsigned idx = m_replay_idx[i]; + lbool val = m_replay_val[i]; + assign(idx, val, justification(justification::AXIOM)); + } + m_replay_idx.reset(); + m_replay_val.reset(); } @@ -778,6 +704,9 @@ namespace opt { TRACE("opt", display(tout);); unsigned conflict_l = m_conflict_l; justification conflict_j(m_conflict_j); + if (conflict_j.is_axiom()) { + return false; + } m_conflict_lvl = get_max_lvl(conflict_l, conflict_j); if (m_conflict_lvl == 0) { return false; @@ -808,6 +737,17 @@ namespace opt { process_antecedent(T[i], num_marks); } } + else if (conflict_j.is_decision()) { + --num_marks; + SASSERT(num_marks == 0); + break; + } + else if (conflict_j.is_axiom()) { + IF_VERBOSE(0, verbose_stream() << "axiom " << conflict_l << " " << value(conflict_l) << " " << num_marks << "\n";); + --num_marks; + SASSERT(num_marks == 0); + break; + } while (true) { unsigned l = m_trail[idx]; if (is_marked(l)) break; @@ -818,16 +758,19 @@ namespace opt { conflict_j = m_justification[conflict_l]; --idx; --num_marks; + if (num_marks == 0 && value(conflict_l) == l_false) { + ++num_marks; + } reset_mark(conflict_l); } while (num_marks > 0); m_lemma[0] = conflict_l; - TRACE("opt", for (unsigned i = 0; i < m_lemma.size(); ++i) { - tout << m_lemma[i] << " " << value(m_lemma[i]) << " "; + tout << m_lemma[i] << " "; } tout << "\n";); + SASSERT(value(conflict_l) == l_true); unsigned new_scope_lvl = 0; for (unsigned i = 1; i < m_lemma.size(); ++i) { SASSERT(l_true == value(m_lemma[i])); @@ -836,17 +779,16 @@ namespace opt { } pop(scope_lvl() - new_scope_lvl); SASSERT(l_undef == value(conflict_l)); - unsigned clause_id = add_exists_false(m_lemma.size(), m_lemma.c_ptr()); - if (clause_id != UINT_MAX) { - assign(conflict_l, l_false, justification(clause_id, false)); - } + justification j = add_exists_false(m_lemma.size(), m_lemma.c_ptr()); + if (!j.is_axiom()) assign(conflict_l, l_false, j); return true; } + void process_antecedent(unsigned antecedent, unsigned& num_marks) { unsigned alvl = lvl(antecedent); SASSERT(alvl <= m_conflict_lvl); - if (!is_marked(antecedent) && alvl > 0) { + if (!is_marked(antecedent) && alvl > 0 && !m_justification[antecedent].is_axiom()) { mark(antecedent); if (alvl == m_conflict_lvl || value(antecedent) == l_false) { ++num_marks; @@ -882,7 +824,6 @@ namespace opt { unsigned next_var() { value_lt lt(m_weights, m_scores); - init_scores(); std::sort(m_indices.begin(), m_indices.end(), lt); unsigned idx = m_indices[0]; if (m_scores[idx] == 0) { @@ -922,18 +863,19 @@ namespace opt { break; } } - //prune_branch(); + prune_branch(); } void propagate(unsigned idx, lbool good_val, vector& watch, vector& Fs) { TRACE("opt", tout << idx << " " << value(idx) << "\n";); - unsigned sz = watch[idx].size(); + unsigned_vector& w = watch[idx]; + unsigned sz = w.size(); lbool bad_val = ~good_val; SASSERT(value(idx) == bad_val); unsigned l = 0; for (unsigned i = 0; i < sz && !canceled(); ++i, ++l) { - unsigned clause_id = watch[idx][i]; + unsigned clause_id = w[i]; set& F = Fs[clause_id]; SASSERT(F.size() >= 2); unsigned k1 = (F[0] == idx)?0:1; @@ -941,11 +883,12 @@ namespace opt { SASSERT(F[k1] == idx); SASSERT(value(F[k1]) == bad_val); if (value(F[k2]) == good_val) { - watch[idx][l] = watch[idx][i]; + w[l] = w[i]; continue; } bool found = false; - for (unsigned j = 2; !found && j < F.size(); ++j) { + unsigned sz2 = F.size(); + for (unsigned j = 2; !found && j < sz2; ++j) { unsigned idx2 = F[j]; if (value(idx2) != bad_val) { found = true; @@ -957,15 +900,20 @@ namespace opt { if (!found) { if (value(F[k2]) == bad_val) { set_conflict(F[k2], justification(clause_id, good_val == l_true)); - for (; l <= i && i < sz; ++i, ++l) { - watch[idx][l] = watch[idx][i]; + if (i == l) { + l = sz; + } + else { + for (; i < sz; ++i, ++l) { + w[l] = w[i]; + } } break; } else { SASSERT(value(F[k2]) == l_undef); assign(F[k2], good_val, justification(clause_id, good_val == l_true)); - watch[idx][l] = watch[idx][i]; + w[l] = w[i]; } } } @@ -982,16 +930,20 @@ namespace opt { } void prune_branch() { - if (infeasible_lookahead()) { - m_inconsistent = true; + if (!inconsistent() && infeasible_lookahead()) { + IF_VERBOSE(4, verbose_stream() << "(hs.prune-branch " << m_weight << ")\n";); + m_lemma.reset(); for (unsigned i = m_trail.size(); i > 0; ) { --i; - if (value(m_trail[i]) == l_true) { - m_conflict_l = m_trail[i]; - m_conflict_j = m_justification[m_conflict_l]; - break; - } + unsigned idx = m_trail[i]; + if (m_justification[idx].is_decision()) { + SASSERT(value(idx) == l_true); + m_lemma.push_back(idx); + } } + justification j = add_exists_false(m_lemma.size(), m_lemma.c_ptr()); + TRACE("opt", display(tout, j);); + set_conflict(m_lemma[0], j); } } From 519c9dba251e1f5ef5b2eb6460d7b61fbadf9fa3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 23 Jun 2014 11:28:38 -0700 Subject: [PATCH 424/925] update hitting set implementation Signed-off-by: Nikolaj Bjorner --- src/math/simplex/simplex_def.h | 11 ++ src/opt/hitting_sets.cpp | 302 ++++++++++++++++++++++----------- 2 files changed, 213 insertions(+), 100 deletions(-) diff --git a/src/math/simplex/simplex_def.h b/src/math/simplex/simplex_def.h index cfd557b33..daa718472 100644 --- a/src/math/simplex/simplex_def.h +++ b/src/math/simplex/simplex_def.h @@ -130,6 +130,7 @@ namespace simplex { void simplex::add_patch(var_t v) { SASSERT(is_base(v)); if (outside_bounds(v)) { + TRACE("simplex", tout << "Add patch: v" << v << "\n";); m_to_patch.insert(v); } } @@ -200,12 +201,18 @@ namespace simplex { var_info& vi = m_vars[var]; em.set(vi.m_lower, b); vi.m_lower_valid = true; + TRACE("simplex", em.display(tout << "v" << var << " lower: ", b); + em.display(tout << " value: ", vi.m_value);); SASSERT(!vi.m_upper_valid || em.le(b, vi.m_upper)); if (!vi.m_is_base && em.lt(vi.m_value, b)) { scoped_eps_numeral delta(em); em.sub(b, vi.m_value, delta); update_value(var, delta); } + else if (vi.m_is_base && em.lt(vi.m_value, b)) { + SASSERT(outside_bounds(var)); + add_patch(var); + } SASSERT(well_formed()); } @@ -220,6 +227,10 @@ namespace simplex { em.sub(b, vi.m_value, delta); update_value(var, delta); } + else if (vi.m_is_base && em.lt(b, vi.m_value)) { + SASSERT(outside_bounds(var)); + add_patch(var); + } SASSERT(well_formed()); } diff --git a/src/opt/hitting_sets.cpp b/src/opt/hitting_sets.cpp index 3d815ddc6..8cc2c0304 100644 --- a/src/opt/hitting_sets.cpp +++ b/src/opt/hitting_sets.cpp @@ -30,7 +30,6 @@ typedef simplex::sparse_matrix sparse_matrix; namespace opt { struct hitting_sets::imp { - typedef unsigned_vector set; class justification { public: enum kind_t { AXIOM, DECISION, CLAUSE }; @@ -55,14 +54,49 @@ namespace opt { kind_t kind() const { return m_kind; } bool pos() const { return m_pos; } }; + + class set { + unsigned m_num_elems; + unsigned m_elems[0]; + set(): m_num_elems(0) {} + public: + + static set* mk(small_object_allocator& alloc, unsigned sz, unsigned const* elems) { + unsigned size = (sz+1)*sizeof(unsigned); + void * mem = alloc.allocate(size); + set* result = new (mem) set(); + result->m_num_elems = sz; + memcpy(result->m_elems, elems, sizeof(unsigned)*sz); + return result; + } + + inline unsigned operator[](unsigned idx) const { + SASSERT(idx < m_num_elems); + return m_elems[idx]; + } + + inline unsigned& operator[](unsigned idx) { + SASSERT(idx < m_num_elems); + return m_elems[idx]; + } + + unsigned size() const { return m_num_elems; } + + unsigned alloc_size() const { return (m_num_elems + 1)*sizeof(unsigned); } + + bool empty() const { return 0 == size(); } + }; + volatile bool m_cancel; rational m_lower; rational m_upper; vector m_weights; + vector m_weights_inv; rational m_max_weight; rational m_denominator; - vector m_T; - vector m_F; + small_object_allocator m_alloc; + ptr_vector m_T; + ptr_vector m_F; svector m_value; svector m_model; vector m_tuse_list; @@ -82,6 +116,18 @@ namespace opt { rational m_weight; // current weight of assignment. unsigned_vector m_indices; unsigned_vector m_scores; + vector m_scored_weights; + svector m_score_updated; + bool m_enable_simplex; + struct compare_scores { + imp* m_imp; + compare_scores(imp* i):m_imp(i) {} + bool operator()(int v1, int v2) const { + return m_imp->m_scored_weights[v1] > m_imp->m_scored_weights[v2]; + } + }; + compare_scores m_compare_scores; + heap m_heap; svector m_mark; struct scope { unsigned m_trail_lim; @@ -105,7 +151,11 @@ namespace opt { m_qhead(0), m_scope_lvl(0), m_conflict_j(justification(justification::AXIOM)), - m_inconsistent(false) { + m_inconsistent(false), + m_compare_scores(this), + m_heap(0, m_compare_scores) { + m_enable_simplex = true; + } ~imp() {} @@ -116,6 +166,7 @@ namespace opt { m_simplex.set_lower(var, mpq_inf(mpq(0),mpq(0))); m_simplex.set_upper(var, mpq_inf(mpq(1),mpq(0))); m_weights.push_back(w); + m_weights_inv.push_back(rational::one()); m_value.push_back(l_undef); m_justification.push_back(justification(justification::DECISION)); m_tuse_list.push_back(unsigned_vector()); @@ -127,6 +178,8 @@ namespace opt { m_model.push_back(l_undef); m_mark.push_back(false); m_scores.push_back(0); + m_scored_weights.push_back(rational(0)); + m_score_updated.push_back(true); m_max_weight += w; } @@ -142,7 +195,7 @@ namespace opt { vector& use_list = sign?m_fuse_list:m_tuse_list; lbool val = sign?l_false:l_true; justification j(justification::AXIOM); - vector& Sets = sign?m_F:m_T; + ptr_vector& Sets = sign?m_F:m_T; vector& watch = sign?m_fwatch:m_twatch; init_weights(); if (sz == 0) { @@ -162,26 +215,28 @@ namespace opt { j = justification(clause_id, !sign); watch[S[0]].push_back(clause_id); watch[S[1]].push_back(clause_id); - Sets.push_back(unsigned_vector(sz, S)); + Sets.push_back(set::mk(m_alloc, sz, S)); if (!sign) { pop(scope_lvl()); inc_score(clause_id); } TRACE("opt", display(tout, j);); - // add_simplex_row(!sign, sz, S); + if (!sign && m_enable_simplex) { + add_simplex_row(!sign, sz, S); + } } return j; } lbool compute_lower() { m_lower.reset(); - // L3() disabled: mostly a waste of time. - if (L1() && L2()) { - return l_true; - } - else { - return l_undef; - } + rational w1 = L1(); + rational w2 = L2(); + rational w3 = L3(); + if (w1 > m_lower) m_lower = w1; + if (w2 > m_lower) m_lower = w2; + if (w3 > m_lower) m_lower = w3; + return l_true; } lbool compute_upper() { @@ -190,11 +245,14 @@ namespace opt { lbool r = search(); pop(scope_lvl()); - std::cout << m_T.size() << " " << m_F.size() << "\n"; +#if 0 // garbage collect agressively on exit. // all learned clases for negative branches are // pruned. + for (unsigned i = fsz; i < m_F.size(); ++i) { + m_alloc.deallocate(m_F[i]->alloc_size(), m_F[i]); + } m_F.resize(fsz); for (unsigned i = 0; i < m_fuse_list.size(); ++i) { unsigned_vector & uses = m_fuse_list[i]; @@ -209,6 +267,7 @@ namespace opt { } watch.resize(k); } +#endif return r; } @@ -263,6 +322,20 @@ namespace opt { m_weights[i] *= d; } } + rational lc(1); + for (unsigned i = 0; i < m_weights.size(); ++i) { + lc = lcm(lc, m_weights[i]); + } + for (unsigned i = 0; i < m_weights.size(); ++i) { + m_weights_inv[i] = lc/m_weights[i]; + } + + m_heap.set_bounds(m_weights.size()); + for (unsigned i = 0; i < m_weights.size(); ++i) { + m_heap.insert(i); + } + update_heap(); + // set up Simplex objective function. for (unsigned i = 0; i < m_weights.size(); ++i) { vars.push_back(i); @@ -272,6 +345,7 @@ namespace opt { vars.push_back(m_weights_var); coeffs.push_back(mpz(-1)); m_simplex.add_row(m_weights_var, coeffs.size(), vars.c_ptr(), coeffs.c_ptr()); + } void display(std::ostream& out) const { @@ -281,10 +355,10 @@ namespace opt { out << i << ": " << value(i) << " w: " << m_weights[i] << " s: " << m_scores[i] << "\n"; } for (unsigned i = 0; i < m_T.size(); ++i) { - display(out << "+" << i << ": ", m_T[i]); + display(out << "+" << i << ": ", *m_T[i]); } for (unsigned i = 0; i < m_F.size(); ++i) { - display(out << "-" << i << ": ", m_F[i]); + display(out << "-" << i << ": ", *m_F[i]); } out << "watch lists:\n"; for (unsigned i = 0; i < m_fwatch.size(); ++i) { @@ -321,7 +395,7 @@ namespace opt { break; case justification::CLAUSE: { out << "clause: "; - set const& S = j.pos()?m_T[j.clause()]:m_F[j.clause()]; + set const& S = j.pos()?(*m_T[j.clause()]):(*m_F[j.clause()]); for (unsigned i = 0; i < S.size(); ++i) { out << S[i] << " "; } @@ -330,50 +404,38 @@ namespace opt { } } - struct scoped_select { + struct scoped_push { imp& s; - unsigned sz; - scoped_select(imp& s):s(s), sz(s.m_trail.size()) { - } - ~scoped_select() { - s.unassign(sz); - } + scoped_push(imp& s):s(s) { s.push(); } + ~scoped_push() { s.pop(1); } }; struct value_lt { vector const& weights; - unsigned_vector const& scores; - value_lt(vector const& weights, unsigned_vector const& scores): - weights(weights), scores(scores) {} + value_lt(vector const& weights): + weights(weights) {} bool operator()(int v1, int v2) const { - // - score1 / w1 < - score2 / w2 - // <=> - // score1 / w1 > score2 / w2 - // <=> - // score1*w2 > score2*w1 - unsigned score1 = scores[v1]; - unsigned score2 = scores[v2]; - rational w1 = weights[v1]; - rational w2 = weights[v2]; - return rational(score1)*w2 > rational(score2)*w1; + return weights[v1] > weights[v2]; } }; void inc_score(unsigned clause_id) { - set const& S = m_T[clause_id]; + set const& S = *m_T[clause_id]; if (!has_selected(S)) { for (unsigned j = 0; j < S.size(); ++j) { ++m_scores[S[j]]; + m_score_updated[S[j]] = true; } } } void dec_score(unsigned clause_id) { - set const& S = m_T[clause_id]; + set const& S = *m_T[clause_id]; if (!has_selected(S)) { for (unsigned j = 0; j < S.size(); ++j) { SASSERT(m_scores[S[j]] > 0); --m_scores[S[j]]; + m_score_updated[S[j]] = true; } } } @@ -390,11 +452,11 @@ namespace opt { } } - bool L1() { - rational w(0); - scoped_select _sc(*this); + rational L1() { + rational w(m_weight); + scoped_push _sc(*this); for (unsigned i = 0; !canceled() && i < m_T.size(); ++i) { - set const& S = m_T[i]; + set const& S = *m_T[i]; SASSERT(!S.empty()); if (!has_selected(S)) { w += m_weights[select_min(S)]; @@ -403,25 +465,42 @@ namespace opt { } } } - if (m_lower < w) { - m_lower = w; - } - return !canceled(); + return w; } - bool L2() { - rational w(0); - scoped_select _sc(*this); + void update_heap() { + for (unsigned i = 0; i < m_scored_weights.size(); ++i) { + if (m_score_updated[i]) { + rational const& old_w = m_scored_weights[i]; + rational new_w = rational(m_scores[i])*m_weights_inv[i]; + if (new_w > old_w) { + m_scored_weights[i] = new_w; + //m_heap.decreased(i); + } + else if (new_w < old_w) { + m_scored_weights[i] = new_w; + //m_heap.increased(i); + } + m_score_updated[i] = false; + } + } + } + + rational L2() { + rational w(m_weight); + scoped_push _sc(*this); int n = 0; for (unsigned i = 0; i < m_T.size(); ++i) { - if (!has_selected(m_T[i])) ++n; + if (!has_selected(*m_T[i])) ++n; } - value_lt lt(m_weights, m_scores); + update_heap(); + value_lt lt(m_scored_weights); std::sort(m_indices.begin(), m_indices.end(), lt); for(unsigned i = 0; i < m_indices.size() && n > 0; ++i) { // deg(c) = score(c) // wt(c) = m_weights[c] + unsigned idx = m_indices[i]; if (m_scores[idx] == 0) { break; @@ -434,13 +513,10 @@ namespace opt { } n -= m_scores[idx]; } - if (m_lower < w) { - m_lower = w; - } - return !canceled(); + return w; } - bool L3() { + rational L3() { TRACE("simplex", m_simplex.display(tout);); VERIFY(l_true == m_simplex.make_feasible()); TRACE("simplex", m_simplex.display(tout);); @@ -450,11 +526,12 @@ namespace opt { unsynch_mpq_manager& mq = mg.mpq_manager(); scoped_mpq c(mq); mg.ceil(val, c); - rational w = rational(c); - if (w > m_lower) { - m_lower = w; - } - return true; + rational w(c); + CTRACE("simplex", + w >= m_weight, tout << w << " " << m_weight << " !!!!\n"; + display(tout);); + SASSERT(w >= m_weight); + return w; } void add_simplex_row(bool is_some_true, unsigned sz, unsigned const* S) { @@ -490,9 +567,9 @@ namespace opt { return result; } - bool have_selected(lbool val, vector const& Sets, unsigned& i) { + bool have_selected(lbool val, ptr_vector const& Sets, unsigned& i) { for (i = 0; i < Sets.size(); ++i) { - if (!has_selected(val, Sets[i])) return false; + if (!has_selected(val, *Sets[i])) return false; } return true; } @@ -508,7 +585,7 @@ namespace opt { bool values_satisfy_Fs(unsigned& i) { unsigned j = 0; for (i = 0; i < m_F.size(); ++i) { - set const& F = m_F[i]; + set const& F = *m_F[i]; for (j = 0; j < F.size(); ++j) { if (m_model[F[j]] == l_false) { break; @@ -575,6 +652,9 @@ namespace opt { if (val == l_true) { m_weight += m_weights[idx]; update_score(idx, false); + if (m_enable_simplex) { + m_simplex.set_lower(idx, mpq_inf(mpq(1),mpq(0))); + } } SASSERT(val != l_true || m_scores[idx] == 0); m_value[idx] = val; @@ -594,7 +674,10 @@ namespace opt { m_value[idx] = l_undef; if (val == l_true) { m_weight -= m_weights[idx]; - update_score(idx, true); + update_score(idx, true); + if (m_enable_simplex) { + m_simplex.set_lower(idx, mpq_inf(mpq(0),mpq(0))); + } } if (m_justification[idx].is_axiom()) { m_replay_idx.push_back(idx); @@ -639,7 +722,7 @@ namespace opt { bool validate_model() { for (unsigned i = 0; i < m_T.size(); ++i) { - set const& S = m_T[i]; + set const& S = *m_T[i]; bool found = false; for (unsigned j = 0; !found && j < S.size(); ++j) { found = value(S[j]) == l_true; @@ -650,7 +733,7 @@ namespace opt { SASSERT(found); } for (unsigned i = 0; i < m_F.size(); ++i) { - set const& S = m_F[i]; + set const& S = *m_F[i]; bool found = false; for (unsigned j = 0; !found && j < S.size(); ++j) { found = value(S[j]) != l_true; @@ -667,13 +750,13 @@ namespace opt { bool invariant() { for (unsigned i = 0; i < m_fwatch.size(); ++i) { for (unsigned j = 0; j < m_fwatch[i].size(); ++j) { - set const& S = m_F[m_fwatch[i][j]]; + set const& S = *m_F[m_fwatch[i][j]]; SASSERT(S[0] == i || S[1] == i); } } for (unsigned i = 0; i < m_twatch.size(); ++i) { for (unsigned j = 0; j < m_twatch[i].size(); ++j) { - set const& S = m_T[m_twatch[i][j]]; + set const& S = *m_T[m_twatch[i][j]]; SASSERT(S[0] == i || S[1] == i); } } @@ -692,9 +775,9 @@ namespace opt { unsigned r = lvl(conflict_l); if (conflict_j.is_clause()) { unsigned clause = conflict_j.clause(); - vector const& S = conflict_j.pos()?m_T:m_F; - r = std::max(r, lvl(S[clause][0])); - r = std::max(r, lvl(S[clause][1])); + ptr_vector const& S = conflict_j.pos()?m_T:m_F; + r = std::max(r, lvl((*S[clause])[0])); + r = std::max(r, lvl((*S[clause])[1])); } return r; } @@ -723,7 +806,7 @@ namespace opt { unsigned cl = conflict_j.clause(); unsigned i = 0; SASSERT(value(conflict_l) != l_undef); - set const& T = conflict_j.pos()?m_T[cl]:m_F[cl]; + set const& T = conflict_j.pos()?(*m_T[cl]):(*m_F[cl]); if (T[0] == conflict_l) { i = 1; } @@ -823,13 +906,24 @@ namespace opt { } unsigned next_var() { - value_lt lt(m_weights, m_scores); + update_heap(); + + value_lt lt(m_scored_weights); std::sort(m_indices.begin(), m_indices.end(), lt); unsigned idx = m_indices[0]; - if (m_scores[idx] == 0) { - idx = UINT_MAX; + if (m_scores[idx] == 0) return UINT_MAX; + return idx; +#if 0 + int min_val = m_heap.min_value(); + if (min_val == -1) { + return UINT_MAX; } - return idx; + SASSERT(0 <= min_val && static_cast(min_val) < m_weights.size()); + if (m_scores[min_val] == 0) { + return UINT_MAX; + } + return static_cast(min_val); +#endif } bool decide() { @@ -866,7 +960,7 @@ namespace opt { prune_branch(); } - void propagate(unsigned idx, lbool good_val, vector& watch, vector& Fs) + void propagate(unsigned idx, lbool good_val, vector& watch, ptr_vector& Fs) { TRACE("opt", tout << idx << " " << value(idx) << "\n";); unsigned_vector& w = watch[idx]; @@ -876,10 +970,10 @@ namespace opt { unsigned l = 0; for (unsigned i = 0; i < sz && !canceled(); ++i, ++l) { unsigned clause_id = w[i]; - set& F = Fs[clause_id]; + set& F = *Fs[clause_id]; SASSERT(F.size() >= 2); - unsigned k1 = (F[0] == idx)?0:1; - unsigned k2 = 1 - k1; + bool k1 = (F[0] != idx); + bool k2 = !k1; SASSERT(F[k1] == idx); SASSERT(value(F[k1]) == bad_val); if (value(F[k2]) == good_val) { @@ -924,27 +1018,35 @@ namespace opt { } bool infeasible_lookahead() { - // TBD: make this more powerful - // by using L1, L2, L3 pruning criteria. - return (m_weight >= m_max_weight); + if (m_enable_simplex && L3() >= m_max_weight) { + return true; + } + return + (L1() >= m_max_weight) || + (L2() >= m_max_weight); } void prune_branch() { - if (!inconsistent() && infeasible_lookahead()) { - IF_VERBOSE(4, verbose_stream() << "(hs.prune-branch " << m_weight << ")\n";); - m_lemma.reset(); - for (unsigned i = m_trail.size(); i > 0; ) { - --i; - unsigned idx = m_trail[i]; - if (m_justification[idx].is_decision()) { - SASSERT(value(idx) == l_true); - m_lemma.push_back(idx); - } - } - justification j = add_exists_false(m_lemma.size(), m_lemma.c_ptr()); - TRACE("opt", display(tout, j);); - set_conflict(m_lemma[0], j); + if (inconsistent() || !infeasible_lookahead()) { + return; } + + IF_VERBOSE(4, verbose_stream() << "(hs.prune-branch " << m_weight << ")\n";); + m_lemma.reset(); + unsigned i = 0; + rational w(0); + for (; i < m_trail.size() && w < m_max_weight; ++i) { + unsigned idx = m_trail[i]; + if (m_justification[idx].is_decision()) { + SASSERT(value(idx) == l_true); + m_lemma.push_back(idx); + w += m_weights[idx]; + } + } + // undo the lower bounds. + justification j = add_exists_false(m_lemma.size(), m_lemma.c_ptr()); + TRACE("opt", display(tout, j);); + set_conflict(m_lemma[0], j); } // TBD: derive strong inequalities and add them to Simplex. From 53f82e3239c26697eb5623fa5ce7f9d7d3336647 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 6 Jul 2014 17:33:54 +0200 Subject: [PATCH 425/925] update model during Lex Signed-off-by: Nikolaj Bjorner --- src/opt/hitting_sets.cpp | 4 +++- src/opt/opt_context.cpp | 4 ++++ src/opt/weighted_maxsat.cpp | 8 ++++---- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/opt/hitting_sets.cpp b/src/opt/hitting_sets.cpp index 8cc2c0304..d85e6b3f4 100644 --- a/src/opt/hitting_sets.cpp +++ b/src/opt/hitting_sets.cpp @@ -204,7 +204,7 @@ namespace opt { set_conflict(0, justification(justification::AXIOM)); } else if (sz == 1) { - IF_VERBOSE(1, verbose_stream() << "unit literal : " << S[0] << " " << val << "\n";); + IF_VERBOSE(2, verbose_stream() << "unit literal : " << S[0] << " " << val << "\n";); assign(S[0], val, justification(justification::AXIOM)); } else { @@ -221,6 +221,7 @@ namespace opt { inc_score(clause_id); } TRACE("opt", display(tout, j);); + IF_VERBOSE(1, if (!sign) display(verbose_stream(), j);); if (!sign && m_enable_simplex) { add_simplex_row(!sign, sz, S); } @@ -246,6 +247,7 @@ namespace opt { pop(scope_lvl()); + IF_VERBOSE(1, verbose_stream() << "(hsmax.negated-size: " << fsz << ")\n";); #if 0 // garbage collect agressively on exit. // all learned clases for negative branches are diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index b8eeb0d09..58c5c2017 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -269,6 +269,9 @@ namespace opt { if (r == l_true && !get_lower_as_num(i).is_finite()) { return r; } + if (r == l_true && i + 1 < m_objectives.size()) { + update_lower(true); + } } DEBUG_CODE(if (r == l_true) validate_lex();); return r; @@ -841,6 +844,7 @@ namespace opt { switch(obj.m_type) { case O_MAXSMT: { rational r = m_maxsmts.find(obj.m_id)->get_upper(); + TRACE("opt", tout << "maxsmt: " << r << " negate: " << obj.m_neg << " offset: " << obj.m_offset << "\n";); if (obj.m_neg) r.neg(); r += obj.m_offset; return inf_eps(r); diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 00c445402..8d405196c 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -701,9 +701,9 @@ namespace opt { TRACE("opt", tout << "no more cores\n";); m_lower = m_upper; return l_true; - } - } - return l_true; + } + } + return l_true; } private: @@ -785,7 +785,7 @@ namespace opt { switch (is_sat) { case l_true: if (lower > m_lower) { - m_lower = lower; + m_lower = lower; } return true; case l_false: From 465eafbf45ae107a40f8ec45a030938d8597fdb7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 9 Jul 2014 05:04:00 +0200 Subject: [PATCH 426/925] fix assertion for integrality, lax noprogress bail out code Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith_aux.h | 6 +++++- src/smt/theory_arith_inv.h | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 1e2a6c238..7178834fa 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -1449,6 +1449,8 @@ namespace smt { /** Move the variable x_i maximally towards its bound as long as bounds of other variables are not violated. + Returns false if an integer bound was truncated and no + progress was made. */ template @@ -1492,7 +1494,9 @@ namespace smt { } } + bool truncated = false; if (is_int(x_i)) { + truncated = !delta_abs.is_int(); delta_abs = floor(delta_abs); } @@ -1505,7 +1509,7 @@ namespace smt { TRACE("opt", tout << "Safe delta: " << delta << "\n";); update_value(x_i, delta); - return !delta.is_zero(); + return !truncated || !delta.is_zero(); } /** diff --git a/src/smt/theory_arith_inv.h b/src/smt/theory_arith_inv.h index f6270e664..99e4303ff 100644 --- a/src/smt/theory_arith_inv.h +++ b/src/smt/theory_arith_inv.h @@ -204,7 +204,7 @@ namespace smt { bool theory_arith::satisfy_integrality() const { int num = get_num_vars(); for (theory_var v = 0; v < num; v++) { - if (!(is_int(v) && get_value(v).is_int())) { + if (is_int(v) && !get_value(v).is_int()) { TRACE("bound_bug", display_var(tout, v); display(tout);); return false; } From 582dbe509cd2a1f6eb8b83c04a2376ca4ad199ec Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 21 Jul 2014 22:24:34 +0200 Subject: [PATCH 427/925] first implementation of maxres Signed-off-by: Nikolaj Bjorner --- src/opt/hitting_sets.cpp | 52 +++++++---- src/opt/maxres.cpp | 194 +++++++++++++++++++++++++++++++++++++++ src/opt/maxres.h | 18 ++++ src/opt/maxsmt.cpp | 4 + 4 files changed, 251 insertions(+), 17 deletions(-) create mode 100644 src/opt/maxres.cpp create mode 100644 src/opt/maxres.h diff --git a/src/opt/hitting_sets.cpp b/src/opt/hitting_sets.cpp index d85e6b3f4..fb9d2d009 100644 --- a/src/opt/hitting_sets.cpp +++ b/src/opt/hitting_sets.cpp @@ -40,11 +40,12 @@ namespace opt { public: explicit justification(kind_t k):m_kind(k), m_value(0), m_pos(false) {} explicit justification(unsigned v, bool pos):m_kind(CLAUSE), m_value(v), m_pos(pos) {} - justification(justification const& other): m_kind(other.m_kind), m_value(other.m_value), m_pos(other.m_pos) {} + justification(justification const& other): + m_kind(other.m_kind), m_value(other.m_value), m_pos(other.m_pos) {} justification& operator=(justification const& other) { - m_kind = other.m_kind; + m_kind = other.m_kind; m_value = other.m_value; - m_pos = other.m_pos; + m_pos = other.m_pos; return *this; } unsigned clause() const { return m_value; } @@ -147,6 +148,7 @@ namespace opt { m_cancel(false), m_max_weight(0), m_denominator(1), + m_alloc("hitting-sets"), m_weights_var(0), m_qhead(0), m_scope_lvl(0), @@ -157,7 +159,14 @@ namespace opt { m_enable_simplex = true; } - ~imp() {} + ~imp() { + for (unsigned i = 0; i < m_T.size(); ++i) { + m_alloc.deallocate(m_T[i]->alloc_size(), m_T[i]); + } + for (unsigned i = 0; i < m_F.size(); ++i) { + m_alloc.deallocate(m_F[i]->alloc_size(), m_F[i]); + } + } void add_weight(rational const& w) { SASSERT(w.is_pos()); @@ -198,9 +207,7 @@ namespace opt { ptr_vector& Sets = sign?m_F:m_T; vector& watch = sign?m_fwatch:m_twatch; init_weights(); - if (sz == 0) { - // TBD - IF_VERBOSE(0, verbose_stream() << "empty clause\n";); + if (sz == 0) { set_conflict(0, justification(justification::AXIOM)); } else if (sz == 1) { @@ -375,7 +382,8 @@ namespace opt { } out << "trail\n"; for (unsigned i = 0; i < m_trail.size(); ++i) { - out << m_trail[i] << " "; + unsigned idx = m_trail[i]; + out << (m_justification[idx].is_decision()?"d":"") << idx << " "; } out << "\n"; } @@ -406,6 +414,14 @@ namespace opt { } } + void display_lemma(std::ostream& out) { + out << "lemma: "; + for (unsigned i = 0; i < m_lemma.size(); ++i) { + out << m_lemma[i] << " "; + } + out << "\n"; + } + struct scoped_push { imp& s; scoped_push(imp& s):s(s) { s.push(); } @@ -850,11 +866,7 @@ namespace opt { } while (num_marks > 0); m_lemma[0] = conflict_l; - TRACE("opt", - for (unsigned i = 0; i < m_lemma.size(); ++i) { - tout << m_lemma[i] << " "; - } - tout << "\n";); + TRACE("opt", display_lemma(tout);); SASSERT(value(conflict_l) == l_true); unsigned new_scope_lvl = 0; for (unsigned i = 1; i < m_lemma.size(); ++i) { @@ -1046,15 +1058,21 @@ namespace opt { } } // undo the lower bounds. + TRACE("opt", + tout << "prune branch: " << m_weight << " "; + display_lemma(tout); + display(tout); + ); justification j = add_exists_false(m_lemma.size(), m_lemma.c_ptr()); - TRACE("opt", display(tout, j);); - set_conflict(m_lemma[0], j); + unsigned idx = m_lemma.empty()?0:m_lemma[0]; + set_conflict(idx, j); } // TBD: derive strong inequalities and add them to Simplex. - // x_i1 + .. + x_ik >= k-1 for each subset k from set n: x_1 + .. + x_n >= k - + // x_i1 + .. + x_ik >= k-1 for each subset k from set n: x_1 + .. + x_n >= k }; + + hitting_sets::hitting_sets() { m_imp = alloc(imp); } hitting_sets::~hitting_sets() { dealloc(m_imp); } void hitting_sets::add_weight(rational const& w) { m_imp->add_weight(w); } diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp new file mode 100644 index 000000000..b9c09350c --- /dev/null +++ b/src/opt/maxres.cpp @@ -0,0 +1,194 @@ +#include "solver.h" +#include "maxsmt.h" +#include "maxres.h" +#include "ast_pp.h" + + +using namespace opt; + +struct maxres::imp { + ast_manager& m; + solver& s; + expr_ref_vector m_B; + expr_ref_vector m_D; + expr_ref_vector m_asms; + model_ref m_model; + expr_ref_vector m_soft_constraints; + volatile bool m_cancel; + rational m_lower; + rational m_upper; + + imp(ast_manager& m, solver& s, expr_ref_vector& soft_constraints): + m(m), s(s), m_B(m), m_D(m), m_asms(m), m_soft_constraints(soft_constraints), + m_cancel(false) + { + } + + bool is_literal(expr* l) { + return + is_uninterp_const(l) || + m.is_not(l, l) && is_uninterp_const(l); + } + + void add_soft(expr* e) { + TRACE("opt", tout << mk_pp(e, m) << "\n";); + if (is_literal(e)) { + m_asms.push_back(e); + } + else { + expr_ref asum(m), fml(m); + asum = m.mk_fresh_const("soft", m.mk_bool_sort()); + fml = m.mk_implies(asum, e); + s.assert_expr(fml); + m_asms.push_back(asum); + } + } + + lbool operator()() { + expr_ref fml(m); + solver::scoped_push _sc(s); + for (unsigned i = 0; i < m_soft_constraints.size(); ++i) { + add_soft(m_soft_constraints[i].get()); + } + m_upper = rational(m_soft_constraints.size()); + while (true) { + TRACE("opt", + display_vec(tout, m_asms.size(), m_asms.c_ptr()); + s.display(tout); + tout << "\n"; + ); + lbool is_sat = s.check_sat(m_asms.size(), m_asms.c_ptr()); + if (m_cancel) { + return l_undef; + } + switch (is_sat) { + case l_true: + s.get_model(m_model); + m_upper = m_lower; + return l_true; + case l_undef: + return l_undef; + default: + ptr_vector core; + s.get_unsat_core(core); + TRACE("opt", display_vec(tout << "core: ", core.size(), core.c_ptr());); + if (core.empty()) { + return l_false; + } + max_resolve(core); + fml = m.mk_not(m.mk_and(m_B.size(), m_B.c_ptr())); + s.assert_expr(fml); + m_lower += rational::one(); + break; + } + IF_VERBOSE(1, verbose_stream() << "(opt.max_res lower: " << m_lower << ")\n";); + } + return l_true; + } + + void display_vec(std::ostream& out, unsigned sz, expr* const* args) { + for (unsigned i = 0; i < sz; ++i) { + out << mk_pp(args[i], m) << " "; + } + out << "\n"; + } + + void max_resolve(ptr_vector& core) { + SASSERT(!core.empty()); + expr_ref fml(m), asum(m); + m_B.reset(); + m_D.reset(); + m_D.resize(core.size()); + m_B.append(core.size(), core.c_ptr()); + m_D[core.size()-1] = m.mk_false(); + // + // d_{sz-1} := false + // d_i := (!core_{i+1} or d_{i+1}) for i = 0...sz-2 + // soft (!d_i or core_i) + // + remove_core(core); + for (unsigned i = core.size()-1; i > 0; ) { + --i; + expr* d_i1 = m_D[i+1].get(); + expr* b_i = m_B[i].get(); + expr* b_i1 = m_B[i+1].get(); + m_D[i] = m.mk_implies(b_i1, d_i1); + expr* d_i = m_D[i].get(); + asum = m.mk_fresh_const("a", m.mk_bool_sort()); + fml = m.mk_implies(asum, m.mk_implies(d_i, b_i)); + s.assert_expr(fml); + m_asms.push_back(asum); + } + } + + void remove_core(ptr_vector const& core) { + for (unsigned i = 0; i < m_asms.size(); ++i) { + if (core.contains(m_asms[i].get())) { + m_asms[i] = m_asms.back(); + m_asms.pop_back(); + --i; + } + } + } + + rational get_lower() const { + return m_lower; + } + + rational get_upper() const { + return m_upper; + } + + bool get_assignment(unsigned index) const { + expr_ref tmp(m); + m_model->eval(m_soft_constraints[index], tmp); + return m.is_true(tmp); + } + void set_cancel(bool f) { + m_cancel = f; + } + void collect_statistics(statistics& st) const { + } + void get_model(model_ref& mdl) { + mdl = m_model; + } + void updt_params(params_ref& p) { + ; + } + +}; + +maxres::maxres(ast_manager& m, solver& s, expr_ref_vector& soft_constraints) { + m_imp = alloc(imp, m, s, soft_constraints); +} + +maxres::~maxres() { + dealloc(m_imp); +} + + +lbool maxres::operator()() { + return (*m_imp)(); +} + +rational maxres::get_lower() const { + return m_imp->get_lower(); +} +rational maxres::get_upper() const { + return m_imp->get_upper(); +} +bool maxres::get_assignment(unsigned index) const { + return m_imp->get_assignment(index); +} +void maxres::set_cancel(bool f) { + m_imp->set_cancel(f); +} +void maxres::collect_statistics(statistics& st) const { + m_imp->collect_statistics(st); +} +void maxres::get_model(model_ref& mdl) { + m_imp->get_model(mdl); +} +void maxres::updt_params(params_ref& p) { + m_imp->updt_params(p); +} diff --git a/src/opt/maxres.h b/src/opt/maxres.h new file mode 100644 index 000000000..8b90158fb --- /dev/null +++ b/src/opt/maxres.h @@ -0,0 +1,18 @@ + +namespace opt { + class maxres : public maxsmt_solver { + struct imp; + imp* m_imp; + public: + maxres(ast_manager& m, solver& s, expr_ref_vector& soft_constraints); + ~maxres(); + virtual lbool operator()(); + virtual rational get_lower() const; + virtual rational get_upper() const; + virtual bool get_assignment(unsigned index) const; + virtual void set_cancel(bool f); + virtual void collect_statistics(statistics& st) const; + virtual void get_model(model_ref& mdl); + virtual void updt_params(params_ref& p); + }; +}; diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 9da9f9f2e..2eb6e426b 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -21,6 +21,7 @@ Notes: #include "maxsmt.h" #include "fu_malik.h" #include "core_maxsat.h" +#include "maxres.h" #include "weighted_maxsat.h" #include "ast_pp.h" #include "opt_params.hpp" @@ -45,6 +46,9 @@ namespace opt { else if (m_maxsat_engine == symbol("weighted_maxsat")) { m_msolver = alloc(wmaxsmt, m, m_s.get(), m_soft_constraints, m_weights); } + else if (m_maxsat_engine == symbol("maxres")) { + m_msolver = alloc(maxres, m, *m_s, m_soft_constraints); + } else { m_msolver = alloc(fu_malik, m, *m_s, m_soft_constraints); } From bf35a62da7d4a8efd4025a35d2e572f62f1ad06f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 21 Jul 2014 23:28:19 +0200 Subject: [PATCH 428/925] adding mus extraction Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 88 ++++++++++++++++++-- src/opt/mus.cpp | 203 +++++++++++++++++++++++++++++++++++++++++++++ src/opt/mus.h | 21 +++++ 3 files changed, 306 insertions(+), 6 deletions(-) create mode 100644 src/opt/mus.cpp create mode 100644 src/opt/mus.h diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index b9c09350c..579a7c6e9 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -1,8 +1,13 @@ +/** + MaxRes (weighted) max-sat algorithm by Nina and Bacchus, AAAI 2014. + +*/ + #include "solver.h" #include "maxsmt.h" #include "maxres.h" #include "ast_pp.h" - +#include "mus.h" using namespace opt; @@ -12,14 +17,16 @@ struct maxres::imp { expr_ref_vector m_B; expr_ref_vector m_D; expr_ref_vector m_asms; + app_ref_vector m_clss; model_ref m_model; expr_ref_vector m_soft_constraints; volatile bool m_cancel; rational m_lower; rational m_upper; + obj_map m_asm2cls; imp(ast_manager& m, solver& s, expr_ref_vector& soft_constraints): - m(m), s(s), m_B(m), m_D(m), m_asms(m), m_soft_constraints(soft_constraints), + m(m), s(s), m_B(m), m_D(m), m_asms(m), m_clss(m), m_soft_constraints(soft_constraints), m_cancel(false) { } @@ -32,20 +39,25 @@ struct maxres::imp { void add_soft(expr* e) { TRACE("opt", tout << mk_pp(e, m) << "\n";); + expr_ref asum(m), fml(m); + app_ref cls(m); + cls = mk_cls(e); + m_clss.push_back(cls); if (is_literal(e)) { m_asms.push_back(e); } else { - expr_ref asum(m), fml(m); asum = m.mk_fresh_const("soft", m.mk_bool_sort()); - fml = m.mk_implies(asum, e); + fml = m.mk_iff(asum, e); s.assert_expr(fml); m_asms.push_back(asum); } + m_asm2cls.insert(m_asms.back(), cls.get()); } lbool operator()() { expr_ref fml(m); + ptr_vector core, new_core; solver::scoped_push _sc(s); for (unsigned i = 0; i < m_soft_constraints.size(); ++i) { add_soft(m_soft_constraints[i].get()); @@ -69,12 +81,37 @@ struct maxres::imp { case l_undef: return l_undef; default: - ptr_vector core; + core.reset(); s.get_unsat_core(core); TRACE("opt", display_vec(tout << "core: ", core.size(), core.c_ptr());); + SASSERT(!core.empty()); if (core.empty()) { return l_false; } +#if 1 + // minimize core: + mus ms(s, m); + for (unsigned i = 0; i < core.size(); ++i) { + app* cls = 0; + VERIFY(m_asm2cls.find(core[i], cls)); + SASSERT(cls); + SASSERT(m.is_or(cls)); + ms.add_soft(core[i], cls->get_num_args(), cls->get_args()); + } + unsigned_vector mus_idx; + is_sat = ms.get_mus(mus_idx); + if (is_sat != l_true) { + return is_sat; + } + new_core.reset(); + for (unsigned i = 0; i < mus_idx.size(); ++i) { + new_core.push_back(core[mus_idx[i]]); + } + core.reset(); + core.append(new_core); + +#endif + TRACE("opt", display_vec(tout << "minimized core: ", core.size(), core.c_ptr());); max_resolve(core); fml = m.mk_not(m.mk_and(m_B.size(), m_B.c_ptr())); s.assert_expr(fml); @@ -96,6 +133,7 @@ struct maxres::imp { void max_resolve(ptr_vector& core) { SASSERT(!core.empty()); expr_ref fml(m), asum(m); + app_ref cls(m); m_B.reset(); m_D.reset(); m_D.resize(core.size()); @@ -115,17 +153,55 @@ struct maxres::imp { m_D[i] = m.mk_implies(b_i1, d_i1); expr* d_i = m_D[i].get(); asum = m.mk_fresh_const("a", m.mk_bool_sort()); - fml = m.mk_implies(asum, m.mk_implies(d_i, b_i)); + cls = m.mk_implies(d_i, b_i); + fml = m.mk_iff(asum, cls); s.assert_expr(fml); m_asms.push_back(asum); + cls = mk_cls(cls); + m_clss.push_back(cls); + m_asm2cls.insert(asum, cls); } } + app_ref mk_cls(expr* e) { + expr_ref_vector disj(m), todo(m); + expr_ref f(m); + app_ref result(m); + expr* e1, *e2; + todo.push_back(e); + while (!todo.empty()) { + f = todo.back(); + todo.pop_back(); + if (m.is_implies(f, e1, e2)) { + todo.push_back(m.mk_not(e1)); + todo.push_back(e2); + } + else if (m.is_not(f, e1) && m.is_not(e1, e2)) { + todo.push_back(e2); + } + else if (m.is_or(f)) { + todo.append(to_app(f)->get_num_args(), to_app(f)->get_args()); + } + else if (m.is_not(f, e1) && m.is_and(e1)) { + for (unsigned i = 0; i < to_app(e1)->get_num_args(); ++i) { + todo.push_back(m.mk_not(to_app(e1)->get_arg(i))); + } + } + else { + disj.push_back(f); + } + } + result = m.mk_or(disj.size(), disj.c_ptr()); + return result; + } + void remove_core(ptr_vector const& core) { for (unsigned i = 0; i < m_asms.size(); ++i) { if (core.contains(m_asms[i].get())) { m_asms[i] = m_asms.back(); + m_clss[i] = m_clss.back(); m_asms.pop_back(); + m_clss.pop_back(); --i; } } diff --git a/src/opt/mus.cpp b/src/opt/mus.cpp new file mode 100644 index 000000000..1bed42f7d --- /dev/null +++ b/src/opt/mus.cpp @@ -0,0 +1,203 @@ +#include "solver.h" +#include "smt_literal.h" +#include "mus.h" +#include "ast_pp.h" + +using namespace opt; + +// Faster MUS extraction based on Belov et.al. HYB (Algorithm 3, 4) + + +struct mus::imp { + solver& s; + ast_manager& m; + expr_ref_vector m_cls2expr; + obj_map m_expr2cls; + vector m_cls2lits; + expr_ref_vector m_vars; + obj_map m_var2idx; + +public: + imp(solver& s, ast_manager& m): s(s), m(m), m_cls2expr(m), m_vars(m) {} + + unsigned add_var(expr* v) { + unsigned idx = m_vars.size(); + if (!m_var2idx.find(v, idx)) { + m_var2idx.insert(v, idx); + m_vars.push_back(v); + } + return idx; + } + + unsigned add_soft(expr* cls, unsigned sz, expr* const* args) { + TRACE("opt", tout << sz << ": " << mk_pp(cls, m) << "\n";); + smt::literal_vector lits; + expr* arg; + for (unsigned i = 0; i < sz; ++i) { + if (m.is_not(args[i], arg)) { + lits.push_back(smt::literal(add_var(arg), true)); + } + else { + lits.push_back(smt::literal(add_var(args[i]), false)); + } + } + unsigned idx = m_cls2lits.size(); + m_expr2cls.insert(cls, idx); + m_cls2expr.push_back(cls); + m_cls2lits.push_back(lits); + return idx; + } + + lbool get_mus(unsigned_vector& mus) { + TRACE("opt", tout << "\n";); + solver::scoped_push _sc(s); + unsigned_vector core; + for (unsigned i = 0; i < m_cls2expr.size(); ++i) { + core.push_back(i); + } + mus.reset(); + expr_ref_vector assumptions(m); + svector model; + ptr_vector core_exprs; + model.resize(m_vars.size()); + while (!core.empty()) { + IF_VERBOSE(0, display_vec(tout << "core: ", core);); + unsigned cls_id = core.back(); + core.pop_back(); + expr* cls = m_cls2expr[cls_id].get(); + expr_ref not_cls(m); + not_cls = m.mk_not(cls); + unsigned sz = assumptions.size(); + assumptions.push_back(not_cls); + add_core(core, assumptions); + lbool is_sat = s.check_sat(assumptions.size(), assumptions.c_ptr()); + assumptions.resize(sz); + switch(is_sat) { + case l_undef: + return is_sat; + case l_true: + assumptions.push_back(cls); + mus.push_back(cls_id); + extract_model(s, model); + sz = core.size(); + core.append(mus); + rmr(core, mus, model); + core.resize(sz); + break; + default: + core_exprs.reset(); + s.get_unsat_core(core_exprs); + if (!core_exprs.contains(not_cls)) { + // core := core_exprs \ mus + core.reset(); + for (unsigned i = 0; i < core_exprs.size(); ++i) { + cls = core_exprs[i]; + cls_id = m_expr2cls.find(cls); + if (!mus.contains(cls_id)) { + core.push_back(cls_id); + } + } + } + break; + } + } + return l_true; + } + + void add_core(unsigned_vector const& core, expr_ref_vector& assumptions) { + for (unsigned i = 0; i < core.size(); ++i) { + assumptions.push_back(m_cls2expr[core[i]].get()); + } + } + + template + void display_vec(std::ostream& out, T const& v) const { + for (unsigned i = 0; i < v.size(); ++i) { + out << mk_pp(v[i], m) << " "; + } + out << "\n"; + } + + void extract_model(solver& s, svector& model) { + model_ref mdl; + s.get_model(mdl); + for (unsigned i = 0; i < m_vars.size(); ++i) { + expr_ref tmp(m); + mdl->eval(m_vars[i].get(), tmp); + model[i] = m.is_true(tmp); + } + } + + /** + Recursive model rotation. + */ + void rmr(unsigned_vector& M, unsigned_vector& mus, svector& model) { + TRACE("opt", + display_vec(tout << "M:", M); + display_vec(tout << "mus:", mus); + display_vec(tout << "model:", model);); + + unsigned cls_id = mus.back(); + smt::literal_vector const& cls = m_cls2lits[cls_id]; + unsigned cls_id_new; + for (unsigned i = 0; i < cls.size(); ++i) { + smt::literal lit = cls[i]; + SASSERT(model[lit.var()] == lit.sign()); // literal evaluates to false. + model[lit.var()] = !model[lit.var()]; // swap assignment + if (has_single_unsat(model, cls_id_new)) { + mus.push_back(cls_id_new); + rmr(M, mus, model); + } + model[lit.var()] = !model[lit.var()]; // swap assignment back + } + } + + bool has_single_unsat(svector const& model, unsigned& cls_id) const { + cls_id = UINT_MAX; + for (unsigned i = 0; i < m_cls2lits.size(); ++i) { + if (!eval(model, m_cls2lits[i])) { + if (cls_id == UINT_MAX) { + cls_id = i; + } + else { + return false; + } + } + } + return cls_id != UINT_MAX; + } + + bool eval(svector const& model, smt::literal_vector const& cls) const { + for (unsigned i = 0; i < cls.size(); ++i) { + if (model[cls[i].var()] != cls[i].sign()) { + return true; + } + } + return false; + } + + template + void display_vec(std::ostream& out, T const& v) { + for (unsigned i = 0; i < v.size(); ++i) { + out << v[i] << " "; + } + out << "\n"; + } +}; + +mus::mus(solver& s, ast_manager& m) { + m_imp = alloc(imp, s, m); +} + +mus::~mus() { + dealloc(m_imp); +} + +unsigned mus::add_soft(expr* cls, unsigned sz, expr* const* args) { + return m_imp->add_soft(cls, sz, args); +} + +lbool mus::get_mus(unsigned_vector& mus) { + return m_imp->get_mus(mus); +} + diff --git a/src/opt/mus.h b/src/opt/mus.h new file mode 100644 index 000000000..a2ba36f14 --- /dev/null +++ b/src/opt/mus.h @@ -0,0 +1,21 @@ + +namespace opt { + class mus { + struct imp; + imp * m_imp; + public: + mus(solver& s, ast_manager& m); + ~mus(); + /** + Add soft constraint. + + Assume that the solver context enforces that + cls is equivalent to a disjunction of args. + Assume also that cls is a literal. + */ + unsigned add_soft(expr* cls, unsigned sz, expr* const* args); + + lbool get_mus(unsigned_vector& mus); + }; + +}; From 5e9bf2ef532fc42fbbf3382d8f21f5fac8ebe7ec Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 22 Jul 2014 15:42:08 +0200 Subject: [PATCH 429/925] maxres revised to handle weighted constraints Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 186 +++++++++++++++++++++++++++++++-------------- src/opt/maxres.h | 2 +- src/opt/maxsmt.cpp | 8 +- src/opt/mus.cpp | 60 ++++++++++----- src/opt/mus.h | 4 + 5 files changed, 177 insertions(+), 83 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 579a7c6e9..11d87a98e 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -12,62 +12,79 @@ using namespace opt; struct maxres::imp { - ast_manager& m; - solver& s; - expr_ref_vector m_B; - expr_ref_vector m_D; - expr_ref_vector m_asms; - app_ref_vector m_clss; - model_ref m_model; - expr_ref_vector m_soft_constraints; - volatile bool m_cancel; - rational m_lower; - rational m_upper; - obj_map m_asm2cls; + struct info { + app* m_cls; + rational m_weight; + info(app* cls, rational const& w): + m_cls(cls), m_weight(w) {} + info(): m_cls(0) {} + }; + ast_manager& m; + solver& s; + expr_ref_vector m_B; + expr_ref_vector m_D; + expr_ref_vector m_asms; + model_ref m_model; + expr_ref_vector m_soft_constraints; + volatile bool m_cancel; + rational m_lower; + rational m_upper; + obj_map m_asm2info; + ptr_vector m_new_core; + mus m_mus; + expr_ref_vector m_trail; - imp(ast_manager& m, solver& s, expr_ref_vector& soft_constraints): - m(m), s(s), m_B(m), m_D(m), m_asms(m), m_clss(m), m_soft_constraints(soft_constraints), - m_cancel(false) + imp(ast_manager& m, solver& s, expr_ref_vector& soft_constraints, vector const& weights): + m(m), s(s), m_B(m), m_D(m), m_asms(m), m_soft_constraints(m), + m_cancel(false), + m_mus(s, m), + m_trail(m) { + // TBD: this introduces an assertion to solver. + init_soft(weights, soft_constraints); } bool is_literal(expr* l) { return is_uninterp_const(l) || - m.is_not(l, l) && is_uninterp_const(l); + (m.is_not(l, l) && is_uninterp_const(l)); } - void add_soft(expr* e) { + void add_soft(expr* e, rational const& w) { TRACE("opt", tout << mk_pp(e, m) << "\n";); expr_ref asum(m), fml(m); app_ref cls(m); cls = mk_cls(e); - m_clss.push_back(cls); + m_trail.push_back(cls); if (is_literal(e)) { - m_asms.push_back(e); + asum = e; } else { asum = m.mk_fresh_const("soft", m.mk_bool_sort()); fml = m.mk_iff(asum, e); s.assert_expr(fml); - m_asms.push_back(asum); } - m_asm2cls.insert(m_asms.back(), cls.get()); + new_assumption(asum, cls, w); + m_upper += w; + } + + void new_assumption(expr* e, app* cls, rational const& w) { + info inf(cls, w); + m_asm2info.insert(e, inf); + m_asms.push_back(e); + m_trail.push_back(e); } lbool operator()() { expr_ref fml(m); - ptr_vector core, new_core; + ptr_vector core; solver::scoped_push _sc(s); - for (unsigned i = 0; i < m_soft_constraints.size(); ++i) { - add_soft(m_soft_constraints[i].get()); - } - m_upper = rational(m_soft_constraints.size()); while (true) { TRACE("opt", display_vec(tout, m_asms.size(), m_asms.c_ptr()); s.display(tout); tout << "\n"; + display(tout); ); lbool is_sat = s.check_sat(m_asms.size(), m_asms.c_ptr()); if (m_cancel) { @@ -85,37 +102,21 @@ struct maxres::imp { s.get_unsat_core(core); TRACE("opt", display_vec(tout << "core: ", core.size(), core.c_ptr());); SASSERT(!core.empty()); + is_sat = minimize_core(core); + SASSERT(!core.empty()); if (core.empty()) { return l_false; } -#if 1 - // minimize core: - mus ms(s, m); - for (unsigned i = 0; i < core.size(); ++i) { - app* cls = 0; - VERIFY(m_asm2cls.find(core[i], cls)); - SASSERT(cls); - SASSERT(m.is_or(cls)); - ms.add_soft(core[i], cls->get_num_args(), cls->get_args()); - } - unsigned_vector mus_idx; - is_sat = ms.get_mus(mus_idx); if (is_sat != l_true) { return is_sat; } - new_core.reset(); - for (unsigned i = 0; i < mus_idx.size(); ++i) { - new_core.push_back(core[mus_idx[i]]); - } - core.reset(); - core.append(new_core); - -#endif + remove_core(core); + rational w = split_core(core); TRACE("opt", display_vec(tout << "minimized core: ", core.size(), core.c_ptr());); - max_resolve(core); + max_resolve(core, w); fml = m.mk_not(m.mk_and(m_B.size(), m_B.c_ptr())); s.assert_expr(fml); - m_lower += rational::one(); + m_lower += w; break; } IF_VERBOSE(1, verbose_stream() << "(opt.max_res lower: " << m_lower << ")\n";); @@ -123,6 +124,57 @@ struct maxres::imp { return l_true; } + lbool minimize_core(ptr_vector& core) { + m_mus.reset(); + for (unsigned i = 0; i < core.size(); ++i) { + app* cls = get_clause(core[i]); + SASSERT(cls); + SASSERT(m.is_or(cls)); + m_mus.add_soft(core[i], cls->get_num_args(), cls->get_args()); + } + unsigned_vector mus_idx; + lbool is_sat = m_mus.get_mus(mus_idx); + if (is_sat != l_true) { + return is_sat; + } + m_new_core.reset(); + for (unsigned i = 0; i < mus_idx.size(); ++i) { + m_new_core.push_back(core[mus_idx[i]]); + } + core.reset(); + core.append(m_new_core); + return l_true; + } + + rational get_weight(expr* e) { + return m_asm2info.find(e).m_weight; + } + + app* get_clause(expr* e) { + return m_asm2info.find(e).m_cls; + } + + rational split_core(ptr_vector const& core) { + + // find the minimal weight: + SASSERT(!core.empty()); + rational w = get_weight(core[0]); + for (unsigned i = 1; i < core.size(); ++i) { + rational w2 = get_weight(core[i]); + if (w2 < w) { + w = w2; + } + } + // add fresh soft clauses for weights that are above w. + for (unsigned i = 0; i < core.size(); ++i) { + rational w2 = get_weight(core[i]); + if (w2 > w) { + new_assumption(core[i], get_clause(core[i]), w2 - w); + } + } + return w; + } + void display_vec(std::ostream& out, unsigned sz, expr* const* args) { for (unsigned i = 0; i < sz; ++i) { out << mk_pp(args[i], m) << " "; @@ -130,7 +182,14 @@ struct maxres::imp { out << "\n"; } - void max_resolve(ptr_vector& core) { + void display(std::ostream& out) { + for (unsigned i = 0; i < m_asms.size(); ++i) { + expr* a = m_asms[i].get(); + out << mk_pp(a, m) << " : " << get_weight(a) << "\n"; + } + } + + void max_resolve(ptr_vector& core, rational const& w) { SASSERT(!core.empty()); expr_ref fml(m), asum(m); app_ref cls(m); @@ -144,7 +203,6 @@ struct maxres::imp { // d_i := (!core_{i+1} or d_{i+1}) for i = 0...sz-2 // soft (!d_i or core_i) // - remove_core(core); for (unsigned i = core.size()-1; i > 0; ) { --i; expr* d_i1 = m_D[i+1].get(); @@ -155,11 +213,10 @@ struct maxres::imp { asum = m.mk_fresh_const("a", m.mk_bool_sort()); cls = m.mk_implies(d_i, b_i); fml = m.mk_iff(asum, cls); - s.assert_expr(fml); - m_asms.push_back(asum); cls = mk_cls(cls); - m_clss.push_back(cls); - m_asm2cls.insert(asum, cls); + m_trail.push_back(cls); + new_assumption(asum, cls, w); + s.assert_expr(fml); } } @@ -199,9 +256,7 @@ struct maxres::imp { for (unsigned i = 0; i < m_asms.size(); ++i) { if (core.contains(m_asms[i].get())) { m_asms[i] = m_asms.back(); - m_clss[i] = m_clss.back(); m_asms.pop_back(); - m_clss.pop_back(); --i; } } @@ -217,11 +272,12 @@ struct maxres::imp { bool get_assignment(unsigned index) const { expr_ref tmp(m); - m_model->eval(m_soft_constraints[index], tmp); + VERIFY(m_model->eval(m_soft_constraints[index], tmp)); return m.is_true(tmp); } void set_cancel(bool f) { m_cancel = f; + m_mus.set_cancel(f); } void collect_statistics(statistics& st) const { } @@ -232,10 +288,22 @@ struct maxres::imp { ; } + void init_soft(vector const& weights, expr_ref_vector const& soft) { + m_soft_constraints.reset(); + m_upper.reset(); + m_lower.reset(); + m_asm2info.reset(); + m_trail.reset(); + m_soft_constraints.append(soft); + for (unsigned i = 0; i < m_soft_constraints.size(); ++i) { + add_soft(m_soft_constraints[i].get(), weights[i]); + } + } + }; -maxres::maxres(ast_manager& m, solver& s, expr_ref_vector& soft_constraints) { - m_imp = alloc(imp, m, s, soft_constraints); +maxres::maxres(ast_manager& m, solver& s, expr_ref_vector& soft_constraints, vector const& weights) { + m_imp = alloc(imp, m, s, soft_constraints, weights); } maxres::~maxres() { diff --git a/src/opt/maxres.h b/src/opt/maxres.h index 8b90158fb..41b57456f 100644 --- a/src/opt/maxres.h +++ b/src/opt/maxres.h @@ -4,7 +4,7 @@ namespace opt { struct imp; imp* m_imp; public: - maxres(ast_manager& m, solver& s, expr_ref_vector& soft_constraints); + maxres(ast_manager& m, solver& s, expr_ref_vector& soft_constraints, vectorconst& weights); ~maxres(); virtual lbool operator()(); virtual rational get_lower() const; diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 2eb6e426b..1cc98d328 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -39,16 +39,16 @@ namespace opt { m_msolver = 0; is_sat = m_s->check_sat(0, 0); } + else if (m_maxsat_engine == symbol("maxres")) { + m_msolver = alloc(maxres, m, *m_s, m_soft_constraints, m_weights); + } else if (is_maxsat_problem(m_weights)) { if (m_maxsat_engine == symbol("core_maxsat")) { m_msolver = alloc(core_maxsat, m, *m_s, m_soft_constraints); } else if (m_maxsat_engine == symbol("weighted_maxsat")) { m_msolver = alloc(wmaxsmt, m, m_s.get(), m_soft_constraints, m_weights); - } - else if (m_maxsat_engine == symbol("maxres")) { - m_msolver = alloc(maxres, m, *m_s, m_soft_constraints); - } + } else { m_msolver = alloc(fu_malik, m, *m_s, m_soft_constraints); } diff --git a/src/opt/mus.cpp b/src/opt/mus.cpp index 1bed42f7d..9d9278a27 100644 --- a/src/opt/mus.cpp +++ b/src/opt/mus.cpp @@ -16,9 +16,21 @@ struct mus::imp { vector m_cls2lits; expr_ref_vector m_vars; obj_map m_var2idx; + volatile bool m_cancel; -public: - imp(solver& s, ast_manager& m): s(s), m(m), m_cls2expr(m), m_vars(m) {} + imp(solver& s, ast_manager& m): s(s), m(m), m_cls2expr(m), m_vars(m), m_cancel(false) {} + + void reset() { + m_cls2expr.reset(); + m_expr2cls.reset(); + m_cls2lits.reset(); + m_vars.reset(); + m_var2idx.reset(); + } + + void set_cancel(bool f) { + m_cancel = f; + } unsigned add_var(expr* v) { unsigned idx = m_vars.size(); @@ -47,10 +59,16 @@ public: m_cls2lits.push_back(lits); return idx; } + + expr* mk_not(expr* e) { + if (m.is_not(e, e)) { + return e; + } + return m.mk_not(e); + } lbool get_mus(unsigned_vector& mus) { TRACE("opt", tout << "\n";); - solver::scoped_push _sc(s); unsigned_vector core; for (unsigned i = 0; i < m_cls2expr.size(); ++i) { core.push_back(i); @@ -61,12 +79,17 @@ public: ptr_vector core_exprs; model.resize(m_vars.size()); while (!core.empty()) { - IF_VERBOSE(0, display_vec(tout << "core: ", core);); + TRACE("opt", + display_vec(tout << "core: ", core); + display_vec(tout << "mus: ", mus); + display_vec(tout << "model: ", model); + ); + IF_VERBOSE(1, verbose_stream() << "(opt.mus reducing core: " << core.size() << " new core: " << mus.size() << ")\n";); unsigned cls_id = core.back(); core.pop_back(); expr* cls = m_cls2expr[cls_id].get(); expr_ref not_cls(m); - not_cls = m.mk_not(cls); + not_cls = mk_not(cls); unsigned sz = assumptions.size(); assumptions.push_back(not_cls); add_core(core, assumptions); @@ -113,7 +136,7 @@ public: template void display_vec(std::ostream& out, T const& v) const { for (unsigned i = 0; i < v.size(); ++i) { - out << mk_pp(v[i], m) << " "; + out << v[i] << " "; } out << "\n"; } @@ -133,19 +156,18 @@ public: */ void rmr(unsigned_vector& M, unsigned_vector& mus, svector& model) { TRACE("opt", - display_vec(tout << "M:", M); - display_vec(tout << "mus:", mus); - display_vec(tout << "model:", model);); + display_vec(tout << "core: ", M); + display_vec(tout << "mus: ", mus); + display_vec(tout << "model: ", model);); unsigned cls_id = mus.back(); smt::literal_vector const& cls = m_cls2lits[cls_id]; - unsigned cls_id_new; for (unsigned i = 0; i < cls.size(); ++i) { smt::literal lit = cls[i]; SASSERT(model[lit.var()] == lit.sign()); // literal evaluates to false. model[lit.var()] = !model[lit.var()]; // swap assignment - if (has_single_unsat(model, cls_id_new)) { - mus.push_back(cls_id_new); + if (!mus.contains(cls_id) && has_single_unsat(model, cls_id)) { + mus.push_back(cls_id); rmr(M, mus, model); } model[lit.var()] = !model[lit.var()]; // swap assignment back @@ -176,13 +198,6 @@ public: return false; } - template - void display_vec(std::ostream& out, T const& v) { - for (unsigned i = 0; i < v.size(); ++i) { - out << v[i] << " "; - } - out << "\n"; - } }; mus::mus(solver& s, ast_manager& m) { @@ -201,3 +216,10 @@ lbool mus::get_mus(unsigned_vector& mus) { return m_imp->get_mus(mus); } +void mus::set_cancel(bool f) { + m_imp->set_cancel(f); +} + +void mus::reset() { + m_imp->reset(); +} diff --git a/src/opt/mus.h b/src/opt/mus.h index a2ba36f14..e3cb4c963 100644 --- a/src/opt/mus.h +++ b/src/opt/mus.h @@ -16,6 +16,10 @@ namespace opt { unsigned add_soft(expr* cls, unsigned sz, expr* const* args); lbool get_mus(unsigned_vector& mus); + + void reset(); + + void set_cancel(bool f); }; }; From 9f1b2ccfc4f8545406b2411b32e66cd8386af67c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 Jul 2014 23:53:03 +0200 Subject: [PATCH 430/925] restructure maxsmt solvers, flatten weighted/non-weighted versions, fix bugs and simplify mus/max-res Signed-off-by: Nikolaj Bjorner --- src/opt/hitting_sets.cpp | 2 +- src/opt/maxres.cpp | 174 +++++++--------- src/opt/maxres.h | 42 ++-- src/opt/maxsmt.cpp | 173 ++++++++++++++-- src/opt/maxsmt.h | 62 ++++++ src/opt/mus.cpp | 86 ++++++-- src/opt/mus.h | 24 ++- src/opt/opt_params.pyg | 3 +- src/opt/weighted_maxsat.cpp | 387 ++++++------------------------------ src/opt/weighted_maxsat.h | 37 ++-- 10 files changed, 492 insertions(+), 498 deletions(-) diff --git a/src/opt/hitting_sets.cpp b/src/opt/hitting_sets.cpp index fb9d2d009..c3436f61d 100644 --- a/src/opt/hitting_sets.cpp +++ b/src/opt/hitting_sets.cpp @@ -228,7 +228,7 @@ namespace opt { inc_score(clause_id); } TRACE("opt", display(tout, j);); - IF_VERBOSE(1, if (!sign) display(verbose_stream(), j);); + IF_VERBOSE(2, if (!sign) display(verbose_stream(), j);); if (!sign && m_enable_simplex) { add_simplex_row(!sign, sz, S); } diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 11d87a98e..2ec73bab4 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -1,7 +1,21 @@ -/** - MaxRes (weighted) max-sat algorithm by Nina and Bacchus, AAAI 2014. +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + maxsres.cpp + +Abstract: -*/ + MaxRes (weighted) max-sat algorithm by Nina and Bacchus, AAAI 2014. + +Author: + + Nikolaj Bjorner (nbjorner) 2014-20-7 + +Notes: + +--*/ #include "solver.h" #include "maxsmt.h" @@ -11,7 +25,8 @@ using namespace opt; -struct maxres::imp { + +class maxres : public maxsmt_solver_base { struct info { app* m_cls; rational m_weight; @@ -19,31 +34,25 @@ struct maxres::imp { m_cls(cls), m_weight(w) {} info(): m_cls(0) {} }; - ast_manager& m; - solver& s; expr_ref_vector m_B; - expr_ref_vector m_D; expr_ref_vector m_asms; - model_ref m_model; - expr_ref_vector m_soft_constraints; - volatile bool m_cancel; - rational m_lower; - rational m_upper; obj_map m_asm2info; ptr_vector m_new_core; mus m_mus; expr_ref_vector m_trail; - imp(ast_manager& m, solver& s, expr_ref_vector& soft_constraints, vector const& weights): - m(m), s(s), m_B(m), m_D(m), m_asms(m), m_soft_constraints(m), - m_cancel(false), - m_mus(s, m), +public: + maxres(ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft): + maxsmt_solver_base(s, m, p, ws, soft), + m_B(m), m_asms(m), + m_mus(m_s, m), m_trail(m) { - // TBD: this introduces an assertion to solver. - init_soft(weights, soft_constraints); } + virtual ~maxres() {} + bool is_literal(expr* l) { return is_uninterp_const(l) || @@ -60,9 +69,9 @@ struct maxres::imp { asum = e; } else { - asum = m.mk_fresh_const("soft", m.mk_bool_sort()); + asum = mk_fresh_bool("soft"); fml = m.mk_iff(asum, e); - s.assert_expr(fml); + m_s->assert_expr(fml); } new_assumption(asum, cls, w); m_upper += w; @@ -78,28 +87,35 @@ struct maxres::imp { lbool operator()() { expr_ref fml(m); ptr_vector core; - solver::scoped_push _sc(s); + solver::scoped_push _sc(*m_s.get()); + init(); + init_local(); while (true) { TRACE("opt", display_vec(tout, m_asms.size(), m_asms.c_ptr()); - s.display(tout); + m_s->display(tout); tout << "\n"; display(tout); ); - lbool is_sat = s.check_sat(m_asms.size(), m_asms.c_ptr()); + lbool is_sat = m_s->check_sat(m_asms.size(), m_asms.c_ptr()); if (m_cancel) { return l_undef; } switch (is_sat) { case l_true: - s.get_model(m_model); + m_s->get_model(m_model); + for (unsigned i = 0; i < m_soft.size(); ++i) { + expr_ref tmp(m); + VERIFY(m_model->eval(m_soft[i].get(), tmp)); + m_assignment[i] = m.is_true(tmp); + } m_upper = m_lower; return l_true; case l_undef: return l_undef; default: core.reset(); - s.get_unsat_core(core); + m_s->get_unsat_core(core); TRACE("opt", display_vec(tout << "core: ", core.size(), core.c_ptr());); SASSERT(!core.empty()); is_sat = minimize_core(core); @@ -115,7 +131,7 @@ struct maxres::imp { TRACE("opt", display_vec(tout << "minimized core: ", core.size(), core.c_ptr());); max_resolve(core, w); fml = m.mk_not(m.mk_and(m_B.size(), m_B.c_ptr())); - s.assert_expr(fml); + m_s->assert_expr(fml); m_lower += w; break; } @@ -192,31 +208,33 @@ struct maxres::imp { void max_resolve(ptr_vector& core, rational const& w) { SASSERT(!core.empty()); expr_ref fml(m), asum(m); - app_ref cls(m); + app_ref cls(m), d(m); m_B.reset(); - m_D.reset(); - m_D.resize(core.size()); m_B.append(core.size(), core.c_ptr()); - m_D[core.size()-1] = m.mk_false(); + d = m.mk_true(); // - // d_{sz-1} := false - // d_i := (!core_{i+1} or d_{i+1}) for i = 0...sz-2 - // soft (!d_i or core_i) - // - for (unsigned i = core.size()-1; i > 0; ) { - --i; - expr* d_i1 = m_D[i+1].get(); - expr* b_i = m_B[i].get(); - expr* b_i1 = m_B[i+1].get(); - m_D[i] = m.mk_implies(b_i1, d_i1); - expr* d_i = m_D[i].get(); - asum = m.mk_fresh_const("a", m.mk_bool_sort()); - cls = m.mk_implies(d_i, b_i); + // d_0 := true + // d_i := b_{i-1} and d_{i-1} for i = 1...sz-1 + // soft (b_i or !d_i) + // == (b_i or !(!b_{i-1} or d_{i-1})) + // == (b_i or b_0 & b_1 & ... & b_{i-1}) + // + // Soft constraint is satisfied if previous soft constraint + // holds or if it is the first soft constraint to fail. + // + // Soundness of this rule can be established using MaxRes + // + for (unsigned i = 1; i < core.size(); ++i) { + expr* b_i = m_B[i-1].get(); + expr* b_i1 = m_B[i].get(); + d = m.mk_and(b_i, d); + asum = mk_fresh_bool("a"); + cls = m.mk_or(b_i1, d); fml = m.mk_iff(asum, cls); cls = mk_cls(cls); m_trail.push_back(cls); new_assumption(asum, cls, w); - s.assert_expr(fml); + m_s->assert_expr(fml); } } @@ -262,77 +280,25 @@ struct maxres::imp { } } - rational get_lower() const { - return m_lower; - } - - rational get_upper() const { - return m_upper; - } - - bool get_assignment(unsigned index) const { - expr_ref tmp(m); - VERIFY(m_model->eval(m_soft_constraints[index], tmp)); - return m.is_true(tmp); - } - void set_cancel(bool f) { - m_cancel = f; + virtual void set_cancel(bool f) { + maxsmt_solver_base::set_cancel(f); m_mus.set_cancel(f); } - void collect_statistics(statistics& st) const { - } - void get_model(model_ref& mdl) { - mdl = m_model; - } - void updt_params(params_ref& p) { - ; - } - void init_soft(vector const& weights, expr_ref_vector const& soft) { - m_soft_constraints.reset(); + void init_local() { m_upper.reset(); m_lower.reset(); m_asm2info.reset(); m_trail.reset(); - m_soft_constraints.append(soft); - for (unsigned i = 0; i < m_soft_constraints.size(); ++i) { - add_soft(m_soft_constraints[i].get(), weights[i]); + for (unsigned i = 0; i < m_soft.size(); ++i) { + add_soft(m_soft[i].get(), m_weights[i]); } } }; -maxres::maxres(ast_manager& m, solver& s, expr_ref_vector& soft_constraints, vector const& weights) { - m_imp = alloc(imp, m, s, soft_constraints, weights); +opt::maxsmt_solver_base* opt::mk_maxres(ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft) { + return alloc(maxres, m, s, p, ws, soft); } -maxres::~maxres() { - dealloc(m_imp); -} - - -lbool maxres::operator()() { - return (*m_imp)(); -} - -rational maxres::get_lower() const { - return m_imp->get_lower(); -} -rational maxres::get_upper() const { - return m_imp->get_upper(); -} -bool maxres::get_assignment(unsigned index) const { - return m_imp->get_assignment(index); -} -void maxres::set_cancel(bool f) { - m_imp->set_cancel(f); -} -void maxres::collect_statistics(statistics& st) const { - m_imp->collect_statistics(st); -} -void maxres::get_model(model_ref& mdl) { - m_imp->get_model(mdl); -} -void maxres::updt_params(params_ref& p) { - m_imp->updt_params(p); -} diff --git a/src/opt/maxres.h b/src/opt/maxres.h index 41b57456f..8058a0376 100644 --- a/src/opt/maxres.h +++ b/src/opt/maxres.h @@ -1,18 +1,30 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + maxsres.h + +Abstract: + + MaxRes (weighted) max-sat algorithm by Nina and Bacchus, AAAI 2014. + +Author: + + Nikolaj Bjorner (nbjorner) 2014-20-7 + +Notes: + +--*/ + +#ifndef _MAXRES_H_ +#define _MAXRES_H_ namespace opt { - class maxres : public maxsmt_solver { - struct imp; - imp* m_imp; - public: - maxres(ast_manager& m, solver& s, expr_ref_vector& soft_constraints, vectorconst& weights); - ~maxres(); - virtual lbool operator()(); - virtual rational get_lower() const; - virtual rational get_upper() const; - virtual bool get_assignment(unsigned index) const; - virtual void set_cancel(bool f); - virtual void collect_statistics(statistics& st) const; - virtual void get_model(model_ref& mdl); - virtual void updt_params(params_ref& p); - }; + maxsmt_solver_base* mk_maxres(ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft); + + }; + +#endif diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 1cc98d328..2b20ccbd0 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -25,9 +25,140 @@ Notes: #include "weighted_maxsat.h" #include "ast_pp.h" #include "opt_params.hpp" +#include "pb_decl_plugin.h" +#include "pb_sls.h" +#include "tactical.h" +#include "tactic.h" +#include "tactic2solver.h" +#include "qfbv_tactic.h" +#include "card2bv_tactic.h" +#include "uint_set.h" +#include "opt_sls_solver.h" +#include "pb_preprocess_tactic.h" + + namespace opt { + void maxsmt_solver_base::updt_params(params_ref& p) { + m_params.copy(p); + s().updt_params(p); + opt_params _p(p); + m_enable_sat = _p.enable_sat(); + m_enable_sls = _p.enable_sls(); + } + + void maxsmt_solver_base::init_soft(vector const& weights, expr_ref_vector const& soft) { + m_weights.reset(); + m_soft.reset(); + m_weights.append(weights); + m_soft.append(soft); + } + + void maxsmt_solver_base::init() { + m_lower.reset(); + m_upper.reset(); + m_assignment.reset(); + for (unsigned i = 0; i < m_weights.size(); ++i) { + expr_ref val(m); + VERIFY(m_model->eval(m_soft[i].get(), val)); + m_assignment.push_back(m.is_true(val)); + if (!m_assignment.back()) { + m_upper += m_weights[i]; + } + } + + TRACE("opt", + tout << m_upper << ": "; + for (unsigned i = 0; i < m_weights.size(); ++i) { + tout << (m_assignment[i]?"1":"0"); + } + tout << "\n";); + } + + expr* maxsmt_solver_base::mk_not(expr* e) { + if (m.is_not(e, e)) { + return e; + } + else { + return m.mk_not(e); + } + } + + struct maxsmt_solver_base::is_bv { + struct found {}; + ast_manager& m; + pb_util pb; + bv_util bv; + is_bv(ast_manager& m): m(m), pb(m), bv(m) {} + void operator()(var *) { throw found(); } + void operator()(quantifier *) { throw found(); } + void operator()(app *n) { + family_id fid = n->get_family_id(); + if (fid != m.get_basic_family_id() && + fid != pb.get_family_id() && + fid != bv.get_family_id() && + !is_uninterp_const(n)) { + throw found(); + } + } + }; + + bool maxsmt_solver_base::probe_bv() { + expr_fast_mark1 visited; + is_bv proc(m); + try { + unsigned sz = s().get_num_assertions(); + for (unsigned i = 0; i < sz; i++) { + quick_for_each_expr(proc, visited, s().get_assertion(i)); + } + sz = m_soft.size(); + for (unsigned i = 0; i < sz; ++i) { + quick_for_each_expr(proc, visited, m_soft[i].get()); + } + } + catch (is_bv::found) { + return false; + } + return true; + } + + void maxsmt_solver_base::enable_bvsat() { + if (m_enable_sat && !m_sat_enabled && probe_bv()) { + tactic_ref pb2bv = mk_card2bv_tactic(m, m_params); + tactic_ref bv2sat = mk_qfbv_tactic(m, m_params); + tactic_ref tac = and_then(pb2bv.get(), bv2sat.get()); + solver* sat_solver = mk_tactic2solver(m, tac.get(), m_params); + unsigned sz = s().get_num_assertions(); + for (unsigned i = 0; i < sz; ++i) { + sat_solver->assert_expr(s().get_assertion(i)); + } + unsigned lvl = m_s->get_scope_level(); + while (lvl > 0) { sat_solver->push(); --lvl; } + m_s = sat_solver; + m_sat_enabled = true; + } + } + + void maxsmt_solver_base::enable_sls() { + if (m_enable_sls && !m_sls_enabled && probe_bv()) { + m_params.set_uint("restarts", 20); + unsigned lvl = m_s->get_scope_level(); + sls_solver* sls = alloc(sls_solver, m, m_s.get(), m_soft, m_weights, m_params); + m_s = sls; + while (lvl > 0) { m_s->push(); --lvl; } + m_sls_enabled = true; + sls->opt(m_model); + } + } + + app* maxsmt_solver_base::mk_fresh_bool(char const* name) { + app* result = m.mk_fresh_const(name, m.mk_bool_sort()); + m_mc->insert(result->get_decl()); + return result; + } + + lbool maxsmt::operator()(opt_solver* s) { lbool is_sat; m_msolver = 0; @@ -39,26 +170,40 @@ namespace opt { m_msolver = 0; is_sat = m_s->check_sat(0, 0); } - else if (m_maxsat_engine == symbol("maxres")) { - m_msolver = alloc(maxres, m, *m_s, m_soft_constraints, m_weights); + else if (m_maxsat_engine == symbol("maxres")) { + m_msolver = mk_maxres(m, s, m_params, m_weights, m_soft_constraints); } - else if (is_maxsat_problem(m_weights)) { - if (m_maxsat_engine == symbol("core_maxsat")) { - m_msolver = alloc(core_maxsat, m, *m_s, m_soft_constraints); - } - else if (m_maxsat_engine == symbol("weighted_maxsat")) { - m_msolver = alloc(wmaxsmt, m, m_s.get(), m_soft_constraints, m_weights); - } - else { - m_msolver = alloc(fu_malik, m, *m_s, m_soft_constraints); - } + else if (m_maxsat_engine == symbol("pbmax")) { + m_msolver = mk_pbmax(m, s, m_params, m_weights, m_soft_constraints); + } + else if (m_maxsat_engine == symbol("wpm2")) { + m_msolver = mk_wpm2(m, s, m_params, m_weights, m_soft_constraints); + } + else if (m_maxsat_engine == symbol("bcd2")) { + m_msolver = mk_bcd2(m, s, m_params, m_weights, m_soft_constraints); + } + else if (m_maxsat_engine == symbol("hsmax")) { + m_msolver = mk_hsmax(m, s, m_params, m_weights, m_soft_constraints); + } + else if (m_maxsat_engine == symbol("sls")) { + // NB: this is experimental one-round version of SLS + m_msolver = mk_sls(m, s, m_params, m_weights, m_soft_constraints); + } + else if (is_maxsat_problem(m_weights) && m_maxsat_engine == symbol("core_maxsat")) { + m_msolver = alloc(core_maxsat, m, *m_s, m_soft_constraints); + } + else if (is_maxsat_problem(m_weights) && m_maxsat_engine == symbol("fu_malik")) { + m_msolver = alloc(fu_malik, m, *m_s, m_soft_constraints); } else { - m_msolver = alloc(wmaxsmt, m, m_s.get(), m_soft_constraints, m_weights); + if (m_maxsat_engine != symbol::null) { + warning_msg("solver %s is not recognized, using default 'wmax'", + m_maxsat_engine.str().c_str()); + } + m_msolver = mk_wmax(m, m_s.get(), m_params, m_weights, m_soft_constraints); } if (m_msolver) { - m_msolver->updt_params(m_params); is_sat = (*m_msolver)(); if (is_sat != l_false) { m_msolver->get_model(m_model); diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index cd26c40e5..0cc833cba 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -37,6 +37,68 @@ namespace opt { virtual void updt_params(params_ref& p) = 0; }; + + // --------------------------------------------- + // base class with common utilities used + // by maxsmt solvers + // + class maxsmt_solver_base : public maxsmt_solver { + protected: + ref m_s; + ast_manager& m; + volatile bool m_cancel; + expr_ref_vector m_soft; + vector m_weights; + rational m_lower; + rational m_upper; + model_ref m_model; + ref m_mc; // model converter to remove fresh variables + svector m_assignment; // truth assignment to soft constraints + params_ref m_params; // config + bool m_enable_sls; // config + bool m_enable_sat; // config + bool m_sls_enabled; + bool m_sat_enabled; + struct is_bv; + + public: + maxsmt_solver_base(opt_solver* s, ast_manager& m, params_ref& p, + vector const& ws, expr_ref_vector const& soft): + m_s(s), m(m), m_cancel(false), m_soft(m), + m_enable_sls(false), m_enable_sat(false), + m_sls_enabled(false), m_sat_enabled(false) { + m_s->get_model(m_model); + SASSERT(m_model); + updt_params(p); + set_converter(s->mc_ref().get()); + init_soft(ws, soft); + } + + virtual ~maxsmt_solver_base() {} + virtual rational get_lower() const { return m_lower; } + virtual rational get_upper() const { return m_upper; } + virtual bool get_assignment(unsigned index) const { return m_assignment[index]; } + virtual void set_cancel(bool f) { m_cancel = f; m_s->set_cancel(f); } + virtual void collect_statistics(statistics& st) const { + if (m_sls_enabled || m_sat_enabled) { + m_s->collect_statistics(st); + } + } + virtual void get_model(model_ref& mdl) { mdl = m_model.get(); } + void set_model() { s().get_model(m_model); } + virtual void updt_params(params_ref& p); + virtual void init_soft(vector const& weights, expr_ref_vector const& soft); + void add_hard(expr* e){ s().assert_expr(e); } + solver& s() { return *m_s; } + void set_converter(filter_model_converter* mc) { m_mc = mc; } + void init(); + expr* mk_not(expr* e); + bool probe_bv(); + void enable_bvsat(); + void enable_sls(); + app* mk_fresh_bool(char const* name); + }; + /** Takes solver with hard constraints added. Returns modified soft constraints that are maximal assignments. diff --git a/src/opt/mus.cpp b/src/opt/mus.cpp index 9d9278a27..2e71f1bb8 100644 --- a/src/opt/mus.cpp +++ b/src/opt/mus.cpp @@ -1,15 +1,37 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + mus.cpp + +Abstract: + + Faster MUS extraction based on Belov et.al. HYB (Algorithm 3, 4) + +Author: + + Nikolaj Bjorner (nbjorner) 2014-20-7 + +Notes: + + Model rotation needs fixes to ensure that hard constraints are satisfied + under pertubed model. Model rotation also has o be consistent with theories. + +--*/ + #include "solver.h" #include "smt_literal.h" #include "mus.h" #include "ast_pp.h" +#include "model_smt2_pp.h" using namespace opt; -// Faster MUS extraction based on Belov et.al. HYB (Algorithm 3, 4) - +// struct mus::imp { - solver& s; + ref& m_s; ast_manager& m; expr_ref_vector m_cls2expr; obj_map m_expr2cls; @@ -18,7 +40,7 @@ struct mus::imp { obj_map m_var2idx; volatile bool m_cancel; - imp(solver& s, ast_manager& m): s(s), m(m), m_cls2expr(m), m_vars(m), m_cancel(false) {} + imp(ref& s, ast_manager& m): m_s(s), m(m), m_cls2expr(m), m_vars(m), m_cancel(false) {} void reset() { m_cls2expr.reset(); @@ -26,6 +48,7 @@ struct mus::imp { m_cls2lits.reset(); m_vars.reset(); m_var2idx.reset(); + m_vars.push_back(m.mk_true()); } void set_cancel(bool f) { @@ -42,7 +65,7 @@ struct mus::imp { } unsigned add_soft(expr* cls, unsigned sz, expr* const* args) { - TRACE("opt", tout << sz << ": " << mk_pp(cls, m) << "\n";); + SASSERT(is_uninterp_const(cls) || m.is_not(cls) && is_uninterp_const(to_app(cls)->get_arg(0))); smt::literal_vector lits; expr* arg; for (unsigned i = 0; i < sz; ++i) { @@ -57,6 +80,10 @@ struct mus::imp { m_expr2cls.insert(cls, idx); m_cls2expr.push_back(cls); m_cls2lits.push_back(lits); + TRACE("opt", + tout << idx << ": " << mk_pp(cls, m) << "\n"; + display_vec(tout, lits); + ); return idx; } @@ -68,7 +95,11 @@ struct mus::imp { } lbool get_mus(unsigned_vector& mus) { - TRACE("opt", tout << "\n";); + TRACE("opt", + for (unsigned i = 0; i < m_cls2lits.size(); ++i) { + display_vec(tout, m_cls2lits[i]); + } + ); unsigned_vector core; for (unsigned i = 0; i < m_cls2expr.size(); ++i) { core.push_back(i); @@ -79,13 +110,13 @@ struct mus::imp { ptr_vector core_exprs; model.resize(m_vars.size()); while (!core.empty()) { + IF_VERBOSE(1, verbose_stream() << "(opt.mus reducing core: " << core.size() << " new core: " << mus.size() << ")\n";); + unsigned cls_id = core.back(); TRACE("opt", display_vec(tout << "core: ", core); display_vec(tout << "mus: ", mus); display_vec(tout << "model: ", model); ); - IF_VERBOSE(1, verbose_stream() << "(opt.mus reducing core: " << core.size() << " new core: " << mus.size() << ")\n";); - unsigned cls_id = core.back(); core.pop_back(); expr* cls = m_cls2expr[cls_id].get(); expr_ref not_cls(m); @@ -93,7 +124,7 @@ struct mus::imp { unsigned sz = assumptions.size(); assumptions.push_back(not_cls); add_core(core, assumptions); - lbool is_sat = s.check_sat(assumptions.size(), assumptions.c_ptr()); + lbool is_sat = m_s->check_sat(assumptions.size(), assumptions.c_ptr()); assumptions.resize(sz); switch(is_sat) { case l_undef: @@ -101,7 +132,7 @@ struct mus::imp { case l_true: assumptions.push_back(cls); mus.push_back(cls_id); - extract_model(s, model); + extract_model(model); sz = core.size(); core.append(mus); rmr(core, mus, model); @@ -109,7 +140,7 @@ struct mus::imp { break; default: core_exprs.reset(); - s.get_unsat_core(core_exprs); + m_s->get_unsat_core(core_exprs); if (!core_exprs.contains(not_cls)) { // core := core_exprs \ mus core.reset(); @@ -141,14 +172,19 @@ struct mus::imp { out << "\n"; } - void extract_model(solver& s, svector& model) { + void extract_model(svector& model) { model_ref mdl; - s.get_model(mdl); + m_s->get_model(mdl); for (unsigned i = 0; i < m_vars.size(); ++i) { expr_ref tmp(m); mdl->eval(m_vars[i].get(), tmp); model[i] = m.is_true(tmp); } + TRACE("opt", + display_vec(tout << "model: ", model); + model_smt2_pp(tout, m, *mdl, 0); + ); + } /** @@ -166,7 +202,9 @@ struct mus::imp { smt::literal lit = cls[i]; SASSERT(model[lit.var()] == lit.sign()); // literal evaluates to false. model[lit.var()] = !model[lit.var()]; // swap assignment - if (!mus.contains(cls_id) && has_single_unsat(model, cls_id)) { + if (has_single_unsat(model, cls_id) && + !mus.contains(cls_id) && + model_check(model, cls_id)) { mus.push_back(cls_id); rmr(M, mus, model); } @@ -174,6 +212,11 @@ struct mus::imp { } } + bool model_check(svector const& model, unsigned cls_id) { + // model has to work for hard constraints. + return false; + } + bool has_single_unsat(svector const& model, unsigned& cls_id) const { cls_id = UINT_MAX; for (unsigned i = 0; i < m_cls2lits.size(); ++i) { @@ -186,21 +229,24 @@ struct mus::imp { } } } + TRACE("opt", display_vec(tout << "clause: " << cls_id << " model: ", model);); return cls_id != UINT_MAX; } bool eval(svector const& model, smt::literal_vector const& cls) const { - for (unsigned i = 0; i < cls.size(); ++i) { - if (model[cls[i].var()] != cls[i].sign()) { - return true; - } + bool result = false; + for (unsigned i = 0; !result && i < cls.size(); ++i) { + result = (model[cls[i].var()] != cls[i].sign()); } - return false; + TRACE("opt", display_vec(tout << "model: ", model); + display_vec(tout << "clause: ", cls); + tout << "result: " << result << "\n";); + return result; } }; -mus::mus(solver& s, ast_manager& m) { +mus::mus(ref& s, ast_manager& m) { m_imp = alloc(imp, s, m); } diff --git a/src/opt/mus.h b/src/opt/mus.h index e3cb4c963..064ab3b0e 100644 --- a/src/opt/mus.h +++ b/src/opt/mus.h @@ -1,10 +1,30 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + mus.h + +Abstract: + + Faster MUS extraction based on Belov et.al. HYB (Algorithm 3, 4) + +Author: + + Nikolaj Bjorner (nbjorner) 2014-20-7 + +Notes: + +--*/ +#ifndef _MUS_H_ +#define _MUS_H_ namespace opt { class mus { struct imp; imp * m_imp; public: - mus(solver& s, ast_manager& m); + mus(ref& s, ast_manager& m); ~mus(); /** Add soft constraint. @@ -23,3 +43,5 @@ namespace opt { }; }; + +#endif diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index 2e6f67219..fbc2a8796 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -3,13 +3,12 @@ def_module_params('opt', export=True, params=(('timeout', UINT, UINT_MAX, 'set timeout'), ('engine', SYMBOL, 'basic', "select optimization engine: 'basic', 'farkas', 'symba'"), - ('maxsat_engine', SYMBOL, 'fu_malik', "select engine for non-weighted maxsat: 'fu_malik', 'core_maxsat'"), + ('maxsat_engine', SYMBOL, 'wmax', "select engine for maxsat: 'fu_malik', 'core_maxsat', 'wmax', 'pbmax', 'maxres', 'bcd2', 'wpm2', 'sls', 'hsmax'"), ('priority', SYMBOL, 'lex', "select how to priortize objectives: 'lex' (lexicographic), 'pareto', or 'box'"), ('dump_benchmarks', BOOL, False, 'dump benchmarks for profiling'), ('print_model', BOOL, False, 'display model for satisfiable constraints'), ('print_all_models', BOOL, False, 'display all intermediary models for satisfiable constraints'), ('debug_conflict', BOOL, False, 'debug conflict resolution'), - ('wmaxsat_engine', SYMBOL, 'wmax', "weighted maxsat engine: 'wmax', 'pbmax', 'bcd2', 'wpm2', 'bvsls', 'sls'"), ('enable_sls', BOOL, False, 'enable SLS tuning during weighted maxsast'), ('enable_sat', BOOL, False, 'enable the new SAT core for propositional constraints'), ('sls_engine', SYMBOL, 'pb', "SLS engine. Either 'bv' or 'pb'"), diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index 8d405196c..dbd5a060f 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -26,19 +26,12 @@ Notes: #include "opt_params.hpp" #include "pb_decl_plugin.h" #include "uint_set.h" -#include "tactical.h" -#include "tactic.h" #include "model_smt2_pp.h" -#include "pb_sls.h" -#include "tactic2solver.h" -#include "pb_preprocess_tactic.h" -#include "qfbv_tactic.h" -#include "card2bv_tactic.h" -#include "opt_sls_solver.h" #include "cancel_eh.h" #include "scoped_timer.h" #include "optsmt.h" #include "hitting_sets.h" +#include "stopwatch.h" namespace opt { @@ -56,162 +49,6 @@ namespace opt { } }; - // --------------------------------------------- - // base class with common utilities used - // by maxsmt solvers - // - class maxsmt_solver_base : public maxsmt_solver { - protected: - ref m_s; - ast_manager& m; - volatile bool m_cancel; - expr_ref_vector m_soft; - vector m_weights; - rational m_lower; - rational m_upper; - model_ref m_model; - ref m_mc; // model converter to remove fresh variables - svector m_assignment; // truth assignment to soft constraints - params_ref m_params; // config - bool m_enable_sls; // config - bool m_enable_sat; // config - bool m_sls_enabled; - bool m_sat_enabled; - public: - maxsmt_solver_base(solver* s, ast_manager& m): - m_s(s), m(m), m_cancel(false), m_soft(m), - m_enable_sls(false), m_enable_sat(false), - m_sls_enabled(false), m_sat_enabled(false) { - m_s->get_model(m_model); - SASSERT(m_model); - } - - virtual ~maxsmt_solver_base() {} - virtual rational get_lower() const { return m_lower; } - virtual rational get_upper() const { return m_upper; } - virtual bool get_assignment(unsigned index) const { return m_assignment[index]; } - virtual void set_cancel(bool f) { m_cancel = f; m_s->set_cancel(f); } - virtual void collect_statistics(statistics& st) const { - if (m_sls_enabled || m_sat_enabled) { - m_s->collect_statistics(st); - } - } - virtual void get_model(model_ref& mdl) { mdl = m_model.get(); } - void set_model() { s().get_model(m_model); } - virtual void updt_params(params_ref& p) { - m_params.copy(p); - s().updt_params(p); - opt_params _p(p); - m_enable_sat = _p.enable_sat(); - m_enable_sls = _p.enable_sls(); - } - virtual void init_soft(vector const& weights, expr_ref_vector const& soft) { - m_weights.reset(); - m_soft.reset(); - m_weights.append(weights); - m_soft.append(soft); - } - void add_hard(expr* e){ s().assert_expr(e); } - solver& s() { return *m_s; } - void set_converter(filter_model_converter* mc) { m_mc = mc; } - - void init() { - m_lower.reset(); - m_upper.reset(); - m_assignment.reset(); - for (unsigned i = 0; i < m_weights.size(); ++i) { - expr_ref val(m); - VERIFY(m_model->eval(m_soft[i].get(), val)); - m_assignment.push_back(m.is_true(val)); - if (!m_assignment.back()) { - m_upper += m_weights[i]; - } - } - - TRACE("opt", - tout << m_upper << ": "; - for (unsigned i = 0; i < m_weights.size(); ++i) { - tout << (m_assignment[i]?"1":"0"); - } - tout << "\n";); - } - - expr* mk_not(expr* e) { - if (m.is_not(e, e)) { - return e; - } - else { - return m.mk_not(e); - } - } - - struct is_bv { - struct found {}; - ast_manager& m; - pb_util pb; - bv_util bv; - is_bv(ast_manager& m): m(m), pb(m), bv(m) {} - void operator()(var *) { throw found(); } - void operator()(quantifier *) { throw found(); } - void operator()(app *n) { - family_id fid = n->get_family_id(); - if (fid != m.get_basic_family_id() && - fid != pb.get_family_id() && - fid != bv.get_family_id() && - !is_uninterp_const(n)) { - throw found(); - } - } - }; - - bool probe_bv() { - expr_fast_mark1 visited; - is_bv proc(m); - try { - unsigned sz = s().get_num_assertions(); - for (unsigned i = 0; i < sz; i++) { - quick_for_each_expr(proc, visited, s().get_assertion(i)); - } - sz = m_soft.size(); - for (unsigned i = 0; i < sz; ++i) { - quick_for_each_expr(proc, visited, m_soft[i].get()); - } - } - catch (is_bv::found) { - return false; - } - return true; - } - - void enable_bvsat() { - if (m_enable_sat && !m_sat_enabled && probe_bv()) { - tactic_ref pb2bv = mk_card2bv_tactic(m, m_params); - tactic_ref bv2sat = mk_qfbv_tactic(m, m_params); - tactic_ref tac = and_then(pb2bv.get(), bv2sat.get()); - solver* sat_solver = mk_tactic2solver(m, tac.get(), m_params); - unsigned sz = s().get_num_assertions(); - for (unsigned i = 0; i < sz; ++i) { - sat_solver->assert_expr(s().get_assertion(i)); - } - unsigned lvl = m_s->get_scope_level(); - while (lvl > 0) { sat_solver->push(); --lvl; } - m_s = sat_solver; - m_sat_enabled = true; - } - } - - void enable_sls() { - if (m_enable_sls && !m_sls_enabled && probe_bv()) { - m_params.set_uint("restarts", 20); - unsigned lvl = m_s->get_scope_level(); - sls_solver* sls = alloc(sls_solver, m, m_s.get(), m_soft, m_weights, m_params); - m_s = sls; - while (lvl > 0) { m_s->push(); --lvl; } - m_sls_enabled = true; - sls->opt(m_model); - } - } - }; // ------------------------------------------------------ // Morgado, Heras, Marques-Silva 2013 @@ -247,8 +84,7 @@ namespace opt { es.push_back(m.mk_not(*it)); } } - virtual void init_soft(vector const& weights, expr_ref_vector const& soft) { - maxsmt_solver_base::init_soft(weights, soft); + void bcd2_init_soft(vector const& weights, expr_ref_vector const& soft) { // normalize weights to be integral: m_den = rational::one(); @@ -290,13 +126,15 @@ namespace opt { } public: - bcd2(solver* s, ast_manager& m): - maxsmt_solver_base(s, m), + bcd2(opt_solver* s, ast_manager& m, params_ref& p, + vector const& ws, expr_ref_vector const& soft): + maxsmt_solver_base(s, m, p, ws, soft), pb(m), m_soft_aux(m), m_trail(m), m_soft_constraints(m), m_enable_lazy(true) { + bcd2_init_soft(ws, soft); } virtual ~bcd2() {} @@ -315,7 +153,7 @@ namespace opt { } process_sat(); while (m_lower < m_upper) { - IF_VERBOSE(1, verbose_stream() << "(wmaxsat.bcd2 [" << m_lower << ":" << m_upper << "])\n";); + IF_VERBOSE(1, verbose_stream() << "(bcd2 [" << m_lower << ":" << m_upper << "])\n";); assert_soft(); solver::scoped_push _scope2(s()); TRACE("opt", display(tout);); @@ -412,10 +250,8 @@ namespace opt { } expr* mk_fresh() { - app_ref r(m); - r = m.mk_fresh_const("r", m.mk_bool_sort()); + expr* r = mk_fresh_bool("r"); m_trail.push_back(r); - m_mc->insert(r->get_decl()); return r; } @@ -627,8 +463,8 @@ namespace opt { public: - hsmax(solver* s, ast_manager& m): - maxsmt_solver_base(s, m), + hsmax(opt_solver* s, ast_manager& m, params_ref& p, vector const& ws, expr_ref_vector const& soft): + maxsmt_solver_base(s, m, p, ws, soft), m_aux(m), pb(m), a(m), @@ -641,10 +477,6 @@ namespace opt { m_hs.set_cancel(f); } - virtual void updt_params(params_ref& p) { - maxsmt_solver_base::updt_params(p); - } - virtual void collect_statistics(statistics& st) const { maxsmt_solver_base::collect_statistics(st); m_hs.collect_statistics(st); @@ -670,8 +502,8 @@ namespace opt { while (m_lower < m_upper) { ++m_stats.m_num_iterations; IF_VERBOSE(1, verbose_stream() << - "(wmaxsat.hsmax [" << m_lower << ":" << m_upper << "])\n";); - TRACE("opt", tout << "(wmaxsat.hsmax [" << m_lower << ":" << m_upper << "])\n";); + "(hsmax [" << m_lower << ":" << m_upper << "])\n";); + TRACE("opt", tout << "(hsmax [" << m_lower << ":" << m_upper << "])\n";); if (m_cancel) { return l_undef; } @@ -688,7 +520,7 @@ namespace opt { break; case l_false: TRACE("opt", tout << "no more seeds\n";); - IF_VERBOSE(1, verbose_stream() << "(wmaxsat.maxhs.no-more-seeds)\n";); + IF_VERBOSE(1, verbose_stream() << "(maxhs.no-more-seeds)\n";); m_lower = m_upper; return l_true; case l_undef: @@ -697,7 +529,7 @@ namespace opt { break; } case l_false: - IF_VERBOSE(1, verbose_stream() << "(wmaxsat.maxhs.no-more-cores)\n";); + IF_VERBOSE(1, verbose_stream() << "(maxhs.no-more-cores)\n";); TRACE("opt", tout << "no more cores\n";); m_lower = m_upper; return l_true; @@ -1119,8 +951,9 @@ namespace opt { class pbmax : public maxsmt_solver_base { public: - pbmax(solver* s, ast_manager& m): - maxsmt_solver_base(s, m) { + pbmax(opt_solver* s, ast_manager& m, params_ref& p, + vector const& ws, expr_ref_vector const& soft): + maxsmt_solver_base(s, m, p, ws, soft) { } virtual ~pbmax() {} @@ -1154,7 +987,7 @@ namespace opt { m_upper += m_weights[i]; } } - IF_VERBOSE(1, verbose_stream() << "(wmaxsat.pb solve with upper bound: " << m_upper << ")\n";); + IF_VERBOSE(1, verbose_stream() << "(pb solve with upper bound: " << m_upper << ")\n";); TRACE("opt", tout << "new upper: " << m_upper << "\n";); fml = u.mk_lt(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper); @@ -1182,15 +1015,16 @@ namespace opt { class wpm2 : public maxsmt_solver_base { scoped_ptr maxs; public: - wpm2(solver* s, ast_manager& m, maxsmt_solver_base* _maxs): - maxsmt_solver_base(s, m), maxs(_maxs) { + wpm2(opt_solver* s, ast_manager& m, maxsmt_solver_base* _maxs, params_ref& p, + vector const& ws, expr_ref_vector const& soft): + maxsmt_solver_base(s, m, p, ws, soft), maxs(_maxs) { } virtual ~wpm2() {} lbool operator()() { enable_sls(); - IF_VERBOSE(1, verbose_stream() << "(wmaxsat.wpm2 solve)\n";); + IF_VERBOSE(1, verbose_stream() << "(wpm2 solve)\n";); solver::scoped_push _s(s()); pb_util u(m); app_ref fml(m), a(m), b(m), c(m); @@ -1203,20 +1037,17 @@ namespace opt { for (unsigned i = 0; i < m_soft.size(); ++i) { rational w = m_weights[i]; - b = m.mk_fresh_const("b", m.mk_bool_sort()); - m_mc->insert(b->get_decl()); + b = mk_fresh_bool("b"); block.push_back(b); expr* bb = b; - a = m.mk_fresh_const("a", m.mk_bool_sort()); - m_mc->insert(a->get_decl()); + a = mk_fresh_bool("a"); ans.push_back(a); ans_index.insert(a, i); fml = m.mk_or(m_soft[i].get(), b, m.mk_not(a)); s().assert_expr(fml); - c = m.mk_fresh_const("c", m.mk_bool_sort()); - m_mc->insert(c->get_decl()); + c = mk_fresh_bool("c"); fml = m.mk_implies(c, u.mk_le(1,&w,&bb,rational(0))); s().assert_expr(fml); @@ -1321,11 +1152,10 @@ namespace opt { B_ge_k = u.mk_ge(ws.size(), ws.c_ptr(), bs.c_ptr(), k); s().assert_expr(B_ge_k); al.push_back(B_ge_k); - IF_VERBOSE(1, verbose_stream() << "(wmaxsat.wpm2 lower bound: " << m_lower << ")\n";); + IF_VERBOSE(1, verbose_stream() << "(wpm2 lower bound: " << m_lower << ")\n";); IF_VERBOSE(2, verbose_stream() << "New lower bound: " << B_ge_k << "\n";); - c = m.mk_fresh_const("c", m.mk_bool_sort()); - m_mc->insert(c->get_decl()); + c = mk_fresh_bool("c"); fml = m.mk_implies(c, B_le_k); s().assert_expr(fml); sc.push_back(B); @@ -1394,8 +1224,9 @@ namespace opt { class sls : public maxsmt_solver_base { public: - sls(solver* s, ast_manager& m): - maxsmt_solver_base(s, m) { + sls(opt_solver* s, ast_manager& m, params_ref& p, + vector const& ws, expr_ref_vector const& soft): + maxsmt_solver_base(s, m, p, ws, soft) { } virtual ~sls() {} lbool operator()() { @@ -1425,8 +1256,9 @@ namespace opt { class maxsmt_solver_wbase : public maxsmt_solver_base { smt::context& ctx; public: - maxsmt_solver_wbase(solver* s, ast_manager& m, smt::context& ctx): - maxsmt_solver_base(s, m), ctx(ctx) {} + maxsmt_solver_wbase(opt_solver* s, ast_manager& m, smt::context& ctx, params_ref& p, + vector const& ws, expr_ref_vector const& soft): + maxsmt_solver_base(s, m, p, ws, soft), ctx(ctx) {} ~maxsmt_solver_wbase() {} class scoped_ensure_theory { @@ -1471,7 +1303,9 @@ namespace opt { class wmax : public maxsmt_solver_wbase { public: - wmax(solver* s, ast_manager& m, smt::context& ctx): maxsmt_solver_wbase(s, m, ctx) {} + wmax(opt_solver* s, ast_manager& m, smt::context& ctx, params_ref& p, + vector const& ws, expr_ref_vector const& soft): + maxsmt_solver_wbase(s, m, ctx, p, ws, soft) {} virtual ~wmax() {} lbool operator()() { @@ -1515,129 +1349,36 @@ namespace opt { } }; - struct wmaxsmt::imp { - ast_manager& m; - ref s; // solver state that contains hard constraints - expr_ref_vector m_soft; // set of soft constraints - vector m_weights; // their weights - symbol m_engine; // config - mutable params_ref m_params; // config - mutable scoped_ptr m_maxsmt; // underlying maxsmt solver - imp(ast_manager& m, - opt_solver* s, - expr_ref_vector const& soft_constraints, - vector const& weights): - m(m), - s(s), - m_soft(soft_constraints), - m_weights(weights) - { - } + maxsmt_solver_base* opt::mk_bcd2(ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft) { + return alloc(bcd2, s, m, p, ws, soft); + } + maxsmt_solver_base* opt::mk_pbmax(ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft) { + return alloc(pbmax, s, m, p, ws, soft); + } + maxsmt_solver_base* opt::mk_hsmax(ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft) { + return alloc(hsmax, s, m, p, ws, soft); + } + maxsmt_solver_base* opt::mk_sls(ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft) { + return alloc(hsmax, s, m, p, ws, soft); + } + maxsmt_solver_base* opt::mk_wmax(ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft) { + return alloc(wmax, s, m, s->get_context(), p, ws, soft); + } + maxsmt_solver_base* opt::mk_wpm2(ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft) { - maxsmt_solver_base& maxsmt() const { - if (m_maxsmt) { - return *m_maxsmt; - } - if (m_engine == symbol("pbmax")) { - m_maxsmt = alloc(pbmax, s.get(), m); - } - else if (m_engine == symbol("wpm2")) { - ref s0 = alloc(opt_solver, m, m_params, symbol()); - // initialize model. - s0->check_sat(0,0); - maxsmt_solver_base* s2 = alloc(pbmax, s0.get(), m); - m_maxsmt = alloc(wpm2, s.get(), m, s2); - } - else if (m_engine == symbol("bcd2")) { - m_maxsmt = alloc(bcd2, s.get(), m); - } - else if (m_engine == symbol("hsmax")) { - m_maxsmt = alloc(hsmax, s.get(), m); - } - // NB: this is experimental one-round version of SLS - else if (m_engine == symbol("sls")) { - m_maxsmt = alloc(sls, s.get(), m); - } - else if (m_engine == symbol::null || m_engine == symbol("wmax")) { - m_maxsmt = alloc(wmax, s.get(), m, s->get_context()); - } - else { - IF_VERBOSE(0, verbose_stream() << "(unknown engine " << m_engine << " using default 'wmax')\n";); - m_maxsmt = alloc(wmax, s.get(), m, s->get_context()); - } - m_maxsmt->updt_params(m_params); - m_maxsmt->init_soft(m_weights, m_soft); - m_maxsmt->set_converter(s->mc_ref().get()); - return *m_maxsmt; - } + ref s0 = alloc(opt_solver, m, p, symbol()); + // initialize model. + s0->check_sat(0,0); + maxsmt_solver_base* s2 = alloc(pbmax, s0.get(), m, p, ws, soft); + return alloc(wpm2, s, m, s2, p, ws, soft); + } - ~imp() {} - /** - Takes solver with hard constraints added. - Returns a maximal satisfying subset of weighted soft_constraints - that are still consistent with the solver state. - */ - lbool operator()() { - return maxsmt()(); - } - rational get_lower() const { - return maxsmt().get_lower(); - } - rational get_upper() const { - return maxsmt().get_upper(); - } - void get_model(model_ref& mdl) { - if (m_maxsmt) m_maxsmt->get_model(mdl); - } - void set_cancel(bool f) { - if (m_maxsmt) m_maxsmt->set_cancel(f); - } - bool get_assignment(unsigned index) const { - return maxsmt().get_assignment(index); - } - void collect_statistics(statistics& st) const { - if (m_maxsmt) m_maxsmt->collect_statistics(st); - } - void updt_params(params_ref& p) { - opt_params _p(p); - m_engine = _p.wmaxsat_engine(); - m_maxsmt = 0; - } - }; - - wmaxsmt::wmaxsmt(ast_manager& m, - opt_solver* s, - expr_ref_vector& soft_constraints, - vector const& weights) { - m_imp = alloc(imp, m, s, soft_constraints, weights); - } - wmaxsmt::~wmaxsmt() { - dealloc(m_imp); - } - lbool wmaxsmt::operator()() { - return (*m_imp)(); - } - rational wmaxsmt::get_lower() const { - return m_imp->get_lower(); - } - rational wmaxsmt::get_upper() const { - return m_imp->get_upper(); - } - bool wmaxsmt::get_assignment(unsigned idx) const { - return m_imp->get_assignment(idx); - } - void wmaxsmt::set_cancel(bool f) { - m_imp->set_cancel(f); - } - void wmaxsmt::collect_statistics(statistics& st) const { - m_imp->collect_statistics(st); - } - void wmaxsmt::get_model(model_ref& mdl) { - m_imp->get_model(mdl); - } - void wmaxsmt::updt_params(params_ref& p) { - m_imp->updt_params(p); - } }; diff --git a/src/opt/weighted_maxsat.h b/src/opt/weighted_maxsat.h index d84f96f0a..5343a3b97 100644 --- a/src/opt/weighted_maxsat.h +++ b/src/opt/weighted_maxsat.h @@ -27,24 +27,25 @@ Notes: #include "maxsmt.h" namespace opt { - class wmaxsmt : public maxsmt_solver { - struct imp; - imp* m_imp; - public: - wmaxsmt(ast_manager& m, - opt_solver* s, - expr_ref_vector& soft_constraints, - vector const& weights); - ~wmaxsmt(); - virtual lbool operator()(); - virtual rational get_lower() const; - virtual rational get_upper() const; - virtual bool get_assignment(unsigned idx) const; - virtual void set_cancel(bool f); - virtual void collect_statistics(statistics& st) const; - virtual void get_model(model_ref& mdl); - virtual void updt_params(params_ref& p); - }; + + maxsmt_solver_base* mk_bcd2(ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft); + + maxsmt_solver_base* mk_hsmax(ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft); + + maxsmt_solver_base* mk_pbmax(ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft); + + maxsmt_solver_base* mk_wpm2(ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft); + + maxsmt_solver_base* mk_sls(ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft); + + maxsmt_solver_base* mk_wmax(ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft); + }; #endif From ff64adf2920ce6818546bf9592d10499d69c992b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 26 Jul 2014 12:45:21 -0700 Subject: [PATCH 431/925] rename hsmax Signed-off-by: Nikolaj Bjorner --- src/opt/maxsmt.cpp | 4 ++-- src/opt/weighted_maxsat.cpp | 38 ++++++++++++++++++------------------- src/opt/weighted_maxsat.h | 2 +- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 2b20ccbd0..1e3c3fcfa 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -182,8 +182,8 @@ namespace opt { else if (m_maxsat_engine == symbol("bcd2")) { m_msolver = mk_bcd2(m, s, m_params, m_weights, m_soft_constraints); } - else if (m_maxsat_engine == symbol("hsmax")) { - m_msolver = mk_hsmax(m, s, m_params, m_weights, m_soft_constraints); + else if (m_maxsat_engine == symbol("maxhs")) { + m_msolver = mk_maxhs(m, s, m_params, m_weights, m_soft_constraints); } else if (m_maxsat_engine == symbol("sls")) { // NB: this is experimental one-round version of SLS diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp index dbd5a060f..8b19c5c94 100644 --- a/src/opt/weighted_maxsat.cpp +++ b/src/opt/weighted_maxsat.cpp @@ -434,7 +434,7 @@ namespace opt { // to the underlying optimization solver for the soft constraints. // - class hsmax : public maxsmt_solver_base { + class maxhs : public maxsmt_solver_base { struct stats { stats() { reset(); } void reset() { memset(this, 0, sizeof(*this)); } @@ -463,14 +463,14 @@ namespace opt { public: - hsmax(opt_solver* s, ast_manager& m, params_ref& p, vector const& ws, expr_ref_vector const& soft): + maxhs(opt_solver* s, ast_manager& m, params_ref& p, vector const& ws, expr_ref_vector const& soft): maxsmt_solver_base(s, m, p, ws, soft), m_aux(m), pb(m), a(m), m_at_lower_bound(false) { } - virtual ~hsmax() {} + virtual ~maxhs() {} virtual void set_cancel(bool f) { maxsmt_solver_base::set_cancel(f); @@ -480,15 +480,15 @@ namespace opt { virtual void collect_statistics(statistics& st) const { maxsmt_solver_base::collect_statistics(st); m_hs.collect_statistics(st); - st.update("hsmax-num-iterations", m_stats.m_num_iterations); - st.update("hsmax-num-core-reductions-n", m_stats.m_num_core_reductions_failure); - st.update("hsmax-num-core-reductions-y", m_stats.m_num_core_reductions_success); - st.update("hsmax-num-model-expansions-n", m_stats.m_num_model_expansions_failure); - st.update("hsmax-num-model-expansions-y", m_stats.m_num_model_expansions_success); - st.update("hsmax-core-reduction-time", m_stats.m_core_reduction_time); - st.update("hsmax-model-expansion-time", m_stats.m_model_expansion_time); - st.update("hsmax-aux-sat-time", m_stats.m_aux_sat_time); - st.update("hsmax-disj-core-time", m_stats.m_disjoint_cores_time); + st.update("maxhs-num-iterations", m_stats.m_num_iterations); + st.update("maxhs-num-core-reductions-n", m_stats.m_num_core_reductions_failure); + st.update("maxhs-num-core-reductions-y", m_stats.m_num_core_reductions_success); + st.update("maxhs-num-model-expansions-n", m_stats.m_num_model_expansions_failure); + st.update("maxhs-num-model-expansions-y", m_stats.m_num_model_expansions_success); + st.update("maxhs-core-reduction-time", m_stats.m_core_reduction_time); + st.update("maxhs-model-expansion-time", m_stats.m_model_expansion_time); + st.update("maxhs-aux-sat-time", m_stats.m_aux_sat_time); + st.update("maxhs-disj-core-time", m_stats.m_disjoint_cores_time); } lbool operator()() { @@ -502,8 +502,8 @@ namespace opt { while (m_lower < m_upper) { ++m_stats.m_num_iterations; IF_VERBOSE(1, verbose_stream() << - "(hsmax [" << m_lower << ":" << m_upper << "])\n";); - TRACE("opt", tout << "(hsmax [" << m_lower << ":" << m_upper << "])\n";); + "(maxhs [" << m_lower << ":" << m_upper << "])\n";); + TRACE("opt", tout << "(maxhs [" << m_lower << ":" << m_upper << "])\n";); if (m_cancel) { return l_undef; } @@ -681,8 +681,8 @@ namespace opt { } struct lt_activity { - hsmax& hs; - lt_activity(hsmax& hs):hs(hs) {} + maxhs& hs; + lt_activity(maxhs& hs):hs(hs) {} bool operator()(expr* a, expr* b) const { unsigned w1 = hs.m_core_activity[hs.m_aux2index.find(a)]; unsigned w2 = hs.m_core_activity[hs.m_aux2index.find(b)]; @@ -1358,13 +1358,13 @@ namespace opt { vector const& ws, expr_ref_vector const& soft) { return alloc(pbmax, s, m, p, ws, soft); } - maxsmt_solver_base* opt::mk_hsmax(ast_manager& m, opt_solver* s, params_ref& p, + maxsmt_solver_base* opt::mk_maxhs(ast_manager& m, opt_solver* s, params_ref& p, vector const& ws, expr_ref_vector const& soft) { - return alloc(hsmax, s, m, p, ws, soft); + return alloc(maxhs, s, m, p, ws, soft); } maxsmt_solver_base* opt::mk_sls(ast_manager& m, opt_solver* s, params_ref& p, vector const& ws, expr_ref_vector const& soft) { - return alloc(hsmax, s, m, p, ws, soft); + return alloc(maxhs, s, m, p, ws, soft); } maxsmt_solver_base* opt::mk_wmax(ast_manager& m, opt_solver* s, params_ref& p, vector const& ws, expr_ref_vector const& soft) { diff --git a/src/opt/weighted_maxsat.h b/src/opt/weighted_maxsat.h index 5343a3b97..e1cad1b55 100644 --- a/src/opt/weighted_maxsat.h +++ b/src/opt/weighted_maxsat.h @@ -31,7 +31,7 @@ namespace opt { maxsmt_solver_base* mk_bcd2(ast_manager& m, opt_solver* s, params_ref& p, vector const& ws, expr_ref_vector const& soft); - maxsmt_solver_base* mk_hsmax(ast_manager& m, opt_solver* s, params_ref& p, + maxsmt_solver_base* mk_maxhs(ast_manager& m, opt_solver* s, params_ref& p, vector const& ws, expr_ref_vector const& soft); maxsmt_solver_base* mk_pbmax(ast_manager& m, opt_solver* s, params_ref& p, From 4ab27eff78276d38853964e5ca40c2614ecbb463 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 28 Jul 2014 08:31:57 -0700 Subject: [PATCH 432/925] refactor weighted-maxsat into separate files Signed-off-by: Nikolaj Bjorner --- src/opt/bcd2.cpp | 408 +++++++++++ src/opt/bcd2.h | 29 + src/opt/dual_maxres.cpp | 429 +++++++++++ src/opt/dual_maxres.h | 32 + src/opt/maxhs.cpp | 561 ++++++++++++++ src/opt/maxhs.h | 29 + src/opt/maxres.cpp | 2 +- src/opt/maxsls.cpp | 63 ++ src/opt/maxsls.h | 36 + src/opt/maxsmt.cpp | 17 +- src/opt/mus.cpp | 15 +- src/opt/pbmax.cpp | 98 +++ src/opt/pbmax.h | 30 + src/opt/weighted_maxsat.cpp | 1384 ----------------------------------- src/opt/weighted_maxsat.h | 51 -- src/opt/wmax.cpp | 130 ++++ src/opt/wmax.h | 30 + src/opt/wpm2.cpp | 251 +++++++ src/opt/wpm2.h | 29 + src/smt/theory_wmaxsat.cpp | 1 - 20 files changed, 2179 insertions(+), 1446 deletions(-) create mode 100644 src/opt/bcd2.cpp create mode 100644 src/opt/bcd2.h create mode 100644 src/opt/dual_maxres.cpp create mode 100644 src/opt/dual_maxres.h create mode 100644 src/opt/maxhs.cpp create mode 100644 src/opt/maxhs.h create mode 100644 src/opt/maxsls.cpp create mode 100644 src/opt/maxsls.h create mode 100644 src/opt/pbmax.cpp create mode 100644 src/opt/pbmax.h delete mode 100644 src/opt/weighted_maxsat.cpp delete mode 100644 src/opt/weighted_maxsat.h create mode 100644 src/opt/wmax.cpp create mode 100644 src/opt/wmax.h create mode 100644 src/opt/wpm2.cpp create mode 100644 src/opt/wpm2.h diff --git a/src/opt/bcd2.cpp b/src/opt/bcd2.cpp new file mode 100644 index 000000000..cb579b9ef --- /dev/null +++ b/src/opt/bcd2.cpp @@ -0,0 +1,408 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + bcd2.cpp + +Abstract: + + bcd2 based MaxSAT. + +Author: + + Nikolaj Bjorner (nbjorner) 2014-4-17 + +Notes: + +--*/ +#include "bcd2.h" +#include "pb_decl_plugin.h" +#include "uint_set.h" +#include "ast_pp.h" + + +namespace opt { + // ------------------------------------------------------ + // Morgado, Heras, Marques-Silva 2013 + // (initial version without model-based optimizations) + // + class bcd2 : public maxsmt_solver_base { + struct wcore { + expr* m_r; + unsigned_vector m_R; + rational m_lower; + rational m_mid; + rational m_upper; + }; + typedef obj_hashtable expr_set; + + pb_util pb; + expr_ref_vector m_soft_aux; + obj_map m_relax2index; // expr |-> index + obj_map m_soft2index; // expr |-> index + expr_ref_vector m_trail; + expr_ref_vector m_soft_constraints; + expr_set m_asm_set; + vector m_cores; + vector m_sigmas; + rational m_den; // least common multiplier of original denominators + bool m_enable_lazy; // enable adding soft constraints lazily (called 'mgbcd2') + unsigned_vector m_lazy_soft; // soft constraints to add lazily. + + void set2asms(expr_set const& set, expr_ref_vector & es) const { + es.reset(); + expr_set::iterator it = set.begin(), end = set.end(); + for (; it != end; ++it) { + es.push_back(m.mk_not(*it)); + } + } + void bcd2_init_soft(vector const& weights, expr_ref_vector const& soft) { + + // normalize weights to be integral: + m_den = rational::one(); + for (unsigned i = 0; i < m_weights.size(); ++i) { + m_den = lcm(m_den, denominator(m_weights[i])); + } + if (!m_den.is_one()) { + for (unsigned i = 0; i < m_weights.size(); ++i) { + m_weights[i] = m_den*m_weights[i]; + SASSERT(m_weights[i].is_int()); + } + } + } + void init_bcd() { + m_trail.reset(); + m_asm_set.reset(); + m_cores.reset(); + m_sigmas.reset(); + m_lazy_soft.reset(); + for (unsigned i = 0; i < m_soft.size(); ++i) { + m_sigmas.push_back(m_weights[i]); + m_soft_aux.push_back(mk_fresh()); + if (m_enable_lazy) { + m_lazy_soft.push_back(i); + } + else { + enable_soft_constraint(i); + } + } + m_upper += rational(1); + } + + void process_sat() { + svector assignment; + update_assignment(assignment); + if (check_lazy_soft(assignment)) { + update_sigmas(); + } + } + + public: + bcd2(opt_solver* s, ast_manager& m, params_ref& p, + vector const& ws, expr_ref_vector const& soft): + maxsmt_solver_base(s, m, p, ws, soft), + pb(m), + m_soft_aux(m), + m_trail(m), + m_soft_constraints(m), + m_enable_lazy(true) { + bcd2_init_soft(ws, soft); + } + + virtual ~bcd2() {} + + virtual lbool operator()() { + expr_ref fml(m), r(m); + lbool is_sat = l_undef; + expr_ref_vector asms(m); + enable_sls(); + solver::scoped_push _scope1(s()); + init(); + init_bcd(); + if (m_cancel) { + normalize_bounds(); + return l_undef; + } + process_sat(); + while (m_lower < m_upper) { + IF_VERBOSE(1, verbose_stream() << "(opt.bcd2 [" << m_lower << ":" << m_upper << "])\n";); + assert_soft(); + solver::scoped_push _scope2(s()); + TRACE("opt", display(tout);); + assert_cores(); + set2asms(m_asm_set, asms); + if (m_cancel) { + normalize_bounds(); + return l_undef; + } + is_sat = s().check_sat(asms.size(), asms.c_ptr()); + switch(is_sat) { + case l_undef: + normalize_bounds(); + return l_undef; + case l_true: + process_sat(); + break; + case l_false: { + ptr_vector unsat_core; + uint_set subC, soft; + s().get_unsat_core(unsat_core); + core2indices(unsat_core, subC, soft); + SASSERT(unsat_core.size() == subC.num_elems() + soft.num_elems()); + if (soft.num_elems() == 0 && subC.num_elems() == 1) { + unsigned s = *subC.begin(); + wcore& c_s = m_cores[s]; + c_s.m_lower = refine(c_s.m_R, c_s.m_mid); + c_s.m_mid = div(c_s.m_lower + c_s.m_upper, rational(2)); + } + else { + wcore c_s; + rational delta = min_of_delta(subC); + rational lower = sum_of_lower(subC); + union_Rs(subC, c_s.m_R); + r = mk_fresh(); + relax(subC, soft, c_s.m_R, delta); + c_s.m_lower = refine(c_s.m_R, lower + delta - rational(1)); + c_s.m_upper = rational::one(); + c_s.m_upper += sum_of_sigmas(c_s.m_R); + c_s.m_mid = div(c_s.m_lower + c_s.m_upper, rational(2)); + c_s.m_r = r; + m_asm_set.insert(r); + subtract(m_cores, subC); + m_relax2index.insert(r, m_cores.size()); + m_cores.push_back(c_s); + } + break; + } + } + m_lower = compute_lower(); + } + normalize_bounds(); + return l_true; + } + + + private: + + void enable_soft_constraint(unsigned i) { + expr_ref fml(m); + expr* r = m_soft_aux[i].get(); + m_soft2index.insert(r, i); + fml = m.mk_or(r, m_soft[i].get()); + m_soft_constraints.push_back(fml); + m_asm_set.insert(r); + SASSERT(m_weights[i].is_int()); + } + + void assert_soft() { + for (unsigned i = 0; i < m_soft_constraints.size(); ++i) { + s().assert_expr(m_soft_constraints[i].get()); + } + m_soft_constraints.reset(); + } + + bool check_lazy_soft(svector const& assignment) { + bool all_satisfied = true; + for (unsigned i = 0; i < m_lazy_soft.size(); ++i) { + unsigned j = m_lazy_soft[i]; + if (!assignment[j]) { + enable_soft_constraint(j); + m_lazy_soft[i] = m_lazy_soft.back(); + m_lazy_soft.pop_back(); + --i; + all_satisfied = false; + } + } + return all_satisfied; + } + + void normalize_bounds() { + m_lower /= m_den; + m_upper /= m_den; + } + + expr* mk_fresh() { + expr* r = mk_fresh_bool("r"); + m_trail.push_back(r); + return r; + } + + void update_assignment(svector& new_assignment) { + expr_ref val(m); + rational new_upper(0); + model_ref model; + new_assignment.reset(); + s().get_model(model); + for (unsigned i = 0; i < m_soft.size(); ++i) { + VERIFY(model->eval(m_soft[i].get(), val)); + new_assignment.push_back(m.is_true(val)); + if (!new_assignment[i]) { + new_upper += m_weights[i]; + } + } + if (new_upper < m_upper) { + m_upper = new_upper; + m_model = model; + m_assignment.reset(); + m_assignment.append(new_assignment); + } + } + + void update_sigmas() { + for (unsigned i = 0; i < m_cores.size(); ++i) { + wcore& c_i = m_cores[i]; + unsigned_vector const& R = c_i.m_R; + c_i.m_upper.reset(); + for (unsigned j = 0; j < R.size(); ++j) { + unsigned r_j = R[j]; + if (!m_assignment[r_j]) { + c_i.m_upper += m_weights[r_j]; + m_sigmas[r_j] = m_weights[r_j]; + } + else { + m_sigmas[r_j].reset(); + } + } + c_i.m_mid = div(c_i.m_lower + c_i.m_upper, rational(2)); + } + } + + /** + * Minimum of two (positive) numbers. Zero is treated as +infinity. + */ + rational min_z(rational const& a, rational const& b) { + if (a.is_zero()) return b; + if (b.is_zero()) return a; + if (a < b) return a; + return b; + } + + rational min_of_delta(uint_set const& subC) { + rational delta(0); + for (uint_set::iterator it = subC.begin(); it != subC.end(); ++it) { + unsigned j = *it; + wcore const& core = m_cores[j]; + rational new_delta = rational(1) + core.m_upper - core.m_mid; + SASSERT(new_delta.is_pos()); + delta = min_z(delta, new_delta); + } + return delta; + } + + rational sum_of_lower(uint_set const& subC) { + rational lower(0); + for (uint_set::iterator it = subC.begin(); it != subC.end(); ++it) { + lower += m_cores[*it].m_lower; + } + return lower; + } + + rational sum_of_sigmas(unsigned_vector const& R) { + rational sum(0); + for (unsigned i = 0; i < R.size(); ++i) { + sum += m_sigmas[R[i]]; + } + return sum; + } + void union_Rs(uint_set const& subC, unsigned_vector& R) { + for (uint_set::iterator it = subC.begin(); it != subC.end(); ++it) { + R.append(m_cores[*it].m_R); + } + } + rational compute_lower() { + rational result(0); + for (unsigned i = 0; i < m_cores.size(); ++i) { + result += m_cores[i].m_lower; + } + return result; + } + void subtract(vector& cores, uint_set const& subC) { + unsigned j = 0; + for (unsigned i = 0; i < cores.size(); ++i) { + if (subC.contains(i)) { + m_asm_set.remove(cores[i].m_r); + } + else { + if (j != i) { + cores[j] = cores[i]; + } + ++j; + } + } + cores.resize(j); + for (unsigned i = 0; i < cores.size(); ++i) { + m_relax2index.insert(cores[i].m_r, i); + } + } + void core2indices(ptr_vector const& core, uint_set& subC, uint_set& soft) { + for (unsigned i = 0; i < core.size(); ++i) { + unsigned j; + expr* a; + VERIFY(m.is_not(core[i], a)); + if (m_relax2index.find(a, j)) { + subC.insert(j); + } + else { + VERIFY(m_soft2index.find(a, j)); + soft.insert(j); + } + } + } + rational refine(unsigned_vector const& idx, rational v) { + return v + rational(1); + } + void relax(uint_set& subC, uint_set& soft, unsigned_vector& R, rational& delta) { + for (uint_set::iterator it = soft.begin(); it != soft.end(); ++it) { + R.push_back(*it); + delta = min_z(delta, m_weights[*it]); + m_asm_set.remove(m_soft_aux[*it].get()); + } + } + void assert_cores() { + for (unsigned i = 0; i < m_cores.size(); ++i) { + assert_core(m_cores[i]); + } + } + void assert_core(wcore const& core) { + expr_ref fml(m); + vector ws; + ptr_vector rs; + rational w(0); + for (unsigned j = 0; j < core.m_R.size(); ++j) { + unsigned idx = core.m_R[j]; + ws.push_back(m_weights[idx]); + w += ws.back(); + rs.push_back(m_soft_aux[idx].get()); + } + w.neg(); + w += core.m_mid; + ws.push_back(w); + rs.push_back(core.m_r); + fml = pb.mk_le(ws.size(), ws.c_ptr(), rs.c_ptr(), core.m_mid); + s().assert_expr(fml); + } + void display(std::ostream& out) { + out << "[" << m_lower << ":" << m_upper << "]\n"; + s().display(out); + out << "\n"; + for (unsigned i = 0; i < m_cores.size(); ++i) { + wcore const& c = m_cores[i]; + out << mk_pp(c.m_r, m) << ": "; + for (unsigned j = 0; j < c.m_R.size(); ++j) { + out << c.m_R[j] << " (" << m_sigmas[c.m_R[j]] << ") "; + } + out << "[" << c.m_lower << ":" << c.m_mid << ":" << c.m_upper << "]\n"; + } + for (unsigned i = 0; i < m_soft.size(); ++i) { + out << mk_pp(m_soft[i].get(), m) << " " << m_weights[i] << "\n"; + } + } + }; + + maxsmt_solver_base* opt::mk_bcd2(ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft) { + return alloc(bcd2, s, m, p, ws, soft); + } + +} diff --git a/src/opt/bcd2.h b/src/opt/bcd2.h new file mode 100644 index 000000000..db08b15ef --- /dev/null +++ b/src/opt/bcd2.h @@ -0,0 +1,29 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + bcd2.h + +Abstract: + + Bcd2 based MaxSAT. + +Author: + + Nikolaj Bjorner (nbjorner) 2014-4-17 + +Notes: + +--*/ + +#ifndef _BCD2_H_ +#define _BCD2_H_ + +#include "maxsmt.h" + +namespace opt { + maxsmt_solver_base* mk_bcd2(ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft); +} +#endif diff --git a/src/opt/dual_maxres.cpp b/src/opt/dual_maxres.cpp new file mode 100644 index 000000000..55d347e9e --- /dev/null +++ b/src/opt/dual_maxres.cpp @@ -0,0 +1,429 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + dual_maxsres.cpp + +Abstract: + + MaxRes (weighted) max-sat algorithm + based on dual refinement of bounds. + + MaxRes is a core-guided approach to maxsat. + DualMaxRes extends the core-guided approach by + leveraging both cores and satisfying assignments + to make progress towards a maximal satisfying assignment. + + Given a (minimal) unsatisfiable core for the soft + constraints the approach works like max-res. + Given a (maximal) satisfying subset of the soft constraints + the approach updates the upper bound if the current assignment + improves the current best assignmet. + Furthermore, take the soft constraints that are complements + to the current satisfying subset. + E.g, if F are the hard constraints and + s1,...,sn, t1,..., tm are the soft clauses and + F & s1 & ... & sn is satisfiable, then the complement + of of the current satisfying subset is t1, .., tm. + Update the hard constraint: + F := F & (t1 or ... or tm) + Replace t1, .., tm by m-1 new soft clauses: + t1 & t2, t3 & (t1 or t2), t4 & (t1 or t2 or t3), ..., tn & (t1 or ... t_{n-1}) + Claim: + If k of these soft clauses are satisfied, then k+1 of + the previous soft clauses are satisfied. + If k of these soft clauses are false in the satisfying assignment + for the updated F, then k of the original soft clauses are also false + under the assignment. + In summary: any assignment to the new clauses that satsfies F has the + same cost. + Claim: + If there are no satisfying assignments to F, then the current best assignment + is the optimum. + + +Author: + + Nikolaj Bjorner (nbjorner) 2014-27-7 + +Notes: + +--*/ + +#include "solver.h" +#include "maxsmt.h" +#include "dual_maxres.h" +#include "ast_pp.h" +#include "mus.h" + +using namespace opt; + + +class dual_maxres : public maxsmt_solver_base { + expr_ref_vector m_B; + expr_ref_vector m_asms; + obj_map m_asm2weight; + ptr_vector m_new_core; + mus m_mus; + expr_ref_vector m_trail; + +public: + dual_maxres(ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft): + maxsmt_solver_base(s, m, p, ws, soft), + m_B(m), m_asms(m), + m_mus(m_s, m), + m_trail(m) + { + } + + virtual ~dual_maxres() {} + + bool is_literal(expr* l) { + return + is_uninterp_const(l) || + (m.is_not(l, l) && is_uninterp_const(l)); + } + + void add_soft(expr* e, rational const& w) { + TRACE("opt", tout << mk_pp(e, m) << "\n";); + expr_ref asum(m), fml(m); + if (is_literal(e)) { + asum = e; + } + else { + asum = mk_fresh_bool("soft"); + fml = m.mk_iff(asum, e); + m_s->assert_expr(fml); + } + new_assumption(asum, w); + m_upper += w; + } + + void new_assumption(expr* e, rational const& w) { + m_asm2weight.insert(e, w); + m_asms.push_back(e); + m_trail.push_back(e); + } + + lbool operator()() { + solver::scoped_push _sc(*m_s.get()); + init(); + init_local(); + lbool was_sat = l_false; + ptr_vector soft_compl; + while (m_lower < m_upper) { + TRACE("opt", + display_vec(tout, m_asms.size(), m_asms.c_ptr()); + m_s->display(tout); + tout << "\n"; + display(tout); + ); + lbool is_sat = m_s->check_sat(0, 0); + if (m_cancel) { + return l_undef; + } + if (is_sat == l_true) { + was_sat = l_true; + is_sat = extend_model(soft_compl); + switch (is_sat) { + case l_undef: + break; + case l_false: + is_sat = process_unsat(soft_compl); + break; + case l_true: + is_sat = process_sat(soft_compl); + break; + } + } + switch (is_sat) { + case l_undef: + return l_undef; + case l_false: + m_lower = m_upper; + return was_sat; + case l_true: + break; + } + } + return was_sat; + } + + lbool process_sat(ptr_vector& softc) { + expr_ref fml(m), tmp(m); + TRACE("opt", display_vec(tout << "softc: ", softc.size(), softc.c_ptr());); + SASSERT(!softc.empty()); // we should somehow stop if all soft are satisfied. + if (softc.empty()) { + return l_false; + } + + remove_soft(softc); + rational w = split_soft(softc); + TRACE("opt", display_vec(tout << " softc: ", softc.size(), softc.c_ptr());); + dual_max_resolve(softc, w); + return l_true; + } + + lbool process_unsat(ptr_vector& core) { + expr_ref fml(m); + TRACE("opt", display_vec(tout << "core: ", core.size(), core.c_ptr());); + SASSERT(!core.empty()); + lbool is_sat = minimize_core(core); + SASSERT(!core.empty()); + if (core.empty()) { + return l_false; + } + if (is_sat != l_true) { + return is_sat; + } + remove_soft(core); + rational w = split_soft(core); + TRACE("opt", display_vec(tout << "minimized core: ", core.size(), core.c_ptr());); + max_resolve(core, w); + m_lower += w; + IF_VERBOSE(1, verbose_stream() << + "(opt.dual_max_res [" << m_lower << ":" << m_upper << "])\n";); + + return is_sat; + } + + // + // The hard constraints are satisfiable. + // Extend the current model to satisfy as many + // soft constraints as possible until either + // hitting an unsatisfiable subset of size < 1/2*#assumptions, + // or producing a maximal satisfying assignment exceeding + // number of soft constraints >= 1/2*#assumptions. + // In both cases, soft constraints that are not satisfied + // is <= 1/2*#assumptions. In this way, the new modified assumptions + // account for at most 1/2 of the current assumptions. + // The core reduction algorithms also need to take into account + // at most 1/2 of the assumptions for minimization. + // + + lbool extend_model(ptr_vector& soft_compl) { + ptr_vector asms; + model_ref mdl; + expr_ref tmp(m); + m_s->get_model(mdl); + unsigned num_true = update_model(mdl, asms, soft_compl); + for (unsigned j = 0; j < m_asms.size(); ++j) { + expr* fml = m_asms[j].get(); + VERIFY(mdl->eval(fml, tmp)); + if (m.is_false(tmp)) { + asms.push_back(fml); + lbool is_sat = m_s->check_sat(asms.size(), asms.c_ptr()); + asms.pop_back(); + switch (is_sat) { + case l_false: + if (num_true*2 < m_asms.size()) { + soft_compl.reset(); + m_s->get_unsat_core(soft_compl); + return l_false; + } + break; + case l_true: + m_s->get_model(mdl); + num_true = update_model(mdl, asms, soft_compl); + break; + case l_undef: + return l_undef; + } + } + } + return l_true; + } + + unsigned update_model(model_ref& mdl, ptr_vector& asms, ptr_vector& soft_compl) { + expr_ref tmp(m); + asms.reset(); + soft_compl.reset(); + rational weight = m_lower; + unsigned num_true = 0; + for (unsigned i = 0; i < m_asms.size(); ++i) { + expr* fml = m_asms[i].get(); + VERIFY(mdl->eval(fml, tmp)); + SASSERT(m.is_false(tmp) || m.is_true(tmp)); + if (m.is_false(tmp)) { + weight += get_weight(fml); + soft_compl.push_back(fml); + } + else { + ++num_true; + asms.push_back(fml); + } + } + if (weight < m_upper) { + m_upper = weight; + m_model = mdl; + for (unsigned i = 0; i < m_soft.size(); ++i) { + expr_ref tmp(m); + VERIFY(m_model->eval(m_soft[i].get(), tmp)); + m_assignment[i] = m.is_true(tmp); + } + IF_VERBOSE(1, verbose_stream() << + "(opt.dual_max_res [" << m_lower << ":" << m_upper << "])\n";); + } + return num_true; + } + + lbool minimize_core(ptr_vector& core) { + m_mus.reset(); + for (unsigned i = 0; i < core.size(); ++i) { + m_mus.add_soft(core[i], 1, core.c_ptr() + i); + } + unsigned_vector mus_idx; + lbool is_sat = m_mus.get_mus(mus_idx); + if (is_sat != l_true) { + return is_sat; + } + m_new_core.reset(); + for (unsigned i = 0; i < mus_idx.size(); ++i) { + m_new_core.push_back(core[mus_idx[i]]); + } + core.reset(); + core.append(m_new_core); + return l_true; + } + + rational get_weight(expr* e) { + return m_asm2weight.find(e); + } + + + // + // find the minimal weight. + // soft clauses with weight larger than the minimal weight + // are (re)added as soft clauses where the weight is updated + // to subtract the minimal weight. + // + rational split_soft(ptr_vector const& soft) { + + SASSERT(!soft.empty()); + rational w = get_weight(soft[0]); + for (unsigned i = 1; i < soft.size(); ++i) { + rational w2 = get_weight(soft[i]); + if (w2 < w) { + w = w2; + } + } + // add fresh soft clauses for weights that are above w. + for (unsigned i = 0; i < soft.size(); ++i) { + rational w2 = get_weight(soft[i]); + if (w2 > w) { + new_assumption(soft[i], w2 - w); + } + } + return w; + } + + void display_vec(std::ostream& out, unsigned sz, expr* const* args) { + for (unsigned i = 0; i < sz; ++i) { + out << mk_pp(args[i], m) << " "; + } + out << "\n"; + } + + void display(std::ostream& out) { + for (unsigned i = 0; i < m_asms.size(); ++i) { + expr* a = m_asms[i].get(); + out << mk_pp(a, m) << " : " << get_weight(a) << "\n"; + } + } + + void max_resolve(ptr_vector& core, rational const& w) { + SASSERT(!core.empty()); + expr_ref fml(m), asum(m); + app_ref cls(m), d(m); + m_B.reset(); + m_B.append(core.size(), core.c_ptr()); + d = m.mk_true(); + // + // d_0 := true + // d_i := b_{i-1} and d_{i-1} for i = 1...sz-1 + // soft (b_i or !d_i) + // == (b_i or !(!b_{i-1} or d_{i-1})) + // == (b_i or b_0 & b_1 & ... & b_{i-1}) + // + // Soft constraint is satisfied if previous soft constraint + // holds or if it is the first soft constraint to fail. + // + // Soundness of this rule can be established using MaxRes + // + for (unsigned i = 1; i < core.size(); ++i) { + expr* b_i = m_B[i-1].get(); + expr* b_i1 = m_B[i].get(); + d = m.mk_and(b_i, d); + asum = mk_fresh_bool("a"); + cls = m.mk_or(b_i1, d); + fml = m.mk_iff(asum, cls); + new_assumption(asum, w); + m_s->assert_expr(fml); + } + fml = m.mk_not(m.mk_and(m_B.size(), m_B.c_ptr())); + m_s->assert_expr(fml); + } + + // satc are the complements of a (maximal) satisfying assignment. + void dual_max_resolve(ptr_vector& satc, rational const& w) { + SASSERT(!satc.empty()); + expr_ref fml(m), asum(m); + app_ref cls(m), d(m); + m_B.reset(); + m_B.append(satc.size(), satc.c_ptr()); + d = m.mk_false(); + // + // d_0 := false + // d_i := b_{i-1} or d_{i-1} for i = 1...sz-1 + // soft (b_i and d_i) + // == (b_i and (b_0 or b_1 or ... or b_{i-1})) + // + for (unsigned i = 1; i < satc.size(); ++i) { + expr* b_i = m_B[i-1].get(); + expr* b_i1 = m_B[i].get(); + d = m.mk_or(b_i, d); + asum = mk_fresh_bool("a"); + cls = m.mk_and(b_i1, d); + fml = m.mk_iff(asum, cls); + new_assumption(asum, w); + m_s->assert_expr(fml); + } + fml = m.mk_or(m_B.size(), m_B.c_ptr()); + m_s->assert_expr(fml); + } + + void remove_soft(ptr_vector const& soft) { + for (unsigned i = 0; i < m_asms.size(); ++i) { + if (soft.contains(m_asms[i].get())) { + m_asms[i] = m_asms.back(); + m_asms.pop_back(); + --i; + } + } + } + + virtual void set_cancel(bool f) { + maxsmt_solver_base::set_cancel(f); + m_mus.set_cancel(f); + } + + void init_local() { + m_upper.reset(); + m_lower.reset(); + m_asm2weight.reset(); + m_trail.reset(); + for (unsigned i = 0; i < m_soft.size(); ++i) { + add_soft(m_soft[i].get(), m_weights[i]); + } + } + +}; + +opt::maxsmt_solver_base* opt::mk_dual_maxres( + ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft) { + return alloc(dual_maxres, m, s, p, ws, soft); +} + diff --git a/src/opt/dual_maxres.h b/src/opt/dual_maxres.h new file mode 100644 index 000000000..2bf1c7b18 --- /dev/null +++ b/src/opt/dual_maxres.h @@ -0,0 +1,32 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + dual_maxsres.h + +Abstract: + + MaxRes (weighted) max-sat algorithm + based on dual refinement of bounds. + +Author: + + Nikolaj Bjorner (nbjorner) 2014-27-7 + +Notes: + +--*/ + +#ifndef _DUAL_MAXRES_H_ +#define _DUAL_MAXRES_H_ + +namespace opt { + maxsmt_solver_base* mk_dual_maxres( + ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft); + + +}; + +#endif diff --git a/src/opt/maxhs.cpp b/src/opt/maxhs.cpp new file mode 100644 index 000000000..35ca630d9 --- /dev/null +++ b/src/opt/maxhs.cpp @@ -0,0 +1,561 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + maxhs.cpp + +Abstract: + + maxhs based MaxSAT. + +Author: + + Nikolaj Bjorner (nbjorner) 2014-4-17 + +Notes: + +--*/ +#include "optsmt.h" +#include "hitting_sets.h" +#include "stopwatch.h" +#include "ast_pp.h" +#include "model_smt2_pp.h" +#include "uint_set.h" +#include "maxhs.h" + +namespace opt { + + class scoped_stopwatch { + double& m_time; + stopwatch m_watch; + public: + scoped_stopwatch(double& time): m_time(time) { + m_watch.start(); + } + ~scoped_stopwatch() { + m_watch.stop(); + m_time += m_watch.get_seconds(); + } + }; + + + // ---------------------------------- + // MaxSatHS+MSS + // variant of MaxSAT-HS (Algorithm 9) + // that also refines upper bound during progressive calls + // to the underlying optimization solver for the soft constraints. + // + + class maxhs : public maxsmt_solver_base { + struct stats { + stats() { reset(); } + void reset() { memset(this, 0, sizeof(*this)); } + unsigned m_num_iterations; + unsigned m_num_core_reductions_success; + unsigned m_num_core_reductions_failure; + unsigned m_num_model_expansions_success; + unsigned m_num_model_expansions_failure; + double m_core_reduction_time; + double m_model_expansion_time; + double m_aux_sat_time; + double m_disjoint_cores_time; + }; + + hitting_sets m_hs; + expr_ref_vector m_aux; // auxiliary (indicator) variables. + obj_map m_aux2index; // expr |-> index + unsigned_vector m_core_activity; // number of times soft constraint is used in a core. + svector m_seed; // clause selected in current model. + svector m_aux_active; // active soft clauses. + ptr_vector m_asms; // assumptions (over aux) + stats m_stats; + bool m_at_lower_bound; + + + public: + maxhs(opt_solver* s, ast_manager& m, params_ref& p, vector const& ws, expr_ref_vector const& soft): + maxsmt_solver_base(s, m, p, ws, soft), + m_aux(m), + m_at_lower_bound(false) { + } + virtual ~maxhs() {} + + virtual void set_cancel(bool f) { + maxsmt_solver_base::set_cancel(f); + m_hs.set_cancel(f); + } + + virtual void collect_statistics(statistics& st) const { + maxsmt_solver_base::collect_statistics(st); + m_hs.collect_statistics(st); + st.update("maxhs-num-iterations", m_stats.m_num_iterations); + st.update("maxhs-num-core-reductions-n", m_stats.m_num_core_reductions_failure); + st.update("maxhs-num-core-reductions-y", m_stats.m_num_core_reductions_success); + st.update("maxhs-num-model-expansions-n", m_stats.m_num_model_expansions_failure); + st.update("maxhs-num-model-expansions-y", m_stats.m_num_model_expansions_success); + st.update("maxhs-core-reduction-time", m_stats.m_core_reduction_time); + st.update("maxhs-model-expansion-time", m_stats.m_model_expansion_time); + st.update("maxhs-aux-sat-time", m_stats.m_aux_sat_time); + st.update("maxhs-disj-core-time", m_stats.m_disjoint_cores_time); + } + + lbool operator()() { + ptr_vector hs; + init(); + init_local(); + if (!disjoint_cores(hs)) { + return l_undef; + } + seed2assumptions(); + while (m_lower < m_upper) { + ++m_stats.m_num_iterations; + IF_VERBOSE(1, verbose_stream() << + "(opt.maxhs [" << m_lower << ":" << m_upper << "])\n";); + TRACE("opt", tout << "(maxhs [" << m_lower << ":" << m_upper << "])\n";); + if (m_cancel) { + return l_undef; + } + + lbool core_found = generate_cores(hs); + switch(core_found) { + case l_undef: + return l_undef; + case l_true: { + lbool is_sat = next_seed(); + switch(is_sat) { + case l_true: + seed2hs(false, hs); + break; + case l_false: + TRACE("opt", tout << "no more seeds\n";); + IF_VERBOSE(1, verbose_stream() << "(opt.maxhs.no-more-seeds)\n";); + m_lower = m_upper; + return l_true; + case l_undef: + return l_undef; + } + break; + } + case l_false: + IF_VERBOSE(1, verbose_stream() << "(opt.maxhs.no-more-cores)\n";); + TRACE("opt", tout << "no more cores\n";); + m_lower = m_upper; + return l_true; + } + } + return l_true; + } + + private: + + unsigned num_soft() const { return m_soft.size(); } + + void init_local() { + unsigned sz = num_soft(); + app_ref fml(m), obj(m); + expr_ref_vector sum(m); + m_asms.reset(); + m_seed.reset(); + m_aux.reset(); + m_aux_active.reset(); + m_aux2index.reset(); + m_core_activity.reset(); + for (unsigned i = 0; i < sz; ++i) { + bool tt = is_true(m_model, m_soft[i].get()); + m_seed.push_back(tt); + m_aux. push_back(mk_fresh(m.mk_bool_sort())); + m_aux_active.push_back(false); + m_core_activity.push_back(0); + m_aux2index.insert(m_aux.back(), i); + if (tt) { + m_asms.push_back(m_aux.back()); + ensure_active(i); + } + } + + for (unsigned i = 0; i < m_weights.size(); ++i) { + m_hs.add_weight(m_weights[i]); + } + TRACE("opt", print_seed(tout);); + } + + + void hs2seed(ptr_vector const& hs) { + for (unsigned i = 0; i < num_soft(); ++i) { + m_seed[i] = true; + } + for (unsigned i = 0; i < hs.size(); ++i) { + m_seed[m_aux2index.find(hs[i])] = false; + } + TRACE("opt", + print_asms(tout << "hitting set: ", hs); + print_seed(tout);); + } + + void seed2hs(bool pos, ptr_vector& hs) { + hs.reset(); + for (unsigned i = 0; i < num_soft(); ++i) { + if (pos == m_seed[i]) { + hs.push_back(m_aux[i].get()); + } + } + TRACE("opt", + print_asms(tout << "hitting set: ", hs); + print_seed(tout);); + + } + + void seed2assumptions() { + seed2hs(true, m_asms); + } + + + // + // Find disjoint cores for soft constraints. + // + bool disjoint_cores(ptr_vector& hs) { + scoped_stopwatch _sw(m_stats.m_disjoint_cores_time); + m_asms.reset(); + svector active(num_soft(), true); + rational lower(0); + update_assumptions(active, lower, hs); + SASSERT(lower.is_zero()); + while (true) { + lbool is_sat = s().check_sat(m_asms.size(), m_asms.c_ptr()); + switch (is_sat) { + case l_true: + if (lower > m_lower) { + m_lower = lower; + } + return true; + case l_false: + if (!shrink()) return false; + block_up(); + update_assumptions(active, lower, hs); + break; + case l_undef: + return false; + } + } + } + + void update_assumptions(svector& active, rational& lower, ptr_vector& hs) { + rational arg_min(0); + expr* e = 0; + for (unsigned i = 0; i < m_asms.size(); ++i) { + unsigned index = m_aux2index.find(m_asms[i]); + active[index] = false; + if (arg_min.is_zero() || arg_min > m_weights[index]) { + arg_min = m_weights[index]; + e = m_asms[i]; + } + } + if (e) { + hs.push_back(e); + lower += arg_min; + } + m_asms.reset(); + for (unsigned i = 0; i < num_soft(); ++i) { + if (active[i]) { + m_asms.push_back(m_aux[i].get()); + ensure_active(i); + } + } + } + + // + // Auxiliary Algorithm 10 for producing cores. + // + lbool generate_cores(ptr_vector& hs) { + bool core = !m_at_lower_bound; + while (true) { + hs2seed(hs); + lbool is_sat = check_subset(); + switch(is_sat) { + case l_undef: + return l_undef; + case l_true: + if (!grow()) return l_undef; + block_down(); + return core?l_true:l_false; + case l_false: + core = true; + if (!shrink()) return l_undef; + block_up(); + find_non_optimal_hitting_set(hs); + break; + } + } + } + + struct lt_activity { + maxhs& hs; + lt_activity(maxhs& hs):hs(hs) {} + bool operator()(expr* a, expr* b) const { + unsigned w1 = hs.m_core_activity[hs.m_aux2index.find(a)]; + unsigned w2 = hs.m_core_activity[hs.m_aux2index.find(b)]; + return w1 < w2; + } + }; + + // + // produce the non-optimal hitting set by using the 10% heuristic. + // of most active cores constraints. + // m_asms contains the current core. + // + void find_non_optimal_hitting_set(ptr_vector& hs) { + std::sort(m_asms.begin(), m_asms.end(), lt_activity(*this)); + for (unsigned i = m_asms.size(); i > 9*m_asms.size()/10;) { + --i; + hs.push_back(m_asms[i]); + } + } + + // + // retrieve the next seed that satisfies state of hs. + // state of hs must be satisfiable before optimization is called. + // + lbool next_seed() { + scoped_stopwatch _sw(m_stats.m_aux_sat_time); + TRACE("opt", tout << "\n";); + + // min c_i*(not x_i) for x_i are soft clauses. + // max c_i*x_i for x_i are soft clauses + + m_at_lower_bound = false; + + lbool is_sat = m_hs.compute_upper(); + + if (is_sat == l_true) { + is_sat = m_hs.compute_lower(); + } + if (is_sat == l_true) { + m_at_lower_bound = m_hs.get_upper() == m_hs.get_lower(); + if (m_hs.get_lower() > m_lower) { + m_lower = m_hs.get_lower(); + } + for (unsigned i = 0; i < num_soft(); ++i) { + m_seed[i] = is_active(i) && !m_hs.get_value(i); + } + TRACE("opt", print_seed(tout);); + } + return is_sat; + } + + // + // check assignment returned by HS with the original + // hard constraints. + // + lbool check_subset() { + TRACE("opt", tout << "\n";); + m_asms.reset(); + for (unsigned i = 0; i < num_soft(); ++i) { + if (m_seed[i]) { + m_asms.push_back(m_aux[i].get()); + ensure_active(i); + } + } + return s().check_sat(m_asms.size(), m_asms.c_ptr()); + } + + // + // extend the current assignment to one that + // satisfies as many soft constraints as possible. + // update the upper bound based on this assignment + // + bool grow() { + scoped_stopwatch _sw(m_stats.m_model_expansion_time); + model_ref mdl; + s().get_model(mdl); + for (unsigned i = 0; i < num_soft(); ++i) { + ensure_active(i); + m_seed[i] = false; + } + for (unsigned i = 0; i < m_asms.size(); ++i) { + m_seed[m_aux2index.find(m_asms[i])] = true; + } + + for (unsigned i = 0; i < num_soft(); ++i) { + if (m_seed[i]) { + // already an assumption + } + else if (is_true(mdl, m_soft[i].get())) { + m_seed[i] = true; + m_asms.push_back(m_aux[i].get()); + } + else { + m_asms.push_back(m_aux[i].get()); + lbool is_sat = s().check_sat(m_asms.size(), m_asms.c_ptr()); + switch(is_sat) { + case l_undef: + return false; + case l_false: + ++m_stats.m_num_model_expansions_failure; + m_asms.pop_back(); + break; + case l_true: + ++m_stats.m_num_model_expansions_success; + s().get_model(mdl); + m_seed[i] = true; + break; + } + } + } + rational upper(0); + for (unsigned i = 0; i < num_soft(); ++i) { + if (!m_seed[i]) { + upper += m_weights[i]; + } + } + if (upper < m_upper) { + m_upper = upper; + m_hs.set_upper(upper); + m_model = mdl; + m_assignment.reset(); + m_assignment.append(m_seed); + TRACE("opt", + tout << "new upper: " << m_upper << "\n"; + model_smt2_pp(tout, m, *(mdl.get()), 0);); + } + DEBUG_CODE( + for (unsigned i = 0; i < num_soft(); ++i) { + SASSERT(is_true(mdl, m_soft[i].get()) == m_seed[i]); + }); + + return true; + } + + // + // remove soft constraints from the current core. + // + bool shrink() { + scoped_stopwatch _sw(m_stats.m_core_reduction_time); + m_asms.reset(); + s().get_unsat_core(m_asms); + TRACE("opt", print_asms(tout, m_asms);); + obj_map asm2index; + for (unsigned i = 0; i < m_asms.size(); ++i) { + asm2index.insert(m_asms[i], i); + } + obj_map::iterator it = asm2index.begin(), end = asm2index.end(); + for (; it != end; ++it) { + unsigned i = it->m_value; + if (i < m_asms.size()) { + expr* tmp = m_asms[i]; + expr* back = m_asms.back(); + m_asms[i] = back; + m_asms.pop_back(); + lbool is_sat = s().check_sat(m_asms.size(), m_asms.c_ptr()); + TRACE("opt", tout << "checking: " << mk_pp(tmp, m) << ": " << is_sat << "\n";); + switch(is_sat) { + case l_true: + ++m_stats.m_num_core_reductions_failure; + // put back literal into core + m_asms.push_back(back); + m_asms[i] = tmp; + break; + case l_false: + // update the core + m_asms.reset(); + ++m_stats.m_num_core_reductions_success; + s().get_unsat_core(m_asms); + TRACE("opt", print_asms(tout, m_asms);); + update_index(asm2index); + break; + case l_undef: + return false; + } + } + } + return true; + } + + void print_asms(std::ostream& out, ptr_vector const& asms) { + for (unsigned j = 0; j < asms.size(); ++j) { + out << mk_pp(asms[j], m) << " "; + } + out << "\n"; + } + + void print_seed(std::ostream& out) { + out << "seed: "; + for (unsigned i = 0; i < num_soft(); ++i) { + out << (m_seed[i]?"1":"0"); + } + out << "\n"; + } + + // + // must include some literal not from asms. + // (furthermore, update upper bound constraint in HS) + // + void block_down() { + uint_set indices; + unsigned_vector c_indices; + for (unsigned i = 0; i < m_asms.size(); ++i) { + indices.insert(m_aux2index.find(m_asms[i])); + } + for (unsigned i = 0; i < num_soft(); ++i) { + if (!indices.contains(i)) { + c_indices.push_back(i); + } + } + m_hs.add_exists_false(c_indices.size(), c_indices.c_ptr()); + } + + // should exclude some literal from core. + void block_up() { + unsigned_vector indices; + for (unsigned i = 0; i < m_asms.size(); ++i) { + unsigned index = m_aux2index.find(m_asms[i]); + m_core_activity[index]++; + indices.push_back(index); + } + m_hs.add_exists_true(indices.size(), indices.c_ptr()); + } + + void update_index(obj_map& asm2index) { + obj_map::iterator it = asm2index.begin(), end = asm2index.end(); + for (; it != end; ++it) { + it->m_value = UINT_MAX; + } + for (unsigned i = 0; i < m_asms.size(); ++i) { + asm2index.find(m_asms[i]) = i; + } + } + + app_ref mk_fresh(sort* s) { + app_ref r(m); + r = m.mk_fresh_const("r", s); + m_mc->insert(r->get_decl()); + return r; + } + + bool is_true(model_ref& mdl, expr* e) { + expr_ref val(m); + VERIFY(mdl->eval(e, val)); + return m.is_true(val); + } + + bool is_active(unsigned i) const { + return m_aux_active[i]; + } + + void ensure_active(unsigned i) { + if (!is_active(i)) { + expr_ref fml(m); + fml = m.mk_implies(m_aux[i].get(), m_soft[i].get()); + s().assert_expr(fml); + m_aux_active[i] = true; + } + } + + }; + + maxsmt_solver_base* opt::mk_maxhs(ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft) { + return alloc(maxhs, s, m, p, ws, soft); + } + +} diff --git a/src/opt/maxhs.h b/src/opt/maxhs.h new file mode 100644 index 000000000..e08a550bd --- /dev/null +++ b/src/opt/maxhs.h @@ -0,0 +1,29 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + maxhs.h + +Abstract: + + HS-max based MaxSAT. + +Author: + + Nikolaj Bjorner (nbjorner) 2014-4-17 + +Notes: + +--*/ + +#ifndef _HS_MAX_H_ +#define _HS_MAX_H_ + +#include "maxsmt.h" + +namespace opt { + maxsmt_solver_base* mk_maxhs(ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft); +} +#endif diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 2ec73bab4..fa0210ee2 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -135,7 +135,7 @@ public: m_lower += w; break; } - IF_VERBOSE(1, verbose_stream() << "(opt.max_res lower: " << m_lower << ")\n";); + IF_VERBOSE(1, verbose_stream() << "(opt.max_res [" << m_lower << ":" << m_upper << "])\n";); } return l_true; } diff --git a/src/opt/maxsls.cpp b/src/opt/maxsls.cpp new file mode 100644 index 000000000..c64e0f3fc --- /dev/null +++ b/src/opt/maxsls.cpp @@ -0,0 +1,63 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + maxsls.cpp + +Abstract: + + Weighted SLS MAXSAT module + +Author: + + Nikolaj Bjorner (nbjorner) 2014-4-17 + +Notes: + +--*/ + +#include "maxsls.h" +#include "ast_pp.h" +#include "model_smt2_pp.h" + + +namespace opt { + + class sls : public maxsmt_solver_base { + public: + sls(opt_solver* s, ast_manager& m, params_ref& p, + vector const& ws, expr_ref_vector const& soft): + maxsmt_solver_base(s, m, p, ws, soft) { + } + virtual ~sls() {} + lbool operator()() { + IF_VERBOSE(1, verbose_stream() << "(opt.sls)\n";); + enable_bvsat(); + enable_sls(); + init(); + lbool is_sat = s().check_sat(0, 0); + if (is_sat == l_true) { + s().get_model(m_model); + m_upper.reset(); + for (unsigned i = 0; i < m_soft.size(); ++i) { + expr_ref tmp(m); + m_model->eval(m_soft[i].get(), tmp, true); + m_assignment[i] = m.is_true(tmp); + if (!m_assignment[i]) { + m_upper += m_weights[i]; + } + } + } + return is_sat; + } + + }; + + maxsmt_solver_base* opt::mk_sls(ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft) { + return alloc(sls, s, m, p, ws, soft); + } + + +}; diff --git a/src/opt/maxsls.h b/src/opt/maxsls.h new file mode 100644 index 000000000..111d6a3b2 --- /dev/null +++ b/src/opt/maxsls.h @@ -0,0 +1,36 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + maxsls.h + +Abstract: + + Weighted SLS MAXSAT module + +Author: + + Nikolaj Bjorner (nbjorner) 2014-4-17 + +Notes: + + Partial, one-round SLS optimizer. Finds the first + local maximum given a resource bound and returns. + +--*/ +#ifndef _OPT_SLS_MAX_SAT_H_ +#define _OPT_SLS_MAX_SAT_H_ + +#include "maxsmt.h" + +namespace opt { + + + maxsmt_solver_base* mk_sls(ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft); + + +}; + +#endif diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 2b20ccbd0..7ae1348ab 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -22,7 +22,13 @@ Notes: #include "fu_malik.h" #include "core_maxsat.h" #include "maxres.h" -#include "weighted_maxsat.h" +#include "dual_maxres.h" +#include "maxhs.h" +#include "bcd2.h" +#include "wpm2.h" +#include "pbmax.h" +#include "wmax.h" +#include "maxsls.h" #include "ast_pp.h" #include "opt_params.hpp" #include "pb_decl_plugin.h" @@ -173,6 +179,9 @@ namespace opt { else if (m_maxsat_engine == symbol("maxres")) { m_msolver = mk_maxres(m, s, m_params, m_weights, m_soft_constraints); } + else if (m_maxsat_engine == symbol("dual-maxres")) { + m_msolver = mk_dual_maxres(m, s, m_params, m_weights, m_soft_constraints); + } else if (m_maxsat_engine == symbol("pbmax")) { m_msolver = mk_pbmax(m, s, m_params, m_weights, m_soft_constraints); } @@ -182,8 +191,8 @@ namespace opt { else if (m_maxsat_engine == symbol("bcd2")) { m_msolver = mk_bcd2(m, s, m_params, m_weights, m_soft_constraints); } - else if (m_maxsat_engine == symbol("hsmax")) { - m_msolver = mk_hsmax(m, s, m_params, m_weights, m_soft_constraints); + else if (m_maxsat_engine == symbol("maxhs")) { + m_msolver = mk_maxhs(m, s, m_params, m_weights, m_soft_constraints); } else if (m_maxsat_engine == symbol("sls")) { // NB: this is experimental one-round version of SLS @@ -196,7 +205,7 @@ namespace opt { m_msolver = alloc(fu_malik, m, *m_s, m_soft_constraints); } else { - if (m_maxsat_engine != symbol::null) { + if (m_maxsat_engine != symbol::null && m_maxsat_engine != symbol("wmax")) { warning_msg("solver %s is not recognized, using default 'wmax'", m_maxsat_engine.str().c_str()); } diff --git a/src/opt/mus.cpp b/src/opt/mus.cpp index 2e71f1bb8..4cfab6376 100644 --- a/src/opt/mus.cpp +++ b/src/opt/mus.cpp @@ -39,8 +39,11 @@ struct mus::imp { expr_ref_vector m_vars; obj_map m_var2idx; volatile bool m_cancel; + bool m_rmr_enabled; - imp(ref& s, ast_manager& m): m_s(s), m(m), m_cls2expr(m), m_vars(m), m_cancel(false) {} + imp(ref& s, ast_manager& m): + m_s(s), m(m), m_cls2expr(m), m_vars(m), m_cancel(false), + m_rmr_enabled(false) {} void reset() { m_cls2expr.reset(); @@ -133,10 +136,12 @@ struct mus::imp { assumptions.push_back(cls); mus.push_back(cls_id); extract_model(model); - sz = core.size(); - core.append(mus); - rmr(core, mus, model); - core.resize(sz); + if (m_rmr_enabled) { + sz = core.size(); + core.append(mus); + rmr(core, mus, model); + core.resize(sz); + } break; default: core_exprs.reset(); diff --git a/src/opt/pbmax.cpp b/src/opt/pbmax.cpp new file mode 100644 index 000000000..fe1d7b70d --- /dev/null +++ b/src/opt/pbmax.cpp @@ -0,0 +1,98 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + pbmax.cpp + +Abstract: + + pb based MaxSAT. + +Author: + + Nikolaj Bjorner (nbjorner) 2014-4-17 + +Notes: + +--*/ +#include "pbmax.h" +#include "pb_decl_plugin.h" +#include "uint_set.h" +#include "ast_pp.h" +#include "model_smt2_pp.h" + + +namespace opt { + + // ---------------------------------- + // incrementally add pseudo-boolean + // lower bounds. + + class pbmax : public maxsmt_solver_base { + public: + pbmax(opt_solver* s, ast_manager& m, params_ref& p, + vector const& ws, expr_ref_vector const& soft): + maxsmt_solver_base(s, m, p, ws, soft) { + } + + virtual ~pbmax() {} + + lbool operator()() { + enable_bvsat(); + enable_sls(); + + TRACE("opt", s().display(tout); tout << "\n"; + for (unsigned i = 0; i < m_soft.size(); ++i) { + tout << mk_pp(m_soft[i].get(), m) << " " << m_weights[i] << "\n"; + } + ); + pb_util u(m); + expr_ref fml(m), val(m); + app_ref b(m); + expr_ref_vector nsoft(m); + init(); + for (unsigned i = 0; i < m_soft.size(); ++i) { + nsoft.push_back(mk_not(m_soft[i].get())); + } + lbool is_sat = l_true; + while (l_true == is_sat) { + TRACE("opt", s().display(tout<<"looping\n"); + model_smt2_pp(tout << "\n", m, *(m_model.get()), 0);); + m_upper.reset(); + for (unsigned i = 0; i < m_soft.size(); ++i) { + VERIFY(m_model->eval(nsoft[i].get(), val)); + m_assignment[i] = !m.is_true(val); + if (!m_assignment[i]) { + m_upper += m_weights[i]; + } + } + IF_VERBOSE(1, verbose_stream() << "(opt.pb [" << m_lower << ":" << m_upper << "])\n";); + TRACE("opt", tout << "new upper: " << m_upper << "\n";); + + fml = u.mk_lt(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper); + solver::scoped_push _scope2(s()); + s().assert_expr(fml); + is_sat = s().check_sat(0,0); + if (m_cancel) { + is_sat = l_undef; + } + if (is_sat == l_true) { + s().get_model(m_model); + } + } + if (is_sat == l_false) { + is_sat = l_true; + m_lower = m_upper; + } + TRACE("opt", tout << "lower: " << m_lower << "\n";); + return is_sat; + } + }; + + maxsmt_solver_base* opt::mk_pbmax(ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft) { + return alloc(pbmax, s, m, p, ws, soft); + } + +} diff --git a/src/opt/pbmax.h b/src/opt/pbmax.h new file mode 100644 index 000000000..8dcb43715 --- /dev/null +++ b/src/opt/pbmax.h @@ -0,0 +1,30 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + pbmax.h + +Abstract: + + MaxSAT based on pb theory. + +Author: + + Nikolaj Bjorner (nbjorner) 2014-4-17 + +Notes: + +--*/ + +#ifndef _PBMAX_H_ +#define _PBMAX_H_ + +#include "maxsmt.h" + +namespace opt { + maxsmt_solver_base* mk_pbmax(ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft); + +} +#endif diff --git a/src/opt/weighted_maxsat.cpp b/src/opt/weighted_maxsat.cpp deleted file mode 100644 index dbd5a060f..000000000 --- a/src/opt/weighted_maxsat.cpp +++ /dev/null @@ -1,1384 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - weighted_maxsat.cpp - -Abstract: - - Weighted MAXSAT module - -Author: - - Nikolaj Bjorner (nbjorner) 2014-4-17 - -Notes: - ---*/ - -#include -#include "weighted_maxsat.h" -#include "smt_theory.h" -#include "smt_context.h" -#include "ast_pp.h" -#include "theory_wmaxsat.h" -#include "opt_params.hpp" -#include "pb_decl_plugin.h" -#include "uint_set.h" -#include "model_smt2_pp.h" -#include "cancel_eh.h" -#include "scoped_timer.h" -#include "optsmt.h" -#include "hitting_sets.h" -#include "stopwatch.h" - - -namespace opt { - - class scoped_stopwatch { - double& m_time; - stopwatch m_watch; - public: - scoped_stopwatch(double& time): m_time(time) { - m_watch.start(); - } - ~scoped_stopwatch() { - m_watch.stop(); - m_time += m_watch.get_seconds(); - } - }; - - - // ------------------------------------------------------ - // Morgado, Heras, Marques-Silva 2013 - // (initial version without model-based optimizations) - // - class bcd2 : public maxsmt_solver_base { - struct wcore { - expr* m_r; - unsigned_vector m_R; - rational m_lower; - rational m_mid; - rational m_upper; - }; - typedef obj_hashtable expr_set; - - pb_util pb; - expr_ref_vector m_soft_aux; - obj_map m_relax2index; // expr |-> index - obj_map m_soft2index; // expr |-> index - expr_ref_vector m_trail; - expr_ref_vector m_soft_constraints; - expr_set m_asm_set; - vector m_cores; - vector m_sigmas; - rational m_den; // least common multiplier of original denominators - bool m_enable_lazy; // enable adding soft constraints lazily (called 'mgbcd2') - unsigned_vector m_lazy_soft; // soft constraints to add lazily. - - void set2asms(expr_set const& set, expr_ref_vector & es) const { - es.reset(); - expr_set::iterator it = set.begin(), end = set.end(); - for (; it != end; ++it) { - es.push_back(m.mk_not(*it)); - } - } - void bcd2_init_soft(vector const& weights, expr_ref_vector const& soft) { - - // normalize weights to be integral: - m_den = rational::one(); - for (unsigned i = 0; i < m_weights.size(); ++i) { - m_den = lcm(m_den, denominator(m_weights[i])); - } - if (!m_den.is_one()) { - for (unsigned i = 0; i < m_weights.size(); ++i) { - m_weights[i] = m_den*m_weights[i]; - SASSERT(m_weights[i].is_int()); - } - } - } - void init_bcd() { - m_trail.reset(); - m_asm_set.reset(); - m_cores.reset(); - m_sigmas.reset(); - m_lazy_soft.reset(); - for (unsigned i = 0; i < m_soft.size(); ++i) { - m_sigmas.push_back(m_weights[i]); - m_soft_aux.push_back(mk_fresh()); - if (m_enable_lazy) { - m_lazy_soft.push_back(i); - } - else { - enable_soft_constraint(i); - } - } - m_upper += rational(1); - } - - void process_sat() { - svector assignment; - update_assignment(assignment); - if (check_lazy_soft(assignment)) { - update_sigmas(); - } - } - - public: - bcd2(opt_solver* s, ast_manager& m, params_ref& p, - vector const& ws, expr_ref_vector const& soft): - maxsmt_solver_base(s, m, p, ws, soft), - pb(m), - m_soft_aux(m), - m_trail(m), - m_soft_constraints(m), - m_enable_lazy(true) { - bcd2_init_soft(ws, soft); - } - - virtual ~bcd2() {} - - virtual lbool operator()() { - expr_ref fml(m), r(m); - lbool is_sat = l_undef; - expr_ref_vector asms(m); - enable_sls(); - solver::scoped_push _scope1(s()); - init(); - init_bcd(); - if (m_cancel) { - normalize_bounds(); - return l_undef; - } - process_sat(); - while (m_lower < m_upper) { - IF_VERBOSE(1, verbose_stream() << "(bcd2 [" << m_lower << ":" << m_upper << "])\n";); - assert_soft(); - solver::scoped_push _scope2(s()); - TRACE("opt", display(tout);); - assert_cores(); - set2asms(m_asm_set, asms); - if (m_cancel) { - normalize_bounds(); - return l_undef; - } - is_sat = s().check_sat(asms.size(), asms.c_ptr()); - switch(is_sat) { - case l_undef: - normalize_bounds(); - return l_undef; - case l_true: - process_sat(); - break; - case l_false: { - ptr_vector unsat_core; - uint_set subC, soft; - s().get_unsat_core(unsat_core); - core2indices(unsat_core, subC, soft); - SASSERT(unsat_core.size() == subC.num_elems() + soft.num_elems()); - if (soft.num_elems() == 0 && subC.num_elems() == 1) { - unsigned s = *subC.begin(); - wcore& c_s = m_cores[s]; - c_s.m_lower = refine(c_s.m_R, c_s.m_mid); - c_s.m_mid = div(c_s.m_lower + c_s.m_upper, rational(2)); - } - else { - wcore c_s; - rational delta = min_of_delta(subC); - rational lower = sum_of_lower(subC); - union_Rs(subC, c_s.m_R); - r = mk_fresh(); - relax(subC, soft, c_s.m_R, delta); - c_s.m_lower = refine(c_s.m_R, lower + delta - rational(1)); - c_s.m_upper = rational::one(); - c_s.m_upper += sum_of_sigmas(c_s.m_R); - c_s.m_mid = div(c_s.m_lower + c_s.m_upper, rational(2)); - c_s.m_r = r; - m_asm_set.insert(r); - subtract(m_cores, subC); - m_relax2index.insert(r, m_cores.size()); - m_cores.push_back(c_s); - } - break; - } - } - m_lower = compute_lower(); - } - normalize_bounds(); - return l_true; - } - - - private: - - void enable_soft_constraint(unsigned i) { - expr_ref fml(m); - expr* r = m_soft_aux[i].get(); - m_soft2index.insert(r, i); - fml = m.mk_or(r, m_soft[i].get()); - m_soft_constraints.push_back(fml); - m_asm_set.insert(r); - SASSERT(m_weights[i].is_int()); - } - - void assert_soft() { - for (unsigned i = 0; i < m_soft_constraints.size(); ++i) { - s().assert_expr(m_soft_constraints[i].get()); - } - m_soft_constraints.reset(); - } - - bool check_lazy_soft(svector const& assignment) { - bool all_satisfied = true; - for (unsigned i = 0; i < m_lazy_soft.size(); ++i) { - unsigned j = m_lazy_soft[i]; - if (!assignment[j]) { - enable_soft_constraint(j); - m_lazy_soft[i] = m_lazy_soft.back(); - m_lazy_soft.pop_back(); - --i; - all_satisfied = false; - } - } - return all_satisfied; - } - - void normalize_bounds() { - m_lower /= m_den; - m_upper /= m_den; - } - - expr* mk_fresh() { - expr* r = mk_fresh_bool("r"); - m_trail.push_back(r); - return r; - } - - void update_assignment(svector& new_assignment) { - expr_ref val(m); - rational new_upper(0); - model_ref model; - new_assignment.reset(); - s().get_model(model); - for (unsigned i = 0; i < m_soft.size(); ++i) { - VERIFY(model->eval(m_soft[i].get(), val)); - new_assignment.push_back(m.is_true(val)); - if (!new_assignment[i]) { - new_upper += m_weights[i]; - } - } - if (new_upper < m_upper) { - m_upper = new_upper; - m_model = model; - m_assignment.reset(); - m_assignment.append(new_assignment); - } - } - - void update_sigmas() { - for (unsigned i = 0; i < m_cores.size(); ++i) { - wcore& c_i = m_cores[i]; - unsigned_vector const& R = c_i.m_R; - c_i.m_upper.reset(); - for (unsigned j = 0; j < R.size(); ++j) { - unsigned r_j = R[j]; - if (!m_assignment[r_j]) { - c_i.m_upper += m_weights[r_j]; - m_sigmas[r_j] = m_weights[r_j]; - } - else { - m_sigmas[r_j].reset(); - } - } - c_i.m_mid = div(c_i.m_lower + c_i.m_upper, rational(2)); - } - } - - /** - * Minimum of two (positive) numbers. Zero is treated as +infinity. - */ - rational min_z(rational const& a, rational const& b) { - if (a.is_zero()) return b; - if (b.is_zero()) return a; - if (a < b) return a; - return b; - } - - rational min_of_delta(uint_set const& subC) { - rational delta(0); - for (uint_set::iterator it = subC.begin(); it != subC.end(); ++it) { - unsigned j = *it; - wcore const& core = m_cores[j]; - rational new_delta = rational(1) + core.m_upper - core.m_mid; - SASSERT(new_delta.is_pos()); - delta = min_z(delta, new_delta); - } - return delta; - } - - rational sum_of_lower(uint_set const& subC) { - rational lower(0); - for (uint_set::iterator it = subC.begin(); it != subC.end(); ++it) { - lower += m_cores[*it].m_lower; - } - return lower; - } - - rational sum_of_sigmas(unsigned_vector const& R) { - rational sum(0); - for (unsigned i = 0; i < R.size(); ++i) { - sum += m_sigmas[R[i]]; - } - return sum; - } - void union_Rs(uint_set const& subC, unsigned_vector& R) { - for (uint_set::iterator it = subC.begin(); it != subC.end(); ++it) { - R.append(m_cores[*it].m_R); - } - } - rational compute_lower() { - rational result(0); - for (unsigned i = 0; i < m_cores.size(); ++i) { - result += m_cores[i].m_lower; - } - return result; - } - void subtract(vector& cores, uint_set const& subC) { - unsigned j = 0; - for (unsigned i = 0; i < cores.size(); ++i) { - if (subC.contains(i)) { - m_asm_set.remove(cores[i].m_r); - } - else { - if (j != i) { - cores[j] = cores[i]; - } - ++j; - } - } - cores.resize(j); - for (unsigned i = 0; i < cores.size(); ++i) { - m_relax2index.insert(cores[i].m_r, i); - } - } - void core2indices(ptr_vector const& core, uint_set& subC, uint_set& soft) { - for (unsigned i = 0; i < core.size(); ++i) { - unsigned j; - expr* a; - VERIFY(m.is_not(core[i], a)); - if (m_relax2index.find(a, j)) { - subC.insert(j); - } - else { - VERIFY(m_soft2index.find(a, j)); - soft.insert(j); - } - } - } - rational refine(unsigned_vector const& idx, rational v) { - return v + rational(1); - } - void relax(uint_set& subC, uint_set& soft, unsigned_vector& R, rational& delta) { - for (uint_set::iterator it = soft.begin(); it != soft.end(); ++it) { - R.push_back(*it); - delta = min_z(delta, m_weights[*it]); - m_asm_set.remove(m_soft_aux[*it].get()); - } - } - void assert_cores() { - for (unsigned i = 0; i < m_cores.size(); ++i) { - assert_core(m_cores[i]); - } - } - void assert_core(wcore const& core) { - expr_ref fml(m); - vector ws; - ptr_vector rs; - rational w(0); - for (unsigned j = 0; j < core.m_R.size(); ++j) { - unsigned idx = core.m_R[j]; - ws.push_back(m_weights[idx]); - w += ws.back(); - rs.push_back(m_soft_aux[idx].get()); - } - w.neg(); - w += core.m_mid; - ws.push_back(w); - rs.push_back(core.m_r); - fml = pb.mk_le(ws.size(), ws.c_ptr(), rs.c_ptr(), core.m_mid); - s().assert_expr(fml); - } - void display(std::ostream& out) { - out << "[" << m_lower << ":" << m_upper << "]\n"; - s().display(out); - out << "\n"; - for (unsigned i = 0; i < m_cores.size(); ++i) { - wcore const& c = m_cores[i]; - out << mk_pp(c.m_r, m) << ": "; - for (unsigned j = 0; j < c.m_R.size(); ++j) { - out << c.m_R[j] << " (" << m_sigmas[c.m_R[j]] << ") "; - } - out << "[" << c.m_lower << ":" << c.m_mid << ":" << c.m_upper << "]\n"; - } - for (unsigned i = 0; i < m_soft.size(); ++i) { - out << mk_pp(m_soft[i].get(), m) << " " << m_weights[i] << "\n"; - } - } - }; - - // ---------------------------------- - // MaxSatHS+MSS - // variant of MaxSAT-HS (Algorithm 9) - // that also refines upper bound during progressive calls - // to the underlying optimization solver for the soft constraints. - // - - class hsmax : public maxsmt_solver_base { - struct stats { - stats() { reset(); } - void reset() { memset(this, 0, sizeof(*this)); } - unsigned m_num_iterations; - unsigned m_num_core_reductions_success; - unsigned m_num_core_reductions_failure; - unsigned m_num_model_expansions_success; - unsigned m_num_model_expansions_failure; - double m_core_reduction_time; - double m_model_expansion_time; - double m_aux_sat_time; - double m_disjoint_cores_time; - }; - - hitting_sets m_hs; - expr_ref_vector m_aux; // auxiliary (indicator) variables. - obj_map m_aux2index; // expr |-> index - unsigned_vector m_core_activity; // number of times soft constraint is used in a core. - svector m_seed; // clause selected in current model. - svector m_aux_active; // active soft clauses. - ptr_vector m_asms; // assumptions (over aux) - pb_util pb; - arith_util a; - stats m_stats; - bool m_at_lower_bound; - - - public: - hsmax(opt_solver* s, ast_manager& m, params_ref& p, vector const& ws, expr_ref_vector const& soft): - maxsmt_solver_base(s, m, p, ws, soft), - m_aux(m), - pb(m), - a(m), - m_at_lower_bound(false) { - } - virtual ~hsmax() {} - - virtual void set_cancel(bool f) { - maxsmt_solver_base::set_cancel(f); - m_hs.set_cancel(f); - } - - virtual void collect_statistics(statistics& st) const { - maxsmt_solver_base::collect_statistics(st); - m_hs.collect_statistics(st); - st.update("hsmax-num-iterations", m_stats.m_num_iterations); - st.update("hsmax-num-core-reductions-n", m_stats.m_num_core_reductions_failure); - st.update("hsmax-num-core-reductions-y", m_stats.m_num_core_reductions_success); - st.update("hsmax-num-model-expansions-n", m_stats.m_num_model_expansions_failure); - st.update("hsmax-num-model-expansions-y", m_stats.m_num_model_expansions_success); - st.update("hsmax-core-reduction-time", m_stats.m_core_reduction_time); - st.update("hsmax-model-expansion-time", m_stats.m_model_expansion_time); - st.update("hsmax-aux-sat-time", m_stats.m_aux_sat_time); - st.update("hsmax-disj-core-time", m_stats.m_disjoint_cores_time); - } - - lbool operator()() { - ptr_vector hs; - init(); - init_local(); - if (!disjoint_cores(hs)) { - return l_undef; - } - seed2assumptions(); - while (m_lower < m_upper) { - ++m_stats.m_num_iterations; - IF_VERBOSE(1, verbose_stream() << - "(hsmax [" << m_lower << ":" << m_upper << "])\n";); - TRACE("opt", tout << "(hsmax [" << m_lower << ":" << m_upper << "])\n";); - if (m_cancel) { - return l_undef; - } - - lbool core_found = generate_cores(hs); - switch(core_found) { - case l_undef: - return l_undef; - case l_true: { - lbool is_sat = next_seed(); - switch(is_sat) { - case l_true: - seed2hs(false, hs); - break; - case l_false: - TRACE("opt", tout << "no more seeds\n";); - IF_VERBOSE(1, verbose_stream() << "(maxhs.no-more-seeds)\n";); - m_lower = m_upper; - return l_true; - case l_undef: - return l_undef; - } - break; - } - case l_false: - IF_VERBOSE(1, verbose_stream() << "(maxhs.no-more-cores)\n";); - TRACE("opt", tout << "no more cores\n";); - m_lower = m_upper; - return l_true; - } - } - return l_true; - } - - private: - - unsigned num_soft() const { return m_soft.size(); } - - void init_local() { - unsigned sz = num_soft(); - app_ref fml(m), obj(m); - expr_ref_vector sum(m); - m_asms.reset(); - m_seed.reset(); - m_aux.reset(); - m_aux_active.reset(); - m_aux2index.reset(); - m_core_activity.reset(); - for (unsigned i = 0; i < sz; ++i) { - bool tt = is_true(m_model, m_soft[i].get()); - m_seed.push_back(tt); - m_aux. push_back(mk_fresh(m.mk_bool_sort())); - m_aux_active.push_back(false); - m_core_activity.push_back(0); - m_aux2index.insert(m_aux.back(), i); - if (tt) { - m_asms.push_back(m_aux.back()); - ensure_active(i); - } - } - - for (unsigned i = 0; i < m_weights.size(); ++i) { - m_hs.add_weight(m_weights[i]); - } - TRACE("opt", print_seed(tout);); - } - - - void hs2seed(ptr_vector const& hs) { - for (unsigned i = 0; i < num_soft(); ++i) { - m_seed[i] = true; - } - for (unsigned i = 0; i < hs.size(); ++i) { - m_seed[m_aux2index.find(hs[i])] = false; - } - TRACE("opt", - print_asms(tout << "hitting set: ", hs); - print_seed(tout);); - } - - void seed2hs(bool pos, ptr_vector& hs) { - hs.reset(); - for (unsigned i = 0; i < num_soft(); ++i) { - if (pos == m_seed[i]) { - hs.push_back(m_aux[i].get()); - } - } - TRACE("opt", - print_asms(tout << "hitting set: ", hs); - print_seed(tout);); - - } - - void seed2assumptions() { - seed2hs(true, m_asms); - } - - - // - // Find disjoint cores for soft constraints. - // - bool disjoint_cores(ptr_vector& hs) { - scoped_stopwatch _sw(m_stats.m_disjoint_cores_time); - m_asms.reset(); - svector active(num_soft(), true); - rational lower(0); - update_assumptions(active, lower, hs); - SASSERT(lower.is_zero()); - while (true) { - lbool is_sat = s().check_sat(m_asms.size(), m_asms.c_ptr()); - switch (is_sat) { - case l_true: - if (lower > m_lower) { - m_lower = lower; - } - return true; - case l_false: - if (!shrink()) return false; - block_up(); - update_assumptions(active, lower, hs); - break; - case l_undef: - return false; - } - } - } - - void update_assumptions(svector& active, rational& lower, ptr_vector& hs) { - rational arg_min(0); - expr* e = 0; - for (unsigned i = 0; i < m_asms.size(); ++i) { - unsigned index = m_aux2index.find(m_asms[i]); - active[index] = false; - if (arg_min.is_zero() || arg_min > m_weights[index]) { - arg_min = m_weights[index]; - e = m_asms[i]; - } - } - if (e) { - hs.push_back(e); - lower += arg_min; - } - m_asms.reset(); - for (unsigned i = 0; i < num_soft(); ++i) { - if (active[i]) { - m_asms.push_back(m_aux[i].get()); - ensure_active(i); - } - } - } - - // - // Auxiliary Algorithm 10 for producing cores. - // - lbool generate_cores(ptr_vector& hs) { - bool core = !m_at_lower_bound; - while (true) { - hs2seed(hs); - lbool is_sat = check_subset(); - switch(is_sat) { - case l_undef: - return l_undef; - case l_true: - if (!grow()) return l_undef; - block_down(); - return core?l_true:l_false; - case l_false: - core = true; - if (!shrink()) return l_undef; - block_up(); - find_non_optimal_hitting_set(hs); - break; - } - } - } - - struct lt_activity { - hsmax& hs; - lt_activity(hsmax& hs):hs(hs) {} - bool operator()(expr* a, expr* b) const { - unsigned w1 = hs.m_core_activity[hs.m_aux2index.find(a)]; - unsigned w2 = hs.m_core_activity[hs.m_aux2index.find(b)]; - return w1 < w2; - } - }; - - // - // produce the non-optimal hitting set by using the 10% heuristic. - // of most active cores constraints. - // m_asms contains the current core. - // - void find_non_optimal_hitting_set(ptr_vector& hs) { - std::sort(m_asms.begin(), m_asms.end(), lt_activity(*this)); - for (unsigned i = m_asms.size(); i > 9*m_asms.size()/10;) { - --i; - hs.push_back(m_asms[i]); - } - } - - // - // retrieve the next seed that satisfies state of hs. - // state of hs must be satisfiable before optimization is called. - // - lbool next_seed() { - scoped_stopwatch _sw(m_stats.m_aux_sat_time); - TRACE("opt", tout << "\n";); - - // min c_i*(not x_i) for x_i are soft clauses. - // max c_i*x_i for x_i are soft clauses - - m_at_lower_bound = false; - - lbool is_sat = m_hs.compute_upper(); - - if (is_sat == l_true) { - is_sat = m_hs.compute_lower(); - } - if (is_sat == l_true) { - m_at_lower_bound = m_hs.get_upper() == m_hs.get_lower(); - if (m_hs.get_lower() > m_lower) { - m_lower = m_hs.get_lower(); - } - for (unsigned i = 0; i < num_soft(); ++i) { - m_seed[i] = is_active(i) && !m_hs.get_value(i); - } - TRACE("opt", print_seed(tout);); - } - return is_sat; - } - - // - // check assignment returned by HS with the original - // hard constraints. - // - lbool check_subset() { - TRACE("opt", tout << "\n";); - m_asms.reset(); - for (unsigned i = 0; i < num_soft(); ++i) { - if (m_seed[i]) { - m_asms.push_back(m_aux[i].get()); - ensure_active(i); - } - } - return s().check_sat(m_asms.size(), m_asms.c_ptr()); - } - - // - // extend the current assignment to one that - // satisfies as many soft constraints as possible. - // update the upper bound based on this assignment - // - bool grow() { - scoped_stopwatch _sw(m_stats.m_model_expansion_time); - model_ref mdl; - s().get_model(mdl); - for (unsigned i = 0; i < num_soft(); ++i) { - ensure_active(i); - m_seed[i] = false; - } - for (unsigned i = 0; i < m_asms.size(); ++i) { - m_seed[m_aux2index.find(m_asms[i])] = true; - } - - for (unsigned i = 0; i < num_soft(); ++i) { - if (m_seed[i]) { - // already an assumption - } - else if (is_true(mdl, m_soft[i].get())) { - m_seed[i] = true; - m_asms.push_back(m_aux[i].get()); - } - else { - m_asms.push_back(m_aux[i].get()); - lbool is_sat = s().check_sat(m_asms.size(), m_asms.c_ptr()); - switch(is_sat) { - case l_undef: - return false; - case l_false: - ++m_stats.m_num_model_expansions_failure; - m_asms.pop_back(); - break; - case l_true: - ++m_stats.m_num_model_expansions_success; - s().get_model(mdl); - m_seed[i] = true; - break; - } - } - } - rational upper(0); - for (unsigned i = 0; i < num_soft(); ++i) { - if (!m_seed[i]) { - upper += m_weights[i]; - } - } - if (upper < m_upper) { - m_upper = upper; - m_hs.set_upper(upper); - m_model = mdl; - m_assignment.reset(); - m_assignment.append(m_seed); - TRACE("opt", - tout << "new upper: " << m_upper << "\n"; - model_smt2_pp(tout, m, *(mdl.get()), 0);); - } - DEBUG_CODE( - for (unsigned i = 0; i < num_soft(); ++i) { - SASSERT(is_true(mdl, m_soft[i].get()) == m_seed[i]); - }); - - return true; - } - - // - // remove soft constraints from the current core. - // - bool shrink() { - scoped_stopwatch _sw(m_stats.m_core_reduction_time); - m_asms.reset(); - s().get_unsat_core(m_asms); - TRACE("opt", print_asms(tout, m_asms);); - obj_map asm2index; - for (unsigned i = 0; i < m_asms.size(); ++i) { - asm2index.insert(m_asms[i], i); - } - obj_map::iterator it = asm2index.begin(), end = asm2index.end(); - for (; it != end; ++it) { - unsigned i = it->m_value; - if (i < m_asms.size()) { - expr* tmp = m_asms[i]; - expr* back = m_asms.back(); - m_asms[i] = back; - m_asms.pop_back(); - lbool is_sat = s().check_sat(m_asms.size(), m_asms.c_ptr()); - TRACE("opt", tout << "checking: " << mk_pp(tmp, m) << ": " << is_sat << "\n";); - switch(is_sat) { - case l_true: - ++m_stats.m_num_core_reductions_failure; - // put back literal into core - m_asms.push_back(back); - m_asms[i] = tmp; - break; - case l_false: - // update the core - m_asms.reset(); - ++m_stats.m_num_core_reductions_success; - s().get_unsat_core(m_asms); - TRACE("opt", print_asms(tout, m_asms);); - update_index(asm2index); - break; - case l_undef: - return false; - } - } - } - return true; - } - - void print_asms(std::ostream& out, ptr_vector const& asms) { - for (unsigned j = 0; j < asms.size(); ++j) { - out << mk_pp(asms[j], m) << " "; - } - out << "\n"; - } - - void print_seed(std::ostream& out) { - out << "seed: "; - for (unsigned i = 0; i < num_soft(); ++i) { - out << (m_seed[i]?"1":"0"); - } - out << "\n"; - } - - // - // must include some literal not from asms. - // (furthermore, update upper bound constraint in HS) - // - void block_down() { - uint_set indices; - unsigned_vector c_indices; - for (unsigned i = 0; i < m_asms.size(); ++i) { - indices.insert(m_aux2index.find(m_asms[i])); - } - for (unsigned i = 0; i < num_soft(); ++i) { - if (!indices.contains(i)) { - c_indices.push_back(i); - } - } - m_hs.add_exists_false(c_indices.size(), c_indices.c_ptr()); - } - - // should exclude some literal from core. - void block_up() { - unsigned_vector indices; - for (unsigned i = 0; i < m_asms.size(); ++i) { - unsigned index = m_aux2index.find(m_asms[i]); - m_core_activity[index]++; - indices.push_back(index); - } - m_hs.add_exists_true(indices.size(), indices.c_ptr()); - } - - void update_index(obj_map& asm2index) { - obj_map::iterator it = asm2index.begin(), end = asm2index.end(); - for (; it != end; ++it) { - it->m_value = UINT_MAX; - } - for (unsigned i = 0; i < m_asms.size(); ++i) { - asm2index.find(m_asms[i]) = i; - } - } - - app_ref mk_fresh(sort* s) { - app_ref r(m); - r = m.mk_fresh_const("r", s); - m_mc->insert(r->get_decl()); - return r; - } - - bool is_true(model_ref& mdl, expr* e) { - expr_ref val(m); - VERIFY(mdl->eval(e, val)); - return m.is_true(val); - } - - bool is_active(unsigned i) const { - return m_aux_active[i]; - } - - void ensure_active(unsigned i) { - if (!is_active(i)) { - expr_ref fml(m); - fml = m.mk_implies(m_aux[i].get(), m_soft[i].get()); - s().assert_expr(fml); - m_aux_active[i] = true; - } - } - - }; - - - // ---------------------------------- - // incrementally add pseudo-boolean - // lower bounds. - - class pbmax : public maxsmt_solver_base { - public: - pbmax(opt_solver* s, ast_manager& m, params_ref& p, - vector const& ws, expr_ref_vector const& soft): - maxsmt_solver_base(s, m, p, ws, soft) { - } - - virtual ~pbmax() {} - - lbool operator()() { - enable_bvsat(); - enable_sls(); - - TRACE("opt", s().display(tout); tout << "\n"; - for (unsigned i = 0; i < m_soft.size(); ++i) { - tout << mk_pp(m_soft[i].get(), m) << " " << m_weights[i] << "\n"; - } - ); - pb_util u(m); - expr_ref fml(m), val(m); - app_ref b(m); - expr_ref_vector nsoft(m); - init(); - for (unsigned i = 0; i < m_soft.size(); ++i) { - nsoft.push_back(mk_not(m_soft[i].get())); - } - lbool is_sat = l_true; - while (l_true == is_sat) { - TRACE("opt", s().display(tout<<"looping\n"); - model_smt2_pp(tout << "\n", m, *(m_model.get()), 0);); - m_upper.reset(); - for (unsigned i = 0; i < m_soft.size(); ++i) { - VERIFY(m_model->eval(nsoft[i].get(), val)); - m_assignment[i] = !m.is_true(val); - if (!m_assignment[i]) { - m_upper += m_weights[i]; - } - } - IF_VERBOSE(1, verbose_stream() << "(pb solve with upper bound: " << m_upper << ")\n";); - TRACE("opt", tout << "new upper: " << m_upper << "\n";); - - fml = u.mk_lt(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper); - solver::scoped_push _scope2(s()); - s().assert_expr(fml); - is_sat = s().check_sat(0,0); - if (m_cancel) { - is_sat = l_undef; - } - if (is_sat == l_true) { - s().get_model(m_model); - } - } - if (is_sat == l_false) { - is_sat = l_true; - m_lower = m_upper; - } - TRACE("opt", tout << "lower: " << m_lower << "\n";); - return is_sat; - } - }; - - // ------------------------------------------------------ - // AAAI 2010 - class wpm2 : public maxsmt_solver_base { - scoped_ptr maxs; - public: - wpm2(opt_solver* s, ast_manager& m, maxsmt_solver_base* _maxs, params_ref& p, - vector const& ws, expr_ref_vector const& soft): - maxsmt_solver_base(s, m, p, ws, soft), maxs(_maxs) { - } - - virtual ~wpm2() {} - - lbool operator()() { - enable_sls(); - IF_VERBOSE(1, verbose_stream() << "(wpm2 solve)\n";); - solver::scoped_push _s(s()); - pb_util u(m); - app_ref fml(m), a(m), b(m), c(m); - expr_ref val(m); - expr_ref_vector block(m), ans(m), al(m), am(m); - obj_map ans_index; - vector amk; - vector sc; - init(); - for (unsigned i = 0; i < m_soft.size(); ++i) { - rational w = m_weights[i]; - - b = mk_fresh_bool("b"); - block.push_back(b); - expr* bb = b; - - a = mk_fresh_bool("a"); - ans.push_back(a); - ans_index.insert(a, i); - fml = m.mk_or(m_soft[i].get(), b, m.mk_not(a)); - s().assert_expr(fml); - - c = mk_fresh_bool("c"); - fml = m.mk_implies(c, u.mk_le(1,&w,&bb,rational(0))); - s().assert_expr(fml); - - sc.push_back(uint_set()); - sc.back().insert(i); - am.push_back(c); - amk.push_back(rational(0)); - } - - while (true) { - expr_ref_vector asms(m); - ptr_vector core; - asms.append(ans); - asms.append(am); - lbool is_sat = s().check_sat(asms.size(), asms.c_ptr()); - TRACE("opt", - tout << "\nassumptions: "; - for (unsigned i = 0; i < asms.size(); ++i) { - tout << mk_pp(asms[i].get(), m) << " "; - } - tout << "\n" << is_sat << "\n"; - tout << "upper: " << m_upper << "\n"; - tout << "lower: " << m_lower << "\n"; - if (is_sat == l_true) { - model_ref mdl; - s().get_model(mdl); - model_smt2_pp(tout, m, *(mdl.get()), 0); - }); - - if (m_cancel && is_sat != l_false) { - is_sat = l_undef; - } - if (is_sat == l_true) { - m_upper = m_lower; - s().get_model(m_model); - for (unsigned i = 0; i < block.size(); ++i) { - VERIFY(m_model->eval(m_soft[i].get(), val)); - TRACE("opt", tout << mk_pp(block[i].get(), m) << " " << val << "\n";); - m_assignment[i] = m.is_true(val); - } - } - if (is_sat != l_false) { - return is_sat; - } - s().get_unsat_core(core); - if (core.empty()) { - return l_false; - } - TRACE("opt", - tout << "core: "; - for (unsigned i = 0; i < core.size(); ++i) { - tout << mk_pp(core[i],m) << " "; - } - tout << "\n";); - uint_set A; - for (unsigned i = 0; i < core.size(); ++i) { - unsigned j; - if (ans_index.find(core[i], j)) { - A.insert(j); - } - } - if (A.empty()) { - return l_false; - } - uint_set B; - rational k(0); - rational old_lower(m_lower); - for (unsigned i = 0; i < sc.size(); ++i) { - uint_set t(sc[i]); - t &= A; - if (!t.empty()) { - B |= sc[i]; - k += amk[i]; - m_lower -= amk[i]; - sc[i] = sc.back(); - sc.pop_back(); - am[i] = am.back(); - am.pop_back(); - amk[i] = amk.back(); - amk.pop_back(); - --i; - } - } - vector ws; - expr_ref_vector bs(m); - for (unsigned i = 0; i < m_soft.size(); ++i) { - if (B.contains(i)) { - ws.push_back(m_weights[i]); - bs.push_back(block[i].get()); - } - } - TRACE("opt", tout << "at most bound: " << k << "\n";); - is_sat = new_bound(al, ws, bs, k); - if (is_sat != l_true) { - return is_sat; - } - m_lower += k; - SASSERT(m_lower > old_lower); - TRACE("opt", tout << "new bound: " << m_lower << "\n";); - expr_ref B_le_k(m), B_ge_k(m); - B_le_k = u.mk_le(ws.size(), ws.c_ptr(), bs.c_ptr(), k); - B_ge_k = u.mk_ge(ws.size(), ws.c_ptr(), bs.c_ptr(), k); - s().assert_expr(B_ge_k); - al.push_back(B_ge_k); - IF_VERBOSE(1, verbose_stream() << "(wpm2 lower bound: " << m_lower << ")\n";); - IF_VERBOSE(2, verbose_stream() << "New lower bound: " << B_ge_k << "\n";); - - c = mk_fresh_bool("c"); - fml = m.mk_implies(c, B_le_k); - s().assert_expr(fml); - sc.push_back(B); - am.push_back(c); - amk.push_back(k); - } - } - - virtual void set_cancel(bool f) { - maxsmt_solver_base::set_cancel(f); - maxs->set_cancel(f); - } - - virtual void collect_statistics(statistics& st) const { - maxsmt_solver_base::collect_statistics(st); - maxs->collect_statistics(st); - } - - private: - lbool new_bound(expr_ref_vector const& al, - vector const& ws, - expr_ref_vector const& bs, - rational& k) { - pb_util u(m); - expr_ref_vector al2(m); - al2.append(al); - // w_j*b_j > k - al2.push_back(m.mk_not(u.mk_le(ws.size(), ws.c_ptr(), bs.c_ptr(), k))); - return bound(al2, ws, bs, k); - } - - // - // minimal k, such that al & w_j*b_j >= k is sat - // minimal k, such that al & 3*x + 4*y >= k is sat - // minimal k, such that al & (or (not x) w3) & (or (not y) w4) - // - lbool bound(expr_ref_vector const& al, - vector const& ws, - expr_ref_vector const& bs, - rational& k) { - expr_ref_vector nbs(m); - opt_solver::scoped_push _sc(maxs->s()); - for (unsigned i = 0; i < al.size(); ++i) { - maxs->add_hard(al[i]); - } - for (unsigned i = 0; i < bs.size(); ++i) { - nbs.push_back(mk_not(bs[i])); - } - TRACE("opt", - maxs->s().display(tout); - tout << "\n"; - for (unsigned i = 0; i < bs.size(); ++i) { - tout << mk_pp(bs[i], m) << " " << ws[i] << "\n"; - }); - maxs->init_soft(ws, nbs); - lbool is_sat = maxs->s().check_sat(0,0); - if (is_sat == l_true) { - maxs->set_model(); - is_sat = (*maxs)(); - } - SASSERT(maxs->get_lower() > k); - k = maxs->get_lower(); - return is_sat; - } - }; - - class sls : public maxsmt_solver_base { - public: - sls(opt_solver* s, ast_manager& m, params_ref& p, - vector const& ws, expr_ref_vector const& soft): - maxsmt_solver_base(s, m, p, ws, soft) { - } - virtual ~sls() {} - lbool operator()() { - IF_VERBOSE(1, verbose_stream() << "(sls solve)\n";); - enable_bvsat(); - enable_sls(); - init(); - lbool is_sat = s().check_sat(0, 0); - if (is_sat == l_true) { - s().get_model(m_model); - m_upper.reset(); - for (unsigned i = 0; i < m_soft.size(); ++i) { - expr_ref tmp(m); - m_model->eval(m_soft[i].get(), tmp, true); - m_assignment[i] = m.is_true(tmp); - if (!m_assignment[i]) { - m_upper += m_weights[i]; - } - } - } - return is_sat; - } - - }; - - - class maxsmt_solver_wbase : public maxsmt_solver_base { - smt::context& ctx; - public: - maxsmt_solver_wbase(opt_solver* s, ast_manager& m, smt::context& ctx, params_ref& p, - vector const& ws, expr_ref_vector const& soft): - maxsmt_solver_base(s, m, p, ws, soft), ctx(ctx) {} - ~maxsmt_solver_wbase() {} - - class scoped_ensure_theory { - smt::theory_wmaxsat* m_wth; - public: - scoped_ensure_theory(maxsmt_solver_wbase& s) { - m_wth = s.ensure_theory(); - } - ~scoped_ensure_theory() { - m_wth->reset(); - } - smt::theory_wmaxsat& operator()() { return *m_wth; } - }; - - smt::theory_wmaxsat* ensure_theory() { - smt::theory_wmaxsat* wth = get_theory(); - if (wth) { - wth->reset(); - } - else { - wth = alloc(smt::theory_wmaxsat, m, m_mc); - ctx.register_plugin(wth); - } - return wth; - } - smt::theory_wmaxsat* get_theory() const { - smt::theory_id th_id = m.get_family_id("weighted_maxsat"); - smt::theory* th = ctx.get_theory(th_id); - if (th) { - return dynamic_cast(th); - } - else { - return 0; - } - } - }; - - // ---------------------------------------------------------- - // weighted max-sat using a custom theory solver for max-sat. - // NB. it is quite similar to pseudo-Boolean propagation. - - - class wmax : public maxsmt_solver_wbase { - public: - wmax(opt_solver* s, ast_manager& m, smt::context& ctx, params_ref& p, - vector const& ws, expr_ref_vector const& soft): - maxsmt_solver_wbase(s, m, ctx, p, ws, soft) {} - virtual ~wmax() {} - - lbool operator()() { - TRACE("opt", tout << "weighted maxsat\n";); - scoped_ensure_theory wth(*this); - solver::scoped_push _s(s()); - lbool is_sat = l_true; - bool was_sat = false; - for (unsigned i = 0; i < m_soft.size(); ++i) { - wth().assert_weighted(m_soft[i].get(), m_weights[i]); - } - solver::scoped_push __s(s()); - while (l_true == is_sat) { - IF_VERBOSE(1, verbose_stream() << "(wmax " << m_upper << ")\n";); - is_sat = s().check_sat(0,0); - if (m_cancel) { - is_sat = l_undef; - } - if (is_sat == l_true) { - if (wth().is_optimal()) { - m_upper = wth().get_min_cost(); - s().get_model(m_model); - } - expr_ref fml = wth().mk_block(); - s().assert_expr(fml); - was_sat = true; - } - } - if (was_sat) { - wth().get_assignment(m_assignment); - } - if (is_sat == l_false && was_sat) { - is_sat = l_true; - } - m_upper = wth().get_min_cost(); - if (is_sat == l_true) { - m_lower = m_upper; - } - TRACE("opt", tout << "min cost: " << m_upper << "\n";); - return is_sat; - } - }; - - - maxsmt_solver_base* opt::mk_bcd2(ast_manager& m, opt_solver* s, params_ref& p, - vector const& ws, expr_ref_vector const& soft) { - return alloc(bcd2, s, m, p, ws, soft); - } - maxsmt_solver_base* opt::mk_pbmax(ast_manager& m, opt_solver* s, params_ref& p, - vector const& ws, expr_ref_vector const& soft) { - return alloc(pbmax, s, m, p, ws, soft); - } - maxsmt_solver_base* opt::mk_hsmax(ast_manager& m, opt_solver* s, params_ref& p, - vector const& ws, expr_ref_vector const& soft) { - return alloc(hsmax, s, m, p, ws, soft); - } - maxsmt_solver_base* opt::mk_sls(ast_manager& m, opt_solver* s, params_ref& p, - vector const& ws, expr_ref_vector const& soft) { - return alloc(hsmax, s, m, p, ws, soft); - } - maxsmt_solver_base* opt::mk_wmax(ast_manager& m, opt_solver* s, params_ref& p, - vector const& ws, expr_ref_vector const& soft) { - return alloc(wmax, s, m, s->get_context(), p, ws, soft); - } - maxsmt_solver_base* opt::mk_wpm2(ast_manager& m, opt_solver* s, params_ref& p, - vector const& ws, expr_ref_vector const& soft) { - - ref s0 = alloc(opt_solver, m, p, symbol()); - // initialize model. - s0->check_sat(0,0); - maxsmt_solver_base* s2 = alloc(pbmax, s0.get(), m, p, ws, soft); - return alloc(wpm2, s, m, s2, p, ws, soft); - } - - -}; diff --git a/src/opt/weighted_maxsat.h b/src/opt/weighted_maxsat.h deleted file mode 100644 index 5343a3b97..000000000 --- a/src/opt/weighted_maxsat.h +++ /dev/null @@ -1,51 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - weighted_maxsat.h - -Abstract: - - Weighted MAXSAT module - -Author: - - Nikolaj Bjorner (nbjorner) 2014-4-17 - -Notes: - - Takes solver with hard constraints added. - Returns a maximal satisfying subset of weighted soft_constraints - that are still consistent with the solver state. - ---*/ -#ifndef _OPT_WEIGHTED_MAX_SAT_H_ -#define _OPT_WEIGHTED_MAX_SAT_H_ - -#include "opt_solver.h" -#include "maxsmt.h" - -namespace opt { - - maxsmt_solver_base* mk_bcd2(ast_manager& m, opt_solver* s, params_ref& p, - vector const& ws, expr_ref_vector const& soft); - - maxsmt_solver_base* mk_hsmax(ast_manager& m, opt_solver* s, params_ref& p, - vector const& ws, expr_ref_vector const& soft); - - maxsmt_solver_base* mk_pbmax(ast_manager& m, opt_solver* s, params_ref& p, - vector const& ws, expr_ref_vector const& soft); - - maxsmt_solver_base* mk_wpm2(ast_manager& m, opt_solver* s, params_ref& p, - vector const& ws, expr_ref_vector const& soft); - - maxsmt_solver_base* mk_sls(ast_manager& m, opt_solver* s, params_ref& p, - vector const& ws, expr_ref_vector const& soft); - - maxsmt_solver_base* mk_wmax(ast_manager& m, opt_solver* s, params_ref& p, - vector const& ws, expr_ref_vector const& soft); - -}; - -#endif diff --git a/src/opt/wmax.cpp b/src/opt/wmax.cpp new file mode 100644 index 000000000..8c76b06ba --- /dev/null +++ b/src/opt/wmax.cpp @@ -0,0 +1,130 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + wmax.cpp + +Abstract: + + Theory based MaxSAT. + +Author: + + Nikolaj Bjorner (nbjorner) 2014-4-17 + +Notes: + +--*/ +#include "wmax.h" +#include "uint_set.h" +#include "ast_pp.h" +#include "model_smt2_pp.h" +#include "smt_theory.h" +#include "smt_context.h" +#include "theory_wmaxsat.h" + + +namespace opt { + class maxsmt_solver_wbase : public maxsmt_solver_base { + smt::context& ctx; + public: + maxsmt_solver_wbase(opt_solver* s, ast_manager& m, smt::context& ctx, params_ref& p, + vector const& ws, expr_ref_vector const& soft): + maxsmt_solver_base(s, m, p, ws, soft), ctx(ctx) {} + ~maxsmt_solver_wbase() {} + + class scoped_ensure_theory { + smt::theory_wmaxsat* m_wth; + public: + scoped_ensure_theory(maxsmt_solver_wbase& s) { + m_wth = s.ensure_theory(); + } + ~scoped_ensure_theory() { + m_wth->reset(); + } + smt::theory_wmaxsat& operator()() { return *m_wth; } + }; + + smt::theory_wmaxsat* ensure_theory() { + smt::theory_wmaxsat* wth = get_theory(); + if (wth) { + wth->reset(); + } + else { + wth = alloc(smt::theory_wmaxsat, m, m_mc); + ctx.register_plugin(wth); + } + return wth; + } + smt::theory_wmaxsat* get_theory() const { + smt::theory_id th_id = m.get_family_id("weighted_maxsat"); + smt::theory* th = ctx.get_theory(th_id); + if (th) { + return dynamic_cast(th); + } + else { + return 0; + } + } + }; + + // ---------------------------------------------------------- + // weighted max-sat using a custom theory solver for max-sat. + // NB. it is quite similar to pseudo-Boolean propagation. + + + class wmax : public maxsmt_solver_wbase { + public: + wmax(opt_solver* s, ast_manager& m, smt::context& ctx, params_ref& p, + vector const& ws, expr_ref_vector const& soft): + maxsmt_solver_wbase(s, m, ctx, p, ws, soft) {} + virtual ~wmax() {} + + lbool operator()() { + TRACE("opt", tout << "weighted maxsat\n";); + scoped_ensure_theory wth(*this); + solver::scoped_push _s(s()); + lbool is_sat = l_true; + bool was_sat = false; + for (unsigned i = 0; i < m_soft.size(); ++i) { + wth().assert_weighted(m_soft[i].get(), m_weights[i]); + } + solver::scoped_push __s(s()); + while (l_true == is_sat) { + IF_VERBOSE(1, verbose_stream() << "(opt.wmax [" << m_lower << ":" << m_upper << "])\n";); + is_sat = s().check_sat(0,0); + if (m_cancel) { + is_sat = l_undef; + } + if (is_sat == l_true) { + if (wth().is_optimal()) { + m_upper = wth().get_min_cost(); + s().get_model(m_model); + } + expr_ref fml = wth().mk_block(); + s().assert_expr(fml); + was_sat = true; + } + } + if (was_sat) { + wth().get_assignment(m_assignment); + } + if (is_sat == l_false && was_sat) { + is_sat = l_true; + } + m_upper = wth().get_min_cost(); + if (is_sat == l_true) { + m_lower = m_upper; + } + TRACE("opt", tout << "min cost: " << m_upper << "\n";); + return is_sat; + } + }; + + maxsmt_solver_base* opt::mk_wmax(ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft) { + return alloc(wmax, s, m, s->get_context(), p, ws, soft); + } + +} diff --git a/src/opt/wmax.h b/src/opt/wmax.h new file mode 100644 index 000000000..bc33eee4a --- /dev/null +++ b/src/opt/wmax.h @@ -0,0 +1,30 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + wmax.h + +Abstract: + + Theory Solver based MaxSAT. + +Author: + + Nikolaj Bjorner (nbjorner) 2014-4-17 + +Notes: + +--*/ + +#ifndef _WMAX_H_ +#define _WMAX_H_ + +#include "maxsmt.h" + +namespace opt { + maxsmt_solver_base* mk_wmax(ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft); + +} +#endif diff --git a/src/opt/wpm2.cpp b/src/opt/wpm2.cpp new file mode 100644 index 000000000..63418861a --- /dev/null +++ b/src/opt/wpm2.cpp @@ -0,0 +1,251 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + wpm2.cpp + +Abstract: + + wpn2 based MaxSAT. + +Author: + + Nikolaj Bjorner (nbjorner) 2014-4-17 + +Notes: + +--*/ +#include "wpm2.h" +#include "pbmax.h" +#include "pb_decl_plugin.h" +#include "uint_set.h" +#include "ast_pp.h" +#include "model_smt2_pp.h" + + +namespace opt { + + // ------------------------------------------------------ + // AAAI 2010 + class wpm2 : public maxsmt_solver_base { + scoped_ptr maxs; + public: + wpm2(opt_solver* s, ast_manager& m, maxsmt_solver_base* _maxs, params_ref& p, + vector const& ws, expr_ref_vector const& soft): + maxsmt_solver_base(s, m, p, ws, soft), maxs(_maxs) { + } + + virtual ~wpm2() {} + + lbool operator()() { + enable_sls(); + IF_VERBOSE(1, verbose_stream() << "(opt.wpm2)\n";); + solver::scoped_push _s(s()); + pb_util u(m); + app_ref fml(m), a(m), b(m), c(m); + expr_ref val(m); + expr_ref_vector block(m), ans(m), al(m), am(m); + obj_map ans_index; + vector amk; + vector sc; + init(); + for (unsigned i = 0; i < m_soft.size(); ++i) { + rational w = m_weights[i]; + + b = mk_fresh_bool("b"); + block.push_back(b); + expr* bb = b; + + a = mk_fresh_bool("a"); + ans.push_back(a); + ans_index.insert(a, i); + fml = m.mk_or(m_soft[i].get(), b, m.mk_not(a)); + s().assert_expr(fml); + + c = mk_fresh_bool("c"); + fml = m.mk_implies(c, u.mk_le(1,&w,&bb,rational(0))); + s().assert_expr(fml); + + sc.push_back(uint_set()); + sc.back().insert(i); + am.push_back(c); + amk.push_back(rational(0)); + } + + while (true) { + expr_ref_vector asms(m); + ptr_vector core; + asms.append(ans); + asms.append(am); + lbool is_sat = s().check_sat(asms.size(), asms.c_ptr()); + TRACE("opt", + tout << "\nassumptions: "; + for (unsigned i = 0; i < asms.size(); ++i) { + tout << mk_pp(asms[i].get(), m) << " "; + } + tout << "\n" << is_sat << "\n"; + tout << "upper: " << m_upper << "\n"; + tout << "lower: " << m_lower << "\n"; + if (is_sat == l_true) { + model_ref mdl; + s().get_model(mdl); + model_smt2_pp(tout, m, *(mdl.get()), 0); + }); + + if (m_cancel && is_sat != l_false) { + is_sat = l_undef; + } + if (is_sat == l_true) { + m_upper = m_lower; + s().get_model(m_model); + for (unsigned i = 0; i < block.size(); ++i) { + VERIFY(m_model->eval(m_soft[i].get(), val)); + TRACE("opt", tout << mk_pp(block[i].get(), m) << " " << val << "\n";); + m_assignment[i] = m.is_true(val); + } + } + if (is_sat != l_false) { + return is_sat; + } + s().get_unsat_core(core); + if (core.empty()) { + return l_false; + } + TRACE("opt", + tout << "core: "; + for (unsigned i = 0; i < core.size(); ++i) { + tout << mk_pp(core[i],m) << " "; + } + tout << "\n";); + uint_set A; + for (unsigned i = 0; i < core.size(); ++i) { + unsigned j; + if (ans_index.find(core[i], j)) { + A.insert(j); + } + } + if (A.empty()) { + return l_false; + } + uint_set B; + rational k(0); + rational old_lower(m_lower); + for (unsigned i = 0; i < sc.size(); ++i) { + uint_set t(sc[i]); + t &= A; + if (!t.empty()) { + B |= sc[i]; + k += amk[i]; + m_lower -= amk[i]; + sc[i] = sc.back(); + sc.pop_back(); + am[i] = am.back(); + am.pop_back(); + amk[i] = amk.back(); + amk.pop_back(); + --i; + } + } + vector ws; + expr_ref_vector bs(m); + for (unsigned i = 0; i < m_soft.size(); ++i) { + if (B.contains(i)) { + ws.push_back(m_weights[i]); + bs.push_back(block[i].get()); + } + } + TRACE("opt", tout << "at most bound: " << k << "\n";); + is_sat = new_bound(al, ws, bs, k); + if (is_sat != l_true) { + return is_sat; + } + m_lower += k; + SASSERT(m_lower > old_lower); + TRACE("opt", tout << "new bound: " << m_lower << "\n";); + expr_ref B_le_k(m), B_ge_k(m); + B_le_k = u.mk_le(ws.size(), ws.c_ptr(), bs.c_ptr(), k); + B_ge_k = u.mk_ge(ws.size(), ws.c_ptr(), bs.c_ptr(), k); + s().assert_expr(B_ge_k); + al.push_back(B_ge_k); + IF_VERBOSE(1, verbose_stream() << "(opt.wpm2 [" << m_lower << ":" << m_upper << "])\n";); + IF_VERBOSE(2, verbose_stream() << "New lower bound: " << B_ge_k << "\n";); + + c = mk_fresh_bool("c"); + fml = m.mk_implies(c, B_le_k); + s().assert_expr(fml); + sc.push_back(B); + am.push_back(c); + amk.push_back(k); + } + } + + virtual void set_cancel(bool f) { + maxsmt_solver_base::set_cancel(f); + maxs->set_cancel(f); + } + + virtual void collect_statistics(statistics& st) const { + maxsmt_solver_base::collect_statistics(st); + maxs->collect_statistics(st); + } + + private: + lbool new_bound(expr_ref_vector const& al, + vector const& ws, + expr_ref_vector const& bs, + rational& k) { + pb_util u(m); + expr_ref_vector al2(m); + al2.append(al); + // w_j*b_j > k + al2.push_back(m.mk_not(u.mk_le(ws.size(), ws.c_ptr(), bs.c_ptr(), k))); + return bound(al2, ws, bs, k); + } + + // + // minimal k, such that al & w_j*b_j >= k is sat + // minimal k, such that al & 3*x + 4*y >= k is sat + // minimal k, such that al & (or (not x) w3) & (or (not y) w4) + // + lbool bound(expr_ref_vector const& al, + vector const& ws, + expr_ref_vector const& bs, + rational& k) { + expr_ref_vector nbs(m); + opt_solver::scoped_push _sc(maxs->s()); + for (unsigned i = 0; i < al.size(); ++i) { + maxs->add_hard(al[i]); + } + for (unsigned i = 0; i < bs.size(); ++i) { + nbs.push_back(mk_not(bs[i])); + } + TRACE("opt", + maxs->s().display(tout); + tout << "\n"; + for (unsigned i = 0; i < bs.size(); ++i) { + tout << mk_pp(bs[i], m) << " " << ws[i] << "\n"; + }); + maxs->init_soft(ws, nbs); + lbool is_sat = maxs->s().check_sat(0,0); + if (is_sat == l_true) { + maxs->set_model(); + is_sat = (*maxs)(); + } + SASSERT(maxs->get_lower() > k); + k = maxs->get_lower(); + return is_sat; + } + }; + + maxsmt_solver_base* opt::mk_wpm2(ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft) { + + ref s0 = alloc(opt_solver, m, p, symbol()); + // initialize model. + s0->check_sat(0,0); + maxsmt_solver_base* s2 = mk_pbmax(m, s0.get(), p, ws, soft); + return alloc(wpm2, s, m, s2, p, ws, soft); + } + +} diff --git a/src/opt/wpm2.h b/src/opt/wpm2.h new file mode 100644 index 000000000..efaddc602 --- /dev/null +++ b/src/opt/wpm2.h @@ -0,0 +1,29 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + wpm2.h + +Abstract: + + Wpm2 based MaxSAT. + +Author: + + Nikolaj Bjorner (nbjorner) 2014-4-17 + +Notes: + +--*/ + +#ifndef _WPM2_H_ +#define _WPM2_H_ + +#include "maxsmt.h" + +namespace opt { + maxsmt_solver_base* mk_wpm2(ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft); +} +#endif diff --git a/src/smt/theory_wmaxsat.cpp b/src/smt/theory_wmaxsat.cpp index 2c33d28da..353ff38a3 100644 --- a/src/smt/theory_wmaxsat.cpp +++ b/src/smt/theory_wmaxsat.cpp @@ -216,7 +216,6 @@ expr_ref theory_wmaxsat::mk_block() { scoped_mpq q(mgr); mgr.set(q, m_zmin_cost, m_den.to_mpq().numerator()); rational rw = rational(q); - IF_VERBOSE(1, verbose_stream() << "(wmaxsat with upper bound: " << rw << ")\n";); m_zmin_cost = weight; m_found_optimal = true; m_cost_save.reset(); From 0c750bc714888b58d9337fe2cb6aa10b9fccb4c4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 28 Jul 2014 12:19:46 -0700 Subject: [PATCH 433/925] update sat solver signature Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 4 ++-- src/sat/sat_solver.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 0e9f50828..9cd6f6add 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -685,8 +685,8 @@ namespace sat { // Search // // ----------------------- - lbool solver::check() { - IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver using the new SAT solver)\n";); + lbool solver::check(unsigned num_lits, literal const* lits) { + IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver using the efficient SAT solver)\n";); SASSERT(scope_lvl() == 0); #ifdef CLONE_BEFORE_SOLVING if (m_mc.empty()) { diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index b18bae06a..9cd62a47f 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -250,7 +250,7 @@ namespace sat { // // ----------------------- public: - lbool check(); + lbool check(unsigned num_lits = 0, literal const* lits = 0); model const & get_model() const { return m_model; } model_converter const & get_model_converter() const { return m_mc; } From e98acf4ece7768aa3dd9b3c65a0989545e0055c0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 29 Jul 2014 07:22:59 -0700 Subject: [PATCH 434/925] working on adding basic cores to efficient SAT solver Signed-off-by: Nikolaj Bjorner --- src/muz/pdr/pdr_smt_context_manager.h | 1 - src/sat/sat_params.pyg | 3 +- src/sat/sat_solver.cpp | 95 ++++++++++++++++++++++----- src/sat/sat_solver.h | 15 ++++- src/sat/tactic/atom2bool_var.cpp | 3 +- src/sat/tactic/goal2sat.cpp | 30 ++++++++- src/sat/tactic/sat_tactic.cpp | 2 +- src/shell/dimacs_frontend.cpp | 84 ++++++++++++++++++++++- 8 files changed, 203 insertions(+), 30 deletions(-) diff --git a/src/muz/pdr/pdr_smt_context_manager.h b/src/muz/pdr/pdr_smt_context_manager.h index ea8947ea1..625428042 100644 --- a/src/muz/pdr/pdr_smt_context_manager.h +++ b/src/muz/pdr/pdr_smt_context_manager.h @@ -21,7 +21,6 @@ Revision History: #define _PDR_SMT_CONTEXT_MANAGER_H_ #include "smt_kernel.h" -#include "sat_solver.h" #include "func_decl_dependencies.h" #include "dl_util.h" diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 71579b86a..570ca5276 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -17,4 +17,5 @@ def_module_params('sat', ('gc.small_lbd', UINT, 3, 'learned clauses with small LBD are never deleted (only used in dyn_psm)'), ('gc.k', UINT, 7, 'learned clauses that are inactive for k gc rounds are permanently deleted (only used in dyn_psm)'), ('minimize_lemmas', BOOL, True, 'minimize learned clauses'), - ('dyn_sub_res', BOOL, True, 'dynamic subsumption resolution for minimizing learned clauses'))) + ('dyn_sub_res', BOOL, True, 'dynamic subsumption resolution for minimizing learned clauses'), + ('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'))) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 0e9f50828..4624432f2 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -685,8 +685,8 @@ namespace sat { // Search // // ----------------------- - lbool solver::check() { - IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver using the new SAT solver)\n";); + lbool solver::check(unsigned num_lits, literal const* lits) { + IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver using the efficient SAT solver)\n";); SASSERT(scope_lvl() == 0); #ifdef CLONE_BEFORE_SOLVING if (m_mc.empty()) { @@ -697,6 +697,7 @@ namespace sat { try { if (inconsistent()) return l_false; init_search(); + init_assumptions(num_lits, lits); propagate(false); if (inconsistent()) return l_false; cleanup(); @@ -706,6 +707,7 @@ namespace sat { if (r != l_undef) return r; pop(scope_lvl()); + reinit_assumptions(); m_conflicts_since_restart = 0; m_restart_threshold = m_config.m_restart_initial; } @@ -851,6 +853,40 @@ namespace sat { } } + void solver::init_assumptions(unsigned num_lits, literal const* lits) { + if (num_lits == 0) { + return; + } + push(); + m_assumptions.reset(); + m_assumption_set.reset(); + for (unsigned i = 0; i < num_lits; ++i) { + literal l = lits[i]; + SASSERT(is_external(l.var())); + m_assumption_set.insert(l); + m_assumptions.push_back(l); + mk_clause(1, &l); + } + } + + void solver::reinit_assumptions() { + if (tracking_assumptions()) { + push(); + for (unsigned i = 0; i < m_assumptions.size(); ++i) { + literal l = m_assumptions[i]; + mk_clause(1, &l); + } + } + } + + bool solver::tracking_assumptions() const { + return !m_assumptions.empty(); + } + + bool solver::is_assumption(literal l) const { + return tracking_assumptions() && m_assumption_set.contains(l); + } + void solver::init_search() { m_phase_counter = 0; m_phase_cache_on = false; @@ -986,6 +1022,7 @@ namespace sat { << " :time " << std::fixed << std::setprecision(2) << m_stopwatch.get_current_seconds() << ")\n";); IF_VERBOSE(30, display_status(verbose_stream());); pop(scope_lvl()); + reinit_assumptions(); m_conflicts_since_restart = 0; switch (m_config.m_restart) { case RS_GEOMETRIC: @@ -1305,7 +1342,7 @@ namespace sat { bool solver::resolve_conflict() { while (true) { - bool r = resolve_conflict_core(); + bool r = resolve_conflict_core(false); CASSERT("sat_check_marks", check_marks()); // after pop, clauses are reinitialized, this may trigger another conflict. if (!r) @@ -1315,7 +1352,7 @@ namespace sat { } } - bool solver::resolve_conflict_core() { + bool solver::resolve_conflict_core(bool generate_core) { TRACE("sat_conflict", tout << "conflict detected\n";); m_stats.m_conflict++; @@ -1324,8 +1361,21 @@ namespace sat { m_conflicts_since_gc++; m_conflict_lvl = get_max_lvl(m_not_l, m_conflict); - if (m_conflict_lvl == 0) + if (!generate_core && m_conflict_lvl <= 1 && tracking_assumptions()) { + resolve_conflict_core(true); + m_core.reset(); + for (unsigned i = 0; i < m_lemma.size(); ++i) { + literal l = ~m_lemma[i]; + if (is_assumption(l)) { + m_core.push_back(l); + } + } return false; + } + if (m_conflict_lvl == 0) { + return false; + } + m_lemma.reset(); forget_phase_of_vars(m_conflict_lvl); @@ -1337,7 +1387,7 @@ namespace sat { unsigned num_marks = 0; if (m_not_l != null_literal) { TRACE("sat_conflict", tout << "not_l: " << m_not_l << "\n";); - process_antecedent(m_not_l, num_marks); + process_antecedent(generate_core, m_not_l, num_marks); } literal consequent = m_not_l; @@ -1350,11 +1400,11 @@ namespace sat { case justification::NONE: break; case justification::BINARY: - process_antecedent(~(js.get_literal()), num_marks); + process_antecedent(generate_core, ~(js.get_literal()), num_marks); break; case justification::TERNARY: - process_antecedent(~(js.get_literal1()), num_marks); - process_antecedent(~(js.get_literal2()), num_marks); + process_antecedent(generate_core, ~(js.get_literal1()), num_marks); + process_antecedent(generate_core, ~(js.get_literal2()), num_marks); break; case justification::CLAUSE: { clause & c = *(m_cls_allocator.get_clause(js.get_clause_offset())); @@ -1365,13 +1415,13 @@ namespace sat { i = 1; } else { - process_antecedent(~c[0], num_marks); + process_antecedent(generate_core, ~c[0], num_marks); i = 2; } } unsigned sz = c.size(); for (; i < sz; i++) - process_antecedent(~c[i], num_marks); + process_antecedent(generate_core, ~c[i], num_marks); break; } case justification::EXT_JUSTIFICATION: { @@ -1379,7 +1429,7 @@ namespace sat { literal_vector::iterator it = m_ext_antecedents.begin(); literal_vector::iterator end = m_ext_antecedents.end(); for (; it != end; ++it) - process_antecedent(*it, num_marks); + process_antecedent(generate_core, *it, num_marks); break; } default: @@ -1408,7 +1458,7 @@ namespace sat { m_lemma[0] = ~consequent; TRACE("sat_lemma", tout << "new lemma size: " << m_lemma.size() << "\n" << m_lemma << "\n";); - if (m_config.m_minimize_lemmas) { + if (m_config.m_minimize_lemmas && !generate_core) { minimize_lemma(); reset_lemma_var_marks(); if (m_config.m_dyn_sub_res) @@ -1431,15 +1481,24 @@ namespace sat { pop(m_scope_lvl - new_scope_lvl); TRACE("sat_conflict_detail", display(tout); tout << "assignment:\n"; display_assignment(tout);); - clause * lemma = mk_clause_core(m_lemma.size(), m_lemma.c_ptr(), true); - if (lemma) { - lemma->set_glue(glue); + if (!generate_core) { + clause * lemma = mk_clause_core(m_lemma.size(), m_lemma.c_ptr(), true); + if (lemma) { + lemma->set_glue(glue); + } } decay_activity(); updt_phase_counters(); return true; } + void solver::mk_unsat_core() { + m_core.reset(); + m_not_l; + m_conflict; + + } + unsigned solver::get_max_lvl(literal consequent, justification js) { if (!m_ext) return scope_lvl(); @@ -1514,14 +1573,14 @@ namespace sat { return idx; } - void solver::process_antecedent(literal antecedent, unsigned & num_marks) { + void solver::process_antecedent(bool generate_core, literal antecedent, unsigned & num_marks) { bool_var var = antecedent.var(); unsigned var_lvl = lvl(var); SASSERT(var < num_vars()); if (!is_marked(var) && var_lvl > 0) { mark(var); inc_activity(var); - if (var_lvl == m_conflict_lvl) + if (var_lvl == m_conflict_lvl && !generate_core) num_marks++; else m_lemma.push_back(~antecedent); diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index b18bae06a..7d0e6b92d 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -118,6 +118,9 @@ namespace sat { stopwatch m_stopwatch; params_ref m_params; scoped_ptr m_clone; // for debugging purposes + literal_vector m_assumptions; + literal_set m_assumption_set; + literal_vector m_core; void del_clauses(clause * const * begin, clause * const * end); @@ -250,8 +253,9 @@ namespace sat { // // ----------------------- public: - lbool check(); + lbool check(unsigned num_lits = 0, literal const* lits = 0); model const & get_model() const { return m_model; } + literal_vector const& get_core() const { return m_core; } model_converter const & get_model_converter() const { return m_mc; } protected: @@ -267,6 +271,11 @@ namespace sat { bool_var next_var(); lbool bounded_search(); void init_search(); + void init_assumptions(unsigned num_lits, literal const* lits); + void reinit_assumptions(); + bool tracking_assumptions() const; + bool is_assumption(literal l) const; + void mk_unsat_core(); void simplify_problem(); void mk_model(); bool check_model(model const & m) const; @@ -311,9 +320,9 @@ namespace sat { literal_vector m_lemma; literal_vector m_ext_antecedents; bool resolve_conflict(); - bool resolve_conflict_core(); + bool resolve_conflict_core(bool generate_core); unsigned get_max_lvl(literal consequent, justification js); - void process_antecedent(literal antecedent, unsigned & num_marks); + void process_antecedent(bool generate_coe, literal antecedent, unsigned & num_marks); void fill_ext_antecedents(literal consequent, justification js); unsigned skip_literals_above_conflict_level(); void forget_phase_of_vars(unsigned from_lvl); diff --git a/src/sat/tactic/atom2bool_var.cpp b/src/sat/tactic/atom2bool_var.cpp index 935eeb28e..2df744138 100644 --- a/src/sat/tactic/atom2bool_var.cpp +++ b/src/sat/tactic/atom2bool_var.cpp @@ -90,8 +90,9 @@ struct collect_boolean_interface_proc { template void operator()(T const & g) { unsigned sz = g.size(); - for (unsigned i = 0; i < sz; i++) + for (unsigned i = 0; i < sz; i++) { process(g.form(i)); + } } void operator()(unsigned sz, expr * const * fs) { diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 16184e2bc..bd3f38d3b 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -360,14 +360,40 @@ struct goal2sat::imp { SASSERT(m_result_stack.empty()); } + void add_assumption(expr* d, expr* literal_d) { + + } + void operator()(goal const & g) { m_interface_vars.reset(); collect_boolean_interface(g, m_interface_vars); - unsigned size = g.size(); + expr_ref f(m), d_new(m); + ptr_vector deps; for (unsigned idx = 0; idx < size; idx++) { - expr * f = g.form(idx); + f = g.form(idx); + // Add assumptions. + if (g.dep(idx)) { + expr_dependency * dep = g.dep(idx); + deps.reset(); + m.linearize(dep, deps); + for (unsigned i = 0; i < deps.size(); ++i) { + expr * d = deps[i]; + expr * d1; + SASSERT(m.is_bool(d)); + if (is_uninterp_const(d)) { + add_assumption(d, d); + } + else if (m.is_not(d, d1) && is_uninterp_const(d1)) { + add_assumption(d, d); + } + else { + // create fresh variable, map back to dependency. + add_assumption(d, d_new); + } + } + } process(f); } } diff --git a/src/sat/tactic/sat_tactic.cpp b/src/sat/tactic/sat_tactic.cpp index 677540991..c7e2ae608 100644 --- a/src/sat/tactic/sat_tactic.cpp +++ b/src/sat/tactic/sat_tactic.cpp @@ -46,8 +46,8 @@ class sat_tactic : public tactic { expr_dependency_ref & core) { mc = 0; pc = 0; core = 0; fail_if_proof_generation("sat", g); - fail_if_unsat_core_generation("sat", g); bool produce_models = g->models_enabled(); + bool produce_core = g->unsat_core_enabled(); TRACE("before_sat_solver", g->display(tout);); g->elim_redundancies(); diff --git a/src/shell/dimacs_frontend.cpp b/src/shell/dimacs_frontend.cpp index 0acd222dd..38b318d2f 100644 --- a/src/shell/dimacs_frontend.cpp +++ b/src/shell/dimacs_frontend.cpp @@ -22,6 +22,7 @@ Revision History: #include"timeout.h" #include"dimacs.h" #include"sat_solver.h" +#include"gparams.h" extern bool g_display_statistics; static sat::solver * g_solver = 0; @@ -63,11 +64,73 @@ static void display_model(sat::solver const & s) { std::cout << "\n"; } +static void display_core(sat::solver const& s, vector const& tracking_clauses) { + std::cout << "core\n"; + sat::literal_vector const& c = s.get_core(); + for (unsigned i = 0; i < c.size(); ++i) { + sat::literal_vector const& cls = tracking_clauses[c[i].var()]; + for (unsigned j = 0; j < cls.size(); ++j) { + std::cout << cls[j] << " "; + } + std::cout << "\n"; + } +} + +static void track_clause(sat::solver& dst, + sat::literal_vector& lits, + sat::literal_vector& assumptions, + vector& tracking_clauses) { + sat::literal lit = sat::literal(dst.mk_var(true, false), false); + tracking_clauses.set(lit.var(), lits); + lits.push_back(~lit); + dst.mk_clause(lits.size(), lits.c_ptr()); + assumptions.push_back(lit); +} + + +static void track_clauses(sat::solver const& src, + sat::solver& dst, + sat::literal_vector& assumptions, + vector& tracking_clauses) { + for (sat::bool_var v = 0; v < src.num_vars(); ++v) { + dst.mk_var(false, true); + } + sat::literal_vector lits; + sat::literal lit; + sat::clause * const * it = src.begin_clauses(); + sat::clause * const * end = src.end_clauses(); + svector bin_clauses; + src.collect_bin_clauses(bin_clauses, false); + tracking_clauses.reserve(2*src.num_vars() + (end - it) + bin_clauses.size()); + + for (sat::bool_var v = 1; v < src.num_vars(); ++v) { + if (src.value(v) != l_undef) { + bool sign = src.value(v) == l_false; + lits.reset(); + lits.push_back(sat::literal(v, sign)); + track_clause(dst, lits, assumptions, tracking_clauses); + } + } + for (; it != end; ++it) { + lits.reset(); + sat::clause& cls = *(*it); + lits.append(cls.end()-cls.begin(), cls.begin()); + track_clause(dst, lits, assumptions, tracking_clauses); + } + for (unsigned i = 0; i < bin_clauses.size(); ++i) { + lits.reset(); + lits.push_back(bin_clauses[i].first); + lits.push_back(bin_clauses[i].second); + track_clause(dst, lits, assumptions, tracking_clauses); + } +} + + unsigned read_dimacs(char const * file_name) { g_start_time = clock(); register_on_timeout_proc(on_timeout); signal(SIGINT, on_ctrl_c); - params_ref p; + params_ref p = gparams::get_module("sat"); p.set_bool("produce_models", true); sat::solver solver(p, 0); g_solver = &solver; @@ -85,17 +148,32 @@ unsigned read_dimacs(char const * file_name) { } IF_VERBOSE(20, solver.display_status(verbose_stream());); - lbool r = solver.check(); + lbool r; + vector tracking_clauses; + sat::solver solver2(p, 0); + if (p.get_bool("dimacs.core", false)) { + g_solver = &solver2; + sat::literal_vector assumptions; + track_clauses(solver, solver2, assumptions, tracking_clauses); + solver2.display(std::cout); + r = g_solver->check(assumptions.size(), assumptions.c_ptr()); + } + else { + r = g_solver->check(); + } switch (r) { case l_true: std::cout << "sat\n"; - display_model(solver); + display_model(*g_solver); break; case l_undef: std::cout << "unknown\n"; break; case l_false: std::cout << "unsat\n"; + if (p.get_bool("dimacs.core", false)) { + display_core(*g_solver, tracking_clauses); + } break; } if (g_display_statistics) From 66f626b50ec1d3125b5419b11b7ab311b4049136 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 29 Jul 2014 07:41:08 -0700 Subject: [PATCH 435/925] local changes Signed-off-by: Nikolaj Bjorner --- src/muz/pdr/pdr_smt_context_manager.h | 1 - src/sat/sat_solver.cpp | 26 +++++++++++++++++++++++++- src/sat/sat_solver.h | 5 +++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/muz/pdr/pdr_smt_context_manager.h b/src/muz/pdr/pdr_smt_context_manager.h index ea8947ea1..625428042 100644 --- a/src/muz/pdr/pdr_smt_context_manager.h +++ b/src/muz/pdr/pdr_smt_context_manager.h @@ -21,7 +21,6 @@ Revision History: #define _PDR_SMT_CONTEXT_MANAGER_H_ #include "smt_kernel.h" -#include "sat_solver.h" #include "func_decl_dependencies.h" #include "dl_util.h" diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 9cd6f6add..679762a2f 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -697,6 +697,7 @@ namespace sat { try { if (inconsistent()) return l_false; init_search(); + init_assumptons(num_lits, lits); propagate(false); if (inconsistent()) return l_false; cleanup(); @@ -851,6 +852,29 @@ namespace sat { } } + void solver::init_assumptions(unsigned num_lits, literal const* lits) { + if (num_lits == 0) { + return; + } + push(); + m_assumptions.reset(); + m_assumption_set.reset(); + for (unsigned i = 0; i < num_lits; ++i) { + literal l = lits[i]; + m_assumption_set.insert(l); + m_assumptions.push_back(l); + mk_clause(1, &l); + } + } + + bool solver::tracking_assumptions() const { + return !m_assumptions.empty(); + } + + bool solver::is_assumption(literal l) const { + return tracking_assumptions() && m_assumption_set.contains(l); + } + void solver::init_search() { m_phase_counter = 0; m_phase_cache_on = false; @@ -1936,7 +1960,7 @@ namespace sat { clause_wrapper cw = m_clauses_to_reinit[i]; bool reinit = false; if (cw.is_binary()) { - if (propagate_bin_clause(cw[0], cw[1])) { +o if (propagate_bin_clause(cw[0], cw[1])) { if (scope_lvl() > 0) { m_clauses_to_reinit[j] = cw; j++; diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 9cd62a47f..9605e5c70 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -118,6 +118,8 @@ namespace sat { stopwatch m_stopwatch; params_ref m_params; scoped_ptr m_clone; // for debugging purposes + literal_vector m_assumptions; + literal_set m_assumption_set; void del_clauses(clause * const * begin, clause * const * end); @@ -267,6 +269,9 @@ namespace sat { bool_var next_var(); lbool bounded_search(); void init_search(); + void init_assumptions(unsigned num_lits, literal const* lits); + bool tracking_assumptions() const; + bool is_assumption(literal l) const; void simplify_problem(); void mk_model(); bool check_model(model const & m) const; From 2b1af8fd503fa510cd2f2f1578cba3d3c60bf7c1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 29 Jul 2014 14:38:17 -0700 Subject: [PATCH 436/925] updated sat solver for cores Signed-off-by: Nikolaj Bjorner --- src/opt/inc_sat_solver.cpp | 3 +- src/sat/sat_solver.cpp | 8 +++-- src/sat/tactic/atom2bool_var.cpp | 9 +++++ src/sat/tactic/goal2sat.cpp | 53 +++++++++++++++++++--------- src/sat/tactic/goal2sat.h | 4 ++- src/sat/tactic/sat_tactic.cpp | 37 ++++++++++++++++--- src/shell/dimacs_frontend.cpp | 1 - src/tactic/probe.cpp | 1 - src/tactic/smtlogics/qfbv_tactic.cpp | 4 +-- 9 files changed, 92 insertions(+), 28 deletions(-) diff --git a/src/opt/inc_sat_solver.cpp b/src/opt/inc_sat_solver.cpp index afd7ae905..5f121726a 100644 --- a/src/opt/inc_sat_solver.cpp +++ b/src/opt/inc_sat_solver.cpp @@ -62,6 +62,7 @@ public: proof_converter_ref pc; model_converter_ref mc; expr_dependency_ref core(m); + obj_map dep2asm; if (!m_fmls.empty()) { goal_ref g = alloc(goal, m); @@ -86,7 +87,7 @@ public: } g = result[0]; TRACE("opt", g->display(tout);); - m_goal2sat(*g, m_params, m_solver, m_map); + m_goal2sat(*g, m_params, m_solver, m_map, dep2asm); } lbool r = m_solver.check(); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 8e8ab3e71..c357f7a29 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -699,7 +699,11 @@ namespace sat { init_search(); init_assumptions(num_lits, lits); propagate(false); - if (inconsistent()) return l_false; + if (inconsistent()) { + if (tracking_assumptions()) + resolve_conflict(); + return l_false; + } cleanup(); if (m_config.m_max_conflicts > 0 && m_config.m_burst_search > 0) { m_restart_threshold = m_config.m_burst_search; @@ -867,6 +871,7 @@ namespace sat { m_assumptions.push_back(l); mk_clause(1, &l); } + TRACE("sat", display(tout);); } void solver::reinit_assumptions() { @@ -1564,7 +1569,6 @@ namespace sat { literal l = m_trail[idx]; if (is_marked(l.var())) break; - SASSERT(idx > 0); idx--; } diff --git a/src/sat/tactic/atom2bool_var.cpp b/src/sat/tactic/atom2bool_var.cpp index 2df744138..58abc2807 100644 --- a/src/sat/tactic/atom2bool_var.cpp +++ b/src/sat/tactic/atom2bool_var.cpp @@ -90,8 +90,17 @@ struct collect_boolean_interface_proc { template void operator()(T const & g) { unsigned sz = g.size(); + ptr_vector deps; for (unsigned i = 0; i < sz; i++) { process(g.form(i)); + if (g.dep(i)) { + deps.reset(); + m.linearize(g.dep(i), deps); + for (unsigned j = 0; j < deps.size(); ++j) { + quick_for_each_expr(proc, tvisited, deps[j]); + } + + } } } diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index bd3f38d3b..7e22fca8b 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -35,6 +35,7 @@ Notes: #include"for_each_expr.h" #include"model_v2_pp.h" #include"tactic.h" +#include"ast_pp.h" struct goal2sat::imp { struct frame { @@ -52,15 +53,19 @@ struct goal2sat::imp { obj_hashtable m_interface_vars; sat::solver & m_solver; atom2bool_var & m_map; + dep2asm_map & m_dep2asm; sat::bool_var m_true; bool m_ite_extra; unsigned long long m_max_memory; volatile bool m_cancel; + expr_ref_vector m_trail; - imp(ast_manager & _m, params_ref const & p, sat::solver & s, atom2bool_var & map): + imp(ast_manager & _m, params_ref const & p, sat::solver & s, atom2bool_var & map, dep2asm_map& dep2asm): m(_m), m_solver(s), - m_map(map) { + m_map(map), + m_dep2asm(dep2asm), + m_trail(m) { updt_params(p); m_cancel = false; m_true = sat::null_bool_var; @@ -360,39 +365,55 @@ struct goal2sat::imp { SASSERT(m_result_stack.empty()); } - void add_assumption(expr* d, expr* literal_d) { - + void insert_dep(expr* dep, bool sign) { + expr_ref new_dep(m), fml(m); + if (is_uninterp_const(dep)) { + new_dep = dep; + } + else { + new_dep = m.mk_fresh_const("dep", m.mk_bool_sort()); + m_trail.push_back(new_dep); + m_interface_vars.insert(new_dep); + fml = m.mk_iff(new_dep, dep); + process(fml); + } + convert_atom(new_dep, false, false); + sat::literal lit = m_result_stack.back(); + m_dep2asm.insert(dep, sign?(~lit):lit); + m_result_stack.pop_back(); } - void operator()(goal const & g) { m_interface_vars.reset(); collect_boolean_interface(g, m_interface_vars); unsigned size = g.size(); expr_ref f(m), d_new(m); ptr_vector deps; + expr_ref_vector fmls(m); for (unsigned idx = 0; idx < size; idx++) { f = g.form(idx); + TRACE("sat", tout << "Formula: " << mk_pp(f, m) << "\n";); // Add assumptions. if (g.dep(idx)) { - expr_dependency * dep = g.dep(idx); deps.reset(); - m.linearize(dep, deps); + fmls.reset(); + m.linearize(g.dep(idx), deps); + fmls.push_back(f); for (unsigned i = 0; i < deps.size(); ++i) { expr * d = deps[i]; expr * d1; SASSERT(m.is_bool(d)); - if (is_uninterp_const(d)) { - add_assumption(d, d); - } - else if (m.is_not(d, d1) && is_uninterp_const(d1)) { - add_assumption(d, d); + if (m.is_not(d, d1)) { + insert_dep(d1, true); + fmls.push_back(d1); } else { - // create fresh variable, map back to dependency. - add_assumption(d, d_new); + insert_dep(d, false); + fmls.push_back(m.mk_not(d)); } } + f = m.mk_or(fmls.size(), fmls.c_ptr()); + TRACE("sat", tout << mk_pp(f, m) << "\n";); } process(f); } @@ -465,8 +486,8 @@ struct goal2sat::scoped_set_imp { } }; -void goal2sat::operator()(goal const & g, params_ref const & p, sat::solver & t, atom2bool_var & m) { - imp proc(g.m(), p, t, m); +void goal2sat::operator()(goal const & g, params_ref const & p, sat::solver & t, atom2bool_var & m, dep2asm_map& dep2asm) { + imp proc(g.m(), p, t, m, dep2asm); scoped_set_imp set(this, &proc); proc(g); } diff --git a/src/sat/tactic/goal2sat.h b/src/sat/tactic/goal2sat.h index 7e38a1ca5..bcc3dd52e 100644 --- a/src/sat/tactic/goal2sat.h +++ b/src/sat/tactic/goal2sat.h @@ -41,6 +41,8 @@ class goal2sat { public: goal2sat(); + typedef obj_map dep2asm_map; + static void collect_param_descrs(param_descrs & r); static bool has_unsupported_bool(goal const & s); @@ -55,7 +57,7 @@ public: \warning conversion throws a tactic_exception, if it is interrupted (by set_cancel), an unsupported operator is found, or memory consumption limit is reached (set with param :max-memory). */ - void operator()(goal const & g, params_ref const & p, sat::solver & t, atom2bool_var & m); + void operator()(goal const & g, params_ref const & p, sat::solver & t, atom2bool_var & m, dep2asm_map& dep2asm); void set_cancel(bool f); }; diff --git a/src/sat/tactic/sat_tactic.cpp b/src/sat/tactic/sat_tactic.cpp index c7e2ae608..8b575c177 100644 --- a/src/sat/tactic/sat_tactic.cpp +++ b/src/sat/tactic/sat_tactic.cpp @@ -52,7 +52,9 @@ class sat_tactic : public tactic { g->elim_redundancies(); atom2bool_var map(m); - m_goal2sat(*g, m_params, m_solver, map); + obj_map dep2asm; + sat::literal_vector assumptions; + m_goal2sat(*g, m_params, m_solver, map, dep2asm); TRACE("sat_solver_unknown", tout << "interpreted_atoms: " << map.interpreted_atoms() << "\n"; atom2bool_var::iterator it = map.begin(); atom2bool_var::iterator end = map.end(); @@ -66,10 +68,21 @@ class sat_tactic : public tactic { CASSERT("sat_solver", m_solver.check_invariant()); IF_VERBOSE(TACTIC_VERBOSITY_LVL, m_solver.display_status(verbose_stream());); TRACE("sat_dimacs", m_solver.display_dimacs(tout);); - - lbool r = m_solver.check(); + dep2assumptions(dep2asm, assumptions); + lbool r = m_solver.check(assumptions.size(), assumptions.c_ptr()); if (r == l_false) { - g->assert_expr(m.mk_false(), 0, 0); + expr_dependency * lcore = 0; + if (produce_core) { + sat::literal_vector const& core = m_solver.get_core(); + u_map asm2dep; + mk_asm2dep(dep2asm, asm2dep); + for (unsigned i = 0; i < core.size(); ++i) { + sat::literal lit = core[i]; + expr* dep = asm2dep.find(lit.index()); + lcore = m.mk_join(lcore, m.mk_leaf(dep)); + } + } + g->assert_expr(m.mk_false(), 0, lcore); } else if (r == l_true && !map.interpreted_atoms()) { // register model @@ -115,6 +128,22 @@ class sat_tactic : public tactic { m_sat2goal.set_cancel(f); m_solver.set_cancel(f); } + + void dep2assumptions(obj_map& dep2asm, + sat::literal_vector& assumptions) { + obj_map::iterator it = dep2asm.begin(), end = dep2asm.end(); + for (; it != end; ++it) { + assumptions.push_back(it->m_value); + } + } + + void mk_asm2dep(obj_map& dep2asm, + u_map& lit2asm) { + obj_map::iterator it = dep2asm.begin(), end = dep2asm.end(); + for (; it != end; ++it) { + lit2asm.insert(it->m_value.index(), it->m_key); + } + } }; struct scoped_set_imp { diff --git a/src/shell/dimacs_frontend.cpp b/src/shell/dimacs_frontend.cpp index 38b318d2f..879c5f212 100644 --- a/src/shell/dimacs_frontend.cpp +++ b/src/shell/dimacs_frontend.cpp @@ -155,7 +155,6 @@ unsigned read_dimacs(char const * file_name) { g_solver = &solver2; sat::literal_vector assumptions; track_clauses(solver, solver2, assumptions, tracking_clauses); - solver2.display(std::cout); r = g_solver->check(assumptions.size(), assumptions.c_ptr()); } else { diff --git a/src/tactic/probe.cpp b/src/tactic/probe.cpp index 8d82d292c..9f1ed8c72 100644 --- a/src/tactic/probe.cpp +++ b/src/tactic/probe.cpp @@ -289,7 +289,6 @@ struct is_non_qfbv_predicate { return; if (is_uninterp_const(n)) return; - throw found(); } }; diff --git a/src/tactic/smtlogics/qfbv_tactic.cpp b/src/tactic/smtlogics/qfbv_tactic.cpp index 3b5c352bb..916ae1386 100644 --- a/src/tactic/smtlogics/qfbv_tactic.cpp +++ b/src/tactic/smtlogics/qfbv_tactic.cpp @@ -105,7 +105,7 @@ tactic * mk_qfbv_tactic(ast_manager& m, params_ref const & p, tactic* sat, tacti cond(mk_is_qfbv_probe(), cond(mk_is_qfbv_eq_probe(), and_then(mk_bv1_blaster_tactic(m), - using_params(smt, solver_p)), + using_params(sat, solver_p)), and_then(mk_bit_blaster_tactic(m), when(mk_lt(mk_memory_probe(), mk_const_probe(MEMLIMIT)), and_then(using_params(and_then(mk_simplify_tactic(m), @@ -126,7 +126,7 @@ tactic * mk_qfbv_tactic(ast_manager& m, params_ref const & p, tactic* sat, tacti tactic * mk_qfbv_tactic(ast_manager & m, params_ref const & p) { - tactic * new_sat = cond(mk_or(mk_produce_proofs_probe(), mk_produce_unsat_cores_probe()), + tactic * new_sat = cond(mk_produce_proofs_probe(), and_then(mk_simplify_tactic(m), mk_smt_tactic()), mk_sat_tactic(m)); From 4f0de9a0cff77de92bc013f59a12909b08a4b2db Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 Jul 2014 09:27:03 -0700 Subject: [PATCH 437/925] implement user scopes for sat solver Signed-off-by: Nikolaj Bjorner --- src/opt/inc_sat_solver.cpp | 8 +-- src/sat/sat_solver.cpp | 112 ++++++++++++++++++++++++++++++---- src/sat/sat_solver.h | 14 ++++- src/sat/tactic/sat_tactic.cpp | 2 +- src/test/main.cpp | 1 + src/test/sat_user_scope.cpp | 102 +++++++++++++++++++++++++++++++ 6 files changed, 220 insertions(+), 19 deletions(-) create mode 100644 src/test/sat_user_scope.cpp diff --git a/src/opt/inc_sat_solver.cpp b/src/opt/inc_sat_solver.cpp index 5f121726a..85fef687a 100644 --- a/src/opt/inc_sat_solver.cpp +++ b/src/opt/inc_sat_solver.cpp @@ -57,7 +57,7 @@ public: virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions) { SASSERT(num_assumptions == 0); - m_solver.pop(m_solver.scope_lvl()); + m_solver.pop_to_base_level(); goal_ref_buffer result; proof_converter_ref pc; model_converter_ref mc; @@ -128,13 +128,13 @@ public: m_preprocess->set_cancel(f); } virtual void push() { - IF_VERBOSE(0, verbose_stream() << "push ignored\n";); + m_solver.user_push(); } virtual void pop(unsigned n) { - IF_VERBOSE(0, verbose_stream() << "pop ignored\n";); + m_solver.user_pop(n); } virtual unsigned get_scope_level() const { - return 0; + return m_solver.scope_lvl(); } virtual void assert_expr(expr * t, expr * a) { if (a) { diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index c357f7a29..bf6d0953f 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -140,7 +140,16 @@ namespace sat { for (unsigned i = 0; i < num_lits; i++) SASSERT(m_eliminated[lits[i].var()] == false); }); - mk_clause_core(num_lits, lits, false); + + if (m_user_scope_literals.empty()) { + mk_clause_core(num_lits, lits, false); + } + else { + m_aux_literals.reset(); + m_aux_literals.append(num_lits, lits); + m_aux_literals.append(m_user_scope_literals); + mk_clause_core(m_aux_literals.size(), m_aux_literals.c_ptr(), false); + } } void solver::mk_clause(literal l1, literal l2) { @@ -686,6 +695,7 @@ namespace sat { // // ----------------------- lbool solver::check(unsigned num_lits, literal const* lits) { + pop_to_base_level(); IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver using the efficient SAT solver)\n";); SASSERT(scope_lvl() == 0); #ifdef CLONE_BEFORE_SOLVING @@ -716,7 +726,7 @@ namespace sat { m_restart_threshold = m_config.m_restart_initial; } - // iff3_finder(*this)(); + // iff3_finder(*this)(); simplify_problem(); if (inconsistent()) return l_false; @@ -858,18 +868,27 @@ namespace sat { } void solver::init_assumptions(unsigned num_lits, literal const* lits) { - if (num_lits == 0) { + if (num_lits == 0 && m_user_scope_literals.empty()) { return; } - push(); m_assumptions.reset(); - m_assumption_set.reset(); + m_assumption_set.reset(); + push(); + + TRACE("sat", display(tout);); +#define _INSERT_LIT(_l_) \ + SASSERT(is_external((_l_).var())); \ + m_assumption_set.insert(_l_); \ + m_assumptions.push_back(_l_); \ + mk_clause_core(1, &(_l_), false); \ + for (unsigned i = 0; i < num_lits; ++i) { - literal l = lits[i]; - SASSERT(is_external(l.var())); - m_assumption_set.insert(l); - m_assumptions.push_back(l); - mk_clause(1, &l); + literal lit = lits[i]; + _INSERT_LIT(lit); + } + for (unsigned i = 0; i < m_user_scope_literals.size(); ++i) { + literal nlit = ~m_user_scope_literals[i]; + _INSERT_LIT(nlit); } TRACE("sat", display(tout);); } @@ -879,7 +898,7 @@ namespace sat { push(); for (unsigned i = 0; i < m_assumptions.size(); ++i) { literal l = m_assumptions[i]; - mk_clause(1, &l); + mk_clause_core(1, &l, false); } } } @@ -911,6 +930,12 @@ namespace sat { \brief Apply all simplifications. */ void solver::simplify_problem() { + + if (tracking_assumptions()) { + // NB. simplification is disabled when tracking assumptions. + return; + } + SASSERT(scope_lvl() == 0); m_cleaner(); @@ -2110,6 +2135,71 @@ namespace sat { m_clauses_to_reinit.shrink(j); } + // + // All new clauses that are added to the solver + // are relative to the user-scope literals. + // + + void solver::user_push() { + literal lit; + if (m_user_scope_literal_pool.empty()) { + bool_var new_v = mk_var(true, false); + lit = literal(new_v, false); + } + else { + lit = m_user_scope_literal_pool.back(); + m_user_scope_literal_pool.pop_back(); + } + m_user_scope_literals.push_back(lit); + } + + void solver::gc_lit(clause_vector &clauses, literal lit) { + unsigned j = 0; + for (unsigned i = 0; i < clauses.size(); ++i) { + clause & c = *(clauses[i]); + if (c.contains(lit)) { + dettach_clause(c); + del_clause(c); + } + else { + clauses[j] = &c; + ++j; + } + } + clauses.shrink(j); + } + + void solver::gc_bin(bool learned, literal nlit) { + m_user_bin_clauses.reset(); + collect_bin_clauses(m_user_bin_clauses, learned); + for (unsigned i = 0; i < m_user_bin_clauses.size(); ++i) { + literal l1 = m_user_bin_clauses[i].first; + literal l2 = m_user_bin_clauses[i].second; + if (nlit == l1 || nlit == l2) { + dettach_bin_clause(l1, l2, learned); + } + } + } + + void solver::user_pop(unsigned num_scopes) { + pop_to_base_level(); + while (num_scopes > 0) { + literal lit = m_user_scope_literals.back(); + m_user_scope_literal_pool.push_back(lit); + m_user_scope_literals.pop_back(); + gc_lit(m_learned, lit); + gc_lit(m_clauses, lit); + gc_bin(true, lit); + gc_bin(false, lit); + TRACE("sat", tout << "gc: " << lit << "\n"; display(tout);); + --num_scopes; + } + } + + void solver::pop_to_base_level() { + pop(scope_lvl()); + } + // ----------------------- // // Misc diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 48067cc48..8c39599bb 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -224,6 +224,7 @@ namespace sat { if (m_cancel) throw solver_exception(Z3_CANCELED_MSG); if (memory::get_allocation_size() > m_config.m_max_memory) throw solver_exception(Z3_MAX_MEMORY_MSG); } + typedef std::pair bin_clause; protected: watch_list & get_wlist(literal l) { return m_watches[l.index()]; } watch_list const & get_wlist(literal l) const { return m_watches[l.index()]; } @@ -350,13 +351,21 @@ namespace sat { // // ----------------------- void push(); - public: void pop(unsigned num_scopes); - protected: void unassign_vars(unsigned old_sz); void reinit_clauses(unsigned old_sz); + literal_vector m_user_scope_literals; + literal_vector m_user_scope_literal_pool; + literal_vector m_aux_literals; + svector m_user_bin_clauses; + void gc_lit(clause_vector& clauses, literal lit); + void gc_bin(bool learned, literal nlit); + public: + void user_push(); + void user_pop(unsigned num_scopes); + void pop_to_base_level(); // ----------------------- // // Simplification @@ -400,7 +409,6 @@ namespace sat { clause * const * end_clauses() const { return m_clauses.end(); } clause * const * begin_learned() const { return m_learned.begin(); } clause * const * end_learned() const { return m_learned.end(); } - typedef std::pair bin_clause; void collect_bin_clauses(svector & r, bool learned) const; // ----------------------- diff --git a/src/sat/tactic/sat_tactic.cpp b/src/sat/tactic/sat_tactic.cpp index 8b575c177..e4d5e6df5 100644 --- a/src/sat/tactic/sat_tactic.cpp +++ b/src/sat/tactic/sat_tactic.cpp @@ -116,7 +116,7 @@ class sat_tactic : public tactic { #if 0 IF_VERBOSE(TACTIC_VERBOSITY_LVL, verbose_stream() << "\"formula constains interpreted atoms, recovering formula from sat solver...\"\n";); #endif - m_solver.pop(m_solver.scope_lvl()); + m_solver.pop_to_base_level(); m_sat2goal(m_solver, map, m_params, *(g.get()), mc); } g->inc_depth(); diff --git a/src/test/main.cpp b/src/test/main.cpp index 3b0179944..d97a94a16 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -219,6 +219,7 @@ int main(int argc, char ** argv) { TST(sorting_network); TST(theory_pb); TST(simplex); + TST(sat_user_scope); //TST_ARGV(hs); } diff --git a/src/test/sat_user_scope.cpp b/src/test/sat_user_scope.cpp new file mode 100644 index 000000000..e39059563 --- /dev/null +++ b/src/test/sat_user_scope.cpp @@ -0,0 +1,102 @@ +#include "sat_solver.h" +#include "util.h" + +typedef sat::literal_vector clause_t; +typedef vector clauses_t; +typedef vector trail_t; + +// [ [c1, c2, ..], [ ...] ] + +static unsigned s_num_vars = 6; +static unsigned s_num_clauses_per_frame = 8; +static unsigned s_num_frames = 7; + +static void add_literal(random_gen& r, clause_t& c) { + c.push_back(sat::literal(r(s_num_vars) + 1, r(2) == 0)); +} + +static clause_t& last_clause(trail_t& t) { + return t.back().back(); +} + +static void add_clause(sat::solver& s, random_gen& r, trail_t& t) { + t.back().push_back(sat::literal_vector()); + clause_t& cls = last_clause(t); + for (unsigned i = 0; i < 3; ++i) { + add_literal(r, cls); + } + s.mk_clause(cls.size(), cls.c_ptr()); +} + +static void display_state(std::ostream& out, sat::solver& s, trail_t& t) { + s.display(out); +} + +static void pop_user_scope(sat::solver& s, trail_t& t) { + std::cout << "pop\n"; + s.user_pop(1); + t.pop_back(); +} + +static void push_user_scope(sat::solver& s, trail_t& t) { + std::cout << "push\n"; + s.user_push(); + t.push_back(clauses_t()); +} + +static void init_vars(sat::solver& s) { + for (unsigned i = 0; i <= s_num_vars; ++i) { + s.mk_var(); + } +} + +static void check_coherence(sat::solver& s1, trail_t& t) { + params_ref p; + sat::solver s2(p, 0); + init_vars(s2); + sat::literal_vector cls; + for (unsigned i = 0; i < t.size(); ++i) { + clauses_t& clss = t[i]; + for (unsigned j = 0; j < clss.size(); ++j) { + cls.reset(); + cls.append(clss[j]); + s2.mk_clause(cls.size(), cls.c_ptr()); + } + } + lbool is_sat1 = s1.check(); + lbool is_sat2 = s2.check(); + if (is_sat1 != is_sat2) { + s1.display(std::cout); + s2.display(std::cout); + } + std::cout << is_sat1 << "\n"; + SASSERT(is_sat1 == is_sat2); +} + +void tst_sat_user_scope() { + random_gen r(0); + trail_t trail; + params_ref p; + sat::solver s(p, 0); // incremental solver + init_vars(s); + while (true) { + for (unsigned i = 0; i < s_num_frames; ++i) { + // push 3 frames, pop 2 + for (unsigned k = 0; k < 3; ++k) { + push_user_scope(s, trail); + for (unsigned j = 0; j < s_num_clauses_per_frame; ++j) { + add_clause(s, r, trail); + } + check_coherence(s, trail); + } + for (unsigned k = 0; k < 2; ++k) { + pop_user_scope(s, trail); + check_coherence(s, trail); + } + } + for (unsigned i = 0; i < s_num_frames; ++i) { + pop_user_scope(s, trail); + check_coherence(s, trail); + } + } +} From 3fefed69b74221363175abac7b26faacb7b42b18 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 Jul 2014 11:12:15 -0700 Subject: [PATCH 438/925] incremental sat Signed-off-by: Nikolaj Bjorner --- src/opt/inc_sat_solver.cpp | 113 +++++++++++++++++++++++++------------ src/opt/inc_sat_solver.h | 27 +++++++++ src/opt/maxsmt.cpp | 35 +++++++----- src/opt/maxsmt.h | 3 + 4 files changed, 129 insertions(+), 49 deletions(-) create mode 100644 src/opt/inc_sat_solver.h diff --git a/src/opt/inc_sat_solver.cpp b/src/opt/inc_sat_solver.cpp index 85fef687a..792686f69 100644 --- a/src/opt/inc_sat_solver.cpp +++ b/src/opt/inc_sat_solver.cpp @@ -19,15 +19,20 @@ class inc_sat_solver : public solver { goal2sat m_goal2sat; params_ref m_params; expr_ref_vector m_fmls; + expr_ref_vector m_core; atom2bool_var m_map; model_ref m_model; model_converter_ref m_mc; tactic_ref m_preprocess; statistics m_stats; + unsigned m_num_scopes; + + typedef obj_map dep2asm_t; public: inc_sat_solver(ast_manager& m, params_ref const& p): m(m), m_solver(p,0), m_params(p), - m_fmls(m), m_map(m) { + m_fmls(m), m_core(m), m_map(m), + m_num_scopes(0) { m_params.set_bool("elim_vars", false); m_solver.updt_params(m_params); params_ref simp2_p = p; @@ -54,21 +59,25 @@ public: virtual void set_progress_callback(progress_callback * callback) { } - virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions) { - SASSERT(num_assumptions == 0); - + virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions) { m_solver.pop_to_base_level(); goal_ref_buffer result; proof_converter_ref pc; model_converter_ref mc; expr_dependency_ref core(m); - obj_map dep2asm; + dep2asm_t dep2asm; - if (!m_fmls.empty()) { - goal_ref g = alloc(goal, m); + if (!m_fmls.empty() || num_assumptions > 0) { + goal_ref g = alloc(goal, m, true, num_assumptions > 0); // models, maybe cores are enabled + SASSERT(num_assumptions == 0 || g->unsat_core_enabled()); + SASSERT(g->models_enabled()); + SASSERT(!g->proofs_enabled()); for (unsigned i = 0; i < m_fmls.size(); ++i) { g->assert_expr(m_fmls[i].get()); } + for (unsigned i = 0; i < num_assumptions; ++i) { + g->assert_expr(assumptions[i], m.mk_leaf(assumptions[i])); + } TRACE("opt", g->display(tout);); m_fmls.reset(); try { @@ -91,33 +100,18 @@ public: } lbool r = m_solver.check(); - if (r == l_true) { - model_ref md = alloc(model, m); - sat::model const & ll_m = m_solver.get_model(); - atom2bool_var::iterator it = m_map.begin(); - atom2bool_var::iterator end = m_map.end(); - for (; it != end; ++it) { - expr * n = it->m_key; - if (is_app(n) && to_app(n)->get_num_args() > 0) { - continue; - } - sat::bool_var v = it->m_value; - switch (sat::value_at(v, ll_m)) { - case l_true: - md->register_decl(to_app(n)->get_decl(), m.mk_true()); - break; - case l_false: - md->register_decl(to_app(n)->get_decl(), m.mk_false()); - break; - default: - break; - } + switch (r) { + case l_true: + extract_model(); + break; + case l_false: + // TBD: expr_dependency core is not accounted for. + if (num_assumptions > 0) { + extract_core(dep2asm); } - m_model = md; - if (m_mc) { - (*m_mc)(m_model); - } - // IF_VERBOSE(0, model_smt2_pp(verbose_stream(), m, *(m_model.get()), 0);); + break; + default: + break; } m_solver.collect_statistics(m_stats); return r; @@ -129,12 +123,15 @@ public: } virtual void push() { m_solver.user_push(); + ++m_num_scopes; } virtual void pop(unsigned n) { + SASSERT(n >= m_num_scopes); m_solver.user_pop(n); + m_num_scopes -= n; } virtual unsigned get_scope_level() const { - return m_solver.scope_lvl(); + return m_num_scopes; } virtual void assert_expr(expr * t, expr * a) { if (a) { @@ -162,7 +159,8 @@ public: st.copy(m_stats); } virtual void get_unsat_core(ptr_vector & r) { - UNREACHABLE(); + r.reset(); + r.append(m_core.size(), m_core.c_ptr()); } virtual void get_model(model_ref & m) { m = m_model; @@ -177,7 +175,50 @@ public: virtual void get_labels(svector & r) { UNREACHABLE(); } - + +private: + + void extract_core(dep2asm_t& dep2asm) { + u_map asm2dep; + dep2asm_t::iterator it = dep2asm.begin(), end = dep2asm.end(); + for (; it != end; ++it) { + asm2dep.insert(it->m_value.index(), it->m_key); + } + sat::literal_vector const& core = m_solver.get_core(); + for (unsigned i = 0; i < core.size(); ++i) { + m_core.push_back(asm2dep.find(core[i].index())); + } + } + + void extract_model() { + model_ref md = alloc(model, m); + sat::model const & ll_m = m_solver.get_model(); + atom2bool_var::iterator it = m_map.begin(); + atom2bool_var::iterator end = m_map.end(); + for (; it != end; ++it) { + expr * n = it->m_key; + if (is_app(n) && to_app(n)->get_num_args() > 0) { + continue; + } + sat::bool_var v = it->m_value; + switch (sat::value_at(v, ll_m)) { + case l_true: + md->register_decl(to_app(n)->get_decl(), m.mk_true()); + break; + case l_false: + md->register_decl(to_app(n)->get_decl(), m.mk_false()); + break; + default: + break; + } + } + m_model = md; + if (m_mc) { + (*m_mc)(m_model); + } + // IF_VERBOSE(0, model_smt2_pp(verbose_stream(), m, *(m_model.get()), 0);); + + } }; solver* mk_inc_sat_solver(ast_manager& m, params_ref& p) { diff --git a/src/opt/inc_sat_solver.h b/src/opt/inc_sat_solver.h new file mode 100644 index 000000000..903d27ebc --- /dev/null +++ b/src/opt/inc_sat_solver.h @@ -0,0 +1,27 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + inc_sat_solver.h + +Abstract: + + incremental solver based on SAT core. + +Author: + + Nikolaj Bjorner (nbjorner) 2014-7-30 + +Notes: + +--*/ + +#ifndef _HS_INC_SAT_SOLVER_H_ +#define _HS_INC_SAT_SOLVER_H_ + +#include "solver.h" + +solver* mk_inc_sat_solver(ast_manager& m, params_ref& p); + +#endif diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 7ae1348ab..df42ac11f 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -41,7 +41,7 @@ Notes: #include "uint_set.h" #include "opt_sls_solver.h" #include "pb_preprocess_tactic.h" - +#include "inc_sat_solver.h" namespace opt { @@ -129,20 +129,29 @@ namespace opt { return true; } + void maxsmt_solver_base::enable_inc_bvsat() { + + } + + void maxsmt_solver_base::enable_noninc_bvsat() { + tactic_ref pb2bv = mk_card2bv_tactic(m, m_params); + tactic_ref bv2sat = mk_qfbv_tactic(m, m_params); + tactic_ref tac = and_then(pb2bv.get(), bv2sat.get()); + solver* sat_solver = mk_tactic2solver(m, tac.get(), m_params); + unsigned sz = s().get_num_assertions(); + for (unsigned i = 0; i < sz; ++i) { + sat_solver->assert_expr(s().get_assertion(i)); + } + unsigned lvl = m_s->get_scope_level(); + while (lvl > 0) { sat_solver->push(); --lvl; } + m_s = sat_solver; + m_sat_enabled = true; + } + + void maxsmt_solver_base::enable_bvsat() { if (m_enable_sat && !m_sat_enabled && probe_bv()) { - tactic_ref pb2bv = mk_card2bv_tactic(m, m_params); - tactic_ref bv2sat = mk_qfbv_tactic(m, m_params); - tactic_ref tac = and_then(pb2bv.get(), bv2sat.get()); - solver* sat_solver = mk_tactic2solver(m, tac.get(), m_params); - unsigned sz = s().get_num_assertions(); - for (unsigned i = 0; i < sz; ++i) { - sat_solver->assert_expr(s().get_assertion(i)); - } - unsigned lvl = m_s->get_scope_level(); - while (lvl > 0) { sat_solver->push(); --lvl; } - m_s = sat_solver; - m_sat_enabled = true; + enable_noninc_bvsat(); } } diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 0cc833cba..f85f30d78 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -97,6 +97,9 @@ namespace opt { void enable_bvsat(); void enable_sls(); app* mk_fresh_bool(char const* name); + private: + void enable_inc_bvsat(); + void enable_noninc_bvsat(); }; /** From e8056e066dd405416e3ffd87dee82e2ab937e4eb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 Jul 2014 12:57:30 -0700 Subject: [PATCH 439/925] enable bvsat, multi disjoint cores for dual-maxres Signed-off-by: Nikolaj Bjorner --- src/opt/dual_maxres.cpp | 72 +++++++++++++++++++++++++++++++++-------- src/opt/maxres.cpp | 1 + src/opt/maxsmt.cpp | 14 ++++++-- 3 files changed, 71 insertions(+), 16 deletions(-) diff --git a/src/opt/dual_maxres.cpp b/src/opt/dual_maxres.cpp index 55d347e9e..95834ca1a 100644 --- a/src/opt/dual_maxres.cpp +++ b/src/opt/dual_maxres.cpp @@ -111,8 +111,11 @@ public: solver::scoped_push _sc(*m_s.get()); init(); init_local(); + enable_bvsat(); + enable_sls(); lbool was_sat = l_false; ptr_vector soft_compl; + vector > cores; while (m_lower < m_upper) { TRACE("opt", display_vec(tout, m_asms.size(), m_asms.c_ptr()); @@ -131,7 +134,10 @@ public: case l_undef: break; case l_false: - is_sat = process_unsat(soft_compl); + is_sat = get_cores(soft_compl, cores); + for (unsigned i = 0; is_sat == l_true && i < cores.size(); ++i) { + is_sat = process_unsat(cores[i]); + } break; case l_true: is_sat = process_sat(soft_compl); @@ -166,18 +172,54 @@ public: return l_true; } + // + // Retrieve a set of disjoint cores over the current assumptions. + // TBD: when the remaining are satisfiable, then extend the + // satisfying model to improve upper bound. + // + lbool get_cores(ptr_vector& core, vector >& cores) { + // assume 'core' is minimal. + expr_ref_vector asms(m); + asms.append(m_asms.size(), m_asms.c_ptr()); + remove_soft(core, asms); + cores.reset(); + cores.push_back(core); + ptr_vector new_core; + while (true) { + lbool is_sat = m_s->check_sat(asms.size(), asms.c_ptr()); + switch (is_sat) { + case l_false: + new_core.reset(); + m_s->get_unsat_core(new_core); + switch (minimize_core(new_core)) { + case l_false: + return l_false; + case l_true: + cores.push_back(new_core); + remove_soft(new_core, asms); + break; + default: + return l_undef; + } + break; + case l_true: + TRACE("opt", + tout << "num cores: " << cores.size() << "\n"; + tout << "num satisfying: " << asms.size() << "\n";); + return l_true; + default: + return l_undef; + } + } + } + lbool process_unsat(ptr_vector& core) { expr_ref fml(m); TRACE("opt", display_vec(tout << "core: ", core.size(), core.c_ptr());); SASSERT(!core.empty()); - lbool is_sat = minimize_core(core); - SASSERT(!core.empty()); if (core.empty()) { return l_false; } - if (is_sat != l_true) { - return is_sat; - } remove_soft(core); rational w = split_soft(core); TRACE("opt", display_vec(tout << "minimized core: ", core.size(), core.c_ptr());); @@ -186,7 +228,7 @@ public: IF_VERBOSE(1, verbose_stream() << "(opt.dual_max_res [" << m_lower << ":" << m_upper << "])\n";); - return is_sat; + return l_true; } // @@ -221,7 +263,7 @@ public: if (num_true*2 < m_asms.size()) { soft_compl.reset(); m_s->get_unsat_core(soft_compl); - return l_false; + return minimize_core(soft_compl); } break; case l_true: @@ -394,16 +436,20 @@ public: m_s->assert_expr(fml); } - void remove_soft(ptr_vector const& soft) { - for (unsigned i = 0; i < m_asms.size(); ++i) { - if (soft.contains(m_asms[i].get())) { - m_asms[i] = m_asms.back(); - m_asms.pop_back(); + void remove_soft(ptr_vector const& soft, expr_ref_vector& asms) { + for (unsigned i = 0; i < asms.size(); ++i) { + if (soft.contains(asms[i].get())) { + asms[i] = asms.back(); + asms.pop_back(); --i; } } } + void remove_soft(ptr_vector const& soft) { + remove_soft(soft, m_asms); + } + virtual void set_cancel(bool f) { maxsmt_solver_base::set_cancel(f); m_mus.set_cancel(f); diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index fa0210ee2..98abb7bfd 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -90,6 +90,7 @@ public: solver::scoped_push _sc(*m_s.get()); init(); init_local(); + enable_bvsat(); while (true) { TRACE("opt", display_vec(tout, m_asms.size(), m_asms.c_ptr()); diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index df42ac11f..821113e28 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -130,7 +130,14 @@ namespace opt { } void maxsmt_solver_base::enable_inc_bvsat() { - + solver* sat_solver = mk_inc_sat_solver(m, m_params); + unsigned sz = s().get_num_assertions(); + for (unsigned i = 0; i < sz; ++i) { + sat_solver->assert_expr(s().get_assertion(i)); + } + unsigned lvl = m_s->get_scope_level(); + while (lvl > 0) { sat_solver->push(); --lvl; } + m_s = sat_solver; } void maxsmt_solver_base::enable_noninc_bvsat() { @@ -145,13 +152,14 @@ namespace opt { unsigned lvl = m_s->get_scope_level(); while (lvl > 0) { sat_solver->push(); --lvl; } m_s = sat_solver; - m_sat_enabled = true; } void maxsmt_solver_base::enable_bvsat() { if (m_enable_sat && !m_sat_enabled && probe_bv()) { - enable_noninc_bvsat(); + enable_inc_bvsat(); + // enable_noninc_bvsat(); + m_sat_enabled = true; } } From bfc0af782051c833f15ff9d6a51959eaec349c2b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 Jul 2014 16:35:46 -0700 Subject: [PATCH 440/925] testing inc-sat solver Signed-off-by: Nikolaj Bjorner --- src/opt/dual_maxres.cpp | 76 +++++++++++++++-------------- src/opt/inc_sat_solver.cpp | 24 +++++++-- src/opt/mus.cpp | 10 +++- src/sat/sat_solver.cpp | 5 +- src/tactic/arith/card2bv_tactic.cpp | 2 +- 5 files changed, 73 insertions(+), 44 deletions(-) diff --git a/src/opt/dual_maxres.cpp b/src/opt/dual_maxres.cpp index 95834ca1a..5895f0573 100644 --- a/src/opt/dual_maxres.cpp +++ b/src/opt/dual_maxres.cpp @@ -134,7 +134,7 @@ public: case l_undef: break; case l_false: - is_sat = get_cores(soft_compl, cores); + is_sat = get_cores(cores); for (unsigned i = 0; is_sat == l_true && i < cores.size(); ++i) { is_sat = process_unsat(cores[i]); } @@ -177,57 +177,61 @@ public: // TBD: when the remaining are satisfiable, then extend the // satisfying model to improve upper bound. // - lbool get_cores(ptr_vector& core, vector >& cores) { - // assume 'core' is minimal. + lbool get_cores(vector >& cores) { + // assume m_s is unsat. + lbool is_sat = l_false; expr_ref_vector asms(m); asms.append(m_asms.size(), m_asms.c_ptr()); - remove_soft(core, asms); cores.reset(); - cores.push_back(core); - ptr_vector new_core; - while (true) { - lbool is_sat = m_s->check_sat(asms.size(), asms.c_ptr()); - switch (is_sat) { - case l_false: - new_core.reset(); - m_s->get_unsat_core(new_core); - switch (minimize_core(new_core)) { - case l_false: - return l_false; - case l_true: - cores.push_back(new_core); - remove_soft(new_core, asms); - break; - default: - return l_undef; - } + ptr_vector core; + while (is_sat == l_false) { + core.reset(); + m_s->get_unsat_core(core); + is_sat = minimize_core(core); + if (is_sat != l_true) { break; - case l_true: - TRACE("opt", - tout << "num cores: " << cores.size() << "\n"; - tout << "num satisfying: " << asms.size() << "\n";); - return l_true; - default: - return l_undef; } - } + cores.push_back(core); + break; + // + // TBD: multiple core refinement + // produces unsound results. + // what is a sound variant? + // + remove_soft(core, asms); + is_sat = m_s->check_sat(asms.size(), asms.c_ptr()); + + } + TRACE("opt", + tout << "num cores: " << cores.size() << "\n"; + for (unsigned i = 0; i < cores.size(); ++i) { + for (unsigned j = 0; j < cores[i].size(); ++j) { + tout << mk_pp(cores[i][j], m) << " "; + } + tout << "\n"; + } + tout << "num satisfying: " << asms.size() << "\n";); + + return is_sat; } lbool process_unsat(ptr_vector& core) { expr_ref fml(m); - TRACE("opt", display_vec(tout << "core: ", core.size(), core.c_ptr());); SASSERT(!core.empty()); if (core.empty()) { return l_false; } remove_soft(core); rational w = split_soft(core); - TRACE("opt", display_vec(tout << "minimized core: ", core.size(), core.c_ptr());); + TRACE("opt", display_vec(tout << "core: ", core.size(), core.c_ptr()); + for (unsigned i = 0; i < core.size(); ++i) { + tout << get_weight(core[i]) << " "; + } + tout << "min-weight: " << w << "\n";); max_resolve(core, w); - m_lower += w; + m_lower += w; IF_VERBOSE(1, verbose_stream() << "(opt.dual_max_res [" << m_lower << ":" << m_upper << "])\n";); - return l_true; } @@ -261,9 +265,7 @@ public: switch (is_sat) { case l_false: if (num_true*2 < m_asms.size()) { - soft_compl.reset(); - m_s->get_unsat_core(soft_compl); - return minimize_core(soft_compl); + return l_false; } break; case l_true: diff --git a/src/opt/inc_sat_solver.cpp b/src/opt/inc_sat_solver.cpp index 792686f69..506e3227c 100644 --- a/src/opt/inc_sat_solver.cpp +++ b/src/opt/inc_sat_solver.cpp @@ -11,6 +11,7 @@ #include "bit_blaster_tactic.h" #include "simplify_tactic.h" #include "goal2sat.h" +#include "ast_pp.h" // incremental SAT solver. class inc_sat_solver : public solver { @@ -78,11 +79,10 @@ public: for (unsigned i = 0; i < num_assumptions; ++i) { g->assert_expr(assumptions[i], m.mk_leaf(assumptions[i])); } - TRACE("opt", g->display(tout);); + TRACE("opt", g->display_with_dependencies(tout);); m_fmls.reset(); try { (*m_preprocess)(g, result, mc, pc, core); - TRACE("opt", result[0]->display(tout);); } catch (tactic_exception & ex) { IF_VERBOSE(0, verbose_stream() << "exception in tactic " << ex.msg() << "\n";); @@ -95,7 +95,7 @@ public: return l_undef; } g = result[0]; - TRACE("opt", g->display(tout);); + TRACE("opt", g->display_with_dependencies(tout);); m_goal2sat(*g, m_params, m_solver, m_map, dep2asm); } @@ -185,8 +185,24 @@ private: asm2dep.insert(it->m_value.index(), it->m_key); } sat::literal_vector const& core = m_solver.get_core(); + + TRACE("opt", + dep2asm_t::iterator it = dep2asm.begin(); + dep2asm_t::iterator end = dep2asm.end(); + for (; it != end; ++it) { + tout << mk_pp(it->m_key, m) << " |-> " << it->m_value << "\n"; + } + tout << "core: "; + for (unsigned i = 0; i < core.size(); ++i) { + tout << core[i] << " "; + } + tout << "\n"; + ); + for (unsigned i = 0; i < core.size(); ++i) { - m_core.push_back(asm2dep.find(core[i].index())); + expr* e; + if (asm2dep.find(core[i].index(), e)) + m_core.push_back(e); } } diff --git a/src/opt/mus.cpp b/src/opt/mus.cpp index 4cfab6376..9ce2dd187 100644 --- a/src/opt/mus.cpp +++ b/src/opt/mus.cpp @@ -129,7 +129,7 @@ struct mus::imp { add_core(core, assumptions); lbool is_sat = m_s->check_sat(assumptions.size(), assumptions.c_ptr()); assumptions.resize(sz); - switch(is_sat) { + switch (is_sat) { case l_undef: return is_sat; case l_true: @@ -160,6 +160,14 @@ struct mus::imp { break; } } + DEBUG_CODE( + assumptions.reset(); + for (unsigned i = 0; i < mus.size(); ++i) { + assumptions.push_back(m_cls2expr[mus[i]].get()); + } + lbool is_sat = m_s->check_sat(assumptions.size(), assumptions.c_ptr()); + SASSERT(is_sat == l_false); + ); return l_true; } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index bf6d0953f..1d3d3ce71 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -2141,6 +2141,9 @@ namespace sat { // void solver::user_push() { + if (m_level.size() == 0) { + return; + } literal lit; if (m_user_scope_literal_pool.empty()) { bool_var new_v = mk_var(true, false); @@ -2183,7 +2186,7 @@ namespace sat { void solver::user_pop(unsigned num_scopes) { pop_to_base_level(); - while (num_scopes > 0) { + while (num_scopes > 0 && !m_user_scope_literals.empty()) { literal lit = m_user_scope_literals.back(); m_user_scope_literal_pool.push_back(lit); m_user_scope_literals.pop_back(); diff --git a/src/tactic/arith/card2bv_tactic.cpp b/src/tactic/arith/card2bv_tactic.cpp index 26bea6343..a433dd307 100644 --- a/src/tactic/arith/card2bv_tactic.cpp +++ b/src/tactic/arith/card2bv_tactic.cpp @@ -198,7 +198,7 @@ public: m_rw1(g->form(idx), new_f1); TRACE("card2bv", tout << "Rewriting " << mk_ismt2_pp(new_f1.get(), m) << std::endl;); m_rw2(new_f1, new_f2); - g->update(idx, new_f2); + g->update(idx, new_f2, g->pr(idx), g->dep(idx)); } g->inc_depth(); From 365f05b41a41ebab61a7af5ca906d16a49f6e2fd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 Jul 2014 17:49:51 -0700 Subject: [PATCH 441/925] testing inc-sat solver Signed-off-by: Nikolaj Bjorner --- src/opt/inc_sat_solver.cpp | 16 +++++++++++++--- src/sat/sat_solver.cpp | 7 +++++-- src/sat/tactic/goal2sat.cpp | 12 +++++++----- src/sat/tactic/goal2sat.h | 2 +- 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/opt/inc_sat_solver.cpp b/src/opt/inc_sat_solver.cpp index 506e3227c..d6404808e 100644 --- a/src/opt/inc_sat_solver.cpp +++ b/src/opt/inc_sat_solver.cpp @@ -27,6 +27,8 @@ class inc_sat_solver : public solver { tactic_ref m_preprocess; statistics m_stats; unsigned m_num_scopes; + sat::literal_vector m_asms; + typedef obj_map dep2asm_t; public: @@ -96,10 +98,10 @@ public: } g = result[0]; TRACE("opt", g->display_with_dependencies(tout);); - m_goal2sat(*g, m_params, m_solver, m_map, dep2asm); + m_goal2sat(*g, m_params, m_solver, m_map, dep2asm, true); } - - lbool r = m_solver.check(); + extract_assumptions(dep2asm, m_asms); + lbool r = m_solver.check(m_asms.size(), m_asms.c_ptr()); switch (r) { case l_true: extract_model(); @@ -178,6 +180,14 @@ public: private: + void extract_assumptions(dep2asm_t& dep2asm, sat::literal_vector& asms) { + asms.reset(); + dep2asm_t::iterator it = dep2asm.begin(), end = dep2asm.end(); + for (; it != end; ++it) { + asms.push_back(it->m_value); + } + } + void extract_core(dep2asm_t& dep2asm) { u_map asm2dep; dep2asm_t::iterator it = dep2asm.begin(), end = dep2asm.end(); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 1d3d3ce71..911c49c74 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -696,7 +696,7 @@ namespace sat { // ----------------------- lbool solver::check(unsigned num_lits, literal const* lits) { pop_to_base_level(); - IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver using the efficient SAT solver)\n";); + IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver)\n";); SASSERT(scope_lvl() == 0); #ifdef CLONE_BEFORE_SOLVING if (m_mc.empty()) { @@ -875,7 +875,10 @@ namespace sat { m_assumption_set.reset(); push(); - TRACE("sat", display(tout);); + TRACE("sat", + for (unsigned i = 0; i < num_lits; ++i) + tout << lits[i] << " "; + tout << "\n";); #define _INSERT_LIT(_l_) \ SASSERT(is_external((_l_).var())); \ m_assumption_set.insert(_l_); \ diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 7e22fca8b..636e8920f 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -59,13 +59,15 @@ struct goal2sat::imp { unsigned long long m_max_memory; volatile bool m_cancel; expr_ref_vector m_trail; + bool m_default_external; - imp(ast_manager & _m, params_ref const & p, sat::solver & s, atom2bool_var & map, dep2asm_map& dep2asm): + imp(ast_manager & _m, params_ref const & p, sat::solver & s, atom2bool_var & map, dep2asm_map& dep2asm, bool default_external): m(_m), m_solver(s), m_map(map), m_dep2asm(dep2asm), - m_trail(m) { + m_trail(m), + m_default_external(default_external) { updt_params(p); m_cancel = false; m_true = sat::null_bool_var; @@ -121,7 +123,7 @@ struct goal2sat::imp { l = sat::literal(mk_true(), !sign); } else { - bool ext = !is_uninterp_const(t) || m_interface_vars.contains(t); + bool ext = m_default_external || !is_uninterp_const(t) || m_interface_vars.contains(t); sat::bool_var v = m_solver.mk_var(ext); m_map.insert(t, v); l = sat::literal(v, sign); @@ -486,8 +488,8 @@ struct goal2sat::scoped_set_imp { } }; -void goal2sat::operator()(goal const & g, params_ref const & p, sat::solver & t, atom2bool_var & m, dep2asm_map& dep2asm) { - imp proc(g.m(), p, t, m, dep2asm); +void goal2sat::operator()(goal const & g, params_ref const & p, sat::solver & t, atom2bool_var & m, dep2asm_map& dep2asm, bool default_external) { + imp proc(g.m(), p, t, m, dep2asm, default_external); scoped_set_imp set(this, &proc); proc(g); } diff --git a/src/sat/tactic/goal2sat.h b/src/sat/tactic/goal2sat.h index bcc3dd52e..b4e9615a0 100644 --- a/src/sat/tactic/goal2sat.h +++ b/src/sat/tactic/goal2sat.h @@ -57,7 +57,7 @@ public: \warning conversion throws a tactic_exception, if it is interrupted (by set_cancel), an unsupported operator is found, or memory consumption limit is reached (set with param :max-memory). */ - void operator()(goal const & g, params_ref const & p, sat::solver & t, atom2bool_var & m, dep2asm_map& dep2asm); + void operator()(goal const & g, params_ref const & p, sat::solver & t, atom2bool_var & m, dep2asm_map& dep2asm, bool default_external = false); void set_cancel(bool f); }; From 39414d8b8d23ac4817f1d1465810c511e23c5cfa Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 31 Jul 2014 22:29:47 -0700 Subject: [PATCH 442/925] testing inc_sat Signed-off-by: Nikolaj Bjorner --- src/opt/inc_sat_solver.cpp | 140 +++++++++++++++++++++---------- src/opt/maxres.cpp | 6 +- src/opt/maxsmt.cpp | 2 - src/opt/mus.cpp | 9 +- src/sat/sat_justification.h | 21 +++++ src/sat/sat_solver.cpp | 76 ++++++++++------- src/sat/sat_solver.h | 1 + src/sat/tactic/atom2bool_var.cpp | 16 ++-- src/sat/tactic/goal2sat.cpp | 24 ++++-- 9 files changed, 200 insertions(+), 95 deletions(-) diff --git a/src/opt/inc_sat_solver.cpp b/src/opt/inc_sat_solver.cpp index d6404808e..72cff950a 100644 --- a/src/opt/inc_sat_solver.cpp +++ b/src/opt/inc_sat_solver.cpp @@ -1,3 +1,21 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + inc_sat_solver.cpp + +Abstract: + + incremental solver based on SAT core. + +Author: + + Nikolaj Bjorner (nbjorner) 2014-7-30 + +Notes: + +--*/ #include "solver.h" #include "tactical.h" @@ -28,6 +46,10 @@ class inc_sat_solver : public solver { statistics m_stats; unsigned m_num_scopes; sat::literal_vector m_asms; + goal_ref_buffer m_subgoals; + proof_converter_ref m_pc; + model_converter_ref m_mc2; + expr_dependency_ref m_dep_core; typedef obj_map dep2asm_t; @@ -35,7 +57,8 @@ public: inc_sat_solver(ast_manager& m, params_ref const& p): m(m), m_solver(p,0), m_params(p), m_fmls(m), m_core(m), m_map(m), - m_num_scopes(0) { + m_num_scopes(0), + m_dep_core(m) { m_params.set_bool("elim_vars", false); m_solver.updt_params(m_params); params_ref simp2_p = p; @@ -53,7 +76,8 @@ public: using_params(mk_simplify_tactic(m), simp2_p), mk_max_bv_sharing_tactic(m), mk_bit_blaster_tactic(m), - mk_aig_tactic()); + mk_aig_tactic(), + using_params(mk_simplify_tactic(m), simp2_p)); } @@ -64,44 +88,14 @@ public: } virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions) { m_solver.pop_to_base_level(); - goal_ref_buffer result; - proof_converter_ref pc; - model_converter_ref mc; - expr_dependency_ref core(m); dep2asm_t dep2asm; - if (!m_fmls.empty() || num_assumptions > 0) { - goal_ref g = alloc(goal, m, true, num_assumptions > 0); // models, maybe cores are enabled - SASSERT(num_assumptions == 0 || g->unsat_core_enabled()); - SASSERT(g->models_enabled()); - SASSERT(!g->proofs_enabled()); - for (unsigned i = 0; i < m_fmls.size(); ++i) { - g->assert_expr(m_fmls[i].get()); - } - for (unsigned i = 0; i < num_assumptions; ++i) { - g->assert_expr(assumptions[i], m.mk_leaf(assumptions[i])); - } - TRACE("opt", g->display_with_dependencies(tout);); - m_fmls.reset(); - try { - (*m_preprocess)(g, result, mc, pc, core); - } - catch (tactic_exception & ex) { - IF_VERBOSE(0, verbose_stream() << "exception in tactic " << ex.msg() << "\n";); - m_preprocess->collect_statistics(m_stats); - return l_undef; - } - m_mc = concat(m_mc.get(), mc.get()); - if (result.size() != 1) { - IF_VERBOSE(0, verbose_stream() << "size of result is not 1, it is: " << result.size() << "\n";); - return l_undef; - } - g = result[0]; - TRACE("opt", g->display_with_dependencies(tout);); - m_goal2sat(*g, m_params, m_solver, m_map, dep2asm, true); - } + lbool r = internalize_formulas(); + if (r != l_true) return r; + r = internalize_assumptions(num_assumptions, assumptions, dep2asm); extract_assumptions(dep2asm, m_asms); - lbool r = m_solver.check(m_asms.size(), m_asms.c_ptr()); + if (r != l_true) return r; + r = m_solver.check(m_asms.size(), m_asms.c_ptr()); switch (r) { case l_true: extract_model(); @@ -128,6 +122,9 @@ public: ++m_num_scopes; } virtual void pop(unsigned n) { + if (n < m_num_scopes) { // allow inc_sat_solver to + n = m_num_scopes; // take over for another solver. + } SASSERT(n >= m_num_scopes); m_solver.user_pop(n); m_num_scopes -= n; @@ -180,6 +177,57 @@ public: private: + lbool internalize_goal(goal_ref& g, dep2asm_t& dep2asm) { + m_mc2.reset(); + m_pc.reset(); + m_dep_core.reset(); + m_subgoals.reset(); + SASSERT(g->models_enabled()); + SASSERT(!g->proofs_enabled()); + TRACE("opt", g->display(tout);); + try { + (*m_preprocess)(g, m_subgoals, m_mc2, m_pc, m_dep_core); + } + catch (tactic_exception & ex) { + IF_VERBOSE(0, verbose_stream() << "exception in tactic " << ex.msg() << "\n";); + m_preprocess->collect_statistics(m_stats); + return l_undef; + } + m_mc = concat(m_mc.get(), m_mc2.get()); + if (m_subgoals.size() != 1) { + IF_VERBOSE(0, verbose_stream() << "size of subgoals is not 1, it is: " << m_subgoals.size() << "\n";); + return l_undef; + } + g = m_subgoals[0]; + TRACE("opt", g->display_with_dependencies(tout);); + m_goal2sat(*g, m_params, m_solver, m_map, dep2asm, true); + return l_true; + } + + lbool internalize_assumptions(unsigned sz, expr* const* asms, dep2asm_t& dep2asm) { + if (sz == 0) { + return l_true; + } + goal_ref g = alloc(goal, m, true, true); // models and cores are enabled. + for (unsigned i = 0; i < sz; ++i) { + g->assert_expr(asms[i], m.mk_leaf(asms[i])); + } + return internalize_goal(g, dep2asm); + } + + lbool internalize_formulas() { + if (m_fmls.empty()) { + return l_true; + } + dep2asm_t dep2asm; + goal_ref g = alloc(goal, m, true, false); // models, maybe cores are enabled + for (unsigned i = 0; i < m_fmls.size(); ++i) { + g->assert_expr(m_fmls[i].get()); + } + m_fmls.reset(); + return internalize_goal(g, dep2asm); + } + void extract_assumptions(dep2asm_t& dep2asm, sat::literal_vector& asms) { asms.reset(); dep2asm_t::iterator it = dep2asm.begin(), end = dep2asm.end(); @@ -196,6 +244,16 @@ private: } sat::literal_vector const& core = m_solver.get_core(); + m_core.reset(); + for (unsigned i = 0; i < core.size(); ++i) { + expr* e; + if (asm2dep.find(core[i].index(), e)) { + if (core[i].sign()) { + e = m.mk_not(e); + } + m_core.push_back(e); + } + } TRACE("opt", dep2asm_t::iterator it = dep2asm.begin(); dep2asm_t::iterator end = dep2asm.end(); @@ -204,16 +262,12 @@ private: } tout << "core: "; for (unsigned i = 0; i < core.size(); ++i) { - tout << core[i] << " "; + tout << core[i] << ": " << mk_pp(m_core[i].get(), m) << " "; } tout << "\n"; ); - for (unsigned i = 0; i < core.size(); ++i) { - expr* e; - if (asm2dep.find(core[i].index(), e)) - m_core.push_back(e); - } + } void extract_model() { diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 98abb7bfd..58cd241d0 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -78,6 +78,7 @@ public: } void new_assumption(expr* e, app* cls, rational const& w) { + TRACE("opt", tout << "insert: " << mk_pp(e, m) << " : " << w << "\n";); info inf(cls, w); m_asm2info.insert(e, inf); m_asms.push_back(e); @@ -186,7 +187,8 @@ public: for (unsigned i = 0; i < core.size(); ++i) { rational w2 = get_weight(core[i]); if (w2 > w) { - new_assumption(core[i], get_clause(core[i]), w2 - w); + rational w3 = w2 - w; + new_assumption(core[i], get_clause(core[i]), w3); } } return w; @@ -194,7 +196,7 @@ public: void display_vec(std::ostream& out, unsigned sz, expr* const* args) { for (unsigned i = 0; i < sz; ++i) { - out << mk_pp(args[i], m) << " "; + out << mk_pp(args[i], m) << " : " << get_weight(args[i]) << " "; } out << "\n"; } diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 821113e28..347f4bf3a 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -135,8 +135,6 @@ namespace opt { for (unsigned i = 0; i < sz; ++i) { sat_solver->assert_expr(s().get_assertion(i)); } - unsigned lvl = m_s->get_scope_level(); - while (lvl > 0) { sat_solver->push(); --lvl; } m_s = sat_solver; } diff --git a/src/opt/mus.cpp b/src/opt/mus.cpp index 9ce2dd187..9204371bc 100644 --- a/src/opt/mus.cpp +++ b/src/opt/mus.cpp @@ -98,6 +98,7 @@ struct mus::imp { } lbool get_mus(unsigned_vector& mus) { + // SASSERT: mus does not have duplicates. TRACE("opt", for (unsigned i = 0; i < m_cls2lits.size(); ++i) { display_vec(tout, m_cls2lits[i]); @@ -107,12 +108,16 @@ struct mus::imp { for (unsigned i = 0; i < m_cls2expr.size(); ++i) { core.push_back(i); } + if (core.size() == 1) { + mus.push_back(core.back()); + return l_true; + } mus.reset(); expr_ref_vector assumptions(m); svector model; ptr_vector core_exprs; model.resize(m_vars.size()); - while (!core.empty()) { + while (!core.empty()) { IF_VERBOSE(1, verbose_stream() << "(opt.mus reducing core: " << core.size() << " new core: " << mus.size() << ")\n";); unsigned cls_id = core.back(); TRACE("opt", @@ -160,6 +165,7 @@ struct mus::imp { break; } } +#if 0 DEBUG_CODE( assumptions.reset(); for (unsigned i = 0; i < mus.size(); ++i) { @@ -168,6 +174,7 @@ struct mus::imp { lbool is_sat = m_s->check_sat(assumptions.size(), assumptions.c_ptr()); SASSERT(is_sat == l_false); ); +#endif return l_true; } diff --git a/src/sat/sat_justification.h b/src/sat/sat_justification.h index dd803feeb..b162662e8 100644 --- a/src/sat/sat_justification.h +++ b/src/sat/sat_justification.h @@ -52,6 +52,27 @@ namespace sat { bool is_ext_justification() const { return m_val2 == EXT_JUSTIFICATION; } ext_justification_idx get_ext_justification_idx() const { return m_val1; } }; + + inline std::ostream & operator<<(std::ostream & out, justification const & j) { + switch (j.get_kind()) { + case justification::NONE: + out << "none"; + break; + case justification::BINARY: + out << "binary " << j.get_literal(); + break; + case justification::TERNARY: + out << "ternary " << j.get_literal1() << " " << j.get_literal2(); + break; + case justification::CLAUSE: + out << "clause"; + break; + case justification::EXT_JUSTIFICATION: + out << "external"; + break; + } + return out; + } }; #endif diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 911c49c74..cfd83955d 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -163,8 +163,8 @@ namespace sat { } clause * solver::mk_clause_core(unsigned num_lits, literal * lits, bool learned) { + TRACE("sat", tout << "mk_clause: " << mk_lits_pp(num_lits, lits) << "\n";); if (!learned) { - TRACE("sat_mk_clause", tout << "mk_clause: " << mk_lits_pp(num_lits, lits) << "\n";); bool keep = simplify_clause(num_lits, lits); TRACE("sat_mk_clause", tout << "mk_clause (after simp), keep: " << keep << "\n" << mk_lits_pp(num_lits, lits) << "\n";); if (!keep) { @@ -468,9 +468,7 @@ namespace sat { void solver::set_conflict(justification c, literal not_l) { if (m_inconsistent) return; - TRACE("sat_conflict", tout << "conflict\n";); - // int * p = 0; - // *p = 0; + TRACE("sat", tout << "conflict: " << not_l << "\n";); m_inconsistent = true; m_conflict = c; m_not_l = not_l; @@ -707,9 +705,12 @@ namespace sat { try { if (inconsistent()) return l_false; init_search(); + propagate(false); + if (inconsistent()) return l_false; init_assumptions(num_lits, lits); propagate(false); if (inconsistent()) { + TRACE("sat", tout << "initialized -> inconsistent\n";); if (tracking_assumptions()) resolve_conflict(); return l_false; @@ -721,7 +722,7 @@ namespace sat { if (r != l_undef) return r; pop(scope_lvl()); - reinit_assumptions(); + SASSERT(scope_lvl() == 1); m_conflicts_since_restart = 0; m_restart_threshold = m_config.m_restart_initial; } @@ -820,7 +821,7 @@ namespace sat { SASSERT(phase != l_undef); literal next_lit(next, phase == l_false); assign(next_lit, justification()); - TRACE("sat_decide", tout << "next-case-split: " << next_lit << "\n";); + TRACE("sat_decide", tout << scope_lvl() << ": next-case-split: " << next_lit << "\n";); return true; } @@ -839,8 +840,10 @@ namespace sat { return l_undef; if (scope_lvl() == 0) { cleanup(); // cleaner may propagate frozen clauses - if (inconsistent()) + if (inconsistent()) { + TRACE("sat", tout << "conflict at level 0\n";); return l_false; + } gc(); } } @@ -883,25 +886,24 @@ namespace sat { SASSERT(is_external((_l_).var())); \ m_assumption_set.insert(_l_); \ m_assumptions.push_back(_l_); \ - mk_clause_core(1, &(_l_), false); \ + assign(_l_, justification()); \ - for (unsigned i = 0; i < num_lits; ++i) { + for (unsigned i = 0; !inconsistent() && i < num_lits; ++i) { literal lit = lits[i]; _INSERT_LIT(lit); } - for (unsigned i = 0; i < m_user_scope_literals.size(); ++i) { + for (unsigned i = 0; !inconsistent() && i < m_user_scope_literals.size(); ++i) { literal nlit = ~m_user_scope_literals[i]; _INSERT_LIT(nlit); } - TRACE("sat", display(tout);); } void solver::reinit_assumptions() { - if (tracking_assumptions()) { + if (tracking_assumptions() && scope_lvl() == 0) { push(); - for (unsigned i = 0; i < m_assumptions.size(); ++i) { + for (unsigned i = 0; !inconsistent() && i < m_assumptions.size(); ++i) { literal l = m_assumptions[i]; - mk_clause_core(1, &l, false); + assign(l, justification()); } } } @@ -927,17 +929,15 @@ namespace sat { m_next_simplify = 0; m_stopwatch.reset(); m_stopwatch.start(); + m_core.reset(); + TRACE("sat", display(tout);); } /** \brief Apply all simplifications. */ void solver::simplify_problem() { - - if (tracking_assumptions()) { - // NB. simplification is disabled when tracking assumptions. - return; - } + pop_core(scope_lvl()); SASSERT(scope_lvl() == 0); @@ -972,6 +972,7 @@ namespace sat { m_ext->clauses_modifed(); m_ext->simplify(); } + reinit_assumptions(); } void solver::sort_watch_lits() { @@ -993,7 +994,7 @@ namespace sat { } TRACE("sat_mc_bug", m_mc.display(tout);); m_mc(m_model); - TRACE("sat_model", for (bool_var v = 0; v < num; v++) tout << v << ": " << m_model[v] << "\n";); + TRACE("sat", for (bool_var v = 0; v < num; v++) tout << v << ": " << m_model[v] << "\n";); #ifndef _EXTERNAL_RELEASE IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "\"checking model\"\n";); @@ -1043,7 +1044,7 @@ namespace sat { } if (!m_mc.check_model(m)) ok = false; - CTRACE("sat_model_bug", !ok, tout << m << "\n";); + TRACE("sat", tout << "checl: " << ok << "\n" << m << "\n";); return ok; } @@ -1055,7 +1056,6 @@ namespace sat { << " :time " << std::fixed << std::setprecision(2) << m_stopwatch.get_current_seconds() << ")\n";); IF_VERBOSE(30, display_status(verbose_stream());); pop(scope_lvl()); - reinit_assumptions(); m_conflicts_since_restart = 0; switch (m_config.m_restart) { case RS_GEOMETRIC: @@ -1328,7 +1328,7 @@ namespace sat { break; } } - TRACE("sat_gc", tout << "after cleanup:\n" << mk_lits_pp(j, c.begin()) << "\n";); + TRACE("sat", tout << "after cleanup:\n" << mk_lits_pp(j, c.begin()) << "\n";); unsigned new_sz = j; switch (new_sz) { case 0: @@ -1393,11 +1393,14 @@ namespace sat { m_conflicts_since_gc++; m_conflict_lvl = get_max_lvl(m_not_l, m_conflict); + TRACE("sat", tout << "conflict detected at level " << m_conflict_lvl << " for "; + if (m_not_l == literal()) tout << "null literal\n"; + else tout << m_not_l << "\n";); + if (m_conflict_lvl <= 1 && tracking_assumptions()) { resolve_conflict_for_unsat_core(); return false; } - TRACE("sat_conflict", tout << "conflict detected\n";); if (m_conflict_lvl == 0) { return false; } @@ -1530,7 +1533,7 @@ namespace sat { } void solver::resolve_conflict_for_unsat_core() { - TRACE("sat_conflict", display(tout);); + TRACE("sat", display(tout);); if (m_conflict_lvl == 0) { return; @@ -1541,8 +1544,11 @@ namespace sat { int idx = skip_literals_above_conflict_level(); if (m_not_l != null_literal) { - TRACE("sat_conflict", tout << "not_l: " << m_not_l << "\n";); + TRACE("sat", tout << "not_l: " << m_not_l << "\n";); process_antecedent_for_unsat_core(m_not_l); + if (is_assumption(~m_not_l)) { + m_core.push_back(~m_not_l); + } } @@ -1550,8 +1556,8 @@ namespace sat { justification js = m_conflict; do { - TRACE("sat_conflict_detail", tout << "processing consequent: " << consequent << "\n"; - tout << "js kind: " << js.get_kind() << "\n";); + TRACE("sat", tout << "processing consequent: " << consequent << "\n"; + tout << "js kind: " << js << "\n";); switch (js.get_kind()) { case justification::NONE: break; @@ -1902,6 +1908,7 @@ namespace sat { for (; i < sz; i++) { literal l = m_lemma[i]; if (implied_by_marked(l)) { + TRACE("sat", tout << "drop: " << l << "\n";); m_unmark.push_back(l.var()); } else { @@ -2063,6 +2070,7 @@ namespace sat { // ----------------------- void solver::push() { SASSERT(!inconsistent()); + TRACE("sat", tout << "q:" << m_qhead << " trail: " << m_trail.size() << "\n";); SASSERT(m_qhead == m_trail.size()); m_scopes.push_back(scope()); scope & s = m_scopes.back(); @@ -2075,6 +2083,11 @@ namespace sat { } void solver::pop(unsigned num_scopes) { + pop_core(num_scopes); + reinit_assumptions(); + } + + void solver::pop_core(unsigned num_scopes) { if (num_scopes == 0) return; if (m_ext) @@ -2144,9 +2157,6 @@ namespace sat { // void solver::user_push() { - if (m_level.size() == 0) { - return; - } literal lit; if (m_user_scope_literal_pool.empty()) { bool_var new_v = mk_var(true, false); @@ -2189,7 +2199,7 @@ namespace sat { void solver::user_pop(unsigned num_scopes) { pop_to_base_level(); - while (num_scopes > 0 && !m_user_scope_literals.empty()) { + while (num_scopes > 0) { literal lit = m_user_scope_literals.back(); m_user_scope_literal_pool.push_back(lit); m_user_scope_literals.pop_back(); @@ -2203,6 +2213,8 @@ namespace sat { } void solver::pop_to_base_level() { + m_assumptions.reset(); + m_assumption_set.reset(); pop(scope_lvl()); } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 8c39599bb..8e4c9911b 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -352,6 +352,7 @@ namespace sat { // ----------------------- void push(); void pop(unsigned num_scopes); + void pop_core(unsigned num_scopes); void unassign_vars(unsigned old_sz); void reinit_clauses(unsigned old_sz); diff --git a/src/sat/tactic/atom2bool_var.cpp b/src/sat/tactic/atom2bool_var.cpp index 58abc2807..48ad85152 100644 --- a/src/sat/tactic/atom2bool_var.cpp +++ b/src/sat/tactic/atom2bool_var.cpp @@ -90,18 +90,22 @@ struct collect_boolean_interface_proc { template void operator()(T const & g) { unsigned sz = g.size(); - ptr_vector deps; + ptr_vector deps, all_deps; for (unsigned i = 0; i < sz; i++) { - process(g.form(i)); if (g.dep(i)) { deps.reset(); m.linearize(g.dep(i), deps); - for (unsigned j = 0; j < deps.size(); ++j) { - quick_for_each_expr(proc, tvisited, deps[j]); - } - + all_deps.append(deps); } } + + for (unsigned i = 0; i < all_deps.size(); i++) { + quick_for_each_expr(proc, tvisited, all_deps[i]); + } + for (unsigned i = 0; i < sz; i++) { + process(g.form(i)); + } + } void operator()(unsigned sz, expr * const * fs) { diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 636e8920f..5d9753a82 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -394,7 +394,6 @@ struct goal2sat::imp { expr_ref_vector fmls(m); for (unsigned idx = 0; idx < size; idx++) { f = g.form(idx); - TRACE("sat", tout << "Formula: " << mk_pp(f, m) << "\n";); // Add assumptions. if (g.dep(idx)) { deps.reset(); @@ -403,21 +402,28 @@ struct goal2sat::imp { fmls.push_back(f); for (unsigned i = 0; i < deps.size(); ++i) { expr * d = deps[i]; - expr * d1; + expr * d1 = d; SASSERT(m.is_bool(d)); - if (m.is_not(d, d1)) { - insert_dep(d1, true); - fmls.push_back(d1); + bool sign = m.is_not(d, d1); + + insert_dep(d1, sign); + if (d == f) { + goto skip_dep; + } + if (sign) { + d_new = d1; } else { - insert_dep(d, false); - fmls.push_back(m.mk_not(d)); + d_new = m.mk_not(d); } - } + fmls.push_back(d_new); + } f = m.mk_or(fmls.size(), fmls.c_ptr()); - TRACE("sat", tout << mk_pp(f, m) << "\n";); } + TRACE("sat", tout << mk_pp(f, m) << "\n";); process(f); + skip_dep: + ; } } From 6438c477b35e64ae5b17f6d04a7541ed09a4fa37 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 31 Jul 2014 23:35:41 -0700 Subject: [PATCH 443/925] working on maxres Signed-off-by: Nikolaj Bjorner --- src/opt/dual_maxres.cpp | 8 ++++++++ src/opt/maxres.cpp | 16 ++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/opt/dual_maxres.cpp b/src/opt/dual_maxres.cpp index 5895f0573..3595149bf 100644 --- a/src/opt/dual_maxres.cpp +++ b/src/opt/dual_maxres.cpp @@ -64,6 +64,7 @@ class dual_maxres : public maxsmt_solver_base { expr_ref_vector m_B; expr_ref_vector m_asms; obj_map m_asm2weight; + obj_map m_soft2asm; ptr_vector m_new_core; mus m_mus; expr_ref_vector m_trail; @@ -89,6 +90,11 @@ public: void add_soft(expr* e, rational const& w) { TRACE("opt", tout << mk_pp(e, m) << "\n";); expr_ref asum(m), fml(m); + expr* f; + if (m_soft2asm.find(e, f)) { + m_asm2weight.find(f) += w; + return; + } if (is_literal(e)) { asum = e; } @@ -97,6 +103,7 @@ public: fml = m.mk_iff(asum, e); m_s->assert_expr(fml); } + m_soft2asm.insert(e, asum); new_assumption(asum, w); m_upper += w; } @@ -461,6 +468,7 @@ public: m_upper.reset(); m_lower.reset(); m_asm2weight.reset(); + m_soft2asm.reset(); m_trail.reset(); for (unsigned i = 0; i < m_soft.size(); ++i) { add_soft(m_soft[i].get(), m_weights[i]); diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 58cd241d0..ecdd788a9 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -63,6 +63,12 @@ public: TRACE("opt", tout << mk_pp(e, m) << "\n";); expr_ref asum(m), fml(m); app_ref cls(m); + info inf(0,rational(0)); + if (m_asm2info.find(e, inf)) { + inf.m_weight += w; + m_asm2info.insert(e, inf); + return; + } cls = mk_cls(e); m_trail.push_back(cls); if (is_literal(e)) { @@ -104,15 +110,21 @@ public: return l_undef; } switch (is_sat) { - case l_true: + case l_true: { m_s->get_model(m_model); + expr_ref tmp(m); + DEBUG_CODE( + for (unsigned i = 0; i < m_asms.size(); ++i) { + VERIFY(m_model->eval(m_asms[i].get(), tmp)); + SASSERT(m.is_true(tmp)); + }); for (unsigned i = 0; i < m_soft.size(); ++i) { - expr_ref tmp(m); VERIFY(m_model->eval(m_soft[i].get(), tmp)); m_assignment[i] = m.is_true(tmp); } m_upper = m_lower; return l_true; + } case l_undef: return l_undef; default: From b9287343487fdaf208fa32e9fc5c5a55478a462d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 1 Aug 2014 16:11:52 -0700 Subject: [PATCH 444/925] perf improvements, mus Signed-off-by: Nikolaj Bjorner --- src/opt/inc_sat_solver.cpp | 16 ++-- src/opt/mus.cpp | 4 +- src/sat/sat_mus.cpp | 163 +++++++++++++++++++++++++++++++++++++ src/sat/sat_mus.h | 44 ++++++++++ src/sat/sat_params.pyg | 1 + src/sat/sat_solver.cpp | 29 ++++--- src/sat/sat_solver.h | 6 +- 7 files changed, 242 insertions(+), 21 deletions(-) create mode 100644 src/sat/sat_mus.cpp create mode 100644 src/sat/sat_mus.h diff --git a/src/opt/inc_sat_solver.cpp b/src/opt/inc_sat_solver.cpp index 72cff950a..c307ef6ae 100644 --- a/src/opt/inc_sat_solver.cpp +++ b/src/opt/inc_sat_solver.cpp @@ -43,7 +43,6 @@ class inc_sat_solver : public solver { model_ref m_model; model_converter_ref m_mc; tactic_ref m_preprocess; - statistics m_stats; unsigned m_num_scopes; sat::literal_vector m_asms; goal_ref_buffer m_subgoals; @@ -89,7 +88,8 @@ public: virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions) { m_solver.pop_to_base_level(); dep2asm_t dep2asm; - + + m_model.reset(); lbool r = internalize_formulas(); if (r != l_true) return r; r = internalize_assumptions(num_assumptions, assumptions, dep2asm); @@ -98,7 +98,6 @@ public: r = m_solver.check(m_asms.size(), m_asms.c_ptr()); switch (r) { case l_true: - extract_model(); break; case l_false: // TBD: expr_dependency core is not accounted for. @@ -109,7 +108,6 @@ public: default: break; } - m_solver.collect_statistics(m_stats); return r; } virtual void set_cancel(bool f) { @@ -155,13 +153,17 @@ public: } virtual void collect_statistics(statistics & st) const { - st.copy(m_stats); + m_preprocess->collect_statistics(st); + m_solver.collect_statistics(st); } virtual void get_unsat_core(ptr_vector & r) { r.reset(); r.append(m_core.size(), m_core.c_ptr()); } virtual void get_model(model_ref & m) { + if (!m_model) { + extract_model(); + } m = m_model; } virtual proof * get_proof() { @@ -190,7 +192,6 @@ private: } catch (tactic_exception & ex) { IF_VERBOSE(0, verbose_stream() << "exception in tactic " << ex.msg() << "\n";); - m_preprocess->collect_statistics(m_stats); return l_undef; } m_mc = concat(m_mc.get(), m_mc2.get()); @@ -270,6 +271,9 @@ private: } + // TBD: this is super-expensive because of the + // bit-blasting model converter. + void extract_model() { model_ref md = alloc(model, m); sat::model const & ll_m = m_solver.get_model(); diff --git a/src/opt/mus.cpp b/src/opt/mus.cpp index 9204371bc..06d77aad9 100644 --- a/src/opt/mus.cpp +++ b/src/opt/mus.cpp @@ -123,7 +123,7 @@ struct mus::imp { TRACE("opt", display_vec(tout << "core: ", core); display_vec(tout << "mus: ", mus); - display_vec(tout << "model: ", model); + // display_vec(tout << "model: ", model); ); core.pop_back(); expr* cls = m_cls2expr[cls_id].get(); @@ -140,8 +140,8 @@ struct mus::imp { case l_true: assumptions.push_back(cls); mus.push_back(cls_id); - extract_model(model); if (m_rmr_enabled) { + extract_model(model); sz = core.size(); core.append(mus); rmr(core, mus, model); diff --git a/src/sat/sat_mus.cpp b/src/sat/sat_mus.cpp new file mode 100644 index 000000000..7000191fc --- /dev/null +++ b/src/sat/sat_mus.cpp @@ -0,0 +1,163 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + sat_mus.cpp + +Abstract: + + Faster MUS extraction based on Belov et.al. HYB (Algorithm 3, 4) + +Author: + + Nikolaj Bjorner (nbjorner) 2014-20-7 + +Notes: + + Model rotation needs fixes to ensure that hard constraints are satisfied + under pertubed model. Model rotation also has o be consistent with theories. + +--*/ + +#include "sat_solver.h" +#include "sat_mus.h" + +namespace sat { + + mus::mus(solver& s):s(s) {} + + mus::~mus() {} + + void mus::reset() { + m_core.reset(); + m_mus.reset(); + m_assumptions.reset(); + } + + void mus::set_core() { + m_core.append(m_mus); + s.m_core.reset(); + s.m_core.append(m_core); + } + + lbool mus::operator()() { + reset(); + literal_vector& core = m_core; + literal_vector& mus = m_mus; + literal_vector& assumptions = m_assumptions; + core.append(s.get_core()); + SASSERT(!core.empty()); + + if (core.size() == 1) { + return l_true; + } + while (!core.empty()) { + TRACE("sat", + tout << "core: " << core << "\n"; + tout << "mus: " << mus << "\n";); + + if (s.m_cancel) { + set_core(); + return l_undef; + } + literal lit = core.back(); + core.pop_back(); + unsigned sz = assumptions.size(); + assumptions.push_back(~lit); + assumptions.append(core); + lbool is_sat = s.check(assumptions.size(), assumptions.c_ptr()); + assumptions.resize(sz); + switch (is_sat) { + case l_undef: + core.push_back(lit); + set_core(); + return l_undef; + case l_true: { + assumptions.push_back(lit); + mus.push_back(lit); + unsigned sz = core.size(); + core.append(mus); + rmr(); + core.resize(sz); + break; + } + case l_false: + core.reset(); + for (unsigned i = 0; i < s.get_core().size(); ++i) { + literal lit = s.get_core()[i]; + if (!mus.contains(lit)) { + core.push_back(lit); + } + } + break; + } + } + return l_true; + } + + lbool mus::eval(literal l) const { + return value_at(l, s.get_model()); + } + + void mus::rmr() { + model& model = s.m_model; + literal lit = m_mus.back(); + literal assumption_lit; + SASSERT(eval(lit) == l_false); // literal is false in current model. + find_swappable(lit); + for (unsigned i = 0; i < m_toswap.size(); ++i) { + lit = m_toswap[i]; + SASSERT(eval(lit) == l_false); + model[lit.var()] = ~model[lit.var()]; // swap assignment + if (has_single_unsat(assumption_lit) && !m_mus.contains(assumption_lit)) { + m_mus.push_back(assumption_lit); + rmr(); + } + model[lit.var()] = ~model[lit.var()]; // swap assignment back + } + } + + bool mus::has_single_unsat(literal& assumption_lit) { + model const& model = s.get_model(); + return false; + } + + void mus::find_swappable(literal lit) { + m_toswap.reset(); + } + +} + +#if 0 + + + bool has_single_unsat(svector const& model, unsigned& cls_id) const { + cls_id = UINT_MAX; + for (unsigned i = 0; i < m_cls2lits.size(); ++i) { + if (!eval(model, m_cls2lits[i])) { + if (cls_id == UINT_MAX) { + cls_id = i; + } + else { + return false; + } + } + } + TRACE("opt", display_vec(tout << "clause: " << cls_id << " model: ", model);); + return cls_id != UINT_MAX; + } + + bool eval(svector const& model, smt::literal_vector const& cls) const { + bool result = false; + for (unsigned i = 0; !result && i < cls.size(); ++i) { + result = (model[cls[i].var()] != cls[i].sign()); + } + TRACE("opt", display_vec(tout << "model: ", model); + display_vec(tout << "clause: ", cls); + tout << "result: " << result << "\n";); + return result; + } + + +#endif diff --git a/src/sat/sat_mus.h b/src/sat/sat_mus.h new file mode 100644 index 000000000..70ba4d21c --- /dev/null +++ b/src/sat/sat_mus.h @@ -0,0 +1,44 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + mus.h + +Abstract: + + Faster MUS extraction based on Belov et.al. HYB (Algorithm 3, 4) + +Author: + + Nikolaj Bjorner (nbjorner) 2014-20-7 + +Notes: + +--*/ +#ifndef _SAT_MUS_H_ +#define _SAT_MUS_H_ + +namespace sat { + class mus { + literal_vector m_core; + literal_vector m_assumptions; + literal_vector m_mus; + literal_vector m_toswap; + solver& s; + public: + mus(solver& s); + ~mus(); + lbool operator()(); + private: + void rmr(); + bool has_single_unsat(literal& assumption_lit); + void find_swappable(literal lit); + void reset(); + void set_core(); + lbool eval(literal l) const; + }; + +}; + +#endif diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 570ca5276..fd35e5d64 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -18,4 +18,5 @@ def_module_params('sat', ('gc.k', UINT, 7, 'learned clauses that are inactive for k gc rounds are permanently deleted (only used in dyn_psm)'), ('minimize_lemmas', BOOL, True, 'minimize learned clauses'), ('dyn_sub_res', BOOL, True, 'dynamic subsumption resolution for minimizing learned clauses'), + ('minimize_core', BOOL, False, 'minimize computed core'), ('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'))) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index cfd83955d..d0d3236c8 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -39,13 +39,15 @@ namespace sat { m_scc(*this, p), m_asymm_branch(*this, p), m_probing(*this, p), + m_mus(*this), m_inconsistent(false), m_num_frozen(0), m_activity_inc(128), m_case_split_queue(m_activity), m_qhead(0), m_scope_lvl(0), - m_params(p) { + m_params(p), + m_minimize_core(p.get_bool("minimize_core", false)) { m_config.updt_params(p); } @@ -710,7 +712,6 @@ namespace sat { init_assumptions(num_lits, lits); propagate(false); if (inconsistent()) { - TRACE("sat", tout << "initialized -> inconsistent\n";); if (tracking_assumptions()) resolve_conflict(); return l_false; @@ -721,8 +722,7 @@ namespace sat { lbool r = bounded_search(); if (r != l_undef) return r; - pop(scope_lvl()); - SASSERT(scope_lvl() == 1); + pop_reinit(scope_lvl()); m_conflicts_since_restart = 0; m_restart_threshold = m_config.m_restart_initial; } @@ -900,10 +900,10 @@ namespace sat { void solver::reinit_assumptions() { if (tracking_assumptions() && scope_lvl() == 0) { + TRACE("sat", tout << m_assumptions.size() << "\n";); push(); for (unsigned i = 0; !inconsistent() && i < m_assumptions.size(); ++i) { - literal l = m_assumptions[i]; - assign(l, justification()); + assign(m_assumptions[i], justification()); } } } @@ -937,7 +937,8 @@ namespace sat { \brief Apply all simplifications. */ void solver::simplify_problem() { - pop_core(scope_lvl()); + pop(scope_lvl()); + m_trail.reset(); SASSERT(scope_lvl() == 0); @@ -1055,7 +1056,7 @@ namespace sat { << " :restarts " << m_stats.m_restart << mk_stat(*this) << " :time " << std::fixed << std::setprecision(2) << m_stopwatch.get_current_seconds() << ")\n";); IF_VERBOSE(30, display_status(verbose_stream());); - pop(scope_lvl()); + pop_reinit(scope_lvl()); m_conflicts_since_restart = 0; switch (m_config.m_restart) { case RS_GEOMETRIC: @@ -1508,7 +1509,7 @@ namespace sat { unsigned glue = num_diff_levels(m_lemma.size(), m_lemma.c_ptr()); - pop(m_scope_lvl - new_scope_lvl); + pop_reinit(m_scope_lvl - new_scope_lvl); TRACE("sat_conflict_detail", display(tout); tout << "assignment:\n"; display_assignment(tout);); clause * lemma = mk_clause_core(m_lemma.size(), m_lemma.c_ptr(), true); if (lemma) { @@ -1620,6 +1621,9 @@ namespace sat { } while (idx > 0); reset_unmark(old_size); + if (m_minimize_core) { + m_mus(); //ignore return value on cancelation. + } } @@ -2082,12 +2086,12 @@ namespace sat { m_ext->push(); } - void solver::pop(unsigned num_scopes) { - pop_core(num_scopes); + void solver::pop_reinit(unsigned num_scopes) { + pop(num_scopes); reinit_assumptions(); } - void solver::pop_core(unsigned num_scopes) { + void solver::pop(unsigned num_scopes) { if (num_scopes == 0) return; if (m_ext) @@ -2232,6 +2236,7 @@ namespace sat { m_probing.updt_params(p); m_scc.updt_params(p); m_rand.set_seed(p.get_uint("random_seed", 0)); + m_minimize_core = p.get_bool("minimize_core", false); } void solver::collect_param_descrs(param_descrs & d) { diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 8e4c9911b..91ecbc3fb 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -32,6 +32,7 @@ Revision History: #include"sat_asymm_branch.h" #include"sat_iff3_finder.h" #include"sat_probing.h" +#include"sat_mus.h" #include"params.h" #include"statistics.h" #include"stopwatch.h" @@ -79,6 +80,7 @@ namespace sat { scc m_scc; asymm_branch m_asymm_branch; probing m_probing; + mus m_mus; bool m_inconsistent; // A conflict is usually a single justification. That is, a justification // for false. If m_not_l is not null_literal, then m_conflict is a @@ -121,6 +123,7 @@ namespace sat { literal_vector m_assumptions; literal_set m_assumption_set; literal_vector m_core; + bool m_minimize_core; void del_clauses(clause * const * begin, clause * const * end); @@ -132,6 +135,7 @@ namespace sat { friend class asymm_branch; friend class probing; friend class iff3_finder; + friend class mus; friend struct mk_stat; public: solver(params_ref const & p, extension * ext); @@ -352,7 +356,7 @@ namespace sat { // ----------------------- void push(); void pop(unsigned num_scopes); - void pop_core(unsigned num_scopes); + void pop_reinit(unsigned num_scopes); void unassign_vars(unsigned old_sz); void reinit_clauses(unsigned old_sz); From 8814ba0629f542e30239e7966ddb2b419f61885f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 2 Aug 2014 12:27:57 -0700 Subject: [PATCH 445/925] testing maxres with sat core Signed-off-by: Nikolaj Bjorner --- src/opt/dual_maxres.cpp | 5 +- src/opt/maxres.cpp | 183 ++++++++++++++++++++-------------------- src/opt/maxsmt.cpp | 15 +--- src/opt/maxsmt.h | 1 - src/opt/mus.cpp | 133 ++--------------------------- src/opt/mus.h | 2 +- src/sat/sat_config.cpp | 1 + src/sat/sat_config.h | 2 + src/sat/sat_mus.cpp | 131 +++++++++++++++------------- src/sat/sat_mus.h | 3 +- src/sat/sat_solver.cpp | 8 +- src/sat/sat_solver.h | 1 - 12 files changed, 187 insertions(+), 298 deletions(-) diff --git a/src/opt/dual_maxres.cpp b/src/opt/dual_maxres.cpp index 3595149bf..292dc5e72 100644 --- a/src/opt/dual_maxres.cpp +++ b/src/opt/dual_maxres.cpp @@ -321,9 +321,12 @@ public: } lbool minimize_core(ptr_vector& core) { + if (m_sat_enabled) { + return l_true; + } m_mus.reset(); for (unsigned i = 0; i < core.size(); ++i) { - m_mus.add_soft(core[i], 1, core.c_ptr() + i); + m_mus.add_soft(core[i]); } unsigned_vector mus_idx; lbool is_sat = m_mus.get_mus(mus_idx); diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index ecdd788a9..393d00f85 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -27,16 +27,9 @@ using namespace opt; class maxres : public maxsmt_solver_base { - struct info { - app* m_cls; - rational m_weight; - info(app* cls, rational const& w): - m_cls(cls), m_weight(w) {} - info(): m_cls(0) {} - }; expr_ref_vector m_B; expr_ref_vector m_asms; - obj_map m_asm2info; + obj_map m_asm2weight; ptr_vector m_new_core; mus m_mus; expr_ref_vector m_trail; @@ -63,14 +56,12 @@ public: TRACE("opt", tout << mk_pp(e, m) << "\n";); expr_ref asum(m), fml(m); app_ref cls(m); - info inf(0,rational(0)); - if (m_asm2info.find(e, inf)) { - inf.m_weight += w; - m_asm2info.insert(e, inf); + rational weight(0); + if (m_asm2weight.find(e, weight)) { + weight += w; + m_asm2weight.insert(e, weight); return; } - cls = mk_cls(e); - m_trail.push_back(cls); if (is_literal(e)) { asum = e; } @@ -79,21 +70,18 @@ public: fml = m.mk_iff(asum, e); m_s->assert_expr(fml); } - new_assumption(asum, cls, w); + new_assumption(asum, w); m_upper += w; } - void new_assumption(expr* e, app* cls, rational const& w) { + void new_assumption(expr* e, rational const& w) { TRACE("opt", tout << "insert: " << mk_pp(e, m) << " : " << w << "\n";); - info inf(cls, w); - m_asm2info.insert(e, inf); + m_asm2weight.insert(e, w); m_asms.push_back(e); m_trail.push_back(e); } lbool operator()() { - expr_ref fml(m); - ptr_vector core; solver::scoped_push _sc(*m_s.get()); init(); init_local(); @@ -125,28 +113,13 @@ public: m_upper = m_lower; return l_true; } + case l_false: + is_sat = process_unsat(); + if (is_sat != l_true) return is_sat; + break; case l_undef: return l_undef; default: - core.reset(); - m_s->get_unsat_core(core); - TRACE("opt", display_vec(tout << "core: ", core.size(), core.c_ptr());); - SASSERT(!core.empty()); - is_sat = minimize_core(core); - SASSERT(!core.empty()); - if (core.empty()) { - return l_false; - } - if (is_sat != l_true) { - return is_sat; - } - remove_core(core); - rational w = split_core(core); - TRACE("opt", display_vec(tout << "minimized core: ", core.size(), core.c_ptr());); - max_resolve(core, w); - fml = m.mk_not(m.mk_and(m_B.size(), m_B.c_ptr())); - m_s->assert_expr(fml); - m_lower += w; break; } IF_VERBOSE(1, verbose_stream() << "(opt.max_res [" << m_lower << ":" << m_upper << "])\n";); @@ -154,13 +127,78 @@ public: return l_true; } + lbool get_cores(vector >& cores) { + // assume m_s is unsat. + lbool is_sat = l_false; + expr_ref_vector asms(m_asms); + cores.reset(); + ptr_vector core; + while (is_sat == l_false) { + core.reset(); + m_s->get_unsat_core(core); + is_sat = minimize_core(core); + if (is_sat != l_true) { + break; + } + cores.push_back(core); + // TBD: ad hoc to avoid searching for large cores.. + if (core.size() >= 3) { + break; + } + remove_soft(core, asms); + TRACE("opt", + display_vec(tout << "core: ", core.size(), core.c_ptr()); + display_vec(tout << "assumptions: ", asms.size(), asms.c_ptr());); + is_sat = m_s->check_sat(asms.size(), asms.c_ptr()); + } + TRACE("opt", + tout << "num cores: " << cores.size() << "\n"; + for (unsigned i = 0; i < cores.size(); ++i) { + for (unsigned j = 0; j < cores[i].size(); ++j) { + tout << mk_pp(cores[i][j], m) << " "; + } + tout << "\n"; + } + tout << "num satisfying: " << asms.size() << "\n";); + + return is_sat; + } + + + lbool process_unsat() { + vector > cores; + lbool is_sat = get_cores(cores); + if (is_sat != l_true) { + return is_sat; + } + if (cores.empty()) { + return l_false; + } + for (unsigned i = 0; is_sat == l_true && i < cores.size(); ++i) { + is_sat = process_unsat(cores[i]); + } + return is_sat; + } + + lbool process_unsat(ptr_vector& core) { + expr_ref fml(m); + remove_core(core); + rational w = split_core(core); + TRACE("opt", display_vec(tout << "minimized core: ", core.size(), core.c_ptr());); + max_resolve(core, w); + fml = m.mk_not(m.mk_and(m_B.size(), m_B.c_ptr())); + m_s->assert_expr(fml); + m_lower += w; + return l_true; + } + lbool minimize_core(ptr_vector& core) { + if (m_sat_enabled) { + return l_true; + } m_mus.reset(); for (unsigned i = 0; i < core.size(); ++i) { - app* cls = get_clause(core[i]); - SASSERT(cls); - SASSERT(m.is_or(cls)); - m_mus.add_soft(core[i], cls->get_num_args(), cls->get_args()); + m_mus.add_soft(core[i]); } unsigned_vector mus_idx; lbool is_sat = m_mus.get_mus(mus_idx); @@ -177,11 +215,7 @@ public: } rational get_weight(expr* e) { - return m_asm2info.find(e).m_weight; - } - - app* get_clause(expr* e) { - return m_asm2info.find(e).m_cls; + return m_asm2weight.find(e); } rational split_core(ptr_vector const& core) { @@ -200,7 +234,7 @@ public: rational w2 = get_weight(core[i]); if (w2 > w) { rational w3 = w2 - w; - new_assumption(core[i], get_clause(core[i]), w3); + new_assumption(core[i], w3); } } return w; @@ -246,55 +280,25 @@ public: asum = mk_fresh_bool("a"); cls = m.mk_or(b_i1, d); fml = m.mk_iff(asum, cls); - cls = mk_cls(cls); - m_trail.push_back(cls); - new_assumption(asum, cls, w); + new_assumption(asum, w); m_s->assert_expr(fml); } } - app_ref mk_cls(expr* e) { - expr_ref_vector disj(m), todo(m); - expr_ref f(m); - app_ref result(m); - expr* e1, *e2; - todo.push_back(e); - while (!todo.empty()) { - f = todo.back(); - todo.pop_back(); - if (m.is_implies(f, e1, e2)) { - todo.push_back(m.mk_not(e1)); - todo.push_back(e2); - } - else if (m.is_not(f, e1) && m.is_not(e1, e2)) { - todo.push_back(e2); - } - else if (m.is_or(f)) { - todo.append(to_app(f)->get_num_args(), to_app(f)->get_args()); - } - else if (m.is_not(f, e1) && m.is_and(e1)) { - for (unsigned i = 0; i < to_app(e1)->get_num_args(); ++i) { - todo.push_back(m.mk_not(to_app(e1)->get_arg(i))); - } - } - else { - disj.push_back(f); - } - } - result = m.mk_or(disj.size(), disj.c_ptr()); - return result; - } - - void remove_core(ptr_vector const& core) { - for (unsigned i = 0; i < m_asms.size(); ++i) { - if (core.contains(m_asms[i].get())) { - m_asms[i] = m_asms.back(); - m_asms.pop_back(); + void remove_soft(ptr_vector const& core, expr_ref_vector& asms) { + for (unsigned i = 0; i < asms.size(); ++i) { + if (core.contains(asms[i].get())) { + asms[i] = asms.back(); + asms.pop_back(); --i; } } } + void remove_core(ptr_vector const& core) { + remove_soft(core, m_asms); + } + virtual void set_cancel(bool f) { maxsmt_solver_base::set_cancel(f); m_mus.set_cancel(f); @@ -303,7 +307,6 @@ public: void init_local() { m_upper.reset(); m_lower.reset(); - m_asm2info.reset(); m_trail.reset(); for (unsigned i = 0; i < m_soft.size(); ++i) { add_soft(m_soft[i].get(), m_weights[i]); diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 347f4bf3a..d183ab4fc 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -130,6 +130,7 @@ namespace opt { } void maxsmt_solver_base::enable_inc_bvsat() { + m_params.set_bool("minimize_core", true); solver* sat_solver = mk_inc_sat_solver(m, m_params); unsigned sz = s().get_num_assertions(); for (unsigned i = 0; i < sz; ++i) { @@ -138,25 +139,11 @@ namespace opt { m_s = sat_solver; } - void maxsmt_solver_base::enable_noninc_bvsat() { - tactic_ref pb2bv = mk_card2bv_tactic(m, m_params); - tactic_ref bv2sat = mk_qfbv_tactic(m, m_params); - tactic_ref tac = and_then(pb2bv.get(), bv2sat.get()); - solver* sat_solver = mk_tactic2solver(m, tac.get(), m_params); - unsigned sz = s().get_num_assertions(); - for (unsigned i = 0; i < sz; ++i) { - sat_solver->assert_expr(s().get_assertion(i)); - } - unsigned lvl = m_s->get_scope_level(); - while (lvl > 0) { sat_solver->push(); --lvl; } - m_s = sat_solver; - } void maxsmt_solver_base::enable_bvsat() { if (m_enable_sat && !m_sat_enabled && probe_bv()) { enable_inc_bvsat(); - // enable_noninc_bvsat(); m_sat_enabled = true; } } diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index f85f30d78..138670693 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -99,7 +99,6 @@ namespace opt { app* mk_fresh_bool(char const* name); private: void enable_inc_bvsat(); - void enable_noninc_bvsat(); }; /** diff --git a/src/opt/mus.cpp b/src/opt/mus.cpp index 06d77aad9..5fd246294 100644 --- a/src/opt/mus.cpp +++ b/src/opt/mus.cpp @@ -7,7 +7,7 @@ Module Name: Abstract: - Faster MUS extraction based on Belov et.al. HYB (Algorithm 3, 4) + MUS extraction. Author: @@ -35,58 +35,28 @@ struct mus::imp { ast_manager& m; expr_ref_vector m_cls2expr; obj_map m_expr2cls; - vector m_cls2lits; - expr_ref_vector m_vars; - obj_map m_var2idx; volatile bool m_cancel; - bool m_rmr_enabled; imp(ref& s, ast_manager& m): - m_s(s), m(m), m_cls2expr(m), m_vars(m), m_cancel(false), - m_rmr_enabled(false) {} + m_s(s), m(m), m_cls2expr(m), m_cancel(false) + {} void reset() { m_cls2expr.reset(); m_expr2cls.reset(); - m_cls2lits.reset(); - m_vars.reset(); - m_var2idx.reset(); - m_vars.push_back(m.mk_true()); } void set_cancel(bool f) { m_cancel = f; } - unsigned add_var(expr* v) { - unsigned idx = m_vars.size(); - if (!m_var2idx.find(v, idx)) { - m_var2idx.insert(v, idx); - m_vars.push_back(v); - } - return idx; - } - unsigned add_soft(expr* cls, unsigned sz, expr* const* args) { + unsigned add_soft(expr* cls) { SASSERT(is_uninterp_const(cls) || m.is_not(cls) && is_uninterp_const(to_app(cls)->get_arg(0))); - smt::literal_vector lits; - expr* arg; - for (unsigned i = 0; i < sz; ++i) { - if (m.is_not(args[i], arg)) { - lits.push_back(smt::literal(add_var(arg), true)); - } - else { - lits.push_back(smt::literal(add_var(args[i]), false)); - } - } - unsigned idx = m_cls2lits.size(); + unsigned idx = m_cls2expr.size(); m_expr2cls.insert(cls, idx); m_cls2expr.push_back(cls); - m_cls2lits.push_back(lits); - TRACE("opt", - tout << idx << ": " << mk_pp(cls, m) << "\n"; - display_vec(tout, lits); - ); + TRACE("opt", tout << idx << ": " << mk_pp(cls, m) << "\n";); return idx; } @@ -99,11 +69,6 @@ struct mus::imp { lbool get_mus(unsigned_vector& mus) { // SASSERT: mus does not have duplicates. - TRACE("opt", - for (unsigned i = 0; i < m_cls2lits.size(); ++i) { - display_vec(tout, m_cls2lits[i]); - } - ); unsigned_vector core; for (unsigned i = 0; i < m_cls2expr.size(); ++i) { core.push_back(i); @@ -114,16 +79,13 @@ struct mus::imp { } mus.reset(); expr_ref_vector assumptions(m); - svector model; ptr_vector core_exprs; - model.resize(m_vars.size()); while (!core.empty()) { IF_VERBOSE(1, verbose_stream() << "(opt.mus reducing core: " << core.size() << " new core: " << mus.size() << ")\n";); unsigned cls_id = core.back(); TRACE("opt", display_vec(tout << "core: ", core); display_vec(tout << "mus: ", mus); - // display_vec(tout << "model: ", model); ); core.pop_back(); expr* cls = m_cls2expr[cls_id].get(); @@ -140,13 +102,6 @@ struct mus::imp { case l_true: assumptions.push_back(cls); mus.push_back(cls_id); - if (m_rmr_enabled) { - extract_model(model); - sz = core.size(); - core.append(mus); - rmr(core, mus, model); - core.resize(sz); - } break; default: core_exprs.reset(); @@ -192,78 +147,6 @@ struct mus::imp { out << "\n"; } - void extract_model(svector& model) { - model_ref mdl; - m_s->get_model(mdl); - for (unsigned i = 0; i < m_vars.size(); ++i) { - expr_ref tmp(m); - mdl->eval(m_vars[i].get(), tmp); - model[i] = m.is_true(tmp); - } - TRACE("opt", - display_vec(tout << "model: ", model); - model_smt2_pp(tout, m, *mdl, 0); - ); - - } - - /** - Recursive model rotation. - */ - void rmr(unsigned_vector& M, unsigned_vector& mus, svector& model) { - TRACE("opt", - display_vec(tout << "core: ", M); - display_vec(tout << "mus: ", mus); - display_vec(tout << "model: ", model);); - - unsigned cls_id = mus.back(); - smt::literal_vector const& cls = m_cls2lits[cls_id]; - for (unsigned i = 0; i < cls.size(); ++i) { - smt::literal lit = cls[i]; - SASSERT(model[lit.var()] == lit.sign()); // literal evaluates to false. - model[lit.var()] = !model[lit.var()]; // swap assignment - if (has_single_unsat(model, cls_id) && - !mus.contains(cls_id) && - model_check(model, cls_id)) { - mus.push_back(cls_id); - rmr(M, mus, model); - } - model[lit.var()] = !model[lit.var()]; // swap assignment back - } - } - - bool model_check(svector const& model, unsigned cls_id) { - // model has to work for hard constraints. - return false; - } - - bool has_single_unsat(svector const& model, unsigned& cls_id) const { - cls_id = UINT_MAX; - for (unsigned i = 0; i < m_cls2lits.size(); ++i) { - if (!eval(model, m_cls2lits[i])) { - if (cls_id == UINT_MAX) { - cls_id = i; - } - else { - return false; - } - } - } - TRACE("opt", display_vec(tout << "clause: " << cls_id << " model: ", model);); - return cls_id != UINT_MAX; - } - - bool eval(svector const& model, smt::literal_vector const& cls) const { - bool result = false; - for (unsigned i = 0; !result && i < cls.size(); ++i) { - result = (model[cls[i].var()] != cls[i].sign()); - } - TRACE("opt", display_vec(tout << "model: ", model); - display_vec(tout << "clause: ", cls); - tout << "result: " << result << "\n";); - return result; - } - }; mus::mus(ref& s, ast_manager& m) { @@ -274,8 +157,8 @@ mus::~mus() { dealloc(m_imp); } -unsigned mus::add_soft(expr* cls, unsigned sz, expr* const* args) { - return m_imp->add_soft(cls, sz, args); +unsigned mus::add_soft(expr* cls) { + return m_imp->add_soft(cls); } lbool mus::get_mus(unsigned_vector& mus) { diff --git a/src/opt/mus.h b/src/opt/mus.h index 064ab3b0e..e9e3b80bd 100644 --- a/src/opt/mus.h +++ b/src/opt/mus.h @@ -33,7 +33,7 @@ namespace opt { cls is equivalent to a disjunction of args. Assume also that cls is a literal. */ - unsigned add_soft(expr* cls, unsigned sz, expr* const* args); + unsigned add_soft(expr* cls); lbool get_mus(unsigned_vector& mus); diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index cc0f97ff0..94ac37de5 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -104,6 +104,7 @@ namespace sat { m_gc_increment = p.gc_increment(); } m_minimize_lemmas = p.minimize_lemmas(); + m_minimize_core = p.minimize_core(); m_dyn_sub_res = p.dyn_sub_res(); } diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 90ebe968b..47804793d 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -68,6 +68,8 @@ namespace sat { bool m_minimize_lemmas; bool m_dyn_sub_res; + bool m_minimize_core; + symbol m_always_true; symbol m_always_false; diff --git a/src/sat/sat_mus.cpp b/src/sat/sat_mus.cpp index 7000191fc..e7eecfe4a 100644 --- a/src/sat/sat_mus.cpp +++ b/src/sat/sat_mus.cpp @@ -15,8 +15,6 @@ Author: Notes: - Model rotation needs fixes to ensure that hard constraints are satisfied - under pertubed model. Model rotation also has o be consistent with theories. --*/ @@ -32,26 +30,23 @@ namespace sat { void mus::reset() { m_core.reset(); m_mus.reset(); - m_assumptions.reset(); } - void mus::set_core() { + void mus::set_core() { m_core.append(m_mus); s.m_core.reset(); s.m_core.append(m_core); } lbool mus::operator()() { + flet _disable_min(s.m_config.m_minimize_core, false); + TRACE("sat", tout << "old core: " << s.get_core() << "\n";); + IF_VERBOSE(2, verbose_stream() << "(sat.mus " << s.get_core() << ")\n";); reset(); literal_vector& core = m_core; literal_vector& mus = m_mus; - literal_vector& assumptions = m_assumptions; core.append(s.get_core()); - SASSERT(!core.empty()); - if (core.size() == 1) { - return l_true; - } while (!core.empty()) { TRACE("sat", tout << "core: " << core << "\n"; @@ -63,29 +58,38 @@ namespace sat { } literal lit = core.back(); core.pop_back(); - unsigned sz = assumptions.size(); - assumptions.push_back(~lit); - assumptions.append(core); - lbool is_sat = s.check(assumptions.size(), assumptions.c_ptr()); - assumptions.resize(sz); + unsigned sz = mus.size(); + //mus.push_back(~lit); // TBD: measure + mus.append(core); + lbool is_sat = s.check(mus.size(), mus.c_ptr()); + mus.resize(sz); switch (is_sat) { case l_undef: core.push_back(lit); set_core(); return l_undef; case l_true: { - assumptions.push_back(lit); + SASSERT(value_at(lit, s.get_model()) == l_false); mus.push_back(lit); - unsigned sz = core.size(); + if (core.empty()) { + break; + } + sz = core.size(); core.append(mus); rmr(); core.resize(sz); + IF_VERBOSE(2, verbose_stream() << "(sat.mus.new " << mus << " " << core << ")\n";); break; } case l_false: + literal_vector const& new_core = s.get_core(); + if (new_core.contains(~lit)) { + break; + } + IF_VERBOSE(2, verbose_stream() << "(sat.mus.new " << new_core << ")\n";); core.reset(); - for (unsigned i = 0; i < s.get_core().size(); ++i) { - literal lit = s.get_core()[i]; + for (unsigned i = 0; i < new_core.size(); ++i) { + literal lit = new_core[i]; if (!mus.contains(lit)) { core.push_back(lit); } @@ -93,22 +97,23 @@ namespace sat { break; } } + TRACE("sat", tout << "new core: " << mus << "\n";); + set_core(); return l_true; } - lbool mus::eval(literal l) const { - return value_at(l, s.get_model()); - } - void mus::rmr() { model& model = s.m_model; literal lit = m_mus.back(); literal assumption_lit; - SASSERT(eval(lit) == l_false); // literal is false in current model. + SASSERT(value_at(lit, model) == l_false); + // literal is false in current model. + unsigned sz = m_toswap.size(); find_swappable(lit); - for (unsigned i = 0; i < m_toswap.size(); ++i) { + unsigned sz1 = m_toswap.size(); + for (unsigned i = sz; i < sz1; ++i) { lit = m_toswap[i]; - SASSERT(eval(lit) == l_false); + SASSERT(value_at(lit, model) == l_false); model[lit.var()] = ~model[lit.var()]; // swap assignment if (has_single_unsat(assumption_lit) && !m_mus.contains(assumption_lit)) { m_mus.push_back(assumption_lit); @@ -116,6 +121,7 @@ namespace sat { } model[lit.var()] = ~model[lit.var()]; // swap assignment back } + m_toswap.resize(sz); } bool mus::has_single_unsat(literal& assumption_lit) { @@ -123,41 +129,50 @@ namespace sat { return false; } + // + // lit is false in model. + // find clauses where ~lit occurs, and all other literals + // are false in model. + // for each of the probed literals, determine if swapping the + // assignment falsifies a hard clause, if not, add to m_toswap. + // + void mus::find_swappable(literal lit) { - m_toswap.reset(); + IF_VERBOSE(2, verbose_stream() << "(sat.mus swap " << lit << ")\n";); + unsigned sz = m_toswap.size(); + literal lit2, lit3; + model const& model = s.get_model(); + SASSERT(value_at(lit, model) == l_false); + watch_list const& wlist = s.get_wlist(lit); + watch_list::const_iterator it = wlist.begin(); + watch_list::const_iterator end = wlist.end(); + for (; it != end; ++it) { + switch (it->get_kind()) { + case watched::BINARY: + lit2 = it->get_literal(); + TRACE("sat", tout << ~lit << " " << lit2 << "\n";); + break; + case watched::TERNARY: + lit2 = it->get_literal1(); + lit3 = it->get_literal2(); + TRACE("sat", tout << ~lit << " " << lit2 << " " << lit3 << "\n";); + break; + case watched::CLAUSE: { + clause_offset cls_off = it->get_clause_offset(); + clause& c = *(s.m_cls_allocator.get_clause(cls_off)); + if (c.is_learned()) { + break; + } + TRACE("sat", tout << c << "\n";); + break; + } + case watched::EXT_CONSTRAINT: + TRACE("sat", tout << "external constraint - should avoid rmr\n";); + m_toswap.resize(sz); + return; + } + } } } -#if 0 - - - bool has_single_unsat(svector const& model, unsigned& cls_id) const { - cls_id = UINT_MAX; - for (unsigned i = 0; i < m_cls2lits.size(); ++i) { - if (!eval(model, m_cls2lits[i])) { - if (cls_id == UINT_MAX) { - cls_id = i; - } - else { - return false; - } - } - } - TRACE("opt", display_vec(tout << "clause: " << cls_id << " model: ", model);); - return cls_id != UINT_MAX; - } - - bool eval(svector const& model, smt::literal_vector const& cls) const { - bool result = false; - for (unsigned i = 0; !result && i < cls.size(); ++i) { - result = (model[cls[i].var()] != cls[i].sign()); - } - TRACE("opt", display_vec(tout << "model: ", model); - display_vec(tout << "clause: ", cls); - tout << "result: " << result << "\n";); - return result; - } - - -#endif diff --git a/src/sat/sat_mus.h b/src/sat/sat_mus.h index 70ba4d21c..b2643ade6 100644 --- a/src/sat/sat_mus.h +++ b/src/sat/sat_mus.h @@ -22,7 +22,6 @@ Notes: namespace sat { class mus { literal_vector m_core; - literal_vector m_assumptions; literal_vector m_mus; literal_vector m_toswap; solver& s; @@ -31,12 +30,12 @@ namespace sat { ~mus(); lbool operator()(); private: + lbool mus2(); void rmr(); bool has_single_unsat(literal& assumption_lit); void find_swappable(literal lit); void reset(); void set_core(); - lbool eval(literal l) const; }; }; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index d0d3236c8..91dada236 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -46,8 +46,7 @@ namespace sat { m_case_split_queue(m_activity), m_qhead(0), m_scope_lvl(0), - m_params(p), - m_minimize_core(p.get_bool("minimize_core", false)) { + m_params(p) { m_config.updt_params(p); } @@ -1045,7 +1044,7 @@ namespace sat { } if (!m_mc.check_model(m)) ok = false; - TRACE("sat", tout << "checl: " << ok << "\n" << m << "\n";); + TRACE("sat", tout << "check: " << ok << "\n" << m << "\n";); return ok; } @@ -1621,7 +1620,7 @@ namespace sat { } while (idx > 0); reset_unmark(old_size); - if (m_minimize_core) { + if (m_config.m_minimize_core) { m_mus(); //ignore return value on cancelation. } } @@ -2236,7 +2235,6 @@ namespace sat { m_probing.updt_params(p); m_scc.updt_params(p); m_rand.set_seed(p.get_uint("random_seed", 0)); - m_minimize_core = p.get_bool("minimize_core", false); } void solver::collect_param_descrs(param_descrs & d) { diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 91ecbc3fb..056567bf9 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -123,7 +123,6 @@ namespace sat { literal_vector m_assumptions; literal_set m_assumption_set; literal_vector m_core; - bool m_minimize_core; void del_clauses(clause * const * begin, clause * const * end); From 9681dc12b11ad22062df3cf0eb8bfe53f9d0c5f2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 2 Aug 2014 14:25:04 -0700 Subject: [PATCH 446/925] tuning auxiliary literals and clauses Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 393d00f85..3c03acf84 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -257,7 +257,7 @@ public: void max_resolve(ptr_vector& core, rational const& w) { SASSERT(!core.empty()); expr_ref fml(m), asum(m); - app_ref cls(m), d(m); + app_ref cls(m), d(m), dd(m); m_B.reset(); m_B.append(core.size(), core.c_ptr()); d = m.mk_true(); @@ -276,10 +276,20 @@ public: for (unsigned i = 1; i < core.size(); ++i) { expr* b_i = m_B[i-1].get(); expr* b_i1 = m_B[i].get(); - d = m.mk_and(b_i, d); + if (i > 2) { + dd = mk_fresh_bool("d"); + fml = m.mk_implies(dd, d); + m_s->assert_expr(fml); + fml = m.mk_implies(dd, b_i); + m_s->assert_expr(fml); + d = dd; + } + else { + d = m.mk_and(b_i, d); + } asum = mk_fresh_bool("a"); cls = m.mk_or(b_i1, d); - fml = m.mk_iff(asum, cls); + fml = m.mk_implies(asum, cls); new_assumption(asum, w); m_s->assert_expr(fml); } From 5e026b78979ef480364186f6f4f2c96bc391e5e2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 2 Aug 2014 23:34:43 -0700 Subject: [PATCH 447/925] mss and maxres tuning Signed-off-by: Nikolaj Bjorner --- src/opt/mss.cpp | 161 ++++++++++++++++++++++++++++++++++++++++++++++++ src/opt/mss.h | 52 ++++++++++++++++ src/opt/mus.cpp | 2 - src/opt/mus.h | 2 +- 4 files changed, 214 insertions(+), 3 deletions(-) create mode 100644 src/opt/mss.cpp create mode 100644 src/opt/mss.h diff --git a/src/opt/mss.cpp b/src/opt/mss.cpp new file mode 100644 index 000000000..d0780c916 --- /dev/null +++ b/src/opt/mss.cpp @@ -0,0 +1,161 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + mss.cpp + +Abstract: + + MSS/MCS extraction. + +Author: + + Nikolaj Bjorner (nbjorner) 2014-2-8 + +Notes: + + +--*/ + +#include "solver.h" +#include "smt_literal.h" +#include "mss.h" +#include "ast_pp.h" +#include "model_smt2_pp.h" + +namespace opt { + + + mss::mss(solver& s, ast_manager& m): s(s), m(m), m_cancel(false) { + } + + mss::~mss() { + } + + + void mss::check_parameters(vector const& cores, exprs& literals) { + expr* n; + for (unsigned i = 0; i < literals.size(); ++i) { + n = literals[i]; + m.is_not(n, n); + if (!is_uninterp_const(n)) { + throw default_exception("arguments have to be uninterpreted literals"); + } + } + // cores are disjoint + // cores are a subset of literals + // literals not in cores evaluate to true in current model + } + + /** + \brief Move literals satisfied in todo into mss. + Precondition: the solver state is satisfiable. + */ + void mss::update_model() { + expr_ref tmp(m); + s.get_model(m_model); + update_set(m_todo); + } + + void mss::update_set(exprs& lits) { + expr_ref tmp(m); + unsigned sz = lits.size(); + unsigned j = 0; + for (unsigned i = 0; i < lits.size(); ++i) { + expr* n = lits[i]; + if (m_mcs.contains(n)) { + // remove from todo. + continue; + } + VERIFY(m_model->eval(n, tmp)); + if (m.is_false(tmp)) { + if (j != i) { + lits[j] = lits[i]; + } + ++j; + } + else { + m_mss.push_back(n); + } + } + lits.resize(j); + } + + + lbool mss::operator()(vector const& cores, exprs& literals) { + m_mss.reset(); + m_mcs.reset(); + m_todo.reset(); + m_todo.append(literals); + check_parameters(cores, literals); + update_model(); + lbool is_sat = l_true; + for (unsigned i = 0; is_sat == l_true && i < cores.size(); ++i) { + is_sat = process_core(cores[i]); + } + if (is_sat == l_true) { + literals.reset(); + literals.append(m_mss); + } + return is_sat; + } + + lbool mss::process_core(exprs const& _core) { + // at least one literal in core is false in current model. + // pick literals in core that are not yet in mss. + exprs core(_core); + update_set(core); + return process_core(1, core); + } + + lbool mss::process_core(unsigned sz, exprs& core) { + TRACE("opt", tout << "process: " << sz << " out of " << core.size() << " literals\n";); + SASSERT(sz > 0); + if (core.empty()) { + return l_true; + } + if (m_cancel) { + return l_undef; + } + sz = std::min(sz, core.size()); + unsigned sz_save = m_mss.size(); + m_mss.append(sz, core.c_ptr()); + lbool is_sat = s.check_sat(m_mss.size(), m_mss.c_ptr()); + m_mss.resize(sz_save); + switch (is_sat) { + case l_true: + update_model(); + update_set(core); + return process_core(2*sz, core); + case l_false: + if (sz == 1) { + m_mcs.insert(core[0]); + core[0] = core.back(); + core.pop_back(); + } + else { + exprs core2; + core2.append(core.size()-sz, core.c_ptr()+sz); + core.resize(sz); + is_sat = process_core(sz, core2); + if (is_sat != l_true) { + return is_sat; + } + } + return process_core(1, core); + case l_undef: + return l_undef; + } + + return l_true; + } + + void mss::display(std::ostream& out) const { + + } +} + + + + diff --git a/src/opt/mss.h b/src/opt/mss.h new file mode 100644 index 000000000..2e5d82df2 --- /dev/null +++ b/src/opt/mss.h @@ -0,0 +1,52 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + mss.h + +Abstract: + + Maximal satisfying subset/minimal correction sets: MSS/MCS + +Author: + + Nikolaj Bjorner (nbjorner) 2014-2-8 + +Notes: + +--*/ +#ifndef _MSS_H_ +#define _MSS_H_ + +namespace opt { + class mss { + solver& s; + ast_manager& m; + volatile bool m_cancel; + typedef ptr_vector exprs; + typedef obj_hashtable expr_set; + exprs m_mss; + expr_set m_mcs; + exprs m_todo; + model_ref m_model; + public: + mss(solver& s, ast_manager& m); + ~mss(); + + lbool operator()(vector > const& cores, ptr_vector& literals); + + void set_cancel(bool f) { m_cancel = f; } + + private: + void check_parameters(vector const& cores, exprs& literals); + void update_model(); + void update_set(exprs& lits); + lbool process_core(exprs const& _core); + lbool process_core(unsigned sz, exprs& core); + void display(std::ostream& out) const; + }; + +}; + +#endif diff --git a/src/opt/mus.cpp b/src/opt/mus.cpp index 5fd246294..a8126e699 100644 --- a/src/opt/mus.cpp +++ b/src/opt/mus.cpp @@ -15,8 +15,6 @@ Author: Notes: - Model rotation needs fixes to ensure that hard constraints are satisfied - under pertubed model. Model rotation also has o be consistent with theories. --*/ diff --git a/src/opt/mus.h b/src/opt/mus.h index e9e3b80bd..3a96b4842 100644 --- a/src/opt/mus.h +++ b/src/opt/mus.h @@ -7,7 +7,7 @@ Module Name: Abstract: - Faster MUS extraction based on Belov et.al. HYB (Algorithm 3, 4) + Basic MUS extraction Author: From a41b1d34ce6bc781286a7ed909fa9d3f30abce69 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Aug 2014 00:08:57 -0700 Subject: [PATCH 448/925] moving dual solver to maxres Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 214 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 210 insertions(+), 4 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 3c03acf84..421b84d10 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -27,20 +27,30 @@ using namespace opt; class maxres : public maxsmt_solver_base { +public: + enum strategy_t { + s_mus, + s_mus_mss, + s_mss + }; +private: expr_ref_vector m_B; expr_ref_vector m_asms; obj_map m_asm2weight; ptr_vector m_new_core; mus m_mus; expr_ref_vector m_trail; + strategy_t m_st; public: maxres(ast_manager& m, opt_solver* s, params_ref& p, - vector const& ws, expr_ref_vector const& soft): + vector const& ws, expr_ref_vector const& soft, + strategy_t st): maxsmt_solver_base(s, m, p, ws, soft), m_B(m), m_asms(m), m_mus(m_s, m), - m_trail(m) + m_trail(m), + m_st(st) { } @@ -81,7 +91,7 @@ public: m_trail.push_back(e); } - lbool operator()() { + lbool mus_solver() { solver::scoped_push _sc(*m_s.get()); init(); init_local(); @@ -127,6 +137,69 @@ public: return l_true; } + lbool mus_mss_solver() { + solver::scoped_push _sc(*m_s.get()); + init(); + init_local(); + enable_bvsat(); + enable_sls(); + lbool was_sat = l_false; + ptr_vector soft_compl; + vector > cores; + while (m_lower < m_upper) { + TRACE("opt", + display_vec(tout, m_asms.size(), m_asms.c_ptr()); + m_s->display(tout); + tout << "\n"; + display(tout); + ); + lbool is_sat = m_s->check_sat(0, 0); + if (m_cancel) { + return l_undef; + } + if (is_sat == l_true) { + was_sat = l_true; + is_sat = extend_model(soft_compl); + switch (is_sat) { + case l_undef: + break; + case l_false: + is_sat = process_unsat(); + break; + case l_true: + is_sat = process_sat(soft_compl); + break; + } + } + switch (is_sat) { + case l_undef: + return l_undef; + case l_false: + m_lower = m_upper; + return was_sat; + case l_true: + break; + } + } + return was_sat; + } + + lbool mss_solver() { + NOT_IMPLEMENTED_YET(); + return l_undef; + } + + lbool operator()() { + switch(m_st) { + case s_mus: + return mus_solver(); + case s_mus_mss: + return mus_mss_solver(); + case s_mss: + return mss_solver(); + } + } + lbool get_cores(vector >& cores) { // assume m_s is unsat. lbool is_sat = l_false; @@ -165,6 +238,21 @@ public: } + lbool process_sat(ptr_vector& corr_set) { + expr_ref fml(m), tmp(m); + TRACE("opt", display_vec(tout << "corr_set: ", corr_set.size(), corr_set.c_ptr());); + SASSERT(!corr_set.empty()); // we should somehow stop if all soft are satisfied. + if (corr_set.empty()) { + return l_false; + } + + remove_core(corr_set); + rational w = split_core(corr_set); + TRACE("opt", display_vec(tout << " corr_set: ", corr_set.size(), corr_set.c_ptr());); + dual_max_resolve(corr_set, w); + return l_true; + } + lbool process_unsat() { vector > cores; lbool is_sat = get_cores(cores); @@ -295,6 +383,124 @@ public: } } + // satc are the complements of a (maximal) satisfying assignment. + void dual_max_resolve(ptr_vector& satc, rational const& w) { + SASSERT(!satc.empty()); + expr_ref fml(m), asum(m); + app_ref cls(m), d(m), dd(m); + m_B.reset(); + m_B.append(satc.size(), satc.c_ptr()); + d = m.mk_false(); + // + // d_0 := false + // d_i := b_{i-1} or d_{i-1} for i = 1...sz-1 + // soft (b_i and d_i) + // == (b_i and (b_0 or b_1 or ... or b_{i-1})) + // + // asm => b_i + // asm => d_{i-1} or b_{i-1} + // d_i => d_{i-1} or b_{i-1} + for (unsigned i = 1; i < satc.size(); ++i) { + expr* b_i = m_B[i-1].get(); + expr* b_i1 = m_B[i].get(); + cls = m.mk_or(b_i, d); + if (i > 2) { + d = mk_fresh_bool("d"); + fml = m.mk_implies(d, cls); + m_s->assert_expr(fml); + } + else { + d = cls; + } + asum = mk_fresh_bool("a"); + fml = m.mk_implies(asum, b_i1); + m_s->assert_expr(fml); + fml = m.mk_implies(asum, cls); + m_s->assert_expr(fml); + new_assumption(asum, w); + } + fml = m.mk_or(m_B.size(), m_B.c_ptr()); + m_s->assert_expr(fml); + } + + // + // The hard constraints are satisfiable. + // Extend the current model to satisfy as many + // soft constraints as possible until either + // hitting an unsatisfiable subset of size < 1/2*#assumptions, + // or producing a maximal satisfying assignment exceeding + // number of soft constraints >= 1/2*#assumptions. + // In both cases, soft constraints that are not satisfied + // is <= 1/2*#assumptions. In this way, the new modified assumptions + // account for at most 1/2 of the current assumptions. + // The core reduction algorithms also need to take into account + // at most 1/2 of the assumptions for minimization. + // + + lbool extend_model(ptr_vector& soft_compl) { + ptr_vector asms; + model_ref mdl; + expr_ref tmp(m); + m_s->get_model(mdl); + unsigned num_true = update_model(mdl, asms, soft_compl); + for (unsigned j = 0; j < m_asms.size(); ++j) { + expr* fml = m_asms[j].get(); + VERIFY(mdl->eval(fml, tmp)); + if (m.is_false(tmp)) { + asms.push_back(fml); + lbool is_sat = m_s->check_sat(asms.size(), asms.c_ptr()); + asms.pop_back(); + switch (is_sat) { + case l_false: + if (num_true*2 < m_asms.size()) { + return l_false; + } + break; + case l_true: + m_s->get_model(mdl); + num_true = update_model(mdl, asms, soft_compl); + break; + case l_undef: + return l_undef; + } + } + } + return l_true; + } + + unsigned update_model(model_ref& mdl, ptr_vector& asms, ptr_vector& soft_compl) { + expr_ref tmp(m); + asms.reset(); + soft_compl.reset(); + rational weight = m_lower; + unsigned num_true = 0; + for (unsigned i = 0; i < m_asms.size(); ++i) { + expr* fml = m_asms[i].get(); + VERIFY(mdl->eval(fml, tmp)); + SASSERT(m.is_false(tmp) || m.is_true(tmp)); + if (m.is_false(tmp)) { + weight += get_weight(fml); + soft_compl.push_back(fml); + } + else { + ++num_true; + asms.push_back(fml); + } + } + if (weight < m_upper) { + m_upper = weight; + m_model = mdl; + for (unsigned i = 0; i < m_soft.size(); ++i) { + expr_ref tmp(m); + VERIFY(m_model->eval(m_soft[i].get(), tmp)); + m_assignment[i] = m.is_true(tmp); + } + IF_VERBOSE(1, verbose_stream() << + "(opt.dual_max_res [" << m_lower << ":" << m_upper << "])\n";); + } + return num_true; + } + void remove_soft(ptr_vector const& core, expr_ref_vector& asms) { for (unsigned i = 0; i < asms.size(); ++i) { if (core.contains(asms[i].get())) { @@ -327,6 +533,6 @@ public: opt::maxsmt_solver_base* opt::mk_maxres(ast_manager& m, opt_solver* s, params_ref& p, vector const& ws, expr_ref_vector const& soft) { - return alloc(maxres, m, s, p, ws, soft); + return alloc(maxres, m, s, p, ws, soft, maxres::s_mus); } From 6a4c08c7cb4b5fc1db061bbe788fba06deb444a7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Aug 2014 00:17:55 -0700 Subject: [PATCH 449/925] moving to maxres consolidation Signed-off-by: Nikolaj Bjorner --- src/opt/dual_maxres.cpp | 34 ---------------------- src/opt/maxres.cpp | 63 +++++++++++++++++++++++++++++++++++------ src/opt/maxres.h | 13 +++++++-- src/opt/maxsmt.cpp | 5 ++-- 4 files changed, 68 insertions(+), 47 deletions(-) diff --git a/src/opt/dual_maxres.cpp b/src/opt/dual_maxres.cpp index 292dc5e72..93d3c80e9 100644 --- a/src/opt/dual_maxres.cpp +++ b/src/opt/dual_maxres.cpp @@ -7,40 +7,6 @@ Module Name: Abstract: - MaxRes (weighted) max-sat algorithm - based on dual refinement of bounds. - - MaxRes is a core-guided approach to maxsat. - DualMaxRes extends the core-guided approach by - leveraging both cores and satisfying assignments - to make progress towards a maximal satisfying assignment. - - Given a (minimal) unsatisfiable core for the soft - constraints the approach works like max-res. - Given a (maximal) satisfying subset of the soft constraints - the approach updates the upper bound if the current assignment - improves the current best assignmet. - Furthermore, take the soft constraints that are complements - to the current satisfying subset. - E.g, if F are the hard constraints and - s1,...,sn, t1,..., tm are the soft clauses and - F & s1 & ... & sn is satisfiable, then the complement - of of the current satisfying subset is t1, .., tm. - Update the hard constraint: - F := F & (t1 or ... or tm) - Replace t1, .., tm by m-1 new soft clauses: - t1 & t2, t3 & (t1 or t2), t4 & (t1 or t2 or t3), ..., tn & (t1 or ... t_{n-1}) - Claim: - If k of these soft clauses are satisfied, then k+1 of - the previous soft clauses are satisfied. - If k of these soft clauses are false in the satisfying assignment - for the updated F, then k of the original soft clauses are also false - under the assignment. - In summary: any assignment to the new clauses that satsfies F has the - same cost. - Claim: - If there are no satisfying assignments to F, then the current best assignment - is the optimum. Author: diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 421b84d10..7e8df3e18 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -7,7 +7,43 @@ Module Name: Abstract: - MaxRes (weighted) max-sat algorithm by Nina and Bacchus, AAAI 2014. + MaxRes (weighted) max-sat algorithms: + + - mus: max-sat algorithm by Nina and Bacchus, AAAI 2014. + - mus-mss: based on dual refinement of bounds. + - mss: based on maximal satisfying sets (only). + + MaxRes is a core-guided approach to maxsat. + MusMssMaxRes extends the core-guided approach by + leveraging both cores and satisfying assignments + to make progress towards a maximal satisfying assignment. + + Given a (minimal) unsatisfiable core for the soft + constraints the approach works like max-res. + Given a (maximal) satisfying subset of the soft constraints + the approach updates the upper bound if the current assignment + improves the current best assignmet. + Furthermore, take the soft constraints that are complements + to the current satisfying subset. + E.g, if F are the hard constraints and + s1,...,sn, t1,..., tm are the soft clauses and + F & s1 & ... & sn is satisfiable, then the complement + of of the current satisfying subset is t1, .., tm. + Update the hard constraint: + F := F & (t1 or ... or tm) + Replace t1, .., tm by m-1 new soft clauses: + t1 & t2, t3 & (t1 or t2), t4 & (t1 or t2 or t3), ..., tn & (t1 or ... t_{n-1}) + Claim: + If k of these soft clauses are satisfied, then k+1 of + the previous soft clauses are satisfied. + If k of these soft clauses are false in the satisfying assignment + for the updated F, then k of the original soft clauses are also false + under the assignment. + In summary: any assignment to the new clauses that satsfies F has the + same cost. + Claim: + If there are no satisfying assignments to F, then the current best assignment + is the optimum. Author: @@ -198,6 +234,7 @@ public: case s_mss: return mss_solver(); } + return l_undef; } lbool get_cores(vector >& cores) { @@ -249,7 +286,7 @@ public: remove_core(corr_set); rational w = split_core(corr_set); TRACE("opt", display_vec(tout << " corr_set: ", corr_set.size(), corr_set.c_ptr());); - dual_max_resolve(corr_set, w); + cs_max_resolve(corr_set, w); return l_true; } @@ -383,13 +420,13 @@ public: } } - // satc are the complements of a (maximal) satisfying assignment. - void dual_max_resolve(ptr_vector& satc, rational const& w) { - SASSERT(!satc.empty()); + // cs is a correction set (a complement of a (maximal) satisfying assignment). + void cs_max_resolve(ptr_vector& cs, rational const& w) { + SASSERT(!cs.empty()); expr_ref fml(m), asum(m); app_ref cls(m), d(m), dd(m); m_B.reset(); - m_B.append(satc.size(), satc.c_ptr()); + m_B.append(cs.size(), cs.c_ptr()); d = m.mk_false(); // // d_0 := false @@ -400,7 +437,7 @@ public: // asm => b_i // asm => d_{i-1} or b_{i-1} // d_i => d_{i-1} or b_{i-1} - for (unsigned i = 1; i < satc.size(); ++i) { + for (unsigned i = 1; i < cs.size(); ++i) { expr* b_i = m_B[i-1].get(); expr* b_i1 = m_B[i].get(); cls = m.mk_or(b_i, d); @@ -496,7 +533,7 @@ public: m_assignment[i] = m.is_true(tmp); } IF_VERBOSE(1, verbose_stream() << - "(opt.dual_max_res [" << m_lower << ":" << m_upper << "])\n";); + "(opt.mus-mss_max_res [" << m_lower << ":" << m_upper << "])\n";); } return num_true; } @@ -536,3 +573,13 @@ opt::maxsmt_solver_base* opt::mk_maxres(ast_manager& m, opt_solver* s, params_re return alloc(maxres, m, s, p, ws, soft, maxres::s_mus); } +opt::maxsmt_solver_base* opt::mk_mus_mss_maxres(ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft) { + return alloc(maxres, m, s, p, ws, soft, maxres::s_mus_mss); +} + +opt::maxsmt_solver_base* opt::mk_mss_maxres(ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft) { + return alloc(maxres, m, s, p, ws, soft, maxres::s_mss); +} + diff --git a/src/opt/maxres.h b/src/opt/maxres.h index 8058a0376..efa8886f7 100644 --- a/src/opt/maxres.h +++ b/src/opt/maxres.h @@ -21,9 +21,18 @@ Notes: #define _MAXRES_H_ namespace opt { - maxsmt_solver_base* mk_maxres(ast_manager& m, opt_solver* s, params_ref& p, - vector const& ws, expr_ref_vector const& soft); + maxsmt_solver_base* mk_maxres( + ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft); + + maxsmt_solver_base* mk_mus_mss_maxres( + ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft); + + maxsmt_solver_base* mk_mss_maxres( + ast_manager& m, opt_solver* s, params_ref& p, + vector const& ws, expr_ref_vector const& soft); }; diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index d183ab4fc..d6663099d 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -22,7 +22,6 @@ Notes: #include "fu_malik.h" #include "core_maxsat.h" #include "maxres.h" -#include "dual_maxres.h" #include "maxhs.h" #include "bcd2.h" #include "wpm2.h" @@ -181,8 +180,8 @@ namespace opt { else if (m_maxsat_engine == symbol("maxres")) { m_msolver = mk_maxres(m, s, m_params, m_weights, m_soft_constraints); } - else if (m_maxsat_engine == symbol("dual-maxres")) { - m_msolver = mk_dual_maxres(m, s, m_params, m_weights, m_soft_constraints); + else if (m_maxsat_engine == symbol("mus-mss-maxres")) { + m_msolver = mk_mus_mss_maxres(m, s, m_params, m_weights, m_soft_constraints); } else if (m_maxsat_engine == symbol("pbmax")) { m_msolver = mk_pbmax(m, s, m_params, m_weights, m_soft_constraints); From 622d8b5cd18254b9d8a2d6c3c6bdc6e6708b0398 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Aug 2014 00:18:09 -0700 Subject: [PATCH 450/925] moving to maxres consolidation Signed-off-by: Nikolaj Bjorner --- src/opt/dual_maxres.cpp | 454 ---------------------------------------- src/opt/dual_maxres.h | 32 --- 2 files changed, 486 deletions(-) delete mode 100644 src/opt/dual_maxres.cpp delete mode 100644 src/opt/dual_maxres.h diff --git a/src/opt/dual_maxres.cpp b/src/opt/dual_maxres.cpp deleted file mode 100644 index 93d3c80e9..000000000 --- a/src/opt/dual_maxres.cpp +++ /dev/null @@ -1,454 +0,0 @@ -/*++ -Copyright (c) 2014 Microsoft Corporation - -Module Name: - - dual_maxsres.cpp - -Abstract: - - - -Author: - - Nikolaj Bjorner (nbjorner) 2014-27-7 - -Notes: - ---*/ - -#include "solver.h" -#include "maxsmt.h" -#include "dual_maxres.h" -#include "ast_pp.h" -#include "mus.h" - -using namespace opt; - - -class dual_maxres : public maxsmt_solver_base { - expr_ref_vector m_B; - expr_ref_vector m_asms; - obj_map m_asm2weight; - obj_map m_soft2asm; - ptr_vector m_new_core; - mus m_mus; - expr_ref_vector m_trail; - -public: - dual_maxres(ast_manager& m, opt_solver* s, params_ref& p, - vector const& ws, expr_ref_vector const& soft): - maxsmt_solver_base(s, m, p, ws, soft), - m_B(m), m_asms(m), - m_mus(m_s, m), - m_trail(m) - { - } - - virtual ~dual_maxres() {} - - bool is_literal(expr* l) { - return - is_uninterp_const(l) || - (m.is_not(l, l) && is_uninterp_const(l)); - } - - void add_soft(expr* e, rational const& w) { - TRACE("opt", tout << mk_pp(e, m) << "\n";); - expr_ref asum(m), fml(m); - expr* f; - if (m_soft2asm.find(e, f)) { - m_asm2weight.find(f) += w; - return; - } - if (is_literal(e)) { - asum = e; - } - else { - asum = mk_fresh_bool("soft"); - fml = m.mk_iff(asum, e); - m_s->assert_expr(fml); - } - m_soft2asm.insert(e, asum); - new_assumption(asum, w); - m_upper += w; - } - - void new_assumption(expr* e, rational const& w) { - m_asm2weight.insert(e, w); - m_asms.push_back(e); - m_trail.push_back(e); - } - - lbool operator()() { - solver::scoped_push _sc(*m_s.get()); - init(); - init_local(); - enable_bvsat(); - enable_sls(); - lbool was_sat = l_false; - ptr_vector soft_compl; - vector > cores; - while (m_lower < m_upper) { - TRACE("opt", - display_vec(tout, m_asms.size(), m_asms.c_ptr()); - m_s->display(tout); - tout << "\n"; - display(tout); - ); - lbool is_sat = m_s->check_sat(0, 0); - if (m_cancel) { - return l_undef; - } - if (is_sat == l_true) { - was_sat = l_true; - is_sat = extend_model(soft_compl); - switch (is_sat) { - case l_undef: - break; - case l_false: - is_sat = get_cores(cores); - for (unsigned i = 0; is_sat == l_true && i < cores.size(); ++i) { - is_sat = process_unsat(cores[i]); - } - break; - case l_true: - is_sat = process_sat(soft_compl); - break; - } - } - switch (is_sat) { - case l_undef: - return l_undef; - case l_false: - m_lower = m_upper; - return was_sat; - case l_true: - break; - } - } - return was_sat; - } - - lbool process_sat(ptr_vector& softc) { - expr_ref fml(m), tmp(m); - TRACE("opt", display_vec(tout << "softc: ", softc.size(), softc.c_ptr());); - SASSERT(!softc.empty()); // we should somehow stop if all soft are satisfied. - if (softc.empty()) { - return l_false; - } - - remove_soft(softc); - rational w = split_soft(softc); - TRACE("opt", display_vec(tout << " softc: ", softc.size(), softc.c_ptr());); - dual_max_resolve(softc, w); - return l_true; - } - - // - // Retrieve a set of disjoint cores over the current assumptions. - // TBD: when the remaining are satisfiable, then extend the - // satisfying model to improve upper bound. - // - lbool get_cores(vector >& cores) { - // assume m_s is unsat. - lbool is_sat = l_false; - expr_ref_vector asms(m); - asms.append(m_asms.size(), m_asms.c_ptr()); - cores.reset(); - ptr_vector core; - while (is_sat == l_false) { - core.reset(); - m_s->get_unsat_core(core); - is_sat = minimize_core(core); - if (is_sat != l_true) { - break; - } - cores.push_back(core); - break; - // - // TBD: multiple core refinement - // produces unsound results. - // what is a sound variant? - // - remove_soft(core, asms); - is_sat = m_s->check_sat(asms.size(), asms.c_ptr()); - - } - TRACE("opt", - tout << "num cores: " << cores.size() << "\n"; - for (unsigned i = 0; i < cores.size(); ++i) { - for (unsigned j = 0; j < cores[i].size(); ++j) { - tout << mk_pp(cores[i][j], m) << " "; - } - tout << "\n"; - } - tout << "num satisfying: " << asms.size() << "\n";); - - return is_sat; - } - - lbool process_unsat(ptr_vector& core) { - expr_ref fml(m); - SASSERT(!core.empty()); - if (core.empty()) { - return l_false; - } - remove_soft(core); - rational w = split_soft(core); - TRACE("opt", display_vec(tout << "core: ", core.size(), core.c_ptr()); - for (unsigned i = 0; i < core.size(); ++i) { - tout << get_weight(core[i]) << " "; - } - tout << "min-weight: " << w << "\n";); - max_resolve(core, w); - m_lower += w; - IF_VERBOSE(1, verbose_stream() << - "(opt.dual_max_res [" << m_lower << ":" << m_upper << "])\n";); - return l_true; - } - - // - // The hard constraints are satisfiable. - // Extend the current model to satisfy as many - // soft constraints as possible until either - // hitting an unsatisfiable subset of size < 1/2*#assumptions, - // or producing a maximal satisfying assignment exceeding - // number of soft constraints >= 1/2*#assumptions. - // In both cases, soft constraints that are not satisfied - // is <= 1/2*#assumptions. In this way, the new modified assumptions - // account for at most 1/2 of the current assumptions. - // The core reduction algorithms also need to take into account - // at most 1/2 of the assumptions for minimization. - // - - lbool extend_model(ptr_vector& soft_compl) { - ptr_vector asms; - model_ref mdl; - expr_ref tmp(m); - m_s->get_model(mdl); - unsigned num_true = update_model(mdl, asms, soft_compl); - for (unsigned j = 0; j < m_asms.size(); ++j) { - expr* fml = m_asms[j].get(); - VERIFY(mdl->eval(fml, tmp)); - if (m.is_false(tmp)) { - asms.push_back(fml); - lbool is_sat = m_s->check_sat(asms.size(), asms.c_ptr()); - asms.pop_back(); - switch (is_sat) { - case l_false: - if (num_true*2 < m_asms.size()) { - return l_false; - } - break; - case l_true: - m_s->get_model(mdl); - num_true = update_model(mdl, asms, soft_compl); - break; - case l_undef: - return l_undef; - } - } - } - return l_true; - } - - unsigned update_model(model_ref& mdl, ptr_vector& asms, ptr_vector& soft_compl) { - expr_ref tmp(m); - asms.reset(); - soft_compl.reset(); - rational weight = m_lower; - unsigned num_true = 0; - for (unsigned i = 0; i < m_asms.size(); ++i) { - expr* fml = m_asms[i].get(); - VERIFY(mdl->eval(fml, tmp)); - SASSERT(m.is_false(tmp) || m.is_true(tmp)); - if (m.is_false(tmp)) { - weight += get_weight(fml); - soft_compl.push_back(fml); - } - else { - ++num_true; - asms.push_back(fml); - } - } - if (weight < m_upper) { - m_upper = weight; - m_model = mdl; - for (unsigned i = 0; i < m_soft.size(); ++i) { - expr_ref tmp(m); - VERIFY(m_model->eval(m_soft[i].get(), tmp)); - m_assignment[i] = m.is_true(tmp); - } - IF_VERBOSE(1, verbose_stream() << - "(opt.dual_max_res [" << m_lower << ":" << m_upper << "])\n";); - } - return num_true; - } - - lbool minimize_core(ptr_vector& core) { - if (m_sat_enabled) { - return l_true; - } - m_mus.reset(); - for (unsigned i = 0; i < core.size(); ++i) { - m_mus.add_soft(core[i]); - } - unsigned_vector mus_idx; - lbool is_sat = m_mus.get_mus(mus_idx); - if (is_sat != l_true) { - return is_sat; - } - m_new_core.reset(); - for (unsigned i = 0; i < mus_idx.size(); ++i) { - m_new_core.push_back(core[mus_idx[i]]); - } - core.reset(); - core.append(m_new_core); - return l_true; - } - - rational get_weight(expr* e) { - return m_asm2weight.find(e); - } - - - // - // find the minimal weight. - // soft clauses with weight larger than the minimal weight - // are (re)added as soft clauses where the weight is updated - // to subtract the minimal weight. - // - rational split_soft(ptr_vector const& soft) { - - SASSERT(!soft.empty()); - rational w = get_weight(soft[0]); - for (unsigned i = 1; i < soft.size(); ++i) { - rational w2 = get_weight(soft[i]); - if (w2 < w) { - w = w2; - } - } - // add fresh soft clauses for weights that are above w. - for (unsigned i = 0; i < soft.size(); ++i) { - rational w2 = get_weight(soft[i]); - if (w2 > w) { - new_assumption(soft[i], w2 - w); - } - } - return w; - } - - void display_vec(std::ostream& out, unsigned sz, expr* const* args) { - for (unsigned i = 0; i < sz; ++i) { - out << mk_pp(args[i], m) << " "; - } - out << "\n"; - } - - void display(std::ostream& out) { - for (unsigned i = 0; i < m_asms.size(); ++i) { - expr* a = m_asms[i].get(); - out << mk_pp(a, m) << " : " << get_weight(a) << "\n"; - } - } - - void max_resolve(ptr_vector& core, rational const& w) { - SASSERT(!core.empty()); - expr_ref fml(m), asum(m); - app_ref cls(m), d(m); - m_B.reset(); - m_B.append(core.size(), core.c_ptr()); - d = m.mk_true(); - // - // d_0 := true - // d_i := b_{i-1} and d_{i-1} for i = 1...sz-1 - // soft (b_i or !d_i) - // == (b_i or !(!b_{i-1} or d_{i-1})) - // == (b_i or b_0 & b_1 & ... & b_{i-1}) - // - // Soft constraint is satisfied if previous soft constraint - // holds or if it is the first soft constraint to fail. - // - // Soundness of this rule can be established using MaxRes - // - for (unsigned i = 1; i < core.size(); ++i) { - expr* b_i = m_B[i-1].get(); - expr* b_i1 = m_B[i].get(); - d = m.mk_and(b_i, d); - asum = mk_fresh_bool("a"); - cls = m.mk_or(b_i1, d); - fml = m.mk_iff(asum, cls); - new_assumption(asum, w); - m_s->assert_expr(fml); - } - fml = m.mk_not(m.mk_and(m_B.size(), m_B.c_ptr())); - m_s->assert_expr(fml); - } - - // satc are the complements of a (maximal) satisfying assignment. - void dual_max_resolve(ptr_vector& satc, rational const& w) { - SASSERT(!satc.empty()); - expr_ref fml(m), asum(m); - app_ref cls(m), d(m); - m_B.reset(); - m_B.append(satc.size(), satc.c_ptr()); - d = m.mk_false(); - // - // d_0 := false - // d_i := b_{i-1} or d_{i-1} for i = 1...sz-1 - // soft (b_i and d_i) - // == (b_i and (b_0 or b_1 or ... or b_{i-1})) - // - for (unsigned i = 1; i < satc.size(); ++i) { - expr* b_i = m_B[i-1].get(); - expr* b_i1 = m_B[i].get(); - d = m.mk_or(b_i, d); - asum = mk_fresh_bool("a"); - cls = m.mk_and(b_i1, d); - fml = m.mk_iff(asum, cls); - new_assumption(asum, w); - m_s->assert_expr(fml); - } - fml = m.mk_or(m_B.size(), m_B.c_ptr()); - m_s->assert_expr(fml); - } - - void remove_soft(ptr_vector const& soft, expr_ref_vector& asms) { - for (unsigned i = 0; i < asms.size(); ++i) { - if (soft.contains(asms[i].get())) { - asms[i] = asms.back(); - asms.pop_back(); - --i; - } - } - } - - void remove_soft(ptr_vector const& soft) { - remove_soft(soft, m_asms); - } - - virtual void set_cancel(bool f) { - maxsmt_solver_base::set_cancel(f); - m_mus.set_cancel(f); - } - - void init_local() { - m_upper.reset(); - m_lower.reset(); - m_asm2weight.reset(); - m_soft2asm.reset(); - m_trail.reset(); - for (unsigned i = 0; i < m_soft.size(); ++i) { - add_soft(m_soft[i].get(), m_weights[i]); - } - } - -}; - -opt::maxsmt_solver_base* opt::mk_dual_maxres( - ast_manager& m, opt_solver* s, params_ref& p, - vector const& ws, expr_ref_vector const& soft) { - return alloc(dual_maxres, m, s, p, ws, soft); -} - diff --git a/src/opt/dual_maxres.h b/src/opt/dual_maxres.h deleted file mode 100644 index 2bf1c7b18..000000000 --- a/src/opt/dual_maxres.h +++ /dev/null @@ -1,32 +0,0 @@ -/*++ -Copyright (c) 2014 Microsoft Corporation - -Module Name: - - dual_maxsres.h - -Abstract: - - MaxRes (weighted) max-sat algorithm - based on dual refinement of bounds. - -Author: - - Nikolaj Bjorner (nbjorner) 2014-27-7 - -Notes: - ---*/ - -#ifndef _DUAL_MAXRES_H_ -#define _DUAL_MAXRES_H_ - -namespace opt { - maxsmt_solver_base* mk_dual_maxres( - ast_manager& m, opt_solver* s, params_ref& p, - vector const& ws, expr_ref_vector const& soft); - - -}; - -#endif From d429e72e922643ab6368846a03799c0c02cdb7d6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Aug 2014 18:50:21 -0700 Subject: [PATCH 451/925] v2 of dual maxres engine Signed-off-by: Nikolaj Bjorner --- src/opt/inc_sat_solver.cpp | 6 +- src/opt/maxres.cpp | 195 ++++++++++++++++++++----------------- src/opt/maxsmt.cpp | 8 +- src/opt/maxsmt.h | 1 + src/opt/mss.cpp | 166 +++++++++++++++++++++++-------- src/opt/mss.h | 16 +-- 6 files changed, 253 insertions(+), 139 deletions(-) diff --git a/src/opt/inc_sat_solver.cpp b/src/opt/inc_sat_solver.cpp index c307ef6ae..f8979edce 100644 --- a/src/opt/inc_sat_solver.cpp +++ b/src/opt/inc_sat_solver.cpp @@ -89,7 +89,7 @@ public: m_solver.pop_to_base_level(); dep2asm_t dep2asm; - m_model.reset(); + m_model = 0; lbool r = internalize_formulas(); if (r != l_true) return r; r = internalize_assumptions(num_assumptions, assumptions, dep2asm); @@ -161,7 +161,7 @@ public: r.append(m_core.size(), m_core.c_ptr()); } virtual void get_model(model_ref & m) { - if (!m_model) { + if (!m_model.get()) { extract_model(); } m = m_model; @@ -275,6 +275,7 @@ private: // bit-blasting model converter. void extract_model() { + TRACE("sat", tout << "retrieve model\n";); model_ref md = alloc(model, m); sat::model const & ll_m = m_solver.get_model(); atom2bool_var::iterator it = m_map.begin(); @@ -300,6 +301,7 @@ private: if (m_mc) { (*m_mc)(m_model); } + SASSERT(m_model); // IF_VERBOSE(0, model_smt2_pp(verbose_stream(), m, *(m_model.get()), 0);); } diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 7e8df3e18..5e7dac0f7 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -58,10 +58,10 @@ Notes: #include "maxres.h" #include "ast_pp.h" #include "mus.h" +#include "mss.h" using namespace opt; - class maxres : public maxsmt_solver_base { public: enum strategy_t { @@ -75,8 +75,10 @@ private: obj_map m_asm2weight; ptr_vector m_new_core; mus m_mus; + mss m_mss; expr_ref_vector m_trail; strategy_t m_st; + rational m_max_upper; public: maxres(ast_manager& m, opt_solver* s, params_ref& p, @@ -85,6 +87,7 @@ public: maxsmt_solver_base(s, m, p, ws, soft), m_B(m), m_asms(m), m_mus(m_s, m), + m_mss(m_s, m), m_trail(m), m_st(st) { @@ -168,7 +171,6 @@ public: default: break; } - IF_VERBOSE(1, verbose_stream() << "(opt.max_res [" << m_lower << ":" << m_upper << "])\n";); } return l_true; } @@ -179,8 +181,7 @@ public: init_local(); enable_bvsat(); enable_sls(); - lbool was_sat = l_false; - ptr_vector soft_compl; + ptr_vector mcs; vector > cores; while (m_lower < m_upper) { TRACE("opt", @@ -189,37 +190,38 @@ public: tout << "\n"; display(tout); ); - lbool is_sat = m_s->check_sat(0, 0); + lbool is_sat = try_improve_bound(cores, mcs); if (m_cancel) { return l_undef; } - if (is_sat == l_true) { - was_sat = l_true; - is_sat = extend_model(soft_compl); - switch (is_sat) { - case l_undef: - break; - case l_false: - is_sat = process_unsat(); - break; - case l_true: - is_sat = process_sat(soft_compl); - break; - } - } switch (is_sat) { case l_undef: return l_undef; case l_false: + SASSERT(cores.empty() && mcs.empty()); m_lower = m_upper; - return was_sat; - case l_true: + return l_true; + case l_true: + SASSERT(cores.empty() || mcs.empty()); + SASSERT(!cores.empty() || !mcs.empty()); + for (unsigned i = 0; is_sat == l_true && i < cores.size(); ++i) { + is_sat = process_unsat(cores[i]); + } + if (is_sat == l_true && !mcs.empty()) { + is_sat = process_sat(mcs); + } + if (is_sat != l_true) { + return is_sat; + } break; } } - return was_sat; + m_lower = m_lower; + return l_true; } + + lbool mss_solver() { NOT_IMPLEMENTED_YET(); return l_undef; @@ -314,6 +316,7 @@ public: fml = m.mk_not(m.mk_and(m_B.size(), m_B.c_ptr())); m_s->assert_expr(fml); m_lower += w; + IF_VERBOSE(1, verbose_stream() << "(opt.maxres [" << m_lower << ":" << m_upper << "])\n";); return l_true; } @@ -422,6 +425,7 @@ public: // cs is a correction set (a complement of a (maximal) satisfying assignment). void cs_max_resolve(ptr_vector& cs, rational const& w) { + TRACE("opt", display_vec(tout << "correction set: ", cs.size(), cs.c_ptr());); SASSERT(!cs.empty()); expr_ref fml(m), asum(m); app_ref cls(m), d(m), dd(m); @@ -437,6 +441,7 @@ public: // asm => b_i // asm => d_{i-1} or b_{i-1} // d_i => d_{i-1} or b_{i-1} + // for (unsigned i = 1; i < cs.size(); ++i) { expr* b_i = m_B[i-1].get(); expr* b_i1 = m_B[i].get(); @@ -460,82 +465,89 @@ public: m_s->assert_expr(fml); } - // - // The hard constraints are satisfiable. - // Extend the current model to satisfy as many - // soft constraints as possible until either - // hitting an unsatisfiable subset of size < 1/2*#assumptions, - // or producing a maximal satisfying assignment exceeding - // number of soft constraints >= 1/2*#assumptions. - // In both cases, soft constraints that are not satisfied - // is <= 1/2*#assumptions. In this way, the new modified assumptions - // account for at most 1/2 of the current assumptions. - // The core reduction algorithms also need to take into account - // at most 1/2 of the assumptions for minimization. - // - - lbool extend_model(ptr_vector& soft_compl) { - ptr_vector asms; - model_ref mdl; - expr_ref tmp(m); - m_s->get_model(mdl); - unsigned num_true = update_model(mdl, asms, soft_compl); - for (unsigned j = 0; j < m_asms.size(); ++j) { - expr* fml = m_asms[j].get(); - VERIFY(mdl->eval(fml, tmp)); - if (m.is_false(tmp)) { - asms.push_back(fml); - lbool is_sat = m_s->check_sat(asms.size(), asms.c_ptr()); - asms.pop_back(); - switch (is_sat) { - case l_false: - if (num_true*2 < m_asms.size()) { - return l_false; - } - break; - case l_true: - m_s->get_model(mdl); - num_true = update_model(mdl, asms, soft_compl); - break; - case l_undef: - return l_undef; + lbool try_improve_bound(vector >& cores, ptr_vector& mcs) { + cores.reset(); + mcs.reset(); + ptr_vector core; + expr_ref_vector asms(m_asms); + while (true) { + rational upper = m_max_upper; + unsigned sz = 0; + for (unsigned i = 0; m_upper <= upper && i < asms.size(); ++i, ++sz) { + upper -= get_weight(asms[i].get()); + } + lbool is_sat = m_s->check_sat(sz, asms.c_ptr()); + switch (is_sat) { + case l_true: { + ptr_vector lits; + lits.append(asms.size(), asms.c_ptr()); + set_mus(false); + is_sat = m_mss(cores, lits); + set_mus(true); + if (is_sat != l_true) { + return is_sat; } + m_mss.get_model(m_model); // last model is best way to reduce search space. + update_assignment(); + if (cores.empty() || asms.size() < cores.back().size()) { + cores.reset(); + mcs.append(asms.size(), asms.c_ptr()); + } + return l_true; + } + case l_undef: + return l_undef; + case l_false: + core.reset(); + m_s->get_unsat_core(core); + is_sat = minimize_core(core); + if (is_sat != l_true) { + break; + } + if (core.empty()) { + cores.reset(); + mcs.reset(); + return l_false; + } + cores.push_back(core); + if (core.size() >= 3) { + return l_true; + } + // + // check arithmetic: cannot improve upper bound + // + if (m_upper <= upper) { + return l_true; + } + + remove_soft(core, asms); + break; } } - return l_true; + + return l_undef; } - unsigned update_model(model_ref& mdl, ptr_vector& asms, ptr_vector& soft_compl) { - expr_ref tmp(m); - asms.reset(); - soft_compl.reset(); - rational weight = m_lower; - unsigned num_true = 0; - for (unsigned i = 0; i < m_asms.size(); ++i) { - expr* fml = m_asms[i].get(); - VERIFY(mdl->eval(fml, tmp)); - SASSERT(m.is_false(tmp) || m.is_true(tmp)); - if (m.is_false(tmp)) { - weight += get_weight(fml); - soft_compl.push_back(fml); - } - else { - ++num_true; - asms.push_back(fml); + + void update_assignment() { + rational upper(0); + for (unsigned i = 0; i < m_soft.size(); ++i) { + expr_ref tmp(m); + expr* n = m_soft[i].get(); + VERIFY(m_model->eval(n, tmp)); + CTRACE("opt", !m.is_true(tmp) && !m.is_false(tmp), + tout << mk_pp(n, m) << " |-> " << mk_pp(tmp, m) << "\n";); + + m_assignment[i] = m.is_true(tmp); + if (!m_assignment[i]) { + upper += m_weights[i]; } } - if (weight < m_upper) { - m_upper = weight; - m_model = mdl; - for (unsigned i = 0; i < m_soft.size(); ++i) { - expr_ref tmp(m); - VERIFY(m_model->eval(m_soft[i].get(), tmp)); - m_assignment[i] = m.is_true(tmp); - } - IF_VERBOSE(1, verbose_stream() << - "(opt.mus-mss_max_res [" << m_lower << ":" << m_upper << "])\n";); - } - return num_true; + SASSERT(upper <= m_upper); + m_upper = upper; + IF_VERBOSE(1, verbose_stream() << + "(opt.maxres [" << m_lower << ":" << m_upper << "])\n";); + } void remove_soft(ptr_vector const& core, expr_ref_vector& asms) { @@ -564,6 +576,7 @@ public: for (unsigned i = 0; i < m_soft.size(); ++i) { add_soft(m_soft[i].get(), m_weights[i]); } + m_max_upper = m_upper; } }; diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index d6663099d..eb0a65ce9 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -138,8 +138,6 @@ namespace opt { m_s = sat_solver; } - - void maxsmt_solver_base::enable_bvsat() { if (m_enable_sat && !m_sat_enabled && probe_bv()) { enable_inc_bvsat(); @@ -159,6 +157,12 @@ namespace opt { } } + void maxsmt_solver_base::set_mus(bool f) { + params_ref p; + p.set_bool("minimize_core", f); + m_s->updt_params(p); + } + app* maxsmt_solver_base::mk_fresh_bool(char const* name) { app* result = m.mk_fresh_const(name, m.mk_bool_sort()); m_mc->insert(result->get_decl()); diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 138670693..df03499c9 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -94,6 +94,7 @@ namespace opt { void init(); expr* mk_not(expr* e); bool probe_bv(); + void set_mus(bool f); void enable_bvsat(); void enable_sls(); app* mk_fresh_bool(char const* name); diff --git a/src/opt/mss.cpp b/src/opt/mss.cpp index d0780c916..8a5bcdfe5 100644 --- a/src/opt/mss.cpp +++ b/src/opt/mss.cpp @@ -27,35 +27,74 @@ Notes: namespace opt { - mss::mss(solver& s, ast_manager& m): s(s), m(m), m_cancel(false) { + mss::mss(ref& s, ast_manager& m): m_s(s), m(m), m_cancel(false) { } mss::~mss() { - } - + } - void mss::check_parameters(vector const& cores, exprs& literals) { + bool mss::check_result() { + lbool is_sat = m_s->check_sat(m_mss.size(), m_mss.c_ptr()); + if (is_sat == l_undef) return true; + SASSERT(is_sat == l_true); + if (is_sat == l_false) return false; + expr_set::iterator it = m_mcs.begin(), end = m_mcs.end(); + for (; it != end; ++it) { + m_mss.push_back(*it); + is_sat = m_s->check_sat(m_mss.size(), m_mss.c_ptr()); + m_mss.pop_back(); + if (is_sat == l_undef) return true; + SASSERT(is_sat == l_false); + if (is_sat == l_true) return false; + } + return true; + } + + void mss::initialize(vector& cores, exprs& literals) { expr* n; + expr_set lits, core_lits; for (unsigned i = 0; i < literals.size(); ++i) { n = literals[i]; + lits.insert(n); m.is_not(n, n); if (!is_uninterp_const(n)) { throw default_exception("arguments have to be uninterpreted literals"); } } - // cores are disjoint - // cores are a subset of literals - // literals not in cores evaluate to true in current model - } - - /** - \brief Move literals satisfied in todo into mss. - Precondition: the solver state is satisfiable. - */ - void mss::update_model() { + exprs rest_core; expr_ref tmp(m); - s.get_model(m_model); - update_set(m_todo); + // + // the last core is a dummy core. It contains literals that + // did not occur in previous cores and did not evaluate to true + // in the current model. + // + for (unsigned i = 0; i < cores.size(); ++i) { + exprs const& core = cores[i]; + for (unsigned j = 0; j < core.size(); ++j) { + expr* n = core[j]; + if (!core_lits.contains(n)) { + core_lits.insert(n); + VERIFY(m_model->eval(n, tmp)); + if (m.is_true(tmp)) { + m_mss.push_back(n); + } + } + } + } + for (unsigned i = 0; i < literals.size(); ++i) { + expr* n = literals[i]; + if (!core_lits.contains(n)) { + VERIFY(m_model->eval(n, tmp)); + if (m.is_true(tmp)) { + m_mss.push_back(n); + } + else { + rest_core.push_back(n); + core_lits.insert(n); + } + } + } + cores.push_back(rest_core); } void mss::update_set(exprs& lits) { @@ -69,7 +108,7 @@ namespace opt { continue; } VERIFY(m_model->eval(n, tmp)); - if (m.is_false(tmp)) { + if (!m.is_true(tmp)) { if (j != i) { lits[j] = lits[i]; } @@ -83,33 +122,44 @@ namespace opt { } - lbool mss::operator()(vector const& cores, exprs& literals) { + lbool mss::operator()(vector const& _cores, exprs& literals) { m_mss.reset(); m_mcs.reset(); - m_todo.reset(); - m_todo.append(literals); - check_parameters(cores, literals); - update_model(); + m_s->get_model(m_model); + SASSERT(m_model); + vector cores(_cores); + TRACE("opt", + for (unsigned i = 0; i < cores.size(); ++i) { + display_vec(tout << "core: ", cores[i].size(), cores[i].c_ptr()); + } + display_vec(tout << "lits: ", literals.size(), literals.c_ptr()); + ); + initialize(cores, literals); + TRACE("opt", display(tout);); lbool is_sat = l_true; for (unsigned i = 0; is_sat == l_true && i < cores.size(); ++i) { - is_sat = process_core(cores[i]); + bool has_mcs = false; + bool is_last = i + 1 < cores.size(); + SASSERT(check_invariant()); + update_set(cores[i]); + is_sat = process_core(1, cores[i], has_mcs, is_last); } if (is_sat == l_true) { + SASSERT(check_invariant()); + TRACE("opt", display(tout);); literals.reset(); literals.append(m_mss); + SASSERT(check_result()); } return is_sat; } + - lbool mss::process_core(exprs const& _core) { - // at least one literal in core is false in current model. - // pick literals in core that are not yet in mss. - exprs core(_core); - update_set(core); - return process_core(1, core); - } - - lbool mss::process_core(unsigned sz, exprs& core) { + // + // at least one literal in core is false in current model. + // pick literals in core that are not yet in mss. + // + lbool mss::process_core(unsigned sz, exprs& core, bool& has_mcs, bool is_last) { TRACE("opt", tout << "process: " << sz << " out of " << core.size() << " literals\n";); SASSERT(sz > 0); if (core.empty()) { @@ -118,18 +168,25 @@ namespace opt { if (m_cancel) { return l_undef; } + if (sz == 1 && is_last && !has_mcs) { + // there has to be at least one false + // literal in the core. + m_mcs.insert(core[0]); + return l_true; + } sz = std::min(sz, core.size()); unsigned sz_save = m_mss.size(); m_mss.append(sz, core.c_ptr()); - lbool is_sat = s.check_sat(m_mss.size(), m_mss.c_ptr()); + lbool is_sat = m_s->check_sat(m_mss.size(), m_mss.c_ptr()); m_mss.resize(sz_save); switch (is_sat) { case l_true: - update_model(); + m_s->get_model(m_model); update_set(core); - return process_core(2*sz, core); + return process_core(2*sz, core, has_mcs, is_last); case l_false: if (sz == 1) { + has_mcs = true; m_mcs.insert(core[0]); core[0] = core.back(); core.pop_back(); @@ -138,12 +195,12 @@ namespace opt { exprs core2; core2.append(core.size()-sz, core.c_ptr()+sz); core.resize(sz); - is_sat = process_core(sz, core2); + is_sat = process_core(sz, core2, has_mcs, false); if (is_sat != l_true) { return is_sat; } } - return process_core(1, core); + return process_core(1, core, has_mcs, is_last); case l_undef: return l_undef; } @@ -151,8 +208,41 @@ namespace opt { return l_true; } + void mss::display_vec(std::ostream& out, unsigned sz, expr* const* args) const { + for (unsigned i = 0; i < sz; ++i) { + out << mk_pp(args[i], m) << " "; + } + out << "\n"; + } + void mss::display(std::ostream& out) const { - + expr_set::iterator it = m_mcs.begin(), end = m_mcs.end(); + out << "mcs:\n"; + for (; it != end; ++it) { + out << mk_pp(*it, m) << "\n"; + } + out << "\n"; + out << "mss:\n"; + for (unsigned i = 0; i < m_mss.size(); ++i) { + out << mk_pp(m_mss[i], m) << "\n"; + } + out << "\n"; + if (m_model) { + model_smt2_pp(out, m, *(m_model.get()), 0); + } + } + + bool mss::check_invariant() const { + if (!m_model) return true; + expr_ref tmp(m); + for (unsigned i = 0; i < m_mss.size(); ++i) { + expr* n = m_mss[i]; + VERIFY(m_model->eval(n, tmp)); + CTRACE("opt", !m.is_true(tmp), tout << mk_pp(n, m) << " |-> " << mk_pp(tmp, m) << "\n";); + SASSERT(!m.is_false(tmp)); + } + + return true; } } diff --git a/src/opt/mss.h b/src/opt/mss.h index 2e5d82df2..c434cd952 100644 --- a/src/opt/mss.h +++ b/src/opt/mss.h @@ -21,30 +21,34 @@ Notes: namespace opt { class mss { - solver& s; + ref& m_s; ast_manager& m; volatile bool m_cancel; typedef ptr_vector exprs; typedef obj_hashtable expr_set; exprs m_mss; expr_set m_mcs; - exprs m_todo; model_ref m_model; public: - mss(solver& s, ast_manager& m); + mss(ref& s, ast_manager& m); ~mss(); - lbool operator()(vector > const& cores, ptr_vector& literals); + lbool operator()(vector const& cores, exprs& literals); void set_cancel(bool f) { m_cancel = f; } + void get_model(model_ref& mdl) { mdl = m_model; } + private: - void check_parameters(vector const& cores, exprs& literals); + void initialize(vector& cores, exprs& literals); + bool check_result(); void update_model(); void update_set(exprs& lits); lbool process_core(exprs const& _core); - lbool process_core(unsigned sz, exprs& core); + lbool process_core(unsigned sz, exprs& core, bool& has_mcs, bool is_last); void display(std::ostream& out) const; + void display_vec(std::ostream& out, unsigned sz, expr* const* args) const; + bool check_invariant() const; }; }; From 317e76a11b231babcaac3bd865bd6007d92f4b36 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Aug 2014 20:23:10 -0700 Subject: [PATCH 452/925] mss and mss-mus-maxres Signed-off-by: Nikolaj Bjorner --- src/opt/mss.cpp | 87 +++++++++++++++++++++++++++++++++---------------- src/opt/mss.h | 8 +++-- 2 files changed, 64 insertions(+), 31 deletions(-) diff --git a/src/opt/mss.cpp b/src/opt/mss.cpp index 8a5bcdfe5..73c35bd79 100644 --- a/src/opt/mss.cpp +++ b/src/opt/mss.cpp @@ -19,7 +19,6 @@ Notes: --*/ #include "solver.h" -#include "smt_literal.h" #include "mss.h" #include "ast_pp.h" #include "model_smt2_pp.h" @@ -76,7 +75,10 @@ namespace opt { core_lits.insert(n); VERIFY(m_model->eval(n, tmp)); if (m.is_true(tmp)) { - m_mss.push_back(n); + add_mss(n); + } + else { + m_todo.push_back(n); } } } @@ -91,40 +93,60 @@ namespace opt { else { rest_core.push_back(n); core_lits.insert(n); + m_todo.push_back(n); } } } cores.push_back(rest_core); } - - void mss::update_set(exprs& lits) { - expr_ref tmp(m); - unsigned sz = lits.size(); + + void mss::add_mss(expr* n) { + if (!m_mss_set.contains(n)) { + m_mss_set.insert(n); + m_mss.push_back(n); + } + } + + void mss::update_core(exprs& core) { unsigned j = 0; - for (unsigned i = 0; i < lits.size(); ++i) { - expr* n = lits[i]; - if (m_mcs.contains(n)) { - // remove from todo. - continue; - } - VERIFY(m_model->eval(n, tmp)); - if (!m.is_true(tmp)) { - if (j != i) { - lits[j] = lits[i]; + for (unsigned i = 0; i < core.size(); ++i) { + expr* n = core[i]; + if (!m_mss_set.contains(n)) { + if (i != j) { + core[j] = core[i]; } ++j; } + } + core.resize(j); + } + + void mss::update_mss() { + expr_ref tmp(m); + unsigned j = 0; + for (unsigned i = 0; i < m_todo.size(); ++i) { + expr* n = m_todo[i]; + SASSERT(!m_mss_set.contains(n)); + if (m_mcs.contains(n)) { + continue; // remove from cores. + } + VERIFY(m_model->eval(n, tmp)); + if (m.is_true(tmp)) { + add_mss(n); + } else { - m_mss.push_back(n); + if (j != i) { + m_todo[j] = m_todo[i]; + } + ++j; } } - lits.resize(j); - } - + m_todo.resize(j); + } lbool mss::operator()(vector const& _cores, exprs& literals) { m_mss.reset(); - m_mcs.reset(); + m_todo.reset(); m_s->get_model(m_model); SASSERT(m_model); vector cores(_cores); @@ -141,8 +163,8 @@ namespace opt { bool has_mcs = false; bool is_last = i + 1 < cores.size(); SASSERT(check_invariant()); - update_set(cores[i]); - is_sat = process_core(1, cores[i], has_mcs, is_last); + update_core(cores[i]); // remove members of mss + is_sat = process_core(1, cores[i], has_mcs, is_last); } if (is_sat == l_true) { SASSERT(check_invariant()); @@ -151,6 +173,8 @@ namespace opt { literals.append(m_mss); SASSERT(check_result()); } + m_mcs.reset(); + m_mss_set.reset(); return is_sat; } @@ -160,7 +184,6 @@ namespace opt { // pick literals in core that are not yet in mss. // lbool mss::process_core(unsigned sz, exprs& core, bool& has_mcs, bool is_last) { - TRACE("opt", tout << "process: " << sz << " out of " << core.size() << " literals\n";); SASSERT(sz > 0); if (core.empty()) { return l_true; @@ -168,13 +191,15 @@ namespace opt { if (m_cancel) { return l_undef; } - if (sz == 1 && is_last && !has_mcs) { + if (sz == 1 && core.size() == 1 && is_last && !has_mcs) { // there has to be at least one false - // literal in the core. + // literal in the core. + TRACE("opt", tout << "mcs: " << mk_pp(core[0], m) << "\n";); m_mcs.insert(core[0]); return l_true; } sz = std::min(sz, core.size()); + TRACE("opt", display_vec(tout << "process (total " << core.size() << ") :", sz, core.c_ptr());); unsigned sz_save = m_mss.size(); m_mss.append(sz, core.c_ptr()); lbool is_sat = m_s->check_sat(m_mss.size(), m_mss.c_ptr()); @@ -182,7 +207,13 @@ namespace opt { switch (is_sat) { case l_true: m_s->get_model(m_model); - update_set(core); + update_mss(); + // sz entries from core should now be in mss. + DEBUG_CODE( + for (unsigned i = 0; i < sz; ++i) { + SASSERT(m_mss_set.contains(core[i])); + }); + update_core(core); return process_core(2*sz, core, has_mcs, is_last); case l_false: if (sz == 1) { @@ -199,6 +230,7 @@ namespace opt { if (is_sat != l_true) { return is_sat; } + update_core(core); } return process_core(1, core, has_mcs, is_last); case l_undef: @@ -241,7 +273,6 @@ namespace opt { CTRACE("opt", !m.is_true(tmp), tout << mk_pp(n, m) << " |-> " << mk_pp(tmp, m) << "\n";); SASSERT(!m.is_false(tmp)); } - return true; } } diff --git a/src/opt/mss.h b/src/opt/mss.h index c434cd952..34767beb6 100644 --- a/src/opt/mss.h +++ b/src/opt/mss.h @@ -28,6 +28,8 @@ namespace opt { typedef obj_hashtable expr_set; exprs m_mss; expr_set m_mcs; + expr_set m_mss_set; + exprs m_todo; model_ref m_model; public: mss(ref& s, ast_manager& m); @@ -42,9 +44,9 @@ namespace opt { private: void initialize(vector& cores, exprs& literals); bool check_result(); - void update_model(); - void update_set(exprs& lits); - lbool process_core(exprs const& _core); + void add_mss(expr* n); + void update_mss(); + void update_core(exprs& core); lbool process_core(unsigned sz, exprs& core, bool& has_mcs, bool is_last); void display(std::ostream& out) const; void display_vec(std::ostream& out, unsigned sz, expr* const* args) const; From e832bdd257e90aaf365e50dc6f799f9c74b1e820 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 10 Aug 2014 21:23:05 -0700 Subject: [PATCH 453/925] fix bug in blocked clause elimination that was enabled for external variables, fix other bugs in maxres Signed-off-by: Nikolaj Bjorner --- src/opt/inc_sat_solver.cpp | 21 ++++- src/opt/maxres.cpp | 103 ++++++++++++++-------- src/opt/maxsmt.cpp | 21 +++-- src/opt/maxsmt.h | 4 + src/opt/mss.cpp | 11 ++- src/opt/mss.h | 2 +- src/sat/sat_simplifier.cpp | 3 + src/sat/sat_solver.cpp | 171 ++++++++++++++++++++++++------------- src/sat/sat_solver.h | 4 +- 9 files changed, 233 insertions(+), 107 deletions(-) diff --git a/src/opt/inc_sat_solver.cpp b/src/opt/inc_sat_solver.cpp index f8979edce..9bab8e624 100644 --- a/src/opt/inc_sat_solver.cpp +++ b/src/opt/inc_sat_solver.cpp @@ -93,11 +93,12 @@ public: lbool r = internalize_formulas(); if (r != l_true) return r; r = internalize_assumptions(num_assumptions, assumptions, dep2asm); - extract_assumptions(dep2asm, m_asms); if (r != l_true) return r; + extract_assumptions(dep2asm, m_asms); r = m_solver.check(m_asms.size(), m_asms.c_ptr()); switch (r) { case l_true: + check_assumptions(dep2asm); break; case l_false: // TBD: expr_dependency core is not accounted for. @@ -271,6 +272,23 @@ private: } + void check_assumptions(dep2asm_t& dep2asm) { + sat::model const & ll_m = m_solver.get_model(); + dep2asm_t::iterator it = dep2asm.begin(), end = dep2asm.end(); + for (; it != end; ++it) { + sat::literal lit = it->m_value; + lbool polarity = lit.sign()?l_false:l_true; + lbool value = sat::value_at(lit.var(), ll_m); + if (value != polarity) { + std::cout << mk_pp(it->m_key, m) << " evaluates to " << value << "\n"; + std::cout << m_asms << "\n"; + m_solver.display_assignment(std::cout); + // m_solver.display(std::cout); + throw default_exception("bad state"); + } + } + } + // TBD: this is super-expensive because of the // bit-blasting model converter. @@ -286,6 +304,7 @@ private: continue; } sat::bool_var v = it->m_value; + // std::cout << mk_pp(n, m) << " -> " << sat::value_at(v, ll_m) << "\n"; switch (sat::value_at(v, ll_m)) { case l_true: md->register_decl(to_app(n)->get_decl(), m.mk_true()); diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 5e7dac0f7..f879ff99a 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -59,6 +59,8 @@ Notes: #include "ast_pp.h" #include "mus.h" #include "mss.h" +#include "inc_sat_solver.h" + using namespace opt; @@ -117,7 +119,7 @@ public: else { asum = mk_fresh_bool("soft"); fml = m.mk_iff(asum, e); - m_s->assert_expr(fml); + s().assert_expr(fml); } new_assumption(asum, w); m_upper += w; @@ -138,17 +140,17 @@ public: while (true) { TRACE("opt", display_vec(tout, m_asms.size(), m_asms.c_ptr()); - m_s->display(tout); + s().display(tout); tout << "\n"; display(tout); ); - lbool is_sat = m_s->check_sat(m_asms.size(), m_asms.c_ptr()); + lbool is_sat = s().check_sat(m_asms.size(), m_asms.c_ptr()); if (m_cancel) { return l_undef; } switch (is_sat) { case l_true: { - m_s->get_model(m_model); + s().get_model(m_model); expr_ref tmp(m); DEBUG_CODE( for (unsigned i = 0; i < m_asms.size(); ++i) { @@ -157,6 +159,7 @@ public: }); for (unsigned i = 0; i < m_soft.size(); ++i) { VERIFY(m_model->eval(m_soft[i].get(), tmp)); + std::cout << mk_pp(m_soft[i].get(), m) << " -> " << tmp << "\n"; m_assignment[i] = m.is_true(tmp); } m_upper = m_lower; @@ -186,7 +189,7 @@ public: while (m_lower < m_upper) { TRACE("opt", display_vec(tout, m_asms.size(), m_asms.c_ptr()); - m_s->display(tout); + s().display(tout); tout << "\n"; display(tout); ); @@ -203,11 +206,10 @@ public: return l_true; case l_true: SASSERT(cores.empty() || mcs.empty()); - SASSERT(!cores.empty() || !mcs.empty()); for (unsigned i = 0; is_sat == l_true && i < cores.size(); ++i) { is_sat = process_unsat(cores[i]); } - if (is_sat == l_true && !mcs.empty()) { + if (is_sat == l_true && cores.empty()) { is_sat = process_sat(mcs); } if (is_sat != l_true) { @@ -216,7 +218,7 @@ public: break; } } - m_lower = m_lower; + m_lower = m_upper; return l_true; } @@ -247,7 +249,7 @@ public: ptr_vector core; while (is_sat == l_false) { core.reset(); - m_s->get_unsat_core(core); + s().get_unsat_core(core); is_sat = minimize_core(core); if (is_sat != l_true) { break; @@ -261,7 +263,7 @@ public: TRACE("opt", display_vec(tout << "core: ", core.size(), core.c_ptr()); display_vec(tout << "assumptions: ", asms.size(), asms.c_ptr());); - is_sat = m_s->check_sat(asms.size(), asms.c_ptr()); + is_sat = s().check_sat(asms.size(), asms.c_ptr()); } TRACE("opt", tout << "num cores: " << cores.size() << "\n"; @@ -280,9 +282,8 @@ public: lbool process_sat(ptr_vector& corr_set) { expr_ref fml(m), tmp(m); TRACE("opt", display_vec(tout << "corr_set: ", corr_set.size(), corr_set.c_ptr());); - SASSERT(!corr_set.empty()); // we should somehow stop if all soft are satisfied. if (corr_set.empty()) { - return l_false; + return l_true; } remove_core(corr_set); @@ -314,7 +315,7 @@ public: TRACE("opt", display_vec(tout << "minimized core: ", core.size(), core.c_ptr());); max_resolve(core, w); fml = m.mk_not(m.mk_and(m_B.size(), m_B.c_ptr())); - m_s->assert_expr(fml); + s().assert_expr(fml); m_lower += w; IF_VERBOSE(1, verbose_stream() << "(opt.maxres [" << m_lower << ":" << m_upper << "])\n";); return l_true; @@ -407,9 +408,9 @@ public: if (i > 2) { dd = mk_fresh_bool("d"); fml = m.mk_implies(dd, d); - m_s->assert_expr(fml); + s().assert_expr(fml); fml = m.mk_implies(dd, b_i); - m_s->assert_expr(fml); + s().assert_expr(fml); d = dd; } else { @@ -419,7 +420,7 @@ public: cls = m.mk_or(b_i1, d); fml = m.mk_implies(asum, cls); new_assumption(asum, w); - m_s->assert_expr(fml); + s().assert_expr(fml); } } @@ -449,20 +450,20 @@ public: if (i > 2) { d = mk_fresh_bool("d"); fml = m.mk_implies(d, cls); - m_s->assert_expr(fml); + s().assert_expr(fml); } else { d = cls; } asum = mk_fresh_bool("a"); fml = m.mk_implies(asum, b_i1); - m_s->assert_expr(fml); + s().assert_expr(fml); fml = m.mk_implies(asum, cls); - m_s->assert_expr(fml); + s().assert_expr(fml); new_assumption(asum, w); } fml = m.mk_or(m_B.size(), m_B.c_ptr()); - m_s->assert_expr(fml); + s().assert_expr(fml); } lbool try_improve_bound(vector >& cores, ptr_vector& mcs) { @@ -473,25 +474,29 @@ public: while (true) { rational upper = m_max_upper; unsigned sz = 0; - for (unsigned i = 0; m_upper <= upper && i < asms.size(); ++i, ++sz) { + for (unsigned i = 0; m_upper <= rational(2)*upper && i < asms.size(); ++i, ++sz) { upper -= get_weight(asms[i].get()); } - lbool is_sat = m_s->check_sat(sz, asms.c_ptr()); + lbool is_sat = s().check_sat(sz, asms.c_ptr()); switch (is_sat) { case l_true: { - ptr_vector lits; - lits.append(asms.size(), asms.c_ptr()); + s().get_model(m_model); // last model is best way to reduce search space. + update_assignment(); + ptr_vector mss; + mss.append(asms.size(), asms.c_ptr()); set_mus(false); - is_sat = m_mss(cores, lits); + is_sat = m_mss(cores, mss, mcs); set_mus(true); if (is_sat != l_true) { return is_sat; } m_mss.get_model(m_model); // last model is best way to reduce search space. update_assignment(); - if (cores.empty() || asms.size() < cores.back().size()) { + if (!cores.empty() && mcs.size() > cores.back().size()) { + mcs.reset(); + } + else { cores.reset(); - mcs.append(asms.size(), asms.c_ptr()); } return l_true; } @@ -499,7 +504,7 @@ public: return l_undef; case l_false: core.reset(); - m_s->get_unsat_core(core); + s().get_unsat_core(core); is_sat = minimize_core(core); if (is_sat != l_true) { break; @@ -531,23 +536,29 @@ public: void update_assignment() { rational upper(0); + expr_ref tmp(m); for (unsigned i = 0; i < m_soft.size(); ++i) { - expr_ref tmp(m); expr* n = m_soft[i].get(); VERIFY(m_model->eval(n, tmp)); - CTRACE("opt", !m.is_true(tmp) && !m.is_false(tmp), - tout << mk_pp(n, m) << " |-> " << mk_pp(tmp, m) << "\n";); - - m_assignment[i] = m.is_true(tmp); - if (!m_assignment[i]) { + if (!m.is_true(tmp)) { upper += m_weights[i]; } + CTRACE("opt", !m.is_true(tmp) && !m.is_false(tmp), + tout << mk_pp(n, m) << " |-> " << mk_pp(tmp, m) << "\n";); + } + if (upper >= m_upper) { + return; + } + + for (unsigned i = 0; i < m_soft.size(); ++i) { + expr* n = m_soft[i].get(); + VERIFY(m_model->eval(n, tmp)); + m_assignment[i] = m.is_true(tmp); } - SASSERT(upper <= m_upper); m_upper = upper; + // verify_assignment(); IF_VERBOSE(1, verbose_stream() << "(opt.maxres [" << m_lower << ":" << m_upper << "])\n";); - } void remove_soft(ptr_vector const& core, expr_ref_vector& asms) { @@ -579,6 +590,26 @@ public: m_max_upper = m_upper; } + void verify_assignment() { + IF_VERBOSE(0, verbose_stream() << "verify assignment\n";); + ref sat_solver = mk_inc_sat_solver(m, m_params); + for (unsigned i = 0; i < m_assertions.size(); ++i) { + sat_solver->assert_expr(m_assertions[i].get()); + } + expr_ref n(m); + for (unsigned i = 0; i < m_soft.size(); ++i) { + n = m_soft[i].get(); + if (!m_assignment[i]) { + n = m.mk_not(n); + } + sat_solver->assert_expr(n); + } + lbool is_sat = sat_solver->check_sat(0, 0); + if (is_sat == l_false) { + IF_VERBOSE(0, verbose_stream() << "assignment is infeasible\n";); + } + } + }; opt::maxsmt_solver_base* opt::mk_maxres(ast_manager& m, opt_solver* s, params_ref& p, diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index eb0a65ce9..572c6e66c 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -134,6 +134,7 @@ namespace opt { unsigned sz = s().get_num_assertions(); for (unsigned i = 0; i < sz; ++i) { sat_solver->assert_expr(s().get_assertion(i)); + m_assertions.push_back(s().get_assertion(i)); } m_s = sat_solver; } @@ -232,16 +233,24 @@ namespace opt { }); DEBUG_CODE(if (is_sat == l_true) { - m_s->push(); - commit_assignment(); - VERIFY(l_true == m_s->check_sat(0,0)); - m_s->pop(1); - // TBD: check that all extensions are unsat too + verify_assignment(); + }); - }); + // TBD: check that all extensions are unsat too + return is_sat; } + void maxsmt::verify_assignment() { + m_s->push(); + commit_assignment(); + if (l_true != m_s->check_sat(0,0)) { + IF_VERBOSE(0, verbose_stream() << "could not verify assignment\n";); + UNREACHABLE(); + } + m_s->pop(1); + } + bool maxsmt::get_assignment(unsigned idx) const { if (m_msolver) { return m_msolver->get_assignment(idx); diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index df03499c9..a36269447 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -48,6 +48,7 @@ namespace opt { ast_manager& m; volatile bool m_cancel; expr_ref_vector m_soft; + expr_ref_vector m_assertions; vector m_weights; rational m_lower; rational m_upper; @@ -65,6 +66,7 @@ namespace opt { maxsmt_solver_base(opt_solver* s, ast_manager& m, params_ref& p, vector const& ws, expr_ref_vector const& soft): m_s(s), m(m), m_cancel(false), m_soft(m), + m_assertions(m), m_enable_sls(false), m_enable_sat(false), m_sls_enabled(false), m_sat_enabled(false) { m_s->get_model(m_model); @@ -148,6 +150,8 @@ namespace opt { private: bool is_maxsat_problem(vector const& ws) const; + + void verify_assignment(); }; diff --git a/src/opt/mss.cpp b/src/opt/mss.cpp index 73c35bd79..d796a2b92 100644 --- a/src/opt/mss.cpp +++ b/src/opt/mss.cpp @@ -144,7 +144,7 @@ namespace opt { m_todo.resize(j); } - lbool mss::operator()(vector const& _cores, exprs& literals) { + lbool mss::operator()(vector const& _cores, exprs& literals, exprs& mcs) { m_mss.reset(); m_todo.reset(); m_s->get_model(m_model); @@ -171,6 +171,11 @@ namespace opt { TRACE("opt", display(tout);); literals.reset(); literals.append(m_mss); + mcs.reset(); + expr_set::iterator it = m_mcs.begin(), end = m_mcs.end(); + for (; it != end; ++it) { + mcs.push_back(*it); + } SASSERT(check_result()); } m_mcs.reset(); @@ -203,12 +208,12 @@ namespace opt { unsigned sz_save = m_mss.size(); m_mss.append(sz, core.c_ptr()); lbool is_sat = m_s->check_sat(m_mss.size(), m_mss.c_ptr()); + IF_VERBOSE(1, display_vec(verbose_stream(), sz, core.c_ptr());); m_mss.resize(sz_save); switch (is_sat) { case l_true: m_s->get_model(m_model); - update_mss(); - // sz entries from core should now be in mss. + update_mss(); DEBUG_CODE( for (unsigned i = 0; i < sz; ++i) { SASSERT(m_mss_set.contains(core[i])); diff --git a/src/opt/mss.h b/src/opt/mss.h index 34767beb6..9f14f66c3 100644 --- a/src/opt/mss.h +++ b/src/opt/mss.h @@ -35,7 +35,7 @@ namespace opt { mss(ref& s, ast_manager& m); ~mss(); - lbool operator()(vector const& cores, exprs& literals); + lbool operator()(vector const& cores, exprs& literals, exprs& mcs); void set_cancel(bool f) { m_cancel = f; } diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 969a6c37a..76d3a1730 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -917,6 +917,9 @@ namespace sat { void process(literal l) { TRACE("blocked_clause", tout << "processing: " << l << "\n";); + if (s.is_external(l.var()) || s.was_eliminated(l.var())) { + return; + } model_converter::entry * new_entry = 0; { m_to_remove.reset(); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 91dada236..870544d92 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -880,7 +880,9 @@ namespace sat { TRACE("sat", for (unsigned i = 0; i < num_lits; ++i) tout << lits[i] << " "; - tout << "\n";); + tout << "\n"; + m_mc.display(tout); + ); #define _INSERT_LIT(_l_) \ SASSERT(is_external((_l_).var())); \ m_assumption_set.insert(_l_); \ @@ -950,7 +952,7 @@ namespace sat { m_simplifier(false); CASSERT("sat_simplify_bug", check_invariant()); CASSERT("sat_missed_prop", check_missed_propagation()); - + if (!m_learned.empty()) { m_simplifier(true); CASSERT("sat_missed_prop", check_missed_propagation()); @@ -1000,6 +1002,7 @@ namespace sat { IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "\"checking model\"\n";); if (!check_model(m_model)) throw solver_exception("check model failed"); + if (m_clone) { IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "\"checking model (on original set of clauses)\"\n";); if (!m_clone->check_model(m_model)) @@ -1018,7 +1021,12 @@ namespace sat { for (; it != end; ++it) { clause const & c = *(*it); if (!c.satisfied_by(m)) { - TRACE("sat_model_bug", tout << "failed: " << c << "\n";); + TRACE("sat", tout << "failed: " << c << "\n"; + tout << "assumptions: " << m_assumptions << "\n"; + tout << "trail: " << m_trail << "\n"; + tout << "model: " << m << "\n"; + m_mc.display(tout); + ); ok = false; } } @@ -1036,15 +1044,28 @@ namespace sat { continue; literal l2 = it2->get_literal(); if (value_at(l2, m) != l_true) { - TRACE("sat_model_bug", tout << "failed binary: " << l << " " << l2 << " learned: " << it2->is_learned() << "\n";); + TRACE("sat", tout << "failed binary: " << l << " " << l2 << " learned: " << it2->is_learned() << "\n"; + m_mc.display(tout);); ok = false; } } } } - if (!m_mc.check_model(m)) + for (unsigned i = 0; i < m_assumptions.size(); ++i) { + if (value_at(m_assumptions[i], m) != l_true) { + TRACE("sat", + tout << m_assumptions[i] << " does not model check\n"; + tout << "trail: " << m_trail << "\n"; + tout << "model: " << m << "\n"; + m_mc.display(tout); + ); + ok = false; + } + } + if (ok && !m_mc.check_model(m)) { ok = false; - TRACE("sat", tout << "check: " << ok << "\n" << m << "\n";); + TRACE("sat", tout << "model: " << m << "\n"; m_mc.display(tout);); + } return ok; } @@ -1532,73 +1553,99 @@ namespace sat { } } - void solver::resolve_conflict_for_unsat_core() { - TRACE("sat", display(tout);); + void solver::process_consequent_for_unsat_core(literal consequent, justification const& js) { + TRACE("sat", tout << "processing consequent: " << consequent << "\n"; + display_justification(tout << "js kind: ", js); + tout << "\n";); + switch (js.get_kind()) { + case justification::NONE: + break; + case justification::BINARY: + process_antecedent_for_unsat_core(~(js.get_literal())); + break; + case justification::TERNARY: + process_antecedent_for_unsat_core(~(js.get_literal1())); + process_antecedent_for_unsat_core(~(js.get_literal2())); + break; + case justification::CLAUSE: { + clause & c = *(m_cls_allocator.get_clause(js.get_clause_offset())); + unsigned i = 0; + if (consequent != null_literal) { + SASSERT(c[0] == consequent || c[1] == consequent); + if (c[0] == consequent) { + i = 1; + } + else { + process_antecedent_for_unsat_core(~c[0]); + i = 2; + } + } + unsigned sz = c.size(); + for (; i < sz; i++) + process_antecedent_for_unsat_core(~c[i]); + break; + } + case justification::EXT_JUSTIFICATION: { + fill_ext_antecedents(consequent, js); + literal_vector::iterator it = m_ext_antecedents.begin(); + literal_vector::iterator end = m_ext_antecedents.end(); + for (; it != end; ++it) + process_antecedent_for_unsat_core(*it); + break; + } + default: + UNREACHABLE(); + break; + } + } + void solver::resolve_conflict_for_unsat_core() { + TRACE("sat", display(tout); + unsigned level = 0; + for (unsigned i = 0; i < m_trail.size(); ++i) { + literal l = m_trail[i]; + if (level != m_level[l.var()]) { + level = m_level[l.var()]; + tout << level << ": "; + } + tout << l; + if (m_mark[l.var()]) { + tout << "*"; + } + tout << " "; + } + tout << "\n"; + ); + + m_core.reset(); if (m_conflict_lvl == 0) { return; } unsigned old_size = m_unmark.size(); - m_core.reset(); int idx = skip_literals_above_conflict_level(); if (m_not_l != null_literal) { - TRACE("sat", tout << "not_l: " << m_not_l << "\n";); + justification js = m_justification[m_not_l.var()]; + TRACE("sat", tout << "not_l: " << m_not_l << "\n"; + display_justification(tout, js); + tout << "\n";); + process_antecedent_for_unsat_core(m_not_l); if (is_assumption(~m_not_l)) { m_core.push_back(~m_not_l); } + else { + process_consequent_for_unsat_core(m_not_l, js); + } } - - + literal consequent = m_not_l; justification js = m_conflict; - do { - TRACE("sat", tout << "processing consequent: " << consequent << "\n"; - tout << "js kind: " << js << "\n";); - switch (js.get_kind()) { - case justification::NONE: - break; - case justification::BINARY: - process_antecedent_for_unsat_core(~(js.get_literal())); - break; - case justification::TERNARY: - process_antecedent_for_unsat_core(~(js.get_literal1())); - process_antecedent_for_unsat_core(~(js.get_literal2())); - break; - case justification::CLAUSE: { - clause & c = *(m_cls_allocator.get_clause(js.get_clause_offset())); - unsigned i = 0; - if (consequent != null_literal) { - SASSERT(c[0] == consequent || c[1] == consequent); - if (c[0] == consequent) { - i = 1; - } - else { - process_antecedent_for_unsat_core(~c[0]); - i = 2; - } - } - unsigned sz = c.size(); - for (; i < sz; i++) - process_antecedent_for_unsat_core(~c[i]); - break; - } - case justification::EXT_JUSTIFICATION: { - fill_ext_antecedents(consequent, js); - literal_vector::iterator it = m_ext_antecedents.begin(); - literal_vector::iterator end = m_ext_antecedents.end(); - for (; it != end; ++it) - process_antecedent_for_unsat_core(*it); - break; - } - default: - UNREACHABLE(); - break; - } - + while (true) { + process_consequent_for_unsat_core(consequent, js); + idx--; while (idx >= 0) { literal l = m_trail[idx]; if (is_marked(l.var())) @@ -1611,17 +1658,16 @@ namespace sat { } consequent = m_trail[idx]; if (lvl(consequent) < m_conflict_lvl) { + TRACE("sat", tout << consequent << " at level " << lvl(consequent) << "\n";); break; } bool_var c_var = consequent.var(); SASSERT(lvl(consequent) == m_conflict_lvl); js = m_justification[c_var]; - idx--; } - while (idx > 0); reset_unmark(old_size); if (m_config.m_minimize_core) { - m_mus(); //ignore return value on cancelation. + m_mus(); // ignore return value on cancelation. } } @@ -2362,6 +2408,13 @@ namespace sat { out << ")\n"; } + void solver::display_justification(std::ostream & out, justification const& js) const { + out << js; + if (js.is_clause()) { + out << *(m_cls_allocator.get_clause(js.get_clause_offset())); + } + } + unsigned solver::num_clauses() const { unsigned num_cls = 0; num_cls += m_trail.size(); // units; diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 056567bf9..e0b386c24 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -328,6 +328,7 @@ namespace sat { unsigned get_max_lvl(literal consequent, justification js); void process_antecedent(literal antecedent, unsigned & num_marks); void process_antecedent_for_unsat_core(literal antecedent); + void process_consequent_for_unsat_core(literal consequent, justification const& js); void fill_ext_antecedents(literal consequent, justification js); unsigned skip_literals_above_conflict_level(); void forget_phase_of_vars(unsigned from_lvl); @@ -425,11 +426,12 @@ namespace sat { void display(std::ostream & out) const; void display_watches(std::ostream & out) const; void display_dimacs(std::ostream & out) const; + void display_assignment(std::ostream & out) const; + void display_justification(std::ostream & out, justification const& j) const; protected: void display_binary(std::ostream & out) const; void display_units(std::ostream & out) const; - void display_assignment(std::ostream & out) const; unsigned num_clauses() const; bool is_unit(clause const & c) const; bool is_empty(clause const & c) const; From 39d90f914d69a1c378dc98aef39e5c396e5ba82a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 10 Aug 2014 21:27:07 -0700 Subject: [PATCH 454/925] NA Signed-off-by: Nikolaj Bjorner --- src/opt/inc_sat_solver.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/opt/inc_sat_solver.cpp b/src/opt/inc_sat_solver.cpp index 9bab8e624..78a980152 100644 --- a/src/opt/inc_sat_solver.cpp +++ b/src/opt/inc_sat_solver.cpp @@ -280,10 +280,10 @@ private: lbool polarity = lit.sign()?l_false:l_true; lbool value = sat::value_at(lit.var(), ll_m); if (value != polarity) { - std::cout << mk_pp(it->m_key, m) << " evaluates to " << value << "\n"; - std::cout << m_asms << "\n"; - m_solver.display_assignment(std::cout); - // m_solver.display(std::cout); + IF_VERBOSE(0, verbose_stream() << mk_pp(it->m_key, m) << " evaluates to " << value << "\n"; + verbose_stream() << m_asms << "\n"; + m_solver.display_assignment(verbose_stream()); + m_solver.display(verbose_stream());); throw default_exception("bad state"); } } @@ -304,7 +304,6 @@ private: continue; } sat::bool_var v = it->m_value; - // std::cout << mk_pp(n, m) << " -> " << sat::value_at(v, ll_m) << "\n"; switch (sat::value_at(v, ll_m)) { case l_true: md->register_decl(to_app(n)->get_decl(), m.mk_true()); From 1652c161635ddcc2bc39fcbd49e702720d42f8ed Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 10 Aug 2014 22:13:55 -0700 Subject: [PATCH 455/925] add missing code Signed-off-by: Nikolaj Bjorner --- src/opt/inc_sat_solver.cpp | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/opt/inc_sat_solver.cpp b/src/opt/inc_sat_solver.cpp index 78a980152..73638f44c 100644 --- a/src/opt/inc_sat_solver.cpp +++ b/src/opt/inc_sat_solver.cpp @@ -38,6 +38,8 @@ class inc_sat_solver : public solver { goal2sat m_goal2sat; params_ref m_params; expr_ref_vector m_fmls; + expr_ref_vector m_current_fmls; + unsigned_vector m_fmls_lim; expr_ref_vector m_core; atom2bool_var m_map; model_ref m_model; @@ -55,7 +57,7 @@ class inc_sat_solver : public solver { public: inc_sat_solver(ast_manager& m, params_ref const& p): m(m), m_solver(p,0), m_params(p), - m_fmls(m), m_core(m), m_map(m), + m_fmls(m), m_current_fmls(m), m_core(m), m_map(m), m_num_scopes(0), m_dep_core(m) { m_params.set_bool("elim_vars", false); @@ -119,28 +121,35 @@ public: virtual void push() { m_solver.user_push(); ++m_num_scopes; + m_fmls_lim.push_back(m_current_fmls.size()); } virtual void pop(unsigned n) { if (n < m_num_scopes) { // allow inc_sat_solver to n = m_num_scopes; // take over for another solver. } SASSERT(n >= m_num_scopes); - m_solver.user_pop(n); + m_solver.user_pop(n); m_num_scopes -= n; + while (n > 0) { + m_current_fmls.resize(m_fmls_lim.back()); + m_fmls_lim.pop_back(); + --n; + } } virtual unsigned get_scope_level() const { return m_num_scopes; } virtual void assert_expr(expr * t, expr * a) { if (a) { - m_fmls.push_back(m.mk_implies(a, t)); + assert_expr(m.mk_implies(a, t)); } else { - m_fmls.push_back(t); + assert_expr(t); } } virtual void assert_expr(expr * t) { m_fmls.push_back(t); + m_current_fmls.push_back(t); } virtual void set_produce_models(bool f) {} virtual void collect_param_descrs(param_descrs & r) { @@ -178,6 +187,15 @@ public: UNREACHABLE(); } + virtual unsigned get_num_assertions() const { + return m_fmls.size(); + } + + virtual expr * get_assertion(unsigned idx) const { + return m_fmls[idx]; + } + + private: lbool internalize_goal(goal_ref& g, dep2asm_t& dep2asm) { From 470b5c11b9856b3d42ec075761eb785a28fc3cf8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 11 Aug 2014 08:06:29 -0700 Subject: [PATCH 456/925] mus logging Signed-off-by: Nikolaj Bjorner --- src/sat/sat_mus.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/sat/sat_mus.cpp b/src/sat/sat_mus.cpp index e7eecfe4a..835777b47 100644 --- a/src/sat/sat_mus.cpp +++ b/src/sat/sat_mus.cpp @@ -59,7 +59,7 @@ namespace sat { literal lit = core.back(); core.pop_back(); unsigned sz = mus.size(); - //mus.push_back(~lit); // TBD: measure + mus.push_back(~lit); // TBD: measure mus.append(core); lbool is_sat = s.check(mus.size(), mus.c_ptr()); mus.resize(sz); @@ -78,7 +78,6 @@ namespace sat { core.append(mus); rmr(); core.resize(sz); - IF_VERBOSE(2, verbose_stream() << "(sat.mus.new " << mus << " " << core << ")\n";); break; } case l_false: @@ -86,7 +85,6 @@ namespace sat { if (new_core.contains(~lit)) { break; } - IF_VERBOSE(2, verbose_stream() << "(sat.mus.new " << new_core << ")\n";); core.reset(); for (unsigned i = 0; i < new_core.size(); ++i) { literal lit = new_core[i]; @@ -99,10 +97,13 @@ namespace sat { } TRACE("sat", tout << "new core: " << mus << "\n";); set_core(); + IF_VERBOSE(2, verbose_stream() << "(sat.mus.new " << core << ")\n";); return l_true; } void mus::rmr() { + return; +#if 0 model& model = s.m_model; literal lit = m_mus.back(); literal assumption_lit; @@ -122,6 +123,7 @@ namespace sat { model[lit.var()] = ~model[lit.var()]; // swap assignment back } m_toswap.resize(sz); +#endif } bool mus::has_single_unsat(literal& assumption_lit) { @@ -138,7 +140,7 @@ namespace sat { // void mus::find_swappable(literal lit) { - IF_VERBOSE(2, verbose_stream() << "(sat.mus swap " << lit << ")\n";); + IF_VERBOSE(3, verbose_stream() << "(sat.mus swap " << lit << ")\n";); unsigned sz = m_toswap.size(); literal lit2, lit3; model const& model = s.get_model(); From 180b0d4ec915c84b770bb609fae4e462118cde50 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 12 Aug 2014 19:24:31 -0700 Subject: [PATCH 457/925] add sls Signed-off-by: Nikolaj Bjorner --- src/opt/pb_sls.cpp | 44 ++-------------- src/sat/sat_mus.cpp | 60 +++++++++++++++++++--- src/sat/sat_mus.h | 3 ++ src/sat/sat_sls.cpp | 96 +++++++++++++++++++++++++++++++++++ src/sat/sat_sls.h | 60 ++++++++++++++++++++++ src/sat/sat_solver.cpp | 8 ++- src/shell/dimacs_frontend.cpp | 4 +- src/test/hilbert_basis.cpp | 30 +++++++++++ 8 files changed, 252 insertions(+), 53 deletions(-) create mode 100644 src/sat/sat_sls.cpp create mode 100644 src/sat/sat_sls.h diff --git a/src/opt/pb_sls.cpp b/src/opt/pb_sls.cpp index a702b6b7b..05bdd5cf8 100644 --- a/src/opt/pb_sls.cpp +++ b/src/opt/pb_sls.cpp @@ -20,49 +20,11 @@ Notes: #include "smt_literal.h" #include "ast_pp.h" #include "th_rewriter.h" +#include "sat_sls.h" namespace smt { struct pb_sls::imp { - struct index_set { - unsigned_vector m_elems; - unsigned_vector m_index; - - unsigned num_elems() const { return m_elems.size(); } - - void reset() { m_elems.reset(); m_index.reset(); } - - bool empty() const { return m_elems.empty(); } - - bool contains(unsigned idx) const { - return - (idx < m_index.size()) && - (m_index[idx] < m_elems.size()) && - (m_elems[m_index[idx]] == idx); - } - - void insert(unsigned idx) { - m_index.reserve(idx+1); - if (!contains(idx)) { - m_index[idx] = m_elems.size(); - m_elems.push_back(idx); - } - } - - void remove(unsigned idx) { - if (!contains(idx)) return; - unsigned pos = m_index[idx]; - m_elems[pos] = m_elems.back(); - m_index[m_elems[pos]] = pos; - m_elems.pop_back(); - } - - unsigned choose(random_gen& rnd) const { - SASSERT(!empty()); - return m_elems[rnd(num_elems())]; - } - }; - struct clause { literal_vector m_lits; scoped_mpz_vector m_weights; @@ -112,8 +74,8 @@ namespace smt { expr_ref_vector m_trail; obj_map m_decl2var; // map declarations to Boolean variables. ptr_vector m_var2decl; // reverse map - index_set m_hard_false; // list of hard clauses that are false. - index_set m_soft_false; // list of soft clauses that are false. + sat::index_set m_hard_false; // list of hard clauses that are false. + sat::index_set m_soft_false; // list of soft clauses that are false. unsigned m_max_flips; // maximal number of flips unsigned m_non_greedy_percent; // percent of moves to do non-greedy style random_gen m_rng; diff --git a/src/sat/sat_mus.cpp b/src/sat/sat_mus.cpp index e7eecfe4a..5f9154e05 100644 --- a/src/sat/sat_mus.cpp +++ b/src/sat/sat_mus.cpp @@ -36,6 +36,7 @@ namespace sat { m_core.append(m_mus); s.m_core.reset(); s.m_core.append(m_core); + m_model.reset(); } lbool mus::operator()() { @@ -46,11 +47,12 @@ namespace sat { literal_vector& core = m_core; literal_vector& mus = m_mus; core.append(s.get_core()); + while (!core.empty()) { TRACE("sat", tout << "core: " << core << "\n"; - tout << "mus: " << mus << "\n";); + tout << "mus: " << mus << "\n";); if (s.m_cancel) { set_core(); @@ -59,7 +61,7 @@ namespace sat { literal lit = core.back(); core.pop_back(); unsigned sz = mus.size(); - //mus.push_back(~lit); // TBD: measure + mus.push_back(~lit); // TBD: measure mus.append(core); lbool is_sat = s.check(mus.size(), mus.c_ptr()); mus.resize(sz); @@ -76,9 +78,9 @@ namespace sat { } sz = core.size(); core.append(mus); - rmr(); + measure_mr(); + // rmr(); core.resize(sz); - IF_VERBOSE(2, verbose_stream() << "(sat.mus.new " << mus << " " << core << ")\n";); break; } case l_false: @@ -86,7 +88,6 @@ namespace sat { if (new_core.contains(~lit)) { break; } - IF_VERBOSE(2, verbose_stream() << "(sat.mus.new " << new_core << ")\n";); core.reset(); for (unsigned i = 0; i < new_core.size(); ++i) { literal lit = new_core[i]; @@ -99,9 +100,27 @@ namespace sat { } TRACE("sat", tout << "new core: " << mus << "\n";); set_core(); + IF_VERBOSE(2, verbose_stream() << "(sat.mus.new " << m_core << ")\n";); return l_true; } + void mus::measure_mr() { + model const& m2 = s.get_model(); + if (!m_model.empty()) { + unsigned n = 0; + for (unsigned i = 0; i < m_model.size(); ++i) { + if (m2[i] != m_model[i]) ++n; + } + std::cout << "model diff: " << n << " out of " << m_model.size() << "\n"; + } + m_model.reset(); + m_model.append(m2); + } + + // + // TBD: eager model rotation allows rotating the same clause + // several times with respect to different models. + // void mus::rmr() { model& model = s.m_model; literal lit = m_mus.back(); @@ -146,16 +165,33 @@ namespace sat { watch_list const& wlist = s.get_wlist(lit); watch_list::const_iterator it = wlist.begin(); watch_list::const_iterator end = wlist.end(); - for (; it != end; ++it) { + unsigned num_cand = 0; + for (; it != end && num_cand <= 1; ++it) { switch (it->get_kind()) { case watched::BINARY: + if (it->is_learned()) { + break; + } lit2 = it->get_literal(); + if (value_at(lit2, model) == l_true) { + break; + } + IF_VERBOSE(1, verbose_stream() << "(" << ~lit << " " << lit2 << ") ";); TRACE("sat", tout << ~lit << " " << lit2 << "\n";); + ++num_cand; break; case watched::TERNARY: lit2 = it->get_literal1(); lit3 = it->get_literal2(); - TRACE("sat", tout << ~lit << " " << lit2 << " " << lit3 << "\n";); + if (value_at(lit2, model) == l_true) { + break; + } + if (value_at(lit3, model) == l_true) { + break; + } + + IF_VERBOSE(1, verbose_stream() << "(" << ~lit << " " << lit2 << " " << lit3 << ") ";); + ++num_cand; break; case watched::CLAUSE: { clause_offset cls_off = it->get_clause_offset(); @@ -163,15 +199,23 @@ namespace sat { if (c.is_learned()) { break; } + ++num_cand; + IF_VERBOSE(1, verbose_stream() << c << " ";); TRACE("sat", tout << c << "\n";); break; } case watched::EXT_CONSTRAINT: TRACE("sat", tout << "external constraint - should avoid rmr\n";); - m_toswap.resize(sz); return; } } + if (num_cand > 1) { + m_toswap.resize(sz); + } + else { + IF_VERBOSE(1, verbose_stream() << "wlist size: " << num_cand << " " << m_core.size() << "\n";); + } + } } diff --git a/src/sat/sat_mus.h b/src/sat/sat_mus.h index b2643ade6..964bddfe5 100644 --- a/src/sat/sat_mus.h +++ b/src/sat/sat_mus.h @@ -24,6 +24,8 @@ namespace sat { literal_vector m_core; literal_vector m_mus; literal_vector m_toswap; + model m_model; + solver& s; public: mus(solver& s); @@ -32,6 +34,7 @@ namespace sat { private: lbool mus2(); void rmr(); + void measure_mr(); bool has_single_unsat(literal& assumption_lit); void find_swappable(literal lit); void reset(); diff --git a/src/sat/sat_sls.cpp b/src/sat/sat_sls.cpp new file mode 100644 index 000000000..128152952 --- /dev/null +++ b/src/sat/sat_sls.cpp @@ -0,0 +1,96 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + sat_sls.cpp + +Abstract: + + SLS for clauses in SAT solver + +Author: + + Nikolaj Bjorner (nbjorner) 2014-12-8 + +Notes: + +--*/ + +#include "sat_sls.h" + +namespace sat { + + bool index_set::contains(unsigned idx) const { + return + (idx < m_index.size()) && + (m_index[idx] < m_elems.size()) && + (m_elems[m_index[idx]] == idx); + } + + void index_set::insert(unsigned idx) { + m_index.reserve(idx+1); + if (!contains(idx)) { + m_index[idx] = m_elems.size(); + m_elems.push_back(idx); + } + } + + void index_set::remove(unsigned idx) { + if (!contains(idx)) return; + unsigned pos = m_index[idx]; + m_elems[pos] = m_elems.back(); + m_index[m_elems[pos]] = pos; + m_elems.pop_back(); + } + + unsigned index_set::choose(random_gen& rnd) const { + SASSERT(!empty()); + return m_elems[rnd(num_elems())]; + } + + sls::sls(solver& s): s(s) { + + } + + sls::~sls() { + + } + +#if 0 + bool_var sls::pick_flip() { + unsigned clause_idx = m_false.choose(m_rand); + clause const& c = m_clauses[clause_idx]; + unsigned result = UINT_MAX; + m_min_vars.reset(); + for (unsigned i = 0; i < c.size(); ++i) { + + } + } + + void sls::flip(bool_var v) { + + } + + bool sls::local_search() { + for (unsigned i = 0; !m_false.empty() && i < m_max_flips; ++i) { + flip(pick_flip()); + } + return m_false.empty(); + } + +#endif + + lbool sls::operator()() { +#if 0 + for (unsigned i = 0; i < m_max_tries; ++i) { + if (local_search()) { + return l_true; + } + } +#endif + return l_undef; + } + +}; + diff --git a/src/sat/sat_sls.h b/src/sat/sat_sls.h new file mode 100644 index 000000000..80f660317 --- /dev/null +++ b/src/sat/sat_sls.h @@ -0,0 +1,60 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + sat_sls.h + +Abstract: + + SLS for clauses in SAT solver + +Author: + + Nikolaj Bjorner (nbjorner) 2014-12-8 + +Notes: + +--*/ +#ifndef _SAT_SLS_H_ +#define _SAT_SLS_H_ + +#include "util.h" +#include "sat_simplifier.h" + +namespace sat { + + class index_set { + unsigned_vector m_elems; + unsigned_vector m_index; + public: + unsigned num_elems() const { return m_elems.size(); } + void reset() { m_elems.reset(); m_index.reset(); } + bool empty() const { return m_elems.empty(); } + bool contains(unsigned idx) const; + void insert(unsigned idx); + void remove(unsigned idx); + unsigned choose(random_gen& rnd) const; + }; + + class sls { + solver& s; + random_gen m_rand; + unsigned m_max_tries; + unsigned m_max_flips; + index_set m_false; + use_list m_use_list; + vector m_clauses; + public: + sls(solver& s); + ~sls(); + lbool operator()(); + private: + bool local_search(); + bool_var pick_flip(); + void flip(bool_var v); + }; + +}; + +#endif diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 870544d92..25ad62361 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -48,6 +48,8 @@ namespace sat { m_scope_lvl(0), m_params(p) { m_config.updt_params(p); + m_conflicts_since_gc = 0; + m_next_simplify = 0; } solver::~solver() { @@ -924,10 +926,8 @@ namespace sat { m_conflicts_since_restart = 0; m_restart_threshold = m_config.m_restart_initial; m_luby_idx = 1; - m_conflicts_since_gc = 0; m_gc_threshold = m_config.m_gc_initial; m_min_d_tk = 1.0; - m_next_simplify = 0; m_stopwatch.reset(); m_stopwatch.start(); m_core.reset(); @@ -1667,6 +1667,10 @@ namespace sat { } reset_unmark(old_size); if (m_config.m_minimize_core) { + // TBD: + // apply optional clause minimization by detecting subsumed literals. + // initial experiment suggests it has no effect. + m_mus(); // ignore return value on cancelation. } } diff --git a/src/shell/dimacs_frontend.cpp b/src/shell/dimacs_frontend.cpp index 879c5f212..abaa2eace 100644 --- a/src/shell/dimacs_frontend.cpp +++ b/src/shell/dimacs_frontend.cpp @@ -101,7 +101,7 @@ static void track_clauses(sat::solver const& src, sat::clause * const * end = src.end_clauses(); svector bin_clauses; src.collect_bin_clauses(bin_clauses, false); - tracking_clauses.reserve(2*src.num_vars() + (end - it) + bin_clauses.size()); + tracking_clauses.reserve(2*src.num_vars() + static_cast(end - it) + bin_clauses.size()); for (sat::bool_var v = 1; v < src.num_vars(); ++v) { if (src.value(v) != l_undef) { @@ -114,7 +114,7 @@ static void track_clauses(sat::solver const& src, for (; it != end; ++it) { lits.reset(); sat::clause& cls = *(*it); - lits.append(cls.end()-cls.begin(), cls.begin()); + lits.append(static_cast(cls.end()-cls.begin()), cls.begin()); track_clause(dst, lits, assumptions, tracking_clauses); } for (unsigned i = 0; i < bin_clauses.size(); ++i) { diff --git a/src/test/hilbert_basis.cpp b/src/test/hilbert_basis.cpp index 4752dd78d..60af1eae8 100644 --- a/src/test/hilbert_basis.cpp +++ b/src/test/hilbert_basis.cpp @@ -540,6 +540,33 @@ static void tst19() { saturate_basis(hb); } +static void test_A_5_5_3() { + hilbert_basis hb; + for (unsigned i = 0; i < 15; ++i) { + vector v; + for (unsigned j = 0; j < 5; ++j) { + for (unsigned k = 0; k < 15; ++k) { + v.push_back(rational(k == i)); + } + } + hb.add_ge(v, R(0)); + } + for (unsigned i = 1; i <= 15; ++i) { + vector v; + for (unsigned k = 1; k <= 5; ++k) { + for (unsigned l = 1; l <= 5; ++l) { + for (unsigned j = 1; j <= 3; ++j) { + bool one = ((j*k <= i) && (((i - j) % 3) == 0); // fixme + v.push_back(rational(one)); + } + } + } + hb.add_ge(v, R(0)); + } + // etc. + saturate_basis(hb); +} + void tst_hilbert_basis() { std::cout << "hilbert basis test\n"; // tst3(); @@ -547,6 +574,9 @@ void tst_hilbert_basis() { g_use_ordered_support = true; + test_A_5_5_3(); + return; + tst18(); return; From 311183e19ac598aa0bb686ded4f12b810ba93318 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 12 Aug 2014 19:26:06 -0700 Subject: [PATCH 458/925] local updates Signed-off-by: Nikolaj Bjorner --- src/sat/sat_mus.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/sat/sat_mus.cpp b/src/sat/sat_mus.cpp index a3685869a..c67ff9b29 100644 --- a/src/sat/sat_mus.cpp +++ b/src/sat/sat_mus.cpp @@ -100,11 +100,7 @@ namespace sat { } TRACE("sat", tout << "new core: " << mus << "\n";); set_core(); -<<<<<<< HEAD IF_VERBOSE(2, verbose_stream() << "(sat.mus.new " << core << ")\n";); -======= - IF_VERBOSE(2, verbose_stream() << "(sat.mus.new " << m_core << ")\n";); ->>>>>>> 180b0d4ec915c84b770bb609fae4e462118cde50 return l_true; } From 1412c183d44d603c926550b78bf98c5e6495e0d3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 12 Aug 2014 21:42:33 -0700 Subject: [PATCH 459/925] finish sls code Signed-off-by: Nikolaj Bjorner --- src/sat/sat_sls.cpp | 182 ++++++++++++++++++++++++++++++++++++------- src/sat/sat_sls.h | 26 +++++-- src/sat/sat_solver.h | 1 + 3 files changed, 173 insertions(+), 36 deletions(-) diff --git a/src/sat/sat_sls.cpp b/src/sat/sat_sls.cpp index 128152952..12900e94e 100644 --- a/src/sat/sat_sls.cpp +++ b/src/sat/sat_sls.cpp @@ -18,6 +18,7 @@ Notes: --*/ #include "sat_sls.h" +#include "sat_solver.h" namespace sat { @@ -50,47 +51,170 @@ namespace sat { } sls::sls(solver& s): s(s) { - + m_max_tries = 10000; + m_prob_choose_min_var = 43; } sls::~sls() { - - } - -#if 0 - bool_var sls::pick_flip() { - unsigned clause_idx = m_false.choose(m_rand); - clause const& c = m_clauses[clause_idx]; - unsigned result = UINT_MAX; - m_min_vars.reset(); - for (unsigned i = 0; i < c.size(); ++i) { - + for (unsigned i = 0; i < m_bin_clauses.size(); ++i) { + m_alloc.del_clause(m_bin_clauses[i]); } } - void sls::flip(bool_var v) { - - } - - bool sls::local_search() { - for (unsigned i = 0; !m_false.empty() && i < m_max_flips; ++i) { - flip(pick_flip()); - } - return m_false.empty(); - } - -#endif - - lbool sls::operator()() { -#if 0 + lbool sls::operator()(unsigned sz, literal const* tabu) { + init(sz, tabu); + for (unsigned i = 0; i < m_max_tries; ++i) { - if (local_search()) { + flip(); + if (m_false.empty()) { + SASSERT(s.check_model(m_model)); return l_true; } } -#endif return l_undef; } + void sls::init(unsigned sz, literal const* tabu) { + init_clauses(); + init_model(sz, tabu); + init_use(); + } + + void sls::init_clauses() { + for (unsigned i = 0; i < m_bin_clauses.size(); ++i) { + m_alloc.del_clause(m_bin_clauses[i]); + } + m_clauses.reset(); + clause * const * it = s.begin_clauses(); + clause * const * end = s.end_clauses(); + for (; it != end; ++it) { + m_clauses.push_back(*it); + } + svector bincs; + s.collect_bin_clauses(bincs, false); + literal lits[2]; + for (unsigned i = 0; i < bincs.size(); ++i) { + lits[0] = bincs[i].first; + lits[1] = bincs[i].second; + m_clauses.push_back(m_alloc.mk_clause(2, lits, false)); + } + } + + void sls::init_model(unsigned sz, literal const* tabu) { + m_num_true.reset(); + m_model.reset(); + m_model.append(s.get_model()); + m_tabu.reset(); + m_tabu.resize(s.num_vars(), false); + for (unsigned i = 0; i < sz; ++i) { + m_model[tabu[i].var()] = tabu[i].sign()?l_false:l_true; + } + + sz = m_clauses.size(); + for (unsigned i = 0; i < sz; ++i) { + clause const& c = *m_clauses[i]; + unsigned n = 0; + unsigned csz = c.size(); + for (unsigned j = 0; j < csz; ++j) { + if (value_at(c[j], m_model) == l_true) { + ++n; + } + } + m_num_true.push_back(n); + if (n == 0) { + m_false.insert(i); + } + } + } + + void sls::init_use() { + m_use_list.reset(); + m_use_list.resize(s.num_vars()*2); + unsigned sz = m_clauses.size(); + for (unsigned i = 0; i < sz; ++i) { + clause const& c = *m_clauses[i]; + unsigned csz = c.size(); + for (unsigned j = 0; j < csz; ++j) { + m_use_list[c[j].index()].push_back(i); + } + } + } + + unsigned_vector const& sls::get_use(literal lit) { + SASSERT(lit.index() < m_use_list.size()); + return m_use_list[lit.index()]; + } + + unsigned sls::get_break_count(literal lit, unsigned min_break) { + SASSERT(value_at(lit, m_model) == l_false); + unsigned result = 0; + unsigned_vector const& uses = get_use(~lit); + unsigned sz = uses.size(); + for (unsigned i = 0; i < sz; ++i) { + if (m_num_true[uses[i]] == 1) { + ++result; + if (result > min_break) return result; + } + } + return result; + } + + bool sls::pick_flip(literal& lit) { + unsigned clause_idx = m_false.choose(m_rand); + clause const& c = *m_clauses[clause_idx]; + SASSERT(!c.satisfied_by(m_model)); + unsigned min_break = UINT_MAX; + unsigned sz = c.size(); + m_min_vars.reset(); + for (unsigned i = 0; i < sz; ++i) { + lit = c[i]; + if (m_tabu[lit.var()]) continue; + unsigned break_count = get_break_count(lit, min_break); + if (break_count < min_break) { + min_break = break_count; + m_min_vars.reset(); + m_min_vars.push_back(lit); + } + else if (break_count == min_break) { + m_min_vars.push_back(lit); + } + } + if (min_break == 0 || (m_min_vars.empty() && m_rand(100) >= m_prob_choose_min_var)) { + lit = m_min_vars[m_rand(m_min_vars.size())]; + return true; + } + else if (min_break == UINT_MAX) { + return false; + } + else { + lit = c[m_rand(c.size())]; + return !m_tabu[lit.var()]; + } + } + + void sls::flip() { + literal lit; + if (!pick_flip(lit)) return; + SASSERT(value_at(lit, m_model) == l_false); + m_model[lit.var()] = lit.sign()?l_true:l_false; + SASSERT(value_at(lit, m_model) == l_true); + unsigned_vector const& use1 = get_use(lit); + unsigned sz = use1.size(); + for (unsigned i = 0; i < sz; ++i) { + unsigned cl = use1[i]; + m_num_true[cl]++; + SASSERT(m_num_true[cl] <= m_clauses[cl]->size()); + if (m_num_true[cl] == 1) m_false.remove(cl); + } + unsigned_vector const& use2 = get_use(~lit); + sz = use2.size(); + for (unsigned i = 0; i < sz; ++i) { + unsigned cl = use2[i]; + SASSERT(m_num_true[cl] > 0); + m_num_true[cl]--; + if (m_num_true[cl] == 0) m_false.insert(cl); + } + } + }; diff --git a/src/sat/sat_sls.h b/src/sat/sat_sls.h index 80f660317..438623bcb 100644 --- a/src/sat/sat_sls.h +++ b/src/sat/sat_sls.h @@ -41,18 +41,30 @@ namespace sat { solver& s; random_gen m_rand; unsigned m_max_tries; - unsigned m_max_flips; - index_set m_false; - use_list m_use_list; - vector m_clauses; + unsigned m_prob_choose_min_var; // number between 0 and 99. + ptr_vector m_clauses; // vector of all clauses. + index_set m_false; // clauses currently false + vector m_use_list; // use lists for literals + unsigned_vector m_num_true; // per clause, count of # true literals + svector m_min_vars; // literals with smallest break count + model m_model; // current model + clause_allocator m_alloc; // clause allocator + clause_vector m_bin_clauses; // binary clauses + svector m_tabu; // variables that cannot be swapped public: sls(solver& s); ~sls(); - lbool operator()(); + lbool operator()(unsigned sz, literal const* tabu); private: bool local_search(); - bool_var pick_flip(); - void flip(bool_var v); + void init(unsigned sz, literal const* tabu); + void init_model(unsigned sz, literal const* tabu); + void init_use(); + void init_clauses(); + bool pick_flip(literal& lit); + void flip(); + unsigned get_break_count(literal lit, unsigned min_break); + unsigned_vector const& get_use(literal lit); }; }; diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index e0b386c24..804bea5ce 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -135,6 +135,7 @@ namespace sat { friend class probing; friend class iff3_finder; friend class mus; + friend class sls; friend struct mk_stat; public: solver(params_ref const & p, extension * ext); From cafb31ff9486538da7b8917dd9b47ec6e5984851 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 12 Aug 2014 22:14:57 -0700 Subject: [PATCH 460/925] sls updates Signed-off-by: Nikolaj Bjorner --- src/sat/sat_mus.cpp | 30 +++++++++++++++++++++++++----- src/sat/sat_sls.cpp | 26 +++++++++++++++++++------- src/sat/sat_sls.h | 2 +- 3 files changed, 45 insertions(+), 13 deletions(-) diff --git a/src/sat/sat_mus.cpp b/src/sat/sat_mus.cpp index c67ff9b29..7717fe795 100644 --- a/src/sat/sat_mus.cpp +++ b/src/sat/sat_mus.cpp @@ -20,6 +20,7 @@ Notes: #include "sat_solver.h" #include "sat_mus.h" +#include "sat_sls.h" namespace sat { @@ -76,11 +77,11 @@ namespace sat { if (core.empty()) { break; } - sz = core.size(); - core.append(mus); - measure_mr(); + // sz = core.size(); + // measure_mr(); + // core.append(mus); // rmr(); - core.resize(sz); + // core.resize(sz); break; } case l_false: @@ -114,7 +115,26 @@ namespace sat { std::cout << "model diff: " << n << " out of " << m_model.size() << "\n"; } m_model.reset(); - m_model.append(m2); + m_model.append(m2); + + sls sls(s); + literal_vector tabu; + tabu.append(m_mus); + tabu.append(m_core); + for (unsigned i = m_mus.size(); i < tabu.size(); ++i) { + tabu[i] = ~tabu[i]; + lbool is_sat = sls(tabu.size(), tabu.c_ptr()); + tabu[i] = ~tabu[i]; + switch (is_sat) { + case l_true: + //m_mus.push_back(tabu[i]); + //m_core.erase(tabu[i]); + std::cout << "in core " << tabu[i] << "\n"; + break; + default: + break; + } + } } // diff --git a/src/sat/sat_sls.cpp b/src/sat/sat_sls.cpp index 12900e94e..615cd7e2c 100644 --- a/src/sat/sat_sls.cpp +++ b/src/sat/sat_sls.cpp @@ -64,12 +64,12 @@ namespace sat { lbool sls::operator()(unsigned sz, literal const* tabu) { init(sz, tabu); - for (unsigned i = 0; i < m_max_tries; ++i) { + for (unsigned i = 0; !m_false.empty() && i < m_max_tries; ++i) { flip(); - if (m_false.empty()) { - SASSERT(s.check_model(m_model)); - return l_true; - } + } + if (m_false.empty()) { + SASSERT(s.check_model(m_model)); + return l_true; } return l_undef; } @@ -84,6 +84,7 @@ namespace sat { for (unsigned i = 0; i < m_bin_clauses.size(); ++i) { m_alloc.del_clause(m_bin_clauses[i]); } + m_bin_clauses.reset(); m_clauses.reset(); clause * const * it = s.begin_clauses(); clause * const * end = s.end_clauses(); @@ -108,6 +109,7 @@ namespace sat { m_tabu.resize(s.num_vars(), false); for (unsigned i = 0; i < sz; ++i) { m_model[tabu[i].var()] = tabu[i].sign()?l_false:l_true; + SASSERT(value_at(tabu[i], m_model) == l_true); } sz = m_clauses.size(); @@ -116,8 +118,18 @@ namespace sat { unsigned n = 0; unsigned csz = c.size(); for (unsigned j = 0; j < csz; ++j) { - if (value_at(c[j], m_model) == l_true) { + lbool val = value_at(c[j], m_model); + switch (val) { + case l_true: ++n; + break; + case l_undef: + ++n; + m_model[c[j].var()] = c[j].sign()?l_false:l_true; + SASSERT(value_at(c[j], m_model) == l_true); + break; + default: + break; } } m_num_true.push_back(n); @@ -196,7 +208,7 @@ namespace sat { literal lit; if (!pick_flip(lit)) return; SASSERT(value_at(lit, m_model) == l_false); - m_model[lit.var()] = lit.sign()?l_true:l_false; + m_model[lit.var()] = lit.sign()?l_false:l_true; SASSERT(value_at(lit, m_model) == l_true); unsigned_vector const& use1 = get_use(lit); unsigned sz = use1.size(); diff --git a/src/sat/sat_sls.h b/src/sat/sat_sls.h index 438623bcb..f651b3123 100644 --- a/src/sat/sat_sls.h +++ b/src/sat/sat_sls.h @@ -38,7 +38,7 @@ namespace sat { }; class sls { - solver& s; + solver& s; random_gen m_rand; unsigned m_max_tries; unsigned m_prob_choose_min_var; // number between 0 and 99. From 999db1e28035867bb7b283bbac855e1c9f80891e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Aug 2014 01:22:45 -0700 Subject: [PATCH 461/925] sls Signed-off-by: Nikolaj Bjorner --- src/sat/sat_mus.cpp | 151 ++++------------------------------------- src/sat/sat_mus.h | 7 +- src/sat/sat_sls.cpp | 79 +++++++++++++++------ src/sat/sat_sls.h | 9 ++- src/sat/sat_solver.cpp | 11 ++- src/sat/sat_solver.h | 3 +- 6 files changed, 92 insertions(+), 168 deletions(-) diff --git a/src/sat/sat_mus.cpp b/src/sat/sat_mus.cpp index 7717fe795..db1e90b39 100644 --- a/src/sat/sat_mus.cpp +++ b/src/sat/sat_mus.cpp @@ -37,7 +37,6 @@ namespace sat { m_core.append(m_mus); s.m_core.reset(); s.m_core.append(m_core); - m_model.reset(); } lbool mus::operator()() { @@ -47,8 +46,7 @@ namespace sat { reset(); literal_vector& core = m_core; literal_vector& mus = m_mus; - core.append(s.get_core()); - + core.append(s.get_core()); while (!core.empty()) { TRACE("sat", @@ -74,14 +72,9 @@ namespace sat { case l_true: { SASSERT(value_at(lit, s.get_model()) == l_false); mus.push_back(lit); - if (core.empty()) { - break; + if (!core.empty()) { + // mr(); // TBD: measure } - // sz = core.size(); - // measure_mr(); - // core.append(mus); - // rmr(); - // core.resize(sz); break; } case l_false: @@ -105,141 +98,27 @@ namespace sat { return l_true; } - void mus::measure_mr() { - model const& m2 = s.get_model(); - if (!m_model.empty()) { - unsigned n = 0; - for (unsigned i = 0; i < m_model.size(); ++i) { - if (m2[i] != m_model[i]) ++n; - } - std::cout << "model diff: " << n << " out of " << m_model.size() << "\n"; - } - m_model.reset(); - m_model.append(m2); - + void mus::mr() { sls sls(s); literal_vector tabu; tabu.append(m_mus); tabu.append(m_core); + bool reuse_model = false; for (unsigned i = m_mus.size(); i < tabu.size(); ++i) { tabu[i] = ~tabu[i]; - lbool is_sat = sls(tabu.size(), tabu.c_ptr()); + lbool is_sat = sls(tabu.size(), tabu.c_ptr(), reuse_model); tabu[i] = ~tabu[i]; - switch (is_sat) { - case l_true: - //m_mus.push_back(tabu[i]); - //m_core.erase(tabu[i]); - std::cout << "in core " << tabu[i] << "\n"; - break; - default: - break; + if (is_sat == l_true) { + m_mus.push_back(tabu[i]); + m_core.erase(tabu[i]); + IF_VERBOSE(2, verbose_stream() << "in core " << tabu[i] << "\n";); + reuse_model = true; + } + else { + IF_VERBOSE(2, verbose_stream() << "NOT in core " << tabu[i] << "\n";); + reuse_model = false; } } } - - // - // TBD: eager model rotation allows rotating the same clause - // several times with respect to different models. - // - void mus::rmr() { - return; -#if 0 - model& model = s.m_model; - literal lit = m_mus.back(); - literal assumption_lit; - SASSERT(value_at(lit, model) == l_false); - // literal is false in current model. - unsigned sz = m_toswap.size(); - find_swappable(lit); - unsigned sz1 = m_toswap.size(); - for (unsigned i = sz; i < sz1; ++i) { - lit = m_toswap[i]; - SASSERT(value_at(lit, model) == l_false); - model[lit.var()] = ~model[lit.var()]; // swap assignment - if (has_single_unsat(assumption_lit) && !m_mus.contains(assumption_lit)) { - m_mus.push_back(assumption_lit); - rmr(); - } - model[lit.var()] = ~model[lit.var()]; // swap assignment back - } - m_toswap.resize(sz); -#endif - } - - bool mus::has_single_unsat(literal& assumption_lit) { - model const& model = s.get_model(); - return false; - } - - // - // lit is false in model. - // find clauses where ~lit occurs, and all other literals - // are false in model. - // for each of the probed literals, determine if swapping the - // assignment falsifies a hard clause, if not, add to m_toswap. - // - - void mus::find_swappable(literal lit) { - IF_VERBOSE(3, verbose_stream() << "(sat.mus swap " << lit << ")\n";); - unsigned sz = m_toswap.size(); - literal lit2, lit3; - model const& model = s.get_model(); - SASSERT(value_at(lit, model) == l_false); - watch_list const& wlist = s.get_wlist(lit); - watch_list::const_iterator it = wlist.begin(); - watch_list::const_iterator end = wlist.end(); - unsigned num_cand = 0; - for (; it != end && num_cand <= 1; ++it) { - switch (it->get_kind()) { - case watched::BINARY: - if (it->is_learned()) { - break; - } - lit2 = it->get_literal(); - if (value_at(lit2, model) == l_true) { - break; - } - IF_VERBOSE(1, verbose_stream() << "(" << ~lit << " " << lit2 << ") ";); - TRACE("sat", tout << ~lit << " " << lit2 << "\n";); - ++num_cand; - break; - case watched::TERNARY: - lit2 = it->get_literal1(); - lit3 = it->get_literal2(); - if (value_at(lit2, model) == l_true) { - break; - } - if (value_at(lit3, model) == l_true) { - break; - } - - IF_VERBOSE(1, verbose_stream() << "(" << ~lit << " " << lit2 << " " << lit3 << ") ";); - ++num_cand; - break; - case watched::CLAUSE: { - clause_offset cls_off = it->get_clause_offset(); - clause& c = *(s.m_cls_allocator.get_clause(cls_off)); - if (c.is_learned()) { - break; - } - ++num_cand; - IF_VERBOSE(1, verbose_stream() << c << " ";); - TRACE("sat", tout << c << "\n";); - break; - } - case watched::EXT_CONSTRAINT: - TRACE("sat", tout << "external constraint - should avoid rmr\n";); - return; - } - } - if (num_cand > 1) { - m_toswap.resize(sz); - } - else { - IF_VERBOSE(1, verbose_stream() << "wlist size: " << num_cand << " " << m_core.size() << "\n";); - } - - } - } diff --git a/src/sat/sat_mus.h b/src/sat/sat_mus.h index 964bddfe5..c91464394 100644 --- a/src/sat/sat_mus.h +++ b/src/sat/sat_mus.h @@ -23,8 +23,6 @@ namespace sat { class mus { literal_vector m_core; literal_vector m_mus; - literal_vector m_toswap; - model m_model; solver& s; public: @@ -33,10 +31,7 @@ namespace sat { lbool operator()(); private: lbool mus2(); - void rmr(); - void measure_mr(); - bool has_single_unsat(literal& assumption_lit); - void find_swappable(literal lit); + void mr(); void reset(); void set_core(); }; diff --git a/src/sat/sat_sls.cpp b/src/sat/sat_sls.cpp index 615cd7e2c..04c8d0605 100644 --- a/src/sat/sat_sls.cpp +++ b/src/sat/sat_sls.cpp @@ -53,6 +53,7 @@ namespace sat { sls::sls(solver& s): s(s) { m_max_tries = 10000; m_prob_choose_min_var = 43; + m_clause_generation = 0; } sls::~sls() { @@ -61,12 +62,13 @@ namespace sat { } } - lbool sls::operator()(unsigned sz, literal const* tabu) { - init(sz, tabu); - - for (unsigned i = 0; !m_false.empty() && i < m_max_tries; ++i) { + lbool sls::operator()(unsigned sz, literal const* tabu, bool reuse_model) { + init(sz, tabu, reuse_model); + unsigned i; + for (i = 0; !m_false.empty() && i < m_max_tries; ++i) { flip(); } + IF_VERBOSE(2, verbose_stream() << "tries " << i << "\n";); if (m_false.empty()) { SASSERT(s.check_model(m_model)); return l_true; @@ -74,10 +76,18 @@ namespace sat { return l_undef; } - void sls::init(unsigned sz, literal const* tabu) { - init_clauses(); - init_model(sz, tabu); - init_use(); + void sls::init(unsigned sz, literal const* tabu, bool reuse_model) { + bool same_generation = (m_clause_generation == s.m_stats.m_non_learned_generation); + if (!same_generation) { + init_clauses(); + init_use(); + IF_VERBOSE(0, verbose_stream() << s.m_stats.m_non_learned_generation << " " << m_clause_generation << "\n";); + } + if (!reuse_model) { + init_model(); + } + init_tabu(sz, tabu); + m_clause_generation = s.m_stats.m_non_learned_generation; } void sls::init_clauses() { @@ -97,22 +107,17 @@ namespace sat { for (unsigned i = 0; i < bincs.size(); ++i) { lits[0] = bincs[i].first; lits[1] = bincs[i].second; - m_clauses.push_back(m_alloc.mk_clause(2, lits, false)); + clause* cl = m_alloc.mk_clause(2, lits, false); + m_clauses.push_back(cl); + m_bin_clauses.push_back(cl); } } - void sls::init_model(unsigned sz, literal const* tabu) { + void sls::init_model() { m_num_true.reset(); m_model.reset(); m_model.append(s.get_model()); - m_tabu.reset(); - m_tabu.resize(s.num_vars(), false); - for (unsigned i = 0; i < sz; ++i) { - m_model[tabu[i].var()] = tabu[i].sign()?l_false:l_true; - SASSERT(value_at(tabu[i], m_model) == l_true); - } - - sz = m_clauses.size(); + unsigned sz = m_clauses.size(); for (unsigned i = 0; i < sz; ++i) { clause const& c = *m_clauses[i]; unsigned n = 0; @@ -136,7 +141,32 @@ namespace sat { if (n == 0) { m_false.insert(i); } - } + } + } + + void sls::init_tabu(unsigned sz, literal const* tabu) { + // our main use is where m_model satisfies all the hard constraints. + // SASSERT(s.check_model(m_model)); + // SASSERT(m_false.empty()); + // ASSERT: m_num_true is correct count. + m_tabu.reset(); + m_tabu.resize(s.num_vars(), false); + for (unsigned i = 0; i < sz; ++i) { + literal lit = tabu[i]; + if (s.m_level[lit.var()] == 0) continue; + if (value_at(lit, m_model) == l_false) { + flip(lit); + } + m_tabu[lit.var()] = true; + } + for (unsigned i = 0; i < s.m_trail.size(); ++i) { + literal lit = s.m_trail[i]; + if (s.m_level[lit.var()] > 0) break; + if (value_at(lit, m_model) != l_true) { + flip(lit); + } + m_tabu[lit.var()] = true; + } } void sls::init_use() { @@ -191,7 +221,7 @@ namespace sat { m_min_vars.push_back(lit); } } - if (min_break == 0 || (m_min_vars.empty() && m_rand(100) >= m_prob_choose_min_var)) { + if (min_break == 0 || (!m_min_vars.empty() && m_rand(100) >= m_prob_choose_min_var)) { lit = m_min_vars[m_rand(m_min_vars.size())]; return true; } @@ -206,8 +236,15 @@ namespace sat { void sls::flip() { literal lit; - if (!pick_flip(lit)) return; + if (pick_flip(lit)) { + flip(lit); + } + } + + void sls::flip(literal lit) { + // IF_VERBOSE(0, verbose_stream() << lit << " ";); SASSERT(value_at(lit, m_model) == l_false); + SASSERT(!m_tabu[lit.var()]); m_model[lit.var()] = lit.sign()?l_false:l_true; SASSERT(value_at(lit, m_model) == l_true); unsigned_vector const& use1 = get_use(lit); diff --git a/src/sat/sat_sls.h b/src/sat/sat_sls.h index f651b3123..6237c5b13 100644 --- a/src/sat/sat_sls.h +++ b/src/sat/sat_sls.h @@ -42,6 +42,7 @@ namespace sat { random_gen m_rand; unsigned m_max_tries; unsigned m_prob_choose_min_var; // number between 0 and 99. + unsigned m_clause_generation; ptr_vector m_clauses; // vector of all clauses. index_set m_false; // clauses currently false vector m_use_list; // use lists for literals @@ -54,15 +55,17 @@ namespace sat { public: sls(solver& s); ~sls(); - lbool operator()(unsigned sz, literal const* tabu); + lbool operator()(unsigned sz, literal const* tabu, bool reuse_model); private: bool local_search(); - void init(unsigned sz, literal const* tabu); - void init_model(unsigned sz, literal const* tabu); + void init(unsigned sz, literal const* tabu, bool reuse_model); + void init_tabu(unsigned sz, literal const* tabu); + void init_model(); void init_use(); void init_clauses(); bool pick_flip(literal& lit); void flip(); + void flip(literal lit); unsigned get_break_count(literal lit, unsigned min_break); unsigned_vector const& get_use(literal lit); }; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 25ad62361..c100f15b1 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -61,6 +61,7 @@ namespace sat { for (clause * const * it = begin; it != end; ++it) { m_cls_allocator.del_clause(*it); } + ++m_stats.m_non_learned_generation; } void solver::copy(solver const & src) { @@ -165,6 +166,12 @@ namespace sat { mk_clause(3, ls); } + void solver::del_clause(clause& c) { + m_cls_allocator.del_clause(&c); + m_stats.m_del_clause++; + if (!c.is_learned()) m_stats.m_non_learned_generation++; + } + clause * solver::mk_clause_core(unsigned num_lits, literal * lits, bool learned) { TRACE("sat", tout << "mk_clause: " << mk_lits_pp(num_lits, lits) << "\n";); if (!learned) { @@ -173,7 +180,8 @@ namespace sat { if (!keep) { return 0; // clause is equivalent to true. } - } + ++m_stats.m_non_learned_generation; + } switch (num_lits) { case 0: @@ -2690,6 +2698,7 @@ namespace sat { m_del_clause = 0; m_minimized_lits = 0; m_dyn_sub_res = 0; + m_non_learned_generation = 0; } void mk_stat::display(std::ostream & out) const { diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 804bea5ce..33e88f64e 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -58,6 +58,7 @@ namespace sat { unsigned m_del_clause; unsigned m_minimized_lits; unsigned m_dyn_sub_res; + unsigned m_non_learned_generation; stats() { reset(); } void reset(); void collect_statistics(statistics & st) const; @@ -173,7 +174,7 @@ namespace sat { void mk_clause(literal l1, literal l2, literal l3); protected: - void del_clause(clause & c) { m_cls_allocator.del_clause(&c); m_stats.m_del_clause++; } + void del_clause(clause & c); clause * mk_clause_core(unsigned num_lits, literal * lits, bool learned); void mk_bin_clause(literal l1, literal l2, bool learned); bool propagate_bin_clause(literal l1, literal l2); From a02cab2194ec2dbb743b26ee7b37aa418d51e9bb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Aug 2014 16:58:02 -0700 Subject: [PATCH 462/925] wsls code Signed-off-by: Nikolaj Bjorner --- src/sat/sat_sls.cpp | 230 ++++++++++++++++++++++++++++++++++++++++++- src/sat/sat_sls.h | 47 +++++++-- src/sat/sat_solver.h | 1 + 3 files changed, 271 insertions(+), 7 deletions(-) diff --git a/src/sat/sat_sls.cpp b/src/sat/sat_sls.cpp index 04c8d0605..78d9b66e5 100644 --- a/src/sat/sat_sls.cpp +++ b/src/sat/sat_sls.cpp @@ -65,7 +65,7 @@ namespace sat { lbool sls::operator()(unsigned sz, literal const* tabu, bool reuse_model) { init(sz, tabu, reuse_model); unsigned i; - for (i = 0; !m_false.empty() && i < m_max_tries; ++i) { + for (i = 0; !m_false.empty() && !m_cancel && i < m_max_tries; ++i) { flip(); } IF_VERBOSE(2, verbose_stream() << "tries " << i << "\n";); @@ -265,5 +265,233 @@ namespace sat { } } + void sls::check_invariant() { + + } + + wsls::wsls(solver& s): + sls(s) + { + m_smoothing_probability = 1; // 1/1000 + } + + wsls::~wsls() {} + + void wsls::set_soft(unsigned sz, double const* weights, literal const* lits) { + m_soft.reset(); + m_weights.reset(); + m_soft.append(sz, lits); + m_weights.append(sz, weights); + } + + void wsls::opt(unsigned sz, literal const* tabu, bool reuse_model) { + init(sz, tabu, reuse_model); + + // + // Initialize m_clause_weights, m_hscore, m_sscore. + // + m_best_value = m_false.empty()?evaluate_model():-1.0; + m_clause_weights.reset(); + m_hscore.reset(); + m_sscore.reset(); + m_H.reset(); + m_S.reset(); + m_clause_weights.resize(m_clauses.size(), 1); + m_sscore.resize(s.num_vars(), 0.0); + m_hscore.resize(s.num_vars(), 0); + for (unsigned i = 0; i < m_soft.size(); ++i) { + literal lit = m_soft[i]; + m_sscore[lit.var()] = m_weights[i]; + if (value_at(lit, m_model) == l_true) { + m_sscore[lit.var()] = -m_sscore[lit.var()]; + } + } + for (unsigned i = 0; i < s.num_vars(); ++i) { + m_hscore[i] = compute_hscore(i); + refresh_scores(i); + } + unsigned i = 0; + for (; !m_cancel && i < m_max_tries; ++i) { + wflip(); + } + IF_VERBOSE(2, verbose_stream() << "tries " << i << "\n";); + } + + void wsls::wflip() { + literal lit; + if (pick_wflip(lit)) { + wflip(lit); + } + } + + bool wsls::pick_wflip(literal & lit) { + if (m_false.empty()) { + double val = evaluate_model(); + if (val < m_best_value || m_best_value < 0.0) { + m_best_model.reset(); + m_best_model.append(m_model); + } + } + unsigned idx; + if (!m_H.empty()) { + idx = m_H.choose(m_rand); + lit = literal(idx, false); + if (value_at(lit, m_model) == l_true) lit.neg(); + } + else if (!m_S.empty()) { + double score = 0.0; + m_min_vars.reset(); + for (unsigned i = 0; i < m_S.num_elems(); ++i) { + unsigned v = m_S[i]; + SASSERT(m_sscore[v] > 0.0); + if (m_sscore[v] > score) { + m_min_vars.reset(); + m_min_vars.push_back(literal(v, false)); + score = m_sscore[v]; + } + else if (m_sscore[v] == score) { + m_min_vars.push_back(literal(v, false)); + } + } + idx = m_min_vars[m_rand(m_min_vars.size())].var(); // pick with largest sscore. + } + else { + update_hard_weights(); + if (!m_false.empty()) { + unsigned cls_idx = m_false.choose(m_rand); + } + else { + lit = m_soft[m_rand(m_soft.size())]; + } + } + return !m_tabu[lit.var()]; + } + + void wsls::wflip(literal lit) { + flip(lit); + unsigned v = lit.var(); + m_hscore[v] = compute_hscore(v); + m_sscore[v] = -m_sscore[v]; + refresh_scores(v); + } + + void wsls::update_hard_weights() { + unsigned csz = m_clauses.size(); + if (m_smoothing_probability >= m_rand(1000)) { + for (unsigned i = 0; i < csz; ++i) { + if (m_clause_weights[i] > 1 && !m_false.contains(i)) { + --m_clause_weights[i]; + if (m_num_true[i] == 1) { + clause const& c = *m_clauses[i]; + unsigned sz = c.size(); + for (unsigned j = 0; j < sz; ++j) { + if (value_at(c[j], m_model) == l_true) { + ++m_hscore[c[j].var()]; + refresh_scores(c[j].var()); + break; + } + } + } + } + } + } + else { + for (unsigned i = 0; i < csz; ++i) { + if (m_false.contains(i)) { + ++m_clause_weights[i]; + clause const& c = *m_clauses[i]; + unsigned sz = c.size(); + for (unsigned j = 0; j < sz; ++j) { + ++m_hscore[c[j].var()]; + refresh_scores(c[j].var()); + } + } + } + } + + DEBUG_CODE(check_invariant();); + } + + double wsls::evaluate_model() { + SASSERT(m_false.empty()); + double result = 0.0; + for (unsigned i = 0; i < m_soft.size(); ++i) { + literal lit = m_soft[i]; + if (value_at(lit, m_model) != l_true) { + result += m_weights[i]; + } + } + return result; + } + + int wsls::compute_hscore(unsigned v) { + literal lit(v, false); + if (value_at(lit, m_model) == l_false) { + lit.neg(); + } + SASSERT(value_at(lit, m_model) == l_true); + int hs = 0; + unsigned_vector const& use1 = get_use(~lit); + unsigned sz = use1.size(); + for (unsigned i = 0; i < sz; ++i) { + unsigned cl = use1[i]; + if (m_num_true[cl] == 0) { + SASSERT(m_false.contains(cl)); + hs += m_clause_weights[cl]; + } + else { + SASSERT(!m_false.contains(cl)); + } + } + unsigned_vector const& use2 = get_use(lit); + sz = use2.size(); + for (unsigned i = 0; i < sz; ++i) { + unsigned cl = use2[i]; + if (m_num_true[cl] == 1) { + SASSERT(!m_false.contains(cl)); + hs -= m_clause_weights[cl]; + } + } + return hs; + } + + void wsls::refresh_scores(unsigned v) { + if (m_hscore[v] > 0) { + m_H.insert(v); + } + else { + m_H.remove(v); + } + if (m_sscore[v] > 0) { + if (m_hscore[v] == 0) { + m_S.insert(v); + } + else { + m_S.remove(v); + } + } + else if (m_sscore[v] < 0) { + m_S.remove(v); + } + } + + void wsls::check_invariant() { + sls::check_invariant(); + // The hscore is the reward for flipping the truth value of variable v. + // hscore(v) = Sum weight(c) for num_true(c) = 0 and v in c + // - Sum weight(c) for num_true(c) = 1 and (v in c, M(v) or !v in c and !M(v)) + for (unsigned v = 0; v < s.num_vars(); ++v) { + int hs = compute_hscore(v); + SASSERT(m_hscore[v] == hs); + } + + // The score(v) is the reward on soft clauses for flipping v. + for (unsigned j = 0; j < m_soft.size(); ++j) { + unsigned v = m_soft[j].var(); + double ss = value_at(m_soft[j], m_model)?(-m_weights[j]):m_weights[j]; + SASSERT(m_sscore[v] == ss); + } + } + }; diff --git a/src/sat/sat_sls.h b/src/sat/sat_sls.h index 6237c5b13..5546b90ac 100644 --- a/src/sat/sat_sls.h +++ b/src/sat/sat_sls.h @@ -28,7 +28,8 @@ namespace sat { unsigned_vector m_elems; unsigned_vector m_index; public: - unsigned num_elems() const { return m_elems.size(); } + unsigned num_elems() const { return m_elems.size(); } + unsigned operator[](unsigned idx) const { return m_elems[idx]; } void reset() { m_elems.reset(); m_index.reset(); } bool empty() const { return m_elems.empty(); } bool contains(unsigned idx) const; @@ -38,6 +39,7 @@ namespace sat { }; class sls { + protected: solver& s; random_gen m_rand; unsigned m_max_tries; @@ -52,22 +54,55 @@ namespace sat { clause_allocator m_alloc; // clause allocator clause_vector m_bin_clauses; // binary clauses svector m_tabu; // variables that cannot be swapped + volatile bool m_cancel; public: sls(solver& s); - ~sls(); + virtual ~sls(); lbool operator()(unsigned sz, literal const* tabu, bool reuse_model); - private: - bool local_search(); + void set_cancel(bool f) { m_cancel = f; } + protected: void init(unsigned sz, literal const* tabu, bool reuse_model); void init_tabu(unsigned sz, literal const* tabu); void init_model(); void init_use(); void init_clauses(); + unsigned_vector const& get_use(literal lit); + void flip(literal lit); + virtual void check_invariant(); + private: bool pick_flip(literal& lit); void flip(); - void flip(literal lit); unsigned get_break_count(literal lit, unsigned min_break); - unsigned_vector const& get_use(literal lit); + }; + + /** + \brief sls with weighted soft clauses. + */ + class wsls : public sls { + unsigned_vector m_clause_weights; + svector m_hscore; + svector m_sscore; + literal_vector m_soft; + svector m_weights; + double m_best_value; + model m_best_model; + index_set m_H, m_S; + unsigned m_smoothing_probability; + public: + wsls(solver& s); + virtual ~wsls(); + void set_soft(unsigned sz, double const* weights, literal const* lits); + void opt(unsigned sz, literal const* tabu, bool reuse_model); + model const& get_model() { return m_best_model; } + private: + void wflip(); + void wflip(literal lit); + void update_hard_weights(); + bool pick_wflip(literal & lit); + double evaluate_model(); + virtual void check_invariant(); + void refresh_scores(unsigned v); + int compute_hscore(unsigned v); }; }; diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 33e88f64e..869330e06 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -137,6 +137,7 @@ namespace sat { friend class iff3_finder; friend class mus; friend class sls; + friend class wsls; friend struct mk_stat; public: solver(params_ref const & p, extension * ext); From ee1a1b11357bdc0706911d3a7f11099fb829c1e6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Aug 2014 10:40:44 -0700 Subject: [PATCH 463/925] refactor sat/sls interface. Remove wpm2 and bvsls dependencies Signed-off-by: Nikolaj Bjorner --- src/opt/bcd2.cpp | 9 +- src/opt/bcd2.h | 3 +- src/opt/bvsls_opt_solver.cpp | 123 ----------------- src/opt/bvsls_opt_solver.h | 57 -------- src/opt/core_maxsat.cpp | 6 +- src/opt/core_maxsat.h | 2 +- src/opt/fu_malik.cpp | 90 +++---------- src/opt/fu_malik.h | 2 +- src/opt/inc_sat_solver.cpp | 93 +++++++++---- src/opt/inc_sat_solver.h | 2 + src/opt/maxhs.cpp | 11 +- src/opt/maxhs.h | 2 +- src/opt/maxres.cpp | 61 ++++++--- src/opt/maxres.h | 6 +- src/opt/maxsls.cpp | 12 +- src/opt/maxsls.h | 2 +- src/opt/maxsmt.cpp | 160 +++++++--------------- src/opt/maxsmt.h | 70 +++------- src/opt/mss.cpp | 14 +- src/opt/mss.h | 4 +- src/opt/mus.cpp | 20 +-- src/opt/mus.h | 2 +- src/opt/opt_context.cpp | 208 +++++++++++++++++++++-------- src/opt/opt_context.h | 28 +++- src/opt/opt_solver.cpp | 11 +- src/opt/opt_solver.h | 7 +- src/opt/pbmax.cpp | 10 +- src/opt/pbmax.h | 2 +- src/opt/wmax.cpp | 18 +-- src/opt/wmax.h | 2 +- src/opt/wpm2.cpp | 251 ----------------------------------- src/opt/wpm2.h | 29 ---- src/sat/sat_config.cpp | 1 + src/sat/sat_config.h | 1 + src/sat/sat_mus.cpp | 1 + src/sat/sat_params.pyg | 1 + src/sat/sat_sls.cpp | 135 +++++++++++++++++-- src/sat/sat_sls.h | 7 +- src/sat/sat_solver.cpp | 11 ++ src/sat/sat_solver.h | 5 +- src/sat/tactic/goal2sat.cpp | 13 +- src/smt/theory_wmaxsat.cpp | 4 +- src/smt/theory_wmaxsat.h | 4 +- 43 files changed, 609 insertions(+), 891 deletions(-) delete mode 100644 src/opt/bvsls_opt_solver.cpp delete mode 100644 src/opt/bvsls_opt_solver.h delete mode 100644 src/opt/wpm2.cpp delete mode 100644 src/opt/wpm2.h diff --git a/src/opt/bcd2.cpp b/src/opt/bcd2.cpp index cb579b9ef..7e5ac38f8 100644 --- a/src/opt/bcd2.cpp +++ b/src/opt/bcd2.cpp @@ -99,9 +99,9 @@ namespace opt { } public: - bcd2(opt_solver* s, ast_manager& m, params_ref& p, + bcd2(context& c, vector const& ws, expr_ref_vector const& soft): - maxsmt_solver_base(s, m, p, ws, soft), + maxsmt_solver_base(c, ws, soft), pb(m), m_soft_aux(m), m_trail(m), @@ -116,7 +116,6 @@ namespace opt { expr_ref fml(m), r(m); lbool is_sat = l_undef; expr_ref_vector asms(m); - enable_sls(); solver::scoped_push _scope1(s()); init(); init_bcd(); @@ -400,9 +399,9 @@ namespace opt { } }; - maxsmt_solver_base* opt::mk_bcd2(ast_manager& m, opt_solver* s, params_ref& p, + maxsmt_solver_base* opt::mk_bcd2(context& c, vector const& ws, expr_ref_vector const& soft) { - return alloc(bcd2, s, m, p, ws, soft); + return alloc(bcd2, c, ws, soft); } } diff --git a/src/opt/bcd2.h b/src/opt/bcd2.h index db08b15ef..6528c2807 100644 --- a/src/opt/bcd2.h +++ b/src/opt/bcd2.h @@ -23,7 +23,6 @@ Notes: #include "maxsmt.h" namespace opt { - maxsmt_solver_base* mk_bcd2(ast_manager& m, opt_solver* s, params_ref& p, - vector const& ws, expr_ref_vector const& soft); + maxsmt_solver_base* mk_bcd2(context& c, vector const& ws, expr_ref_vector const& soft); } #endif diff --git a/src/opt/bvsls_opt_solver.cpp b/src/opt/bvsls_opt_solver.cpp deleted file mode 100644 index 9bb858856..000000000 --- a/src/opt/bvsls_opt_solver.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - bvsls_opt_solver.cpp - -Abstract: - - Uses the bvsls engine for optimization - -Author: - - Christoph (cwinter) 2014-3-28 - -Notes: - ---*/ - -#include "bvsls_opt_solver.h" - -namespace opt { - - bvsls_opt_solver::bvsls_opt_solver(ast_manager & m, params_ref const & p) : - opt_solver(m, p, symbol("QF_BV")), - m_manager(m), - m_params(p), - m_engine(m, p) - { - } - - bvsls_opt_solver::~bvsls_opt_solver() - { - } - - void bvsls_opt_solver::updt_params(params_ref & p) - { - opt_solver::updt_params(p); - m_engine.updt_params(p); - } - - void bvsls_opt_solver::collect_param_descrs(param_descrs & r) - { - opt_solver::collect_param_descrs(r); - } - - void bvsls_opt_solver::collect_statistics(statistics & st) const - { - opt_solver::collect_statistics(st); - } - - void bvsls_opt_solver::assert_expr(expr * t) { - m_engine.assert_expr(t); - } - - void bvsls_opt_solver::push_core() - { - opt_solver::push_core(); - } - - void bvsls_opt_solver::pop_core(unsigned n) - { - opt_solver::pop_core(n); - } - - lbool bvsls_opt_solver::check_sat_core(unsigned num_assumptions, expr * const * assumptions) - { - SASSERT(num_assumptions == 0); - SASSERT(assumptions == 0); - return m_engine(); - } - - void bvsls_opt_solver::get_unsat_core(ptr_vector & r) - { - NOT_IMPLEMENTED_YET(); - } - - void bvsls_opt_solver::get_model(model_ref & m) - { - NOT_IMPLEMENTED_YET(); - } - - proof * bvsls_opt_solver::get_proof() - { - NOT_IMPLEMENTED_YET(); - } - - std::string bvsls_opt_solver::reason_unknown() const - { - NOT_IMPLEMENTED_YET(); - } - - void bvsls_opt_solver::get_labels(svector & r) - { - opt_solver::get_labels(r); - } - - void bvsls_opt_solver::set_cancel(bool f) - { - opt_solver::set_cancel(f); - m_engine.set_cancel(f); - } - - void bvsls_opt_solver::set_progress_callback(progress_callback * callback) - { - opt_solver::set_progress_callback(callback); - } - - unsigned bvsls_opt_solver::get_num_assertions() const - { - NOT_IMPLEMENTED_YET(); - } - - expr * bvsls_opt_solver::get_assertion(unsigned idx) const - { - NOT_IMPLEMENTED_YET(); - } - - void bvsls_opt_solver::display(std::ostream & out) const - { - NOT_IMPLEMENTED_YET(); - } -} \ No newline at end of file diff --git a/src/opt/bvsls_opt_solver.h b/src/opt/bvsls_opt_solver.h deleted file mode 100644 index eac1d0403..000000000 --- a/src/opt/bvsls_opt_solver.h +++ /dev/null @@ -1,57 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - bvsls_opt_solver.h - -Abstract: - - Uses the bvsls engine for optimization - -Author: - - Christoph (cwinter) 2014-3-28 - -Notes: - ---*/ -#ifndef _BVSLS_OPT_SOLVER_H_ -#define _BVSLS_OPT_SOLVER_H_ - -#include "bvsls_opt_engine.h" -#include "opt_solver.h" - -namespace opt { - - class bvsls_opt_solver : public opt_solver { - ast_manager & m_manager; - params_ref const & m_params; - bvsls_opt_engine m_engine; - - public: - bvsls_opt_solver(ast_manager & m, params_ref const & p); - virtual ~bvsls_opt_solver(); - - virtual void updt_params(params_ref & p); - virtual void collect_param_descrs(param_descrs & r); - virtual void collect_statistics(statistics & st) const; - virtual void assert_expr(expr * t); - virtual void push_core(); - virtual void pop_core(unsigned n); - virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions); - virtual void get_unsat_core(ptr_vector & r); - virtual void get_model(model_ref & m); - virtual proof * get_proof(); - virtual std::string reason_unknown() const; - virtual void get_labels(svector & r); - virtual void set_cancel(bool f); - virtual void set_progress_callback(progress_callback * callback); - virtual unsigned get_num_assertions() const; - virtual expr * get_assertion(unsigned idx) const; - virtual void display(std::ostream & out) const; - }; - -} - -#endif \ No newline at end of file diff --git a/src/opt/core_maxsat.cpp b/src/opt/core_maxsat.cpp index 053f4dc5a..0663f9abc 100644 --- a/src/opt/core_maxsat.cpp +++ b/src/opt/core_maxsat.cpp @@ -19,11 +19,13 @@ Notes: #include "core_maxsat.h" #include "pb_decl_plugin.h" #include "ast_pp.h" +#include "opt_context.h" namespace opt { - core_maxsat::core_maxsat(ast_manager& m, solver& s, expr_ref_vector& soft_constraints): - m(m), s(s), m_lower(0), m_upper(soft_constraints.size()), m_soft(soft_constraints) { + core_maxsat::core_maxsat(context& c, expr_ref_vector& soft_constraints): + m(c.get_manager()), s(c.get_solver()), + m_lower(0), m_upper(soft_constraints.size()), m_soft(soft_constraints) { m_answer.resize(m_soft.size(), false); } diff --git a/src/opt/core_maxsat.h b/src/opt/core_maxsat.h index f5a1a9bb3..bbb173a3f 100644 --- a/src/opt/core_maxsat.h +++ b/src/opt/core_maxsat.h @@ -34,7 +34,7 @@ namespace opt { unsigned m_lower; model_ref m_model; public: - core_maxsat(ast_manager& m, solver& s, expr_ref_vector& soft_constraints); + core_maxsat(context& c, expr_ref_vector& soft_constraints); virtual ~core_maxsat(); virtual lbool operator()(); virtual rational get_lower() const; diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index 75b8f86d0..b410a102e 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -23,9 +23,9 @@ Notes: #include "goal.h" #include "probe.h" #include "tactic.h" -#include "smt_context.h" #include "ast_pp.h" #include "model_smt2_pp.h" +#include "opt_context.h" /** \brief Fu & Malik procedure for MaxSAT. This procedure is based on @@ -44,9 +44,9 @@ Notes: namespace opt { struct fu_malik::imp { - ast_manager& m; - opt_solver & m_opt_solver; - ref m_s; + ast_manager& m; + solver& m_s; + filter_model_converter& m_fm; expr_ref_vector m_soft; expr_ref_vector m_orig_soft; expr_ref_vector m_aux; @@ -55,10 +55,10 @@ namespace opt { unsigned m_lower; model_ref m_model; - imp(ast_manager& m, opt_solver& s, expr_ref_vector const& soft): - m(m), - m_opt_solver(s), - m_s(&s), + imp(context& c, expr_ref_vector const& soft): + m(c.get_manager()), + m_s(c.get_solver()), + m_fm(c.fm()), m_soft(soft), m_orig_soft(soft), m_aux(m), @@ -69,7 +69,7 @@ namespace opt { m_assignment.resize(m_soft.size(), false); } - solver& s() { return *m_s; } + solver& s() { return m_s; } /** \brief One step of the Fu&Malik algorithm. @@ -96,10 +96,8 @@ namespace opt { } } + void collect_statistics(statistics& st) const { - if (m_s != &m_opt_solver) { - m_s->collect_statistics(st); - } st.update("opt-fm-num-steps", m_soft.size() + 2 - m_upper); } @@ -145,8 +143,8 @@ namespace opt { app_ref block_var(m), tmp(m); block_var = m.mk_fresh_const("block_var", m.mk_bool_sort()); m_aux[i] = m.mk_fresh_const("aux", m.mk_bool_sort()); - m_opt_solver.mc().insert(block_var->get_decl()); - m_opt_solver.mc().insert(to_app(m_aux[i].get())->get_decl()); + m_fm.insert(block_var->get_decl()); + m_fm.insert(to_app(m_aux[i].get())->get_decl()); m_soft[i] = m.mk_or(m_soft[i].get(), block_var); block_vars.push_back(block_var); tmp = m.mk_or(m_soft[i].get(), m_aux[i].get()); @@ -181,17 +179,6 @@ namespace opt { } } - void set_solver() { - if (m_opt_solver.dump_benchmarks()) - return; - - solver& current_solver = s(); - goal g(m, true, false); - unsigned num_assertions = current_solver.get_num_assertions(); - for (unsigned i = 0; i < num_assertions; ++i) { - g.assert_expr(current_solver.get_assertion(i)); - } - } // TBD: bug when cancel flag is set, fu_malik returns is_sat == l_true instead of l_undef lbool operator()() { @@ -199,7 +186,6 @@ namespace opt { if (m_soft.empty()) { return is_sat; } - set_solver(); solver::scoped_push _sp(s()); expr_ref tmp(m); @@ -211,7 +197,7 @@ namespace opt { for (unsigned i = 0; i < m_soft.size(); ++i) { m_aux.push_back(m.mk_fresh_const("p", m.mk_bool_sort())); - m_opt_solver.mc().insert(to_app(m_aux.back())->get_decl()); + m_fm.insert(to_app(m_aux.back())->get_decl()); tmp = m.mk_or(m_soft[i].get(), m_aux[i].get()); s().assert_expr(tmp); } @@ -247,8 +233,8 @@ namespace opt { }; - fu_malik::fu_malik(ast_manager& m, opt_solver& s, expr_ref_vector& soft_constraints) { - m_imp = alloc(imp, m, s, soft_constraints); + fu_malik::fu_malik(context& c, expr_ref_vector& soft_constraints) { + m_imp = alloc(imp, c, soft_constraints); } fu_malik::~fu_malik() { dealloc(m_imp); @@ -281,49 +267,3 @@ namespace opt { } }; -#if 0 - void quick_explain(expr_ref_vector const& assumptions, expr_ref_vector & literals, bool has_set, expr_set & core) { - if (has_set && s().check_sat(assumptions.size(), assumptions.c_ptr()) == l_false) { - core.reset(); - return; - } - - SASSERT(!literals.empty()); - if (literals.size() == 1) { - core.reset(); - core.insert(literals[0].get()); - return; - } - - unsigned mid = literals.size()/2; - expr_ref_vector ls1(m), ls2(m); - ls1.append(mid, literals.c_ptr()); - ls2.append(literals.size()-mid, literals.c_ptr() + mid); -#if Z3DEBUG - expr_ref_vector ls(m); - ls.append(ls1); - ls.append(ls2); - SASSERT(ls.size() == literals.size()); - for (unsigned i = 0; i < literals.size(); ++i) { - SASSERT(ls[i].get() == literals[i].get()); - } -#endif - expr_ref_vector as1(m); - as1.append(assumptions); - as1.append(ls1); - expr_set core2; - quick_explain(as1, ls2, !ls1.empty(), core2); - - expr_ref_vector as2(m), cs2(m); - as2.append(assumptions); - set2vector(core2, cs2); - as2.append(cs2); - expr_set core1; - quick_explain(as2, ls1, !core2.empty(), core1); - - set_union(core1, core2, core); - } - -#endif - - diff --git a/src/opt/fu_malik.h b/src/opt/fu_malik.h index e9c994faf..8eb363cb6 100644 --- a/src/opt/fu_malik.h +++ b/src/opt/fu_malik.h @@ -33,7 +33,7 @@ namespace opt { struct imp; imp* m_imp; public: - fu_malik(ast_manager& m, opt_solver& s, expr_ref_vector& soft_constraints); + fu_malik(context& c, expr_ref_vector& soft_constraints); virtual ~fu_malik(); virtual lbool operator()(); virtual rational get_lower() const; diff --git a/src/opt/inc_sat_solver.cpp b/src/opt/inc_sat_solver.cpp index 73638f44c..89f9e79fd 100644 --- a/src/opt/inc_sat_solver.cpp +++ b/src/opt/inc_sat_solver.cpp @@ -40,18 +40,19 @@ class inc_sat_solver : public solver { expr_ref_vector m_fmls; expr_ref_vector m_current_fmls; unsigned_vector m_fmls_lim; - expr_ref_vector m_core; - atom2bool_var m_map; - model_ref m_model; + expr_ref_vector m_core; + atom2bool_var m_map; + model_ref m_model; model_converter_ref m_mc; - tactic_ref m_preprocess; - unsigned m_num_scopes; + tactic_ref m_preprocess; + unsigned m_num_scopes; sat::literal_vector m_asms; goal_ref_buffer m_subgoals; proof_converter_ref m_pc; model_converter_ref m_mc2; expr_dependency_ref m_dep_core; - + expr_ref_vector m_soft; + vector m_weights; typedef obj_map dep2asm_t; public: @@ -59,7 +60,8 @@ public: m(m), m_solver(p,0), m_params(p), m_fmls(m), m_current_fmls(m), m_core(m), m_map(m), m_num_scopes(0), - m_dep_core(m) { + m_dep_core(m), + m_soft(m) { m_params.set_bool("elim_vars", false); m_solver.updt_params(m_params); params_ref simp2_p = p; @@ -78,29 +80,32 @@ public: mk_max_bv_sharing_tactic(m), mk_bit_blaster_tactic(m), mk_aig_tactic(), - using_params(mk_simplify_tactic(m), simp2_p)); - - + using_params(mk_simplify_tactic(m), simp2_p)); } virtual ~inc_sat_solver() {} - virtual void set_progress_callback(progress_callback * callback) { - } + virtual void set_progress_callback(progress_callback * callback) {} + virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions) { m_solver.pop_to_base_level(); dep2asm_t dep2asm; - m_model = 0; lbool r = internalize_formulas(); if (r != l_true) return r; r = internalize_assumptions(num_assumptions, assumptions, dep2asm); if (r != l_true) return r; extract_assumptions(dep2asm, m_asms); + + r = initialize_soft_constraints(); + if (r != l_true) return r; + r = m_solver.check(m_asms.size(), m_asms.c_ptr()); switch (r) { case l_true: - check_assumptions(dep2asm); + if (num_assumptions > 0) { + check_assumptions(dep2asm); + } break; case l_false: // TBD: expr_dependency core is not accounted for. @@ -160,8 +165,7 @@ public: m_params = p; m_params.set_bool("elim_vars", false); m_solver.updt_params(m_params); - } - + } virtual void collect_statistics(statistics & st) const { m_preprocess->collect_statistics(st); m_solver.collect_statistics(st); @@ -186,18 +190,57 @@ public: virtual void get_labels(svector & r) { UNREACHABLE(); } - virtual unsigned get_num_assertions() const { return m_fmls.size(); } - virtual expr * get_assertion(unsigned idx) const { return m_fmls[idx]; } - + void set_soft(unsigned sz, expr*const* soft, rational const* weights) { + m_soft.reset(); + m_weights.reset(); + m_soft.append(sz, soft); + m_weights.append(sz, weights); + } private: + lbool initialize_soft_constraints() { + dep2asm_t dep2asm; + if (m_soft.empty()) { + return l_true; + } + expr_ref_vector soft(m_soft); + for (unsigned i = 0; i < soft.size(); ++i) { + expr* e = soft[i].get(), *e1; + if (is_uninterp_const(e) || (m.is_not(e, e1) && is_uninterp_const(e1))) { + continue; + } + expr_ref asum(m), fml(m); + asum = m.mk_fresh_const("soft", m.mk_bool_sort()); + fml = m.mk_iff(asum, e); + m_fmls.push_back(fml); + soft[i] = asum; + } + m_soft.reset(); + lbool r = internalize_formulas(); + if (r != l_true) return r; + r = internalize_assumptions(soft.size(), soft.c_ptr(), dep2asm); + sat::literal_vector lits; + svector weights; + + if (r == l_true) { + for (unsigned i = 0; i < soft.size(); ++i) { + weights.push_back(m_weights[i].get_double()); + lits.push_back(dep2asm.find(soft[i].get())); + } + m_solver.initialize_soft(lits.size(), lits.c_ptr(), weights.c_ptr()); + m_params.set_bool("optimize_model", true); + m_solver.updt_params(m_params); + } + return r; + } + lbool internalize_goal(goal_ref& g, dep2asm_t& dep2asm) { m_mc2.reset(); m_pc.reset(); @@ -295,10 +338,8 @@ private: dep2asm_t::iterator it = dep2asm.begin(), end = dep2asm.end(); for (; it != end; ++it) { sat::literal lit = it->m_value; - lbool polarity = lit.sign()?l_false:l_true; - lbool value = sat::value_at(lit.var(), ll_m); - if (value != polarity) { - IF_VERBOSE(0, verbose_stream() << mk_pp(it->m_key, m) << " evaluates to " << value << "\n"; + if (sat::value_at(lit, ll_m) != l_true) { + IF_VERBOSE(0, verbose_stream() << mk_pp(it->m_key, m) << " does not evaluate to true\n"; verbose_stream() << m_asms << "\n"; m_solver.display_assignment(verbose_stream()); m_solver.display(verbose_stream());); @@ -343,6 +384,12 @@ private: } }; + solver* mk_inc_sat_solver(ast_manager& m, params_ref& p) { return alloc(inc_sat_solver, m, p); } + +void set_soft_inc_sat(solver* _s, unsigned sz, expr*const* soft, rational const* weights) { + inc_sat_solver* s = dynamic_cast(_s); + s->set_soft(sz, soft, weights); +} diff --git a/src/opt/inc_sat_solver.h b/src/opt/inc_sat_solver.h index 903d27ebc..8bb4c288a 100644 --- a/src/opt/inc_sat_solver.h +++ b/src/opt/inc_sat_solver.h @@ -24,4 +24,6 @@ Notes: solver* mk_inc_sat_solver(ast_manager& m, params_ref& p); +void set_soft_inc_sat(solver* s, unsigned sz, expr*const* soft, rational const* weights); + #endif diff --git a/src/opt/maxhs.cpp b/src/opt/maxhs.cpp index 35ca630d9..76645ee7e 100644 --- a/src/opt/maxhs.cpp +++ b/src/opt/maxhs.cpp @@ -23,6 +23,7 @@ Notes: #include "model_smt2_pp.h" #include "uint_set.h" #include "maxhs.h" +#include "opt_context.h" namespace opt { @@ -74,8 +75,8 @@ namespace opt { public: - maxhs(opt_solver* s, ast_manager& m, params_ref& p, vector const& ws, expr_ref_vector const& soft): - maxsmt_solver_base(s, m, p, ws, soft), + maxhs(context& c, vector const& ws, expr_ref_vector const& soft): + maxsmt_solver_base(c, ws, soft), m_aux(m), m_at_lower_bound(false) { } @@ -528,7 +529,7 @@ namespace opt { app_ref mk_fresh(sort* s) { app_ref r(m); r = m.mk_fresh_const("r", s); - m_mc->insert(r->get_decl()); + m_c.fm().insert(r->get_decl()); return r; } @@ -553,9 +554,9 @@ namespace opt { }; - maxsmt_solver_base* opt::mk_maxhs(ast_manager& m, opt_solver* s, params_ref& p, + maxsmt_solver_base* opt::mk_maxhs(context& c, vector const& ws, expr_ref_vector const& soft) { - return alloc(maxhs, s, m, p, ws, soft); + return alloc(maxhs, c, ws, soft); } } diff --git a/src/opt/maxhs.h b/src/opt/maxhs.h index e08a550bd..6bb7a2696 100644 --- a/src/opt/maxhs.h +++ b/src/opt/maxhs.h @@ -23,7 +23,7 @@ Notes: #include "maxsmt.h" namespace opt { - maxsmt_solver_base* mk_maxhs(ast_manager& m, opt_solver* s, params_ref& p, + maxsmt_solver_base* mk_maxhs(context& c, vector const& ws, expr_ref_vector const& soft); } #endif diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index f879ff99a..a4ccf567f 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -60,6 +60,7 @@ Notes: #include "mus.h" #include "mss.h" #include "inc_sat_solver.h" +#include "opt_context.h" using namespace opt; @@ -83,10 +84,10 @@ private: rational m_max_upper; public: - maxres(ast_manager& m, opt_solver* s, params_ref& p, + maxres(context& c, vector const& ws, expr_ref_vector const& soft, strategy_t st): - maxsmt_solver_base(s, m, p, ws, soft), + maxsmt_solver_base(c, ws, soft), m_B(m), m_asms(m), m_mus(m_s, m), m_mss(m_s, m), @@ -133,10 +134,9 @@ public: } lbool mus_solver() { - solver::scoped_push _sc(*m_s.get()); + solver::scoped_push _sc(m_s); init(); init_local(); - enable_bvsat(); while (true) { TRACE("opt", display_vec(tout, m_asms.size(), m_asms.c_ptr()); @@ -159,7 +159,6 @@ public: }); for (unsigned i = 0; i < m_soft.size(); ++i) { VERIFY(m_model->eval(m_soft[i].get(), tmp)); - std::cout << mk_pp(m_soft[i].get(), m) << " -> " << tmp << "\n"; m_assignment[i] = m.is_true(tmp); } m_upper = m_lower; @@ -179,11 +178,10 @@ public: } lbool mus_mss_solver() { - solver::scoped_push _sc(*m_s.get()); + solver::scoped_push _sc(s()); init(); init_local(); - enable_bvsat(); - enable_sls(); + enable_sls(m_asms); ptr_vector mcs; vector > cores; while (m_lower < m_upper) { @@ -222,11 +220,32 @@ public: return l_true; } - - lbool mss_solver() { NOT_IMPLEMENTED_YET(); - return l_undef; + solver::scoped_push _sc(s()); + init(); + init_local(); + ptr_vector mcs; + while (m_lower < m_upper) { + lbool is_sat = s().check_sat(0, 0); + // is_sat = get_mcs(mcs); + switch (is_sat) { + case l_undef: + return l_undef; + case l_false: + m_lower = m_upper; + break; + case l_true: + // + is_sat = process_sat(mcs); + if (is_sat != l_true) { + return is_sat; + } + break; + } + } + m_lower = m_upper; + return l_true; } lbool operator()() { @@ -322,7 +341,7 @@ public: } lbool minimize_core(ptr_vector& core) { - if (m_sat_enabled) { + if (m_c.sat_enabled()) { return l_true; } m_mus.reset(); @@ -592,9 +611,9 @@ public: void verify_assignment() { IF_VERBOSE(0, verbose_stream() << "verify assignment\n";); - ref sat_solver = mk_inc_sat_solver(m, m_params); - for (unsigned i = 0; i < m_assertions.size(); ++i) { - sat_solver->assert_expr(m_assertions[i].get()); + ref sat_solver = mk_inc_sat_solver(m, m_params); + for (unsigned i = 0; i < s().get_num_assertions(); ++i) { + sat_solver->assert_expr(s().get_assertion(i)); } expr_ref n(m); for (unsigned i = 0; i < m_soft.size(); ++i) { @@ -612,18 +631,18 @@ public: }; -opt::maxsmt_solver_base* opt::mk_maxres(ast_manager& m, opt_solver* s, params_ref& p, +opt::maxsmt_solver_base* opt::mk_maxres(context& c, vector const& ws, expr_ref_vector const& soft) { - return alloc(maxres, m, s, p, ws, soft, maxres::s_mus); + return alloc(maxres, c, ws, soft, maxres::s_mus); } -opt::maxsmt_solver_base* opt::mk_mus_mss_maxres(ast_manager& m, opt_solver* s, params_ref& p, +opt::maxsmt_solver_base* opt::mk_mus_mss_maxres(context& c, vector const& ws, expr_ref_vector const& soft) { - return alloc(maxres, m, s, p, ws, soft, maxres::s_mus_mss); + return alloc(maxres, c, ws, soft, maxres::s_mus_mss); } -opt::maxsmt_solver_base* opt::mk_mss_maxres(ast_manager& m, opt_solver* s, params_ref& p, +opt::maxsmt_solver_base* opt::mk_mss_maxres(context& c, vector const& ws, expr_ref_vector const& soft) { - return alloc(maxres, m, s, p, ws, soft, maxres::s_mss); + return alloc(maxres, c, ws, soft, maxres::s_mss); } diff --git a/src/opt/maxres.h b/src/opt/maxres.h index efa8886f7..5f4ea8db3 100644 --- a/src/opt/maxres.h +++ b/src/opt/maxres.h @@ -23,15 +23,15 @@ Notes: namespace opt { maxsmt_solver_base* mk_maxres( - ast_manager& m, opt_solver* s, params_ref& p, + context& c, vector const& ws, expr_ref_vector const& soft); maxsmt_solver_base* mk_mus_mss_maxres( - ast_manager& m, opt_solver* s, params_ref& p, + context& c, vector const& ws, expr_ref_vector const& soft); maxsmt_solver_base* mk_mss_maxres( - ast_manager& m, opt_solver* s, params_ref& p, + context& c, vector const& ws, expr_ref_vector const& soft); }; diff --git a/src/opt/maxsls.cpp b/src/opt/maxsls.cpp index c64e0f3fc..be8e99c3a 100644 --- a/src/opt/maxsls.cpp +++ b/src/opt/maxsls.cpp @@ -26,16 +26,14 @@ namespace opt { class sls : public maxsmt_solver_base { public: - sls(opt_solver* s, ast_manager& m, params_ref& p, - vector const& ws, expr_ref_vector const& soft): - maxsmt_solver_base(s, m, p, ws, soft) { + sls(context& c, vector const& ws, expr_ref_vector const& soft): + maxsmt_solver_base(c, ws, soft) { } virtual ~sls() {} lbool operator()() { IF_VERBOSE(1, verbose_stream() << "(opt.sls)\n";); - enable_bvsat(); - enable_sls(); init(); + enable_sls(m_soft); lbool is_sat = s().check_sat(0, 0); if (is_sat == l_true) { s().get_model(m_model); @@ -54,9 +52,9 @@ namespace opt { }; - maxsmt_solver_base* opt::mk_sls(ast_manager& m, opt_solver* s, params_ref& p, + maxsmt_solver_base* opt::mk_sls(context& c, vector const& ws, expr_ref_vector const& soft) { - return alloc(sls, s, m, p, ws, soft); + return alloc(sls, c, ws, soft); } diff --git a/src/opt/maxsls.h b/src/opt/maxsls.h index 111d6a3b2..0ba94d6e8 100644 --- a/src/opt/maxsls.h +++ b/src/opt/maxsls.h @@ -27,7 +27,7 @@ Notes: namespace opt { - maxsmt_solver_base* mk_sls(ast_manager& m, opt_solver* s, params_ref& p, + maxsmt_solver_base* mk_sls(context& c, vector const& ws, expr_ref_vector const& soft); diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 572c6e66c..d7cbbc910 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -24,12 +24,10 @@ Notes: #include "maxres.h" #include "maxhs.h" #include "bcd2.h" -#include "wpm2.h" #include "pbmax.h" #include "wmax.h" #include "maxsls.h" #include "ast_pp.h" -#include "opt_params.hpp" #include "pb_decl_plugin.h" #include "pb_sls.h" #include "tactical.h" @@ -38,19 +36,27 @@ Notes: #include "qfbv_tactic.h" #include "card2bv_tactic.h" #include "uint_set.h" -#include "opt_sls_solver.h" #include "pb_preprocess_tactic.h" -#include "inc_sat_solver.h" +#include "opt_context.h" namespace opt { + maxsmt_solver_base::maxsmt_solver_base( + context& c, vector const& ws, expr_ref_vector const& soft): + m_s(c.get_solver()), + m(c.get_manager()), + m_c(c), + m_cancel(false), m_soft(m), + m_assertions(m) { + m_s.get_model(m_model); + SASSERT(m_model); + updt_params(c.params()); + init_soft(ws, soft); + } + void maxsmt_solver_base::updt_params(params_ref& p) { m_params.copy(p); - s().updt_params(p); - opt_params _p(p); - m_enable_sat = _p.enable_sat(); - m_enable_sls = _p.enable_sls(); } void maxsmt_solver_base::init_soft(vector const& weights, expr_ref_vector const& soft) { @@ -90,132 +96,68 @@ namespace opt { } } - struct maxsmt_solver_base::is_bv { - struct found {}; - ast_manager& m; - pb_util pb; - bv_util bv; - is_bv(ast_manager& m): m(m), pb(m), bv(m) {} - void operator()(var *) { throw found(); } - void operator()(quantifier *) { throw found(); } - void operator()(app *n) { - family_id fid = n->get_family_id(); - if (fid != m.get_basic_family_id() && - fid != pb.get_family_id() && - fid != bv.get_family_id() && - !is_uninterp_const(n)) { - throw found(); - } - } - }; - - bool maxsmt_solver_base::probe_bv() { - expr_fast_mark1 visited; - is_bv proc(m); - try { - unsigned sz = s().get_num_assertions(); - for (unsigned i = 0; i < sz; i++) { - quick_for_each_expr(proc, visited, s().get_assertion(i)); - } - sz = m_soft.size(); - for (unsigned i = 0; i < sz; ++i) { - quick_for_each_expr(proc, visited, m_soft[i].get()); - } - } - catch (is_bv::found) { - return false; - } - return true; - } - - void maxsmt_solver_base::enable_inc_bvsat() { - m_params.set_bool("minimize_core", true); - solver* sat_solver = mk_inc_sat_solver(m, m_params); - unsigned sz = s().get_num_assertions(); - for (unsigned i = 0; i < sz; ++i) { - sat_solver->assert_expr(s().get_assertion(i)); - m_assertions.push_back(s().get_assertion(i)); - } - m_s = sat_solver; - } - - void maxsmt_solver_base::enable_bvsat() { - if (m_enable_sat && !m_sat_enabled && probe_bv()) { - enable_inc_bvsat(); - m_sat_enabled = true; - } - } - - void maxsmt_solver_base::enable_sls() { - if (m_enable_sls && !m_sls_enabled && probe_bv()) { - m_params.set_uint("restarts", 20); - unsigned lvl = m_s->get_scope_level(); - sls_solver* sls = alloc(sls_solver, m, m_s.get(), m_soft, m_weights, m_params); - m_s = sls; - while (lvl > 0) { m_s->push(); --lvl; } - m_sls_enabled = true; - sls->opt(m_model); - } - } - void maxsmt_solver_base::set_mus(bool f) { params_ref p; p.set_bool("minimize_core", f); - m_s->updt_params(p); + m_s.updt_params(p); + } + + void maxsmt_solver_base::enable_sls(expr_ref_vector const& soft) { + m_c.enable_sls(soft, m_weights); } app* maxsmt_solver_base::mk_fresh_bool(char const* name) { app* result = m.mk_fresh_const(name, m.mk_bool_sort()); - m_mc->insert(result->get_decl()); + m_c.fm().insert(result->get_decl()); return result; } + maxsmt::maxsmt(context& c): + m_s(c.get_solver()), m(c.get_manager()), m_c(c), m_cancel(false), + m_soft_constraints(m), m_answer(m) {} - lbool maxsmt::operator()(opt_solver* s) { + lbool maxsmt::operator()(solver* s) { lbool is_sat; m_msolver = 0; - m_s = s; + symbol const& maxsat_engine = m_c.maxsat_engine(); IF_VERBOSE(1, verbose_stream() << "(maxsmt)\n";); TRACE("opt", tout << "maxsmt\n";); if (m_soft_constraints.empty()) { TRACE("opt", tout << "no constraints\n";); m_msolver = 0; - is_sat = m_s->check_sat(0, 0); + is_sat = m_s.check_sat(0, 0); } - else if (m_maxsat_engine == symbol("maxres")) { - m_msolver = mk_maxres(m, s, m_params, m_weights, m_soft_constraints); + else if (maxsat_engine == symbol("maxres")) { + m_msolver = mk_maxres(m_c, m_weights, m_soft_constraints); } - else if (m_maxsat_engine == symbol("mus-mss-maxres")) { - m_msolver = mk_mus_mss_maxres(m, s, m_params, m_weights, m_soft_constraints); + else if (maxsat_engine == symbol("mus-mss-maxres")) { + m_msolver = mk_mus_mss_maxres(m_c, m_weights, m_soft_constraints); } - else if (m_maxsat_engine == symbol("pbmax")) { - m_msolver = mk_pbmax(m, s, m_params, m_weights, m_soft_constraints); + else if (maxsat_engine == symbol("pbmax")) { + m_msolver = mk_pbmax(m_c, m_weights, m_soft_constraints); } - else if (m_maxsat_engine == symbol("wpm2")) { - m_msolver = mk_wpm2(m, s, m_params, m_weights, m_soft_constraints); + else if (maxsat_engine == symbol("bcd2")) { + m_msolver = mk_bcd2(m_c, m_weights, m_soft_constraints); } - else if (m_maxsat_engine == symbol("bcd2")) { - m_msolver = mk_bcd2(m, s, m_params, m_weights, m_soft_constraints); + else if (maxsat_engine == symbol("maxhs")) { + m_msolver = mk_maxhs(m_c, m_weights, m_soft_constraints); } - else if (m_maxsat_engine == symbol("maxhs")) { - m_msolver = mk_maxhs(m, s, m_params, m_weights, m_soft_constraints); - } - else if (m_maxsat_engine == symbol("sls")) { + else if (maxsat_engine == symbol("sls")) { // NB: this is experimental one-round version of SLS - m_msolver = mk_sls(m, s, m_params, m_weights, m_soft_constraints); + m_msolver = mk_sls(m_c, m_weights, m_soft_constraints); } - else if (is_maxsat_problem(m_weights) && m_maxsat_engine == symbol("core_maxsat")) { - m_msolver = alloc(core_maxsat, m, *m_s, m_soft_constraints); + else if (is_maxsat_problem(m_weights) && maxsat_engine == symbol("core_maxsat")) { + m_msolver = alloc(core_maxsat, m_c, m_soft_constraints); } - else if (is_maxsat_problem(m_weights) && m_maxsat_engine == symbol("fu_malik")) { - m_msolver = alloc(fu_malik, m, *m_s, m_soft_constraints); + else if (is_maxsat_problem(m_weights) && maxsat_engine == symbol("fu_malik")) { + m_msolver = alloc(fu_malik, m_c, m_soft_constraints); } else { - if (m_maxsat_engine != symbol::null && m_maxsat_engine != symbol("wmax")) { + if (maxsat_engine != symbol::null && maxsat_engine != symbol("wmax")) { warning_msg("solver %s is not recognized, using default 'wmax'", - m_maxsat_engine.str().c_str()); + maxsat_engine.str().c_str()); } - m_msolver = mk_wmax(m, m_s.get(), m_params, m_weights, m_soft_constraints); + m_msolver = mk_wmax(m_c, m_weights, m_soft_constraints); } if (m_msolver) { @@ -242,13 +184,12 @@ namespace opt { } void maxsmt::verify_assignment() { - m_s->push(); + solver::scoped_push _sp(m_s); commit_assignment(); - if (l_true != m_s->check_sat(0,0)) { + if (l_true != m_s.check_sat(0,0)) { IF_VERBOSE(0, verbose_stream() << "could not verify assignment\n";); UNREACHABLE(); } - m_s->pop(1); } bool maxsmt::get_assignment(unsigned idx) const { @@ -292,7 +233,6 @@ namespace opt { } void maxsmt::commit_assignment() { - SASSERT(m_s); for (unsigned i = 0; i < m_soft_constraints.size(); ++i) { expr_ref tmp(m); tmp = m_soft_constraints[i].get(); @@ -300,7 +240,7 @@ namespace opt { tmp = m.mk_not(tmp); } TRACE("opt", tout << "committing: " << tmp << "\n";); - m_s->assert_expr(tmp); + m_s.assert_expr(tmp); } } @@ -337,9 +277,7 @@ namespace opt { } void maxsmt::updt_params(params_ref& p) { - opt_params _p(p); - m_maxsat_engine = _p.maxsat_engine(); - m_params = p; + m_params.append(p); if (m_msolver) { m_msolver->updt_params(p); } diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index a36269447..0110132f2 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -19,11 +19,16 @@ Notes: #ifndef _OPT_MAXSMT_H_ #define _OPT_MAXSMT_H_ -#include "opt_solver.h" -#include "statistics.h" +#include"ast.h" +#include"params.h" +#include"solver.h" +#include"filter_model_converter.h" +#include"statistics.h" namespace opt { + class context; + class maxsmt_solver { public: virtual ~maxsmt_solver() {} @@ -44,8 +49,9 @@ namespace opt { // class maxsmt_solver_base : public maxsmt_solver { protected: - ref m_s; + solver& m_s; ast_manager& m; + context& m_c; volatile bool m_cancel; expr_ref_vector m_soft; expr_ref_vector m_assertions; @@ -53,55 +59,30 @@ namespace opt { rational m_lower; rational m_upper; model_ref m_model; - ref m_mc; // model converter to remove fresh variables svector m_assignment; // truth assignment to soft constraints params_ref m_params; // config - bool m_enable_sls; // config - bool m_enable_sat; // config - bool m_sls_enabled; - bool m_sat_enabled; - struct is_bv; public: - maxsmt_solver_base(opt_solver* s, ast_manager& m, params_ref& p, - vector const& ws, expr_ref_vector const& soft): - m_s(s), m(m), m_cancel(false), m_soft(m), - m_assertions(m), - m_enable_sls(false), m_enable_sat(false), - m_sls_enabled(false), m_sat_enabled(false) { - m_s->get_model(m_model); - SASSERT(m_model); - updt_params(p); - set_converter(s->mc_ref().get()); - init_soft(ws, soft); - } + maxsmt_solver_base(context& c, vector const& ws, expr_ref_vector const& soft); virtual ~maxsmt_solver_base() {} virtual rational get_lower() const { return m_lower; } virtual rational get_upper() const { return m_upper; } virtual bool get_assignment(unsigned index) const { return m_assignment[index]; } - virtual void set_cancel(bool f) { m_cancel = f; m_s->set_cancel(f); } - virtual void collect_statistics(statistics& st) const { - if (m_sls_enabled || m_sat_enabled) { - m_s->collect_statistics(st); - } - } + virtual void set_cancel(bool f) { m_cancel = f; s().set_cancel(f); } + virtual void collect_statistics(statistics& st) const { } virtual void get_model(model_ref& mdl) { mdl = m_model.get(); } void set_model() { s().get_model(m_model); } virtual void updt_params(params_ref& p); virtual void init_soft(vector const& weights, expr_ref_vector const& soft); void add_hard(expr* e){ s().assert_expr(e); } - solver& s() { return *m_s; } - void set_converter(filter_model_converter* mc) { m_mc = mc; } + solver& s() { return m_s; } void init(); expr* mk_not(expr* e); - bool probe_bv(); void set_mus(bool f); - void enable_bvsat(); - void enable_sls(); app* mk_fresh_bool(char const* name); - private: - void enable_inc_bvsat(); + protected: + void enable_sls(expr_ref_vector const& soft); }; /** @@ -110,32 +91,27 @@ namespace opt { */ class maxsmt { - ast_manager& m; - ref m_s; + ast_manager& m; + solver& m_s; + context& m_c; + scoped_ptr m_msolver; volatile bool m_cancel; expr_ref_vector m_soft_constraints; expr_ref_vector m_answer; vector m_weights; rational m_lower; rational m_upper; - scoped_ptr m_msolver; - symbol m_maxsat_engine; model_ref m_model; params_ref m_params; public: - maxsmt(ast_manager& m): m(m), m_s(0), m_cancel(false), m_soft_constraints(m), m_answer(m) {} - - lbool operator()(opt_solver* s); - + maxsmt(context& c); + lbool operator()(solver* s); void set_cancel(bool f); - void updt_params(params_ref& p); - void add(expr* f, rational const& w); unsigned size() const { return m_soft_constraints.size(); } expr* operator[](unsigned idx) const { return m_soft_constraints[idx]; } rational weight(unsigned idx) const { return m_weights[idx]; } - void commit_assignment(); rational get_value() const; rational get_lower() const; @@ -146,13 +122,9 @@ namespace opt { bool get_assignment(unsigned index) const; void display_answer(std::ostream& out) const; void collect_statistics(statistics& st) const; - private: - bool is_maxsat_problem(vector const& ws) const; - void verify_assignment(); - }; }; diff --git a/src/opt/mss.cpp b/src/opt/mss.cpp index d796a2b92..63a7a72bf 100644 --- a/src/opt/mss.cpp +++ b/src/opt/mss.cpp @@ -26,21 +26,21 @@ Notes: namespace opt { - mss::mss(ref& s, ast_manager& m): m_s(s), m(m), m_cancel(false) { + mss::mss(solver& s, ast_manager& m): m_s(s), m(m), m_cancel(false) { } mss::~mss() { } bool mss::check_result() { - lbool is_sat = m_s->check_sat(m_mss.size(), m_mss.c_ptr()); + lbool is_sat = m_s.check_sat(m_mss.size(), m_mss.c_ptr()); if (is_sat == l_undef) return true; SASSERT(is_sat == l_true); if (is_sat == l_false) return false; expr_set::iterator it = m_mcs.begin(), end = m_mcs.end(); for (; it != end; ++it) { m_mss.push_back(*it); - is_sat = m_s->check_sat(m_mss.size(), m_mss.c_ptr()); + is_sat = m_s.check_sat(m_mss.size(), m_mss.c_ptr()); m_mss.pop_back(); if (is_sat == l_undef) return true; SASSERT(is_sat == l_false); @@ -147,7 +147,7 @@ namespace opt { lbool mss::operator()(vector const& _cores, exprs& literals, exprs& mcs) { m_mss.reset(); m_todo.reset(); - m_s->get_model(m_model); + m_s.get_model(m_model); SASSERT(m_model); vector cores(_cores); TRACE("opt", @@ -207,12 +207,12 @@ namespace opt { TRACE("opt", display_vec(tout << "process (total " << core.size() << ") :", sz, core.c_ptr());); unsigned sz_save = m_mss.size(); m_mss.append(sz, core.c_ptr()); - lbool is_sat = m_s->check_sat(m_mss.size(), m_mss.c_ptr()); - IF_VERBOSE(1, display_vec(verbose_stream(), sz, core.c_ptr());); + lbool is_sat = m_s.check_sat(m_mss.size(), m_mss.c_ptr()); + IF_VERBOSE(2, display_vec(verbose_stream() << "mss: ", m_mss.size(), m_mss.c_ptr());); m_mss.resize(sz_save); switch (is_sat) { case l_true: - m_s->get_model(m_model); + m_s.get_model(m_model); update_mss(); DEBUG_CODE( for (unsigned i = 0; i < sz; ++i) { diff --git a/src/opt/mss.h b/src/opt/mss.h index 9f14f66c3..cf69c14f9 100644 --- a/src/opt/mss.h +++ b/src/opt/mss.h @@ -21,7 +21,7 @@ Notes: namespace opt { class mss { - ref& m_s; + solver& m_s; ast_manager& m; volatile bool m_cancel; typedef ptr_vector exprs; @@ -32,7 +32,7 @@ namespace opt { exprs m_todo; model_ref m_model; public: - mss(ref& s, ast_manager& m); + mss(solver& s, ast_manager& m); ~mss(); lbool operator()(vector const& cores, exprs& literals, exprs& mcs); diff --git a/src/opt/mus.cpp b/src/opt/mus.cpp index a8126e699..545aba2cc 100644 --- a/src/opt/mus.cpp +++ b/src/opt/mus.cpp @@ -29,13 +29,13 @@ using namespace opt; // struct mus::imp { - ref& m_s; - ast_manager& m; - expr_ref_vector m_cls2expr; - obj_map m_expr2cls; - volatile bool m_cancel; + solver& m_s; + ast_manager& m; + expr_ref_vector m_cls2expr; + obj_map m_expr2cls; + volatile bool m_cancel; - imp(ref& s, ast_manager& m): + imp(solver& s, ast_manager& m): m_s(s), m(m), m_cls2expr(m), m_cancel(false) {} @@ -92,7 +92,7 @@ struct mus::imp { unsigned sz = assumptions.size(); assumptions.push_back(not_cls); add_core(core, assumptions); - lbool is_sat = m_s->check_sat(assumptions.size(), assumptions.c_ptr()); + lbool is_sat = m_s.check_sat(assumptions.size(), assumptions.c_ptr()); assumptions.resize(sz); switch (is_sat) { case l_undef: @@ -103,7 +103,7 @@ struct mus::imp { break; default: core_exprs.reset(); - m_s->get_unsat_core(core_exprs); + m_s.get_unsat_core(core_exprs); if (!core_exprs.contains(not_cls)) { // core := core_exprs \ mus core.reset(); @@ -124,7 +124,7 @@ struct mus::imp { for (unsigned i = 0; i < mus.size(); ++i) { assumptions.push_back(m_cls2expr[mus[i]].get()); } - lbool is_sat = m_s->check_sat(assumptions.size(), assumptions.c_ptr()); + lbool is_sat = m_s.check_sat(assumptions.size(), assumptions.c_ptr()); SASSERT(is_sat == l_false); ); #endif @@ -147,7 +147,7 @@ struct mus::imp { }; -mus::mus(ref& s, ast_manager& m) { +mus::mus(solver& s, ast_manager& m) { m_imp = alloc(imp, s, m); } diff --git a/src/opt/mus.h b/src/opt/mus.h index 3a96b4842..94eb42cc6 100644 --- a/src/opt/mus.h +++ b/src/opt/mus.h @@ -24,7 +24,7 @@ namespace opt { struct imp; imp * m_imp; public: - mus(ref& s, ast_manager& m); + mus(solver& s, ast_manager& m); ~mus(); /** Add soft constraint. diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 58c5c2017..d2de3ae80 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -34,8 +34,10 @@ Notes: #include "tactical.h" #include "model_smt2_pp.h" #include "card2bv_tactic.h" -#include "bvsls_opt_solver.h" #include "nnf_tactic.h" +#include "inc_sat_solver.h" +#include "bv_decl_plugin.h" +#include "pb_decl_plugin.h" namespace opt { @@ -114,13 +116,18 @@ namespace opt { m_arith(m), m_bv(m), m_hard_constraints(m), + m_solver(0), m_optsmt(m), m_scoped_state(m), - m_objective_refs(m) + m_fm(m), + m_objective_refs(m), + m_enable_sat(false), + m_enable_sls(false) { - m_params.set_bool("model", true); - m_params.set_bool("unsat_core", true); - m_solver = alloc(opt_solver, m, m_params, symbol()); + params_ref p; + p.set_bool("model", true); + p.set_bool("unsat_core", true); + updt_params(p); } context::~context() { @@ -172,9 +179,7 @@ namespace opt { objective& obj = s.m_objectives[i]; m_objectives.push_back(obj); if (obj.m_type == O_MAXSMT) { - maxsmt* ms = alloc(maxsmt, m); - ms->updt_params(m_params); - m_maxsmts.insert(obj.m_id, ms); + add_maxsmt(obj.m_id); } } m_hard_constraints.append(s.m_hard); @@ -184,18 +189,19 @@ namespace opt { if (m_pareto) { return execute_pareto(); } - import_scoped_state(); + init_solver(); + import_scoped_state(); normalize(); internalize(); - opt_solver& s = get_solver(); - solver::scoped_push _sp(s); + update_solver(); + solver& s = get_solver(); for (unsigned i = 0; i < m_hard_constraints.size(); ++i) { TRACE("opt", tout << "Hard constraint: " << mk_ismt2_pp(m_hard_constraints[i].get(), m) << std::endl;); s.assert_expr(m_hard_constraints[i].get()); } IF_VERBOSE(1, verbose_stream() << "(optimize:check-sat)\n";); - lbool is_sat = s.check_sat_core(0,0); + lbool is_sat = s.check_sat(0,0); TRACE("opt", tout << "initial search result: " << is_sat << "\n";); if (is_sat != l_true) { m_model = 0; @@ -203,7 +209,7 @@ namespace opt { } IF_VERBOSE(1, verbose_stream() << "(optimize:sat)\n";); s.get_model(m_model); - m_optsmt.setup(s); + m_optsmt.setup(*m_opt_solver.get()); update_lower(true); switch (m_objectives.size()) { case 0: @@ -214,7 +220,6 @@ namespace opt { opt_params optp(m_params); symbol pri = optp.priority(); if (pri == symbol("pareto")) { - _sp.disable_pop(); return execute_pareto(); } else if (pri == symbol("box")) { @@ -233,7 +238,7 @@ namespace opt { if (m_model_converter) { (*m_model_converter)(mdl, 0); } - get_solver().mc()(mdl, 0); + m_fm(mdl, 0); } } @@ -243,7 +248,7 @@ namespace opt { if (result == l_true) m_optsmt.get_model(m_model); return result; } - + lbool context::execute_maxsat(symbol const& id, bool committed) { model_ref tmp; maxsmt& ms = *m_maxsmts.find(id); @@ -265,7 +270,10 @@ namespace opt { lbool context::execute_lex() { lbool r = l_true; for (unsigned i = 0; r == l_true && i < m_objectives.size(); ++i) { + bool is_last = i + 1 == m_objectives.size(); + if (!is_last) get_solver().push(); r = execute(m_objectives[i], i + 1 < m_objectives.size()); + if (!is_last) get_solver().pop(1); if (r == l_true && !get_lower_as_num(i).is_finite()) { return r; } @@ -282,9 +290,8 @@ namespace opt { for (unsigned i = 0; r == l_true && i < m_objectives.size(); ++i) { objective const& obj = m_objectives[i]; if (obj.m_type == O_MAXSMT) { - get_solver().push(); + solver::scoped_push _sp(get_solver()); r = execute(obj, false); - get_solver().pop(1); } } return r; @@ -381,12 +388,13 @@ namespace opt { } lbool context::execute_pareto() { + if (!m_pareto) { - m_pareto = alloc(gia_pareto, m, *this, m_solver.get(), m_params); + set_pareto(alloc(gia_pareto, m, *this, m_solver.get(), m_params)); } lbool is_sat = (*(m_pareto.get()))(); if (is_sat != l_true) { - m_pareto = 0; + set_pareto(0); } if (is_sat == l_true) { yield(); @@ -395,7 +403,6 @@ namespace opt { m_solver->pop(1); } return is_sat; - // NB. fix race condition for set_cancel } void context::display_bounds(std::ostream& out, bounds_t const& b) const { @@ -411,10 +418,98 @@ namespace opt { } } - opt_solver& context::get_solver() { + solver& context::get_solver() { return *m_solver.get(); } + void context::init_solver() { + #pragma omp critical (opt_context) + { + m_opt_solver = alloc(opt_solver, m, m_params, m_fm, symbol()); + m_solver = m_opt_solver.get(); + } + } + + void context::update_solver() { + if (!m_enable_sat || !probe_bv()) { + return; + } + if (m_maxsat_engine != symbol("maxres") && + m_maxsat_engine != symbol("mus-mss-maxres") && + m_maxsat_engine != symbol("bcd2") && + m_maxsat_engine != symbol("sls")) { + return; + } + m_params.set_bool("minimize_core", true); + m_sat_solver = mk_inc_sat_solver(m, m_params); + unsigned sz = get_solver().get_num_assertions(); + for (unsigned i = 0; i < sz; ++i) { + m_sat_solver->assert_expr(get_solver().get_assertion(i)); + } + #pragma omp critical (opt_context) + { + m_solver = m_sat_solver.get(); + } + } + + void context::enable_sls(expr_ref_vector const& soft, vector const& weights) { + SASSERT(soft.size() == weights.size()); + if (m_enable_sls && m_sat_solver.get()) { + set_soft_inc_sat(m_sat_solver.get(), soft.size(), soft.c_ptr(), weights.c_ptr()); + } + } + + struct context::is_bv { + struct found {}; + ast_manager& m; + pb_util pb; + bv_util bv; + is_bv(ast_manager& m): m(m), pb(m), bv(m) {} + void operator()(var *) { throw found(); } + void operator()(quantifier *) { throw found(); } + void operator()(app *n) { + family_id fid = n->get_family_id(); + if (fid != m.get_basic_family_id() && + fid != pb.get_family_id() && + fid != bv.get_family_id() && + !is_uninterp_const(n)) { + throw found(); + } + } + }; + + bool context::probe_bv() { + expr_fast_mark1 visited; + is_bv proc(m); + try { + for (unsigned i = 0; i < m_objectives.size(); ++i) { + objective & obj = m_objectives[i]; + if (obj.m_type != O_MAXSMT) return false; + maxsmt& ms = *m_maxsmts.find(obj.m_id); + for (unsigned j = 0; j < ms.size(); ++j) { + quick_for_each_expr(proc, visited, ms[j]); + } + } + unsigned sz = get_solver().get_num_assertions(); + for (unsigned i = 0; i < sz; i++) { + quick_for_each_expr(proc, visited, get_solver().get_assertion(i)); + } + } + catch (is_bv::found) { + return false; + } + return true; + } + + void context::add_maxsmt(symbol const& id) { + maxsmt* ms = alloc(maxsmt, *this); + ms->updt_params(m_params); + #pragma omp critical (opt_context) + { + m_maxsmts.insert(id, ms); + } + } + bool context::is_numeral(expr* e, rational & n) const { unsigned sz; return m_arith.is_numeral(e, n) || m_bv.is_numeral(e, n, sz); @@ -440,28 +535,16 @@ namespace opt { mk_simplify_tactic(m)); opt_params optp(m_params); tactic_ref tac2, tac3; - if (optp.engine() == "bvsls") { + if (optp.elim_01()) { tac2 = mk_elim01_tactic(m); tac3 = mk_lia2card_tactic(m); params_ref lia_p; lia_p.set_bool("compile_equality", optp.pb_compile_equality()); tac3->updt_params(lia_p); - m_simplify = and_then(tac0.get(), tac2.get(), tac3.get(), - mk_card2bv_tactic(m), - mk_simplify_tactic(m), - mk_nnf_tactic(m)); - m_solver = alloc(bvsls_opt_solver, m, m_params); - } - else if (optp.elim_01()) { - tac2 = mk_elim01_tactic(m); - tac3 = mk_lia2card_tactic(m); - params_ref lia_p; - lia_p.set_bool("compile_equality", optp.pb_compile_equality()); - tac3->updt_params(lia_p); - m_simplify = and_then(tac0.get(), tac2.get(), tac3.get()); + set_simplify(and_then(tac0.get(), tac2.get(), tac3.get())); } else { - m_simplify = tac0.get(); + set_simplify(tac0.get()); } proof_converter_ref pc; expr_dependency_ref core(m); @@ -657,9 +740,7 @@ namespace opt { obj.m_type = O_MAXSMT; obj.m_weights.append(weights); SASSERT(!m_maxsmts.contains(id)); - maxsmt* ms = alloc(maxsmt, m); - ms->updt_params(m_params); - m_maxsmts.insert(id, ms); + add_maxsmt(id); } SASSERT(obj.m_id == id); obj.m_terms.reset(); @@ -899,22 +980,39 @@ namespace opt { default: return expr_ref(m_arith.mk_add(args.size(), args.c_ptr()), m); } } - + + void context::set_simplify(tactic* tac) { + #pragma omp critical (opt_context) + { + m_simplify = tac; + } + } + + void context::set_pareto(pareto_base* p) { + #pragma omp critical (opt_context) + { + m_pareto = p; + } + } + void context::set_cancel(bool f) { - if (m_solver) { - m_solver->set_cancel(f); - } - if (m_simplify) { - m_simplify->set_cancel(f); - } - if (m_pareto) { - m_pareto->set_cancel(f); + #pragma omp critical (opt_context) + { + if (m_solver) { + m_solver->set_cancel(f); + } + if (m_pareto) { + m_pareto->set_cancel(f); + } + if (m_simplify) { + m_simplify->set_cancel(f); + } + map_t::iterator it = m_maxsmts.begin(), end = m_maxsmts.end(); + for (; it != end; ++it) { + it->m_value->set_cancel(f); + } } m_optsmt.set_cancel(f); - map_t::iterator it = m_maxsmts.begin(), end = m_maxsmts.end(); - for (; it != end; ++it) { - it->m_value->set_cancel(f); - } } void context::collect_statistics(statistics& stats) const { @@ -944,6 +1042,10 @@ namespace opt { for (; it != end; ++it) { it->m_value->updt_params(m_params); } + opt_params _p(p); + m_enable_sat = _p.enable_sat(); + m_enable_sls = _p.enable_sls(); + m_maxsat_engine = _p.maxsat_engine(); } typedef obj_hashtable func_decl_set; diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 1f7eb55af..33af6c912 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -108,7 +108,9 @@ namespace opt { arith_util m_arith; bv_util m_bv; expr_ref_vector m_hard_constraints; - ref m_solver; + ref m_opt_solver; + ref m_solver; + ref m_sat_solver; scoped_ptr m_pareto; params_ref m_params; optsmt m_optsmt; @@ -116,11 +118,15 @@ namespace opt { scoped_state m_scoped_state; vector m_objectives; model_ref m_model; - model_converter_ref m_model_converter; + model_converter_ref m_model_converter; + filter_model_converter m_fm; obj_map m_objective_fns; obj_map m_objective_orig; func_decl_ref_vector m_objective_refs; tactic_ref m_simplify; + bool m_enable_sat; + bool m_enable_sls; + symbol m_maxsat_engine; public: context(ast_manager& m); virtual ~context(); @@ -163,6 +169,15 @@ namespace opt { virtual expr_ref mk_ge(unsigned i, model_ref& model); virtual expr_ref mk_le(unsigned i, model_ref& model); + smt::context& smt_context() { return m_opt_solver->get_context(); } + filter_model_converter& fm() { return m_fm; } + bool sat_enabled() const { return 0 != m_sat_solver.get(); } + solver& get_solver(); + ast_manager& get_manager() { return this->m; } + params_ref& params() { return m_params; } + void enable_sls(expr_ref_vector const& soft, vector const& weights); + symbol const& maxsat_engine() const { return m_maxsat_engine; } + private: void validate_feasibility(maxsmt& ms); @@ -199,7 +214,14 @@ namespace opt { inf_eps get_upper_as_num(unsigned idx); - opt_solver& get_solver(); + struct is_bv; + bool probe_bv(); + + void init_solver(); + void update_solver(); + void add_maxsmt(symbol const& id); + void set_simplify(tactic *simplify); + void set_pareto(pareto_base* p); bool is_numeral(expr* e, rational& n) const; diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 21667e5f8..186a63105 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -35,13 +35,14 @@ Notes: namespace opt { - opt_solver::opt_solver(ast_manager & mgr, params_ref const & p, symbol const & l): + opt_solver::opt_solver(ast_manager & mgr, params_ref const & p, + filter_model_converter& fm, symbol const & l): solver_na2as(mgr), m_params(p), m_context(mgr, m_params), m(mgr), m_dump_benchmarks(false), - m_fm(alloc(filter_model_converter, m)) { + m_fm(fm) { m_logic = l; if (m_logic != symbol::null) { m_context.set_logic(m_logic); @@ -233,20 +234,20 @@ namespace opt { if (typeid(smt::theory_inf_arith) == typeid(opt)) { smt::theory_inf_arith& th = dynamic_cast(opt); - return expr_ref(th.mk_ge(mc(), v, val), m); + return expr_ref(th.mk_ge(m_fm, v, val), m); } if (typeid(smt::theory_mi_arith) == typeid(opt)) { smt::theory_mi_arith& th = dynamic_cast(opt); SASSERT(val.is_finite()); - return expr_ref(th.mk_ge(mc(), v, val.get_numeral()), m); + return expr_ref(th.mk_ge(m_fm, v, val.get_numeral()), m); } if (typeid(smt::theory_i_arith) == typeid(opt)) { SASSERT(val.is_finite()); SASSERT(val.get_infinitesimal().is_zero()); smt::theory_i_arith& th = dynamic_cast(opt); - return expr_ref(th.mk_ge(mc(), v, val.get_rational()), m); + return expr_ref(th.mk_ge(m_fm, v, val.get_rational()), m); } // difference logic? diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 5ac794ab4..128e12798 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -42,6 +42,7 @@ namespace opt { smt_params m_params; smt::kernel m_context; ast_manager& m; + filter_model_converter& m_fm; progress_callback * m_callback; symbol m_logic; bool m_objective_enabled; @@ -50,9 +51,8 @@ namespace opt { bool m_dump_benchmarks; static unsigned m_dump_count; statistics m_stats; - ref m_fm; public: - opt_solver(ast_manager & m, params_ref const & p, symbol const & l); + opt_solver(ast_manager & m, params_ref const & p, filter_model_converter& fm, symbol const & l); virtual ~opt_solver(); virtual void updt_params(params_ref & p); @@ -82,9 +82,6 @@ namespace opt { inf_eps const & get_objective_value(unsigned obj_index); expr_ref mk_ge(unsigned obj_index, inf_eps const& val); - filter_model_converter& mc() { return *(m_fm.get()); } - ref& mc_ref() { return m_fm; } - static opt_solver& to_opt(solver& s); bool dump_benchmarks(); diff --git a/src/opt/pbmax.cpp b/src/opt/pbmax.cpp index fe1d7b70d..a2191686e 100644 --- a/src/opt/pbmax.cpp +++ b/src/opt/pbmax.cpp @@ -31,16 +31,14 @@ namespace opt { class pbmax : public maxsmt_solver_base { public: - pbmax(opt_solver* s, ast_manager& m, params_ref& p, + pbmax(context& c, vector const& ws, expr_ref_vector const& soft): - maxsmt_solver_base(s, m, p, ws, soft) { + maxsmt_solver_base(c, ws, soft) { } virtual ~pbmax() {} lbool operator()() { - enable_bvsat(); - enable_sls(); TRACE("opt", s().display(tout); tout << "\n"; for (unsigned i = 0; i < m_soft.size(); ++i) { @@ -90,9 +88,9 @@ namespace opt { } }; - maxsmt_solver_base* opt::mk_pbmax(ast_manager& m, opt_solver* s, params_ref& p, + maxsmt_solver_base* opt::mk_pbmax(context & c, vector const& ws, expr_ref_vector const& soft) { - return alloc(pbmax, s, m, p, ws, soft); + return alloc(pbmax, c, ws, soft); } } diff --git a/src/opt/pbmax.h b/src/opt/pbmax.h index 8dcb43715..50a989abd 100644 --- a/src/opt/pbmax.h +++ b/src/opt/pbmax.h @@ -23,7 +23,7 @@ Notes: #include "maxsmt.h" namespace opt { - maxsmt_solver_base* mk_pbmax(ast_manager& m, opt_solver* s, params_ref& p, + maxsmt_solver_base* mk_pbmax(context& c, vector const& ws, expr_ref_vector const& soft); } diff --git a/src/opt/wmax.cpp b/src/opt/wmax.cpp index 8c76b06ba..84a1a4e52 100644 --- a/src/opt/wmax.cpp +++ b/src/opt/wmax.cpp @@ -23,15 +23,15 @@ Notes: #include "smt_theory.h" #include "smt_context.h" #include "theory_wmaxsat.h" - +#include "opt_context.h" namespace opt { class maxsmt_solver_wbase : public maxsmt_solver_base { smt::context& ctx; public: - maxsmt_solver_wbase(opt_solver* s, ast_manager& m, smt::context& ctx, params_ref& p, + maxsmt_solver_wbase(context& c, vector const& ws, expr_ref_vector const& soft): - maxsmt_solver_base(s, m, p, ws, soft), ctx(ctx) {} + maxsmt_solver_base(c, ws, soft), ctx(c.smt_context()) {} ~maxsmt_solver_wbase() {} class scoped_ensure_theory { @@ -52,7 +52,7 @@ namespace opt { wth->reset(); } else { - wth = alloc(smt::theory_wmaxsat, m, m_mc); + wth = alloc(smt::theory_wmaxsat, m, m_c.fm()); ctx.register_plugin(wth); } return wth; @@ -76,9 +76,9 @@ namespace opt { class wmax : public maxsmt_solver_wbase { public: - wmax(opt_solver* s, ast_manager& m, smt::context& ctx, params_ref& p, + wmax(context& c, vector const& ws, expr_ref_vector const& soft): - maxsmt_solver_wbase(s, m, ctx, p, ws, soft) {} + maxsmt_solver_wbase(c, ws, soft) {} virtual ~wmax() {} lbool operator()() { @@ -122,9 +122,9 @@ namespace opt { } }; - maxsmt_solver_base* opt::mk_wmax(ast_manager& m, opt_solver* s, params_ref& p, - vector const& ws, expr_ref_vector const& soft) { - return alloc(wmax, s, m, s->get_context(), p, ws, soft); + maxsmt_solver_base* opt::mk_wmax(context& c, + vector const& ws, expr_ref_vector const& soft) { + return alloc(wmax, c, ws, soft); } } diff --git a/src/opt/wmax.h b/src/opt/wmax.h index bc33eee4a..77be62f92 100644 --- a/src/opt/wmax.h +++ b/src/opt/wmax.h @@ -23,7 +23,7 @@ Notes: #include "maxsmt.h" namespace opt { - maxsmt_solver_base* mk_wmax(ast_manager& m, opt_solver* s, params_ref& p, + maxsmt_solver_base* mk_wmax(context& c, vector const& ws, expr_ref_vector const& soft); } diff --git a/src/opt/wpm2.cpp b/src/opt/wpm2.cpp deleted file mode 100644 index 63418861a..000000000 --- a/src/opt/wpm2.cpp +++ /dev/null @@ -1,251 +0,0 @@ -/*++ -Copyright (c) 2014 Microsoft Corporation - -Module Name: - - wpm2.cpp - -Abstract: - - wpn2 based MaxSAT. - -Author: - - Nikolaj Bjorner (nbjorner) 2014-4-17 - -Notes: - ---*/ -#include "wpm2.h" -#include "pbmax.h" -#include "pb_decl_plugin.h" -#include "uint_set.h" -#include "ast_pp.h" -#include "model_smt2_pp.h" - - -namespace opt { - - // ------------------------------------------------------ - // AAAI 2010 - class wpm2 : public maxsmt_solver_base { - scoped_ptr maxs; - public: - wpm2(opt_solver* s, ast_manager& m, maxsmt_solver_base* _maxs, params_ref& p, - vector const& ws, expr_ref_vector const& soft): - maxsmt_solver_base(s, m, p, ws, soft), maxs(_maxs) { - } - - virtual ~wpm2() {} - - lbool operator()() { - enable_sls(); - IF_VERBOSE(1, verbose_stream() << "(opt.wpm2)\n";); - solver::scoped_push _s(s()); - pb_util u(m); - app_ref fml(m), a(m), b(m), c(m); - expr_ref val(m); - expr_ref_vector block(m), ans(m), al(m), am(m); - obj_map ans_index; - vector amk; - vector sc; - init(); - for (unsigned i = 0; i < m_soft.size(); ++i) { - rational w = m_weights[i]; - - b = mk_fresh_bool("b"); - block.push_back(b); - expr* bb = b; - - a = mk_fresh_bool("a"); - ans.push_back(a); - ans_index.insert(a, i); - fml = m.mk_or(m_soft[i].get(), b, m.mk_not(a)); - s().assert_expr(fml); - - c = mk_fresh_bool("c"); - fml = m.mk_implies(c, u.mk_le(1,&w,&bb,rational(0))); - s().assert_expr(fml); - - sc.push_back(uint_set()); - sc.back().insert(i); - am.push_back(c); - amk.push_back(rational(0)); - } - - while (true) { - expr_ref_vector asms(m); - ptr_vector core; - asms.append(ans); - asms.append(am); - lbool is_sat = s().check_sat(asms.size(), asms.c_ptr()); - TRACE("opt", - tout << "\nassumptions: "; - for (unsigned i = 0; i < asms.size(); ++i) { - tout << mk_pp(asms[i].get(), m) << " "; - } - tout << "\n" << is_sat << "\n"; - tout << "upper: " << m_upper << "\n"; - tout << "lower: " << m_lower << "\n"; - if (is_sat == l_true) { - model_ref mdl; - s().get_model(mdl); - model_smt2_pp(tout, m, *(mdl.get()), 0); - }); - - if (m_cancel && is_sat != l_false) { - is_sat = l_undef; - } - if (is_sat == l_true) { - m_upper = m_lower; - s().get_model(m_model); - for (unsigned i = 0; i < block.size(); ++i) { - VERIFY(m_model->eval(m_soft[i].get(), val)); - TRACE("opt", tout << mk_pp(block[i].get(), m) << " " << val << "\n";); - m_assignment[i] = m.is_true(val); - } - } - if (is_sat != l_false) { - return is_sat; - } - s().get_unsat_core(core); - if (core.empty()) { - return l_false; - } - TRACE("opt", - tout << "core: "; - for (unsigned i = 0; i < core.size(); ++i) { - tout << mk_pp(core[i],m) << " "; - } - tout << "\n";); - uint_set A; - for (unsigned i = 0; i < core.size(); ++i) { - unsigned j; - if (ans_index.find(core[i], j)) { - A.insert(j); - } - } - if (A.empty()) { - return l_false; - } - uint_set B; - rational k(0); - rational old_lower(m_lower); - for (unsigned i = 0; i < sc.size(); ++i) { - uint_set t(sc[i]); - t &= A; - if (!t.empty()) { - B |= sc[i]; - k += amk[i]; - m_lower -= amk[i]; - sc[i] = sc.back(); - sc.pop_back(); - am[i] = am.back(); - am.pop_back(); - amk[i] = amk.back(); - amk.pop_back(); - --i; - } - } - vector ws; - expr_ref_vector bs(m); - for (unsigned i = 0; i < m_soft.size(); ++i) { - if (B.contains(i)) { - ws.push_back(m_weights[i]); - bs.push_back(block[i].get()); - } - } - TRACE("opt", tout << "at most bound: " << k << "\n";); - is_sat = new_bound(al, ws, bs, k); - if (is_sat != l_true) { - return is_sat; - } - m_lower += k; - SASSERT(m_lower > old_lower); - TRACE("opt", tout << "new bound: " << m_lower << "\n";); - expr_ref B_le_k(m), B_ge_k(m); - B_le_k = u.mk_le(ws.size(), ws.c_ptr(), bs.c_ptr(), k); - B_ge_k = u.mk_ge(ws.size(), ws.c_ptr(), bs.c_ptr(), k); - s().assert_expr(B_ge_k); - al.push_back(B_ge_k); - IF_VERBOSE(1, verbose_stream() << "(opt.wpm2 [" << m_lower << ":" << m_upper << "])\n";); - IF_VERBOSE(2, verbose_stream() << "New lower bound: " << B_ge_k << "\n";); - - c = mk_fresh_bool("c"); - fml = m.mk_implies(c, B_le_k); - s().assert_expr(fml); - sc.push_back(B); - am.push_back(c); - amk.push_back(k); - } - } - - virtual void set_cancel(bool f) { - maxsmt_solver_base::set_cancel(f); - maxs->set_cancel(f); - } - - virtual void collect_statistics(statistics& st) const { - maxsmt_solver_base::collect_statistics(st); - maxs->collect_statistics(st); - } - - private: - lbool new_bound(expr_ref_vector const& al, - vector const& ws, - expr_ref_vector const& bs, - rational& k) { - pb_util u(m); - expr_ref_vector al2(m); - al2.append(al); - // w_j*b_j > k - al2.push_back(m.mk_not(u.mk_le(ws.size(), ws.c_ptr(), bs.c_ptr(), k))); - return bound(al2, ws, bs, k); - } - - // - // minimal k, such that al & w_j*b_j >= k is sat - // minimal k, such that al & 3*x + 4*y >= k is sat - // minimal k, such that al & (or (not x) w3) & (or (not y) w4) - // - lbool bound(expr_ref_vector const& al, - vector const& ws, - expr_ref_vector const& bs, - rational& k) { - expr_ref_vector nbs(m); - opt_solver::scoped_push _sc(maxs->s()); - for (unsigned i = 0; i < al.size(); ++i) { - maxs->add_hard(al[i]); - } - for (unsigned i = 0; i < bs.size(); ++i) { - nbs.push_back(mk_not(bs[i])); - } - TRACE("opt", - maxs->s().display(tout); - tout << "\n"; - for (unsigned i = 0; i < bs.size(); ++i) { - tout << mk_pp(bs[i], m) << " " << ws[i] << "\n"; - }); - maxs->init_soft(ws, nbs); - lbool is_sat = maxs->s().check_sat(0,0); - if (is_sat == l_true) { - maxs->set_model(); - is_sat = (*maxs)(); - } - SASSERT(maxs->get_lower() > k); - k = maxs->get_lower(); - return is_sat; - } - }; - - maxsmt_solver_base* opt::mk_wpm2(ast_manager& m, opt_solver* s, params_ref& p, - vector const& ws, expr_ref_vector const& soft) { - - ref s0 = alloc(opt_solver, m, p, symbol()); - // initialize model. - s0->check_sat(0,0); - maxsmt_solver_base* s2 = mk_pbmax(m, s0.get(), p, ws, soft); - return alloc(wpm2, s, m, s2, p, ws, soft); - } - -} diff --git a/src/opt/wpm2.h b/src/opt/wpm2.h deleted file mode 100644 index efaddc602..000000000 --- a/src/opt/wpm2.h +++ /dev/null @@ -1,29 +0,0 @@ -/*++ -Copyright (c) 2014 Microsoft Corporation - -Module Name: - - wpm2.h - -Abstract: - - Wpm2 based MaxSAT. - -Author: - - Nikolaj Bjorner (nbjorner) 2014-4-17 - -Notes: - ---*/ - -#ifndef _WPM2_H_ -#define _WPM2_H_ - -#include "maxsmt.h" - -namespace opt { - maxsmt_solver_base* mk_wpm2(ast_manager& m, opt_solver* s, params_ref& p, - vector const& ws, expr_ref_vector const& soft); -} -#endif diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 94ac37de5..f142100ad 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -105,6 +105,7 @@ namespace sat { } m_minimize_lemmas = p.minimize_lemmas(); m_minimize_core = p.minimize_core(); + m_optimize_model = p.optimize_model(); m_dyn_sub_res = p.dyn_sub_res(); } diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 47804793d..df11629ab 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -69,6 +69,7 @@ namespace sat { bool m_minimize_lemmas; bool m_dyn_sub_res; bool m_minimize_core; + bool m_optimize_model; symbol m_always_true; diff --git a/src/sat/sat_mus.cpp b/src/sat/sat_mus.cpp index db1e90b39..11d0fc15d 100644 --- a/src/sat/sat_mus.cpp +++ b/src/sat/sat_mus.cpp @@ -41,6 +41,7 @@ namespace sat { lbool mus::operator()() { flet _disable_min(s.m_config.m_minimize_core, false); + flet _disable_opt(s.m_config.m_optimize_model, false); TRACE("sat", tout << "old core: " << s.get_core() << "\n";); IF_VERBOSE(2, verbose_stream() << "(sat.mus " << s.get_core() << ")\n";); reset(); diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index fd35e5d64..fb4a7fe6d 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -19,4 +19,5 @@ def_module_params('sat', ('minimize_lemmas', BOOL, True, 'minimize learned clauses'), ('dyn_sub_res', BOOL, True, 'dynamic subsumption resolution for minimizing learned clauses'), ('minimize_core', BOOL, False, 'minimize computed core'), + ('optimize_model', BOOL, False, 'enable optimization of soft constraints'), ('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'))) diff --git a/src/sat/sat_sls.cpp b/src/sat/sat_sls.cpp index 78d9b66e5..fdb9bd5e2 100644 --- a/src/sat/sat_sls.cpp +++ b/src/sat/sat_sls.cpp @@ -50,8 +50,8 @@ namespace sat { return m_elems[rnd(num_elems())]; } - sls::sls(solver& s): s(s) { - m_max_tries = 10000; + sls::sls(solver& s): s(s), m_cancel(false) { + m_max_tries = 1000000; m_prob_choose_min_var = 43; m_clause_generation = 0; } @@ -180,6 +180,7 @@ namespace sat { m_use_list[c[j].index()].push_back(i); } } + DEBUG_CODE(check_use_list();); } unsigned_vector const& sls::get_use(literal lit) { @@ -242,7 +243,7 @@ namespace sat { } void sls::flip(literal lit) { - // IF_VERBOSE(0, verbose_stream() << lit << " ";); + //IF_VERBOSE(0, verbose_stream() << lit << " ";); SASSERT(value_at(lit, m_model) == l_false); SASSERT(!m_tabu[lit.var()]); m_model[lit.var()] = lit.sign()?l_false:l_true; @@ -266,9 +267,70 @@ namespace sat { } void sls::check_invariant() { - + for (unsigned i = 0; i < m_clauses.size(); ++i) { + clause const& c = *m_clauses[i]; + bool is_sat = c.satisfied_by(m_model); + SASSERT(is_sat != m_false.contains(i)); + SASSERT(is_sat == m_num_true[i] > 0); + } } + void sls::check_use_list() { + + for (unsigned i = 0; i < m_clauses.size(); ++i) { + clause const& c = *m_clauses[i]; + for (unsigned j = 0; j < c.size(); ++j) { + unsigned idx = c[j].index(); + SASSERT(m_use_list[idx].contains(i)); + } + } + + for (unsigned i = 0; i < m_use_list.size(); ++i) { + literal lit = to_literal(i); + for (unsigned j = 0; j < m_use_list[i].size(); ++j) { + clause const& c = *m_clauses[m_use_list[i][j]]; + bool found = false; + for (unsigned k = 0; !found && k < c.size(); ++k) { + found = c[k] == lit; + } + SASSERT(found); + } + } + } + + void sls::display(std::ostream& out) const { + out << "Model\n"; + for (bool_var v = 0; v < m_model.size(); ++v) { + out << v << ": " << m_model[v] << "\n"; + } + out << "Clauses\n"; + unsigned sz = m_false.num_elems(); + for (unsigned i = 0; i < sz; ++i) { + out << *m_clauses[m_false[i]] << "\n"; + } + for (unsigned i = 0; i < m_clauses.size(); ++i) { + if (m_false.contains(i)) continue; + clause const& c = *m_clauses[i]; + out << c << " " << m_num_true[i] << "\n"; + } + bool has_tabu = false; + for (unsigned i = 0; !has_tabu && i < m_tabu.size(); ++i) { + has_tabu = m_tabu[i]; + } + if (has_tabu) { + out << "Tabu: "; + for (unsigned i = 0; i < m_tabu.size(); ++i) { + if (m_tabu[i]) { + literal lit(i, false); + if (value_at(lit, m_model) == l_false) lit.neg(); + out << lit << " "; + } + } + out << "\n"; + } + } + + wsls::wsls(solver& s): sls(s) { @@ -277,7 +339,7 @@ namespace sat { wsls::~wsls() {} - void wsls::set_soft(unsigned sz, double const* weights, literal const* lits) { + void wsls::set_soft(unsigned sz, literal const* lits, double const* weights) { m_soft.reset(); m_weights.reset(); m_soft.append(sz, lits); @@ -291,14 +353,17 @@ namespace sat { // Initialize m_clause_weights, m_hscore, m_sscore. // m_best_value = m_false.empty()?evaluate_model():-1.0; + m_best_model.reset(); m_clause_weights.reset(); m_hscore.reset(); m_sscore.reset(); m_H.reset(); m_S.reset(); + m_best_model.append(s.get_model()); m_clause_weights.resize(m_clauses.size(), 1); m_sscore.resize(s.num_vars(), 0.0); m_hscore.resize(s.num_vars(), 0); + unsigned num_violated = 0; for (unsigned i = 0; i < m_soft.size(); ++i) { literal lit = m_soft[i]; m_sscore[lit.var()] = m_weights[i]; @@ -310,16 +375,19 @@ namespace sat { m_hscore[i] = compute_hscore(i); refresh_scores(i); } + DEBUG_CODE(check_invariant();); unsigned i = 0; - for (; !m_cancel && i < m_max_tries; ++i) { + for (; !m_cancel && m_best_value > 0 && i < m_max_tries; ++i) { wflip(); } - IF_VERBOSE(2, verbose_stream() << "tries " << i << "\n";); + TRACE("sat", display(tout);); + IF_VERBOSE(0, verbose_stream() << "tries " << i << "\n";); } void wsls::wflip() { literal lit; if (pick_wflip(lit)) { + // IF_VERBOSE(0, verbose_stream() << lit << " ";); wflip(lit); } } @@ -328,8 +396,10 @@ namespace sat { if (m_false.empty()) { double val = evaluate_model(); if (val < m_best_value || m_best_value < 0.0) { + m_best_value = val; m_best_model.reset(); m_best_model.append(m_model); + IF_VERBOSE(0, verbose_stream() << "new value:" << val << "\n";); } } unsigned idx; @@ -337,6 +407,8 @@ namespace sat { idx = m_H.choose(m_rand); lit = literal(idx, false); if (value_at(lit, m_model) == l_true) lit.neg(); + SASSERT(value_at(lit, m_model) == l_false); + TRACE("sat", tout << "flip H(" << m_H.num_elems() << ") " << lit << "\n";); } else if (!m_S.empty()) { double score = 0.0; @@ -353,16 +425,38 @@ namespace sat { m_min_vars.push_back(literal(v, false)); } } - idx = m_min_vars[m_rand(m_min_vars.size())].var(); // pick with largest sscore. + lit = m_min_vars[m_rand(m_min_vars.size())]; // pick with largest sscore. + SASSERT(value_at(lit, m_model) == l_false); + TRACE("sat", tout << "flip S(" << m_min_vars.size() << "," << score << ") " << lit << "\n";); } else { update_hard_weights(); if (!m_false.empty()) { unsigned cls_idx = m_false.choose(m_rand); + clause const& c = *m_clauses[cls_idx]; + lit = c[m_rand(c.size())]; + TRACE("sat", tout << "flip hard(" << m_false.num_elems() << "," << c.size() << ") " << lit << "\n";); } else { - lit = m_soft[m_rand(m_soft.size())]; + m_min_vars.reset(); + for (unsigned i = 0; i < m_soft.size(); ++i) { + lit = m_soft[i]; + if (value_at(lit, m_model) == l_false) { + m_min_vars.push_back(lit); + } + } + if (m_min_vars.empty()) { + SASSERT(m_best_value == 0.0); + UNREACHABLE(); // we should have exited the main loop before. + return false; + } + else { + lit = m_min_vars[m_rand(m_min_vars.size())]; + } + TRACE("sat", tout << "flip soft(" << m_min_vars.size() << ") " << lit << "\n";); + } + SASSERT(value_at(lit, m_model) == l_false); } return !m_tabu[lit.var()]; } @@ -408,7 +502,6 @@ namespace sat { } } } - DEBUG_CODE(check_invariant();); } @@ -488,9 +581,29 @@ namespace sat { // The score(v) is the reward on soft clauses for flipping v. for (unsigned j = 0; j < m_soft.size(); ++j) { unsigned v = m_soft[j].var(); - double ss = value_at(m_soft[j], m_model)?(-m_weights[j]):m_weights[j]; + double ss = (l_true == value_at(m_soft[j], m_model))?(-m_weights[j]):m_weights[j]; SASSERT(m_sscore[v] == ss); } + + // m_H are values such that m_hscore >= 0. + for (bool_var v = 0; v < m_hscore.size(); ++v) { + SASSERT(m_hscore[v] > 0 == m_H.contains(v)); + } + + // m_S are values such that hscore = 0, sscore > 0 + for (bool_var v = 0; v < m_sscore.size(); ++v) { + SASSERT((m_hscore[v] == 0 && m_sscore[v] > 0) == m_S.contains(v)); + } + } + + void wsls::display(std::ostream& out) const { + sls::display(out); + out << "Best model\n"; + for (bool_var v = 0; v < m_best_model.size(); ++v) { + out << v << ": " << m_best_model[v] << " h: " << m_hscore[v]; + if (m_sscore[v] != 0.0) out << " s: " << m_sscore[v]; + out << "\n"; + } } }; diff --git a/src/sat/sat_sls.h b/src/sat/sat_sls.h index 5546b90ac..57b883994 100644 --- a/src/sat/sat_sls.h +++ b/src/sat/sat_sls.h @@ -60,6 +60,8 @@ namespace sat { virtual ~sls(); lbool operator()(unsigned sz, literal const* tabu, bool reuse_model); void set_cancel(bool f) { m_cancel = f; } + void set_max_tries(unsigned mx) { m_max_tries = mx; } + virtual void display(std::ostream& out) const; protected: void init(unsigned sz, literal const* tabu, bool reuse_model); void init_tabu(unsigned sz, literal const* tabu); @@ -69,6 +71,7 @@ namespace sat { unsigned_vector const& get_use(literal lit); void flip(literal lit); virtual void check_invariant(); + void check_use_list(); private: bool pick_flip(literal& lit); void flip(); @@ -91,9 +94,11 @@ namespace sat { public: wsls(solver& s); virtual ~wsls(); - void set_soft(unsigned sz, double const* weights, literal const* lits); + void set_soft(unsigned sz, literal const* lits, double const* weights); + bool has_soft() const { return !m_soft.empty(); } void opt(unsigned sz, literal const* tabu, bool reuse_model); model const& get_model() { return m_best_model; } + virtual void display(std::ostream& out) const; private: void wflip(); void wflip(literal lit); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index c100f15b1..e4e34b8a3 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -40,6 +40,7 @@ namespace sat { m_asymm_branch(*this, p), m_probing(*this, p), m_mus(*this), + m_wsls(*this), m_inconsistent(false), m_num_frozen(0), m_activity_inc(128), @@ -528,6 +529,10 @@ namespace sat { return found_undef ? l_undef : l_false; } + void solver::initialize_soft(unsigned sz, literal const* lits, double const* weights) { + m_wsls.set_soft(sz, lits, weights); + } + // ----------------------- // // Propagation @@ -1003,6 +1008,11 @@ namespace sat { m_model[v] = value(v); } TRACE("sat_mc_bug", m_mc.display(tout);); + if (m_config.m_optimize_model) { + m_wsls.opt(0, 0, false); + m_model.reset(); + m_model.append(m_wsls.get_model()); + } m_mc(m_model); TRACE("sat", for (bool_var v = 0; v < num; v++) tout << v << ": " << m_model[v] << "\n";); @@ -2305,6 +2315,7 @@ namespace sat { void solver::set_cancel(bool f) { m_cancel = f; + m_wsls.set_cancel(f); } void solver::collect_statistics(statistics & st) const { diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 869330e06..5f45ab424 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -33,6 +33,7 @@ Revision History: #include"sat_iff3_finder.h" #include"sat_probing.h" #include"sat_mus.h" +#include"sat_sls.h" #include"params.h" #include"statistics.h" #include"stopwatch.h" @@ -82,6 +83,7 @@ namespace sat { asymm_branch m_asymm_branch; probing m_probing; mus m_mus; + wsls m_wsls; bool m_inconsistent; // A conflict is usually a single justification. That is, a justification // for false. If m_not_l is not null_literal, then m_conflict is a @@ -224,13 +226,14 @@ namespace sat { void assign_core(literal l, justification jst); void set_conflict(justification c, literal not_l); void set_conflict(justification c) { set_conflict(c, null_literal); } - lbool status(clause const & c) const; + lbool status(clause const & c) const; clause_offset get_offset(clause const & c) const { return m_cls_allocator.get_offset(&c); } void checkpoint() { if (m_cancel) throw solver_exception(Z3_CANCELED_MSG); if (memory::get_allocation_size() > m_config.m_max_memory) throw solver_exception(Z3_MAX_MEMORY_MSG); } typedef std::pair bin_clause; + void initialize_soft(unsigned sz, literal const* lits, double const* weights); protected: watch_list & get_wlist(literal l) { return m_watches[l.index()]; } watch_list const & get_wlist(literal l) const { return m_watches[l.index()]; } diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 5d9753a82..38a22095a 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -36,6 +36,7 @@ Notes: #include"model_v2_pp.h" #include"tactic.h" #include"ast_pp.h" +#include struct goal2sat::imp { struct frame { @@ -78,8 +79,9 @@ struct goal2sat::imp { m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX)); } - void throw_op_not_handled() { - throw tactic_exception("operator not supported, apply simplifier before invoking translator"); + void throw_op_not_handled(std::string const& s) { + std::string s0 = "operator " + s + " not supported, apply simplifier before invoking translator"; + throw tactic_exception(s0.c_str()); } void mk_clause(sat::literal l) { @@ -183,9 +185,12 @@ struct goal2sat::imp { case OP_AND: case OP_XOR: case OP_IMPLIES: - case OP_DISTINCT: + case OP_DISTINCT: { TRACE("goal2sat_not_handled", tout << mk_ismt2_pp(t, m) << "\n";); - throw_op_not_handled(); + std::ostringstream strm; + strm << mk_ismt2_pp(t, m); + throw_op_not_handled(strm.str()); + } default: convert_atom(t, root, sign); return true; diff --git a/src/smt/theory_wmaxsat.cpp b/src/smt/theory_wmaxsat.cpp index 353ff38a3..e6f410442 100644 --- a/src/smt/theory_wmaxsat.cpp +++ b/src/smt/theory_wmaxsat.cpp @@ -24,7 +24,7 @@ Notes: namespace smt { -theory_wmaxsat::theory_wmaxsat(ast_manager& m, ref& mc): +theory_wmaxsat::theory_wmaxsat(ast_manager& m, filter_model_converter& mc): theory(m.mk_family_id("weighted_maxsat")), m_mc(mc), m_vars(m), @@ -91,7 +91,7 @@ bool_var theory_wmaxsat::assert_weighted(expr* fml, rational const& w) { ast_manager& m = get_manager(); app_ref var(m), wfml(m); var = m.mk_fresh_const("w", m.mk_bool_sort()); - m_mc->insert(var->get_decl()); + m_mc.insert(var->get_decl()); wfml = m.mk_or(var, fml); ctx.assert_expr(wfml); m_rweights.push_back(w); diff --git a/src/smt/theory_wmaxsat.h b/src/smt/theory_wmaxsat.h index b6974957c..feac6c04e 100644 --- a/src/smt/theory_wmaxsat.h +++ b/src/smt/theory_wmaxsat.h @@ -28,7 +28,7 @@ namespace smt { void reset() { memset(this, 0, sizeof(*this)); } stats() { reset(); } }; - ref m_mc; + filter_model_converter& m_mc; mutable unsynch_mpz_manager m_mpz; app_ref_vector m_vars; // Auxiliary variables per soft clause expr_ref_vector m_fmls; // Formulas per soft clause @@ -50,7 +50,7 @@ namespace smt { svector m_assigned; stats m_stats; public: - theory_wmaxsat(ast_manager& m, ref& mc); + theory_wmaxsat(ast_manager& m, filter_model_converter& mc); virtual ~theory_wmaxsat(); void get_assignment(svector& result); virtual void init_search_eh(); From be1cceba3427f262cbedbd3b02acc7528350f007 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Aug 2014 11:29:08 -0700 Subject: [PATCH 464/925] fix scope and mus with user-scopes Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 5 +---- src/sat/sat_mus.cpp | 11 ++++++++++- src/sat/sat_solver.cpp | 4 ++++ 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index a4ccf567f..f31c9e048 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -134,7 +134,6 @@ public: } lbool mus_solver() { - solver::scoped_push _sc(m_s); init(); init_local(); while (true) { @@ -178,10 +177,9 @@ public: } lbool mus_mss_solver() { - solver::scoped_push _sc(s()); init(); init_local(); - enable_sls(m_asms); + //enable_sls(m_asms); ptr_vector mcs; vector > cores; while (m_lower < m_upper) { @@ -222,7 +220,6 @@ public: lbool mss_solver() { NOT_IMPLEMENTED_YET(); - solver::scoped_push _sc(s()); init(); init_local(); ptr_vector mcs; diff --git a/src/sat/sat_mus.cpp b/src/sat/sat_mus.cpp index 11d0fc15d..6295513a9 100644 --- a/src/sat/sat_mus.cpp +++ b/src/sat/sat_mus.cpp @@ -48,6 +48,13 @@ namespace sat { literal_vector& core = m_core; literal_vector& mus = m_mus; core.append(s.get_core()); + for (unsigned i = 0; i < core.size(); ++i) { + s.m_user_scope_literals.contains(core[i]); + mus.push_back(core[i]); + core[i] = core.back(); + core.pop_back(); + --i; + } while (!core.empty()) { TRACE("sat", @@ -61,9 +68,10 @@ namespace sat { literal lit = core.back(); core.pop_back(); unsigned sz = mus.size(); - mus.push_back(~lit); // TBD: measure + // mus.push_back(~lit); // TBD: measure mus.append(core); lbool is_sat = s.check(mus.size(), mus.c_ptr()); + TRACE("sat", tout << "mus: " << mus << "\n";); mus.resize(sz); switch (is_sat) { case l_undef: @@ -83,6 +91,7 @@ namespace sat { if (new_core.contains(~lit)) { break; } + TRACE("sat", tout << "new core: " << new_core << "\n";); core.reset(); for (unsigned i = 0; i < new_core.size(); ++i) { literal lit = new_core[i]; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index e4e34b8a3..e779c9495 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -896,6 +896,9 @@ namespace sat { for (unsigned i = 0; i < num_lits; ++i) tout << lits[i] << " "; tout << "\n"; + if (!m_user_scope_literals.empty()) { + tout << "user literals: " << m_user_scope_literals << "\n"; + } m_mc.display(tout); ); #define _INSERT_LIT(_l_) \ @@ -2237,6 +2240,7 @@ namespace sat { lit = m_user_scope_literal_pool.back(); m_user_scope_literal_pool.pop_back(); } + TRACE("sat", tout << "user_push: " << lit << "\n";); m_user_scope_literals.push_back(lit); } From ddb9e6e8d4110bba82307d7210e681a543f5f9c8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Aug 2014 18:30:06 -0700 Subject: [PATCH 465/925] fix flipper Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 2 +- src/sat/sat_mus.cpp | 3 +- src/sat/sat_mus.h | 2 ++ src/sat/sat_probing.cpp | 1 + src/sat/sat_sls.cpp | 71 +++++++++++++++++++++++++++++++++++------ src/sat/sat_sls.h | 8 +++-- src/sat/sat_solver.cpp | 15 +++++++-- 7 files changed, 86 insertions(+), 16 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index f31c9e048..ae5396f32 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -179,7 +179,7 @@ public: lbool mus_mss_solver() { init(); init_local(); - //enable_sls(m_asms); + enable_sls(m_asms); ptr_vector mcs; vector > cores; while (m_lower < m_upper) { diff --git a/src/sat/sat_mus.cpp b/src/sat/sat_mus.cpp index 6295513a9..e6c9376ea 100644 --- a/src/sat/sat_mus.cpp +++ b/src/sat/sat_mus.cpp @@ -24,7 +24,7 @@ Notes: namespace sat { - mus::mus(solver& s):s(s) {} + mus::mus(solver& s):s(s), m_is_active(false) {} mus::~mus() {} @@ -42,6 +42,7 @@ namespace sat { lbool mus::operator()() { flet _disable_min(s.m_config.m_minimize_core, false); flet _disable_opt(s.m_config.m_optimize_model, false); + flet _is_active(m_is_active, true); TRACE("sat", tout << "old core: " << s.get_core() << "\n";); IF_VERBOSE(2, verbose_stream() << "(sat.mus " << s.get_core() << ")\n";); reset(); diff --git a/src/sat/sat_mus.h b/src/sat/sat_mus.h index c91464394..2f5879a0e 100644 --- a/src/sat/sat_mus.h +++ b/src/sat/sat_mus.h @@ -23,12 +23,14 @@ namespace sat { class mus { literal_vector m_core; literal_vector m_mus; + bool m_is_active; solver& s; public: mus(solver& s); ~mus(); lbool operator()(); + bool is_active() const { return m_is_active; } private: lbool mus2(); void mr(); diff --git a/src/sat/sat_probing.cpp b/src/sat/sat_probing.cpp index e9710c2d4..165d39ad8 100644 --- a/src/sat/sat_probing.cpp +++ b/src/sat/sat_probing.cpp @@ -196,6 +196,7 @@ namespace sat { s.propagate(false); // make sure propagation queue is empty if (s.inconsistent()) return true; + SASSERT(s.m_qhead == s.m_trail.size()); CASSERT("probing", s.check_invariant()); if (!force && m_counter > 0) return true; diff --git a/src/sat/sat_sls.cpp b/src/sat/sat_sls.cpp index fdb9bd5e2..839519760 100644 --- a/src/sat/sat_sls.cpp +++ b/src/sat/sat_sls.cpp @@ -363,6 +363,7 @@ namespace sat { m_clause_weights.resize(m_clauses.size(), 1); m_sscore.resize(s.num_vars(), 0.0); m_hscore.resize(s.num_vars(), 0); + m_marked.resize(s.num_vars(), false); unsigned num_violated = 0; for (unsigned i = 0; i < m_soft.size(); ++i) { literal lit = m_soft[i]; @@ -453,7 +454,7 @@ namespace sat { else { lit = m_min_vars[m_rand(m_min_vars.size())]; } - TRACE("sat", tout << "flip soft(" << m_min_vars.size() << ") " << lit << "\n";); + TRACE("sat", tout << "flip soft(" << m_min_vars.size() << ", " << m_sscore[lit.var()] << ") " << lit << "\n";); } SASSERT(value_at(lit, m_model) == l_false); @@ -464,9 +465,10 @@ namespace sat { void wsls::wflip(literal lit) { flip(lit); unsigned v = lit.var(); - m_hscore[v] = compute_hscore(v); m_sscore[v] = -m_sscore[v]; + m_hscore[v] = compute_hscore(v); refresh_scores(v); + recompute_hscores(v); } void wsls::update_hard_weights() { @@ -517,7 +519,7 @@ namespace sat { return result; } - int wsls::compute_hscore(unsigned v) { + int wsls::compute_hscore(bool_var v) { literal lit(v, false); if (value_at(lit, m_model) == l_false) { lit.neg(); @@ -548,15 +550,65 @@ namespace sat { return hs; } - void wsls::refresh_scores(unsigned v) { - if (m_hscore[v] > 0) { + void wsls::recompute_hscores(bool_var v) { + literal lit(v, false); + if (value_at(lit, m_model) == l_false) { + lit.neg(); + } + m_marked[v] = true; + unsigned_vector const& use1 = get_use(~lit); + unsigned sz = use1.size(); + unsigned csz; + for (unsigned i = 0; i < sz; ++i) { + unsigned cl = use1[i]; + if (m_num_true[cl] > 2) continue; + clause const& c = *m_clauses[cl]; + csz = c.size(); + for (unsigned j = 0; j < csz; ++j) { + add_refresh(c[j].var()); + } + } + unsigned_vector const& use2 = get_use(lit); + sz = use2.size(); + for (unsigned i = 0; i < sz; ++i) { + unsigned cl = use2[i]; + if (m_num_true[cl] > 2) continue; + clause const& c = *m_clauses[cl]; + csz = c.size(); + for (unsigned j = 0; j < csz; ++j) { + add_refresh(c[j].var()); + } + } + m_marked[v] = false; + for (unsigned i = 0; i < m_to_refresh.size(); ++i) { + v = m_to_refresh[i]; + int hs = compute_hscore(v); + if (hs != m_hscore[v]) { + TRACE("sat_verbose", tout << "refresh: " << v << " from " << m_hscore[v] << " to " << hs << "\n";); + m_hscore[v] = hs; + refresh_scores(v); + } + m_marked[v] = false; + } + m_to_refresh.reset(); + } + + void wsls::add_refresh(bool_var v) { + if (!m_marked[v]) { + m_to_refresh.push_back(v); + m_marked[v] = true; + } + } + + void wsls::refresh_scores(bool_var v) { + if (m_hscore[v] > 0 && !m_tabu[v] && m_sscore[v] == 0) { m_H.insert(v); } else { m_H.remove(v); } if (m_sscore[v] > 0) { - if (m_hscore[v] == 0) { + if (m_hscore[v] == 0 && !m_tabu[v]) { m_S.insert(v); } else { @@ -575,6 +627,7 @@ namespace sat { // - Sum weight(c) for num_true(c) = 1 and (v in c, M(v) or !v in c and !M(v)) for (unsigned v = 0; v < s.num_vars(); ++v) { int hs = compute_hscore(v); + CTRACE("sat", hs != m_hscore[v], display(tout << v << " - computed: " << hs << " - assigned: " << m_hscore[v] << "\n");); SASSERT(m_hscore[v] == hs); } @@ -585,14 +638,14 @@ namespace sat { SASSERT(m_sscore[v] == ss); } - // m_H are values such that m_hscore >= 0. + // m_H are values such that m_hscore > 0 and sscore = 0. for (bool_var v = 0; v < m_hscore.size(); ++v) { - SASSERT(m_hscore[v] > 0 == m_H.contains(v)); + SASSERT((m_hscore[v] > 0 && !m_tabu[v] && m_sscore[v] == 0) == m_H.contains(v)); } // m_S are values such that hscore = 0, sscore > 0 for (bool_var v = 0; v < m_sscore.size(); ++v) { - SASSERT((m_hscore[v] == 0 && m_sscore[v] > 0) == m_S.contains(v)); + SASSERT((m_hscore[v] == 0 && m_sscore[v] > 0 && !m_tabu[v]) == m_S.contains(v)); } } diff --git a/src/sat/sat_sls.h b/src/sat/sat_sls.h index 57b883994..adcc67ec7 100644 --- a/src/sat/sat_sls.h +++ b/src/sat/sat_sls.h @@ -91,6 +91,8 @@ namespace sat { model m_best_model; index_set m_H, m_S; unsigned m_smoothing_probability; + svector m_marked; + unsigned_vector m_to_refresh; public: wsls(solver& s); virtual ~wsls(); @@ -106,8 +108,10 @@ namespace sat { bool pick_wflip(literal & lit); double evaluate_model(); virtual void check_invariant(); - void refresh_scores(unsigned v); - int compute_hscore(unsigned v); + void refresh_scores(bool_var v); + int compute_hscore(bool_var v); + void recompute_hscores(bool_var v); + void add_refresh(bool_var v); }; }; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index e779c9495..a0ba9c391 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -692,6 +692,7 @@ namespace sat { } wlist.set_end(it2); } + SASSERT(m_qhead == m_trail.size()); SASSERT(!m_inconsistent); return true; } @@ -952,10 +953,15 @@ namespace sat { /** \brief Apply all simplifications. + */ void solver::simplify_problem() { - pop(scope_lvl()); - m_trail.reset(); + + // Disable simplification during MUS computation. + // if (m_mus.is_active()) return; + TRACE("sat", tout << "simplify\n";); + + pop(scope_lvl()); SASSERT(scope_lvl() == 0); @@ -990,6 +996,9 @@ namespace sat { m_ext->clauses_modifed(); m_ext->simplify(); } + + TRACE("sat", display(tout << "consistent: " << (!inconsistent()) << "\n");); + reinit_assumptions(); } @@ -2144,7 +2153,7 @@ namespace sat { // ----------------------- void solver::push() { SASSERT(!inconsistent()); - TRACE("sat", tout << "q:" << m_qhead << " trail: " << m_trail.size() << "\n";); + TRACE("sat_verbose", tout << "q:" << m_qhead << " trail: " << m_trail.size() << "\n";); SASSERT(m_qhead == m_trail.size()); m_scopes.push_back(scope()); scope & s = m_scopes.back(); From 33f74b9c9f946c5e549d5cb8100e06b8faa86845 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Aug 2014 22:49:21 -0700 Subject: [PATCH 466/925] sls Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 47 +++++++++++++----- src/opt/maxsmt.cpp | 11 ++--- src/sat/sat_sls.cpp | 116 ++++++++++++++++++++++++++------------------ src/sat/sat_sls.h | 7 ++- 4 files changed, 110 insertions(+), 71 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index ae5396f32..6bf4f6e1d 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -219,27 +219,50 @@ public: } lbool mss_solver() { - NOT_IMPLEMENTED_YET(); init(); init_local(); + enable_sls(m_asms); + set_mus(false); ptr_vector mcs; while (m_lower < m_upper) { - lbool is_sat = s().check_sat(0, 0); - // is_sat = get_mcs(mcs); + IF_VERBOSE(1, verbose_stream() << "(opt.maxres [" << m_lower << ":" << m_upper << "])\n";); + + lbool is_sat = s().check_sat(0, 0); + if (is_sat == l_true) { + vector > cores; + ptr_vector mss; + model_ref mdl; + expr_ref tmp(m); + mcs.reset(); + s().get_model(mdl); + update_assignment(mdl.get()); + for (unsigned i = 0; i < m_asms.size(); ++i) { + VERIFY(mdl->eval(m_asms[i].get(), tmp)); + if (m.is_true(tmp)) { + mss.push_back(m_asms[i].get()); + } + } + is_sat = m_mss(cores, mss, mcs); + std::cout << mcs.size() << " " << is_sat << "\n"; + } switch (is_sat) { case l_undef: return l_undef; case l_false: m_lower = m_upper; break; - case l_true: - // + case l_true: { + is_sat = process_sat(mcs); if (is_sat != l_true) { return is_sat; } + model_ref mdl; + m_mss.get_model(mdl); + update_assignment(mdl.get()); break; } + } } m_lower = m_upper; return l_true; @@ -496,8 +519,9 @@ public: lbool is_sat = s().check_sat(sz, asms.c_ptr()); switch (is_sat) { case l_true: { - s().get_model(m_model); // last model is best way to reduce search space. - update_assignment(); + model_ref mdl; + s().get_model(mdl); // last model is best way to reduce search space. + update_assignment(mdl.get()); ptr_vector mss; mss.append(asms.size(), asms.c_ptr()); set_mus(false); @@ -506,8 +530,8 @@ public: if (is_sat != l_true) { return is_sat; } - m_mss.get_model(m_model); // last model is best way to reduce search space. - update_assignment(); + m_mss.get_model(mdl); // last model is best way to reduce search space. + update_assignment(mdl.get()); if (!cores.empty() && mcs.size() > cores.back().size()) { mcs.reset(); } @@ -550,12 +574,12 @@ public: } - void update_assignment() { + void update_assignment(model* mdl) { rational upper(0); expr_ref tmp(m); for (unsigned i = 0; i < m_soft.size(); ++i) { expr* n = m_soft[i].get(); - VERIFY(m_model->eval(n, tmp)); + VERIFY(mdl->eval(n, tmp)); if (!m.is_true(tmp)) { upper += m_weights[i]; } @@ -565,6 +589,7 @@ public: if (upper >= m_upper) { return; } + m_model = mdl; for (unsigned i = 0; i < m_soft.size(); ++i) { expr* n = m_soft[i].get(); diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index d7cbbc910..e3c9e860c 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -28,15 +28,7 @@ Notes: #include "wmax.h" #include "maxsls.h" #include "ast_pp.h" -#include "pb_decl_plugin.h" -#include "pb_sls.h" -#include "tactical.h" -#include "tactic.h" -#include "tactic2solver.h" -#include "qfbv_tactic.h" -#include "card2bv_tactic.h" #include "uint_set.h" -#include "pb_preprocess_tactic.h" #include "opt_context.h" @@ -133,6 +125,9 @@ namespace opt { else if (maxsat_engine == symbol("mus-mss-maxres")) { m_msolver = mk_mus_mss_maxres(m_c, m_weights, m_soft_constraints); } + else if (maxsat_engine == symbol("mss-maxres")) { + m_msolver = mk_mss_maxres(m_c, m_weights, m_soft_constraints); + } else if (maxsat_engine == symbol("pbmax")) { m_msolver = mk_pbmax(m_c, m_weights, m_soft_constraints); } diff --git a/src/sat/sat_sls.cpp b/src/sat/sat_sls.cpp index 839519760..8f4e09173 100644 --- a/src/sat/sat_sls.cpp +++ b/src/sat/sat_sls.cpp @@ -51,7 +51,6 @@ namespace sat { } sls::sls(solver& s): s(s), m_cancel(false) { - m_max_tries = 1000000; m_prob_choose_min_var = 43; m_clause_generation = 0; } @@ -88,6 +87,9 @@ namespace sat { } init_tabu(sz, tabu); m_clause_generation = s.m_stats.m_non_learned_generation; + + m_max_tries = 10*(s.num_vars() + m_clauses.size()); + } void sls::init_clauses() { @@ -363,7 +365,6 @@ namespace sat { m_clause_weights.resize(m_clauses.size(), 1); m_sscore.resize(s.num_vars(), 0.0); m_hscore.resize(s.num_vars(), 0); - m_marked.resize(s.num_vars(), false); unsigned num_violated = 0; for (unsigned i = 0; i < m_soft.size(); ++i) { literal lit = m_soft[i]; @@ -372,7 +373,7 @@ namespace sat { m_sscore[lit.var()] = -m_sscore[lit.var()]; } } - for (unsigned i = 0; i < s.num_vars(); ++i) { + for (bool_var i = 0; i < s.num_vars(); ++i) { m_hscore[i] = compute_hscore(i); refresh_scores(i); } @@ -380,6 +381,16 @@ namespace sat { unsigned i = 0; for (; !m_cancel && m_best_value > 0 && i < m_max_tries; ++i) { wflip(); + if (m_false.empty()) { + double val = evaluate_model(); + if (val < m_best_value || m_best_value < 0.0) { + m_best_value = val; + m_best_model.reset(); + m_best_model.append(m_model); + IF_VERBOSE(0, verbose_stream() << "new value: " << val << " @ " << i << "\n";); + m_max_tries *= 2; + } + } } TRACE("sat", display(tout);); IF_VERBOSE(0, verbose_stream() << "tries " << i << "\n";); @@ -394,15 +405,6 @@ namespace sat { } bool wsls::pick_wflip(literal & lit) { - if (m_false.empty()) { - double val = evaluate_model(); - if (val < m_best_value || m_best_value < 0.0) { - m_best_value = val; - m_best_model.reset(); - m_best_model.append(m_model); - IF_VERBOSE(0, verbose_stream() << "new value:" << val << "\n";); - } - } unsigned idx; if (!m_H.empty()) { idx = m_H.choose(m_rand); @@ -468,7 +470,7 @@ namespace sat { m_sscore[v] = -m_sscore[v]; m_hscore[v] = compute_hscore(v); refresh_scores(v); - recompute_hscores(v); + recompute_hscores(lit); } void wsls::update_hard_weights() { @@ -550,53 +552,71 @@ namespace sat { return hs; } - void wsls::recompute_hscores(bool_var v) { - literal lit(v, false); - if (value_at(lit, m_model) == l_false) { - lit.neg(); - } - m_marked[v] = true; - unsigned_vector const& use1 = get_use(~lit); + void wsls::recompute_hscores(literal lit) { + SASSERT(value_at(lit, m_model) == l_true); + bool_var v = lit.var(); + TRACE("sat", tout << v << " := " << m_hscore[v] << "\n";); + unsigned_vector const& use1 = get_use(lit); unsigned sz = use1.size(); - unsigned csz; for (unsigned i = 0; i < sz; ++i) { - unsigned cl = use1[i]; - if (m_num_true[cl] > 2) continue; - clause const& c = *m_clauses[cl]; - csz = c.size(); - for (unsigned j = 0; j < csz; ++j) { - add_refresh(c[j].var()); + unsigned cl = use1[i]; + TRACE("sat", tout << *m_clauses[cl] << " " << m_num_true[cl] << "\n";); + SASSERT(m_num_true[cl] > 0); + if (m_num_true[cl] == 1) { + // num_true 0 -> 1 + // other literals don't have upside any more. + // subtract one from all other literals + adjust_all_values(lit, cl, -static_cast(m_clause_weights[cl])); + } + else if (m_num_true[cl] == 2) { + // num_true 1 -> 2, previous critical literal is no longer critical + adjust_pivot_value(lit, cl, +m_clause_weights[cl]); } } - unsigned_vector const& use2 = get_use(lit); + unsigned_vector const& use2 = get_use(~lit); sz = use2.size(); for (unsigned i = 0; i < sz; ++i) { unsigned cl = use2[i]; - if (m_num_true[cl] > 2) continue; - clause const& c = *m_clauses[cl]; - csz = c.size(); - for (unsigned j = 0; j < csz; ++j) { - add_refresh(c[j].var()); + TRACE("sat", tout << *m_clauses[cl] << " " << m_num_true[cl] << "\n";); + if (m_num_true[cl] == 0) { + // num_true 1 -> 0 + // all variables became critical. + adjust_all_values(~lit, cl, +m_clause_weights[cl]); } - } - m_marked[v] = false; - for (unsigned i = 0; i < m_to_refresh.size(); ++i) { - v = m_to_refresh[i]; - int hs = compute_hscore(v); - if (hs != m_hscore[v]) { - TRACE("sat_verbose", tout << "refresh: " << v << " from " << m_hscore[v] << " to " << hs << "\n";); - m_hscore[v] = hs; - refresh_scores(v); + else if (m_num_true[cl] == 1) { + adjust_pivot_value(~lit, cl, -static_cast(m_clause_weights[cl])); } - m_marked[v] = false; + // else n+1 -> n >= 2 } - m_to_refresh.reset(); } - void wsls::add_refresh(bool_var v) { - if (!m_marked[v]) { - m_to_refresh.push_back(v); - m_marked[v] = true; + void wsls::adjust_all_values(literal lit, unsigned cl, int delta) { + clause const& c = *m_clauses[cl]; + unsigned sz = c.size(); + TRACE("sat", tout << lit << " " << c << " delta: " << delta << " nt: " << m_num_true[cl] << "\n";); + for (unsigned i = 0; i < sz; ++i) { + literal lit2 = c[i]; + if (lit2 != lit) { + TRACE("sat", tout << lit2.var() << " := " << m_hscore[lit2.var()] << "\n";); + m_hscore[lit2.var()] += delta; + TRACE("sat", tout << lit2.var() << " := " << m_hscore[lit2.var()] << "\n";); + refresh_scores(lit2.var()); + } + } + } + + void wsls::adjust_pivot_value(literal lit, unsigned cl, int delta) { + clause const& c = *m_clauses[cl]; + unsigned csz = c.size(); + for (unsigned j = 0; j < csz; ++j) { + literal lit2 = c[j]; + if (lit2 != lit && value_at(lit2, m_model) == l_true) { + TRACE("sat", tout << lit2.var() << " := " << m_hscore[lit2.var()] << "\n";); + m_hscore[lit2.var()] += delta; + TRACE("sat", tout << lit2.var() << " := " << m_hscore[lit2.var()] << "\n";); + refresh_scores(lit2.var()); + break; + } } } diff --git a/src/sat/sat_sls.h b/src/sat/sat_sls.h index adcc67ec7..8efc337cc 100644 --- a/src/sat/sat_sls.h +++ b/src/sat/sat_sls.h @@ -91,8 +91,6 @@ namespace sat { model m_best_model; index_set m_H, m_S; unsigned m_smoothing_probability; - svector m_marked; - unsigned_vector m_to_refresh; public: wsls(solver& s); virtual ~wsls(); @@ -110,8 +108,9 @@ namespace sat { virtual void check_invariant(); void refresh_scores(bool_var v); int compute_hscore(bool_var v); - void recompute_hscores(bool_var v); - void add_refresh(bool_var v); + void recompute_hscores(literal lit); + void adjust_all_values(literal lit, unsigned cl, int delta); + void adjust_pivot_value(literal lit, unsigned cl, int delta); }; }; From f748a03ac7d2a6030c0e28b94ccde7e367f783c2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 16 Aug 2014 22:31:54 -0700 Subject: [PATCH 467/925] opt Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 41 +++++++++++++--------------- src/opt/maxsmt.cpp | 3 ++ src/opt/maxsmt.h | 1 - src/opt/mss.cpp | 35 ++++++++++++------------ src/opt/mss.h | 3 +- src/opt/opt_context.cpp | 1 + src/opt/wmax.cpp | 4 +-- src/sat/sat_solver.cpp | 1 + src/sat/sat_solver.h | 14 ++++++---- src/tactic/bv/bit_blaster_tactic.cpp | 8 ++++-- 10 files changed, 60 insertions(+), 51 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 6bf4f6e1d..8a4f07b18 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -224,35 +224,26 @@ public: enable_sls(m_asms); set_mus(false); ptr_vector mcs; - while (m_lower < m_upper) { + lbool is_sat = l_true; + while (m_lower < m_upper && is_sat == l_true) { IF_VERBOSE(1, verbose_stream() << "(opt.maxres [" << m_lower << ":" << m_upper << "])\n";); + vector > cores; + ptr_vector mss; + model_ref mdl; + expr_ref tmp(m); + mcs.reset(); + s().get_model(mdl); + update_assignment(mdl.get()); + mss.append(m_asms.size(), m_asms.c_ptr()); + is_sat = m_mss(cores, mss, mcs); - lbool is_sat = s().check_sat(0, 0); - if (is_sat == l_true) { - vector > cores; - ptr_vector mss; - model_ref mdl; - expr_ref tmp(m); - mcs.reset(); - s().get_model(mdl); - update_assignment(mdl.get()); - for (unsigned i = 0; i < m_asms.size(); ++i) { - VERIFY(mdl->eval(m_asms[i].get(), tmp)); - if (m.is_true(tmp)) { - mss.push_back(m_asms[i].get()); - } - } - is_sat = m_mss(cores, mss, mcs); - std::cout << mcs.size() << " " << is_sat << "\n"; - } switch (is_sat) { case l_undef: return l_undef; case l_false: m_lower = m_upper; - break; - case l_true: { - + return l_true; + case l_true: { is_sat = process_sat(mcs); if (is_sat != l_true) { return is_sat; @@ -263,6 +254,12 @@ public: break; } } + if (m_cancel) { + return l_undef; + } + if (m_lower < m_upper) { + is_sat = s().check_sat(0, 0); + } } m_lower = m_upper; return l_true; diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index e3c9e860c..44f898443 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -179,6 +179,9 @@ namespace opt { } void maxsmt::verify_assignment() { + // TBD: have to use a different solver + // because we don't push local scope any longer. + return; solver::scoped_push _sp(m_s); commit_assignment(); if (l_true != m_s.check_sat(0,0)) { diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 0110132f2..ee275e7f6 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -75,7 +75,6 @@ namespace opt { void set_model() { s().get_model(m_model); } virtual void updt_params(params_ref& p); virtual void init_soft(vector const& weights, expr_ref_vector const& soft); - void add_hard(expr* e){ s().assert_expr(e); } solver& s() { return m_s; } void init(); expr* mk_not(expr* e); diff --git a/src/opt/mss.cpp b/src/opt/mss.cpp index 63a7a72bf..77dd39409 100644 --- a/src/opt/mss.cpp +++ b/src/opt/mss.cpp @@ -49,7 +49,7 @@ namespace opt { return true; } - void mss::initialize(vector& cores, exprs& literals) { + void mss::initialize(exprs& literals) { expr* n; expr_set lits, core_lits; for (unsigned i = 0; i < literals.size(); ++i) { @@ -67,8 +67,8 @@ namespace opt { // did not occur in previous cores and did not evaluate to true // in the current model. // - for (unsigned i = 0; i < cores.size(); ++i) { - exprs const& core = cores[i]; + for (unsigned i = 0; i < m_cores.size(); ++i) { + exprs const& core = m_cores[i]; for (unsigned j = 0; j < core.size(); ++j) { expr* n = core[j]; if (!core_lits.contains(n)) { @@ -97,7 +97,7 @@ namespace opt { } } } - cores.push_back(rest_core); + m_cores.push_back(rest_core); } void mss::add_mss(expr* n) { @@ -148,23 +148,20 @@ namespace opt { m_mss.reset(); m_todo.reset(); m_s.get_model(m_model); + m_cores.reset(); SASSERT(m_model); - vector cores(_cores); + m_cores.append(_cores); + initialize(literals); TRACE("opt", - for (unsigned i = 0; i < cores.size(); ++i) { - display_vec(tout << "core: ", cores[i].size(), cores[i].c_ptr()); - } display_vec(tout << "lits: ", literals.size(), literals.c_ptr()); - ); - initialize(cores, literals); - TRACE("opt", display(tout);); + display(tout);); lbool is_sat = l_true; - for (unsigned i = 0; is_sat == l_true && i < cores.size(); ++i) { + for (unsigned i = 0; is_sat == l_true && i < m_cores.size(); ++i) { bool has_mcs = false; - bool is_last = i + 1 < cores.size(); + bool is_last = i + 1 < m_cores.size(); SASSERT(check_invariant()); - update_core(cores[i]); // remove members of mss - is_sat = process_core(1, cores[i], has_mcs, is_last); + update_core(m_cores[i]); // remove members of mss + is_sat = process_core(1, m_cores[i], has_mcs, is_last); } if (is_sat == l_true) { SASSERT(check_invariant()); @@ -180,6 +177,7 @@ namespace opt { } m_mcs.reset(); m_mss_set.reset(); + IF_VERBOSE(2, display_vec(verbose_stream() << "mcs: ", mcs.size(), mcs.c_ptr());); return is_sat; } @@ -208,7 +206,7 @@ namespace opt { unsigned sz_save = m_mss.size(); m_mss.append(sz, core.c_ptr()); lbool is_sat = m_s.check_sat(m_mss.size(), m_mss.c_ptr()); - IF_VERBOSE(2, display_vec(verbose_stream() << "mss: ", m_mss.size(), m_mss.c_ptr());); + IF_VERBOSE(3, display_vec(verbose_stream() << "mss: ", m_mss.size(), m_mss.c_ptr());); m_mss.resize(sz_save); switch (is_sat) { case l_true: @@ -253,6 +251,9 @@ namespace opt { } void mss::display(std::ostream& out) const { + for (unsigned i = 0; i < m_cores.size(); ++i) { + display_vec(out << "core: ", m_cores[i].size(), m_cores[i].c_ptr()); + } expr_set::iterator it = m_mcs.begin(), end = m_mcs.end(); out << "mcs:\n"; for (; it != end; ++it) { @@ -261,7 +262,7 @@ namespace opt { out << "\n"; out << "mss:\n"; for (unsigned i = 0; i < m_mss.size(); ++i) { - out << mk_pp(m_mss[i], m) << "\n"; + out << mk_pp(m_mss[i], m) << "\n"; } out << "\n"; if (m_model) { diff --git a/src/opt/mss.h b/src/opt/mss.h index cf69c14f9..057161eaa 100644 --- a/src/opt/mss.h +++ b/src/opt/mss.h @@ -29,6 +29,7 @@ namespace opt { exprs m_mss; expr_set m_mcs; expr_set m_mss_set; + vector m_cores; exprs m_todo; model_ref m_model; public: @@ -42,7 +43,7 @@ namespace opt { void get_model(model_ref& mdl) { mdl = m_model; } private: - void initialize(vector& cores, exprs& literals); + void initialize(exprs& literals); bool check_result(); void add_mss(expr* n); void update_mss(); diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index d2de3ae80..327a636f7 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -436,6 +436,7 @@ namespace opt { } if (m_maxsat_engine != symbol("maxres") && m_maxsat_engine != symbol("mus-mss-maxres") && + m_maxsat_engine != symbol("mss-maxres") && m_maxsat_engine != symbol("bcd2") && m_maxsat_engine != symbol("sls")) { return; diff --git a/src/opt/wmax.cpp b/src/opt/wmax.cpp index 84a1a4e52..c9cf44b2a 100644 --- a/src/opt/wmax.cpp +++ b/src/opt/wmax.cpp @@ -84,15 +84,12 @@ namespace opt { lbool operator()() { TRACE("opt", tout << "weighted maxsat\n";); scoped_ensure_theory wth(*this); - solver::scoped_push _s(s()); lbool is_sat = l_true; bool was_sat = false; for (unsigned i = 0; i < m_soft.size(); ++i) { wth().assert_weighted(m_soft[i].get(), m_weights[i]); } - solver::scoped_push __s(s()); while (l_true == is_sat) { - IF_VERBOSE(1, verbose_stream() << "(opt.wmax [" << m_lower << ":" << m_upper << "])\n";); is_sat = s().check_sat(0,0); if (m_cancel) { is_sat = l_undef; @@ -106,6 +103,7 @@ namespace opt { s().assert_expr(fml); was_sat = true; } + IF_VERBOSE(1, verbose_stream() << "(opt.wmax [" << m_lower << ":" << m_upper << "])\n";); } if (was_sat) { wth().get_assignment(m_assignment); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index a0ba9c391..5b626f170 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -51,6 +51,7 @@ namespace sat { m_config.updt_params(p); m_conflicts_since_gc = 0; m_next_simplify = 0; + m_num_checkpoints = 0; } solver::~solver() { diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 5f45ab424..f7e6a009d 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -82,8 +82,8 @@ namespace sat { scc m_scc; asymm_branch m_asymm_branch; probing m_probing; - mus m_mus; - wsls m_wsls; + mus m_mus; // MUS for minimal core extraction + wsls m_wsls; // SLS facility for MaxSAT use bool m_inconsistent; // A conflict is usually a single justification. That is, a justification // for false. If m_not_l is not null_literal, then m_conflict is a @@ -123,9 +123,9 @@ namespace sat { stopwatch m_stopwatch; params_ref m_params; scoped_ptr m_clone; // for debugging purposes - literal_vector m_assumptions; - literal_set m_assumption_set; - literal_vector m_core; + literal_vector m_assumptions; // additional assumptions during check + literal_set m_assumption_set; // set of enabled assumptions + literal_vector m_core; // unsat core void del_clauses(clause * const * begin, clause * const * end); @@ -230,6 +230,9 @@ namespace sat { clause_offset get_offset(clause const & c) const { return m_cls_allocator.get_offset(&c); } void checkpoint() { if (m_cancel) throw solver_exception(Z3_CANCELED_MSG); + ++m_num_checkpoints; + if (m_num_checkpoints < 10) return; + m_num_checkpoints = 0; if (memory::get_allocation_size() > m_config.m_max_memory) throw solver_exception(Z3_MAX_MEMORY_MSG); } typedef std::pair bin_clause; @@ -275,6 +278,7 @@ namespace sat { unsigned m_luby_idx; unsigned m_conflicts_since_gc; unsigned m_gc_threshold; + unsigned m_num_checkpoints; double m_min_d_tk; unsigned m_next_simplify; bool decide(); diff --git a/src/tactic/bv/bit_blaster_tactic.cpp b/src/tactic/bv/bit_blaster_tactic.cpp index 0330141cb..7c7eca33b 100644 --- a/src/tactic/bv/bit_blaster_tactic.cpp +++ b/src/tactic/bv/bit_blaster_tactic.cpp @@ -69,6 +69,7 @@ class bit_blaster_tactic : public tactic { expr_ref new_curr(m()); proof_ref new_pr(m()); unsigned size = g->size(); + bool change = false; for (unsigned idx = 0; idx < size; idx++) { if (g->inconsistent()) break; @@ -79,10 +80,13 @@ class bit_blaster_tactic : public tactic { proof * pr = g->pr(idx); new_pr = m().mk_modus_ponens(pr, new_pr); } - g->update(idx, new_curr, new_pr, g->dep(idx)); + if (curr != new_curr) { + change = true; + g->update(idx, new_curr, new_pr, g->dep(idx)); + } } - if (g->models_enabled()) + if (change && g->models_enabled()) mc = mk_bit_blaster_model_converter(m(), m_rewriter.const2bits()); else mc = 0; From ddbff6f77b88bf00b410bdfab7f5456b68087e9b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Aug 2014 01:03:11 -0700 Subject: [PATCH 468/925] revamp configuration parameter names for fixedpoint Signed-off-by: Nikolaj Bjorner --- src/muz/base/dl_context.cpp | 54 ++--- src/muz/base/fixedpoint_params.pyg | 217 +++++++++++------- src/muz/bmc/dl_bmc_engine.cpp | 2 +- src/muz/duality/duality_dl_interface.cpp | 20 +- src/muz/fp/horn_tactic.cpp | 2 +- src/muz/pdr/pdr_context.cpp | 258 +++++++++++++--------- src/muz/pdr/pdr_context.h | 21 +- src/muz/pdr/pdr_dl_interface.cpp | 10 +- src/muz/pdr/pdr_prop_solver.cpp | 2 +- src/muz/rel/rel_context.cpp | 8 +- src/muz/transforms/dl_mk_rule_inliner.cpp | 6 +- src/muz/transforms/dl_transforms.cpp | 4 +- 12 files changed, 358 insertions(+), 246 deletions(-) diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index fbef46ae3..859d4419f 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -272,34 +272,34 @@ namespace datalog { bool context::generate_proof_trace() const { return m_params->generate_proof_trace(); } - bool context::output_profile() const { return m_params->output_profile(); } - bool context::output_tuples() const { return m_params->output_tuples(); } - bool context::use_map_names() const { return m_params->use_map_names(); } - bool context::fix_unbound_vars() const { return m_params->fix_unbound_vars(); } - symbol context::default_table() const { return m_params->default_table(); } - symbol context::default_relation() const { return m_params->default_relation(); } // external_relation_plugin::get_name()); - symbol context::default_table_checker() const { return m_params->default_table_checker(); } - bool context::default_table_checked() const { return m_params->default_table_checked(); } - bool context::dbg_fpr_nonempty_relation_signature() const { return m_params->dbg_fpr_nonempty_relation_signature(); } - unsigned context::dl_profile_milliseconds_threshold() const { return m_params->profile_timeout_milliseconds(); } - bool context::all_or_nothing_deltas() const { return m_params->all_or_nothing_deltas(); } - bool context::compile_with_widening() const { return m_params->compile_with_widening(); } - bool context::unbound_compressor() const { return m_params->unbound_compressor(); } - bool context::similarity_compressor() const { return m_params->similarity_compressor(); } - unsigned context::similarity_compressor_threshold() const { return m_params->similarity_compressor_threshold(); } + bool context::output_profile() const { return m_params->datalog_output_profile(); } + bool context::output_tuples() const { return m_params->datalog_print_tuples(); } + bool context::use_map_names() const { return m_params->datalog_use_map_names(); } + bool context::fix_unbound_vars() const { return m_params->xform_fix_unbound_vars(); } + symbol context::default_table() const { return m_params->datalog_default_table(); } + symbol context::default_relation() const { return m_params->datalog_default_relation(); } // external_relation_plugin::get_name()); + symbol context::default_table_checker() const { return m_params->datalog_default_table_checker(); } + bool context::default_table_checked() const { return m_params->datalog_default_table_checked(); } + bool context::dbg_fpr_nonempty_relation_signature() const { return m_params->datalog_dbg_fpr_nonempty_relation_signature(); } + unsigned context::dl_profile_milliseconds_threshold() const { return m_params->datalog_profile_timeout_milliseconds(); } + bool context::all_or_nothing_deltas() const { return m_params->datalog_all_or_nothing_deltas(); } + bool context::compile_with_widening() const { return m_params->datalog_compile_with_widening(); } + bool context::unbound_compressor() const { return m_params->datalog_unbound_compressor(); } + bool context::similarity_compressor() const { return m_params->datalog_similarity_compressor(); } + unsigned context::similarity_compressor_threshold() const { return m_params->datalog_similarity_compressor_threshold(); } unsigned context::soft_timeout() const { return m_fparams.m_soft_timeout; } - unsigned context::initial_restart_timeout() const { return m_params->initial_restart_timeout(); } - bool context::generate_explanations() const { return m_params->generate_explanations(); } - bool context::explanations_on_relation_level() const { return m_params->explanations_on_relation_level(); } - bool context::magic_sets_for_queries() const { return m_params->magic_sets_for_queries(); } - bool context::eager_emptiness_checking() const { return m_params->eager_emptiness_checking(); } + unsigned context::initial_restart_timeout() const { return m_params->datalog_initial_restart_timeout(); } + bool context::generate_explanations() const { return m_params->datalog_generate_explanations(); } + bool context::explanations_on_relation_level() const { return m_params->datalog_explanations_on_relation_level(); } + bool context::magic_sets_for_queries() const { return m_params->datalog_magic_sets_for_queries(); } + bool context::eager_emptiness_checking() const { return m_params->datalog_eager_emptiness_checking(); } - bool context::bit_blast() const { return m_params->bit_blast(); } - bool context::karr() const { return m_params->karr(); } - bool context::scale() const { return m_params->scale(); } - bool context::magic() const { return m_params->magic(); } - bool context::quantify_arrays() const { return m_params->quantify_arrays(); } - bool context::instantiate_quantifiers() const { return m_params->instantiate_quantifiers(); } + bool context::bit_blast() const { return m_params->xform_bit_blast(); } + bool context::karr() const { return m_params->xform_karr(); } + bool context::scale() const { return m_params->xform_scale(); } + bool context::magic() const { return m_params->xform_magic(); } + bool context::quantify_arrays() const { return m_params->xform_quantify_arrays(); } + bool context::instantiate_quantifiers() const { return m_params->xform_instantiate_quantifiers(); } void context::register_finite_sort(sort * s, sort_kind k) { @@ -1153,7 +1153,7 @@ namespace datalog { expr_ref fml(m); expr_ref_vector rules(m); svector names; - bool use_fixedpoint_extensions = m_params->print_with_fixedpoint_extensions(); + bool use_fixedpoint_extensions = m_params->print_fixedpoint_extensions(); bool print_low_level = m_params->print_low_level_smt2(); bool do_declare_vars = m_params->print_with_variable_declarations(); diff --git a/src/muz/base/fixedpoint_params.pyg b/src/muz/base/fixedpoint_params.pyg index 5bfbba6b2..d61c442d3 100644 --- a/src/muz/base/fixedpoint_params.pyg +++ b/src/muz/base/fixedpoint_params.pyg @@ -2,82 +2,147 @@ def_module_params('fixedpoint', description='fixedpoint parameters', export=True, params=(('timeout', UINT, UINT_MAX, 'set timeout'), - ('engine', SYMBOL, 'auto-config', 'Select: auto-config, datalog, pdr, bmc'), - ('default_table', SYMBOL, 'sparse', 'default table implementation: sparse, hashtable, bitvector, interval'), - ('default_relation', SYMBOL, 'pentagon', 'default relation implementation: external_relation, pentagon'), - ('generate_explanations', BOOL, False, '(DATALOG) produce explanations for produced facts when using the datalog engine'), - ('use_map_names', BOOL, True, "(DATALOG) use names from map files when displaying tuples"), - ('bit_blast', BOOL, False, '(PDR) bit-blast bit-vectors'), - ('explanations_on_relation_level', BOOL, False, '(DATALOG) if true, explanations are generated as history of each relation, rather than per fact (generate_explanations must be set to true for this option to have any effect)'), - ('magic_sets_for_queries', BOOL, False, "(DATALOG) magic set transformation will be used for queries"), - ('magic', BOOL, False, "perform symbolic magic set transformation"), - ('scale', BOOL, False, "add scaling variable to linear real arithemtic clauses"), - ('unbound_compressor', BOOL, True, "auxiliary relations will be introduced to avoid unbound variables in rule heads"), - ('similarity_compressor', BOOL, True, "(DATALOG) rules that differ only in values of constants will be merged into a single rule"), - ('similarity_compressor_threshold', UINT, 11, "(DATALOG) if similarity_compressor is on, this value determines how many similar rules there must be in order for them to be merged"), - ('all_or_nothing_deltas', BOOL, False, "(DATALOG) compile rules so that it is enough for the delta relation in union and widening operations to determine only whether the updated relation was modified or not"), - ('compile_with_widening', BOOL, False, "(DATALOG) widening will be used to compile recursive rules"), - ('eager_emptiness_checking', BOOL, True, "(DATALOG) emptiness of affected relations will be checked after each instruction, so that we may ommit unnecessary instructions"), - ('default_table_checked', BOOL, False, "if true, the detault table will be default_table inside a wrapper that checks that its results are the same as of default_table_checker table"), - ('default_table_checker', SYMBOL, 'null', "see default_table_checked"), - - - ('initial_restart_timeout', UINT, 0, "length of saturation run before the first restart (in ms), zero means no restarts"), - ('output_profile', BOOL, False, "determines whether profile informations should be output when outputting Datalog rules or instructions"), - ('inline_linear', BOOL, True, "try linear inlining method"), - ('inline_eager', BOOL, True, "try eager inlining of rules"), - ('inline_linear_branch', BOOL, False, "try linear inlining method with potential expansion"), - ('fix_unbound_vars', BOOL, False, "fix unbound variables in tail"), - ('output_tuples', BOOL, True, "determines whether tuples for output predicates should be output"), - ('print_with_fixedpoint_extensions', BOOL, True, "use SMT-LIB2 fixedpoint extensions, instead of pure SMT2, when printing rules"), - ('print_low_level_smt2', BOOL, False, "use (faster) low-level SMT2 printer (the printer is scalable but the result may not be as readable)"), - ('print_with_variable_declarations', BOOL, True, "use variable declarations when displaying rules (instead of attempting to use original names)"), - ('bfs_model_search', BOOL, True, "PDR: use BFS strategy for expanding model search"), - ('use_farkas', BOOL, True, "PDR: use lemma generator based on Farkas (for linear real arithmetic)"), - ('generate_proof_trace', BOOL, False, "PDR: trace for 'sat' answer as proof object"), - ('flexible_trace', BOOL, False, "PDR: allow PDR generate long counter-examples " - "by extending candidate trace within search area"), - ('unfold_rules', UINT, 0, "PDR: unfold rules statically using iterative squarring"), - ('use_model_generalizer', BOOL, False, "PDR: use model for backwards propagation (instead of symbolic simulation)"), - ('validate_result', BOOL, False, "PDR validate result (by proof checking or model checking)"), - ('simplify_formulas_pre', BOOL, False, "PDR: simplify derived formulas before inductive propagation"), - ('simplify_formulas_post', BOOL, False, "PDR: simplify derived formulas after inductive propagation"), - ('slice', BOOL, True, "PDR: simplify clause set using slicing"), - ('karr', BOOL, False, "Add linear invariants to clauses using Karr's method"), - ('quantify_arrays', BOOL, False, "create quantified Horn clauses from clauses with arrays"), - ('instantiate_quantifiers', BOOL, False, "instantiate quantified Horn clauses using E-matching heuristic"), - ('coalesce_rules', BOOL, False, "BMC: coalesce rules"), - ('use_multicore_generalizer', BOOL, False, "PDR: extract multiple cores for blocking states"), - ('use_inductive_generalizer', BOOL, True, "PDR: generalize lemmas using induction strengthening"), - ('use_arith_inductive_generalizer', BOOL, False, "PDR: generalize lemmas using arithmetic heuristics for induction strengthening"), - ('use_convex_closure_generalizer', BOOL, False, "PDR: generalize using convex closures of lemmas"), - ('use_convex_interior_generalizer', BOOL, False, "PDR: generalize using convex interiors of lemmas"), - ('cache_mode', UINT, 0, "PDR: use no (0), symbolic (1) or explicit cache (2) for model search"), - ('inductive_reachability_check', BOOL, False, "PDR: assume negation of the cube on the previous level when " - "checking for reachability (not only during cube weakening)"), - ('max_num_contexts', UINT, 500, "PDR: maximal number of contexts to create"), - ('try_minimize_core', BOOL, False, "PDR: try to reduce core size (before inductive minimization)"), - ('profile_timeout_milliseconds', UINT, 0, "instructions and rules that took less than the threshold will not be printed when printed the instruction/rule list"), - ('dbg_fpr_nonempty_relation_signature', BOOL, False, - "if true, finite_product_relation will attempt to avoid creating inner relation with empty signature " - "by putting in half of the table columns, if it would have been empty otherwise"), - ('print_answer', BOOL, False, 'print answer instance(s) to query'), - ('print_certificate', BOOL, False, 'print certificate for reachability or non-reachability'), - ('print_boogie_certificate', BOOL, False, 'print certificate for reachability or non-reachability using a format understood by Boogie'), - ('print_statistics', BOOL, False, 'print statistics'), - ('use_utvpi', BOOL, True, 'PDR: Enable UTVPI strategy'), - ('tab_selection', SYMBOL, 'weight', 'selection method for tabular strategy: weight (default), first, var-use'), - ('full_expand', BOOL, False, 'DUALITY: Fully expand derivation trees'), - ('no_conj', BOOL, False, 'DUALITY: No forced covering (conjectures)'), - ('feasible_edges', BOOL, True, 'DUALITY: Don\'t expand definitley infeasible edges'), - ('use_underapprox', BOOL, False, 'DUALITY: Use underapproximations'), - ('stratified_inlining', BOOL, False, 'DUALITY: Use stratified inlining'), - ('recursion_bound', UINT, UINT_MAX, 'DUALITY: Recursion bound for stratified inlining'), - ('profile', BOOL, False, 'DUALITY: profile run time'), - ('mbqi', BOOL, True, 'DUALITY: use model-based quantifier instantion'), - ('batch_expand', BOOL, False, 'DUALITY: use batch expansion'), - ('dump_aig', SYMBOL, '', 'Dump clauses in AIG text format (AAG) to the given file name'), - ('conjecture_file', STRING, '', 'DUALITY: save conjectures to file'), + ('engine', SYMBOL, 'auto-config', + 'Select: auto-config, datalog, duality, pdr, bmc'), + ('datalog.default_table', SYMBOL, 'sparse', + 'default table implementation: sparse, hashtable, bitvector, interval'), + ('datalog.default_relation', SYMBOL, 'pentagon', + 'default relation implementation: external_relation, pentagon'), + ('datalog.generate_explanations', BOOL, False, + 'produce explanations for produced facts when using the datalog engine'), + ('datalog.use_map_names', BOOL, True, + "use names from map files when displaying tuples"), + ('datalog.magic_sets_for_queries', BOOL, False, + "magic set transformation will be used for queries"), + ('datalog.explanations_on_relation_level', BOOL, False, + 'if true, explanations are generated as history of each relation, ' + + 'rather than per fact (generate_explanations must be set to true for ' + + 'this option to have any effect)'), + ('datalog.unbound_compressor', BOOL, True, + "auxiliary relations will be introduced to avoid unbound variables " + + "in rule heads"), + ('datalog.similarity_compressor', BOOL, True, + "rules that differ only in values of constants will be merged into " + + "a single rule"), + ('datalog.similarity_compressor_threshold', UINT, 11, + "if similarity_compressor is on, this value determines how many " + + "similar rules there must be in order for them to be merged"), + ('datalog.all_or_nothing_deltas', BOOL, False, + "compile rules so that it is enough for the delta relation in " + + "union and widening operations to determine only whether the " + + "updated relation was modified or not"), + ('datalog.compile_with_widening', BOOL, False, + "widening will be used to compile recursive rules"), + ('datalog.eager_emptiness_checking', BOOL, True, + "emptiness of affected relations will be checked after each instruction, " + + "so that we may ommit unnecessary instructions"), + ('datalog.default_table_checked', BOOL, False, "if true, the detault " + + 'table will be default_table inside a wrapper that checks that its results ' + + 'are the same as of default_table_checker table'), + ('datalog.default_table_checker', SYMBOL, 'null', "see default_table_checked"), + ('datalog.initial_restart_timeout', UINT, 0, + "length of saturation run before the first restart (in ms), " + + "zero means no restarts"), + ('datalog.output_profile', BOOL, False, + "determines whether profile information should be " + + "output when outputting Datalog rules or instructions"), + ('datalog.print.tuples', BOOL, True, + "determines whether tuples for output predicates should be output"), + ('datalog.profile_timeout_milliseconds', UINT, 0, + "instructions and rules that took less than the threshold " + + "will not be printed when printed the instruction/rule list"), + ('datalog.dbg_fpr_nonempty_relation_signature', BOOL, False, + "if true, finite_product_relation will attempt to avoid creating " + + "inner relation with empty signature by putting in half of the " + + "table columns, if it would have been empty otherwise"), + ('duality.full_expand', BOOL, False, 'Fully expand derivation trees'), + ('duality.no_conj', BOOL, False, 'No forced covering (conjectures)'), + ('duality.feasible_edges', BOOL, True, + 'Don\'t expand definitley infeasible edges'), + ('duality.use_underapprox', BOOL, False, 'Use underapproximations'), + ('duality.stratified_inlining', BOOL, False, 'Use stratified inlining'), + ('duality.recursion_bound', UINT, UINT_MAX, + 'Recursion bound for stratified inlining'), + ('duality.profile', BOOL, False, 'profile run time'), + ('duality.mbqi', BOOL, True, 'use model-based quantifier instantion'), + ('duality.batch_expand', BOOL, False, 'use batch expansion'), + ('duality.conjecture_file', STRING, '', 'save conjectures to file'), + ('pdr.bfs_model_search', BOOL, True, + "use BFS strategy for expanding model search"), + ('pdr.farkas', BOOL, True, + "use lemma generator based on Farkas (for linear real arithmetic)"), + ('generate_proof_trace', BOOL, False, "trace for 'sat' answer as proof object"), + ('pdr.flexible_trace', BOOL, False, + "allow PDR generate long counter-examples " + + "by extending candidate trace within search area"), + ('pdr.use_model_generalizer', BOOL, False, + "use model for backwards propagation (instead of symbolic simulation)"), + ('pdr.validate_result', BOOL, False, + "validate result (by proof checking or model checking)"), + ('pdr.simplify_formulas_pre', BOOL, False, + "simplify derived formulas before inductive propagation"), + ('pdr.simplify_formulas_post', BOOL, False, + "simplify derived formulas after inductive propagation"), + ('pdr.use_multicore_generalizer', BOOL, False, + "extract multiple cores for blocking states"), + ('pdr.use_inductive_generalizer', BOOL, True, + "generalize lemmas using induction strengthening"), + ('pdr.use_arith_inductive_generalizer', BOOL, False, + "generalize lemmas using arithmetic heuristics for induction strengthening"), + ('pdr.use_convex_closure_generalizer', BOOL, False, + "generalize using convex closures of lemmas"), + ('pdr.use_convex_interior_generalizer', BOOL, False, + "generalize using convex interiors of lemmas"), + ('pdr.cache_mode', UINT, 0, "use no (0), symbolic (1) or explicit " + + "cache (2) for model search"), + ('pdr.inductive_reachability_check', BOOL, False, + "assume negation of the cube on the previous level when " + + "checking for reachability (not only during cube weakening)"), + ('pdr.max_num_contexts', UINT, 500, "maximal number of contexts to create"), + ('pdr.try_minimize_core', BOOL, False, + "try to reduce core size (before inductive minimization)"), + ('pdr.utvpi', BOOL, True, 'Enable UTVPI strategy'), + ('print.fixedpoint_extensions', BOOL, True, + "use SMT-LIB2 fixedpoint extensions, instead of pure SMT2, " + + "when printing rules"), + ('print.low_level_smt2', BOOL, False, + "use (faster) low-level SMT2 printer (the printer is scalable " + + "but the result may not be as readable)"), + ('print.with_variable_declarations', BOOL, True, + "use variable declarations when displaying rules " + + "(instead of attempting to use original names)"), + ('print.answer', BOOL, False, 'print answer instance(s) to query'), + ('print.certificate', BOOL, False, + 'print certificate for reachability or non-reachability'), + ('print.boogie_certificate', BOOL, False, + 'print certificate for reachability or non-reachability using a ' + + 'format understood by Boogie'), + ('print.statistics', BOOL, False, 'print statistics'), + ('print.aig', SYMBOL, '', + 'Dump clauses in AIG text format (AAG) to the given file name'), + ('tab.selection', SYMBOL, 'weight', + 'selection method for tabular strategy: weight (default), first, var-use'), + ('xform.bit_blast', BOOL, False, + 'bit-blast bit-vectors'), + ('xform.magic', BOOL, False, + "perform symbolic magic set transformation"), + ('xform.scale', BOOL, False, + "add scaling variable to linear real arithemtic clauses"), + ('xform.inline_linear', BOOL, True, "try linear inlining method"), + ('xform.inline_eager', BOOL, True, "try eager inlining of rules"), + ('xform.inline_linear_branch', BOOL, False, + "try linear inlining method with potential expansion"), + ('xform.fix_unbound_vars', BOOL, False, "fix unbound variables in tail"), + ('xform.unfold_rules', UINT, 0, + "unfold rules statically using iterative squarring"), + ('xform.slice', BOOL, True, "simplify clause set using slicing"), + ('xform.karr', BOOL, False, + "Add linear invariants to clauses using Karr's method"), + ('xform.quantify_arrays', BOOL, False, + "create quantified Horn clauses from clauses with arrays"), + ('xform.instantiate_quantifiers', BOOL, False, + "instantiate quantified Horn clauses using E-matching heuristic"), + ('xform.coalesce_rules', BOOL, False, "coalesce rules"), )) diff --git a/src/muz/bmc/dl_bmc_engine.cpp b/src/muz/bmc/dl_bmc_engine.cpp index 51b1a5295..2ad5b3b94 100644 --- a/src/muz/bmc/dl_bmc_engine.cpp +++ b/src/muz/bmc/dl_bmc_engine.cpp @@ -1442,7 +1442,7 @@ namespace datalog { expr_ref bg_assertion = m_ctx.get_background_assertion(); apply_default_transformation(m_ctx); - if (m_ctx.get_params().slice()) { + if (m_ctx.get_params().xform_slice()) { datalog::rule_transformer transformer(m_ctx); datalog::mk_slice* slice = alloc(datalog::mk_slice, m_ctx); transformer.register_plugin(slice); diff --git a/src/muz/duality/duality_dl_interface.cpp b/src/muz/duality/duality_dl_interface.cpp index 0584e6b58..3f035b453 100755 --- a/src/muz/duality/duality_dl_interface.cpp +++ b/src/muz/duality/duality_dl_interface.cpp @@ -146,7 +146,7 @@ lbool dl_interface::query(::expr * query) { // make a new problem and solver _d = alloc(duality_data,m_ctx.get_manager()); - _d->ctx.set("mbqi",m_ctx.get_params().mbqi()); + _d->ctx.set("mbqi",m_ctx.get_params().duality_mbqi()); _d->ls = alloc(RPFP::iZ3LogicSolver,_d->ctx); _d->rpfp = alloc(RPFP,_d->ls); @@ -223,14 +223,14 @@ lbool dl_interface::query(::expr * query) { // set its options IF_VERBOSE(1, rs->SetOption("report","1");); - rs->SetOption("full_expand",m_ctx.get_params().full_expand() ? "1" : "0"); - rs->SetOption("no_conj",m_ctx.get_params().no_conj() ? "1" : "0"); - rs->SetOption("feasible_edges",m_ctx.get_params().feasible_edges() ? "1" : "0"); - rs->SetOption("use_underapprox",m_ctx.get_params().use_underapprox() ? "1" : "0"); - rs->SetOption("stratified_inlining",m_ctx.get_params().stratified_inlining() ? "1" : "0"); - rs->SetOption("batch_expand",m_ctx.get_params().batch_expand() ? "1" : "0"); - rs->SetOption("conjecture_file",m_ctx.get_params().conjecture_file()); - unsigned rb = m_ctx.get_params().recursion_bound(); + rs->SetOption("full_expand",m_ctx.get_params().duality_full_expand() ? "1" : "0"); + rs->SetOption("no_conj",m_ctx.get_params().duality_no_conj() ? "1" : "0"); + rs->SetOption("feasible_edges",m_ctx.get_params().duality_feasible_edges() ? "1" : "0"); + rs->SetOption("use_underapprox",m_ctx.get_params().duality_use_underapprox() ? "1" : "0"); + rs->SetOption("stratified_inlining",m_ctx.get_params().duality_stratified_inlining() ? "1" : "0"); + rs->SetOption("batch_expand",m_ctx.get_params().duality_batch_expand() ? "1" : "0"); + rs->SetOption("conjecture_file",m_ctx.get_params().duality_conjecture_file()); + unsigned rb = m_ctx.get_params().duality_recursion_bound(); if(rb != UINT_MAX){ std::ostringstream os; os << rb; rs->SetOption("recursion_bound", os.str()); @@ -250,7 +250,7 @@ lbool dl_interface::query(::expr * query) { // profile! - if(m_ctx.get_params().profile()) + if(m_ctx.get_params().duality_profile()) print_profile(std::cout); // save the result and counterexample if there is one diff --git a/src/muz/fp/horn_tactic.cpp b/src/muz/fp/horn_tactic.cpp index 0c094c277..1e7a6e617 100644 --- a/src/muz/fp/horn_tactic.cpp +++ b/src/muz/fp/horn_tactic.cpp @@ -316,7 +316,7 @@ class horn_tactic : public tactic { m_ctx.get_rules(); // flush adding rules. apply_default_transformation(m_ctx); - if (m_ctx.get_params().slice()) { + if (m_ctx.get_params().xform_slice()) { datalog::rule_transformer transformer(m_ctx); datalog::mk_slice* slice = alloc(datalog::mk_slice, m_ctx); transformer.register_plugin(slice); diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index e55806243..2ddfd1c01 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -81,7 +81,7 @@ namespace pdr { ctx(ctx), m_head(head, m), m_sig(m), m_solver(pm, ctx.get_params(), head->get_name()), m_invariants(m), m_transition(m), m_initial_state(m), - m_reachable(pm, (datalog::PDR_CACHE_MODE)ctx.get_params().cache_mode()) {} + m_reachable(pm, (datalog::PDR_CACHE_MODE)ctx.get_params().pdr_cache_mode()) {} pred_transformer::~pred_transformer() { rule2inst::iterator it2 = m_rule2inst.begin(), end2 = m_rule2inst.end(); @@ -738,6 +738,11 @@ namespace pdr { m_closed = true; } + void model_node::reopen() { + SASSERT(m_closed); + m_closed = false; + } + static bool is_ini(datalog::rule const& r) { return r.get_uninterpreted_tail_size() == 0; } @@ -747,6 +752,7 @@ namespace pdr { return const_cast(m_rule); } // only initial states are not set by the PDR search. + SASSERT(m_model.get()); datalog::rule const& rl1 = pt().find_rule(*m_model); if (is_ini(rl1)) { set_rule(&rl1); @@ -866,9 +872,10 @@ namespace pdr { } void model_search::add_leaf(model_node& n) { - unsigned& count = cache(n).insert_if_not_there2(n.state(), 0)->get_data().m_value; - ++count; - if (count == 1 || is_repeated(n)) { + model_nodes ns; + model_nodes& nodes = cache(n).insert_if_not_there2(n.state(), ns)->get_data().m_value; + nodes.push_back(&n); + if (nodes.size() == 1 || is_repeated(n)) { set_leaf(n); } else { @@ -877,7 +884,7 @@ namespace pdr { } void model_search::set_leaf(model_node& n) { - erase_children(n); + erase_children(n, true); SASSERT(n.is_open()); enqueue_leaf(n); } @@ -899,7 +906,7 @@ namespace pdr { set_leaf(*root); } - obj_map& model_search::cache(model_node const& n) { + obj_map >& model_search::cache(model_node const& n) { unsigned l = n.orig_level(); if (l >= m_cache.size()) { m_cache.resize(l + 1); @@ -907,7 +914,7 @@ namespace pdr { return m_cache[l]; } - void model_search::erase_children(model_node& n) { + void model_search::erase_children(model_node& n, bool backtrack) { ptr_vector todo, nodes; todo.append(n.children()); erase_leaf(n); @@ -918,13 +925,20 @@ namespace pdr { nodes.push_back(m); todo.append(m->children()); erase_leaf(*m); - remove_node(*m); + remove_node(*m, backtrack); } std::for_each(nodes.begin(), nodes.end(), delete_proc()); } - void model_search::remove_node(model_node& n) { - if (0 == --cache(n).find(n.state())) { + void model_search::remove_node(model_node& n, bool backtrack) { + model_nodes& nodes = cache(n).find(n.state()); + nodes.erase(&n); + if (nodes.size() > 0 && n.is_open() && backtrack) { + for (unsigned i = 0; i < nodes.size(); ++i) { + nodes[i]->reopen(); + } + } + if (nodes.empty()) { cache(n).remove(n.state()); } } @@ -971,6 +985,9 @@ namespace pdr { if (n->get_model_ptr()) { models.insert(n->state(), n->get_model_ptr()); rules.insert(n->state(), n->get_rule()); + pred_transformer& pt = n->pt(); + context& ctx = pt.get_context(); + datalog::context& dctx = ctx.get_context(); } todo.pop_back(); todo.append(n->children().size(), n->children().c_ptr()); @@ -981,12 +998,18 @@ namespace pdr { model_node* n = todo.back(); model* md = 0; ast_manager& m = n->pt().get_manager(); - if (!n->get_model_ptr() && models.find(n->state(), md)) { - TRACE("pdr", tout << mk_pp(n->state(), m) << "\n";); - model_ref mr(md); - n->set_model(mr); - datalog::rule const* rule = rules.find(n->state()); - n->set_rule(rule); + if (!n->get_model_ptr()) { + if (models.find(n->state(), md)) { + TRACE("pdr", tout << mk_pp(n->state(), m) << "\n";); + model_ref mr(md); + n->set_model(mr); + datalog::rule const* rule = rules.find(n->state()); + n->set_rule(rule); + } + else { + IF_VERBOSE(1, n->display(verbose_stream() << "no model:\n", 0); + verbose_stream() << mk_pp(n->state(), m) << "\n";); + } } todo.pop_back(); todo.append(n->children().size(), n->children().c_ptr()); @@ -1205,8 +1228,8 @@ namespace pdr { void model_search::reset() { if (m_root) { - erase_children(*m_root); - remove_node(*m_root); + erase_children(*m_root, false); + remove_node(*m_root, false); dealloc(m_root); m_root = 0; } @@ -1239,10 +1262,10 @@ namespace pdr { m_params(params), m(m), m_context(0), - m_pm(m_fparams, params.max_num_contexts(), m), + m_pm(m_fparams, params.pdr_max_num_contexts(), m), m_query_pred(m), m_query(0), - m_search(m_params.bfs_model_search()), + m_search(m_params.pdr_bfs_model_search(), m), m_last_result(l_undef), m_inductive_lvl(0), m_expanded_lvl(0), @@ -1470,93 +1493,108 @@ namespace pdr { } } }; - - void context::validate() { - if (!m_params.validate_result()) { - return; - } + + void context::validate_proof() { std::stringstream msg; - - switch(m_last_result) { - case l_true: { - proof_ref pr = get_proof(); - proof_checker checker(m); - expr_ref_vector side_conditions(m); - bool ok = checker.check(pr, side_conditions); - if (!ok) { - msg << "proof validation failed"; + proof_ref pr = get_proof(); + proof_checker checker(m); + expr_ref_vector side_conditions(m); + bool ok = checker.check(pr, side_conditions); + if (!ok) { + msg << "proof validation failed"; + IF_VERBOSE(0, verbose_stream() << msg.str() << "\n";); + throw default_exception(msg.str()); + } + for (unsigned i = 0; i < side_conditions.size(); ++i) { + expr* cond = side_conditions[i].get(); + expr_ref tmp(m); + + tmp = m.mk_not(cond); + IF_VERBOSE(2, verbose_stream() << "checking side-condition:\n" << mk_pp(cond, m) << "\n";); + smt::kernel solver(m, get_fparams()); + solver.assert_expr(tmp); + lbool res = solver.check(); + if (res != l_false) { + msg << "rule validation failed when checking: " << mk_pp(cond, m); IF_VERBOSE(0, verbose_stream() << msg.str() << "\n";); throw default_exception(msg.str()); - } - for (unsigned i = 0; i < side_conditions.size(); ++i) { - expr* cond = side_conditions[i].get(); - expr_ref tmp(m); - tmp = m.mk_not(cond); - IF_VERBOSE(2, verbose_stream() << "checking side-condition:\n" << mk_pp(cond, m) << "\n";); + } + } + } + + void context::validate_search() { + expr_ref tr = m_search.get_trace(*this); + // TBD: tr << "\n"; + } + + void context::validate_model() { + std::stringstream msg; + expr_ref_vector refs(m); + expr_ref tmp(m); + model_ref model; + vector rs; + model_converter_ref mc; + get_level_property(m_inductive_lvl, refs, rs); + inductive_property ex(m, mc, rs); + ex.to_model(model); + decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); + var_subst vs(m, false); + for (; it != end; ++it) { + ptr_vector const& rules = it->m_value->rules(); + for (unsigned i = 0; i < rules.size(); ++i) { + datalog::rule& r = *rules[i]; + model->eval(r.get_head(), tmp); + expr_ref_vector fmls(m); + fmls.push_back(m.mk_not(tmp)); + unsigned utsz = r.get_uninterpreted_tail_size(); + unsigned tsz = r.get_tail_size(); + for (unsigned j = 0; j < utsz; ++j) { + model->eval(r.get_tail(j), tmp); + fmls.push_back(tmp); + } + for (unsigned j = utsz; j < tsz; ++j) { + fmls.push_back(r.get_tail(j)); + } + tmp = m.mk_and(fmls.size(), fmls.c_ptr()); + ptr_vector sorts; + svector names; + get_free_vars(tmp, sorts); + for (unsigned i = 0; i < sorts.size(); ++i) { + if (!sorts[i]) { + sorts[i] = m.mk_bool_sort(); + } + names.push_back(symbol(i)); + } + sorts.reverse(); + if (!sorts.empty()) { + tmp = m.mk_exists(sorts.size(), sorts.c_ptr(), names.c_ptr(), tmp); + } smt::kernel solver(m, get_fparams()); solver.assert_expr(tmp); lbool res = solver.check(); if (res != l_false) { - msg << "rule validation failed when checking: " << mk_pp(cond, m); + msg << "rule validation failed when checking: " << mk_pp(tmp, m); IF_VERBOSE(0, verbose_stream() << msg.str() << "\n";); throw default_exception(msg.str()); - } - } - break; - } - case l_false: { - expr_ref_vector refs(m); - expr_ref tmp(m); - model_ref model; - vector rs; - model_converter_ref mc; - get_level_property(m_inductive_lvl, refs, rs); - inductive_property ex(m, mc, rs); - ex.to_model(model); - decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); - var_subst vs(m, false); - for (; it != end; ++it) { - ptr_vector const& rules = it->m_value->rules(); - for (unsigned i = 0; i < rules.size(); ++i) { - datalog::rule& r = *rules[i]; - model->eval(r.get_head(), tmp); - expr_ref_vector fmls(m); - fmls.push_back(m.mk_not(tmp)); - unsigned utsz = r.get_uninterpreted_tail_size(); - unsigned tsz = r.get_tail_size(); - for (unsigned j = 0; j < utsz; ++j) { - model->eval(r.get_tail(j), tmp); - fmls.push_back(tmp); - } - for (unsigned j = utsz; j < tsz; ++j) { - fmls.push_back(r.get_tail(j)); - } - tmp = m.mk_and(fmls.size(), fmls.c_ptr()); - ptr_vector sorts; - svector names; - get_free_vars(tmp, sorts); - for (unsigned i = 0; i < sorts.size(); ++i) { - if (!sorts[i]) { - sorts[i] = m.mk_bool_sort(); - } - names.push_back(symbol(i)); - } - sorts.reverse(); - if (!sorts.empty()) { - tmp = m.mk_exists(sorts.size(), sorts.c_ptr(), names.c_ptr(), tmp); - } - smt::kernel solver(m, get_fparams()); - solver.assert_expr(tmp); - lbool res = solver.check(); - if (res != l_false) { - msg << "rule validation failed when checking: " << mk_pp(tmp, m); - IF_VERBOSE(0, verbose_stream() << msg.str() << "\n";); - throw default_exception(msg.str()); - } } } - break; } + } + + void context::validate() { + if (!m_params.pdr_validate_result()) { + return; + } + switch(m_last_result) { + case l_true: + if (m_params.generate_proof_trace()) { + validate_proof(); + } + validate_search(); + break; + case l_false: + validate_model(); + break; default: break; } @@ -1570,7 +1608,7 @@ namespace pdr { void context::init_core_generalizers(datalog::rule_set& rules) { reset_core_generalizers(); classifier_proc classify(m, rules); - bool use_mc = m_params.use_multicore_generalizer(); + bool use_mc = m_params.pdr_use_multicore_generalizer(); if (use_mc) { m_core_generalizers.push_back(alloc(core_multi_generalizer, *this, 0)); } @@ -1580,9 +1618,9 @@ namespace pdr { m_fparams.m_arith_auto_config_simplex = true; m_fparams.m_arith_propagate_eqs = false; m_fparams.m_arith_eager_eq_axioms = false; - if (m_params.use_utvpi() && - !m_params.use_convex_closure_generalizer() && - !m_params.use_convex_interior_generalizer()) { + if (m_params.pdr_utvpi() && + !m_params.pdr_use_convex_closure_generalizer() && + !m_params.pdr_use_convex_interior_generalizer()) { if (classify.is_dl()) { m_fparams.m_arith_mode = AS_DIFF_LOGIC; m_fparams.m_arith_expand_eqs = true; @@ -1594,19 +1632,19 @@ namespace pdr { } } } - if (m_params.use_convex_closure_generalizer()) { + if (m_params.pdr_use_convex_closure_generalizer()) { m_core_generalizers.push_back(alloc(core_convex_hull_generalizer, *this, true)); } - if (m_params.use_convex_interior_generalizer()) { + if (m_params.pdr_use_convex_interior_generalizer()) { m_core_generalizers.push_back(alloc(core_convex_hull_generalizer, *this, false)); } - if (!use_mc && m_params.use_inductive_generalizer()) { + if (!use_mc && m_params.pdr_use_inductive_generalizer()) { m_core_generalizers.push_back(alloc(core_bool_inductive_generalizer, *this, 0)); } - if (m_params.inductive_reachability_check()) { + if (m_params.pdr_inductive_reachability_check()) { m_core_generalizers.push_back(alloc(core_induction_generalizer, *this)); } - if (m_params.use_arith_inductive_generalizer()) { + if (m_params.pdr_use_arith_inductive_generalizer()) { m_core_generalizers.push_back(alloc(core_arith_inductive_generalizer, *this)); } @@ -1824,7 +1862,7 @@ namespace pdr { m_expanded_lvl = n.level(); } - pred_transformer::scoped_farkas sf (n.pt(), m_params.use_farkas()); + pred_transformer::scoped_farkas sf (n.pt(), m_params.pdr_farkas()); if (n.pt().is_reachable(n.state())) { TRACE("pdr", tout << "reachable\n";); close_node(n); @@ -1865,7 +1903,7 @@ namespace pdr { n.pt().add_property(ncore, uses_level?n.level():infty_level); } CASSERT("pdr",n.level() == 0 || check_invariant(n.level()-1)); - m_search.backtrack_level(!found_invariant && m_params.flexible_trace(), n); + m_search.backtrack_level(!found_invariant && m_params.pdr_flexible_trace(), n); break; } case l_undef: { @@ -1892,7 +1930,7 @@ namespace pdr { } void context::propagate(unsigned max_prop_lvl) { - if (m_params.simplify_formulas_pre()) { + if (m_params.pdr_simplify_formulas_pre()) { simplify_formulas(); } for (unsigned lvl = m_expanded_lvl; lvl <= max_prop_lvl; lvl++) { @@ -1911,7 +1949,7 @@ namespace pdr { throw inductive_exception(); } } - if (m_params.simplify_formulas_post()) { + if (m_params.pdr_simplify_formulas_post()) { simplify_formulas(); } } @@ -1959,16 +1997,18 @@ namespace pdr { */ void context::create_children(model_node& n) { SASSERT(n.level() > 0); - bool use_model_generalizer = m_params.use_model_generalizer(); + bool use_model_generalizer = m_params.pdr_use_model_generalizer(); scoped_no_proof _sc(m); pred_transformer& pt = n.pt(); model_ref M = n.get_model_ptr(); + SASSERT(M.get()); datalog::rule const& r = pt.find_rule(*M); expr* T = pt.get_transition(r); expr* phi = n.state(); n.set_rule(&r); + TRACE("pdr", tout << "Model:\n"; diff --git a/src/muz/pdr/pdr_context.h b/src/muz/pdr/pdr_context.h index 8a4f3e438..63adfa1f6 100644 --- a/src/muz/pdr/pdr_context.h +++ b/src/muz/pdr/pdr_context.h @@ -124,6 +124,7 @@ namespace pdr { unsigned get_num_levels() { return m_levels.size(); } expr_ref get_cover_delta(func_decl* p_orig, int level); void add_cover(unsigned level, expr* property); + context& get_context() { return ctx; } std::ostream& display(std::ostream& strm) const; @@ -231,6 +232,7 @@ namespace pdr { } void set_closed(); + void reopen(); void set_pre_closed() { m_closed = true; } void reset() { m_children.reset(); } @@ -243,19 +245,21 @@ namespace pdr { }; class model_search { + typedef ptr_vector model_nodes; + ast_manager& m; bool m_bfs; model_node* m_root; std::deque m_leaves; - vector > m_cache; - - obj_map& cache(model_node const& n); - void erase_children(model_node& n); + vector > m_cache; + + obj_map& cache(model_node const& n); + void erase_children(model_node& n, bool backtrack); void erase_leaf(model_node& n); - void remove_node(model_node& n); + void remove_node(model_node& n, bool backtrack); void enqueue_leaf(model_node& n); // add leaf to priority queue. void update_models(); public: - model_search(bool bfs): m_bfs(bfs), m_root(0) {} + model_search(bool bfs, ast_manager& m): m(m), m_bfs(bfs), m_root(0) {} ~model_search(); void reset(); @@ -267,7 +271,7 @@ namespace pdr { void set_root(model_node* n); model_node& get_root() const { return *m_root; } std::ostream& display(std::ostream& out) const; - expr_ref get_trace(context const& ctx); + expr_ref get_trace(context const& ctx); proof_ref get_proof_trace(context const& ctx); void backtrack_level(bool uses_level, model_node& n); }; @@ -355,6 +359,9 @@ namespace pdr { void reset_core_generalizers(); void validate(); + void validate_proof(); + void validate_search(); + void validate_model(); public: diff --git a/src/muz/pdr/pdr_dl_interface.cpp b/src/muz/pdr/pdr_dl_interface.cpp index 45872fe99..b75be70c1 100644 --- a/src/muz/pdr/pdr_dl_interface.cpp +++ b/src/muz/pdr/pdr_dl_interface.cpp @@ -105,7 +105,7 @@ lbool dl_interface::query(expr * query) { apply_default_transformation(m_ctx); - if (m_ctx.get_params().slice()) { + if (m_ctx.get_params().xform_slice()) { datalog::rule_transformer transformer(m_ctx); datalog::mk_slice* slice = alloc(datalog::mk_slice, m_ctx); transformer.register_plugin(slice); @@ -122,12 +122,12 @@ lbool dl_interface::query(expr * query) { } } - if (m_ctx.get_params().unfold_rules() > 0) { - unsigned num_unfolds = m_ctx.get_params().unfold_rules(); + if (m_ctx.get_params().xform_unfold_rules() > 0) { + unsigned num_unfolds = m_ctx.get_params().xform_unfold_rules(); datalog::rule_transformer transf1(m_ctx), transf2(m_ctx); transf1.register_plugin(alloc(datalog::mk_coalesce, m_ctx)); transf2.register_plugin(alloc(datalog::mk_unfold, m_ctx)); - if (m_ctx.get_params().coalesce_rules()) { + if (m_ctx.get_params().xform_coalesce_rules()) { m_ctx.transform_rules(transf1); } while (num_unfolds > 0) { @@ -176,7 +176,7 @@ expr_ref dl_interface::get_cover_delta(int level, func_decl* pred_orig) { } void dl_interface::add_cover(int level, func_decl* pred, expr* property) { - if (m_ctx.get_params().slice()) { + if (m_ctx.get_params().xform_slice()) { throw default_exception("Covers are incompatible with slicing. Disable slicing before using covers"); } m_context->add_cover(level, pred, property); diff --git a/src/muz/pdr/pdr_prop_solver.cpp b/src/muz/pdr/pdr_prop_solver.cpp index 8fe8c0e0e..06f858608 100644 --- a/src/muz/pdr/pdr_prop_solver.cpp +++ b/src/muz/pdr/pdr_prop_solver.cpp @@ -231,7 +231,7 @@ namespace pdr { m(pm.get_manager()), m_pm(pm), m_name(name), - m_try_minimize_core(p.try_minimize_core()), + m_try_minimize_core(p.pdr_try_minimize_core()), m_ctx(pm.mk_fresh()), m_pos_level_atoms(m), m_neg_level_atoms(m), diff --git a/src/muz/rel/rel_context.cpp b/src/muz/rel/rel_context.cpp index 3b5e07c41..1a3d2cdae 100644 --- a/src/muz/rel/rel_context.cpp +++ b/src/muz/rel/rel_context.cpp @@ -150,8 +150,8 @@ namespace datalog { } TRACE("dl", m_context.display(tout);); - if (m_context.get_params().dump_aig().size()) { - const char *filename = static_cast(m_context.get_params().dump_aig().c_ptr()); + if (m_context.get_params().print_aig().size()) { + const char *filename = static_cast(m_context.get_params().print_aig().c_ptr()); aig_exporter aig(m_context.get_rules(), get_context(), &m_table_facts); std::ofstream strm(filename, std::ios_base::binary); aig(strm); @@ -284,7 +284,7 @@ namespace datalog { transf.register_plugin(alloc(mk_interp_tail_simplifier, m_context)); transf.register_plugin(alloc(mk_separate_negated_tails, m_context)); - if (m_context.get_params().bit_blast()) { + if (m_context.get_params().xform_bit_blast()) { transf.register_plugin(alloc(mk_bit_blast, m_context, 22000)); transf.register_plugin(alloc(mk_interp_tail_simplifier, m_context, 21000)); } @@ -518,7 +518,7 @@ namespace datalog { void rel_context::add_fact(func_decl* pred, relation_fact const& fact) { get_rmanager().reset_saturated_marks(); get_relation(pred).add_fact(fact); - if (m_context.get_params().dump_aig().size()) { + if (m_context.get_params().print_aig().size()) { m_table_facts.push_back(std::make_pair(pred, fact)); } } diff --git a/src/muz/transforms/dl_mk_rule_inliner.cpp b/src/muz/transforms/dl_mk_rule_inliner.cpp index 522bd2e86..366547575 100644 --- a/src/muz/transforms/dl_mk_rule_inliner.cpp +++ b/src/muz/transforms/dl_mk_rule_inliner.cpp @@ -754,7 +754,7 @@ namespace datalog { valid.reset(); valid.resize(sz, true); - bool allow_branching = m_context.get_params().inline_linear_branch(); + bool allow_branching = m_context.get_params().xform_inline_linear_branch(); for (unsigned i = 0; i < sz; ++i) { @@ -866,7 +866,7 @@ namespace datalog { scoped_ptr res = alloc(rule_set, m_context); - if (m_context.get_params().inline_eager()) { + if (m_context.get_params().xform_inline_eager()) { TRACE("dl", source.display(tout << "before eager inlining\n");); plan_inlining(source); something_done = transform_rules(source, *res); @@ -884,7 +884,7 @@ namespace datalog { res = alloc(rule_set, source); } - if (m_context.get_params().inline_linear() && inline_linear(res)) { + if (m_context.get_params().xform_inline_linear() && inline_linear(res)) { something_done = true; } diff --git a/src/muz/transforms/dl_transforms.cpp b/src/muz/transforms/dl_transforms.cpp index 80634c676..9cdc1ab01 100644 --- a/src/muz/transforms/dl_transforms.cpp +++ b/src/muz/transforms/dl_transforms.cpp @@ -44,12 +44,12 @@ namespace datalog { transf.register_plugin(alloc(datalog::mk_coi_filter, ctx)); transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, ctx)); - if (ctx.get_params().quantify_arrays()) { + if (ctx.get_params().xform_quantify_arrays()) { transf.register_plugin(alloc(datalog::mk_quantifier_abstraction, ctx, 38000)); } transf.register_plugin(alloc(datalog::mk_quantifier_instantiation, ctx, 37000)); transf.register_plugin(alloc(datalog::mk_scale, ctx, 36030)); - if (ctx.get_params().magic()) { + if (ctx.get_params().xform_magic()) { transf.register_plugin(alloc(datalog::mk_magic_symbolic, ctx, 36020)); } transf.register_plugin(alloc(datalog::mk_karr_invariants, ctx, 36010)); From 1c56d6ee95608f05106d66e21f6f6492067a5d48 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Aug 2014 01:17:26 -0700 Subject: [PATCH 469/925] align lengths of weights and soft constraints Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 12 ++++++++++-- src/opt/maxsls.cpp | 2 +- src/opt/maxsmt.cpp | 4 ++-- src/opt/maxsmt.h | 2 +- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 8a4f07b18..a8b21436e 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -179,7 +179,7 @@ public: lbool mus_mss_solver() { init(); init_local(); - enable_sls(m_asms); + sls(); ptr_vector mcs; vector > cores; while (m_lower < m_upper) { @@ -221,7 +221,7 @@ public: lbool mss_solver() { init(); init_local(); - enable_sls(m_asms); + sls(); set_mus(false); ptr_vector mcs; lbool is_sat = l_true; @@ -383,6 +383,14 @@ public: return m_asm2weight.find(e); } + void sls() { + vector ws; + for (unsigned i = 0; i < m_asms.size(); ++i) { + ws.push_back(get_weight(m_asms[i].get())); + } + enable_sls(m_asms, ws); + } + rational split_core(ptr_vector const& core) { // find the minimal weight: diff --git a/src/opt/maxsls.cpp b/src/opt/maxsls.cpp index be8e99c3a..6145d1e71 100644 --- a/src/opt/maxsls.cpp +++ b/src/opt/maxsls.cpp @@ -33,7 +33,7 @@ namespace opt { lbool operator()() { IF_VERBOSE(1, verbose_stream() << "(opt.sls)\n";); init(); - enable_sls(m_soft); + enable_sls(m_soft, m_weights); lbool is_sat = s().check_sat(0, 0); if (is_sat == l_true) { s().get_model(m_model); diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 44f898443..d084dc5b5 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -94,8 +94,8 @@ namespace opt { m_s.updt_params(p); } - void maxsmt_solver_base::enable_sls(expr_ref_vector const& soft) { - m_c.enable_sls(soft, m_weights); + void maxsmt_solver_base::enable_sls(expr_ref_vector const& soft, vector const& ws) { + m_c.enable_sls(soft, ws); } app* maxsmt_solver_base::mk_fresh_bool(char const* name) { diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index ee275e7f6..54b2110b3 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -81,7 +81,7 @@ namespace opt { void set_mus(bool f); app* mk_fresh_bool(char const* name); protected: - void enable_sls(expr_ref_vector const& soft); + void enable_sls(expr_ref_vector const& soft, vector const& ws); }; /** From a47f3df70349c93bf0d415d30576b3d5f0225bd8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Aug 2014 23:43:51 -0700 Subject: [PATCH 470/925] fix bug in unsat core extraction in sat solver Signed-off-by: Nikolaj Bjorner --- src/opt/bcd2.cpp | 9 ++++----- src/opt/bcd2.h | 2 +- src/opt/maxhs.cpp | 6 +++--- src/opt/maxres.cpp | 14 +++++++------- src/opt/maxres.h | 12 +++--------- src/opt/maxsls.cpp | 6 +++--- src/opt/maxsls.h | 3 +-- src/opt/maxsmt.h | 10 ++++++---- src/opt/opt_context.h | 3 ++- src/opt/pbmax.cpp | 7 +++---- src/opt/pbmax.h | 3 +-- src/opt/wmax.cpp | 2 ++ src/sat/sat_solver.cpp | 44 ++++++++++++++++++++++++++++++------------ src/sat/sat_solver.h | 2 ++ 14 files changed, 70 insertions(+), 53 deletions(-) diff --git a/src/opt/bcd2.cpp b/src/opt/bcd2.cpp index 7e5ac38f8..5d5fa2f7c 100644 --- a/src/opt/bcd2.cpp +++ b/src/opt/bcd2.cpp @@ -57,7 +57,7 @@ namespace opt { es.push_back(m.mk_not(*it)); } } - void bcd2_init_soft(vector const& weights, expr_ref_vector const& soft) { + void bcd2_init_soft(weights_t& weights, expr_ref_vector const& soft) { // normalize weights to be integral: m_den = rational::one(); @@ -100,7 +100,7 @@ namespace opt { public: bcd2(context& c, - vector const& ws, expr_ref_vector const& soft): + weights_t& ws, expr_ref_vector const& soft): maxsmt_solver_base(c, ws, soft), pb(m), m_soft_aux(m), @@ -116,7 +116,6 @@ namespace opt { expr_ref fml(m), r(m); lbool is_sat = l_undef; expr_ref_vector asms(m); - solver::scoped_push _scope1(s()); init(); init_bcd(); if (m_cancel) { @@ -399,8 +398,8 @@ namespace opt { } }; - maxsmt_solver_base* opt::mk_bcd2(context& c, - vector const& ws, expr_ref_vector const& soft) { + maxsmt_solver_base* opt::mk_bcd2( + context& c, weights_t& ws, expr_ref_vector const& soft) { return alloc(bcd2, c, ws, soft); } diff --git a/src/opt/bcd2.h b/src/opt/bcd2.h index 6528c2807..79d528e20 100644 --- a/src/opt/bcd2.h +++ b/src/opt/bcd2.h @@ -23,6 +23,6 @@ Notes: #include "maxsmt.h" namespace opt { - maxsmt_solver_base* mk_bcd2(context& c, vector const& ws, expr_ref_vector const& soft); + maxsmt_solver_base* mk_bcd2(context& c, weights_t& ws, expr_ref_vector const& soft); } #endif diff --git a/src/opt/maxhs.cpp b/src/opt/maxhs.cpp index 76645ee7e..fd585065b 100644 --- a/src/opt/maxhs.cpp +++ b/src/opt/maxhs.cpp @@ -75,7 +75,7 @@ namespace opt { public: - maxhs(context& c, vector const& ws, expr_ref_vector const& soft): + maxhs(context& c, weights_t& ws, expr_ref_vector const& soft): maxsmt_solver_base(c, ws, soft), m_aux(m), m_at_lower_bound(false) { @@ -554,8 +554,8 @@ namespace opt { }; - maxsmt_solver_base* opt::mk_maxhs(context& c, - vector const& ws, expr_ref_vector const& soft) { + maxsmt_solver_base* opt::mk_maxhs( + context& c, weights_t& ws, expr_ref_vector const& soft) { return alloc(maxhs, c, ws, soft); } diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index a8b21436e..231c72578 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -85,7 +85,7 @@ private: public: maxres(context& c, - vector const& ws, expr_ref_vector const& soft, + weights_t& ws, expr_ref_vector const& soft, strategy_t st): maxsmt_solver_base(c, ws, soft), m_B(m), m_asms(m), @@ -658,18 +658,18 @@ public: }; -opt::maxsmt_solver_base* opt::mk_maxres(context& c, - vector const& ws, expr_ref_vector const& soft) { +opt::maxsmt_solver_base* opt::mk_maxres( + context& c, weights_t& ws, expr_ref_vector const& soft) { return alloc(maxres, c, ws, soft, maxres::s_mus); } -opt::maxsmt_solver_base* opt::mk_mus_mss_maxres(context& c, - vector const& ws, expr_ref_vector const& soft) { +opt::maxsmt_solver_base* opt::mk_mus_mss_maxres( + context& c, weights_t& ws, expr_ref_vector const& soft) { return alloc(maxres, c, ws, soft, maxres::s_mus_mss); } -opt::maxsmt_solver_base* opt::mk_mss_maxres(context& c, - vector const& ws, expr_ref_vector const& soft) { +opt::maxsmt_solver_base* opt::mk_mss_maxres( + context& c, weights_t& ws, expr_ref_vector const& soft) { return alloc(maxres, c, ws, soft, maxres::s_mss); } diff --git a/src/opt/maxres.h b/src/opt/maxres.h index 5f4ea8db3..efe21c214 100644 --- a/src/opt/maxres.h +++ b/src/opt/maxres.h @@ -22,17 +22,11 @@ Notes: namespace opt { - maxsmt_solver_base* mk_maxres( - context& c, - vector const& ws, expr_ref_vector const& soft); + maxsmt_solver_base* mk_maxres(context& c, weights_t & ws, expr_ref_vector const& soft); - maxsmt_solver_base* mk_mus_mss_maxres( - context& c, - vector const& ws, expr_ref_vector const& soft); + maxsmt_solver_base* mk_mus_mss_maxres(context& c, weights_t & ws, expr_ref_vector const& soft); - maxsmt_solver_base* mk_mss_maxres( - context& c, - vector const& ws, expr_ref_vector const& soft); + maxsmt_solver_base* mk_mss_maxres(context& c, weights_t & ws, expr_ref_vector const& soft); }; diff --git a/src/opt/maxsls.cpp b/src/opt/maxsls.cpp index 6145d1e71..48fa48821 100644 --- a/src/opt/maxsls.cpp +++ b/src/opt/maxsls.cpp @@ -26,7 +26,7 @@ namespace opt { class sls : public maxsmt_solver_base { public: - sls(context& c, vector const& ws, expr_ref_vector const& soft): + sls(context& c, weights_t& ws, expr_ref_vector const& soft): maxsmt_solver_base(c, ws, soft) { } virtual ~sls() {} @@ -52,8 +52,8 @@ namespace opt { }; - maxsmt_solver_base* opt::mk_sls(context& c, - vector const& ws, expr_ref_vector const& soft) { + maxsmt_solver_base* opt::mk_sls( + context& c, weights_t& ws, expr_ref_vector const& soft) { return alloc(sls, c, ws, soft); } diff --git a/src/opt/maxsls.h b/src/opt/maxsls.h index 0ba94d6e8..c4314171f 100644 --- a/src/opt/maxsls.h +++ b/src/opt/maxsls.h @@ -27,8 +27,7 @@ Notes: namespace opt { - maxsmt_solver_base* mk_sls(context& c, - vector const& ws, expr_ref_vector const& soft); + maxsmt_solver_base* mk_sls(context& c, weights_t& ws, expr_ref_vector const& soft); }; diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 54b2110b3..b3e17ad71 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -27,6 +27,8 @@ Notes: namespace opt { + typedef vector const weights_t; + class context; class maxsmt_solver { @@ -63,7 +65,7 @@ namespace opt { params_ref m_params; // config public: - maxsmt_solver_base(context& c, vector const& ws, expr_ref_vector const& soft); + maxsmt_solver_base(context& c, weights_t& ws, expr_ref_vector const& soft); virtual ~maxsmt_solver_base() {} virtual rational get_lower() const { return m_lower; } @@ -74,14 +76,14 @@ namespace opt { virtual void get_model(model_ref& mdl) { mdl = m_model.get(); } void set_model() { s().get_model(m_model); } virtual void updt_params(params_ref& p); - virtual void init_soft(vector const& weights, expr_ref_vector const& soft); + virtual void init_soft(weights_t& weights, expr_ref_vector const& soft); solver& s() { return m_s; } void init(); expr* mk_not(expr* e); void set_mus(bool f); app* mk_fresh_bool(char const* name); protected: - void enable_sls(expr_ref_vector const& soft, vector const& ws); + void enable_sls(expr_ref_vector const& soft, weights_t& ws); }; /** @@ -122,7 +124,7 @@ namespace opt { void display_answer(std::ostream& out) const; void collect_statistics(statistics& st) const; private: - bool is_maxsat_problem(vector const& ws) const; + bool is_maxsat_problem(weights_t& ws) const; void verify_assignment(); }; diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 33af6c912..63ac13edc 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -34,6 +34,7 @@ namespace opt { class opt_solver; + class context : public opt_wrapper, public pareto_callback { struct free_func_visitor; typedef map map_t; @@ -175,7 +176,7 @@ namespace opt { solver& get_solver(); ast_manager& get_manager() { return this->m; } params_ref& params() { return m_params; } - void enable_sls(expr_ref_vector const& soft, vector const& weights); + void enable_sls(expr_ref_vector const& soft, weights_t& weights); symbol const& maxsat_engine() const { return m_maxsat_engine; } diff --git a/src/opt/pbmax.cpp b/src/opt/pbmax.cpp index a2191686e..b975543e3 100644 --- a/src/opt/pbmax.cpp +++ b/src/opt/pbmax.cpp @@ -31,8 +31,7 @@ namespace opt { class pbmax : public maxsmt_solver_base { public: - pbmax(context& c, - vector const& ws, expr_ref_vector const& soft): + pbmax(context& c, weights_t& ws, expr_ref_vector const& soft): maxsmt_solver_base(c, ws, soft) { } @@ -88,8 +87,8 @@ namespace opt { } }; - maxsmt_solver_base* opt::mk_pbmax(context & c, - vector const& ws, expr_ref_vector const& soft) { + maxsmt_solver_base* opt::mk_pbmax( + context & c, weights_t& ws, expr_ref_vector const& soft) { return alloc(pbmax, c, ws, soft); } diff --git a/src/opt/pbmax.h b/src/opt/pbmax.h index 50a989abd..78d43b045 100644 --- a/src/opt/pbmax.h +++ b/src/opt/pbmax.h @@ -23,8 +23,7 @@ Notes: #include "maxsmt.h" namespace opt { - maxsmt_solver_base* mk_pbmax(context& c, - vector const& ws, expr_ref_vector const& soft); + maxsmt_solver_base* mk_pbmax(context& c, weights_t& ws, expr_ref_vector const& soft); } #endif diff --git a/src/opt/wmax.cpp b/src/opt/wmax.cpp index c9cf44b2a..390c3608d 100644 --- a/src/opt/wmax.cpp +++ b/src/opt/wmax.cpp @@ -84,11 +84,13 @@ namespace opt { lbool operator()() { TRACE("opt", tout << "weighted maxsat\n";); scoped_ensure_theory wth(*this); + solver::scoped_push _s1(s()); lbool is_sat = l_true; bool was_sat = false; for (unsigned i = 0; i < m_soft.size(); ++i) { wth().assert_weighted(m_soft[i].get(), m_weights[i]); } + solver::scoped_push _s2(s()); while (l_true == is_sat) { is_sat = s().check_sat(0,0); if (m_cancel) { diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 5b626f170..ed49e22b7 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -727,11 +727,7 @@ namespace sat { if (inconsistent()) return l_false; init_assumptions(num_lits, lits); propagate(false); - if (inconsistent()) { - if (tracking_assumptions()) - resolve_conflict(); - return l_false; - } + if (check_inconsistent()) return l_false; cleanup(); if (m_config.m_max_conflicts > 0 && m_config.m_burst_search > 0) { m_restart_threshold = m_config.m_burst_search; @@ -745,8 +741,8 @@ namespace sat { // iff3_finder(*this)(); simplify_problem(); + if (check_inconsistent()) return l_false; - if (inconsistent()) return l_false; m_next_simplify = m_config.m_restart_initial * m_config.m_simplify_mult1; if (m_config.m_max_conflicts == 0) { @@ -769,6 +765,7 @@ namespace sat { restart(); if (m_conflicts >= m_next_simplify) { simplify_problem(); + if (check_inconsistent()) return l_false; m_next_simplify = static_cast(m_conflicts * m_config.m_simplify_mult2); if (m_next_simplify > m_conflicts + m_config.m_simplify_max) m_next_simplify = m_conflicts + m_config.m_simplify_max; @@ -886,6 +883,17 @@ namespace sat { } } + bool solver::check_inconsistent() { + if (inconsistent()) { + if (tracking_assumptions()) + resolve_conflict(); + return true; + } + else { + return false; + } + } + void solver::init_assumptions(unsigned num_lits, literal const* lits) { if (num_lits == 0 && m_user_scope_literals.empty()) { return; @@ -1575,32 +1583,37 @@ namespace sat { bool_var var = antecedent.var(); unsigned var_lvl = lvl(var); SASSERT(var < num_vars()); + TRACE("sat", tout << antecedent << " " << (is_marked(var)?"+":"-") << "\n";); if (!is_marked(var)) { mark(var); m_unmark.push_back(var); if (is_assumption(antecedent)) { m_core.push_back(antecedent); } - } + } } void solver::process_consequent_for_unsat_core(literal consequent, justification const& js) { - TRACE("sat", tout << "processing consequent: " << consequent << "\n"; + TRACE("sat", tout << "processing consequent: "; + if (consequent == null_literal) tout << "null\n"; + else tout << consequent << "\n"; display_justification(tout << "js kind: ", js); tout << "\n";); switch (js.get_kind()) { case justification::NONE: break; case justification::BINARY: + SASSERT(consequent != null_literal); process_antecedent_for_unsat_core(~(js.get_literal())); break; case justification::TERNARY: + SASSERT(consequent != null_literal); process_antecedent_for_unsat_core(~(js.get_literal1())); process_antecedent_for_unsat_core(~(js.get_literal2())); break; case justification::CLAUSE: { clause & c = *(m_cls_allocator.get_clause(js.get_clause_offset())); - unsigned i = 0; + unsigned i = 0; if (consequent != null_literal) { SASSERT(c[0] == consequent || c[1] == consequent); if (c[0] == consequent) { @@ -1611,7 +1624,7 @@ namespace sat { i = 2; } } - unsigned sz = c.size(); + unsigned sz = c.size(); for (; i < sz; i++) process_antecedent_for_unsat_core(~c[i]); break; @@ -1652,6 +1665,11 @@ namespace sat { if (m_conflict_lvl == 0) { return; } + SASSERT(m_unmark.empty()); + DEBUG_CODE({ + for (unsigned i = 0; i < m_trail.size(); ++i) { + SASSERT(!is_marked(m_trail[i].var())); + }}); unsigned old_size = m_unmark.size(); int idx = skip_literals_above_conflict_level(); @@ -1674,9 +1692,9 @@ namespace sat { literal consequent = m_not_l; justification js = m_conflict; + while (true) { process_consequent_for_unsat_core(consequent, js); - idx--; while (idx >= 0) { literal l = m_trail[idx]; if (is_marked(l.var())) @@ -1695,6 +1713,7 @@ namespace sat { bool_var c_var = consequent.var(); SASSERT(lvl(consequent) == m_conflict_lvl); js = m_justification[c_var]; + idx--; } reset_unmark(old_size); if (m_config.m_minimize_core) { @@ -1983,7 +2002,8 @@ namespace sat { assigned at level 0. */ void solver::minimize_lemma() { - m_unmark.reset(); + SASSERT(m_unmark.empty()); + //m_unmark.reset(); updt_lemma_lvl_set(); unsigned sz = m_lemma.size(); diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index f7e6a009d..e83da892b 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -247,6 +247,8 @@ namespace sat { bool is_marked_lit(literal l) const { return m_lit_mark[l.index()] != 0; } void mark_lit(literal l) { SASSERT(!is_marked_lit(l)); m_lit_mark[l.index()] = true; } void unmark_lit(literal l) { SASSERT(is_marked_lit(l)); m_lit_mark[l.index()] = false; } + bool check_inconsistent(); + // ----------------------- // From 78c03ed83554233877cf4459913227ebb305dd15 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Aug 2014 19:36:15 -0700 Subject: [PATCH 471/925] fix crash on delete clauses Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index ed49e22b7..1c0cc145a 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -169,9 +169,9 @@ namespace sat { } void solver::del_clause(clause& c) { + if (!c.is_learned()) m_stats.m_non_learned_generation++; m_cls_allocator.del_clause(&c); m_stats.m_del_clause++; - if (!c.is_learned()) m_stats.m_non_learned_generation++; } clause * solver::mk_clause_core(unsigned num_lits, literal * lits, bool learned) { From 8822bc17550bdb60feec8f55bcf8da5921752cdc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 20 Aug 2014 16:03:25 -0700 Subject: [PATCH 472/925] fix bug in unsat core finding Signed-off-by: Nikolaj Bjorner --- src/sat/sat_mus.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/sat/sat_mus.cpp b/src/sat/sat_mus.cpp index e6c9376ea..e582a9f5c 100644 --- a/src/sat/sat_mus.cpp +++ b/src/sat/sat_mus.cpp @@ -50,14 +50,16 @@ namespace sat { literal_vector& mus = m_mus; core.append(s.get_core()); for (unsigned i = 0; i < core.size(); ++i) { - s.m_user_scope_literals.contains(core[i]); - mus.push_back(core[i]); - core[i] = core.back(); - core.pop_back(); - --i; + if (s.m_user_scope_literals.contains(core[i])) { + mus.push_back(core[i]); + core[i] = core.back(); + core.pop_back(); + --i; + } } while (!core.empty()) { + IF_VERBOSE(2, verbose_stream() << "(opt.mus reducing core: " << core.size() << " new core: " << mus.size() << ")\n";); TRACE("sat", tout << "core: " << core << "\n"; tout << "mus: " << mus << "\n";); From b596828d2390f1ac539c3a333c2a2e82364bef64 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 21 Aug 2014 18:04:46 -0700 Subject: [PATCH 473/925] add DDNF based engine Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 3 +- src/muz/base/dl_context.cpp | 6 + src/muz/base/dl_engine_base.h | 5 +- src/muz/ddnf/ddnf.cpp | 620 ++++++++++++++++++++++++++++++ src/muz/ddnf/ddnf.h | 46 +++ src/muz/fp/dl_register_engine.cpp | 3 + src/opt/maxres.cpp | 52 ++- src/sat/sat_mus.cpp | 3 +- src/sat/sat_solver.cpp | 15 +- src/util/bit_vector.cpp | 16 + src/util/bit_vector.h | 3 + 11 files changed, 761 insertions(+), 11 deletions(-) create mode 100644 src/muz/ddnf/ddnf.cpp create mode 100644 src/muz/ddnf/ddnf.h diff --git a/scripts/mk_project.py b/scripts/mk_project.py index ce1014ebe..9ceec29eb 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -66,8 +66,9 @@ def init_project_def(): add_lib('clp', ['muz', 'transforms'], 'muz/clp') add_lib('tab', ['muz', 'transforms'], 'muz/tab') add_lib('bmc', ['muz', 'transforms'], 'muz/bmc') + add_lib('ddnf', ['muz', 'transforms'], 'muz/ddnf') add_lib('duality_intf', ['muz', 'transforms', 'duality'], 'muz/duality') - add_lib('fp', ['muz', 'pdr', 'clp', 'tab', 'rel', 'bmc', 'duality_intf'], 'muz/fp') + add_lib('fp', ['muz', 'pdr', 'clp', 'tab', 'rel', 'bmc', 'duality_intf', 'ddnf'], 'muz/fp') add_lib('smtlogic_tactics', ['arith_tactics', 'bv_tactics', 'nlsat_tactic', 'smt_tactic', 'aig_tactic', 'fp', 'muz','qe'], 'tactic/smtlogics') add_lib('ufbv_tactic', ['normal_forms', 'core_tactics', 'macros', 'smt_tactic', 'rewriter'], 'tactic/ufbv') add_lib('portfolio', ['smtlogic_tactics', 'ufbv_tactic', 'fpa_tactics', 'aig_tactic', 'fp', 'qe','sls_tactic', 'subpaving_tactic'], 'tactic/portfolio') diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 859d4419f..774db6c6a 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -712,6 +712,8 @@ namespace datalog { check_existential_tail(r); check_positive_predicates(r); break; + case DDNF_ENGINE: + break; case LAST_ENGINE: default: UNREACHABLE(); @@ -932,6 +934,9 @@ namespace datalog { else if (e == symbol("duality")) { m_engine_type = DUALITY_ENGINE; } + else if (e == symbol("ddnf")) { + m_engine_type = DDNF_ENGINE; + } if (m_engine_type == LAST_ENGINE) { expr_fast_mark1 mark; @@ -980,6 +985,7 @@ namespace datalog { case QBMC_ENGINE: case TAB_ENGINE: case CLP_ENGINE: + case DDNF_ENGINE: flush_add_rules(); break; case DUALITY_ENGINE: diff --git a/src/muz/base/dl_engine_base.h b/src/muz/base/dl_engine_base.h index eaeebe979..21a07fcb0 100644 --- a/src/muz/base/dl_engine_base.h +++ b/src/muz/base/dl_engine_base.h @@ -30,8 +30,9 @@ namespace datalog { QBMC_ENGINE, TAB_ENGINE, CLP_ENGINE, - LAST_ENGINE, - DUALITY_ENGINE + DUALITY_ENGINE, + DDNF_ENGINE, + LAST_ENGINE }; class engine_base { diff --git a/src/muz/ddnf/ddnf.cpp b/src/muz/ddnf/ddnf.cpp new file mode 100644 index 000000000..92e01bd2f --- /dev/null +++ b/src/muz/ddnf/ddnf.cpp @@ -0,0 +1,620 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + ddnf.cpp + +Abstract: + + DDNF based engine. + +Author: + + Nikolaj Bjorner (nbjorner) 2014-08-21 + +Revision History: + + - inherits from Nuno Lopes Hassel utilities + and Garvit Juniwal's DDNF engine. + +--*/ + +#include "ddnf.h" +#include "trail.h" +#include "dl_rule_set.h" +#include "dl_context.h" +#include "dl_mk_rule_inliner.h" +#include "smt_kernel.h" +#include "qe_lite.h" +#include "bool_rewriter.h" +#include "th_rewriter.h" +#include "datatype_decl_plugin.h" +#include "for_each_expr.h" +#include "matcher.h" +#include "scoped_proof.h" +#include "fixedpoint_params.hpp" + + +namespace datalog { + +#define BIT_0 ((0<<1)|1) +#define BIT_1 ((1<<1)|0) +#define BIT_x ((1<<1)|1) +#define BIT_z 0 + + class tbv : private bit_vector { + public: + tbv(): bit_vector() {} + tbv(unsigned n): bit_vector(2*n) {} + tbv(tbv const& other): bit_vector(other) {} + tbv(unsigned n, unsigned val): bit_vector() { + SASSERT(val <= 3); + resize(n, val); + } + tbv(uint64 val, unsigned n) : bit_vector(2*n) { + for (unsigned bit = n; bit > 0;) { + --bit; + if (val & (1ULL << bit)) { + set(bit, BIT_1); + } else { + set(bit, BIT_0); + } + } + } + + tbv(rational const& v, unsigned n) : bit_vector(2*n) { + if (v.is_uint64() && n <= 64) { + tbv tmp(v.get_uint64(), n); + *this = tmp; + return; + } + + for (unsigned bit = n; bit > 0; ) { + --bit; + if (bitwise_and(v, rational::power_of_two(bit)).is_zero()) { + set(bit, BIT_0); + } else { + set(bit, BIT_1); + } + } + } + + tbv& operator=(tbv const& other) { + bit_vector::operator=(other); + return *this; + } + + bool operator!=(tbv const& other) const { + return bit_vector::operator!=(other); + } + + bool operator==(tbv const& other) const { + return bit_vector::operator==(other); + } + + void resize(unsigned n, unsigned val) { + while (size() < n) { + bit_vector::push_back((val & 2) != 0); + bit_vector::push_back((val & 1) != 0); + } + } + + bool empty() const { return false; } // TBD + + bool is_subset(tbv const& other) const { + SASSERT(size() == other.size()); + return other.contains(*this); + } + + bool is_superset(tbv const& other) const { + SASSERT(size() == other.size()); + return contains(other); + } + + unsigned size() const { return bit_vector::size()/2; } + + void display(std::ostream& out) const { + for (unsigned i = 0; i < size(); ++i) { + switch (get(i)) { + case BIT_0: + out << '0'; + break; + case BIT_1: + out << '1'; + break; + case BIT_x: + out << 'x'; + break; + case BIT_z: + out << 'z'; + break; + default: + UNREACHABLE(); + } + } + } + + private: + void set(unsigned index, unsigned value) { + SASSERT(value <= 3); + bit_vector::set(2*index, (value & 2) != 0); + bit_vector::set(2*index+1, (value & 1) != 0); + } + + unsigned get(unsigned index) const { + index *= 2; + return (bit_vector::get(index) << 1) | (unsigned)bit_vector::get(index+1); + } + + }; + + class dot { + tbv m_pos; + vector m_negs; + public: + dot(tbv const& pos, vector const& negs): + m_pos(pos), m_negs(negs) {} + + bool operator==(dot const& other) const { + if (m_pos != other.m_pos) return false; + if (m_negs.size() != other.m_negs.size()) return false; + for (unsigned i = 0; i < m_negs.size(); ++i) { + if (m_negs[i] != other.m_negs[i]) return false; + } + return true; + } + void display(std::ostream& out) { + out << "<"; + m_pos.display(out); + out << "\\"; + for (unsigned i = 0; i < m_negs.size(); ++i) { + m_negs[i].display(out); + if (i + 1 < m_negs.size()) out << " u "; + } + out << ">"; + } + }; + + class ddnf_mgr; + class ddnf_node; + typedef ref_vector ddnf_node_vector; + + class ddnf_node { + tbv m_tbv; + ddnf_node_vector m_children; + vector m_pos; + vector m_neg; + unsigned m_refs; + + public: + ddnf_node(ddnf_mgr& m, tbv const& tbv): + m_tbv(tbv), + m_children(m), + m_refs(0) { + } + + unsigned inc_ref() { + return ++m_refs; + } + + unsigned dec_ref() { + SASSERT(m_refs > 0); + return --m_refs; + } + + unsigned num_children() const { return m_children.size(); } + + ddnf_node* operator[](unsigned index) { return m_children[index].get(); } + + tbv const& get_tbv() const { return m_tbv; } + + void add_child(ddnf_node* n); + + void remove_child(ddnf_node* n); + + bool contains_child(ddnf_node* n) const; + + }; + + class ddnf_mgr { + unsigned m_num_bits; + ddnf_node* m_root; + ddnf_node_vector m_nodes; + vector m_dots; + public: + ddnf_mgr(unsigned n): m_num_bits(n), m_nodes(*this) { + m_root = alloc(ddnf_node, *this, tbv(n, BIT_x)); + m_nodes.push_back(m_root); + } + + void inc_ref(ddnf_node* n) { + n->inc_ref(); + } + + void dec_ref(ddnf_node* n) { + unsigned count = n->dec_ref(); + NOT_IMPLEMENTED_YET(); + } + + private: + void insert_new(ddnf_node& root, ddnf_node* new_n, + ptr_vector& new_intersections) { + SASSERT(root.get_tbv().is_superset(new_n->get_tbv())); +// if (root == *new_n) return; + bool inserted = false; + for (unsigned i = 0; i < root.num_children(); ++i) { + ddnf_node& child = *(root[i]); + if (child.get_tbv().is_superset(new_n->get_tbv())) { + inserted = true; + insert_new(child, new_n, new_intersections); + } + } + if (inserted) return; + ddnf_node_vector subset_children(*this); + for (unsigned i = 0; i < root.num_children(); ++i) { + ddnf_node& child = *(root[i]); + // cannot be superset + // checking for subset + if (child.get_tbv().is_subset(new_n->get_tbv())) { + subset_children.push_back(&child); + } + // this means there is a non-full intersection + else { + tbv intr; + // TBD intersect(child.get_tbv(), new_n->get_tbv(), intr); + if (!intr.empty()) { + // TBD new_intersections.push_back(intr); + } + } + } + for (unsigned i = 0; i < subset_children.size(); ++i) { + root.remove_child(subset_children[i].get()); + new_n->add_child(subset_children[i].get()); + } + root.add_child(new_n); + } + + +#if 0 + + DDNFNode InsertTBV(TernaryBitVector aTbv) + { + foreach (DDNFNode node in allNodes) + { + if (node.tbv.IsEqualset(aTbv)) + { + return node; + } + } + DDNFNode newNode = new DDNFNode(aTbv); + this.allNodes.Add(newNode); + List newIntersections = new List(); + InsertNewNode(this.root, newNode, newIntersections); + + // add the TBVs corresponding to new intersections + foreach (TernaryBitVector newIntr in newIntersections) + { + // this assert guarantees termination since you can only + // insert smaller tbvs recursively + Debug.Assert(!newIntr.IsSupset(aTbv)); + + InsertTBV(newIntr); + } + + return newNode; + } + + public void InsertDot(DOT aDot) + { + this.allDots.Add(aDot); + DDNFNode posNode = InsertTBV(aDot.pos); + List negNodes = new List(); + foreach (TernaryBitVector neg in aDot.negs) + { + negNodes.Add(InsertTBV(neg)); + } + + posNode.posDots.Add(aDot); + foreach (DDNFNode negNode in negNodes) + { + negNode.negDots.Add(aDot); + } + } + + // remove all negNodes for each dot in dot2Nodes + void RemoveNegNodesForAllDots(DDNFNode aNode, HashSet activeDots, + ref Dictionary> dot2Nodes) + { + foreach (DOT negDot in aNode.negDots) + { + activeDots.Add(negDot); + } + + foreach (DOT activeDot in activeDots) + { + dot2Nodes[activeDot].Remove(aNode); + } + + foreach (DDNFNode child in aNode.children) + + { + RemoveNegNodesForAllDots(child, new HashSet(activeDots), ref dot2Nodes); + } + } + + // add all posNodes for each dot in dot2Nodes + void AddPosNodesForAllDots(DDNFNode aNode, HashSet activeDots, + ref Dictionary> dot2Nodes) + { + foreach (DOT posDot in aNode.posDots) + { + activeDots.Add(posDot); + } + + foreach (DOT activeDot in activeDots) + { + dot2Nodes[activeDot].Add(aNode); + } + + foreach (DDNFNode child in aNode.children) + { + AddPosNodesForAllDots(child, new HashSet(activeDots), ref dot2Nodes); + } + } + + public Dictionary> NodesForAllDots() + { + Dictionary> dot2Nodes = + new Dictionary>(); + + foreach (DOT dot in allDots) + { + dot2Nodes[dot] = new HashSet(); + } + AddPosNodesForAllDots(this.root, new HashSet(), ref dot2Nodes); + RemoveNegNodesForAllDots(this.root, new HashSet(), ref dot2Nodes); + + return dot2Nodes; + + } + public string PrintNodes() + { + StringBuilder retVal = new StringBuilder(); + retVal.Append("").ToString(); + } + } + + +} + +#endif + + }; + +void ddnf_node::add_child(ddnf_node* n) { + SASSERT(!m_tbv.is_subset(n->m_tbv)); + m_children.push_back(n); +} + +void ddnf_node::remove_child(ddnf_node* n) { + m_children.erase(n); +} + +bool ddnf_node::contains_child(ddnf_node* n) const { + return m_children.contains(n); +} + + + + class ddnf::imp { + struct stats { + stats() { reset(); } + void reset() { memset(this, 0, sizeof(*this)); } + }; + + context& m_ctx; + ast_manager& m; + rule_manager& rm; + volatile bool m_cancel; + ptr_vector m_todo; + ast_mark m_visited1, m_visited2; + stats m_stats; + + public: + imp(context& ctx): + m_ctx(ctx), + m(ctx.get_manager()), + rm(ctx.get_rule_manager()), + m_cancel(false) + { + } + + ~imp() {} + + lbool query(expr* query) { + m_ctx.ensure_opened(); + if (!can_handle_rules()) { + return l_undef; + } + IF_VERBOSE(0, verbose_stream() << "rules are OK\n";); + return run(); + } + + void cancel() { + m_cancel = true; + } + + void cleanup() { + m_cancel = false; + } + + void reset_statistics() { + m_stats.reset(); + } + + void collect_statistics(statistics& st) const { + } + + void display_certificate(std::ostream& out) const { + expr_ref ans = get_answer(); + out << mk_pp(ans, m) << "\n"; + } + + expr_ref get_answer() const { + UNREACHABLE(); + return expr_ref(m.mk_true(), m); + } + private: + + proof_ref get_proof() const { + scoped_proof sp(m); + proof_ref pr(m); + return pr; + } + + lbool run() { + return l_undef; + } + + bool can_handle_rules() { + m_visited1.reset(); + m_todo.reset(); + rule_set const& rules = m_ctx.get_rules(); + datalog::rule_set::iterator it = rules.begin(); + datalog::rule_set::iterator end = rules.end(); + for (; it != end; ++it) { + if (!can_handle_rule(**it)) { + return false; + } + } + return true; + } + + bool can_handle_rule(rule const& r) { + // all predicates are monadic. + unsigned utsz = r.get_uninterpreted_tail_size(); + unsigned sz = r.get_tail_size(); + for (unsigned i = utsz; i < sz; ++i) { + m_todo.push_back(r.get_tail(i)); + } + if (check_monadic()) { + return true; + } + else { + r.display(m_ctx, std::cout); + return false; + } + } + + bool check_monadic() { + expr* e1, *e2; + while (!m_todo.empty()) { + expr* e = m_todo.back(); + m_todo.pop_back(); + if (m_visited1.is_marked(e)) { + continue; + } + m_visited1.mark(e, true); + if (is_var(e)) { + continue; + } + if (is_quantifier(e)) { + return false; + } + if (m.is_and(e) || + m.is_or(e) || + m.is_iff(e) || + m.is_not(e) || + m.is_implies(e)) { + m_todo.append(to_app(e)->get_num_args(), to_app(e)->get_args()); + continue; + } + if (m.is_eq(e, e1, e2)) { + if (is_var(e1) && is_ground(e2)) { + continue; + } + if (is_var(e2) && is_ground(e1)) { + continue; + } + if (is_var(e1) && is_var(e2)) { + continue; + } + } + if (is_ground(e)) { + continue; + } + if (is_unary(e)) { + continue; + } + IF_VERBOSE(0, verbose_stream() << "Could not handle: " << mk_pp(e, m) << "\n";); + return false; + } + return true; + } + + bool is_unary(expr* e) { + var* v = 0; + m_visited2.reset(); + unsigned sz = m_todo.size(); + m_todo.push_back(e); + while (m_todo.size() > sz) { + expr* e = m_todo.back(); + m_todo.pop_back(); + if (m_visited2.is_marked(e)) { + continue; + } + m_visited2.mark(e, true); + if (is_var(e)) { + if (v && v != e) { + return false; + } + v = to_var(e); + } + else if (is_app(e)) { + m_todo.append(to_app(e)->get_num_args(), to_app(e)->get_args()); + } + else { + return false; + } + } + return true; + } + + }; + + ddnf::ddnf(context& ctx): + datalog::engine_base(ctx.get_manager(),"tabulation"), + m_imp(alloc(imp, ctx)) { + } + ddnf::~ddnf() { + dealloc(m_imp); + } + lbool ddnf::query(expr* query) { + return m_imp->query(query); + } + void ddnf::cancel() { + m_imp->cancel(); + } + void ddnf::cleanup() { + m_imp->cleanup(); + } + void ddnf::reset_statistics() { + m_imp->reset_statistics(); + } + void ddnf::collect_statistics(statistics& st) const { + m_imp->collect_statistics(st); + } + void ddnf::display_certificate(std::ostream& out) const { + m_imp->display_certificate(out); + } + expr_ref ddnf::get_answer() { + return m_imp->get_answer(); + } + +}; diff --git a/src/muz/ddnf/ddnf.h b/src/muz/ddnf/ddnf.h new file mode 100644 index 000000000..8121dc090 --- /dev/null +++ b/src/muz/ddnf/ddnf.h @@ -0,0 +1,46 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + ddnf.h + +Abstract: + + DDNF based engine. + +Author: + + Nikolaj Bjorner (nbjorner) 2014-08-21 + +Revision History: + +--*/ +#ifndef _DDNF__H_ +#define _DDNF__H_ + +#include "ast.h" +#include "lbool.h" +#include "statistics.h" +#include "dl_engine_base.h" + +namespace datalog { + class context; + + class ddnf : public engine_base { + class imp; + imp* m_imp; + public: + ddnf(context& ctx); + ~ddnf(); + virtual lbool query(expr* query); + virtual void cancel(); + virtual void cleanup(); + virtual void reset_statistics(); + virtual void collect_statistics(statistics& st) const; + virtual void display_certificate(std::ostream& out) const; + virtual expr_ref get_answer(); + }; +}; + +#endif diff --git a/src/muz/fp/dl_register_engine.cpp b/src/muz/fp/dl_register_engine.cpp index 57413b7cb..6e1ba40ce 100644 --- a/src/muz/fp/dl_register_engine.cpp +++ b/src/muz/fp/dl_register_engine.cpp @@ -22,6 +22,7 @@ Revision History: #include "tab_context.h" #include "rel_context.h" #include "pdr_dl_interface.h" +#include "ddnf.h" #include "duality_dl_interface.h" namespace datalog { @@ -43,6 +44,8 @@ namespace datalog { return alloc(clp, *m_ctx); case DUALITY_ENGINE: return alloc(Duality::dl_interface, *m_ctx); + case DDNF_ENGINE: + return alloc(ddnf, *m_ctx); case LAST_ENGINE: UNREACHABLE(); return 0; diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 231c72578..be3470ad8 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -82,6 +82,7 @@ private: expr_ref_vector m_trail; strategy_t m_st; rational m_max_upper; + bool m_hill_climb; public: maxres(context& c, @@ -92,7 +93,8 @@ public: m_mus(m_s, m), m_mss(m_s, m), m_trail(m), - m_st(st) + m_st(st), + m_hill_climb(true) { } @@ -299,7 +301,21 @@ public: TRACE("opt", display_vec(tout << "core: ", core.size(), core.c_ptr()); display_vec(tout << "assumptions: ", asms.size(), asms.c_ptr());); - is_sat = s().check_sat(asms.size(), asms.c_ptr()); + + if (m_hill_climb) { + /** + Give preference to cores that have large minmal values. + */ + sort_assumptions(asms); + unsigned index = 0; + while (index < asms.size() && is_sat != l_false) { + index = next_index(asms, index); + is_sat = s().check_sat(index, asms.c_ptr()); + } + } + else { + is_sat = s().check_sat(asms.size(), asms.c_ptr()); + } } TRACE("opt", tout << "num cores: " << cores.size() << "\n"; @@ -315,6 +331,36 @@ public: } + struct compare_asm { + maxres& mr; + compare_asm(maxres& mr):mr(mr) {} + bool operator()(expr* a, expr* b) const { + return mr.get_weight(a) > mr.get_weight(b); + } + }; + + void sort_assumptions(expr_ref_vector& _asms) { + compare_asm comp(*this); + ptr_vector asms(_asms.size(), _asms.c_ptr()); + expr_ref_vector trail(_asms); + std::sort(asms.begin(), asms.end(), comp); + _asms.reset(); + _asms.append(asms.size(), asms.c_ptr()); + DEBUG_CODE( + for (unsigned i = 0; i + 1 < asms.size(); ++i) { + SASSERT(get_weight(asms[i]) >= get_weight(asms[i+1])); + }); + } + + unsigned next_index(expr_ref_vector const& asms, unsigned index) { + if (index < asms.size()) { + rational w = get_weight(asms[index]); + ++index; + for (; index < asms.size() && w == get_weight(asms[index]); ++index); + } + return index; + } + lbool process_sat(ptr_vector& corr_set) { expr_ref fml(m), tmp(m); TRACE("opt", display_vec(tout << "corr_set: ", corr_set.size(), corr_set.c_ptr());); @@ -379,7 +425,7 @@ public: return l_true; } - rational get_weight(expr* e) { + rational get_weight(expr* e) const { return m_asm2weight.find(e); } diff --git a/src/sat/sat_mus.cpp b/src/sat/sat_mus.cpp index e582a9f5c..74f17f8ea 100644 --- a/src/sat/sat_mus.cpp +++ b/src/sat/sat_mus.cpp @@ -71,7 +71,7 @@ namespace sat { literal lit = core.back(); core.pop_back(); unsigned sz = mus.size(); - // mus.push_back(~lit); // TBD: measure + mus.push_back(~lit); // TBD: measure mus.append(core); lbool is_sat = s.check(mus.size(), mus.c_ptr()); TRACE("sat", tout << "mus: " << mus << "\n";); @@ -102,6 +102,7 @@ namespace sat { core.push_back(lit); } } + IF_VERBOSE(2, verbose_stream() << "reduced core: " << core.size() << "\n";); break; } } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 1c0cc145a..d21c49b0c 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -902,6 +902,11 @@ namespace sat { m_assumption_set.reset(); push(); + propagate(false); + if (inconsistent()) { + return; + } + TRACE("sat", for (unsigned i = 0; i < num_lits; ++i) tout << lits[i] << " "; @@ -916,15 +921,17 @@ namespace sat { m_assumption_set.insert(_l_); \ m_assumptions.push_back(_l_); \ assign(_l_, justification()); \ +// propagate(false); \ + + for (unsigned i = 0; !inconsistent() && i < m_user_scope_literals.size(); ++i) { + literal nlit = ~m_user_scope_literals[i]; + _INSERT_LIT(nlit); + } for (unsigned i = 0; !inconsistent() && i < num_lits; ++i) { literal lit = lits[i]; _INSERT_LIT(lit); } - for (unsigned i = 0; !inconsistent() && i < m_user_scope_literals.size(); ++i) { - literal nlit = ~m_user_scope_literals[i]; - _INSERT_LIT(nlit); - } } void solver::reinit_assumptions() { diff --git a/src/util/bit_vector.cpp b/src/util/bit_vector.cpp index 6885b93e8..207d22d6a 100644 --- a/src/util/bit_vector.cpp +++ b/src/util/bit_vector.cpp @@ -208,6 +208,22 @@ void bit_vector::display(std::ostream & out) const { #endif } +bool bit_vector::contains(bit_vector const& other) const { + unsigned n = num_words(); + if (n == 0) + return true; + + for (unsigned i = 0; i < n - 1; ++i) { + if ((m_data[i] & other.m_data[i]) != other.m_data[i]) + return false; + } + unsigned bit_rest = m_num_bits % 32; + unsigned mask = (1U << bit_rest) - 1; + if (mask == 0) mask = UINT_MAX; + unsigned other_data = other.m_data[n-1] & mask; + return (m_data[n-1] & other_data) == other_data; +} + void fr_bit_vector::reset() { unsigned sz = size(); unsigned_vector::const_iterator it = m_one_idxs.begin(); diff --git a/src/util/bit_vector.h b/src/util/bit_vector.h index 0ccdeae9e..c703f524b 100644 --- a/src/util/bit_vector.h +++ b/src/util/bit_vector.h @@ -200,6 +200,9 @@ public: bit_vector & operator&=(bit_vector const & source); void display(std::ostream & out) const; + + bool contains(const bit_vector & other) const; + }; inline std::ostream & operator<<(std::ostream & out, bit_vector const & b) { From 34aa06b5a3c9e49a09fa7ea0d60bf3e894d5a8bf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 21 Aug 2014 21:57:44 -0700 Subject: [PATCH 474/925] more ddnf Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/ddnf.cpp | 328 +++++++++++++++++++++++----------------- src/util/bit_vector.cpp | 4 + src/util/bit_vector.h | 2 + 3 files changed, 199 insertions(+), 135 deletions(-) diff --git a/src/muz/ddnf/ddnf.cpp b/src/muz/ddnf/ddnf.cpp index 92e01bd2f..c856b6903 100644 --- a/src/muz/ddnf/ddnf.cpp +++ b/src/muz/ddnf/ddnf.cpp @@ -93,6 +93,10 @@ namespace datalog { return bit_vector::operator==(other); } + unsigned get_hash() const { + return bit_vector::get_hash(); + } + void resize(unsigned n, unsigned val) { while (size() < n) { bit_vector::push_back((val & 2) != 0); @@ -100,8 +104,6 @@ namespace datalog { } } - bool empty() const { return false; } // TBD - bool is_subset(tbv const& other) const { SASSERT(size() == other.size()); return other.contains(*this); @@ -134,6 +136,8 @@ namespace datalog { } } } + + friend bool intersect(tbv const& a, tbv const& b, tbv& result); private: void set(unsigned index, unsigned value) { @@ -146,16 +150,29 @@ namespace datalog { index *= 2; return (bit_vector::get(index) << 1) | (unsigned)bit_vector::get(index+1); } - }; + bool intersect(tbv const& a, tbv const& b, tbv& result) { + result = a; + result &= b; + for (unsigned i = 0; i < result.size(); ++i) { + if (result.get(i) == BIT_z) return false; + } + return true; + } + class dot { tbv m_pos; vector m_negs; public: + dot() {} dot(tbv const& pos, vector const& negs): m_pos(pos), m_negs(negs) {} + tbv const& pos() const { return m_pos; } + tbv neg(unsigned i) const { return m_negs[i]; } + unsigned size() const { return m_negs.size(); } + bool operator==(dot const& other) const { if (m_pos != other.m_pos) return false; if (m_negs.size() != other.m_negs.size()) return false; @@ -164,6 +181,7 @@ namespace datalog { } return true; } + void display(std::ostream& out) { out << "<"; m_pos.display(out); @@ -174,6 +192,28 @@ namespace datalog { } out << ">"; } + + struct eq { + bool operator()(dot const& d1, dot const& d2) const { + if (d1.pos() != d2.pos()) return false; + if (d1.size() != d2.size()) return false; + for (unsigned i = 0; i < d1.size(); ++i) { + if (d1.neg(i) != d2.neg(i)) return false; + } + return true; + } + }; + + struct hash { + unsigned operator()(dot const& d) const { + unsigned h = d.pos().get_hash(); + for (unsigned i = 0; i < d.size(); ++i) { + h ^= d.neg(i).get_hash(); + } + return h; + } + }; + }; class ddnf_mgr; @@ -186,28 +226,53 @@ namespace datalog { vector m_pos; vector m_neg; unsigned m_refs; + unsigned m_id; + friend class ddnf_mgr; + public: - ddnf_node(ddnf_mgr& m, tbv const& tbv): + ddnf_node(ddnf_mgr& m, tbv const& tbv, unsigned id): m_tbv(tbv), m_children(m), - m_refs(0) { + m_refs(0), + m_id(id) { } + ~ddnf_node() {} + unsigned inc_ref() { return ++m_refs; } - unsigned dec_ref() { + void dec_ref() { SASSERT(m_refs > 0); - return --m_refs; + --m_refs; + if (m_refs == 0) { + dealloc(this); + } } + + struct eq { + bool operator()(ddnf_node* n1, ddnf_node* n2) const { + return n1->get_tbv() == n2->get_tbv(); + } + }; + + struct hash { + unsigned operator()(ddnf_node* n) const { + return n->get_tbv().get_hash(); + } + }; + + unsigned get_id() const { return m_id; } unsigned num_children() const { return m_children.size(); } ddnf_node* operator[](unsigned index) { return m_children[index].get(); } tbv const& get_tbv() const { return m_tbv; } + vector const& pos() const { return m_pos; } + vector const& neg() const { return m_neg; } void add_child(ddnf_node* n); @@ -215,17 +280,40 @@ namespace datalog { bool contains_child(ddnf_node* n) const; + ddnf_node* add_pos(dot const& d) { m_pos.push_back(d); return this; } + + ddnf_node* add_neg(dot const& d) { m_neg.push_back(d); return this; } + + void display(std::ostream& out) const { + out << "node["; + m_tbv.display(out); + for (unsigned i = 0; i < m_children.size(); ++i) { + out << " " << m_children[i]->get_id(); + } + out << "]"; + } }; - class ddnf_mgr { + typedef ptr_hashtable ddnf_nodes; + + class ddnf_mgr { unsigned m_num_bits; ddnf_node* m_root; - ddnf_node_vector m_nodes; - vector m_dots; + ddnf_node_vector m_noderefs; + ddnf_nodes m_nodes; + ptr_vector m_tables; + map m_dots; + bool m_internalized; public: - ddnf_mgr(unsigned n): m_num_bits(n), m_nodes(*this) { - m_root = alloc(ddnf_node, *this, tbv(n, BIT_x)); - m_nodes.push_back(m_root); + ddnf_mgr(unsigned n): m_num_bits(n), m_noderefs(*this), m_internalized(false) { + m_root = alloc(ddnf_node, *this, tbv(n, BIT_x), m_nodes.size()); + m_noderefs.push_back(m_root); + m_nodes.insert(m_root); + } + + ~ddnf_mgr() { + m_noderefs.reset(); + std::for_each(m_tables.begin(), m_tables.end(), delete_proc()); } void inc_ref(ddnf_node* n) { @@ -233,38 +321,84 @@ namespace datalog { } void dec_ref(ddnf_node* n) { - unsigned count = n->dec_ref(); - NOT_IMPLEMENTED_YET(); + n->dec_ref(); + } + + void insert(dot const& d) { + SASSERT(!m_internalized); + if (m_dots.contains(d)) return; + ddnf_nodes* ns = alloc(ddnf_nodes); + m_tables.push_back(ns); + m_dots.insert(d, ns); + insert(d.pos())->add_pos(d); + for (unsigned i = 0; i < d.size(); ++i) { + insert(d.neg(i))->add_neg(d); + } + } + + void display(std::ostream& out) const { + for (unsigned i = 0; i < m_noderefs.size(); ++i) { + m_noderefs[i]->display(out); + out << "\n"; + } } private: - void insert_new(ddnf_node& root, ddnf_node* new_n, - ptr_vector& new_intersections) { - SASSERT(root.get_tbv().is_superset(new_n->get_tbv())); -// if (root == *new_n) return; + + ddnf_node* insert(tbv const& t) { + vector new_tbvs; + new_tbvs.push_back(t); + for (unsigned i = 0; i < new_tbvs.size(); ++i) { + tbv const& nt = new_tbvs[i]; + if (contains(nt)) continue; + ddnf_node* n = alloc(ddnf_node, *this, nt, m_noderefs.size()); + m_noderefs.push_back(n); + m_nodes.insert(n); + insert(*m_root, n, new_tbvs); + } + return find(t); + } + + ddnf_node* find(tbv const& t) { + ddnf_node dummy(*this, t, 0); + return *(m_nodes.find(&dummy)); + } + + bool contains(tbv const& t) { + ddnf_node dummy(*this, t, 0); + return m_nodes.contains(&dummy); + } + + void insert(ddnf_node& root, ddnf_node* new_n, vector& new_intersections) { + tbv const& new_tbv = new_n->get_tbv(); + + SASSERT(new_tbv.is_subset(root.get_tbv())); + if (&root == new_n) return; bool inserted = false; for (unsigned i = 0; i < root.num_children(); ++i) { ddnf_node& child = *(root[i]); - if (child.get_tbv().is_superset(new_n->get_tbv())) { + if (child.get_tbv().is_superset(new_tbv)) { inserted = true; - insert_new(child, new_n, new_intersections); + insert(child, new_n, new_intersections); } } - if (inserted) return; + if (inserted) { + return; + } ddnf_node_vector subset_children(*this); + tbv intr; for (unsigned i = 0; i < root.num_children(); ++i) { ddnf_node& child = *(root[i]); // cannot be superset + SASSERT(!child.get_tbv().is_superset(new_tbv)); // checking for subset - if (child.get_tbv().is_subset(new_n->get_tbv())) { + if (child.get_tbv().is_subset(new_tbv)) { subset_children.push_back(&child); } // this means there is a non-full intersection else { - tbv intr; - // TBD intersect(child.get_tbv(), new_n->get_tbv(), intr); - if (!intr.empty()) { - // TBD new_intersections.push_back(intr); + if (intersect(child.get_tbv(), new_tbv, intr)) { + new_intersections.push_back(intr); } } } @@ -275,125 +409,49 @@ namespace datalog { root.add_child(new_n); } - -#if 0 - - DDNFNode InsertTBV(TernaryBitVector aTbv) - { - foreach (DDNFNode node in allNodes) - { - if (node.tbv.IsEqualset(aTbv)) - { - return node; - } - } - DDNFNode newNode = new DDNFNode(aTbv); - this.allNodes.Add(newNode); - List newIntersections = new List(); - InsertNewNode(this.root, newNode, newIntersections); - - // add the TBVs corresponding to new intersections - foreach (TernaryBitVector newIntr in newIntersections) - { - // this assert guarantees termination since you can only - // insert smaller tbvs recursively - Debug.Assert(!newIntr.IsSupset(aTbv)); - - InsertTBV(newIntr); - } - - return newNode; - } - - public void InsertDot(DOT aDot) - { - this.allDots.Add(aDot); - DDNFNode posNode = InsertTBV(aDot.pos); - List negNodes = new List(); - foreach (TernaryBitVector neg in aDot.negs) - { - negNodes.Add(InsertTBV(neg)); - } - - posNode.posDots.Add(aDot); - foreach (DDNFNode negNode in negNodes) - { - negNode.negDots.Add(aDot); + void internalize() { + // create map: dot |-> ddnf_node set + if (!m_internalized) { + vector dots1, dots2; + add_pos(*m_root, dots1); + del_neg(*m_root, dots2); + m_internalized = true; } } - // remove all negNodes for each dot in dot2Nodes - void RemoveNegNodesForAllDots(DDNFNode aNode, HashSet activeDots, - ref Dictionary> dot2Nodes) - { - foreach (DOT negDot in aNode.negDots) - { - activeDots.Add(negDot); - } - - foreach (DOT activeDot in activeDots) - { - dot2Nodes[activeDot].Remove(aNode); - } - - foreach (DDNFNode child in aNode.children) - - { - RemoveNegNodesForAllDots(child, new HashSet(activeDots), ref dot2Nodes); - } + ddnf_nodes const& lookup(dot const& d) const { + return *m_dots.find(d); } - // add all posNodes for each dot in dot2Nodes - void AddPosNodesForAllDots(DDNFNode aNode, HashSet activeDots, - ref Dictionary> dot2Nodes) - { - foreach (DOT posDot in aNode.posDots) - { - activeDots.Add(posDot); + void add_pos(ddnf_node& n, vector& active) { + for (unsigned i = 0; i < n.pos().size(); ++i) { + active.push_back(n.pos()[i]); + // TBD: Garvit; prove (or disprove): there are no repetitions. + // the argument may be that the sub-expressions are + // traversed in DFS order, and that repeated dots + // cannot occur below each-other. } - - foreach (DOT activeDot in activeDots) - { - dot2Nodes[activeDot].Add(aNode); - } - - foreach (DDNFNode child in aNode.children) - { - AddPosNodesForAllDots(child, new HashSet(activeDots), ref dot2Nodes); + for (unsigned i = 0; i < active.size(); ++i) { + m_dots.find(active[i])->insert(&n); } + for (unsigned i = 0; i < n.num_children(); ++i) { + vector active1(active); + add_pos(*n[i], active1); + } } - public Dictionary> NodesForAllDots() - { - Dictionary> dot2Nodes = - new Dictionary>(); - - foreach (DOT dot in allDots) - { - dot2Nodes[dot] = new HashSet(); + void del_neg(ddnf_node& n, vector& active) { + for (unsigned i = 0; i < n.neg().size(); ++i) { + active.push_back(n.neg()[i]); } - AddPosNodesForAllDots(this.root, new HashSet(), ref dot2Nodes); - RemoveNegNodesForAllDots(this.root, new HashSet(), ref dot2Nodes); - - return dot2Nodes; - - } - public string PrintNodes() - { - StringBuilder retVal = new StringBuilder(); - retVal.Append("remove(&n); } - return retVal.Append(">").ToString(); - } - } - - -} - -#endif + for (unsigned i = 0; i < n.num_children(); ++i) { + vector active1(active); + del_neg(*n[i], active1); + } + } }; diff --git a/src/util/bit_vector.cpp b/src/util/bit_vector.cpp index 207d22d6a..c0c385210 100644 --- a/src/util/bit_vector.cpp +++ b/src/util/bit_vector.cpp @@ -224,6 +224,10 @@ bool bit_vector::contains(bit_vector const& other) const { return (m_data[n-1] & other_data) == other_data; } +unsigned bit_vector::get_hash() const { + return string_hash(reinterpret_cast(m_data), size()/8, 0); +} + void fr_bit_vector::reset() { unsigned sz = size(); unsigned_vector::const_iterator it = m_one_idxs.begin(); diff --git a/src/util/bit_vector.h b/src/util/bit_vector.h index c703f524b..6ec2c18ee 100644 --- a/src/util/bit_vector.h +++ b/src/util/bit_vector.h @@ -125,6 +125,8 @@ public: unsigned get_word(unsigned word_idx) const { return m_data[word_idx]; } + + unsigned get_hash() const; bool get(unsigned bit_idx) const { SASSERT(bit_idx < size()); From eaabae3219c58580d4f3c1ee770be2ecf6b37e17 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 21 Aug 2014 22:16:51 -0700 Subject: [PATCH 475/925] more ddnf Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/ddnf.cpp | 113 ++++++++++++++++++++++++++++-------------- 1 file changed, 77 insertions(+), 36 deletions(-) diff --git a/src/muz/ddnf/ddnf.cpp b/src/muz/ddnf/ddnf.cpp index c856b6903..686c9f300 100644 --- a/src/muz/ddnf/ddnf.cpp +++ b/src/muz/ddnf/ddnf.cpp @@ -21,19 +21,9 @@ Revision History: --*/ #include "ddnf.h" -#include "trail.h" #include "dl_rule_set.h" #include "dl_context.h" -#include "dl_mk_rule_inliner.h" -#include "smt_kernel.h" -#include "qe_lite.h" -#include "bool_rewriter.h" -#include "th_rewriter.h" -#include "datatype_decl_plugin.h" -#include "for_each_expr.h" -#include "matcher.h" #include "scoped_proof.h" -#include "fixedpoint_params.hpp" namespace datalog { @@ -167,11 +157,18 @@ namespace datalog { public: dot() {} dot(tbv const& pos, vector const& negs): - m_pos(pos), m_negs(negs) {} + m_pos(pos), m_negs(negs) { + DEBUG_CODE( + for (unsigned i = 0; i < negs.size(); ++i) { + SASSERT(pos.size() == negs[i].size()); + } + ); + } tbv const& pos() const { return m_pos; } tbv neg(unsigned i) const { return m_negs[i]; } unsigned size() const { return m_negs.size(); } + unsigned num_bits() const { return m_pos.size(); } bool operator==(dot const& other) const { if (m_pos != other.m_pos) return false; @@ -195,12 +192,7 @@ namespace datalog { struct eq { bool operator()(dot const& d1, dot const& d2) const { - if (d1.pos() != d2.pos()) return false; - if (d1.size() != d2.size()) return false; - for (unsigned i = 0; i < d1.size(); ++i) { - if (d1.neg(i) != d2.neg(i)) return false; - } - return true; + return d1 == d2; } }; @@ -295,15 +287,16 @@ namespace datalog { }; typedef ptr_hashtable ddnf_nodes; + typedef map dot2nodes; class ddnf_mgr { - unsigned m_num_bits; - ddnf_node* m_root; + unsigned m_num_bits; + ddnf_node* m_root; ddnf_node_vector m_noderefs; ddnf_nodes m_nodes; ptr_vector m_tables; - map m_dots; - bool m_internalized; + dot2nodes m_dots; + bool m_internalized; public: ddnf_mgr(unsigned n): m_num_bits(n), m_noderefs(*this), m_internalized(false) { m_root = alloc(ddnf_node, *this, tbv(n, BIT_x), m_nodes.size()); @@ -325,6 +318,7 @@ namespace datalog { } void insert(dot const& d) { + SASSERT(d.size() == m_num_bits); SASSERT(!m_internalized); if (m_dots.contains(d)) return; ddnf_nodes* ns = alloc(ddnf_nodes); @@ -336,6 +330,11 @@ namespace datalog { } } + ddnf_nodes const& lookup(dot const& d) { + internalize(); + return *m_dots.find(d); + } + void display(std::ostream& out) const { for (unsigned i = 0; i < m_noderefs.size(); ++i) { m_noderefs[i]->display(out); @@ -409,6 +408,7 @@ namespace datalog { root.add_child(new_n); } + void internalize() { // create map: dot |-> ddnf_node set if (!m_internalized) { @@ -418,11 +418,7 @@ namespace datalog { m_internalized = true; } } - - ddnf_nodes const& lookup(dot const& d) const { - return *m_dots.find(d); - } - + void add_pos(ddnf_node& n, vector& active) { for (unsigned i = 0; i < n.pos().size(); ++i) { active.push_back(n.pos()[i]); @@ -455,19 +451,54 @@ namespace datalog { }; -void ddnf_node::add_child(ddnf_node* n) { - SASSERT(!m_tbv.is_subset(n->m_tbv)); - m_children.push_back(n); -} + void ddnf_node::add_child(ddnf_node* n) { + SASSERT(!m_tbv.is_subset(n->m_tbv)); + m_children.push_back(n); + } + + void ddnf_node::remove_child(ddnf_node* n) { + m_children.erase(n); + } + + bool ddnf_node::contains_child(ddnf_node* n) const { + return m_children.contains(n); + } -void ddnf_node::remove_child(ddnf_node* n) { - m_children.erase(n); -} -bool ddnf_node::contains_child(ddnf_node* n) const { - return m_children.contains(n); -} + class ddnfs { + u_map m_mgrs; + public: + ddnfs() {} + ~ddnfs() { + u_map::iterator it = m_mgrs.begin(), end = m_mgrs.end(); + for (; it != end; ++it) { + dealloc(it->m_value); + } + } + + void insert(dot const& d) { + unsigned n = d.num_bits(); + ddnf_mgr* m = 0; + if (!m_mgrs.find(n, m)) { + m = alloc(ddnf_mgr, n); + m_mgrs.insert(n, m); + } + m->insert(d); + } + + ddnf_nodes const& lookup(dot const& d) const { + return m_mgrs.find(d.num_bits())->lookup(d); + } + + void display(std::ostream& out) const { + u_map::iterator it = m_mgrs.begin(), end = m_mgrs.end(); + for (; it != end; ++it) { + it->m_value->display(out); + } + } + + }; class ddnf::imp { @@ -482,6 +513,7 @@ bool ddnf_node::contains_child(ddnf_node* n) const { volatile bool m_cancel; ptr_vector m_todo; ast_mark m_visited1, m_visited2; + ddnfs m_ddnfs; stats m_stats; public: @@ -528,6 +560,7 @@ bool ddnf_node::contains_child(ddnf_node* n) const { UNREACHABLE(); return expr_ref(m.mk_true(), m); } + private: proof_ref get_proof() const { @@ -644,6 +677,14 @@ bool ddnf_node::contains_child(ddnf_node* n) const { return true; } + void compile(expr* e) { + // TBD: + // compiles monadic predicates into dots. + // saves the mapping from expr |-> dot + // such that atomic sub-formula can be expressed + // as a set of ddnf_nodes + } + }; ddnf::ddnf(context& ctx): From 3d0cb6a5e91759e96e7cf4ccb00eb950b5a2ee10 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 21 Aug 2014 23:48:36 -0700 Subject: [PATCH 476/925] more ddnf Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/ddnf.cpp | 208 +++++++++++++++++++++++++++++------------- 1 file changed, 145 insertions(+), 63 deletions(-) diff --git a/src/muz/ddnf/ddnf.cpp b/src/muz/ddnf/ddnf.cpp index 686c9f300..ce9a1934e 100644 --- a/src/muz/ddnf/ddnf.cpp +++ b/src/muz/ddnf/ddnf.cpp @@ -24,6 +24,7 @@ Revision History: #include "dl_rule_set.h" #include "dl_context.h" #include "scoped_proof.h" +#include "bv_decl_plugin.h" namespace datalog { @@ -43,6 +44,7 @@ namespace datalog { resize(n, val); } tbv(uint64 val, unsigned n) : bit_vector(2*n) { + resize(n, BIT_x); for (unsigned bit = n; bit > 0;) { --bit; if (val & (1ULL << bit)) { @@ -53,6 +55,14 @@ namespace datalog { } } + tbv(uint64 v, unsigned sz, unsigned hi, unsigned lo) : bit_vector(2*sz) { + resize(sz, BIT_x); + SASSERT(64 >= sz && sz > hi && hi >= lo); + for (unsigned i = 0; i < hi - lo + 1; ++i) { + set(lo + i, (v & (1ULL << i))?BIT_1:BIT_0); + } + } + tbv(rational const& v, unsigned n) : bit_vector(2*n) { if (v.is_uint64() && n <= 64) { tbv tmp(v.get_uint64(), n); @@ -60,6 +70,7 @@ namespace datalog { return; } + resize(n, BIT_x); for (unsigned bit = n; bit > 0; ) { --bit; if (bitwise_and(v, rational::power_of_two(bit)).is_zero()) { @@ -126,6 +137,19 @@ namespace datalog { } } } + + struct eq { + bool operator()(tbv const& d1, tbv const& d2) const { + return d1 == d2; + } + }; + + struct hash { + unsigned operator()(tbv const& d) const { + return d.get_hash(); + } + }; + friend bool intersect(tbv const& a, tbv const& b, tbv& result); @@ -142,6 +166,11 @@ namespace datalog { } }; + std::ostream& operator<<(std::ostream& out, tbv const& t) { + t.display(out); + return out; + } + bool intersect(tbv const& a, tbv const& b, tbv& result) { result = a; result &= b; @@ -156,6 +185,7 @@ namespace datalog { vector m_negs; public: dot() {} + dot(tbv const& pos): m_pos(pos) {} dot(tbv const& pos, vector const& negs): m_pos(pos), m_negs(negs) { DEBUG_CODE( @@ -277,7 +307,7 @@ namespace datalog { ddnf_node* add_neg(dot const& d) { m_neg.push_back(d); return this; } void display(std::ostream& out) const { - out << "node["; + out << "node[" << get_id() << ": "; m_tbv.display(out); for (unsigned i = 0; i < m_children.size(); ++i) { out << " " << m_children[i]->get_id(); @@ -317,24 +347,33 @@ namespace datalog { n->dec_ref(); } - void insert(dot const& d) { - SASSERT(d.size() == m_num_bits); + void insert(dot const& d) { + SASSERT(d.num_bits() == m_num_bits); SASSERT(!m_internalized); if (m_dots.contains(d)) return; ddnf_nodes* ns = alloc(ddnf_nodes); m_tables.push_back(ns); m_dots.insert(d, ns); - insert(d.pos())->add_pos(d); + insert_tbv(d.pos())->add_pos(d); for (unsigned i = 0; i < d.size(); ++i) { - insert(d.neg(i))->add_neg(d); + insert_tbv(d.neg(i))->add_neg(d); } } + void insert(tbv const& t) { + insert(dot(t)); + } + ddnf_nodes const& lookup(dot const& d) { internalize(); return *m_dots.find(d); } + ddnf_nodes const& lookup(tbv const& t) { + internalize(); + return *m_dots.find(dot(t)); + } + void display(std::ostream& out) const { for (unsigned i = 0; i < m_noderefs.size(); ++i) { m_noderefs[i]->display(out); @@ -344,7 +383,18 @@ namespace datalog { private: - ddnf_node* insert(tbv const& t) { + + ddnf_node* find(tbv const& t) { + ddnf_node dummy(*this, t, 0); + return *(m_nodes.find(&dummy)); + } + + bool contains(tbv const& t) { + ddnf_node dummy(*this, t, 0); + return m_nodes.contains(&dummy); + } + + ddnf_node* insert_tbv(tbv const& t) { vector new_tbvs; new_tbvs.push_back(t); for (unsigned i = 0; i < new_tbvs.size(); ++i) { @@ -358,15 +408,6 @@ namespace datalog { return find(t); } - ddnf_node* find(tbv const& t) { - ddnf_node dummy(*this, t, 0); - return *(m_nodes.find(&dummy)); - } - - bool contains(tbv const& t) { - ddnf_node dummy(*this, t, 0); - return m_nodes.contains(&dummy); - } void insert(ddnf_node& root, ddnf_node* new_n, vector& new_intersections) { tbv const& new_tbv = new_n->get_tbv(); @@ -486,6 +527,10 @@ namespace datalog { } m->insert(d); } + + void insert(tbv const& t) { + insert(dot(t)); + } ddnf_nodes const& lookup(dot const& d) const { return m_mgrs.find(d.num_bits())->lookup(d); @@ -510,17 +555,20 @@ namespace datalog { context& m_ctx; ast_manager& m; rule_manager& rm; + bv_util bv; volatile bool m_cancel; ptr_vector m_todo; ast_mark m_visited1, m_visited2; ddnfs m_ddnfs; stats m_stats; + obj_map m_cache; public: imp(context& ctx): m_ctx(ctx), m(ctx.get_manager()), rm(ctx.get_rule_manager()), + bv(m), m_cancel(false) { } @@ -529,10 +577,11 @@ namespace datalog { lbool query(expr* query) { m_ctx.ensure_opened(); - if (!can_handle_rules()) { + if (!process_rules()) { return l_undef; } IF_VERBOSE(0, verbose_stream() << "rules are OK\n";); + IF_VERBOSE(0, m_ddnfs.display(verbose_stream());); return run(); } @@ -573,28 +622,29 @@ namespace datalog { return l_undef; } - bool can_handle_rules() { + bool process_rules() { m_visited1.reset(); m_todo.reset(); + m_cache.reset(); rule_set const& rules = m_ctx.get_rules(); datalog::rule_set::iterator it = rules.begin(); datalog::rule_set::iterator end = rules.end(); for (; it != end; ++it) { - if (!can_handle_rule(**it)) { + if (!process_rule(**it)) { return false; } } return true; } - bool can_handle_rule(rule const& r) { + bool process_rule(rule const& r) { // all predicates are monadic. unsigned utsz = r.get_uninterpreted_tail_size(); unsigned sz = r.get_tail_size(); for (unsigned i = utsz; i < sz; ++i) { m_todo.push_back(r.get_tail(i)); } - if (check_monadic()) { + if (process_todo()) { return true; } else { @@ -603,8 +653,7 @@ namespace datalog { } } - bool check_monadic() { - expr* e1, *e2; + bool process_todo() { while (!m_todo.empty()) { expr* e = m_todo.back(); m_todo.pop_back(); @@ -626,63 +675,96 @@ namespace datalog { m_todo.append(to_app(e)->get_num_args(), to_app(e)->get_args()); continue; } - if (m.is_eq(e, e1, e2)) { - if (is_var(e1) && is_ground(e2)) { - continue; - } - if (is_var(e2) && is_ground(e1)) { - continue; - } - if (is_var(e1) && is_var(e2)) { - continue; - } - } if (is_ground(e)) { continue; } - if (is_unary(e)) { + if (process_atomic(e)) { continue; } IF_VERBOSE(0, verbose_stream() << "Could not handle: " << mk_pp(e, m) << "\n";); return false; } return true; + } + + bool process_atomic(expr* e) { + expr* e1, *e2, *e3; + unsigned lo, hi; + + if (m.is_eq(e, e1, e2) && bv.is_bv(e1)) { + if (is_var(e1) && is_ground(e2)) { + return process_eq(e, to_var(e1), bv.get_bv_size(e1)-1, 0, e2); + } + if (is_var(e2) && is_ground(e1)) { + return process_eq(e, to_var(e2), bv.get_bv_size(e2)-1, 0, e1); + } + if (bv.is_extract(e1, lo, hi, e3) && is_var(e3) && is_ground(e2)) { + return process_eq(e, to_var(e3), hi, lo, e2); + } + if (bv.is_extract(e2, lo, hi, e3) && is_var(e3) && is_ground(e1)) { + return process_eq(e, to_var(e3), hi, lo, e1); + } + if (is_var(e1) && is_var(e2)) { + std::cout << mk_pp(e, m) << "\n"; + return true; + } + } + return false; } - bool is_unary(expr* e) { - var* v = 0; - m_visited2.reset(); - unsigned sz = m_todo.size(); - m_todo.push_back(e); - while (m_todo.size() > sz) { - expr* e = m_todo.back(); - m_todo.pop_back(); - if (m_visited2.is_marked(e)) { - continue; - } - m_visited2.mark(e, true); - if (is_var(e)) { - if (v && v != e) { - return false; - } - v = to_var(e); - } - else if (is_app(e)) { - m_todo.append(to_app(e)->get_num_args(), to_app(e)->get_args()); - } - else { - return false; - } + bool process_eq(expr* e, var* v, unsigned hi, unsigned lo, expr* c) { + rational val; + unsigned sz_c; + unsigned sz_v = bv.get_bv_size(v); + if (!bv.is_numeral(c, val, sz_c)) { + return false; } + if (!val.is_uint64()) { + return false; + } + // v[hi:lo] = val + tbv tbv(val.get_uint64(), sz_v, hi, lo); + m_ddnfs.insert(tbv); + m_cache.insert(e, tbv); + std::cout << mk_pp(v, m) << " " << lo << " " << hi << " " << v << " " << tbv << "\n"; return true; } - void compile(expr* e) { + void compile(expr* phi) { // TBD: - // compiles monadic predicates into dots. - // saves the mapping from expr |-> dot - // such that atomic sub-formula can be expressed - // as a set of ddnf_nodes + + // for each v + // associate a set of ddnf nodes that they can + // take. + // - for each v, find the number of nodes associated with + // bit-width of v. + // - associate bit-vector for such nodes (the ids are consecutive). + // - compile formula into cross-product of such ranges. + // - disjunction requires special casing (which is not typical case) + // - negation over a tbv is the complemment of the set associated with + // the tbv. + + + // extract(hi, lo, v) == k + // |-> + // tbv (set of nodes associated with tbv) + + // compile(not (phi)) + // |-> complement of ddnf nodes associated with phi + + // compile (phi1 & phi2) + // |-> intersection of ddnf nodes associated with phi1, phi2 + + // compile (phi | phi2) + // |-> union + + // v1 == v2 + // no-op !!! + + // extract(hi1, lo1, v) == extract(h2, lo2, v) + // |-> TBD + + // } }; From dcdd7e36471fdb6dd0fd3daaee3166b315ce9244 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 22 Aug 2014 09:01:58 -0700 Subject: [PATCH 477/925] ddnf Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/ddnf.cpp | 489 ++++++++++++++++++++++++------------------ 1 file changed, 286 insertions(+), 203 deletions(-) diff --git a/src/muz/ddnf/ddnf.cpp b/src/muz/ddnf/ddnf.cpp index ce9a1934e..926b88a27 100644 --- a/src/muz/ddnf/ddnf.cpp +++ b/src/muz/ddnf/ddnf.cpp @@ -180,76 +180,33 @@ namespace datalog { return true; } - class dot { - tbv m_pos; - vector m_negs; - public: - dot() {} - dot(tbv const& pos): m_pos(pos) {} - dot(tbv const& pos, vector const& negs): - m_pos(pos), m_negs(negs) { - DEBUG_CODE( - for (unsigned i = 0; i < negs.size(); ++i) { - SASSERT(pos.size() == negs[i].size()); - } - ); - } - - tbv const& pos() const { return m_pos; } - tbv neg(unsigned i) const { return m_negs[i]; } - unsigned size() const { return m_negs.size(); } - unsigned num_bits() const { return m_pos.size(); } - - bool operator==(dot const& other) const { - if (m_pos != other.m_pos) return false; - if (m_negs.size() != other.m_negs.size()) return false; - for (unsigned i = 0; i < m_negs.size(); ++i) { - if (m_negs[i] != other.m_negs[i]) return false; - } - return true; - } - - void display(std::ostream& out) { - out << "<"; - m_pos.display(out); - out << "\\"; - for (unsigned i = 0; i < m_negs.size(); ++i) { - m_negs[i].display(out); - if (i + 1 < m_negs.size()) out << " u "; - } - out << ">"; - } - - struct eq { - bool operator()(dot const& d1, dot const& d2) const { - return d1 == d2; - } - }; - - struct hash { - unsigned operator()(dot const& d) const { - unsigned h = d.pos().get_hash(); - for (unsigned i = 0; i < d.size(); ++i) { - h ^= d.neg(i).get_hash(); - } - return h; - } - }; - - }; - class ddnf_mgr; class ddnf_node; typedef ref_vector ddnf_node_vector; class ddnf_node { + public: + + struct eq { + bool operator()(ddnf_node* n1, ddnf_node* n2) const { + return n1->get_tbv() == n2->get_tbv(); + } + }; + + struct hash { + unsigned operator()(ddnf_node* n) const { + return n->get_tbv().get_hash(); + } + }; + + typedef ptr_hashtable ddnf_nodes; + private: tbv m_tbv; ddnf_node_vector m_children; - vector m_pos; - vector m_neg; unsigned m_refs; unsigned m_id; - + ddnf_nodes m_descendants; + friend class ddnf_mgr; public: @@ -274,17 +231,7 @@ namespace datalog { } } - struct eq { - bool operator()(ddnf_node* n1, ddnf_node* n2) const { - return n1->get_tbv() == n2->get_tbv(); - } - }; - - struct hash { - unsigned operator()(ddnf_node* n) const { - return n->get_tbv().get_hash(); - } - }; + ddnf_nodes& descendants() { return m_descendants; } unsigned get_id() const { return m_id; } @@ -293,8 +240,6 @@ namespace datalog { ddnf_node* operator[](unsigned index) { return m_children[index].get(); } tbv const& get_tbv() const { return m_tbv; } - vector const& pos() const { return m_pos; } - vector const& neg() const { return m_neg; } void add_child(ddnf_node* n); @@ -302,10 +247,6 @@ namespace datalog { bool contains_child(ddnf_node* n) const; - ddnf_node* add_pos(dot const& d) { m_pos.push_back(d); return this; } - - ddnf_node* add_neg(dot const& d) { m_neg.push_back(d); return this; } - void display(std::ostream& out) const { out << "node[" << get_id() << ": "; m_tbv.display(out); @@ -316,16 +257,14 @@ namespace datalog { } }; - typedef ptr_hashtable ddnf_nodes; - typedef map dot2nodes; + typedef ddnf_node::ddnf_nodes ddnf_nodes; + class ddnf_mgr { unsigned m_num_bits; ddnf_node* m_root; ddnf_node_vector m_noderefs; ddnf_nodes m_nodes; - ptr_vector m_tables; - dot2nodes m_dots; bool m_internalized; public: ddnf_mgr(unsigned n): m_num_bits(n), m_noderefs(*this), m_internalized(false) { @@ -336,7 +275,6 @@ namespace datalog { ~ddnf_mgr() { m_noderefs.reset(); - std::for_each(m_tables.begin(), m_tables.end(), delete_proc()); } void inc_ref(ddnf_node* n) { @@ -347,31 +285,25 @@ namespace datalog { n->dec_ref(); } - void insert(dot const& d) { - SASSERT(d.num_bits() == m_num_bits); + ddnf_node* insert(tbv const& t) { + SASSERT(t.size() == m_num_bits); SASSERT(!m_internalized); - if (m_dots.contains(d)) return; - ddnf_nodes* ns = alloc(ddnf_nodes); - m_tables.push_back(ns); - m_dots.insert(d, ns); - insert_tbv(d.pos())->add_pos(d); - for (unsigned i = 0; i < d.size(); ++i) { - insert_tbv(d.neg(i))->add_neg(d); + vector new_tbvs; + new_tbvs.push_back(t); + for (unsigned i = 0; i < new_tbvs.size(); ++i) { + tbv const& nt = new_tbvs[i]; + if (contains(nt)) continue; + ddnf_node* n = alloc(ddnf_node, *this, nt, m_noderefs.size()); + m_noderefs.push_back(n); + m_nodes.insert(n); + insert(*m_root, n, new_tbvs); } - } - - void insert(tbv const& t) { - insert(dot(t)); - } - - ddnf_nodes const& lookup(dot const& d) { - internalize(); - return *m_dots.find(d); + return find(t); } ddnf_nodes const& lookup(tbv const& t) { internalize(); - return *m_dots.find(dot(t)); + return find(t)->descendants(); } void display(std::ostream& out) const { @@ -383,7 +315,6 @@ namespace datalog { private: - ddnf_node* find(tbv const& t) { ddnf_node dummy(*this, t, 0); return *(m_nodes.find(&dummy)); @@ -394,21 +325,6 @@ namespace datalog { return m_nodes.contains(&dummy); } - ddnf_node* insert_tbv(tbv const& t) { - vector new_tbvs; - new_tbvs.push_back(t); - for (unsigned i = 0; i < new_tbvs.size(); ++i) { - tbv const& nt = new_tbvs[i]; - if (contains(nt)) continue; - ddnf_node* n = alloc(ddnf_node, *this, nt, m_noderefs.size()); - m_noderefs.push_back(n); - m_nodes.insert(n); - insert(*m_root, n, new_tbvs); - } - return find(t); - } - - void insert(ddnf_node& root, ddnf_node* new_n, vector& new_intersections) { tbv const& new_tbv = new_n->get_tbv(); @@ -435,11 +351,9 @@ namespace datalog { if (child.get_tbv().is_subset(new_tbv)) { subset_children.push_back(&child); } - // this means there is a non-full intersection - else { - if (intersect(child.get_tbv(), new_tbv, intr)) { - new_intersections.push_back(intr); - } + else if (intersect(child.get_tbv(), new_tbv, intr)) { + // this means there is a non-full intersection + new_intersections.push_back(intr); } } for (unsigned i = 0; i < subset_children.size(); ++i) { @@ -451,44 +365,47 @@ namespace datalog { void internalize() { - // create map: dot |-> ddnf_node set - if (!m_internalized) { - vector dots1, dots2; - add_pos(*m_root, dots1); - del_neg(*m_root, dots2); - m_internalized = true; + // populate maps (should be bit-sets) of decendants. + if (m_internalized) { + return; } - } - - void add_pos(ddnf_node& n, vector& active) { - for (unsigned i = 0; i < n.pos().size(); ++i) { - active.push_back(n.pos()[i]); - // TBD: Garvit; prove (or disprove): there are no repetitions. - // the argument may be that the sub-expressions are - // traversed in DFS order, and that repeated dots - // cannot occur below each-other. + ptr_vector todo; + todo.push_back(m_root); + svector done(m_noderefs.size(), false); + while (!todo.empty()) { + ddnf_node& n = *todo.back(); + if (done[n.get_id()]) { + todo.pop_back(); + continue; + } + unsigned sz = n.num_children(); + bool all_done = true; + for (unsigned i = 0; i < sz; ++i) { + ddnf_node* child = n[i]; + if (!done[child->get_id()]) { + all_done = false; + todo.push_back(child); + } + } + if (all_done) { + n.descendants().insert(&n); + for (unsigned i = 0; i < sz; ++i) { + ddnf_node* child = n[i]; + add_table(n.descendants(), child->descendants()); + } + done[n.get_id()] = true; + todo.pop_back(); + } } - for (unsigned i = 0; i < active.size(); ++i) { - m_dots.find(active[i])->insert(&n); - } - for (unsigned i = 0; i < n.num_children(); ++i) { - vector active1(active); - add_pos(*n[i], active1); - } + m_internalized = true; } - void del_neg(ddnf_node& n, vector& active) { - for (unsigned i = 0; i < n.neg().size(); ++i) { - active.push_back(n.neg()[i]); + void add_table(ddnf_nodes& dst, ddnf_nodes const& src) { + ddnf_nodes::iterator it = src.begin(), end = src.end(); + for (; it != end; ++it) { + dst.insert(*it); } - for (unsigned i = 0; i < active.size(); ++i) { - m_dots.find(active[i])->remove(&n); - } - for (unsigned i = 0; i < n.num_children(); ++i) { - vector active1(active); - del_neg(*n[i], active1); - } - } + } }; @@ -518,22 +435,18 @@ namespace datalog { } } - void insert(dot const& d) { - unsigned n = d.num_bits(); + void insert(tbv const& t) { + unsigned n = t.size(); ddnf_mgr* m = 0; if (!m_mgrs.find(n, m)) { m = alloc(ddnf_mgr, n); m_mgrs.insert(n, m); } - m->insert(d); - } - - void insert(tbv const& t) { - insert(dot(t)); + m->insert(t); } - ddnf_nodes const& lookup(dot const& d) const { - return m_mgrs.find(d.num_bits())->lookup(d); + ddnf_node::ddnf_nodes const& lookup(tbv const& t) const { + return m_mgrs.find(t.size())->lookup(t); } void display(std::ostream& out) const { @@ -542,10 +455,10 @@ namespace datalog { it->m_value->display(out); } } - }; + class ddnf::imp { struct stats { stats() { reset(); } @@ -577,7 +490,10 @@ namespace datalog { lbool query(expr* query) { m_ctx.ensure_opened(); - if (!process_rules()) { + if (!pre_process_rules()) { + return l_undef; + } + if (!compile_rules()) { return l_undef; } IF_VERBOSE(0, verbose_stream() << "rules are OK\n";); @@ -622,7 +538,20 @@ namespace datalog { return l_undef; } - bool process_rules() { + bool compile_rules() { + rule_set const& rules = m_ctx.get_rules(); + datalog::rule_set::iterator it = rules.begin(); + datalog::rule_set::iterator end = rules.end(); + unsigned idx = 0; + for (; it != end; ++idx, ++it) { + if (!compile_rule(**it, idx)) { + return false; + } + } + return true; + } + + bool pre_process_rules() { m_visited1.reset(); m_todo.reset(); m_cache.reset(); @@ -630,14 +559,14 @@ namespace datalog { datalog::rule_set::iterator it = rules.begin(); datalog::rule_set::iterator end = rules.end(); for (; it != end; ++it) { - if (!process_rule(**it)) { + if (!pre_process_rule(**it)) { return false; } } return true; } - bool process_rule(rule const& r) { + bool pre_process_rule(rule const& r) { // all predicates are monadic. unsigned utsz = r.get_uninterpreted_tail_size(); unsigned sz = r.get_tail_size(); @@ -730,41 +659,44 @@ namespace datalog { return true; } - void compile(expr* phi) { + bool compile_rule(rule& r, unsigned idx) { + return true; + + // // TBD: - - // for each v - // associate a set of ddnf nodes that they can - // take. - // - for each v, find the number of nodes associated with - // bit-width of v. - // - associate bit-vector for such nodes (the ids are consecutive). - // - compile formula into cross-product of such ranges. - // - disjunction requires special casing (which is not typical case) - // - negation over a tbv is the complemment of the set associated with - // the tbv. - - - // extract(hi, lo, v) == k - // |-> - // tbv (set of nodes associated with tbv) - - // compile(not (phi)) - // |-> complement of ddnf nodes associated with phi - - // compile (phi1 & phi2) - // |-> intersection of ddnf nodes associated with phi1, phi2 - - // compile (phi | phi2) - // |-> union - - // v1 == v2 - // no-op !!! - - // extract(hi1, lo1, v) == extract(h2, lo2, v) - // |-> TBD - + // 1: H(x) :- P(x), phi(x). + // 2: H(x) :- P(y), phi(x), psi(y). + // 3: H(x) :- P(y), R(z), phi(x), psi(y), rho(z). + // 4: general case ... // + // 1. compile phi(x) into a filter set. + // map each element in the filter set into P |-> E |-> rule + // 2. compile psi(y) into filter set P |-> E |-> rule + // 3. compile P |-> E |-> (rule,1), 2. R |-> E |-> rule (map for second position). + // + // E |-> rule is trie for elements of tuple E into set of rules as a bit-vector. + // + + // work list + + if (is_forwarding_rule(r)) { + return true; + } + // r.display(m_ctx, std::cout); + return true; + } + + bool is_forwarding_rule(rule const& r) { + unsigned utsz = r.get_uninterpreted_tail_size(); + unsigned sz = r.get_tail_size(); + if (utsz != 1) return false; + app* h = r.get_head(); + app* p = r.get_tail(0); + if (h->get_num_args() != p->get_num_args()) return false; + for (unsigned i = 0; i < h->get_num_args(); ++i) { + if (h->get_arg(i) != p->get_arg(i)) return false; + } + return true; } }; @@ -799,3 +731,154 @@ namespace datalog { } }; + +#if 0 + + void add_pos(ddnf_node& n, vector& active) { + for (unsigned i = 0; i < n.pos().size(); ++i) { + active.push_back(n.pos()[i]); + // TBD: Garvit; prove (or disprove): there are no repetitions. + // the argument may be that the sub-expressions are + // traversed in DFS order, and that repeated dots + // cannot occur below each-other. + } + for (unsigned i = 0; i < active.size(); ++i) { + m_dots.find(active[i])->insert(&n); + } + for (unsigned i = 0; i < n.num_children(); ++i) { + vector active1(active); + add_pos(*n[i], active1); + } + } + + void del_neg(ddnf_node& n, vector& active) { + for (unsigned i = 0; i < n.neg().size(); ++i) { + active.push_back(n.neg()[i]); + } + for (unsigned i = 0; i < active.size(); ++i) { + m_dots.find(active[i])->remove(&n); + } + for (unsigned i = 0; i < n.num_children(); ++i) { + vector active1(active); + del_neg(*n[i], active1); + } + } + + class trie { + public: + class node { + + }; + + class leaf : public trie_node { + bit_vector m_set; + public: + leaf(unsigned n): m_set(n) { + m_set.resize(n, false); + } + bit_vector& set() { return m_set; } + }; + + class node : public trie_node { + u_map m_map; + public: + u_map map() { return m_map; } + }; + + // insert + // bv1 x bv2 x bv3 -> set bit-i of n-bits + // such that every value in (bv1,bv2,bv3) maps to an element where bit-i is set. + // for each j1 in bv1: + // if j1 is in root of trie, then insert recursively with bv2, bv3 + // else insert recursively into empty node, each bit in bv1 point + // to returned node. + private: + trie_node* insert(unsigned nbv, bit_vector const* bvs, unsigned i, trie_node* n) { + if (nbv == 0) { + SASSERT(!n); + return mk_leaf(i); + } + bit_vector const& bv = bvs[0]; + if (!n) { + n = insert(nbv-1, bvs+1, i, n); + node* nd = mk_node(); + for (unsigned j = 0; j < bv.size(); ++j) { + if (bv.get(j)) { + nd->map().insert(j, n); + } + } + return nd; + } + + } + }; +#endif + +#if 0 + class dot { + tbv m_pos; + vector m_negs; + public: + dot() {} + dot(tbv const& pos): m_pos(pos) {} + dot(tbv const& pos, vector const& negs): + m_pos(pos), m_negs(negs) { + DEBUG_CODE( + for (unsigned i = 0; i < negs.size(); ++i) { + SASSERT(pos.size() == negs[i].size()); + } + ); + } + + tbv const& pos() const { return m_pos; } + tbv neg(unsigned i) const { return m_negs[i]; } + unsigned size() const { return m_negs.size(); } + unsigned num_bits() const { return m_pos.size(); } + + bool operator==(dot const& other) const { + if (m_pos != other.m_pos) return false; + if (m_negs.size() != other.m_negs.size()) return false; + for (unsigned i = 0; i < m_negs.size(); ++i) { + if (m_negs[i] != other.m_negs[i]) return false; + } + return true; + } + + void display(std::ostream& out) { + out << "<"; + m_pos.display(out); + out << "\\"; + for (unsigned i = 0; i < m_negs.size(); ++i) { + m_negs[i].display(out); + if (i + 1 < m_negs.size()) out << " u "; + } + out << ">"; + } + + struct eq { + bool operator()(dot const& d1, dot const& d2) const { + return d1 == d2; + } + }; + + struct hash { + unsigned operator()(dot const& d) const { + unsigned h = d.pos().get_hash(); + for (unsigned i = 0; i < d.size(); ++i) { + h ^= d.neg(i).get_hash(); + } + return h; + } + }; + + }; + + vector m_pos; + vector m_neg; + vector const& pos() const { return m_pos; } + vector const& neg() const { return m_neg; } + ddnf_node* add_pos(dot const& d) { m_pos.push_back(d); return this; } + ddnf_node* add_neg(dot const& d) { m_neg.push_back(d); return this; } + + +#endif From cc642d26933ea3ec080bde6d54c6f05c38cfe502 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 22 Aug 2014 14:18:36 -0700 Subject: [PATCH 478/925] ddnf Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/ddnf.cpp | 318 +++++++++++++++++++++++++++++++++++------- 1 file changed, 265 insertions(+), 53 deletions(-) diff --git a/src/muz/ddnf/ddnf.cpp b/src/muz/ddnf/ddnf.cpp index 926b88a27..ad0e0ad34 100644 --- a/src/muz/ddnf/ddnf.cpp +++ b/src/muz/ddnf/ddnf.cpp @@ -25,7 +25,7 @@ Revision History: #include "dl_context.h" #include "scoped_proof.h" #include "bv_decl_plugin.h" - +#include "dl_decl_plugin.h" namespace datalog { @@ -301,6 +301,10 @@ namespace datalog { return find(t); } + unsigned size() const { + return m_noderefs.size(); + } + ddnf_nodes const& lookup(tbv const& t) { internalize(); return find(t)->descendants(); @@ -436,16 +440,19 @@ namespace datalog { } void insert(tbv const& t) { - unsigned n = t.size(); - ddnf_mgr* m = 0; - if (!m_mgrs.find(n, m)) { - m = alloc(ddnf_mgr, n); - m_mgrs.insert(n, m); - } - m->insert(t); + get(t.size()).insert(t); } - ddnf_node::ddnf_nodes const& lookup(tbv const& t) const { + ddnf_mgr& get(unsigned sz) { + ddnf_mgr* result = 0; + if (!m_mgrs.find(sz, result)) { + result = insert(sz); + m_mgrs.insert(sz, result); + } + return *result; + } + + ddnf_nodes const& lookup(tbv const& t) const { return m_mgrs.find(t.size())->lookup(t); } @@ -455,10 +462,19 @@ namespace datalog { it->m_value->display(out); } } + + private: + + ddnf_mgr* insert(unsigned n) { + ddnf_mgr* m = 0; + if (!m_mgrs.find(n, m)) { + m = alloc(ddnf_mgr, n); + m_mgrs.insert(n, m); + } + return m; + } }; - - class ddnf::imp { struct stats { stats() { reset(); } @@ -469,12 +485,16 @@ namespace datalog { ast_manager& m; rule_manager& rm; bv_util bv; + dl_decl_util dl; volatile bool m_cancel; ptr_vector m_todo; ast_mark m_visited1, m_visited2; ddnfs m_ddnfs; stats m_stats; - obj_map m_cache; + obj_map m_expr2tbv; + obj_map m_cache; + expr_ref_vector m_trail; + context m_inner_ctx; public: imp(context& ctx): @@ -482,27 +502,37 @@ namespace datalog { m(ctx.get_manager()), rm(ctx.get_rule_manager()), bv(m), - m_cancel(false) + dl(m), + m_cancel(false), + m_trail(m), + m_inner_ctx(m, m_ctx.get_register_engine(), m_ctx.get_fparams()) { + params_ref params; + params.set_sym("engine", symbol("datalog")); + m_inner_ctx.updt_params(params); } ~imp() {} lbool query(expr* query) { m_ctx.ensure_opened(); + rule_set new_rules(m_ctx); if (!pre_process_rules()) { return l_undef; } - if (!compile_rules()) { + if (!compile_rules1(new_rules)) { return l_undef; } + return execute_rules(new_rules); + IF_VERBOSE(0, verbose_stream() << "rules are OK\n";); - IF_VERBOSE(0, m_ddnfs.display(verbose_stream());); + IF_VERBOSE(2, m_ddnfs.display(verbose_stream());); return run(); } void cancel() { m_cancel = true; + m_inner_ctx.cancel(); } void cleanup() { @@ -538,23 +568,12 @@ namespace datalog { return l_undef; } - bool compile_rules() { - rule_set const& rules = m_ctx.get_rules(); - datalog::rule_set::iterator it = rules.begin(); - datalog::rule_set::iterator end = rules.end(); - unsigned idx = 0; - for (; it != end; ++idx, ++it) { - if (!compile_rule(**it, idx)) { - return false; - } - } - return true; - } bool pre_process_rules() { m_visited1.reset(); m_todo.reset(); m_cache.reset(); + m_expr2tbv.reset(); rule_set const& rules = m_ctx.get_rules(); datalog::rule_set::iterator it = rules.begin(); datalog::rule_set::iterator end = rules.end(); @@ -634,7 +653,6 @@ namespace datalog { return process_eq(e, to_var(e3), hi, lo, e1); } if (is_var(e1) && is_var(e2)) { - std::cout << mk_pp(e, m) << "\n"; return true; } } @@ -654,38 +672,211 @@ namespace datalog { // v[hi:lo] = val tbv tbv(val.get_uint64(), sz_v, hi, lo); m_ddnfs.insert(tbv); - m_cache.insert(e, tbv); - std::cout << mk_pp(v, m) << " " << lo << " " << hi << " " << v << " " << tbv << "\n"; + m_expr2tbv.insert(e, tbv); + // std::cout << mk_pp(v, m) << " " << lo << " " << hi << " " << v << " " << tbv << "\n"; return true; } - bool compile_rule(rule& r, unsigned idx) { - return true; - - // - // TBD: - // 1: H(x) :- P(x), phi(x). - // 2: H(x) :- P(y), phi(x), psi(y). - // 3: H(x) :- P(y), R(z), phi(x), psi(y), rho(z). - // 4: general case ... - // - // 1. compile phi(x) into a filter set. - // map each element in the filter set into P |-> E |-> rule - // 2. compile psi(y) into filter set P |-> E |-> rule - // 3. compile P |-> E |-> (rule,1), 2. R |-> E |-> rule (map for second position). - // - // E |-> rule is trie for elements of tuple E into set of rules as a bit-vector. - // - - // work list - - if (is_forwarding_rule(r)) { - return true; + lbool execute_rules(rule_set& rules) { + ptr_vector heads; + m_inner_ctx.reset(); + rel_context_base& rcx = *m_inner_ctx.get_rel_context(); + func_decl_set const& predicates = m_ctx.get_predicates(); + for (func_decl_set::iterator fit = predicates.begin(); fit != predicates.end(); ++fit) { + m_inner_ctx.register_predicate(*fit, false); } - // r.display(m_ctx, std::cout); + m_inner_ctx.ensure_opened(); + m_inner_ctx.replace_rules(rules); + m_inner_ctx.close(); + rule_set::decl2rules::iterator dit = rules.begin_grouped_rules(); + rule_set::decl2rules::iterator dend = rules.end_grouped_rules(); + for (; dit != dend; ++dit) { + heads.push_back(dit->m_key); + std::cout << mk_pp(dit->m_key, m) << "\n"; + } + return m_inner_ctx.rel_query(heads.size(), heads.c_ptr()); + } + + bool compile_rules1(rule_set& new_rules) { + rule_set const& rules = m_ctx.get_rules(); + datalog::rule_set::iterator it = rules.begin(); + datalog::rule_set::iterator end = rules.end(); + unsigned idx = 0; + for (; it != end; ++idx, ++it) { + if (!compile_rule1(**it, new_rules)) { + return false; + } + } + return true; + } + + bool compile_rule1(rule& r, rule_set& new_rules) { + app_ref head(m), pred(m); + app_ref_vector body(m); + expr_ref tmp(m); + compile_predicate(r.get_head(), head); + unsigned utsz = r.get_uninterpreted_tail_size(); + unsigned sz = r.get_tail_size(); + for (unsigned i = 0; i < utsz; ++i) { + compile_predicate(r.get_tail(i), pred); + body.push_back(pred); + } + for (unsigned i = utsz; i < sz; ++i) { + compile_expr(r.get_tail(i), tmp); + body.push_back(to_app(tmp)); + } + rule* r_new = rm.mk(head, body.size(), body.c_ptr(), 0, r.name(), true); + new_rules.add_rule(r_new); + IF_VERBOSE(2, r_new->display(m_ctx, verbose_stream());); return true; } + void compile_predicate(app* p, app_ref& result) { + sort_ref_vector domain(m); + func_decl* d = p->get_decl(); + SASSERT(d->get_family_id() == null_family_id); + for (unsigned i = 0; i < p->get_num_args(); ++i) { + domain.push_back(compile_sort(m.get_sort(p->get_arg(i)))); + } + func_decl_ref fn(m); + fn = m.mk_func_decl(d->get_name(), domain.size(), domain.c_ptr(), m.mk_bool_sort()); + m_ctx.register_predicate(fn, false); + expr_ref_vector args(m); + expr_ref tmp(m); + for (unsigned i = 0; i < p->get_num_args(); ++i) { + compile_expr(p->get_arg(i), tmp); + args.push_back(tmp); + } + result = m.mk_app(fn, args.size(), args.c_ptr()); + } + + void insert_cache(expr* e, expr* r) { + m_trail.push_back(r); + m_cache.insert(e, r); + } + + void compile_var(var* v, var_ref& result) { + expr* r; + if (m_cache.find(v, r)) { + result = to_var(r); + } + else { + result = m.mk_var(v->get_id(), compile_sort(v->get_sort())); + insert_cache(v, result); + } + } + + sort* compile_sort(sort* s) { + if (m.is_bool(s)) { + return s; + } + if (bv.is_bv_sort(s)) { + unsigned sz = bv.get_bv_size(s); + ddnf_mgr const& mgr = m_ddnfs.get(sz); + unsigned num_elems = mgr.size(); + std::ostringstream strm; + strm << "S" << num_elems; + symbol name(strm.str().c_str()); + return dl.mk_sort(name, num_elems); + } + UNREACHABLE(); + return 0; + } + + void compile_expr(expr* e, expr_ref& result) { + expr* r = 0; + if (m_cache.find(e, r)) { + result = r; + return; + } + + if (is_ground(e)) { + result = e; + m_cache.insert(e, result); + return; + } + + if (is_var(e)) { + var_ref w(m); + compile_var(to_var(e), w); + result = w; + return; + } + + if (m.is_and(e) || + m.is_or(e) || + m.is_iff(e) || + m.is_not(e) || + m.is_implies(e)) { + app* a = to_app(e); + expr_ref tmp(m); + expr_ref_vector args(m); + for (unsigned i = 0; i < a->get_num_args(); ++i) { + compile_expr(a->get_arg(i), tmp); + args.push_back(tmp); + } + result = m.mk_app(a->get_decl(), args.size(), args.c_ptr()); + insert_cache(e, result); + return; + } + + expr* e1, *e2, *e3; + unsigned lo, hi; + if (m.is_eq(e, e1, e2) && bv.is_bv(e1)) { + if (is_var(e1) && is_ground(e2)) { + compile_eq(e, result, to_var(e1), bv.get_bv_size(e1)-1, 0, e2); + } + else if (is_var(e2) && is_ground(e1)) { + compile_eq(e, result, to_var(e2), bv.get_bv_size(e2)-1, 0, e1); + } + else if (bv.is_extract(e1, lo, hi, e3) && is_var(e3) && is_ground(e2)) { + compile_eq(e, result, to_var(e3), hi, lo, e2); + } + else if (bv.is_extract(e2, lo, hi, e3) && is_var(e3) && is_ground(e1)) { + compile_eq(e, result, to_var(e3), hi, lo, e1); + } + else if (is_var(e1) && is_var(e2)) { + var_ref v1(m), v2(m); + compile_var(to_var(e1), v1); + compile_var(to_var(e2), v2); + result = m.mk_eq(v1, v2); + } + else { + UNREACHABLE(); + } + insert_cache(e, result); + return; + } + std::cout << mk_pp(e, m) << "\n"; + UNREACHABLE(); + } + + void compile_eq(expr* e, expr_ref& result, var* v, unsigned hi, unsigned lo, expr* c) { + tbv t; + VERIFY(m_expr2tbv.find(e, t)); + var_ref w(m); + compile_var(v, w); + ddnf_nodes const& ns = m_ddnfs.lookup(t); + ddnf_nodes::iterator it = ns.begin(), end = ns.end(); + expr_ref_vector eqs(m); + sort* s = m.get_sort(w); + for (; it != end; ++it) { + eqs.push_back(m.mk_eq(w, dl.mk_numeral((*it)->get_id(), s))); + } + switch (eqs.size()) { + case 0: + UNREACHABLE(); + result = m.mk_false(); + break; + case 1: + result = eqs[0].get(); + break; + default: + result = m.mk_or(eqs.size(), eqs.c_ptr()); + break; + } + } + bool is_forwarding_rule(rule const& r) { unsigned utsz = r.get_uninterpreted_tail_size(); unsigned sz = r.get_tail_size(); @@ -732,8 +923,29 @@ namespace datalog { }; + + + + #if 0 + // + // TBD: + // 1: H(x) :- P(x), phi(x). + // 2: H(x) :- P(y), phi(x), psi(y). + // 3: H(x) :- P(y), R(z), phi(x), psi(y), rho(z). + // 4: general case ... + // + // 1. compile phi(x) into a filter set. + // map each element in the filter set into P |-> E |-> rule + // 2. compile psi(y) into filter set P |-> E |-> rule + // 3. compile P |-> E |-> (rule,1), 2. R |-> E |-> rule (map for second position). + // + // E |-> rule is trie for elements of tuple E into set of rules as a bit-vector. + // + +------------------------------- + void add_pos(ddnf_node& n, vector& active) { for (unsigned i = 0; i < n.pos().size(); ++i) { active.push_back(n.pos()[i]); From c3f2eb773a4936a0f16d996a68342da3ad19fb5d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 22 Aug 2014 14:19:31 -0700 Subject: [PATCH 479/925] ddnf Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/ddnf.cpp | 99 ------------------------------------------- 1 file changed, 99 deletions(-) diff --git a/src/muz/ddnf/ddnf.cpp b/src/muz/ddnf/ddnf.cpp index ad0e0ad34..e80bf144e 100644 --- a/src/muz/ddnf/ddnf.cpp +++ b/src/muz/ddnf/ddnf.cpp @@ -945,37 +945,6 @@ namespace datalog { // ------------------------------- - - void add_pos(ddnf_node& n, vector& active) { - for (unsigned i = 0; i < n.pos().size(); ++i) { - active.push_back(n.pos()[i]); - // TBD: Garvit; prove (or disprove): there are no repetitions. - // the argument may be that the sub-expressions are - // traversed in DFS order, and that repeated dots - // cannot occur below each-other. - } - for (unsigned i = 0; i < active.size(); ++i) { - m_dots.find(active[i])->insert(&n); - } - for (unsigned i = 0; i < n.num_children(); ++i) { - vector active1(active); - add_pos(*n[i], active1); - } - } - - void del_neg(ddnf_node& n, vector& active) { - for (unsigned i = 0; i < n.neg().size(); ++i) { - active.push_back(n.neg()[i]); - } - for (unsigned i = 0; i < active.size(); ++i) { - m_dots.find(active[i])->remove(&n); - } - for (unsigned i = 0; i < n.num_children(); ++i) { - vector active1(active); - del_neg(*n[i], active1); - } - } - class trie { public: class node { @@ -1026,71 +995,3 @@ namespace datalog { }; #endif -#if 0 - class dot { - tbv m_pos; - vector m_negs; - public: - dot() {} - dot(tbv const& pos): m_pos(pos) {} - dot(tbv const& pos, vector const& negs): - m_pos(pos), m_negs(negs) { - DEBUG_CODE( - for (unsigned i = 0; i < negs.size(); ++i) { - SASSERT(pos.size() == negs[i].size()); - } - ); - } - - tbv const& pos() const { return m_pos; } - tbv neg(unsigned i) const { return m_negs[i]; } - unsigned size() const { return m_negs.size(); } - unsigned num_bits() const { return m_pos.size(); } - - bool operator==(dot const& other) const { - if (m_pos != other.m_pos) return false; - if (m_negs.size() != other.m_negs.size()) return false; - for (unsigned i = 0; i < m_negs.size(); ++i) { - if (m_negs[i] != other.m_negs[i]) return false; - } - return true; - } - - void display(std::ostream& out) { - out << "<"; - m_pos.display(out); - out << "\\"; - for (unsigned i = 0; i < m_negs.size(); ++i) { - m_negs[i].display(out); - if (i + 1 < m_negs.size()) out << " u "; - } - out << ">"; - } - - struct eq { - bool operator()(dot const& d1, dot const& d2) const { - return d1 == d2; - } - }; - - struct hash { - unsigned operator()(dot const& d) const { - unsigned h = d.pos().get_hash(); - for (unsigned i = 0; i < d.size(); ++i) { - h ^= d.neg(i).get_hash(); - } - return h; - } - }; - - }; - - vector m_pos; - vector m_neg; - vector const& pos() const { return m_pos; } - vector const& neg() const { return m_neg; } - ddnf_node* add_pos(dot const& d) { m_pos.push_back(d); return this; } - ddnf_node* add_neg(dot const& d) { m_neg.push_back(d); return this; } - - -#endif From 183c27a0b9627542d5cb9d66c457ac62324293b7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 22 Aug 2014 15:45:18 -0700 Subject: [PATCH 480/925] ddnf Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/ddnf.cpp | 88 ------------------------------------------- 1 file changed, 88 deletions(-) diff --git a/src/muz/ddnf/ddnf.cpp b/src/muz/ddnf/ddnf.cpp index e80bf144e..b2d18f629 100644 --- a/src/muz/ddnf/ddnf.cpp +++ b/src/muz/ddnf/ddnf.cpp @@ -876,20 +876,6 @@ namespace datalog { break; } } - - bool is_forwarding_rule(rule const& r) { - unsigned utsz = r.get_uninterpreted_tail_size(); - unsigned sz = r.get_tail_size(); - if (utsz != 1) return false; - app* h = r.get_head(); - app* p = r.get_tail(0); - if (h->get_num_args() != p->get_num_args()) return false; - for (unsigned i = 0; i < h->get_num_args(); ++i) { - if (h->get_arg(i) != p->get_arg(i)) return false; - } - return true; - } - }; ddnf::ddnf(context& ctx): @@ -920,78 +906,4 @@ namespace datalog { expr_ref ddnf::get_answer() { return m_imp->get_answer(); } - }; - - - - - -#if 0 - - // - // TBD: - // 1: H(x) :- P(x), phi(x). - // 2: H(x) :- P(y), phi(x), psi(y). - // 3: H(x) :- P(y), R(z), phi(x), psi(y), rho(z). - // 4: general case ... - // - // 1. compile phi(x) into a filter set. - // map each element in the filter set into P |-> E |-> rule - // 2. compile psi(y) into filter set P |-> E |-> rule - // 3. compile P |-> E |-> (rule,1), 2. R |-> E |-> rule (map for second position). - // - // E |-> rule is trie for elements of tuple E into set of rules as a bit-vector. - // - -------------------------------- - class trie { - public: - class node { - - }; - - class leaf : public trie_node { - bit_vector m_set; - public: - leaf(unsigned n): m_set(n) { - m_set.resize(n, false); - } - bit_vector& set() { return m_set; } - }; - - class node : public trie_node { - u_map m_map; - public: - u_map map() { return m_map; } - }; - - // insert - // bv1 x bv2 x bv3 -> set bit-i of n-bits - // such that every value in (bv1,bv2,bv3) maps to an element where bit-i is set. - // for each j1 in bv1: - // if j1 is in root of trie, then insert recursively with bv2, bv3 - // else insert recursively into empty node, each bit in bv1 point - // to returned node. - private: - trie_node* insert(unsigned nbv, bit_vector const* bvs, unsigned i, trie_node* n) { - if (nbv == 0) { - SASSERT(!n); - return mk_leaf(i); - } - bit_vector const& bv = bvs[0]; - if (!n) { - n = insert(nbv-1, bvs+1, i, n); - node* nd = mk_node(); - for (unsigned j = 0; j < bv.size(); ++j) { - if (bv.get(j)) { - nd->map().insert(j, n); - } - } - return nd; - } - - } - }; -#endif - From da8c9134f820b2a479ba3c9c5aceac019ae25c8e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 22 Aug 2014 17:06:51 -0700 Subject: [PATCH 481/925] ddnf Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/ddnf.cpp | 68 ++++++++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 17 deletions(-) diff --git a/src/muz/ddnf/ddnf.cpp b/src/muz/ddnf/ddnf.cpp index b2d18f629..dc45a9879 100644 --- a/src/muz/ddnf/ddnf.cpp +++ b/src/muz/ddnf/ddnf.cpp @@ -25,7 +25,7 @@ Revision History: #include "dl_context.h" #include "scoped_proof.h" #include "bv_decl_plugin.h" -#include "dl_decl_plugin.h" +//#include "dl_decl_plugin.h" namespace datalog { @@ -485,7 +485,7 @@ namespace datalog { ast_manager& m; rule_manager& rm; bv_util bv; - dl_decl_util dl; + // dl_decl_util dl; volatile bool m_cancel; ptr_vector m_todo; ast_mark m_visited1, m_visited2; @@ -502,7 +502,7 @@ namespace datalog { m(ctx.get_manager()), rm(ctx.get_rule_manager()), bv(m), - dl(m), + // dl(m), m_cancel(false), m_trail(m), m_inner_ctx(m, m_ctx.get_register_engine(), m_ctx.get_fparams()) @@ -516,6 +516,8 @@ namespace datalog { lbool query(expr* query) { m_ctx.ensure_opened(); + rm.mk_query(query, m_ctx.get_rules()); + rule_set new_rules(m_ctx); if (!pre_process_rules()) { return l_undef; @@ -523,11 +525,12 @@ namespace datalog { if (!compile_rules1(new_rules)) { return l_undef; } - return execute_rules(new_rules); - - IF_VERBOSE(0, verbose_stream() << "rules are OK\n";); IF_VERBOSE(2, m_ddnfs.display(verbose_stream());); - return run(); + + dump_rules(new_rules); + return l_undef; + + // return execute_rules(new_rules); } void cancel() { @@ -564,11 +567,6 @@ namespace datalog { return pr; } - lbool run() { - return l_undef; - } - - bool pre_process_rules() { m_visited1.reset(); m_todo.reset(); @@ -677,10 +675,8 @@ namespace datalog { return true; } - lbool execute_rules(rule_set& rules) { - ptr_vector heads; + void init_ctx(rule_set& rules) { m_inner_ctx.reset(); - rel_context_base& rcx = *m_inner_ctx.get_rel_context(); func_decl_set const& predicates = m_ctx.get_predicates(); for (func_decl_set::iterator fit = predicates.begin(); fit != predicates.end(); ++fit) { m_inner_ctx.register_predicate(*fit, false); @@ -688,11 +684,39 @@ namespace datalog { m_inner_ctx.ensure_opened(); m_inner_ctx.replace_rules(rules); m_inner_ctx.close(); + } + + void dump_rules(rule_set& rules) { + init_ctx(rules); + func_decl* q = rules.get_output_predicate(); + rule_vector const& qs = rules.get_predicate_rules(q); + SASSERT(qs.size() == 1); + app* qa = qs[0]->get_head(); + expr_ref query(m); + ptr_vector sorts; + vector names; + get_free_vars(qa, sorts); + // TBD: get the real names from the original query. + for (unsigned i = 0; i < sorts.size(); ++i) { + if (!sorts[i]) sorts[i] = m.mk_bool_sort(); + std::ostringstream strm; + strm << "q" << i; + names.push_back(symbol(strm.str().c_str())); + } + sorts.reverse(); + query = m.mk_quantifier(false, sorts.size(), sorts.c_ptr(), names.c_ptr(), qa); + expr* qe = query; + m_inner_ctx.display_smt2(1, &qe, std::cout); + } + + lbool execute_rules(rule_set& rules) { + init_ctx(rules); + + ptr_vector heads; rule_set::decl2rules::iterator dit = rules.begin_grouped_rules(); rule_set::decl2rules::iterator dend = rules.end_grouped_rules(); for (; dit != dend; ++dit) { heads.push_back(dit->m_key); - std::cout << mk_pp(dit->m_key, m) << "\n"; } return m_inner_ctx.rel_query(heads.size(), heads.c_ptr()); } @@ -728,6 +752,9 @@ namespace datalog { rule* r_new = rm.mk(head, body.size(), body.c_ptr(), 0, r.name(), true); new_rules.add_rule(r_new); IF_VERBOSE(2, r_new->display(m_ctx, verbose_stream());); + if (m_ctx.get_rules().is_output_predicate(r.get_decl())) { + new_rules.set_output_predicate(r_new->get_decl()); + } return true; } @@ -774,10 +801,17 @@ namespace datalog { unsigned sz = bv.get_bv_size(s); ddnf_mgr const& mgr = m_ddnfs.get(sz); unsigned num_elems = mgr.size(); + unsigned nb = 1; + while ((1UL << nb) <= num_elems) { + ++nb; + } + return bv.mk_sort(nb); +#if 0 std::ostringstream strm; strm << "S" << num_elems; symbol name(strm.str().c_str()); return dl.mk_sort(name, num_elems); +#endif } UNREACHABLE(); return 0; @@ -861,7 +895,7 @@ namespace datalog { expr_ref_vector eqs(m); sort* s = m.get_sort(w); for (; it != end; ++it) { - eqs.push_back(m.mk_eq(w, dl.mk_numeral((*it)->get_id(), s))); + eqs.push_back(m.mk_eq(w, bv.mk_numeral(rational((*it)->get_id()), s))); } switch (eqs.size()) { case 0: From 9b893c625bf55030391ba6be3b32e8d727e70a90 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 22 Aug 2014 21:17:05 -0700 Subject: [PATCH 482/925] print output predicates as part of displaying rules Signed-off-by: Nikolaj Bjorner --- src/api/api_datalog.cpp | 9 ++++--- src/muz/base/dl_context.cpp | 53 +++++++++++++++++++++++++------------ src/muz/base/dl_context.h | 4 +-- src/muz/ddnf/ddnf.cpp | 29 +------------------- 4 files changed, 45 insertions(+), 50 deletions(-) diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index ad6b5ad69..2d2b50f3d 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -125,7 +125,7 @@ namespace api { return "unknown"; } } - std::string to_string(unsigned num_queries, expr*const* queries) { + std::string to_string(unsigned num_queries, expr* const* queries) { std::stringstream str; m_context.display_smt2(num_queries, queries, str); return str.str(); @@ -466,13 +466,16 @@ extern "C" { ast_manager& m = mk_c(c)->m(); Z3_ast_vector_ref* v = alloc(Z3_ast_vector_ref, m); mk_c(c)->save_object(v); - expr_ref_vector rules(m); + expr_ref_vector rules(m), queries(m); svector names; - to_fixedpoint_ref(d)->ctx().get_rules_as_formulas(rules, names); + to_fixedpoint_ref(d)->ctx().get_rules_as_formulas(rules, queries, names); for (unsigned i = 0; i < rules.size(); ++i) { v->m_ast_vector.push_back(rules[i].get()); } + for (unsigned i = 0; i < queries.size(); ++i) { + v->m_ast_vector.push_back(m.mk_not(queries[i].get())); + } RETURN_Z3(of_ast_vector(v)); Z3_CATCH_RETURN(0); } diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 774db6c6a..f3088fa04 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -1117,7 +1117,7 @@ namespace datalog { } } - void context::get_rules_as_formulas(expr_ref_vector& rules, svector& names) { + void context::get_rules_as_formulas(expr_ref_vector& rules, expr_ref_vector& queries, svector& names) { expr_ref fml(m); datalog::rule_manager& rm = get_rule_manager(); @@ -1136,9 +1136,30 @@ namespace datalog { } rule_set::iterator it = m_rule_set.begin(), end = m_rule_set.end(); for (; it != end; ++it) { - (*it)->to_formula(fml); - rules.push_back(fml); - names.push_back((*it)->name()); + rule* r = *it; + r->to_formula(fml); + func_decl* h = r->get_decl(); + if (m_rule_set.is_output_predicate(h)) { + expr* body = fml; + expr* e2; + if (is_quantifier(body)) { + quantifier* q = to_quantifier(body); + expr* e = q->get_expr(); + VERIFY(m.is_implies(e, body, e2)); + fml = m.mk_quantifier(false, q->get_num_decls(), + q->get_decl_sorts(), q->get_decl_names(), + body); + } + else { + VERIFY(m.is_implies(body, body, e2)); + fml = body; + } + queries.push_back(fml); + } + else { + rules.push_back(fml); + names.push_back(r->name()); + } } for (unsigned i = m_rule_fmls_head; i < m_rule_fmls.size(); ++i) { rules.push_back(m_rule_fmls[i].get()); @@ -1146,10 +1167,7 @@ namespace datalog { } } - void context::display_smt2( - unsigned num_queries, - expr* const* queries, - std::ostream& out) { + void context::display_smt2(unsigned num_queries, expr* const* qs, std::ostream& out) { ast_manager& m = get_manager(); free_func_visitor visitor(m); expr_mark visited; @@ -1157,7 +1175,7 @@ namespace datalog { unsigned num_axioms = m_background.size(); expr* const* axioms = m_background.c_ptr(); expr_ref fml(m); - expr_ref_vector rules(m); + expr_ref_vector rules(m), queries(m); svector names; bool use_fixedpoint_extensions = m_params->print_fixedpoint_extensions(); bool print_low_level = m_params->print_low_level_smt2(); @@ -1165,13 +1183,14 @@ namespace datalog { #define PP(_e_) if (print_low_level) out << mk_smt_pp(_e_, m); else ast_smt2_pp(out, _e_, env); - get_rules_as_formulas(rules, names); + get_rules_as_formulas(rules, queries, names); + queries.append(num_queries, qs); smt2_pp_environment_dbg env(m); mk_fresh_name fresh_names; collect_free_funcs(num_axioms, axioms, visited, visitor, fresh_names); collect_free_funcs(rules.size(), rules.c_ptr(), visited, visitor, fresh_names); - collect_free_funcs(num_queries, queries, visited, visitor, fresh_names); + collect_free_funcs(queries.size(), queries.c_ptr(), visited, visitor, fresh_names); func_decl_set funcs; func_decl_set::iterator it = visitor.funcs().begin(); func_decl_set::iterator end = visitor.funcs().end(); @@ -1257,22 +1276,22 @@ namespace datalog { out << ")\n"; } if (use_fixedpoint_extensions) { - for (unsigned i = 0; i < num_queries; ++i) { + for (unsigned i = 0; i < queries.size(); ++i) { out << "(query "; - PP(queries[i]); + PP(queries[i].get()); out << ")\n"; } } else { - for (unsigned i = 0; i < num_queries; ++i) { - if (num_queries > 1) out << "(push)\n"; + for (unsigned i = 0; i < queries.size(); ++i) { + if (queries.size() > 1) out << "(push)\n"; out << "(assert "; expr_ref q(m); - q = m.mk_not(queries[i]); + q = m.mk_not(queries[i].get()); PP(q); out << ")\n"; out << "(check-sat)\n"; - if (num_queries > 1) out << "(pop)\n"; + if (queries.size() > 1) out << "(pop)\n"; } } } diff --git a/src/muz/base/dl_context.h b/src/muz/base/dl_context.h index 1952cc42f..b7bcbb5fe 100644 --- a/src/muz/base/dl_context.h +++ b/src/muz/base/dl_context.h @@ -362,7 +362,7 @@ namespace datalog { rule_set & get_rules() { flush_add_rules(); return m_rule_set; } - void get_rules_as_formulas(expr_ref_vector& fmls, svector& names); + void get_rules_as_formulas(expr_ref_vector& fmls, expr_ref_vector& qs, svector& names); void get_raw_rule_formulas(expr_ref_vector& fmls, svector& names); void add_fact(app * head); @@ -463,7 +463,7 @@ namespace datalog { void display(std::ostream & out) const; - void display_smt2(unsigned num_queries, expr* const* queries, std::ostream& out); + void display_smt2(unsigned num_queries, expr* const* qs, std::ostream& out); void display_profile(std::ostream& out) const; diff --git a/src/muz/ddnf/ddnf.cpp b/src/muz/ddnf/ddnf.cpp index dc45a9879..9a47976b2 100644 --- a/src/muz/ddnf/ddnf.cpp +++ b/src/muz/ddnf/ddnf.cpp @@ -25,7 +25,6 @@ Revision History: #include "dl_context.h" #include "scoped_proof.h" #include "bv_decl_plugin.h" -//#include "dl_decl_plugin.h" namespace datalog { @@ -485,7 +484,6 @@ namespace datalog { ast_manager& m; rule_manager& rm; bv_util bv; - // dl_decl_util dl; volatile bool m_cancel; ptr_vector m_todo; ast_mark m_visited1, m_visited2; @@ -502,7 +500,6 @@ namespace datalog { m(ctx.get_manager()), rm(ctx.get_rule_manager()), bv(m), - // dl(m), m_cancel(false), m_trail(m), m_inner_ctx(m, m_ctx.get_register_engine(), m_ctx.get_fparams()) @@ -688,25 +685,7 @@ namespace datalog { void dump_rules(rule_set& rules) { init_ctx(rules); - func_decl* q = rules.get_output_predicate(); - rule_vector const& qs = rules.get_predicate_rules(q); - SASSERT(qs.size() == 1); - app* qa = qs[0]->get_head(); - expr_ref query(m); - ptr_vector sorts; - vector names; - get_free_vars(qa, sorts); - // TBD: get the real names from the original query. - for (unsigned i = 0; i < sorts.size(); ++i) { - if (!sorts[i]) sorts[i] = m.mk_bool_sort(); - std::ostringstream strm; - strm << "q" << i; - names.push_back(symbol(strm.str().c_str())); - } - sorts.reverse(); - query = m.mk_quantifier(false, sorts.size(), sorts.c_ptr(), names.c_ptr(), qa); - expr* qe = query; - m_inner_ctx.display_smt2(1, &qe, std::cout); + m_inner_ctx.display_smt2(0, 0, std::cout); } lbool execute_rules(rule_set& rules) { @@ -806,12 +785,6 @@ namespace datalog { ++nb; } return bv.mk_sort(nb); -#if 0 - std::ostringstream strm; - strm << "S" << num_elems; - symbol name(strm.str().c_str()); - return dl.mk_sort(name, num_elems); -#endif } UNREACHABLE(); return 0; From 54c959783d0e83fc40890dee6da6f553e85dc625 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 23 Aug 2014 20:51:30 -0700 Subject: [PATCH 483/925] profile, optimize, trying out product-set Signed-off-by: Nikolaj Bjorner --- src/muz/base/dl_context.cpp | 56 ++-- src/muz/base/dl_context.h | 11 +- src/muz/ddnf/ddnf.cpp | 25 +- src/muz/rel/dl_vector_relation.h | 5 +- src/muz/rel/product_set.cpp | 510 +++++++++++++++++++++++++++++++ src/muz/rel/product_set.h | 187 ++++++++++++ src/muz/rel/rel_context.cpp | 2 + 7 files changed, 748 insertions(+), 48 deletions(-) create mode 100644 src/muz/rel/product_set.cpp create mode 100644 src/muz/rel/product_set.h diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index f3088fa04..529028606 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -233,6 +233,7 @@ namespace datalog { m_engine_type(LAST_ENGINE), m_cancel(false) { re.set_context(this); + m_generate_proof_trace = m_params->generate_proof_trace(); } context::~context() { @@ -271,7 +272,7 @@ namespace datalog { } - bool context::generate_proof_trace() const { return m_params->generate_proof_trace(); } + bool context::generate_proof_trace() const { return m_generate_proof_trace; } bool context::output_profile() const { return m_params->datalog_output_profile(); } bool context::output_tuples() const { return m_params->datalog_print_tuples(); } bool context::use_map_names() const { return m_params->datalog_use_map_names(); } @@ -489,10 +490,8 @@ namespace datalog { ++m_rule_fmls_head; } rule_set::iterator it = m_rule_set.begin(), end = m_rule_set.end(); - rule_ref r(m_rule_manager); for (; it != end; ++it) { - r = *it; - check_rule(r); + check_rule(*(*it)); } } @@ -579,35 +578,35 @@ namespace datalog { m_engine->add_cover(level, pred, property); } - void context::check_uninterpreted_free(rule_ref& r) { + void context::check_uninterpreted_free(rule& r) { func_decl* f = 0; - if (r->has_uninterpreted_non_predicates(m, f)) { + if (r.has_uninterpreted_non_predicates(m, f)) { std::stringstream stm; stm << "Uninterpreted '" << f->get_name() << "' in "; - r->display(*this, stm); + r.display(*this, stm); throw default_exception(stm.str()); } } - void context::check_quantifier_free(rule_ref& r) { - if (r->has_quantifiers()) { + void context::check_quantifier_free(rule& r) { + if (r.has_quantifiers()) { std::stringstream stm; stm << "cannot process quantifiers in rule "; - r->display(*this, stm); + r.display(*this, stm); throw default_exception(stm.str()); } } - void context::check_existential_tail(rule_ref& r) { - unsigned ut_size = r->get_uninterpreted_tail_size(); - unsigned t_size = r->get_tail_size(); + void context::check_existential_tail(rule& r) { + unsigned ut_size = r.get_uninterpreted_tail_size(); + unsigned t_size = r.get_tail_size(); - TRACE("dl", r->display_smt2(get_manager(), tout); tout << "\n";); + TRACE("dl", r.display_smt2(get_manager(), tout); tout << "\n";); for (unsigned i = ut_size; i < t_size; ++i) { - app* t = r->get_tail(i); + app* t = r.get_tail(i); TRACE("dl", tout << "checking: " << mk_ismt2_pp(t, get_manager()) << "\n";); if (m_check_pred(t)) { std::ostringstream out; @@ -617,14 +616,14 @@ namespace datalog { } } - void context::check_positive_predicates(rule_ref& r) { + void context::check_positive_predicates(rule& r) { ast_mark visited; ptr_vector todo, tocheck; - unsigned ut_size = r->get_uninterpreted_tail_size(); - unsigned t_size = r->get_tail_size(); + unsigned ut_size = r.get_uninterpreted_tail_size(); + unsigned t_size = r.get_tail_size(); for (unsigned i = 0; i < ut_size; ++i) { - if (r->is_neg_tail(i)) { - tocheck.push_back(r->get_tail(i)); + if (r.is_neg_tail(i)) { + tocheck.push_back(r.get_tail(i)); } } ast_manager& m = get_manager(); @@ -632,7 +631,7 @@ namespace datalog { check_pred check_pred(contains_p, get_manager()); for (unsigned i = ut_size; i < t_size; ++i) { - todo.push_back(r->get_tail(i)); + todo.push_back(r.get_tail(i)); } while (!todo.empty()) { expr* e = todo.back(), *e1, *e2; @@ -670,14 +669,14 @@ namespace datalog { if (check_pred(e)) { std::ostringstream out; out << "recursive predicate " << mk_ismt2_pp(e, get_manager()) << " occurs nested in body"; - r->display(*this, out << "\n"); + r.display(*this, out << "\n"); throw default_exception(out.str()); } } } - void context::check_rule(rule_ref& r) { + void context::check_rule(rule& r) { switch(get_engine()) { case DATALOG_ENGINE: check_quantifier_free(r); @@ -719,8 +718,8 @@ namespace datalog { UNREACHABLE(); break; } - if (generate_proof_trace() && !r->get_proof()) { - m_rule_manager.mk_rule_asserted_proof(*r.get()); + if (generate_proof_trace() && !r.get_proof()) { + m_rule_manager.mk_rule_asserted_proof(r); } } @@ -847,6 +846,7 @@ namespace datalog { void context::updt_params(params_ref const& p) { m_params_ref.copy(p); if (m_engine.get()) m_engine->updt_params(); + m_generate_proof_trace = m_params->generate_proof_trace(); } expr_ref context::get_background_assertion() { @@ -908,6 +908,9 @@ namespace datalog { }; void context::configure_engine() { + if (m_engine_type != LAST_ENGINE) { + return; + } symbol e = m_params->engine(); if (e == symbol("datalog")) { @@ -969,8 +972,7 @@ namespace datalog { rule_set::iterator it = m_rule_set.begin(), end = m_rule_set.end(); rule_ref r(m_rule_manager); for (; it != end; ++it) { - r = *it; - check_rule(r); + check_rule(*(*it)); } } #endif diff --git a/src/muz/base/dl_context.h b/src/muz/base/dl_context.h index b7bcbb5fe..66addc37c 100644 --- a/src/muz/base/dl_context.h +++ b/src/muz/base/dl_context.h @@ -171,6 +171,7 @@ namespace datalog { smt_params & m_fparams; params_ref m_params_ref; fixedpoint_params* m_params; + bool m_generate_proof_trace; dl_decl_util m_decl_util; th_rewriter m_rewriter; var_subst m_var_subst; @@ -416,7 +417,7 @@ namespace datalog { /** \brief Check if rule is well-formed according to engine. */ - void check_rule(rule_ref& r); + void check_rule(rule& r); /** \brief Return true if facts to \c pred can be added using the \c add_table_fact() function. @@ -562,10 +563,10 @@ namespace datalog { void ensure_engine(); - void check_quantifier_free(rule_ref& r); - void check_uninterpreted_free(rule_ref& r); - void check_existential_tail(rule_ref& r); - void check_positive_predicates(rule_ref& r); + void check_quantifier_free(rule& r); + void check_uninterpreted_free(rule& r); + void check_existential_tail(rule& r); + void check_positive_predicates(rule& r); // auxilary functions for SMT2 pretty-printer. void declare_vars(expr_ref_vector& rules, mk_fresh_name& mk_fresh, std::ostream& out); diff --git a/src/muz/ddnf/ddnf.cpp b/src/muz/ddnf/ddnf.cpp index 9a47976b2..6d5dd1c80 100644 --- a/src/muz/ddnf/ddnf.cpp +++ b/src/muz/ddnf/ddnf.cpp @@ -513,13 +513,13 @@ namespace datalog { lbool query(expr* query) { m_ctx.ensure_opened(); - rm.mk_query(query, m_ctx.get_rules()); - + rule_set& old_rules = m_ctx.get_rules(); + rm.mk_query(query, old_rules); rule_set new_rules(m_ctx); - if (!pre_process_rules()) { + if (!pre_process_rules(old_rules)) { return l_undef; } - if (!compile_rules1(new_rules)) { + if (!compile_rules1(old_rules, new_rules)) { return l_undef; } IF_VERBOSE(2, m_ddnfs.display(verbose_stream());); @@ -564,12 +564,11 @@ namespace datalog { return pr; } - bool pre_process_rules() { + bool pre_process_rules(rule_set const& rules) { m_visited1.reset(); m_todo.reset(); m_cache.reset(); m_expr2tbv.reset(); - rule_set const& rules = m_ctx.get_rules(); datalog::rule_set::iterator it = rules.begin(); datalog::rule_set::iterator end = rules.end(); for (; it != end; ++it) { @@ -700,20 +699,19 @@ namespace datalog { return m_inner_ctx.rel_query(heads.size(), heads.c_ptr()); } - bool compile_rules1(rule_set& new_rules) { - rule_set const& rules = m_ctx.get_rules(); + bool compile_rules1(rule_set const& rules, rule_set& new_rules) { datalog::rule_set::iterator it = rules.begin(); datalog::rule_set::iterator end = rules.end(); unsigned idx = 0; for (; it != end; ++idx, ++it) { - if (!compile_rule1(**it, new_rules)) { + if (!compile_rule1(**it, rules, new_rules)) { return false; } } return true; } - bool compile_rule1(rule& r, rule_set& new_rules) { + bool compile_rule1(rule& r, rule_set const& old_rules, rule_set& new_rules) { app_ref head(m), pred(m); app_ref_vector body(m); expr_ref tmp(m); @@ -728,10 +726,10 @@ namespace datalog { compile_expr(r.get_tail(i), tmp); body.push_back(to_app(tmp)); } - rule* r_new = rm.mk(head, body.size(), body.c_ptr(), 0, r.name(), true); + rule* r_new = rm.mk(head, body.size(), body.c_ptr(), 0, r.name(), false); new_rules.add_rule(r_new); IF_VERBOSE(2, r_new->display(m_ctx, verbose_stream());); - if (m_ctx.get_rules().is_output_predicate(r.get_decl())) { + if (old_rules.is_output_predicate(r.get_decl())) { new_rules.set_output_predicate(r_new->get_decl()); } return true; @@ -767,7 +765,8 @@ namespace datalog { result = to_var(r); } else { - result = m.mk_var(v->get_id(), compile_sort(v->get_sort())); + unsigned idx = v->get_idx(); + result = m.mk_var(idx, compile_sort(v->get_sort())); insert_cache(v, result); } } diff --git a/src/muz/rel/dl_vector_relation.h b/src/muz/rel/dl_vector_relation.h index 114f4ca43..6c55e7b6d 100644 --- a/src/muz/rel/dl_vector_relation.h +++ b/src/muz/rel/dl_vector_relation.h @@ -42,8 +42,6 @@ namespace datalog { union_find_default_ctx m_ctx; union_find<>* m_eqs; - friend class vector_relation_plugin; - public: vector_relation(relation_plugin& p, relation_signature const& s, bool is_empty, T const& t = T()): relation_base(p, s), @@ -107,9 +105,10 @@ namespace datalog { display_index(i, (*m_elems)[i], out); } else { - out << i << " = " << find(i) << "\n"; + out << i << " = " << find(i) << " "; } } + out << "\n"; } diff --git a/src/muz/rel/product_set.cpp b/src/muz/rel/product_set.cpp new file mode 100644 index 000000000..2812c56e2 --- /dev/null +++ b/src/muz/rel/product_set.cpp @@ -0,0 +1,510 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + product_set.cpp + +Abstract: + + Product set. + +Author: + + Nikolaj Bjorner (nbjorner) 2014-08-23 + +Revision History: + +--*/ + +#include "product_set.h" +#include "bv_decl_plugin.h" +#include "dl_relation_manager.h" +#include "bool_rewriter.h" + +namespace datalog { + + product_set::product_set( + product_set_plugin& p, relation_signature const& s, + bool is_empty, T const& t): + vector_relation(p, s, is_empty, t), m_refs(0) { + for (unsigned i = 0; i < s.size(); ++i) { + (*this)[i] = bit_vector(p.set_size(s[i])); + } + } + + + unsigned product_set::get_hash() const { + unsigned hash = 0; + for (unsigned i = 0; i < get_signature().size(); ++i) { + hash ^= (*this)[i].get_hash(); + } + return hash; + } + + bool product_set::operator==(product_set const& p) const { + for (unsigned i = 0; i < get_signature().size(); ++i) { + if ((*this)[i] != p[i]) return false; + } + return true; + } + + bool product_set::contains(product_set const& p) const { + for (unsigned i = 0; i < get_signature().size(); ++i) { + if ((*this)[i].contains(p[i])) return false; + } + return true; + } + + void product_set::add_fact(const relation_fact & f) { + UNREACHABLE(); + } + bool product_set::contains_fact(const relation_fact & f) const { + return false; + } + relation_base * product_set::clone() const { + UNREACHABLE(); + return 0; + } + relation_base * product_set::complement(func_decl*) const { + UNREACHABLE(); + return 0; + } + void product_set::to_formula(expr_ref& fml) const { + ast_manager& m = fml.get_manager(); + bv_util bv(m); + expr_ref_vector conjs(m), disjs(m); + relation_signature const& sig = get_signature(); + if (m_empty) { + fml = m.mk_false(); + return; + } + for (unsigned i = 0; i < sig.size(); ++i) { + sort* ty = sig[i]; + expr_ref var(m.mk_var(i, ty), m); + unsigned j = find(i); + if (i != j) { + conjs.push_back(m.mk_eq(var, m.mk_var(j, sig[j]))); + continue; + } + T const& t = (*this)[i]; + disjs.reset(); + for (j = 0; j < t.size(); ++j) { + if (t.get(j)) { + disjs.push_back(m.mk_eq(var, bv.mk_numeral(rational(j), ty))); + } + } + if (disjs.empty()) { + UNREACHABLE(); + fml = m.mk_false(); + return; + } + if (disjs.size() == 1) { + conjs.push_back(disjs[0].get()); + } + else { + conjs.push_back(m.mk_or(disjs.size(), disjs.c_ptr())); + } + } + bool_rewriter br(m); + br.mk_and(conjs.size(), conjs.c_ptr(), fml); + } + void product_set::display_index(unsigned i, const T& t, std::ostream& out) const { + out << i << ":"; + t.display(out); + } + bool product_set::mk_intersect(unsigned idx, T const& t) { + if (!m_empty) { + (*this)[idx] &= t; + m_empty = is_empty(idx, (*this)[idx]); + } + return !m_empty; + } + + // product_set_relation + + + product_set_relation::product_set_relation(product_set_plugin& p, relation_signature const& s): + relation_base(p, s) { + } + + product_set_relation::~product_set_relation() { + product_sets::iterator it = m_elems.begin(), end = m_elems.end(); + for (; it != end; ++it) { + (*it)->dec_ref(); + } + } + + void product_set_relation::add_fact(const relation_fact & f) { + ast_manager& m = get_plugin().get_ast_manager(); + bv_util bv(m); + rational v; + unsigned bv_size; + product_set* s = alloc(product_set, get_plugin(), get_signature(), false); + for (unsigned i = 0; i < f.size(); ++i) { + VERIFY(bv.is_numeral(f[i], v, bv_size)); + SASSERT(v.is_unsigned()); + (*s)[i] = bit_vector(get_plugin().set_size(m.get_sort(f[i]))); + (*s)[i].set(v.get_unsigned(), true); + } + s->display(std::cout << "fact"); + if (m_elems.contains(s)) { + dealloc(s); + } + else { + s->inc_ref(); + m_elems.insert(s); + } + + } + bool product_set_relation::contains_fact(const relation_fact & f) const { + std::cout << "contains fact\n"; + NOT_IMPLEMENTED_YET(); + return false; + } + product_set_relation * product_set_relation::clone() const { + product_set_relation* r = alloc(product_set_relation, get_plugin(), get_signature()); + product_sets::iterator it = m_elems.begin(), end = m_elems.end(); + for (; it != end; ++it) { + // TBD: have to copy because other operations are destructive. + (*it)->inc_ref(); + r->m_elems.insert(*it); + } + return r; + } + product_set_relation * product_set_relation::complement(func_decl*) const { + std::cout << "complement\n"; + NOT_IMPLEMENTED_YET(); + return 0; + } + void product_set_relation::to_formula(expr_ref& fml) const { + product_sets::iterator it = m_elems.begin(), end = m_elems.end(); + ast_manager& m = get_plugin().get_manager().get_context().get_manager(); + expr_ref_vector disjs(m); + for (; it != end; ++it) { + (*it)->to_formula(fml); + disjs.push_back(fml); + } + fml = m.mk_or(disjs.size(), disjs.c_ptr()); + } + product_set_plugin& product_set_relation::get_plugin() const { + return static_cast(relation_base::get_plugin()); + } + + void product_set_relation::display(std::ostream& out) const { + product_sets::iterator it = m_elems.begin(), end = m_elems.end(); + for (; it != end; ++it) { + (*it)->display(out); + } + } + + // product_set_plugin + + product_set_plugin::product_set_plugin(relation_manager& rm): + relation_plugin(product_set_plugin::get_name(), rm) { + } + + bool product_set_plugin::can_handle_signature(const relation_signature & sig) { + bv_util bv(get_manager().get_context().get_manager()); + for (unsigned i = 0; i < sig.size(); ++i) { + if (!bv.is_bv_sort(sig[i])) return false; + } + return true; + } + + product_set_relation& product_set_plugin::get(relation_base& r) { + return dynamic_cast(r); + } + product_set_relation* product_set_plugin::get(relation_base* r) { + return r?dynamic_cast(r):0; + } + product_set_relation const & product_set_plugin::get(relation_base const& r) { + return dynamic_cast(r); + } + relation_base * product_set_plugin::mk_empty(const relation_signature & s) { + return alloc(product_set_relation, *this, s); + } + relation_base * product_set_plugin::mk_full(func_decl* p, const relation_signature & sig) { + product_set_relation* result = alloc(product_set_relation, *this, sig); + product_set* s = alloc(product_set, *this, sig, false); + s->inc_ref(); + for (unsigned i = 0; i < sig.size(); ++i) { + bit_vector& t = (*s)[i]; + t = bit_vector(set_size(sig[i])); + for (unsigned j = 0; j < t.size(); ++j) { + t.set(j, true); + } + } + result->m_elems.insert(s); + return result; + } + product_set* product_set_plugin::insert(product_set* s, product_set_relation* r) { + if (s->empty()) { + s->reset(); + } + else if (r->m_elems.contains(s)) { + s->reset(); + } + else { + s->inc_ref(); + r->m_elems.insert(s); + s = alloc(product_set, *this, r->get_signature(), false); + } + return s; + } + + unsigned product_set_plugin::set_size(sort* ty) { + bv_util bv(get_ast_manager()); + unsigned bv_size = bv.get_bv_size(ty); + SASSERT(bv_size <= 16); + if (bv_size > 16) { + throw default_exception("bit-vector based sets are not suitable for this domain size"); + } + return 1 << bv_size; + } + + class product_set_plugin::join_fn : public convenient_relation_join_fn { + public: + join_fn(const relation_signature & o1_sig, const relation_signature & o2_sig, unsigned col_cnt, + const unsigned * cols1, const unsigned * cols2) + : convenient_relation_join_fn(o1_sig, o2_sig, col_cnt, cols1, cols2){ + } + + virtual relation_base * operator()(const relation_base & _r1, const relation_base & _r2) { + product_set_relation const& r1 = get(_r1); + product_set_relation const& r2 = get(_r2); + product_set_plugin& p = r1.get_plugin(); + relation_signature const& sig = get_result_signature(); + product_set_relation * result = alloc(product_set_relation, p, sig); + product_set* s = alloc(product_set, p, sig, false); + product_sets::iterator it1 = r1.m_elems.begin(), end1 = r1.m_elems.end(); + for (; it1 != end1; ++it1) { + product_sets::iterator it2 = r2.m_elems.begin(), end2 = r2.m_elems.end(); + for (; it2 != end2; ++it2) { + s->mk_join(*(*it1), *(*it2), m_cols1.size(), m_cols1.c_ptr(), m_cols2.c_ptr()); + s = p.insert(s, result); + } + } + dealloc(s); + return result; + } + }; + relation_join_fn * product_set_plugin::mk_join_fn( + const relation_base & r1, const relation_base & r2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { + if (!check_kind(r1) || !check_kind(r2)) { + return 0; + } + return alloc(join_fn, r1.get_signature(), r2.get_signature(), col_cnt, cols1, cols2); + } + + class product_set_plugin::project_fn : public convenient_relation_project_fn { + public: + project_fn(const relation_signature & orig_sig, unsigned removed_col_cnt, + const unsigned * removed_cols) + : convenient_relation_project_fn(orig_sig, removed_col_cnt, removed_cols) { + } + + virtual relation_base * operator()(const relation_base & _r) { + product_set_relation const& r = get(_r); + product_set_plugin& p = r.get_plugin(); + relation_signature const& sig = get_result_signature(); + product_set_relation* result = alloc(product_set_relation, p, sig); + product_set* s = alloc(product_set, p, sig, false); + product_sets::iterator it = r.m_elems.begin(), end = r.m_elems.end(); + for (; it != end; ++it) { + s->mk_project(*(*it), m_removed_cols.size(), m_removed_cols.c_ptr()); + s = p.insert(s, result); + } + dealloc(s); + return result; + } + }; + relation_transformer_fn * product_set_plugin::mk_project_fn( + const relation_base & r, unsigned col_cnt, + const unsigned * removed_cols) { + if (check_kind(r)) { + return alloc(project_fn, r.get_signature(), col_cnt, removed_cols); + } + else { + return 0; + } + } + class product_set_plugin::rename_fn : public convenient_relation_rename_fn { + public: + rename_fn(const relation_signature & orig_sig, unsigned cycle_len, const unsigned * cycle) + : convenient_relation_rename_fn(orig_sig, cycle_len, cycle) { + } + + virtual relation_base * operator()(const relation_base & _r) { + product_set_relation const& r = get(_r); + product_set_plugin& p = r.get_plugin(); + relation_signature const& sig = get_result_signature(); + product_set_relation* result = alloc(product_set_relation, p, sig); + product_set* s = alloc(product_set, p, sig, false); + product_sets::iterator it = r.m_elems.begin(), end = r.m_elems.end(); + for (; it != end; ++it) { + s->mk_rename(*(*it), m_cycle.size(), m_cycle.c_ptr()); + s = p.insert(s, result); + } + dealloc(s); + return result; + } + }; + + relation_transformer_fn * product_set_plugin::mk_rename_fn(const relation_base & r, + unsigned cycle_len, const unsigned * permutation_cycle) { + if (check_kind(r)) { + return alloc(rename_fn, r.get_signature(), cycle_len, permutation_cycle); + } + else { + return 0; + } + } + + class product_set_plugin::union_fn : public relation_union_fn { + public: + union_fn() {} + + virtual void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) { + + TRACE("dl", _r.display(tout << "dst:\n"); _src.display(tout << "src:\n");); + + product_set_relation& r = get(_r); + product_set_relation const& src = get(_src); + product_set_relation* d = get(_delta); + product_sets::iterator it = src.m_elems.begin(), end = src.m_elems.end(); + for (; it != end; ++it) { + product_set* ps = *it; + if (!r.m_elems.contains(ps)) { + ps->inc_ref(); + r.m_elems.insert(ps); + if (d) { + ps->inc_ref(); + d->m_elems.insert(ps); + } + } + } + } + }; + relation_union_fn * product_set_plugin::mk_union_fn( + const relation_base & tgt, const relation_base & src, + const relation_base * delta) { + if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) { + return 0; + } + return alloc(union_fn); + } + relation_union_fn * product_set_plugin::mk_widen_fn( + const relation_base & tgt, const relation_base & src, + const relation_base * delta) { + return mk_union_fn(tgt, src, delta); + } + + + class product_set_plugin::filter_identical_fn : public relation_mutator_fn { + unsigned_vector m_identical_cols; + public: + filter_identical_fn(unsigned col_cnt, const unsigned * identical_cols) + : m_identical_cols(col_cnt, identical_cols) {} + + virtual void operator()(relation_base & _r) { + product_set_relation & r = get(_r); + product_set_plugin& p = r.get_plugin(); + ptr_vector elems; + product_sets::iterator it = r.m_elems.begin(), end = r.m_elems.end(); + for (; it != end; ++it) { + elems.push_back(*it); + } + r.m_elems.reset(); + for (unsigned i = 0; i < elems.size(); ++i) { + product_set* s = elems[i]; + if (equate(*s)) { + r.m_elems.insert(s); + } + else { + s->dec_ref(); + } + } + } + private: + bool equate(product_set& dst) { + for (unsigned i = 1; !dst.empty() && i < m_identical_cols.size(); ++i) { + unsigned c1 = m_identical_cols[0]; + unsigned c2 = m_identical_cols[i]; + dst.equate(c1, c2); + } + return !dst.empty(); + } + }; + relation_mutator_fn * product_set_plugin::mk_filter_identical_fn( + const relation_base & t, unsigned col_cnt, const unsigned * identical_cols) { + return check_kind(t)?alloc(filter_identical_fn, col_cnt, identical_cols):0; + } + + class product_set_plugin::filter_equal_fn : public relation_mutator_fn { + unsigned m_col; + bit_vector m_value; + public: + filter_equal_fn(product_set_plugin& p, const relation_element & value, unsigned col, bool is_eq) + : m_col(col) { + ast_manager& m = p.get_ast_manager(); + // m.get_context().get_manager() + bv_util bv(m); + rational v; + unsigned bv_size; + unsigned sz = p.set_size(m.get_sort(value)); + VERIFY(bv.is_numeral(value, v, bv_size)); + SASSERT(v.is_unsigned()); + unsigned w = v.get_unsigned(); + SASSERT(w < sz); + m_value = bit_vector(sz); + if (is_eq) { + m_value.set(w, true); + } + else { + for (unsigned i = 0; i < sz; ++i) { + m_value.set(i, i != w); + } + } + } + + virtual void operator()(relation_base & _r) { + product_set_relation & r = get(_r); + product_set_plugin & p = r.get_plugin(); + + ptr_vector elems; + product_sets::iterator it = r.m_elems.begin(), end = r.m_elems.end(); + for (; it != end; ++it) { + elems.push_back(*it); + } + r.m_elems.reset(); + for (unsigned i = 0; i < elems.size(); ++i) { + product_set* s = elems[i]; + + if (s->mk_intersect(m_col, m_value)) { + r.m_elems.insert(s); + } + else { + s->dec_ref(); + } + } + } + }; + + relation_mutator_fn * product_set_plugin::mk_filter_equal_fn(const relation_base & r, + const relation_element & value, unsigned col) { + return check_kind(r)?alloc(filter_equal_fn, *this, value, col, true):0; + } + + relation_mutator_fn * product_set_plugin::mk_filter_interpreted_fn( + const relation_base & t, app * condition) { + ast_manager& m =get_manager().get_context().get_manager(); + std::cout << "filter interpreted '" << mk_pp(condition, m) << "'\n"; + NOT_IMPLEMENTED_YET(); + return 0; + } + + +}; + diff --git a/src/muz/rel/product_set.h b/src/muz/rel/product_set.h new file mode 100644 index 000000000..670ec1cbf --- /dev/null +++ b/src/muz/rel/product_set.h @@ -0,0 +1,187 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + product_set.h + +Abstract: + + Product set relation. + A product set is a tuple of sets. + The meaning of a product set is the set of + elements in the cross-product. + A product set relation is a set of product sets, + and the meaning of this relation is the union of + all elements from the products. + It is to be used when computing over product sets is + (much) cheaper than over the space of tuples. + +Author: + + Nikolaj Bjorner (nbjorner) 2014-08-23 + +Revision History: + +--*/ +#ifndef _DL_PRODUCT_SET__H_ +#define _DL_PRODUCT_SET__H_ + +#include "util.h" +#include "bit_vector.h" +#include "dl_base.h" +#include "dl_vector_relation.h" + +namespace datalog { + + class product_set_plugin; + + class product_set : public vector_relation { + typedef bit_vector T; + unsigned m_refs; + public: + product_set(product_set_plugin& p, relation_signature const& s, bool is_empty, T const& t = T()); + + virtual ~product_set() {} + unsigned get_hash() const; + bool operator==(product_set const& p) const; + bool contains(product_set const& p) const; + + void inc_ref() { ++m_refs; } + void dec_ref() { --m_refs; if (0 == m_refs) dealloc(this); } + unsigned ref_count() const { return m_refs; } + + struct eq { + bool operator()(product_set const* s1, product_set const* s2) const { + return *s1 == *s2; + } + }; + + struct hash { + unsigned operator()(product_set const* s) const { + return s->get_hash(); + } + }; + + virtual void add_fact(const relation_fact & f); + virtual bool contains_fact(const relation_fact & f) const; + virtual relation_base * clone() const; + virtual relation_base * complement(func_decl*) const; + virtual void to_formula(expr_ref& fml) const; + + bool mk_intersect(unsigned idx, T const& t); + + private: + virtual void display_index(unsigned i, const T&, std::ostream& out) const; + virtual T mk_intersect(T const& t1, T const& t2, bool& _is_empty) const { + T result(t1); + result &= t2; + _is_empty = is_empty(0, result); + return result; + } + + virtual T mk_widen(T const& t1, T const& t2) const { + UNREACHABLE(); + return t1; + } + + virtual T mk_unite(T const& t1, T const& t2) const { + UNREACHABLE(); + return t1; + } + + virtual bool is_subset_of(T const& t1, T const& t2) const { + return t2.contains(t1); + } + + virtual bool is_full(T const& t) const { + for (unsigned j = 0; j < t.size(); ++j) { + if (!t.get(j)) return false; + } + return true; + } + + virtual bool is_empty(unsigned i, T const& t) const { + for (unsigned j = 0; j < t.size(); ++j) { + if (t.get(j)) return false; + } + return true; + } + + virtual void mk_rename_elem(T& t, unsigned col_cnt, unsigned const* cycle) { + // no-op. + } + + virtual T mk_eq(union_find<> const& old_eqs, union_find<> const& neq_eqs, T const& t) const { + UNREACHABLE(); + return t; + } + + + }; + + typedef ptr_hashtable product_sets; + + class product_set_relation : public relation_base { + friend class product_set_plugin; + product_sets m_elems; + public: + product_set_relation(product_set_plugin& p, relation_signature const& s); + virtual ~product_set_relation(); + virtual void add_fact(const relation_fact & f); + virtual bool contains_fact(const relation_fact & f) const; + virtual product_set_relation * clone() const; + virtual product_set_relation * complement(func_decl*) const; + virtual void to_formula(expr_ref& fml) const; + product_set_plugin& get_plugin() const; + virtual bool empty() const { return m_elems.empty(); } + virtual void display(std::ostream& out) const; + + virtual bool is_precise() const { return true; } + }; + + class product_set_plugin : public relation_plugin { + friend class product_set_relation; + class join_fn; + class project_fn; + class union_fn; + class rename_fn; + class filter_equal_fn; + class filter_identical_fn; + class filter_interpreted_fn; + class filter_by_negation_fn; + + public: + product_set_plugin(relation_manager& rm); + virtual bool can_handle_signature(const relation_signature & s); + static symbol get_name() { return symbol("product_set"); } + virtual relation_base * mk_empty(const relation_signature & s); + virtual relation_base * mk_full(func_decl* p, const relation_signature & s); + virtual relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); + virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, + const unsigned * removed_cols); + virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle); + virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta); + virtual relation_union_fn * mk_widen_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta); + virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, + const unsigned * identical_cols); + virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, + unsigned col); + virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); + + unsigned set_size(sort* ty); + + private: + static product_set_relation& get(relation_base& r); + static product_set_relation* get(relation_base* r); + static product_set_relation const & get(relation_base const& r); + product_set* insert(product_set* s, product_set_relation* r); + }; + +}; + +#endif diff --git a/src/muz/rel/rel_context.cpp b/src/muz/rel/rel_context.cpp index 1a3d2cdae..742930b5c 100644 --- a/src/muz/rel/rel_context.cpp +++ b/src/muz/rel/rel_context.cpp @@ -31,6 +31,7 @@ Revision History: #include"dl_interval_relation.h" #include"karr_relation.h" #include"dl_finite_product_relation.h" +#include"product_set.h" #include"dl_lazy_table.h" #include"dl_sparse_table.h" #include"dl_table.h" @@ -112,6 +113,7 @@ namespace datalog { rm.register_plugin(alloc(bound_relation_plugin, rm)); rm.register_plugin(alloc(interval_relation_plugin, rm)); rm.register_plugin(alloc(karr_relation_plugin, rm)); + rm.register_plugin(alloc(product_set_plugin, rm)); } rel_context::~rel_context() { From d67a73820d5ca4b4b07dbed83e5f59fe8eccfcac Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 23 Aug 2014 21:08:14 -0700 Subject: [PATCH 484/925] persisting check_predicate_proc to gain sme efficiency Signed-off-by: Nikolaj Bjorner --- src/muz/base/hnf.cpp | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/muz/base/hnf.cpp b/src/muz/base/hnf.cpp index 9d6f3c1ab..90f5ad352 100644 --- a/src/muz/base/hnf.cpp +++ b/src/muz/base/hnf.cpp @@ -58,6 +58,19 @@ Notes: #include"for_each_expr.h" class hnf::imp { + + class contains_predicate_proc { + imp const& m; + public: + struct found {}; + contains_predicate_proc(imp const& m): m(m) {} + void operator()(var * n) {} + void operator()(quantifier * n) {} + void operator()(app* n) { + if (m.is_predicate(n)) throw found(); + } + }; + ast_manager& m; bool m_produce_proofs; volatile bool m_cancel; @@ -73,6 +86,7 @@ class hnf::imp { func_decl_ref_vector m_fresh_predicates; expr_ref_vector m_body; proof_ref_vector m_defs; + contains_predicate_proc m_proc; public: @@ -87,7 +101,8 @@ public: m_qh(m), m_fresh_predicates(m), m_body(m), - m_defs(m) { + m_defs(m), + m_proc(*this) { } void operator()(expr * n, @@ -166,22 +181,9 @@ private: return m.is_bool(f->get_range()) && f->get_family_id() == null_family_id; } - class contains_predicate_proc { - imp const& m; - public: - struct found {}; - contains_predicate_proc(imp const& m): m(m) {} - void operator()(var * n) {} - void operator()(quantifier * n) {} - void operator()(app* n) { - if (m.is_predicate(n)) throw found(); - } - }; - - bool contains_predicate(expr* fml) const { - contains_predicate_proc proc(*this); + bool contains_predicate(expr* fml) { try { - quick_for_each_expr(proc, fml); + quick_for_each_expr(m_proc, fml); } catch (contains_predicate_proc::found) { return true; From aa695f6a6c14519f7119cc24898776d8f8e4ad24 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Aug 2014 12:47:57 -0700 Subject: [PATCH 485/925] improve incremental use of sat solver: carry over simplification threshold Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index d21c49b0c..cb4242af7 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -50,6 +50,7 @@ namespace sat { m_params(p) { m_config.updt_params(p); m_conflicts_since_gc = 0; + m_conflicts = 0; m_next_simplify = 0; m_num_checkpoints = 0; } @@ -742,8 +743,7 @@ namespace sat { // iff3_finder(*this)(); simplify_problem(); if (check_inconsistent()) return l_false; - - m_next_simplify = m_config.m_restart_initial * m_config.m_simplify_mult1; + if (m_config.m_max_conflicts == 0) { IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "\"abort: max-conflicts = 0\"\n";); @@ -763,13 +763,8 @@ namespace sat { } restart(); - if (m_conflicts >= m_next_simplify) { - simplify_problem(); - if (check_inconsistent()) return l_false; - m_next_simplify = static_cast(m_conflicts * m_config.m_simplify_mult2); - if (m_next_simplify > m_conflicts + m_config.m_simplify_max) - m_next_simplify = m_conflicts + m_config.m_simplify_max; - } + simplify_problem(); + if (check_inconsistent()) return l_false; gc(); } } @@ -955,7 +950,6 @@ namespace sat { void solver::init_search() { m_phase_counter = 0; m_phase_cache_on = false; - m_conflicts = 0; m_conflicts_since_restart = 0; m_restart_threshold = m_config.m_restart_initial; m_luby_idx = 1; @@ -972,6 +966,9 @@ namespace sat { */ void solver::simplify_problem() { + if (m_conflicts < m_next_simplify) { + return; + } // Disable simplification during MUS computation. // if (m_mus.is_active()) return; @@ -1016,6 +1013,15 @@ namespace sat { TRACE("sat", display(tout << "consistent: " << (!inconsistent()) << "\n");); reinit_assumptions(); + + if (m_next_simplify == 0) { + m_next_simplify = m_config.m_restart_initial * m_config.m_simplify_mult1; + } + else { + m_next_simplify = static_cast(m_conflicts * m_config.m_simplify_mult2); + if (m_next_simplify > m_conflicts + m_config.m_simplify_max) + m_next_simplify = m_conflicts + m_config.m_simplify_max; + } } void solver::sort_watch_lits() { From 16bffab8fde856d05660cf06479bcb336db2cb49 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Aug 2014 14:21:15 -0700 Subject: [PATCH 486/925] add saner Shannon decomposition Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 1 + src/tactic/arith/card2bv_tactic.cpp | 197 +++++++++++++++++++++++++--- src/tactic/arith/card2bv_tactic.h | 2 + 3 files changed, 185 insertions(+), 15 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index cb4242af7..3d854522b 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -969,6 +969,7 @@ namespace sat { if (m_conflicts < m_next_simplify) { return; } + IF_VERBOSE(2, verbose_stream() << "(sat.simplify)\n";); // Disable simplification during MUS computation. // if (m_mus.is_active()) return; diff --git a/src/tactic/arith/card2bv_tactic.cpp b/src/tactic/arith/card2bv_tactic.cpp index ea4bd4aed..4661dc7db 100644 --- a/src/tactic/arith/card2bv_tactic.cpp +++ b/src/tactic/arith/card2bv_tactic.cpp @@ -59,8 +59,13 @@ namespace pb { return BR_DONE; } else if (f->get_family_id() == pb.get_family_id()) { - // return mk_shannon(f, sz, args, result); - return mk_bv(f, sz, args, result); + br_status st = mk_shannon(f, sz, args, result); + if (st == BR_FAILED) { + return mk_bv(f, sz, args, result); + } + else { + return st; + } } // NSB: review // we should remove this code and rely on a layer above to deal with @@ -143,20 +148,182 @@ namespace pb { return BR_DONE; } - br_status card2bv_rewriter::mk_shannon(func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { - pb_rewriter rw(m); - if (sz == 0) { - rw.mk_app_core(f, sz, args, result); - return BR_DONE; + struct argc_t { + expr* m_arg; + rational m_coeff; + argc_t():m_arg(0), m_coeff(0) {} + argc_t(expr* arg, rational const& r): m_arg(arg), m_coeff(r) {} + }; + struct argc_gt { + bool operator()(argc_t const& a, argc_t const& b) const { + return a.m_coeff > b.m_coeff; } - expr_ref r1(m), r2(m); - ptr_vector new_args(sz, args); - new_args[0] = m.mk_true(); - rw.mk_app_core(f, sz, new_args.c_ptr(), r1); - new_args[0] = m.mk_false(); - rw.mk_app_core(f, sz, new_args.c_ptr(), r2); - result = m.mk_ite(args[0], r1, r2); - return BR_REWRITE_FULL; + }; + struct argc_entry { + unsigned m_index; + rational m_k; + expr* m_value; + argc_entry(unsigned i, rational const& k): m_index(i), m_k(k), m_value(0) {} + argc_entry():m_index(0), m_k(0), m_value(0) {} + + struct eq { + bool operator()(argc_entry const& a, argc_entry const& b) const { + return a.m_index == b.m_index && a.m_k == b.m_k; + } + }; + struct hash { + unsigned operator()(argc_entry const& a) const { + return a.m_index ^ a.m_k.hash(); + } + }; + }; + typedef hashtable argc_cache; + + br_status card2bv_rewriter::mk_shannon( + func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { + + return BR_FAILED; + + // disabled for now. + unsigned max_clauses = sz*10; + vector argcs; + for (unsigned i = 0; i < sz; ++i) { + argcs.push_back(argc_t(args[i], pb.get_coeff(f, i))); + } + std::sort(argcs.begin(), argcs.end(), argc_gt()); + DEBUG_CODE( + for (unsigned i = 0; i + 1 < sz; ++i) { + SASSERT(argcs[i].m_coeff >= argcs[i+1].m_coeff); + } + ); + argc_cache cache; + expr_ref_vector trail(m); + vector todo_k; + unsigned_vector todo_i; + todo_k.push_back(pb.get_k(f)); + todo_i.push_back(0); + decl_kind kind = f->get_decl_kind(); + argc_entry entry1; + while (!todo_i.empty()) { + + if (cache.size() > max_clauses) { + return BR_FAILED; + } + unsigned i = todo_i.back(); + rational k = todo_k.back(); + argc_entry entry(i, k); + if (cache.contains(entry)) { + todo_i.pop_back(); + todo_k.pop_back(); + continue; + } + SASSERT(i < sz); + SASSERT(!k.is_neg()); + rational const& coeff = argcs[i].m_coeff; + expr* arg = argcs[i].m_arg; + if (i + 1 == sz) { + switch(kind) { + case OP_AT_MOST_K: + case OP_PB_LE: + if (coeff <= k) { + entry.m_value = m.mk_true(); + } + else { + entry.m_value = negate(arg); + trail.push_back(entry.m_value); + } + break; + case OP_AT_LEAST_K: + case OP_PB_GE: + if (coeff < k) { + entry.m_value = m.mk_false(); + } + else if (coeff.is_zero()) { + entry.m_value = m.mk_true(); + } + else { + entry.m_value = arg; + } + break; + case OP_PB_EQ: + if (coeff == k) { + entry.m_value = arg; + } + else if (k.is_zero()) { + entry.m_value = negate(arg); + trail.push_back(entry.m_value); + } + else { + entry.m_value = m.mk_false(); + } + break; + } + todo_i.pop_back(); + todo_k.pop_back(); + cache.insert(entry); + continue; + } + entry.m_index++; + expr* lo = 0, *hi = 0; + if (cache.find(entry, entry1)) { + lo = entry1.m_value; + } + else { + todo_i.push_back(i+1); + todo_k.push_back(k); + } + entry.m_k -= coeff; + if (kind != OP_PB_EQ && entry.m_k.is_neg()) { + switch (kind) { + case OP_AT_MOST_K: + case OP_PB_LE: + hi = m.mk_false(); + break; + case OP_AT_LEAST_K: + case OP_PB_GE: + hi = m.mk_true(); + break; + default: + UNREACHABLE(); + } + } + else if (cache.find(entry, entry1)) { + hi = entry1.m_value; + } + else { + todo_i.push_back(i+1); + todo_k.push_back(entry.m_k); + } + if (hi && lo) { + todo_i.pop_back(); + todo_k.pop_back(); + entry.m_index = i; + entry.m_k = k; + entry.m_value = mk_ite(arg, hi, lo); + trail.push_back(entry.m_value); + cache.insert(entry); + } + } + argc_entry entry(0, pb.get_k(f)); + VERIFY(cache.find(entry, entry)); + result = entry.m_value; + return BR_DONE; + } + + expr* card2bv_rewriter::negate(expr* e) { + if (m.is_not(e, e)) return e; + return m.mk_not(e); + } + + expr* card2bv_rewriter::mk_ite(expr* c, expr* hi, expr* lo) { + if (hi == lo) return hi; + if (m.is_true(hi) && m.is_false(lo)) return c; + if (m.is_false(hi) && m.is_true(lo)) return negate(c); + if (m.is_true(hi)) return m.mk_or(c, lo); + if (m.is_false(lo)) return m.mk_and(c, hi); + if (m.is_false(hi)) return m.mk_and(negate(c), lo); + if (m.is_true(lo)) return m.mk_implies(c, hi); + return m.mk_ite(c, hi, lo); } }; diff --git a/src/tactic/arith/card2bv_tactic.h b/src/tactic/arith/card2bv_tactic.h index e1fa6dbde..d5e110cf3 100644 --- a/src/tactic/arith/card2bv_tactic.h +++ b/src/tactic/arith/card2bv_tactic.h @@ -37,6 +37,8 @@ namespace pb { unsigned get_num_bits(func_decl* f); br_status mk_bv(func_decl * f, unsigned sz, expr * const* args, expr_ref & result); br_status mk_shannon(func_decl * f, unsigned sz, expr * const* args, expr_ref & result); + expr* negate(expr* e); + expr* mk_ite(expr* c, expr* hi, expr* lo); public: card2bv_rewriter(ast_manager& m); br_status mk_app_core(func_decl * f, unsigned sz, expr * const* args, expr_ref & result); From b82a68f4d465d056392f344d681dd1c78eff8bc7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Aug 2014 19:53:55 -0700 Subject: [PATCH 487/925] fix bug in sls Signed-off-by: Nikolaj Bjorner --- src/opt/inc_sat_solver.cpp | 16 +++++++++++++++- src/opt/maxsls.cpp | 1 + src/opt/maxsmt.cpp | 4 ++++ src/opt/maxsmt.h | 2 ++ src/opt/opt_context.h | 1 + src/sat/sat_sls.cpp | 6 ++++-- 6 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/opt/inc_sat_solver.cpp b/src/opt/inc_sat_solver.cpp index 89f9e79fd..49315a895 100644 --- a/src/opt/inc_sat_solver.cpp +++ b/src/opt/inc_sat_solver.cpp @@ -228,11 +228,25 @@ private: r = internalize_assumptions(soft.size(), soft.c_ptr(), dep2asm); sat::literal_vector lits; svector weights; + sat::literal lit; if (r == l_true) { for (unsigned i = 0; i < soft.size(); ++i) { weights.push_back(m_weights[i].get_double()); - lits.push_back(dep2asm.find(soft[i].get())); + expr* s = soft[i].get(); + bool is_neg = m.is_not(s, s); + if (!dep2asm.find(s, lit)) { + std::cout << "not found: " << mk_pp(s, m) << "\n"; + dep2asm_t::iterator it = dep2asm.begin(), end = dep2asm.end(); + for (; it != end; ++it) { + std::cout << mk_pp(it->m_key, m) << " " << it->m_value << "\n"; + } + UNREACHABLE(); + } + if (is_neg) { + lit.neg(); + } + lits.push_back(lit); } m_solver.initialize_soft(lits.size(), lits.c_ptr(), weights.c_ptr()); m_params.set_bool("optimize_model", true); diff --git a/src/opt/maxsls.cpp b/src/opt/maxsls.cpp index 48fa48821..c679a6929 100644 --- a/src/opt/maxsls.cpp +++ b/src/opt/maxsls.cpp @@ -33,6 +33,7 @@ namespace opt { lbool operator()() { IF_VERBOSE(1, verbose_stream() << "(opt.sls)\n";); init(); + set_enable_sls(true); enable_sls(m_soft, m_weights); lbool is_sat = s().check_sat(0, 0); if (is_sat == l_true) { diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index d084dc5b5..9fe704942 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -98,6 +98,10 @@ namespace opt { m_c.enable_sls(soft, ws); } + void maxsmt_solver_base::set_enable_sls(bool f) { + m_c.set_enable_sls(f); + } + app* maxsmt_solver_base::mk_fresh_bool(char const* name) { app* result = m.mk_fresh_const(name, m.mk_bool_sort()); m_c.fm().insert(result->get_decl()); diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index b3e17ad71..47b903e17 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -84,6 +84,8 @@ namespace opt { app* mk_fresh_bool(char const* name); protected: void enable_sls(expr_ref_vector const& soft, weights_t& ws); + void set_enable_sls(bool f); + }; /** diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 63ac13edc..5f3bd88cb 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -177,6 +177,7 @@ namespace opt { ast_manager& get_manager() { return this->m; } params_ref& params() { return m_params; } void enable_sls(expr_ref_vector const& soft, weights_t& weights); + void set_enable_sls(bool f) { m_enable_sls = f; } symbol const& maxsat_engine() const { return m_maxsat_engine; } diff --git a/src/sat/sat_sls.cpp b/src/sat/sat_sls.cpp index 8f4e09173..3a520742e 100644 --- a/src/sat/sat_sls.cpp +++ b/src/sat/sat_sls.cpp @@ -387,8 +387,10 @@ namespace sat { m_best_value = val; m_best_model.reset(); m_best_model.append(m_model); - IF_VERBOSE(0, verbose_stream() << "new value: " << val << " @ " << i << "\n";); - m_max_tries *= 2; + IF_VERBOSE(1, verbose_stream() << "new value: " << val << " @ " << i << "\n";); + if (i*2 > m_max_tries) { + m_max_tries *= 2; + } } } } From 8938de2ba2a8ae33f031c8e0b3dc422a5ff93a4b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Aug 2014 12:11:34 -0700 Subject: [PATCH 488/925] fix build error reported by Ari Signed-off-by: Nikolaj Bjorner --- src/opt/maxhs.h | 2 +- src/sat/sat_mus.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/opt/maxhs.h b/src/opt/maxhs.h index 6bb7a2696..f31cbce9f 100644 --- a/src/opt/maxhs.h +++ b/src/opt/maxhs.h @@ -24,6 +24,6 @@ Notes: namespace opt { maxsmt_solver_base* mk_maxhs(context& c, - vector const& ws, expr_ref_vector const& soft); + weights_t& ws, expr_ref_vector const& soft); } #endif diff --git a/src/sat/sat_mus.cpp b/src/sat/sat_mus.cpp index 74f17f8ea..b33c9420c 100644 --- a/src/sat/sat_mus.cpp +++ b/src/sat/sat_mus.cpp @@ -71,7 +71,7 @@ namespace sat { literal lit = core.back(); core.pop_back(); unsigned sz = mus.size(); - mus.push_back(~lit); // TBD: measure + // mus.push_back(~lit); // TBD: measure mus.append(core); lbool is_sat = s.check(mus.size(), mus.c_ptr()); TRACE("sat", tout << "mus: " << mus << "\n";); From 20728535e8aca86562cf6191c11023c78357411a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Aug 2014 13:12:49 -0700 Subject: [PATCH 489/925] remove extra qualifier Signed-off-by: Nikolaj Bjorner --- src/opt/bcd2.cpp | 2 +- src/opt/hitting_sets.cpp | 2 +- src/util/mpq_inf.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/opt/bcd2.cpp b/src/opt/bcd2.cpp index 5d5fa2f7c..779654e7e 100644 --- a/src/opt/bcd2.cpp +++ b/src/opt/bcd2.cpp @@ -398,7 +398,7 @@ namespace opt { } }; - maxsmt_solver_base* opt::mk_bcd2( + maxsmt_solver_base* mk_bcd2( context& c, weights_t& ws, expr_ref_vector const& soft) { return alloc(bcd2, c, ws, soft); } diff --git a/src/opt/hitting_sets.cpp b/src/opt/hitting_sets.cpp index c3436f61d..37b800428 100644 --- a/src/opt/hitting_sets.cpp +++ b/src/opt/hitting_sets.cpp @@ -541,7 +541,7 @@ namespace opt { VERIFY(l_true == m_simplex.minimize(m_weights_var)); mpq_inf const& val = m_simplex.get_value(m_weights_var); unsynch_mpq_inf_manager mg; - unsynch_mpq_manager& mq = mg.mpq_manager(); + unsynch_mpq_manager& mq = mg.get_mpq_manager(); scoped_mpq c(mq); mg.ceil(val, c); rational w(c); diff --git a/src/util/mpq_inf.h b/src/util/mpq_inf.h index d7202a79a..640c827ae 100644 --- a/src/util/mpq_inf.h +++ b/src/util/mpq_inf.h @@ -276,7 +276,7 @@ public: out << to_string(a); } - mpq_manager& mpq_manager() { return m; } + mpq_manager& get_mpq_manager() { return m; } }; typedef mpq_inf_manager synch_mpq_inf_manager; From 4d589de970886e90ba12c0fe4052488939cb4cba Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Aug 2014 13:13:43 -0700 Subject: [PATCH 490/925] remove extra qualifier Signed-off-by: Nikolaj Bjorner --- src/opt/maxhs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/opt/maxhs.cpp b/src/opt/maxhs.cpp index fd585065b..9f8aa2d11 100644 --- a/src/opt/maxhs.cpp +++ b/src/opt/maxhs.cpp @@ -554,7 +554,7 @@ namespace opt { }; - maxsmt_solver_base* opt::mk_maxhs( + maxsmt_solver_base* mk_maxhs( context& c, weights_t& ws, expr_ref_vector const& soft) { return alloc(maxhs, c, ws, soft); } From 2dcbf192cce28fc43c17a319f230eb4a15d05897 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Aug 2014 13:14:20 -0700 Subject: [PATCH 491/925] remove extra qualifier Signed-off-by: Nikolaj Bjorner --- src/opt/maxsls.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/opt/maxsls.cpp b/src/opt/maxsls.cpp index c679a6929..1c6e745a4 100644 --- a/src/opt/maxsls.cpp +++ b/src/opt/maxsls.cpp @@ -53,7 +53,7 @@ namespace opt { }; - maxsmt_solver_base* opt::mk_sls( + maxsmt_solver_base* mk_sls( context& c, weights_t& ws, expr_ref_vector const& soft) { return alloc(sls, c, ws, soft); } From ff501986f1e677ff70e2f26001c9f5fd7aa2e92d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Aug 2014 13:15:01 -0700 Subject: [PATCH 492/925] remove extra qualifier Signed-off-by: Nikolaj Bjorner --- src/opt/pbmax.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/opt/pbmax.cpp b/src/opt/pbmax.cpp index b975543e3..a30fe3acb 100644 --- a/src/opt/pbmax.cpp +++ b/src/opt/pbmax.cpp @@ -87,7 +87,7 @@ namespace opt { } }; - maxsmt_solver_base* opt::mk_pbmax( + maxsmt_solver_base* mk_pbmax( context & c, weights_t& ws, expr_ref_vector const& soft) { return alloc(pbmax, c, ws, soft); } From 3ae10abf046d2a553eb341a56be11d0f1af104f3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Aug 2014 13:15:29 -0700 Subject: [PATCH 493/925] remove extra qualifier Signed-off-by: Nikolaj Bjorner --- src/opt/wmax.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/opt/wmax.cpp b/src/opt/wmax.cpp index 390c3608d..24f381dbd 100644 --- a/src/opt/wmax.cpp +++ b/src/opt/wmax.cpp @@ -122,8 +122,8 @@ namespace opt { } }; - maxsmt_solver_base* opt::mk_wmax(context& c, - vector const& ws, expr_ref_vector const& soft) { + maxsmt_solver_base* mk_wmax(context& c, + vector const& ws, expr_ref_vector const& soft) { return alloc(wmax, c, ws, soft); } From 9e7cef7d6bf3fcf37357e3f9c7a571e79bc6a0a2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 26 Aug 2014 16:45:45 -0700 Subject: [PATCH 494/925] working on product sets Signed-off-by: Nikolaj Bjorner --- src/muz/rel/dl_relation_manager.cpp | 21 ++ src/muz/rel/dl_relation_manager.h | 5 + src/muz/rel/product_set.cpp | 352 +++++++++++++++++++++++----- src/muz/rel/product_set.h | 34 ++- src/opt/opt_params.pyg | 5 +- src/sat/sat_mus.cpp | 16 +- src/util/bit_vector.cpp | 8 + src/util/bit_vector.h | 2 + 8 files changed, 377 insertions(+), 66 deletions(-) diff --git a/src/muz/rel/dl_relation_manager.cpp b/src/muz/rel/dl_relation_manager.cpp index 9421b26df..3c034ff0f 100644 --- a/src/muz/rel/dl_relation_manager.cpp +++ b/src/muz/rel/dl_relation_manager.cpp @@ -668,6 +668,27 @@ namespace datalog { return res; } + class relation_manager::default_relation_apply_sequential_fn : public relation_mutator_fn { + ptr_vector m_mutators; + public: + default_relation_apply_sequential_fn(unsigned n, relation_mutator_fn ** mutators): + m_mutators(n, mutators) { + } + virtual ~default_relation_apply_sequential_fn() { + std::for_each(m_mutators.begin(), m_mutators.end(), delete_proc()); + } + + virtual void operator()(relation_base& t) { + for (unsigned i = 0; i < m_mutators.size(); ++i) { + if (t.empty()) return; + (*(m_mutators[i]))(t); + } + } + }; + + relation_mutator_fn * relation_manager::mk_apply_sequential_fn(unsigned n, relation_mutator_fn ** mutators) { + return alloc(default_relation_apply_sequential_fn, n, mutators); + } class relation_manager::default_relation_join_project_fn : public relation_join_fn { scoped_ptr m_join; diff --git a/src/muz/rel/dl_relation_manager.h b/src/muz/rel/dl_relation_manager.h index 2c148c5e6..be81a7afa 100644 --- a/src/muz/rel/dl_relation_manager.h +++ b/src/muz/rel/dl_relation_manager.h @@ -43,6 +43,7 @@ namespace datalog { class default_relation_select_equal_and_project_fn; class default_relation_intersection_filter_fn; class default_relation_filter_interpreted_and_project_fn; + class default_relation_apply_sequential_fn; class auxiliary_table_transformer_fn; class auxiliary_table_filter_fn; @@ -352,9 +353,13 @@ namespace datalog { relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); + relation_transformer_fn * mk_filter_interpreted_and_project_fn(const relation_base & t, app * condition, unsigned removed_col_cnt, const unsigned * removed_cols); + relation_mutator_fn * mk_apply_sequential_fn(unsigned n, relation_mutator_fn* * mutators); + + /** \brief Operations that returns all rows of \c t for which is column \c col equal to \c value with the column \c col removed. diff --git a/src/muz/rel/product_set.cpp b/src/muz/rel/product_set.cpp index 2812c56e2..a0c534934 100644 --- a/src/muz/rel/product_set.cpp +++ b/src/muz/rel/product_set.cpp @@ -26,10 +26,14 @@ namespace datalog { product_set::product_set( product_set_plugin& p, relation_signature const& s, - bool is_empty, T const& t): - vector_relation(p, s, is_empty, t), m_refs(0) { + initial_t init, T const& t): + vector_relation(p, s, false, t), m_refs(0) { for (unsigned i = 0; i < s.size(); ++i) { - (*this)[i] = bit_vector(p.set_size(s[i])); + unsigned sz = p.set_size(s[i]); + (*this)[i].resize(sz); + if (init == FULL_t) { + (*this)[i].neg(); + } } } @@ -135,19 +139,43 @@ namespace datalog { } } + class product_set_plugin::filter_interpreted_fn : public relation_mutator_fn { + app_ref m_condition; + public: + filter_interpreted_fn(ast_manager& m, app* condition): m_condition(condition, m) { + + }; + virtual ~filter_interpreted_fn() {} + + virtual void operator()(relation_base & _r) { + ast_manager& m = m_condition.get_manager(); + if (m.is_false(m_condition)) { + _r.reset(); + return; + } + if (m.is_true(m_condition)) { + return; + } + product_set_relation & r = get(_r); + product_set_plugin & p = r.get_plugin(); + NOT_IMPLEMENTED_YET(); + } + }; + void product_set_relation::add_fact(const relation_fact & f) { ast_manager& m = get_plugin().get_ast_manager(); bv_util bv(m); + product_set* s = alloc(product_set, get_plugin(), get_signature(), product_set::EMPTY_t); rational v; unsigned bv_size; - product_set* s = alloc(product_set, get_plugin(), get_signature(), false); + // the bit-vector sets are empty at this point so they need to be primed. for (unsigned i = 0; i < f.size(); ++i) { VERIFY(bv.is_numeral(f[i], v, bv_size)); SASSERT(v.is_unsigned()); (*s)[i] = bit_vector(get_plugin().set_size(m.get_sort(f[i]))); (*s)[i].set(v.get_unsigned(), true); } - s->display(std::cout << "fact"); + // s->display(std::cout << "fact"); if (m_elems.contains(s)) { dealloc(s); } @@ -201,7 +229,9 @@ namespace datalog { // product_set_plugin product_set_plugin::product_set_plugin(relation_manager& rm): - relation_plugin(product_set_plugin::get_name(), rm) { + relation_plugin(product_set_plugin::get_name(), rm), + m(rm.get_context().get_manager()), + bv(m) { } bool product_set_plugin::can_handle_signature(const relation_signature & sig) { @@ -226,15 +256,8 @@ namespace datalog { } relation_base * product_set_plugin::mk_full(func_decl* p, const relation_signature & sig) { product_set_relation* result = alloc(product_set_relation, *this, sig); - product_set* s = alloc(product_set, *this, sig, false); + product_set* s = alloc(product_set, *this, sig, product_set::FULL_t); s->inc_ref(); - for (unsigned i = 0; i < sig.size(); ++i) { - bit_vector& t = (*s)[i]; - t = bit_vector(set_size(sig[i])); - for (unsigned j = 0; j < t.size(); ++j) { - t.set(j, true); - } - } result->m_elems.insert(s); return result; } @@ -248,7 +271,7 @@ namespace datalog { else { s->inc_ref(); r->m_elems.insert(s); - s = alloc(product_set, *this, r->get_signature(), false); + s = alloc(product_set, *this, r->get_signature(), product_set::FULL_t); } return s; } @@ -276,7 +299,7 @@ namespace datalog { product_set_plugin& p = r1.get_plugin(); relation_signature const& sig = get_result_signature(); product_set_relation * result = alloc(product_set_relation, p, sig); - product_set* s = alloc(product_set, p, sig, false); + product_set* s = alloc(product_set, p, sig, product_set::FULL_t); product_sets::iterator it1 = r1.m_elems.begin(), end1 = r1.m_elems.end(); for (; it1 != end1; ++it1) { product_sets::iterator it2 = r2.m_elems.begin(), end2 = r2.m_elems.end(); @@ -310,7 +333,7 @@ namespace datalog { product_set_plugin& p = r.get_plugin(); relation_signature const& sig = get_result_signature(); product_set_relation* result = alloc(product_set_relation, p, sig); - product_set* s = alloc(product_set, p, sig, false); + product_set* s = alloc(product_set, p, sig, product_set::FULL_t); product_sets::iterator it = r.m_elems.begin(), end = r.m_elems.end(); for (; it != end; ++it) { s->mk_project(*(*it), m_removed_cols.size(), m_removed_cols.c_ptr()); @@ -341,7 +364,7 @@ namespace datalog { product_set_plugin& p = r.get_plugin(); relation_signature const& sig = get_result_signature(); product_set_relation* result = alloc(product_set_relation, p, sig); - product_set* s = alloc(product_set, p, sig, false); + product_set* s = alloc(product_set, p, sig, product_set::FULL_t); product_sets::iterator it = r.m_elems.begin(), end = r.m_elems.end(); for (; it != end; ++it) { s->mk_rename(*(*it), m_cycle.size(), m_cycle.c_ptr()); @@ -373,20 +396,24 @@ namespace datalog { product_set_relation& r = get(_r); product_set_relation const& src = get(_src); product_set_relation* d = get(_delta); - product_sets::iterator it = src.m_elems.begin(), end = src.m_elems.end(); - for (; it != end; ++it) { - product_set* ps = *it; - if (!r.m_elems.contains(ps)) { + r.get_plugin().mk_union(r, src, d); + } + }; + void product_set_plugin::mk_union( + product_set_relation& dst, product_set_relation const& src, product_set_relation* delta) { + product_sets::iterator it = src.m_elems.begin(), end = src.m_elems.end(); + for (; it != end; ++it) { + product_set* ps = *it; + if (!dst.m_elems.contains(ps)) { + ps->inc_ref(); + dst.m_elems.insert(ps); + if (delta) { ps->inc_ref(); - r.m_elems.insert(ps); - if (d) { - ps->inc_ref(); - d->m_elems.insert(ps); - } + delta->m_elems.insert(ps); } } } - }; + } relation_union_fn * product_set_plugin::mk_union_fn( const relation_base & tgt, const relation_base & src, const relation_base * delta) { @@ -442,31 +469,13 @@ namespace datalog { return check_kind(t)?alloc(filter_identical_fn, col_cnt, identical_cols):0; } - class product_set_plugin::filter_equal_fn : public relation_mutator_fn { - unsigned m_col; - bit_vector m_value; + + class product_set_plugin::filter_mask_fn : public relation_mutator_fn { + unsigned m_col; + bit_vector m_mask; public: - filter_equal_fn(product_set_plugin& p, const relation_element & value, unsigned col, bool is_eq) - : m_col(col) { - ast_manager& m = p.get_ast_manager(); - // m.get_context().get_manager() - bv_util bv(m); - rational v; - unsigned bv_size; - unsigned sz = p.set_size(m.get_sort(value)); - VERIFY(bv.is_numeral(value, v, bv_size)); - SASSERT(v.is_unsigned()); - unsigned w = v.get_unsigned(); - SASSERT(w < sz); - m_value = bit_vector(sz); - if (is_eq) { - m_value.set(w, true); - } - else { - for (unsigned i = 0; i < sz; ++i) { - m_value.set(i, i != w); - } - } + filter_mask_fn(product_set_plugin& p, bit_vector const& mask, unsigned col) + : m_col(col), m_mask(mask) { } virtual void operator()(relation_base & _r) { @@ -482,7 +491,7 @@ namespace datalog { for (unsigned i = 0; i < elems.size(); ++i) { product_set* s = elems[i]; - if (s->mk_intersect(m_col, m_value)) { + if (s->mk_intersect(m_col, m_mask)) { r.m_elems.insert(s); } else { @@ -494,17 +503,246 @@ namespace datalog { relation_mutator_fn * product_set_plugin::mk_filter_equal_fn(const relation_base & r, const relation_element & value, unsigned col) { - return check_kind(r)?alloc(filter_equal_fn, *this, value, col, true):0; + bit_vector mask; + expr* v = value; + extract_mask(1, &v, mask); + return check_kind(r)?alloc(filter_mask_fn, *this, mask, col):0; } + class product_set_plugin::filter_by_union_fn : public relation_mutator_fn { + ptr_vector m_mutators; + public: + filter_by_union_fn(unsigned n, relation_mutator_fn ** mutators): + m_mutators(n, mutators) { + } + virtual ~filter_by_union_fn() { + std::for_each(m_mutators.begin(), m_mutators.end(), delete_proc()); + } + + virtual void operator()(relation_base& _r) { + product_set_relation & r = get(_r); + product_set_plugin & p = r.get_plugin(); + + SASSERT(!m_mutators.empty()); + if (m_mutators.size() == 1) { + (*(m_mutators[0]))(r); + return; + } + product_set_relation src(p, r.get_signature()); + for (unsigned i = 1; i < m_mutators.size(); ++i) { + product_set_relation* r1 = r.clone(); + (*(m_mutators[i]))(*r1); + p.mk_union(src, *r1, 0); + r1->deallocate(); + } + (*(m_mutators[0]))(r); + p.mk_union(r, src, 0); + } + }; + + product_set_plugin::decomp_t product_set_plugin::decompose( + expr* condition, expr_ref_vector& args, unsigned& col) { + args.reset(); + expr* e1, *e2; + app* value; + if (m.is_not(condition, e1) && m.is_not(e1, e2)) { + return decompose(e2, args, col); + } + if (m.is_not(condition, e1) && m.is_and(e1)) { + expr_ref tmp(m); + app* a = to_app(e1); + unsigned sz = a->get_num_args(); + for (unsigned i = 0; i < sz; ++i) { + args.push_back(mk_not(a->get_arg(i))); + } + tmp = m.mk_or(args.size(), args.c_ptr()); + return decompose(tmp, args, col); + } + if (m.is_not(condition, e1) && m.is_or(e1)) { + expr_ref tmp(m); + app* a = to_app(e1); + unsigned sz = a->get_num_args(); + for (unsigned i = 0; i < sz; ++i) { + args.push_back(mk_not(a->get_arg(i))); + } + tmp = m.mk_and(args.size(), args.c_ptr()); + return decompose(tmp, args, col); + } + if (m.is_and(condition)) { + app* a = to_app(condition); + unsigned sz = a->get_num_args(); + args.append(sz, a->get_args()); + return AND_d; + } + if (is_setof(condition, args, col)) { + return SET_d; + } + if (m.is_or(condition)) { + app* a = to_app(condition); + unsigned sz = a->get_num_args(); + args.append(sz, a->get_args()); + return OR_d; + } + if (is_value_ne(condition, value, col)) { + args.push_back(value); + return NE_d; + } + if (is_value_eq(condition, value, col)) { + args.push_back(value); + return EQ_d; + } + if (m.is_not(condition, e1) && m.is_true(e1)) { + return F_d; + } + if (m.is_false(condition)) { + return F_d; + } + if (m.is_not(condition, e1) && m.is_false(e1)) { + return T_d; + } + if (m.is_true(condition)) { + return T_d; + } + return UNHANDLED_d; + } + + bool product_set_plugin::mk_filter_interpreted( + const relation_base & t, expr_ref_vector const& args, + ptr_vector& mutators) { + unsigned sz = args.size(); + + for (unsigned i = 0; i < sz; ++i) { + expr* arg = args[i]; + if (!is_app(arg)) { + break; + } + relation_mutator_fn* mut = mk_filter_interpreted_fn(t, to_app(arg)); + if (!mut) { + break; + } + mutators.push_back(mut); + } + if (mutators.size() < sz) { + std::for_each(mutators.begin(), mutators.end(), delete_proc()); + return false; + } + else { + return true; + } + } relation_mutator_fn * product_set_plugin::mk_filter_interpreted_fn( const relation_base & t, app * condition) { - ast_manager& m =get_manager().get_context().get_manager(); - std::cout << "filter interpreted '" << mk_pp(condition, m) << "'\n"; - NOT_IMPLEMENTED_YET(); + if (!check_kind(t)) return 0; + unsigned col; + ptr_vector mutators; + expr_ref_vector args(m); + std::cout << mk_pp(condition, m) << "\n"; + bit_vector mask; + switch (decompose(condition, args, col)) { + case NE_d: + SASSERT(args.size() == 1); + extract_mask(1, args.c_ptr(), mask); + mask.neg(); + return alloc(filter_mask_fn, *this, mask, col); + case EQ_d: + SASSERT(args.size() == 1); + extract_mask(1, args.c_ptr(), mask); + return alloc(filter_mask_fn, *this, mask, col); + case AND_d: + if (!mk_filter_interpreted(t, args, mutators)) { + return 0; + } + return get_manager().mk_apply_sequential_fn(mutators.size(), mutators.c_ptr()); + case OR_d: + if (!mk_filter_interpreted(t, args, mutators)) { + return 0; + } + return alloc(filter_by_union_fn, mutators.size(), mutators.c_ptr()); + case F_d: + return alloc(filter_interpreted_fn, m, m.mk_false()); + case T_d: + return alloc(filter_interpreted_fn, m, m.mk_true()); + case SET_d: + extract_mask(args.size(), args.c_ptr(), mask); + return alloc(filter_mask_fn, *this, mask, col); + case UNHANDLED_d: + std::cout << "filter interpreted unhandled '" << mk_pp(condition, m) << "'\n"; + NOT_IMPLEMENTED_YET(); + return 0; + default: + UNREACHABLE(); + } return 0; } + void product_set_plugin::extract_mask(unsigned n, expr* const* values, bit_vector& mask) { + SASSERT(n > 0); + unsigned sz = set_size(m.get_sort(values[0])); + mask.resize(sz, false); + rational v; + unsigned bv_size; + for (unsigned i = 0; i < n; ++i) { + expr* value = values[i]; + VERIFY(bv.is_numeral(value, v, bv_size)); + SASSERT(v.is_unsigned()); + unsigned w = v.get_unsigned(); + SASSERT(w < sz); + mask.set(w, true); + } + } + + bool product_set_plugin::is_setof(expr* condition, expr_ref_vector& values, unsigned & col) { + if (!m.is_or(condition)) return false; + unsigned sz = to_app(condition)->get_num_args(); + col = UINT_MAX; + unsigned col1; + if (sz == 0) return false; + values.reset(); + app* value; + for (unsigned i = 0; i < sz; ++i) { + expr* arg = to_app(condition)->get_arg(i); + if (is_value_eq(arg, value, col1)) { + if (col == UINT_MAX) { + col = col1; + values.push_back(value); + } + else if (col != col1) { + return false; + } + else { + values.push_back(value); + } + } + } + return true; + } + + bool product_set_plugin::is_value_eq(expr* e, app*& value, unsigned& col) { + expr* e1, *e2; + rational val; + unsigned bv_size; + if (!m.is_eq(e, e1, e2)) return false; + if (!is_var(e1)) { + std::swap(e1, e2); + } + if (!is_var(e1)) return false; + if (!bv.is_numeral(e2, val, bv_size)) return false; + if (!val.is_unsigned()) return false; + value = to_app(e2); + col = to_var(e1)->get_idx(); + return true; + } + + bool product_set_plugin::is_value_ne(expr* condition, relation_element& value, unsigned& col) { + expr* e; + if (m.is_not(condition, e)) { + return is_value_eq(e, value, col); + } + else { + return false; + } + } + }; diff --git a/src/muz/rel/product_set.h b/src/muz/rel/product_set.h index 670ec1cbf..c099e579a 100644 --- a/src/muz/rel/product_set.h +++ b/src/muz/rel/product_set.h @@ -40,7 +40,11 @@ namespace datalog { typedef bit_vector T; unsigned m_refs; public: - product_set(product_set_plugin& p, relation_signature const& s, bool is_empty, T const& t = T()); + enum initial_t { + EMPTY_t, + FULL_t + }; + product_set(product_set_plugin& p, relation_signature const& s, initial_t init, T const& t = T()); virtual ~product_set() {} unsigned get_hash() const; @@ -146,10 +150,13 @@ namespace datalog { class project_fn; class union_fn; class rename_fn; - class filter_equal_fn; + class filter_mask_fn; class filter_identical_fn; class filter_interpreted_fn; class filter_by_negation_fn; + class filter_by_union_fn; + ast_manager& m; + bv_util bv; public: product_set_plugin(relation_manager& rm); @@ -180,6 +187,29 @@ namespace datalog { static product_set_relation* get(relation_base* r); static product_set_relation const & get(relation_base const& r); product_set* insert(product_set* s, product_set_relation* r); + + enum decomp_t { + AND_d, // conjunction + OR_d, // disjunction + EQ_d, // value = col + NE_d, // value != col + F_d, // false + T_d, // true + SET_d, // disjunction value_i = col + UNHANDLED_d + }; + + decomp_t decompose(expr* condition, expr_ref_vector& args, unsigned& col); + + bool is_value_ne(expr* condition, relation_element& value, unsigned& col); + bool is_value_eq(expr* condition, relation_element& value, unsigned& col); + bool is_setof(expr* condition, expr_ref_vector& values, unsigned& col); + expr* mk_not(expr* e) { return m.is_not(e,e)?e:m.mk_not(e); } + void mk_union(product_set_relation& dst, product_set_relation const& src, product_set_relation* delta); + void extract_mask(unsigned sz, expr* const* values, bit_vector& mask); + bool mk_filter_interpreted( + const relation_base & t, expr_ref_vector const& args, + ptr_vector& mutators); }; }; diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index fbc2a8796..86c3fba11 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -3,15 +3,12 @@ def_module_params('opt', export=True, params=(('timeout', UINT, UINT_MAX, 'set timeout'), ('engine', SYMBOL, 'basic', "select optimization engine: 'basic', 'farkas', 'symba'"), - ('maxsat_engine', SYMBOL, 'wmax', "select engine for maxsat: 'fu_malik', 'core_maxsat', 'wmax', 'pbmax', 'maxres', 'bcd2', 'wpm2', 'sls', 'hsmax'"), + ('maxsat_engine', SYMBOL, 'wmax', "select engine for maxsat: 'fu_malik', 'core_maxsat', 'wmax', 'pbmax', 'maxres', 'bcd2', 'wpm2', 'sls', 'maxhs'"), ('priority', SYMBOL, 'lex', "select how to priortize objectives: 'lex' (lexicographic), 'pareto', or 'box'"), ('dump_benchmarks', BOOL, False, 'dump benchmarks for profiling'), ('print_model', BOOL, False, 'display model for satisfiable constraints'), - ('print_all_models', BOOL, False, 'display all intermediary models for satisfiable constraints'), - ('debug_conflict', BOOL, False, 'debug conflict resolution'), ('enable_sls', BOOL, False, 'enable SLS tuning during weighted maxsast'), ('enable_sat', BOOL, False, 'enable the new SAT core for propositional constraints'), - ('sls_engine', SYMBOL, 'pb', "SLS engine. Either 'bv' or 'pb'"), ('elim_01', BOOL, True, 'eliminate 01 variables'), ('pb.compile_equality', BOOL, False, 'compile arithmetical equalities into pseudo-Boolean equality (instead of two inequalites)') diff --git a/src/sat/sat_mus.cpp b/src/sat/sat_mus.cpp index b33c9420c..b6c7390e5 100644 --- a/src/sat/sat_mus.cpp +++ b/src/sat/sat_mus.cpp @@ -71,18 +71,19 @@ namespace sat { literal lit = core.back(); core.pop_back(); unsigned sz = mus.size(); - // mus.push_back(~lit); // TBD: measure mus.append(core); + mus.push_back(~lit); // TBD: measure lbool is_sat = s.check(mus.size(), mus.c_ptr()); TRACE("sat", tout << "mus: " << mus << "\n";); - mus.resize(sz); switch (is_sat) { case l_undef: + mus.resize(sz); core.push_back(lit); set_core(); return l_undef; case l_true: { SASSERT(value_at(lit, s.get_model()) == l_false); + mus.resize(sz); mus.push_back(lit); if (!core.empty()) { // mr(); // TBD: measure @@ -92,8 +93,18 @@ namespace sat { case l_false: literal_vector const& new_core = s.get_core(); if (new_core.contains(~lit)) { + mus.resize(sz); break; +#if 0 + mus.pop_back(); + is_sat = s.check(mus.size(), mus.c_ptr()); + SASSERT(is_sat != l_true); + if (is_sat != l_false) { + return l_undef; + } +#endif } + mus.resize(sz); TRACE("sat", tout << "new core: " << new_core << "\n";); core.reset(); for (unsigned i = 0; i < new_core.size(); ++i) { @@ -102,7 +113,6 @@ namespace sat { core.push_back(lit); } } - IF_VERBOSE(2, verbose_stream() << "reduced core: " << core.size() << "\n";); break; } } diff --git a/src/util/bit_vector.cpp b/src/util/bit_vector.cpp index c0c385210..b8cbdade2 100644 --- a/src/util/bit_vector.cpp +++ b/src/util/bit_vector.cpp @@ -228,6 +228,14 @@ unsigned bit_vector::get_hash() const { return string_hash(reinterpret_cast(m_data), size()/8, 0); } +bit_vector& bit_vector::neg() { + unsigned n = num_words(); + for (unsigned i = 0; i < n; ++i) { + m_data[i] = ~m_data[i]; + } + return *this; +} + void fr_bit_vector::reset() { unsigned sz = size(); unsigned_vector::const_iterator it = m_one_idxs.begin(); diff --git a/src/util/bit_vector.h b/src/util/bit_vector.h index 6ec2c18ee..6bfccd914 100644 --- a/src/util/bit_vector.h +++ b/src/util/bit_vector.h @@ -200,6 +200,8 @@ public: bit_vector & operator|=(bit_vector const & source); bit_vector & operator&=(bit_vector const & source); + + bit_vector & neg(); void display(std::ostream & out) const; From 965c9397b5b789838631ecabfd0446f9bb2365e5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 27 Aug 2014 14:32:31 -0700 Subject: [PATCH 495/925] expanding product_set Signed-off-by: Nikolaj Bjorner --- src/muz/rel/dl_base.cpp | 3 +- src/muz/rel/product_set.cpp | 63 ++++++++++++++++++++++++------------- src/muz/rel/product_set.h | 3 ++ 3 files changed, 46 insertions(+), 23 deletions(-) diff --git a/src/muz/rel/dl_base.cpp b/src/muz/rel/dl_base.cpp index dc10b5f8e..7a7f9819b 100644 --- a/src/muz/rel/dl_base.cpp +++ b/src/muz/rel/dl_base.cpp @@ -89,8 +89,7 @@ namespace datalog { void relation_base::reset() { ast_manager & m = get_plugin().get_ast_manager(); app_ref bottom_ref(m.mk_false(), m); - scoped_ptr reset_fn = - get_manager().mk_filter_interpreted_fn(static_cast(*this), bottom_ref); + scoped_ptr reset_fn = get_manager().mk_filter_interpreted_fn(*this, bottom_ref); if(!reset_fn) { NOT_IMPLEMENTED_YET(); } diff --git a/src/muz/rel/product_set.cpp b/src/muz/rel/product_set.cpp index a0c534934..730d8221c 100644 --- a/src/muz/rel/product_set.cpp +++ b/src/muz/rel/product_set.cpp @@ -52,27 +52,40 @@ namespace datalog { } return true; } - bool product_set::contains(product_set const& p) const { for (unsigned i = 0; i < get_signature().size(); ++i) { if ((*this)[i].contains(p[i])) return false; } return true; } - + void product_set::reset() { + for (unsigned i = 0; i < get_signature().size(); ++i) { + (*this)[i].fill0(); + } + } void product_set::add_fact(const relation_fact & f) { UNREACHABLE(); } bool product_set::contains_fact(const relation_fact & f) const { + UNREACHABLE(); return false; } relation_base * product_set::clone() const { - UNREACHABLE(); - return 0; + product_set* result = alloc(product_set, dynamic_cast(get_plugin()), get_signature(), EMPTY_t); + result->copy(*this); + return result; } relation_base * product_set::complement(func_decl*) const { - UNREACHABLE(); - return 0; + product_set* result = alloc(product_set, dynamic_cast(get_plugin()), get_signature(), EMPTY_t); + result->copy(*this); + result->complement(); + return result; + } + + void product_set::complement() { + for (unsigned i = 0; i < get_signature().size(); ++i) { + (*this)[i].neg(); + } } void product_set::to_formula(expr_ref& fml) const { ast_manager& m = fml.get_manager(); @@ -133,10 +146,7 @@ namespace datalog { } product_set_relation::~product_set_relation() { - product_sets::iterator it = m_elems.begin(), end = m_elems.end(); - for (; it != end; ++it) { - (*it)->dec_ref(); - } + reset(); } class product_set_plugin::filter_interpreted_fn : public relation_mutator_fn { @@ -150,7 +160,8 @@ namespace datalog { virtual void operator()(relation_base & _r) { ast_manager& m = m_condition.get_manager(); if (m.is_false(m_condition)) { - _r.reset(); + product_set_relation & r = get(_r); + r.reset(); return; } if (m.is_true(m_condition)) { @@ -172,7 +183,6 @@ namespace datalog { for (unsigned i = 0; i < f.size(); ++i) { VERIFY(bv.is_numeral(f[i], v, bv_size)); SASSERT(v.is_unsigned()); - (*s)[i] = bit_vector(get_plugin().set_size(m.get_sort(f[i]))); (*s)[i].set(v.get_unsigned(), true); } // s->display(std::cout << "fact"); @@ -194,12 +204,19 @@ namespace datalog { product_set_relation* r = alloc(product_set_relation, get_plugin(), get_signature()); product_sets::iterator it = m_elems.begin(), end = m_elems.end(); for (; it != end; ++it) { - // TBD: have to copy because other operations are destructive. - (*it)->inc_ref(); - r->m_elems.insert(*it); + product_set* ps = dynamic_cast((*it)->clone()); + ps->inc_ref(); + r->m_elems.insert(ps); } return r; } + void product_set_relation::reset() { + product_sets::iterator it = m_elems.begin(), end = m_elems.end(); + for (; it != end; ++it) { + (*it)->dec_ref(); + } + m_elems.reset(); + } product_set_relation * product_set_relation::complement(func_decl*) const { std::cout << "complement\n"; NOT_IMPLEMENTED_YET(); @@ -264,9 +281,11 @@ namespace datalog { product_set* product_set_plugin::insert(product_set* s, product_set_relation* r) { if (s->empty()) { s->reset(); + s->complement(); } else if (r->m_elems.contains(s)) { s->reset(); + s->complement(); } else { s->inc_ref(); @@ -309,6 +328,7 @@ namespace datalog { } } dealloc(s); + std::cout << "join " << result->m_elems.size() << "\n"; return result; } }; @@ -397,6 +417,7 @@ namespace datalog { product_set_relation const& src = get(_src); product_set_relation* d = get(_delta); r.get_plugin().mk_union(r, src, d); + std::cout << "union: " << r.m_elems.size() << "\n"; } }; void product_set_plugin::mk_union( @@ -540,8 +561,7 @@ namespace datalog { } }; - product_set_plugin::decomp_t product_set_plugin::decompose( - expr* condition, expr_ref_vector& args, unsigned& col) { + product_set_plugin::decomp_t product_set_plugin::decompose(expr* condition, expr_ref_vector& args, unsigned& col) { args.reset(); expr* e1, *e2; app* value; @@ -575,6 +595,7 @@ namespace datalog { return AND_d; } if (is_setof(condition, args, col)) { + SASSERT(!args.empty()); return SET_d; } if (m.is_or(condition)) { @@ -636,7 +657,6 @@ namespace datalog { unsigned col; ptr_vector mutators; expr_ref_vector args(m); - std::cout << mk_pp(condition, m) << "\n"; bit_vector mask; switch (decompose(condition, args, col)) { case NE_d: @@ -713,6 +733,9 @@ namespace datalog { values.push_back(value); } } + else { + return false; + } } return true; } @@ -722,9 +745,7 @@ namespace datalog { rational val; unsigned bv_size; if (!m.is_eq(e, e1, e2)) return false; - if (!is_var(e1)) { - std::swap(e1, e2); - } + if (!is_var(e1)) std::swap(e1, e2); if (!is_var(e1)) return false; if (!bv.is_numeral(e2, val, bv_size)) return false; if (!val.is_unsigned()) return false; diff --git a/src/muz/rel/product_set.h b/src/muz/rel/product_set.h index c099e579a..5865ce28a 100644 --- a/src/muz/rel/product_set.h +++ b/src/muz/rel/product_set.h @@ -71,9 +71,11 @@ namespace datalog { virtual bool contains_fact(const relation_fact & f) const; virtual relation_base * clone() const; virtual relation_base * complement(func_decl*) const; + virtual void reset(); virtual void to_formula(expr_ref& fml) const; bool mk_intersect(unsigned idx, T const& t); + void complement(); private: virtual void display_index(unsigned i, const T&, std::ostream& out) const; @@ -132,6 +134,7 @@ namespace datalog { public: product_set_relation(product_set_plugin& p, relation_signature const& s); virtual ~product_set_relation(); + virtual void reset(); virtual void add_fact(const relation_fact & f); virtual bool contains_fact(const relation_fact & f) const; virtual product_set_relation * clone() const; From 16e0ad14aad2ef92f75132fba1d541b797947664 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 Aug 2014 20:56:41 -0700 Subject: [PATCH 496/925] add MUS/MCS plan Signed-off-by: Nikolaj Bjorner --- src/muz/rel/product_set.h | 69 +++++++++++++++++++++++++++++++++++++-- src/opt/maxres.cpp | 43 ++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 2 deletions(-) diff --git a/src/muz/rel/product_set.h b/src/muz/rel/product_set.h index 5865ce28a..3bc5994f3 100644 --- a/src/muz/rel/product_set.h +++ b/src/muz/rel/product_set.h @@ -122,10 +122,9 @@ namespace datalog { UNREACHABLE(); return t; } - - }; + typedef ptr_hashtable product_sets; class product_set_relation : public relation_base { @@ -215,6 +214,72 @@ namespace datalog { ptr_vector& mutators); }; + class product_set_factory; + + + class product_set2 { + friend class product_set_factory; + unsigned char m_data[0]; + public: + enum initial_t { + EMPTY_t, + FULL_t + }; + product_set2(product_set_factory& fac, initial_t init); + ~product_set2(); + unsigned get_hash(product_set_factory& fac) const; + bool equals(product_set_factory& fac, product_set2 const& other) const; + void add_fact(product_set_factory& fac, const relation_fact & f); + bool contains_fact(product_set_factory& fac, const relation_fact & f) const; + relation_base * clone(product_set_factory& fac) const; + void reset(product_set_factory& fac); + void mk_join(product_set_factory& fac, product_set2 const& r1, product_set2 const& r2, + unsigned num_cols, unsigned const* cols1, unsigned const* cols2); + void mk_project(product_set_factory& fac, + product_set2 const& r, unsigned col_cnt, unsigned const* removed_cols); + void mk_rename(product_set_factory& fac, + product_set2 const& r, unsigned col_cnt, unsigned const* cycle); + void mk_union(product_set_factory& fac, + product_set2 const& src, product_set2* delta, bool is_widen); + unsigned find(product_set_factory& fac, unsigned i); + void merge(product_set_factory& fac, unsigned i, unsigned j); + void display(product_set_factory& fac, std::ostream& out) const; + }; + + + class product_set_factory { + friend class product_set_factory; + unsigned char m_data[0]; + public: + enum initial_t { + EMPTY_t, + FULL_t + }; + product_set_factory(product_set_plugin& p, relation_signature const& sig); + ~product_set_factory(); + product_set2* create(); + void retire(product_set2*); + + unsigned get_hash(product_set2& ps) const; + bool equals(product_set2 const& p1, product_set2 const& p2); + void add_fact(product_set2& p, const relation_fact & f); + bool contains_fact(product_set2& p, const relation_fact & f) const; + relation_base * clone(product_set2& p) const; + void reset(product_set2& p); + void mk_join(product_set2& p, product_set2 const& r1, product_set2 const& r2, + unsigned num_cols, unsigned const* cols1, unsigned const* cols2); + void mk_project(product_set2& p, + product_set2 const& r, unsigned col_cnt, unsigned const* removed_cols); + void mk_rename(product_set2& p, + product_set2 const& r, unsigned col_cnt, unsigned const* cycle); + void mk_union(product_set2& p, + product_set2 const& src, product_set2* delta, bool is_widen); + unsigned find(product_set2& p, unsigned i); + void merge(product_set2& p, unsigned i, unsigned j); + void display(product_set2& p, std::ostream& out) const; + }; + + }; #endif diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index be3470ad8..607ea81ae 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -70,6 +70,7 @@ public: enum strategy_t { s_mus, s_mus_mss, + s_mus_mss2, s_mss }; private: @@ -267,12 +268,54 @@ public: return l_true; } + /** + Plan: + - Get maximal set of disjoint cores. + - Update the lower bound using the cores. + - As a side-effect find a satisfying assignment that + has maximal weight. + (during core minimization several queries are bound to be SAT, + those can be used to boot-strap the MCS search). + - Use the best satisfying assignment to find an MCS of least weight. + - Update the upper bound using the MCS. + - Update the soft constraints using first the cores. + - Then update the resulting soft constraints using the evaluation of the MCS/MSS + - Add a cardinality constraint to force new satisfying assignments to improve + the new upper bound. + - In every iteration, the lower bound is improved using the cores. + - In every iteration, the upper bound is improved using the MCS + */ + lbool mus_mss2_solver() { + init(); + init_local(); + sls(); + NOT_IMPLEMENTED_YET(); + ptr_vector mcs; + vector > cores; + return l_undef; +#if 0 + while (m_lower < m_upper) { + TRACE("opt", + display_vec(tout, m_asms.size(), m_asms.c_ptr()); + s().display(tout); + tout << "\n"; + display(tout); + ); + } + m_lower = m_upper; + return l_true; +#endif + } + + lbool operator()() { switch(m_st) { case s_mus: return mus_solver(); case s_mus_mss: return mus_mss_solver(); + case s_mus_mss2: + return mus_mss2_solver(); case s_mss: return mss_solver(); } From bd8875bf5f8f17a2cf12f628680bd3560899e999 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 Aug 2014 21:18:17 -0700 Subject: [PATCH 497/925] add MUS/MCS plan Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 607ea81ae..955531c16 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -272,18 +272,23 @@ public: Plan: - Get maximal set of disjoint cores. - Update the lower bound using the cores. - - As a side-effect find a satisfying assignment that - has maximal weight. + - As a side-effect find a satisfying assignment that has maximal weight. (during core minimization several queries are bound to be SAT, those can be used to boot-strap the MCS search). - - Use the best satisfying assignment to find an MCS of least weight. + - Use the best satisfying assignment from the MUS search to find an MCS of least weight. - Update the upper bound using the MCS. - Update the soft constraints using first the cores. - Then update the resulting soft constraints using the evaluation of the MCS/MSS - Add a cardinality constraint to force new satisfying assignments to improve the new upper bound. - In every iteration, the lower bound is improved using the cores. - - In every iteration, the upper bound is improved using the MCS + - In every iteration, the upper bound is improved using the MCS. + - Optionally: add a cardinality constraint to prune the upper bound. + + What are the corner cases: + - suppose that cost of cores adds up to current upper bound. + -> it means that each core is a unit (?) + */ lbool mus_mss2_solver() { init(); From 1b9529e1e1520b31c71d5f652ffdda621bf109e0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 29 Aug 2014 01:55:32 -0700 Subject: [PATCH 498/925] fix scope bugs per Klaus Becker's examples Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 90 +++++++++++++++++++++++++++++------------ src/opt/maxsmt.cpp | 2 +- src/opt/opt_context.cpp | 35 ++++++++-------- src/opt/opt_context.h | 7 ++-- 4 files changed, 88 insertions(+), 46 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 955531c16..c0bb1cd8f 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -84,6 +84,7 @@ private: strategy_t m_st; rational m_max_upper; bool m_hill_climb; + bool m_all_cores; public: maxres(context& c, @@ -95,7 +96,8 @@ public: m_mss(m_s, m), m_trail(m), m_st(st), - m_hill_climb(true) + m_hill_climb(true), + m_all_cores(false) { } @@ -151,21 +153,9 @@ public: return l_undef; } switch (is_sat) { - case l_true: { - s().get_model(m_model); - expr_ref tmp(m); - DEBUG_CODE( - for (unsigned i = 0; i < m_asms.size(); ++i) { - VERIFY(m_model->eval(m_asms[i].get(), tmp)); - SASSERT(m.is_true(tmp)); - }); - for (unsigned i = 0; i < m_soft.size(); ++i) { - VERIFY(m_model->eval(m_soft[i].get(), tmp)); - m_assignment[i] = m.is_true(tmp); - } - m_upper = m_lower; + case l_true: + found_optimum(); return l_true; - } case l_false: is_sat = process_unsat(); if (is_sat != l_true) return is_sat; @@ -294,22 +284,67 @@ public: init(); init_local(); sls(); + m_all_cores = true; NOT_IMPLEMENTED_YET(); - ptr_vector mcs; vector > cores; return l_undef; -#if 0 - while (m_lower < m_upper) { + lbool is_sat = l_true; + while (m_lower < m_upper && is_sat == l_true) { TRACE("opt", display_vec(tout, m_asms.size(), m_asms.c_ptr()); s().display(tout); tout << "\n"; display(tout); ); + lbool is_sat = s().check_sat(m_asms.size(), m_asms.c_ptr()); + if (m_cancel) { + return l_undef; + } + switch (is_sat) { + case l_true: + found_optimum(); + return l_true; + case l_false: + is_sat = process_unsat(cores); + break; + default: + break; + } + if (is_sat == l_undef) { + return l_undef; + } + if (cores.empty()) { + SASSERT(is_sat == l_false); + break; + } + SASSERT(is_sat == l_true); + // there is some best model, + // extend it to a maximal assignment + // extracting the mss and mcs. + set_mus(false); + ptr_vector mss, mcs; + is_sat = m_mss(cores, mss, mcs); + set_mus(true); + if (is_sat != l_true) return is_sat; + // } m_lower = m_upper; return l_true; -#endif + } + + void found_optimum() { + s().get_model(m_model); + expr_ref tmp(m); + DEBUG_CODE( + for (unsigned i = 0; i < m_asms.size(); ++i) { + VERIFY(m_model->eval(m_asms[i].get(), tmp)); + SASSERT(m.is_true(tmp)); + }); + for (unsigned i = 0; i < m_soft.size(); ++i) { + VERIFY(m_model->eval(m_soft[i].get(), tmp)); + m_assignment[i] = m.is_true(tmp); + } + m_upper = m_lower; } @@ -341,8 +376,7 @@ public: break; } cores.push_back(core); - // TBD: ad hoc to avoid searching for large cores.. - if (core.size() >= 3) { + if (!m_all_cores && core.size() >= 3) { break; } remove_soft(core, asms); @@ -409,7 +443,7 @@ public: return index; } - lbool process_sat(ptr_vector& corr_set) { + lbool process_sat(ptr_vector const& corr_set) { expr_ref fml(m), tmp(m); TRACE("opt", display_vec(tout << "corr_set: ", corr_set.size(), corr_set.c_ptr());); if (corr_set.empty()) { @@ -425,6 +459,10 @@ public: lbool process_unsat() { vector > cores; + return process_unsat(cores); + } + + lbool process_unsat(vector >& cores) { lbool is_sat = get_cores(cores); if (is_sat != l_true) { return is_sat; @@ -438,7 +476,7 @@ public: return is_sat; } - lbool process_unsat(ptr_vector& core) { + lbool process_unsat(ptr_vector const& core) { expr_ref fml(m); remove_core(core); rational w = split_core(core); @@ -452,7 +490,7 @@ public: } lbool minimize_core(ptr_vector& core) { - if (m_c.sat_enabled()) { + if (m_c.sat_enabled() || core.empty()) { return l_true; } m_mus.reset(); @@ -521,7 +559,7 @@ public: } } - void max_resolve(ptr_vector& core, rational const& w) { + void max_resolve(ptr_vector const& core, rational const& w) { SASSERT(!core.empty()); expr_ref fml(m), asum(m); app_ref cls(m), d(m), dd(m); @@ -563,7 +601,7 @@ public: } // cs is a correction set (a complement of a (maximal) satisfying assignment). - void cs_max_resolve(ptr_vector& cs, rational const& w) { + void cs_max_resolve(ptr_vector const& cs, rational const& w) { TRACE("opt", display_vec(tout << "correction set: ", cs.size(), cs.c_ptr());); SASSERT(!cs.empty()); expr_ref fml(m), asum(m); diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 9fe704942..8c9148e17 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -41,7 +41,7 @@ namespace opt { m_c(c), m_cancel(false), m_soft(m), m_assertions(m) { - m_s.get_model(m_model); + c.get_base_model(m_model); SASSERT(m_model); updt_params(c.params()); init_soft(ws, soft); diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 327a636f7..59b0ee566 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -215,7 +215,7 @@ namespace opt { case 0: return is_sat; case 1: - return execute(m_objectives[0], true); + return execute(m_objectives[0], true, false); default: { opt_params optp(m_params); symbol pri = optp.priority(); @@ -232,6 +232,10 @@ namespace opt { } } + void context::get_base_model(model_ref& mdl) { + mdl = m_model; + } + void context::get_model(model_ref& mdl) { mdl = m_model; if (mdl) { @@ -242,27 +246,31 @@ namespace opt { } } - lbool context::execute_min_max(unsigned index, bool committed) { + lbool context::execute_min_max(unsigned index, bool committed, bool scoped) { + if (scoped) get_solver().push(); lbool result = m_optsmt.lex(index); - if (result == l_true && committed) m_optsmt.commit_assignment(index); if (result == l_true) m_optsmt.get_model(m_model); + if (scoped) get_solver().pop(1); + if (result == l_true && committed) m_optsmt.commit_assignment(index); return result; } - lbool context::execute_maxsat(symbol const& id, bool committed) { + lbool context::execute_maxsat(symbol const& id, bool committed, bool scoped) { model_ref tmp; maxsmt& ms = *m_maxsmts.find(id); + if (scoped) get_solver().push(); lbool result = ms(m_solver.get()); - if (result == l_true && committed) ms.commit_assignment(); if (result != l_false && (ms.get_model(tmp), tmp.get())) ms.get_model(m_model); + if (scoped) get_solver().pop(1); + if (result == l_true && committed) ms.commit_assignment(); return result; } - lbool context::execute(objective const& obj, bool committed) { + lbool context::execute(objective const& obj, bool committed, bool scoped) { switch(obj.m_type) { - case O_MAXIMIZE: return execute_min_max(obj.m_index, committed); - case O_MINIMIZE: return execute_min_max(obj.m_index, committed); - case O_MAXSMT: return execute_maxsat(obj.m_id, committed); + case O_MAXIMIZE: return execute_min_max(obj.m_index, committed, scoped); + case O_MINIMIZE: return execute_min_max(obj.m_index, committed, scoped); + case O_MAXSMT: return execute_maxsat(obj.m_id, committed, scoped); default: UNREACHABLE(); return l_undef; } } @@ -271,9 +279,7 @@ namespace opt { lbool r = l_true; for (unsigned i = 0; r == l_true && i < m_objectives.size(); ++i) { bool is_last = i + 1 == m_objectives.size(); - if (!is_last) get_solver().push(); - r = execute(m_objectives[i], i + 1 < m_objectives.size()); - if (!is_last) get_solver().pop(1); + r = execute(m_objectives[i], i + 1 < m_objectives.size(), !is_last); if (r == l_true && !get_lower_as_num(i).is_finite()) { return r; } @@ -291,7 +297,7 @@ namespace opt { objective const& obj = m_objectives[i]; if (obj.m_type == O_MAXSMT) { solver::scoped_push _sp(get_solver()); - r = execute(obj, false); + r = execute(obj, false, false); } } return r; @@ -399,9 +405,6 @@ namespace opt { if (is_sat == l_true) { yield(); } - else { - m_solver->pop(1); - } return is_sat; } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 5f3bd88cb..c2c9f46d8 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -179,14 +179,15 @@ namespace opt { void enable_sls(expr_ref_vector const& soft, weights_t& weights); void set_enable_sls(bool f) { m_enable_sls = f; } symbol const& maxsat_engine() const { return m_maxsat_engine; } + void get_base_model(model_ref& m); private: void validate_feasibility(maxsmt& ms); - lbool execute(objective const& obj, bool committed); - lbool execute_min_max(unsigned index, bool committed); - lbool execute_maxsat(symbol const& s, bool committed); + lbool execute(objective const& obj, bool committed, bool scoped); + lbool execute_min_max(unsigned index, bool committed, bool scoped); + lbool execute_maxsat(symbol const& s, bool committed, bool scoped); lbool execute_lex(); lbool execute_box(); lbool execute_pareto(); From 0c6ce3a338c7ef3a3d878da2ee54030cb31154af Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 29 Aug 2014 08:36:47 -0700 Subject: [PATCH 499/925] product set local changes Signed-off-by: Nikolaj Bjorner --- src/muz/rel/product_set.cpp | 19 +++++++++++++++++++ src/muz/rel/product_set.h | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/muz/rel/product_set.cpp b/src/muz/rel/product_set.cpp index 730d8221c..e3c275c67 100644 --- a/src/muz/rel/product_set.cpp +++ b/src/muz/rel/product_set.cpp @@ -24,19 +24,38 @@ Revision History: namespace datalog { + static unsigned s_ps_num_bits = 0; + static unsigned s_num_ps = 0; + product_set::product_set( product_set_plugin& p, relation_signature const& s, initial_t init, T const& t): vector_relation(p, s, false, t), m_refs(0) { + unsigned delta = 0; for (unsigned i = 0; i < s.size(); ++i) { unsigned sz = p.set_size(s[i]); (*this)[i].resize(sz); if (init == FULL_t) { (*this)[i].neg(); } + delta += sz; + } + s_ps_num_bits += delta; + s_num_ps ++; + if ((s_num_ps % 1000) == 0) { + std::cout << s_num_ps << " " << s_ps_num_bits << " " << delta << "\n"; } } + product_set::~product_set() { + relation_signature const& s = get_signature(); + product_set_plugin& p = dynamic_cast(get_plugin()); + for (unsigned i = 0; i < s.size(); ++i) { + unsigned sz = p.set_size(s[i]); + s_ps_num_bits -= sz; + } + --s_num_ps; + } unsigned product_set::get_hash() const { unsigned hash = 0; diff --git a/src/muz/rel/product_set.h b/src/muz/rel/product_set.h index 5865ce28a..17f888ca4 100644 --- a/src/muz/rel/product_set.h +++ b/src/muz/rel/product_set.h @@ -46,7 +46,7 @@ namespace datalog { }; product_set(product_set_plugin& p, relation_signature const& s, initial_t init, T const& t = T()); - virtual ~product_set() {} + virtual ~product_set(); unsigned get_hash() const; bool operator==(product_set const& p) const; bool contains(product_set const& p) const; From c928f776da3a5893dd430bbbf0ac1e68e62ec17b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 29 Aug 2014 08:39:31 -0700 Subject: [PATCH 500/925] working on mss/mus v2 Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 44 ++++++++++++++++++++++++++-------------- src/opt/mus.cpp | 50 ++++++++++++++++++++++++++++++++++++++++++++-- src/opt/mus.h | 10 ++++++++++ 3 files changed, 87 insertions(+), 17 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index c0bb1cd8f..4d64cbab9 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -61,6 +61,7 @@ Notes: #include "mss.h" #include "inc_sat_solver.h" #include "opt_context.h" +#include "pb_decl_plugin.h" using namespace opt; @@ -85,6 +86,7 @@ private: rational m_max_upper; bool m_hill_climb; bool m_all_cores; + bool m_add_upper_bound_block; public: maxres(context& c, @@ -97,7 +99,8 @@ public: m_trail(m), m_st(st), m_hill_climb(true), - m_all_cores(false) + m_all_cores(false), + m_add_upper_bound_block(false) { } @@ -281,13 +284,12 @@ public: */ lbool mus_mss2_solver() { + m_all_cores = true; + m_add_upper_bound_block = true; init(); init_local(); sls(); - m_all_cores = true; - NOT_IMPLEMENTED_YET(); vector > cores; - return l_undef; lbool is_sat = l_true; while (m_lower < m_upper && is_sat == l_true) { TRACE("opt", @@ -318,15 +320,21 @@ public: break; } SASSERT(is_sat == l_true); - // there is some best model, + + // TBD: there is some best model, + // retrieve it from the get_cores calls. // extend it to a maximal assignment // extracting the mss and mcs. + set_mus(false); ptr_vector mss, mcs; is_sat = m_mss(cores, mss, mcs); set_mus(true); if (is_sat != l_true) return is_sat; - // + model_ref mdl; + m_mss.get_model(mdl); // last model is best way to reduce search space. + update_assignment(mdl.get()); + is_sat = process_sat(mcs); } m_lower = m_upper; return l_true; @@ -446,14 +454,9 @@ public: lbool process_sat(ptr_vector const& corr_set) { expr_ref fml(m), tmp(m); TRACE("opt", display_vec(tout << "corr_set: ", corr_set.size(), corr_set.c_ptr());); - if (corr_set.empty()) { - return l_true; - } - remove_core(corr_set); rational w = split_core(corr_set); - TRACE("opt", display_vec(tout << " corr_set: ", corr_set.size(), corr_set.c_ptr());); - cs_max_resolve(corr_set, w); + cs_max_resolve(corr_set, w); return l_true; } @@ -479,6 +482,7 @@ public: lbool process_unsat(ptr_vector const& core) { expr_ref fml(m); remove_core(core); + SASSERT(!core.empty()); rational w = split_core(core); TRACE("opt", display_vec(tout << "minimized core: ", core.size(), core.c_ptr());); max_resolve(core, w); @@ -524,9 +528,8 @@ public: } rational split_core(ptr_vector const& core) { - + if (core.empty()) return rational(0); // find the minimal weight: - SASSERT(!core.empty()); rational w = get_weight(core[0]); for (unsigned i = 1; i < core.size(); ++i) { rational w2 = get_weight(core[i]); @@ -602,8 +605,8 @@ public: // cs is a correction set (a complement of a (maximal) satisfying assignment). void cs_max_resolve(ptr_vector const& cs, rational const& w) { + if (cs.empty()) return; TRACE("opt", display_vec(tout << "correction set: ", cs.size(), cs.c_ptr());); - SASSERT(!cs.empty()); expr_ref fml(m), asum(m); app_ref cls(m), d(m), dd(m); m_B.reset(); @@ -737,6 +740,17 @@ public: // verify_assignment(); IF_VERBOSE(1, verbose_stream() << "(opt.maxres [" << m_lower << ":" << m_upper << "])\n";); + + if (m_add_upper_bound_block) { + pb_util u(m); + expr_ref_vector nsoft(m); + expr_ref fml(m); + for (unsigned i = 0; i < m_soft.size(); ++i) { + nsoft.push_back(m.mk_not(m_soft[i].get())); + } + fml = u.mk_lt(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper); + s().assert_expr(fml); + } } void remove_soft(ptr_vector const& core, expr_ref_vector& asms) { diff --git a/src/opt/mus.cpp b/src/opt/mus.cpp index 545aba2cc..932d9ccf7 100644 --- a/src/opt/mus.cpp +++ b/src/opt/mus.cpp @@ -22,7 +22,6 @@ Notes: #include "smt_literal.h" #include "mus.h" #include "ast_pp.h" -#include "model_smt2_pp.h" using namespace opt; @@ -34,9 +33,13 @@ struct mus::imp { expr_ref_vector m_cls2expr; obj_map m_expr2cls; volatile bool m_cancel; + model_ref m_model; + expr_ref_vector m_soft; + vector m_weights; + rational m_weight; imp(solver& s, ast_manager& m): - m_s(s), m(m), m_cls2expr(m), m_cancel(false) + m_s(s), m(m), m_cls2expr(m), m_cancel(false), m_soft(m) {} void reset() { @@ -100,6 +103,7 @@ struct mus::imp { case l_true: assumptions.push_back(cls); mus.push_back(cls_id); + update_model(); break; default: core_exprs.reset(); @@ -145,6 +149,40 @@ struct mus::imp { out << "\n"; } + void set_soft(unsigned sz, expr* const* soft, rational const* weights) { + m_model.reset(); + m_weight.reset(); + m_soft.append(sz, soft); + m_weights.append(sz, weights); + for (unsigned i = 0; i < sz; ++i) { + m_weight += weights[i]; + } + } + + void update_model() { + if (m_soft.empty()) return; + model_ref mdl; + expr_ref tmp(m); + m_s.get_model(mdl); + rational w; + for (unsigned i = 0; i < m_soft.size(); ++i) { + mdl->eval(m_soft[i].get(), tmp); + if (!m.is_true(tmp)) { + w += m_weights[i]; + } + } + if (w < m_weight || !m_model.get()) { + m_model = mdl; + m_weight = w; + } + } + + rational get_best_model(model_ref& mdl) { + mdl = m_model; + return m_weight; + } + + }; mus::mus(solver& s, ast_manager& m) { @@ -170,3 +208,11 @@ void mus::set_cancel(bool f) { void mus::reset() { m_imp->reset(); } + +void mus::set_soft(unsigned sz, expr* const* soft, rational const* weights) { + m_imp->set_soft(sz, soft, weights); +} + +rational mus::get_best_model(model_ref& mdl) { + return m_imp->get_best_model(mdl); +} diff --git a/src/opt/mus.h b/src/opt/mus.h index 94eb42cc6..12cd8b0b2 100644 --- a/src/opt/mus.h +++ b/src/opt/mus.h @@ -40,6 +40,16 @@ namespace opt { void reset(); void set_cancel(bool f); + + /** + Instrument MUS extraction to also provide the minimal + penalty model, if any is found. + The minimal penalty model has the least weight for the + supplied soft constraints. + */ + void set_soft(unsigned sz, expr* const* soft, rational const* weights); + rational get_best_model(model_ref& mdl); + }; }; From 3da60804fc76879d786aa7cb8fc061bc64f7640f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 29 Aug 2014 09:52:56 -0700 Subject: [PATCH 501/925] basic primal/dual Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 157 ++++++++++++++++++++++++++++++--------------- src/opt/mss.cpp | 4 +- src/opt/mss.h | 2 +- 3 files changed, 109 insertions(+), 54 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 4d64cbab9..b666e14e4 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -88,6 +88,8 @@ private: bool m_all_cores; bool m_add_upper_bound_block; + typedef ptr_vector exprs; + public: maxres(context& c, weights_t& ws, expr_ref_vector const& soft, @@ -176,8 +178,8 @@ public: init(); init_local(); sls(); - ptr_vector mcs; - vector > cores; + exprs mcs; + vector cores; while (m_lower < m_upper) { TRACE("opt", display_vec(tout, m_asms.size(), m_asms.c_ptr()); @@ -219,19 +221,18 @@ public: init_local(); sls(); set_mus(false); - ptr_vector mcs; + exprs mcs; lbool is_sat = l_true; while (m_lower < m_upper && is_sat == l_true) { IF_VERBOSE(1, verbose_stream() << "(opt.maxres [" << m_lower << ":" << m_upper << "])\n";); - vector > cores; - ptr_vector mss; + vector cores; + exprs mss; model_ref mdl; expr_ref tmp(m); mcs.reset(); s().get_model(mdl); update_assignment(mdl.get()); - mss.append(m_asms.size(), m_asms.c_ptr()); - is_sat = m_mss(cores, mss, mcs); + is_sat = get_mss(cores, mss, mcs); switch (is_sat) { case l_undef: @@ -244,9 +245,7 @@ public: if (is_sat != l_true) { return is_sat; } - model_ref mdl; - m_mss.get_model(mdl); - update_assignment(mdl.get()); + update_mss_model(); break; } } @@ -285,11 +284,12 @@ public: */ lbool mus_mss2_solver() { m_all_cores = true; - m_add_upper_bound_block = true; + //m_add_upper_bound_block = true; init(); init_local(); sls(); - vector > cores; + vector cores; + m_mus.set_soft(m_soft.size(), m_soft.c_ptr(), m_weights.c_ptr()); lbool is_sat = l_true; while (m_lower < m_upper && is_sat == l_true) { TRACE("opt", @@ -307,7 +307,7 @@ public: found_optimum(); return l_true; case l_false: - is_sat = process_unsat(cores); + is_sat = get_cores(cores); break; default: break; @@ -315,27 +315,42 @@ public: if (is_sat == l_undef) { return l_undef; } + SASSERT((is_sat == l_false) == cores.empty()); + SASSERT((is_sat == l_true) == !cores.empty()); if (cores.empty()) { - SASSERT(is_sat == l_false); break; } - SASSERT(is_sat == l_true); - // TBD: there is some best model, - // retrieve it from the get_cores calls. - // extend it to a maximal assignment - // extracting the mss and mcs. - - set_mus(false); - ptr_vector mss, mcs; - is_sat = m_mss(cores, mss, mcs); - set_mus(true); + // + // There is a best model, + // retrieve it from the previous + // core calls. + // + update_mus_model(); + // + // Extend the current model to a (maximal) + // assignment extracting the ss and cs. + // ss - satisfying subset + // cs - correction set (complement of it). + // + exprs ss, cs; + is_sat = get_mss(cores, ss, cs); + if (is_sat != l_true) return is_sat; + update_mss_model(); + // + // block the hard constraints corresponding to the cores. + // block the soft constraints corresponding to the cs. + // The original cs is not disjoint from the cores, + // after the cores are blocked, the soft constraints + // are changed. + // + is_sat = process_unsat(cores); + if (is_sat != l_true) return is_sat; + get_current_correction_set(cs); + is_sat = process_sat(cs); if (is_sat != l_true) return is_sat; - model_ref mdl; - m_mss.get_model(mdl); // last model is best way to reduce search space. - update_assignment(mdl.get()); - is_sat = process_sat(mcs); } + m_lower = m_upper; return l_true; } @@ -370,12 +385,12 @@ public: return l_undef; } - lbool get_cores(vector >& cores) { + lbool get_cores(vector& cores) { // assume m_s is unsat. lbool is_sat = l_false; expr_ref_vector asms(m_asms); cores.reset(); - ptr_vector core; + exprs core; while (is_sat == l_false) { core.reset(); s().get_unsat_core(core); @@ -420,6 +435,18 @@ public: return is_sat; } + void get_current_correction_set(exprs& cs) { + TRACE("opt", display_vec(tout << "old correction set: ", cs.size(), cs.c_ptr());); + cs.reset(); + expr_ref tmp(m); + for (unsigned i = 0; i < m_asms.size(); ++i) { + VERIFY(m_model->eval(m_asms[i].get(), tmp)); + if (!m.is_true(tmp)) { + cs.push_back(m_asms[i].get()); + } + } + TRACE("opt", display_vec(tout << "new correction set: ", cs.size(), cs.c_ptr());); + } struct compare_asm { maxres& mr; @@ -431,7 +458,7 @@ public: void sort_assumptions(expr_ref_vector& _asms) { compare_asm comp(*this); - ptr_vector asms(_asms.size(), _asms.c_ptr()); + exprs asms(_asms.size(), _asms.c_ptr()); expr_ref_vector trail(_asms); std::sort(asms.begin(), asms.end(), comp); _asms.reset(); @@ -451,7 +478,7 @@ public: return index; } - lbool process_sat(ptr_vector const& corr_set) { + lbool process_sat(exprs const& corr_set) { expr_ref fml(m), tmp(m); TRACE("opt", display_vec(tout << "corr_set: ", corr_set.size(), corr_set.c_ptr());); remove_core(corr_set); @@ -461,11 +488,7 @@ public: } lbool process_unsat() { - vector > cores; - return process_unsat(cores); - } - - lbool process_unsat(vector >& cores) { + vector cores; lbool is_sat = get_cores(cores); if (is_sat != l_true) { return is_sat; @@ -473,13 +496,20 @@ public: if (cores.empty()) { return l_false; } + else { + return process_unsat(cores); + } + } + + lbool process_unsat(vector& cores) { + lbool is_sat = l_true; for (unsigned i = 0; is_sat == l_true && i < cores.size(); ++i) { is_sat = process_unsat(cores[i]); } return is_sat; } - lbool process_unsat(ptr_vector const& core) { + lbool process_unsat(exprs const& core) { expr_ref fml(m); remove_core(core); SASSERT(!core.empty()); @@ -493,7 +523,33 @@ public: return l_true; } - lbool minimize_core(ptr_vector& core) { + void update_mus_model() { + if (!m_c.sat_enabled()) { + model_ref mdl; + rational w = m_mus.get_best_model(mdl); + if (mdl.get() && w < m_upper) { + update_assignment(mdl.get()); + } + } + } + + void update_mss_model() { + model_ref mdl; + m_mss.get_model(mdl); // last model is best way to reduce search space. + update_assignment(mdl.get()); + } + + lbool get_mss(vector const& cores, exprs& literals, exprs& mcs) { + literals.reset(); + mcs.reset(); + literals.append(m_asms.size(), m_asms.c_ptr()); + set_mus(false); + lbool is_sat = m_mss(m_model.get(), cores, literals, mcs); + set_mus(true); + return is_sat; + } + + lbool minimize_core(exprs& core) { if (m_c.sat_enabled() || core.empty()) { return l_true; } @@ -527,7 +583,7 @@ public: enable_sls(m_asms, ws); } - rational split_core(ptr_vector const& core) { + rational split_core(exprs const& core) { if (core.empty()) return rational(0); // find the minimal weight: rational w = get_weight(core[0]); @@ -562,7 +618,7 @@ public: } } - void max_resolve(ptr_vector const& core, rational const& w) { + void max_resolve(exprs const& core, rational const& w) { SASSERT(!core.empty()); expr_ref fml(m), asum(m); app_ref cls(m), d(m), dd(m); @@ -604,7 +660,7 @@ public: } // cs is a correction set (a complement of a (maximal) satisfying assignment). - void cs_max_resolve(ptr_vector const& cs, rational const& w) { + void cs_max_resolve(exprs const& cs, rational const& w) { if (cs.empty()) return; TRACE("opt", display_vec(tout << "correction set: ", cs.size(), cs.c_ptr());); expr_ref fml(m), asum(m); @@ -645,10 +701,10 @@ public: s().assert_expr(fml); } - lbool try_improve_bound(vector >& cores, ptr_vector& mcs) { + lbool try_improve_bound(vector& cores, exprs& mcs) { cores.reset(); mcs.reset(); - ptr_vector core; + exprs core; expr_ref_vector asms(m_asms); while (true) { rational upper = m_max_upper; @@ -662,16 +718,15 @@ public: model_ref mdl; s().get_model(mdl); // last model is best way to reduce search space. update_assignment(mdl.get()); - ptr_vector mss; + exprs mss; mss.append(asms.size(), asms.c_ptr()); set_mus(false); - is_sat = m_mss(cores, mss, mcs); + is_sat = m_mss(m_model.get(), cores, mss, mcs); set_mus(true); if (is_sat != l_true) { return is_sat; } - m_mss.get_model(mdl); // last model is best way to reduce search space. - update_assignment(mdl.get()); + update_mss_model(); if (!cores.empty() && mcs.size() > cores.back().size()) { mcs.reset(); } @@ -753,7 +808,7 @@ public: } } - void remove_soft(ptr_vector const& core, expr_ref_vector& asms) { + void remove_soft(exprs const& core, expr_ref_vector& asms) { for (unsigned i = 0; i < asms.size(); ++i) { if (core.contains(asms[i].get())) { asms[i] = asms.back(); @@ -763,7 +818,7 @@ public: } } - void remove_core(ptr_vector const& core) { + void remove_core(exprs const& core) { remove_soft(core, m_asms); } @@ -811,7 +866,7 @@ opt::maxsmt_solver_base* opt::mk_maxres( opt::maxsmt_solver_base* opt::mk_mus_mss_maxres( context& c, weights_t& ws, expr_ref_vector const& soft) { - return alloc(maxres, c, ws, soft, maxres::s_mus_mss); + return alloc(maxres, c, ws, soft, maxres::s_mus_mss2); } opt::maxsmt_solver_base* opt::mk_mss_maxres( diff --git a/src/opt/mss.cpp b/src/opt/mss.cpp index 77dd39409..3597aa6b9 100644 --- a/src/opt/mss.cpp +++ b/src/opt/mss.cpp @@ -144,10 +144,10 @@ namespace opt { m_todo.resize(j); } - lbool mss::operator()(vector const& _cores, exprs& literals, exprs& mcs) { + lbool mss::operator()(model* initial_model, vector const& _cores, exprs& literals, exprs& mcs) { m_mss.reset(); m_todo.reset(); - m_s.get_model(m_model); + m_model = initial_model; m_cores.reset(); SASSERT(m_model); m_cores.append(_cores); diff --git a/src/opt/mss.h b/src/opt/mss.h index 057161eaa..02d218e4d 100644 --- a/src/opt/mss.h +++ b/src/opt/mss.h @@ -36,7 +36,7 @@ namespace opt { mss(solver& s, ast_manager& m); ~mss(); - lbool operator()(vector const& cores, exprs& literals, exprs& mcs); + lbool operator()(model* initial_model, vector const& cores, exprs& literals, exprs& mcs); void set_cancel(bool f) { m_cancel = f; } From 5fdb58348e04da756e1022c2471105f9473379d5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 29 Aug 2014 15:34:48 -0700 Subject: [PATCH 502/925] working on mus-mss Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index b666e14e4..a6130158d 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -78,6 +78,7 @@ private: expr_ref_vector m_B; expr_ref_vector m_asms; obj_map m_asm2weight; + obj_map m_asm2value; ptr_vector m_new_core; mus m_mus; mss m_mss; @@ -285,6 +286,7 @@ public: lbool mus_mss2_solver() { m_all_cores = true; //m_add_upper_bound_block = true; + bool maximize_assignment = false; init(); init_local(); sls(); @@ -333,19 +335,24 @@ public: // ss - satisfying subset // cs - correction set (complement of it). // - exprs ss, cs; - is_sat = get_mss(cores, ss, cs); - if (is_sat != l_true) return is_sat; - update_mss_model(); + if (maximize_assignment) { + exprs ss, cs; + is_sat = get_mss(cores, ss, cs); + if (is_sat != l_true) return is_sat; + update_mss_model(); + } // // block the hard constraints corresponding to the cores. - // block the soft constraints corresponding to the cs. - // The original cs is not disjoint from the cores, - // after the cores are blocked, the soft constraints - // are changed. + // block the soft constraints corresponding to the cs + // obtained from the current best model. + // + // TBD: model must be updated with definitions for the + // fresh variables. // is_sat = process_unsat(cores); if (is_sat != l_true) return is_sat; + + exprs cs; get_current_correction_set(cs); is_sat = process_sat(cs); if (is_sat != l_true) return is_sat; From b45b2872d839a0fb388147c6173de9acc1216b13 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 29 Aug 2014 16:24:46 -0700 Subject: [PATCH 503/925] basic primal/dual Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 43 +++++++++++++++++++++++++++---------------- src/opt/mss.cpp | 2 +- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index a6130158d..0124cf6c1 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -78,7 +78,7 @@ private: expr_ref_vector m_B; expr_ref_vector m_asms; obj_map m_asm2weight; - obj_map m_asm2value; + obj_map m_asm2value; ptr_vector m_new_core; mus m_mus; mss m_mss; @@ -284,8 +284,8 @@ public: */ lbool mus_mss2_solver() { - m_all_cores = true; - //m_add_upper_bound_block = true; + // m_all_cores = true; + // m_add_upper_bound_block = true; bool maximize_assignment = false; init(); init_local(); @@ -333,10 +333,11 @@ public: // Extend the current model to a (maximal) // assignment extracting the ss and cs. // ss - satisfying subset - // cs - correction set (complement of it). + // cs - correction set (complement of ss). // if (maximize_assignment) { exprs ss, cs; + // TBD: current model has to evaluate all auxiliary predicates. is_sat = get_mss(cores, ss, cs); if (is_sat != l_true) return is_sat; update_mss_model(); @@ -364,15 +365,13 @@ public: void found_optimum() { s().get_model(m_model); - expr_ref tmp(m); + m_asm2value.reset(); DEBUG_CODE( for (unsigned i = 0; i < m_asms.size(); ++i) { - VERIFY(m_model->eval(m_asms[i].get(), tmp)); - SASSERT(m.is_true(tmp)); + SASSERT(is_true(m_asms[i].get())); }); for (unsigned i = 0; i < m_soft.size(); ++i) { - VERIFY(m_model->eval(m_soft[i].get(), tmp)); - m_assignment[i] = m.is_true(tmp); + m_assignment[i] = is_true(m_soft[i].get()); } m_upper = m_lower; } @@ -445,10 +444,8 @@ public: void get_current_correction_set(exprs& cs) { TRACE("opt", display_vec(tout << "old correction set: ", cs.size(), cs.c_ptr());); cs.reset(); - expr_ref tmp(m); for (unsigned i = 0; i < m_asms.size(); ++i) { - VERIFY(m_model->eval(m_asms[i].get(), tmp)); - if (!m.is_true(tmp)) { + if (!is_true(m_asms[i].get())) { cs.push_back(m_asms[i].get()); } } @@ -653,12 +650,17 @@ public: s().assert_expr(fml); fml = m.mk_implies(dd, b_i); s().assert_expr(fml); + m_asm2value.insert(dd, is_true(d) && is_true(b_i)); d = dd; } else { - d = m.mk_and(b_i, d); + dd = m.mk_and(b_i, d); + m_asm2value.insert(dd, is_true(d) && is_true(b_i)); + m_trail.push_back(dd); + d = dd; } asum = mk_fresh_bool("a"); + m_asm2value.insert(asum, is_true(b_i1) || is_true(d)); cls = m.mk_or(b_i1, d); fml = m.mk_implies(asum, cls); new_assumption(asum, w); @@ -792,11 +794,10 @@ public: return; } m_model = mdl; + m_asm2value.reset(); for (unsigned i = 0; i < m_soft.size(); ++i) { - expr* n = m_soft[i].get(); - VERIFY(m_model->eval(n, tmp)); - m_assignment[i] = m.is_true(tmp); + m_assignment[i] = is_true(m_soft[i].get()); } m_upper = upper; // verify_assignment(); @@ -815,6 +816,16 @@ public: } } + bool is_true(expr* e) { + bool truth_value; + if (m_asm2value.find(e, truth_value)) { + return truth_value; + } + expr_ref tmp(m); + VERIFY(m_model->eval(e, tmp)); + return m.is_true(tmp); + } + void remove_soft(exprs const& core, expr_ref_vector& asms) { for (unsigned i = 0; i < asms.size(); ++i) { if (core.contains(asms[i].get())) { diff --git a/src/opt/mss.cpp b/src/opt/mss.cpp index 3597aa6b9..9d44180a6 100644 --- a/src/opt/mss.cpp +++ b/src/opt/mss.cpp @@ -35,7 +35,7 @@ namespace opt { bool mss::check_result() { lbool is_sat = m_s.check_sat(m_mss.size(), m_mss.c_ptr()); if (is_sat == l_undef) return true; - SASSERT(is_sat == l_true); + SASSERT(m_mss.empty() || is_sat == l_true); if (is_sat == l_false) return false; expr_set::iterator it = m_mcs.begin(), end = m_mcs.end(); for (; it != end; ++it) { From 83a7d1a658088157e2281d7ad2a55d204ce2eb01 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 30 Aug 2014 11:46:29 -0700 Subject: [PATCH 504/925] adding options to maxres for experiments, include option to pretty print module parameters in smt2 style Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 185 +++++++++++++++++++++++-------------- src/opt/maxsmt.cpp | 36 ++++++++ src/opt/maxsmt.h | 15 +++ src/opt/opt_context.cpp | 5 + src/opt/opt_params.pyg | 9 +- src/opt/wmax.cpp | 54 +---------- src/opt/wmax.h | 3 +- src/sat/sat_mus.cpp | 4 + src/sat/sat_mus.h | 3 + src/sat/sat_solver.cpp | 2 + src/smt/theory_wmaxsat.cpp | 4 + src/smt/theory_wmaxsat.h | 9 +- src/util/params.cpp | 50 +++++++++- src/util/params.h | 1 + 14 files changed, 249 insertions(+), 131 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 0124cf6c1..d4fef002d 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -62,6 +62,7 @@ Notes: #include "inc_sat_solver.h" #include "opt_context.h" #include "pb_decl_plugin.h" +#include "opt_params.hpp" using namespace opt; @@ -85,9 +86,14 @@ private: expr_ref_vector m_trail; strategy_t m_st; rational m_max_upper; - bool m_hill_climb; - bool m_all_cores; - bool m_add_upper_bound_block; + bool m_hill_climb; // prefer large weight soft clauses for cores + bool m_add_upper_bound_block; // restrict upper bound with constraint + unsigned m_max_num_cores; // max number of cores per round. + unsigned m_max_core_size; // max core size per round. + bool m_maximize_assignment; // maximize assignment to find MCS + unsigned m_max_correction_set_size;// maximal set of correction set that is tolerated. + bool m_wmax; // Block upper bound using wmax + // this option is disabled if SAT core is used. typedef ptr_vector exprs; @@ -102,8 +108,11 @@ public: m_trail(m), m_st(st), m_hill_climb(true), - m_all_cores(false), - m_add_upper_bound_block(false) + m_add_upper_bound_block(false), + m_max_num_cores(UINT_MAX), + m_max_core_size(3), + m_maximize_assignment(false), + m_max_correction_set_size(3) { } @@ -201,14 +210,11 @@ public: return l_true; case l_true: SASSERT(cores.empty() || mcs.empty()); - for (unsigned i = 0; is_sat == l_true && i < cores.size(); ++i) { - is_sat = process_unsat(cores[i]); + for (unsigned i = 0; i < cores.size(); ++i) { + process_unsat(cores[i]); } - if (is_sat == l_true && cores.empty()) { - is_sat = process_sat(mcs); - } - if (is_sat != l_true) { - return is_sat; + if (cores.empty()) { + process_sat(mcs); } break; } @@ -233,8 +239,8 @@ public: mcs.reset(); s().get_model(mdl); update_assignment(mdl.get()); - is_sat = get_mss(cores, mss, mcs); - + is_sat = get_mss(mdl.get(), cores, mss, mcs); + switch (is_sat) { case l_undef: return l_undef; @@ -242,11 +248,8 @@ public: m_lower = m_upper; return l_true; case l_true: { - is_sat = process_sat(mcs); - if (is_sat != l_true) { - return is_sat; - } - update_mss_model(); + process_sat(mcs); + get_mss_model(); break; } } @@ -281,12 +284,15 @@ public: What are the corner cases: - suppose that cost of cores adds up to current upper bound. -> it means that each core is a unit (?) + + TBD: + - Block upper bound using wmax or pb constraint, or in case of + unweighted constraints using incremental tricks. + - Throttle when correction set gets added based on its size. + Suppose correction set is huge. Do we really need it? */ lbool mus_mss2_solver() { - // m_all_cores = true; - // m_add_upper_bound_block = true; - bool maximize_assignment = false; init(); init_local(); sls(); @@ -321,42 +327,46 @@ public: SASSERT((is_sat == l_true) == !cores.empty()); if (cores.empty()) { break; - } + } // - // There is a best model, - // retrieve it from the previous - // core calls. + // There is a best model, retrieve + // it from the previous core calls. // - update_mus_model(); + model_ref mdl; + get_mus_model(mdl); + // // Extend the current model to a (maximal) // assignment extracting the ss and cs. // ss - satisfying subset // cs - correction set (complement of ss). // - if (maximize_assignment) { + if (m_maximize_assignment && mdl.get()) { exprs ss, cs; - // TBD: current model has to evaluate all auxiliary predicates. - is_sat = get_mss(cores, ss, cs); + is_sat = get_mss(mdl.get(), cores, ss, cs); if (is_sat != l_true) return is_sat; - update_mss_model(); + get_mss_model(); } // // block the hard constraints corresponding to the cores. // block the soft constraints corresponding to the cs // obtained from the current best model. // - // TBD: model must be updated with definitions for the - // fresh variables. - // - is_sat = process_unsat(cores); - if (is_sat != l_true) return is_sat; + + // + // TBD: throttle blocking on correction sets if they are too big. + // likewise, if the cores are too big, don't block the cores. + // + + process_unsat(cores); exprs cs; get_current_correction_set(cs); - is_sat = process_sat(cs); - if (is_sat != l_true) return is_sat; + unsigned max_core = max_core_size(cores); + if (cs.size() <= std::max(max_core, m_max_correction_set_size)) { + process_sat(cs); + } } m_lower = m_upper; @@ -404,8 +414,15 @@ public: if (is_sat != l_true) { break; } + if (core.empty()) { + cores.reset(); + return l_false; + } cores.push_back(core); - if (!m_all_cores && core.size() >= 3) { + if (core.size() >= m_max_core_size) { + break; + } + if (cores.size() >= m_max_num_cores) { break; } remove_soft(core, asms); @@ -442,7 +459,6 @@ public: } void get_current_correction_set(exprs& cs) { - TRACE("opt", display_vec(tout << "old correction set: ", cs.size(), cs.c_ptr());); cs.reset(); for (unsigned i = 0; i < m_asms.size(); ++i) { if (!is_true(m_asms[i].get())) { @@ -482,13 +498,12 @@ public: return index; } - lbool process_sat(exprs const& corr_set) { + void process_sat(exprs const& corr_set) { expr_ref fml(m), tmp(m); TRACE("opt", display_vec(tout << "corr_set: ", corr_set.size(), corr_set.c_ptr());); remove_core(corr_set); rational w = split_core(corr_set); cs_max_resolve(corr_set, w); - return l_true; } lbool process_unsat() { @@ -501,19 +516,26 @@ public: return l_false; } else { - return process_unsat(cores); + process_unsat(cores); + return l_true; } } - lbool process_unsat(vector& cores) { - lbool is_sat = l_true; - for (unsigned i = 0; is_sat == l_true && i < cores.size(); ++i) { - is_sat = process_unsat(cores[i]); + unsigned max_core_size(vector const& cores) { + unsigned result = 0; + for (unsigned i = 0; i < cores.size(); ++i) { + result = std::max(cores[i].size(), result); + } + return result; + } + + void process_unsat(vector const& cores) { + for (unsigned i = 0; i < cores.size(); ++i) { + process_unsat(cores[i]); } - return is_sat; } - lbool process_unsat(exprs const& core) { + void process_unsat(exprs const& core) { expr_ref fml(m); remove_core(core); SASSERT(!core.empty()); @@ -524,31 +546,35 @@ public: s().assert_expr(fml); m_lower += w; IF_VERBOSE(1, verbose_stream() << "(opt.maxres [" << m_lower << ":" << m_upper << "])\n";); - return l_true; } - void update_mus_model() { - if (!m_c.sat_enabled()) { - model_ref mdl; - rational w = m_mus.get_best_model(mdl); - if (mdl.get() && w < m_upper) { - update_assignment(mdl.get()); - } + void get_mus_model(model_ref& mdl) { + rational w(0); + if (m_c.sat_enabled()) { + // SAT solver core extracts some model + // during unsat core computation. + s().get_model(mdl); + } + else { + w = m_mus.get_best_model(mdl); + } + if (mdl.get() && w < m_upper) { + update_assignment(mdl.get()); } } - void update_mss_model() { + void get_mss_model() { model_ref mdl; m_mss.get_model(mdl); // last model is best way to reduce search space. update_assignment(mdl.get()); } - lbool get_mss(vector const& cores, exprs& literals, exprs& mcs) { + lbool get_mss(model* mdl, vector const& cores, exprs& literals, exprs& mcs) { literals.reset(); mcs.reset(); literals.append(m_asms.size(), m_asms.c_ptr()); set_mus(false); - lbool is_sat = m_mss(m_model.get(), cores, literals, mcs); + lbool is_sat = m_mss(mdl, cores, literals, mcs); set_mus(true); return is_sat; } @@ -735,7 +761,7 @@ public: if (is_sat != l_true) { return is_sat; } - update_mss_model(); + get_mss_model(); if (!cores.empty() && mcs.size() > cores.back().size()) { mcs.reset(); } @@ -804,16 +830,19 @@ public: IF_VERBOSE(1, verbose_stream() << "(opt.maxres [" << m_lower << ":" << m_upper << "])\n";); - if (m_add_upper_bound_block) { - pb_util u(m); - expr_ref_vector nsoft(m); - expr_ref fml(m); - for (unsigned i = 0; i < m_soft.size(); ++i) { - nsoft.push_back(m.mk_not(m_soft[i].get())); - } - fml = u.mk_lt(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper); - s().assert_expr(fml); - } + add_upper_bound_block(); + } + + void add_upper_bound_block() { + if (!m_add_upper_bound_block) return; + pb_util u(m); + expr_ref_vector nsoft(m); + expr_ref fml(m); + for (unsigned i = 0; i < m_soft.size(); ++i) { + nsoft.push_back(m.mk_not(m_soft[i].get())); + } + fml = u.mk_lt(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper); + s().assert_expr(fml); } bool is_true(expr* e) { @@ -845,6 +874,19 @@ public: m_mus.set_cancel(f); } + virtual void updt_params(params_ref& p) { + maxsmt_solver_base::updt_params(p); + opt_params _p(p); + + m_hill_climb = _p.maxres_hill_climb(); + m_add_upper_bound_block = _p.maxres_add_upper_bound_block(); + m_max_num_cores = _p.maxres_max_num_cores(); + m_max_core_size = _p.maxres_max_core_size(); + m_maximize_assignment = _p.maxres_maximize_assignment(); + m_max_correction_set_size = _p.maxres_max_correction_set_size(); + m_wmax = _p.maxres_wmax(); + } + void init_local() { m_upper.reset(); m_lower.reset(); @@ -853,6 +895,7 @@ public: add_soft(m_soft[i].get(), m_weights[i]); } m_max_upper = m_upper; + add_upper_bound_block(); } void verify_assignment() { diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 8c9148e17..73931a3cd 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -30,6 +30,7 @@ Notes: #include "ast_pp.h" #include "uint_set.h" #include "opt_context.h" +#include "theory_wmaxsat.h" namespace opt { @@ -108,6 +109,40 @@ namespace opt { return result; } + smt::theory_wmaxsat* maxsmt_solver_base::get_wmax_theory() const { + smt::theory_id th_id = m.get_family_id("weighted_maxsat"); + smt::theory* th = m_c.smt_context().get_theory(th_id); + if (th) { + return dynamic_cast(th); + } + else { + return 0; + } + } + + smt::theory_wmaxsat* maxsmt_solver_base::ensure_wmax_theory() { + smt::theory_wmaxsat* wth = get_wmax_theory(); + if (wth) { + wth->reset_local(); + } + else { + wth = alloc(smt::theory_wmaxsat, m, m_c.fm()); + m_c.smt_context().register_plugin(wth); + } + return wth; + } + + maxsmt_solver_base::scoped_ensure_theory::scoped_ensure_theory(maxsmt_solver_base& s) { + m_wth = s.ensure_wmax_theory(); + } + maxsmt_solver_base::scoped_ensure_theory::~scoped_ensure_theory() { + //m_wth->reset(); + } + smt::theory_wmaxsat& maxsmt_solver_base::scoped_ensure_theory::operator()() { return *m_wth; } + + + + maxsmt::maxsmt(context& c): m_s(c.get_solver()), m(c.get_manager()), m_c(c), m_cancel(false), m_soft_constraints(m), m_answer(m) {} @@ -160,6 +195,7 @@ namespace opt { } if (m_msolver) { + m_msolver->updt_params(m_params); is_sat = (*m_msolver)(); if (is_sat != l_false) { m_msolver->get_model(m_model); diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 47b903e17..2b868408a 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -24,6 +24,9 @@ Notes: #include"solver.h" #include"filter_model_converter.h" #include"statistics.h" +#include"smt_context.h" +#include"smt_theory.h" +#include"theory_wmaxsat.h" namespace opt { @@ -82,6 +85,18 @@ namespace opt { expr* mk_not(expr* e); void set_mus(bool f); app* mk_fresh_bool(char const* name); + + class smt::theory_wmaxsat* get_wmax_theory() const; + smt::theory_wmaxsat* ensure_wmax_theory(); + class scoped_ensure_theory { + smt::theory_wmaxsat* m_wth; + public: + scoped_ensure_theory(maxsmt_solver_base& s); + ~scoped_ensure_theory(); + smt::theory_wmaxsat& operator()(); + }; + + protected: void enable_sls(expr_ref_vector const& soft, weights_t& ws); void set_enable_sls(bool f); diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 59b0ee566..39316b772 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -1157,6 +1157,11 @@ namespace opt { break; } } + + param_descrs descrs; + collect_param_descrs(descrs); + m_params.display_smt2(out, "opt", descrs); + out << "(check-sat)\n"; return out.str(); } diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index 86c3fba11..fd291336c 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -10,7 +10,14 @@ def_module_params('opt', ('enable_sls', BOOL, False, 'enable SLS tuning during weighted maxsast'), ('enable_sat', BOOL, False, 'enable the new SAT core for propositional constraints'), ('elim_01', BOOL, True, 'eliminate 01 variables'), - ('pb.compile_equality', BOOL, False, 'compile arithmetical equalities into pseudo-Boolean equality (instead of two inequalites)') + ('pb.compile_equality', BOOL, False, 'compile arithmetical equalities into pseudo-Boolean equality (instead of two inequalites)'), + ('maxres.hill_climb', BOOL, True, 'give preference for large weight cores'), + ('maxres.add_upper_bound_block', BOOL, False, 'restict upper bound with constraint'), + ('maxres.max_num_cores', UINT, UINT_MAX, 'maximal number of cores per round'), + ('maxres.max_core_size', UINT, 3, 'break batch of generated cores if size reaches this number'), + ('maxres.maximize_assignment', BOOL, False, 'find an MSS/MCS to improve current assignment'), + ('maxres.max_correction_set_size', UINT, 3, 'allow generating correction set constraints up to maximal size'), + ('maxres.wmax', BOOL, False, 'use weighted theory solver to constrain upper bounds') )) diff --git a/src/opt/wmax.cpp b/src/opt/wmax.cpp index 24f381dbd..bb6451c41 100644 --- a/src/opt/wmax.cpp +++ b/src/opt/wmax.cpp @@ -26,59 +26,15 @@ Notes: #include "opt_context.h" namespace opt { - class maxsmt_solver_wbase : public maxsmt_solver_base { - smt::context& ctx; - public: - maxsmt_solver_wbase(context& c, - vector const& ws, expr_ref_vector const& soft): - maxsmt_solver_base(c, ws, soft), ctx(c.smt_context()) {} - ~maxsmt_solver_wbase() {} - - class scoped_ensure_theory { - smt::theory_wmaxsat* m_wth; - public: - scoped_ensure_theory(maxsmt_solver_wbase& s) { - m_wth = s.ensure_theory(); - } - ~scoped_ensure_theory() { - m_wth->reset(); - } - smt::theory_wmaxsat& operator()() { return *m_wth; } - }; - - smt::theory_wmaxsat* ensure_theory() { - smt::theory_wmaxsat* wth = get_theory(); - if (wth) { - wth->reset(); - } - else { - wth = alloc(smt::theory_wmaxsat, m, m_c.fm()); - ctx.register_plugin(wth); - } - return wth; - } - smt::theory_wmaxsat* get_theory() const { - smt::theory_id th_id = m.get_family_id("weighted_maxsat"); - smt::theory* th = ctx.get_theory(th_id); - if (th) { - return dynamic_cast(th); - } - else { - return 0; - } - } - }; - // ---------------------------------------------------------- // weighted max-sat using a custom theory solver for max-sat. // NB. it is quite similar to pseudo-Boolean propagation. - class wmax : public maxsmt_solver_wbase { + class wmax : public maxsmt_solver_base { public: - wmax(context& c, - vector const& ws, expr_ref_vector const& soft): - maxsmt_solver_wbase(c, ws, soft) {} + wmax(context& c, weights_t& ws, expr_ref_vector const& soft): + maxsmt_solver_base(c, ws, soft) {} virtual ~wmax() {} lbool operator()() { @@ -90,7 +46,6 @@ namespace opt { for (unsigned i = 0; i < m_soft.size(); ++i) { wth().assert_weighted(m_soft[i].get(), m_weights[i]); } - solver::scoped_push _s2(s()); while (l_true == is_sat) { is_sat = s().check_sat(0,0); if (m_cancel) { @@ -122,8 +77,7 @@ namespace opt { } }; - maxsmt_solver_base* mk_wmax(context& c, - vector const& ws, expr_ref_vector const& soft) { + maxsmt_solver_base* mk_wmax(context& c, weights_t& ws, expr_ref_vector const& soft) { return alloc(wmax, c, ws, soft); } diff --git a/src/opt/wmax.h b/src/opt/wmax.h index 77be62f92..bb1be1b4e 100644 --- a/src/opt/wmax.h +++ b/src/opt/wmax.h @@ -23,8 +23,7 @@ Notes: #include "maxsmt.h" namespace opt { - maxsmt_solver_base* mk_wmax(context& c, - vector const& ws, expr_ref_vector const& soft); + maxsmt_solver_base* mk_wmax(context& c, weights_t & ws, expr_ref_vector const& soft); } #endif diff --git a/src/sat/sat_mus.cpp b/src/sat/sat_mus.cpp index b6c7390e5..fd4cf0338 100644 --- a/src/sat/sat_mus.cpp +++ b/src/sat/sat_mus.cpp @@ -31,6 +31,7 @@ namespace sat { void mus::reset() { m_core.reset(); m_mus.reset(); + m_model.reset(); } void mus::set_core() { @@ -88,6 +89,9 @@ namespace sat { if (!core.empty()) { // mr(); // TBD: measure } + if (m_model.empty()) { + m_model.append(s.m_model); + } break; } case l_false: diff --git a/src/sat/sat_mus.h b/src/sat/sat_mus.h index 2f5879a0e..b68f4ee5c 100644 --- a/src/sat/sat_mus.h +++ b/src/sat/sat_mus.h @@ -24,6 +24,8 @@ namespace sat { literal_vector m_core; literal_vector m_mus; bool m_is_active; + model m_model; // model obtained during minimal unsat core + solver& s; public: @@ -31,6 +33,7 @@ namespace sat { ~mus(); lbool operator()(); bool is_active() const { return m_is_active; } + model const& get_model() const { return m_model; } private: lbool mus2(); void mr(); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 3d854522b..ad7f4ea02 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1736,6 +1736,8 @@ namespace sat { // initial experiment suggests it has no effect. m_mus(); // ignore return value on cancelation. + m_model.reset(); + m_model.append(m_mus.get_model()); } } diff --git a/src/smt/theory_wmaxsat.cpp b/src/smt/theory_wmaxsat.cpp index e6f410442..17ec4ff0a 100644 --- a/src/smt/theory_wmaxsat.cpp +++ b/src/smt/theory_wmaxsat.cpp @@ -164,6 +164,10 @@ final_check_status theory_wmaxsat::final_check_eh() { void theory_wmaxsat::reset_eh() { theory::reset_eh(); + reset_local(); +} + +void theory_wmaxsat::reset_local() { m_vars.reset(); m_fmls.reset(); m_rweights.reset(); diff --git a/src/smt/theory_wmaxsat.h b/src/smt/theory_wmaxsat.h index feac6c04e..1ddb388ca 100644 --- a/src/smt/theory_wmaxsat.h +++ b/src/smt/theory_wmaxsat.h @@ -17,6 +17,9 @@ Notes: --*/ +#ifndef _THEORY_WMAXSAT_H_ +#define _THEORY_WMAXSAT_H_ + #include "smt_theory.h" #include "smt_clause.h" #include "filter_model_converter.h" @@ -84,9 +87,7 @@ namespace smt { virtual bool build_models() const { return false; } - void reset() { - reset_eh(); - } + void reset_local(); virtual void reset_eh(); virtual theory * mk_fresh(context * new_ctx) { return 0; } virtual bool internalize_atom(app * atom, bool gate_ctx) { return false; } @@ -123,3 +124,5 @@ namespace smt { }; }; + +#endif diff --git a/src/util/params.cpp b/src/util/params.cpp index 4aff0de92..7d517fb10 100644 --- a/src/util/params.cpp +++ b/src/util/params.cpp @@ -347,11 +347,11 @@ public: out << "(params"; svector::const_iterator it = m_entries.begin(); svector::const_iterator end = m_entries.end(); - for (; it != end; ++it) { - out << " " << it->first; + for (; it != end; ++it) { + out << " " << it->first; switch (it->second.m_kind) { case CPK_BOOL: - out << " " << it->second.m_bool_value; + out << " " << (it->second.m_bool_value?"true":"false"); break; case CPK_UINT: out << " " <second.m_uint_value; @@ -376,6 +376,41 @@ public: out << ")"; } + void display_smt2(std::ostream & out, char const* module, param_descrs& descrs) const { + svector::const_iterator it = m_entries.begin(); + svector::const_iterator end = m_entries.end(); + for (; it != end; ++it) { + if (!descrs.contains(it->first)) continue; + out << "(set-option :"; + out << module << "."; + out << it->first; + switch (it->second.m_kind) { + case CPK_BOOL: + out << " " << (it->second.m_bool_value?"true":"false"); + break; + case CPK_UINT: + out << " " <second.m_uint_value; + break; + case CPK_DOUBLE: + out << " " << it->second.m_double_value; + break; + case CPK_NUMERAL: + out << " " << *(it->second.m_rat_value); + break; + case CPK_SYMBOL: + out << " " << symbol::mk_symbol_from_c_ptr(it->second.m_sym_value); + break; + case CPK_STRING: + out << " " << it->second.m_str_value; + break; + default: + UNREACHABLE(); + break; + } + out << ")\n"; + } + } + void display(std::ostream & out, symbol const & k) const { svector::const_iterator it = m_entries.begin(); svector::const_iterator end = m_entries.end(); @@ -423,10 +458,17 @@ params_ref::params_ref(params_ref const & p): void params_ref::display(std::ostream & out) const { if (m_params) m_params->display(out); - else + else out << "(params)"; } +void params_ref::display_smt2(std::ostream& out, char const* module, param_descrs& descrs) const { + if (m_params) + m_params->display_smt2(out, module, descrs); + +} + + void params_ref::display(std::ostream & out, char const * k) const { display(out, symbol(k)); } diff --git a/src/util/params.h b/src/util/params.h index 15be825b0..06be486bb 100644 --- a/src/util/params.h +++ b/src/util/params.h @@ -90,6 +90,7 @@ public: void set_sym(char const * k, symbol const & v); void display(std::ostream & out) const; + void display_smt2(std::ostream& out, char const* module, param_descrs& module_desc) const; void validate(param_descrs const & p) const; From afe7fc367b388750cfc0f133e9ff31c629068d76 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 30 Aug 2014 12:40:37 -0700 Subject: [PATCH 505/925] working on maxres Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 3 ++- src/opt/maxsmt.cpp | 1 - src/opt/wmax.cpp | 1 - src/smt/theory_wmaxsat.cpp | 1 - 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index d4fef002d..5ff2cc745 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -503,7 +503,8 @@ public: TRACE("opt", display_vec(tout << "corr_set: ", corr_set.size(), corr_set.c_ptr());); remove_core(corr_set); rational w = split_core(corr_set); - cs_max_resolve(corr_set, w); + cs_max_resolve(corr_set, w); + IF_VERBOSE(2, verbose_stream() << "(opt.maxres.correction-set " << corr_set.size() << ")\n";); } lbool process_unsat() { diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 73931a3cd..2b8bcb462 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -136,7 +136,6 @@ namespace opt { m_wth = s.ensure_wmax_theory(); } maxsmt_solver_base::scoped_ensure_theory::~scoped_ensure_theory() { - //m_wth->reset(); } smt::theory_wmaxsat& maxsmt_solver_base::scoped_ensure_theory::operator()() { return *m_wth; } diff --git a/src/opt/wmax.cpp b/src/opt/wmax.cpp index bb6451c41..3499c51ff 100644 --- a/src/opt/wmax.cpp +++ b/src/opt/wmax.cpp @@ -40,7 +40,6 @@ namespace opt { lbool operator()() { TRACE("opt", tout << "weighted maxsat\n";); scoped_ensure_theory wth(*this); - solver::scoped_push _s1(s()); lbool is_sat = l_true; bool was_sat = false; for (unsigned i = 0; i < m_soft.size(); ++i) { diff --git a/src/smt/theory_wmaxsat.cpp b/src/smt/theory_wmaxsat.cpp index 17ec4ff0a..539a3e909 100644 --- a/src/smt/theory_wmaxsat.cpp +++ b/src/smt/theory_wmaxsat.cpp @@ -171,7 +171,6 @@ void theory_wmaxsat::reset_local() { m_vars.reset(); m_fmls.reset(); m_rweights.reset(); - m_costs.reset(); m_rmin_cost.reset(); m_rcost.reset(); m_zweights.reset(); From 37b96a61337b35429503f3ace7249cf761a4362b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 31 Aug 2014 11:16:08 -0700 Subject: [PATCH 506/925] bounds axiom tuning Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith_core.h | 74 ++++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 49032bdc8..71a0a2713 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -818,6 +818,79 @@ namespace smt { atoms & occs = m_var_occs[v]; typename atoms::iterator it = occs.begin(); typename atoms::iterator end = occs.end(); + parameter coeffs[3] = { parameter(symbol("farkas")), parameter(rational(1)), parameter(rational(1)) }; + + optional lo_inf, lo_sup, hi_inf, hi_sup; + literal lit1, lit2, lit3, lit4; + for (; it != end; ++it) { + atom * a2 = *it; + literal l2(a2->get_bool_var()); + inf_numeral const & k2 = a2->get_k(); + atom_kind kind2 = a2->get_atom_kind(); + SASSERT(k1 != k2 || kind1 != kind2); + if (kind2 == A_LOWER) { + if (k2 < k1) { + if (!lo_inf || k2 > *lo_inf) { + lo_inf = k2; + lit1 = l2; + } + } + else if (!lo_sup || k2 < *lo_sup) { + lo_sup = k2; + lit2 = l2; + } + } + else { + if (k2 < k1) { + if (!hi_inf || k2 > *hi_inf) { + hi_inf = k2; + lit3 = l2; + } + } + else if (!hi_sup || k2 < *hi_sup) { + hi_sup = k2; + lit4 = l2; + } + } + } + if (kind1 == A_LOWER) { + if (lo_inf) { + // k1 > lo_inf, k1 <= x => lo_inf <= x + mk_clause(~l1, lit1, 3, coeffs); + } + if (lo_sup) { + // k1 < lo_sup, lo_sup <= x => k1 <= x + mk_clause(l1, ~lit2, 3, coeffs); + } + if (hi_inf) { + // k1 > hi_inf, k1 <= x => ~(x <= hi_inf) + mk_clause(~l1, ~lit3, 3, coeffs); + } + if (hi_sup) { + // k1 < hi_sup, k1 <= x or x <= hi_sup + mk_clause(l1, lit4, 3, coeffs); + } + } + else { + if (lo_inf) { + // k1 > lo_inf, ~(k1 >= x) => lo_inf <= x + mk_clause(l1, lit1, 3, coeffs); + } + if (lo_sup) { + // k1 < lo_sup, lo_sup <= x => ~(x <= k1) + mk_clause(~l1, ~lit2, 3, coeffs); + } + if (hi_inf) { + // k1 > hi_inf, x <= hi_inf => x <= k1 + mk_clause(l1, ~lit3, 3, coeffs); + } + if (hi_sup) { + // k1 < hi_sup, ~(x <= k1) or x <= hi_sup + mk_clause(~l1, lit4, 3, coeffs); + } + } + return; + for (; it != end; ++it) { atom * a2 = *it; literal l2(a2->get_bool_var()); @@ -825,7 +898,6 @@ namespace smt { atom_kind kind2 = a2->get_atom_kind(); SASSERT(k1 != k2 || kind1 != kind2); SASSERT(a2->get_var() == v); - parameter coeffs[3] = { parameter(symbol("farkas")), parameter(rational(1)), parameter(rational(1)) }; if (kind1 == A_LOWER) { if (kind2 == A_LOWER) { // x >= k1, x >= k2 From 7f49135b3b708ba651bf5956fb236c2d0b2ea8db Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 31 Aug 2014 11:48:00 -0700 Subject: [PATCH 507/925] bounds axiom tuning Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith_core.h | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 71a0a2713..21ae186f9 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -855,37 +855,48 @@ namespace smt { } if (kind1 == A_LOWER) { if (lo_inf) { - // k1 > lo_inf, k1 <= x => lo_inf <= x + // k1 >= lo_inf, k1 <= x => lo_inf <= x mk_clause(~l1, lit1, 3, coeffs); } if (lo_sup) { - // k1 < lo_sup, lo_sup <= x => k1 <= x + // k1 <= lo_sup, lo_sup <= x => k1 <= x mk_clause(l1, ~lit2, 3, coeffs); } if (hi_inf) { - // k1 > hi_inf, k1 <= x => ~(x <= hi_inf) - mk_clause(~l1, ~lit3, 3, coeffs); + // k1 == hi_inf, k1 <= x or x <= hi_inf + if (k1 == *hi_inf) { + mk_clause(l1, lit3, 3, coeffs); + } + else { + // k1 > hi_inf, k1 <= x => ~(x <= hi_inf) + mk_clause(~l1, ~lit3, 3, coeffs); + } } if (hi_sup) { - // k1 < hi_sup, k1 <= x or x <= hi_sup + // k1 <= hi_sup, k1 <= x or x <= hi_sup mk_clause(l1, lit4, 3, coeffs); } } else { if (lo_inf) { - // k1 > lo_inf, ~(k1 >= x) => lo_inf <= x + // k1 >= lo_inf, k1 >= x or lo_inf <= x mk_clause(l1, lit1, 3, coeffs); } if (lo_sup) { - // k1 < lo_sup, lo_sup <= x => ~(x <= k1) - mk_clause(~l1, ~lit2, 3, coeffs); + if (k1 == *lo_sup) { + mk_clause(l1, lit2, 3, coeffs); + } + else { + // k1 < lo_sup, lo_sup <= x => ~(x <= k1) + mk_clause(~l1, ~lit2, 3, coeffs); + } } if (hi_inf) { - // k1 > hi_inf, x <= hi_inf => x <= k1 + // k1 >= hi_inf, x <= hi_inf => x <= k1 mk_clause(l1, ~lit3, 3, coeffs); } if (hi_sup) { - // k1 < hi_sup, ~(x <= k1) or x <= hi_sup + // k1 <= hi_sup , x <= k1 => x <= hi_sup mk_clause(~l1, lit4, 3, coeffs); } } From 3cbcd19a9ba5a7803c40c9ba4587219f4534075d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 31 Aug 2014 12:40:13 -0700 Subject: [PATCH 508/925] bounds axiom tuning Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith.h | 2 +- src/smt/theory_arith_core.h | 50 +++++++++++++++++++++++-------------- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 0ddaf67d9..7179ba8bf 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -282,7 +282,7 @@ namespace smt { atom(bool_var bv, theory_var v, inf_numeral const & k, atom_kind kind); atom_kind get_atom_kind() const { return static_cast(m_atom_kind); } virtual ~atom() {} - inf_numeral const & get_k() const { return m_k; } + inline inf_numeral const & get_k() const { return m_k; } bool_var get_bool_var() const { return m_bvar; } bool is_true() const { return m_is_true; } void assign_eh(bool is_true, inf_numeral const & epsilon); diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 21ae186f9..b27c1eacd 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -814,13 +814,15 @@ namespace smt { literal l1(a1->get_bool_var()); inf_numeral const & k1(a1->get_k()); atom_kind kind1 = a1->get_atom_kind(); + bool v_is_int = is_int(v); TRACE("mk_bound_axioms", tout << "making bound axioms for v" << v << " " << kind1 << " " << k1 << "\n";); atoms & occs = m_var_occs[v]; typename atoms::iterator it = occs.begin(); typename atoms::iterator end = occs.end(); parameter coeffs[3] = { parameter(symbol("farkas")), parameter(rational(1)), parameter(rational(1)) }; - optional lo_inf, lo_sup, hi_inf, hi_sup; + typename atoms::iterator lo_inf = occs.end(), lo_sup = occs.end(); + typename atoms::iterator hi_inf = occs.end(), hi_sup = occs.end(); literal lit1, lit2, lit3, lit4; for (; it != end; ++it) { atom * a2 = *it; @@ -830,72 +832,82 @@ namespace smt { SASSERT(k1 != k2 || kind1 != kind2); if (kind2 == A_LOWER) { if (k2 < k1) { - if (!lo_inf || k2 > *lo_inf) { - lo_inf = k2; + if (lit1 == null_literal || k2 > (*lo_inf)->get_k()) { + lo_inf = it; lit1 = l2; } } - else if (!lo_sup || k2 < *lo_sup) { - lo_sup = k2; + else if (lit2 == null_literal || k2 < (*lo_sup)->get_k()) { + lo_sup = it; lit2 = l2; } } else { if (k2 < k1) { - if (!hi_inf || k2 > *hi_inf) { - hi_inf = k2; + if (lit3 == null_literal || k2 > (*hi_inf)->get_k()) { + hi_inf = it; lit3 = l2; } } - else if (!hi_sup || k2 < *hi_sup) { - hi_sup = k2; + else if (lit4 == null_literal || k2 < (*hi_sup)->get_k()) { + hi_sup = it; lit4 = l2; } } } + if (kind1 == A_LOWER) { - if (lo_inf) { + if (lo_inf != occs.end()) { // k1 >= lo_inf, k1 <= x => lo_inf <= x mk_clause(~l1, lit1, 3, coeffs); } - if (lo_sup) { + if (lo_sup != occs.end()) { // k1 <= lo_sup, lo_sup <= x => k1 <= x mk_clause(l1, ~lit2, 3, coeffs); } - if (hi_inf) { + if (hi_inf != occs.end()) { // k1 == hi_inf, k1 <= x or x <= hi_inf - if (k1 == *hi_inf) { + if (k1 == (*hi_inf)->get_k()) { mk_clause(l1, lit3, 3, coeffs); } else { // k1 > hi_inf, k1 <= x => ~(x <= hi_inf) mk_clause(~l1, ~lit3, 3, coeffs); + if (v_is_int && k1 == (*hi_inf)->get_k() + inf_numeral(1)) { + // k1 <= x or x <= k1-1 + mk_clause(l1, lit3, 3, coeffs); + } } } - if (hi_sup) { + if (hi_sup != occs.end()) { // k1 <= hi_sup, k1 <= x or x <= hi_sup mk_clause(l1, lit4, 3, coeffs); } } else { - if (lo_inf) { + if (lo_inf != occs.end()) { // k1 >= lo_inf, k1 >= x or lo_inf <= x mk_clause(l1, lit1, 3, coeffs); } - if (lo_sup) { - if (k1 == *lo_sup) { + if (lo_sup != occs.end()) { + if (k1 == (*lo_sup)->get_k()) { mk_clause(l1, lit2, 3, coeffs); } else { // k1 < lo_sup, lo_sup <= x => ~(x <= k1) mk_clause(~l1, ~lit2, 3, coeffs); + if (v_is_int && k1 == (*lo_sup)->get_k() - inf_numeral(1)) { + // x <= k1 or k1+l <= x + mk_clause(l1, lit2, 3, coeffs); + } + } } - if (hi_inf) { + if (hi_inf != occs.end()) { // k1 >= hi_inf, x <= hi_inf => x <= k1 mk_clause(l1, ~lit3, 3, coeffs); } - if (hi_sup) { + if (hi_sup != occs.end()) { // k1 <= hi_sup , x <= k1 => x <= hi_sup mk_clause(~l1, lit4, 3, coeffs); } From 7ee28445099d61f9fc844cd478f86929b82748a2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 31 Aug 2014 12:49:12 -0700 Subject: [PATCH 509/925] bounds axiom tuning Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith_core.h | 39 ++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index b27c1eacd..017833210 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -821,51 +821,50 @@ namespace smt { typename atoms::iterator end = occs.end(); parameter coeffs[3] = { parameter(symbol("farkas")), parameter(rational(1)), parameter(rational(1)) }; - typename atoms::iterator lo_inf = occs.end(), lo_sup = occs.end(); - typename atoms::iterator hi_inf = occs.end(), hi_sup = occs.end(); + typename atoms::iterator lo_inf = end, lo_sup = end; + typename atoms::iterator hi_inf = end, hi_sup = end; literal lit1, lit2, lit3, lit4; for (; it != end; ++it) { - atom * a2 = *it; - literal l2(a2->get_bool_var()); + atom * a2 = *it; inf_numeral const & k2 = a2->get_k(); atom_kind kind2 = a2->get_atom_kind(); SASSERT(k1 != k2 || kind1 != kind2); if (kind2 == A_LOWER) { if (k2 < k1) { - if (lit1 == null_literal || k2 > (*lo_inf)->get_k()) { + if (lo_inf == end || k2 > (*lo_inf)->get_k()) { lo_inf = it; - lit1 = l2; + lit1 = literal(a2->get_bool_var()); } } - else if (lit2 == null_literal || k2 < (*lo_sup)->get_k()) { + else if (lo_sup == end || k2 < (*lo_sup)->get_k()) { lo_sup = it; - lit2 = l2; + lit2 = literal(a2->get_bool_var()); } } else { if (k2 < k1) { - if (lit3 == null_literal || k2 > (*hi_inf)->get_k()) { + if (hi_inf == end || k2 > (*hi_inf)->get_k()) { hi_inf = it; - lit3 = l2; + lit3 = literal(a2->get_bool_var()); } } - else if (lit4 == null_literal || k2 < (*hi_sup)->get_k()) { + else if (hi_sup == end || k2 < (*hi_sup)->get_k()) { hi_sup = it; - lit4 = l2; + lit4 = literal(a2->get_bool_var()); } } } if (kind1 == A_LOWER) { - if (lo_inf != occs.end()) { + if (lo_inf != end) { // k1 >= lo_inf, k1 <= x => lo_inf <= x mk_clause(~l1, lit1, 3, coeffs); } - if (lo_sup != occs.end()) { + if (lo_sup != end) { // k1 <= lo_sup, lo_sup <= x => k1 <= x mk_clause(l1, ~lit2, 3, coeffs); } - if (hi_inf != occs.end()) { + if (hi_inf != end) { // k1 == hi_inf, k1 <= x or x <= hi_inf if (k1 == (*hi_inf)->get_k()) { mk_clause(l1, lit3, 3, coeffs); @@ -879,17 +878,17 @@ namespace smt { } } } - if (hi_sup != occs.end()) { + if (hi_sup != end) { // k1 <= hi_sup, k1 <= x or x <= hi_sup mk_clause(l1, lit4, 3, coeffs); } } else { - if (lo_inf != occs.end()) { + if (lo_inf != end) { // k1 >= lo_inf, k1 >= x or lo_inf <= x mk_clause(l1, lit1, 3, coeffs); } - if (lo_sup != occs.end()) { + if (lo_sup != end) { if (k1 == (*lo_sup)->get_k()) { mk_clause(l1, lit2, 3, coeffs); } @@ -903,11 +902,11 @@ namespace smt { } } - if (hi_inf != occs.end()) { + if (hi_inf != end) { // k1 >= hi_inf, x <= hi_inf => x <= k1 mk_clause(l1, ~lit3, 3, coeffs); } - if (hi_sup != occs.end()) { + if (hi_sup != end) { // k1 <= hi_sup , x <= k1 => x <= hi_sup mk_clause(~l1, lit4, 3, coeffs); } From 89f03190435995f6e6feb1b4e70eb26789d99e44 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 1 Sep 2014 11:19:05 -0700 Subject: [PATCH 510/925] tune assertions of bounds Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith.h | 12 ++ src/smt/theory_arith_core.h | 252 ++++++++++++++++++++++-------------- 2 files changed, 169 insertions(+), 95 deletions(-) diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 7179ba8bf..638d3c6b0 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -573,6 +573,18 @@ namespace smt { void mk_clause(literal l1, literal l2, unsigned num_params, parameter * params); void mk_clause(literal l1, literal l2, literal l3, unsigned num_params, parameter * params); void mk_bound_axioms(atom * a); + void mk_bound_axiom(atom* a1, atom* a2); + ptr_vector m_new_atoms; + void flush_bound_axioms(); + typename atoms::iterator next_sup(atom* a1, atom_kind kind, + typename atoms::iterator it, + typename atoms::iterator end); + typename atoms::iterator next_inf(atom* a1, atom_kind kind, + typename atoms::iterator it, + typename atoms::iterator end); + struct compare_atoms { + bool operator()(atom* a1, atom* a2) const { return a1->get_k() < a2->get_k(); } + }; virtual bool default_internalizer() const { return false; } virtual bool internalize_atom(app * n, bool gate_ctx); virtual bool internalize_term(app * term); diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 017833210..e037ea9e3 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -810,143 +810,204 @@ namespace smt { template void theory_arith::mk_bound_axioms(atom * a1) { + if (!get_context().is_searching()) { + // + // NB. We make an assumption that user push calls propagation + // before internal scopes are pushed. This flushes all newly + // asserted atoms into the right context. + // + m_new_atoms.push_back(a1); + return; + } theory_var v = a1->get_var(); - literal l1(a1->get_bool_var()); inf_numeral const & k1(a1->get_k()); atom_kind kind1 = a1->get_atom_kind(); - bool v_is_int = is_int(v); TRACE("mk_bound_axioms", tout << "making bound axioms for v" << v << " " << kind1 << " " << k1 << "\n";); atoms & occs = m_var_occs[v]; typename atoms::iterator it = occs.begin(); typename atoms::iterator end = occs.end(); - parameter coeffs[3] = { parameter(symbol("farkas")), parameter(rational(1)), parameter(rational(1)) }; typename atoms::iterator lo_inf = end, lo_sup = end; typename atoms::iterator hi_inf = end, hi_sup = end; - literal lit1, lit2, lit3, lit4; for (; it != end; ++it) { atom * a2 = *it; - inf_numeral const & k2 = a2->get_k(); - atom_kind kind2 = a2->get_atom_kind(); + inf_numeral const & k2(a2->get_k()); + atom_kind kind2 = a2->get_atom_kind(); SASSERT(k1 != k2 || kind1 != kind2); if (kind2 == A_LOWER) { if (k2 < k1) { if (lo_inf == end || k2 > (*lo_inf)->get_k()) { lo_inf = it; - lit1 = literal(a2->get_bool_var()); } } else if (lo_sup == end || k2 < (*lo_sup)->get_k()) { lo_sup = it; - lit2 = literal(a2->get_bool_var()); } } - else { - if (k2 < k1) { - if (hi_inf == end || k2 > (*hi_inf)->get_k()) { - hi_inf = it; - lit3 = literal(a2->get_bool_var()); - } - } - else if (hi_sup == end || k2 < (*hi_sup)->get_k()) { - hi_sup = it; - lit4 = literal(a2->get_bool_var()); + else if (k2 < k1) { + if (hi_inf == end || k2 > (*hi_inf)->get_k()) { + hi_inf = it; } } + else if (hi_sup == end || k2 < (*hi_sup)->get_k()) { + hi_sup = it; + } } + if (lo_inf != end) mk_bound_axiom(a1, *lo_inf); + if (lo_sup != end) mk_bound_axiom(a1, *lo_sup); + if (hi_inf != end) mk_bound_axiom(a1, *hi_inf); + if (hi_sup != end) mk_bound_axiom(a1, *hi_sup); + } + + template + void theory_arith::mk_bound_axiom(atom* a1, atom* a2) { + theory_var v = a1->get_var(); + literal l1(a1->get_bool_var()); + literal l2(a2->get_bool_var()); + inf_numeral const & k1(a1->get_k()); + inf_numeral const & k2(a2->get_k()); + atom_kind kind1 = a1->get_atom_kind(); + atom_kind kind2 = a2->get_atom_kind(); + bool v_is_int = is_int(v); + SASSERT(v === a2->get_var()); + SASSERT(k1 != k2 || kind1 != kind2); + parameter coeffs[3] = { parameter(symbol("farkas")), + parameter(rational(1)), parameter(rational(1)) }; if (kind1 == A_LOWER) { - if (lo_inf != end) { - // k1 >= lo_inf, k1 <= x => lo_inf <= x - mk_clause(~l1, lit1, 3, coeffs); - } - if (lo_sup != end) { - // k1 <= lo_sup, lo_sup <= x => k1 <= x - mk_clause(l1, ~lit2, 3, coeffs); - } - if (hi_inf != end) { - // k1 == hi_inf, k1 <= x or x <= hi_inf - if (k1 == (*hi_inf)->get_k()) { - mk_clause(l1, lit3, 3, coeffs); + if (kind2 == A_LOWER) { + if (k2 <= k1) { + mk_clause(~l1, l2, 3, coeffs); } else { - // k1 > hi_inf, k1 <= x => ~(x <= hi_inf) - mk_clause(~l1, ~lit3, 3, coeffs); - if (v_is_int && k1 == (*hi_inf)->get_k() + inf_numeral(1)) { - // k1 <= x or x <= k1-1 - mk_clause(l1, lit3, 3, coeffs); - } + mk_clause(l1, ~l2, 3, coeffs); } } - if (hi_sup != end) { - // k1 <= hi_sup, k1 <= x or x <= hi_sup - mk_clause(l1, lit4, 3, coeffs); + else if (k1 <= k2) { + // k1 <= k2, k1 <= x or x <= k2 + mk_clause(l1, l2, 3, coeffs); + } + else { + // k1 > hi_inf, k1 <= x => ~(x <= hi_inf) + mk_clause(~l1, ~l2, 3, coeffs); + if (v_is_int && k1 == k2 + inf_numeral(1)) { + // k1 <= x or x <= k1-1 + mk_clause(l1, l2, 3, coeffs); + } + } + } + else if (kind2 == A_LOWER) { + if (k1 >= k2) { + // k1 >= lo_inf, k1 >= x or lo_inf <= x + mk_clause(l1, l2, 3, coeffs); + } + else { + // k1 < k2, k2 <= x => ~(x <= k1) + mk_clause(~l1, ~l2, 3, coeffs); + if (v_is_int && k1 == k2 - inf_numeral(1)) { + // x <= k1 or k1+l <= x + mk_clause(l1, l2, 3, coeffs); + } + } } else { - if (lo_inf != end) { - // k1 >= lo_inf, k1 >= x or lo_inf <= x - mk_clause(l1, lit1, 3, coeffs); - } - if (lo_sup != end) { - if (k1 == (*lo_sup)->get_k()) { - mk_clause(l1, lit2, 3, coeffs); - } - else { - // k1 < lo_sup, lo_sup <= x => ~(x <= k1) - mk_clause(~l1, ~lit2, 3, coeffs); - if (v_is_int && k1 == (*lo_sup)->get_k() - inf_numeral(1)) { - // x <= k1 or k1+l <= x - mk_clause(l1, lit2, 3, coeffs); - } - - } - } - if (hi_inf != end) { - // k1 >= hi_inf, x <= hi_inf => x <= k1 - mk_clause(l1, ~lit3, 3, coeffs); - } - if (hi_sup != end) { - // k1 <= hi_sup , x <= k1 => x <= hi_sup - mk_clause(~l1, lit4, 3, coeffs); - } - } - return; - - for (; it != end; ++it) { - atom * a2 = *it; - literal l2(a2->get_bool_var()); - inf_numeral const & k2 = a2->get_k(); - atom_kind kind2 = a2->get_atom_kind(); - SASSERT(k1 != k2 || kind1 != kind2); - SASSERT(a2->get_var() == v); - if (kind1 == A_LOWER) { - if (kind2 == A_LOWER) { - // x >= k1, x >= k2 - if (k1 >= k2) mk_clause(~l1, l2, 3, coeffs); - else mk_clause(~l2, l1, 3, coeffs); - } - else { - // x >= k1, x <= k2 - if (k1 > k2) mk_clause(~l1, ~l2, 3, coeffs); - else mk_clause(l1, l2, 3, coeffs); - } + // kind1 == A_UPPER, kind2 == A_UPPER + if (k1 >= k2) { + // k1 >= k2, x <= k2 => x <= k1 + mk_clause(l1, ~l2, 3, coeffs); } else { - if (kind2 == A_LOWER) { - // x <= k1, x >= k2 - if (k1 < k2) mk_clause(~l1, ~l2, 3, coeffs); - else mk_clause(l1, l2, 3, coeffs); - } - else { - // x <= k1, x <= k2 - if (k1 < k2) mk_clause(~l1, l2, 3, coeffs); - else mk_clause(~l2, l1, 3, coeffs); + // k1 <= hi_sup , x <= k1 => x <= hi_sup + mk_clause(~l1, l2, 3, coeffs); + } + } + } + + template + void theory_arith::flush_bound_axioms() { + while (!m_new_atoms.empty()) { + ptr_vector atoms; + atoms.push_back(m_new_atoms.back()); + m_new_atoms.pop_back(); + theory_var v = atoms.back()->get_var(); + for (unsigned i = 0; i < m_new_atoms.size(); ++i) { + if (m_new_atoms[i]->get_var() == v) { + atoms.push_back(m_new_atoms[i]); + m_new_atoms[i] = m_new_atoms.back(); + m_new_atoms.pop_back(); + --i; } } + ptr_vector occs(m_var_occs[v]); + + std::sort(atoms.begin(), atoms.end(), compare_atoms()); + std::sort(occs.begin(), occs.end(), compare_atoms()); + + typename atoms::iterator begin = occs.begin(); + typename atoms::iterator end = occs.end(); + typename atoms::iterator lo_inf = begin, lo_sup = begin; + typename atoms::iterator hi_inf = begin, hi_sup = begin; + + for (unsigned i = 0; i < atoms.size(); ++i) { + atom* a1 = atoms[i]; + lo_inf = next_inf(a1, A_LOWER, lo_inf, end); + hi_inf = next_inf(a1, A_UPPER, hi_inf, end); + lo_sup = next_sup(a1, A_LOWER, lo_sup, end); + hi_sup = next_sup(a1, A_UPPER, hi_sup, end); + if (lo_inf != end) mk_bound_axiom(a1, *lo_inf); + if (lo_sup != end) mk_bound_axiom(a1, *lo_sup); + if (hi_inf != end) mk_bound_axiom(a1, *hi_inf); + if (hi_sup != end) mk_bound_axiom(a1, *hi_sup); + } } } + template + typename theory_arith::atoms::iterator + theory_arith::next_inf( + atom* a1, + atom_kind kind, + typename atoms::iterator it, + typename atoms::iterator end) { + inf_numeral const & k1(a1->get_k()); + typename atoms::iterator result = end; + for (; it != end; ++it) { + atom * a2 = *it; + if (a1 == a2) continue; + if (a2->get_atom_kind() != kind) continue; + inf_numeral const & k2(a2->get_k()); + if (k2 <= k1) { + result = it; + } + else { + break; + } + } + return result; + } + + template + typename theory_arith::atoms::iterator + theory_arith::next_sup( + atom* a1, + atom_kind kind, + typename atoms::iterator it, + typename atoms::iterator end) { + inf_numeral const & k1(a1->get_k()); + for (; it != end; ++it) { + atom * a2 = *it; + if (a1 == a2) continue; + if (a2->get_atom_kind() != kind) continue; + inf_numeral const & k2(a2->get_k()); + if (k2 > k1) { + return it; + } + } + return end; + } + + template bool theory_arith::internalize_atom(app * n, bool gate_ctx) { TRACE("arith_internalize", tout << "internalising atom:\n" << mk_pp(n, this->get_manager()) << "\n";); @@ -1248,6 +1309,7 @@ namespace smt { CASSERT("arith", wf_columns()); CASSERT("arith", valid_row_assignment()); + flush_bound_axioms(); propagate_linear_monomials(); while (m_asserted_qhead < m_asserted_bounds.size()) { bound * b = m_asserted_bounds[m_asserted_qhead]; From 75c114feabf6f931a435e773e3668c376c17798d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 1 Sep 2014 14:37:58 -0700 Subject: [PATCH 511/925] fix regression on push/pop Signed-off-by: Nikolaj Bjorner --- src/opt/maxsmt.cpp | 1 + src/opt/opt_context.cpp | 2 -- src/smt/theory_arith_core.h | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 2b8bcb462..d128e57f2 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -136,6 +136,7 @@ namespace opt { m_wth = s.ensure_wmax_theory(); } maxsmt_solver_base::scoped_ensure_theory::~scoped_ensure_theory() { + //m_wth->reset_local(); } smt::theory_wmaxsat& maxsmt_solver_base::scoped_ensure_theory::operator()() { return *m_wth; } diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 39316b772..d931afbff 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -143,11 +143,9 @@ namespace opt { void context::push() { m_scoped_state.push(); - m_solver->push(); } void context::pop(unsigned n) { - m_solver->pop(n); for (unsigned i = 0; i < n; ++i) { m_scoped_state.pop(); } diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index e037ea9e3..b80a1f415 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -869,7 +869,7 @@ namespace smt { atom_kind kind1 = a1->get_atom_kind(); atom_kind kind2 = a2->get_atom_kind(); bool v_is_int = is_int(v); - SASSERT(v === a2->get_var()); + SASSERT(v == a2->get_var()); SASSERT(k1 != k2 || kind1 != kind2); parameter coeffs[3] = { parameter(symbol("farkas")), parameter(rational(1)), parameter(rational(1)) }; From 31f16d7aa4f0fc54b78cac33c4477d656c6d4969 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 1 Sep 2014 14:58:58 -0700 Subject: [PATCH 512/925] add push/pop to optimization context for convenience Signed-off-by: Nikolaj Bjorner --- src/api/api_opt.cpp | 17 +++++++++++++++++ src/api/c++/z3++.h | 6 ++++++ src/api/dotnet/Optimize.cs | 20 ++++++++++++++++++++ src/api/python/z3.py | 8 ++++++++ src/api/z3_api.h | 28 ++++++++++++++++++++++++++-- 5 files changed, 77 insertions(+), 2 deletions(-) diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index 3c4089a34..d9369092a 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -102,6 +102,23 @@ extern "C" { Z3_CATCH_RETURN(0); } + void Z3_API Z3_optimize_push(Z3_context c,Z3_optimize d) { + Z3_TRY; + LOG_Z3_optimize_push(c, d); + RESET_ERROR_CODE(); + to_optimize_ptr(d)->push(); + Z3_CATCH; + } + + void Z3_API Z3_optimize_pop(Z3_context c,Z3_optimize d) { + Z3_TRY; + LOG_Z3_optimize_pop(c, d); + RESET_ERROR_CODE(); + to_optimize_ptr(d)->pop(1); + Z3_CATCH; + } + + Z3_lbool Z3_API Z3_optimize_check(Z3_context c, Z3_optimize o) { Z3_TRY; LOG_Z3_optimize_check(c, o); diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index b4e90f4f4..1cbdd5a9a 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1511,6 +1511,12 @@ namespace z3 { handle minimize(expr const& e) { return handle(Z3_optimize_minimize(ctx(), m_opt, e)); } + void push() { + Z3_optimize_push(ctx(), m_opt); + } + void pop() { + Z3_optimize_pop(ctx(), m_opt); + } check_result check() { Z3_lbool r = Z3_optimize_check(ctx(), m_opt); check_error(); return to_check_result(r); } model get_model() const { Z3_model m = Z3_optimize_get_model(ctx(), m_opt); check_error(); return model(ctx(), m); } void set(params const & p) { Z3_optimize_set_params(ctx(), m_opt, p); check_error(); } diff --git a/src/api/dotnet/Optimize.cs b/src/api/dotnet/Optimize.cs index 93d1e0478..ddbebcfa6 100644 --- a/src/api/dotnet/Optimize.cs +++ b/src/api/dotnet/Optimize.cs @@ -111,6 +111,26 @@ namespace Microsoft.Z3 } } + /// + /// Creates a backtracking point. + /// + /// + public void Push() + { + Native.Z3_optimize_push(Context.nCtx, NativeObject); + } + + /// + /// Backtrack one backtracking point. + /// + /// Note that an exception is thrown if Pop is called without a corresponding Push + /// + public void Pop() + { + Native.Z3_optimize_pop(Context.nCtx, NativeObject); + } + + /// /// The model of the last Check. /// diff --git a/src/api/python/z3.py b/src/api/python/z3.py index 98759e81a..3504170fd 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -6382,6 +6382,14 @@ class Optimize(Z3PPObject): """Add objective function to minimize.""" return OptimizeObjective(Z3_optimize_minimize(self.ctx.ref(), self.optimize, arg.as_ast())) + def push(self): + """create a backtracking point for added rules, facts and assertions""" + Z3_optimize_push(self.ctx.ref(), self.optimize) + + def pop(self): + """restore to previously created backtracking point""" + Z3_optimize_pop(self.ctx.ref(), self.optimize) + def check(self): """Check satisfiability while optimizing objective functions.""" return CheckSatResult(Z3_optimize_check(self.ctx.ref(), self.optimize)) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index efbb2a923..ebaa44339 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -6007,7 +6007,7 @@ END_MLAPI_EXCLUDE /** - \brief Add a maximiztion constraint. + \brief Add a maximization constraint. \param c - context \param o - optimization context \param a - arithmetical term @@ -6016,7 +6016,7 @@ END_MLAPI_EXCLUDE unsigned Z3_API Z3_optimize_maximize(Z3_context, Z3_optimize o, Z3_ast t); /** - \brief Add a minimiztion constraint. + \brief Add a minimization constraint. \param c - context \param o - optimization context \param a - arithmetical term @@ -6025,6 +6025,30 @@ END_MLAPI_EXCLUDE */ unsigned Z3_API Z3_optimize_minimize(Z3_context, Z3_optimize o, Z3_ast t); + + /** + \brief Create a backtracking point. + + The optimize solver contains a set of rules, added facts and assertions. + The set of rules, facts and assertions are restored upon calling #Z3_optimize_pop. + + \sa Z3_optimize_pop + + def_API('Z3_optimize_push', VOID, (_in(CONTEXT), _in(OPTIMIZE))) + */ + void Z3_API Z3_optimize_push(Z3_context c,Z3_optimize d); + + /** + \brief Backtrack one level. + + \sa Z3_optimize_push + + \pre The number of calls to pop cannot exceed calls to push. + + def_API('Z3_optimize_pop', VOID, (_in(CONTEXT), _in(OPTIMIZE))) + */ + void Z3_API Z3_optimize_pop(Z3_context c,Z3_optimize d); + /** \brief Check consistency and produce optimal values. \param c - context From 3f8083dfa692b24a4525f548b3673fa274394dca Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 2 Sep 2014 09:32:38 -0700 Subject: [PATCH 513/925] fix push/pop bugs in optimize context, add example to c++, fix bug in arithemtic bounds axiom addition Signed-off-by: Nikolaj Bjorner --- examples/c++/example.cpp | 25 ++++++++++++++++++++++++- src/opt/opt_context.cpp | 9 +++++++++ src/smt/theory_arith_core.h | 1 + 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/examples/c++/example.cpp b/examples/c++/example.cpp index 7ffa04709..454f3ebae 100644 --- a/examples/c++/example.cpp +++ b/examples/c++/example.cpp @@ -972,7 +972,29 @@ void substitute_example() { std::cout << new_f << std::endl; } - +void opt_example() { + context c; + optimize opt(c); + params p(c); + p.set("priority",c.str_symbol("pareto")); + opt.set(p); + expr x = c.int_const("x"); + expr y = c.int_const("y"); + opt.add(10 >= x && x >= 0); + opt.add(10 >= y && y >= 0); + opt.add(x + y <= 11); + optimize::handle h1 = opt.maximize(x); + optimize::handle h2 = opt.maximize(y); + check_result r = sat; + while (true) { + if (sat == opt.check()) { + std::cout << x << ": " << opt.lower(h1) << " " << y << ": " << opt.lower(h2) << "\n"; + } + else { + break; + } + } +} int main() { try { @@ -1012,6 +1034,7 @@ int main() { expr_vector_example(); std::cout << "\n"; exists_expr_vector_example(); std::cout << "\n"; substitute_example(); std::cout << "\n"; + opt_example(); std::cout << "\n"; std::cout << "done\n"; } catch (exception & ex) { diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index d931afbff..9098a1323 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -139,6 +139,7 @@ namespace opt { for (; it != end; ++it) { dealloc(it->m_value); } + m_maxsmts.reset(); } void context::push() { @@ -149,21 +150,29 @@ namespace opt { for (unsigned i = 0; i < n; ++i) { m_scoped_state.pop(); } + m_model.reset(); + reset_maxsmts(); + m_optsmt.reset(); + m_hard_constraints.reset(); } void context::set_hard_constraints(ptr_vector& fmls) { m_scoped_state.set(fmls); + m_model.reset(); } void context::add_hard_constraint(expr* f) { m_scoped_state.add(f); + m_model.reset(); } unsigned context::add_soft_constraint(expr* f, rational const& w, symbol const& id) { + m_model.reset(); return m_scoped_state.add(f, w, id); } unsigned context::add_objective(app* t, bool is_max) { + m_model.reset(); return m_scoped_state.add(t, is_max); } diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index b80a1f415..366054d79 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -3090,6 +3090,7 @@ namespace smt { SASSERT(m_to_patch.empty()); m_to_check.reset(); m_in_to_check.reset(); + m_new_atoms.reset(); CASSERT("arith", wf_rows()); CASSERT("arith", wf_columns()); CASSERT("arith", valid_row_assignment()); From b5bbf838475fefc1c9b711457e8d26f5aab0c259 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 2 Sep 2014 19:05:28 -0700 Subject: [PATCH 514/925] update core generation to be partial, update maxres to use current model too Signed-off-by: Nikolaj Bjorner --- src/opt/inc_sat_solver.cpp | 6 +++++- src/opt/maxres.cpp | 13 +++++++++---- src/opt/opt_context.cpp | 2 +- src/sat/sat_config.cpp | 1 + src/sat/sat_config.h | 1 + src/sat/sat_mus.cpp | 25 ++++++++++++++++--------- src/sat/sat_params.pyg | 1 + src/sat/sat_solver.cpp | 2 +- src/smt/theory_arith_core.h | 2 +- 9 files changed, 36 insertions(+), 17 deletions(-) diff --git a/src/opt/inc_sat_solver.cpp b/src/opt/inc_sat_solver.cpp index 49315a895..9e041e0a3 100644 --- a/src/opt/inc_sat_solver.cpp +++ b/src/opt/inc_sat_solver.cpp @@ -367,8 +367,12 @@ private: void extract_model() { TRACE("sat", tout << "retrieve model\n";); - model_ref md = alloc(model, m); sat::model const & ll_m = m_solver.get_model(); + if (ll_m.empty()) { + m_model = 0; + return; + } + model_ref md = alloc(model, m); atom2bool_var::iterator it = m_map.begin(); atom2bool_var::iterator end = m_map.end(); for (; it != end; ++it) { diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 5ff2cc745..7befdd235 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -156,7 +156,7 @@ public: lbool mus_solver() { init(); init_local(); - while (true) { + while (m_lower < m_upper) { TRACE("opt", display_vec(tout, m_asms.size(), m_asms.c_ptr()); s().display(tout); @@ -167,6 +167,7 @@ public: if (m_cancel) { return l_undef; } + model_ref mdl; switch (is_sat) { case l_true: found_optimum(); @@ -174,6 +175,7 @@ public: case l_false: is_sat = process_unsat(); if (is_sat != l_true) return is_sat; + get_mus_model(mdl); break; case l_undef: return l_undef; @@ -359,14 +361,16 @@ public: // likewise, if the cores are too big, don't block the cores. // - process_unsat(cores); exprs cs; get_current_correction_set(cs); unsigned max_core = max_core_size(cores); - if (cs.size() <= std::max(max_core, m_max_correction_set_size)) { + if (!cs.empty() && cs.size() < max_core) { process_sat(cs); } + else { + process_unsat(cores); + } } m_lower = m_upper; @@ -465,6 +469,7 @@ public: cs.push_back(m_asms[i].get()); } } + IF_VERBOSE(2, verbose_stream() << "(opt.maxres correction set size: " << cs.size() << ")\n";); TRACE("opt", display_vec(tout << "new correction set: ", cs.size(), cs.c_ptr());); } @@ -554,7 +559,7 @@ public: if (m_c.sat_enabled()) { // SAT solver core extracts some model // during unsat core computation. - s().get_model(mdl); + s().get_model(mdl); } else { w = m_mus.get_best_model(mdl); diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 9098a1323..ffb1f815d 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -451,7 +451,7 @@ namespace opt { m_maxsat_engine != symbol("sls")) { return; } - m_params.set_bool("minimize_core", true); + m_params.set_bool("minimize_core_partial", true); m_sat_solver = mk_inc_sat_solver(m, m_params); unsigned sz = get_solver().get_num_assertions(); for (unsigned i = 0; i < sz; ++i) { diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index f142100ad..17eda1707 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -105,6 +105,7 @@ namespace sat { } m_minimize_lemmas = p.minimize_lemmas(); m_minimize_core = p.minimize_core(); + m_minimize_core_partial = p.minimize_core_partial(); m_optimize_model = p.optimize_model(); m_dyn_sub_res = p.dyn_sub_res(); } diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index df11629ab..044c91989 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -69,6 +69,7 @@ namespace sat { bool m_minimize_lemmas; bool m_dyn_sub_res; bool m_minimize_core; + bool m_minimize_core_partial; bool m_optimize_model; diff --git a/src/sat/sat_mus.cpp b/src/sat/sat_mus.cpp index fd4cf0338..035423a19 100644 --- a/src/sat/sat_mus.cpp +++ b/src/sat/sat_mus.cpp @@ -41,7 +41,9 @@ namespace sat { } lbool mus::operator()() { + bool minimize_partial = s.m_config.m_minimize_core_partial; flet _disable_min(s.m_config.m_minimize_core, false); + flet _disable_min_partial(s.m_config.m_minimize_core_partial, false); flet _disable_opt(s.m_config.m_optimize_model, false); flet _is_active(m_is_active, true); TRACE("sat", tout << "old core: " << s.get_core() << "\n";); @@ -58,7 +60,7 @@ namespace sat { --i; } } - + unsigned delta_time = 0; while (!core.empty()) { IF_VERBOSE(2, verbose_stream() << "(opt.mus reducing core: " << core.size() << " new core: " << mus.size() << ")\n";); TRACE("sat", @@ -69,6 +71,11 @@ namespace sat { set_core(); return l_undef; } + if (minimize_partial && delta_time > 4) { + break; + } + unsigned num_literals = core.size() + mus.size(); + literal lit = core.back(); core.pop_back(); unsigned sz = mus.size(); @@ -99,14 +106,6 @@ namespace sat { if (new_core.contains(~lit)) { mus.resize(sz); break; -#if 0 - mus.pop_back(); - is_sat = s.check(mus.size(), mus.c_ptr()); - SASSERT(is_sat != l_true); - if (is_sat != l_false) { - return l_undef; - } -#endif } mus.resize(sz); TRACE("sat", tout << "new core: " << new_core << "\n";); @@ -119,6 +118,14 @@ namespace sat { } break; } + + unsigned new_num_literals = core.size() + mus.size(); + if (new_num_literals == num_literals) { + delta_time++; + } + else { + delta_time = 0; + } } TRACE("sat", tout << "new core: " << mus << "\n";); set_core(); diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index fb4a7fe6d..b0be62eef 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -19,5 +19,6 @@ def_module_params('sat', ('minimize_lemmas', BOOL, True, 'minimize learned clauses'), ('dyn_sub_res', BOOL, True, 'dynamic subsumption resolution for minimizing learned clauses'), ('minimize_core', BOOL, False, 'minimize computed core'), + ('minimize_core_partial', BOOL, False, 'apply partial (cheap) core minimization'), ('optimize_model', BOOL, False, 'enable optimization of soft constraints'), ('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'))) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index ad7f4ea02..1d3f4f68c 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1730,7 +1730,7 @@ namespace sat { idx--; } reset_unmark(old_size); - if (m_config.m_minimize_core) { + if (m_config.m_minimize_core || m_config.m_minimize_core_partial) { // TBD: // apply optional clause minimization by detecting subsumed literals. // initial experiment suggests it has no effect. diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 366054d79..3f6597a37 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -938,7 +938,7 @@ namespace smt { m_new_atoms.pop_back(); --i; } - } + } ptr_vector occs(m_var_occs[v]); std::sort(atoms.begin(), atoms.end(), compare_atoms()); From 18b491eee0bb9c403cfb3323ac272f0adbdcca44 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 3 Sep 2014 10:03:56 -0700 Subject: [PATCH 515/925] fixes to maxres/mss Signed-off-by: Nikolaj Bjorner --- src/opt/inc_sat_solver.cpp | 50 ++++++++--------- src/opt/maxres.cpp | 104 ++++++++++-------------------------- src/opt/mus.cpp | 1 + src/opt/opt_context.cpp | 6 ++- src/sat/sat_mus.cpp | 8 +++ src/sat/sat_mus.h | 1 + src/sat/sat_sls.cpp | 8 +-- src/sat/sat_sls.h | 2 +- src/sat/sat_solver.cpp | 2 +- src/sat/tactic/goal2sat.cpp | 8 +-- 10 files changed, 76 insertions(+), 114 deletions(-) diff --git a/src/opt/inc_sat_solver.cpp b/src/opt/inc_sat_solver.cpp index 9e041e0a3..11aa24d71 100644 --- a/src/opt/inc_sat_solver.cpp +++ b/src/opt/inc_sat_solver.cpp @@ -37,6 +37,7 @@ class inc_sat_solver : public solver { sat::solver m_solver; goal2sat m_goal2sat; params_ref m_params; + bool m_optimize_model; // parameter expr_ref_vector m_fmls; expr_ref_vector m_current_fmls; unsigned_vector m_fmls_lim; @@ -54,10 +55,12 @@ class inc_sat_solver : public solver { expr_ref_vector m_soft; vector m_weights; + typedef obj_map dep2asm_t; public: inc_sat_solver(ast_manager& m, params_ref const& p): - m(m), m_solver(p,0), m_params(p), + m(m), m_solver(p,0), + m_params(p), m_optimize_model(false), m_fmls(m), m_current_fmls(m), m_core(m), m_map(m), m_num_scopes(0), m_dep_core(m), @@ -165,6 +168,7 @@ public: m_params = p; m_params.set_bool("elim_vars", false); m_solver.updt_params(m_params); + m_optimize_model = m_params.get_bool("optimize_model", false); } virtual void collect_statistics(statistics & st) const { m_preprocess->collect_statistics(st); @@ -226,32 +230,26 @@ private: lbool r = internalize_formulas(); if (r != l_true) return r; r = internalize_assumptions(soft.size(), soft.c_ptr(), dep2asm); + if (r != l_true) return r; sat::literal_vector lits; svector weights; sat::literal lit; - - if (r == l_true) { - for (unsigned i = 0; i < soft.size(); ++i) { - weights.push_back(m_weights[i].get_double()); - expr* s = soft[i].get(); - bool is_neg = m.is_not(s, s); - if (!dep2asm.find(s, lit)) { - std::cout << "not found: " << mk_pp(s, m) << "\n"; - dep2asm_t::iterator it = dep2asm.begin(), end = dep2asm.end(); - for (; it != end; ++it) { - std::cout << mk_pp(it->m_key, m) << " " << it->m_value << "\n"; - } - UNREACHABLE(); - } - if (is_neg) { - lit.neg(); - } - lits.push_back(lit); + for (unsigned i = 0; i < soft.size(); ++i) { + weights.push_back(m_weights[i].get_double()); + expr* s = soft[i].get(); + if (!dep2asm.find(s, lit)) { + IF_VERBOSE(0, + verbose_stream() << "not found: " << mk_pp(s, m) << "\n"; + dep2asm_t::iterator it = dep2asm.begin(); + dep2asm_t::iterator end = dep2asm.end(); + for (; it != end; ++it) { + verbose_stream() << mk_pp(it->m_key, m) << " " << it->m_value << "\n"; + } + UNREACHABLE();); } - m_solver.initialize_soft(lits.size(), lits.c_ptr(), weights.c_ptr()); - m_params.set_bool("optimize_model", true); - m_solver.updt_params(m_params); + lits.push_back(lit); } + m_solver.initialize_soft(lits.size(), lits.c_ptr(), weights.c_ptr()); return r; } @@ -324,12 +322,8 @@ private: m_core.reset(); for (unsigned i = 0; i < core.size(); ++i) { expr* e; - if (asm2dep.find(core[i].index(), e)) { - if (core[i].sign()) { - e = m.mk_not(e); - } - m_core.push_back(e); - } + VERIFY (asm2dep.find(core[i].index(), e)); + m_core.push_back(e); } TRACE("opt", dep2asm_t::iterator it = dep2asm.begin(); diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 7befdd235..f879c8934 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -72,14 +72,12 @@ public: enum strategy_t { s_mus, s_mus_mss, - s_mus_mss2, s_mss }; private: expr_ref_vector m_B; expr_ref_vector m_asms; obj_map m_asm2weight; - obj_map m_asm2value; ptr_vector m_new_core; mus m_mus; mss m_mss; @@ -186,44 +184,6 @@ public: return l_true; } - lbool mus_mss_solver() { - init(); - init_local(); - sls(); - exprs mcs; - vector cores; - while (m_lower < m_upper) { - TRACE("opt", - display_vec(tout, m_asms.size(), m_asms.c_ptr()); - s().display(tout); - tout << "\n"; - display(tout); - ); - lbool is_sat = try_improve_bound(cores, mcs); - if (m_cancel) { - return l_undef; - } - switch (is_sat) { - case l_undef: - return l_undef; - case l_false: - SASSERT(cores.empty() && mcs.empty()); - m_lower = m_upper; - return l_true; - case l_true: - SASSERT(cores.empty() || mcs.empty()); - for (unsigned i = 0; i < cores.size(); ++i) { - process_unsat(cores[i]); - } - if (cores.empty()) { - process_sat(mcs); - } - break; - } - } - m_lower = m_upper; - return l_true; - } lbool mss_solver() { init(); @@ -234,6 +194,9 @@ public: lbool is_sat = l_true; while (m_lower < m_upper && is_sat == l_true) { IF_VERBOSE(1, verbose_stream() << "(opt.maxres [" << m_lower << ":" << m_upper << "])\n";); + if (m_cancel) { + return l_undef; + } vector cores; exprs mss; model_ref mdl; @@ -241,6 +204,12 @@ public: mcs.reset(); s().get_model(mdl); update_assignment(mdl.get()); + + exprs cs; + get_current_correction_set(mdl.get(), cs); + process_sat(cs); + +#if 0 is_sat = get_mss(mdl.get(), cores, mss, mcs); switch (is_sat) { @@ -249,15 +218,12 @@ public: case l_false: m_lower = m_upper; return l_true; - case l_true: { + case l_true: process_sat(mcs); get_mss_model(); - break; - } - } - if (m_cancel) { - return l_undef; + break; } +#endif if (m_lower < m_upper) { is_sat = s().check_sat(0, 0); } @@ -294,7 +260,7 @@ public: Suppose correction set is huge. Do we really need it? */ - lbool mus_mss2_solver() { + lbool mus_mss_solver() { init(); init_local(); sls(); @@ -356,14 +322,8 @@ public: // obtained from the current best model. // - // - // TBD: throttle blocking on correction sets if they are too big. - // likewise, if the cores are too big, don't block the cores. - // - - exprs cs; - get_current_correction_set(cs); + get_current_correction_set(mdl.get(), cs); unsigned max_core = max_core_size(cores); if (!cs.empty() && cs.size() < max_core) { process_sat(cs); @@ -379,7 +339,6 @@ public: void found_optimum() { s().get_model(m_model); - m_asm2value.reset(); DEBUG_CODE( for (unsigned i = 0; i < m_asms.size(); ++i) { SASSERT(is_true(m_asms[i].get())); @@ -397,8 +356,6 @@ public: return mus_solver(); case s_mus_mss: return mus_mss_solver(); - case s_mus_mss2: - return mus_mss2_solver(); case s_mss: return mss_solver(); } @@ -462,14 +419,14 @@ public: return is_sat; } - void get_current_correction_set(exprs& cs) { + void get_current_correction_set(model* mdl, exprs& cs) { cs.reset(); + if (!mdl) return; for (unsigned i = 0; i < m_asms.size(); ++i) { - if (!is_true(m_asms[i].get())) { + if (!is_true(mdl, m_asms[i].get())) { cs.push_back(m_asms[i].get()); } } - IF_VERBOSE(2, verbose_stream() << "(opt.maxres correction set size: " << cs.size() << ")\n";); TRACE("opt", display_vec(tout << "new correction set: ", cs.size(), cs.c_ptr());); } @@ -554,7 +511,7 @@ public: IF_VERBOSE(1, verbose_stream() << "(opt.maxres [" << m_lower << ":" << m_upper << "])\n";); } - void get_mus_model(model_ref& mdl) { + bool get_mus_model(model_ref& mdl) { rational w(0); if (m_c.sat_enabled()) { // SAT solver core extracts some model @@ -567,6 +524,7 @@ public: if (mdl.get() && w < m_upper) { update_assignment(mdl.get()); } + return 0 != mdl.get(); } void get_mss_model() { @@ -682,17 +640,13 @@ public: s().assert_expr(fml); fml = m.mk_implies(dd, b_i); s().assert_expr(fml); - m_asm2value.insert(dd, is_true(d) && is_true(b_i)); d = dd; } else { - dd = m.mk_and(b_i, d); - m_asm2value.insert(dd, is_true(d) && is_true(b_i)); - m_trail.push_back(dd); - d = dd; + d = m.mk_and(b_i, d); + m_trail.push_back(d); } asum = mk_fresh_bool("a"); - m_asm2value.insert(asum, is_true(b_i1) || is_true(d)); cls = m.mk_or(b_i1, d); fml = m.mk_implies(asum, cls); new_assumption(asum, w); @@ -809,7 +763,6 @@ public: return l_undef; } - void update_assignment(model* mdl) { rational upper(0); expr_ref tmp(m); @@ -826,7 +779,6 @@ public: return; } m_model = mdl; - m_asm2value.reset(); for (unsigned i = 0; i < m_soft.size(); ++i) { m_assignment[i] = is_true(m_soft[i].get()); @@ -851,16 +803,16 @@ public: s().assert_expr(fml); } - bool is_true(expr* e) { - bool truth_value; - if (m_asm2value.find(e, truth_value)) { - return truth_value; - } + bool is_true(model* mdl, expr* e) { expr_ref tmp(m); - VERIFY(m_model->eval(e, tmp)); + VERIFY(mdl->eval(e, tmp)); return m.is_true(tmp); } + bool is_true(expr* e) { + return is_true(m_model.get(), e); + } + void remove_soft(exprs const& core, expr_ref_vector& asms) { for (unsigned i = 0; i < asms.size(); ++i) { if (core.contains(asms[i].get())) { @@ -933,7 +885,7 @@ opt::maxsmt_solver_base* opt::mk_maxres( opt::maxsmt_solver_base* opt::mk_mus_mss_maxres( context& c, weights_t& ws, expr_ref_vector const& soft) { - return alloc(maxres, c, ws, soft, maxres::s_mus_mss2); + return alloc(maxres, c, ws, soft, maxres::s_mus_mss); } opt::maxsmt_solver_base* opt::mk_mss_maxres( diff --git a/src/opt/mus.cpp b/src/opt/mus.cpp index 932d9ccf7..abb0b326e 100644 --- a/src/opt/mus.cpp +++ b/src/opt/mus.cpp @@ -70,6 +70,7 @@ struct mus::imp { lbool get_mus(unsigned_vector& mus) { // SASSERT: mus does not have duplicates. + m_model.reset(); unsigned_vector core; for (unsigned i = 0; i < m_cls2expr.size(); ++i) { core.push_back(i); diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index ffb1f815d..caa71eeaa 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -465,9 +465,13 @@ namespace opt { void context::enable_sls(expr_ref_vector const& soft, vector const& weights) { SASSERT(soft.size() == weights.size()); - if (m_enable_sls && m_sat_solver.get()) { + if (m_sat_solver.get()) { set_soft_inc_sat(m_sat_solver.get(), soft.size(), soft.c_ptr(), weights.c_ptr()); } + if (m_enable_sls && m_sat_solver.get()) { + m_params.set_bool("optimize_model", true); + m_sat_solver->updt_params(m_params); + } } struct context::is_bv { diff --git a/src/sat/sat_mus.cpp b/src/sat/sat_mus.cpp index 035423a19..4468f5b34 100644 --- a/src/sat/sat_mus.cpp +++ b/src/sat/sat_mus.cpp @@ -32,6 +32,7 @@ namespace sat { m_core.reset(); m_mus.reset(); m_model.reset(); + m_best_value = 0; } void mus::set_core() { @@ -96,8 +97,15 @@ namespace sat { if (!core.empty()) { // mr(); // TBD: measure } + double new_value = s.m_wsls.evaluate_model(s.m_model); if (m_model.empty()) { m_model.append(s.m_model); + m_best_value = new_value; + } + else if (m_best_value > new_value) { + m_model.reset(); + m_model.append(s.m_model); + m_best_value = new_value; } break; } diff --git a/src/sat/sat_mus.h b/src/sat/sat_mus.h index b68f4ee5c..eede15c63 100644 --- a/src/sat/sat_mus.h +++ b/src/sat/sat_mus.h @@ -25,6 +25,7 @@ namespace sat { literal_vector m_mus; bool m_is_active; model m_model; // model obtained during minimal unsat core + double m_best_value; solver& s; diff --git a/src/sat/sat_sls.cpp b/src/sat/sat_sls.cpp index 3a520742e..bd0f8855a 100644 --- a/src/sat/sat_sls.cpp +++ b/src/sat/sat_sls.cpp @@ -354,7 +354,7 @@ namespace sat { // // Initialize m_clause_weights, m_hscore, m_sscore. // - m_best_value = m_false.empty()?evaluate_model():-1.0; + m_best_value = m_false.empty()?evaluate_model(m_model):-1.0; m_best_model.reset(); m_clause_weights.reset(); m_hscore.reset(); @@ -382,7 +382,7 @@ namespace sat { for (; !m_cancel && m_best_value > 0 && i < m_max_tries; ++i) { wflip(); if (m_false.empty()) { - double val = evaluate_model(); + double val = evaluate_model(m_model); if (val < m_best_value || m_best_value < 0.0) { m_best_value = val; m_best_model.reset(); @@ -511,12 +511,12 @@ namespace sat { DEBUG_CODE(check_invariant();); } - double wsls::evaluate_model() { + double wsls::evaluate_model(model& mdl) { SASSERT(m_false.empty()); double result = 0.0; for (unsigned i = 0; i < m_soft.size(); ++i) { literal lit = m_soft[i]; - if (value_at(lit, m_model) != l_true) { + if (value_at(lit, mdl) != l_true) { result += m_weights[i]; } } diff --git a/src/sat/sat_sls.h b/src/sat/sat_sls.h index 8efc337cc..530d4be0c 100644 --- a/src/sat/sat_sls.h +++ b/src/sat/sat_sls.h @@ -99,12 +99,12 @@ namespace sat { void opt(unsigned sz, literal const* tabu, bool reuse_model); model const& get_model() { return m_best_model; } virtual void display(std::ostream& out) const; + double evaluate_model(model& mdl); private: void wflip(); void wflip(literal lit); void update_hard_weights(); bool pick_wflip(literal & lit); - double evaluate_model(); virtual void check_invariant(); void refresh_scores(bool_var v); int compute_hscore(bool_var v); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 1d3f4f68c..4b1bd32b1 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1737,7 +1737,7 @@ namespace sat { m_mus(); // ignore return value on cancelation. m_model.reset(); - m_model.append(m_mus.get_model()); + m_model.append(m_mus.get_model()); } } diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 38a22095a..7224de971 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -372,7 +372,9 @@ struct goal2sat::imp { SASSERT(m_result_stack.empty()); } - void insert_dep(expr* dep, bool sign) { + void insert_dep(expr* dep0, expr* dep, bool sign) { + SASSERT(sign || dep0 == dep); // !sign || (not dep0) == dep. + SASSERT(!sign || m.is_not(dep0)); expr_ref new_dep(m), fml(m); if (is_uninterp_const(dep)) { new_dep = dep; @@ -386,7 +388,7 @@ struct goal2sat::imp { } convert_atom(new_dep, false, false); sat::literal lit = m_result_stack.back(); - m_dep2asm.insert(dep, sign?(~lit):lit); + m_dep2asm.insert(dep0, sign?~lit:lit); m_result_stack.pop_back(); } @@ -411,7 +413,7 @@ struct goal2sat::imp { SASSERT(m.is_bool(d)); bool sign = m.is_not(d, d1); - insert_dep(d1, sign); + insert_dep(d, d1, sign); if (d == f) { goto skip_dep; } From c1580fb85aa2a653e72fb3dda27a175c5e28c8f4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 7 Sep 2014 11:52:14 -0700 Subject: [PATCH 516/925] follow logic annotation/enable diff logic when configured Signed-off-by: Nikolaj Bjorner --- src/api/api_model.cpp | 3 +++ src/cmd_context/cmd_context.cpp | 1 + src/cmd_context/cmd_context.h | 1 + src/muz/pdr/pdr_context.cpp | 29 ++++++++++++++++++++++++----- src/opt/opt_context.cpp | 4 +++- src/opt/opt_context.h | 2 ++ src/opt/opt_solver.cpp | 22 +++++++++++++++------- src/opt/opt_solver.h | 6 ++++-- src/opt/optsmt.cpp | 1 - src/smt/smt_setup.cpp | 10 +++++----- src/smt/theory_diff_logic_def.h | 22 +++++++++++++--------- 11 files changed, 71 insertions(+), 30 deletions(-) diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index f17f7a586..f0c31d800 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -60,6 +60,7 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } + mk_c(c)->save_ast_trail(r); RETURN_Z3(of_expr(r)); Z3_CATCH_RETURN(0); } @@ -263,6 +264,7 @@ extern "C" { RESET_ERROR_CODE(); CHECK_NON_NULL(f, 0); expr * e = to_func_interp_ref(f)->get_else(); + mk_c(c)->save_ast_trail(e); RETURN_Z3(of_expr(e)); Z3_CATCH_RETURN(0); } @@ -301,6 +303,7 @@ extern "C" { LOG_Z3_func_entry_get_value(c, e); RESET_ERROR_CODE(); expr * v = to_func_entry_ref(e)->get_result(); + mk_c(c)->save_ast_trail(v); RETURN_Z3(of_expr(v)); Z3_CATCH_RETURN(0); } diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index a76933912..1acdb047e 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -362,6 +362,7 @@ void cmd_context::set_opt(opt_wrapper* opt) { for (unsigned i = 0; i < m_scopes.size(); ++i) { m_opt->push(); } + m_opt->set_logic(m_logic); } void cmd_context::global_params_updated() { diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index 0dfea0441..091e0765d 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -123,6 +123,7 @@ public: virtual void set_hard_constraints(ptr_vector & hard) = 0; virtual void display_assignment(std::ostream& out) = 0; virtual bool is_pareto() = 0; + virtual void set_logic(symbol const& s) = 0; }; class cmd_context : public progress_callback, public tactic_manager, public ast_printer_context { diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index 2ddfd1c01..00e6c0336 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -49,6 +49,7 @@ Notes: #include "scoped_proof.h" #include "blast_term_ite_tactic.h" #include "model_implicant.h" +#include "expr_safe_replace.h" namespace pdr { @@ -1073,10 +1074,7 @@ namespace pdr { predicates.pop_back(); for (unsigned i = rule->get_uninterpreted_tail_size(); i < rule->get_tail_size(); ++i) { subst.apply(2, deltas, expr_offset(rule->get_tail(i), 1), tmp); - dctx.get_rewriter()(tmp); - if (!m.is_true(tmp)) { - constraints.push_back(tmp); - } + constraints.push_back(tmp); } for (unsigned i = 0; i < constraints.size(); ++i) { max_var = std::max(vc.get_max_var(constraints[i].get()), max_var); @@ -1099,7 +1097,27 @@ namespace pdr { children.append(n->children()); } - return pm.mk_and(constraints); + expr_safe_replace repl(m); + for (unsigned i = 0; i < constraints.size(); ++i) { + expr* e = constraints[i].get(), *e1, *e2; + if (m.is_eq(e, e1, e2) && is_var(e1) && is_ground(e2)) { + repl.insert(e1, e2); + } + else if (m.is_eq(e, e1, e2) && is_var(e2) && is_ground(e1)) { + repl.insert(e2, e1); + } + } + expr_ref_vector result(m); + for (unsigned i = 0; i < constraints.size(); ++i) { + expr_ref tmp(m); + tmp = constraints[i].get(); + repl(tmp); + dctx.get_rewriter()(tmp); + if (!m.is_true(tmp)) { + result.push_back(tmp); + } + } + return pm.mk_and(result); } proof_ref model_search::get_proof_trace(context const& ctx) { @@ -1232,6 +1250,7 @@ namespace pdr { remove_node(*m_root, false); dealloc(m_root); m_root = 0; + m_cache.reset(); } } diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index caa71eeaa..79986067e 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -284,6 +284,7 @@ namespace opt { lbool context::execute_lex() { lbool r = l_true; + IF_VERBOSE(1, verbose_stream() << "(optsmt:lex)\n";); for (unsigned i = 0; r == l_true && i < m_objectives.size(); ++i) { bool is_last = i + 1 == m_objectives.size(); r = execute(m_objectives[i], i + 1 < m_objectives.size(), !is_last); @@ -435,7 +436,8 @@ namespace opt { void context::init_solver() { #pragma omp critical (opt_context) { - m_opt_solver = alloc(opt_solver, m, m_params, m_fm, symbol()); + m_opt_solver = alloc(opt_solver, m, m_params, m_fm); + m_opt_solver->set_logic(m_logic); m_solver = m_opt_solver.get(); } } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index c2c9f46d8..bbecb4996 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -128,6 +128,7 @@ namespace opt { bool m_enable_sat; bool m_enable_sls; symbol m_maxsat_engine; + symbol m_logic; public: context(ast_manager& m); virtual ~context(); @@ -153,6 +154,7 @@ namespace opt { virtual void display_assignment(std::ostream& out); virtual bool is_pareto() { return m_pareto.get() != 0; } + virtual void set_logic(symbol const& s) { m_logic = s; } void display(std::ostream& out); static void collect_param_descrs(param_descrs & r); diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 186a63105..470acae38 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -36,17 +36,14 @@ Notes: namespace opt { opt_solver::opt_solver(ast_manager & mgr, params_ref const & p, - filter_model_converter& fm, symbol const & l): + filter_model_converter& fm): solver_na2as(mgr), m_params(p), m_context(mgr, m_params), m(mgr), m_dump_benchmarks(false), - m_fm(fm) { - m_logic = l; - if (m_logic != symbol::null) { - m_context.set_logic(m_logic); - } + m_fm(fm), + m_first(true) { m_params.updt_params(p); m_params.m_relevancy_lvl = 0; } @@ -83,6 +80,10 @@ namespace opt { m_context.pop(n); } + void opt_solver::set_logic(symbol const& logic) { + m_context.set_logic(logic); + } + smt::theory_opt& opt_solver::get_optimizer() { smt::context& ctx = m_context.get_context(); smt::theory_id arith_id = m_context.m().get_family_id("arith"); @@ -143,7 +144,14 @@ namespace opt { IF_VERBOSE(1, verbose_stream() << "(created benchmark: " << file_name.str() << "..."; verbose_stream().flush();); } - lbool r = m_context.check(num_assumptions, assumptions); + lbool r; + if (m_first && num_assumptions == 0 && m_context.get_scope_level() == 0) { + r = m_context.setup_and_check(); + } + else { + r = m_context.check(num_assumptions, assumptions); + } + m_first = false; if (dump_benchmarks()) { w.stop(); IF_VERBOSE(1, verbose_stream() << ".. " << r << " " << std::fixed << w.get_seconds() << ")\n";); diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 128e12798..07f2e756b 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -51,8 +51,9 @@ namespace opt { bool m_dump_benchmarks; static unsigned m_dump_count; statistics m_stats; + bool m_first; public: - opt_solver(ast_manager & m, params_ref const & p, filter_model_converter& fm, symbol const & l); + opt_solver(ast_manager & m, params_ref const & p, filter_model_converter& fm); virtual ~opt_solver(); virtual void updt_params(params_ref & p); @@ -61,7 +62,7 @@ namespace opt { virtual void assert_expr(expr * t); virtual void push_core(); virtual void pop_core(unsigned n); - virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions); + virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions); virtual void get_unsat_core(ptr_vector & r); virtual void get_model(model_ref & m); virtual proof * get_proof(); @@ -72,6 +73,7 @@ namespace opt { virtual unsigned get_num_assertions() const; virtual expr * get_assertion(unsigned idx) const; virtual void display(std::ostream & out) const; + void set_logic(symbol const& logic); smt::theory_var add_objective(app* term); void reset_objectives(); diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 8428f03ab..0a441755b 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -235,7 +235,6 @@ namespace opt { } lbool optsmt::lex(unsigned obj_index) { - IF_VERBOSE(1, verbose_stream() << "(optsmt:lex)\n";); TRACE("opt", tout << "optsmt:lex\n";); solver::scoped_push _push(*m_s); SASSERT(obj_index < m_vars.size()); diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index d933a5f43..a392f8959 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -301,7 +301,7 @@ namespace smt { } void setup::setup_QF_IDL() { - TRACE("setup", tout << "setup_QF_IDL(st)\n";); + TRACE("setup", tout << "setup_QF_IDL()\n";); m_params.m_relevancy_lvl = 0; m_params.m_arith_expand_eqs = true; m_params.m_arith_reflect = false; @@ -351,16 +351,15 @@ namespace smt { else if (!m_params.m_arith_auto_config_simplex && is_dense(st)) { TRACE("setup", tout << "using dense diff logic...\n";); m_params.m_phase_selection = PS_CACHING_CONSERVATIVE; -#if 0 - m_context.register_plugin(alloc(smt::theory_idl, m_manager, m_params)); -#else if (st.m_arith_k_sum < rational(INT_MAX / 8)) m_context.register_plugin(alloc(smt::theory_dense_si, m_manager, m_params)); else m_context.register_plugin(alloc(smt::theory_dense_i, m_manager, m_params)); -#endif } + else if (!m_params.m_arith_auto_config_simplex && !is_dense(st)) { + m_context.register_plugin(alloc(smt::theory_idl, m_manager, m_params)); + } else { // if (st.m_arith_k_sum < rational(INT_MAX / 8)) { // TRACE("setup", tout << "using small integer simplex...\n";); @@ -379,6 +378,7 @@ namespace smt { m_params.m_arith_reflect = false; m_params.m_nnf_cnf = false; m_params.m_arith_eq_bounds = true; + m_params.m_arith_expand_eqs = true; m_params.m_phase_selection = PS_ALWAYS_FALSE; m_params.m_restart_strategy = RS_GEOMETRIC; m_params.m_restart_factor = 1.5; diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index 700ed83a3..d7bc45374 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -81,8 +81,10 @@ template bool theory_diff_logic::internalize_term(app * term) { bool result = null_theory_var != mk_term(term); CTRACE("arith", !result, tout << "Did not internalize " << mk_pp(term, get_manager()) << "\n";); - TRACE("non_diff_logic", tout << "Terms may not be internalized\n";); - found_non_diff_logic_expr(term); + if (!result) { + TRACE("non_diff_logic", tout << "Terms may not be internalized\n";); + found_non_diff_logic_expr(term); + } return result; } @@ -273,6 +275,8 @@ bool theory_diff_logic::internalize_atom(app * n, bool gate_ctx) { template void theory_diff_logic::internalize_eq_eh(app * atom, bool_var v) { context & ctx = get_context(); + ast_manager& m = get_manager(); + TRACE("arith", tout << mk_pp(atom, m) << "\n";); app * lhs = to_app(atom->get_arg(0)); app * rhs = to_app(atom->get_arg(1)); app * s; @@ -1070,13 +1074,13 @@ inf_eps_rational theory_diff_logic::maximize(theory_var v, ex ast_manager& m = get_manager(); objective_term const& objective = m_objectives[v]; - IF_VERBOSE(1, - for (unsigned i = 0; i < objective.size(); ++i) { - verbose_stream() << "Coefficient " << objective[i].second - << " of theory_var " << objective[i].first << "\n"; - } - verbose_stream() << "Free coefficient " << m_objective_consts[v] << "\n";); - + TRACE("arith", + for (unsigned i = 0; i < objective.size(); ++i) { + tout << "Coefficient " << objective[i].second + << " of theory_var " << objective[i].first << "\n"; + } + tout << "Free coefficient " << m_objective_consts[v] << "\n"; + ); unsigned num_nodes = m_graph.get_num_nodes(); unsigned num_edges = m_graph.get_num_edges(); vector > const& es = m_graph.get_all_edges(); From d9c61464d0789f245583f97c606f47e4561f29cf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 7 Sep 2014 16:46:46 -0700 Subject: [PATCH 517/925] make difference logic simplex optimizer incremental Signed-off-by: Nikolaj Bjorner --- src/math/simplex/simplex.h | 1 + src/math/simplex/simplex_def.h | 10 ++ src/math/simplex/sparse_matrix.h | 1 + src/math/simplex/sparse_matrix_def.h | 10 ++ src/smt/theory_diff_logic.h | 18 ++- src/smt/theory_diff_logic_def.h | 175 ++++++++++++++++++--------- 6 files changed, 159 insertions(+), 56 deletions(-) diff --git a/src/math/simplex/simplex.h b/src/math/simplex/simplex.h index 86429b1a2..9685af589 100644 --- a/src/math/simplex/simplex.h +++ b/src/math/simplex/simplex.h @@ -142,6 +142,7 @@ namespace simplex { void set_value(var_t var, eps_numeral const& b); void set_cancel(bool f) { m_cancel = f; } void set_max_iterations(unsigned m) { m_max_iterations = m; } + void reset(); lbool make_feasible(); lbool minimize(var_t var); eps_numeral const& get_value(var_t v); diff --git a/src/math/simplex/simplex_def.h b/src/math/simplex/simplex_def.h index daa718472..3c1a90a7a 100644 --- a/src/math/simplex/simplex_def.h +++ b/src/math/simplex/simplex_def.h @@ -310,6 +310,16 @@ namespace simplex { } } + template + void simplex::reset() { + M.reset(); + m_to_patch.reset(); + m_vars.reset(); + m_row2base.reset(); + m_left_basis.reset(); + m_base_vars.reset(); + } + template lbool simplex::make_feasible() { ++m_stats.m_num_checks; diff --git a/src/math/simplex/sparse_matrix.h b/src/math/simplex/sparse_matrix.h index 1c9f0fde8..80454a52c 100644 --- a/src/math/simplex/sparse_matrix.h +++ b/src/math/simplex/sparse_matrix.h @@ -145,6 +145,7 @@ namespace simplex { sparse_matrix(manager& m): m(m) {} ~sparse_matrix(); + void reset(); class row { unsigned m_id; diff --git a/src/math/simplex/sparse_matrix_def.h b/src/math/simplex/sparse_matrix_def.h index f4c25658e..9fa3ceda7 100644 --- a/src/math/simplex/sparse_matrix_def.h +++ b/src/math/simplex/sparse_matrix_def.h @@ -280,6 +280,16 @@ namespace simplex { } } + template + void sparse_matrix::reset() { + m_rows.reset(); + m_dead_rows.reset(); + m_columns.reset(); + m_var_pos.reset(); + m_var_pos_idx.reset(); + + } + template void sparse_matrix::ensure_var(var_t v) { while (m_columns.size() <= v) { diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h index e09b4f91e..27a2d3e58 100644 --- a/src/smt/theory_diff_logic.h +++ b/src/smt/theory_diff_logic.h @@ -38,6 +38,8 @@ Revision History: #include"numeral_factory.h" #include"smt_clause.h" #include"theory_opt.h" +#include"simplex.h" +#include"simplex_def.h" // The DL theory can represent term such as n + k, where n is an enode and k is a numeral. namespace smt { @@ -62,6 +64,7 @@ namespace smt { class theory_diff_logic : public theory, public theory_opt, private Ext { typedef typename Ext::numeral numeral; + typedef simplex::simplex Simplex; class atom { bool_var m_bvar; @@ -194,6 +197,9 @@ namespace smt { vector m_objectives; vector m_objective_consts; vector m_objective_assignments; + vector m_objective_rows; + Simplex m_S; + unsigned m_num_simplex_edges; // Set a conflict due to a negative cycle. void set_neg_cycle_conflict(); @@ -228,7 +234,8 @@ namespace smt { m_is_lia(true), m_non_diff_logic_exprs(false), m_factory(0), - m_nc_functor(*this) { + m_nc_functor(*this), + m_num_simplex_edges(0) { } virtual ~theory_diff_logic() { @@ -369,6 +376,15 @@ namespace smt { void inc_conflicts(); + // Optimization: + // convert variables, edges and objectives to simplex. + unsigned node2simplex(unsigned v); + unsigned edge2simplex(unsigned e); + unsigned obj2simplex(unsigned v); + unsigned num_simplex_vars(); + bool is_simplex_edge(unsigned e); + unsigned simplex2edge(unsigned e); + void update_simplex(Simplex& S); }; struct idl_ext { diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index d7bc45374..7189ee219 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -29,8 +29,6 @@ Revision History: #include"warning.h" #include"smt_model_generator.h" #include"model_implicant.h" -#include"simplex.h" -#include"simplex_def.h" using namespace smt; @@ -343,7 +341,13 @@ void theory_diff_logic::pop_scope_eh(unsigned num_scopes) { m_asserted_atoms.shrink(s.m_asserted_atoms_lim); m_asserted_qhead = s.m_asserted_qhead_old; m_scopes.shrink(new_lvl); + unsigned num_edges = m_graph.get_num_edges(); m_graph.pop(num_scopes); + if (num_edges != m_graph.get_num_edges() && m_num_simplex_edges > 0) { + m_S.reset(); + m_num_simplex_edges = 0; + m_objective_rows.reset(); + } theory::pop_scope_eh(num_scopes); } @@ -1066,12 +1070,120 @@ void theory_diff_logic::get_implied_bound_antecedents(edge_id bridge_edge, m_graph.explain_subsumed_lazy(bridge_edge, subsumed_edge, f); } +template +unsigned theory_diff_logic::node2simplex(unsigned v) { + //return v; + return m_objectives.size() + 2*v + 1; +} +template +unsigned theory_diff_logic::edge2simplex(unsigned e) { + //return m_graph.get_num_nodes() + e; + return m_objectives.size() + 2*e; +} +template +unsigned theory_diff_logic::obj2simplex(unsigned e) { + //return m_graph.get_num_nodes() + m_graph.get_num_edges() + e; + return e; +} + +template +unsigned theory_diff_logic::num_simplex_vars() { + //return m_graph.get_num_nodes() + m_graph.get_num_edges() + m_objectives.size(); + return m_objectives.size() + std::max(2*m_graph.get_num_edges(),2*m_graph.get_num_nodes()+1); +} + +template +bool theory_diff_logic::is_simplex_edge(unsigned e) { +#if 0 + return + m_graph.get_num_nodes() <= e && + e < m_graph.get_num_nodes() + m_graph.get_num_edges(); +#else + if (e < m_objectives.size()) return false; + e -= m_objectives.size(); + return (0 == (e & 0x1)); +#endif +} + +template +unsigned theory_diff_logic::simplex2edge(unsigned e) { + SASSERT(is_simplex_edge(e)); + //return e - m_graph.get_num_nodes(); + return (e - m_objectives.size())/2; +} + +template +void theory_diff_logic::update_simplex(Simplex& S) { + unsigned num_nodes = m_graph.get_num_nodes(); + vector > const& es = m_graph.get_all_edges(); + S.ensure_var(num_simplex_vars()); + for (unsigned i = 0; i < num_nodes; ++i) { + numeral const& a = m_graph.get_assignment(i); + rational fin = a.get_rational().to_rational(); + rational inf = a.get_infinitesimal().to_rational(); + mpq_inf q(fin.to_mpq(), inf.to_mpq()); + S.set_value(node2simplex(i), q); + } + S.set_lower(node2simplex(get_zero()), mpq_inf(mpq(0), mpq(0))); + S.set_upper(node2simplex(get_zero()), mpq_inf(mpq(0), mpq(0))); + svector vars; + unsynch_mpq_manager mgr; + scoped_mpq_vector coeffs(mgr); + coeffs.push_back(mpq(1)); + coeffs.push_back(mpq(-1)); + coeffs.push_back(mpq(-1)); + vars.resize(3); + for (unsigned i = m_num_simplex_edges; i < es.size(); ++i) { + // t - s <= w + // => + // t - s - b = 0, b >= w + dl_edge const& e = es[i]; + unsigned base_var = edge2simplex(i); + vars[0] = node2simplex(e.get_target()); + vars[1] = node2simplex(e.get_source()); + vars[2] = base_var; + S.add_row(base_var, 3, vars.c_ptr(), coeffs.c_ptr()); + } + m_num_simplex_edges = es.size(); + for (unsigned i = 0; i < es.size(); ++i) { + dl_edge const& e = es[i]; + unsigned base_var = edge2simplex(i); + if (e.is_enabled()) { + numeral const& w = e.get_weight(); + rational fin = w.get_rational().to_rational(); + rational inf = w.get_infinitesimal().to_rational(); + mpq_inf q(fin.to_mpq(),inf.to_mpq()); + S.set_upper(base_var, q); + } + else { + S.unset_upper(base_var); + } + } + for (unsigned v = m_objective_rows.size(); v < m_objectives.size(); ++v) { + unsigned w = obj2simplex(v); + objective_term const& objective = m_objectives[v]; + + // add objective function as row. + coeffs.reset(); + vars.reset(); + for (unsigned i = 0; i < objective.size(); ++i) { + coeffs.push_back(objective[i].second.to_mpq()); + vars.push_back(node2simplex(objective[i].first)); + } + coeffs.push_back(mpq(1)); + vars.push_back(w); + Simplex::row row = S.add_row(w, vars.size(), vars.c_ptr(), coeffs.c_ptr()); + m_objective_rows.push_back(row); + } +} + template inf_eps_rational theory_diff_logic::maximize(theory_var v, expr_ref& blocker) { - typedef simplex::simplex Simplex; - Simplex S; + Simplex& S = m_S; ast_manager& m = get_manager(); + + update_simplex(S); objective_term const& objective = m_objectives[v]; TRACE("arith", @@ -1081,55 +1193,6 @@ inf_eps_rational theory_diff_logic::maximize(theory_var v, ex } tout << "Free coefficient " << m_objective_consts[v] << "\n"; ); - unsigned num_nodes = m_graph.get_num_nodes(); - unsigned num_edges = m_graph.get_num_edges(); - vector > const& es = m_graph.get_all_edges(); - S.ensure_var(num_nodes + num_edges + m_objectives.size()); - for (unsigned i = 0; i < num_nodes; ++i) { - numeral const& a = m_graph.get_assignment(i); - rational fin = a.get_rational().to_rational(); - rational inf = a.get_infinitesimal().to_rational(); - mpq_inf q(fin.to_mpq(), inf.to_mpq()); - S.set_value(i, q); - } - S.set_lower(get_zero(), mpq_inf(mpq(0), mpq(0))); - S.set_upper(get_zero(), mpq_inf(mpq(0), mpq(0))); - svector vars; - unsynch_mpq_manager mgr; - scoped_mpq_vector coeffs(mgr); - coeffs.push_back(mpq(1)); - coeffs.push_back(mpq(-1)); - coeffs.push_back(mpq(-1)); - vars.resize(3); - for (unsigned i = 0; i < es.size(); ++i) { - dl_edge const& e = es[i]; - if (e.is_enabled()) { - unsigned base_var = num_nodes + i; - vars[0] = e.get_target(); - vars[1] = e.get_source(); - vars[2] = base_var; - S.add_row(base_var, 3, vars.c_ptr(), coeffs.c_ptr()); - // t - s <= w - // t - s - b = 0, b >= w - numeral const& w = e.get_weight(); - rational fin = w.get_rational().to_rational(); - rational inf = w.get_infinitesimal().to_rational(); - mpq_inf q(fin.to_mpq(),inf.to_mpq()); - S.set_upper(base_var, q); - } - } - unsigned w = num_nodes + num_edges + v; - - // add objective function as row. - coeffs.reset(); - vars.reset(); - for (unsigned i = 0; i < objective.size(); ++i) { - coeffs.push_back(objective[i].second.to_mpq()); - vars.push_back(objective[i].first); - } - coeffs.push_back(mpq(1)); - vars.push_back(w); - Simplex::row row = S.add_row(w, vars.size(), vars.c_ptr(), coeffs.c_ptr()); TRACE("opt", S.display(tout); display(tout);); @@ -1141,11 +1204,13 @@ inf_eps_rational theory_diff_logic::maximize(theory_var v, ex } TRACE("opt", S.display(tout); ); SASSERT(is_sat != l_false); + unsigned w = obj2simplex(v); lbool is_fin = S.minimize(w); switch (is_fin) { case l_true: { simplex::mpq_ext::eps_numeral const& val = S.get_value(w); inf_rational r(-rational(val.first), -rational(val.second)); + Simplex::row row = m_objective_rows[v]; TRACE("opt", tout << r << " " << "\n"; S.display_row(tout, row, true);); Simplex::row_iterator it = S.row_begin(row), end = S.row_end(row); @@ -1154,8 +1219,8 @@ inf_eps_rational theory_diff_logic::maximize(theory_var v, ex core.reset(); for (; it != end; ++it) { unsigned v = it->m_var; - if (num_nodes <= v && v < num_nodes + num_edges) { - unsigned edge_id = v - num_nodes; + if (is_simplex_edge(v)) { + unsigned edge_id = simplex2edge(v); literal lit = m_graph.get_explanation(edge_id); get_context().literal2expr(lit, tmp); core.push_back(tmp); From f7e1ad5277c672f82ed8c86a2beca645752c08ed Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 7 Sep 2014 18:30:45 -0700 Subject: [PATCH 518/925] tweaking card2bv conversion Signed-off-by: Nikolaj Bjorner --- src/tactic/arith/card2bv_tactic.cpp | 39 ++++++++++++++++++++++++----- src/tactic/arith/card2bv_tactic.h | 3 +++ 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/tactic/arith/card2bv_tactic.cpp b/src/tactic/arith/card2bv_tactic.cpp index 4661dc7db..55f50fbb2 100644 --- a/src/tactic/arith/card2bv_tactic.cpp +++ b/src/tactic/arith/card2bv_tactic.cpp @@ -59,6 +59,14 @@ namespace pb { return BR_DONE; } else if (f->get_family_id() == pb.get_family_id()) { + if (is_or(f)) { + result = m.mk_or(sz, args); + return BR_DONE; + } + if (is_and(f)) { + result = m.mk_and(sz, args); + return BR_DONE; + } br_status st = mk_shannon(f, sz, args, result); if (st == BR_FAILED) { return mk_bv(f, sz, args, result); @@ -95,7 +103,7 @@ namespace pb { if (au.is_int(args[i]) && au.is_numeral(args[i], val1)) q = bv.mk_numeral(val1, bits); else - q = m.mk_ite(to_app(args[i])->get_arg(0), bv.mk_numeral(1, bits), bv.mk_numeral(0, bits)); + q = mk_ite(to_app(args[i])->get_arg(0), bv.mk_numeral(1, bits), bv.mk_numeral(0, bits)); result = (i == 0) ? q : bv.mk_bv_add(result.get(), q); } return BR_DONE; @@ -107,14 +115,33 @@ namespace pb { return BR_FAILED; } + bool card2bv_rewriter::is_or(func_decl* f) { + switch (f->get_decl_kind()) { + case OP_AT_MOST_K: + case OP_PB_LE: + return false; + case OP_AT_LEAST_K: + case OP_PB_GE: + return pb.get_k(f).is_one(); + case OP_PB_EQ: + return false; + default: + UNREACHABLE(); + return false; + } + } + + bool card2bv_rewriter::is_and(func_decl* f) { + return false; + } br_status card2bv_rewriter::mk_bv(func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { expr_ref zero(m), a(m), b(m); expr_ref_vector es(m); - unsigned bw = get_num_bits(f); + unsigned bw = get_num_bits(f); zero = bv.mk_numeral(rational(0), bw); for (unsigned i = 0; i < sz; ++i) { - es.push_back(m.mk_ite(args[i], bv.mk_numeral(pb.get_coeff(f, i), bw), zero)); + es.push_back(mk_ite(args[i], bv.mk_numeral(pb.get_coeff(f, i), bw), zero)); } switch (es.size()) { case 0: a = zero; break; @@ -182,9 +209,6 @@ namespace pb { br_status card2bv_rewriter::mk_shannon( func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { - return BR_FAILED; - - // disabled for now. unsigned max_clauses = sz*10; vector argcs; for (unsigned i = 0; i < sz; ++i) { @@ -316,6 +340,9 @@ namespace pb { } expr* card2bv_rewriter::mk_ite(expr* c, expr* hi, expr* lo) { + while (m.is_not(c, c)) { + std::swap(hi, lo); + } if (hi == lo) return hi; if (m.is_true(hi) && m.is_false(lo)) return c; if (m.is_false(hi) && m.is_true(lo)) return negate(c); diff --git a/src/tactic/arith/card2bv_tactic.h b/src/tactic/arith/card2bv_tactic.h index d5e110cf3..925e6d0d2 100644 --- a/src/tactic/arith/card2bv_tactic.h +++ b/src/tactic/arith/card2bv_tactic.h @@ -39,6 +39,9 @@ namespace pb { br_status mk_shannon(func_decl * f, unsigned sz, expr * const* args, expr_ref & result); expr* negate(expr* e); expr* mk_ite(expr* c, expr* hi, expr* lo); + bool is_or(func_decl* f); + bool is_and(func_decl* f); + public: card2bv_rewriter(ast_manager& m); br_status mk_app_core(func_decl * f, unsigned sz, expr * const* args, expr_ref & result); From f151879c0bb3b78155455893b3efc377a18500a6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 9 Sep 2014 16:25:41 -0700 Subject: [PATCH 519/925] enable neat vs. less neat pretty priting as an option Signed-off-by: Nikolaj Bjorner --- src/api/python/z3printer.py | 2 + src/opt/opt_context.cpp | 9 +++- src/opt/opt_context.h | 1 + src/opt/opt_params.pyg | 1 + src/smt/smt_internalizer.cpp | 2 +- src/smt/smt_setup.cpp | 14 ++++++- src/smt/theory_arith.h | 9 +++- src/smt/theory_arith_core.h | 73 +++++++++++++++++++++++++-------- src/smt/theory_diff_logic_def.h | 9 ++++ 9 files changed, 98 insertions(+), 22 deletions(-) diff --git a/src/api/python/z3printer.py b/src/api/python/z3printer.py index d1d85d30e..bd4c72477 100644 --- a/src/api/python/z3printer.py +++ b/src/api/python/z3printer.py @@ -842,6 +842,8 @@ class Formatter: return self.pp_seq(a.assertions(), 0, []) elif isinstance(a, z3.Fixedpoint): return a.sexpr() + elif isinstance(a, z3.Optimize): + return a.sexpr() elif isinstance(a, z3.ApplyResult): return self.pp_seq_seq(a, 0, []) elif isinstance(a, z3.ModelRef): diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 79986067e..db373494a 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -38,6 +38,7 @@ Notes: #include "inc_sat_solver.h" #include "bv_decl_plugin.h" #include "pb_decl_plugin.h" +#include "ast_smt_pp.h" namespace opt { @@ -122,7 +123,8 @@ namespace opt { m_fm(m), m_objective_refs(m), m_enable_sat(false), - m_enable_sls(false) + m_enable_sls(false), + m_pp_neat(false) { params_ref p; p.set_bool("model", true); @@ -1063,6 +1065,7 @@ namespace opt { m_enable_sat = _p.enable_sat(); m_enable_sls = _p.enable_sls(); m_maxsat_engine = _p.maxsat_engine(); + m_pp_neat = _p.pp_neat(); } typedef obj_hashtable func_decl_set; @@ -1095,9 +1098,11 @@ namespace opt { std::string context::to_string() const { smt2_pp_environment_dbg env(m); + ast_smt_pp ll_smt2_pp(m); free_func_visitor visitor(m); std::ostringstream out; #define PP(_e_) ast_smt2_pp(out, _e_, env); +#define PPE(_e_) if (m_pp_neat) ast_smt2_pp(out, _e_, env); else ll_smt2_pp.display_expr_smt2(out, _e_); for (unsigned i = 0; i < m_scoped_state.m_hard.size(); ++i) { visitor.collect(m_scoped_state.m_hard[i]); } @@ -1132,7 +1137,7 @@ namespace opt { } for (unsigned i = 0; i < m_scoped_state.m_hard.size(); ++i) { out << "(assert "; - PP(m_scoped_state.m_hard[i]); + PPE(m_scoped_state.m_hard[i]); out << ")\n"; } for (unsigned i = 0; i < m_scoped_state.m_objectives.size(); ++i) { diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index bbecb4996..a22c18373 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -127,6 +127,7 @@ namespace opt { tactic_ref m_simplify; bool m_enable_sat; bool m_enable_sls; + bool m_pp_neat; symbol m_maxsat_engine; symbol m_logic; public: diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index fd291336c..9d20dcb33 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -10,6 +10,7 @@ def_module_params('opt', ('enable_sls', BOOL, False, 'enable SLS tuning during weighted maxsast'), ('enable_sat', BOOL, False, 'enable the new SAT core for propositional constraints'), ('elim_01', BOOL, True, 'eliminate 01 variables'), + ('pp.neat', BOOL, True, 'use neat (as opposed to less readable, but faster) pretty printer when displaying context'), ('pb.compile_equality', BOOL, False, 'compile arithmetical equalities into pseudo-Boolean equality (instead of two inequalites)'), ('maxres.hill_climb', BOOL, True, 'give preference for large weight cores'), ('maxres.add_upper_bound_block', BOOL, False, 'restict upper bound with constraint'), diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index bfe1a3bb1..74f2e09fa 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -814,7 +814,7 @@ namespace smt { */ bool_var context::mk_bool_var(expr * n) { SASSERT(!b_internalized(n)); - SASSERT(!m_manager.is_not(n)); + //SASSERT(!m_manager.is_not(n)); unsigned id = n->get_id(); bool_var v = m_b_internalized_stack.size(); #ifndef _EXTERNAL_RELEASE diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index a392f8959..092db9f1a 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -411,6 +411,15 @@ namespace smt { return; } } +#if 0 + switch (m_params.m_arith_mode) { + case AS_DIFF_LOGIC: + case AS_DENSE_DIFF_LOGIC: + case AS_UTVPI: + setup_arith(); + return; + } +#endif m_params.m_arith_eq_bounds = true; m_params.m_phase_selection = PS_ALWAYS_FALSE; m_params.m_restart_strategy = RS_GEOMETRIC; @@ -420,7 +429,7 @@ namespace smt { m_context.register_plugin(alloc(smt::theory_mi_arith, m_manager, m_params)); } // else if (st.m_arith_k_sum < rational(INT_MAX / 8)) - // m_context.register_plugin(alloc(smt::theory_si_arith, m_manager, m_params)); + // m_context.register_plugin(alloc(smt::theory_dense_si, m_manager, m_params)); else m_context.register_plugin(alloc(smt::theory_i_arith, m_manager, m_params)); } @@ -703,6 +712,7 @@ namespace smt { m_context.register_plugin(alloc(smt::theory_dummy, m_manager.mk_family_id("arith"), "no arithmetic")); break; case AS_DIFF_LOGIC: + m_params.m_arith_expand_eqs = true; if (m_params.m_arith_fixnum) { if (m_params.m_arith_int_only) m_context.register_plugin(alloc(smt::theory_fidl, m_manager, m_params)); @@ -717,6 +727,7 @@ namespace smt { } break; case AS_DENSE_DIFF_LOGIC: + m_params.m_arith_expand_eqs = true; if (m_params.m_arith_fixnum) { if (m_params.m_arith_int_only) m_context.register_plugin(alloc(smt::theory_dense_si, m_manager, m_params)); @@ -731,6 +742,7 @@ namespace smt { } break; case AS_UTVPI: + m_params.m_arith_expand_eqs = true; if (m_params.m_arith_int_only) m_context.register_plugin(alloc(smt::theory_iutvpi, m_manager)); else diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 638d3c6b0..1c38ca343 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -578,10 +578,15 @@ namespace smt { void flush_bound_axioms(); typename atoms::iterator next_sup(atom* a1, atom_kind kind, typename atoms::iterator it, - typename atoms::iterator end); + typename atoms::iterator end, + bool& found_compatible); typename atoms::iterator next_inf(atom* a1, atom_kind kind, typename atoms::iterator it, - typename atoms::iterator end); + typename atoms::iterator end, + bool& found_compatible); + typename atoms::iterator first(atom_kind kind, + typename atoms::iterator it, + typename atoms::iterator end); struct compare_atoms { bool operator()(atom* a1, atom* a2) const { return a1->get_k() < a2->get_k(); } }; diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 3f6597a37..f5f446095 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -810,6 +810,8 @@ namespace smt { template void theory_arith::mk_bound_axioms(atom * a1) { + theory_var v = a1->get_var(); + atoms & occs = m_var_occs[v]; if (!get_context().is_searching()) { // // NB. We make an assumption that user push calls propagation @@ -819,11 +821,9 @@ namespace smt { m_new_atoms.push_back(a1); return; } - theory_var v = a1->get_var(); inf_numeral const & k1(a1->get_k()); atom_kind kind1 = a1->get_atom_kind(); TRACE("mk_bound_axioms", tout << "making bound axioms for v" << v << " " << kind1 << " " << k1 << "\n";); - atoms & occs = m_var_occs[v]; typename atoms::iterator it = occs.begin(); typename atoms::iterator end = occs.end(); @@ -874,6 +874,9 @@ namespace smt { parameter coeffs[3] = { parameter(symbol("farkas")), parameter(rational(1)), parameter(rational(1)) }; + //std::cout << "v" << v << " " << ((kind1==A_LOWER)?"<= ":">= ") << k1 << "\t "; + //std::cout << "v" << v << " " << ((kind2==A_LOWER)?"<= ":">= ") << k2 << "\n"; + if (kind1 == A_LOWER) { if (kind2 == A_LOWER) { if (k2 <= k1) { @@ -944,39 +947,74 @@ namespace smt { std::sort(atoms.begin(), atoms.end(), compare_atoms()); std::sort(occs.begin(), occs.end(), compare_atoms()); - typename atoms::iterator begin = occs.begin(); + typename atoms::iterator begin1 = occs.begin(); + typename atoms::iterator begin2 = occs.begin(); typename atoms::iterator end = occs.end(); - typename atoms::iterator lo_inf = begin, lo_sup = begin; - typename atoms::iterator hi_inf = begin, hi_sup = begin; + begin1 = first(A_LOWER, begin1, end); + begin2 = first(A_UPPER, begin2, end); + typename atoms::iterator lo_inf = begin1, lo_sup = begin1; + typename atoms::iterator hi_inf = begin2, hi_sup = begin2; + typename atoms::iterator lo_inf1 = begin1, lo_sup1 = begin1; + typename atoms::iterator hi_inf1 = begin2, hi_sup1 = begin2; + bool flo_inf, fhi_inf, flo_sup, fhi_sup; + //std::cout << atoms.size() << "\n"; + ptr_addr_hashtable visited; for (unsigned i = 0; i < atoms.size(); ++i) { atom* a1 = atoms[i]; - lo_inf = next_inf(a1, A_LOWER, lo_inf, end); - hi_inf = next_inf(a1, A_UPPER, hi_inf, end); - lo_sup = next_sup(a1, A_LOWER, lo_sup, end); - hi_sup = next_sup(a1, A_UPPER, hi_sup, end); - if (lo_inf != end) mk_bound_axiom(a1, *lo_inf); - if (lo_sup != end) mk_bound_axiom(a1, *lo_sup); - if (hi_inf != end) mk_bound_axiom(a1, *hi_inf); - if (hi_sup != end) mk_bound_axiom(a1, *hi_sup); + lo_inf1 = next_inf(a1, A_LOWER, lo_inf, end, flo_inf); + hi_inf1 = next_inf(a1, A_UPPER, hi_inf, end, fhi_inf); + lo_sup1 = next_sup(a1, A_LOWER, lo_sup, end, flo_sup); + hi_sup1 = next_sup(a1, A_UPPER, hi_sup, end, fhi_sup); + //std::cout << "v" << a1->get_var() << ((a1->get_atom_kind()==A_LOWER)?" <= ":" >= ") << a1->get_k() << "\n"; + //std::cout << (lo_inf1 != end) << " " << (lo_sup1 != end) << " " << (hi_inf1 != end) << " " << (hi_sup1 != end) << "\n"; + if (lo_inf1 != end) lo_inf = lo_inf1; + if (lo_sup1 != end) lo_sup = lo_sup1; + if (hi_inf1 != end) hi_inf = hi_inf1; + if (hi_sup1 != end) hi_sup = hi_sup1; + if (!flo_inf) lo_inf = end; + if (!fhi_inf) hi_inf = end; + if (!flo_sup) lo_sup = end; + if (!fhi_sup) hi_sup = end; + visited.insert(a1); + if (lo_inf1 != end && lo_inf != end && !visited.contains(*lo_inf)) mk_bound_axiom(a1, *lo_inf); + if (lo_sup1 != end && lo_sup != end && !visited.contains(*lo_sup)) mk_bound_axiom(a1, *lo_sup); + if (hi_inf1 != end && hi_inf != end && !visited.contains(*hi_inf)) mk_bound_axiom(a1, *hi_inf); + if (hi_sup1 != end && hi_sup != end && !visited.contains(*hi_sup)) mk_bound_axiom(a1, *hi_sup); } } } + template + typename theory_arith::atoms::iterator + theory_arith::first( + atom_kind kind, + typename atoms::iterator it, + typename atoms::iterator end) { + for (; it != end; ++it) { + atom* a = *it; + if (a->get_atom_kind() == kind) return it; + } + return end; + } + template typename theory_arith::atoms::iterator theory_arith::next_inf( atom* a1, atom_kind kind, typename atoms::iterator it, - typename atoms::iterator end) { + typename atoms::iterator end, + bool& found_compatible) { inf_numeral const & k1(a1->get_k()); typename atoms::iterator result = end; + found_compatible = false; for (; it != end; ++it) { atom * a2 = *it; if (a1 == a2) continue; if (a2->get_atom_kind() != kind) continue; inf_numeral const & k2(a2->get_k()); + found_compatible = true; if (k2 <= k1) { result = it; } @@ -993,14 +1031,17 @@ namespace smt { atom* a1, atom_kind kind, typename atoms::iterator it, - typename atoms::iterator end) { + typename atoms::iterator end, + bool& found_compatible) { inf_numeral const & k1(a1->get_k()); + found_compatible = false; for (; it != end; ++it) { atom * a2 = *it; if (a1 == a2) continue; if (a2->get_atom_kind() != kind) continue; inf_numeral const & k2(a2->get_k()); - if (k2 > k1) { + found_compatible = true; + if (k1 < k2) { return it; } } diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index 7189ee219..85f7f948a 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -722,6 +722,7 @@ theory_var theory_diff_logic::mk_term(app* n) { app* a, *offset; theory_var source, target; enode* e; + context& ctx = get_context(); TRACE("arith", tout << mk_pp(n, get_manager()) << "\n";); @@ -732,6 +733,13 @@ theory_var theory_diff_logic::mk_term(app* n) { else if (is_offset(n, a, offset, r)) { // n = a + k source = mk_var(a); + for (unsigned i = 0; i < n->get_num_args(); ++i) { + expr* arg = n->get_arg(i); + std::cout << "internalize: " << mk_pp(arg, get_manager()) << " " << ctx.e_internalized(arg) << "\n"; + if (!ctx.e_internalized(arg)) { + ctx.internalize(arg, false); + } + } e = get_context().mk_enode(n, false, false, true); target = mk_var(e); numeral k(r); @@ -779,6 +787,7 @@ theory_var theory_diff_logic::mk_num(app* n, rational const& r) { } else { theory_var zero = get_zero(); + SASSERT(n->get_num_args() == 0); e = ctx.mk_enode(n, false, false, true); v = mk_var(e); // internalizer is marking enodes as interpreted whenever the associated ast is a value and a constant. From 72f09e47291a1bb4511b9cc058a86a1607f624ce Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 9 Sep 2014 16:57:43 -0700 Subject: [PATCH 520/925] better verbose pretty printing Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 8 ++--- src/opt/opt_context.h | 2 +- src/opt/optsmt.cpp | 73 +++++++---------------------------------- src/opt/optsmt.h | 6 ++-- 4 files changed, 18 insertions(+), 71 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index db373494a..27185228d 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -255,9 +255,9 @@ namespace opt { } } - lbool context::execute_min_max(unsigned index, bool committed, bool scoped) { + lbool context::execute_min_max(unsigned index, bool committed, bool scoped, bool is_max) { if (scoped) get_solver().push(); - lbool result = m_optsmt.lex(index); + lbool result = m_optsmt.lex(index, is_max); if (result == l_true) m_optsmt.get_model(m_model); if (scoped) get_solver().pop(1); if (result == l_true && committed) m_optsmt.commit_assignment(index); @@ -277,8 +277,8 @@ namespace opt { lbool context::execute(objective const& obj, bool committed, bool scoped) { switch(obj.m_type) { - case O_MAXIMIZE: return execute_min_max(obj.m_index, committed, scoped); - case O_MINIMIZE: return execute_min_max(obj.m_index, committed, scoped); + case O_MAXIMIZE: return execute_min_max(obj.m_index, committed, scoped, true); + case O_MINIMIZE: return execute_min_max(obj.m_index, committed, scoped, false); case O_MAXSMT: return execute_maxsat(obj.m_id, committed, scoped); default: UNREACHABLE(); return l_undef; } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index a22c18373..09ddb725a 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -189,7 +189,7 @@ namespace opt { void validate_feasibility(maxsmt& ms); lbool execute(objective const& obj, bool committed, bool scoped); - lbool execute_min_max(unsigned index, bool committed, bool scoped); + lbool execute_min_max(unsigned index, bool committed, bool scoped, bool is_max); lbool execute_maxsat(symbol const& s, bool committed, bool scoped); lbool execute_lex(); lbool execute_box(); diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 0a441755b..6cc6eeeab 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -15,7 +15,6 @@ Author: Notes: - Suppose we obtain solution t1 = k1, ..., tn = kn-epsilon Assert: t1 > k1 \/ t2 > k2 \/ ... \/ tn >= kn @@ -24,15 +23,7 @@ Notes: Claim: we don't necessarily have to freeze assignments of t_i when optimizing assignment for t_j because the state will always satisfy the disjunction. - If one of the k_i is unbounded, then omit a disjunction for it. - Claim: the end result (when the constraints are no longer feasible) - is Pareto optimal, but convergence will probably not be as fast - as when fixing one parameter at a time. - E.g., a different approach is first to find a global maximal for one - variable. Then add a method to "freeze" that variable at the extremum if it is finite. - To do this, add lower and upper bounds for that variable using infinitesimals. - If the variable is unbounded, then this is of course not sufficient by itself. - + If one of the k_i is unbounded, then omit a disjunction for it. --*/ @@ -234,14 +225,14 @@ namespace opt { } } - lbool optsmt::lex(unsigned obj_index) { + lbool optsmt::lex(unsigned obj_index, bool is_maximize) { TRACE("opt", tout << "optsmt:lex\n";); solver::scoped_push _push(*m_s); SASSERT(obj_index < m_vars.size()); - return basic_lex(obj_index); + return basic_lex(obj_index, is_maximize); } - lbool optsmt::basic_lex(unsigned obj_index) { + lbool optsmt::basic_lex(unsigned obj_index, bool is_maximize) { lbool is_sat = l_true; expr_ref block(m), tmp(m); @@ -253,8 +244,13 @@ namespace opt { m_s->get_model(m_model); inf_eps obj = m_s->get_objective_value(obj_index); if (obj > m_lower[obj_index]) { - m_lower[obj_index] = obj; - IF_VERBOSE(1, verbose_stream() << "(optsmt lower bound: " << obj << ")\n";); + m_lower[obj_index] = obj; + IF_VERBOSE(1, + if (is_maximize) + verbose_stream() << "(optsmt lower bound: " << obj << ")\n"; + else + verbose_stream() << "(optsmt upper bound: " << (-obj) << ")\n"; + ); for (unsigned i = obj_index+1; i < m_vars.size(); ++i) { m_s->maximize_objective(i, tmp); m_lower[i] = m_s->get_objective_value(i); @@ -281,53 +277,6 @@ namespace opt { } - lbool optsmt::pareto(unsigned obj_index) { - lbool is_sat = l_true; - expr_ref block(m); - for (unsigned i = 0; i < m_lower.size(); ++i) { - m_lower[i] = inf_eps(rational(-1),inf_rational(0)); - m_upper[i] = inf_eps(rational(1), inf_rational(0)); - } - bool was_sat = false; - - while (is_sat == l_true && !m_cancel) { - is_sat = m_s->check_sat(0, 0); - if (is_sat != l_true) break; - was_sat = true; - m_s->maximize_objective(obj_index, block); - m_s->get_model(m_model); - inf_eps obj = m_s->get_objective_value(obj_index); - if (obj > m_lower[obj_index]) { - m_lower[obj_index] = obj; - IF_VERBOSE(1, verbose_stream() << "(optsmt lower bound: " << obj << ")\n";); - } - m_s->assert_expr(block); - } - - if (m_cancel || is_sat == l_undef) { - return l_undef; - } - if (!was_sat) { - return l_false; - } - - // set the solution tight. - // and set lower bounds on other values. - m_upper[obj_index] = m_lower[obj_index]; - expr_ref val(m); - rational r; - arith_util a(m); - for (unsigned i = 0; i < m_lower.size(); ++i) { - if (i != obj_index) { - VERIFY(m_model->eval(m_objs[i].get(), val) && a.is_numeral(val, r)); - m_lower[i] = inf_eps(r); - } - } - - return l_true; - } - - /** Takes solver with hard constraints added. Returns an optimal assignment to objective functions. diff --git a/src/opt/optsmt.h b/src/opt/optsmt.h index 5f4a2988f..95e24a439 100644 --- a/src/opt/optsmt.h +++ b/src/opt/optsmt.h @@ -44,9 +44,7 @@ namespace opt { lbool box(); - lbool lex(unsigned obj_index); - - lbool pareto(unsigned obj_index); + lbool lex(unsigned obj_index, bool is_maximize); unsigned add(app* t); @@ -69,7 +67,7 @@ namespace opt { lbool basic_opt(); - lbool basic_lex(unsigned idx); + lbool basic_lex(unsigned idx, bool is_maximize); lbool farkas_opt(); From 019ff77613990f6f552254cf51a5eb09325d6bad Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 11 Sep 2014 18:47:21 -0700 Subject: [PATCH 521/925] fix sorting network bug, add network compilation,... Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 16 +++++ src/ast/ast.h | 3 + src/ast/pb_decl_plugin.cpp | 9 +++ src/ast/pb_decl_plugin.h | 3 + src/opt/maxres.cpp | 6 +- src/opt/opt_context.cpp | 34 ++++----- src/opt/opt_context.h | 13 ++-- src/opt/opt_solver.h | 27 ++++++++ src/smt/theory_arith_core.h | 6 +- src/smt/theory_pb.cpp | 6 +- src/tactic/arith/card2bv_tactic.cpp | 81 ++++++++++++++++++++-- src/tactic/arith/card2bv_tactic.h | 42 ++++++++++-- src/test/hilbert_basis.cpp | 2 +- src/test/sorting_network.cpp | 99 +++++++++++++++++++++++++- src/util/sorting_network.h | 103 ++++++++++++++-------------- 15 files changed, 350 insertions(+), 100 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 68f7596ee..0915ae1b6 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -2058,6 +2058,22 @@ app * ast_manager::mk_app(func_decl * decl, unsigned num_args, expr * const * ar return r; } +expr* ast_manager::mk_or_reduced(unsigned n, expr* const* args) { + switch (n) { + case 0: return mk_false(); + case 1: return args[0]; + default: return mk_or(n, args); + } +} + +expr* ast_manager::mk_and_reduced(unsigned n, expr* const* args) { + switch (n) { + case 0: return mk_true(); + case 1: return args[0]; + default: return mk_and(n, args); + } +} + func_decl * ast_manager::mk_fresh_func_decl(symbol const & prefix, symbol const & suffix, unsigned arity, sort * const * domain, sort * range) { func_decl_info info(null_family_id, null_decl_kind); diff --git a/src/ast/ast.h b/src/ast/ast.h index 68f08e1ac..f8ba43554 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -2004,6 +2004,9 @@ public: app * mk_true() { return m_true; } app * mk_false() { return m_false; } app * mk_interp(expr * arg) { return mk_app(m_basic_family_id, OP_INTERP, arg); } + expr * mk_or_reduced(unsigned num_args, expr * const * args); + expr * mk_and_reduced(unsigned num_args, expr * const * args); + func_decl* mk_and_decl() { sort* domain[2] = { m_bool_sort, m_bool_sort }; diff --git a/src/ast/pb_decl_plugin.cpp b/src/ast/pb_decl_plugin.cpp index 0cfe1c096..36103c4f0 100644 --- a/src/ast/pb_decl_plugin.cpp +++ b/src/ast/pb_decl_plugin.cpp @@ -271,3 +271,12 @@ rational pb_util::to_rational(parameter const& p) const { SASSERT(p.is_rational()); return p.get_rational(); } + +bool pb_util::has_unit_coefficients(func_decl* f) const { + if (is_at_most_k(f) || is_at_least_k(f)) return true; + unsigned sz = f->get_arity(); + for (unsigned i = 0; i < sz; ++i) { + if (!get_coeff(f, i).is_one()) return false; + } + return true; +} diff --git a/src/ast/pb_decl_plugin.h b/src/ast/pb_decl_plugin.h index 8ecf0f259..0bc8eab17 100644 --- a/src/ast/pb_decl_plugin.h +++ b/src/ast/pb_decl_plugin.h @@ -103,6 +103,9 @@ public: bool is_ge(expr* a, rational& k) const; rational get_coeff(expr* a, unsigned index) const { return get_coeff(to_app(a)->get_decl(), index); } rational get_coeff(func_decl* a, unsigned index) const; + bool has_unit_coefficients(func_decl* f) const; + bool has_unit_coefficients(expr* f) const { return is_app(f) && has_unit_coefficients(to_app(f)->get_decl()); } + bool is_eq(func_decl* f) const; bool is_eq(expr* e) const { return is_app(e) && is_eq(to_app(e)->get_decl()); } diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index f879c8934..48dbb410b 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -397,8 +397,12 @@ public: */ sort_assumptions(asms); unsigned index = 0; + unsigned last_index = 0; while (index < asms.size() && is_sat != l_false) { - index = next_index(asms, index); + while (asms.size() > 10*(index - last_index) && index < asms.size()) { + index = next_index(asms, index); + } + last_index = index; is_sat = s().check_sat(index, asms.c_ptr()); } } diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 27185228d..ca4b40740 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -69,7 +69,6 @@ namespace opt { m_objectives_lim.pop_back(); m_hard_lim.pop_back(); } - void context::scoped_state::add(expr* hard) { m_hard.push_back(hard); @@ -608,7 +607,7 @@ namespace opt { for (unsigned i = 0; i < a->get_num_args(); ++i) { expr* arg = a->get_arg(i); if (m.is_true(arg)) { - + // skip } else if (m.is_false(arg)) { offset += m_objectives[index].m_weights[i]; @@ -764,8 +763,8 @@ namespace opt { SASSERT(obj.m_id == id); obj.m_terms.reset(); obj.m_terms.append(terms); - obj.m_offset = offset; - obj.m_neg = neg; + obj.m_adjust_bound.set_offset(offset); + obj.m_adjust_bound.set_negate(neg); TRACE("opt", tout << "maxsat: " << id << " offset:" << offset << "\n";); } else if (is_maximize(fml, tr, orig_term, index)) { @@ -835,23 +834,23 @@ namespace opt { switch(obj.m_type) { case O_MINIMIZE: if (m_model->eval(obj.m_term, val) && is_numeral(val, r)) { - r += obj.m_offset; + inf_eps val = obj.m_adjust_bound.neg_add(r); if (is_lower) { - m_optsmt.update_lower(obj.m_index, inf_eps(-r), override); + m_optsmt.update_lower(obj.m_index, val, override); } else { - m_optsmt.update_upper(obj.m_index, inf_eps(-r), override); + m_optsmt.update_upper(obj.m_index, val, override); } } break; case O_MAXIMIZE: if (m_model->eval(obj.m_term, val) && is_numeral(val, r)) { - r += obj.m_offset; + inf_eps val = obj.m_adjust_bound.neg_add(r); if (is_lower) { - m_optsmt.update_lower(obj.m_index, inf_eps(r), override); + m_optsmt.update_lower(obj.m_index, val, override); } else { - m_optsmt.update_upper(obj.m_index, inf_eps(r), override); + m_optsmt.update_upper(obj.m_index, val, override); } } break; @@ -921,10 +920,7 @@ namespace opt { switch(obj.m_type) { case O_MAXSMT: { rational r = m_maxsmts.find(obj.m_id)->get_lower(); - TRACE("opt", tout << "maxsmt: " << r << " negate: " << obj.m_neg << " offset: " << obj.m_offset << "\n";); - if (obj.m_neg) r.neg(); - r += obj.m_offset; - return inf_eps(r); + return obj.m_adjust_bound.neg_add(r); } case O_MINIMIZE: return -m_optsmt.get_upper(obj.m_index); @@ -942,13 +938,9 @@ namespace opt { } objective const& obj = m_objectives[idx]; switch(obj.m_type) { - case O_MAXSMT: { - rational r = m_maxsmts.find(obj.m_id)->get_upper(); - TRACE("opt", tout << "maxsmt: " << r << " negate: " << obj.m_neg << " offset: " << obj.m_offset << "\n";); - if (obj.m_neg) r.neg(); - r += obj.m_offset; - return inf_eps(r); - } + case O_MAXSMT: + return obj.m_adjust_bound.neg_add(m_maxsmts.find(obj.m_id)->get_upper()); + // TBD: adjust bound case O_MINIMIZE: return -m_optsmt.get_lower(obj.m_index); case O_MAXIMIZE: diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 09ddb725a..051729aff 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -51,8 +51,7 @@ namespace opt { app_ref m_term; // for maximize, minimize term expr_ref_vector m_terms; // for maxsmt vector m_weights; // for maxsmt - rational m_offset; // for maxsmt - bool m_neg; // negate + bound_adjustment m_adjust_bound; symbol m_id; // for maxsmt unsigned m_index; // for maximize/minimize index @@ -60,18 +59,18 @@ namespace opt { m_type(is_max?O_MAXIMIZE:O_MINIMIZE), m_term(t), m_terms(t.get_manager()), - m_offset(0), - m_neg(false), m_id(), m_index(idx) - {} + { + if (!is_max) { + m_adjust_bound.set_negate(true); + } + } objective(ast_manager& m, symbol id): m_type(O_MAXSMT), m_term(m), m_terms(m), - m_offset(0), - m_neg(false), m_id(id), m_index(0) {} diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 07f2e756b..0e59a9eb9 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -36,6 +36,33 @@ namespace opt { typedef inf_eps_rational inf_eps; + // Adjust bound bound |-> (m_negate?-1:1)*(m_offset + bound) + class bound_adjustment { + rational m_offset; + bool m_negate; + public: + bound_adjustment(rational const& offset, bool neg): + m_offset(offset), + m_negate(neg) + {} + bound_adjustment(): m_offset(0), m_negate(false) {} + void set_offset(rational const& o) { m_offset = o; } + void set_negate(bool neg) { m_negate = neg; } + rational const& get_offset() const { return m_offset; } + bool get_negate() { return m_negate; } + inf_eps add_neg(rational const& r) const { + rational result = r + m_offset; + if (m_negate) result.neg(); + return inf_eps(result); + } + inf_eps neg_add(rational const& r) const { + rational result = r; + if (m_negate) result.neg(); + result += m_offset; + return inf_eps(result); + } + }; + class opt_solver : public solver_na2as { private: diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index f5f446095..3d95f1c72 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -958,7 +958,7 @@ namespace smt { typename atoms::iterator lo_inf1 = begin1, lo_sup1 = begin1; typename atoms::iterator hi_inf1 = begin2, hi_sup1 = begin2; bool flo_inf, fhi_inf, flo_sup, fhi_sup; - //std::cout << atoms.size() << "\n"; + // std::cout << atoms.size() << "\n"; ptr_addr_hashtable visited; for (unsigned i = 0; i < atoms.size(); ++i) { atom* a1 = atoms[i]; @@ -966,8 +966,8 @@ namespace smt { hi_inf1 = next_inf(a1, A_UPPER, hi_inf, end, fhi_inf); lo_sup1 = next_sup(a1, A_LOWER, lo_sup, end, flo_sup); hi_sup1 = next_sup(a1, A_UPPER, hi_sup, end, fhi_sup); - //std::cout << "v" << a1->get_var() << ((a1->get_atom_kind()==A_LOWER)?" <= ":" >= ") << a1->get_k() << "\n"; - //std::cout << (lo_inf1 != end) << " " << (lo_sup1 != end) << " " << (hi_inf1 != end) << " " << (hi_sup1 != end) << "\n"; +// std::cout << "v" << a1->get_var() << ((a1->get_atom_kind()==A_LOWER)?" <= ":" >= ") << a1->get_k() << "\n"; + // std::cout << (lo_inf1 != end) << " " << (lo_sup1 != end) << " " << (hi_inf1 != end) << " " << (hi_sup1 != end) << "\n"; if (lo_inf1 != end) lo_inf = lo_inf1; if (lo_sup1 != end) lo_sup = lo_sup1; if (hi_inf1 != end) hi_inf = hi_inf1; diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 7570a73c5..b8a5e7bd1 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1156,7 +1156,7 @@ namespace smt { return literal(ctx.mk_bool_var(y)); } - literal max(literal a, literal b) { + literal mk_max(literal a, literal b) { if (a == b) return a; expr_ref t1(m), t2(m), t3(m); ctx.literal2expr(a, t1); @@ -1166,7 +1166,7 @@ namespace smt { return literal(v); } - literal min(literal a, literal b) { + literal mk_min(literal a, literal b) { if (a == b) return a; expr_ref t1(m), t2(m), t3(m); ctx.literal2expr(a, t1); @@ -1176,6 +1176,8 @@ namespace smt { return literal(v); } + literal mk_not(literal a) { return ~a; } + void mk_clause(unsigned n, literal const* ls) { literal_vector tmp(n, ls); ctx.mk_clause(n, tmp.c_ptr(), 0, CLS_AUX, 0); diff --git a/src/tactic/arith/card2bv_tactic.cpp b/src/tactic/arith/card2bv_tactic.cpp index 55f50fbb2..3d112e36f 100644 --- a/src/tactic/arith/card2bv_tactic.cpp +++ b/src/tactic/arith/card2bv_tactic.cpp @@ -39,8 +39,55 @@ namespace pb { m(m), au(m), pb(m), - bv(m) + bv(m), + m_sort(*this), + m_lemmas(m), + m_trail(m) {} + + void card2bv_rewriter::mk_assert(func_decl * f, unsigned sz, expr * const* args, expr_ref & result, expr_ref_vector& lemmas) { + m_lemmas.reset(); + SASSERT(f->get_family_id() == pb.get_family_id()); + if (is_or(f)) { + result = m.mk_or(sz, args); + } + else if (is_and(f)) { + result = m.mk_and(sz, args); + } + else if (pb.is_eq(f) && pb.get_k(f).is_unsigned() && pb.has_unit_coefficients(f)) { + result = m_sort.eq(pb.get_k(f).get_unsigned(), sz, args); + } + else if (pb.is_le(f) && pb.get_k(f).is_unsigned() && pb.has_unit_coefficients(f)) { + result = m_sort.le(false, pb.get_k(f).get_unsigned(), sz, args); + } + else if (pb.is_ge(f) && pb.get_k(f).is_unsigned() && pb.has_unit_coefficients(f)) { + result = m_sort.ge(false, pb.get_k(f).get_unsigned(), sz, args); + } + else { + br_status st = mk_shannon(f, sz, args, result); + if (st == BR_FAILED) { + mk_bv(f, sz, args, result); + } + } + lemmas.append(m_lemmas); + } + + std::ostream& card2bv_rewriter::pp(std::ostream& out, literal lit) { + return out << mk_ismt2_pp(lit, m); + } + + card2bv_rewriter::literal card2bv_rewriter::trail(literal l) { + m_trail.push_back(l); + return l; + } + card2bv_rewriter::literal card2bv_rewriter::fresh() { + return trail(m.mk_fresh_const("sn", m.mk_bool_sort())); + } + + void card2bv_rewriter::mk_clause(unsigned n, literal const* lits) { + m_lemmas.push_back(m.mk_or_reduced(n, lits)); + } + br_status card2bv_rewriter::mk_app_core(func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { if (f->get_family_id() == null_family_id) { @@ -69,7 +116,8 @@ namespace pb { } br_status st = mk_shannon(f, sz, args, result); if (st == BR_FAILED) { - return mk_bv(f, sz, args, result); + mk_bv(f, sz, args, result); + return BR_DONE; } else { return st; @@ -135,7 +183,7 @@ namespace pb { return false; } - br_status card2bv_rewriter::mk_bv(func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { + void card2bv_rewriter::mk_bv(func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { expr_ref zero(m), a(m), b(m); expr_ref_vector es(m); unsigned bw = get_num_bits(f); @@ -172,7 +220,6 @@ namespace pb { default: UNREACHABLE(); } - return BR_DONE; } struct argc_t { @@ -352,10 +399,30 @@ namespace pb { if (m.is_true(lo)) return m.mk_implies(c, hi); return m.mk_ite(c, hi, lo); } + + void card_pb_rewriter::rewrite(expr* e, expr_ref& result) { + if (pb.is_eq(e)) { + app* a = to_app(e); + ast_manager& m = m_lemmas.get_manager(); + unsigned sz = a->get_num_args(); + expr_ref_vector args(m); + expr_ref tmp(m); + for (unsigned i = 0; i < sz; ++i) { + (*this)(a->get_arg(i), tmp); + args.push_back(tmp); + } + m_cfg.m_r.mk_assert(a->get_decl(), sz, args.c_ptr(), result, m_lemmas); + } + else { + (*this)(e, result); + } + } + }; template class rewriter_tpl; + class card2bv_tactic : public tactic { ast_manager & m; params_ref m_params; @@ -402,6 +469,7 @@ public: tactic_report report("card2bv", *g); m_rw1.reset(); m_rw2.reset(); + m_rw2.lemmas().reset(); if (g->inconsistent()) { result.push_back(g.get()); @@ -413,9 +481,12 @@ public: for (unsigned idx = 0; idx < size; idx++) { m_rw1(g->form(idx), new_f1); TRACE("card2bv", tout << "Rewriting " << mk_ismt2_pp(new_f1.get(), m) << std::endl;); - m_rw2(new_f1, new_f2); + m_rw2.rewrite(new_f1, new_f2); g->update(idx, new_f2, g->pr(idx), g->dep(idx)); } + for (unsigned i = 0; i < m_rw2.lemmas().size(); ++i) { + g->assert_expr(m_rw2.lemmas()[i].get()); + } g->inc_depth(); result.push_back(g.get()); diff --git a/src/tactic/arith/card2bv_tactic.h b/src/tactic/arith/card2bv_tactic.h index 925e6d0d2..ed96376b5 100644 --- a/src/tactic/arith/card2bv_tactic.h +++ b/src/tactic/arith/card2bv_tactic.h @@ -23,6 +23,9 @@ Notes: #include"pb_decl_plugin.h" #include"th_rewriter.h" #include"rewriter.h" +#include +#include"sorting_network.h" + class ast_manager; class tactic; @@ -30,12 +33,20 @@ class tactic; namespace pb { class card2bv_rewriter { + public: + typedef expr* literal; + typedef ptr_vector literal_vector; + private: ast_manager& m; arith_util au; pb_util pb; bv_util bv; + psort_nw m_sort; + expr_ref_vector m_lemmas; + expr_ref_vector m_trail; + unsigned get_num_bits(func_decl* f); - br_status mk_bv(func_decl * f, unsigned sz, expr * const* args, expr_ref & result); + void mk_bv(func_decl * f, unsigned sz, expr * const* args, expr_ref & result); br_status mk_shannon(func_decl * f, unsigned sz, expr * const* args, expr_ref & result); expr* negate(expr* e); expr* mk_ite(expr* c, expr* hi, expr* lo); @@ -45,6 +56,19 @@ namespace pb { public: card2bv_rewriter(ast_manager& m); br_status mk_app_core(func_decl * f, unsigned sz, expr * const* args, expr_ref & result); + void mk_assert(func_decl * f, unsigned sz, expr * const* args, expr_ref & result, expr_ref_vector& lemmas); + + // definitions used for sorting network + literal mk_false() { return m.mk_false(); } + literal mk_true() { return m.mk_true(); } + literal mk_max(literal a, literal b) { return trail(m.mk_or(a, b)); } + literal mk_min(literal a, literal b) { return trail(m.mk_and(a, b)); } + literal mk_not(literal a) { if (m.is_not(a,a)) return a; return trail(m.mk_not(a)); } + std::ostream& pp(std::ostream& out, literal lit); + literal fresh(); + literal trail(literal l); + void mk_clause(unsigned n, literal const* lits); + }; struct card2bv_rewriter_cfg : public default_rewriter_cfg { @@ -55,15 +79,23 @@ namespace pb { result_pr = 0; return m_r.mk_app_core(f, num, args, result); } - card2bv_rewriter_cfg(ast_manager & m):m_r(m) {} + card2bv_rewriter_cfg(ast_manager & m):m_r(m) {} }; class card_pb_rewriter : public rewriter_tpl { card2bv_rewriter_cfg m_cfg; + pb_util pb; + expr_ref_vector m_lemmas; public: - card_pb_rewriter(ast_manager & m): - rewriter_tpl(m, false, m_cfg), - m_cfg(m) {} + card_pb_rewriter(ast_manager & m): + rewriter_tpl(m, false, m_cfg), + m_cfg(m), + pb(m), + m_lemmas(m) {} + + void rewrite(expr* e, expr_ref& result); + + expr_ref_vector& lemmas() { return m_lemmas; } }; }; diff --git a/src/test/hilbert_basis.cpp b/src/test/hilbert_basis.cpp index 60af1eae8..6fdfb1560 100644 --- a/src/test/hilbert_basis.cpp +++ b/src/test/hilbert_basis.cpp @@ -556,7 +556,7 @@ static void test_A_5_5_3() { for (unsigned k = 1; k <= 5; ++k) { for (unsigned l = 1; l <= 5; ++l) { for (unsigned j = 1; j <= 3; ++j) { - bool one = ((j*k <= i) && (((i - j) % 3) == 0); // fixme + bool one = ((j*k <= i) && (((i - j) % 3) == 0)); // fixme v.push_back(rational(one)); } } diff --git a/src/test/sorting_network.cpp b/src/test/sorting_network.cpp index 5ae6362b1..8792a4795 100644 --- a/src/test/sorting_network.cpp +++ b/src/test/sorting_network.cpp @@ -1,9 +1,13 @@ - -#include "sorting_network.h" +#include "trace.h" #include "vector.h" #include "ast.h" #include "ast_pp.h" #include "reg_decl_plugins.h" +#include "sorting_network.h" +#include "smt_kernel.h" +#include "model_smt2_pp.h" +#include "smt_params.h" + struct ast_ext { @@ -26,6 +30,8 @@ struct ast_ext { } }; + + struct unsigned_ext { unsigned_ext() {} typedef unsigned T; @@ -41,6 +47,7 @@ struct unsigned_ext { } }; + static void is_sorted(svector const& v) { for (unsigned i = 0; i + 1 < v.size(); ++i) { SASSERT(v[i] <= v[i+1]); @@ -134,9 +141,97 @@ void test_sorting3() { } } + +struct ast_ext2 { + ast_manager& m; + expr_ref_vector m_clauses; + expr_ref_vector m_trail; + ast_ext2(ast_manager& m):m(m), m_clauses(m), m_trail(m) {} + typedef expr* literal; + typedef ptr_vector literal_vector; + + expr* trail(expr* e) { + m_trail.push_back(e); + return e; + } + + literal mk_false() { return m.mk_false(); } + literal mk_true() { return m.mk_true(); } + literal mk_max(literal a, literal b) { + return trail(m.mk_or(a, b)); + } + literal mk_min(literal a, literal b) { return trail(m.mk_and(a, b)); } + literal mk_not(literal a) { if (m.is_not(a,a)) return a; + return trail(m.mk_not(a)); + } + std::ostream& pp(std::ostream& out, literal lit) { + return out << mk_pp(lit, m); + } + literal fresh() { + return trail(m.mk_fresh_const("x", m.mk_bool_sort())); + } + void mk_clause(unsigned n, literal const* lits) { + m_clauses.push_back(m.mk_or_reduced(n, lits)); + } +}; + + +void test_sorting5(unsigned n, unsigned k) { + std::cout << "n: " << n << " k: " << k << "\n"; + SASSERT(k < n); + ast_manager m; + reg_decl_plugins(m); + ast_ext2 ext(m); + expr_ref_vector in(m), out(m); + for (unsigned i = 0; i < n; ++i) { + in.push_back(m.mk_fresh_const("a",m.mk_bool_sort())); + } + smt_params fp; + smt::kernel solver(m, fp); + psort_nw sn(ext); + expr_ref result(m); + result = sn.eq(k, in.size(), in.c_ptr()); + solver.assert_expr(result); + for (unsigned i = 0; i < ext.m_clauses.size(); ++i) { + solver.assert_expr(ext.m_clauses[i].get()); + } + lbool res = solver.check(); + SASSERT(res == l_true); + std::cout << res << "\n"; + + solver.push(); + for (unsigned i = 0; i < k; ++i) { + solver.assert_expr(in[i].get()); + } + res = solver.check(); + SASSERT(res == l_true); + solver.assert_expr(in[k].get()); + res = solver.check(); + if (res == l_true) { + TRACE("pb", + unsigned sz = solver.size(); + for (unsigned i = 0; i < sz; ++i) { + tout << mk_pp(solver.get_formulas()[i], m) << "\n"; + }); + model_ref model; + solver.get_model(model); + model_smt2_pp(std::cout, m, *model, 0); + TRACE("pb", model_smt2_pp(tout, m, *model, 0);); + } + SASSERT(res == l_false); + solver.pop(1); + +} + void tst_sorting_network() { test_sorting1(); test_sorting2(); test_sorting3(); test_sorting4(); + test_sorting5(7,6); + for (unsigned n = 3; n < 10; n += 2) { + for (unsigned k = 1; k < n; ++k) { + test_sorting5(n, k); + } + } } diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index f403f9e16..c2bdc600e 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -144,7 +144,7 @@ Notes: } }; - static vc min(vc const& v1, vc const& v2) { + static vc mk_min(vc const& v1, vc const& v2) { return (v1.to_int() < v2.to_int())?v1:v2; } @@ -205,7 +205,7 @@ Notes: SASSERT(2*k <= n); m_t = full?LE_FULL:LE; card(k + 1, n, xs, out); - return ~out[k]; + return ctx.mk_not(out[k]); } } @@ -219,11 +219,11 @@ Notes: return eq(k, n, in.c_ptr()); } else { - SASSERT(2*k < n); + SASSERT(2*k <= n); m_t = EQ; card(k+1, n, xs, out); SASSERT(out.size() >= k+1); - return out[k-1]; // & ~out[m] TBD + return ctx.mk_min(out[k-1], ctx.mk_not(out[k])); } } @@ -253,10 +253,10 @@ Notes: } k = N - k; for (unsigned i = 0; i < N; ++i) { - in.push_back(~xs[i]); + in.push_back(ctx.mk_not(xs[i])); } TRACE("pb", - pp(tout << N << ": ", in); + pp(tout << N << ": ", in); tout << " ~ " << k << "\n";); return true; } @@ -269,16 +269,16 @@ Notes: unsigned power2(unsigned n) const { SASSERT(n < 10); return 1 << n; } - literal max(literal a, literal b) { + literal mk_max(literal a, literal b) { if (a == b) return a; m_stats.m_num_compiled_vars++; - return ctx.max(a, b); + return ctx.mk_max(a, b); } - literal min(literal a, literal b) { + literal mk_min(literal a, literal b) { if (a == b) return a; m_stats.m_num_compiled_vars++; - return ctx.min(a, b); + return ctx.mk_min(a, b); } literal fresh() { @@ -299,20 +299,20 @@ Notes: ctx.mk_clause(n, tmp.c_ptr()); } - // y1 <= max(x1,x2) - // y2 <= min(x1,x2) + // y1 <= mk_max(x1,x2) + // y2 <= mk_min(x1,x2) void cmp_ge(literal x1, literal x2, literal y1, literal y2) { - add_clause(~y2, x1); - add_clause(~y2, x2); - add_clause(~y1, x1, x2); + add_clause(ctx.mk_not(y2), x1); + add_clause(ctx.mk_not(y2), x2); + add_clause(ctx.mk_not(y1), x1, x2); } - // max(x1,x2) <= y1 - // min(x1,x2) <= y2 + // mk_max(x1,x2) <= y1 + // mk_min(x1,x2) <= y2 void cmp_le(literal x1, literal x2, literal y1, literal y2) { - add_clause(~x1, y1); - add_clause(~x2, y1); - add_clause(~x1, ~x2, y2); + add_clause(ctx.mk_not(x1), y1); + add_clause(ctx.mk_not(x2), y1); + add_clause(ctx.mk_not(x1), ctx.mk_not(x2), y2); } void cmp_eq(literal x1, literal x2, literal y1, literal y2) { @@ -376,8 +376,8 @@ Notes: literal_vector& out) { TRACE("pb", tout << "merge a: " << a << " b: " << b << "\n";); if (a == 1 && b == 1) { - literal y1 = max(as[0], bs[0]); - literal y2 = min(as[0], bs[0]); + literal y1 = mk_max(as[0], bs[0]); + literal y2 = mk_min(as[0], bs[0]); out.push_back(y1); out.push_back(y2); psort_nw::cmp(as[0], bs[0], y1, y2); @@ -453,8 +453,8 @@ Notes: out.push_back(as[0]); unsigned sz = std::min(as.size()-1, bs.size()); for (unsigned i = 0; i < sz; ++i) { - literal y1 = max(as[i+1],bs[i]); - literal y2 = min(as[i+1],bs[i]); + literal y1 = mk_max(as[i+1],bs[i]); + literal y2 = mk_min(as[i+1],bs[i]); psort_nw::cmp(as[i+1], bs[i], y1, y2); out.push_back(y1); out.push_back(y2); @@ -539,16 +539,16 @@ Notes: literal_vector& out) { TRACE("pb", tout << "smerge: c:" << c << " a:" << a << " b:" << b << "\n";); if (a == 1 && b == 1 && c == 1) { - literal y = max(as[0], bs[0]); + literal y = mk_max(as[0], bs[0]); if (m_t != GE) { - // x1 <= max(x1,x2) - // x2 <= max(x1,x2) - add_clause(~as[0], y); - add_clause(~bs[0], y); + // x1 <= mk_max(x1,x2) + // x2 <= mk_max(x1,x2) + add_clause(ctx.mk_not(as[0]), y); + add_clause(ctx.mk_not(bs[0]), y); } if (m_t != LE) { - // max(x1,x2) <= x1, x2 - add_clause(~y, as[0], bs[0]); + // mk_max(x1,x2) <= x1, x2 + add_clause(ctx.mk_not(y), as[0], bs[0]); } out.push_back(y); } @@ -597,13 +597,13 @@ Notes: literal z2 = out2.back(); out1.pop_back(); out2.pop_back(); - y = max(z1, z2); + y = mk_max(z1, z2); if (m_t != GE) { - add_clause(~z1, y); - add_clause(~z2, y); + add_clause(ctx.mk_not(z1), y); + add_clause(ctx.mk_not(z2), y); } if (m_t != LE) { - add_clause(~y, z1, z2); + add_clause(ctx.mk_not(y), z1, z2); } } interleave(out1, out2, out); @@ -664,31 +664,28 @@ Notes: } if (m_t != GE) { for (unsigned i = 0; i < a; ++i) { - add_clause(~as[i], out[i]); + add_clause(ctx.mk_not(as[i]), out[i]); } for (unsigned i = 0; i < b; ++i) { - add_clause(~bs[i], out[i]); + add_clause(ctx.mk_not(bs[i]), out[i]); } for (unsigned i = 1; i <= a; ++i) { for (unsigned j = 1; j <= b && i + j <= c; ++j) { - add_clause(~as[i-1],~bs[j-1],out[i+j-1]); + add_clause(ctx.mk_not(as[i-1]),ctx.mk_not(bs[j-1]),out[i+j-1]); } } } if (m_t != LE) { - for (unsigned k = 1; k <= c; ++k) { - literal_vector ls; - ls.push_back(~out[k-1]); - if (k <= a) { - ls.push_back(as[k-1]); - } - if (k <= b) { - ls.push_back(bs[k-1]); - } - for (unsigned i = 1; i <= std::min(a,k-1); ++i) { - if (k + 1 - i <= b) { - ls.push_back(as[i-1]); - ls.push_back(bs[k-i]); + literal_vector ls; + for (unsigned k = 0; k < c; ++k) { + ls.reset(); + ls.push_back(ctx.mk_not(out[k])); + for (unsigned i = 0; i < std::min(a,k + 1); ++i) { + unsigned j = k - i; + SASSERT(i + j == k); + if (j < b) { + ls.push_back(as[i]); + ls.push_back(bs[j]); add_clause(ls.size(), ls.c_ptr()); ls.pop_back(); ls.pop_back(); @@ -726,7 +723,7 @@ Notes: } if (m_t != LE) { for (unsigned k = 1; k <= m; ++k) { - lits.push_back(~out[k-1]); + lits.push_back(ctx.mk_not(out[k-1])); add_subset(false, n-k+1, 0, lits, n, xs); lits.pop_back(); } @@ -754,7 +751,7 @@ Notes: return; } for (unsigned i = offset; i < n - k + 1; ++i) { - lits.push_back(polarity?~xs[i]:xs[i]); + lits.push_back(polarity?ctx.mk_not(xs[i]):xs[i]); add_subset(polarity, k-1, i+1, lits, n, xs); lits.pop_back(); } From e288b7795d788f102fe197635791870489585fa3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 11 Sep 2014 20:33:37 -0700 Subject: [PATCH 522/925] add to unit test Signed-off-by: Nikolaj Bjorner --- src/test/sorting_network.cpp | 112 +++++++++++++++++++++++++++++++++-- 1 file changed, 107 insertions(+), 5 deletions(-) diff --git a/src/test/sorting_network.cpp b/src/test/sorting_network.cpp index 8792a4795..2a6ba3666 100644 --- a/src/test/sorting_network.cpp +++ b/src/test/sorting_network.cpp @@ -176,8 +176,7 @@ struct ast_ext2 { }; -void test_sorting5(unsigned n, unsigned k) { - std::cout << "n: " << n << " k: " << k << "\n"; +static void test_sorting_eq(unsigned n, unsigned k) { SASSERT(k < n); ast_manager m; reg_decl_plugins(m); @@ -190,6 +189,10 @@ void test_sorting5(unsigned n, unsigned k) { smt::kernel solver(m, fp); psort_nw sn(ext); expr_ref result(m); + + // equality: + std::cout << "eq " << k << "\n"; + solver.push(); result = sn.eq(k, in.size(), in.c_ptr()); solver.assert_expr(result); for (unsigned i = 0; i < ext.m_clauses.size(); ++i) { @@ -197,7 +200,6 @@ void test_sorting5(unsigned n, unsigned k) { } lbool res = solver.check(); SASSERT(res == l_true); - std::cout << res << "\n"; solver.push(); for (unsigned i = 0; i < k; ++i) { @@ -220,7 +222,107 @@ void test_sorting5(unsigned n, unsigned k) { } SASSERT(res == l_false); solver.pop(1); + ext.m_clauses.reset(); +} +static void test_sorting_le(unsigned n, unsigned k) { + ast_manager m; + reg_decl_plugins(m); + ast_ext2 ext(m); + expr_ref_vector in(m), out(m); + for (unsigned i = 0; i < n; ++i) { + in.push_back(m.mk_fresh_const("a",m.mk_bool_sort())); + } + smt_params fp; + smt::kernel solver(m, fp); + psort_nw sn(ext); + expr_ref result(m); + // k <= B + std::cout << "le " << k << "\n"; + solver.push(); + result = sn.le(false, k, in.size(), in.c_ptr()); + solver.assert_expr(result); + for (unsigned i = 0; i < ext.m_clauses.size(); ++i) { + solver.assert_expr(ext.m_clauses[i].get()); + } + lbool res = solver.check(); + SASSERT(res == l_true); + + for (unsigned i = 0; i < n - k; ++i) { + solver.assert_expr(m.mk_not(in[i].get())); + } + res = solver.check(); + SASSERT(res == l_true); + solver.assert_expr(m.mk_not(in[n - k].get())); + res = solver.check(); + if (res == l_true) { + TRACE("pb", + unsigned sz = solver.size(); + for (unsigned i = 0; i < sz; ++i) { + tout << mk_pp(solver.get_formulas()[i], m) << "\n"; + }); + model_ref model; + solver.get_model(model); + model_smt2_pp(std::cout, m, *model, 0); + TRACE("pb", model_smt2_pp(tout, m, *model, 0);); + } + SASSERT(res == l_false); + solver.pop(1); + ext.m_clauses.reset(); +} + + +void test_sorting_ge(unsigned n, unsigned k) { + ast_manager m; + reg_decl_plugins(m); + ast_ext2 ext(m); + expr_ref_vector in(m), out(m); + for (unsigned i = 0; i < n; ++i) { + in.push_back(m.mk_fresh_const("a",m.mk_bool_sort())); + } + smt_params fp; + smt::kernel solver(m, fp); + psort_nw sn(ext); + expr_ref result(m); + // k >= B + std::cout << "ge " << k << "\n"; + solver.push(); + result = sn.ge(false, k, in.size(), in.c_ptr()); + solver.assert_expr(result); + for (unsigned i = 0; i < ext.m_clauses.size(); ++i) { + solver.assert_expr(ext.m_clauses[i].get()); + } + lbool res = solver.check(); + SASSERT(res == l_true); + + solver.push(); + for (unsigned i = 0; i < n - k; ++i) { + solver.assert_expr(m.mk_not(in[i].get())); + } + res = solver.check(); + SASSERT(res == l_true); + solver.assert_expr(m.mk_not(in[n - k].get())); + res = solver.check(); + if (res == l_true) { + TRACE("pb", + unsigned sz = solver.size(); + for (unsigned i = 0; i < sz; ++i) { + tout << mk_pp(solver.get_formulas()[i], m) << "\n"; + }); + model_ref model; + solver.get_model(model); + model_smt2_pp(std::cout, m, *model, 0); + TRACE("pb", model_smt2_pp(tout, m, *model, 0);); + } + SASSERT(res == l_false); + solver.pop(1); +} + +void test_sorting5(unsigned n, unsigned k) { + std::cout << "n: " << n << " k: " << k << "\n"; + test_sorting_le(n, k); + test_sorting_eq(n, k); + test_sorting_ge(n, k); } void tst_sorting_network() { @@ -228,8 +330,8 @@ void tst_sorting_network() { test_sorting2(); test_sorting3(); test_sorting4(); - test_sorting5(7,6); - for (unsigned n = 3; n < 10; n += 2) { + test_sorting5(11,4); + for (unsigned n = 3; n < 20; n += 2) { for (unsigned k = 1; k < n; ++k) { test_sorting5(n, k); } From 770d0d58fe1580c8e1a6956157ffb120b1a8ef21 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 11 Sep 2014 21:53:12 -0700 Subject: [PATCH 523/925] bug fixes to sorting network Signed-off-by: Nikolaj Bjorner --- src/test/sorting_network.cpp | 20 ++++++++++---------- src/util/sorting_network.h | 6 ++++++ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/test/sorting_network.cpp b/src/test/sorting_network.cpp index 2a6ba3666..d54c575ca 100644 --- a/src/test/sorting_network.cpp +++ b/src/test/sorting_network.cpp @@ -237,7 +237,7 @@ static void test_sorting_le(unsigned n, unsigned k) { smt::kernel solver(m, fp); psort_nw sn(ext); expr_ref result(m); - // k <= B + // B <= k std::cout << "le " << k << "\n"; solver.push(); result = sn.le(false, k, in.size(), in.c_ptr()); @@ -248,12 +248,12 @@ static void test_sorting_le(unsigned n, unsigned k) { lbool res = solver.check(); SASSERT(res == l_true); - for (unsigned i = 0; i < n - k; ++i) { - solver.assert_expr(m.mk_not(in[i].get())); + for (unsigned i = 0; i < k; ++i) { + solver.assert_expr(in[i].get()); } res = solver.check(); SASSERT(res == l_true); - solver.assert_expr(m.mk_not(in[n - k].get())); + solver.assert_expr(in[k].get()); res = solver.check(); if (res == l_true) { TRACE("pb", @@ -284,7 +284,7 @@ void test_sorting_ge(unsigned n, unsigned k) { smt::kernel solver(m, fp); psort_nw sn(ext); expr_ref result(m); - // k >= B + // k <= B std::cout << "ge " << k << "\n"; solver.push(); result = sn.ge(false, k, in.size(), in.c_ptr()); @@ -326,14 +326,14 @@ void test_sorting5(unsigned n, unsigned k) { } void tst_sorting_network() { - test_sorting1(); - test_sorting2(); - test_sorting3(); - test_sorting4(); - test_sorting5(11,4); + test_sorting_eq(11,7); for (unsigned n = 3; n < 20; n += 2) { for (unsigned k = 1; k < n; ++k) { test_sorting5(n, k); } } + test_sorting1(); + test_sorting2(); + test_sorting3(); + test_sorting4(); } diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index c2bdc600e..ee01d2cd2 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -680,6 +680,12 @@ Notes: for (unsigned k = 0; k < c; ++k) { ls.reset(); ls.push_back(ctx.mk_not(out[k])); + if (a <= k) { + add_clause(ctx.mk_not(out[k]), bs[k-a]); + } + if (b <= k) { + add_clause(ctx.mk_not(out[k]), as[k-b]); + } for (unsigned i = 0; i < std::min(a,k + 1); ++i) { unsigned j = k - i; SASSERT(i + j == k); From a96fa0c555d4fdd6b2b5831b851799caaf76f6d7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 14 Sep 2014 11:55:47 -0700 Subject: [PATCH 524/925] remove deprecated maxsat solvers, adjust values inline Signed-off-by: Nikolaj Bjorner --- src/opt/bcd2.cpp | 2 +- src/opt/core_maxsat.cpp | 168 ---------------------------------------- src/opt/core_maxsat.h | 55 ------------- src/opt/maxhs.cpp | 3 +- src/opt/maxres.cpp | 7 +- src/opt/maxsmt.cpp | 31 ++++---- src/opt/maxsmt.h | 13 +++- src/opt/opt_context.cpp | 42 +++++----- src/opt/opt_context.h | 8 +- src/opt/opt_solver.h | 19 ++--- src/opt/pbmax.cpp | 95 ----------------------- src/opt/pbmax.h | 29 ------- src/opt/wmax.cpp | 2 +- 13 files changed, 66 insertions(+), 408 deletions(-) delete mode 100644 src/opt/core_maxsat.cpp delete mode 100644 src/opt/core_maxsat.h delete mode 100644 src/opt/pbmax.cpp delete mode 100644 src/opt/pbmax.h diff --git a/src/opt/bcd2.cpp b/src/opt/bcd2.cpp index 779654e7e..bf041a6bd 100644 --- a/src/opt/bcd2.cpp +++ b/src/opt/bcd2.cpp @@ -124,7 +124,7 @@ namespace opt { } process_sat(); while (m_lower < m_upper) { - IF_VERBOSE(1, verbose_stream() << "(opt.bcd2 [" << m_lower << ":" << m_upper << "])\n";); + trace_bounds("bcd2"); assert_soft(); solver::scoped_push _scope2(s()); TRACE("opt", display(tout);); diff --git a/src/opt/core_maxsat.cpp b/src/opt/core_maxsat.cpp deleted file mode 100644 index 0663f9abc..000000000 --- a/src/opt/core_maxsat.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - core_maxsat.h - -Abstract: - - Core and SAT guided MaxSAT with cardinality constraints. - -Author: - - Nikolaj Bjorner (nbjorner) 2013-11-9 - -Notes: - ---*/ -#include "core_maxsat.h" -#include "pb_decl_plugin.h" -#include "ast_pp.h" -#include "opt_context.h" - -namespace opt { - - core_maxsat::core_maxsat(context& c, expr_ref_vector& soft_constraints): - m(c.get_manager()), s(c.get_solver()), - m_lower(0), m_upper(soft_constraints.size()), m_soft(soft_constraints) { - m_answer.resize(m_soft.size(), false); - } - - core_maxsat::~core_maxsat() {} - - lbool core_maxsat::operator()() { - expr_ref_vector aux(m); // auxiliary variables to track soft constraints - expr_set core_vars; // variables used so far in some core - expr_set block_vars; // variables that should be blocked. - solver::scoped_push _sp(s); - for (unsigned i = 0; i < m_soft.size(); ++i) { - expr* a = m.mk_fresh_const("p", m.mk_bool_sort()); - aux.push_back(m.mk_not(a)); - s.assert_expr(m.mk_or(a, m_soft[i].get())); - block_vars.insert(aux.back()); - } - while (m_lower < m_upper) { - ptr_vector vars; - set2vector(block_vars, vars); - lbool is_sat = s.check_sat(vars.size(), vars.c_ptr()); - - switch(is_sat) { - case l_undef: - return l_undef; - case l_true: { - model_ref mdl; - svector ans; - unsigned new_lower = 0; - s.get_model(mdl); - for (unsigned i = 0; i < aux.size(); ++i) { - expr_ref val(m); - VERIFY(mdl->eval(m_soft[i].get(), val)); - ans.push_back(m.is_true(val)); - if (ans.back()) ++new_lower; - } - TRACE("opt", tout << "sat\n"; - for (unsigned i = 0; i < ans.size(); ++i) { - tout << mk_pp(m_soft[i].get(), m) << " |-> " << ans[i] << "\n"; - }); - IF_VERBOSE(1, verbose_stream() << "(maxsat.core sat with lower bound: " << new_lower << "\n";); - if (new_lower > m_lower) { - m_answer.reset(); - m_answer.append(ans); - m_model = mdl.get(); - m_lower = new_lower; - } - if (m_lower == m_upper) { - return l_true; - } - SASSERT(m_soft.size() >= new_lower+1); - unsigned k = m_soft.size()-new_lower-1; - expr_ref fml = mk_at_most(core_vars, k); - TRACE("opt", tout << "add: " << fml << "\n";); - s.assert_expr(fml); - break; - } - case l_false: { - ptr_vector core; - s.get_unsat_core(core); - TRACE("opt", tout << "core"; - for (unsigned i = 0; i < core.size(); ++i) { - tout << mk_pp(core[i], m) << " "; - } - tout << "\n";); - for (unsigned i = 0; i < core.size(); ++i) { - core_vars.insert(get_not(core[i])); - block_vars.remove(core[i]); - } - IF_VERBOSE(1, verbose_stream() << "(maxsat.core unsat (core size = " << core.size() << ")\n";); - if (core.empty()) { - m_upper = m_lower; - return l_true; - } - else { - // at least one core variable is True - expr_ref fml = mk_at_most(core_vars, 0); - fml = m.mk_not(fml); - TRACE("opt", tout << "add: " << fml << "\n";); - s.assert_expr(fml); - } - --m_upper; - } - } - } - return l_true; - } - - void core_maxsat::set2vector(expr_set const& set, ptr_vector& es) const { - es.reset(); - expr_set::iterator it = set.begin(), end = set.end(); - for (; it != end; ++it) { - es.push_back(*it); - } - } - - expr_ref core_maxsat::mk_at_most(expr_set const& set, unsigned k) { - pb_util pb(m); - ptr_vector es; - set2vector(set, es); - return expr_ref(pb.mk_at_most_k(es.size(), es.c_ptr(), k), m); - } - - expr* core_maxsat::get_not(expr* e) const { - expr* result = 0; - VERIFY(m.is_not(e, result)); - return result; - } - - rational core_maxsat::get_lower() const { - return rational(m_soft.size()-m_upper); - } - rational core_maxsat::get_upper() const { - return rational(m_soft.size()-m_lower); - } - bool core_maxsat::get_assignment(unsigned idx) const { - return m_answer[idx]; - } - void core_maxsat::set_cancel(bool f) { - - } - void core_maxsat::collect_statistics(statistics& st) const { - // nothing specific - } - void core_maxsat::updt_params(params_ref& p) { - // no-op - } - void core_maxsat::get_model(model_ref& mdl) { - mdl = m_model.get(); - if (!mdl) { - SASSERT(m_upper == 0); - lbool is_sat = s.check_sat(0, 0); - if (is_sat == l_true) { - s.get_model(m_model); - } - mdl = m_model; - } - } - - -}; diff --git a/src/opt/core_maxsat.h b/src/opt/core_maxsat.h deleted file mode 100644 index bbb173a3f..000000000 --- a/src/opt/core_maxsat.h +++ /dev/null @@ -1,55 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - core_maxsat.h - -Abstract: - Core and SAT guided MaxSAT with cardinality constraints. - -Author: - - Nikolaj Bjorner (nbjorner) 2013-11-9 - -Notes: - ---*/ -#ifndef _OPT_CORE_MAXSAT_H_ -#define _OPT_CORE_MAXSAT_H_ - -#include "solver.h" -#include "maxsmt.h" - -namespace opt { - - class core_maxsat : public maxsmt_solver { - typedef obj_hashtable expr_set; - - ast_manager& m; - solver& s; - expr_ref_vector m_soft; - svector m_answer; - unsigned m_upper; - unsigned m_lower; - model_ref m_model; - public: - core_maxsat(context& c, expr_ref_vector& soft_constraints); - virtual ~core_maxsat(); - virtual lbool operator()(); - virtual rational get_lower() const; - virtual rational get_upper() const; - virtual bool get_assignment(unsigned idx) const; - virtual void set_cancel(bool f); - virtual void collect_statistics(statistics& st) const; - virtual void get_model(model_ref& mdl); - virtual void updt_params(params_ref& p); - private: - void set2vector(expr_set const& set, ptr_vector& es) const; - expr_ref mk_at_most(expr_set const& set, unsigned k); - expr* get_not(expr* e) const; - }; - -}; - -#endif diff --git a/src/opt/maxhs.cpp b/src/opt/maxhs.cpp index 9f8aa2d11..a7425b22e 100644 --- a/src/opt/maxhs.cpp +++ b/src/opt/maxhs.cpp @@ -111,8 +111,7 @@ namespace opt { seed2assumptions(); while (m_lower < m_upper) { ++m_stats.m_num_iterations; - IF_VERBOSE(1, verbose_stream() << - "(opt.maxhs [" << m_lower << ":" << m_upper << "])\n";); + trace_bounds("maxhs"); TRACE("opt", tout << "(maxhs [" << m_lower << ":" << m_upper << "])\n";); if (m_cancel) { return l_undef; diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 48dbb410b..60cc11555 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -193,7 +193,7 @@ public: exprs mcs; lbool is_sat = l_true; while (m_lower < m_upper && is_sat == l_true) { - IF_VERBOSE(1, verbose_stream() << "(opt.maxres [" << m_lower << ":" << m_upper << "])\n";); + trace_bounds("maxres"); if (m_cancel) { return l_undef; } @@ -512,7 +512,7 @@ public: fml = m.mk_not(m.mk_and(m_B.size(), m_B.c_ptr())); s().assert_expr(fml); m_lower += w; - IF_VERBOSE(1, verbose_stream() << "(opt.maxres [" << m_lower << ":" << m_upper << "])\n";); + trace_bounds("maxres"); } bool get_mus_model(model_ref& mdl) { @@ -789,8 +789,7 @@ public: } m_upper = upper; // verify_assignment(); - IF_VERBOSE(1, verbose_stream() << - "(opt.maxres [" << m_lower << ":" << m_upper << "])\n";); + trace_bounds("maxres"); add_upper_bound_block(); } diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index d128e57f2..e737f9efe 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -20,11 +20,9 @@ Notes: #include #include "maxsmt.h" #include "fu_malik.h" -#include "core_maxsat.h" #include "maxres.h" #include "maxhs.h" #include "bcd2.h" -#include "pbmax.h" #include "wmax.h" #include "maxsls.h" #include "ast_pp.h" @@ -140,6 +138,13 @@ namespace opt { } smt::theory_wmaxsat& maxsmt_solver_base::scoped_ensure_theory::operator()() { return *m_wth; } + void maxsmt_solver_base::trace_bounds(char const * solver) { + IF_VERBOSE(1, + rational l = m_adjust_value(m_lower); + rational u = m_adjust_value(m_upper); + if (l > u) std::swap(l, u); + verbose_stream() << "(opt." << solver << " [" << l << ":" << u << "])\n";); + } @@ -167,9 +172,6 @@ namespace opt { else if (maxsat_engine == symbol("mss-maxres")) { m_msolver = mk_mss_maxres(m_c, m_weights, m_soft_constraints); } - else if (maxsat_engine == symbol("pbmax")) { - m_msolver = mk_pbmax(m_c, m_weights, m_soft_constraints); - } else if (maxsat_engine == symbol("bcd2")) { m_msolver = mk_bcd2(m_c, m_weights, m_soft_constraints); } @@ -180,9 +182,6 @@ namespace opt { // NB: this is experimental one-round version of SLS m_msolver = mk_sls(m_c, m_weights, m_soft_constraints); } - else if (is_maxsat_problem(m_weights) && maxsat_engine == symbol("core_maxsat")) { - m_msolver = alloc(core_maxsat, m_c, m_soft_constraints); - } else if (is_maxsat_problem(m_weights) && maxsat_engine == symbol("fu_malik")) { m_msolver = alloc(fu_malik, m_c, m_soft_constraints); } @@ -196,6 +195,7 @@ namespace opt { if (m_msolver) { m_msolver->updt_params(m_params); + m_msolver->set_adjust_value(m_adjust_value); is_sat = (*m_msolver)(); if (is_sat != l_false) { m_msolver->get_model(m_model); @@ -245,7 +245,7 @@ namespace opt { rational q = m_msolver->get_lower(); if (q > r) r = q; } - return r; + return m_adjust_value(r); } rational maxsmt::get_upper() const { @@ -254,17 +254,16 @@ namespace opt { rational q = m_msolver->get_upper(); if (q < r) r = q; } - return r; + return m_adjust_value(r); } - void maxsmt::update_lower(rational const& r, bool override) { - if (m_lower > r || override) m_lower = r; + void maxsmt::update_lower(rational const& r) { + if (m_lower > r) m_lower = r; } - void maxsmt::update_upper(rational const& r, bool override) { - if (m_upper < r || override) m_upper = r; - } - + void maxsmt::update_upper(rational const& r) { + if (m_upper < r) m_upper = r; + } void maxsmt::get_model(model_ref& mdl) { mdl = m_model.get(); diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 2b868408a..4c0d8d825 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -27,6 +27,7 @@ Notes: #include"smt_context.h" #include"smt_theory.h" #include"theory_wmaxsat.h" +#include"opt_solver.h" namespace opt { @@ -35,6 +36,8 @@ namespace opt { class context; class maxsmt_solver { + protected: + adjust_value m_adjust_value; public: virtual ~maxsmt_solver() {} virtual lbool operator()() = 0; @@ -45,6 +48,7 @@ namespace opt { virtual void collect_statistics(statistics& st) const = 0; virtual void get_model(model_ref& mdl) = 0; virtual void updt_params(params_ref& p) = 0; + void set_adjust_value(adjust_value& adj) { m_adjust_value = adj; } }; @@ -100,6 +104,7 @@ namespace opt { protected: void enable_sls(expr_ref_vector const& soft, weights_t& ws); void set_enable_sls(bool f); + void trace_bounds(char const* solver); }; @@ -119,6 +124,7 @@ namespace opt { vector m_weights; rational m_lower; rational m_upper; + adjust_value m_adjust_value; model_ref m_model; params_ref m_params; public: @@ -127,15 +133,16 @@ namespace opt { void set_cancel(bool f); void updt_params(params_ref& p); void add(expr* f, rational const& w); + void set_adjust_value(adjust_value& adj) { m_adjust_value = adj; } unsigned size() const { return m_soft_constraints.size(); } expr* operator[](unsigned idx) const { return m_soft_constraints[idx]; } rational weight(unsigned idx) const { return m_weights[idx]; } void commit_assignment(); rational get_value() const; rational get_lower() const; - rational get_upper() const; - void update_lower(rational const& r, bool override); - void update_upper(rational const& r, bool override); + rational get_upper() const; + void update_lower(rational const& r); + void update_upper(rational const& r); void get_model(model_ref& mdl); bool get_assignment(unsigned index) const; void display_answer(std::ostream& out) const; diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index ca4b40740..b71826e9b 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -218,7 +218,7 @@ namespace opt { IF_VERBOSE(1, verbose_stream() << "(optimize:sat)\n";); s.get_model(m_model); m_optsmt.setup(*m_opt_solver.get()); - update_lower(true); + update_lower(); switch (m_objectives.size()) { case 0: return is_sat; @@ -293,7 +293,7 @@ namespace opt { return r; } if (r == l_true && i + 1 < m_objectives.size()) { - update_lower(true); + update_lower(); } } DEBUG_CODE(if (r == l_true) validate_lex();); @@ -398,8 +398,8 @@ namespace opt { void context::yield() { m_pareto->get_model(m_model); - update_bound(true, true); - update_bound(true, false); + update_bound(true); + update_bound(false); } lbool context::execute_pareto() { @@ -763,8 +763,9 @@ namespace opt { SASSERT(obj.m_id == id); obj.m_terms.reset(); obj.m_terms.append(terms); - obj.m_adjust_bound.set_offset(offset); - obj.m_adjust_bound.set_negate(neg); + obj.m_adjust_value.set_offset(offset); + obj.m_adjust_value.set_negate(neg); + m_maxsmts.find(id)->set_adjust_value(obj.m_adjust_value); TRACE("opt", tout << "maxsat: " << id << " offset:" << offset << "\n";); } else if (is_maximize(fml, tr, orig_term, index)) { @@ -772,6 +773,7 @@ namespace opt { } else if (is_minimize(fml, tr, orig_term, index)) { m_objectives[index].m_term = tr; + m_objectives[index].m_adjust_value.set_negate(true); } else { m_hard_constraints.push_back(fml); @@ -826,15 +828,16 @@ namespace opt { } } - void context::update_bound(bool override, bool is_lower) { + void context::update_bound(bool is_lower) { expr_ref val(m); + bool override = true; for (unsigned i = 0; i < m_objectives.size(); ++i) { objective const& obj = m_objectives[i]; rational r; switch(obj.m_type) { case O_MINIMIZE: if (m_model->eval(obj.m_term, val) && is_numeral(val, r)) { - inf_eps val = obj.m_adjust_bound.neg_add(r); + inf_eps val = inf_eps(obj.m_adjust_value(r)); if (is_lower) { m_optsmt.update_lower(obj.m_index, val, override); } @@ -845,7 +848,7 @@ namespace opt { break; case O_MAXIMIZE: if (m_model->eval(obj.m_term, val) && is_numeral(val, r)) { - inf_eps val = obj.m_adjust_bound.neg_add(r); + inf_eps val = inf_eps(obj.m_adjust_value(r)); if (is_lower) { m_optsmt.update_lower(obj.m_index, val, override); } @@ -868,10 +871,10 @@ namespace opt { } if (ok) { if (is_lower) { - m_maxsmts.find(obj.m_id)->update_upper(r, override); + m_maxsmts.find(obj.m_id)->update_upper(r); } else { - m_maxsmts.find(obj.m_id)->update_lower(r, override); + m_maxsmts.find(obj.m_id)->update_lower(r); } } break; @@ -918,14 +921,12 @@ namespace opt { } objective const& obj = m_objectives[idx]; switch(obj.m_type) { - case O_MAXSMT: { - rational r = m_maxsmts.find(obj.m_id)->get_lower(); - return obj.m_adjust_bound.neg_add(r); - } + case O_MAXSMT: + return inf_eps(m_maxsmts.find(obj.m_id)->get_lower()); case O_MINIMIZE: - return -m_optsmt.get_upper(obj.m_index); + return obj.m_adjust_value(m_optsmt.get_upper(obj.m_index)); case O_MAXIMIZE: - return m_optsmt.get_lower(obj.m_index); + return obj.m_adjust_value(m_optsmt.get_lower(obj.m_index)); default: UNREACHABLE(); return inf_eps(); @@ -939,12 +940,11 @@ namespace opt { objective const& obj = m_objectives[idx]; switch(obj.m_type) { case O_MAXSMT: - return obj.m_adjust_bound.neg_add(m_maxsmts.find(obj.m_id)->get_upper()); - // TBD: adjust bound + return inf_eps(m_maxsmts.find(obj.m_id)->get_upper()); case O_MINIMIZE: - return -m_optsmt.get_lower(obj.m_index); + return obj.m_adjust_value(m_optsmt.get_lower(obj.m_index)); case O_MAXIMIZE: - return m_optsmt.get_upper(obj.m_index); + return obj.m_adjust_value(m_optsmt.get_upper(obj.m_index)); default: UNREACHABLE(); return inf_eps(); diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 051729aff..eb8dd6fc6 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -51,7 +51,7 @@ namespace opt { app_ref m_term; // for maximize, minimize term expr_ref_vector m_terms; // for maxsmt vector m_weights; // for maxsmt - bound_adjustment m_adjust_bound; + adjust_value m_adjust_value; symbol m_id; // for maxsmt unsigned m_index; // for maximize/minimize index @@ -63,7 +63,7 @@ namespace opt { m_index(idx) { if (!is_max) { - m_adjust_bound.set_negate(true); + m_adjust_value.set_negate(true); } } @@ -212,8 +212,8 @@ namespace opt { void from_fmls(expr_ref_vector const& fmls); void simplify_fmls(expr_ref_vector& fmls); - void update_lower(bool override) { update_bound(override, true); } - void update_bound(bool override, bool is_lower); + void update_lower() { update_bound(true); } + void update_bound(bool is_lower); inf_eps get_lower_as_num(unsigned idx); inf_eps get_upper_as_num(unsigned idx); diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 0e59a9eb9..29b450e08 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -36,30 +36,31 @@ namespace opt { typedef inf_eps_rational inf_eps; - // Adjust bound bound |-> (m_negate?-1:1)*(m_offset + bound) - class bound_adjustment { + // Adjust bound bound |-> m_offset + (m_negate?-1:1)*bound + class adjust_value { rational m_offset; bool m_negate; public: - bound_adjustment(rational const& offset, bool neg): + adjust_value(rational const& offset, bool neg): m_offset(offset), m_negate(neg) {} - bound_adjustment(): m_offset(0), m_negate(false) {} + adjust_value(): m_offset(0), m_negate(false) {} void set_offset(rational const& o) { m_offset = o; } void set_negate(bool neg) { m_negate = neg; } rational const& get_offset() const { return m_offset; } bool get_negate() { return m_negate; } - inf_eps add_neg(rational const& r) const { - rational result = r + m_offset; + inf_eps operator()(inf_eps const& r) const { + inf_eps result = r; if (m_negate) result.neg(); - return inf_eps(result); + result += m_offset; + return result; } - inf_eps neg_add(rational const& r) const { + rational operator()(rational const& r) const { rational result = r; if (m_negate) result.neg(); result += m_offset; - return inf_eps(result); + return result; } }; diff --git a/src/opt/pbmax.cpp b/src/opt/pbmax.cpp deleted file mode 100644 index a30fe3acb..000000000 --- a/src/opt/pbmax.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/*++ -Copyright (c) 2014 Microsoft Corporation - -Module Name: - - pbmax.cpp - -Abstract: - - pb based MaxSAT. - -Author: - - Nikolaj Bjorner (nbjorner) 2014-4-17 - -Notes: - ---*/ -#include "pbmax.h" -#include "pb_decl_plugin.h" -#include "uint_set.h" -#include "ast_pp.h" -#include "model_smt2_pp.h" - - -namespace opt { - - // ---------------------------------- - // incrementally add pseudo-boolean - // lower bounds. - - class pbmax : public maxsmt_solver_base { - public: - pbmax(context& c, weights_t& ws, expr_ref_vector const& soft): - maxsmt_solver_base(c, ws, soft) { - } - - virtual ~pbmax() {} - - lbool operator()() { - - TRACE("opt", s().display(tout); tout << "\n"; - for (unsigned i = 0; i < m_soft.size(); ++i) { - tout << mk_pp(m_soft[i].get(), m) << " " << m_weights[i] << "\n"; - } - ); - pb_util u(m); - expr_ref fml(m), val(m); - app_ref b(m); - expr_ref_vector nsoft(m); - init(); - for (unsigned i = 0; i < m_soft.size(); ++i) { - nsoft.push_back(mk_not(m_soft[i].get())); - } - lbool is_sat = l_true; - while (l_true == is_sat) { - TRACE("opt", s().display(tout<<"looping\n"); - model_smt2_pp(tout << "\n", m, *(m_model.get()), 0);); - m_upper.reset(); - for (unsigned i = 0; i < m_soft.size(); ++i) { - VERIFY(m_model->eval(nsoft[i].get(), val)); - m_assignment[i] = !m.is_true(val); - if (!m_assignment[i]) { - m_upper += m_weights[i]; - } - } - IF_VERBOSE(1, verbose_stream() << "(opt.pb [" << m_lower << ":" << m_upper << "])\n";); - TRACE("opt", tout << "new upper: " << m_upper << "\n";); - - fml = u.mk_lt(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper); - solver::scoped_push _scope2(s()); - s().assert_expr(fml); - is_sat = s().check_sat(0,0); - if (m_cancel) { - is_sat = l_undef; - } - if (is_sat == l_true) { - s().get_model(m_model); - } - } - if (is_sat == l_false) { - is_sat = l_true; - m_lower = m_upper; - } - TRACE("opt", tout << "lower: " << m_lower << "\n";); - return is_sat; - } - }; - - maxsmt_solver_base* mk_pbmax( - context & c, weights_t& ws, expr_ref_vector const& soft) { - return alloc(pbmax, c, ws, soft); - } - -} diff --git a/src/opt/pbmax.h b/src/opt/pbmax.h deleted file mode 100644 index 78d43b045..000000000 --- a/src/opt/pbmax.h +++ /dev/null @@ -1,29 +0,0 @@ -/*++ -Copyright (c) 2014 Microsoft Corporation - -Module Name: - - pbmax.h - -Abstract: - - MaxSAT based on pb theory. - -Author: - - Nikolaj Bjorner (nbjorner) 2014-4-17 - -Notes: - ---*/ - -#ifndef _PBMAX_H_ -#define _PBMAX_H_ - -#include "maxsmt.h" - -namespace opt { - maxsmt_solver_base* mk_pbmax(context& c, weights_t& ws, expr_ref_vector const& soft); - -} -#endif diff --git a/src/opt/wmax.cpp b/src/opt/wmax.cpp index 3499c51ff..78675387c 100644 --- a/src/opt/wmax.cpp +++ b/src/opt/wmax.cpp @@ -59,7 +59,7 @@ namespace opt { s().assert_expr(fml); was_sat = true; } - IF_VERBOSE(1, verbose_stream() << "(opt.wmax [" << m_lower << ":" << m_upper << "])\n";); + trace_bounds("wmax"); } if (was_sat) { wth().get_assignment(m_assignment); From 73070585b83c77bee5ebe08664d350056d5463c6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 14 Sep 2014 13:06:01 -0700 Subject: [PATCH 525/925] fix bug in core generation in legacy core: it ignores complementary literals Signed-off-by: Nikolaj Bjorner --- src/opt/inc_sat_solver.cpp | 7 ++----- src/opt/maxres.cpp | 3 +++ src/opt/maxsmt.cpp | 4 ++-- src/opt/opt_context.cpp | 1 + src/sat/sat_solver.cpp | 3 +++ src/sat/sat_solver.h | 4 +++- src/smt/smt_context.cpp | 18 ++++++++---------- src/smt/smt_context.h | 6 +++--- 8 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/opt/inc_sat_solver.cpp b/src/opt/inc_sat_solver.cpp index 11aa24d71..41e4d12de 100644 --- a/src/opt/inc_sat_solver.cpp +++ b/src/opt/inc_sat_solver.cpp @@ -356,16 +356,13 @@ private: } } - // TBD: this is super-expensive because of the - // bit-blasting model converter. - void extract_model() { TRACE("sat", tout << "retrieve model\n";); - sat::model const & ll_m = m_solver.get_model(); - if (ll_m.empty()) { + if (!m_solver.model_is_current()) { m_model = 0; return; } + sat::model const & ll_m = m_solver.get_model(); model_ref md = alloc(model, m); atom2bool_var::iterator it = m_map.begin(); atom2bool_var::iterator end = m_map.end(); diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 60cc11555..c2de70ad6 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -130,6 +130,7 @@ public: if (m_asm2weight.find(e, weight)) { weight += w; m_asm2weight.insert(e, weight); + m_upper += w; return; } if (is_literal(e)) { @@ -154,6 +155,7 @@ public: lbool mus_solver() { init(); init_local(); + trace_bounds("maxres"); while (m_lower < m_upper) { TRACE("opt", display_vec(tout, m_asms.size(), m_asms.c_ptr()); @@ -776,6 +778,7 @@ public: if (!m.is_true(tmp)) { upper += m_weights[i]; } + TRACE("opt", tout << mk_pp(n, m) << " |-> " << mk_pp(tmp, m) << "\n";); CTRACE("opt", !m.is_true(tmp) && !m.is_false(tmp), tout << mk_pp(n, m) << " |-> " << mk_pp(tmp, m) << "\n";); } diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index e737f9efe..d12fabfa7 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -71,9 +71,9 @@ namespace opt { } TRACE("opt", - tout << m_upper << ": "; + tout << "upper: " << m_upper << " assignments: "; for (unsigned i = 0; i < m_weights.size(); ++i) { - tout << (m_assignment[i]?"1":"0"); + tout << (m_assignment[i]?"T":"F"); } tout << "\n";); } diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index b71826e9b..9b48707bd 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -830,6 +830,7 @@ namespace opt { void context::update_bound(bool is_lower) { expr_ref val(m); + if (!m_model.get()) return; bool override = true; for (unsigned i = 0; i < m_objectives.size(); ++i) { objective const& obj = m_objectives[i]; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 4b1bd32b1..082a4a4b4 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -948,6 +948,7 @@ namespace sat { } void solver::init_search() { + m_model_is_current = false; m_phase_counter = 0; m_phase_cache_on = false; m_conflicts_since_restart = 0; @@ -1036,6 +1037,7 @@ namespace sat { void solver::mk_model() { m_model.reset(); + m_model_is_current = true; unsigned num = num_vars(); m_model.resize(num, l_undef); for (bool_var v = 0; v < num; v++) { @@ -1738,6 +1740,7 @@ namespace sat { m_mus(); // ignore return value on cancelation. m_model.reset(); m_model.append(m_mus.get_model()); + m_model_is_current = true; } } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index e83da892b..f2602ff25 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -76,8 +76,9 @@ namespace sat { random_gen m_rand; clause_allocator m_cls_allocator; cleaner m_cleaner; - model m_model; + model m_model; model_converter m_mc; + bool m_model_is_current; simplifier m_simplifier; scc m_scc; asymm_branch m_asymm_branch; @@ -270,6 +271,7 @@ namespace sat { public: lbool check(unsigned num_lits = 0, literal const* lits = 0); model const & get_model() const { return m_model; } + bool model_is_current() const { return m_model_is_current; } literal_vector const& get_core() const { return m_core; } model_converter const & get_model_converter() const { return m_mc; } diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index bd518faff..d86b2da77 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -2852,7 +2852,7 @@ namespace smt { void context::init_assumptions(unsigned num_assumptions, expr * const * assumptions) { reset_assumptions(); - m_bool_var2assumption.reset(); + m_literal2assumption.reset(); m_unsat_core.reset(); if (num_assumptions > 0) { // We must give a chance to the theories to propagate before we create a new scope... @@ -2868,7 +2868,7 @@ namespace smt { proof * pr = m_manager.mk_asserted(curr_assumption); internalize_assertion(curr_assumption, pr, 0); literal l = get_literal(curr_assumption); - m_bool_var2assumption.insert(l.var(), curr_assumption); + m_literal2assumption.insert(l.index(), curr_assumption); // mark_as_relevant(l); <<< not needed // internalize_assertion marked l as relevant. SASSERT(is_relevant(l)); @@ -2877,7 +2877,7 @@ namespace smt { assign(l, mk_justification(justification_proof_wrapper(*this, pr))); else assign(l, b_justification::mk_axiom()); - m_assumptions.push_back(l.var()); + m_assumptions.push_back(l); get_bdata(l.var()).m_assumption = true; } } @@ -2887,10 +2887,10 @@ namespace smt { } void context::reset_assumptions() { - bool_var_vector::iterator it = m_assumptions.begin(); - bool_var_vector::iterator end = m_assumptions.end(); + literal_vector::iterator it = m_assumptions.begin(); + literal_vector::iterator end = m_assumptions.end(); for (; it != end; ++it) - get_bdata(*it).m_assumption = false; + get_bdata(it->var()).m_assumption = false; m_assumptions.reset(); } @@ -2907,10 +2907,8 @@ namespace smt { literal l = *it; TRACE("unsat_core_bug", tout << "answer literal: " << l << "\n";); SASSERT(get_bdata(l.var()).m_assumption); - SASSERT(m_bool_var2assumption.contains(l.var())); - expr * a = 0; - m_bool_var2assumption.find(l.var(), a); - SASSERT(a); + SASSERT(m_literal2assumption.contains(l.index())); + expr * a = m_literal2assumption[l.index()]; if (!already_found_assumptions.contains(a)) { already_found_assumptions.insert(a); m_unsat_core.push_back(a); diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 42af9738b..d3dc8a492 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -201,9 +201,9 @@ namespace smt { // Unsat core extraction // // ----------------------------------- - typedef u_map bool_var2assumption; - bool_var_vector m_assumptions; - bool_var2assumption m_bool_var2assumption; // maps an expression associated with a literal to the original assumption + typedef u_map literal2assumption; + literal_vector m_assumptions; + literal2assumption m_literal2assumption; // maps an expression associated with a literal to the original assumption expr_ref_vector m_unsat_core; // ----------------------------------- From c09903288ff0aba8262586a874b17d7b5d0ab490 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 15 Sep 2014 16:14:22 -0700 Subject: [PATCH 526/925] have free variable utility use a class for more efficient re-use Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/ast_counter.cpp | 13 +- src/ast/rewriter/ast_counter.h | 13 +- src/ast/rewriter/var_subst.cpp | 30 +++- src/ast/rewriter/var_subst.h | 18 +- src/muz/base/dl_context.cpp | 30 ++-- src/muz/base/dl_context.h | 1 + src/muz/base/dl_rule.cpp | 157 ++++++++---------- src/muz/base/dl_rule.h | 16 +- src/muz/base/dl_rule_set.h | 6 +- src/muz/base/dl_util.cpp | 19 ++- src/muz/base/dl_util.h | 9 +- src/muz/base/hnf.cpp | 13 +- src/muz/bmc/dl_bmc_engine.cpp | 24 +-- src/muz/clp/clp_context.cpp | 14 +- src/muz/ddnf/ddnf.cpp | 6 +- src/muz/fp/dl_cmds.cpp | 1 + src/muz/fp/horn_tactic.cpp | 2 +- src/muz/pdr/pdr_context.cpp | 36 ++-- src/muz/pdr/pdr_generalizers.cpp | 18 +- src/muz/pdr/pdr_manager.cpp | 4 +- src/muz/pdr/pdr_manager.h | 4 +- src/muz/rel/dl_compiler.cpp | 39 ++--- src/muz/rel/dl_compiler.h | 11 +- src/muz/rel/dl_mk_simple_joins.cpp | 2 +- src/muz/rel/dl_relation_manager.cpp | 10 +- src/muz/tab/tab_context.cpp | 20 ++- src/muz/transforms/dl_mk_array_blast.cpp | 2 +- src/muz/transforms/dl_mk_bit_blast.cpp | 5 +- src/muz/transforms/dl_mk_coalesce.cpp | 6 +- .../dl_mk_quantifier_instantiation.cpp | 2 +- src/muz/transforms/dl_mk_rule_inliner.cpp | 2 +- .../dl_mk_separate_negated_tails.cpp | 6 +- .../transforms/dl_mk_separate_negated_tails.h | 2 +- src/muz/transforms/dl_mk_slice.cpp | 15 +- src/muz/transforms/dl_mk_unfold.cpp | 2 +- src/qe/qe.cpp | 15 +- src/smt/theory_arith.h | 1 + src/smt/theory_arith_core.h | 3 +- src/tactic/horn_subsume_model_converter.cpp | 26 ++- 39 files changed, 300 insertions(+), 303 deletions(-) diff --git a/src/ast/rewriter/ast_counter.cpp b/src/ast/rewriter/ast_counter.cpp index 6f49a232f..f1ec03528 100644 --- a/src/ast/rewriter/ast_counter.cpp +++ b/src/ast/rewriter/ast_counter.cpp @@ -18,12 +18,9 @@ Revision History: --*/ #include "ast_counter.h" -#include "var_subst.h" void counter::update(unsigned el, int delta) { int & counter = get(el); - SASSERT(!m_stay_non_negative || counter>=0); - SASSERT(!m_stay_non_negative || static_cast(counter)>=-delta); counter += delta; } @@ -92,16 +89,14 @@ int counter::get_max_counter_value() const { void var_counter::count_vars(ast_manager & m, const app * pred, int coef) { unsigned n = pred->get_num_args(); for (unsigned i = 0; i < n; i++) { - m_sorts.reset(); - m_todo.reset(); - m_mark.reset(); - ::get_free_vars(m_mark, m_todo, pred->get_arg(i), m_sorts); - for (unsigned j = 0; j < m_sorts.size(); ++j) { - if (m_sorts[j]) { + m_fv(pred->get_arg(i)); + for (unsigned j = 0; j < m_fv.size(); ++j) { + if (m_fv[j]) { update(j, coef); } } } + m_fv.reset(); } diff --git a/src/ast/rewriter/ast_counter.h b/src/ast/rewriter/ast_counter.h index e7251079f..8b3ec3bbd 100644 --- a/src/ast/rewriter/ast_counter.h +++ b/src/ast/rewriter/ast_counter.h @@ -27,16 +27,16 @@ Revision History: #include "ast.h" #include "map.h" #include "uint_set.h" +#include "var_subst.h" class counter { protected: typedef u_map map_impl; map_impl m_data; - const bool m_stay_non_negative; public: typedef map_impl::iterator iterator; - counter(bool stay_non_negative = true) : m_stay_non_negative(stay_non_negative) {} + counter() {} void reset() { m_data.reset(); } iterator begin() const { return m_data.begin(); } @@ -69,14 +69,13 @@ public: class var_counter : public counter { protected: - ptr_vector m_sorts; expr_fast_mark1 m_visited; + expr_free_vars m_fv; ptr_vector m_todo; - ast_mark m_mark; unsigned_vector m_scopes; unsigned get_max_var(bool & has_var); public: - var_counter(bool stay_non_negative = true): counter(stay_non_negative) {} + var_counter() {} void count_vars(ast_manager & m, const app * t, int coef = 1); unsigned get_max_var(expr* e); unsigned get_next_var(expr* e); @@ -85,11 +84,10 @@ public: class ast_counter { typedef obj_map map_impl; map_impl m_data; - bool m_stay_non_negative; public: typedef map_impl::iterator iterator; - ast_counter(bool stay_non_negative = true) : m_stay_non_negative(stay_non_negative) {} + ast_counter() {} iterator begin() const { return m_data.begin(); } iterator end() const { return m_data.end(); } @@ -99,7 +97,6 @@ class ast_counter { } void update(ast * el, int delta){ get(el) += delta; - SASSERT(!m_stay_non_negative || get(el) >= 0); } void inc(ast * el) { update(el, 1); } diff --git a/src/ast/rewriter/var_subst.cpp b/src/ast/rewriter/var_subst.cpp index 930267dad..1d01ef85c 100644 --- a/src/ast/rewriter/var_subst.cpp +++ b/src/ast/rewriter/var_subst.cpp @@ -164,7 +164,7 @@ void instantiate(ast_manager & m, quantifier * q, expr * const * exprs, expr_ref tout << "\n----->\n" << mk_ismt2_pp(result, m) << "\n";); } -static void get_free_vars_offset(ast_mark& mark, ptr_vector& todo, unsigned offset, expr* e, ptr_vector& sorts) { +static void get_free_vars_offset(expr_sparse_mark& mark, ptr_vector& todo, unsigned offset, expr* e, ptr_vector& sorts) { todo.push_back(e); while (!todo.empty()) { e = todo.back(); @@ -176,7 +176,7 @@ static void get_free_vars_offset(ast_mark& mark, ptr_vector& todo, unsigne switch(e->get_kind()) { case AST_QUANTIFIER: { quantifier* q = to_quantifier(e); - ast_mark mark1; + expr_sparse_mark mark1; ptr_vector todo1; get_free_vars_offset(mark1, todo1, offset+q->get_num_decls(), q->get_expr(), sorts); break; @@ -210,11 +210,33 @@ static void get_free_vars_offset(ast_mark& mark, ptr_vector& todo, unsigne void get_free_vars(expr* e, ptr_vector& sorts) { - ast_mark mark; + expr_sparse_mark mark; ptr_vector todo; get_free_vars_offset(mark, todo, 0, e, sorts); } -void get_free_vars(ast_mark& mark, ptr_vector& todo, expr* e, ptr_vector& sorts) { +void get_free_vars(expr_sparse_mark& mark, ptr_vector& todo, expr* e, ptr_vector& sorts) { get_free_vars_offset(mark, todo, 0, e, sorts); } + +void expr_free_vars::reset() { + m_mark.reset(); + m_sorts.reset(); + SASSERT(m_todo.empty()); +} + +void expr_free_vars::set_default_sort(sort *s) { + for (unsigned i = 0; i < m_sorts.size(); ++i) { + if (!m_sorts[i]) m_sorts[i] = s; + } +} + +void expr_free_vars::operator()(expr* e) { + reset(); + get_free_vars_offset(m_mark, m_todo, 0, e, m_sorts); +} + +void expr_free_vars::accumulate(expr* e) { + SASSERT(m_todo.empty()); + get_free_vars_offset(m_mark, m_todo, 0, e, m_sorts); +} diff --git a/src/ast/rewriter/var_subst.h b/src/ast/rewriter/var_subst.h index ffc21e691..7db756d30 100644 --- a/src/ast/rewriter/var_subst.h +++ b/src/ast/rewriter/var_subst.h @@ -81,9 +81,23 @@ void instantiate(ast_manager & m, quantifier * q, expr * const * exprs, expr_ref Return the sorts of the free variables. */ -void get_free_vars(expr* e, ptr_vector& sorts); -void get_free_vars(ast_mark& mark, ptr_vector& todo, expr* e, ptr_vector& sorts); +class expr_free_vars { + expr_sparse_mark m_mark; + ptr_vector m_sorts; + ptr_vector m_todo; +public: + void reset(); + void operator()(expr* e); + void accumulate(expr* e); + bool empty() const { return m_sorts.empty(); } + unsigned size() const { return m_sorts.size(); } + sort* operator[](unsigned idx) const { return m_sorts[idx]; } + bool contains(unsigned idx) const { return idx < m_sorts.size() && m_sorts[idx] != 0; } + void set_default_sort(sort* s); + void reverse() { m_sorts.reverse(); } + sort*const* c_ptr() const { return m_sorts.c_ptr(); } +}; #endif diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 529028606..d37e9cca8 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -334,21 +334,13 @@ namespace datalog { else { m_names.reset(); m_abstractor(0, vars.size(), reinterpret_cast(vars.c_ptr()), fml, result); - rm.collect_vars(result); - ptr_vector& sorts = rm.get_var_sorts(); - if (sorts.empty()) { + m_free_vars(result); + if (m_free_vars.empty()) { result = fml; } else { - for (unsigned i = 0; i < sorts.size(); ++i) { - if (!sorts[i]) { - if (i < vars.size()) { - sorts[i] = vars[i]->get_decl()->get_range(); - } - else { - sorts[i] = m.mk_bool_sort(); - } - } + m_free_vars.set_default_sort(m.mk_bool_sort()); + for (unsigned i = 0; i < m_free_vars.size(); ++i) { if (i < vars.size()) { m_names.push_back(vars[i]->get_decl()->get_name()); } @@ -357,8 +349,8 @@ namespace datalog { } } quantifier_ref q(m); - sorts.reverse(); - q = m.mk_quantifier(is_forall, sorts.size(), sorts.c_ptr(), m_names.c_ptr(), result); + m_free_vars.reverse(); + q = m.mk_quantifier(is_forall, m_free_vars.size(), m_free_vars.c_ptr(), m_names.c_ptr(), result); m_elim_unused_vars(q, result); } } @@ -604,7 +596,7 @@ namespace datalog { unsigned ut_size = r.get_uninterpreted_tail_size(); unsigned t_size = r.get_tail_size(); - TRACE("dl", r.display_smt2(get_manager(), tout); tout << "\n";); + TRACE("dl", get_rule_manager().display_smt2(r, tout); tout << "\n";); for (unsigned i = ut_size; i < t_size; ++i) { app* t = r.get_tail(i); TRACE("dl", tout << "checking: " << mk_ismt2_pp(t, get_manager()) << "\n";); @@ -1121,13 +1113,13 @@ namespace datalog { void context::get_rules_as_formulas(expr_ref_vector& rules, expr_ref_vector& queries, svector& names) { expr_ref fml(m); - datalog::rule_manager& rm = get_rule_manager(); + rule_manager& rm = get_rule_manager(); // ensure that rules are all using bound variables. for (unsigned i = m_rule_fmls_head; i < m_rule_fmls.size(); ++i) { ptr_vector sorts; - get_free_vars(m_rule_fmls[i].get(), sorts); - if (!sorts.empty()) { + m_free_vars(m_rule_fmls[i].get()); + if (!m_free_vars.empty()) { rm.mk_rule(m_rule_fmls[i].get(), 0, m_rule_set, m_rule_names[i]); m_rule_fmls[i] = m_rule_fmls.back(); m_rule_names[i] = m_rule_names.back(); @@ -1139,7 +1131,7 @@ namespace datalog { rule_set::iterator it = m_rule_set.begin(), end = m_rule_set.end(); for (; it != end; ++it) { rule* r = *it; - r->to_formula(fml); + rm.to_formula(*r, fml); func_decl* h = r->get_decl(); if (m_rule_set.is_output_predicate(h)) { expr* body = fml; diff --git a/src/muz/base/dl_context.h b/src/muz/base/dl_context.h index 66addc37c..fb49f02bc 100644 --- a/src/muz/base/dl_context.h +++ b/src/muz/base/dl_context.h @@ -191,6 +191,7 @@ namespace datalog { pred2syms m_argument_var_names; rule_set m_rule_set; rule_set m_transformed_rule_set; + expr_free_vars m_free_vars; unsigned m_rule_fmls_head; expr_ref_vector m_rule_fmls; svector m_rule_names; diff --git a/src/muz/base/dl_rule.cpp b/src/muz/base/dl_rule.cpp index 017bac724..6296717da 100644 --- a/src/muz/base/dl_rule.cpp +++ b/src/muz/base/dl_rule.cpp @@ -111,16 +111,14 @@ namespace datalog { } void rule_manager::reset_collect_vars() { - m_vars.reset(); m_var_idx.reset(); - m_todo.reset(); - m_mark.reset(); + m_free_vars.reset(); } var_idx_set& rule_manager::finalize_collect_vars() { - unsigned sz = m_vars.size(); - for (unsigned i=0; i sorts; - ::get_free_vars(fml, sorts); ); expr_ref_vector fmls(m); proof_ref_vector prs(m); m_hnf.reset(); @@ -200,8 +196,6 @@ namespace datalog { m_ctx.register_predicate(m_hnf.get_fresh_predicates()[i], false); } for (unsigned i = 0; i < fmls.size(); ++i) { - DEBUG_CODE(ptr_vector sorts; - ::get_free_vars(fmls[i].get(), sorts); ); mk_horn_rule(fmls[i].get(), prs[i].get(), rules, name); } } @@ -228,7 +222,7 @@ namespace datalog { expr_ref fml1(m); if (p) { - r->to_formula(fml1); + to_formula(*r, fml1); if (fml1 == fml) { // no-op. } @@ -246,7 +240,7 @@ namespace datalog { if (p) { expr_ref fml2(m); - r->to_formula(fml2); + to_formula(*r, fml2); if (fml1 != fml2) { p = m.mk_modus_ponens(p, m.mk_rewrite(fml1, fml2)); } @@ -299,7 +293,8 @@ namespace datalog { quantifier_hoister qh(m); qh.pull_quantifier(false, q, 0, &names); // retrieve free variables. - get_free_vars(q, vars); + m_free_vars(q); + vars.append(m_free_vars.size(), m_free_vars.c_ptr()); if (vars.contains(static_cast(0))) { var_subst sub(m, false); expr_ref_vector args(m); @@ -316,7 +311,8 @@ namespace datalog { } sub(q, args.size(), args.c_ptr(), q); vars.reset(); - get_free_vars(q, vars); + m_free_vars(q); + vars.append(m_free_vars.size(), m_free_vars.c_ptr()); } SASSERT(!vars.contains(static_cast(0)) && "Unused variables have been eliminated"); @@ -498,11 +494,6 @@ namespace datalog { app * * uninterp_tail = r->m_tail; //grows upwards app * * interp_tail = r->m_tail+n; //grows downwards - DEBUG_CODE(ptr_vector sorts; - ::get_free_vars(head, sorts); - for (unsigned i = 0; i < n; ++i) { - ::get_free_vars(tail[i], sorts); - }); bool has_neg = false; @@ -556,11 +547,6 @@ namespace datalog { if (normalize) { r->norm_vars(*this); } - DEBUG_CODE(ptr_vector sorts; - ::get_free_vars(head, sorts); - for (unsigned i = 0; i < n; ++i) { - ::get_free_vars(tail[i], sorts); - }); return r; } @@ -587,6 +573,55 @@ namespace datalog { return r; } + void rule_manager::to_formula(rule const& r, expr_ref& fml) { + ast_manager & m = fml.get_manager(); + expr_ref_vector body(m); + for (unsigned i = 0; i < r.get_tail_size(); i++) { + body.push_back(r.get_tail(i)); + if (r.is_neg_tail(i)) { + body[body.size()-1] = m.mk_not(body.back()); + } + } + fml = r.get_head(); + switch (body.size()) { + case 0: break; + case 1: fml = m.mk_implies(body[0].get(), fml); break; + default: fml = m.mk_implies(m.mk_and(body.size(), body.c_ptr()), fml); break; + } + + m_free_vars(fml); + if (m_free_vars.empty()) { + return; + } + svector names; + used_symbols<> us; + m_free_vars.set_default_sort(m.mk_bool_sort()); + + us(fml); + m_free_vars.reverse(); + for (unsigned j = 0, i = 0; i < m_free_vars.size(); ++j) { + for (char c = 'A'; i < m_free_vars.size() && c <= 'Z'; ++c) { + func_decl_ref f(m); + std::stringstream _name; + _name << c; + if (j > 0) _name << j; + symbol name(_name.str().c_str()); + if (!us.contains(name)) { + names.push_back(name); + ++i; + } + } + } + fml = m.mk_forall(m_free_vars.size(), m_free_vars.c_ptr(), names.c_ptr(), fml); + } + + std::ostream& rule_manager::display_smt2(rule const& r, std::ostream & out) { + expr_ref fml(m); + to_formula(r, fml); + return out << mk_ismt2_pp(fml, m); + } + + void rule_manager::reduce_unbound_vars(rule_ref& r) { unsigned ut_len = r->get_uninterpreted_tail_size(); unsigned t_len = r->get_tail_size(); @@ -647,9 +682,7 @@ namespace datalog { svector tail_neg; app_ref head(r->get_head(), m); - collect_rule_vars(r); vctr.count_vars(m, head); - ptr_vector& free_rule_vars = m_vars; for (unsigned i = 0; i < ut_len; i++) { app * t = r->get_tail(i); @@ -658,18 +691,16 @@ namespace datalog { tail_neg.push_back(r->is_neg_tail(i)); } - ptr_vector interp_vars; var_idx_set unbound_vars; expr_ref_vector tails_with_unbound(m); for (unsigned i = ut_len; i < t_len; i++) { app * t = r->get_tail(i); - interp_vars.reset(); - ::get_free_vars(t, interp_vars); + m_free_vars(t); bool has_unbound = false; - unsigned iv_size = interp_vars.size(); + unsigned iv_size = m_free_vars.size(); for (unsigned i=0; i qsorts; qsorts.resize(q_var_cnt); unsigned q_idx = 0; - for (unsigned v = 0; v <= max_var; ++v) { - sort * v_sort = free_rule_vars[v]; + for (unsigned v = 0; v < m_free_vars.size(); ++v) { + sort * v_sort = m_free_vars[v]; if (!v_sort) { //this variable index is not used continue; @@ -780,7 +810,7 @@ namespace datalog { !new_rule.get_proof() && old_rule.get_proof()) { expr_ref fml(m); - new_rule.to_formula(fml); + to_formula(new_rule, fml); scoped_proof _sc(m); proof* p = m.mk_rewrite(m.get_fact(old_rule.get_proof()), fml); new_rule.set_proof(m, m.mk_modus_ponens(old_rule.get_proof(), p)); @@ -791,7 +821,7 @@ namespace datalog { if (m_ctx.generate_proof_trace()) { scoped_proof _scp(m); expr_ref fml(m); - r.to_formula(fml); + to_formula(r, fml); r.set_proof(m, m.mk_asserted(fml)); } } @@ -1066,57 +1096,6 @@ namespace datalog { } } - void rule::to_formula(expr_ref& fml) const { - ast_manager & m = fml.get_manager(); - expr_ref_vector body(m); - for (unsigned i = 0; i < m_tail_size; i++) { - body.push_back(get_tail(i)); - if (is_neg_tail(i)) { - body[body.size()-1] = m.mk_not(body.back()); - } - } - switch(body.size()) { - case 0: fml = m_head; break; - case 1: fml = m.mk_implies(body[0].get(), m_head); break; - default: fml = m.mk_implies(m.mk_and(body.size(), body.c_ptr()), m_head); break; - } - - ptr_vector sorts; - get_free_vars(fml, sorts); - if (sorts.empty()) { - return; - } - svector names; - used_symbols<> us; - for (unsigned i = 0; i < sorts.size(); ++i) { - if (!sorts[i]) { - sorts[i] = m.mk_bool_sort(); - } - } - - us(fml); - sorts.reverse(); - for (unsigned j = 0, i = 0; i < sorts.size(); ++j) { - for (char c = 'A'; i < sorts.size() && c <= 'Z'; ++c) { - func_decl_ref f(m); - std::stringstream _name; - _name << c; - if (j > 0) _name << j; - symbol name(_name.str().c_str()); - if (!us.contains(name)) { - names.push_back(name); - ++i; - } - } - } - fml = m.mk_forall(sorts.size(), sorts.c_ptr(), names.c_ptr(), fml); - } - - std::ostream& rule::display_smt2(ast_manager& m, std::ostream & out) const { - expr_ref fml(m); - to_formula(fml); - return out << mk_ismt2_pp(fml, m); - } bool rule_eq_proc::operator()(const rule * r1, const rule * r2) const { if (r1->get_head()!=r2->get_head()) { return false; } diff --git a/src/muz/base/dl_rule.h b/src/muz/base/dl_rule.h index 7104bae1f..e90edefa1 100644 --- a/src/muz/base/dl_rule.h +++ b/src/muz/base/dl_rule.h @@ -30,6 +30,7 @@ Revision History: #include"rewriter.h" #include"hnf.h" #include"qe_lite.h" +#include"var_subst.h" namespace datalog { @@ -64,10 +65,8 @@ namespace datalog { context& m_ctx; rule_counter m_counter; used_vars m_used; - ptr_vector m_vars; var_idx_set m_var_idx; - ptr_vector m_todo; - ast_mark m_mark; + expr_free_vars m_free_vars; app_ref_vector m_body; app_ref m_head; expr_ref_vector m_args; @@ -143,7 +142,7 @@ namespace datalog { void accumulate_vars(expr* pred); - ptr_vector& get_var_sorts() { return m_vars; } + // ptr_vector& get_var_sorts() { return m_vars; } var_idx_set& get_var_idx() { return m_var_idx; } @@ -213,11 +212,14 @@ namespace datalog { */ bool is_fact(app * head) const; - static bool is_forall(ast_manager& m, expr* e, quantifier*& q); rule_counter& get_counter() { return m_counter; } + void to_formula(rule const& r, expr_ref& result); + + std::ostream& display_smt2(rule const& r, std::ostream & out); + }; class rule : public accounted_object { @@ -306,12 +308,8 @@ namespace datalog { void get_vars(ast_manager& m, ptr_vector& sorts) const; - void to_formula(expr_ref& result) const; - void display(context & ctx, std::ostream & out) const; - std::ostream& display_smt2(ast_manager& m, std::ostream & out) const; - symbol const& name() const { return m_name; } unsigned hash() const; diff --git a/src/muz/base/dl_rule_set.h b/src/muz/base/dl_rule_set.h index c1fc7ea3f..e13d92105 100644 --- a/src/muz/base/dl_rule_set.h +++ b/src/muz/base/dl_rule_set.h @@ -39,10 +39,10 @@ namespace datalog { Each master object is also present as a key of the map, even if its master set is empty. */ - deps_type m_data; - context & m_context; + deps_type m_data; + context & m_context; ptr_vector m_todo; - ast_mark m_visited; + expr_sparse_mark m_visited; //we need to take care with removing to avoid memory leaks diff --git a/src/muz/base/dl_util.cpp b/src/muz/base/dl_util.cpp index a6647a1d2..2f60ddec8 100644 --- a/src/muz/base/dl_util.cpp +++ b/src/muz/base/dl_util.cpp @@ -56,9 +56,9 @@ namespace datalog { bool contains_var(expr * trm, unsigned var_idx) { - ptr_vector vars; - ::get_free_vars(trm, vars); - return var_idx < vars.size() && vars[var_idx] != 0; + expr_free_vars fv; + fv(trm); + return fv.contains(var_idx); } unsigned count_variable_arguments(app * pred) @@ -300,14 +300,15 @@ namespace datalog { } - void resolve_rule(replace_proof_converter* pc, rule const& r1, rule const& r2, unsigned idx, + void resolve_rule(rule_manager& rm, + replace_proof_converter* pc, rule const& r1, rule const& r2, unsigned idx, expr_ref_vector const& s1, expr_ref_vector const& s2, rule const& res) { if (!pc) return; ast_manager& m = s1.get_manager(); expr_ref fml1(m), fml2(m), fml3(m); - r1.to_formula(fml1); - r2.to_formula(fml2); - res.to_formula(fml3); + rm.to_formula(r1, fml1); + rm.to_formula(r2, fml2); + rm.to_formula(res, fml3); vector substs; svector > positions; substs.push_back(s1); @@ -337,7 +338,7 @@ namespace datalog { pc->insert(pr); } - void resolve_rule(rule const& r1, rule const& r2, unsigned idx, + void resolve_rule(rule_manager& rm, rule const& r1, rule const& r2, unsigned idx, expr_ref_vector const& s1, expr_ref_vector const& s2, rule& res) { if (!r1.get_proof()) { return; @@ -345,7 +346,7 @@ namespace datalog { SASSERT(r2.get_proof()); ast_manager& m = s1.get_manager(); expr_ref fml(m); - res.to_formula(fml); + rm.to_formula(res, fml); vector substs; svector > positions; substs.push_back(s1); diff --git a/src/muz/base/dl_util.h b/src/muz/base/dl_util.h index e3ba4b1cd..bf5c225ef 100644 --- a/src/muz/base/dl_util.h +++ b/src/muz/base/dl_util.h @@ -41,6 +41,7 @@ namespace datalog { class pentagon_relation; class relation_fact; class relation_signature; + class rule_manager; class verbose_action { unsigned m_lvl; @@ -345,17 +346,19 @@ namespace datalog { class rule_counter : public var_counter { public: - rule_counter(bool stay_non_negative = true): var_counter(stay_non_negative) {} + rule_counter(){} void count_rule_vars(ast_manager & m, const rule * r, int coef = 1); unsigned get_max_rule_var(const rule& r); }; void del_rule(horn_subsume_model_converter* mc, rule& r); - void resolve_rule(replace_proof_converter* pc, rule const& r1, rule const& r2, unsigned idx, + void resolve_rule(rule_manager& rm, + replace_proof_converter* pc, rule const& r1, rule const& r2, unsigned idx, expr_ref_vector const& s1, expr_ref_vector const& s2, rule const& res); - void resolve_rule(rule const& r1, rule const& r2, unsigned idx, + void resolve_rule(rule_manager& rm, + rule const& r1, rule const& r2, unsigned idx, expr_ref_vector const& s1, expr_ref_vector const& s2, rule& res); model_converter* mk_skip_model_converter(); diff --git a/src/muz/base/hnf.cpp b/src/muz/base/hnf.cpp index 90f5ad352..c30ca8b0e 100644 --- a/src/muz/base/hnf.cpp +++ b/src/muz/base/hnf.cpp @@ -87,6 +87,7 @@ class hnf::imp { expr_ref_vector m_body; proof_ref_vector m_defs; contains_predicate_proc m_proc; + expr_free_vars m_free_vars; public: @@ -350,13 +351,13 @@ private: } app_ref mk_fresh_head(expr* e) { - ptr_vector sorts0, sorts1; - get_free_vars(e, sorts0); + ptr_vector sorts1; + m_free_vars(e); expr_ref_vector args(m); - for (unsigned i = 0; i < sorts0.size(); ++i) { - if (sorts0[i]) { - args.push_back(m.mk_var(i, sorts0[i])); - sorts1.push_back(sorts0[i]); + for (unsigned i = 0; i < m_free_vars.size(); ++i) { + if (m_free_vars[i]) { + args.push_back(m.mk_var(i, m_free_vars[i])); + sorts1.push_back(m_free_vars[i]); } } func_decl_ref f(m); diff --git a/src/muz/bmc/dl_bmc_engine.cpp b/src/muz/bmc/dl_bmc_engine.cpp index 2ad5b3b94..1d1a59e5f 100644 --- a/src/muz/bmc/dl_bmc_engine.cpp +++ b/src/muz/bmc/dl_bmc_engine.cpp @@ -297,7 +297,7 @@ namespace datalog { vector substs; expr_ref fml(m), concl(m); - r->to_formula(fml); + rm.to_formula(*r, fml); r2 = r; rm.substitute(r2, sub.size(), sub.c_ptr()); proof_ref p(m); @@ -307,7 +307,7 @@ namespace datalog { expr_ref_vector sub2 = unifier.get_rule_subst(*r2.get(), false); apply_subst(sub, sub2); unifier.apply(*r0.get(), 0, *r2.get(), r1); - r1->to_formula(concl); + rm.to_formula(*r1.get(), concl); scoped_proof _sp(m); p = r->get_proof(); @@ -324,7 +324,7 @@ namespace datalog { r0 = r1; } else { - r2->to_formula(concl); + rm.to_formula(*r, concl); scoped_proof _sp(m); p = r->get_proof(); if (!p) { @@ -488,7 +488,7 @@ namespace datalog { return proof_ref(0, m); } TRACE("bmc", tout << "Predicate: " << pred->get_name() << "\n";); - + rule_manager& rm = b.m_ctx.get_rule_manager(); expr_ref prop_r(m), prop_v(m), fml(m), prop_body(m), tmp(m), body(m); expr_ref_vector args(m); proof_ref_vector prs(m); @@ -508,7 +508,7 @@ namespace datalog { } } SASSERT(r); - r->to_formula(fml); + rm.to_formula(*r, fml); IF_VERBOSE(1, verbose_stream() << mk_pp(fml, m) << "\n";); prs.push_back(r->get_proof()); unsigned sz = r->get_uninterpreted_tail_size(); @@ -624,11 +624,12 @@ namespace datalog { } expr_ref bind_vars(expr* e, expr* pat) { - ptr_vector vars, sorts; + ptr_vector sorts; svector names; expr_ref_vector binding(m), patterns(m); expr_ref tmp(m), head(m); - get_free_vars(e, vars); + expr_free_vars vars; + vars(e); for (unsigned i = 0; i < vars.size(); ++i) { if (vars[i]) { binding.push_back(m.mk_var(sorts.size(), vars[i])); @@ -1028,6 +1029,7 @@ namespace datalog { proof_ref get_proof(model_ref& md, app* trace, app* path) { datatype_util dtu(m); + rule_manager& rm = b.m_ctx.get_rule_manager(); sort* trace_sort = m.get_sort(trace); func_decl* p = m_sort2pred.find(trace_sort); datalog::rule_vector const& rules = b.m_rules.get_predicate_rules(p); @@ -1046,7 +1048,7 @@ namespace datalog { var_subst vs(m, false); mk_subst(*rules[i], path, trace, sub); - rules[i]->to_formula(fml); + rm.to_formula(*rules[i], fml); prs.push_back(rules[i]->get_proof()); unsigned sz = trace->get_num_args(); if (sub.empty() && sz == 0) { @@ -1219,7 +1221,7 @@ namespace datalog { vector substs; expr_ref fml(m), concl(m); - r->to_formula(fml); + rm.to_formula(*r, fml); r2 = r; rm.substitute(r2, sub.size(), sub.c_ptr()); proof_ref p(m); @@ -1237,7 +1239,7 @@ namespace datalog { expr_ref_vector sub2 = unifier.get_rule_subst(*r2.get(), false); apply_subst(sub, sub2); unifier.apply(*r0.get(), 0, *r2.get(), r1); - r1->to_formula(concl); + rm.to_formula(*r1.get(), concl); scoped_proof _sp(m); proof* premises[2] = { pr, p }; @@ -1250,7 +1252,7 @@ namespace datalog { r0 = r1; } else { - r2->to_formula(concl); + rm.to_formula(*r2.get(), concl); scoped_proof _sp(m); if (sub.empty()) { pr = p; diff --git a/src/muz/clp/clp_context.cpp b/src/muz/clp/clp_context.cpp index 0cd08e5b3..2c66c3cd5 100644 --- a/src/muz/clp/clp_context.cpp +++ b/src/muz/clp/clp_context.cpp @@ -123,14 +123,14 @@ namespace datalog { } void ground(expr_ref& e) { - ptr_vector sorts; - get_free_vars(e, sorts); - if (m_ground.size() < sorts.size()) { - m_ground.resize(sorts.size()); + expr_free_vars fv; + fv(e); + if (m_ground.size() < fv.size()) { + m_ground.resize(fv.size()); } - for (unsigned i = 0; i < sorts.size(); ++i) { - if (sorts[i] && !m_ground[i].get()) { - m_ground[i] = m.mk_fresh_const("c",sorts[i]); + for (unsigned i = 0; i < fv.size(); ++i) { + if (fv[i] && !m_ground[i].get()) { + m_ground[i] = m.mk_fresh_const("c", fv[i]); } } m_var_subst(e, m_ground.size(), m_ground.c_ptr(), e); diff --git a/src/muz/ddnf/ddnf.cpp b/src/muz/ddnf/ddnf.cpp index 6d5dd1c80..db2981f45 100644 --- a/src/muz/ddnf/ddnf.cpp +++ b/src/muz/ddnf/ddnf.cpp @@ -516,13 +516,15 @@ namespace datalog { rule_set& old_rules = m_ctx.get_rules(); rm.mk_query(query, old_rules); rule_set new_rules(m_ctx); + IF_VERBOSE(10, verbose_stream() << "(ddnf.preprocess)\n";); if (!pre_process_rules(old_rules)) { return l_undef; } + IF_VERBOSE(10, verbose_stream() << "(ddnf.compile)\n";); if (!compile_rules1(old_rules, new_rules)) { return l_undef; } - IF_VERBOSE(2, m_ddnfs.display(verbose_stream());); + IF_VERBOSE(15, m_ddnfs.display(verbose_stream());); dump_rules(new_rules); return l_undef; @@ -728,7 +730,7 @@ namespace datalog { } rule* r_new = rm.mk(head, body.size(), body.c_ptr(), 0, r.name(), false); new_rules.add_rule(r_new); - IF_VERBOSE(2, r_new->display(m_ctx, verbose_stream());); + IF_VERBOSE(20, r_new->display(m_ctx, verbose_stream());); if (old_rules.is_output_predicate(r.get_decl())) { new_rules.set_output_predicate(r_new->get_decl()); } diff --git a/src/muz/fp/dl_cmds.cpp b/src/muz/fp/dl_cmds.cpp index 827b90e60..9807cec4a 100644 --- a/src/muz/fp/dl_cmds.cpp +++ b/src/muz/fp/dl_cmds.cpp @@ -226,6 +226,7 @@ public: bool query_exn = false; lbool status = l_undef; { + IF_VERBOSE(10, verbose_stream() << "(query)\n";); scoped_ctrl_c ctrlc(eh); scoped_timer timer(timeout, &eh); cmd_context::scoped_watch sw(ctx); diff --git a/src/muz/fp/horn_tactic.cpp b/src/muz/fp/horn_tactic.cpp index 1e7a6e617..a1c556baf 100644 --- a/src/muz/fp/horn_tactic.cpp +++ b/src/muz/fp/horn_tactic.cpp @@ -334,7 +334,7 @@ class horn_tactic : public tactic { datalog::rule_set::iterator it = rules.begin(), end = rules.end(); for (; it != end; ++it) { datalog::rule* r = *it; - r->to_formula(fml); + m_ctx.get_rule_manager().to_formula(*r, fml); (*rep)(fml); g->assert_expr(fml); } diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index 00e6c0336..722661e38 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -97,8 +97,9 @@ namespace pdr { std::ostream& pred_transformer::display(std::ostream& out) const { if (!rules().empty()) out << "rules\n"; + datalog::rule_manager& rm = ctx.get_context().get_rule_manager(); for (unsigned i = 0; i < rules().size(); ++i) { - rules()[i]->display_smt2(m, out) << "\n"; + rm.display_smt2(*rules()[i], out) << "\n"; } out << "transition\n" << mk_pp(transition(), m) << "\n"; return out; @@ -149,12 +150,13 @@ namespace pdr { } datalog::rule const& pred_transformer::find_rule(model_core const& model) const { + datalog::rule_manager& rm = ctx.get_context().get_rule_manager(); obj_map::iterator it = m_tag2rule.begin(), end = m_tag2rule.end(); TRACE("pdr_verbose", for (; it != end; ++it) { expr* pred = it->m_key; tout << mk_pp(pred, m) << ":\n"; - if (it->m_value) it->m_value->display_smt2(m, tout) << "\n"; + if (it->m_value) rm.display_smt2(*it->m_value, tout) << "\n"; } ); @@ -639,14 +641,14 @@ namespace pdr { // create constants for free variables in tail. void pred_transformer::ground_free_vars(expr* e, app_ref_vector& vars, ptr_vector& aux_vars) { - ptr_vector sorts; - get_free_vars(e, sorts); - while (vars.size() < sorts.size()) { + expr_free_vars fv; + fv(e); + while (vars.size() < fv.size()) { vars.push_back(0); } - for (unsigned i = 0; i < sorts.size(); ++i) { - if (sorts[i] && !vars[i].get()) { - vars[i] = m.mk_fresh_const("aux", sorts[i]); + for (unsigned i = 0; i < fv.size(); ++i) { + if (fv[i] && !vars[i].get()) { + vars[i] = m.mk_fresh_const("aux", fv[i]); aux_vars.push_back(vars[i].get()); } } @@ -1226,7 +1228,7 @@ namespace pdr { } expr_ref fml_concl(m); - reduced_rule->to_formula(fml_concl); + rm.to_formula(*reduced_rule.get(), fml_concl); p1 = m.mk_hyper_resolve(pfs.size(), pfs.c_ptr(), fml_concl, positions, substs); } @@ -1558,6 +1560,7 @@ namespace pdr { ex.to_model(model); decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); var_subst vs(m, false); + expr_free_vars fv; for (; it != end; ++it) { ptr_vector const& rules = it->m_value->rules(); for (unsigned i = 0; i < rules.size(); ++i) { @@ -1575,18 +1578,15 @@ namespace pdr { fmls.push_back(r.get_tail(j)); } tmp = m.mk_and(fmls.size(), fmls.c_ptr()); - ptr_vector sorts; svector names; - get_free_vars(tmp, sorts); - for (unsigned i = 0; i < sorts.size(); ++i) { - if (!sorts[i]) { - sorts[i] = m.mk_bool_sort(); - } + fv(tmp); + fv.set_default_sort(m.mk_bool_sort()); + for (unsigned i = 0; i < fv.size(); ++i) { names.push_back(symbol(i)); } - sorts.reverse(); - if (!sorts.empty()) { - tmp = m.mk_exists(sorts.size(), sorts.c_ptr(), names.c_ptr(), tmp); + fv.reverse(); + if (!fv.empty()) { + tmp = m.mk_exists(fv.size(), fv.c_ptr(), names.c_ptr(), tmp); } smt::kernel solver(m, get_fparams()); solver.assert_expr(tmp); diff --git a/src/muz/pdr/pdr_generalizers.cpp b/src/muz/pdr/pdr_generalizers.cpp index 7c2557260..8b6f6a4c6 100644 --- a/src/muz/pdr/pdr_generalizers.cpp +++ b/src/muz/pdr/pdr_generalizers.cpp @@ -558,7 +558,6 @@ namespace pdr { { expr_ref_vector conj(m), sub(m); expr_ref result(m); - ptr_vector sorts; svector names; unsigned ut_size = rule.get_uninterpreted_tail_size(); unsigned t_size = rule.get_tail_size(); @@ -599,16 +598,15 @@ namespace pdr { expr_ref tmp = result; var_subst(m, false)(tmp, sub.size(), sub.c_ptr(), result); } - get_free_vars(result, sorts); - for (unsigned i = 0; i < sorts.size(); ++i) { - if (!sorts[i]) { - sorts[i] = m.mk_bool_sort(); - } - names.push_back(symbol(sorts.size() - i - 1)); + expr_free_vars fv; + fv(result); + fv.set_default_sort(m.mk_bool_sort()); + for (unsigned i = 0; i < fv.size(); ++i) { + names.push_back(symbol(fv.size() - i - 1)); } - if (!sorts.empty()) { - sorts.reverse(); - result = m.mk_exists(sorts.size(), sorts.c_ptr(), names.c_ptr(), result); + if (!fv.empty()) { + fv.reverse(); + result = m.mk_exists(fv.size(), fv.c_ptr(), names.c_ptr(), result); } return result; } diff --git a/src/muz/pdr/pdr_manager.cpp b/src/muz/pdr/pdr_manager.cpp index bda54dbd7..c029d1b16 100644 --- a/src/muz/pdr/pdr_manager.cpp +++ b/src/muz/pdr/pdr_manager.cpp @@ -119,7 +119,7 @@ namespace pdr { } - void inductive_property::display(ptr_vector const& rules, std::ostream& out) const { + void inductive_property::display(datalog::rule_manager& rm, ptr_vector const& rules, std::ostream& out) const { func_decl_set bound_decls, aux_decls; collect_decls_proc collect_decls(bound_decls, aux_decls); @@ -153,7 +153,7 @@ namespace pdr { for (unsigned i = 0; i < rules.size(); ++i) { out << "(push)\n"; out << "(assert (not\n"; - rules[i]->display_smt2(m, out); + rm.display_smt2(*rules[i], out); out << "))\n"; out << "(check-sat)\n"; out << "(pop)\n"; diff --git a/src/muz/pdr/pdr_manager.h b/src/muz/pdr/pdr_manager.h index 0e8e890e8..f892e4d97 100644 --- a/src/muz/pdr/pdr_manager.h +++ b/src/muz/pdr/pdr_manager.h @@ -70,8 +70,8 @@ namespace pdr { expr_ref to_expr() const; void to_model(model_ref& md) const; - - void display(ptr_vector const& rules, std::ostream& out) const; + + void display(datalog::rule_manager& rm, ptr_vector const& rules, std::ostream& out) const; }; class manager diff --git a/src/muz/rel/dl_compiler.cpp b/src/muz/rel/dl_compiler.cpp index 276e7b836..4f8be942d 100644 --- a/src/muz/rel/dl_compiler.cpp +++ b/src/muz/rel/dl_compiler.cpp @@ -184,7 +184,7 @@ namespace datalog { TRACE("dl", tout << "Adding unbound column " << mk_pp(pred, m_context.get_manager()) << "\n";); IF_VERBOSE(3, { expr_ref e(m_context.get_manager()); - compiled_rule->to_formula(e); + m_context.get_rule_manager().to_formula(*compiled_rule, e); verbose_stream() << "Compiling unsafe rule column " << col_idx << "\n" << mk_ismt2_pp(e, m_context.get_manager()) << "\n"; }); @@ -641,14 +641,14 @@ namespace datalog { if (!tail.empty()) { app_ref filter_cond(tail.size() == 1 ? to_app(tail.back()) : m.mk_and(tail.size(), tail.c_ptr()), m); ptr_vector filter_vars; - get_free_vars(filter_cond, filter_vars); + m_free_vars(filter_cond); // create binding expr_ref_vector binding(m); - binding.resize(filter_vars.size()+1); + binding.resize(m_free_vars.size()+1); - for (unsigned v = 0; v < filter_vars.size(); ++v) { - if (!filter_vars[v]) + for (unsigned v = 0; v < m_free_vars.size(); ++v) { + if (!m_free_vars[v]) continue; int2ints::entry * entry = var_indexes.find_core(v); @@ -657,7 +657,7 @@ namespace datalog { src_col = entry->get_data().m_value.back(); } else { // we have an unbound variable, so we add an unbound column for it - relation_sort unbound_sort = filter_vars[v]; + relation_sort unbound_sort = m_free_vars[v]; reg_idx new_reg; bool new_dealloc; @@ -674,19 +674,18 @@ namespace datalog { entry->get_data().m_value.push_back(src_col); } relation_sort var_sort = m_reg_signatures[filtered_res][src_col]; - binding[filter_vars.size()-v] = m.mk_var(src_col, var_sort); + binding[m_free_vars.size()-v] = m.mk_var(src_col, var_sort); } // check if there are any columns to remove unsigned_vector remove_columns; { unsigned_vector var_idx_to_remove; - ptr_vector vars; - get_free_vars(r->get_head(), vars); + m_free_vars(r->get_head()); for (int2ints::iterator I = var_indexes.begin(), E = var_indexes.end(); I != E; ++I) { unsigned var_idx = I->m_key; - if (!vars.get(var_idx, 0)) { + if (!m_free_vars.contains(var_idx)) { unsigned_vector & cols = I->m_value; for (unsigned i = 0; i < cols.size(); ++i) { remove_columns.push_back(cols[i]); @@ -745,10 +744,9 @@ namespace datalog { unsigned ft_len=r->get_tail_size(); //full tail for(unsigned tail_index=ut_len; tail_indexget_tail(tail_index); - ptr_vector t_vars; - ::get_free_vars(t, t_vars); + m_free_vars(t); - if(t_vars.empty()) { + if (m_free_vars.empty()) { expr_ref simplified(m); m_context.get_rewriter()(t, simplified); if(m.is_true(simplified)) { @@ -761,23 +759,22 @@ namespace datalog { } //determine binding size - while (!t_vars.back()) { - t_vars.pop_back(); - } - unsigned max_var = t_vars.size(); + + unsigned max_var = m_free_vars.size(); + while (max_var > 0 && !m_free_vars[max_var-1]) --max_var; //create binding expr_ref_vector binding(m); - binding.resize(max_var+1); + binding.resize(max_var); - for(unsigned v = 0; v < t_vars.size(); ++v) { - if (!t_vars[v]) { + for(unsigned v = 0; v < max_var; ++v) { + if (!m_free_vars[v]) { continue; } int2ints::entry * e = var_indexes.find_core(v); if(!e) { //we have an unbound variable, so we add an unbound column for it - relation_sort unbound_sort = t_vars[v]; + relation_sort unbound_sort = m_free_vars[v]; reg_idx new_reg; TRACE("dl", tout << mk_pp(head_pred, m_context.get_manager()) << "\n";); diff --git a/src/muz/rel/dl_compiler.h b/src/muz/rel/dl_compiler.h index e0f9af424..92f50eb02 100644 --- a/src/muz/rel/dl_compiler.h +++ b/src/muz/rel/dl_compiler.h @@ -111,12 +111,13 @@ namespace datalog { */ instruction_block & m_top_level_code; pred2idx m_pred_regs; - reg_idx m_new_reg; - vector m_reg_signatures; - obj_pair_map m_constant_registers; + reg_idx m_new_reg; + vector m_reg_signatures; + obj_pair_map m_constant_registers; obj_pair_map m_total_registers; - obj_map m_empty_tables_registers; - instruction_observer m_instruction_observer; + obj_map m_empty_tables_registers; + instruction_observer m_instruction_observer; + expr_free_vars m_free_vars; /** If true, the union operation on the underlying structure only provides the information diff --git a/src/muz/rel/dl_mk_simple_joins.cpp b/src/muz/rel/dl_mk_simple_joins.cpp index c2214dad9..e33de8c6d 100644 --- a/src/muz/rel/dl_mk_simple_joins.cpp +++ b/src/muz/rel/dl_mk_simple_joins.cpp @@ -326,7 +326,7 @@ namespace datalog { for(unsigned i=0; iget_tail(i)); } - for(unsigned i=0; iget_tail(i); var_idx_set t1_vars = rm.collect_vars(t1); counter.count_vars(m, t1, -1); //temporarily remove t1 variables from counter diff --git a/src/muz/rel/dl_relation_manager.cpp b/src/muz/rel/dl_relation_manager.cpp index 3c034ff0f..f5795df0c 100644 --- a/src/muz/rel/dl_relation_manager.cpp +++ b/src/muz/rel/dl_relation_manager.cpp @@ -1405,7 +1405,7 @@ namespace datalog { dl_decl_util & m_decl_util; th_rewriter & m_simp; app_ref m_condition; - ptr_vector m_var_sorts; + expr_free_vars m_free_vars; expr_ref_vector m_args; public: default_table_filter_interpreted_fn(context & ctx, unsigned col_cnt, app* condition) @@ -1415,8 +1415,7 @@ namespace datalog { m_simp(ctx.get_rewriter()), m_condition(condition, ctx.get_manager()), m_args(ctx.get_manager()) { - m_var_sorts.resize(col_cnt); - get_free_vars(m_condition, m_var_sorts); + m_free_vars(m_condition); } virtual bool should_remove(const table_fact & f) const { @@ -1426,14 +1425,13 @@ namespace datalog { //arguments need to be in reverse order for the substitution unsigned col_cnt = f.size(); for(int i=col_cnt-1;i>=0;i--) { - sort * var_sort = m_var_sorts[i]; - if(!var_sort) { + if(!m_free_vars.contains(i)) { args.push_back(0); continue; //this variable does not occur in the condition; } table_element el = f[i]; - args.push_back(m_decl_util.mk_numeral(el, var_sort)); + args.push_back(m_decl_util.mk_numeral(el, m_free_vars[i])); } expr_ref ground(m_ast_manager); diff --git a/src/muz/tab/tab_context.cpp b/src/muz/tab/tab_context.cpp index 83842a68b..d75ebe20e 100644 --- a/src/muz/tab/tab_context.cpp +++ b/src/muz/tab/tab_context.cpp @@ -216,11 +216,13 @@ namespace tb { } void get_free_vars(ptr_vector& vars) const { - ::get_free_vars(m_head, vars); + expr_free_vars fv; + fv(m_head); for (unsigned i = 0; i < m_predicates.size(); ++i) { - ::get_free_vars(m_predicates[i], vars); + fv.accumulate(m_predicates[i]); } - ::get_free_vars(m_constraint, vars); + fv.accumulate(m_constraint); + vars.append(fv.size(), fv.c_ptr()); } expr_ref to_formula() const { @@ -1107,16 +1109,16 @@ namespace tb { m_S1.apply(2, delta, expr_offset(tgt.get_constraint(), 0), tmp); m_S1.apply(2, delta, expr_offset(src.get_constraint(), 1), tmp2); constraint = m.mk_and(tmp, tmp2); - ptr_vector vars; // perform trival quantifier-elimination: uint_set index_set; - get_free_vars(head, vars); + expr_free_vars fv; + fv(head); for (unsigned i = 0; i < predicates.size(); ++i) { - get_free_vars(predicates[i].get(), vars); + fv.accumulate(predicates[i].get()); } - for (unsigned i = 0; i < vars.size(); ++i) { - if (vars[i]) { + for (unsigned i = 0; i < fv.size(); ++i) { + if (fv[i]) { index_set.insert(i); } } @@ -1127,7 +1129,7 @@ namespace tb { // initialize rule. result->init(head, predicates, constraint); - vars.reset(); + ptr_vector vars; result->get_free_vars(vars); bool change = false; var_ref w(m); diff --git a/src/muz/transforms/dl_mk_array_blast.cpp b/src/muz/transforms/dl_mk_array_blast.cpp index 641d40779..fb860f2ac 100644 --- a/src/muz/transforms/dl_mk_array_blast.cpp +++ b/src/muz/transforms/dl_mk_array_blast.cpp @@ -294,7 +294,7 @@ namespace datalog { if (m_simplifier.transform_rule(new_rules.last(), new_rule)) { if (r.get_proof()) { scoped_proof _sc(m); - r.to_formula(fml1); + rm.to_formula(r, fml1); p = m.mk_rewrite(fml1, fml2); p = m.mk_modus_ponens(r.get_proof(), p); new_rule->set_proof(m, p); diff --git a/src/muz/transforms/dl_mk_bit_blast.cpp b/src/muz/transforms/dl_mk_bit_blast.cpp index fd1dbb205..fcd20d78f 100644 --- a/src/muz/transforms/dl_mk_bit_blast.cpp +++ b/src/muz/transforms/dl_mk_bit_blast.cpp @@ -225,7 +225,6 @@ namespace datalog { mk_interp_tail_simplifier m_simplifier; bit_blaster_rewriter m_blaster; expand_mkbv m_rewriter; - bool blast(rule *r, expr_ref& fml) { proof_ref pr(m); @@ -235,7 +234,7 @@ namespace datalog { if (!m_simplifier.transform_rule(r, r2)) { r2 = r; } - r2->to_formula(fml1); + m_context.get_rule_manager().to_formula(*r2.get(), fml1); m_blaster(fml1, fml2, pr); m_rewriter(fml2, fml3); TRACE("dl", tout << mk_pp(fml, m) << " -> " << mk_pp(fml2, m) << " -> " << mk_pp(fml3, m) << "\n";); @@ -274,7 +273,7 @@ namespace datalog { m_rewriter.m_cfg.set_dst(result); for (unsigned i = 0; !m_context.canceled() && i < sz; ++i) { rule * r = source.get_rule(i); - r->to_formula(fml); + rm.to_formula(*r, fml); if (blast(r, fml)) { proof_ref pr(m); if (r->get_proof()) { diff --git a/src/muz/transforms/dl_mk_coalesce.cpp b/src/muz/transforms/dl_mk_coalesce.cpp index ac7a58d8d..7476a5655 100644 --- a/src/muz/transforms/dl_mk_coalesce.cpp +++ b/src/muz/transforms/dl_mk_coalesce.cpp @@ -134,9 +134,9 @@ namespace datalog { is_neg.push_back(false); res = rm.mk(head, tail.size(), tail.c_ptr(), is_neg.c_ptr(), tgt->name()); if (m_ctx.generate_proof_trace()) { - src.to_formula(fml1); - tgt->to_formula(fml2); - res->to_formula(fml); + rm.to_formula(src, fml1); + rm.to_formula(*tgt.get(),fml2); + rm.to_formula(*res.get(),fml); #if 0 sort* ps = m.mk_proof_sort(); sort* domain[3] = { ps, ps, m.mk_bool_sort() }; diff --git a/src/muz/transforms/dl_mk_quantifier_instantiation.cpp b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp index fcb8d7b85..afb22e55f 100644 --- a/src/muz/transforms/dl_mk_quantifier_instantiation.cpp +++ b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp @@ -238,7 +238,7 @@ namespace datalog { proof* p1 = r.get_proof(); for (unsigned i = 0; i < added_rules.get_num_rules(); ++i) { rule* r2 = added_rules.get_rule(i); - r2->to_formula(fml); + rm.to_formula(*r2, fml); pr = m.mk_modus_ponens(m.mk_def_axiom(m.mk_implies(m.get_fact(p1), fml)), p1); r2->set_proof(m, pr); } diff --git a/src/muz/transforms/dl_mk_rule_inliner.cpp b/src/muz/transforms/dl_mk_rule_inliner.cpp index 366547575..d3eb24b9a 100644 --- a/src/muz/transforms/dl_mk_rule_inliner.cpp +++ b/src/muz/transforms/dl_mk_rule_inliner.cpp @@ -179,7 +179,7 @@ namespace datalog { if (m_context.generate_proof_trace()) { expr_ref_vector s1 = m_unifier.get_rule_subst(tgt, true); expr_ref_vector s2 = m_unifier.get_rule_subst(src, false); - datalog::resolve_rule(tgt, src, tail_index, s1, s2, *res.get()); + datalog::resolve_rule(m_rm, tgt, src, tail_index, s1, s2, *res.get()); } return true; } diff --git a/src/muz/transforms/dl_mk_separate_negated_tails.cpp b/src/muz/transforms/dl_mk_separate_negated_tails.cpp index 782e1011d..9a78c0d4d 100644 --- a/src/muz/transforms/dl_mk_separate_negated_tails.cpp +++ b/src/muz/transforms/dl_mk_separate_negated_tails.cpp @@ -37,10 +37,10 @@ namespace datalog { void mk_separate_negated_tails::get_private_vars(rule const& r, unsigned j) { m_vars.reset(); m_fv.reset(); - get_free_vars(r.get_head(), m_fv); + m_fv(r.get_head()); for (unsigned i = 0; i < r.get_tail_size(); ++i) { if (i != j) { - get_free_vars(r.get_tail(i), m_fv); + m_fv.accumulate(r.get_tail(i)); } } @@ -49,7 +49,7 @@ namespace datalog { expr* v = p->get_arg(i); if (is_var(v)) { unsigned idx = to_var(v)->get_idx(); - if (idx >= m_fv.size() || !m_fv[idx]) { + if (!m_fv.contains(idx)) { m_vars.push_back(v); } } diff --git a/src/muz/transforms/dl_mk_separate_negated_tails.h b/src/muz/transforms/dl_mk_separate_negated_tails.h index 8cd806f43..03a52c997 100644 --- a/src/muz/transforms/dl_mk_separate_negated_tails.h +++ b/src/muz/transforms/dl_mk_separate_negated_tails.h @@ -42,7 +42,7 @@ namespace datalog { rule_manager& rm; context & m_ctx; ptr_vector m_vars; - ptr_vector m_fv; + expr_free_vars m_fv; bool has_private_vars(rule const& r, unsigned j); void get_private_vars(rule const& r, unsigned j); diff --git a/src/muz/transforms/dl_mk_slice.cpp b/src/muz/transforms/dl_mk_slice.cpp index 0df75324d..f162d550f 100644 --- a/src/muz/transforms/dl_mk_slice.cpp +++ b/src/muz/transforms/dl_mk_slice.cpp @@ -120,7 +120,7 @@ namespace datalog { obj_map::iterator end = m_rule2slice.end(); expr_ref fml(m); for (; it != end; ++it) { - it->m_value->to_formula(fml); + rm.to_formula(*it->m_value, fml); m_pinned_exprs.push_back(fml); TRACE("dl", tout << "orig: " << mk_pp(fml, m) << "\n"; @@ -238,7 +238,7 @@ namespace datalog { r3->display(m_ctx, tout << "res:");); r1 = r3; } - r1->to_formula(concl); + rm.to_formula(*r1.get(), concl); proof* new_p = m.mk_hyper_resolve(premises.size(), premises.c_ptr(), concl, positions, substs); m_pinned_exprs.push_back(new_p); m_pinned_rules.push_back(r1.get()); @@ -676,10 +676,10 @@ namespace datalog { } void mk_slice::add_free_vars(uint_set& result, expr* e) { - ptr_vector sorts; - get_free_vars(e, sorts); - for (unsigned i = 0; i < sorts.size(); ++i) { - if (sorts[i]) { + expr_free_vars fv; + fv(e); + for (unsigned i = 0; i < fv.size(); ++i) { + if (fv[i]) { result.insert(i); } } @@ -773,14 +773,11 @@ namespace datalog { init_vars(r); app_ref_vector tail(m); app_ref head(m); - ptr_vector sorts; update_predicate(r.get_head(), head); - get_free_vars(head.get(), sorts); for (unsigned i = 0; i < r.get_uninterpreted_tail_size(); ++i) { app_ref t(m); update_predicate(r.get_tail(i), t); tail.push_back(t); - get_free_vars(t, sorts); } expr_ref_vector conjs = get_tail_conjs(r); diff --git a/src/muz/transforms/dl_mk_unfold.cpp b/src/muz/transforms/dl_mk_unfold.cpp index a9357f88a..cc460bca1 100644 --- a/src/muz/transforms/dl_mk_unfold.cpp +++ b/src/muz/transforms/dl_mk_unfold.cpp @@ -43,7 +43,7 @@ namespace datalog { m_unify.apply(r, tail_idx, r2, new_rule)) { expr_ref_vector s1 = m_unify.get_rule_subst(r, true); expr_ref_vector s2 = m_unify.get_rule_subst(r2, false); - resolve_rule(r, r2, tail_idx, s1, s2, *new_rule.get()); + resolve_rule(rm, r, r2, tail_idx, s1, s2, *new_rule.get()); expand_tail(*new_rule.get(), tail_idx+r2.get_uninterpreted_tail_size(), src, dst); } } diff --git a/src/qe/qe.cpp b/src/qe/qe.cpp index e8fffd57e..17a1ccb1d 100644 --- a/src/qe/qe.cpp +++ b/src/qe/qe.cpp @@ -2271,17 +2271,14 @@ namespace qe { void expr_quant_elim::instantiate_expr(expr_ref_vector& bound, expr_ref& fml) { - ptr_vector sorts; - get_free_vars(fml, sorts); - if (!sorts.empty()) { + expr_free_vars fv; + fv(fml); + fv.set_default_sort(m.mk_bool_sort()); + if (!fv.empty()) { expr_ref tmp(m); - for (unsigned i = sorts.size(); i > 0;) { + for (unsigned i = fv.size(); i > 0;) { --i; - sort* s = sorts[i]; - if (!s) { - s = m.mk_bool_sort(); - } - bound.push_back(m.mk_fresh_const("bound", s)); + bound.push_back(m.mk_fresh_const("bound", fv[i])); } var_subst subst(m); subst(fml, bound.size(), bound.c_ptr(), tmp); diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 1c38ca343..cd043c8a7 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -87,6 +87,7 @@ namespace smt { typedef typename Ext::numeral numeral; typedef typename Ext::inf_numeral inf_numeral; typedef vector numeral_vector; + typedef map, default_eq > rational2var; static const int dead_row_id = -1; protected: diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 3d95f1c72..9dae2d0c4 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -2993,7 +2993,6 @@ namespace smt { */ template void theory_arith::refine_epsilon() { - typedef map, default_eq > rational2var; while (true) { rational2var mapping; theory_var num = get_num_vars(); @@ -3001,6 +3000,8 @@ namespace smt { for (theory_var v = 0; v < num; v++) { if (is_int(v)) continue; + if (!get_context().is_shared(get_enode(v))) + continue; inf_numeral const & val = get_value(v); if (Ext::is_infinite(val)) { continue; diff --git a/src/tactic/horn_subsume_model_converter.cpp b/src/tactic/horn_subsume_model_converter.cpp index ced4e657b..25da094fa 100644 --- a/src/tactic/horn_subsume_model_converter.cpp +++ b/src/tactic/horn_subsume_model_converter.cpp @@ -43,7 +43,7 @@ bool horn_subsume_model_converter::mk_horn( app* head, expr* body, func_decl_ref& pred, expr_ref& body_res) { expr_ref_vector conjs(m), subst(m); - ptr_vector sorts, sorts2; + ptr_vector sorts2; var_subst vs(m, false); if (!is_uninterp(head)) { @@ -53,28 +53,27 @@ bool horn_subsume_model_converter::mk_horn( pred = head->get_decl(); unsigned arity = head->get_num_args(); - get_free_vars(head, sorts); - get_free_vars(body, sorts); + expr_free_vars fv; + fv(head); + fv.accumulate(body); - if (arity == 0 && sorts.empty()) { + if (arity == 0 && fv.empty()) { body_res = body; return true; } + fv.set_default_sort(m.mk_bool_sort()); svector names; - for (unsigned i = 0; i < sorts.size(); ++i) { - if (!sorts[i]) { - sorts[i] = m.mk_bool_sort(); - } + for (unsigned i = 0; i < fv.size(); ++i) { names.push_back(symbol(i)); } names.reverse(); - sorts.reverse(); + fv.reverse(); conjs.push_back(body); for (unsigned i = 0; i < arity; ++i) { expr* arg = head->get_arg(i); var_ref v(m); - v = m.mk_var(sorts.size()+i, m.get_sort(arg)); + v = m.mk_var(fv.size()+i, m.get_sort(arg)); if (is_var(arg)) { unsigned w = to_var(arg)->get_idx(); @@ -101,12 +100,12 @@ bool horn_subsume_model_converter::mk_horn( vs(tmp, subst.size(), subst.c_ptr(), body_expr); } - if (sorts.empty()) { + if (fv.empty()) { SASSERT(subst.empty()); body_res = body_expr; } else { - body_res = m.mk_exists(sorts.size(), sorts.c_ptr(), names.c_ptr(), body_expr.get()); + body_res = m.mk_exists(fv.size(), fv.c_ptr(), names.c_ptr(), body_expr.get()); m_rewrite(body_res); } @@ -120,10 +119,9 @@ bool horn_subsume_model_converter::mk_horn( bool horn_subsume_model_converter::mk_horn( expr* clause, func_decl_ref& pred, expr_ref& body) { - ptr_vector sorts; // formula is closed. - DEBUG_CODE(get_free_vars(clause, sorts); SASSERT(sorts.empty());); + DEBUG_CODE(expr_free_vars fv; fv(clause); SASSERT(fv.empty());); while (is_quantifier(clause) && to_quantifier(clause)->is_forall()) { quantifier* q = to_quantifier(clause); From cd12fa8461a9c2e973e95168abeb69c8c94fb10b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 15 Sep 2014 20:00:45 -0700 Subject: [PATCH 527/925] adding fixed size bit-vectors Signed-off-by: Nikolaj Bjorner --- src/test/fixed_bit_vector.cpp | 118 ++++++++++++++++++++++++++ src/test/main.cpp | 1 + src/util/fixed_bit_vector.cpp | 151 ++++++++++++++++++++++++++++++++++ src/util/fixed_bit_vector.h | 118 ++++++++++++++++++++++++++ 4 files changed, 388 insertions(+) create mode 100644 src/test/fixed_bit_vector.cpp create mode 100644 src/util/fixed_bit_vector.cpp create mode 100644 src/util/fixed_bit_vector.h diff --git a/src/test/fixed_bit_vector.cpp b/src/test/fixed_bit_vector.cpp new file mode 100644 index 000000000..01d60c347 --- /dev/null +++ b/src/test/fixed_bit_vector.cpp @@ -0,0 +1,118 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + fixed_bit_vector.cpp + +Abstract: + + Test fixed-size bit vector module + +Author: + + Nikolaj Bjorner (nbjorner) 2014-9-15. + +Revision History: + + based on bit_vector.cpp + +--*/ +#include +#include +#include"fixed_bit_vector.h" +#include"vector.h" + + +static void tst1() { + fixed_bit_vector_manager m(30); + fixed_bit_vector *b; + b = m.allocate0(); + b->set(0, true); + b->set(1, false); + b->set(2, true); + SASSERT(b->get(0) == true); + SASSERT(b->get(1) == false); + SASSERT(b->get(2) == true); + SASSERT(b->get(3) == false); + SASSERT(b->get(29) == false); + m.deallocate(b); +} + +static void tst_or() { + { + fixed_bit_vector_manager m(10); + fixed_bit_vector *b1, *b2; + b1 = m.allocate0(); + b2 = m.allocate0(); + + b1->set(4); + b2->set(8); + b2->set(3); + b2->set(2); + b2->set(1); + m.display(std::cout, *b1) << "\n"; + m.display(std::cout, *b2) << "\n"; + m.set_or(*b1, *b2); + m.display(std::cout, *b1) << "\n"; + SASSERT(!m.equals(*b1, *b2)); + b1->unset(4); + SASSERT(m.equals(*b1, *b2)); + b1->unset(3); + SASSERT(!m.equals(*b1, *b2)); + m.deallocate(b1); + m.deallocate(b2); + } +} + +static void tst_and() { + +} + + + +static void tst_eq(unsigned num_bits) { + fixed_bit_vector_manager m(num_bits); + fixed_bit_vector* b1 = m.allocate0(); + fixed_bit_vector* b2 = m.allocate0(); + fixed_bit_vector* b3 = m.allocate0(); + + b1->set(3, true); + SASSERT(!m.equals(*b1, *b2)); + SASSERT(m.equals(*b2, *b3)); + + b3->set(3, true); + SASSERT(m.equals(*b1, *b3)); + + b2->set(num_bits-1, true); + b3->set(num_bits-1); + b3->unset(3); + SASSERT(m.equals(*b2, *b3)); + m.fill0(*b1); + m.set_neg(*b1); + m.fill1(*b2); + SASSERT(m.equals(*b1, *b2)); + m.fill0(*b1); + for (unsigned i = 0; i < num_bits; ++i) { + b1->set(i, true); + } + SASSERT(m.equals(*b1, *b2)); + m.deallocate(b1); + m.deallocate(b2); + m.deallocate(b3); +} + +void tst_fixed_bit_vector() { + tst1(); + tst_or(); + tst_and(); + tst_eq(15); + tst_eq(16); + tst_eq(17); + tst_eq(31); + tst_eq(32); + tst_eq(33); + tst_eq(63); + tst_eq(64); + tst_eq(65); +} diff --git a/src/test/main.cpp b/src/test/main.cpp index d97a94a16..e58845bcf 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -140,6 +140,7 @@ int main(int argc, char ** argv) { TST(ast); TST(optional); TST(bit_vector); + TST(fixed_bit_vector); TST(string_buffer); TST(map); TST(diff_logic); diff --git a/src/util/fixed_bit_vector.cpp b/src/util/fixed_bit_vector.cpp new file mode 100644 index 000000000..c674bafda --- /dev/null +++ b/src/util/fixed_bit_vector.cpp @@ -0,0 +1,151 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + fixed_bit_vector.cpp + +Abstract: + + Simple bitvector implementation for fixed size bit-vectors. + +Author: + + Nikolaj Bjorner (nbjorner) 2014-9-15. + Leonardo de Moura (leonardo) 2006-10-03. + +Revision History: + Based on bit_vector.cpp + +--*/ + +#include +#include"fixed_bit_vector.h" +#include"trace.h" +#include"hash.h" + + +fixed_bit_vector_manager::fixed_bit_vector_manager(unsigned num_bits): + m_alloc("fixed_bit_vector") { + m_num_bits = num_bits; + m_num_words = num_words(num_bits); + m_num_bytes = m_num_words * sizeof(unsigned); + unsigned bit_rest = m_num_bits % 32; + m_mask = (1U << bit_rest) - 1; + if (m_mask == 0) m_mask = UINT_MAX; +} + + +fixed_bit_vector* fixed_bit_vector_manager::allocate() { + return static_cast(m_alloc.allocate(m_num_bytes)); +} + +fixed_bit_vector* fixed_bit_vector_manager::allocate0() { + fixed_bit_vector* result = allocate(); + fill0(*result); + return result; +} + +fixed_bit_vector* fixed_bit_vector_manager::allocate1() { + fixed_bit_vector* result = allocate(); + fill1(*result); + return result; +} + +fixed_bit_vector* fixed_bit_vector_manager::allocate(fixed_bit_vector& bv) { + fixed_bit_vector* result = allocate(); + copy(*result, bv); + return result; +} + +void fixed_bit_vector_manager::deallocate(fixed_bit_vector* bv) { + m_alloc.deallocate(m_num_bytes, bv); +} + + +void fixed_bit_vector_manager::copy(fixed_bit_vector& dst, fixed_bit_vector const& src) const { + memcpy(dst.m_data, src.m_data, num_bytes()); +} + + +fixed_bit_vector& +fixed_bit_vector_manager::fill0(fixed_bit_vector& bv) const { + memset(bv.m_data, 0, num_bytes()); + return bv; +} + +fixed_bit_vector& +fixed_bit_vector_manager::fill1(fixed_bit_vector& bv) const { + memset(bv.m_data, 0xFF, num_bytes()); + return bv; +} + +fixed_bit_vector& +fixed_bit_vector_manager::set_and(fixed_bit_vector& dst, fixed_bit_vector const& src) const { + for (unsigned i = 0; i < m_num_words; i++) + dst.m_data[i] &= src.m_data[i]; + return dst; +} + +fixed_bit_vector& +fixed_bit_vector_manager::set_or(fixed_bit_vector& dst, fixed_bit_vector const& src) const { + for (unsigned i = 0; i < m_num_words; i++) + dst.m_data[i] |= src.m_data[i]; + return dst; +} + +fixed_bit_vector& +fixed_bit_vector_manager::set_neg(fixed_bit_vector& dst) const { + for (unsigned i = 0; i < m_num_words; i++) + dst.m_data[i] = ~dst.m_data[i]; + return dst; +} + +unsigned fixed_bit_vector_manager::last_word(fixed_bit_vector const& bv) const { + unsigned n = num_words(); + if (n == 0) return 0; + return bv.m_data[n-1] & m_mask; +} + +bool fixed_bit_vector_manager::equals(fixed_bit_vector const& a, fixed_bit_vector const& b) const { + if (&a == &b) return true; + unsigned n = num_words(); + if (n == 0) + return true; + for (unsigned i = 0; i < n - 1; i++) { + if (a.m_data[i] != b.m_data[i]) + return false; + } + return last_word(a) == last_word(b); +} +unsigned fixed_bit_vector_manager::hash(fixed_bit_vector const& src) const { + return string_hash(reinterpret_cast(src.m_data), num_bits()/8, num_bits()); +} + +bool fixed_bit_vector_manager::contains(fixed_bit_vector const& a, fixed_bit_vector const& b) const { + unsigned n = num_words(); + if (n == 0) + return true; + + for (unsigned i = 0; i < n - 1; ++i) { + if ((a.m_data[i] & b.m_data[i]) != b.m_data[i]) + return false; + } + unsigned b_data = last_word(b); + return (last_word(a) & b_data) == b_data; +} + +std::ostream& fixed_bit_vector_manager::display(std::ostream& out, fixed_bit_vector const& b) const { + unsigned i = num_bits(); + while (i > 0) { + --i; + if (b.get(i)) + out << "1"; + else + out << "0"; + } + return out; +} + + + diff --git a/src/util/fixed_bit_vector.h b/src/util/fixed_bit_vector.h new file mode 100644 index 000000000..636c03e1b --- /dev/null +++ b/src/util/fixed_bit_vector.h @@ -0,0 +1,118 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + fixed_bit_vector.h + +Abstract: + + Simple bitvector implementation for fixed size bit-vectors. + +Author: + + Nikolaj Bjorner (nbjorner) 2014-9-15. + +Revision History: + + Related to bit_vector, but is based on a manager. + +--*/ +#ifndef _FIXED_BIT_VECTOR_H_ +#define _FIXED_BIT_VECTOR_H_ + +#include +#include"debug.h" +#include"small_object_allocator.h" + +class fixed_bit_vector; +class fixed_bit_vector_manager { + friend class fixed_bit_vector; + small_object_allocator m_alloc; + unsigned m_num_bits; + unsigned m_num_bytes; + unsigned m_num_words; + unsigned m_mask; + unsigned num_bytes() const { return m_num_bytes; } + + static unsigned num_words(unsigned num_bits) { + return (num_bits + 31) / 32; + } + +public: + fixed_bit_vector_manager(unsigned num_bits); + + fixed_bit_vector* allocate(); + fixed_bit_vector* allocate1(); + fixed_bit_vector* allocate0(); + fixed_bit_vector* allocate(fixed_bit_vector& bv); + void deallocate(fixed_bit_vector* bv); + + void copy(fixed_bit_vector& dst, fixed_bit_vector const& src) const; + unsigned num_words() const { return m_num_words; } + unsigned num_bits() const { return m_num_bits; } + fixed_bit_vector& reset(fixed_bit_vector& bv) const { return fill0(bv); } + fixed_bit_vector& fill0(fixed_bit_vector& bv) const; + fixed_bit_vector& fill1(fixed_bit_vector& bv) const; + fixed_bit_vector& set_and(fixed_bit_vector& dst, fixed_bit_vector const& src) const; + fixed_bit_vector& set_or(fixed_bit_vector& dst, fixed_bit_vector const& src) const; + fixed_bit_vector& set_neg(fixed_bit_vector& dst) const; + unsigned last_word(fixed_bit_vector const& bv) const; + bool equals(fixed_bit_vector const& a, fixed_bit_vector const& b) const; + unsigned hash(fixed_bit_vector const& src) const; + bool contains(fixed_bit_vector const& a, fixed_bit_vector const& b) const; + std::ostream& display(std::ostream& out, fixed_bit_vector const& b) const; +}; + +class fixed_bit_vector { + friend class fixed_bit_vector_manager; + unsigned m_data[1]; + + static unsigned get_pos_mask(unsigned bit_idx) { + return 1 << (bit_idx % 32); + } + + + unsigned get_bit_word(unsigned bit_idx) const { + return m_data[bit_idx / 32]; + } + + unsigned & get_bit_word(unsigned bit_idx) { + return m_data[bit_idx / 32]; + } + +public: + + fixed_bit_vector() {} + + ~fixed_bit_vector() {} + + unsigned get_word(unsigned word_idx) const { return m_data[word_idx]; } + + bool operator[](unsigned bit_idx) const { + return get(bit_idx); + } + + bool get(unsigned bit_idx) const { + return (get_bit_word(bit_idx) & get_pos_mask(bit_idx)) != 0; + } + + void set(unsigned bit_idx) { + get_bit_word(bit_idx) |= get_pos_mask(bit_idx); + } + + void unset(unsigned bit_idx) { + get_bit_word(bit_idx) &= ~get_pos_mask(bit_idx); + } + + void set(unsigned bit_idx, bool val) { + int _val = static_cast(val); + get_bit_word(bit_idx) ^= (-_val ^ get_bit_word(bit_idx)) & get_pos_mask(bit_idx); + } + +}; + + + +#endif /* _FIXED_BIT_VECTOR_H_ */ + From d9dafe7b94bed16afc265120d0d7e6b48cec22af Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 15 Sep 2014 21:23:03 -0700 Subject: [PATCH 528/925] tbv utilities Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/tbv.cpp | 141 ++++++++++++++++++++++++++++++++++ src/muz/ddnf/tbv.h | 97 +++++++++++++++++++++++ src/test/main.cpp | 1 + src/test/tbv.cpp | 39 ++++++++++ src/util/fixed_bit_vector.cpp | 2 +- src/util/fixed_bit_vector.h | 5 +- 6 files changed, 282 insertions(+), 3 deletions(-) create mode 100644 src/muz/ddnf/tbv.cpp create mode 100644 src/muz/ddnf/tbv.h create mode 100644 src/test/tbv.cpp diff --git a/src/muz/ddnf/tbv.cpp b/src/muz/ddnf/tbv.cpp new file mode 100644 index 000000000..f96a7078b --- /dev/null +++ b/src/muz/ddnf/tbv.cpp @@ -0,0 +1,141 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + tbv.cpp + +Abstract: + + ternary bit-vector utilities. + +Author: + + Nikolaj Bjorner (nbjorner) 2014-09-15 + +Revision History: + + +--*/ + +#include "tbv.h" + +tbv* tbv_manager::allocate() { + return reinterpret_cast(m.allocate()); +} +tbv* tbv_manager::allocate1() { + tbv* v = allocate(); + fill1(*v); + return v; +} +tbv* tbv_manager::allocate0() { + tbv* v = allocate(); + fill0(*v); + return v; +} +tbv* tbv_manager::allocateX() { + tbv* v = allocate(); + fillX(*v); + return v; +} +tbv* tbv_manager::allocate(tbv const& bv) { + return reinterpret_cast(m.allocate(bv)); +} +tbv* tbv_manager::allocate(uint64 val) { + tbv* v = allocate0(); + for (unsigned bit = num_tbits(); bit > 0;) { + --bit; + if (val & (1ULL << bit)) { + v->set(bit, BIT_1); + } else { + v->set(bit, BIT_0); + } + } + return v; +} +tbv* tbv_manager::allocate(rational const& r) { + if (r.is_uint64()) { + return allocate(r.get_uint64()); + } + tbv* v = allocate0(); + for (unsigned bit = num_tbits(); bit > 0; ) { + --bit; + if (bitwise_and(r, rational::power_of_two(bit)).is_zero()) { + v->set(bit, BIT_0); + } else { + v->set(bit, BIT_1); + } + } + return v; +} +void tbv_manager::deallocate(tbv* bv) { + m.deallocate(bv); +} +void tbv_manager::copy(tbv& dst, tbv const& src) const { + m.copy(dst, src); +} +tbv& tbv_manager::fill0(tbv& bv) const { + // 01010101 = 1 + 4 + 16 + 64 + memset(bv.m_data, 1 + 4 + 16 + 64, m.num_bytes()); + return bv; +} +tbv& tbv_manager::fill1(tbv& bv) const { + // 10101010 = 2 + 8 + 32 + 128 + memset(bv.m_data, 2 + 8 + 32 + 128, m.num_bytes()); + return bv; +} +tbv& tbv_manager::fillX(tbv& bv) const { + m.fill1(bv); + return bv; +} +tbv& tbv_manager::set_and(tbv& dst, tbv const& src) const { + m.set_and(dst, src); + return dst; +} +tbv& tbv_manager::set_or(tbv& dst, tbv const& src) const { + m.set_or(dst, src); + return dst; +} +tbv& tbv_manager::set_neg(tbv& dst) const { + m.set_neg(dst); + return dst; +} +bool tbv_manager::equals(tbv const& a, tbv const& b) const { + return m.equals(a, b); +} +unsigned tbv_manager::hash(tbv const& src) const { + return m.hash(src); +} +bool tbv_manager::contains(tbv const& a, tbv const& b) const { + return m.contains(a, b); +} +bool tbv_manager::intersect(tbv const& a, tbv const& b, tbv& result) { + copy(result, a); + set_and(result, b); + for (unsigned i = 0; i < num_tbits(); ++i) { + if (result.get(i) == BIT_z) return false; + } + return true; +} + +std::ostream& tbv_manager::display(std::ostream& out, tbv const& b) const { + for (unsigned i = 0; i < num_tbits(); ++i) { + switch (b.get(i)) { + case BIT_0: + out << '0'; + break; + case BIT_1: + out << '1'; + break; + case BIT_x: + out << 'x'; + break; + case BIT_z: + out << 'z'; + break; + default: + UNREACHABLE(); + } + } + return out; +} diff --git a/src/muz/ddnf/tbv.h b/src/muz/ddnf/tbv.h new file mode 100644 index 000000000..a5c282865 --- /dev/null +++ b/src/muz/ddnf/tbv.h @@ -0,0 +1,97 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + tbv.h + +Abstract: + + ternary bit-vector utilities. + +Author: + + Nikolaj Bjorner (nbjorner) 2014-09-15 + +Revision History: + + +--*/ + +#ifndef _TBV_H_ +#define _TBV_H_ + +#include "fixed_bit_vector.h" +#include "rational.h" + +class tbv; + +class tbv_manager { + static const unsigned BIT_0 = 0x1; + static const unsigned BIT_1 = 0x2; + static const unsigned BIT_x = 0x3; + static const unsigned BIT_z = 0x0; + fixed_bit_vector_manager m; +public: + tbv_manager(unsigned n): m(2*n) {} + tbv* allocate(); + tbv* allocate1(); + tbv* allocate0(); + tbv* allocateX(); + tbv* allocate(tbv const& bv); + tbv* allocate(uint64 n); + tbv* allocate(rational const& r); + void deallocate(tbv* bv); + + void copy(tbv& dst, tbv const& src) const; + unsigned num_tbits() const { return m.num_bits()/2; } + tbv& reset(tbv& bv) const { return fill0(bv); } + tbv& fill0(tbv& bv) const; + tbv& fill1(tbv& bv) const; + tbv& fillX(tbv& bv) const; + tbv& set_and(tbv& dst, tbv const& src) const; + tbv& set_or(tbv& dst, tbv const& src) const; + tbv& set_neg(tbv& dst) const; + bool equals(tbv const& a, tbv const& b) const; + unsigned hash(tbv const& src) const; + bool contains(tbv const& a, tbv const& b) const; + bool intersect(tbv const& a, tbv const& b, tbv& result); + std::ostream& display(std::ostream& out, tbv const& b) const; +}; + +class tbv: private fixed_bit_vector { + friend class fixed_bit_vector_manager; + friend class tbv_manager; +public: + + struct eq { + tbv_manager& m; + eq(tbv_manager& m):m(m) {} + bool operator()(tbv const& d1, tbv const& d2) const { + return m.equals(d1, d2); + } + }; + + struct hash { + tbv_manager& m; + hash(tbv_manager& m):m(m) {} + unsigned operator()(tbv const& d) const { + return m.hash(d); + } + }; + +private: + void set(unsigned index, unsigned value) { + SASSERT(value <= 3); + fixed_bit_vector::set(2*index, (value & 2) != 0); + fixed_bit_vector::set(2*index+1, (value & 1) != 0); + } + + unsigned get(unsigned index) const { + index *= 2; + return (fixed_bit_vector::get(index) << 1) | (unsigned)fixed_bit_vector::get(index+1); + } +}; + + +#endif /* _TBV_H_ */ diff --git a/src/test/main.cpp b/src/test/main.cpp index e58845bcf..5d30bb0af 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -141,6 +141,7 @@ int main(int argc, char ** argv) { TST(optional); TST(bit_vector); TST(fixed_bit_vector); + TST(tbv); TST(string_buffer); TST(map); TST(diff_logic); diff --git a/src/test/tbv.cpp b/src/test/tbv.cpp new file mode 100644 index 000000000..21ecdd697 --- /dev/null +++ b/src/test/tbv.cpp @@ -0,0 +1,39 @@ +#include "tbv.h" + +static void tst1(unsigned num_bits) { + tbv_manager m(num_bits); + + tbv* b1 = m.allocate1(); + tbv* b0 = m.allocate0(); + tbv* bX = m.allocateX(); + tbv* bN = m.allocate(31); + m.display(std::cout, *b0) << "\n"; + m.display(std::cout, *b1) << "\n"; + m.display(std::cout, *bX) << "\n"; + m.display(std::cout, *bN) << "\n"; + SASSERT(!m.equals(*b1,*b0)); + SASSERT(!m.equals(*b1,*bX)); + SASSERT(!m.equals(*b0,*bX)); + m.set_and(*bX,*b0); + SASSERT(m.equals(*b0,*bX)); + SASSERT(!m.equals(*b1,*bX)); + m.copy(*bX,*b1); + SASSERT(m.equals(*b1,*bX)); + SASSERT(!m.equals(*b0,*bX)); + m.fillX(*bX); + VERIFY(m.intersect(*bX,*b0,*bN)); + SASSERT(m.equals(*b0, *bN)); + VERIFY(!m.intersect(*b0,*b1,*bN)); + m.deallocate(b0); + m.deallocate(b1); + m.deallocate(bX); + m.deallocate(bN); +} + +void tst_tbv() { + tst1(31); + tst1(11); + tst1(15); + tst1(16); + tst1(17); +} diff --git a/src/util/fixed_bit_vector.cpp b/src/util/fixed_bit_vector.cpp index c674bafda..f2af843c7 100644 --- a/src/util/fixed_bit_vector.cpp +++ b/src/util/fixed_bit_vector.cpp @@ -52,7 +52,7 @@ fixed_bit_vector* fixed_bit_vector_manager::allocate1() { return result; } -fixed_bit_vector* fixed_bit_vector_manager::allocate(fixed_bit_vector& bv) { +fixed_bit_vector* fixed_bit_vector_manager::allocate(fixed_bit_vector const& bv) { fixed_bit_vector* result = allocate(); copy(*result, bv); return result; diff --git a/src/util/fixed_bit_vector.h b/src/util/fixed_bit_vector.h index 636c03e1b..390faa504 100644 --- a/src/util/fixed_bit_vector.h +++ b/src/util/fixed_bit_vector.h @@ -33,7 +33,6 @@ class fixed_bit_vector_manager { unsigned m_num_bytes; unsigned m_num_words; unsigned m_mask; - unsigned num_bytes() const { return m_num_bytes; } static unsigned num_words(unsigned num_bits) { return (num_bits + 31) / 32; @@ -45,11 +44,12 @@ public: fixed_bit_vector* allocate(); fixed_bit_vector* allocate1(); fixed_bit_vector* allocate0(); - fixed_bit_vector* allocate(fixed_bit_vector& bv); + fixed_bit_vector* allocate(fixed_bit_vector const& bv); void deallocate(fixed_bit_vector* bv); void copy(fixed_bit_vector& dst, fixed_bit_vector const& src) const; unsigned num_words() const { return m_num_words; } + unsigned num_bytes() const { return m_num_bytes; } unsigned num_bits() const { return m_num_bits; } fixed_bit_vector& reset(fixed_bit_vector& bv) const { return fill0(bv); } fixed_bit_vector& fill0(fixed_bit_vector& bv) const; @@ -66,6 +66,7 @@ public: class fixed_bit_vector { friend class fixed_bit_vector_manager; + friend class tbv_manager; unsigned m_data[1]; static unsigned get_pos_mask(unsigned bit_idx) { From 4e4346576a3ef3a38367a0464f82aa770966247a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 15 Sep 2014 22:01:13 -0700 Subject: [PATCH 529/925] move to managed tbvs Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/ddnf.cpp | 258 +++++++++--------------------------- src/muz/ddnf/tbv.cpp | 13 ++ src/muz/ddnf/tbv.h | 3 + src/util/fixed_bit_vector.h | 1 + 4 files changed, 83 insertions(+), 192 deletions(-) diff --git a/src/muz/ddnf/ddnf.cpp b/src/muz/ddnf/ddnf.cpp index db2981f45..4cccec6c7 100644 --- a/src/muz/ddnf/ddnf.cpp +++ b/src/muz/ddnf/ddnf.cpp @@ -25,160 +25,10 @@ Revision History: #include "dl_context.h" #include "scoped_proof.h" #include "bv_decl_plugin.h" +#include "tbv.h" namespace datalog { -#define BIT_0 ((0<<1)|1) -#define BIT_1 ((1<<1)|0) -#define BIT_x ((1<<1)|1) -#define BIT_z 0 - - class tbv : private bit_vector { - public: - tbv(): bit_vector() {} - tbv(unsigned n): bit_vector(2*n) {} - tbv(tbv const& other): bit_vector(other) {} - tbv(unsigned n, unsigned val): bit_vector() { - SASSERT(val <= 3); - resize(n, val); - } - tbv(uint64 val, unsigned n) : bit_vector(2*n) { - resize(n, BIT_x); - for (unsigned bit = n; bit > 0;) { - --bit; - if (val & (1ULL << bit)) { - set(bit, BIT_1); - } else { - set(bit, BIT_0); - } - } - } - - tbv(uint64 v, unsigned sz, unsigned hi, unsigned lo) : bit_vector(2*sz) { - resize(sz, BIT_x); - SASSERT(64 >= sz && sz > hi && hi >= lo); - for (unsigned i = 0; i < hi - lo + 1; ++i) { - set(lo + i, (v & (1ULL << i))?BIT_1:BIT_0); - } - } - - tbv(rational const& v, unsigned n) : bit_vector(2*n) { - if (v.is_uint64() && n <= 64) { - tbv tmp(v.get_uint64(), n); - *this = tmp; - return; - } - - resize(n, BIT_x); - for (unsigned bit = n; bit > 0; ) { - --bit; - if (bitwise_and(v, rational::power_of_two(bit)).is_zero()) { - set(bit, BIT_0); - } else { - set(bit, BIT_1); - } - } - } - - tbv& operator=(tbv const& other) { - bit_vector::operator=(other); - return *this; - } - - bool operator!=(tbv const& other) const { - return bit_vector::operator!=(other); - } - - bool operator==(tbv const& other) const { - return bit_vector::operator==(other); - } - - unsigned get_hash() const { - return bit_vector::get_hash(); - } - - void resize(unsigned n, unsigned val) { - while (size() < n) { - bit_vector::push_back((val & 2) != 0); - bit_vector::push_back((val & 1) != 0); - } - } - - bool is_subset(tbv const& other) const { - SASSERT(size() == other.size()); - return other.contains(*this); - } - - bool is_superset(tbv const& other) const { - SASSERT(size() == other.size()); - return contains(other); - } - - unsigned size() const { return bit_vector::size()/2; } - - void display(std::ostream& out) const { - for (unsigned i = 0; i < size(); ++i) { - switch (get(i)) { - case BIT_0: - out << '0'; - break; - case BIT_1: - out << '1'; - break; - case BIT_x: - out << 'x'; - break; - case BIT_z: - out << 'z'; - break; - default: - UNREACHABLE(); - } - } - } - - struct eq { - bool operator()(tbv const& d1, tbv const& d2) const { - return d1 == d2; - } - }; - - struct hash { - unsigned operator()(tbv const& d) const { - return d.get_hash(); - } - }; - - - friend bool intersect(tbv const& a, tbv const& b, tbv& result); - - private: - void set(unsigned index, unsigned value) { - SASSERT(value <= 3); - bit_vector::set(2*index, (value & 2) != 0); - bit_vector::set(2*index+1, (value & 1) != 0); - } - - unsigned get(unsigned index) const { - index *= 2; - return (bit_vector::get(index) << 1) | (unsigned)bit_vector::get(index+1); - } - }; - - std::ostream& operator<<(std::ostream& out, tbv const& t) { - t.display(out); - return out; - } - - bool intersect(tbv const& a, tbv const& b, tbv& result) { - result = a; - result &= b; - for (unsigned i = 0; i < result.size(); ++i) { - if (result.get(i) == BIT_z) return false; - } - return true; - } - class ddnf_mgr; class ddnf_node; typedef ref_vector ddnf_node_vector; @@ -187,33 +37,46 @@ namespace datalog { public: struct eq { + tbv_manager& m; + eq(tbv_manager& m):m(m) {} bool operator()(ddnf_node* n1, ddnf_node* n2) const { - return n1->get_tbv() == n2->get_tbv(); + return m.equals(n1->get_tbv(), n2->get_tbv()); } }; struct hash { + tbv_manager& m; + hash(tbv_manager& m):m(m) {} unsigned operator()(ddnf_node* n) const { - return n->get_tbv().get_hash(); + return m.hash(n->get_tbv()); } }; typedef ptr_hashtable ddnf_nodes; private: - tbv m_tbv; + ddnf_mgr& m; + tbv_manager& tbvm; + tbv const& m_tbv; ddnf_node_vector m_children; unsigned m_refs; unsigned m_id; + ddnf_node::hash m_hash; + ddnf_node::eq m_eq; ddnf_nodes m_descendants; friend class ddnf_mgr; public: - ddnf_node(ddnf_mgr& m, tbv const& tbv, unsigned id): + ddnf_node(ddnf_mgr& m, tbv_manager& tbvm, tbv const& tbv, unsigned id): + m(m), + tbvm(tbvm), m_tbv(tbv), m_children(m), m_refs(0), - m_id(id) { + m_id(id), + m_hash(tbvm), + m_eq(tbvm), + m_descendants(DEFAULT_HASHTABLE_INITIAL_CAPACITY, m_hash, m_eq) { } ~ddnf_node() {} @@ -248,7 +111,7 @@ namespace datalog { void display(std::ostream& out) const { out << "node[" << get_id() << ": "; - m_tbv.display(out); + tbvm.display(out, m_tbv); for (unsigned i = 0; i < m_children.size(); ++i) { out << " " << m_children[i]->get_id(); } @@ -263,17 +126,24 @@ namespace datalog { unsigned m_num_bits; ddnf_node* m_root; ddnf_node_vector m_noderefs; - ddnf_nodes m_nodes; bool m_internalized; + tbv_manager m_tbv; + ddnf_node::hash m_hash; + ddnf_node::eq m_eq; + ddnf_nodes m_nodes; public: - ddnf_mgr(unsigned n): m_num_bits(n), m_noderefs(*this), m_internalized(false) { - m_root = alloc(ddnf_node, *this, tbv(n, BIT_x), m_nodes.size()); + ddnf_mgr(unsigned n): m_num_bits(n), m_noderefs(*this), m_internalized(false), m_tbv(n), + m_hash(m_tbv), m_eq(m_tbv), + m_nodes(DEFAULT_HASHTABLE_INITIAL_CAPACITY, m_hash, m_eq) { + tbv* bX = m_tbv.allocateX(); + m_root = alloc(ddnf_node, *this, m_tbv, *bX, m_nodes.size()); m_noderefs.push_back(m_root); m_nodes.insert(m_root); } ~ddnf_mgr() { m_noderefs.reset(); + m_tbv.reset(); } void inc_ref(ddnf_node* n) { @@ -285,14 +155,13 @@ namespace datalog { } ddnf_node* insert(tbv const& t) { - SASSERT(t.size() == m_num_bits); SASSERT(!m_internalized); - vector new_tbvs; - new_tbvs.push_back(t); + ptr_vector new_tbvs; + new_tbvs.push_back(&t); for (unsigned i = 0; i < new_tbvs.size(); ++i) { - tbv const& nt = new_tbvs[i]; + tbv const& nt = *new_tbvs[i]; if (contains(nt)) continue; - ddnf_node* n = alloc(ddnf_node, *this, nt, m_noderefs.size()); + ddnf_node* n = alloc(ddnf_node, *this, m_tbv, nt, m_noderefs.size()); m_noderefs.push_back(n); m_nodes.insert(n); insert(*m_root, n, new_tbvs); @@ -300,6 +169,11 @@ namespace datalog { return find(t); } + tbv* allocate(uint64 v, unsigned hi, unsigned lo) { + return m_tbv.allocate(v, hi, lo); + } + + unsigned size() const { return m_noderefs.size(); } @@ -319,24 +193,24 @@ namespace datalog { private: ddnf_node* find(tbv const& t) { - ddnf_node dummy(*this, t, 0); + ddnf_node dummy(*this, m_tbv, t, 0); return *(m_nodes.find(&dummy)); } bool contains(tbv const& t) { - ddnf_node dummy(*this, t, 0); + ddnf_node dummy(*this, m_tbv, t, 0); return m_nodes.contains(&dummy); } - void insert(ddnf_node& root, ddnf_node* new_n, vector& new_intersections) { + void insert(ddnf_node& root, ddnf_node* new_n, ptr_vector& new_intersections) { tbv const& new_tbv = new_n->get_tbv(); - SASSERT(new_tbv.is_subset(root.get_tbv())); + SASSERT(m_tbv.contains(root.get_tbv(), new_tbv)); if (&root == new_n) return; bool inserted = false; for (unsigned i = 0; i < root.num_children(); ++i) { ddnf_node& child = *(root[i]); - if (child.get_tbv().is_superset(new_tbv)) { + if (m_tbv.contains(child.get_tbv(), new_tbv)) { inserted = true; insert(child, new_n, new_intersections); } @@ -345,20 +219,22 @@ namespace datalog { return; } ddnf_node_vector subset_children(*this); - tbv intr; + tbv* intr = m_tbv.allocate(); for (unsigned i = 0; i < root.num_children(); ++i) { ddnf_node& child = *(root[i]); // cannot be superset - SASSERT(!child.get_tbv().is_superset(new_tbv)); + SASSERT(!m_tbv.contains(child.get_tbv(),new_tbv)); // checking for subset - if (child.get_tbv().is_subset(new_tbv)) { + if (m_tbv.contains(new_tbv, child.get_tbv())) { subset_children.push_back(&child); } - else if (intersect(child.get_tbv(), new_tbv, intr)) { + else if (m_tbv.intersect(child.get_tbv(), new_tbv, *intr)) { // this means there is a non-full intersection new_intersections.push_back(intr); + intr = m_tbv.allocate(); } } + m_tbv.deallocate(intr); for (unsigned i = 0; i < subset_children.size(); ++i) { root.remove_child(subset_children[i].get()); new_n->add_child(subset_children[i].get()); @@ -413,7 +289,7 @@ namespace datalog { }; void ddnf_node::add_child(ddnf_node* n) { - SASSERT(!m_tbv.is_subset(n->m_tbv)); + //SASSERT(!m_tbv.is_subset(n->m_tbv)); m_children.push_back(n); } @@ -438,21 +314,19 @@ namespace datalog { } } - void insert(tbv const& t) { - get(t.size()).insert(t); + tbv* allocate(unsigned num_bits, uint64 v, unsigned hi, unsigned lo) { + return get(num_bits).allocate(v, hi, lo); + } + void insert(unsigned num_bits, tbv const& t) { + get(num_bits).insert(t); } - ddnf_mgr& get(unsigned sz) { - ddnf_mgr* result = 0; - if (!m_mgrs.find(sz, result)) { - result = insert(sz); - m_mgrs.insert(sz, result); - } - return *result; + ddnf_mgr& get(unsigned num_bits) { + return *insert(num_bits); } - ddnf_nodes const& lookup(tbv const& t) const { - return m_mgrs.find(t.size())->lookup(t); + ddnf_nodes const& lookup(unsigned n, tbv const& t) const { + return m_mgrs.find(n)->lookup(t); } void display(std::ostream& out) const { @@ -489,7 +363,7 @@ namespace datalog { ast_mark m_visited1, m_visited2; ddnfs m_ddnfs; stats m_stats; - obj_map m_expr2tbv; + obj_map m_expr2tbv; obj_map m_cache; expr_ref_vector m_trail; context m_inner_ctx; @@ -666,9 +540,9 @@ namespace datalog { return false; } // v[hi:lo] = val - tbv tbv(val.get_uint64(), sz_v, hi, lo); - m_ddnfs.insert(tbv); - m_expr2tbv.insert(e, tbv); + tbv* tv = m_ddnfs.allocate(sz_v, val.get_uint64(), hi, lo); + m_ddnfs.insert(sz_v, *tv); + m_expr2tbv.insert(e, tv); // std::cout << mk_pp(v, m) << " " << lo << " " << hi << " " << v << " " << tbv << "\n"; return true; } @@ -860,11 +734,11 @@ namespace datalog { } void compile_eq(expr* e, expr_ref& result, var* v, unsigned hi, unsigned lo, expr* c) { - tbv t; + tbv* t; VERIFY(m_expr2tbv.find(e, t)); var_ref w(m); compile_var(v, w); - ddnf_nodes const& ns = m_ddnfs.lookup(t); + ddnf_nodes const& ns = m_ddnfs.lookup(0xFFFFF, *t); ddnf_nodes::iterator it = ns.begin(), end = ns.end(); expr_ref_vector eqs(m); sort* s = m.get_sort(w); diff --git a/src/muz/ddnf/tbv.cpp b/src/muz/ddnf/tbv.cpp index f96a7078b..416b29b8b 100644 --- a/src/muz/ddnf/tbv.cpp +++ b/src/muz/ddnf/tbv.cpp @@ -20,6 +20,9 @@ Revision History: #include "tbv.h" +void tbv_manager::reset() { + m.reset(); +} tbv* tbv_manager::allocate() { return reinterpret_cast(m.allocate()); } @@ -53,6 +56,16 @@ tbv* tbv_manager::allocate(uint64 val) { } return v; } + +tbv* tbv_manager::allocate(uint64 val, unsigned hi, unsigned lo) { + tbv* v = allocateX(); + SASSERT(64 >= m.num_bits() && m.num_bits() > hi && hi >= lo); + for (unsigned i = 0; i < hi - lo + 1; ++i) { + v->set(lo + i, (val & (1ULL << i))?BIT_1:BIT_0); + } + return v; +} + tbv* tbv_manager::allocate(rational const& r) { if (r.is_uint64()) { return allocate(r.get_uint64()); diff --git a/src/muz/ddnf/tbv.h b/src/muz/ddnf/tbv.h index a5c282865..3921ca558 100644 --- a/src/muz/ddnf/tbv.h +++ b/src/muz/ddnf/tbv.h @@ -34,6 +34,7 @@ class tbv_manager { fixed_bit_vector_manager m; public: tbv_manager(unsigned n): m(2*n) {} + void reset(); tbv* allocate(); tbv* allocate1(); tbv* allocate0(); @@ -41,6 +42,8 @@ public: tbv* allocate(tbv const& bv); tbv* allocate(uint64 n); tbv* allocate(rational const& r); + tbv* allocate(uint64 n, unsigned hi, unsigned lo); + void deallocate(tbv* bv); void copy(tbv& dst, tbv const& src) const; diff --git a/src/util/fixed_bit_vector.h b/src/util/fixed_bit_vector.h index 390faa504..1ac3363d4 100644 --- a/src/util/fixed_bit_vector.h +++ b/src/util/fixed_bit_vector.h @@ -41,6 +41,7 @@ class fixed_bit_vector_manager { public: fixed_bit_vector_manager(unsigned num_bits); + void reset() { m_alloc.reset(); } fixed_bit_vector* allocate(); fixed_bit_vector* allocate1(); fixed_bit_vector* allocate0(); From bae4d549550ebff179ec5214fe9a3d9e312fd1ec Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 15 Sep 2014 22:11:35 -0700 Subject: [PATCH 530/925] fix bv size Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/ddnf.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/muz/ddnf/ddnf.cpp b/src/muz/ddnf/ddnf.cpp index 4cccec6c7..833051429 100644 --- a/src/muz/ddnf/ddnf.cpp +++ b/src/muz/ddnf/ddnf.cpp @@ -738,7 +738,8 @@ namespace datalog { VERIFY(m_expr2tbv.find(e, t)); var_ref w(m); compile_var(v, w); - ddnf_nodes const& ns = m_ddnfs.lookup(0xFFFFF, *t); + unsigned num_bits = bv.get_bv_size(e); + ddnf_nodes const& ns = m_ddnfs.lookup(num_bits, *t); ddnf_nodes::iterator it = ns.begin(), end = ns.end(); expr_ref_vector eqs(m); sort* s = m.get_sort(w); From 31c7f79afdf552c7932dbbced55799749915bdce Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 15 Sep 2014 22:13:56 -0700 Subject: [PATCH 531/925] fix bv size Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/ddnf.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/muz/ddnf/ddnf.cpp b/src/muz/ddnf/ddnf.cpp index 833051429..6c4f79f7c 100644 --- a/src/muz/ddnf/ddnf.cpp +++ b/src/muz/ddnf/ddnf.cpp @@ -735,10 +735,11 @@ namespace datalog { void compile_eq(expr* e, expr_ref& result, var* v, unsigned hi, unsigned lo, expr* c) { tbv* t; + // TBD: hi, lo are ignored. VERIFY(m_expr2tbv.find(e, t)); var_ref w(m); compile_var(v, w); - unsigned num_bits = bv.get_bv_size(e); + unsigned num_bits = bv.get_bv_size(c); ddnf_nodes const& ns = m_ddnfs.lookup(num_bits, *t); ddnf_nodes::iterator it = ns.begin(), end = ns.end(); expr_ref_vector eqs(m); From 887e6e53921b391b2f183b206991e78937e913c8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 16 Sep 2014 00:45:17 -0700 Subject: [PATCH 532/925] doc Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/doc.h | 215 +++++++++++++++++++++++++++++++++++++++++++ src/muz/ddnf/tbv.cpp | 18 ++-- src/muz/ddnf/tbv.h | 2 +- 3 files changed, 225 insertions(+), 10 deletions(-) create mode 100644 src/muz/ddnf/doc.h diff --git a/src/muz/ddnf/doc.h b/src/muz/ddnf/doc.h new file mode 100644 index 000000000..641e9513c --- /dev/null +++ b/src/muz/ddnf/doc.h @@ -0,0 +1,215 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + doc.h + +Abstract: + + difference of cubes. + +Author: + + Nikolaj Bjorner (nbjorner) 2014-09-15 + +Revision History: + + Based on ternary_diff_bitvector by Nuno Lopes. + +--*/ + +#ifndef _DOC_H_ +#define _DOC_H_ + +#if 0 + +#include "tbv.h" + +class doc; +template class union_bvec; + +class doc_manager { + tbv_manager m; +public: + doc_manager(unsigned n): m(n) {} + tbv_manager& tbv() { return m; } + void reset(); + doc* allocate(); + doc* allocate1(); + doc* allocate0(); + doc* allocateX(); + doc* allocate(doc const& src); + doc* allocate(uint64 n); + doc* allocate(rational const& r); + doc* allocate(uint64 n, unsigned hi, unsigned lo); + void deallocate(doc* src); + void copy(doc& dst, doc const& src) const; + doc& reset(doc& src) const { return fill0(src); } + doc& fill0(doc& src) const; + doc& fill1(doc& src) const; + doc& fillX(doc& src) const; + bool set_and(doc& dst, doc const& src) const; + // doc& set_or(doc& dst, doc const& src) const; + void neg(doc const& src, union_bvec& result) const; + bool equals(doc const& a, doc const& b) const; + unsigned hash(doc const& src) const; + bool contains(doc const& a, doc const& b) const; + std::ostream& display(std::ostream& out, doc const& b) const; +}; + +// union of tbv*, union of doc* +template +class union_bvec { + ptr_vector m_elems; // TBD: reuse allocator of M +public: + unsigned size() const { return m_elems.size(); } + T& operator[](unsigned idx) const { return *m_elems[idx]; } + void reset(M& m) { + for (unsigned i = 0; i < m_elems.size(); ++i) { + m.deallocate(m_elems[i]); + } + m_elems.reset(); + } + void insert(M& m, T* t) { + unsigned sz = size(), j = 0; + bool found = false; + for (unsigned i = 0; i < sz; ++i, ++j) { + if (!found && m.contains(*t, *m_elems[i])) { + m.deallocate(m_elems[i]); + --j; + } + else if (m.contains(*m_elems[i], *t)) { + found = true; + } + else if (i != j) { + m_elems[j] = m_elems[i]; + } + } + if (j != sz) m_elems.resize(j); + if (found) { + m.deallocate(t); + } + else { + m_elems.push_back(t); + } + } + bool intersect(M& m, T& t) { + unsigned sz = size(); + for (unsigned i = 0; i < sz; ++i) { + if (!m.set_and(m_elems[i], t)) + return false; + } + return true; + } + void insert(M& m, union_set const& other) { + for (unsigned i = 0; i < other.size(); ++i) { + insert(m, other[i]); + } + } + void intersect(M& m, union_set const& other, union_set& result) { + result.reset(m); + unsigned sz1 = size(); + unsigned sz2 = other.size(); + T* inter = m.allocate(); + for (unsigned i = 0; i < sz1; ++i) { + for (unsigned j = 0; j < sz2; ++j) { + if (m.intesect(*m_elems[i], other[j], *inter)) { + result.push_back(inter); + inter = m.allocate(); + } + } + } + m.deallocate(inter); + } + void neg(M& m, union_set& result) { + union_set negated; + result.reset(m); + result.push_back(m.allocateX()); + unsigned sz = size(); + for (unsigned i = 0; !result.empty() && i < sz; ++i) { + // m.set_neg(*m_elems[i]); + // result.intersect(m, negated); + } + } + + void subtract(M& m, union_set const& other, union_set& result) { + result.reset(m); + + } +}; + +class doc { + // pos \ (neg_0 \/ ... \/ neg_n) + friend class doc_manager; + tbv* m_pos; + union_bvec m_neg; +public: + + struct eq { + doc_manager& m; + eq(doc_manager& m):m(m) {} + bool operator()(doc const& d1, doc const& d2) const { + return m.equals(d1, d2); + } + }; + + struct hash { + doc_manager& m; + hash(doc_manager& m):m(m) {} + unsigned operator()(doc const& d) const { + return m.hash(d); + } + }; + +}; + +#endif + +#endif /* _DOC_H_ */ + +#if 0 + + class utbv { + friend class ternary_bitvector; + + ternary_bitvector m_pos; + union_ternary_bitvector m_neg; + + public: + utbv() : m_pos(), m_neg(0) {} + utbv(unsigned size) : m_pos(size), m_neg(size) {} + utbv(unsigned size, bool full); + utbv(const rational& n, unsigned num_bits); + explicit utbv(const ternary_bitvector & tbv); + + bool contains(const utbv & other) const; + bool contains(const ternary_bitvector & other) const; + bool contains(unsigned offset, const utbv& other, + unsigned other_offset, unsigned length) const; + bool is_empty() const; + + utbv band(const utbv& other) const; + void neg(union_ternary_bitvector& result) const; + + static bool has_subtract() { return true; } + void subtract(const union_ternary_bitvector& other, + union_ternary_bitvector& result) const; + + + unsigned get(unsigned idx); + void set(unsigned idx, unsigned val); + + void swap(utbv & other); + void reset(); + + + void display(std::ostream & out) const; + + private: + void add_negated(const ternary_bitvector& neg); + void add_negated(const union_ternary_bitvector& neg); + bool fold_neg(); + }; + +#endif diff --git a/src/muz/ddnf/tbv.cpp b/src/muz/ddnf/tbv.cpp index 416b29b8b..71bc8dc44 100644 --- a/src/muz/ddnf/tbv.cpp +++ b/src/muz/ddnf/tbv.cpp @@ -101,14 +101,18 @@ tbv& tbv_manager::fillX(tbv& bv) const { m.fill1(bv); return bv; } -tbv& tbv_manager::set_and(tbv& dst, tbv const& src) const { - m.set_and(dst, src); - return dst; -} + tbv& tbv_manager::set_or(tbv& dst, tbv const& src) const { m.set_or(dst, src); return dst; } +bool tbv_manager::set_and(tbv& dst, tbv const& src) const { + m.set_and(dst, src); + for (unsigned i = 0; i < num_tbits(); ++i) { + if (dst.get(i) == BIT_z) return false; + } + return true; +} tbv& tbv_manager::set_neg(tbv& dst) const { m.set_neg(dst); return dst; @@ -124,11 +128,7 @@ bool tbv_manager::contains(tbv const& a, tbv const& b) const { } bool tbv_manager::intersect(tbv const& a, tbv const& b, tbv& result) { copy(result, a); - set_and(result, b); - for (unsigned i = 0; i < num_tbits(); ++i) { - if (result.get(i) == BIT_z) return false; - } - return true; + return set_and(result, b); } std::ostream& tbv_manager::display(std::ostream& out, tbv const& b) const { diff --git a/src/muz/ddnf/tbv.h b/src/muz/ddnf/tbv.h index 3921ca558..626a942aa 100644 --- a/src/muz/ddnf/tbv.h +++ b/src/muz/ddnf/tbv.h @@ -52,7 +52,7 @@ public: tbv& fill0(tbv& bv) const; tbv& fill1(tbv& bv) const; tbv& fillX(tbv& bv) const; - tbv& set_and(tbv& dst, tbv const& src) const; + bool set_and(tbv& dst, tbv const& src) const; tbv& set_or(tbv& dst, tbv const& src) const; tbv& set_neg(tbv& dst) const; bool equals(tbv const& a, tbv const& b) const; From 1058de1aa7d5a7f18e6f51b18da760fe36dfb6e2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 16 Sep 2014 13:22:04 -0700 Subject: [PATCH 533/925] adding udoc_relation Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 2 +- src/ast/substitution/substitution_tree.cpp | 10 +- src/ast/substitution/substitution_tree.h | 2 + src/muz/ddnf/doc.cpp | 82 ++++++ src/muz/ddnf/doc.h | 117 ++++----- src/muz/ddnf/tbv.cpp | 52 +++- src/muz/ddnf/tbv.h | 17 +- src/muz/ddnf/udoc_relation.cpp | 274 +++++++++++++++++++++ src/muz/ddnf/udoc_relation.h | 110 +++++++++ 9 files changed, 590 insertions(+), 76 deletions(-) create mode 100644 src/muz/ddnf/doc.cpp create mode 100644 src/muz/ddnf/udoc_relation.cpp create mode 100644 src/muz/ddnf/udoc_relation.h diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 9ceec29eb..f9f752a18 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -66,7 +66,7 @@ def init_project_def(): add_lib('clp', ['muz', 'transforms'], 'muz/clp') add_lib('tab', ['muz', 'transforms'], 'muz/tab') add_lib('bmc', ['muz', 'transforms'], 'muz/bmc') - add_lib('ddnf', ['muz', 'transforms'], 'muz/ddnf') + add_lib('ddnf', ['muz', 'transforms', 'rel'], 'muz/ddnf') add_lib('duality_intf', ['muz', 'transforms', 'duality'], 'muz/duality') add_lib('fp', ['muz', 'pdr', 'clp', 'tab', 'rel', 'bmc', 'duality_intf', 'ddnf'], 'muz/fp') add_lib('smtlogic_tactics', ['arith_tactics', 'bv_tactics', 'nlsat_tactic', 'smt_tactic', 'aig_tactic', 'fp', 'muz','qe'], 'tactic/smtlogics') diff --git a/src/ast/substitution/substitution_tree.cpp b/src/ast/substitution/substitution_tree.cpp index 037d51e32..6aaa2da66 100644 --- a/src/ast/substitution/substitution_tree.cpp +++ b/src/ast/substitution/substitution_tree.cpp @@ -793,8 +793,10 @@ bool substitution_tree::visit(expr * e, st_visitor & st, node * r) { } else { TRACE("st_bug", tout << "found match:\n"; m_subst->display(tout); tout << "m_subst: " << m_subst << "\n";); - if (!st(n->m_expr)) + if (!st(n->m_expr)) { + clear_stack(); return false; + } if (!backtrack()) break; } @@ -806,12 +808,16 @@ bool substitution_tree::visit(expr * e, st_visitor & st, node * r) { else if (!backtrack()) break; } + clear_stack(); + return true; +} + +void substitution_tree::clear_stack() { while (!m_bstack.empty()) { m_subst->pop_scope(); m_bstack.pop_back(); } m_subst->pop_scope(); - return true; } template diff --git a/src/ast/substitution/substitution_tree.h b/src/ast/substitution/substitution_tree.h index caa3d37cb..07723a8e4 100644 --- a/src/ast/substitution/substitution_tree.h +++ b/src/ast/substitution/substitution_tree.h @@ -123,6 +123,8 @@ class substitution_tree { template void visit(expr * e, st_visitor & st, unsigned in_offset, unsigned st_offset, unsigned reg_offset); + void clear_stack(); + public: substitution_tree(ast_manager & m); ~substitution_tree(); diff --git a/src/muz/ddnf/doc.cpp b/src/muz/ddnf/doc.cpp new file mode 100644 index 000000000..8690e8218 --- /dev/null +++ b/src/muz/ddnf/doc.cpp @@ -0,0 +1,82 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + doc.cpp + +Abstract: + + difference of cubes. + +Author: + + Nuno Lopes (a-nlopes) 2013-03-01 + Nikolaj Bjorner (nbjorner) 2014-09-15 + +Revision History: + + Based on ternary_diff_bitvector by Nuno Lopes. + +--*/ + +#include "doc.h" +void doc_manager::reset() { +} +doc* doc_manager::allocate() { + return 0; +} +doc* doc_manager::allocate1() { + return 0; +} +doc* doc_manager::allocate0() { + return 0; +} +doc* doc_manager::allocateX() { + return 0; +} +doc* doc_manager::allocate(doc const& src) { + return 0; +} +doc* doc_manager::allocate(uint64 n) { + return 0; +} +doc* doc_manager::allocate(rational const& r) { + return 0; +} +doc* doc_manager::allocate(uint64 n, unsigned hi, unsigned lo) { + return 0; +} +void doc_manager::deallocate(doc* src) { +} +void doc_manager::copy(doc& dst, doc const& src) const { +} +doc& doc_manager::fill0(doc& src) const { + return src; +} +doc& doc_manager::fill1(doc& src) const { + return src; +} +doc& doc_manager::fillX(doc& src) const { + return src; +} +bool doc_manager::set_and(doc& dst, doc const& src) const { + return false; +} +void doc_manager::complement(doc const& src, ptr_vector& result) { +} +void doc_manager::subtract(doc const& A, doc const& B, ptr_vector& result) { +} +bool doc_manager::equals(doc const& a, doc const& b) const { + return false; +} +unsigned doc_manager::hash(doc const& src) const { + return 0; +} +bool doc_manager::contains(doc const& a, doc const& b) const { + return false; +} +std::ostream& doc_manager::display(std::ostream& out, doc const& b) const { + return out; +} + diff --git a/src/muz/ddnf/doc.h b/src/muz/ddnf/doc.h index 641e9513c..aa32fd47a 100644 --- a/src/muz/ddnf/doc.h +++ b/src/muz/ddnf/doc.h @@ -11,6 +11,7 @@ Abstract: Author: + Nuno Lopes (a-nlopes) 2013-03-01 Nikolaj Bjorner (nbjorner) 2014-09-15 Revision History: @@ -22,8 +23,6 @@ Revision History: #ifndef _DOC_H_ #define _DOC_H_ -#if 0 - #include "tbv.h" class doc; @@ -50,27 +49,38 @@ public: doc& fill1(doc& src) const; doc& fillX(doc& src) const; bool set_and(doc& dst, doc const& src) const; - // doc& set_or(doc& dst, doc const& src) const; - void neg(doc const& src, union_bvec& result) const; + void complement(doc const& src, ptr_vector& result); + void subtract(doc const& A, doc const& B, ptr_vector& result); bool equals(doc const& a, doc const& b) const; unsigned hash(doc const& src) const; bool contains(doc const& a, doc const& b) const; std::ostream& display(std::ostream& out, doc const& b) const; + unsigned num_tbits() const { return m.num_tbits(); } }; // union of tbv*, union of doc* template -class union_bvec { +class union_bvec { ptr_vector m_elems; // TBD: reuse allocator of M public: unsigned size() const { return m_elems.size(); } T& operator[](unsigned idx) const { return *m_elems[idx]; } + bool empty() const { return m_elems.empty(); } + bool contains(M& m, T& t) const { + for (unsigned i = 0; i < m_elems.size(); ++i) { + if (m.contains(*m_elems[i], t)) return true; + } + return false; + } + void push_back(T* t) { + m_elems.push_back(t); + } void reset(M& m) { for (unsigned i = 0; i < m_elems.size(); ++i) { m.deallocate(m_elems[i]); } m_elems.reset(); - } + } void insert(M& m, T* t) { unsigned sz = size(), j = 0; bool found = false; @@ -102,13 +112,13 @@ public: } return true; } - void insert(M& m, union_set const& other) { + void insert(M& m, union_bvec const& other) { for (unsigned i = 0; i < other.size(); ++i) { insert(m, other[i]); } } - void intersect(M& m, union_set const& other, union_set& result) { - result.reset(m); + void intersect(M& m, union_bvec const& other) { + union_bvec result; unsigned sz1 = size(); unsigned sz2 = other.size(); T* inter = m.allocate(); @@ -121,29 +131,30 @@ public: } } m.deallocate(inter); + std::swap(result, *this); + result.reset(); } - void neg(M& m, union_set& result) { - union_set negated; + void complement(M& m, union_bvec& result) { + union_bvec negated; result.reset(m); result.push_back(m.allocateX()); unsigned sz = size(); - for (unsigned i = 0; !result.empty() && i < sz; ++i) { - // m.set_neg(*m_elems[i]); - // result.intersect(m, negated); + for (unsigned i = 0; !empty() && i < sz; ++i) { + m.complement(*m_elems[i], negated.m_elems); + result.intersect(m, negated); + negated.reset(m); } } - void subtract(M& m, union_set const& other, union_set& result) { - result.reset(m); - - } }; +typedef union_bvec utbv; + class doc { // pos \ (neg_0 \/ ... \/ neg_n) friend class doc_manager; tbv* m_pos; - union_bvec m_neg; + utbv m_neg; public: struct eq { @@ -161,55 +172,31 @@ public: return m.hash(d); } }; + + tbv& pos() { return *m_pos; } + utbv& neg() { return m_neg; } + tbv const& pos() const { return *m_pos; } + utbv const& neg() const { return m_neg; } }; -#endif +typedef union_bvec udoc; + +class doc_ref { + doc_manager& dm; + doc* d; +public: + doc_ref(doc_manager& dm):dm(dm),d(0) {} + doc_ref(doc_manager& dm, doc* d):dm(dm),d(d) {} + ~doc_ref() { + if (d) dm.deallocate(d); + } + doc_ref& operator=(doc* d2) { + if (d) dm.deallocate(d); + d = d2; + } + doc& operator*() { return *d; } +}; #endif /* _DOC_H_ */ -#if 0 - - class utbv { - friend class ternary_bitvector; - - ternary_bitvector m_pos; - union_ternary_bitvector m_neg; - - public: - utbv() : m_pos(), m_neg(0) {} - utbv(unsigned size) : m_pos(size), m_neg(size) {} - utbv(unsigned size, bool full); - utbv(const rational& n, unsigned num_bits); - explicit utbv(const ternary_bitvector & tbv); - - bool contains(const utbv & other) const; - bool contains(const ternary_bitvector & other) const; - bool contains(unsigned offset, const utbv& other, - unsigned other_offset, unsigned length) const; - bool is_empty() const; - - utbv band(const utbv& other) const; - void neg(union_ternary_bitvector& result) const; - - static bool has_subtract() { return true; } - void subtract(const union_ternary_bitvector& other, - union_ternary_bitvector& result) const; - - - unsigned get(unsigned idx); - void set(unsigned idx, unsigned val); - - void swap(utbv & other); - void reset(); - - - void display(std::ostream & out) const; - - private: - void add_negated(const ternary_bitvector& neg); - void add_negated(const union_ternary_bitvector& neg); - bool fold_neg(); - }; - -#endif diff --git a/src/muz/ddnf/tbv.cpp b/src/muz/ddnf/tbv.cpp index 71bc8dc44..b6b5e1b6d 100644 --- a/src/muz/ddnf/tbv.cpp +++ b/src/muz/ddnf/tbv.cpp @@ -60,11 +60,33 @@ tbv* tbv_manager::allocate(uint64 val) { tbv* tbv_manager::allocate(uint64 val, unsigned hi, unsigned lo) { tbv* v = allocateX(); SASSERT(64 >= m.num_bits() && m.num_bits() > hi && hi >= lo); - for (unsigned i = 0; i < hi - lo + 1; ++i) { - v->set(lo + i, (val & (1ULL << i))?BIT_1:BIT_0); - } + v->set(val, hi, lo); return v; } +void tbv::set(uint64 val, unsigned hi, unsigned lo) { + for (unsigned i = 0; i < hi - lo + 1; ++i) { + set(lo + i, (val & (1ULL << i))?BIT_1:BIT_0); + } +} +void tbv::set(rational const& r, unsigned hi, unsigned lo) { + if (r.is_uint64()) { + set(r.get_uint64(), hi, lo); + return; + } + for (unsigned i = 0; i < hi - lo + 1; ++i) { + if (bitwise_and(r, rational::power_of_two(i)).is_zero()) + set(lo + i, BIT_0); + else + set(lo + i, BIT_1); + } +} + +void tbv::set(tbv const& other, unsigned hi, unsigned lo) { + for (unsigned i = 0; i < hi - lo + 1; ++i) { + set(lo + i, other.get(i)); + } +} + tbv* tbv_manager::allocate(rational const& r) { if (r.is_uint64()) { @@ -113,10 +135,28 @@ bool tbv_manager::set_and(tbv& dst, tbv const& src) const { } return true; } -tbv& tbv_manager::set_neg(tbv& dst) const { - m.set_neg(dst); - return dst; + +void tbv_manager::complement(tbv const& src, ptr_vector& result) { + tbv* r; + unsigned n = num_tbits(); + for (unsigned i = 0; i < n; ++i) { + switch (src.get(i)) { + case BIT_0: + r = allocate(src); + r->set(i, BIT_1); + result.push_back(r); + break; + case BIT_1: + r = allocate(src); + r->set(i, BIT_0); + result.push_back(r); + break; + default: + break; + } + } } + bool tbv_manager::equals(tbv const& a, tbv const& b) const { return m.equals(a, b); } diff --git a/src/muz/ddnf/tbv.h b/src/muz/ddnf/tbv.h index 626a942aa..190ad0cde 100644 --- a/src/muz/ddnf/tbv.h +++ b/src/muz/ddnf/tbv.h @@ -27,6 +27,7 @@ Revision History: class tbv; class tbv_manager { + friend class tbv; static const unsigned BIT_0 = 0x1; static const unsigned BIT_1 = 0x2; static const unsigned BIT_x = 0x3; @@ -54,7 +55,7 @@ public: tbv& fillX(tbv& bv) const; bool set_and(tbv& dst, tbv const& src) const; tbv& set_or(tbv& dst, tbv const& src) const; - tbv& set_neg(tbv& dst) const; + void complement(tbv const& src, ptr_vector& result); bool equals(tbv const& a, tbv const& b) const; unsigned hash(tbv const& src) const; bool contains(tbv const& a, tbv const& b) const; @@ -65,8 +66,14 @@ public: class tbv: private fixed_bit_vector { friend class fixed_bit_vector_manager; friend class tbv_manager; + public: + static const unsigned BIT_0 = tbv_manager::BIT_0; + static const unsigned BIT_1 = tbv_manager::BIT_1; + static const unsigned BIT_x = tbv_manager::BIT_x; + static const unsigned BIT_z = tbv_manager::BIT_z; + struct eq { tbv_manager& m; eq(tbv_manager& m):m(m) {} @@ -83,13 +90,19 @@ public: } }; -private: + void set(uint64 n, unsigned hi, unsigned lo); + void set(rational const& r, unsigned hi, unsigned lo); + void set(tbv const& other, unsigned hi, unsigned lo); + + unsigned operator[](unsigned idx) { return get(idx); } void set(unsigned index, unsigned value) { SASSERT(value <= 3); fixed_bit_vector::set(2*index, (value & 2) != 0); fixed_bit_vector::set(2*index+1, (value & 1) != 0); } +private: + unsigned get(unsigned index) const { index *= 2; return (fixed_bit_vector::get(index) << 1) | (unsigned)fixed_bit_vector::get(index+1); diff --git a/src/muz/ddnf/udoc_relation.cpp b/src/muz/ddnf/udoc_relation.cpp new file mode 100644 index 000000000..5e7e0f314 --- /dev/null +++ b/src/muz/ddnf/udoc_relation.cpp @@ -0,0 +1,274 @@ +#include "udoc_relation.h" +#include "dl_relation_manager.h" + +namespace datalog { + + udoc_relation::udoc_relation(udoc_plugin& p, relation_signature const& sig): + relation_base(p, sig), + dm(p.dm(num_signature_bits(p.bv, sig))) { + unsigned column = 0; + for (unsigned i = 0; i < sig.size(); ++i) { + m_column_info.push_back(column); + column += p.bv.get_bv_size(sig[i]); + } + m_column_info.push_back(column); + } + udoc_relation::~udoc_relation() { + reset(); + } + unsigned udoc_relation::num_signature_bits(bv_util& bv, relation_signature const& sig) { + unsigned result = 0; + for (unsigned i = 0; i < sig.size(); ++i) { + result += bv.get_bv_size(sig[i]); + } + return result; + } + void udoc_relation::reset() { + m_elems.reset(dm); + } + void udoc_relation::expand_column_vector(unsigned_vector& v, udoc_relation* other) const { + unsigned_vector orig; + orig.swap(v); + for (unsigned i = 0; i < orig.size(); ++i) { + unsigned col, limit; + if (orig[i] < get_num_cols()) { + col = column_idx(orig[i]); + limit = col + column_num_bits(orig[i]); + } else { + unsigned idx = orig[i] - get_num_cols(); + col = get_num_bits() + other->column_idx(idx); + limit = col + other->column_num_bits(idx); + } + for (; col < limit; ++col) { + v.push_back(col); + } + } + } + + doc* udoc_relation::fact2doc(const relation_fact & f) const { + doc* d = dm.allocate0(); + for (unsigned i = 0; i < f.size(); ++i) { + unsigned bv_size; + rational val; + VERIFY(get_plugin().bv.is_numeral(f[i], val, bv_size)); + SASSERT(bv_size == column_num_bits(i)); + unsigned lo = column_idx(i); + unsigned hi = column_idx(i + 1); + d->pos().set(val, hi, lo); + } + return d; + } + void udoc_relation::add_fact(const relation_fact & f) { + doc* d = fact2doc(f); + m_elems.insert(dm, d); + } + bool udoc_relation::contains_fact(const relation_fact & f) const { + doc_ref d(dm, fact2doc(f)); + return m_elems.contains(dm, *d); + } + udoc_relation * udoc_relation::clone() const { + NOT_IMPLEMENTED_YET(); + return 0; + } + udoc_relation * udoc_relation::complement(func_decl* f) const { + NOT_IMPLEMENTED_YET(); + return 0; + } + void udoc_relation::to_formula(expr_ref& fml) const { + NOT_IMPLEMENTED_YET(); + } + udoc_plugin& udoc_relation::get_plugin() const { + return static_cast(relation_base::get_plugin()); + } + + void udoc_relation::display(std::ostream& out) const { + NOT_IMPLEMENTED_YET(); + } + + // ------------- + + udoc_plugin::udoc_plugin(relation_manager& rm): + relation_plugin(udoc_plugin::get_name(), rm), + m(rm.get_context().get_manager()), + bv(m) { + } + udoc_plugin::~udoc_plugin() { + u_map::iterator it = m_dms.begin(), end = m_dms.end(); + for (; it != end; ++it) { + dealloc(it->m_value); + } + } + udoc_relation& udoc_plugin::get(relation_base& r) { + return dynamic_cast(r); + } + udoc_relation* udoc_plugin::get(relation_base* r) { + return r?dynamic_cast(r):0; + } + udoc_relation const & udoc_plugin::get(relation_base const& r) { + return dynamic_cast(r); + } + + doc_manager& udoc_plugin::dm(unsigned n) { + doc_manager* r; + if (!m_dms.find(n, r)) { + r = alloc(doc_manager, n); + m_dms.insert(n, r); + } + return *r; + } + bool udoc_plugin::can_handle_signature(const relation_signature & s) { + NOT_IMPLEMENTED_YET(); + return false; + } + relation_base * udoc_plugin::mk_empty(const relation_signature & s) { + NOT_IMPLEMENTED_YET(); + return 0; + } + relation_base * udoc_plugin::mk_full(func_decl* p, const relation_signature & s) { + NOT_IMPLEMENTED_YET(); + return 0; + } + class udoc_plugin::join_fn : public convenient_relation_join_fn { + doc_manager& dm; + doc_manager& dm1; + doc_manager& dm2; + public: + join_fn(udoc_plugin& p, udoc_relation const& t1, udoc_relation const& t2, unsigned col_cnt, + const unsigned * cols1, const unsigned * cols2) + : convenient_relation_join_fn(t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2), + dm(p.dm(get_result_signature())), + dm1(t1.get_dm()), + dm2(t2.get_dm()) { + t1.expand_column_vector(m_cols1); + t2.expand_column_vector(m_cols2); + } + + void join(doc const& d1, doc const& d2, udoc& result) { + doc* d = dm.allocateX(); + tbv& pos = d->pos(); + utbv& neg = d->neg(); + unsigned mid = dm1.num_tbits(); + unsigned hi = dm.num_tbits(); + pos.set(d1.pos(), mid-1, 0); + pos.set(d2.pos(), hi-1, mid); + // first fix bits + for (unsigned i = 0; i < m_cols1.size(); ++i) { + unsigned idx1 = m_cols1[i]; + unsigned idx2 = mid + m_cols2[i]; + unsigned v1 = pos[idx1]; + unsigned v2 = pos[idx2]; + + if (v1 == tbv::BIT_x) { + if (v2 != tbv::BIT_x) + pos.set(idx1, v2); + } else if (v2 == tbv::BIT_x) { + pos.set(idx2, v1); + } else if (v1 != v2) { + dm.deallocate(d); + // columns don't match + return; + } + } + // fix equality of don't care columns + for (unsigned i = 0; i < m_cols1.size(); ++i) { + unsigned idx1 = m_cols1[i]; + unsigned idx2 = mid + m_cols2[i]; + unsigned v1 = pos[idx1]; + unsigned v2 = pos[idx2]; + + if (v1 == tbv::BIT_x && v2 == tbv::BIT_x) { + // add to subtracted TBVs: 1xx0 and 0xx1 + tbv* r = dm.tbv().allocate(pos); + r->set(idx1, tbv::BIT_0); + r->set(idx2, tbv::BIT_1); + neg.push_back(r); + + r = dm.tbv().allocate(pos); + r->set(idx1, tbv::BIT_1); + r->set(idx2, tbv::BIT_0); + neg.push_back(r); + } + } + + // handle subtracted TBVs: 1010 -> 1010xxx + for (unsigned i = 0; i < d1.neg().size(); ++i) { + tbv* t = dm.tbv().allocate(); + t->set(d1.neg()[i], mid-1, 0); + t->set(d2.pos(), hi - 1, mid); + neg.push_back(t); + } + for (unsigned i = 0; i < d2.neg().size(); ++i) { + tbv* t = dm.tbv().allocate(); + t->set(d1.pos(), mid-1, 0); + t->set(d2.neg()[i], hi - 1, mid); + neg.push_back(t); + } + result.insert(dm, d); + } + + virtual relation_base * operator()(const relation_base & _r1, const relation_base & _r2) { + udoc_relation const& r1 = get(_r1); + udoc_relation const& r2 = get(_r2); + udoc_plugin& p = r1.get_plugin(); + relation_signature const& sig = get_result_signature(); + udoc_relation * result = alloc(udoc_relation, p, sig); + udoc const& d1 = r1.get_udoc(); + udoc const& d2 = r2.get_udoc(); + udoc& r = result->get_udoc(); + for (unsigned i = 0; i < d1.size(); ++i) { + for (unsigned j = 0; j < d2.size(); ++j) { + join(d1[i], d2[j], r); + } + } + return result; + } + }; + relation_join_fn * udoc_plugin::mk_join_fn( + const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { + if (!check_kind(t1) || !check_kind(t2)) { + return 0; + } + return alloc(join_fn, *this, get(t1), get(t2), col_cnt, cols1, cols2); + } + relation_transformer_fn * udoc_plugin::mk_project_fn( + const relation_base & t, unsigned col_cnt, + const unsigned * removed_cols) { + NOT_IMPLEMENTED_YET(); + return 0; + } + relation_transformer_fn * udoc_plugin::mk_rename_fn( + const relation_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle) { + NOT_IMPLEMENTED_YET(); + return 0; + } + relation_union_fn * udoc_plugin::mk_union_fn( + const relation_base & tgt, const relation_base & src, + const relation_base * delta) { + NOT_IMPLEMENTED_YET(); + return 0; + } + relation_union_fn * udoc_plugin::mk_widen_fn( + const relation_base & tgt, const relation_base & src, + const relation_base * delta) { + NOT_IMPLEMENTED_YET(); + return 0; + } + relation_mutator_fn * udoc_plugin::mk_filter_identical_fn( + const relation_base & t, unsigned col_cnt, + const unsigned * identical_cols) { + NOT_IMPLEMENTED_YET(); + return 0; + } + relation_mutator_fn * udoc_plugin::mk_filter_equal_fn( + const relation_base & t, const relation_element & value, unsigned col) { + NOT_IMPLEMENTED_YET(); + return 0; + } + relation_mutator_fn * udoc_plugin::mk_filter_interpreted_fn(const relation_base & t, app * condition) { + NOT_IMPLEMENTED_YET(); + return 0; + } + +} diff --git a/src/muz/ddnf/udoc_relation.h b/src/muz/ddnf/udoc_relation.h new file mode 100644 index 000000000..2dfa49553 --- /dev/null +++ b/src/muz/ddnf/udoc_relation.h @@ -0,0 +1,110 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + udoc_relation.h + +Abstract: + + Relation based on union of DOCs. + +Author: + + Nuno Lopes (a-nlopes) 2013-03-01 + Nikolaj Bjorner (nbjorner) 2014-09-15 + +Revision History: + + +--*/ + +#ifndef _UDOC_RELATION_H_ +#define _UDOC_RELATION_H_ + +#include "doc.h" +#include "dl_base.h" + +namespace datalog { + class udoc_plugin; + class udoc_relation; + + class udoc_relation : public relation_base { + friend class udoc_relation; + doc_manager& dm; + udoc m_elems; + unsigned_vector m_column_info; + static unsigned num_signature_bits(bv_util& bv, relation_signature const& sig); + doc* fact2doc(relation_fact const& f) const; + public: + udoc_relation(udoc_plugin& p, relation_signature const& s); + virtual ~udoc_relation(); + virtual void reset(); + virtual void add_fact(const relation_fact & f); + virtual bool contains_fact(const relation_fact & f) const; + virtual udoc_relation * clone() const; + virtual udoc_relation * complement(func_decl*) const; + virtual void to_formula(expr_ref& fml) const; + udoc_plugin& get_plugin() const; + virtual bool empty() const { return m_elems.empty(); } + virtual void display(std::ostream& out) const; + virtual bool is_precise() const { return true; } + + doc_manager& get_dm() const { return dm; } + udoc const& get_udoc() const { return m_elems; } + udoc& get_udoc() { return m_elems; } + unsigned get_num_bits() const { return m_column_info.back(); } + unsigned get_num_cols() const { return m_column_info.size()-1; } + unsigned column_idx(unsigned col) const { return m_column_info[col]; } + unsigned column_num_bits(unsigned col) const { return m_column_info[col+1] - m_column_info[col]; } + void expand_column_vector(unsigned_vector& v, udoc_relation* other = 0) const; + }; + + class udoc_plugin : public relation_plugin { + friend class udoc_relation; + class join_fn; + class project_fn; + class union_fn; + class rename_fn; + class filter_mask_fn; + class filter_identical_fn; + class filter_interpreted_fn; + class filter_by_negation_fn; + class filter_by_union_fn; + ast_manager& m; + bv_util bv; + u_map m_dms; + doc_manager& dm(unsigned sz); + doc_manager& dm(relation_signature const& sig); + static udoc_relation& get(relation_base& r); + static udoc_relation* get(relation_base* r); + static udoc_relation const & get(relation_base const& r); + + public: + udoc_plugin(relation_manager& rm); + ~udoc_plugin(); + virtual bool can_handle_signature(const relation_signature & s); + static symbol get_name() { return symbol("doc"); } + virtual relation_base * mk_empty(const relation_signature & s); + virtual relation_base * mk_full(func_decl* p, const relation_signature & s); + virtual relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); + virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, + const unsigned * removed_cols); + virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle); + virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta); + virtual relation_union_fn * mk_widen_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta); + virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, + const unsigned * identical_cols); + virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, + unsigned col); + virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); + // project join select + }; +}; + +#endif /* _UDOC_RELATION_H_ */ + From f71730b0dfb79a95bcad6529148e35542f0559f4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 16 Sep 2014 15:50:12 -0700 Subject: [PATCH 534/925] porting fun Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/doc.cpp | 3 + src/muz/ddnf/doc.h | 106 ++++++++++++++++++++++- src/muz/ddnf/tbv.cpp | 9 +- src/muz/ddnf/tbv.h | 15 ++-- src/muz/ddnf/udoc_relation.cpp | 149 +++++++++++++++++++++++++++------ src/muz/ddnf/udoc_relation.h | 5 +- 6 files changed, 248 insertions(+), 39 deletions(-) diff --git a/src/muz/ddnf/doc.cpp b/src/muz/ddnf/doc.cpp index 8690e8218..5dd3d0eb1 100644 --- a/src/muz/ddnf/doc.cpp +++ b/src/muz/ddnf/doc.cpp @@ -47,6 +47,9 @@ doc* doc_manager::allocate(rational const& r) { doc* doc_manager::allocate(uint64 n, unsigned hi, unsigned lo) { return 0; } +doc* doc_manager::allocate(doc, unsigned const* permutation) { + return 0; +} void doc_manager::deallocate(doc* src) { } void doc_manager::copy(doc& dst, doc const& src) const { diff --git a/src/muz/ddnf/doc.h b/src/muz/ddnf/doc.h index aa32fd47a..22f9ecf7b 100644 --- a/src/muz/ddnf/doc.h +++ b/src/muz/ddnf/doc.h @@ -24,6 +24,8 @@ Revision History: #define _DOC_H_ #include "tbv.h" +#include "union_find.h" + class doc; template class union_bvec; @@ -42,6 +44,7 @@ public: doc* allocate(uint64 n); doc* allocate(rational const& r); doc* allocate(uint64 n, unsigned hi, unsigned lo); + doc* allocate(doc, unsigned const* permutation); void deallocate(doc* src); void copy(doc& dst, doc const& src) const; doc& reset(doc& src) const { return fill0(src); } @@ -62,6 +65,15 @@ public: template class union_bvec { ptr_vector m_elems; // TBD: reuse allocator of M + + enum fix_bit_result_t { + e_row_removed, // = 1 + e_duplicate_row, // = 2 + e_fixed + }; + + typedef union_find<> subset_ints; + public: unsigned size() const { return m_elems.size(); } T& operator[](unsigned idx) const { return *m_elems[idx]; } @@ -81,7 +93,7 @@ public: } m_elems.reset(); } - void insert(M& m, T* t) { + bool insert(M& m, T* t) { unsigned sz = size(), j = 0; bool found = false; for (unsigned i = 0; i < sz; ++i, ++j) { @@ -103,6 +115,7 @@ public: else { m_elems.push_back(t); } + return !found; } bool intersect(M& m, T& t) { unsigned sz = size(); @@ -145,6 +158,97 @@ public: negated.reset(m); } } + void fix_eq_bits(unsigned idx1, tbv* BV, unsigned idx2, unsigned length, + subset_ints& equalities, const bit_vector& discard_cols) { + for (unsigned i = 0; i < length; ++i) { + unsigned k = 0; + for (unsigned j = 0; j < size(); ++j, ++k) { + +#if 0 + T *eqBV = BV ? const_cast(BV) : &*I; + bool discard_col = discard_cols.get(idx1+i) || (!BV && discard_cols.get(idx2+i)); + + switch (fix_single_bit(*I, idx1+i, eqBV, idx2+i, equalities, discard_col)) { + case 1: + // remove row + I = m_bitvectors.erase(I); + break; + + case 2: { + // don't care column equality. try subtraction first. + union_ternary_bitvector diff(I->size()), result(I->size()); + T BV(I->size(), true); + BV.set(idx1+i, BIT_0); + BV.set(idx2+i, BIT_1); + diff.add_new_fact(BV); + + BV.set(idx1+i, BIT_1); + BV.set(idx2+i, BIT_0); + diff.add_new_fact(BV); + + I->subtract(diff, result); + *I = *result.begin(); + ++I; + break; + } + + default: + if (I->is_empty()) { + I = m_bitvectors.erase(I); + } else { + // bits fixed + ++I; + } + } +#endif + } + } + } + +private: + + fix_bit_result_t fix_single_bit(tbv& bv, unsigned idx, unsigned value, const subset_ints& equalities) { + unsigned root = equalities.find(idx); + idx = root; + do { + unsigned bitval = bv.get(idx); + if (bitval == tbv::BIT_x) { + bv.set(idx, value); + } + else if (bitval != value) { + return e_row_removed; + } + idx = equalities.next(idx); + } + while (idx != root); + return e_fixed; + } + + fix_bit_result_t fix_single_bit(tbv & BV1, unsigned idx1, tbv & BV2, unsigned idx2, + subset_ints& equalities, bool discard_col) { + unsigned A = BV1.get(idx1); + unsigned B = BV2.get(idx2); + + if (A == tbv::BIT_x) { + if (B == tbv::BIT_x) { + // Both are don't cares. + if (!discard_col) + return e_duplicate_row; + equalities.merge(idx1, idx2); + return e_fixed; + } else { + // only A is don't care. + return fix_single_bit(BV1, idx1, B, equalities); + } + } else if (B == tbv::BIT_x) { + // Only B is don't care. + return fix_single_bit(BV2, idx2, A, equalities); + } else if (A == B) { + return e_fixed; + } else { + return e_row_removed; + } + } }; diff --git a/src/muz/ddnf/tbv.cpp b/src/muz/ddnf/tbv.cpp index b6b5e1b6d..ad6dae69e 100644 --- a/src/muz/ddnf/tbv.cpp +++ b/src/muz/ddnf/tbv.cpp @@ -59,10 +59,17 @@ tbv* tbv_manager::allocate(uint64 val) { tbv* tbv_manager::allocate(uint64 val, unsigned hi, unsigned lo) { tbv* v = allocateX(); - SASSERT(64 >= m.num_bits() && m.num_bits() > hi && hi >= lo); + SASSERT(64 >= num_tbits() && num_tbits() > hi && hi >= lo); v->set(val, hi, lo); return v; } +tbv* tbv_manager::allocate(tbv const& bv, unsigned const* permutation) { + tbv* r = allocate(); + for (unsigned i = 0; i < num_tbits(); ++i) { + r->set(permutation[i], bv.get(i)); + } + return r; +} void tbv::set(uint64 val, unsigned hi, unsigned lo) { for (unsigned i = 0; i < hi - lo + 1; ++i) { set(lo + i, (val & (1ULL << i))?BIT_1:BIT_0); diff --git a/src/muz/ddnf/tbv.h b/src/muz/ddnf/tbv.h index 190ad0cde..c583dd3f1 100644 --- a/src/muz/ddnf/tbv.h +++ b/src/muz/ddnf/tbv.h @@ -26,12 +26,13 @@ Revision History: class tbv; +#define BIT_0 0x1 +#define BIT_1 0x2 +#define BIT_x 0x3 +#define BIT_z 0x0 + class tbv_manager { friend class tbv; - static const unsigned BIT_0 = 0x1; - static const unsigned BIT_1 = 0x2; - static const unsigned BIT_x = 0x3; - static const unsigned BIT_z = 0x0; fixed_bit_vector_manager m; public: tbv_manager(unsigned n): m(2*n) {} @@ -44,6 +45,7 @@ public: tbv* allocate(uint64 n); tbv* allocate(rational const& r); tbv* allocate(uint64 n, unsigned hi, unsigned lo); + tbv* allocate(tbv const& bv, unsigned const* permutation); void deallocate(tbv* bv); @@ -69,11 +71,6 @@ class tbv: private fixed_bit_vector { public: - static const unsigned BIT_0 = tbv_manager::BIT_0; - static const unsigned BIT_1 = tbv_manager::BIT_1; - static const unsigned BIT_x = tbv_manager::BIT_x; - static const unsigned BIT_z = tbv_manager::BIT_z; - struct eq { tbv_manager& m; eq(tbv_manager& m):m(m) {} diff --git a/src/muz/ddnf/udoc_relation.cpp b/src/muz/ddnf/udoc_relation.cpp index 5e7e0f314..83b6c28fb 100644 --- a/src/muz/ddnf/udoc_relation.cpp +++ b/src/muz/ddnf/udoc_relation.cpp @@ -108,6 +108,10 @@ namespace datalog { return dynamic_cast(r); } + doc_manager& udoc_plugin::dm(relation_signature const& sig) { + return dm(udoc_relation::num_signature_bits(bv, sig)); + } + doc_manager& udoc_plugin::dm(unsigned n) { doc_manager* r; if (!m_dms.find(n, r)) { @@ -116,17 +120,20 @@ namespace datalog { } return *r; } - bool udoc_plugin::can_handle_signature(const relation_signature & s) { - NOT_IMPLEMENTED_YET(); - return false; + bool udoc_plugin::can_handle_signature(const relation_signature & sig) { + for (unsigned i = 0; i < sig.size(); ++i) { + if (!bv.is_bv_sort(sig[i])) + return false; + } + return true; } - relation_base * udoc_plugin::mk_empty(const relation_signature & s) { - NOT_IMPLEMENTED_YET(); - return 0; + relation_base * udoc_plugin::mk_empty(const relation_signature & sig) { + return alloc(udoc_relation, *this, sig); } relation_base * udoc_plugin::mk_full(func_decl* p, const relation_signature & s) { - NOT_IMPLEMENTED_YET(); - return 0; + udoc_relation* r = get(mk_empty(s)); + r->get_udoc().push_back(dm(s).allocateX()); + return r; } class udoc_plugin::join_fn : public convenient_relation_join_fn { doc_manager& dm; @@ -158,10 +165,10 @@ namespace datalog { unsigned v1 = pos[idx1]; unsigned v2 = pos[idx2]; - if (v1 == tbv::BIT_x) { - if (v2 != tbv::BIT_x) + if (v1 == BIT_x) { + if (v2 != BIT_x) pos.set(idx1, v2); - } else if (v2 == tbv::BIT_x) { + } else if (v2 == BIT_x) { pos.set(idx2, v1); } else if (v1 != v2) { dm.deallocate(d); @@ -176,16 +183,16 @@ namespace datalog { unsigned v1 = pos[idx1]; unsigned v2 = pos[idx2]; - if (v1 == tbv::BIT_x && v2 == tbv::BIT_x) { + if (v1 == BIT_x && v2 == BIT_x) { // add to subtracted TBVs: 1xx0 and 0xx1 tbv* r = dm.tbv().allocate(pos); - r->set(idx1, tbv::BIT_0); - r->set(idx2, tbv::BIT_1); + r->set(idx1, BIT_0); + r->set(idx2, BIT_1); neg.push_back(r); r = dm.tbv().allocate(pos); - r->set(idx1, tbv::BIT_1); - r->set(idx2, tbv::BIT_0); + r->set(idx1, BIT_1); + r->set(idx2, BIT_0); neg.push_back(r); } } @@ -237,29 +244,119 @@ namespace datalog { NOT_IMPLEMENTED_YET(); return 0; } + + class udoc_plugin::rename_fn : public convenient_relation_rename_fn { + unsigned_vector m_permutation; + public: + rename_fn(const relation_signature & orig_sig, unsigned cycle_len, const unsigned * cycle) + : convenient_relation_rename_fn(orig_sig, cycle_len, cycle) { + NOT_IMPLEMENTED_YET(); + // compute permuation. + } + + virtual relation_base * operator()(const relation_base & _r) { + udoc_relation const& r = get(_r); + udoc_plugin& p = r.get_plugin(); + relation_signature const& sig = get_result_signature(); + udoc_relation* result = alloc(udoc_relation, p, sig); + udoc const& src = r.get_udoc(); + udoc& dst = result->get_udoc(); + doc_manager& dm = r.get_dm(); + for (unsigned i = 0; i < src.size(); ++i) { + dst.push_back(dm.allocate(src[i], m_permutation.c_ptr())); + } + return result; + } + }; relation_transformer_fn * udoc_plugin::mk_rename_fn( - const relation_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle) { - NOT_IMPLEMENTED_YET(); - return 0; + const relation_base & r, + unsigned cycle_len, const unsigned * permutation_cycle) { + if (check_kind(r)) { + return alloc(rename_fn, r.get_signature(), cycle_len, permutation_cycle); + } + else { + return 0; + } + } + class udoc_plugin::union_fn : public relation_union_fn { + public: + union_fn() {} + + virtual void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) { + + TRACE("dl", _r.display(tout << "dst:\n"); _src.display(tout << "src:\n");); + + udoc_relation& r = get(_r); + udoc_relation const& src = get(_src); + udoc_relation* d = get(_delta); + udoc* d1 = 0; + if (d) d1 = &d->get_udoc(); + r.get_plugin().mk_union(r.get_dm(), r.get_udoc(), src.get_udoc(), d1); + } + }; + void udoc_plugin::mk_union(doc_manager& dm, udoc& dst, udoc const& src, udoc* delta) { + for (unsigned i = 0; i < src.size(); ++i) { + doc* d = dm.allocate(src[i]); + if (dst.insert(dm, d)) { + if (delta) { + delta->insert(dm, dm.allocate(src[i])); + } + } + } } relation_union_fn * udoc_plugin::mk_union_fn( const relation_base & tgt, const relation_base & src, const relation_base * delta) { - NOT_IMPLEMENTED_YET(); - return 0; + if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) { + return 0; + } + return alloc(union_fn); } relation_union_fn * udoc_plugin::mk_widen_fn( const relation_base & tgt, const relation_base & src, const relation_base * delta) { - NOT_IMPLEMENTED_YET(); - return 0; + return mk_union_fn(tgt, src, delta); } + + class udoc_plugin::filter_identical_fn : public relation_mutator_fn { + unsigned_vector m_cols; + unsigned m_size; + bit_vector m_empty_bv; + union_find_default_ctx union_ctx; + union_find<> m_equalities; + public: + filter_identical_fn(const relation_base & _r, unsigned col_cnt, const unsigned *identical_cols) + : m_cols(col_cnt), m_equalities(union_ctx) { + udoc_relation const& r = get(_r); + doc_manager& dm = r.get_dm(); + unsigned num_bits = dm.num_tbits(); + m_size = r.column_num_bits(identical_cols[0]); + m_empty_bv.resize(r.get_num_bits(), false); + + for (unsigned i = 0; i < col_cnt; ++i) { + m_cols[i] = r.column_idx(identical_cols[i]); + } + + for (unsigned i = 0, e = m_empty_bv.size(); i < e; ++i) { + m_equalities.mk_var(); + } + } + + virtual void operator()(relation_base & _r) { + udoc_relation& r = get(_r); + udoc& d = r.get_udoc(); + for (unsigned i = 1; i < m_cols.size(); ++i) { + d.fix_eq_bits(m_cols[0], 0, m_cols[i], m_size, m_equalities, m_empty_bv); + } + TRACE("dl", tout << "final size: " << r.get_size_estimate_rows() << '\n';); + } + }; relation_mutator_fn * udoc_plugin::mk_filter_identical_fn( const relation_base & t, unsigned col_cnt, const unsigned * identical_cols) { - NOT_IMPLEMENTED_YET(); - return 0; + if (!check_kind(t)) + return 0; + return alloc(filter_identical_fn, t, col_cnt, identical_cols); } relation_mutator_fn * udoc_plugin::mk_filter_equal_fn( const relation_base & t, const relation_element & value, unsigned col) { diff --git a/src/muz/ddnf/udoc_relation.h b/src/muz/ddnf/udoc_relation.h index 2dfa49553..27035dd53 100644 --- a/src/muz/ddnf/udoc_relation.h +++ b/src/muz/ddnf/udoc_relation.h @@ -30,7 +30,7 @@ namespace datalog { class udoc_relation; class udoc_relation : public relation_base { - friend class udoc_relation; + friend class udoc_plugin; doc_manager& dm; udoc m_elems; unsigned_vector m_column_info; @@ -53,6 +53,7 @@ namespace datalog { doc_manager& get_dm() const { return dm; } udoc const& get_udoc() const { return m_elems; } udoc& get_udoc() { return m_elems; } + unsigned get_num_records() const { return m_elems.size(); } unsigned get_num_bits() const { return m_column_info.back(); } unsigned get_num_cols() const { return m_column_info.size()-1; } unsigned column_idx(unsigned col) const { return m_column_info[col]; } @@ -79,7 +80,7 @@ namespace datalog { static udoc_relation& get(relation_base& r); static udoc_relation* get(relation_base* r); static udoc_relation const & get(relation_base const& r); - + void mk_union(doc_manager& dm, udoc& dst, udoc const& src, udoc* delta); public: udoc_plugin(relation_manager& rm); ~udoc_plugin(); From 44e8833369a7674f77164c194ab8d807bb0ea634 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 16 Sep 2014 17:06:05 -0700 Subject: [PATCH 535/925] more udoc Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/doc.h | 17 +++- src/muz/ddnf/tbv.h | 16 +++ src/muz/ddnf/udoc_relation.cpp | 172 ++++++++++++++++++++++++++++++++- src/muz/ddnf/udoc_relation.h | 13 ++- 4 files changed, 208 insertions(+), 10 deletions(-) diff --git a/src/muz/ddnf/doc.h b/src/muz/ddnf/doc.h index 22f9ecf7b..b311a9ef0 100644 --- a/src/muz/ddnf/doc.h +++ b/src/muz/ddnf/doc.h @@ -117,13 +117,19 @@ public: } return !found; } - bool intersect(M& m, T& t) { + void intersect(M& m, T& t) { unsigned sz = size(); - for (unsigned i = 0; i < sz; ++i) { - if (!m.set_and(m_elems[i], t)) - return false; + unsigned j = 0; + for (unsigned i = 0; i < sz; ++i, ++j) { + if (!m.set_and(*m_elems[i], t)) { + m.deallocate(m_elems[i]); + --j; + } + else if (i != j) { + m_elems[i] = m_elems[j]; + } } - return true; + if (j != sz) m_elems.resize(j); } void insert(M& m, union_bvec const& other) { for (unsigned i = 0; i < other.size(); ++i) { @@ -163,6 +169,7 @@ public: for (unsigned i = 0; i < length; ++i) { unsigned k = 0; for (unsigned j = 0; j < size(); ++j, ++k) { + NOT_IMPLEMENTED_YET(); #if 0 T *eqBV = BV ? const_cast(BV) : &*I; diff --git a/src/muz/ddnf/tbv.h b/src/muz/ddnf/tbv.h index c583dd3f1..2ae79a10d 100644 --- a/src/muz/ddnf/tbv.h +++ b/src/muz/ddnf/tbv.h @@ -106,5 +106,21 @@ private: } }; +class tbv_ref { + tbv_manager& mgr; + tbv* d; +public: + tbv_ref(tbv_manager& mgr):mgr(mgr),d(0) {} + tbv_ref(tbv_manager& mgr, tbv* d):mgr(mgr),d(d) {} + ~tbv_ref() { + if (d) mgr.deallocate(d); + } + tbv_ref& operator=(tbv* d2) { + if (d) mgr.deallocate(d); + d = d2; + } + tbv& operator*() { return *d; } +}; + #endif /* _TBV_H_ */ diff --git a/src/muz/ddnf/udoc_relation.cpp b/src/muz/ddnf/udoc_relation.cpp index 83b6c28fb..8f422e77a 100644 --- a/src/muz/ddnf/udoc_relation.cpp +++ b/src/muz/ddnf/udoc_relation.cpp @@ -358,14 +358,178 @@ namespace datalog { return 0; return alloc(filter_identical_fn, t, col_cnt, identical_cols); } + class udoc_plugin::filter_equal_fn : public relation_mutator_fn { + doc_manager& dm; + doc* m_filter; + public: + filter_equal_fn(udoc_plugin& p, const udoc_relation & t, const relation_element val, unsigned col): + dm(p.dm(t.get_signature())) { + rational r; + unsigned num_bits; + VERIFY(p.bv.is_numeral(val, r, num_bits)); + m_filter = dm.allocateX(); + unsigned lo = t.column_idx(col); + unsigned hi = t.column_idx(col+1); + SASSERT(num_bits == hi - lo); + m_filter->pos().set(r, hi-1, lo); + } + virtual ~filter_equal_fn() { + dm.deallocate(m_filter); + } + virtual void operator()(relation_base & tb) { + udoc_relation & t = get(tb); + t.get_udoc().intersect(dm, *m_filter); + } + }; relation_mutator_fn * udoc_plugin::mk_filter_equal_fn( const relation_base & t, const relation_element & value, unsigned col) { - NOT_IMPLEMENTED_YET(); - return 0; + if (!check_kind(t)) + return 0; + return alloc(filter_equal_fn, *this, get(t), value, col); } +#if 0 + static bool cond_is_guard(const expr *e, const table_information& t) { + switch (e->get_kind()) { + case AST_APP: { + const app *app = to_app(e); + switch (app->get_decl_kind()) { + case OP_AND: + case OP_OR: + case OP_NOT: + for (unsigned i = 0; i < app->get_num_args(); ++i) { + if (!cond_is_guard(app->get_arg(i), t)) + return false; + } + return true; + + case OP_EQ: { + const expr *a = app->get_arg(0), *b = app->get_arg(1); + + // column equality is not succinctly representable with TBVs + if (is_var(a) && is_var(b)) + return false; + + // (= var (concat var foo)) + if (t.get_bv_util().is_concat(b)) + return false; + + return true;} + + case OP_FALSE: + case OP_TRUE: + return true; + + default: + return false; + } + break;} + + case AST_VAR: + return true; + + default: + break; + } + return false; + } + + static void split_cond_guard(app *cond, expr_ref& guard, expr_ref& leftover, const table_information& t) { + expr_ref_vector guards(guard.m()); + expr_ref_vector leftovers(leftover.m()); + + if (is_app(cond) && to_app(cond)->get_decl_kind() == OP_AND) { + app *a = to_app(cond); + for (unsigned i = 0; i < a->get_num_args(); ++i) { + expr *arg = a->get_arg(i); + if (cond_is_guard(arg, t)) { + guards.push_back(arg); + } else { + leftovers.push_back(arg); + } + } + } else if (cond_is_guard(cond, t)) { + guard = cond; + return; + } else { + leftover = cond; + return; + } + + if (guards.size() > 1) { + guard = guard.m().mk_and(guards.size(), guards.c_ptr()); + } else if (guards.size() == 1) { + guard = guards.get(0); + } + + if (leftovers.size() > 1) { + leftover = leftover.m().mk_and(leftovers.size(), leftovers.c_ptr()); + } else if (leftovers.size() == 1) { + leftover = leftovers.get(0); + } + } +#endif + class udoc_plugin::filter_interpreted_fn : public relation_mutator_fn { + expr_ref m_condition; + //typename T::bitset_t m_filter; + //bit_vector m_empty_bv; + public: + filter_interpreted_fn(const udoc_relation & t, ast_manager& m, app *condition) : + m_condition(m) { + NOT_IMPLEMENTED_YET(); + //m_filter(t.get_num_bits(), true); + //m_empty_bv.resize(t.get_num_bits(), false); + + //expr_ref guard(m); + //split_cond_guard(condition, guard, m_condition, t); + //if (guard) + // m_filter.filter(guard, m_empty_bv, t); + } + + virtual void operator()(relation_base & tb) { + udoc_relation & t = get(tb); + // first apply guard and then run the interpreter on the leftover + //t.m_bitsets = m_filter.band(t.m_bitsets); + //if (m_condition) + // t.m_bitsets.filter(m_condition, m_empty_bv, t); + TRACE("dl", tout << "final size: " << t.get_size_estimate_rows() << '\n';); + } + }; + + + relation_mutator_fn * udoc_plugin::mk_filter_interpreted_fn(const relation_base & t, app * condition) { - NOT_IMPLEMENTED_YET(); - return 0; + if (!check_kind(t)) + return 0; + TRACE("dl", tout << mk_pp(condition, get_ast_manager()) << '\n';); + return alloc(filter_interpreted_fn, get(t), get_ast_manager(), condition); } + class udoc_plugin::negation_filter_fn : public relation_intersection_filter_fn { + const unsigned_vector m_t_cols; + const unsigned_vector m_neg_cols; + public: + negation_filter_fn(const udoc_relation & r, const udoc_relation & neg, unsigned joined_col_cnt, + const unsigned *t_cols, const unsigned *neg_cols) + : m_t_cols(joined_col_cnt, t_cols), m_neg_cols(joined_col_cnt, neg_cols) { + SASSERT(joined_col_cnt > 0); + } + + virtual void operator()(relation_base& tb, const relation_base& negb) { + udoc_relation& t = get(tb); + udoc_relation const& neg = get(negb); + NOT_IMPLEMENTED_YET(); + // t.m_bitsets.filter_negate(t, neg.m_bitsets, neg, m_t_cols, m_neg_cols); + } + }; + + relation_intersection_filter_fn * udoc_plugin::mk_filter_by_negation_fn( + const relation_base& t, + const relation_base& neg, unsigned joined_col_cnt, const unsigned *t_cols, + const unsigned *negated_cols) { + if (!check_kind(t) || !check_kind(neg)) + return 0; + return alloc(negation_filter_fn, get(t), get(neg), joined_col_cnt, t_cols, negated_cols); + } + + } diff --git a/src/muz/ddnf/udoc_relation.h b/src/muz/ddnf/udoc_relation.h index 27035dd53..4e9c9c308 100644 --- a/src/muz/ddnf/udoc_relation.h +++ b/src/muz/ddnf/udoc_relation.h @@ -49,6 +49,7 @@ namespace datalog { virtual bool empty() const { return m_elems.empty(); } virtual void display(std::ostream& out) const; virtual bool is_precise() const { return true; } + virtual unsigned get_size_estimate_rows() const { return m_elems.size(); } doc_manager& get_dm() const { return dm; } udoc const& get_udoc() const { return m_elems; } @@ -67,11 +68,13 @@ namespace datalog { class project_fn; class union_fn; class rename_fn; - class filter_mask_fn; + class filter_equal_fn; class filter_identical_fn; class filter_interpreted_fn; class filter_by_negation_fn; class filter_by_union_fn; + class filter_proj_fn; + class negation_filter_fn; ast_manager& m; bv_util bv; u_map m_dms; @@ -103,6 +106,14 @@ namespace datalog { virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, unsigned col); virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); + virtual relation_intersection_filter_fn * udoc_plugin::mk_filter_by_negation_fn( + const relation_base& t, + const relation_base& neg, unsigned joined_col_cnt, const unsigned *t_cols, + const unsigned *negated_cols); + virtual relation_transformer_fn * mk_filter_interpreted_and_project_fn( + const relation_base & t, app * condition, + unsigned removed_col_cnt, const unsigned * removed_cols); + // project join select }; }; From e32448d7ea197178b87d043a09965a9d9b8a3720 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 16 Sep 2014 21:46:39 -0700 Subject: [PATCH 536/925] more fun with docs Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 7 - src/ast/ast.h | 1 - src/muz/ddnf/doc.cpp | 3 + src/muz/ddnf/doc.h | 10 +- src/muz/ddnf/tbv.h | 2 + src/muz/ddnf/udoc_relation.cpp | 318 +++++++++++++++++++++++---------- src/muz/ddnf/udoc_relation.h | 6 + 7 files changed, 244 insertions(+), 103 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 0915ae1b6..95d47dc03 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -2066,13 +2066,6 @@ expr* ast_manager::mk_or_reduced(unsigned n, expr* const* args) { } } -expr* ast_manager::mk_and_reduced(unsigned n, expr* const* args) { - switch (n) { - case 0: return mk_true(); - case 1: return args[0]; - default: return mk_and(n, args); - } -} func_decl * ast_manager::mk_fresh_func_decl(symbol const & prefix, symbol const & suffix, unsigned arity, sort * const * domain, sort * range) { diff --git a/src/ast/ast.h b/src/ast/ast.h index f8ba43554..1c4771e7f 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -2005,7 +2005,6 @@ public: app * mk_false() { return m_false; } app * mk_interp(expr * arg) { return mk_app(m_basic_family_id, OP_INTERP, arg); } expr * mk_or_reduced(unsigned num_args, expr * const * args); - expr * mk_and_reduced(unsigned num_args, expr * const * args); func_decl* mk_and_decl() { diff --git a/src/muz/ddnf/doc.cpp b/src/muz/ddnf/doc.cpp index 5dd3d0eb1..2c6b4696e 100644 --- a/src/muz/ddnf/doc.cpp +++ b/src/muz/ddnf/doc.cpp @@ -73,6 +73,9 @@ void doc_manager::subtract(doc const& A, doc const& B, ptr_vector& result) bool doc_manager::equals(doc const& a, doc const& b) const { return false; } +bool doc_manager::is_full(doc const& src) const { + return false; +} unsigned doc_manager::hash(doc const& src) const { return 0; } diff --git a/src/muz/ddnf/doc.h b/src/muz/ddnf/doc.h index b311a9ef0..074045c95 100644 --- a/src/muz/ddnf/doc.h +++ b/src/muz/ddnf/doc.h @@ -51,7 +51,9 @@ public: doc& fill0(doc& src) const; doc& fill1(doc& src) const; doc& fillX(doc& src) const; + bool is_full(doc const& src) const; bool set_and(doc& dst, doc const& src) const; + bool intersect(doc const& A, doc const& B, doc& result) const; void complement(doc const& src, ptr_vector& result); void subtract(doc const& A, doc const& B, ptr_vector& result); bool equals(doc const& a, doc const& b) const; @@ -61,6 +63,8 @@ public: unsigned num_tbits() const { return m.num_tbits(); } }; +typedef union_find<> subset_ints; + // union of tbv*, union of doc* template class union_bvec { @@ -72,12 +76,12 @@ class union_bvec { e_fixed }; - typedef union_find<> subset_ints; public: unsigned size() const { return m_elems.size(); } T& operator[](unsigned idx) const { return *m_elems[idx]; } bool empty() const { return m_elems.empty(); } + bool is_full(M& m) const { return size() == 1 && m.is_full(*m_elems[0]); } bool contains(M& m, T& t) const { for (unsigned i = 0; i < m_elems.size(); ++i) { if (m.contains(*m_elems[i], t)) return true; @@ -143,7 +147,7 @@ public: T* inter = m.allocate(); for (unsigned i = 0; i < sz1; ++i) { for (unsigned j = 0; j < sz2; ++j) { - if (m.intesect(*m_elems[i], other[j], *inter)) { + if (m.intersect(*m_elems[i], other[j], *inter)) { result.push_back(inter); inter = m.allocate(); } @@ -151,7 +155,7 @@ public: } m.deallocate(inter); std::swap(result, *this); - result.reset(); + result.reset(m); } void complement(M& m, union_bvec& result) { union_bvec negated; diff --git a/src/muz/ddnf/tbv.h b/src/muz/ddnf/tbv.h index 2ae79a10d..c8b9b5c96 100644 --- a/src/muz/ddnf/tbv.h +++ b/src/muz/ddnf/tbv.h @@ -118,8 +118,10 @@ public: tbv_ref& operator=(tbv* d2) { if (d) mgr.deallocate(d); d = d2; + return *this; } tbv& operator*() { return *d; } + tbv* get() { return d; } }; diff --git a/src/muz/ddnf/udoc_relation.cpp b/src/muz/ddnf/udoc_relation.cpp index 8f422e77a..e14e5b98c 100644 --- a/src/muz/ddnf/udoc_relation.cpp +++ b/src/muz/ddnf/udoc_relation.cpp @@ -1,5 +1,7 @@ #include "udoc_relation.h" #include "dl_relation_manager.h" +#include "qe_util.h" +#include "ast_util.h" namespace datalog { @@ -387,110 +389,171 @@ namespace datalog { return 0; return alloc(filter_equal_fn, *this, get(t), value, col); } + + bool udoc_relation::is_guard(unsigned n, expr* const* gs) const { + for (unsigned i = 0; i < n; ++i) { + if (!is_guard(gs[i])) return false; + } + return true; + } + bool udoc_relation::is_guard(expr* g) const { + ast_manager& m = get_plugin().get_ast_manager(); + expr* e1, *e2; + if (m.is_and(g) || m.is_or(g) || m.is_not(g) || m.is_true(g) || m.is_false(g)) { + return is_guard(to_app(g)->get_num_args(), to_app(g)->get_args()); + } + if (m.is_eq(g, e1, e2)) { + if (is_var(e1) && is_var(e2)) return false; + NOT_IMPLEMENTED_YET(); + // TBD + } + if (is_var(g)) { + return true; + } + return false; + } + + void udoc_relation::extract_guard(expr* cond, expr_ref& guard, expr_ref& rest) const { + rest.reset(); + ast_manager& m = get_plugin().get_ast_manager(); + expr_ref_vector conds(m), guards(m), rests(m); + conds.push_back(cond); + qe::flatten_and(conds); + for (unsigned i = 0; i < conds.size(); ++i) { + expr* g = conds[i].get(); + if (is_guard(g)) { + guards.push_back(g); + } + else { + rests.push_back(g); + } + } + guard = mk_and(m, guards.size(), guards.c_ptr()); + rest = mk_and(m, rests.size(), rests.c_ptr()); + } + void udoc_relation::compile_guard(expr* g, udoc& d) const { + NOT_IMPLEMENTED_YET(); + } + void udoc_relation::apply_guard(expr* g, udoc& result, bit_vector const& discard_cols) { + // datastructure to store equalities with columns that will be projected out + union_find_default_ctx union_ctx; + subset_ints equalities(union_ctx); + for (unsigned i = 0, e = discard_cols.size(); i < e; ++i) { + equalities.mk_var(); + } + apply_guard(g, result, equalities, discard_cols); + } + void udoc_relation::apply_guard( + expr* g, udoc& result, subset_ints& equalities, + bit_vector const& discard_cols) { + ast_manager& m = get_plugin().get_ast_manager(); + expr* e1, *e2; + if (result.empty()) { + } + else if (m.is_and(g)) { + for (unsigned i = 0; !result.empty() && i < to_app(g)->get_num_args(); ++i) { + apply_guard(to_app(g)->get_arg(i), result, equalities, discard_cols); + } + } + else if (m.is_not(g, e1)) { + udoc sub; + sub.push_back(dm.allocateX()); + apply_guard(e1, sub, equalities, discard_cols); + // TBD: result.subtract(dm, sub); + } + else if (m.is_or(g)) { + udoc sub; + sub.push_back(dm.allocateX()); + for (unsigned i = 0; !sub.empty() && i < to_app(g)->get_num_args(); ++i) { + expr_ref arg(m); + arg = to_app(g)->get_arg(i); + if (m.is_not(arg, e1)) { + arg = e1; + } + else { + arg = m.mk_not(arg); + } + apply_guard(arg, result, equalities, discard_cols); + } + // TBD: result.subtract(dm, sub); + } + else if (m.is_true(g)) { + } + else if (m.is_false(g)) { + result.reset(dm); + } + else if (is_var(g)) { + SASSERT(m.is_bool(g)); + unsigned v = to_var(g)->get_idx(); + unsigned idx = column_idx(v); + doc_manager& dm1 = get_plugin().dm(1); + tbv_ref bit1(dm1.tbv()); + bit1 = dm1.tbv().allocate1(); + result.fix_eq_bits(idx, bit1.get(), 0, 1, equalities, discard_cols); + } + else if (m.is_eq(g, e1, e2)) { #if 0 - static bool cond_is_guard(const expr *e, const table_information& t) { - switch (e->get_kind()) { - case AST_APP: { - const app *app = to_app(e); - switch (app->get_decl_kind()) { - case OP_AND: - case OP_OR: - case OP_NOT: - for (unsigned i = 0; i < app->get_num_args(); ++i) { - if (!cond_is_guard(app->get_arg(i), t)) - return false; - } - return true; - - case OP_EQ: { - const expr *a = app->get_arg(0), *b = app->get_arg(1); - - // column equality is not succinctly representable with TBVs - if (is_var(a) && is_var(b)) - return false; - - // (= var (concat var foo)) - if (t.get_bv_util().is_concat(b)) - return false; - - return true;} - - case OP_FALSE: - case OP_TRUE: - return true; - - default: - return false; - } - break;} - - case AST_VAR: - return true; - - default: - break; - } - return false; - } - - static void split_cond_guard(app *cond, expr_ref& guard, expr_ref& leftover, const table_information& t) { - expr_ref_vector guards(guard.m()); - expr_ref_vector leftovers(leftover.m()); - - if (is_app(cond) && to_app(cond)->get_decl_kind() == OP_AND) { - app *a = to_app(cond); - for (unsigned i = 0; i < a->get_num_args(); ++i) { - expr *arg = a->get_arg(i); - if (cond_is_guard(arg, t)) { - guards.push_back(arg); - } else { - leftovers.push_back(arg); - } - } - } else if (cond_is_guard(cond, t)) { - guard = cond; - return; + const var *v; + unsigned vidx = 0; + unsigned length; + + unsigned low, high; + expr *e2; + if (is_var(e1)) { + v = to_var(e1); + length = column_num_bits(v->get_idx()); + } else if (bv.is_extract(e1, low, high, e11)) { + vidx = bv.get_bv_size(e11) - high - 1; + length = high - low + 1; + SASSERT(is_var(e11)); + v = to_var(e11); } else { - leftover = cond; - return; + NOT_IMPLEMENTED_YET(); } - - if (guards.size() > 1) { - guard = guard.m().mk_and(guards.size(), guards.c_ptr()); - } else if (guards.size() == 1) { - guard = guards.get(0); - } - - if (leftovers.size() > 1) { - leftover = leftover.m().mk_and(leftovers.size(), leftovers.c_ptr()); - } else if (leftovers.size() == 1) { - leftover = leftovers.get(0); - } - } + vidx += t.column_idx(v->get_idx()); + + unsigned final_idx = fix_eq_bits(vidx, e2, 0, length, t, equalities, discard_cols); + SASSERT(final_idx == vidx + length); + (void)final_idx; #endif + } + else { + // std::ostringstream strm; + // strm << "Guard expression is not handled" << mk_pp(g, m); + // throw default_exception(strm.str()); + throw 0; + } + } + class udoc_plugin::filter_interpreted_fn : public relation_mutator_fn { - expr_ref m_condition; - //typename T::bitset_t m_filter; - //bit_vector m_empty_bv; + doc_manager& dm; + expr_ref m_condition; + udoc m_udoc; + bit_vector m_empty_bv; public: filter_interpreted_fn(const udoc_relation & t, ast_manager& m, app *condition) : + dm(t.get_dm()), m_condition(m) { - NOT_IMPLEMENTED_YET(); - //m_filter(t.get_num_bits(), true); - //m_empty_bv.resize(t.get_num_bits(), false); - - //expr_ref guard(m); - //split_cond_guard(condition, guard, m_condition, t); - //if (guard) - // m_filter.filter(guard, m_empty_bv, t); + m_empty_bv.resize(t.get_num_bits(), false); + expr_ref guard(m), rest(m); + t.extract_guard(condition, guard, m_condition); + t.compile_guard(guard, m_udoc); + if (m.is_true(m_condition)) { + m_condition = 0; + } + } + + virtual ~filter_interpreted_fn() { + m_udoc.reset(dm); } virtual void operator()(relation_base & tb) { udoc_relation & t = get(tb); - // first apply guard and then run the interpreter on the leftover - //t.m_bitsets = m_filter.band(t.m_bitsets); - //if (m_condition) - // t.m_bitsets.filter(m_condition, m_empty_bv, t); + udoc& u = t.get_udoc(); + u.intersect(dm, m_udoc); + if (m_condition && !u.empty()) { + t.apply_guard(m_condition, u, m_empty_bv); + } TRACE("dl", tout << "final size: " << t.get_size_estimate_rows() << '\n';); } }; @@ -531,5 +594,76 @@ namespace datalog { return alloc(negation_filter_fn, get(t), get(neg), joined_col_cnt, t_cols, negated_cols); } +#if 0 + /// make bits of table [idx,idx+max_length] equal to e sliced starting at idx2 + unsigned fix_eq_bits(unsigned idx, expr *e, unsigned idx2, unsigned max_length, + const table_information& t, subset_ints& equalities, + const bit_vector & discard_cols) { + const bv_util& bvu = t.get_bv_util(); + const dl_decl_util& dutil = t.get_decl_util(); + + rational n; + unsigned bv_size; + if (bvu.is_numeral(e, n, bv_size)) { + SASSERT(idx2 < bv_size); + max_length = std::min(max_length, bv_size - idx2); + T num(n, max_length); + fix_eq_bits(idx, &num, idx2, max_length, equalities, discard_cols); + return idx + max_length; + } + + uint64 num; + if (dutil.is_numeral(e, num)) { + T num_bv(rational(num,rational::ui64()), max_length); + fix_eq_bits(idx, &num_bv, idx2, max_length, equalities, discard_cols); + return idx + max_length; + } + + if (bvu.is_concat(e)) { + const app *a = to_app(e); + + // skip the first elements of the concat if e.g. we have a top level extract + unsigned i = 0; + for (; i < a->get_num_args(); ++i) { + unsigned arg_size = bvu.get_bv_size(a->get_arg(i)); + if (idx2 < arg_size) + break; + idx2 -= arg_size; + } + + SASSERT(i < a->get_num_args()); + for (; max_length > 0 && i < a->get_num_args(); ++i) { + unsigned idx0 = idx; + idx = fix_eq_bits(idx, a->get_arg(i), idx2, max_length, t, equalities, discard_cols); + idx2 = 0; + SASSERT((idx - idx0) <= max_length); + max_length = max_length - (idx - idx0); + } + return idx; + } + + unsigned low, high; + expr *e2; + if (bvu.is_extract(e, low, high, e2)) { + SASSERT(low <= high); + unsigned size = bvu.get_bv_size(e2); + unsigned offset = size - (high+1) + idx2; + SASSERT(idx2 < (high-low+1)); + max_length = std::min(max_length, high - low + 1 - idx2); + return fix_eq_bits(idx, e2, offset, max_length, t, equalities, discard_cols); + } + + if (e->get_kind() == AST_VAR) { + unsigned idx_var = idx2 + t.column_idx(to_var(e)->get_idx()); + SASSERT(idx2 < t.column_num_bits(to_var(e)->get_idx())); + max_length = std::min(max_length, t.column_num_bits(to_var(e)->get_idx()) - idx2); + fix_eq_bits(idx, 0, idx_var, max_length, equalities, discard_cols); + return idx + max_length; + } + + NOT_IMPLEMENTED_YET(); + return 0; + } +#endif } diff --git a/src/muz/ddnf/udoc_relation.h b/src/muz/ddnf/udoc_relation.h index 4e9c9c308..6c10a62bb 100644 --- a/src/muz/ddnf/udoc_relation.h +++ b/src/muz/ddnf/udoc_relation.h @@ -60,6 +60,12 @@ namespace datalog { unsigned column_idx(unsigned col) const { return m_column_info[col]; } unsigned column_num_bits(unsigned col) const { return m_column_info[col+1] - m_column_info[col]; } void expand_column_vector(unsigned_vector& v, udoc_relation* other = 0) const; + void extract_guard(expr* condition, expr_ref& guard, expr_ref& rest) const; + bool is_guard(expr* g) const; + bool is_guard(unsigned n, expr* const *g) const; + void compile_guard(expr* g, udoc& d) const; + void apply_guard(expr* g, udoc& result, bit_vector const& discard_cols); + void apply_guard(expr* g, udoc& result, subset_ints& equalities, bit_vector const& discard_cols); }; class udoc_plugin : public relation_plugin { From 7e91fb5c1527f1f930328856f472a0737e640d56 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 16 Sep 2014 22:14:58 -0700 Subject: [PATCH 537/925] remove mk_or_reduced Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 7 -- src/ast/ast.h | 1 - src/muz/ddnf/doc.h | 17 ++++ src/muz/ddnf/udoc_relation.cpp | 144 +++++++--------------------- src/muz/ddnf/udoc_relation.h | 1 + src/tactic/arith/card2bv_tactic.cpp | 3 +- 6 files changed, 53 insertions(+), 120 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 95d47dc03..7dd320e06 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -2058,13 +2058,6 @@ app * ast_manager::mk_app(func_decl * decl, unsigned num_args, expr * const * ar return r; } -expr* ast_manager::mk_or_reduced(unsigned n, expr* const* args) { - switch (n) { - case 0: return mk_false(); - case 1: return args[0]; - default: return mk_or(n, args); - } -} func_decl * ast_manager::mk_fresh_func_decl(symbol const & prefix, symbol const & suffix, unsigned arity, diff --git a/src/ast/ast.h b/src/ast/ast.h index 1c4771e7f..f21f821b9 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -2004,7 +2004,6 @@ public: app * mk_true() { return m_true; } app * mk_false() { return m_false; } app * mk_interp(expr * arg) { return mk_app(m_basic_family_id, OP_INTERP, arg); } - expr * mk_or_reduced(unsigned num_args, expr * const * args); func_decl* mk_and_decl() { diff --git a/src/muz/ddnf/doc.h b/src/muz/ddnf/doc.h index 074045c95..42db3c545 100644 --- a/src/muz/ddnf/doc.h +++ b/src/muz/ddnf/doc.h @@ -157,6 +157,23 @@ public: std::swap(result, *this); result.reset(m); } + void subtract(M& m, union_bvec const& other) { + unsigned sz = other.size(); + for (unsigned i = 0; !empty() && i < sz; ++i) { + subtract(m, other[i]); + } + // TBD compress? + } + void subtract(M& m, T& t) { + unsigned sz = size(); + bool found = false; + union_bvec result; + for (unsigned i = 0; i < sz; ++i) { + m.subtract(*m_elems[i], t, result.m_elems); + } + std::swap(m_elems, result.m_elems); + result.reset(m); + } void complement(M& m, union_bvec& result) { union_bvec negated; result.reset(m); diff --git a/src/muz/ddnf/udoc_relation.cpp b/src/muz/ddnf/udoc_relation.cpp index e14e5b98c..393b85d54 100644 --- a/src/muz/ddnf/udoc_relation.cpp +++ b/src/muz/ddnf/udoc_relation.cpp @@ -444,9 +444,10 @@ namespace datalog { apply_guard(g, result, equalities, discard_cols); } void udoc_relation::apply_guard( - expr* g, udoc& result, subset_ints& equalities, - bit_vector const& discard_cols) { + expr* g, udoc& result, + subset_ints& equalities, bit_vector const& discard_cols) { ast_manager& m = get_plugin().get_ast_manager(); + bv_util& bv = get_plugin().bv; expr* e1, *e2; if (result.empty()) { } @@ -459,23 +460,17 @@ namespace datalog { udoc sub; sub.push_back(dm.allocateX()); apply_guard(e1, sub, equalities, discard_cols); - // TBD: result.subtract(dm, sub); + result.subtract(dm, sub); } else if (m.is_or(g)) { udoc sub; sub.push_back(dm.allocateX()); for (unsigned i = 0; !sub.empty() && i < to_app(g)->get_num_args(); ++i) { expr_ref arg(m); - arg = to_app(g)->get_arg(i); - if (m.is_not(arg, e1)) { - arg = e1; - } - else { - arg = m.mk_not(arg); - } + arg = mk_not(m, to_app(g)->get_arg(i)); apply_guard(arg, result, equalities, discard_cols); } - // TBD: result.subtract(dm, sub); + result.subtract(dm, sub); } else if (m.is_true(g)) { } @@ -491,37 +486,36 @@ namespace datalog { bit1 = dm1.tbv().allocate1(); result.fix_eq_bits(idx, bit1.get(), 0, 1, equalities, discard_cols); } - else if (m.is_eq(g, e1, e2)) { -#if 0 - const var *v; - unsigned vidx = 0; - unsigned length; - - unsigned low, high; - expr *e2; - if (is_var(e1)) { - v = to_var(e1); - length = column_num_bits(v->get_idx()); - } else if (bv.is_extract(e1, low, high, e11)) { - vidx = bv.get_bv_size(e11) - high - 1; - length = high - low + 1; - SASSERT(is_var(e11)); - v = to_var(e11); - } else { - NOT_IMPLEMENTED_YET(); + else if (m.is_eq(g, e1, e2) && bv.is_bv(e1)) { + unsigned hi, lo; + expr* e3; + // TBD: equalities and discard_cols? + if (is_var(e1) && is_ground(e2)) { + apply_eq(g, result, to_var(e1), bv.get_bv_size(e1)-1, 0, e2); } - vidx += t.column_idx(v->get_idx()); - - unsigned final_idx = fix_eq_bits(vidx, e2, 0, length, t, equalities, discard_cols); - SASSERT(final_idx == vidx + length); - (void)final_idx; -#endif + else if (is_var(e2) && is_ground(e1)) { + apply_eq(g, result, to_var(e2), bv.get_bv_size(e2)-1, 0, e1); + } + else if (bv.is_extract(e1, lo, hi, e3) && is_var(e3) && is_ground(e2)) { + apply_eq(g, result, to_var(e3), hi, lo, e2); + } + else if (bv.is_extract(e2, lo, hi, e3) && is_var(e3) && is_ground(e1)) { + apply_eq(g, result, to_var(e3), hi, lo, e1); + } + else if (is_var(e1) && is_var(e2)) { + var* v1 = to_var(e1); + var* v2 = to_var(e2); + // TBD + } + else { + goto failure_case; + } } else { - // std::ostringstream strm; - // strm << "Guard expression is not handled" << mk_pp(g, m); - // throw default_exception(strm.str()); - throw 0; + failure_case: + std::ostringstream strm; + strm << "Guard expression is not handled" << mk_pp(g, m); + throw default_exception(strm.str()); } } @@ -594,76 +588,4 @@ namespace datalog { return alloc(negation_filter_fn, get(t), get(neg), joined_col_cnt, t_cols, negated_cols); } -#if 0 - /// make bits of table [idx,idx+max_length] equal to e sliced starting at idx2 - unsigned fix_eq_bits(unsigned idx, expr *e, unsigned idx2, unsigned max_length, - const table_information& t, subset_ints& equalities, - const bit_vector & discard_cols) { - const bv_util& bvu = t.get_bv_util(); - const dl_decl_util& dutil = t.get_decl_util(); - - rational n; - unsigned bv_size; - if (bvu.is_numeral(e, n, bv_size)) { - SASSERT(idx2 < bv_size); - max_length = std::min(max_length, bv_size - idx2); - T num(n, max_length); - fix_eq_bits(idx, &num, idx2, max_length, equalities, discard_cols); - return idx + max_length; - } - - uint64 num; - if (dutil.is_numeral(e, num)) { - T num_bv(rational(num,rational::ui64()), max_length); - fix_eq_bits(idx, &num_bv, idx2, max_length, equalities, discard_cols); - return idx + max_length; - } - - if (bvu.is_concat(e)) { - const app *a = to_app(e); - - // skip the first elements of the concat if e.g. we have a top level extract - unsigned i = 0; - for (; i < a->get_num_args(); ++i) { - unsigned arg_size = bvu.get_bv_size(a->get_arg(i)); - if (idx2 < arg_size) - break; - idx2 -= arg_size; - } - - SASSERT(i < a->get_num_args()); - for (; max_length > 0 && i < a->get_num_args(); ++i) { - unsigned idx0 = idx; - idx = fix_eq_bits(idx, a->get_arg(i), idx2, max_length, t, equalities, discard_cols); - idx2 = 0; - SASSERT((idx - idx0) <= max_length); - max_length = max_length - (idx - idx0); - } - return idx; - } - - unsigned low, high; - expr *e2; - if (bvu.is_extract(e, low, high, e2)) { - SASSERT(low <= high); - unsigned size = bvu.get_bv_size(e2); - unsigned offset = size - (high+1) + idx2; - SASSERT(idx2 < (high-low+1)); - max_length = std::min(max_length, high - low + 1 - idx2); - return fix_eq_bits(idx, e2, offset, max_length, t, equalities, discard_cols); - } - - if (e->get_kind() == AST_VAR) { - unsigned idx_var = idx2 + t.column_idx(to_var(e)->get_idx()); - SASSERT(idx2 < t.column_num_bits(to_var(e)->get_idx())); - max_length = std::min(max_length, t.column_num_bits(to_var(e)->get_idx()) - idx2); - fix_eq_bits(idx, 0, idx_var, max_length, equalities, discard_cols); - return idx + max_length; - } - - NOT_IMPLEMENTED_YET(); - return 0; - } -#endif - } diff --git a/src/muz/ddnf/udoc_relation.h b/src/muz/ddnf/udoc_relation.h index 6c10a62bb..197e16fb9 100644 --- a/src/muz/ddnf/udoc_relation.h +++ b/src/muz/ddnf/udoc_relation.h @@ -66,6 +66,7 @@ namespace datalog { void compile_guard(expr* g, udoc& d) const; void apply_guard(expr* g, udoc& result, bit_vector const& discard_cols); void apply_guard(expr* g, udoc& result, subset_ints& equalities, bit_vector const& discard_cols); + void apply_eq(expr* g, udoc& result, var* v, unsigned hi, unsigned lo, expr* c); }; class udoc_plugin : public relation_plugin { diff --git a/src/tactic/arith/card2bv_tactic.cpp b/src/tactic/arith/card2bv_tactic.cpp index 3d112e36f..5f9f28898 100644 --- a/src/tactic/arith/card2bv_tactic.cpp +++ b/src/tactic/arith/card2bv_tactic.cpp @@ -23,6 +23,7 @@ Notes: #include"expr_substitution.h" #include"card2bv_tactic.h" #include"pb_rewriter.h" +#include"ast_util.h" namespace pb { unsigned card2bv_rewriter::get_num_bits(func_decl* f) { @@ -85,7 +86,7 @@ namespace pb { } void card2bv_rewriter::mk_clause(unsigned n, literal const* lits) { - m_lemmas.push_back(m.mk_or_reduced(n, lits)); + m_lemmas.push_back(mk_or(m, n, lits)); } From 99ff13b651e428b111cf29d2bee9bdddccdcc915 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 17 Sep 2014 11:39:25 -0700 Subject: [PATCH 538/925] opt + udoc Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/udoc_relation.cpp | 82 ++++++++++++++++++++++++++-------- src/muz/ddnf/udoc_relation.h | 8 ++-- src/opt/maxres.cpp | 50 ++++++++++++--------- 3 files changed, 96 insertions(+), 44 deletions(-) diff --git a/src/muz/ddnf/udoc_relation.cpp b/src/muz/ddnf/udoc_relation.cpp index 393b85d54..0490bd034 100644 --- a/src/muz/ddnf/udoc_relation.cpp +++ b/src/muz/ddnf/udoc_relation.cpp @@ -333,12 +333,10 @@ namespace datalog { doc_manager& dm = r.get_dm(); unsigned num_bits = dm.num_tbits(); m_size = r.column_num_bits(identical_cols[0]); - m_empty_bv.resize(r.get_num_bits(), false); - + m_empty_bv.resize(r.get_num_bits(), false); for (unsigned i = 0; i < col_cnt; ++i) { m_cols[i] = r.column_idx(identical_cols[i]); - } - + } for (unsigned i = 0, e = m_empty_bv.size(); i < e; ++i) { m_equalities.mk_var(); } @@ -354,11 +352,8 @@ namespace datalog { } }; relation_mutator_fn * udoc_plugin::mk_filter_identical_fn( - const relation_base & t, unsigned col_cnt, - const unsigned * identical_cols) { - if (!check_kind(t)) - return 0; - return alloc(filter_identical_fn, t, col_cnt, identical_cols); + const relation_base & t, unsigned col_cnt, const unsigned * identical_cols) { + return check_kind(t)?alloc(filter_identical_fn, t, col_cnt, identical_cols):0; } class udoc_plugin::filter_equal_fn : public relation_mutator_fn { doc_manager& dm; @@ -434,7 +429,7 @@ namespace datalog { void udoc_relation::compile_guard(expr* g, udoc& d) const { NOT_IMPLEMENTED_YET(); } - void udoc_relation::apply_guard(expr* g, udoc& result, bit_vector const& discard_cols) { + void udoc_relation::apply_guard(expr* g, udoc& result, bit_vector const& discard_cols) const { // datastructure to store equalities with columns that will be projected out union_find_default_ctx union_ctx; subset_ints equalities(union_ctx); @@ -443,9 +438,13 @@ namespace datalog { } apply_guard(g, result, equalities, discard_cols); } + void udoc_relation::apply_eq(expr* g, udoc& result, var* v, unsigned hi, unsigned lo, expr* c) const { + NOT_IMPLEMENTED_YET(); + } + void udoc_relation::apply_guard( expr* g, udoc& result, - subset_ints& equalities, bit_vector const& discard_cols) { + subset_ints& equalities, bit_vector const& discard_cols) const { ast_manager& m = get_plugin().get_ast_manager(); bv_util& bv = get_plugin().bv; expr* e1, *e2; @@ -489,6 +488,7 @@ namespace datalog { else if (m.is_eq(g, e1, e2) && bv.is_bv(e1)) { unsigned hi, lo; expr* e3; + NOT_IMPLEMENTED_YET(); // TBD: equalities and discard_cols? if (is_var(e1) && is_ground(e2)) { apply_eq(g, result, to_var(e1), bv.get_bv_size(e1)-1, 0, e2); @@ -506,6 +506,7 @@ namespace datalog { var* v1 = to_var(e1); var* v2 = to_var(e2); // TBD + NOT_IMPLEMENTED_YET(); } else { goto failure_case; @@ -551,14 +552,8 @@ namespace datalog { TRACE("dl", tout << "final size: " << t.get_size_estimate_rows() << '\n';); } }; - - - relation_mutator_fn * udoc_plugin::mk_filter_interpreted_fn(const relation_base & t, app * condition) { - if (!check_kind(t)) - return 0; - TRACE("dl", tout << mk_pp(condition, get_ast_manager()) << '\n';); - return alloc(filter_interpreted_fn, get(t), get_ast_manager(), condition); + return check_kind(t)?alloc(filter_interpreted_fn, get(t), get_ast_manager(), condition):0; } class udoc_plugin::negation_filter_fn : public relation_intersection_filter_fn { @@ -588,4 +583,55 @@ namespace datalog { return alloc(negation_filter_fn, get(t), get(neg), joined_col_cnt, t_cols, negated_cols); } + class udoc_plugin::filter_proj_fn : public convenient_relation_project_fn { + doc_manager& dm; + expr_ref m_condition; + udoc m_udoc; + bit_vector m_col_list; // map: col idx -> bool (whether the column is to be removed) + public: + filter_proj_fn(const udoc_relation & t, ast_manager& m, app *condition, + unsigned col_cnt, const unsigned * removed_cols) : + convenient_relation_project_fn(t.get_signature(), col_cnt, removed_cols), + dm(t.get_dm()), + m_condition(m) { + t.expand_column_vector(m_removed_cols); + m_col_list.resize(t.get_num_bits(), false); + for (unsigned i = 0; i < m_removed_cols.size(); ++i) { + m_col_list.set(m_removed_cols[i]); + } + m_removed_cols.push_back(UINT_MAX); + expr_ref guard(m), rest(m); + t.extract_guard(condition, guard, m_condition); + t.compile_guard(guard, m_udoc); + if (m.is_true(m_condition)) { + m_condition = 0; + } + } + + virtual ~filter_proj_fn() { + m_udoc.reset(dm); + } + virtual relation_base* operator()(const relation_base & tb) { + udoc_relation const & t = get(tb); + udoc const& u1 = t.get_udoc(); + udoc u2; + // copy u1 -> u2; + NOT_IMPLEMENTED_YET(); + u2.intersect(dm, m_udoc); + if (m_condition && !u2.empty()) { + t.apply_guard(m_condition, u2, m_col_list); + } + udoc_relation* res = get(t.get_plugin().mk_empty(get_result_signature())); + NOT_IMPLEMENTED_YET(); + // u2.project(m_removed_cols, res->get_dm(), res->get_udoc()); + return res; + } + }; + relation_transformer_fn * udoc_plugin::mk_filter_interpreted_and_project_fn( + const relation_base & t, app * condition, + unsigned removed_col_cnt, const unsigned * removed_cols) { + return check_kind(t)?alloc(filter_proj_fn, get(t), get_ast_manager(), condition, removed_col_cnt, removed_cols):0; + } + + } diff --git a/src/muz/ddnf/udoc_relation.h b/src/muz/ddnf/udoc_relation.h index 197e16fb9..eaa653c83 100644 --- a/src/muz/ddnf/udoc_relation.h +++ b/src/muz/ddnf/udoc_relation.h @@ -64,9 +64,9 @@ namespace datalog { bool is_guard(expr* g) const; bool is_guard(unsigned n, expr* const *g) const; void compile_guard(expr* g, udoc& d) const; - void apply_guard(expr* g, udoc& result, bit_vector const& discard_cols); - void apply_guard(expr* g, udoc& result, subset_ints& equalities, bit_vector const& discard_cols); - void apply_eq(expr* g, udoc& result, var* v, unsigned hi, unsigned lo, expr* c); + void apply_guard(expr* g, udoc& result, bit_vector const& discard_cols) const; + void apply_guard(expr* g, udoc& result, subset_ints& equalities, bit_vector const& discard_cols) const; + void apply_eq(expr* g, udoc& result, var* v, unsigned hi, unsigned lo, expr* c) const; }; class udoc_plugin : public relation_plugin { @@ -120,8 +120,6 @@ namespace datalog { virtual relation_transformer_fn * mk_filter_interpreted_and_project_fn( const relation_base & t, app * condition, unsigned removed_col_cnt, const unsigned * removed_cols); - - // project join select }; }; diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index c2de70ad6..e032cb80e 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -163,7 +163,7 @@ public: tout << "\n"; display(tout); ); - lbool is_sat = s().check_sat(m_asms.size(), m_asms.c_ptr()); + lbool is_sat = check_sat_hill_climb(m_asms); if (m_cancel) { return l_undef; } @@ -276,7 +276,7 @@ public: tout << "\n"; display(tout); ); - lbool is_sat = s().check_sat(m_asms.size(), m_asms.c_ptr()); + lbool is_sat = check_sat_hill_climb(m_asms); if (m_cancel) { return l_undef; } @@ -339,6 +339,32 @@ public: return l_true; } + lbool check_sat_hill_climb(expr_ref_vector& asms1) { + expr_ref_vector asms(asms1); + lbool is_sat = l_true; + if (m_hill_climb) { + /** + Give preference to cores that have large minmal values. + */ + sort_assumptions(asms); + unsigned index = 0; + unsigned last_index = 0; + while (index < asms.size() && is_sat == l_true) { + while (asms.size() > 20*(index - last_index) && index < asms.size()) { + index = next_index(asms, index); + //std::cout << "weight: " << get_weight(asms[index-1].get()) << "\n"; + //break; + } + last_index = index; + is_sat = s().check_sat(index, asms.c_ptr()); + } + } + else { + is_sat = s().check_sat(asms.size(), asms.c_ptr()); + } + return is_sat; + } + void found_optimum() { s().get_model(m_model); DEBUG_CODE( @@ -392,25 +418,7 @@ public: TRACE("opt", display_vec(tout << "core: ", core.size(), core.c_ptr()); display_vec(tout << "assumptions: ", asms.size(), asms.c_ptr());); - - if (m_hill_climb) { - /** - Give preference to cores that have large minmal values. - */ - sort_assumptions(asms); - unsigned index = 0; - unsigned last_index = 0; - while (index < asms.size() && is_sat != l_false) { - while (asms.size() > 10*(index - last_index) && index < asms.size()) { - index = next_index(asms, index); - } - last_index = index; - is_sat = s().check_sat(index, asms.c_ptr()); - } - } - else { - is_sat = s().check_sat(asms.size(), asms.c_ptr()); - } + is_sat = check_sat_hill_climb(asms); } TRACE("opt", tout << "num cores: " << cores.size() << "\n"; From c6e0a62cb950f937866cb59f1863df059ea3e24a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 17 Sep 2014 15:42:35 -0700 Subject: [PATCH 539/925] udoc Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/doc.h | 11 +- src/muz/ddnf/tbv.h | 2 +- src/muz/ddnf/udoc_relation.cpp | 221 ++++++++++++++++++++++++++------- src/muz/ddnf/udoc_relation.h | 14 ++- 4 files changed, 200 insertions(+), 48 deletions(-) diff --git a/src/muz/ddnf/doc.h b/src/muz/ddnf/doc.h index 42db3c545..f62f3e5ca 100644 --- a/src/muz/ddnf/doc.h +++ b/src/muz/ddnf/doc.h @@ -88,6 +88,14 @@ public: } return false; } + std::ostream& display(M& m, std::ostream& out) const { + for (unsigned i = 0; i < size(); ++i) { + m.display(out, *m_elems[i]); + if (i + 1 < size()) out << ", "; + } + return out << "\n"; + } + void push_back(T* t) { m_elems.push_back(t); } @@ -174,7 +182,7 @@ public: std::swap(m_elems, result.m_elems); result.reset(m); } - void complement(M& m, union_bvec& result) { + void complement(M& m, union_bvec& result) const { union_bvec negated; result.reset(m); result.push_back(m.allocateX()); @@ -328,6 +336,7 @@ public: d = d2; } doc& operator*() { return *d; } + doc* operator->() { return d; } }; #endif /* _DOC_H_ */ diff --git a/src/muz/ddnf/tbv.h b/src/muz/ddnf/tbv.h index c8b9b5c96..e8eb7b589 100644 --- a/src/muz/ddnf/tbv.h +++ b/src/muz/ddnf/tbv.h @@ -91,7 +91,7 @@ public: void set(rational const& r, unsigned hi, unsigned lo); void set(tbv const& other, unsigned hi, unsigned lo); - unsigned operator[](unsigned idx) { return get(idx); } + unsigned operator[](unsigned idx) const { return get(idx); } void set(unsigned index, unsigned value) { SASSERT(value <= 3); fixed_bit_vector::set(2*index, (value & 2) != 0); diff --git a/src/muz/ddnf/udoc_relation.cpp b/src/muz/ddnf/udoc_relation.cpp index 0490bd034..c257e5317 100644 --- a/src/muz/ddnf/udoc_relation.cpp +++ b/src/muz/ddnf/udoc_relation.cpp @@ -7,24 +7,17 @@ namespace datalog { udoc_relation::udoc_relation(udoc_plugin& p, relation_signature const& sig): relation_base(p, sig), - dm(p.dm(num_signature_bits(p.bv, sig))) { + dm(p.dm(p.num_signature_bits(sig))) { unsigned column = 0; for (unsigned i = 0; i < sig.size(); ++i) { m_column_info.push_back(column); - column += p.bv.get_bv_size(sig[i]); + column += p.num_sort_bits(sig[i]); } m_column_info.push_back(column); } udoc_relation::~udoc_relation() { reset(); } - unsigned udoc_relation::num_signature_bits(bv_util& bv, relation_signature const& sig) { - unsigned result = 0; - for (unsigned i = 0; i < sig.size(); ++i) { - result += bv.get_bv_size(sig[i]); - } - return result; - } void udoc_relation::reset() { m_elems.reset(dm); } @@ -52,7 +45,7 @@ namespace datalog { for (unsigned i = 0; i < f.size(); ++i) { unsigned bv_size; rational val; - VERIFY(get_plugin().bv.is_numeral(f[i], val, bv_size)); + VERIFY(get_plugin().is_numeral(f[i], val, bv_size)); SASSERT(bv_size == column_num_bits(i)); unsigned lo = column_idx(i); unsigned hi = column_idx(i + 1); @@ -69,22 +62,91 @@ namespace datalog { return m_elems.contains(dm, *d); } udoc_relation * udoc_relation::clone() const { - NOT_IMPLEMENTED_YET(); - return 0; + udoc_relation* result = udoc_plugin::get(get_plugin().mk_empty(get_signature())); + for (unsigned i = 0; i < m_elems.size(); ++i) { + result->m_elems.push_back(dm.allocate(m_elems[i])); + } + return result; } udoc_relation * udoc_relation::complement(func_decl* f) const { - NOT_IMPLEMENTED_YET(); - return 0; + udoc_relation* result = udoc_plugin::get(get_plugin().mk_empty(get_signature())); + m_elems.complement(dm, result->m_elems); + return result; } void udoc_relation::to_formula(expr_ref& fml) const { - NOT_IMPLEMENTED_YET(); + ast_manager& m = fml.get_manager(); + expr_ref_vector disj(m); + for (unsigned i = 0; i < m_elems.size(); ++i) { + disj.push_back(to_formula(m_elems[i])); + } + fml = mk_or(m, disj.size(), disj.c_ptr()); } + expr_ref udoc_relation::to_formula(doc const& d) const { + ast_manager& m = get_plugin().get_ast_manager(); + expr_ref result(m); + expr_ref_vector conjs(m); + conjs.push_back(to_formula(d.pos())); + for (unsigned i = 0; i < d.neg().size(); ++i) { + conjs.push_back(m.mk_not(to_formula(d.neg()[i]))); + } + result = mk_and(m, conjs.size(), conjs.c_ptr()); + return result; + } + expr_ref udoc_relation::to_formula(tbv const& t) const { + udoc_plugin& p = get_plugin(); + ast_manager& m = p.get_ast_manager(); + expr_ref result(m); + expr_ref_vector conjs(m); + for (unsigned i = 0; i < get_num_cols(); ++i) { + var_ref v(m); + v = m.mk_var(i, get_signature()[i]); + unsigned lo = column_idx(i); + unsigned hi = column_idx(i+1); + rational r(0); + unsigned lo0 = lo; + bool is_x = true; + for (unsigned j = lo; j < hi; ++j) { + switch(t[j]) { + case BIT_0: + if (is_x) is_x = false, lo0 = j, r.reset(); + break; + case BIT_1: + if (is_x) is_x = false, lo0 = j, r.reset(); + r += rational::power_of_two(j - lo0); + break; + case BIT_x: + if (!is_x) { + conjs.push_back(m.mk_eq(p.bv.mk_extract(j-1,lo0,v), + p.bv.mk_numeral(r,j-lo0))); + } + is_x = true; + break; + default: + UNREACHABLE(); + } + } + if (!is_x) { + expr_ref num(m); + if (lo0 == lo) { + num = p.mk_numeral(r, get_signature()[i]); + conjs.push_back(m.mk_eq(v, num)); + } + else { + num = p.bv.mk_numeral(r, hi-lo0); + conjs.push_back(m.mk_eq(p.bv.mk_extract(hi-1,lo0,v), num)); + } + } + } + result = mk_and(m, conjs.size(), conjs.c_ptr()); + return result; + } + udoc_plugin& udoc_relation::get_plugin() const { return static_cast(relation_base::get_plugin()); } void udoc_relation::display(std::ostream& out) const { - NOT_IMPLEMENTED_YET(); + m_elems.display(dm, out); } // ------------- @@ -92,7 +154,8 @@ namespace datalog { udoc_plugin::udoc_plugin(relation_manager& rm): relation_plugin(udoc_plugin::get_name(), rm), m(rm.get_context().get_manager()), - bv(m) { + bv(m), + dl(m) { } udoc_plugin::~udoc_plugin() { u_map::iterator it = m_dms.begin(), end = m_dms.end(); @@ -111,7 +174,7 @@ namespace datalog { } doc_manager& udoc_plugin::dm(relation_signature const& sig) { - return dm(udoc_relation::num_signature_bits(bv, sig)); + return dm(num_signature_bits(sig)); } doc_manager& udoc_plugin::dm(unsigned n) { @@ -122,9 +185,53 @@ namespace datalog { } return *r; } + expr* udoc_plugin::mk_numeral(rational const& r, sort* s) { + if (bv.is_bv_sort(s)) { + return bv.mk_numeral(r, s); + } + SASSERT(dl.is_finite_sort(s)); + return dl.mk_numeral(r.get_uint64(), s); + } + bool udoc_plugin::is_numeral(expr* e, rational& r, unsigned& num_bits) { + if (bv.is_numeral(e, r, num_bits)) return true; + uint64 n, sz; + ast_manager& m = get_ast_manager(); + if (dl.is_numeral(e, n) && dl.try_get_size(m.get_sort(e), sz)) { + num_bits = 0; + while (sz > 0) ++num_bits, sz = sz/2; + r = rational(n, rational::ui64()); + return true; + } + return false; + } + unsigned udoc_plugin::num_sort_bits(sort* s) const { + unsigned num_bits = 0; + if (bv.is_bv_sort(s)) + return bv.get_bv_size(s); + uint64 sz; + if (dl.try_get_size(s, sz)) { + while (sz > 0) ++num_bits, sz /= 2; + return num_bits; + } + UNREACHABLE(); + return 0; + } + unsigned udoc_plugin::num_signature_bits(relation_signature const& sig) { + unsigned result = 0; + for (unsigned i = 0; i < sig.size(); ++i) { + result += num_sort_bits(sig[i]); + } + return result; + } + + bool udoc_plugin::is_finite_sort(sort* s) const { + return bv.is_bv_sort(s) || dl.is_finite_sort(s); + } + + bool udoc_plugin::can_handle_signature(const relation_signature & sig) { for (unsigned i = 0; i < sig.size(); ++i) { - if (!bv.is_bv_sort(sig[i])) + if (!is_finite_sort(sig[i])) return false; } return true; @@ -250,10 +357,24 @@ namespace datalog { class udoc_plugin::rename_fn : public convenient_relation_rename_fn { unsigned_vector m_permutation; public: - rename_fn(const relation_signature & orig_sig, unsigned cycle_len, const unsigned * cycle) - : convenient_relation_rename_fn(orig_sig, cycle_len, cycle) { - NOT_IMPLEMENTED_YET(); - // compute permuation. + rename_fn(udoc_relation const& t, unsigned cycle_len, const unsigned * cycle) + : convenient_relation_rename_fn(t.get_signature(), cycle_len, cycle) { + udoc_plugin& p = t.get_plugin(); + for (unsigned i = 0; i < t.get_num_bits(); ++i) { + m_permutation.push_back(i); + } + unsigned len = t.column_num_bits(cycle[0]); + for (unsigned i = 0; i < cycle_len; ++i) { + unsigned j = (i + 1)%cycle_len; + unsigned col1 = cycle[i]; + unsigned col2 = cycle[j]; + unsigned lo1 = t.column_idx(col1); + unsigned lo2 = t.column_idx(col2); + for (unsigned k = 0; k < len; ++k) { + m_permutation[k + lo1] = k + lo2; + } + SASSERT(column_num_bits(col1) == column_num_bits(col2)); + } } virtual relation_base * operator()(const relation_base & _r) { @@ -274,7 +395,7 @@ namespace datalog { const relation_base & r, unsigned cycle_len, const unsigned * permutation_cycle) { if (check_kind(r)) { - return alloc(rename_fn, r.get_signature(), cycle_len, permutation_cycle); + return alloc(rename_fn, get(r), cycle_len, permutation_cycle); } else { return 0; @@ -363,7 +484,7 @@ namespace datalog { dm(p.dm(t.get_signature())) { rational r; unsigned num_bits; - VERIFY(p.bv.is_numeral(val, r, num_bits)); + VERIFY(p.is_numeral(val, r, num_bits)); m_filter = dm.allocateX(); unsigned lo = t.column_idx(col); unsigned hi = t.column_idx(col+1); @@ -426,8 +547,10 @@ namespace datalog { guard = mk_and(m, guards.size(), guards.c_ptr()); rest = mk_and(m, rests.size(), rests.c_ptr()); } - void udoc_relation::compile_guard(expr* g, udoc& d) const { - NOT_IMPLEMENTED_YET(); + void udoc_relation::compile_guard(expr* g, udoc& d, bit_vector const& discard_cols) const { + d.reset(dm); + d.push_back(dm.allocateX()); + apply_guard(g, d, discard_cols); } void udoc_relation::apply_guard(expr* g, udoc& result, bit_vector const& discard_cols) const { // datastructure to store equalities with columns that will be projected out @@ -438,8 +561,22 @@ namespace datalog { } apply_guard(g, result, equalities, discard_cols); } - void udoc_relation::apply_eq(expr* g, udoc& result, var* v, unsigned hi, unsigned lo, expr* c) const { - NOT_IMPLEMENTED_YET(); + bool udoc_relation::apply_eq(expr* g, udoc& result, var* v, unsigned hi, unsigned lo, expr* c) const { + udoc_plugin& p = get_plugin(); + unsigned num_bits; + rational r; + unsigned idx = v->get_idx(); + unsigned col = column_idx(idx); + lo += col; + hi += col; + if (p.is_numeral(c, r, num_bits)) { + doc_ref d(dm, dm.allocateX()); + d->pos().set(r, hi, lo); + result.intersect(dm, *d); + return true; + } + // other cases? + return false; } void udoc_relation::apply_guard( @@ -488,25 +625,23 @@ namespace datalog { else if (m.is_eq(g, e1, e2) && bv.is_bv(e1)) { unsigned hi, lo; expr* e3; - NOT_IMPLEMENTED_YET(); - // TBD: equalities and discard_cols? - if (is_var(e1) && is_ground(e2)) { - apply_eq(g, result, to_var(e1), bv.get_bv_size(e1)-1, 0, e2); + if (is_var(e1) && is_ground(e2) && + apply_eq(g, result, to_var(e1), bv.get_bv_size(e1)-1, 0, e2)) { } - else if (is_var(e2) && is_ground(e1)) { - apply_eq(g, result, to_var(e2), bv.get_bv_size(e2)-1, 0, e1); + else if (is_var(e2) && is_ground(e1) && + apply_eq(g, result, to_var(e2), bv.get_bv_size(e2)-1, 0, e1)) { } - else if (bv.is_extract(e1, lo, hi, e3) && is_var(e3) && is_ground(e2)) { - apply_eq(g, result, to_var(e3), hi, lo, e2); + else if (bv.is_extract(e1, lo, hi, e3) && is_var(e3) && is_ground(e2) && + apply_eq(g, result, to_var(e3), hi, lo, e2)) { } - else if (bv.is_extract(e2, lo, hi, e3) && is_var(e3) && is_ground(e1)) { - apply_eq(g, result, to_var(e3), hi, lo, e1); + else if (bv.is_extract(e2, lo, hi, e3) && is_var(e3) && is_ground(e1) && + apply_eq(g, result, to_var(e3), hi, lo, e1)) { } else if (is_var(e1) && is_var(e2)) { + NOT_IMPLEMENTED_YET(); + // TBD: equalities and discard_cols? var* v1 = to_var(e1); var* v2 = to_var(e2); - // TBD - NOT_IMPLEMENTED_YET(); } else { goto failure_case; @@ -532,7 +667,7 @@ namespace datalog { m_empty_bv.resize(t.get_num_bits(), false); expr_ref guard(m), rest(m); t.extract_guard(condition, guard, m_condition); - t.compile_guard(guard, m_udoc); + t.compile_guard(guard, m_udoc, m_empty_bv); if (m.is_true(m_condition)) { m_condition = 0; } @@ -602,7 +737,7 @@ namespace datalog { m_removed_cols.push_back(UINT_MAX); expr_ref guard(m), rest(m); t.extract_guard(condition, guard, m_condition); - t.compile_guard(guard, m_udoc); + t.compile_guard(guard, m_udoc, m_col_list); if (m.is_true(m_condition)) { m_condition = 0; } diff --git a/src/muz/ddnf/udoc_relation.h b/src/muz/ddnf/udoc_relation.h index eaa653c83..155e650e5 100644 --- a/src/muz/ddnf/udoc_relation.h +++ b/src/muz/ddnf/udoc_relation.h @@ -34,8 +34,9 @@ namespace datalog { doc_manager& dm; udoc m_elems; unsigned_vector m_column_info; - static unsigned num_signature_bits(bv_util& bv, relation_signature const& sig); doc* fact2doc(relation_fact const& f) const; + expr_ref to_formula(tbv const& t) const; + expr_ref to_formula(doc const& d) const; public: udoc_relation(udoc_plugin& p, relation_signature const& s); virtual ~udoc_relation(); @@ -63,10 +64,10 @@ namespace datalog { void extract_guard(expr* condition, expr_ref& guard, expr_ref& rest) const; bool is_guard(expr* g) const; bool is_guard(unsigned n, expr* const *g) const; - void compile_guard(expr* g, udoc& d) const; + void compile_guard(expr* g, udoc& result, bit_vector const& discard_cols) const; void apply_guard(expr* g, udoc& result, bit_vector const& discard_cols) const; void apply_guard(expr* g, udoc& result, subset_ints& equalities, bit_vector const& discard_cols) const; - void apply_eq(expr* g, udoc& result, var* v, unsigned hi, unsigned lo, expr* c) const; + bool apply_eq(expr* g, udoc& result, var* v, unsigned hi, unsigned lo, expr* c) const; }; class udoc_plugin : public relation_plugin { @@ -84,6 +85,7 @@ namespace datalog { class negation_filter_fn; ast_manager& m; bv_util bv; + dl_decl_util dl; u_map m_dms; doc_manager& dm(unsigned sz); doc_manager& dm(relation_signature const& sig); @@ -91,6 +93,12 @@ namespace datalog { static udoc_relation* get(relation_base* r); static udoc_relation const & get(relation_base const& r); void mk_union(doc_manager& dm, udoc& dst, udoc const& src, udoc* delta); + bool is_numeral(expr* e, rational& r, unsigned& num_bits); + unsigned num_sort_bits(expr* e) const { return num_sort_bits(get_ast_manager().get_sort(e)); } + unsigned num_sort_bits(sort* s) const; + bool is_finite_sort(sort* s) const; + unsigned num_signature_bits(relation_signature const& sig); + expr* mk_numeral(rational const& r, sort* s); public: udoc_plugin(relation_manager& rm); ~udoc_plugin(); From 4c3605421c27f08a6c1313d8c11ef7d266eb6518 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 17 Sep 2014 16:48:41 -0700 Subject: [PATCH 540/925] doc snapshot Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/doc.h | 6 +-- src/muz/ddnf/udoc_relation.cpp | 79 ++++++++++++++++++++++++++-------- src/muz/ddnf/udoc_relation.h | 2 +- 3 files changed, 65 insertions(+), 22 deletions(-) diff --git a/src/muz/ddnf/doc.h b/src/muz/ddnf/doc.h index f62f3e5ca..7196afc45 100644 --- a/src/muz/ddnf/doc.h +++ b/src/muz/ddnf/doc.h @@ -80,7 +80,7 @@ class union_bvec { public: unsigned size() const { return m_elems.size(); } T& operator[](unsigned idx) const { return *m_elems[idx]; } - bool empty() const { return m_elems.empty(); } + bool is_empty() const { return m_elems.empty(); } bool is_full(M& m) const { return size() == 1 && m.is_full(*m_elems[0]); } bool contains(M& m, T& t) const { for (unsigned i = 0; i < m_elems.size(); ++i) { @@ -167,7 +167,7 @@ public: } void subtract(M& m, union_bvec const& other) { unsigned sz = other.size(); - for (unsigned i = 0; !empty() && i < sz; ++i) { + for (unsigned i = 0; !is_empty() && i < sz; ++i) { subtract(m, other[i]); } // TBD compress? @@ -187,7 +187,7 @@ public: result.reset(m); result.push_back(m.allocateX()); unsigned sz = size(); - for (unsigned i = 0; !empty() && i < sz; ++i) { + for (unsigned i = 0; !is_empty() && i < sz; ++i) { m.complement(*m_elems[i], negated.m_elems); result.intersect(m, negated); negated.reset(m); diff --git a/src/muz/ddnf/udoc_relation.cpp b/src/muz/ddnf/udoc_relation.cpp index c257e5317..1425535f1 100644 --- a/src/muz/ddnf/udoc_relation.cpp +++ b/src/muz/ddnf/udoc_relation.cpp @@ -373,7 +373,7 @@ namespace datalog { for (unsigned k = 0; k < len; ++k) { m_permutation[k + lo1] = k + lo2; } - SASSERT(column_num_bits(col1) == column_num_bits(col2)); + SASSERT(t.column_num_bits(col1) == t.column_num_bits(col2)); } } @@ -513,15 +513,19 @@ namespace datalog { return true; } bool udoc_relation::is_guard(expr* g) const { - ast_manager& m = get_plugin().get_ast_manager(); - expr* e1, *e2; + udoc_plugin& p = get_plugin(); + ast_manager& m = p.get_ast_manager(); + bv_util& bv = p.bv; + expr* e1, *e2, *e3; + unsigned hi, lo; if (m.is_and(g) || m.is_or(g) || m.is_not(g) || m.is_true(g) || m.is_false(g)) { return is_guard(to_app(g)->get_num_args(), to_app(g)->get_args()); } - if (m.is_eq(g, e1, e2)) { - if (is_var(e1) && is_var(e2)) return false; - NOT_IMPLEMENTED_YET(); - // TBD + if (m.is_eq(g, e1, e2) && bv.is_bv(e1)) { + if (is_var(e1) && is_ground(e2)) return true; + if (is_var(e2) && is_ground(e1)) return true; + if (bv.is_extract(e1, lo, hi, e3) && is_var(e3) && is_ground(e2)) return true; + if (bv.is_extract(e2, lo, hi, e3) && is_var(e3) && is_ground(e1)) return true; } if (is_var(g)) { return true; @@ -580,19 +584,22 @@ namespace datalog { } void udoc_relation::apply_guard( - expr* g, udoc& result, - subset_ints& equalities, bit_vector const& discard_cols) const { + expr* g, udoc& result, subset_ints& equalities, bit_vector const& discard_cols) const { ast_manager& m = get_plugin().get_ast_manager(); bv_util& bv = get_plugin().bv; expr* e1, *e2; - if (result.empty()) { + if (result.is_empty()) { } else if (m.is_and(g)) { - for (unsigned i = 0; !result.empty() && i < to_app(g)->get_num_args(); ++i) { + for (unsigned i = 0; !result.is_empty() && i < to_app(g)->get_num_args(); ++i) { apply_guard(to_app(g)->get_arg(i), result, equalities, discard_cols); } } else if (m.is_not(g, e1)) { + // REVIEW: (not (= x y)) should not cause + // the equivalence class to collapse. + // It seems the current organization with fix_eq_bits + // will merge the equivalence class as a side-effect. udoc sub; sub.push_back(dm.allocateX()); apply_guard(e1, sub, equalities, discard_cols); @@ -601,7 +608,7 @@ namespace datalog { else if (m.is_or(g)) { udoc sub; sub.push_back(dm.allocateX()); - for (unsigned i = 0; !sub.empty() && i < to_app(g)->get_num_args(); ++i) { + for (unsigned i = 0; !sub.is_empty() && i < to_app(g)->get_num_args(); ++i) { expr_ref arg(m); arg = mk_not(m, to_app(g)->get_arg(i)); apply_guard(arg, result, equalities, discard_cols); @@ -638,10 +645,12 @@ namespace datalog { apply_eq(g, result, to_var(e3), hi, lo, e1)) { } else if (is_var(e1) && is_var(e2)) { - NOT_IMPLEMENTED_YET(); - // TBD: equalities and discard_cols? var* v1 = to_var(e1); var* v2 = to_var(e2); + unsigned idx1 = column_idx(v1->get_idx()); + unsigned idx2 = column_idx(v2->get_idx()); + unsigned length = column_num_bits(v1->get_idx()); + result.fix_eq_bits(idx1, 0, idx2, length, equalities, discard_cols); } else { goto failure_case; @@ -681,7 +690,7 @@ namespace datalog { udoc_relation & t = get(tb); udoc& u = t.get_udoc(); u.intersect(dm, m_udoc); - if (m_condition && !u.empty()) { + if (m_condition && !u.is_empty()) { t.apply_guard(m_condition, u, m_empty_bv); } TRACE("dl", tout << "final size: " << t.get_size_estimate_rows() << '\n';); @@ -703,9 +712,43 @@ namespace datalog { virtual void operator()(relation_base& tb, const relation_base& negb) { udoc_relation& t = get(tb); - udoc_relation const& neg = get(negb); + udoc_relation const& negt = get(negb); + udoc & dst = t.get_udoc(); + udoc const & neg = negt.get_udoc(); + doc_manager& dm = t.get_dm(); + udoc result; + for (unsigned i = 0; i < dst.size(); ++i) { + bool done_i = false; + for (unsigned j = 0; !done_i && j < neg.size(); ++j) { + bool done_j = false; + for (unsigned c = 0; !done_i && !done_j && c < m_t_cols.size(); ++c) { + unsigned t_col = m_t_cols[c]; + unsigned n_col = m_neg_cols[c]; + SASSERT(t.column_num_bits(t_col) == negt.column_num_bits(n_col)); + NOT_IMPLEMENTED_YET(); + //if (!neg[j].contains(negt.column_idx(n_col), dst[i], t.column_idx(t_col), t.column_num_bits(t_col))) { + // done_j = true; + //} + } + if (done_j) { + result.push_back(&dst[i]); + } + else { + dm.deallocate(&dst[i]); + done_i = true; + } + } + } + std::swap(dst, result); + if (dst.is_empty()) { + return; + } + + // slow case + udoc renamed_neg; NOT_IMPLEMENTED_YET(); - // t.m_bitsets.filter_negate(t, neg.m_bitsets, neg, m_t_cols, m_neg_cols); + // neg.rename(m_neg_cols, negt, m_t_cols, t, renamed_neg); + dst.subtract(t.get_dm(), renamed_neg); } }; @@ -753,7 +796,7 @@ namespace datalog { // copy u1 -> u2; NOT_IMPLEMENTED_YET(); u2.intersect(dm, m_udoc); - if (m_condition && !u2.empty()) { + if (m_condition && !u2.is_empty()) { t.apply_guard(m_condition, u2, m_col_list); } udoc_relation* res = get(t.get_plugin().mk_empty(get_result_signature())); diff --git a/src/muz/ddnf/udoc_relation.h b/src/muz/ddnf/udoc_relation.h index 155e650e5..5205a9547 100644 --- a/src/muz/ddnf/udoc_relation.h +++ b/src/muz/ddnf/udoc_relation.h @@ -47,7 +47,7 @@ namespace datalog { virtual udoc_relation * complement(func_decl*) const; virtual void to_formula(expr_ref& fml) const; udoc_plugin& get_plugin() const; - virtual bool empty() const { return m_elems.empty(); } + virtual bool empty() const { return m_elems.is_empty(); } virtual void display(std::ostream& out) const; virtual bool is_precise() const { return true; } virtual unsigned get_size_estimate_rows() const { return m_elems.size(); } From 4eadaabe640566af1fdf6c6d2901c83119b450ae Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 18 Sep 2014 03:53:14 -0700 Subject: [PATCH 541/925] doc Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/doc.cpp | 174 +++++++++++++++++++++++++++++++++ src/muz/ddnf/doc.h | 17 +++- src/muz/ddnf/tbv.cpp | 17 +++- src/muz/ddnf/tbv.h | 20 ++-- src/muz/ddnf/udoc_relation.cpp | 20 ++-- 5 files changed, 229 insertions(+), 19 deletions(-) diff --git a/src/muz/ddnf/doc.cpp b/src/muz/ddnf/doc.cpp index 2c6b4696e..27192ed26 100644 --- a/src/muz/ddnf/doc.cpp +++ b/src/muz/ddnf/doc.cpp @@ -66,6 +66,180 @@ doc& doc_manager::fillX(doc& src) const { bool doc_manager::set_and(doc& dst, doc const& src) const { return false; } +bool doc_manager::fold_neg(doc& dst) { + start_over: + for (unsigned i = 0; i < dst.neg().size(); ++i) { + unsigned index; + unsigned count = diff_by_012(dst.pos(), dst.neg()[i], index); + if (count != 2) { + if (count == 0) { + return false; + } + else if (count == 3) { + dst.neg().erase(tbvm(), i); + --i; + } + else { // count == 1: + dst.pos().set(index, neg(dst.neg()[i][index])); + dst.neg().erase(tbvm(), i); + goto start_over; + } + } + } + return true; +} + +unsigned doc_manager::diff_by_012(tbv const& pos, tbv const& neg, unsigned& index) { + unsigned n = num_tbits(); + unsigned count = 0; + for (unsigned i = 0; i < n; ++i) { + tbit b1 = pos[i]; + tbit b2 = neg[i]; + SASSERT(b1 != BIT_z && b2 != BIT_z); + if (b1 != b2) { + if (count == 1) return 2; + if (b1 == BIT_x) { + index = i; + count = 1; + } + else if (b2 != BIT_x) { + return 3; + } + } + } + return count; +} +doc* doc_manager::project(unsigned n, bool const* to_delete, doc const& src) { + tbv* p = tbvm().project(n, to_delete, src.pos()); + if (src.neg().is_empty()) { + // build doc from p. + return 0; + } + ptr_vector todo; +#if 0 + // tbv & ~tbv1 & ~tbv2 & .. + // Semantics of ~tbv1 is that it is a clause of literals. + // indices where BIT_1 is set are negative. + // indices where BIT_0 is set are positive. + // The first loop is supposed to project tbv_i directly + // when some safety condition is met. + // The second loop handles the remaining tbv_i that + // don't meet the safety condition. + for (unsigned i = 0; i < src.neg().size(); ++i) { + if (can_project_neg(n, to_delete, src.neg()[i])) { + + } + } +#endif +#if 0 + // REVIEW: what is the spec for this code? + ternary_diff_bitvector TBV(*this); + if (!TBV.fold_neg()) + return false; + + std::set todo; + cpy_bits_t cpy_bits; + ternary_bitvector newneg; + for (union_ternary_bitvector::iterator I = TBV.m_neg.begin(), + E = TBV.m_neg.end(); I != E; ++I) { + // check if subtract TBV should be skiped + for (unsigned i = 0; i < delcols.size()-1; ++i) { + unsigned idx = delcols[i]; + if (I->get(idx) != TBV.m_pos.get(idx)) { // xx \ 1x + if (analyze_copy_bit(TBV.m_pos, *I, delcols, cpy_bits)) + todo.insert(&*I); + goto skip_row; + } + } + + newneg.reset(); + I->project(delcols, new_size, newneg); + result.m_neg.add_fact(newneg); + skip_row: ; + } + + if (!todo.empty()) { + for (std::set::iterator I = todo.begin(), + E = todo.end(); I != E; ++I) { + for (unsigned i = 0; i < delcols.size()-1; ++i) { + unsigned idx = delcols[i]; + if ((*I)->get(idx) != TBV.m_pos.get(idx)) { + cpy_bits_t::iterator II = cpy_bits.find(idx); + if (II == cpy_bits.end()) + goto skip_bv; + + unsigned idx_keep = II->second.first; + unsigned cpy_val = II->second.second; + + if (!((*I)->get(idx) & cpy_val) || (*I)->get(idx_keep) != BIT_x) + goto skip_bv; + + (*I)->set(idx_keep, (*I)->get(idx)); + } + } + + newneg.reset(); + (*I)->project(delcols, new_size, newneg); + result.m_neg.add_fact(newneg); + skip_bv: ; + } + } + + return !result.is_empty(); + + + // idx_del -> + // val -> BIT_* + typedef std::map > cpy_bits_t; + + static bool analyze_copy_bit(const ternary_bitvector& pos, const ternary_bitvector& neg, + const unsigned_vector& delcols, cpy_bits_t& cpy_bits) { + unsigned *del = delcols.c_ptr(); + bool got_del_col = false, got_keep_col = false; + unsigned del_col = 0, keep_col = 0; + + for (unsigned i = 0; i < pos.size(); ++i) { + if (pos.get(i) != neg.get(i)) { + if (*del == i) { + if (got_del_col) + return true; + del_col = i; + got_del_col = true; + } else { + if (got_keep_col) + return true; + keep_col = i; + got_keep_col = true; + } + } + + if (i == *del) + ++del; + } + + if (!got_del_col || !got_keep_col) + return true; + if (neg.get(keep_col) == neg.get(del_col)) + return false; + + + unsigned char val = neg.get(del_col); + cpy_bits_t::iterator I = cpy_bits.find(del_col); + if (I == cpy_bits.end()) + cpy_bits[del_col] = std::make_pair(keep_col, val); + else { + // FIXME: eq classes with size > 1 not supported for now + SASSERT(I->second.first == keep_col); + I->second.second |= val; + } + + return false; + } + +#endif + return 0; +} + void doc_manager::complement(doc const& src, ptr_vector& result) { } void doc_manager::subtract(doc const& A, doc const& B, ptr_vector& result) { diff --git a/src/muz/ddnf/doc.h b/src/muz/ddnf/doc.h index 7196afc45..78cd5c94b 100644 --- a/src/muz/ddnf/doc.h +++ b/src/muz/ddnf/doc.h @@ -34,7 +34,7 @@ class doc_manager { tbv_manager m; public: doc_manager(unsigned n): m(n) {} - tbv_manager& tbv() { return m; } + tbv_manager& tbvm() { return m; } void reset(); doc* allocate(); doc* allocate1(); @@ -53,6 +53,7 @@ public: doc& fillX(doc& src) const; bool is_full(doc const& src) const; bool set_and(doc& dst, doc const& src) const; + bool fold_neg(doc& dst); bool intersect(doc const& A, doc const& B, doc& result) const; void complement(doc const& src, ptr_vector& result); void subtract(doc const& A, doc const& B, ptr_vector& result); @@ -61,6 +62,9 @@ public: bool contains(doc const& a, doc const& b) const; std::ostream& display(std::ostream& out, doc const& b) const; unsigned num_tbits() const { return m.num_tbits(); } + doc* project(unsigned n, bool const* to_delete, doc const& src); +private: + unsigned diff_by_012(tbv const& pos, tbv const& neg, unsigned& index); }; typedef union_find<> subset_ints; @@ -99,6 +103,11 @@ public: void push_back(T* t) { m_elems.push_back(t); } + void erase(M& m, unsigned idx) { + T* t = m_elems[idx]; + m_elems.erase(t); + m.deallocate(t); + } void reset(M& m) { for (unsigned i = 0; i < m_elems.size(); ++i) { m.deallocate(m_elems[i]); @@ -193,6 +202,12 @@ public: negated.reset(m); } } + void copy(M& m, union_bvec const& other) { + reset(m); + for (unsigned i = 0; i < other.size(); ++i) { + push_back(m.allocate(other[i])); + } + } void fix_eq_bits(unsigned idx1, tbv* BV, unsigned idx2, unsigned length, subset_ints& equalities, const bit_vector& discard_cols) { for (unsigned i = 0; i < length; ++i) { diff --git a/src/muz/ddnf/tbv.cpp b/src/muz/ddnf/tbv.cpp index ad6dae69e..b1e5d5344 100644 --- a/src/muz/ddnf/tbv.cpp +++ b/src/muz/ddnf/tbv.cpp @@ -66,10 +66,23 @@ tbv* tbv_manager::allocate(uint64 val, unsigned hi, unsigned lo) { tbv* tbv_manager::allocate(tbv const& bv, unsigned const* permutation) { tbv* r = allocate(); for (unsigned i = 0; i < num_tbits(); ++i) { - r->set(permutation[i], bv.get(i)); + r->set(permutation[i], bv[i]); } return r; } +tbv* tbv_manager::project(unsigned n, bool const* to_delete, tbv const& src) { + tbv* r = allocate(); + unsigned i, j; + for (i = 0, j = 0; i < n; ++i) { + if (!to_delete[i]) { + r->set(j, src[i]); + ++j; + } + } + SASSERT(num_tbits() == j); + return r; +} + void tbv::set(uint64 val, unsigned hi, unsigned lo) { for (unsigned i = 0; i < hi - lo + 1; ++i) { set(lo + i, (val & (1ULL << i))?BIT_1:BIT_0); @@ -90,7 +103,7 @@ void tbv::set(rational const& r, unsigned hi, unsigned lo) { void tbv::set(tbv const& other, unsigned hi, unsigned lo) { for (unsigned i = 0; i < hi - lo + 1; ++i) { - set(lo + i, other.get(i)); + set(lo + i, other[i]); } } diff --git a/src/muz/ddnf/tbv.h b/src/muz/ddnf/tbv.h index e8eb7b589..bbe993b21 100644 --- a/src/muz/ddnf/tbv.h +++ b/src/muz/ddnf/tbv.h @@ -26,10 +26,16 @@ Revision History: class tbv; -#define BIT_0 0x1 -#define BIT_1 0x2 -#define BIT_x 0x3 -#define BIT_z 0x0 +enum tbit { + BIT_z = 0x0, + BIT_0 = 0x1, + BIT_1 = 0x2, + BIT_x = 0x3 +}; + +inline tbit neg(tbit t) { + return (tbit)(t ^ 0x3); +} class tbv_manager { friend class tbv; @@ -63,6 +69,7 @@ public: bool contains(tbv const& a, tbv const& b) const; bool intersect(tbv const& a, tbv const& b, tbv& result); std::ostream& display(std::ostream& out, tbv const& b) const; + tbv* project(unsigned n, bool const* to_delete, tbv const& src); }; class tbv: private fixed_bit_vector { @@ -91,13 +98,14 @@ public: void set(rational const& r, unsigned hi, unsigned lo); void set(tbv const& other, unsigned hi, unsigned lo); - unsigned operator[](unsigned idx) const { return get(idx); } - void set(unsigned index, unsigned value) { + tbit operator[](unsigned idx) const { return (tbit)get(idx); } + void set(unsigned index, tbit value) { SASSERT(value <= 3); fixed_bit_vector::set(2*index, (value & 2) != 0); fixed_bit_vector::set(2*index+1, (value & 1) != 0); } + private: unsigned get(unsigned index) const { diff --git a/src/muz/ddnf/udoc_relation.cpp b/src/muz/ddnf/udoc_relation.cpp index 1425535f1..34156c2c7 100644 --- a/src/muz/ddnf/udoc_relation.cpp +++ b/src/muz/ddnf/udoc_relation.cpp @@ -271,8 +271,8 @@ namespace datalog { for (unsigned i = 0; i < m_cols1.size(); ++i) { unsigned idx1 = m_cols1[i]; unsigned idx2 = mid + m_cols2[i]; - unsigned v1 = pos[idx1]; - unsigned v2 = pos[idx2]; + tbit v1 = pos[idx1]; + tbit v2 = pos[idx2]; if (v1 == BIT_x) { if (v2 != BIT_x) @@ -294,12 +294,12 @@ namespace datalog { if (v1 == BIT_x && v2 == BIT_x) { // add to subtracted TBVs: 1xx0 and 0xx1 - tbv* r = dm.tbv().allocate(pos); + tbv* r = dm.tbvm().allocate(pos); r->set(idx1, BIT_0); r->set(idx2, BIT_1); neg.push_back(r); - r = dm.tbv().allocate(pos); + r = dm.tbvm().allocate(pos); r->set(idx1, BIT_1); r->set(idx2, BIT_0); neg.push_back(r); @@ -308,13 +308,13 @@ namespace datalog { // handle subtracted TBVs: 1010 -> 1010xxx for (unsigned i = 0; i < d1.neg().size(); ++i) { - tbv* t = dm.tbv().allocate(); + tbv* t = dm.tbvm().allocate(); t->set(d1.neg()[i], mid-1, 0); t->set(d2.pos(), hi - 1, mid); neg.push_back(t); } for (unsigned i = 0; i < d2.neg().size(); ++i) { - tbv* t = dm.tbv().allocate(); + tbv* t = dm.tbvm().allocate(); t->set(d1.pos(), mid-1, 0); t->set(d2.neg()[i], hi - 1, mid); neg.push_back(t); @@ -625,8 +625,8 @@ namespace datalog { unsigned v = to_var(g)->get_idx(); unsigned idx = column_idx(v); doc_manager& dm1 = get_plugin().dm(1); - tbv_ref bit1(dm1.tbv()); - bit1 = dm1.tbv().allocate1(); + tbv_ref bit1(dm1.tbvm()); + bit1 = dm1.tbvm().allocate1(); result.fix_eq_bits(idx, bit1.get(), 0, 1, equalities, discard_cols); } else if (m.is_eq(g, e1, e2) && bv.is_bv(e1)) { @@ -792,9 +792,9 @@ namespace datalog { virtual relation_base* operator()(const relation_base & tb) { udoc_relation const & t = get(tb); udoc const& u1 = t.get_udoc(); + doc_manager& dm = t.get_dm(); udoc u2; - // copy u1 -> u2; - NOT_IMPLEMENTED_YET(); + u2.copy(dm, u1); u2.intersect(dm, m_udoc); if (m_condition && !u2.is_empty()) { t.apply_guard(m_condition, u2, m_col_list); From 2a00f2b38cb09a49e5a2cffe8a1297eac174410e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 18 Sep 2014 05:19:52 -0700 Subject: [PATCH 542/925] adding unit tests for doc Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/doc.cpp | 64 ++++++++++++++++++------- src/muz/ddnf/doc.h | 16 ++++--- src/test/doc.cpp | 93 ++++++++++++++++++++++++++++++++++++ src/test/main.cpp | 1 + src/test/sorting_network.cpp | 3 +- 5 files changed, 153 insertions(+), 24 deletions(-) create mode 100644 src/test/doc.cpp diff --git a/src/muz/ddnf/doc.cpp b/src/muz/ddnf/doc.cpp index 27192ed26..b9aca8bc7 100644 --- a/src/muz/ddnf/doc.cpp +++ b/src/muz/ddnf/doc.cpp @@ -22,49 +22,81 @@ Revision History: #include "doc.h" void doc_manager::reset() { + // m.reset(); - not until docs are in small object allocator. } doc* doc_manager::allocate() { - return 0; + return alloc(doc, m.allocate()); } doc* doc_manager::allocate1() { - return 0; + return alloc(doc, m.allocate1()); } doc* doc_manager::allocate0() { - return 0; + return alloc(doc, m.allocate0()); } doc* doc_manager::allocateX() { - return 0; + return alloc(doc, m.allocateX()); } doc* doc_manager::allocate(doc const& src) { - return 0; + doc* r = alloc(doc, m.allocate(src.pos())); + for (unsigned i = 0; i < src.neg().size(); ++i) { + r->neg().push_back(m.allocate(src.neg()[i])); + } + return r; } doc* doc_manager::allocate(uint64 n) { - return 0; + return alloc(doc, m.allocate(n)); } doc* doc_manager::allocate(rational const& r) { - return 0; + return alloc(doc, m.allocate(r)); } doc* doc_manager::allocate(uint64 n, unsigned hi, unsigned lo) { - return 0; + return alloc(doc, m.allocate(n, hi, lo)); } -doc* doc_manager::allocate(doc, unsigned const* permutation) { - return 0; +doc* doc_manager::allocate(doc const& src, unsigned const* permutation) { + doc* r = alloc(doc, m.allocate(src.pos(), permutation)); + for (unsigned i = 0; i < src.neg().size(); ++i) { + r->neg().push_back(m.allocate(src.neg()[i], permutation)); + } + return r; } void doc_manager::deallocate(doc* src) { + dealloc(src); } -void doc_manager::copy(doc& dst, doc const& src) const { +void doc_manager::copy(doc& dst, doc const& src) { + m.copy(dst.pos(), src.pos()); + unsigned n = std::min(src.neg().size(), dst.neg().size()); + for (unsigned i = 0; i < n; ++i) { + m.copy(dst.neg()[i], src.neg()[i]); + } + for (unsigned i = n; i < dst.neg().size(); ++i) { + dst.neg().erase(m, dst.neg().size()-1); + } + for (unsigned i = n; i < src.neg().size(); ++i) { + dst.neg().push_back(m.allocate(src.neg()[i])); + } } -doc& doc_manager::fill0(doc& src) const { +doc& doc_manager::fill0(doc& src) { + src.neg().reset(m); + m.fill0(src.pos()); return src; } -doc& doc_manager::fill1(doc& src) const { +doc& doc_manager::fill1(doc& src) { + src.neg().reset(m); + m.fill1(src.pos()); return src; } -doc& doc_manager::fillX(doc& src) const { +doc& doc_manager::fillX(doc& src) { + src.neg().reset(m); + m.fillX(src.pos()); return src; } -bool doc_manager::set_and(doc& dst, doc const& src) const { - return false; +bool doc_manager::set_and(doc& dst, doc const& src) { + // (A \ B) & (C \ D) = (A & C) \ (B u D) + if (!m.set_and(dst.pos(), src.pos())) return false; + for (unsigned i = 0; i < src.neg().size(); ++i) { + dst.neg().insert(m, m.allocate(src.neg()[i])); + } + return (src.neg().is_empty() || fold_neg(dst)); } bool doc_manager::fold_neg(doc& dst) { start_over: diff --git a/src/muz/ddnf/doc.h b/src/muz/ddnf/doc.h index 78cd5c94b..3b24b52d1 100644 --- a/src/muz/ddnf/doc.h +++ b/src/muz/ddnf/doc.h @@ -44,15 +44,15 @@ public: doc* allocate(uint64 n); doc* allocate(rational const& r); doc* allocate(uint64 n, unsigned hi, unsigned lo); - doc* allocate(doc, unsigned const* permutation); + doc* allocate(doc const& src, unsigned const* permutation); void deallocate(doc* src); - void copy(doc& dst, doc const& src) const; - doc& reset(doc& src) const { return fill0(src); } - doc& fill0(doc& src) const; - doc& fill1(doc& src) const; - doc& fillX(doc& src) const; + void copy(doc& dst, doc const& src); + doc& reset(doc& src) { return fill0(src); } + doc& fill0(doc& src); + doc& fill1(doc& src); + doc& fillX(doc& src); bool is_full(doc const& src) const; - bool set_and(doc& dst, doc const& src) const; + bool set_and(doc& dst, doc const& src); bool fold_neg(doc& dst); bool intersect(doc const& A, doc const& B, doc& result) const; void complement(doc const& src, ptr_vector& result); @@ -328,6 +328,7 @@ public: } }; + doc(tbv* t): m_pos(t) {} tbv& pos() { return *m_pos; } utbv& neg() { return m_neg; } tbv const& pos() const { return *m_pos; } @@ -349,6 +350,7 @@ public: doc_ref& operator=(doc* d2) { if (d) dm.deallocate(d); d = d2; + return *this; } doc& operator*() { return *d; } doc* operator->() { return d; } diff --git a/src/test/doc.cpp b/src/test/doc.cpp new file mode 100644 index 000000000..27508bac4 --- /dev/null +++ b/src/test/doc.cpp @@ -0,0 +1,93 @@ +#include "doc.h" + +static void tst_doc1(unsigned n) { + doc_manager m(n); + + m.allocate(); + m.reset(); + + doc_ref d(m, m.allocate()); + doc_ref d1(m, m.allocate1()); + doc_ref d0(m, m.allocate0()); + doc_ref dX(m, m.allocateX()); + doc_ref dXc(m, m.allocate(*dX)); + doc_ref d10(m, m.allocate(10)); + doc_ref d20(m, m.allocate(rational(20))); + unsigned hi = 3, lo = 1; + SASSERT(hi <= n); + doc_ref d111X(m, m.allocate(0xFF, hi, lo)); + m.copy(*d, *d10); + SASSERT(m.equals(*d, *d10)); + m.reset(*d); + SASSERT(!m.equals(*d, *d10)); + m.fill0(*d10); + SASSERT(m.equals(*d, *d10)); + m.fill1(*d); + d10 = m.allocate(10); + SASSERT(!m.equals(*d, *d10)); + SASSERT(m.equals(*d, *d1)); + m.fillX(*d); + SASSERT(m.equals(*d, *dX)); + SASSERT(m.is_full(*dX)); + SASSERT(!m.is_full(*d1)); + + VERIFY(m.set_and(*dX,*dX)); + SASSERT(m.equals(*dXc,*dX)); + VERIFY(m.set_and(*dX,*d1)); + SASSERT(!m.equals(*dXc,*dX)); + SASSERT(m.equals(*dX,*d1)); + VERIFY(m.fold_neg(*dX)); + ptr_vector result; + // VERIFY(!m.intersect(*d1,*d0, result)); + m.subtract(*d1,*d0, result); + SASSERT(result.empty()); + SASSERT(m.contains(*dX,*d1)); + SASSERT(m.contains(*dX,*d0)); + SASSERT(!m.contains(*d0,*d1)); + SASSERT(!m.contains(*d1,*d0)); + + + d1->neg().push_back(m.tbvm().allocate0()); + m.display(std::cout, *d1) << " -> "; + VERIFY(m.fold_neg(*d1)); + m.display(std::cout, *d1) << "\n"; + + + svector to_delete(n); + to_delete[1] = true; + to_delete[3] = true; + doc_manager m1(n-2); + doc_ref d1_1(m1, m1.project(n, to_delete.c_ptr(), *d0)); + doc_ref d1_2(m1, m1.allocate1()); + m.display(std::cout, *d1) << " -> "; + m1.display(std::cout, *d1_1) << "\n"; + SASSERT(m1.equals(*d1_1,*d1_2)); + +} + + +// generate "all" clauses over num_vars +// create XXXX \ clauses +// project 0, 1, 2, 3 variables +// check that result is the same as QE over those clauses. + +class test_doc_project { + random_gen m_ran; + + void test_clauses(unsigned num_vars, unsigned num_clauses) { + // + } + +public: + void operator()(unsigned num_vars, unsigned min_clauses, unsigned max_clauses) { + for (unsigned i = min_clauses; i < max_clauses; ++i) { + test_clauses(num_vars, i); + } + } +}; + +void tst_doc() { + tst_doc1(5); + tst_doc1(10); + tst_doc1(70); +} diff --git a/src/test/main.cpp b/src/test/main.cpp index 5d30bb0af..f613402b8 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -142,6 +142,7 @@ int main(int argc, char ** argv) { TST(bit_vector); TST(fixed_bit_vector); TST(tbv); + TST(doc); TST(string_buffer); TST(map); TST(diff_logic); diff --git a/src/test/sorting_network.cpp b/src/test/sorting_network.cpp index d54c575ca..dd46b61df 100644 --- a/src/test/sorting_network.cpp +++ b/src/test/sorting_network.cpp @@ -7,6 +7,7 @@ #include "smt_kernel.h" #include "model_smt2_pp.h" #include "smt_params.h" +#include "ast_util.h" @@ -171,7 +172,7 @@ struct ast_ext2 { return trail(m.mk_fresh_const("x", m.mk_bool_sort())); } void mk_clause(unsigned n, literal const* lits) { - m_clauses.push_back(m.mk_or_reduced(n, lits)); + m_clauses.push_back(mk_or(m, n, lits)); } }; From 9a3a1835cc8a95eb755382f25df754a6d9167702 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 18 Sep 2014 05:52:09 -0700 Subject: [PATCH 543/925] doc Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/doc.cpp | 51 +++++++++++++++++++++++++++++++++++++++----- src/muz/ddnf/doc.h | 4 +++- src/test/doc.cpp | 32 ++++++++++++++++++++++++--- 3 files changed, 78 insertions(+), 9 deletions(-) diff --git a/src/muz/ddnf/doc.cpp b/src/muz/ddnf/doc.cpp index b9aca8bc7..ab3905acd 100644 --- a/src/muz/ddnf/doc.cpp +++ b/src/muz/ddnf/doc.cpp @@ -21,6 +21,15 @@ Revision History: --*/ #include "doc.h" + +doc_manager::doc_manager(unsigned n): m(n) { + m_full = m.allocateX(); +} + +doc_manager::~doc_manager() { + m.deallocate(m_full); +} + void doc_manager::reset() { // m.reset(); - not until docs are in small object allocator. } @@ -60,6 +69,9 @@ doc* doc_manager::allocate(doc const& src, unsigned const* permutation) { return r; } void doc_manager::deallocate(doc* src) { + if (!src) return; + m.deallocate(&src->pos()); + src->neg().reset(m); dealloc(src); } void doc_manager::copy(doc& dst, doc const& src) { @@ -277,18 +289,47 @@ void doc_manager::complement(doc const& src, ptr_vector& result) { void doc_manager::subtract(doc const& A, doc const& B, ptr_vector& result) { } bool doc_manager::equals(doc const& a, doc const& b) const { - return false; + if (!m.equals(a.pos(), b.pos())) return false; + if (a.neg().size() != b.neg().size()) return false; + for (unsigned i = 0; i < a.neg().size(); ++i) { + if (!m.equals(a.neg()[i], b.neg()[i])) return false; + } + return true; } bool doc_manager::is_full(doc const& src) const { - return false; + return src.neg().is_empty() && m.equals(src.pos(), *m_full); } unsigned doc_manager::hash(doc const& src) const { - return 0; + unsigned r = 0; + for (unsigned i = 0; i < src.neg().size(); ++i) { + r = 2*r + m.hash(src.neg()[i]); + } + return r + m.hash(src.pos()); } +// approximation +// A \ (A1 u A2) contains B \ (B1 u B2) +// if +// A contains B +// B1 contains A1 or A2 bool doc_manager::contains(doc const& a, doc const& b) const { - return false; + if (!m.contains(a.pos(), b.pos())) return false; + for (unsigned i = 0; i < b.neg().size(); ++i) { + bool found = false; + for (unsigned j = 0; !found && j < a.neg().size(); ++j) { + found = m.contains(b.neg()[i],a.neg()[j]); + } + if (!found) return false; + } + return true; } std::ostream& doc_manager::display(std::ostream& out, doc const& b) const { - return out; + m.display(out, b.pos()); + if (b.neg().is_empty()) return out; + out << " \\ {"; + for (unsigned i = 0; i < b.neg().size(); ++i) { + m.display(out, b.neg()[i]); + if (i + 1 < b.neg().size()) out << ", "; + } + return out << "}"; } diff --git a/src/muz/ddnf/doc.h b/src/muz/ddnf/doc.h index 3b24b52d1..e85d6f74a 100644 --- a/src/muz/ddnf/doc.h +++ b/src/muz/ddnf/doc.h @@ -32,8 +32,10 @@ template class union_bvec; class doc_manager { tbv_manager m; + tbv* m_full; public: - doc_manager(unsigned n): m(n) {} + doc_manager(unsigned num_bits); + ~doc_manager(); tbv_manager& tbvm() { return m; } void reset(); doc* allocate(); diff --git a/src/test/doc.cpp b/src/test/doc.cpp index 27508bac4..9d37654af 100644 --- a/src/test/doc.cpp +++ b/src/test/doc.cpp @@ -73,15 +73,41 @@ static void tst_doc1(unsigned n) { class test_doc_project { random_gen m_ran; + int m_num_vars; - void test_clauses(unsigned num_vars, unsigned num_clauses) { + unsigned choose_var() { + return m_ran(m_num_vars) + 1; + } + tbit choose_tbit() { + switch(m_ran(3)) { + case 0: return BIT_0; + case 1: return BIT_1; + default : return BIT_x; + } + } + void mk_clause(svector& clause, tbv& t) { + for (int i = 0; i < m_num_vars; ++i) { + tbit b = choose_tbit(); + t.set(i, b); + switch (b) { + case BIT_0: clause.push_back(-i-1); break; + case BIT_1: clause.push_back(i+1); break; + default: break; + } + } + } + + void test_clauses(unsigned num_clauses) { + // } public: - void operator()(unsigned num_vars, unsigned min_clauses, unsigned max_clauses) { + test_doc_project(unsigned num_vars): m_num_vars(num_vars) {} + + void operator()(unsigned min_clauses, unsigned max_clauses) { for (unsigned i = min_clauses; i < max_clauses; ++i) { - test_clauses(num_vars, i); + test_clauses(i); } } }; From 06f00379176e5e83ffe2cd5721f3dc40c4f125a9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 18 Sep 2014 05:53:20 -0700 Subject: [PATCH 544/925] doc Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/doc.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/muz/ddnf/doc.cpp b/src/muz/ddnf/doc.cpp index ab3905acd..7968f55be 100644 --- a/src/muz/ddnf/doc.cpp +++ b/src/muz/ddnf/doc.cpp @@ -159,6 +159,7 @@ doc* doc_manager::project(unsigned n, bool const* to_delete, doc const& src) { // build doc from p. return 0; } + NOT_IMPLEMENTED_YET(); ptr_vector todo; #if 0 // tbv & ~tbv1 & ~tbv2 & .. @@ -285,8 +286,10 @@ doc* doc_manager::project(unsigned n, bool const* to_delete, doc const& src) { } void doc_manager::complement(doc const& src, ptr_vector& result) { + NOT_IMPLEMENTED_YET(); } void doc_manager::subtract(doc const& A, doc const& B, ptr_vector& result) { + NOT_IMPLEMENTED_YET(); } bool doc_manager::equals(doc const& a, doc const& b) const { if (!m.equals(a.pos(), b.pos())) return false; From 9116d386284a99ebbcfceb0e902b43c1298a8556 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 18 Sep 2014 06:07:03 -0700 Subject: [PATCH 545/925] doc Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/tbv.cpp | 10 +++++----- src/test/doc.cpp | 12 ++++++++++-- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/muz/ddnf/tbv.cpp b/src/muz/ddnf/tbv.cpp index b1e5d5344..371233590 100644 --- a/src/muz/ddnf/tbv.cpp +++ b/src/muz/ddnf/tbv.cpp @@ -130,15 +130,15 @@ void tbv_manager::copy(tbv& dst, tbv const& src) const { m.copy(dst, src); } tbv& tbv_manager::fill0(tbv& bv) const { - // 01010101 = 1 + 4 + 16 + 64 - memset(bv.m_data, 1 + 4 + 16 + 64, m.num_bytes()); - return bv; -} -tbv& tbv_manager::fill1(tbv& bv) const { // 10101010 = 2 + 8 + 32 + 128 memset(bv.m_data, 2 + 8 + 32 + 128, m.num_bytes()); return bv; } +tbv& tbv_manager::fill1(tbv& bv) const { + // 01010101 = 1 + 4 + 16 + 64 + memset(bv.m_data, 1 + 4 + 16 + 64, m.num_bytes()); + return bv; +} tbv& tbv_manager::fillX(tbv& bv) const { m.fill1(bv); return bv; diff --git a/src/test/doc.cpp b/src/test/doc.cpp index 9d37654af..ea5202efe 100644 --- a/src/test/doc.cpp +++ b/src/test/doc.cpp @@ -13,6 +13,11 @@ static void tst_doc1(unsigned n) { doc_ref dXc(m, m.allocate(*dX)); doc_ref d10(m, m.allocate(10)); doc_ref d20(m, m.allocate(rational(20))); + m.display(std::cout, *d1) << "\n"; + m.display(std::cout, *d0) << "\n"; + m.display(std::cout, *dX) << "\n"; + m.display(std::cout, *d10) << "\n"; + m.display(std::cout, *d20) << "\n"; unsigned hi = 3, lo = 1; SASSERT(hi <= n); doc_ref d111X(m, m.allocate(0xFF, hi, lo)); @@ -39,8 +44,11 @@ static void tst_doc1(unsigned n) { VERIFY(m.fold_neg(*dX)); ptr_vector result; // VERIFY(!m.intersect(*d1,*d0, result)); - m.subtract(*d1,*d0, result); + // m.subtract(*d1,*d0, result); SASSERT(result.empty()); + dX = m.allocateX(); + m.display(std::cout, *d0) << "\n"; + m.display(std::cout, *dX) << "\n"; SASSERT(m.contains(*dX,*d1)); SASSERT(m.contains(*dX,*d0)); SASSERT(!m.contains(*d0,*d1)); @@ -53,7 +61,7 @@ static void tst_doc1(unsigned n) { m.display(std::cout, *d1) << "\n"; - svector to_delete(n); + svector to_delete(n, false); to_delete[1] = true; to_delete[3] = true; doc_manager m1(n-2); From 53ac452253bb2c1d68b2ad4d8e7ca10c1c15a408 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 18 Sep 2014 06:39:59 -0700 Subject: [PATCH 546/925] doc Signed-off-by: Nikolaj Bjorner --- src/test/doc.cpp | 73 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 19 deletions(-) diff --git a/src/test/doc.cpp b/src/test/doc.cpp index ea5202efe..71eb9945a 100644 --- a/src/test/doc.cpp +++ b/src/test/doc.cpp @@ -1,4 +1,15 @@ #include "doc.h" +#include "trace.h" +#include "vector.h" +#include "ast.h" +#include "ast_pp.h" +#include "reg_decl_plugins.h" +#include "sorting_network.h" +#include "smt_kernel.h" +#include "model_smt2_pp.h" +#include "smt_params.h" +#include "ast_util.h" + static void tst_doc1(unsigned n) { doc_manager m(n); @@ -18,9 +29,11 @@ static void tst_doc1(unsigned n) { m.display(std::cout, *dX) << "\n"; m.display(std::cout, *d10) << "\n"; m.display(std::cout, *d20) << "\n"; - unsigned hi = 3, lo = 1; - SASSERT(hi <= n); - doc_ref d111X(m, m.allocate(0xFF, hi, lo)); + if (n < 64) { + unsigned hi = 3, lo = 1; + SASSERT(hi <= n); + doc_ref d111X(m, m.allocate(0xFF, hi, lo)); + } m.copy(*d, *d10); SASSERT(m.equals(*d, *d10)); m.reset(*d); @@ -61,6 +74,7 @@ static void tst_doc1(unsigned n) { m.display(std::cout, *d1) << "\n"; +#if 0 svector to_delete(n, false); to_delete[1] = true; to_delete[3] = true; @@ -70,7 +84,7 @@ static void tst_doc1(unsigned n) { m.display(std::cout, *d1) << " -> "; m1.display(std::cout, *d1_1) << "\n"; SASSERT(m1.equals(*d1_1,*d1_2)); - +#endif } @@ -80,42 +94,60 @@ static void tst_doc1(unsigned n) { // check that result is the same as QE over those clauses. class test_doc_project { - random_gen m_ran; - int m_num_vars; + random_gen m_ran; + ast_manager m; + doc_manager dm; + expr_ref_vector m_vars; - unsigned choose_var() { - return m_ran(m_num_vars) + 1; - } tbit choose_tbit() { - switch(m_ran(3)) { + switch (m_ran(3)) { case 0: return BIT_0; case 1: return BIT_1; default : return BIT_x; } } - void mk_clause(svector& clause, tbv& t) { - for (int i = 0; i < m_num_vars; ++i) { + void mk_clause(expr_ref& result, tbv& t) { + expr_ref_vector clause(m); + for (unsigned i = 0; i < m_vars.size(); ++i) { tbit b = choose_tbit(); t.set(i, b); switch (b) { - case BIT_0: clause.push_back(-i-1); break; - case BIT_1: clause.push_back(i+1); break; + case BIT_0: clause.push_back(m.mk_not(m_vars[i].get())); break; + case BIT_1: clause.push_back(m_vars[i].get()); break; default: break; } } + result = mk_or(m, clause.size(), clause.c_ptr()); } void test_clauses(unsigned num_clauses) { - + doc_ref d(dm, dm.allocateX()); + expr_ref_vector fmls(m); + expr_ref fml(m); + for (unsigned i = 0; i < num_clauses; ++i) { + expr_ref clause(m); + tbv* t = dm.tbvm().allocate(); + mk_clause(clause, *t); + d->neg().push_back(t); + fmls.push_back(clause); + } + fml = mk_and(m, fmls.size(), fmls.c_ptr()); + dm.display(std::cout, *d) << "\n"; + std::cout << fml << "\n"; // } public: - test_doc_project(unsigned num_vars): m_num_vars(num_vars) {} + test_doc_project(unsigned num_vars): dm(num_vars), m_vars(m) { + reg_decl_plugins(m); + for (unsigned i = 0; i < num_vars; ++i) { + m_vars.push_back(m.mk_fresh_const("b", m.mk_bool_sort())); + } + } - void operator()(unsigned min_clauses, unsigned max_clauses) { - for (unsigned i = min_clauses; i < max_clauses; ++i) { - test_clauses(i); + void operator()(unsigned num_rounds, unsigned num_clauses) { + for (unsigned i = 0; i < num_rounds; ++i) { + test_clauses(num_clauses); } } }; @@ -124,4 +156,7 @@ void tst_doc() { tst_doc1(5); tst_doc1(10); tst_doc1(70); + + test_doc_project tp(4); + tp(5,7); } From 8384a27eca2dc32774fb8764c093702654db6a4b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 18 Sep 2014 11:43:18 -0700 Subject: [PATCH 547/925] handle fix_eq functionality Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/doc.cpp | 101 +++++++++++++++++++++++++++++- src/muz/ddnf/doc.h | 111 +++++++-------------------------- src/muz/ddnf/tbv.cpp | 6 +- src/muz/ddnf/tbv.h | 2 + src/muz/ddnf/udoc_relation.cpp | 20 +++--- 5 files changed, 143 insertions(+), 97 deletions(-) diff --git a/src/muz/ddnf/doc.cpp b/src/muz/ddnf/doc.cpp index 7968f55be..2d8df7758 100644 --- a/src/muz/ddnf/doc.cpp +++ b/src/muz/ddnf/doc.cpp @@ -105,11 +105,31 @@ doc& doc_manager::fillX(doc& src) { bool doc_manager::set_and(doc& dst, doc const& src) { // (A \ B) & (C \ D) = (A & C) \ (B u D) if (!m.set_and(dst.pos(), src.pos())) return false; + for (unsigned i = 0; i < dst.neg().size(); ++i) { + if (!m.set_and(dst.neg()[i], dst.pos())) { + dst.neg().erase(m, i); + --i; + } + } + tbv_ref t(m); for (unsigned i = 0; i < src.neg().size(); ++i) { - dst.neg().insert(m, m.allocate(src.neg()[i])); + t = m.allocate(src.neg()[i]); + if (m.set_and(*t, dst.pos())) { + dst.neg().insert(m, t.detach()); + } } return (src.neg().is_empty() || fold_neg(dst)); } + +bool doc_manager::well_formed(doc const& d) const { + if (!m.is_well_formed(d.pos())) return false; + for (unsigned i = 0; i < d.neg().size(); ++i) { + if (!m.is_well_formed(d.neg()[i])) return false; + if (!m.contains(d.pos(), d.neg()[i])) return false; + } + return true; +} + bool doc_manager::fold_neg(doc& dst) { start_over: for (unsigned i = 0; i < dst.neg().size(); ++i) { @@ -153,6 +173,85 @@ unsigned doc_manager::diff_by_012(tbv const& pos, tbv const& neg, unsigned& inde } return count; } + +void doc_manager::set(doc& d, unsigned idx, tbit value) { + d.pos().set(idx, value); + for (unsigned i = 0; i < d.neg().size(); ++i) { + d.neg()[i].set(idx, value); + } +} + +// +// merge range from [lo:lo+length-1] with each index in equivalence class. +// under assumption of equalities and columns that are discarded. +// +bool doc_manager::merge(doc& d, unsigned lo, unsigned length, subset_ints& equalities, bit_vector const& discard_cols) { + for (unsigned i = 0; i < length; ++i) { + unsigned idx = lo + i; + if (!merge(d, lo + i, equalities, discard_cols)) return false; + } + return true; +} +bool doc_manager::merge(doc& d, unsigned idx, subset_ints& equalities, bit_vector const& discard_cols) { + unsigned root = equalities.find(idx); + idx = root; + unsigned num_x = 0; + unsigned root1; + tbit value = BIT_x; + do { + switch (d[idx]) { + case BIT_0: + if (value == BIT_1) return false; + value = BIT_0; + break; + case BIT_1: + if (value == BIT_0) return false; + value = BIT_1; + break; + case BIT_x: + if (!discard_cols.get(idx)) { + ++num_x; + root1 = idx; + } + break; + default: + break; + } + idx = equalities.next(idx); + } + while (idx != root); + + if (num_x == 0) { + // nothing to do. + } + else if (value != BIT_x) { + do { + if (d[idx] == BIT_x) { + set(d, idx, value); + } + idx = equalities.next(idx); + } + while (idx != root); + } + else { + do { + if (!discard_cols.get(idx) && idx != root1) { + tbv* t = tbvm().allocate(d.pos()); + t->set(idx, BIT_0); + t->set(root1, BIT_1); + d.neg().insert(tbvm(), t); + t = tbvm().allocate(d.pos()); + t->set(idx, BIT_1); + t->set(root1, BIT_0); + d.neg().insert(tbvm(), t); + } + idx = equalities.next(idx); + } + while (idx != root); + } + return true; +} + doc* doc_manager::project(unsigned n, bool const* to_delete, doc const& src) { tbv* p = tbvm().project(n, to_delete, src.pos()); if (src.neg().is_empty()) { diff --git a/src/muz/ddnf/doc.h b/src/muz/ddnf/doc.h index e85d6f74a..7ee9a2db8 100644 --- a/src/muz/ddnf/doc.h +++ b/src/muz/ddnf/doc.h @@ -29,6 +29,7 @@ Revision History: class doc; template class union_bvec; +typedef union_find<> subset_ints; class doc_manager { tbv_manager m; @@ -65,11 +66,14 @@ public: std::ostream& display(std::ostream& out, doc const& b) const; unsigned num_tbits() const { return m.num_tbits(); } doc* project(unsigned n, bool const* to_delete, doc const& src); + bool well_formed(doc const& d) const; + bool merge(doc& d, unsigned lo, unsigned length, subset_ints& equalities, bit_vector const& discard_cols); + void set(doc& d, unsigned idx, tbit value); private: unsigned diff_by_012(tbv const& pos, tbv const& neg, unsigned& index); + bool merge(doc& d, unsigned idx, subset_ints& equalities, bit_vector const& discard_cols); }; -typedef union_find<> subset_ints; // union of tbv*, union of doc* template @@ -210,98 +214,31 @@ public: push_back(m.allocate(other[i])); } } - void fix_eq_bits(unsigned idx1, tbv* BV, unsigned idx2, unsigned length, - subset_ints& equalities, const bit_vector& discard_cols) { - for (unsigned i = 0; i < length; ++i) { - unsigned k = 0; - for (unsigned j = 0; j < size(); ++j, ++k) { - NOT_IMPLEMENTED_YET(); -#if 0 - T *eqBV = BV ? const_cast(BV) : &*I; - bool discard_col = discard_cols.get(idx1+i) || (!BV && discard_cols.get(idx2+i)); - - switch (fix_single_bit(*I, idx1+i, eqBV, idx2+i, equalities, discard_col)) { - case 1: - // remove row - I = m_bitvectors.erase(I); - break; - - case 2: { - // don't care column equality. try subtraction first. - union_ternary_bitvector diff(I->size()), result(I->size()); - T BV(I->size(), true); - BV.set(idx1+i, BIT_0); - BV.set(idx2+i, BIT_1); - diff.add_new_fact(BV); - - BV.set(idx1+i, BIT_1); - BV.set(idx2+i, BIT_0); - diff.add_new_fact(BV); - - I->subtract(diff, result); - *I = *result.begin(); - ++I; - break; - } - - default: - if (I->is_empty()) { - I = m_bitvectors.erase(I); - } else { - // bits fixed - ++I; - } - } -#endif + void merge(M& m, unsigned lo, unsigned length, subset_ints & equalities, bit_vector const& discard_cols) { + for (unsigned i = 0; i < size(); ++i) { + if (!m.merge(*m_elems[i], lo, length, equalities, discard_cols)) { + erase(m, i); + --i; } } } + void merge(M& m, unsigned lo1, unsigned lo2, unsigned length, bit_vector const& discard_cols) { + union_find_default_ctx union_ctx; + subset_ints equalities(union_ctx); + for (unsigned i = 0; i < discard_cols.size(); ++i) { + equalities.mk_var(); + } + for (unsigned j = 0; j < length; ++j) { + equalities.merge(lo1 + j, lo2 + j); + } + merge(m, lo1, length, equalities, discard_cols); + } + + private: - fix_bit_result_t fix_single_bit(tbv& bv, unsigned idx, unsigned value, const subset_ints& equalities) { - unsigned root = equalities.find(idx); - idx = root; - do { - unsigned bitval = bv.get(idx); - if (bitval == tbv::BIT_x) { - bv.set(idx, value); - } - else if (bitval != value) { - return e_row_removed; - } - idx = equalities.next(idx); - } - while (idx != root); - return e_fixed; - } - - fix_bit_result_t fix_single_bit(tbv & BV1, unsigned idx1, tbv & BV2, unsigned idx2, - subset_ints& equalities, bool discard_col) { - unsigned A = BV1.get(idx1); - unsigned B = BV2.get(idx2); - - if (A == tbv::BIT_x) { - if (B == tbv::BIT_x) { - // Both are don't cares. - if (!discard_col) - return e_duplicate_row; - equalities.merge(idx1, idx2); - return e_fixed; - } else { - // only A is don't care. - return fix_single_bit(BV1, idx1, B, equalities); - } - } else if (B == tbv::BIT_x) { - // Only B is don't care. - return fix_single_bit(BV2, idx2, A, equalities); - } else if (A == B) { - return e_fixed; - } else { - return e_row_removed; - } - } }; @@ -335,7 +272,7 @@ public: utbv& neg() { return m_neg; } tbv const& pos() const { return *m_pos; } utbv const& neg() const { return m_neg; } - + tbit operator[](unsigned idx) const { return pos()[idx]; } }; typedef union_bvec udoc; diff --git a/src/muz/ddnf/tbv.cpp b/src/muz/ddnf/tbv.cpp index 371233590..24f4e060c 100644 --- a/src/muz/ddnf/tbv.cpp +++ b/src/muz/ddnf/tbv.cpp @@ -150,8 +150,12 @@ tbv& tbv_manager::set_or(tbv& dst, tbv const& src) const { } bool tbv_manager::set_and(tbv& dst, tbv const& src) const { m.set_and(dst, src); + return is_well_formed(dst); +} + +bool tbv_manager::is_well_formed(tbv const& dst) const { for (unsigned i = 0; i < num_tbits(); ++i) { - if (dst.get(i) == BIT_z) return false; + if (dst[i] == BIT_z) return false; } return true; } diff --git a/src/muz/ddnf/tbv.h b/src/muz/ddnf/tbv.h index bbe993b21..0cbe3db8c 100644 --- a/src/muz/ddnf/tbv.h +++ b/src/muz/ddnf/tbv.h @@ -70,6 +70,7 @@ public: bool intersect(tbv const& a, tbv const& b, tbv& result); std::ostream& display(std::ostream& out, tbv const& b) const; tbv* project(unsigned n, bool const* to_delete, tbv const& src); + bool is_well_formed(tbv const& b) const; // - does not contain BIT_z; }; class tbv: private fixed_bit_vector { @@ -130,6 +131,7 @@ public: } tbv& operator*() { return *d; } tbv* get() { return d; } + tbv* detach() { tbv* result = d; d = 0; return result; } }; diff --git a/src/muz/ddnf/udoc_relation.cpp b/src/muz/ddnf/udoc_relation.cpp index 34156c2c7..9c63e7fd5 100644 --- a/src/muz/ddnf/udoc_relation.cpp +++ b/src/muz/ddnf/udoc_relation.cpp @@ -461,14 +461,18 @@ namespace datalog { for (unsigned i = 0, e = m_empty_bv.size(); i < e; ++i) { m_equalities.mk_var(); } + for (unsigned i = 1; i < col_cnt; ++i) { + for (unsigned j = 0; j < m_size; ++j) { + m_equalities.merge(m_cols[0]+j ,m_cols[i]+j); + } + } } virtual void operator()(relation_base & _r) { udoc_relation& r = get(_r); udoc& d = r.get_udoc(); - for (unsigned i = 1; i < m_cols.size(); ++i) { - d.fix_eq_bits(m_cols[0], 0, m_cols[i], m_size, m_equalities, m_empty_bv); - } + doc_manager& dm = r.get_dm(); + d.merge(dm, m_cols[0], m_size, m_equalities, m_empty_bv); TRACE("dl", tout << "final size: " << r.get_size_estimate_rows() << '\n';); } }; @@ -624,10 +628,10 @@ namespace datalog { SASSERT(m.is_bool(g)); unsigned v = to_var(g)->get_idx(); unsigned idx = column_idx(v); - doc_manager& dm1 = get_plugin().dm(1); - tbv_ref bit1(dm1.tbvm()); - bit1 = dm1.tbvm().allocate1(); - result.fix_eq_bits(idx, bit1.get(), 0, 1, equalities, discard_cols); + doc_ref d(dm); + d = dm.allocateX(); + dm.set(*d, idx, BIT_1); + result.intersect(dm, *d); } else if (m.is_eq(g, e1, e2) && bv.is_bv(e1)) { unsigned hi, lo; @@ -650,7 +654,7 @@ namespace datalog { unsigned idx1 = column_idx(v1->get_idx()); unsigned idx2 = column_idx(v2->get_idx()); unsigned length = column_num_bits(v1->get_idx()); - result.fix_eq_bits(idx1, 0, idx2, length, equalities, discard_cols); + result.merge(dm, idx1, idx2, length, discard_cols); } else { goto failure_case; From c2db127a456754fb56fcb2f682074cf2f0a28fb2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 18 Sep 2014 14:04:06 -0700 Subject: [PATCH 548/925] fix-eq bits and projection Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/doc.cpp | 261 ++++++++++++++++++++++--------------------- src/muz/ddnf/doc.h | 6 +- 2 files changed, 136 insertions(+), 131 deletions(-) diff --git a/src/muz/ddnf/doc.cpp b/src/muz/ddnf/doc.cpp index 2d8df7758..ec66d5c34 100644 --- a/src/muz/ddnf/doc.cpp +++ b/src/muz/ddnf/doc.cpp @@ -34,35 +34,38 @@ void doc_manager::reset() { // m.reset(); - not until docs are in small object allocator. } doc* doc_manager::allocate() { - return alloc(doc, m.allocate()); + return allocate(m.allocate()); } doc* doc_manager::allocate1() { - return alloc(doc, m.allocate1()); + return allocate(m.allocate1()); } doc* doc_manager::allocate0() { - return alloc(doc, m.allocate0()); + return allocate(m.allocate0()); } doc* doc_manager::allocateX() { - return alloc(doc, m.allocateX()); + return allocate(m.allocateX()); } doc* doc_manager::allocate(doc const& src) { - doc* r = alloc(doc, m.allocate(src.pos())); + doc* r = allocate(m.allocate(src.pos())); for (unsigned i = 0; i < src.neg().size(); ++i) { r->neg().push_back(m.allocate(src.neg()[i])); } return r; } +doc* doc_manager::allocate(tbv const& src) { + return allocate(m.allocate(src)); +} doc* doc_manager::allocate(uint64 n) { - return alloc(doc, m.allocate(n)); + return allocate(m.allocate(n)); } doc* doc_manager::allocate(rational const& r) { - return alloc(doc, m.allocate(r)); + return allocate(m.allocate(r)); } doc* doc_manager::allocate(uint64 n, unsigned hi, unsigned lo) { - return alloc(doc, m.allocate(n, hi, lo)); + return allocate(m.allocate(n, hi, lo)); } doc* doc_manager::allocate(doc const& src, unsigned const* permutation) { - doc* r = alloc(doc, m.allocate(src.pos(), permutation)); + doc* r = allocate(m.allocate(src.pos(), permutation)); for (unsigned i = 0; i < src.neg().size(); ++i) { r->neg().push_back(m.allocate(src.neg()[i], permutation)); } @@ -252,143 +255,141 @@ bool doc_manager::merge(doc& d, unsigned idx, subset_ints& equalities, bit_vecto return true; } -doc* doc_manager::project(unsigned n, bool const* to_delete, doc const& src) { - tbv* p = tbvm().project(n, to_delete, src.pos()); +// +// 1. If n = 0,1: can project directly. +// 2. If tbv_i uses X in all positions with vars or constant where tbv is constant: can project directly. +// 3. Perform resolution on remaining tbv_i +// +// tbv & ~tbv1 & ~tbv2 & .. & ~tbv_n +// Semantics of ~tbv1 is that it is a clause of literals. +// indices where BIT_1 is set are negative. +// indices where BIT_0 is set are positive. +// + +doc* doc_manager::project(doc_manager& dstm, unsigned n, bool const* to_delete, doc const& src) { + tbv_manager& dstt = dstm.m; + doc* r = dstm.allocate(dstt.project(n, to_delete, src.pos())); + if (src.neg().is_empty()) { - // build doc from p. - return 0; + return r; } - NOT_IMPLEMENTED_YET(); + if (src.neg().size() == 1) { + r->neg().push_back(dstt.project(n, to_delete, src.neg()[0])); + return r; + } + + // + // All negations can be projected if they are sign compatible. + // + tbv_ref bits(tbvm(), tbvm().allocateX()); + for (unsigned i = 0; i < src.neg().size(); ++i) { + tbvm().set_and(*bits, src.neg()[i]); + } + bool can_project_all = true; + for (unsigned i = 0; can_project_all && i < n; ++i) { + can_project_all = !to_delete[i] || (*bits)[i] != BIT_z; + } + if (can_project_all) { + for (unsigned i = 0; i < src.neg().size(); ++i) { + r->neg().push_back(dstt.project(n, to_delete, src.neg()[i])); + } + return r; + } + + // + // A negation can be projected directly if it does not constrain + // deleted variables. + // ptr_vector todo; -#if 0 - // tbv & ~tbv1 & ~tbv2 & .. - // Semantics of ~tbv1 is that it is a clause of literals. - // indices where BIT_1 is set are negative. - // indices where BIT_0 is set are positive. - // The first loop is supposed to project tbv_i directly - // when some safety condition is met. - // The second loop handles the remaining tbv_i that - // don't meet the safety condition. - for (unsigned i = 0; i < src.neg().size(); ++i) { - if (can_project_neg(n, to_delete, src.neg()[i])) { - + for (unsigned i = 0; i < src.neg().size(); ++i) { + if (can_project_neg(src.pos(), n, to_delete, src.neg()[i])) { + r->neg().push_back(dstt.project(n, to_delete, src.neg()[i])); + } + else { + todo.push_back(tbvm().allocate(src.neg()[i])); } } -#endif -#if 0 - // REVIEW: what is the spec for this code? - ternary_diff_bitvector TBV(*this); - if (!TBV.fold_neg()) - return false; - - std::set todo; - cpy_bits_t cpy_bits; - ternary_bitvector newneg; - for (union_ternary_bitvector::iterator I = TBV.m_neg.begin(), - E = TBV.m_neg.end(); I != E; ++I) { - // check if subtract TBV should be skiped - for (unsigned i = 0; i < delcols.size()-1; ++i) { - unsigned idx = delcols[i]; - if (I->get(idx) != TBV.m_pos.get(idx)) { // xx \ 1x - if (analyze_copy_bit(TBV.m_pos, *I, delcols, cpy_bits)) - todo.insert(&*I); - goto skip_row; - } - } - - newneg.reset(); - I->project(delcols, new_size, newneg); - result.m_neg.add_fact(newneg); - skip_row: ; + if (todo.empty()) { + return r; } - - if (!todo.empty()) { - for (std::set::iterator I = todo.begin(), - E = todo.end(); I != E; ++I) { - for (unsigned i = 0; i < delcols.size()-1; ++i) { - unsigned idx = delcols[i]; - if ((*I)->get(idx) != TBV.m_pos.get(idx)) { - cpy_bits_t::iterator II = cpy_bits.find(idx); - if (II == cpy_bits.end()) - goto skip_bv; - - unsigned idx_keep = II->second.first; - unsigned cpy_val = II->second.second; - - if (!((*I)->get(idx) & cpy_val) || (*I)->get(idx_keep) != BIT_x) - goto skip_bv; - - (*I)->set(idx_keep, (*I)->get(idx)); + ptr_vector pos, neg, new_todo; + tbv_ref t1(tbvm()), t2(tbvm()); + for (unsigned i = 0; i < n; ++i) { + if (to_delete[i] && (*bits)[i] == BIT_z) { + new_todo.reset(); + for (unsigned j = 0; j < todo.size(); ++j) { + tbv& t = *todo[j]; + switch(t[i]) { + case BIT_x: new_todo.push_back(&t); break; + case BIT_0: pos.push_back(&t); break; + case BIT_1: neg.push_back(&t); break; + default: UNREACHABLE(); break; } } - - newneg.reset(); - (*I)->project(delcols, new_size, newneg); - result.m_neg.add_fact(newneg); - skip_bv: ; + if (pos.empty() || neg.empty()) { + continue; + } + for (unsigned j = 0; j < pos.size(); ++j) { + t1 = tbvm().allocate(*pos[j]); + (*t1).set(i, BIT_x); + for (unsigned k = 0; k < neg.size(); ++k) { + if (tbvm().set_and(*t1, *neg[k])) { + new_todo.push_back(t1.detach()); + t1 = tbvm().allocate(*pos[j]); + (*t1).set(i, BIT_x); + } + } + } + for (unsigned i = 0; i < pos.size(); ++i) { + tbvm().deallocate(pos[i]); + } + for (unsigned i = 0; i < neg.size(); ++i) { + tbvm().deallocate(neg[i]); + } + std::swap(todo, new_todo); } } - - return !result.is_empty(); - - - // idx_del -> - // val -> BIT_* - typedef std::map > cpy_bits_t; - - static bool analyze_copy_bit(const ternary_bitvector& pos, const ternary_bitvector& neg, - const unsigned_vector& delcols, cpy_bits_t& cpy_bits) { - unsigned *del = delcols.c_ptr(); - bool got_del_col = false, got_keep_col = false; - unsigned del_col = 0, keep_col = 0; - - for (unsigned i = 0; i < pos.size(); ++i) { - if (pos.get(i) != neg.get(i)) { - if (*del == i) { - if (got_del_col) - return true; - del_col = i; - got_del_col = true; - } else { - if (got_keep_col) - return true; - keep_col = i; - got_keep_col = true; - } - } - - if (i == *del) - ++del; - } - - if (!got_del_col || !got_keep_col) - return true; - if (neg.get(keep_col) == neg.get(del_col)) - return false; - - - unsigned char val = neg.get(del_col); - cpy_bits_t::iterator I = cpy_bits.find(del_col); - if (I == cpy_bits.end()) - cpy_bits[del_col] = std::make_pair(keep_col, val); - else { - // FIXME: eq classes with size > 1 not supported for now - SASSERT(I->second.first == keep_col); - I->second.second |= val; - } - - return false; + for (unsigned i = 0; i < todo.size(); ++i) { + r->neg().push_back(dstt.project(n, to_delete, *todo[i])); + tbvm().deallocate(todo[i]); } - -#endif - return 0; + return r; } +bool doc_manager::can_project_neg(tbv const& pos, unsigned n, bool const* to_delete, tbv const& neg) { + for (unsigned i = 0; i < n; ++i) { + if (to_delete[i] && BIT_x != neg[i] && BIT_x == pos[i]) return false; + } + return true; +} + + void doc_manager::complement(doc const& src, ptr_vector& result) { - NOT_IMPLEMENTED_YET(); + result.reset(); + if (is_full(src)) { + return; + } + doc* r = allocateX(); + r->neg().push_back(m.allocate(src.pos())); + result.push_back(r); + for (unsigned i = 0; i < src.neg().size(); ++i) { + result.push_back(allocate(src.neg()[i])); + } } void doc_manager::subtract(doc const& A, doc const& B, ptr_vector& result) { - NOT_IMPLEMENTED_YET(); + doc_ref r(*this), r2(*this); + r = allocate(A); + if (r->neg().insert(m, m.allocate(B.pos()))) { + result.push_back(r.detach()); + r = allocate(A); + } + for (unsigned i = 0; i < B.neg().size(); ++i) { + r2 = allocate(B.neg()[i]); + if (set_and(*r, *r2)) { + result.push_back(r.detach()); + r = allocate(A); + } + } } bool doc_manager::equals(doc const& a, doc const& b) const { if (!m.equals(a.pos(), b.pos())) return false; diff --git a/src/muz/ddnf/doc.h b/src/muz/ddnf/doc.h index 7ee9a2db8..107720a23 100644 --- a/src/muz/ddnf/doc.h +++ b/src/muz/ddnf/doc.h @@ -44,6 +44,8 @@ public: doc* allocate0(); doc* allocateX(); doc* allocate(doc const& src); + doc* allocate(tbv const& src); + doc* allocate(tbv * src); doc* allocate(uint64 n); doc* allocate(rational const& r); doc* allocate(uint64 n, unsigned hi, unsigned lo); @@ -65,13 +67,14 @@ public: bool contains(doc const& a, doc const& b) const; std::ostream& display(std::ostream& out, doc const& b) const; unsigned num_tbits() const { return m.num_tbits(); } - doc* project(unsigned n, bool const* to_delete, doc const& src); + doc* project(doc_manager& dstm, unsigned n, bool const* to_delete, doc const& src); bool well_formed(doc const& d) const; bool merge(doc& d, unsigned lo, unsigned length, subset_ints& equalities, bit_vector const& discard_cols); void set(doc& d, unsigned idx, tbit value); private: unsigned diff_by_012(tbv const& pos, tbv const& neg, unsigned& index); bool merge(doc& d, unsigned idx, subset_ints& equalities, bit_vector const& discard_cols); + bool can_project_neg(tbv const& pos, unsigned n, bool const* to_delete, tbv const& neg); }; @@ -293,6 +296,7 @@ public: } doc& operator*() { return *d; } doc* operator->() { return d; } + doc* detach() { doc* r = d; d = 0; return r; } }; #endif /* _DOC_H_ */ From 4173bf930bd9392d5b6277ec6ede54d27f8460fb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 18 Sep 2014 14:08:53 -0700 Subject: [PATCH 549/925] fix-eq bits and projection Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/doc.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/muz/ddnf/doc.cpp b/src/muz/ddnf/doc.cpp index ec66d5c34..1a35c19ad 100644 --- a/src/muz/ddnf/doc.cpp +++ b/src/muz/ddnf/doc.cpp @@ -334,6 +334,7 @@ doc* doc_manager::project(doc_manager& dstm, unsigned n, bool const* to_delete, (*t1).set(i, BIT_x); for (unsigned k = 0; k < neg.size(); ++k) { if (tbvm().set_and(*t1, *neg[k])) { + (*t1).set(i, BIT_x); new_todo.push_back(t1.detach()); t1 = tbvm().allocate(*pos[j]); (*t1).set(i, BIT_x); From 8154fc24e1b9e3d7a99aef11582ad82e29a2c6d0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 18 Sep 2014 15:42:30 -0700 Subject: [PATCH 550/925] testing projection Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/doc.cpp | 5 +++++ src/muz/ddnf/tbv.cpp | 16 ++++++++++++++-- src/test/doc.cpp | 32 +++++++++++++++++++++++++++----- src/test/tbv.cpp | 10 ++++++++++ 4 files changed, 56 insertions(+), 7 deletions(-) diff --git a/src/muz/ddnf/doc.cpp b/src/muz/ddnf/doc.cpp index 1a35c19ad..12883d005 100644 --- a/src/muz/ddnf/doc.cpp +++ b/src/muz/ddnf/doc.cpp @@ -52,6 +52,9 @@ doc* doc_manager::allocate(doc const& src) { } return r; } +doc* doc_manager::allocate(tbv* t) { + return alloc(doc, t); +} doc* doc_manager::allocate(tbv const& src) { return allocate(m.allocate(src)); } @@ -317,6 +320,8 @@ doc* doc_manager::project(doc_manager& dstm, unsigned n, bool const* to_delete, for (unsigned i = 0; i < n; ++i) { if (to_delete[i] && (*bits)[i] == BIT_z) { new_todo.reset(); + pos.reset(); + neg.reset(); for (unsigned j = 0; j < todo.size(); ++j) { tbv& t = *todo[j]; switch(t[i]) { diff --git a/src/muz/ddnf/tbv.cpp b/src/muz/ddnf/tbv.cpp index 24f4e060c..1bcad2281 100644 --- a/src/muz/ddnf/tbv.cpp +++ b/src/muz/ddnf/tbv.cpp @@ -19,12 +19,17 @@ Revision History: --*/ #include "tbv.h" +#include "hashtable.h" + +static ptr_addr_hashtable allocated_tbvs; void tbv_manager::reset() { m.reset(); } tbv* tbv_manager::allocate() { - return reinterpret_cast(m.allocate()); + tbv* r = reinterpret_cast(m.allocate()); + allocated_tbvs.insert(r); + return r; } tbv* tbv_manager::allocate1() { tbv* v = allocate(); @@ -42,7 +47,9 @@ tbv* tbv_manager::allocateX() { return v; } tbv* tbv_manager::allocate(tbv const& bv) { - return reinterpret_cast(m.allocate(bv)); + tbv* r = allocate(); + copy(*r, bv); + return r; } tbv* tbv_manager::allocate(uint64 val) { tbv* v = allocate0(); @@ -124,6 +131,11 @@ tbv* tbv_manager::allocate(rational const& r) { return v; } void tbv_manager::deallocate(tbv* bv) { + if (!allocated_tbvs.contains(bv)) { + std::cout << "double deallocate: " << bv << "\n"; + UNREACHABLE(); + } + allocated_tbvs.erase(bv); m.deallocate(bv); } void tbv_manager::copy(tbv& dst, tbv const& src) const { diff --git a/src/test/doc.cpp b/src/test/doc.cpp index 71eb9945a..b516a45b4 100644 --- a/src/test/doc.cpp +++ b/src/test/doc.cpp @@ -74,17 +74,25 @@ static void tst_doc1(unsigned n) { m.display(std::cout, *d1) << "\n"; -#if 0 svector to_delete(n, false); to_delete[1] = true; to_delete[3] = true; doc_manager m1(n-2); - doc_ref d1_1(m1, m1.project(n, to_delete.c_ptr(), *d0)); + doc_ref d1_1(m1, m.project(m1, n, to_delete.c_ptr(), *d1)); doc_ref d1_2(m1, m1.allocate1()); m.display(std::cout, *d1) << " -> "; m1.display(std::cout, *d1_1) << "\n"; SASSERT(m1.equals(*d1_1,*d1_2)); -#endif + m.set(*d1,2,BIT_x); + m.set(*d1,4,BIT_x); + d1_1 = m.project(m1, n, to_delete.c_ptr(), *d1); + m.display(std::cout, *d1) << " -> "; + m1.display(std::cout, *d1_1) << "\n"; + d1->neg().push_back(m.tbvm().allocate1()); + SASSERT(m.well_formed(*d1)); + d1_1 = m.project(m1, n, to_delete.c_ptr(), *d1); + m.display(std::cout, *d1) << " -> "; + m1.display(std::cout, *d1_1) << "\n"; } @@ -120,6 +128,13 @@ class test_doc_project { result = mk_or(m, clause.size(), clause.c_ptr()); } + void project(doc const& d, doc_manager& m2, bool const* to_delete) { + doc_ref result(m2); + dm.display(std::cout, d) << " -> "; + result = dm.project(m2, m_vars.size(), to_delete, d); + m2.display(std::cout, *result) << "\n"; + } + void test_clauses(unsigned num_clauses) { doc_ref d(dm, dm.allocateX()); expr_ref_vector fmls(m); @@ -132,8 +147,15 @@ class test_doc_project { fmls.push_back(clause); } fml = mk_and(m, fmls.size(), fmls.c_ptr()); - dm.display(std::cout, *d) << "\n"; - std::cout << fml << "\n"; + svector to_delete(m_vars.size(), false); + unsigned num_bits = 1; + for (unsigned i = 1; i < to_delete.size(); ++i) { + to_delete[i] = (m_ran(2) == 0); + if (!to_delete[i]) ++num_bits; + } + doc_manager m2(num_bits); + project(*d, m2, to_delete.c_ptr()); + // std::cout << fml << "\n"; // } diff --git a/src/test/tbv.cpp b/src/test/tbv.cpp index 21ecdd697..d56fcd84a 100644 --- a/src/test/tbv.cpp +++ b/src/test/tbv.cpp @@ -24,6 +24,16 @@ static void tst1(unsigned num_bits) { VERIFY(m.intersect(*bX,*b0,*bN)); SASSERT(m.equals(*b0, *bN)); VERIFY(!m.intersect(*b0,*b1,*bN)); + m.fill1(*b1); + svector to_delete(num_bits, false); + tbv_manager m2(num_bits-2); + to_delete[1] = true; + to_delete[3] = true; + (*b1).set(2, BIT_0); + (*b1).set(4, BIT_x); + tbv_ref b2(m2, m2.project(num_bits, to_delete.c_ptr(), *b1)); + m.display(std::cout, *b1) << " -> "; + m2.display(std::cout, *b2) << "\n"; m.deallocate(b0); m.deallocate(b1); m.deallocate(bX); From b524603287706dea1f94c21b69c99885bd3d313c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 18 Sep 2014 15:47:09 -0700 Subject: [PATCH 551/925] local Signed-off-by: Nikolaj Bjorner --- src/test/doc.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/test/doc.cpp b/src/test/doc.cpp index 71eb9945a..e16860b55 100644 --- a/src/test/doc.cpp +++ b/src/test/doc.cpp @@ -134,7 +134,20 @@ class test_doc_project { fml = mk_and(m, fmls.size(), fmls.c_ptr()); dm.display(std::cout, *d) << "\n"; std::cout << fml << "\n"; - // + for (unsigned i = 0; i < m_vars.size(); ++i) { + //test_project(i, fml, *d); + } + } + + void test_project(unsigned i, expr* fml, doc& d) { + svector to_delete(m_vars.size(), false); + to_delete[i] = true; + doc_manager dm1(m_vars.size()-1); + doc_ref d1(dm1, dm1.project(m_vars.size(), to_delete.c_ptr(), d)); + expr_ref fml1(m); + // fml1 = m.mk_exists(); + // extrac formula fml2 from d1, + // check that fml1 is equivalent to fml2 } public: From 6db3ca1236ad149f5c8364881829d0175ac0d336 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 18 Sep 2014 21:58:11 -0700 Subject: [PATCH 552/925] unit test merge Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/doc.cpp | 49 ++++++++++++++++++---------------- src/muz/ddnf/doc.h | 14 +++++----- src/muz/ddnf/tbv.cpp | 14 +++++++--- src/muz/ddnf/tbv.h | 2 +- src/test/doc.cpp | 62 +++++++++++++++++++++++++++++++++++++++----- 5 files changed, 101 insertions(+), 40 deletions(-) diff --git a/src/muz/ddnf/doc.cpp b/src/muz/ddnf/doc.cpp index 4c12b4bee..4292aac05 100644 --- a/src/muz/ddnf/doc.cpp +++ b/src/muz/ddnf/doc.cpp @@ -190,7 +190,10 @@ void doc_manager::set(doc& d, unsigned idx, tbit value) { // merge range from [lo:lo+length-1] with each index in equivalence class. // under assumption of equalities and columns that are discarded. // -bool doc_manager::merge(doc& d, unsigned lo, unsigned length, subset_ints& equalities, bit_vector const& discard_cols) { +bool doc_manager::merge( + doc& d, unsigned lo, unsigned length, + subset_ints& equalities, bit_vector const& discard_cols) { + std::cout << "merge\n"; for (unsigned i = 0; i < length; ++i) { unsigned idx = lo + i; if (!merge(d, lo + i, equalities, discard_cols)) return false; @@ -242,10 +245,12 @@ bool doc_manager::merge(doc& d, unsigned idx, subset_ints& equalities, bit_vecto do { if (!discard_cols.get(idx) && idx != root1) { tbv* t = tbvm().allocate(d.pos()); + std::cout << "insert " << t << "\n"; t->set(idx, BIT_0); t->set(root1, BIT_1); d.neg().insert(tbvm(), t); t = tbvm().allocate(d.pos()); + std::cout << "insert " << t << "\n"; t->set(idx, BIT_1); t->set(root1, BIT_0); d.neg().insert(tbvm(), t); @@ -314,7 +319,8 @@ doc* doc_manager::project(doc_manager& dstm, unsigned n, bool const* to_delete, if (todo.empty()) { return r; } - ptr_vector pos, neg, new_todo; + ptr_vector new_todo; + utbv pos, neg; tbv_ref t1(tbvm()), t2(tbvm()); for (unsigned i = 0; i < n; ++i) { if (to_delete[i] && (*bits)[i] != BIT_x) { @@ -323,50 +329,49 @@ doc* doc_manager::project(doc_manager& dstm, unsigned n, bool const* to_delete, tbvm().display(tout, *todo[j]) << " "; } tout << "\n";); - new_todo.reset(); - pos.reset(); - neg.reset(); - for (unsigned j = 0; j < todo.size(); ++j) { - tbv& t = *todo[j]; - switch(t[i]) { - case BIT_x: new_todo.push_back(&t); break; - case BIT_0: neg.push_back(&t); break; - case BIT_1: pos.push_back(&t); break; + SASSERT(pos.is_empty()); + SASSERT(neg.is_empty()); + SASSERT(new_todo.empty()); + while (!todo.empty()) { + tbv* t = todo.back(); + todo.pop_back(); + switch((*t)[i]) { + case BIT_x: new_todo.push_back(t); break; + case BIT_0: neg.push_back(t); break; + case BIT_1: pos.push_back(t); break; default: UNREACHABLE(); break; } } - if (pos.empty() || neg.empty()) { + if (pos.is_empty() || neg.is_empty()) { std::swap(new_todo, todo); + pos.reset(tbvm()); + neg.reset(tbvm()); continue; } TRACE("doc", tout << "pos: "; for (unsigned i = 0; i < pos.size(); ++i) { - tbvm().display(tout, *pos[i]) << " "; + tbvm().display(tout, pos[i]) << " "; } tout << "\nneg: "; for (unsigned i = 0; i < neg.size(); ++i) { - tbvm().display(tout, *neg[i]) << " "; + tbvm().display(tout, neg[i]) << " "; } tout << "\n"; ); for (unsigned j = 0; j < pos.size(); ++j) { for (unsigned k = 0; k < neg.size(); ++k) { - t1 = tbvm().allocate(*pos[j]); + t1 = tbvm().allocate(pos[j]); (*t1).set(i, BIT_x); - if (tbvm().set_and(*t1, *neg[k])) { + if (tbvm().set_and(*t1, neg[k])) { (*t1).set(i, BIT_x); new_todo.push_back(t1.detach()); } } } - for (unsigned i = 0; i < pos.size(); ++i) { - tbvm().deallocate(pos[i]); - } - for (unsigned i = 0; i < neg.size(); ++i) { - tbvm().deallocate(neg[i]); - } + pos.reset(tbvm()); + neg.reset(tbvm()); std::swap(todo, new_todo); } } diff --git a/src/muz/ddnf/doc.h b/src/muz/ddnf/doc.h index 4a4841dae..e3d36019b 100644 --- a/src/muz/ddnf/doc.h +++ b/src/muz/ddnf/doc.h @@ -131,12 +131,14 @@ public: m.deallocate(m_elems[i]); --j; } - else if (m.contains(*m_elems[i], *t)) { - found = true; - } - else if (i != j) { - m_elems[j] = m_elems[i]; - } + else { + if (m.contains(*m_elems[i], *t)) { + found = true; + } + if (i != j) { + m_elems[j] = m_elems[i]; + } + } } if (j != sz) m_elems.resize(j); if (found) { diff --git a/src/muz/ddnf/tbv.cpp b/src/muz/ddnf/tbv.cpp index e9c04d139..a83a3874e 100644 --- a/src/muz/ddnf/tbv.cpp +++ b/src/muz/ddnf/tbv.cpp @@ -22,8 +22,11 @@ Revision History: #include "hashtable.h" +//#define _DEBUG_MEM 1 +#define _DEBUG_MEM 0 + tbv_manager::~tbv_manager() { -#if 0 +#if _DEBUG_MEM ptr_vector::iterator it = allocated_tbvs.begin(), end = allocated_tbvs.end(); for (; it != end; ++it) { std::cout << "dangling: " << (*it) << "\n"; @@ -36,8 +39,10 @@ void tbv_manager::reset() { } tbv* tbv_manager::allocate() { tbv* r = reinterpret_cast(m.allocate()); - //std::cout << allocated_tbvs.size() << " " << r << "\n"; - //allocated_tbvs.insert(r); +#if _DEBUG_MEM + std::cout << allocated_tbvs.size() << " " << r << "\n"; + allocated_tbvs.insert(r); +#endif return r; } tbv* tbv_manager::allocate1() { @@ -140,11 +145,12 @@ tbv* tbv_manager::allocate(rational const& r) { return v; } void tbv_manager::deallocate(tbv* bv) { -#if 0 +#if _DEBUG_MEM if (!allocated_tbvs.contains(bv)) { std::cout << "double deallocate: " << bv << "\n"; UNREACHABLE(); } + std::cout << "deallocate: " << bv << "\n"; allocated_tbvs.erase(bv); #endif m.deallocate(bv); diff --git a/src/muz/ddnf/tbv.h b/src/muz/ddnf/tbv.h index 05584e391..f8c2d6643 100644 --- a/src/muz/ddnf/tbv.h +++ b/src/muz/ddnf/tbv.h @@ -40,7 +40,7 @@ inline tbit neg(tbit t) { class tbv_manager { friend class tbv; fixed_bit_vector_manager m; - // ptr_vector allocated_tbvs; + ptr_vector allocated_tbvs; public: tbv_manager(unsigned n): m(2*n) {} ~tbv_manager(); diff --git a/src/test/doc.cpp b/src/test/doc.cpp index f6ebd1e0b..2747ef35d 100644 --- a/src/test/doc.cpp +++ b/src/test/doc.cpp @@ -100,7 +100,7 @@ static void tst_doc1(unsigned n) { // project 0, 1, 2, 3 variables // check that result is the same as QE over those clauses. -class test_doc_project { +class test_doc_cls { random_gen m_ran; ast_manager m; doc_manager dm; @@ -179,7 +179,7 @@ class test_doc_project { ); } - void test_clauses(unsigned num_clauses) { + void test_project(unsigned num_clauses) { doc_ref d(dm, dm.allocateX()); expr_ref_vector fmls(m); th_rewriter rw(m); @@ -222,26 +222,74 @@ class test_doc_project { SASSERT(res == l_false); } + void test_merge(unsigned num_clauses) { + doc_ref d(dm, dm.allocateX()); + expr_ref_vector fmls(m); + th_rewriter rw(m); + unsigned N = m_vars.size(); + expr_ref fml1(m), fml2(m), fml3(m), tmp1(m), tmp2(m), fml(m); + for (unsigned i = 0; i < num_clauses; ++i) { + tbv* t = dm.tbvm().allocate(); + fmls.push_back(m.mk_not(mk_conj(*t))); + d->neg().push_back(t); + } + fml1 = mk_and(m, fmls.size(), fmls.c_ptr()); + svector to_merge(N, false), to_delete(N, false); + bit_vector discard_cols; + discard_cols.resize(N, false); + unsigned num_bits = 1; + union_find_default_ctx union_ctx; + subset_ints equalities(union_ctx); + unsigned lo = N; + equalities.mk_var(); + for (unsigned i = 1; i < N; ++i) { + to_merge[i] = (m_ran(2) == 0); + if (!to_merge[i]) ++num_bits; else lo = i; + equalities.mk_var(); + } + if (lo == N) return; + for (unsigned i = 0; i < N; ++i) { + if (to_merge[i] && i != lo) { + equalities.merge(i, lo); + } + } + fml1 = to_formula(*d, dm, to_delete.c_ptr()); + if (dm.merge(*d, lo, 1, equalities, discard_cols)) { + fml2 = to_formula(*d, dm, to_delete.c_ptr()); + std::cout << fml1 << "\n"; + std::cout << fml2 << "\n"; + } + // ... + } + public: - test_doc_project(unsigned num_vars): dm(num_vars), m_vars(m) { + test_doc_cls(unsigned num_vars): dm(num_vars), m_vars(m) { reg_decl_plugins(m); for (unsigned i = 0; i < num_vars; ++i) { m_vars.push_back(m.mk_fresh_const("b", m.mk_bool_sort())); } } - void operator()(unsigned num_rounds, unsigned num_clauses) { + void test_project(unsigned num_rounds, unsigned num_clauses) { for (unsigned i = 0; i < num_rounds; ++i) { - test_clauses(num_clauses); + test_project(num_clauses); + } + } + + void test_merge(unsigned num_rounds, unsigned num_clauses) { + for (unsigned i = 0; i < num_rounds; ++i) { + test_merge(num_clauses); } } }; + void tst_doc() { tst_doc1(5); tst_doc1(10); tst_doc1(70); - test_doc_project tp(4); - tp(200,7); + test_doc_cls tp(4); + tp.test_merge(200,7); + tp.test_project(200,7); } From adce20119f0986b38132cdeff40dae14f2066dbf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 18 Sep 2014 22:30:45 -0700 Subject: [PATCH 553/925] doing project Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/udoc_relation.cpp | 57 +++++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/src/muz/ddnf/udoc_relation.cpp b/src/muz/ddnf/udoc_relation.cpp index 9c63e7fd5..0d80fd8ce 100644 --- a/src/muz/ddnf/udoc_relation.cpp +++ b/src/muz/ddnf/udoc_relation.cpp @@ -347,11 +347,44 @@ namespace datalog { } return alloc(join_fn, *this, get(t1), get(t2), col_cnt, cols1, cols2); } + class udoc_plugin::project_fn : public convenient_relation_project_fn { + svector m_to_delete; + public: + project_fn(udoc_relation const & t, unsigned removed_col_cnt, const unsigned * removed_cols) + : convenient_relation_project_fn(t.get_signature(), removed_col_cnt, removed_cols) { + t.expand_column_vector(m_removed_cols); + unsigned n = t.get_dm().num_tbits(); + m_to_delete.resize(n, false); + for (unsigned i = 0; i < m_removed_cols.size(); ++i) { + m_to_delete[m_removed_cols[i]] = true; + } + } + + virtual relation_base * operator()(const relation_base & tb) { + udoc_relation const& t = get(tb); + udoc_plugin& p = t.get_plugin(); + udoc_relation* r = udoc_plugin::get(p.mk_empty(get_result_signature())); + doc_manager& dm1 = t.get_dm(); + doc_manager& dm2 = r->get_dm(); + doc_ref d2(dm2); + udoc const& ud1 = t.get_udoc(); + udoc& ud2 = r->get_udoc(); + for (unsigned i = 0; i < ud1.size(); ++i) { + d2 = dm1.project(dm2, m_to_delete.size(), m_to_delete.c_ptr(), ud1[i]); + ud2.push_back(d2.detach()); + } + TRACE("dl_hassel", tout << "final size: " << r->get_size_estimate_rows() << '\n';); + return r; + } + }; + + relation_transformer_fn * udoc_plugin::mk_project_fn( const relation_base & t, unsigned col_cnt, const unsigned * removed_cols) { - NOT_IMPLEMENTED_YET(); - return 0; + if (!check_kind(t)) + return 0; + return alloc(project_fn, get(t), col_cnt, removed_cols); } class udoc_plugin::rename_fn : public convenient_relation_rename_fn { @@ -770,6 +803,7 @@ namespace datalog { expr_ref m_condition; udoc m_udoc; bit_vector m_col_list; // map: col idx -> bool (whether the column is to be removed) + svector m_to_delete; // same public: filter_proj_fn(const udoc_relation & t, ast_manager& m, app *condition, unsigned col_cnt, const unsigned * removed_cols) : @@ -779,9 +813,12 @@ namespace datalog { t.expand_column_vector(m_removed_cols); m_col_list.resize(t.get_num_bits(), false); for (unsigned i = 0; i < m_removed_cols.size(); ++i) { - m_col_list.set(m_removed_cols[i]); + m_col_list.set(m_removed_cols[i], true); + } + m_to_delete.resize(m_removed_cols.size(), false); + for (unsigned i = 0; i < m_removed_cols.size(); ++i) { + m_to_delete[m_removed_cols[i]] = true; } - m_removed_cols.push_back(UINT_MAX); expr_ref guard(m), rest(m); t.extract_guard(condition, guard, m_condition); t.compile_guard(guard, m_udoc, m_col_list); @@ -803,10 +840,14 @@ namespace datalog { if (m_condition && !u2.is_empty()) { t.apply_guard(m_condition, u2, m_col_list); } - udoc_relation* res = get(t.get_plugin().mk_empty(get_result_signature())); - NOT_IMPLEMENTED_YET(); - // u2.project(m_removed_cols, res->get_dm(), res->get_udoc()); - return res; + udoc_relation* r = get(t.get_plugin().mk_empty(get_result_signature())); + doc_manager& dm2 = r->get_dm(); + for (unsigned i = 0; i < u2.size(); ++i) { + doc* d = dm.project(dm2, m_to_delete.size(), m_to_delete.c_ptr(), u2[i]); + r->get_udoc().insert(dm2, d); + } + u2.reset(dm); + return r; } }; relation_transformer_fn * udoc_plugin::mk_filter_interpreted_and_project_fn( From cb8ad76677b45fb12bf438f3971ee92cb54e0dbd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 18 Sep 2014 23:51:11 -0700 Subject: [PATCH 554/925] finished code Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/udoc_relation.cpp | 55 ++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 12 deletions(-) diff --git a/src/muz/ddnf/udoc_relation.cpp b/src/muz/ddnf/udoc_relation.cpp index 0d80fd8ce..817909f14 100644 --- a/src/muz/ddnf/udoc_relation.cpp +++ b/src/muz/ddnf/udoc_relation.cpp @@ -325,6 +325,7 @@ namespace datalog { virtual relation_base * operator()(const relation_base & _r1, const relation_base & _r2) { udoc_relation const& r1 = get(_r1); udoc_relation const& r2 = get(_r2); + TRACE("dl", r1.display(tout << "r1:\n"); r2.display(tout << "r2:\n");); udoc_plugin& p = r1.get_plugin(); relation_signature const& sig = get_result_signature(); udoc_relation * result = alloc(udoc_relation, p, sig); @@ -336,6 +337,7 @@ namespace datalog { join(d1[i], d2[j], r); } } + TRACE("dl", result->display(tout << "result:\n");); return result; } }; @@ -361,6 +363,7 @@ namespace datalog { } virtual relation_base * operator()(const relation_base & tb) { + TRACE("dl", tb.display(tout << "src:\n");); udoc_relation const& t = get(tb); udoc_plugin& p = t.get_plugin(); udoc_relation* r = udoc_plugin::get(p.mk_empty(get_result_signature())); @@ -373,7 +376,7 @@ namespace datalog { d2 = dm1.project(dm2, m_to_delete.size(), m_to_delete.c_ptr(), ud1[i]); ud2.push_back(d2.detach()); } - TRACE("dl_hassel", tout << "final size: " << r->get_size_estimate_rows() << '\n';); + TRACE("dl", tout << "final size: " << r->get_size_estimate_rows() << '\n';); return r; } }; @@ -412,6 +415,7 @@ namespace datalog { virtual relation_base * operator()(const relation_base & _r) { udoc_relation const& r = get(_r); + TRACE("dl", r.display(tout << "r:\n");); udoc_plugin& p = r.get_plugin(); relation_signature const& sig = get_result_signature(); udoc_relation* result = alloc(udoc_relation, p, sig); @@ -421,6 +425,7 @@ namespace datalog { for (unsigned i = 0; i < src.size(); ++i) { dst.push_back(dm.allocate(src[i], m_permutation.c_ptr())); } + TRACE("dl", result->display(tout << "result:\n");); return result; } }; @@ -439,15 +444,14 @@ namespace datalog { union_fn() {} virtual void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) { - TRACE("dl", _r.display(tout << "dst:\n"); _src.display(tout << "src:\n");); - udoc_relation& r = get(_r); udoc_relation const& src = get(_src); udoc_relation* d = get(_delta); udoc* d1 = 0; if (d) d1 = &d->get_udoc(); r.get_plugin().mk_union(r.get_dm(), r.get_udoc(), src.get_udoc(), d1); + TRACE("dl", _r.display(tout << "dst':\n");); } }; void udoc_plugin::mk_union(doc_manager& dm, udoc& dst, udoc const& src, udoc* delta) { @@ -717,6 +721,9 @@ namespace datalog { if (m.is_true(m_condition)) { m_condition = 0; } + TRACE("dl", + tout << "condition: " << mk_pp(condition, m) << "\n"; + tout << m_condition << "\n"; m_udoc.display(dm, tout) << "\n";); } virtual ~filter_interpreted_fn() { @@ -749,9 +756,9 @@ namespace datalog { virtual void operator()(relation_base& tb, const relation_base& negb) { udoc_relation& t = get(tb); - udoc_relation const& negt = get(negb); + udoc_relation const& n = get(negb); udoc & dst = t.get_udoc(); - udoc const & neg = negt.get_udoc(); + udoc const & neg = n.get_udoc(); doc_manager& dm = t.get_dm(); udoc result; for (unsigned i = 0; i < dst.size(); ++i) { @@ -761,11 +768,16 @@ namespace datalog { for (unsigned c = 0; !done_i && !done_j && c < m_t_cols.size(); ++c) { unsigned t_col = m_t_cols[c]; unsigned n_col = m_neg_cols[c]; - SASSERT(t.column_num_bits(t_col) == negt.column_num_bits(n_col)); - NOT_IMPLEMENTED_YET(); - //if (!neg[j].contains(negt.column_idx(n_col), dst[i], t.column_idx(t_col), t.column_num_bits(t_col))) { - // done_j = true; - //} + unsigned num_bits = t.column_num_bits(t_col); + SASSERT(num_bits == n.column_num_bits(n_col)); + unsigned t_idx = t.column_idx(t_col); + unsigned n_idx = n.column_idx(n_col); + for (unsigned k = 0; !done_j && k < num_bits; ++k) { + tbit n_bit = neg[j][n_idx + k]; + tbit d_bit = dst[i][t_idx + k]; + // neg does not contain dst. + done_j = (n_bit != BIT_x && n_bit != d_bit); + } } if (done_j) { result.push_back(&dst[i]); @@ -783,10 +795,29 @@ namespace datalog { // slow case udoc renamed_neg; - NOT_IMPLEMENTED_YET(); - // neg.rename(m_neg_cols, negt, m_t_cols, t, renamed_neg); + for (unsigned i = 0; i < neg.size(); ++i) { + doc_ref newD(dm, dm.allocateX()); + for (unsigned j = 0; j < m_neg_cols.size(); ++j) { + copy_column(*newD, neg[i], m_t_cols[j], m_neg_cols[j], t, n); + } + renamed_neg.push_back(newD.detach()); + } dst.subtract(t.get_dm(), renamed_neg); } + void copy_column( + doc& dst, doc const& src, + unsigned col_dst, unsigned col_src, + udoc_relation const& dstt, + udoc_relation const& srct) { + doc_manager& dm = dstt.get_dm(); + unsigned idx_dst = dstt.column_idx(col_dst); + unsigned idx_src = srct.column_idx(col_src); + unsigned num_bits = dstt.column_num_bits(col_dst); + SASSERT(num_bits == srct.column_num_bits(col_src)); + for (unsigned i = 0; i < num_bits; ++i) { + dm.set(dst, idx_dst+i, src[idx_src+i]); + } + } }; relation_intersection_filter_fn * udoc_plugin::mk_filter_by_negation_fn( From 5679cc7567618b345ea429ac96e3f3b2be6d2ad4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 19 Sep 2014 11:00:30 -0700 Subject: [PATCH 555/925] move doc code to rel, adding unit test Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/udoc_relation.cpp | 2 +- src/muz/rel/dl_relation_manager.cpp | 1 + src/muz/{ddnf => rel}/doc.cpp | 17 +- src/muz/{ddnf => rel}/doc.h | 7 +- src/muz/rel/rel_context.cpp | 2 + src/muz/{ddnf => rel}/tbv.cpp | 0 src/muz/{ddnf => rel}/tbv.h | 0 src/muz/rel/udoc_relation.cpp | 893 ++++++++++++++++++++++++++ src/muz/{ddnf => rel}/udoc_relation.h | 2 +- src/test/doc.cpp | 21 +- src/test/main.cpp | 1 + src/test/udoc_relation.cpp | 211 ++++++ 12 files changed, 1138 insertions(+), 19 deletions(-) rename src/muz/{ddnf => rel}/doc.cpp (97%) rename src/muz/{ddnf => rel}/doc.h (98%) rename src/muz/{ddnf => rel}/tbv.cpp (100%) rename src/muz/{ddnf => rel}/tbv.h (100%) create mode 100644 src/muz/rel/udoc_relation.cpp rename src/muz/{ddnf => rel}/udoc_relation.h (98%) create mode 100644 src/test/udoc_relation.cpp diff --git a/src/muz/ddnf/udoc_relation.cpp b/src/muz/ddnf/udoc_relation.cpp index 817909f14..dce993e87 100644 --- a/src/muz/ddnf/udoc_relation.cpp +++ b/src/muz/ddnf/udoc_relation.cpp @@ -146,7 +146,7 @@ namespace datalog { } void udoc_relation::display(std::ostream& out) const { - m_elems.display(dm, out); + m_elems.display(dm, out << "{") << "}"; } // ------------- diff --git a/src/muz/rel/dl_relation_manager.cpp b/src/muz/rel/dl_relation_manager.cpp index f5795df0c..a4c254272 100644 --- a/src/muz/rel/dl_relation_manager.cpp +++ b/src/muz/rel/dl_relation_manager.cpp @@ -206,6 +206,7 @@ namespace datalog { } void relation_manager::register_relation_plugin_impl(relation_plugin * plugin) { + TRACE("dl", tout << "register: " << plugin->get_name() << "\n";); m_relation_plugins.push_back(plugin); plugin->initialize(get_next_relation_fid(*plugin)); if (plugin->get_name() == get_context().default_relation()) { diff --git a/src/muz/ddnf/doc.cpp b/src/muz/rel/doc.cpp similarity index 97% rename from src/muz/ddnf/doc.cpp rename to src/muz/rel/doc.cpp index 4292aac05..cf27f3751 100644 --- a/src/muz/ddnf/doc.cpp +++ b/src/muz/rel/doc.cpp @@ -193,7 +193,6 @@ void doc_manager::set(doc& d, unsigned idx, tbit value) { bool doc_manager::merge( doc& d, unsigned lo, unsigned length, subset_ints& equalities, bit_vector const& discard_cols) { - std::cout << "merge\n"; for (unsigned i = 0; i < length; ++i) { unsigned idx = lo + i; if (!merge(d, lo + i, equalities, discard_cols)) return false; @@ -245,12 +244,10 @@ bool doc_manager::merge(doc& d, unsigned idx, subset_ints& equalities, bit_vecto do { if (!discard_cols.get(idx) && idx != root1) { tbv* t = tbvm().allocate(d.pos()); - std::cout << "insert " << t << "\n"; t->set(idx, BIT_0); t->set(root1, BIT_1); d.neg().insert(tbvm(), t); t = tbvm().allocate(d.pos()); - std::cout << "insert " << t << "\n"; t->set(idx, BIT_1); t->set(root1, BIT_0); d.neg().insert(tbvm(), t); @@ -262,6 +259,11 @@ bool doc_manager::merge(doc& d, unsigned idx, subset_ints& equalities, bit_vecto return true; } +bool doc_manager::intersect(doc const& A, doc const& B, doc& result) { + copy(result, A); + return set_and(result, B); +} + // // 1. If n = 0,1: can project directly. // 2. If tbv_i uses X in all positions with vars or constant where tbv is constant: can project directly. @@ -454,11 +456,8 @@ bool doc_manager::contains(doc const& a, doc const& b) const { std::ostream& doc_manager::display(std::ostream& out, doc const& b) const { m.display(out, b.pos()); if (b.neg().is_empty()) return out; - out << " \\ {"; - for (unsigned i = 0; i < b.neg().size(); ++i) { - m.display(out, b.neg()[i]); - if (i + 1 < b.neg().size()) out << ", "; - } - return out << "}"; + out << " \\ "; + b.neg().display(m, out); + return out; } diff --git a/src/muz/ddnf/doc.h b/src/muz/rel/doc.h similarity index 98% rename from src/muz/ddnf/doc.h rename to src/muz/rel/doc.h index e3d36019b..01772543a 100644 --- a/src/muz/ddnf/doc.h +++ b/src/muz/rel/doc.h @@ -59,7 +59,7 @@ public: bool is_full(doc const& src) const; bool set_and(doc& dst, doc const& src); bool fold_neg(doc& dst); - bool intersect(doc const& A, doc const& B, doc& result) const; + bool intersect(doc const& A, doc const& B, doc& result); void complement(doc const& src, ptr_vector& result); void subtract(doc const& A, doc const& B, ptr_vector& result); bool equals(doc const& a, doc const& b) const; @@ -101,12 +101,13 @@ public: } return false; } - std::ostream& display(M& m, std::ostream& out) const { + std::ostream& display(M const& m, std::ostream& out) const { + out << "{"; for (unsigned i = 0; i < size(); ++i) { m.display(out, *m_elems[i]); if (i + 1 < size()) out << ", "; } - return out << "\n"; + return out << "}"; } void push_back(T* t) { diff --git a/src/muz/rel/rel_context.cpp b/src/muz/rel/rel_context.cpp index 742930b5c..920a0924a 100644 --- a/src/muz/rel/rel_context.cpp +++ b/src/muz/rel/rel_context.cpp @@ -32,6 +32,7 @@ Revision History: #include"karr_relation.h" #include"dl_finite_product_relation.h" #include"product_set.h" +#include"udoc_relation.h" #include"dl_lazy_table.h" #include"dl_sparse_table.h" #include"dl_table.h" @@ -114,6 +115,7 @@ namespace datalog { rm.register_plugin(alloc(interval_relation_plugin, rm)); rm.register_plugin(alloc(karr_relation_plugin, rm)); rm.register_plugin(alloc(product_set_plugin, rm)); + rm.register_plugin(alloc(udoc_plugin, rm)); } rel_context::~rel_context() { diff --git a/src/muz/ddnf/tbv.cpp b/src/muz/rel/tbv.cpp similarity index 100% rename from src/muz/ddnf/tbv.cpp rename to src/muz/rel/tbv.cpp diff --git a/src/muz/ddnf/tbv.h b/src/muz/rel/tbv.h similarity index 100% rename from src/muz/ddnf/tbv.h rename to src/muz/rel/tbv.h diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp new file mode 100644 index 000000000..f1f919ec7 --- /dev/null +++ b/src/muz/rel/udoc_relation.cpp @@ -0,0 +1,893 @@ +#include "udoc_relation.h" +#include "dl_relation_manager.h" +#include "qe_util.h" +#include "ast_util.h" + +namespace datalog { + + udoc_relation::udoc_relation(udoc_plugin& p, relation_signature const& sig): + relation_base(p, sig), + dm(p.dm(p.num_signature_bits(sig))) { + unsigned column = 0; + for (unsigned i = 0; i < sig.size(); ++i) { + m_column_info.push_back(column); + column += p.num_sort_bits(sig[i]); + } + m_column_info.push_back(column); + } + udoc_relation::~udoc_relation() { + reset(); + } + void udoc_relation::reset() { + m_elems.reset(dm); + } + void udoc_relation::expand_column_vector(unsigned_vector& v, udoc_relation* other) const { + unsigned_vector orig; + orig.swap(v); + for (unsigned i = 0; i < orig.size(); ++i) { + unsigned col, limit; + if (orig[i] < get_num_cols()) { + col = column_idx(orig[i]); + limit = col + column_num_bits(orig[i]); + } else { + unsigned idx = orig[i] - get_num_cols(); + col = get_num_bits() + other->column_idx(idx); + limit = col + other->column_num_bits(idx); + } + for (; col < limit; ++col) { + v.push_back(col); + } + } + } + + doc* udoc_relation::fact2doc(const relation_fact & f) const { + doc* d = dm.allocate0(); + for (unsigned i = 0; i < f.size(); ++i) { + unsigned bv_size; + rational val; + VERIFY(get_plugin().is_numeral(f[i], val, bv_size)); + SASSERT(bv_size == column_num_bits(i)); + unsigned lo = column_idx(i); + unsigned hi = column_idx(i + 1); + d->pos().set(val, hi, lo); + } + return d; + } + void udoc_relation::add_fact(const relation_fact & f) { + doc* d = fact2doc(f); + m_elems.insert(dm, d); + } + bool udoc_relation::contains_fact(const relation_fact & f) const { + doc_ref d(dm, fact2doc(f)); + return m_elems.contains(dm, *d); + } + udoc_relation * udoc_relation::clone() const { + udoc_relation* result = udoc_plugin::get(get_plugin().mk_empty(get_signature())); + for (unsigned i = 0; i < m_elems.size(); ++i) { + result->m_elems.push_back(dm.allocate(m_elems[i])); + } + return result; + } + udoc_relation * udoc_relation::complement(func_decl* f) const { + udoc_relation* result = udoc_plugin::get(get_plugin().mk_empty(get_signature())); + m_elems.complement(dm, result->m_elems); + return result; + } + void udoc_relation::to_formula(expr_ref& fml) const { + ast_manager& m = fml.get_manager(); + expr_ref_vector disj(m); + for (unsigned i = 0; i < m_elems.size(); ++i) { + disj.push_back(to_formula(m_elems[i])); + } + fml = mk_or(m, disj.size(), disj.c_ptr()); + } + expr_ref udoc_relation::to_formula(doc const& d) const { + ast_manager& m = get_plugin().get_ast_manager(); + expr_ref result(m); + expr_ref_vector conjs(m); + conjs.push_back(to_formula(d.pos())); + for (unsigned i = 0; i < d.neg().size(); ++i) { + conjs.push_back(m.mk_not(to_formula(d.neg()[i]))); + } + result = mk_and(m, conjs.size(), conjs.c_ptr()); + return result; + } + expr_ref udoc_relation::to_formula(tbv const& t) const { + udoc_plugin& p = get_plugin(); + ast_manager& m = p.get_ast_manager(); + expr_ref result(m); + expr_ref_vector conjs(m); + for (unsigned i = 0; i < get_num_cols(); ++i) { + var_ref v(m); + v = m.mk_var(i, get_signature()[i]); + unsigned lo = column_idx(i); + unsigned hi = column_idx(i+1); + rational r(0); + unsigned lo0 = lo; + bool is_x = true; + for (unsigned j = lo; j < hi; ++j) { + switch(t[j]) { + case BIT_0: + if (is_x) is_x = false, lo0 = j, r.reset(); + break; + case BIT_1: + if (is_x) is_x = false, lo0 = j, r.reset(); + r += rational::power_of_two(j - lo0); + break; + case BIT_x: + if (!is_x) { + conjs.push_back(m.mk_eq(p.bv.mk_extract(j-1,lo0,v), + p.bv.mk_numeral(r,j-lo0))); + } + is_x = true; + break; + default: + UNREACHABLE(); + } + } + if (!is_x) { + expr_ref num(m); + if (lo0 == lo) { + num = p.mk_numeral(r, get_signature()[i]); + conjs.push_back(m.mk_eq(v, num)); + } + else { + num = p.bv.mk_numeral(r, hi-lo0); + conjs.push_back(m.mk_eq(p.bv.mk_extract(hi-1,lo0,v), num)); + } + } + } + result = mk_and(m, conjs.size(), conjs.c_ptr()); + return result; + } + + udoc_plugin& udoc_relation::get_plugin() const { + return static_cast(relation_base::get_plugin()); + } + + void udoc_relation::display(std::ostream& out) const { + m_elems.display(dm, out); + } + + // ------------- + + udoc_plugin::udoc_plugin(relation_manager& rm): + relation_plugin(udoc_plugin::get_name(), rm), + m(rm.get_context().get_manager()), + bv(m), + dl(m) { + } + udoc_plugin::~udoc_plugin() { + u_map::iterator it = m_dms.begin(), end = m_dms.end(); + for (; it != end; ++it) { + dealloc(it->m_value); + } + } + udoc_relation& udoc_plugin::get(relation_base& r) { + return dynamic_cast(r); + } + udoc_relation* udoc_plugin::get(relation_base* r) { + return r?dynamic_cast(r):0; + } + udoc_relation const & udoc_plugin::get(relation_base const& r) { + return dynamic_cast(r); + } + + doc_manager& udoc_plugin::dm(relation_signature const& sig) { + return dm(num_signature_bits(sig)); + } + + doc_manager& udoc_plugin::dm(unsigned n) { + doc_manager* r; + if (!m_dms.find(n, r)) { + r = alloc(doc_manager, n); + m_dms.insert(n, r); + } + return *r; + } + expr* udoc_plugin::mk_numeral(rational const& r, sort* s) { + if (bv.is_bv_sort(s)) { + return bv.mk_numeral(r, s); + } + SASSERT(dl.is_finite_sort(s)); + return dl.mk_numeral(r.get_uint64(), s); + } + bool udoc_plugin::is_numeral(expr* e, rational& r, unsigned& num_bits) { + if (bv.is_numeral(e, r, num_bits)) return true; + uint64 n, sz; + ast_manager& m = get_ast_manager(); + if (dl.is_numeral(e, n) && dl.try_get_size(m.get_sort(e), sz)) { + num_bits = 0; + while (sz > 0) ++num_bits, sz = sz/2; + r = rational(n, rational::ui64()); + return true; + } + return false; + } + unsigned udoc_plugin::num_sort_bits(sort* s) const { + unsigned num_bits = 0; + if (bv.is_bv_sort(s)) + return bv.get_bv_size(s); + uint64 sz; + if (dl.try_get_size(s, sz)) { + while (sz > 0) ++num_bits, sz /= 2; + return num_bits; + } + UNREACHABLE(); + return 0; + } + unsigned udoc_plugin::num_signature_bits(relation_signature const& sig) { + unsigned result = 0; + for (unsigned i = 0; i < sig.size(); ++i) { + result += num_sort_bits(sig[i]); + } + return result; + } + + bool udoc_plugin::is_finite_sort(sort* s) const { + return bv.is_bv_sort(s) || dl.is_finite_sort(s); + } + + + bool udoc_plugin::can_handle_signature(const relation_signature & sig) { + for (unsigned i = 0; i < sig.size(); ++i) { + if (!is_finite_sort(sig[i])) + return false; + } + return true; + } + relation_base * udoc_plugin::mk_empty(const relation_signature & sig) { + return alloc(udoc_relation, *this, sig); + } + relation_base * udoc_plugin::mk_full(func_decl* p, const relation_signature & s) { + udoc_relation* r = get(mk_empty(s)); + r->get_udoc().push_back(dm(s).allocateX()); + return r; + } + class udoc_plugin::join_fn : public convenient_relation_join_fn { + doc_manager& dm; + doc_manager& dm1; + doc_manager& dm2; + public: + join_fn(udoc_plugin& p, udoc_relation const& t1, udoc_relation const& t2, unsigned col_cnt, + const unsigned * cols1, const unsigned * cols2) + : convenient_relation_join_fn(t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2), + dm(p.dm(get_result_signature())), + dm1(t1.get_dm()), + dm2(t2.get_dm()) { + t1.expand_column_vector(m_cols1); + t2.expand_column_vector(m_cols2); + } + + void join(doc const& d1, doc const& d2, udoc& result) { + doc* d = dm.allocateX(); + tbv& pos = d->pos(); + utbv& neg = d->neg(); + unsigned mid = dm1.num_tbits(); + unsigned hi = dm.num_tbits(); + pos.set(d1.pos(), mid-1, 0); + pos.set(d2.pos(), hi-1, mid); + // first fix bits + for (unsigned i = 0; i < m_cols1.size(); ++i) { + unsigned idx1 = m_cols1[i]; + unsigned idx2 = mid + m_cols2[i]; + tbit v1 = pos[idx1]; + tbit v2 = pos[idx2]; + + if (v1 == BIT_x) { + if (v2 != BIT_x) + pos.set(idx1, v2); + } else if (v2 == BIT_x) { + pos.set(idx2, v1); + } else if (v1 != v2) { + dm.deallocate(d); + // columns don't match + return; + } + } + // fix equality of don't care columns + for (unsigned i = 0; i < m_cols1.size(); ++i) { + unsigned idx1 = m_cols1[i]; + unsigned idx2 = mid + m_cols2[i]; + unsigned v1 = pos[idx1]; + unsigned v2 = pos[idx2]; + + if (v1 == BIT_x && v2 == BIT_x) { + // add to subtracted TBVs: 1xx0 and 0xx1 + tbv* r = dm.tbvm().allocate(pos); + r->set(idx1, BIT_0); + r->set(idx2, BIT_1); + neg.push_back(r); + + r = dm.tbvm().allocate(pos); + r->set(idx1, BIT_1); + r->set(idx2, BIT_0); + neg.push_back(r); + } + } + + // handle subtracted TBVs: 1010 -> 1010xxx + for (unsigned i = 0; i < d1.neg().size(); ++i) { + tbv* t = dm.tbvm().allocate(); + t->set(d1.neg()[i], mid-1, 0); + t->set(d2.pos(), hi - 1, mid); + neg.push_back(t); + } + for (unsigned i = 0; i < d2.neg().size(); ++i) { + tbv* t = dm.tbvm().allocate(); + t->set(d1.pos(), mid-1, 0); + t->set(d2.neg()[i], hi - 1, mid); + neg.push_back(t); + } + result.insert(dm, d); + } + + virtual relation_base * operator()(const relation_base & _r1, const relation_base & _r2) { + udoc_relation const& r1 = get(_r1); + udoc_relation const& r2 = get(_r2); + TRACE("dl", r1.display(tout << "r1:\n"); r2.display(tout << "r2:\n");); + udoc_plugin& p = r1.get_plugin(); + relation_signature const& sig = get_result_signature(); + udoc_relation * result = alloc(udoc_relation, p, sig); + udoc const& d1 = r1.get_udoc(); + udoc const& d2 = r2.get_udoc(); + udoc& r = result->get_udoc(); + for (unsigned i = 0; i < d1.size(); ++i) { + for (unsigned j = 0; j < d2.size(); ++j) { + join(d1[i], d2[j], r); + } + } + TRACE("dl", result->display(tout << "result:\n");); + return result; + } + }; + relation_join_fn * udoc_plugin::mk_join_fn( + const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { + if (!check_kind(t1) || !check_kind(t2)) { + return 0; + } + return alloc(join_fn, *this, get(t1), get(t2), col_cnt, cols1, cols2); + } + class udoc_plugin::project_fn : public convenient_relation_project_fn { + svector m_to_delete; + public: + project_fn(udoc_relation const & t, unsigned removed_col_cnt, const unsigned * removed_cols) + : convenient_relation_project_fn(t.get_signature(), removed_col_cnt, removed_cols) { + t.expand_column_vector(m_removed_cols); + unsigned n = t.get_dm().num_tbits(); + m_to_delete.resize(n, false); + for (unsigned i = 0; i < m_removed_cols.size(); ++i) { + m_to_delete[m_removed_cols[i]] = true; + } + } + + virtual relation_base * operator()(const relation_base & tb) { + TRACE("dl", tb.display(tout << "src:\n");); + udoc_relation const& t = get(tb); + udoc_plugin& p = t.get_plugin(); + udoc_relation* r = udoc_plugin::get(p.mk_empty(get_result_signature())); + doc_manager& dm1 = t.get_dm(); + doc_manager& dm2 = r->get_dm(); + doc_ref d2(dm2); + udoc const& ud1 = t.get_udoc(); + udoc& ud2 = r->get_udoc(); + for (unsigned i = 0; i < ud1.size(); ++i) { + d2 = dm1.project(dm2, m_to_delete.size(), m_to_delete.c_ptr(), ud1[i]); + ud2.push_back(d2.detach()); + } + TRACE("dl", tout << "final size: " << r->get_size_estimate_rows() << '\n';); + return r; + } + }; + + + relation_transformer_fn * udoc_plugin::mk_project_fn( + const relation_base & t, unsigned col_cnt, + const unsigned * removed_cols) { + if (!check_kind(t)) + return 0; + return alloc(project_fn, get(t), col_cnt, removed_cols); + } + + class udoc_plugin::rename_fn : public convenient_relation_rename_fn { + unsigned_vector m_permutation; + public: + rename_fn(udoc_relation const& t, unsigned cycle_len, const unsigned * cycle) + : convenient_relation_rename_fn(t.get_signature(), cycle_len, cycle) { + udoc_plugin& p = t.get_plugin(); + for (unsigned i = 0; i < t.get_num_bits(); ++i) { + m_permutation.push_back(i); + } + unsigned len = t.column_num_bits(cycle[0]); + for (unsigned i = 0; i < cycle_len; ++i) { + unsigned j = (i + 1)%cycle_len; + unsigned col1 = cycle[i]; + unsigned col2 = cycle[j]; + unsigned lo1 = t.column_idx(col1); + unsigned lo2 = t.column_idx(col2); + for (unsigned k = 0; k < len; ++k) { + m_permutation[k + lo1] = k + lo2; + } + SASSERT(t.column_num_bits(col1) == t.column_num_bits(col2)); + } + } + + virtual relation_base * operator()(const relation_base & _r) { + udoc_relation const& r = get(_r); + TRACE("dl", r.display(tout << "r:\n");); + udoc_plugin& p = r.get_plugin(); + relation_signature const& sig = get_result_signature(); + udoc_relation* result = alloc(udoc_relation, p, sig); + udoc const& src = r.get_udoc(); + udoc& dst = result->get_udoc(); + doc_manager& dm = r.get_dm(); + for (unsigned i = 0; i < src.size(); ++i) { + dst.push_back(dm.allocate(src[i], m_permutation.c_ptr())); + } + TRACE("dl", result->display(tout << "result:\n");); + return result; + } + }; + relation_transformer_fn * udoc_plugin::mk_rename_fn( + const relation_base & r, + unsigned cycle_len, const unsigned * permutation_cycle) { + if (check_kind(r)) { + return alloc(rename_fn, get(r), cycle_len, permutation_cycle); + } + else { + return 0; + } + } + class udoc_plugin::union_fn : public relation_union_fn { + public: + union_fn() {} + + virtual void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) { + TRACE("dl", _r.display(tout << "dst:\n"); _src.display(tout << "src:\n");); + udoc_relation& r = get(_r); + udoc_relation const& src = get(_src); + udoc_relation* d = get(_delta); + doc_manager& dm = r.get_dm(); + udoc* d1 = 0; + if (d) d1 = &d->get_udoc(); + if (d1) d1->reset(dm); + r.get_plugin().mk_union(dm, r.get_udoc(), src.get_udoc(), d1); + TRACE("dl", _r.display(tout << "dst':\n");); + } + }; + void udoc_plugin::mk_union(doc_manager& dm, udoc& dst, udoc const& src, udoc* delta) { + for (unsigned i = 0; i < src.size(); ++i) { + doc* d = dm.allocate(src[i]); + if (dst.insert(dm, d)) { + if (delta) { + delta->insert(dm, dm.allocate(src[i])); + } + } + } + } + relation_union_fn * udoc_plugin::mk_union_fn( + const relation_base & tgt, const relation_base & src, + const relation_base * delta) { + if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) { + return 0; + } + return alloc(union_fn); + } + relation_union_fn * udoc_plugin::mk_widen_fn( + const relation_base & tgt, const relation_base & src, + const relation_base * delta) { + return mk_union_fn(tgt, src, delta); + } + + class udoc_plugin::filter_identical_fn : public relation_mutator_fn { + unsigned_vector m_cols; + unsigned m_size; + bit_vector m_empty_bv; + union_find_default_ctx union_ctx; + union_find<> m_equalities; + public: + filter_identical_fn(const relation_base & _r, unsigned col_cnt, const unsigned *identical_cols) + : m_cols(col_cnt), m_equalities(union_ctx) { + udoc_relation const& r = get(_r); + doc_manager& dm = r.get_dm(); + unsigned num_bits = dm.num_tbits(); + m_size = r.column_num_bits(identical_cols[0]); + m_empty_bv.resize(r.get_num_bits(), false); + for (unsigned i = 0; i < col_cnt; ++i) { + m_cols[i] = r.column_idx(identical_cols[i]); + } + for (unsigned i = 0, e = m_empty_bv.size(); i < e; ++i) { + m_equalities.mk_var(); + } + for (unsigned i = 1; i < col_cnt; ++i) { + for (unsigned j = 0; j < m_size; ++j) { + m_equalities.merge(m_cols[0]+j ,m_cols[i]+j); + } + } + } + + virtual void operator()(relation_base & _r) { + udoc_relation& r = get(_r); + udoc& d = r.get_udoc(); + doc_manager& dm = r.get_dm(); + d.merge(dm, m_cols[0], m_size, m_equalities, m_empty_bv); + TRACE("dl", tout << "final size: " << r.get_size_estimate_rows() << '\n';); + } + }; + relation_mutator_fn * udoc_plugin::mk_filter_identical_fn( + const relation_base & t, unsigned col_cnt, const unsigned * identical_cols) { + return check_kind(t)?alloc(filter_identical_fn, t, col_cnt, identical_cols):0; + } + class udoc_plugin::filter_equal_fn : public relation_mutator_fn { + doc_manager& dm; + doc* m_filter; + public: + filter_equal_fn(udoc_plugin& p, const udoc_relation & t, const relation_element val, unsigned col): + dm(p.dm(t.get_signature())) { + rational r; + unsigned num_bits; + VERIFY(p.is_numeral(val, r, num_bits)); + m_filter = dm.allocateX(); + unsigned lo = t.column_idx(col); + unsigned hi = t.column_idx(col+1); + SASSERT(num_bits == hi - lo); + m_filter->pos().set(r, hi-1, lo); + } + virtual ~filter_equal_fn() { + dm.deallocate(m_filter); + } + virtual void operator()(relation_base & tb) { + udoc_relation & t = get(tb); + t.get_udoc().intersect(dm, *m_filter); + } + }; + relation_mutator_fn * udoc_plugin::mk_filter_equal_fn( + const relation_base & t, const relation_element & value, unsigned col) { + if (!check_kind(t)) + return 0; + return alloc(filter_equal_fn, *this, get(t), value, col); + } + + bool udoc_relation::is_guard(unsigned n, expr* const* gs) const { + for (unsigned i = 0; i < n; ++i) { + if (!is_guard(gs[i])) return false; + } + return true; + } + bool udoc_relation::is_guard(expr* g) const { + udoc_plugin& p = get_plugin(); + ast_manager& m = p.get_ast_manager(); + bv_util& bv = p.bv; + expr* e1, *e2, *e3; + unsigned hi, lo; + if (m.is_and(g) || m.is_or(g) || m.is_not(g) || m.is_true(g) || m.is_false(g)) { + return is_guard(to_app(g)->get_num_args(), to_app(g)->get_args()); + } + if (m.is_eq(g, e1, e2) && bv.is_bv(e1)) { + if (is_var(e1) && is_ground(e2)) return true; + if (is_var(e2) && is_ground(e1)) return true; + if (bv.is_extract(e1, lo, hi, e3) && is_var(e3) && is_ground(e2)) return true; + if (bv.is_extract(e2, lo, hi, e3) && is_var(e3) && is_ground(e1)) return true; + } + if (is_var(g)) { + return true; + } + return false; + } + + void udoc_relation::extract_guard(expr* cond, expr_ref& guard, expr_ref& rest) const { + rest.reset(); + ast_manager& m = get_plugin().get_ast_manager(); + expr_ref_vector conds(m), guards(m), rests(m); + conds.push_back(cond); + qe::flatten_and(conds); + for (unsigned i = 0; i < conds.size(); ++i) { + expr* g = conds[i].get(); + if (is_guard(g)) { + guards.push_back(g); + } + else { + rests.push_back(g); + } + } + guard = mk_and(m, guards.size(), guards.c_ptr()); + rest = mk_and(m, rests.size(), rests.c_ptr()); + } + void udoc_relation::compile_guard(expr* g, udoc& d, bit_vector const& discard_cols) const { + d.reset(dm); + d.push_back(dm.allocateX()); + apply_guard(g, d, discard_cols); + } + void udoc_relation::apply_guard(expr* g, udoc& result, bit_vector const& discard_cols) const { + // datastructure to store equalities with columns that will be projected out + union_find_default_ctx union_ctx; + subset_ints equalities(union_ctx); + for (unsigned i = 0, e = discard_cols.size(); i < e; ++i) { + equalities.mk_var(); + } + apply_guard(g, result, equalities, discard_cols); + } + bool udoc_relation::apply_eq(expr* g, udoc& result, var* v, unsigned hi, unsigned lo, expr* c) const { + udoc_plugin& p = get_plugin(); + unsigned num_bits; + rational r; + unsigned idx = v->get_idx(); + unsigned col = column_idx(idx); + lo += col; + hi += col; + if (p.is_numeral(c, r, num_bits)) { + doc_ref d(dm, dm.allocateX()); + d->pos().set(r, hi, lo); + result.intersect(dm, *d); + return true; + } + // other cases? + return false; + } + + void udoc_relation::apply_guard( + expr* g, udoc& result, subset_ints& equalities, bit_vector const& discard_cols) const { + ast_manager& m = get_plugin().get_ast_manager(); + bv_util& bv = get_plugin().bv; + expr* e1, *e2; + if (result.is_empty()) { + } + else if (m.is_and(g)) { + for (unsigned i = 0; !result.is_empty() && i < to_app(g)->get_num_args(); ++i) { + apply_guard(to_app(g)->get_arg(i), result, equalities, discard_cols); + } + } + else if (m.is_not(g, e1)) { + // REVIEW: (not (= x y)) should not cause + // the equivalence class to collapse. + // It seems the current organization with fix_eq_bits + // will merge the equivalence class as a side-effect. + udoc sub; + sub.push_back(dm.allocateX()); + apply_guard(e1, sub, equalities, discard_cols); + result.subtract(dm, sub); + } + else if (m.is_or(g)) { + udoc sub; + sub.push_back(dm.allocateX()); + for (unsigned i = 0; !sub.is_empty() && i < to_app(g)->get_num_args(); ++i) { + expr_ref arg(m); + arg = mk_not(m, to_app(g)->get_arg(i)); + apply_guard(arg, result, equalities, discard_cols); + } + result.subtract(dm, sub); + } + else if (m.is_true(g)) { + } + else if (m.is_false(g)) { + result.reset(dm); + } + else if (is_var(g)) { + SASSERT(m.is_bool(g)); + unsigned v = to_var(g)->get_idx(); + unsigned idx = column_idx(v); + doc_ref d(dm); + d = dm.allocateX(); + dm.set(*d, idx, BIT_1); + result.intersect(dm, *d); + } + else if (m.is_eq(g, e1, e2) && bv.is_bv(e1)) { + unsigned hi, lo; + expr* e3; + if (is_var(e1) && is_ground(e2) && + apply_eq(g, result, to_var(e1), bv.get_bv_size(e1)-1, 0, e2)) { + } + else if (is_var(e2) && is_ground(e1) && + apply_eq(g, result, to_var(e2), bv.get_bv_size(e2)-1, 0, e1)) { + } + else if (bv.is_extract(e1, lo, hi, e3) && is_var(e3) && is_ground(e2) && + apply_eq(g, result, to_var(e3), hi, lo, e2)) { + } + else if (bv.is_extract(e2, lo, hi, e3) && is_var(e3) && is_ground(e1) && + apply_eq(g, result, to_var(e3), hi, lo, e1)) { + } + else if (is_var(e1) && is_var(e2)) { + var* v1 = to_var(e1); + var* v2 = to_var(e2); + unsigned idx1 = column_idx(v1->get_idx()); + unsigned idx2 = column_idx(v2->get_idx()); + unsigned length = column_num_bits(v1->get_idx()); + result.merge(dm, idx1, idx2, length, discard_cols); + } + else { + goto failure_case; + } + } + else { + failure_case: + std::ostringstream strm; + strm << "Guard expression is not handled" << mk_pp(g, m); + throw default_exception(strm.str()); + } + } + + class udoc_plugin::filter_interpreted_fn : public relation_mutator_fn { + doc_manager& dm; + expr_ref m_condition; + udoc m_udoc; + bit_vector m_empty_bv; + public: + filter_interpreted_fn(const udoc_relation & t, ast_manager& m, app *condition) : + dm(t.get_dm()), + m_condition(m) { + m_empty_bv.resize(t.get_num_bits(), false); + expr_ref guard(m), rest(m); + t.extract_guard(condition, guard, m_condition); + t.compile_guard(guard, m_udoc, m_empty_bv); + if (m.is_true(m_condition)) { + m_condition = 0; + } + TRACE("dl", + tout << "condition: " << mk_pp(condition, m) << "\n"; + tout << m_condition << "\n"; m_udoc.display(dm, tout) << "\n";); + } + + virtual ~filter_interpreted_fn() { + m_udoc.reset(dm); + } + + virtual void operator()(relation_base & tb) { + udoc_relation & t = get(tb); + udoc& u = t.get_udoc(); + u.intersect(dm, m_udoc); + if (m_condition && !u.is_empty()) { + t.apply_guard(m_condition, u, m_empty_bv); + } + TRACE("dl", tout << "final size: " << t.get_size_estimate_rows() << '\n';); + } + }; + relation_mutator_fn * udoc_plugin::mk_filter_interpreted_fn(const relation_base & t, app * condition) { + return check_kind(t)?alloc(filter_interpreted_fn, get(t), get_ast_manager(), condition):0; + } + + class udoc_plugin::negation_filter_fn : public relation_intersection_filter_fn { + const unsigned_vector m_t_cols; + const unsigned_vector m_neg_cols; + public: + negation_filter_fn(const udoc_relation & r, const udoc_relation & neg, unsigned joined_col_cnt, + const unsigned *t_cols, const unsigned *neg_cols) + : m_t_cols(joined_col_cnt, t_cols), m_neg_cols(joined_col_cnt, neg_cols) { + SASSERT(joined_col_cnt > 0); + } + + virtual void operator()(relation_base& tb, const relation_base& negb) { + udoc_relation& t = get(tb); + udoc_relation const& n = get(negb); + udoc & dst = t.get_udoc(); + udoc const & neg = n.get_udoc(); + doc_manager& dm = t.get_dm(); + udoc result; + for (unsigned i = 0; i < dst.size(); ++i) { + bool done_i = false; + for (unsigned j = 0; !done_i && j < neg.size(); ++j) { + bool done_j = false; + for (unsigned c = 0; !done_i && !done_j && c < m_t_cols.size(); ++c) { + unsigned t_col = m_t_cols[c]; + unsigned n_col = m_neg_cols[c]; + unsigned num_bits = t.column_num_bits(t_col); + SASSERT(num_bits == n.column_num_bits(n_col)); + unsigned t_idx = t.column_idx(t_col); + unsigned n_idx = n.column_idx(n_col); + for (unsigned k = 0; !done_j && k < num_bits; ++k) { + tbit n_bit = neg[j][n_idx + k]; + tbit d_bit = dst[i][t_idx + k]; + // neg does not contain dst. + done_j = (n_bit != BIT_x && n_bit != d_bit); + } + } + if (done_j) { + result.push_back(&dst[i]); + } + else { + dm.deallocate(&dst[i]); + done_i = true; + } + } + } + std::swap(dst, result); + if (dst.is_empty()) { + return; + } + + // slow case + udoc renamed_neg; + for (unsigned i = 0; i < neg.size(); ++i) { + doc_ref newD(dm, dm.allocateX()); + for (unsigned j = 0; j < m_neg_cols.size(); ++j) { + copy_column(*newD, neg[i], m_t_cols[j], m_neg_cols[j], t, n); + } + renamed_neg.push_back(newD.detach()); + } + dst.subtract(t.get_dm(), renamed_neg); + } + void copy_column( + doc& dst, doc const& src, + unsigned col_dst, unsigned col_src, + udoc_relation const& dstt, + udoc_relation const& srct) { + doc_manager& dm = dstt.get_dm(); + unsigned idx_dst = dstt.column_idx(col_dst); + unsigned idx_src = srct.column_idx(col_src); + unsigned num_bits = dstt.column_num_bits(col_dst); + SASSERT(num_bits == srct.column_num_bits(col_src)); + for (unsigned i = 0; i < num_bits; ++i) { + dm.set(dst, idx_dst+i, src[idx_src+i]); + } + } + }; + + relation_intersection_filter_fn * udoc_plugin::mk_filter_by_negation_fn( + const relation_base& t, + const relation_base& neg, unsigned joined_col_cnt, const unsigned *t_cols, + const unsigned *negated_cols) { + if (!check_kind(t) || !check_kind(neg)) + return 0; + return alloc(negation_filter_fn, get(t), get(neg), joined_col_cnt, t_cols, negated_cols); + } + + class udoc_plugin::filter_proj_fn : public convenient_relation_project_fn { + doc_manager& dm; + expr_ref m_condition; + udoc m_udoc; + bit_vector m_col_list; // map: col idx -> bool (whether the column is to be removed) + svector m_to_delete; // same + public: + filter_proj_fn(const udoc_relation & t, ast_manager& m, app *condition, + unsigned col_cnt, const unsigned * removed_cols) : + convenient_relation_project_fn(t.get_signature(), col_cnt, removed_cols), + dm(t.get_dm()), + m_condition(m) { + t.expand_column_vector(m_removed_cols); + m_col_list.resize(t.get_num_bits(), false); + for (unsigned i = 0; i < m_removed_cols.size(); ++i) { + m_col_list.set(m_removed_cols[i], true); + } + m_to_delete.resize(m_removed_cols.size(), false); + for (unsigned i = 0; i < m_removed_cols.size(); ++i) { + m_to_delete[m_removed_cols[i]] = true; + } + expr_ref guard(m), rest(m); + t.extract_guard(condition, guard, m_condition); + t.compile_guard(guard, m_udoc, m_col_list); + if (m.is_true(m_condition)) { + m_condition = 0; + } + } + + virtual ~filter_proj_fn() { + m_udoc.reset(dm); + } + virtual relation_base* operator()(const relation_base & tb) { + udoc_relation const & t = get(tb); + udoc const& u1 = t.get_udoc(); + doc_manager& dm = t.get_dm(); + udoc u2; + u2.copy(dm, u1); + u2.intersect(dm, m_udoc); + if (m_condition && !u2.is_empty()) { + t.apply_guard(m_condition, u2, m_col_list); + } + udoc_relation* r = get(t.get_plugin().mk_empty(get_result_signature())); + doc_manager& dm2 = r->get_dm(); + for (unsigned i = 0; i < u2.size(); ++i) { + doc* d = dm.project(dm2, m_to_delete.size(), m_to_delete.c_ptr(), u2[i]); + r->get_udoc().insert(dm2, d); + } + u2.reset(dm); + return r; + } + }; + relation_transformer_fn * udoc_plugin::mk_filter_interpreted_and_project_fn( + const relation_base & t, app * condition, + unsigned removed_col_cnt, const unsigned * removed_cols) { + return check_kind(t)?alloc(filter_proj_fn, get(t), get_ast_manager(), condition, removed_col_cnt, removed_cols):0; + } + + +} diff --git a/src/muz/ddnf/udoc_relation.h b/src/muz/rel/udoc_relation.h similarity index 98% rename from src/muz/ddnf/udoc_relation.h rename to src/muz/rel/udoc_relation.h index 5205a9547..4befa228a 100644 --- a/src/muz/ddnf/udoc_relation.h +++ b/src/muz/rel/udoc_relation.h @@ -121,7 +121,7 @@ namespace datalog { virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, unsigned col); virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); - virtual relation_intersection_filter_fn * udoc_plugin::mk_filter_by_negation_fn( + virtual relation_intersection_filter_fn * mk_filter_by_negation_fn( const relation_base& t, const relation_base& neg, unsigned joined_col_cnt, const unsigned *t_cols, const unsigned *negated_cols); diff --git a/src/test/doc.cpp b/src/test/doc.cpp index 2747ef35d..890ce4204 100644 --- a/src/test/doc.cpp +++ b/src/test/doc.cpp @@ -224,7 +224,7 @@ class test_doc_cls { void test_merge(unsigned num_clauses) { doc_ref d(dm, dm.allocateX()); - expr_ref_vector fmls(m); + expr_ref_vector fmls(m), eqs(m); th_rewriter rw(m); unsigned N = m_vars.size(); expr_ref fml1(m), fml2(m), fml3(m), tmp1(m), tmp2(m), fml(m); @@ -251,15 +251,26 @@ class test_doc_cls { for (unsigned i = 0; i < N; ++i) { if (to_merge[i] && i != lo) { equalities.merge(i, lo); + eqs.push_back(m.mk_eq(m_vars[i].get(), m_vars[lo].get())); } } - fml1 = to_formula(*d, dm, to_delete.c_ptr()); + eqs.push_back(to_formula(*d, dm, to_delete.c_ptr())); + fml1 = mk_and(m, eqs.size(), eqs.c_ptr()); if (dm.merge(*d, lo, 1, equalities, discard_cols)) { fml2 = to_formula(*d, dm, to_delete.c_ptr()); - std::cout << fml1 << "\n"; - std::cout << fml2 << "\n"; } - // ... + else { + fml2 = m.mk_false(); + } + rw(fml1); + rw(fml2); + smt_params fp; + smt::kernel solver(m, fp); + TRACE("doc", tout << "manual project:\n" << fml1 << "\nautomatic project: \n" << fml2 << "\n";); + fml = m.mk_not(m.mk_eq(fml1, fml2)); + solver.assert_expr(fml); + lbool res = solver.check(); + SASSERT(res == l_false); } public: diff --git a/src/test/main.cpp b/src/test/main.cpp index f613402b8..d5608a7d4 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -143,6 +143,7 @@ int main(int argc, char ** argv) { TST(fixed_bit_vector); TST(tbv); TST(doc); + TST(udoc_relation); TST(string_buffer); TST(map); TST(diff_logic); diff --git a/src/test/udoc_relation.cpp b/src/test/udoc_relation.cpp new file mode 100644 index 000000000..2c5540fe2 --- /dev/null +++ b/src/test/udoc_relation.cpp @@ -0,0 +1,211 @@ +#include "udoc_relation.h" +#include "trace.h" +#include "vector.h" +#include "ast.h" +#include "ast_pp.h" +#include "reg_decl_plugins.h" +#include "sorting_network.h" +#include "smt_kernel.h" +#include "model_smt2_pp.h" +#include "smt_params.h" +#include "ast_util.h" +#include "expr_safe_replace.h" +#include "th_rewriter.h" +#include "dl_relation_manager.h" +#include "dl_register_engine.h" +#include "rel_context.h" +#include "bv_decl_plugin.h" + +class udoc_tester { + typedef datalog::relation_base relation_base; + typedef datalog::udoc_relation udoc_relation; + typedef datalog::udoc_plugin udoc_plugin; + typedef datalog::relation_signature relation_signature; + + struct init { + init(ast_manager& m) { + reg_decl_plugins(m); + } + }; + random_gen m_rand; + ast_manager m; + init m_init; + bv_util bv; + expr_ref_vector m_vars; + smt_params m_smt_params; + datalog::register_engine m_reg; + datalog::context m_ctx; + datalog::rel_context rc; + udoc_plugin& p; +public: + udoc_tester(): m_init(m), bv(m), m_vars(m), m_ctx(m, m_reg, m_smt_params), rc(m_ctx), + p(dynamic_cast(*rc.get_rmanager().get_relation_plugin(symbol("doc")))) + { + } + + udoc_relation* mk_empty(relation_signature const& sig) { + SASSERT(p.can_handle_signature(sig)); + relation_base* empty = p.mk_empty(sig); + return dynamic_cast(empty); + } + + udoc_relation* mk_full(relation_signature const& sig) { + func_decl_ref fn(m); + fn = m.mk_func_decl(symbol("full"), sig.size(), sig.c_ptr(), m.mk_bool_sort()); + relation_base* full = p.mk_full(fn, sig); + return dynamic_cast(full); + } + + void test1() { + datalog::relation_signature sig; + sig.push_back(bv.mk_sort(12)); + sig.push_back(bv.mk_sort(6)); + sig.push_back(bv.mk_sort(12)); + + datalog::relation_fact fact1(m), fact2(m), fact3(m); + fact1.push_back(bv.mk_numeral(rational(1), 12)); + fact1.push_back(bv.mk_numeral(rational(6), 6)); + fact1.push_back(bv.mk_numeral(rational(56), 12)); + fact2.push_back(bv.mk_numeral(rational(8), 12)); + fact2.push_back(bv.mk_numeral(rational(16), 6)); + fact2.push_back(bv.mk_numeral(rational(32), 12)); + fact3.push_back(bv.mk_numeral(rational(32), 12)); + fact3.push_back(bv.mk_numeral(rational(16), 6)); + fact3.push_back(bv.mk_numeral(rational(4), 12)); + + relation_base* t; + expr_ref fml(m); + // empty + { + std::cout << "empty\n"; + t = mk_empty(sig); + t->display(std::cout); std::cout << "\n"; + t->to_formula(fml); + std::cout << fml << "\n"; + t->deallocate(); + } + + // full + { + std::cout << "full\n"; + t = mk_full(sig); + t->display(std::cout); std::cout << "\n"; + t->to_formula(fml); + std::cout << fml << "\n"; + t->deallocate(); + } + + // join + { + udoc_relation* t1 = mk_full(sig); + udoc_relation* t2 = mk_full(sig); + udoc_relation* t3 = mk_empty(sig); + unsigned_vector jc1, jc2; + jc1.push_back(1); + jc2.push_back(1); + datalog::relation_join_fn* join_fn = p.mk_join_fn(*t1, *t2, jc1.size(), jc1.c_ptr(), jc2.c_ptr()); + SASSERT(join_fn); + t = (*join_fn)(*t1, *t2); + t->display(std::cout); std::cout << "\n"; + t->deallocate(); + + t = (*join_fn)(*t1, *t3); + SASSERT(t->empty()); + t->display(std::cout); std::cout << "\n"; + t->deallocate(); + + t = (*join_fn)(*t3, *t3); + SASSERT(t->empty()); + t->display(std::cout); std::cout << "\n"; + t->deallocate(); + + dealloc(join_fn); + t1->deallocate(); + t2->deallocate(); + t3->deallocate(); + } + + // project + { + std::cout << "project\n"; + udoc_relation* t1 = mk_full(sig); + unsigned_vector pc; + pc.push_back(0); + datalog::relation_transformer_fn* proj_fn = p.mk_project_fn(*t1, pc.size(), pc.c_ptr()); + t = (*proj_fn)(*t1); + t->display(std::cout); std::cout << "\n"; + t->deallocate(); + + t1->reset(); + t = (*proj_fn)(*t1); + t->display(std::cout); std::cout << "\n"; + t->deallocate(); + + t1->add_fact(fact1); + t1->add_fact(fact2); + t1->add_fact(fact3); + t = (*proj_fn)(*t1); + t1->display(std::cout); std::cout << "\n"; + t->display(std::cout); std::cout << "\n"; + t->deallocate(); + + dealloc(proj_fn); + t1->deallocate(); + } + + // rename + { + udoc_relation* t1 = mk_empty(sig); + unsigned_vector cycle; + cycle.push_back(0); + cycle.push_back(2); + datalog::relation_transformer_fn* rename = p.mk_rename_fn(*t1, cycle.size(), cycle.c_ptr()); + + t1->add_fact(fact1); + t1->add_fact(fact2); + t1->add_fact(fact3); + t = (*rename)(*t1); + t1->display(std::cout); std::cout << "\n"; + t->display(std::cout); std::cout << "\n"; + t->deallocate(); + + dealloc(rename); + t1->deallocate(); + } + + // union + { + udoc_relation* t1 = mk_empty(sig); + udoc_relation* t2 = mk_empty(sig); + udoc_relation* delta = mk_full(sig); + t2->add_fact(fact1); + t2->add_fact(fact2); + t1->add_fact(fact3); + + datalog::relation_union_fn* union_fn = p.mk_union_fn(*t1, *t2, 0); + + t1->display(std::cout << "t1 before:"); std::cout << "\n"; + (*union_fn)(*t1, *t2, delta); + t1->display(std::cout << "t1 after:"); std::cout << "\n"; + delta->display(std::cout << "delta:"); std::cout << "\n"; + + t1->deallocate(); + t2->deallocate(); + delta->deallocate(); + } + + // filter_identical + + // filter_interpreted + + // filter_by_negation + + // filter_interpreted_project + } +}; + +void tst_udoc_relation() { + udoc_tester tester; + + tester.test1(); +} From 6a8623ef0ca6c526e34f163a67121e8ed40d4abb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 19 Sep 2014 11:01:38 -0700 Subject: [PATCH 556/925] remove extra udoc_relation Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/udoc_relation.cpp | 891 --------------------------------- 1 file changed, 891 deletions(-) delete mode 100644 src/muz/ddnf/udoc_relation.cpp diff --git a/src/muz/ddnf/udoc_relation.cpp b/src/muz/ddnf/udoc_relation.cpp deleted file mode 100644 index dce993e87..000000000 --- a/src/muz/ddnf/udoc_relation.cpp +++ /dev/null @@ -1,891 +0,0 @@ -#include "udoc_relation.h" -#include "dl_relation_manager.h" -#include "qe_util.h" -#include "ast_util.h" - -namespace datalog { - - udoc_relation::udoc_relation(udoc_plugin& p, relation_signature const& sig): - relation_base(p, sig), - dm(p.dm(p.num_signature_bits(sig))) { - unsigned column = 0; - for (unsigned i = 0; i < sig.size(); ++i) { - m_column_info.push_back(column); - column += p.num_sort_bits(sig[i]); - } - m_column_info.push_back(column); - } - udoc_relation::~udoc_relation() { - reset(); - } - void udoc_relation::reset() { - m_elems.reset(dm); - } - void udoc_relation::expand_column_vector(unsigned_vector& v, udoc_relation* other) const { - unsigned_vector orig; - orig.swap(v); - for (unsigned i = 0; i < orig.size(); ++i) { - unsigned col, limit; - if (orig[i] < get_num_cols()) { - col = column_idx(orig[i]); - limit = col + column_num_bits(orig[i]); - } else { - unsigned idx = orig[i] - get_num_cols(); - col = get_num_bits() + other->column_idx(idx); - limit = col + other->column_num_bits(idx); - } - for (; col < limit; ++col) { - v.push_back(col); - } - } - } - - doc* udoc_relation::fact2doc(const relation_fact & f) const { - doc* d = dm.allocate0(); - for (unsigned i = 0; i < f.size(); ++i) { - unsigned bv_size; - rational val; - VERIFY(get_plugin().is_numeral(f[i], val, bv_size)); - SASSERT(bv_size == column_num_bits(i)); - unsigned lo = column_idx(i); - unsigned hi = column_idx(i + 1); - d->pos().set(val, hi, lo); - } - return d; - } - void udoc_relation::add_fact(const relation_fact & f) { - doc* d = fact2doc(f); - m_elems.insert(dm, d); - } - bool udoc_relation::contains_fact(const relation_fact & f) const { - doc_ref d(dm, fact2doc(f)); - return m_elems.contains(dm, *d); - } - udoc_relation * udoc_relation::clone() const { - udoc_relation* result = udoc_plugin::get(get_plugin().mk_empty(get_signature())); - for (unsigned i = 0; i < m_elems.size(); ++i) { - result->m_elems.push_back(dm.allocate(m_elems[i])); - } - return result; - } - udoc_relation * udoc_relation::complement(func_decl* f) const { - udoc_relation* result = udoc_plugin::get(get_plugin().mk_empty(get_signature())); - m_elems.complement(dm, result->m_elems); - return result; - } - void udoc_relation::to_formula(expr_ref& fml) const { - ast_manager& m = fml.get_manager(); - expr_ref_vector disj(m); - for (unsigned i = 0; i < m_elems.size(); ++i) { - disj.push_back(to_formula(m_elems[i])); - } - fml = mk_or(m, disj.size(), disj.c_ptr()); - } - expr_ref udoc_relation::to_formula(doc const& d) const { - ast_manager& m = get_plugin().get_ast_manager(); - expr_ref result(m); - expr_ref_vector conjs(m); - conjs.push_back(to_formula(d.pos())); - for (unsigned i = 0; i < d.neg().size(); ++i) { - conjs.push_back(m.mk_not(to_formula(d.neg()[i]))); - } - result = mk_and(m, conjs.size(), conjs.c_ptr()); - return result; - } - expr_ref udoc_relation::to_formula(tbv const& t) const { - udoc_plugin& p = get_plugin(); - ast_manager& m = p.get_ast_manager(); - expr_ref result(m); - expr_ref_vector conjs(m); - for (unsigned i = 0; i < get_num_cols(); ++i) { - var_ref v(m); - v = m.mk_var(i, get_signature()[i]); - unsigned lo = column_idx(i); - unsigned hi = column_idx(i+1); - rational r(0); - unsigned lo0 = lo; - bool is_x = true; - for (unsigned j = lo; j < hi; ++j) { - switch(t[j]) { - case BIT_0: - if (is_x) is_x = false, lo0 = j, r.reset(); - break; - case BIT_1: - if (is_x) is_x = false, lo0 = j, r.reset(); - r += rational::power_of_two(j - lo0); - break; - case BIT_x: - if (!is_x) { - conjs.push_back(m.mk_eq(p.bv.mk_extract(j-1,lo0,v), - p.bv.mk_numeral(r,j-lo0))); - } - is_x = true; - break; - default: - UNREACHABLE(); - } - } - if (!is_x) { - expr_ref num(m); - if (lo0 == lo) { - num = p.mk_numeral(r, get_signature()[i]); - conjs.push_back(m.mk_eq(v, num)); - } - else { - num = p.bv.mk_numeral(r, hi-lo0); - conjs.push_back(m.mk_eq(p.bv.mk_extract(hi-1,lo0,v), num)); - } - } - } - result = mk_and(m, conjs.size(), conjs.c_ptr()); - return result; - } - - udoc_plugin& udoc_relation::get_plugin() const { - return static_cast(relation_base::get_plugin()); - } - - void udoc_relation::display(std::ostream& out) const { - m_elems.display(dm, out << "{") << "}"; - } - - // ------------- - - udoc_plugin::udoc_plugin(relation_manager& rm): - relation_plugin(udoc_plugin::get_name(), rm), - m(rm.get_context().get_manager()), - bv(m), - dl(m) { - } - udoc_plugin::~udoc_plugin() { - u_map::iterator it = m_dms.begin(), end = m_dms.end(); - for (; it != end; ++it) { - dealloc(it->m_value); - } - } - udoc_relation& udoc_plugin::get(relation_base& r) { - return dynamic_cast(r); - } - udoc_relation* udoc_plugin::get(relation_base* r) { - return r?dynamic_cast(r):0; - } - udoc_relation const & udoc_plugin::get(relation_base const& r) { - return dynamic_cast(r); - } - - doc_manager& udoc_plugin::dm(relation_signature const& sig) { - return dm(num_signature_bits(sig)); - } - - doc_manager& udoc_plugin::dm(unsigned n) { - doc_manager* r; - if (!m_dms.find(n, r)) { - r = alloc(doc_manager, n); - m_dms.insert(n, r); - } - return *r; - } - expr* udoc_plugin::mk_numeral(rational const& r, sort* s) { - if (bv.is_bv_sort(s)) { - return bv.mk_numeral(r, s); - } - SASSERT(dl.is_finite_sort(s)); - return dl.mk_numeral(r.get_uint64(), s); - } - bool udoc_plugin::is_numeral(expr* e, rational& r, unsigned& num_bits) { - if (bv.is_numeral(e, r, num_bits)) return true; - uint64 n, sz; - ast_manager& m = get_ast_manager(); - if (dl.is_numeral(e, n) && dl.try_get_size(m.get_sort(e), sz)) { - num_bits = 0; - while (sz > 0) ++num_bits, sz = sz/2; - r = rational(n, rational::ui64()); - return true; - } - return false; - } - unsigned udoc_plugin::num_sort_bits(sort* s) const { - unsigned num_bits = 0; - if (bv.is_bv_sort(s)) - return bv.get_bv_size(s); - uint64 sz; - if (dl.try_get_size(s, sz)) { - while (sz > 0) ++num_bits, sz /= 2; - return num_bits; - } - UNREACHABLE(); - return 0; - } - unsigned udoc_plugin::num_signature_bits(relation_signature const& sig) { - unsigned result = 0; - for (unsigned i = 0; i < sig.size(); ++i) { - result += num_sort_bits(sig[i]); - } - return result; - } - - bool udoc_plugin::is_finite_sort(sort* s) const { - return bv.is_bv_sort(s) || dl.is_finite_sort(s); - } - - - bool udoc_plugin::can_handle_signature(const relation_signature & sig) { - for (unsigned i = 0; i < sig.size(); ++i) { - if (!is_finite_sort(sig[i])) - return false; - } - return true; - } - relation_base * udoc_plugin::mk_empty(const relation_signature & sig) { - return alloc(udoc_relation, *this, sig); - } - relation_base * udoc_plugin::mk_full(func_decl* p, const relation_signature & s) { - udoc_relation* r = get(mk_empty(s)); - r->get_udoc().push_back(dm(s).allocateX()); - return r; - } - class udoc_plugin::join_fn : public convenient_relation_join_fn { - doc_manager& dm; - doc_manager& dm1; - doc_manager& dm2; - public: - join_fn(udoc_plugin& p, udoc_relation const& t1, udoc_relation const& t2, unsigned col_cnt, - const unsigned * cols1, const unsigned * cols2) - : convenient_relation_join_fn(t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2), - dm(p.dm(get_result_signature())), - dm1(t1.get_dm()), - dm2(t2.get_dm()) { - t1.expand_column_vector(m_cols1); - t2.expand_column_vector(m_cols2); - } - - void join(doc const& d1, doc const& d2, udoc& result) { - doc* d = dm.allocateX(); - tbv& pos = d->pos(); - utbv& neg = d->neg(); - unsigned mid = dm1.num_tbits(); - unsigned hi = dm.num_tbits(); - pos.set(d1.pos(), mid-1, 0); - pos.set(d2.pos(), hi-1, mid); - // first fix bits - for (unsigned i = 0; i < m_cols1.size(); ++i) { - unsigned idx1 = m_cols1[i]; - unsigned idx2 = mid + m_cols2[i]; - tbit v1 = pos[idx1]; - tbit v2 = pos[idx2]; - - if (v1 == BIT_x) { - if (v2 != BIT_x) - pos.set(idx1, v2); - } else if (v2 == BIT_x) { - pos.set(idx2, v1); - } else if (v1 != v2) { - dm.deallocate(d); - // columns don't match - return; - } - } - // fix equality of don't care columns - for (unsigned i = 0; i < m_cols1.size(); ++i) { - unsigned idx1 = m_cols1[i]; - unsigned idx2 = mid + m_cols2[i]; - unsigned v1 = pos[idx1]; - unsigned v2 = pos[idx2]; - - if (v1 == BIT_x && v2 == BIT_x) { - // add to subtracted TBVs: 1xx0 and 0xx1 - tbv* r = dm.tbvm().allocate(pos); - r->set(idx1, BIT_0); - r->set(idx2, BIT_1); - neg.push_back(r); - - r = dm.tbvm().allocate(pos); - r->set(idx1, BIT_1); - r->set(idx2, BIT_0); - neg.push_back(r); - } - } - - // handle subtracted TBVs: 1010 -> 1010xxx - for (unsigned i = 0; i < d1.neg().size(); ++i) { - tbv* t = dm.tbvm().allocate(); - t->set(d1.neg()[i], mid-1, 0); - t->set(d2.pos(), hi - 1, mid); - neg.push_back(t); - } - for (unsigned i = 0; i < d2.neg().size(); ++i) { - tbv* t = dm.tbvm().allocate(); - t->set(d1.pos(), mid-1, 0); - t->set(d2.neg()[i], hi - 1, mid); - neg.push_back(t); - } - result.insert(dm, d); - } - - virtual relation_base * operator()(const relation_base & _r1, const relation_base & _r2) { - udoc_relation const& r1 = get(_r1); - udoc_relation const& r2 = get(_r2); - TRACE("dl", r1.display(tout << "r1:\n"); r2.display(tout << "r2:\n");); - udoc_plugin& p = r1.get_plugin(); - relation_signature const& sig = get_result_signature(); - udoc_relation * result = alloc(udoc_relation, p, sig); - udoc const& d1 = r1.get_udoc(); - udoc const& d2 = r2.get_udoc(); - udoc& r = result->get_udoc(); - for (unsigned i = 0; i < d1.size(); ++i) { - for (unsigned j = 0; j < d2.size(); ++j) { - join(d1[i], d2[j], r); - } - } - TRACE("dl", result->display(tout << "result:\n");); - return result; - } - }; - relation_join_fn * udoc_plugin::mk_join_fn( - const relation_base & t1, const relation_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { - if (!check_kind(t1) || !check_kind(t2)) { - return 0; - } - return alloc(join_fn, *this, get(t1), get(t2), col_cnt, cols1, cols2); - } - class udoc_plugin::project_fn : public convenient_relation_project_fn { - svector m_to_delete; - public: - project_fn(udoc_relation const & t, unsigned removed_col_cnt, const unsigned * removed_cols) - : convenient_relation_project_fn(t.get_signature(), removed_col_cnt, removed_cols) { - t.expand_column_vector(m_removed_cols); - unsigned n = t.get_dm().num_tbits(); - m_to_delete.resize(n, false); - for (unsigned i = 0; i < m_removed_cols.size(); ++i) { - m_to_delete[m_removed_cols[i]] = true; - } - } - - virtual relation_base * operator()(const relation_base & tb) { - TRACE("dl", tb.display(tout << "src:\n");); - udoc_relation const& t = get(tb); - udoc_plugin& p = t.get_plugin(); - udoc_relation* r = udoc_plugin::get(p.mk_empty(get_result_signature())); - doc_manager& dm1 = t.get_dm(); - doc_manager& dm2 = r->get_dm(); - doc_ref d2(dm2); - udoc const& ud1 = t.get_udoc(); - udoc& ud2 = r->get_udoc(); - for (unsigned i = 0; i < ud1.size(); ++i) { - d2 = dm1.project(dm2, m_to_delete.size(), m_to_delete.c_ptr(), ud1[i]); - ud2.push_back(d2.detach()); - } - TRACE("dl", tout << "final size: " << r->get_size_estimate_rows() << '\n';); - return r; - } - }; - - - relation_transformer_fn * udoc_plugin::mk_project_fn( - const relation_base & t, unsigned col_cnt, - const unsigned * removed_cols) { - if (!check_kind(t)) - return 0; - return alloc(project_fn, get(t), col_cnt, removed_cols); - } - - class udoc_plugin::rename_fn : public convenient_relation_rename_fn { - unsigned_vector m_permutation; - public: - rename_fn(udoc_relation const& t, unsigned cycle_len, const unsigned * cycle) - : convenient_relation_rename_fn(t.get_signature(), cycle_len, cycle) { - udoc_plugin& p = t.get_plugin(); - for (unsigned i = 0; i < t.get_num_bits(); ++i) { - m_permutation.push_back(i); - } - unsigned len = t.column_num_bits(cycle[0]); - for (unsigned i = 0; i < cycle_len; ++i) { - unsigned j = (i + 1)%cycle_len; - unsigned col1 = cycle[i]; - unsigned col2 = cycle[j]; - unsigned lo1 = t.column_idx(col1); - unsigned lo2 = t.column_idx(col2); - for (unsigned k = 0; k < len; ++k) { - m_permutation[k + lo1] = k + lo2; - } - SASSERT(t.column_num_bits(col1) == t.column_num_bits(col2)); - } - } - - virtual relation_base * operator()(const relation_base & _r) { - udoc_relation const& r = get(_r); - TRACE("dl", r.display(tout << "r:\n");); - udoc_plugin& p = r.get_plugin(); - relation_signature const& sig = get_result_signature(); - udoc_relation* result = alloc(udoc_relation, p, sig); - udoc const& src = r.get_udoc(); - udoc& dst = result->get_udoc(); - doc_manager& dm = r.get_dm(); - for (unsigned i = 0; i < src.size(); ++i) { - dst.push_back(dm.allocate(src[i], m_permutation.c_ptr())); - } - TRACE("dl", result->display(tout << "result:\n");); - return result; - } - }; - relation_transformer_fn * udoc_plugin::mk_rename_fn( - const relation_base & r, - unsigned cycle_len, const unsigned * permutation_cycle) { - if (check_kind(r)) { - return alloc(rename_fn, get(r), cycle_len, permutation_cycle); - } - else { - return 0; - } - } - class udoc_plugin::union_fn : public relation_union_fn { - public: - union_fn() {} - - virtual void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) { - TRACE("dl", _r.display(tout << "dst:\n"); _src.display(tout << "src:\n");); - udoc_relation& r = get(_r); - udoc_relation const& src = get(_src); - udoc_relation* d = get(_delta); - udoc* d1 = 0; - if (d) d1 = &d->get_udoc(); - r.get_plugin().mk_union(r.get_dm(), r.get_udoc(), src.get_udoc(), d1); - TRACE("dl", _r.display(tout << "dst':\n");); - } - }; - void udoc_plugin::mk_union(doc_manager& dm, udoc& dst, udoc const& src, udoc* delta) { - for (unsigned i = 0; i < src.size(); ++i) { - doc* d = dm.allocate(src[i]); - if (dst.insert(dm, d)) { - if (delta) { - delta->insert(dm, dm.allocate(src[i])); - } - } - } - } - relation_union_fn * udoc_plugin::mk_union_fn( - const relation_base & tgt, const relation_base & src, - const relation_base * delta) { - if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) { - return 0; - } - return alloc(union_fn); - } - relation_union_fn * udoc_plugin::mk_widen_fn( - const relation_base & tgt, const relation_base & src, - const relation_base * delta) { - return mk_union_fn(tgt, src, delta); - } - - class udoc_plugin::filter_identical_fn : public relation_mutator_fn { - unsigned_vector m_cols; - unsigned m_size; - bit_vector m_empty_bv; - union_find_default_ctx union_ctx; - union_find<> m_equalities; - public: - filter_identical_fn(const relation_base & _r, unsigned col_cnt, const unsigned *identical_cols) - : m_cols(col_cnt), m_equalities(union_ctx) { - udoc_relation const& r = get(_r); - doc_manager& dm = r.get_dm(); - unsigned num_bits = dm.num_tbits(); - m_size = r.column_num_bits(identical_cols[0]); - m_empty_bv.resize(r.get_num_bits(), false); - for (unsigned i = 0; i < col_cnt; ++i) { - m_cols[i] = r.column_idx(identical_cols[i]); - } - for (unsigned i = 0, e = m_empty_bv.size(); i < e; ++i) { - m_equalities.mk_var(); - } - for (unsigned i = 1; i < col_cnt; ++i) { - for (unsigned j = 0; j < m_size; ++j) { - m_equalities.merge(m_cols[0]+j ,m_cols[i]+j); - } - } - } - - virtual void operator()(relation_base & _r) { - udoc_relation& r = get(_r); - udoc& d = r.get_udoc(); - doc_manager& dm = r.get_dm(); - d.merge(dm, m_cols[0], m_size, m_equalities, m_empty_bv); - TRACE("dl", tout << "final size: " << r.get_size_estimate_rows() << '\n';); - } - }; - relation_mutator_fn * udoc_plugin::mk_filter_identical_fn( - const relation_base & t, unsigned col_cnt, const unsigned * identical_cols) { - return check_kind(t)?alloc(filter_identical_fn, t, col_cnt, identical_cols):0; - } - class udoc_plugin::filter_equal_fn : public relation_mutator_fn { - doc_manager& dm; - doc* m_filter; - public: - filter_equal_fn(udoc_plugin& p, const udoc_relation & t, const relation_element val, unsigned col): - dm(p.dm(t.get_signature())) { - rational r; - unsigned num_bits; - VERIFY(p.is_numeral(val, r, num_bits)); - m_filter = dm.allocateX(); - unsigned lo = t.column_idx(col); - unsigned hi = t.column_idx(col+1); - SASSERT(num_bits == hi - lo); - m_filter->pos().set(r, hi-1, lo); - } - virtual ~filter_equal_fn() { - dm.deallocate(m_filter); - } - virtual void operator()(relation_base & tb) { - udoc_relation & t = get(tb); - t.get_udoc().intersect(dm, *m_filter); - } - }; - relation_mutator_fn * udoc_plugin::mk_filter_equal_fn( - const relation_base & t, const relation_element & value, unsigned col) { - if (!check_kind(t)) - return 0; - return alloc(filter_equal_fn, *this, get(t), value, col); - } - - bool udoc_relation::is_guard(unsigned n, expr* const* gs) const { - for (unsigned i = 0; i < n; ++i) { - if (!is_guard(gs[i])) return false; - } - return true; - } - bool udoc_relation::is_guard(expr* g) const { - udoc_plugin& p = get_plugin(); - ast_manager& m = p.get_ast_manager(); - bv_util& bv = p.bv; - expr* e1, *e2, *e3; - unsigned hi, lo; - if (m.is_and(g) || m.is_or(g) || m.is_not(g) || m.is_true(g) || m.is_false(g)) { - return is_guard(to_app(g)->get_num_args(), to_app(g)->get_args()); - } - if (m.is_eq(g, e1, e2) && bv.is_bv(e1)) { - if (is_var(e1) && is_ground(e2)) return true; - if (is_var(e2) && is_ground(e1)) return true; - if (bv.is_extract(e1, lo, hi, e3) && is_var(e3) && is_ground(e2)) return true; - if (bv.is_extract(e2, lo, hi, e3) && is_var(e3) && is_ground(e1)) return true; - } - if (is_var(g)) { - return true; - } - return false; - } - - void udoc_relation::extract_guard(expr* cond, expr_ref& guard, expr_ref& rest) const { - rest.reset(); - ast_manager& m = get_plugin().get_ast_manager(); - expr_ref_vector conds(m), guards(m), rests(m); - conds.push_back(cond); - qe::flatten_and(conds); - for (unsigned i = 0; i < conds.size(); ++i) { - expr* g = conds[i].get(); - if (is_guard(g)) { - guards.push_back(g); - } - else { - rests.push_back(g); - } - } - guard = mk_and(m, guards.size(), guards.c_ptr()); - rest = mk_and(m, rests.size(), rests.c_ptr()); - } - void udoc_relation::compile_guard(expr* g, udoc& d, bit_vector const& discard_cols) const { - d.reset(dm); - d.push_back(dm.allocateX()); - apply_guard(g, d, discard_cols); - } - void udoc_relation::apply_guard(expr* g, udoc& result, bit_vector const& discard_cols) const { - // datastructure to store equalities with columns that will be projected out - union_find_default_ctx union_ctx; - subset_ints equalities(union_ctx); - for (unsigned i = 0, e = discard_cols.size(); i < e; ++i) { - equalities.mk_var(); - } - apply_guard(g, result, equalities, discard_cols); - } - bool udoc_relation::apply_eq(expr* g, udoc& result, var* v, unsigned hi, unsigned lo, expr* c) const { - udoc_plugin& p = get_plugin(); - unsigned num_bits; - rational r; - unsigned idx = v->get_idx(); - unsigned col = column_idx(idx); - lo += col; - hi += col; - if (p.is_numeral(c, r, num_bits)) { - doc_ref d(dm, dm.allocateX()); - d->pos().set(r, hi, lo); - result.intersect(dm, *d); - return true; - } - // other cases? - return false; - } - - void udoc_relation::apply_guard( - expr* g, udoc& result, subset_ints& equalities, bit_vector const& discard_cols) const { - ast_manager& m = get_plugin().get_ast_manager(); - bv_util& bv = get_plugin().bv; - expr* e1, *e2; - if (result.is_empty()) { - } - else if (m.is_and(g)) { - for (unsigned i = 0; !result.is_empty() && i < to_app(g)->get_num_args(); ++i) { - apply_guard(to_app(g)->get_arg(i), result, equalities, discard_cols); - } - } - else if (m.is_not(g, e1)) { - // REVIEW: (not (= x y)) should not cause - // the equivalence class to collapse. - // It seems the current organization with fix_eq_bits - // will merge the equivalence class as a side-effect. - udoc sub; - sub.push_back(dm.allocateX()); - apply_guard(e1, sub, equalities, discard_cols); - result.subtract(dm, sub); - } - else if (m.is_or(g)) { - udoc sub; - sub.push_back(dm.allocateX()); - for (unsigned i = 0; !sub.is_empty() && i < to_app(g)->get_num_args(); ++i) { - expr_ref arg(m); - arg = mk_not(m, to_app(g)->get_arg(i)); - apply_guard(arg, result, equalities, discard_cols); - } - result.subtract(dm, sub); - } - else if (m.is_true(g)) { - } - else if (m.is_false(g)) { - result.reset(dm); - } - else if (is_var(g)) { - SASSERT(m.is_bool(g)); - unsigned v = to_var(g)->get_idx(); - unsigned idx = column_idx(v); - doc_ref d(dm); - d = dm.allocateX(); - dm.set(*d, idx, BIT_1); - result.intersect(dm, *d); - } - else if (m.is_eq(g, e1, e2) && bv.is_bv(e1)) { - unsigned hi, lo; - expr* e3; - if (is_var(e1) && is_ground(e2) && - apply_eq(g, result, to_var(e1), bv.get_bv_size(e1)-1, 0, e2)) { - } - else if (is_var(e2) && is_ground(e1) && - apply_eq(g, result, to_var(e2), bv.get_bv_size(e2)-1, 0, e1)) { - } - else if (bv.is_extract(e1, lo, hi, e3) && is_var(e3) && is_ground(e2) && - apply_eq(g, result, to_var(e3), hi, lo, e2)) { - } - else if (bv.is_extract(e2, lo, hi, e3) && is_var(e3) && is_ground(e1) && - apply_eq(g, result, to_var(e3), hi, lo, e1)) { - } - else if (is_var(e1) && is_var(e2)) { - var* v1 = to_var(e1); - var* v2 = to_var(e2); - unsigned idx1 = column_idx(v1->get_idx()); - unsigned idx2 = column_idx(v2->get_idx()); - unsigned length = column_num_bits(v1->get_idx()); - result.merge(dm, idx1, idx2, length, discard_cols); - } - else { - goto failure_case; - } - } - else { - failure_case: - std::ostringstream strm; - strm << "Guard expression is not handled" << mk_pp(g, m); - throw default_exception(strm.str()); - } - } - - class udoc_plugin::filter_interpreted_fn : public relation_mutator_fn { - doc_manager& dm; - expr_ref m_condition; - udoc m_udoc; - bit_vector m_empty_bv; - public: - filter_interpreted_fn(const udoc_relation & t, ast_manager& m, app *condition) : - dm(t.get_dm()), - m_condition(m) { - m_empty_bv.resize(t.get_num_bits(), false); - expr_ref guard(m), rest(m); - t.extract_guard(condition, guard, m_condition); - t.compile_guard(guard, m_udoc, m_empty_bv); - if (m.is_true(m_condition)) { - m_condition = 0; - } - TRACE("dl", - tout << "condition: " << mk_pp(condition, m) << "\n"; - tout << m_condition << "\n"; m_udoc.display(dm, tout) << "\n";); - } - - virtual ~filter_interpreted_fn() { - m_udoc.reset(dm); - } - - virtual void operator()(relation_base & tb) { - udoc_relation & t = get(tb); - udoc& u = t.get_udoc(); - u.intersect(dm, m_udoc); - if (m_condition && !u.is_empty()) { - t.apply_guard(m_condition, u, m_empty_bv); - } - TRACE("dl", tout << "final size: " << t.get_size_estimate_rows() << '\n';); - } - }; - relation_mutator_fn * udoc_plugin::mk_filter_interpreted_fn(const relation_base & t, app * condition) { - return check_kind(t)?alloc(filter_interpreted_fn, get(t), get_ast_manager(), condition):0; - } - - class udoc_plugin::negation_filter_fn : public relation_intersection_filter_fn { - const unsigned_vector m_t_cols; - const unsigned_vector m_neg_cols; - public: - negation_filter_fn(const udoc_relation & r, const udoc_relation & neg, unsigned joined_col_cnt, - const unsigned *t_cols, const unsigned *neg_cols) - : m_t_cols(joined_col_cnt, t_cols), m_neg_cols(joined_col_cnt, neg_cols) { - SASSERT(joined_col_cnt > 0); - } - - virtual void operator()(relation_base& tb, const relation_base& negb) { - udoc_relation& t = get(tb); - udoc_relation const& n = get(negb); - udoc & dst = t.get_udoc(); - udoc const & neg = n.get_udoc(); - doc_manager& dm = t.get_dm(); - udoc result; - for (unsigned i = 0; i < dst.size(); ++i) { - bool done_i = false; - for (unsigned j = 0; !done_i && j < neg.size(); ++j) { - bool done_j = false; - for (unsigned c = 0; !done_i && !done_j && c < m_t_cols.size(); ++c) { - unsigned t_col = m_t_cols[c]; - unsigned n_col = m_neg_cols[c]; - unsigned num_bits = t.column_num_bits(t_col); - SASSERT(num_bits == n.column_num_bits(n_col)); - unsigned t_idx = t.column_idx(t_col); - unsigned n_idx = n.column_idx(n_col); - for (unsigned k = 0; !done_j && k < num_bits; ++k) { - tbit n_bit = neg[j][n_idx + k]; - tbit d_bit = dst[i][t_idx + k]; - // neg does not contain dst. - done_j = (n_bit != BIT_x && n_bit != d_bit); - } - } - if (done_j) { - result.push_back(&dst[i]); - } - else { - dm.deallocate(&dst[i]); - done_i = true; - } - } - } - std::swap(dst, result); - if (dst.is_empty()) { - return; - } - - // slow case - udoc renamed_neg; - for (unsigned i = 0; i < neg.size(); ++i) { - doc_ref newD(dm, dm.allocateX()); - for (unsigned j = 0; j < m_neg_cols.size(); ++j) { - copy_column(*newD, neg[i], m_t_cols[j], m_neg_cols[j], t, n); - } - renamed_neg.push_back(newD.detach()); - } - dst.subtract(t.get_dm(), renamed_neg); - } - void copy_column( - doc& dst, doc const& src, - unsigned col_dst, unsigned col_src, - udoc_relation const& dstt, - udoc_relation const& srct) { - doc_manager& dm = dstt.get_dm(); - unsigned idx_dst = dstt.column_idx(col_dst); - unsigned idx_src = srct.column_idx(col_src); - unsigned num_bits = dstt.column_num_bits(col_dst); - SASSERT(num_bits == srct.column_num_bits(col_src)); - for (unsigned i = 0; i < num_bits; ++i) { - dm.set(dst, idx_dst+i, src[idx_src+i]); - } - } - }; - - relation_intersection_filter_fn * udoc_plugin::mk_filter_by_negation_fn( - const relation_base& t, - const relation_base& neg, unsigned joined_col_cnt, const unsigned *t_cols, - const unsigned *negated_cols) { - if (!check_kind(t) || !check_kind(neg)) - return 0; - return alloc(negation_filter_fn, get(t), get(neg), joined_col_cnt, t_cols, negated_cols); - } - - class udoc_plugin::filter_proj_fn : public convenient_relation_project_fn { - doc_manager& dm; - expr_ref m_condition; - udoc m_udoc; - bit_vector m_col_list; // map: col idx -> bool (whether the column is to be removed) - svector m_to_delete; // same - public: - filter_proj_fn(const udoc_relation & t, ast_manager& m, app *condition, - unsigned col_cnt, const unsigned * removed_cols) : - convenient_relation_project_fn(t.get_signature(), col_cnt, removed_cols), - dm(t.get_dm()), - m_condition(m) { - t.expand_column_vector(m_removed_cols); - m_col_list.resize(t.get_num_bits(), false); - for (unsigned i = 0; i < m_removed_cols.size(); ++i) { - m_col_list.set(m_removed_cols[i], true); - } - m_to_delete.resize(m_removed_cols.size(), false); - for (unsigned i = 0; i < m_removed_cols.size(); ++i) { - m_to_delete[m_removed_cols[i]] = true; - } - expr_ref guard(m), rest(m); - t.extract_guard(condition, guard, m_condition); - t.compile_guard(guard, m_udoc, m_col_list); - if (m.is_true(m_condition)) { - m_condition = 0; - } - } - - virtual ~filter_proj_fn() { - m_udoc.reset(dm); - } - virtual relation_base* operator()(const relation_base & tb) { - udoc_relation const & t = get(tb); - udoc const& u1 = t.get_udoc(); - doc_manager& dm = t.get_dm(); - udoc u2; - u2.copy(dm, u1); - u2.intersect(dm, m_udoc); - if (m_condition && !u2.is_empty()) { - t.apply_guard(m_condition, u2, m_col_list); - } - udoc_relation* r = get(t.get_plugin().mk_empty(get_result_signature())); - doc_manager& dm2 = r->get_dm(); - for (unsigned i = 0; i < u2.size(); ++i) { - doc* d = dm.project(dm2, m_to_delete.size(), m_to_delete.c_ptr(), u2[i]); - r->get_udoc().insert(dm2, d); - } - u2.reset(dm); - return r; - } - }; - relation_transformer_fn * udoc_plugin::mk_filter_interpreted_and_project_fn( - const relation_base & t, app * condition, - unsigned removed_col_cnt, const unsigned * removed_cols) { - return check_kind(t)?alloc(filter_proj_fn, get(t), get_ast_manager(), condition, removed_col_cnt, removed_cols):0; - } - - -} From 25914c0492be8881fb4bfe9c99902cb61306e43d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 19 Sep 2014 18:18:40 -0700 Subject: [PATCH 557/925] testing filter interpreted Signed-off-by: Nikolaj Bjorner --- src/muz/rel/doc.h | 12 +++++ src/muz/rel/udoc_relation.cpp | 1 + src/test/udoc_relation.cpp | 88 +++++++++++++++++++++++++++++++---- 3 files changed, 93 insertions(+), 8 deletions(-) diff --git a/src/muz/rel/doc.h b/src/muz/rel/doc.h index 01772543a..510ee8bef 100644 --- a/src/muz/rel/doc.h +++ b/src/muz/rel/doc.h @@ -220,6 +220,18 @@ public: push_back(m.allocate(other[i])); } } + void simplify(M& m) { + union_bvec result; + for (unsigned i = 0; i < size(); ++i) { + if (m.fold_neg(*m_elems[i])) { + result.insert(m, m_elems[i]); + } + else { + m.deallocate(m_elems[i]); + } + } + std::swap(*this, result); + } void merge(M& m, unsigned lo, unsigned length, subset_ints & equalities, bit_vector const& discard_cols) { for (unsigned i = 0; i < size(); ++i) { diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index f1f919ec7..fb1d1c9e8 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -739,6 +739,7 @@ namespace datalog { if (m_condition && !u.is_empty()) { t.apply_guard(m_condition, u, m_empty_bv); } + u.simplify(dm); TRACE("dl", tout << "final size: " << t.get_size_estimate_rows() << '\n';); } }; diff --git a/src/test/udoc_relation.cpp b/src/test/udoc_relation.cpp index 2c5540fe2..7a616fdd0 100644 --- a/src/test/udoc_relation.cpp +++ b/src/test/udoc_relation.cpp @@ -21,6 +21,9 @@ class udoc_tester { typedef datalog::udoc_relation udoc_relation; typedef datalog::udoc_plugin udoc_plugin; typedef datalog::relation_signature relation_signature; + typedef datalog::relation_fact relation_fact; + typedef scoped_ptr rel_mut; + typedef scoped_ptr rel_union; struct init { init(ast_manager& m) { @@ -61,6 +64,7 @@ public: sig.push_back(bv.mk_sort(12)); sig.push_back(bv.mk_sort(6)); sig.push_back(bv.mk_sort(12)); + datalog::relation_fact fact1(m), fact2(m), fact3(m); fact1.push_back(bv.mk_numeral(rational(1), 12)); @@ -73,7 +77,15 @@ public: fact3.push_back(bv.mk_numeral(rational(16), 6)); fact3.push_back(bv.mk_numeral(rational(4), 12)); + relation_signature sig2; + sig2.push_back(bv.mk_sort(3)); + sig2.push_back(bv.mk_sort(6)); + sig2.push_back(bv.mk_sort(3)); + sig2.push_back(bv.mk_sort(3)); + sig2.push_back(bv.mk_sort(3)); + relation_base* t; + udoc_relation* t1, *t2, *t3; expr_ref fml(m); // empty { @@ -97,9 +109,9 @@ public: // join { - udoc_relation* t1 = mk_full(sig); - udoc_relation* t2 = mk_full(sig); - udoc_relation* t3 = mk_empty(sig); + t1 = mk_full(sig); + t2 = mk_full(sig); + t3 = mk_empty(sig); unsigned_vector jc1, jc2; jc1.push_back(1); jc2.push_back(1); @@ -128,7 +140,7 @@ public: // project { std::cout << "project\n"; - udoc_relation* t1 = mk_full(sig); + t1 = mk_full(sig); unsigned_vector pc; pc.push_back(0); datalog::relation_transformer_fn* proj_fn = p.mk_project_fn(*t1, pc.size(), pc.c_ptr()); @@ -155,7 +167,7 @@ public: // rename { - udoc_relation* t1 = mk_empty(sig); + t1 = mk_empty(sig); unsigned_vector cycle; cycle.push_back(0); cycle.push_back(2); @@ -175,14 +187,14 @@ public: // union { - udoc_relation* t1 = mk_empty(sig); - udoc_relation* t2 = mk_empty(sig); + t1 = mk_empty(sig); + t2 = mk_empty(sig); udoc_relation* delta = mk_full(sig); t2->add_fact(fact1); t2->add_fact(fact2); t1->add_fact(fact3); - datalog::relation_union_fn* union_fn = p.mk_union_fn(*t1, *t2, 0); + rel_union union_fn = p.mk_union_fn(*t1, *t2, 0); t1->display(std::cout << "t1 before:"); std::cout << "\n"; (*union_fn)(*t1, *t2, delta); @@ -195,9 +207,69 @@ public: } // filter_identical + { + t1 = mk_empty(sig2); + unsigned_vector id; + id.push_back(0); + id.push_back(2); + id.push_back(4); + datalog::relation_mutator_fn* filter_id = p.mk_filter_identical_fn(*t1, id.size(), id.c_ptr()); + relation_fact f1(m); + f1.push_back(bv.mk_numeral(rational(1),3)); + f1.push_back(bv.mk_numeral(rational(1),6)); + f1.push_back(bv.mk_numeral(rational(1),3)); + f1.push_back(bv.mk_numeral(rational(1),3)); + f1.push_back(bv.mk_numeral(rational(1),3)); + t1->add_fact(f1); + f1[4] = bv.mk_numeral(rational(2),3); + t1->add_fact(f1); + t1->display(std::cout); std::cout << "\n"; + (*filter_id)(*t1); + t1->display(std::cout); std::cout << "\n"; + t1->deallocate(); + dealloc(filter_id); + } // filter_interpreted + { + std::cout << "filter interpreted\n"; + t1 = mk_full(sig2); + t2 = mk_full(sig2); + var_ref v0(m.mk_var(0, bv.mk_sort(3)),m); + var_ref v1(m.mk_var(1, bv.mk_sort(6)),m); + var_ref v2(m.mk_var(2, bv.mk_sort(3)),m); + var_ref v3(m.mk_var(3, bv.mk_sort(3)),m); + var_ref v4(m.mk_var(4, bv.mk_sort(3)),m); + app_ref cond1(m), cond2(m), cond3(m), cond4(m); + app_ref cond5(m), cond6(m), cond7(m), cond8(m); + cond1 = m.mk_true(); + cond2 = m.mk_false(); + cond3 = m.mk_eq(v0, v2); + cond4 = m.mk_not(m.mk_eq(v0, v2)); + cond5 = m.mk_eq(v0, bv.mk_numeral(rational(2), 3)); + rel_union union_fn = p.mk_union_fn(*t1, *t2, 0); + rel_mut fint1 = p.mk_filter_interpreted_fn(*t1, cond1); + rel_mut fint2 = p.mk_filter_interpreted_fn(*t1, cond2); + rel_mut fint3 = p.mk_filter_interpreted_fn(*t1, cond3); + rel_mut fint4 = p.mk_filter_interpreted_fn(*t1, cond4); + rel_mut fint5 = p.mk_filter_interpreted_fn(*t1, cond5); + (*fint1)(*t1); + t1->display(std::cout << "filter: " << cond1 << " "); std::cout << "\n"; + (*fint2)(*t1); + t1->display(std::cout << "filter: " << cond2 << " "); std::cout << "\n"; + (*union_fn)(*t1, *t2); + (*fint3)(*t1); + t1->display(std::cout << "filter: " << cond3 << " "); std::cout << "\n"; + (*fint4)(*t1); + t1->display(std::cout << "filter: " << cond4 << " "); std::cout << "\n"; + (*union_fn)(*t1, *t2); + (*fint5)(*t1); + t1->display(std::cout << "filter: " << cond5 << " "); std::cout << "\n"; + t1->deallocate(); + t2->deallocate(); + + } // filter_by_negation // filter_interpreted_project From 2b2ba2d541e7aef394711c33b242ef2a59487cdf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 19 Sep 2014 21:55:20 -0700 Subject: [PATCH 558/925] unit testing doc relation Signed-off-by: Nikolaj Bjorner --- src/muz/rel/doc.cpp | 7 +- src/muz/rel/udoc_relation.cpp | 98 ++++++++++++++++------ src/test/udoc_relation.cpp | 150 ++++++++++++++++++++++++++++------ 3 files changed, 204 insertions(+), 51 deletions(-) diff --git a/src/muz/rel/doc.cpp b/src/muz/rel/doc.cpp index cf27f3751..baff1f504 100644 --- a/src/muz/rel/doc.cpp +++ b/src/muz/rel/doc.cpp @@ -441,12 +441,13 @@ unsigned doc_manager::hash(doc const& src) const { // A \ (A1 u A2) contains B \ (B1 u B2) // if // A contains B -// B1 contains A1 or A2 +// B1 contains A1 or B2 contains A1 +// B1 contains A2 or B2 contains A2 bool doc_manager::contains(doc const& a, doc const& b) const { if (!m.contains(a.pos(), b.pos())) return false; - for (unsigned i = 0; i < b.neg().size(); ++i) { + for (unsigned i = 0; i < a.neg().size(); ++i) { bool found = false; - for (unsigned j = 0; !found && j < a.neg().size(); ++j) { + for (unsigned j = 0; !found && j < b.neg().size(); ++j) { found = m.contains(b.neg()[i],a.neg()[j]); } if (!found) return false; diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index fb1d1c9e8..a9a858c43 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -103,21 +103,21 @@ namespace datalog { unsigned lo = column_idx(i); unsigned hi = column_idx(i+1); rational r(0); - unsigned lo0 = lo; + unsigned lo1 = lo; bool is_x = true; for (unsigned j = lo; j < hi; ++j) { switch(t[j]) { case BIT_0: - if (is_x) is_x = false, lo0 = j, r.reset(); + if (is_x) is_x = false, lo1 = j, r.reset(); break; case BIT_1: - if (is_x) is_x = false, lo0 = j, r.reset(); - r += rational::power_of_two(j - lo0); + if (is_x) is_x = false, lo1 = j, r.reset(); + r += rational::power_of_two(j - lo1); break; case BIT_x: if (!is_x) { - conjs.push_back(m.mk_eq(p.bv.mk_extract(j-1,lo0,v), - p.bv.mk_numeral(r,j-lo0))); + conjs.push_back(m.mk_eq(p.bv.mk_extract(j-1-lo,lo1-lo,v), + p.bv.mk_numeral(r,j-lo1))); } is_x = true; break; @@ -127,13 +127,13 @@ namespace datalog { } if (!is_x) { expr_ref num(m); - if (lo0 == lo) { + if (lo1 == lo) { num = p.mk_numeral(r, get_signature()[i]); conjs.push_back(m.mk_eq(v, num)); } else { - num = p.bv.mk_numeral(r, hi-lo0); - conjs.push_back(m.mk_eq(p.bv.mk_extract(hi-1,lo0,v), num)); + num = p.bv.mk_numeral(r, hi-lo1); + conjs.push_back(m.mk_eq(p.bv.mk_extract(hi-1-lo,lo1-lo,v), num)); } } } @@ -146,7 +146,7 @@ namespace datalog { } void udoc_relation::display(std::ostream& out) const { - m_elems.display(dm, out); + m_elems.display(dm, out); out << "\n"; } // ------------- @@ -189,11 +189,25 @@ namespace datalog { if (bv.is_bv_sort(s)) { return bv.mk_numeral(r, s); } + if (m.is_bool(s)) { + if (r.is_zero()) return m.mk_false(); + return m.mk_true(); + } SASSERT(dl.is_finite_sort(s)); return dl.mk_numeral(r.get_uint64(), s); } bool udoc_plugin::is_numeral(expr* e, rational& r, unsigned& num_bits) { if (bv.is_numeral(e, r, num_bits)) return true; + if (m.is_true(e)) { + r = rational(1); + num_bits = 1; + return true; + } + if (m.is_false(e)) { + r = rational(0); + num_bits = 1; + return true; + } uint64 n, sz; ast_manager& m = get_ast_manager(); if (dl.is_numeral(e, n) && dl.try_get_size(m.get_sort(e), sz)) { @@ -208,6 +222,9 @@ namespace datalog { unsigned num_bits = 0; if (bv.is_bv_sort(s)) return bv.get_bv_size(s); + if (m.is_bool(s)) { + return 1; + } uint64 sz; if (dl.try_get_size(s, sz)) { while (sz > 0) ++num_bits, sz /= 2; @@ -325,7 +342,7 @@ namespace datalog { virtual relation_base * operator()(const relation_base & _r1, const relation_base & _r2) { udoc_relation const& r1 = get(_r1); udoc_relation const& r2 = get(_r2); - TRACE("dl", r1.display(tout << "r1:\n"); r2.display(tout << "r2:\n");); + TRACE("doc", r1.display(tout << "r1:\n"); r2.display(tout << "r2:\n");); udoc_plugin& p = r1.get_plugin(); relation_signature const& sig = get_result_signature(); udoc_relation * result = alloc(udoc_relation, p, sig); @@ -337,7 +354,7 @@ namespace datalog { join(d1[i], d2[j], r); } } - TRACE("dl", result->display(tout << "result:\n");); + TRACE("doc", result->display(tout << "result:\n");); return result; } }; @@ -363,7 +380,7 @@ namespace datalog { } virtual relation_base * operator()(const relation_base & tb) { - TRACE("dl", tb.display(tout << "src:\n");); + TRACE("doc", tb.display(tout << "src:\n");); udoc_relation const& t = get(tb); udoc_plugin& p = t.get_plugin(); udoc_relation* r = udoc_plugin::get(p.mk_empty(get_result_signature())); @@ -376,7 +393,7 @@ namespace datalog { d2 = dm1.project(dm2, m_to_delete.size(), m_to_delete.c_ptr(), ud1[i]); ud2.push_back(d2.detach()); } - TRACE("dl", tout << "final size: " << r->get_size_estimate_rows() << '\n';); + TRACE("doc", tout << "final size: " << r->get_size_estimate_rows() << '\n';); return r; } }; @@ -415,7 +432,7 @@ namespace datalog { virtual relation_base * operator()(const relation_base & _r) { udoc_relation const& r = get(_r); - TRACE("dl", r.display(tout << "r:\n");); + TRACE("doc", r.display(tout << "r:\n");); udoc_plugin& p = r.get_plugin(); relation_signature const& sig = get_result_signature(); udoc_relation* result = alloc(udoc_relation, p, sig); @@ -425,7 +442,7 @@ namespace datalog { for (unsigned i = 0; i < src.size(); ++i) { dst.push_back(dm.allocate(src[i], m_permutation.c_ptr())); } - TRACE("dl", result->display(tout << "result:\n");); + TRACE("doc", result->display(tout << "result:\n");); return result; } }; @@ -444,7 +461,7 @@ namespace datalog { union_fn() {} virtual void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) { - TRACE("dl", _r.display(tout << "dst:\n"); _src.display(tout << "src:\n");); + TRACE("doc", _r.display(tout << "dst:\n"); _src.display(tout << "src:\n");); udoc_relation& r = get(_r); udoc_relation const& src = get(_src); udoc_relation* d = get(_delta); @@ -453,7 +470,7 @@ namespace datalog { if (d) d1 = &d->get_udoc(); if (d1) d1->reset(dm); r.get_plugin().mk_union(dm, r.get_udoc(), src.get_udoc(), d1); - TRACE("dl", _r.display(tout << "dst':\n");); + TRACE("doc", _r.display(tout << "dst':\n"); ); } }; void udoc_plugin::mk_union(doc_manager& dm, udoc& dst, udoc const& src, udoc* delta) { @@ -512,7 +529,7 @@ namespace datalog { udoc& d = r.get_udoc(); doc_manager& dm = r.get_dm(); d.merge(dm, m_cols[0], m_size, m_equalities, m_empty_bv); - TRACE("dl", tout << "final size: " << r.get_size_estimate_rows() << '\n';); + TRACE("doc", tout << "final size: " << r.get_size_estimate_rows() << '\n';); } }; relation_mutator_fn * udoc_plugin::mk_filter_identical_fn( @@ -643,10 +660,15 @@ namespace datalog { // the equivalence class to collapse. // It seems the current organization with fix_eq_bits // will merge the equivalence class as a side-effect. + TRACE("doc", result.display(dm, tout << "result0:") << "\n";); udoc sub; sub.push_back(dm.allocateX()); apply_guard(e1, sub, equalities, discard_cols); + TRACE("doc", sub.display(dm, tout << "sub:") << "\n";); result.subtract(dm, sub); + result.simplify(dm); + TRACE("doc", result.display(dm, tout << "result:") << "\n";); + } else if (m.is_or(g)) { udoc sub; @@ -654,9 +676,10 @@ namespace datalog { for (unsigned i = 0; !sub.is_empty() && i < to_app(g)->get_num_args(); ++i) { expr_ref arg(m); arg = mk_not(m, to_app(g)->get_arg(i)); - apply_guard(arg, result, equalities, discard_cols); + apply_guard(arg, sub, equalities, discard_cols); } result.subtract(dm, sub); + sub.reset(dm); } else if (m.is_true(g)) { } @@ -672,9 +695,25 @@ namespace datalog { dm.set(*d, idx, BIT_1); result.intersect(dm, *d); } + else if ((m.is_eq(g, e1, e2) || m.is_iff(g, e1, e2)) && m.is_bool(e1)) { + udoc diff1, diff2; + diff1.push_back(dm.allocateX()); + diff2.push_back(dm.allocateX()); + expr_ref f1(m), f2(m); + f1 = mk_not(m, e1); + f2 = mk_not(m, e2); + apply_guard(e1, diff1, equalities, discard_cols); + apply_guard(f2, diff1, equalities, discard_cols); + result.subtract(dm, diff1); + diff1.reset(dm); + apply_guard(f1, diff2, equalities, discard_cols); + apply_guard(e2, diff2, equalities, discard_cols); + result.subtract(dm, diff2); + diff2.reset(dm); + } else if (m.is_eq(g, e1, e2) && bv.is_bv(e1)) { - unsigned hi, lo; - expr* e3; + unsigned hi, lo, lo1, lo2, hi1, hi2; + expr* e3, *e4; if (is_var(e1) && is_ground(e2) && apply_eq(g, result, to_var(e1), bv.get_bv_size(e1)-1, 0, e2)) { } @@ -695,6 +734,14 @@ namespace datalog { unsigned length = column_num_bits(v1->get_idx()); result.merge(dm, idx1, idx2, length, discard_cols); } + else if (bv.is_extract(e1, lo1, hi1, e3) && is_var(e3) && + bv.is_extract(e2, lo2, hi2, e4) && is_var(e4)) { + var* v1 = to_var(e3); + var* v2 = to_var(e4); + unsigned idx1 = lo1 + column_idx(v1->get_idx()); + unsigned idx2 = lo2 + column_idx(v2->get_idx()); + result.merge(dm, idx1, idx2, hi1-lo1+1, discard_cols); + } else { goto failure_case; } @@ -723,9 +770,10 @@ namespace datalog { if (m.is_true(m_condition)) { m_condition = 0; } - TRACE("dl", + TRACE("doc", tout << "condition: " << mk_pp(condition, m) << "\n"; - tout << m_condition << "\n"; m_udoc.display(dm, tout) << "\n";); + if (m_condition) tout << m_condition << "\n"; + m_udoc.display(dm, tout) << "\n";); } virtual ~filter_interpreted_fn() { @@ -740,7 +788,7 @@ namespace datalog { t.apply_guard(m_condition, u, m_empty_bv); } u.simplify(dm); - TRACE("dl", tout << "final size: " << t.get_size_estimate_rows() << '\n';); + TRACE("doc", tout << "final size: " << t.get_size_estimate_rows() << '\n';); } }; relation_mutator_fn * udoc_plugin::mk_filter_interpreted_fn(const relation_base & t, app * condition) { diff --git a/src/test/udoc_relation.cpp b/src/test/udoc_relation.cpp index 7a616fdd0..e307455cc 100644 --- a/src/test/udoc_relation.cpp +++ b/src/test/udoc_relation.cpp @@ -213,7 +213,7 @@ public: id.push_back(0); id.push_back(2); id.push_back(4); - datalog::relation_mutator_fn* filter_id = p.mk_filter_identical_fn(*t1, id.size(), id.c_ptr()); + rel_mut filter_id = p.mk_filter_identical_fn(*t1, id.size(), id.c_ptr()); relation_fact f1(m); f1.push_back(bv.mk_numeral(rational(1),3)); f1.push_back(bv.mk_numeral(rational(1),6)); @@ -227,14 +227,42 @@ public: (*filter_id)(*t1); t1->display(std::cout); std::cout << "\n"; t1->deallocate(); - dealloc(filter_id); + } + + { + relation_signature sig3; + sig3.push_back(m.mk_bool_sort()); + sig3.push_back(m.mk_bool_sort()); + sig3.push_back(m.mk_bool_sort()); + var_ref v0(m.mk_var(0, m.mk_bool_sort()),m); + var_ref v1(m.mk_var(1, m.mk_bool_sort()),m); + var_ref v2(m.mk_var(2, m.mk_bool_sort()),m); + app_ref cond1(m); + cond1 = m.mk_or(m.mk_eq(v0,v1),m.mk_eq(v0,v2)); + t1 = mk_full(sig3); + apply_filter(*t1, cond1); + t1->deallocate(); + } + + { + relation_signature sig3; + sig3.push_back(bv.mk_sort(1)); + sig3.push_back(bv.mk_sort(1)); + sig3.push_back(bv.mk_sort(1)); + var_ref v0(m.mk_var(0, bv.mk_sort(1)),m); + var_ref v1(m.mk_var(1, bv.mk_sort(1)),m); + var_ref v2(m.mk_var(2, bv.mk_sort(1)),m); + app_ref cond1(m); + cond1 = m.mk_or(m.mk_eq(v0,v1),m.mk_eq(v0,v2)); + t1 = mk_full(sig3); + apply_filter(*t1, cond1); + t1->deallocate(); } // filter_interpreted { std::cout << "filter interpreted\n"; t1 = mk_full(sig2); - t2 = mk_full(sig2); var_ref v0(m.mk_var(0, bv.mk_sort(3)),m); var_ref v1(m.mk_var(1, bv.mk_sort(6)),m); var_ref v2(m.mk_var(2, bv.mk_sort(3)),m); @@ -248,36 +276,112 @@ public: cond4 = m.mk_not(m.mk_eq(v0, v2)); cond5 = m.mk_eq(v0, bv.mk_numeral(rational(2), 3)); - rel_union union_fn = p.mk_union_fn(*t1, *t2, 0); - rel_mut fint1 = p.mk_filter_interpreted_fn(*t1, cond1); - rel_mut fint2 = p.mk_filter_interpreted_fn(*t1, cond2); - rel_mut fint3 = p.mk_filter_interpreted_fn(*t1, cond3); - rel_mut fint4 = p.mk_filter_interpreted_fn(*t1, cond4); - rel_mut fint5 = p.mk_filter_interpreted_fn(*t1, cond5); - (*fint1)(*t1); - t1->display(std::cout << "filter: " << cond1 << " "); std::cout << "\n"; - (*fint2)(*t1); - t1->display(std::cout << "filter: " << cond2 << " "); std::cout << "\n"; - (*union_fn)(*t1, *t2); - (*fint3)(*t1); - t1->display(std::cout << "filter: " << cond3 << " "); std::cout << "\n"; - (*fint4)(*t1); - t1->display(std::cout << "filter: " << cond4 << " "); std::cout << "\n"; - (*union_fn)(*t1, *t2); - (*fint5)(*t1); - t1->display(std::cout << "filter: " << cond5 << " "); std::cout << "\n"; + apply_filter(*t1, cond1); + apply_filter(*t1, cond2); + apply_filter(*t1, cond3); + apply_filter(*t1, cond4); + apply_filter(*t1, cond5); + + cond1 = m.mk_eq(ex(2,1,v0),bv.mk_numeral(rational(3),2)); + apply_filter(*t1, cond1); + + cond2 = m.mk_or(cond1,m.mk_eq(v3,v4)); + apply_filter(*t1, cond2); + + cond2 = m.mk_or(cond1,m.mk_eq(ex(2,1,v3),ex(1,0,v4))); + apply_filter(*t1, cond2); + + cond1 = m.mk_or(m.mk_eq(v0,v2),m.mk_eq(v0,v4)); + apply_filter(*t1, cond1); + + cond1 = m.mk_or(m.mk_eq(v0,v2),m.mk_eq(v3,v4)); + apply_filter(*t1, cond1); + + cond1 = m.mk_or(m.mk_eq(ex(2,1,v0),ex(1,0,v2)),m.mk_eq(v3,v4)); + apply_filter(*t1, cond1); + + cond1 = m.mk_or(m.mk_eq(ex(2,1,v0),bv.mk_numeral(rational(3),2)), + m.mk_eq(v3,v4)); + apply_filter(*t1, cond1); + + cond1 = m.mk_or(m.mk_eq(ex(2,1,v0),bv.mk_numeral(rational(3),2)), + m.mk_eq(v3,bv.mk_numeral(rational(3),5))); + apply_filter(*t1, cond1); + + cond1 = m.mk_or(m.mk_eq(v0,bv.mk_numeral(rational(5),3)), + m.mk_eq(v3,bv.mk_numeral(rational(5),3))); + apply_filter(*t1, cond1); + + cond1 = m.mk_or(m.mk_eq(v0,bv.mk_numeral(rational(7),3)), + m.mk_eq(v3,bv.mk_numeral(rational(7),3))); + apply_filter(*t1, cond1); + + cond1 = m.mk_not(m.mk_or(m.mk_eq(v0,v2),m.mk_eq(v3,v4))); + apply_filter(*t1, cond1); + + t1->deallocate(); - t2->deallocate(); } // filter_by_negation // filter_interpreted_project } + + expr_ref ex(unsigned hi, unsigned lo, expr* e) { + expr_ref result(m); + result = bv.mk_extract(hi, lo, e); + return result; + } + + void apply_filter(udoc_relation& t, app* cond) { + udoc_relation* full = mk_full(t.get_signature()); + rel_union union_fn = p.mk_union_fn(t, *full, 0); + (*union_fn)(t, *full, 0); + rel_mut fint = p.mk_filter_interpreted_fn(t, cond); + (*fint)(t); + t.display(std::cout << "filter: " << mk_pp(cond, m) << " "); std::cout << "\n"; + verify_filter(t, cond); + full->deallocate(); + } + + void verify_filter(udoc_relation& r, expr* fml2) { + expr_ref fml1(m), tmp(m); + r.to_formula(fml1); + tmp = m.mk_not(m.mk_eq(fml1, fml2)); + relation_signature const& sig = r.get_signature(); + expr_ref_vector vars(m); + var_subst sub(m, false); + for (unsigned i = 0; i < sig.size(); ++i) { + std::stringstream strm; + strm << "x" << i; + vars.push_back(m.mk_const(symbol(strm.str().c_str()), sig[i])); + } + + sub(tmp, vars.size(), vars.c_ptr(), tmp); + + smt_params fp; + smt::kernel solver(m, fp); + TRACE("doc", + tout << "Original formula:\n"; + tout << mk_pp(fml2, m) << "\n"; + tout << "Filtered formula: \n"; + tout << mk_pp(fml1,m) << "\n"; + tout << tmp << "\n"; + ); + solver.assert_expr(tmp); + lbool res = solver.check(); + SASSERT(res == l_false); + } }; void tst_udoc_relation() { udoc_tester tester; - tester.test1(); + try { + tester.test1(); + } + catch (z3_exception& ex) { + std::cout << ex.msg() << "\n"; + } } From f94bdf40351efc3da868764eb3c0977908058ade Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 20 Sep 2014 01:05:43 -0700 Subject: [PATCH 559/925] updated unit tests Signed-off-by: Nikolaj Bjorner --- src/muz/rel/doc.cpp | 2 +- src/muz/rel/tbv.cpp | 47 +++--- src/muz/rel/tbv.h | 3 + src/muz/rel/udoc_relation.cpp | 7 +- src/test/doc.cpp | 71 +++++++- src/test/udoc_relation.cpp | 300 +++++++++++++++++++++++++++------- 6 files changed, 346 insertions(+), 84 deletions(-) diff --git a/src/muz/rel/doc.cpp b/src/muz/rel/doc.cpp index baff1f504..6cf719fd2 100644 --- a/src/muz/rel/doc.cpp +++ b/src/muz/rel/doc.cpp @@ -415,8 +415,8 @@ void doc_manager::subtract(doc const& A, doc const& B, ptr_vector& result) r2 = allocate(B.neg()[i]); if (set_and(*r, *r2)) { result.push_back(r.detach()); - r = allocate(A); } + r = allocate(A); } } bool doc_manager::equals(doc const& a, doc const& b) const { diff --git a/src/muz/rel/tbv.cpp b/src/muz/rel/tbv.cpp index a83a3874e..23745f333 100644 --- a/src/muz/rel/tbv.cpp +++ b/src/muz/rel/tbv.cpp @@ -22,16 +22,20 @@ Revision History: #include "hashtable.h" -//#define _DEBUG_MEM 1 -#define _DEBUG_MEM 0 +static bool s_debug_alloc = false; + +void tbv_manager::debug_alloc() { + s_debug_alloc = true; +} tbv_manager::~tbv_manager() { -#if _DEBUG_MEM - ptr_vector::iterator it = allocated_tbvs.begin(), end = allocated_tbvs.end(); - for (; it != end; ++it) { - std::cout << "dangling: " << (*it) << "\n"; - } -#endif + DEBUG_CODE( + ptr_vector::iterator it = allocated_tbvs.begin(); + ptr_vector::iterator end = allocated_tbvs.end(); + for (; it != end; ++it) { + std::cout << "dangling: " << (*it) << "\n"; + TRACE("doc", tout << "dangling: " << (*it) << "\n";); + }); } void tbv_manager::reset() { @@ -39,10 +43,12 @@ void tbv_manager::reset() { } tbv* tbv_manager::allocate() { tbv* r = reinterpret_cast(m.allocate()); -#if _DEBUG_MEM - std::cout << allocated_tbvs.size() << " " << r << "\n"; - allocated_tbvs.insert(r); -#endif + DEBUG_CODE( + if (s_debug_alloc) { + TRACE("doc", tout << allocated_tbvs.size() << " " << r << "\n";); + } + allocated_tbvs.insert(r); + ); return r; } tbv* tbv_manager::allocate1() { @@ -145,14 +151,15 @@ tbv* tbv_manager::allocate(rational const& r) { return v; } void tbv_manager::deallocate(tbv* bv) { -#if _DEBUG_MEM - if (!allocated_tbvs.contains(bv)) { - std::cout << "double deallocate: " << bv << "\n"; - UNREACHABLE(); - } - std::cout << "deallocate: " << bv << "\n"; - allocated_tbvs.erase(bv); -#endif + DEBUG_CODE( + if (!allocated_tbvs.contains(bv)) { + std::cout << "double deallocate: " << bv << "\n"; + UNREACHABLE(); + } + if (s_debug_alloc) { + TRACE("doc", tout << "deallocate: " << bv << "\n";); + } + allocated_tbvs.erase(bv);); m.deallocate(bv); } void tbv_manager::copy(tbv& dst, tbv const& src) const { diff --git a/src/muz/rel/tbv.h b/src/muz/rel/tbv.h index f8c2d6643..90965f7d0 100644 --- a/src/muz/rel/tbv.h +++ b/src/muz/rel/tbv.h @@ -73,6 +73,8 @@ public: std::ostream& display(std::ostream& out, tbv const& b) const; tbv* project(unsigned n, bool const* to_delete, tbv const& src); bool is_well_formed(tbv const& b) const; // - does not contain BIT_z; + + static void debug_alloc(); }; class tbv: private fixed_bit_vector { @@ -132,6 +134,7 @@ public: return *this; } tbv& operator*() { return *d; } + tbv* operator->() { return d; } tbv* get() { return d; } tbv* detach() { tbv* result = d; d = 0; return result; } }; diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index a9a858c43..ebebe4063 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -667,6 +667,7 @@ namespace datalog { TRACE("doc", sub.display(dm, tout << "sub:") << "\n";); result.subtract(dm, sub); result.simplify(dm); + sub.reset(dm); TRACE("doc", result.display(dm, tout << "result:") << "\n";); } @@ -678,7 +679,11 @@ namespace datalog { arg = mk_not(m, to_app(g)->get_arg(i)); apply_guard(arg, sub, equalities, discard_cols); } + TRACE("doc", result.display(dm, tout << "result0:") << "\n";); result.subtract(dm, sub); + TRACE("doc", + sub.display(dm, tout << "sub:") << "\n"; + result.display(dm, tout << "result:") << "\n";); sub.reset(dm); } else if (m.is_true(g)) { @@ -897,7 +902,7 @@ namespace datalog { for (unsigned i = 0; i < m_removed_cols.size(); ++i) { m_col_list.set(m_removed_cols[i], true); } - m_to_delete.resize(m_removed_cols.size(), false); + m_to_delete.resize(t.get_num_bits(), false); for (unsigned i = 0; i < m_removed_cols.size(); ++i) { m_to_delete[m_removed_cols[i]] = true; } diff --git a/src/test/doc.cpp b/src/test/doc.cpp index 890ce4204..6bd7e50b9 100644 --- a/src/test/doc.cpp +++ b/src/test/doc.cpp @@ -167,6 +167,16 @@ class test_doc_cls { return result; } + expr_ref to_formula(udoc const& ud, doc_manager& m2, bool const* to_delete) { + expr_ref result(m); + expr_ref_vector disjs(m); + for (unsigned i = 0; i < ud.size(); ++i) { + disjs.push_back(to_formula(ud[i], m2, to_delete)); + } + result = mk_or(m, disjs.size(), disjs.c_ptr()); + return result; + } + void project(doc const& d, doc_manager& m2, bool const* to_delete, doc_ref& result) { result = dm.project(m2, m_vars.size(), to_delete, d); TRACE("doc", @@ -264,15 +274,20 @@ class test_doc_cls { } rw(fml1); rw(fml2); + check_equiv(fml1, fml2); + } + + void check_equiv(expr* fml1, expr* fml2) { smt_params fp; smt::kernel solver(m, fp); - TRACE("doc", tout << "manual project:\n" << fml1 << "\nautomatic project: \n" << fml2 << "\n";); + expr_ref fml(m); fml = m.mk_not(m.mk_eq(fml1, fml2)); solver.assert_expr(fml); lbool res = solver.check(); SASSERT(res == l_false); } + public: test_doc_cls(unsigned num_vars): dm(num_vars), m_vars(m) { reg_decl_plugins(m); @@ -292,15 +307,61 @@ public: test_merge(num_clauses); } } + + void test_subtract() { + doc_ref d1(dm); + doc_ref d2(dm); + doc_ref d3(dm); + udoc ds1, ds2; + d1 = dm.allocateX(); + d2 = dm.allocateX(); + d3 = dm.allocateX(); + dm.set(*d1, 0, BIT_1); + dm.set(*d1, 1, BIT_0); + dm.set(*d2, 0, BIT_0); + dm.set(*d2, 1, BIT_1); + //ds1.push_back(d1.detach()); + ds1.push_back(d2.detach()); + // ds1 = {10x, 01x} + d1 = dm.allocateX(); + tbv_ref t1(dm.tbvm()); + tbv_ref t2(dm.tbvm()); + t1 = dm.tbvm().allocateX(); + t2 = dm.tbvm().allocateX(); + t1->set(0, BIT_1); + t1->set(2, BIT_0); + t2->set(0, BIT_0); + t2->set(2, BIT_1); + d1->neg().push_back(t1.detach()); + d1->neg().push_back(t2.detach()); + ds2.push_back(d1.detach()); + ds1.display(dm, std::cout) << "\n"; + ds2.display(dm, std::cout) << "\n"; + svector to_delete(m_vars.size(), false); + expr_ref fml1 = to_formula(ds1, dm, to_delete.c_ptr()); + expr_ref fml2 = to_formula(ds2, dm, to_delete.c_ptr()); + ds1.subtract(dm, ds2); + ds1.display(dm, std::cout) << "\n"; + expr_ref fml3 = to_formula(ds1, dm, to_delete.c_ptr()); + fml1 = m.mk_and(fml1, m.mk_not(fml2)); + check_equiv(fml1, fml3); + ds1.reset(dm); + ds2.reset(dm); + //sub:{xxx \ {1x0, 0x1}} + //result:{100} + } + }; void tst_doc() { + + test_doc_cls tp(4); + tp.test_subtract(); + tp.test_merge(200,7); + tp.test_project(200,7); + tst_doc1(5); tst_doc1(10); tst_doc1(70); - - test_doc_cls tp(4); - tp.test_merge(200,7); - tp.test_project(200,7); } diff --git a/src/test/udoc_relation.cpp b/src/test/udoc_relation.cpp index e307455cc..67a008688 100644 --- a/src/test/udoc_relation.cpp +++ b/src/test/udoc_relation.cpp @@ -87,6 +87,43 @@ public: relation_base* t; udoc_relation* t1, *t2, *t3; expr_ref fml(m); + + // filter_by_negation + + /* + The filter_by_negation postcondition: + filter_by_negation(tgt, neg, columns in tgt: c1,...,cN, + corresponding columns in neg: d1,...,dN): + tgt_1:={x: x\in tgt_0 && ! \exists y: ( y \in neg & pi_c1(x)= pi_d1(y) & ... & pi_cN(x)= pi_dN(y) ) } + */ + { + relation_signature sig4; + sig4.push_back(bv.mk_sort(1)); + sig4.push_back(bv.mk_sort(1)); + sig4.push_back(bv.mk_sort(1)); + t1 = mk_empty(sig4); + t2 = mk_empty(sig4); + unsigned_vector cols1, cols2; + unsigned num_bits = t1->get_dm().num_tbits(); + + cols1.push_back(0); + cols2.push_back(1); + for (unsigned i = 0; i < 100; ++i) { + set_random(*t1, 2*num_bits/3); + set_random(*t2, 2*num_bits/3); + apply_filter_neg(*t1,*t2, cols1, cols2); + } + cols1.push_back(1); + cols2.push_back(2); + for (unsigned i = 0; i < 100; ++i) { + set_random(*t1, 2*num_bits/3); + set_random(*t2, 2*num_bits/3); + apply_filter_neg(*t1,*t2, cols1, cols2); + } + t1->deallocate(); + t2->deallocate(); + } + // empty { std::cout << "empty\n"; @@ -228,6 +265,22 @@ public: t1->display(std::cout); std::cout << "\n"; t1->deallocate(); } + + // tbv_manager::debug_alloc(); + { + relation_signature sig3; + sig3.push_back(m.mk_bool_sort()); + sig3.push_back(m.mk_bool_sort()); + sig3.push_back(m.mk_bool_sort()); + var_ref v0(m.mk_var(0, m.mk_bool_sort()),m); + var_ref v1(m.mk_var(1, m.mk_bool_sort()),m); + var_ref v2(m.mk_var(2, m.mk_bool_sort()),m); + app_ref cond1(m); + t1 = mk_full(sig3); + cond1 = m.mk_eq(v0,v1); + apply_filter(*t1, cond1); + t1->deallocate(); + } { relation_signature sig3; @@ -238,8 +291,8 @@ public: var_ref v1(m.mk_var(1, m.mk_bool_sort()),m); var_ref v2(m.mk_var(2, m.mk_bool_sort()),m); app_ref cond1(m); - cond1 = m.mk_or(m.mk_eq(v0,v1),m.mk_eq(v0,v2)); t1 = mk_full(sig3); + cond1 = m.mk_or(m.mk_eq(v0,v1),m.mk_eq(v0,v2)); apply_filter(*t1, cond1); t1->deallocate(); } @@ -259,73 +312,138 @@ public: t1->deallocate(); } + + app_ref_vector conds(m); + app_ref cond1(m); + var_ref v0(m.mk_var(0, bv.mk_sort(3)),m); + var_ref v1(m.mk_var(1, bv.mk_sort(6)),m); + var_ref v2(m.mk_var(2, bv.mk_sort(3)),m); + var_ref v3(m.mk_var(3, bv.mk_sort(3)),m); + var_ref v4(m.mk_var(4, bv.mk_sort(3)),m); + conds.push_back(m.mk_true()); + conds.push_back(m.mk_false()); + conds.push_back(m.mk_eq(v0, v2)); + conds.push_back(m.mk_not(m.mk_eq(v0, v2))); + conds.push_back(m.mk_eq(v0, bv.mk_numeral(rational(2), 3))); + cond1 = m.mk_eq(ex(2,1,v0),bv.mk_numeral(rational(3),2)); + conds.push_back(cond1); + conds.push_back(m.mk_or(cond1,m.mk_eq(v3,v4))); + conds.push_back(m.mk_or(cond1,m.mk_eq(ex(2,1,v3),ex(1,0,v4)))); + conds.push_back(m.mk_or(m.mk_eq(v0,v2),m.mk_eq(v0,v4))); + conds.push_back(m.mk_or(m.mk_eq(v0,v2),m.mk_eq(v3,v4))); + conds.push_back(m.mk_or(m.mk_eq(ex(2,1,v0),ex(1,0,v2)),m.mk_eq(v3,v4))); + conds.push_back(m.mk_or(m.mk_eq(ex(2,1,v0),bv.mk_numeral(rational(3),2)), + m.mk_eq(v3,v4))); + conds.push_back(m.mk_or(m.mk_eq(ex(2,1,v0),bv.mk_numeral(rational(3),2)), + m.mk_eq(v3,bv.mk_numeral(rational(3),3)))); + conds.push_back(m.mk_or(m.mk_eq(v0,bv.mk_numeral(rational(5),3)), + m.mk_eq(v3,bv.mk_numeral(rational(5),3)))); + conds.push_back(m.mk_or(m.mk_eq(v0,bv.mk_numeral(rational(7),3)), + m.mk_eq(v3,bv.mk_numeral(rational(7),3)))); + conds.push_back(m.mk_not(m.mk_or(m.mk_eq(v0,v2),m.mk_eq(v3,v4)))); + + // filter_interpreted { std::cout << "filter interpreted\n"; t1 = mk_full(sig2); - var_ref v0(m.mk_var(0, bv.mk_sort(3)),m); - var_ref v1(m.mk_var(1, bv.mk_sort(6)),m); - var_ref v2(m.mk_var(2, bv.mk_sort(3)),m); - var_ref v3(m.mk_var(3, bv.mk_sort(3)),m); - var_ref v4(m.mk_var(4, bv.mk_sort(3)),m); - app_ref cond1(m), cond2(m), cond3(m), cond4(m); - app_ref cond5(m), cond6(m), cond7(m), cond8(m); - cond1 = m.mk_true(); - cond2 = m.mk_false(); - cond3 = m.mk_eq(v0, v2); - cond4 = m.mk_not(m.mk_eq(v0, v2)); - cond5 = m.mk_eq(v0, bv.mk_numeral(rational(2), 3)); - - apply_filter(*t1, cond1); - apply_filter(*t1, cond2); - apply_filter(*t1, cond3); - apply_filter(*t1, cond4); - apply_filter(*t1, cond5); - - cond1 = m.mk_eq(ex(2,1,v0),bv.mk_numeral(rational(3),2)); - apply_filter(*t1, cond1); - - cond2 = m.mk_or(cond1,m.mk_eq(v3,v4)); - apply_filter(*t1, cond2); - - cond2 = m.mk_or(cond1,m.mk_eq(ex(2,1,v3),ex(1,0,v4))); - apply_filter(*t1, cond2); - - cond1 = m.mk_or(m.mk_eq(v0,v2),m.mk_eq(v0,v4)); - apply_filter(*t1, cond1); - - cond1 = m.mk_or(m.mk_eq(v0,v2),m.mk_eq(v3,v4)); - apply_filter(*t1, cond1); - - cond1 = m.mk_or(m.mk_eq(ex(2,1,v0),ex(1,0,v2)),m.mk_eq(v3,v4)); - apply_filter(*t1, cond1); - - cond1 = m.mk_or(m.mk_eq(ex(2,1,v0),bv.mk_numeral(rational(3),2)), - m.mk_eq(v3,v4)); - apply_filter(*t1, cond1); - - cond1 = m.mk_or(m.mk_eq(ex(2,1,v0),bv.mk_numeral(rational(3),2)), - m.mk_eq(v3,bv.mk_numeral(rational(3),5))); - apply_filter(*t1, cond1); - - cond1 = m.mk_or(m.mk_eq(v0,bv.mk_numeral(rational(5),3)), - m.mk_eq(v3,bv.mk_numeral(rational(5),3))); - apply_filter(*t1, cond1); - - cond1 = m.mk_or(m.mk_eq(v0,bv.mk_numeral(rational(7),3)), - m.mk_eq(v3,bv.mk_numeral(rational(7),3))); - apply_filter(*t1, cond1); - - cond1 = m.mk_not(m.mk_or(m.mk_eq(v0,v2),m.mk_eq(v3,v4))); - apply_filter(*t1, cond1); + for (unsigned i = 0; i < conds.size(); ++i) { + apply_filter(*t1, conds[i].get()); + } t1->deallocate(); } - // filter_by_negation // filter_interpreted_project + { + unsigned_vector remove; + remove.push_back(0); + remove.push_back(2); + t1 = mk_full(sig2); + for (unsigned i = 0; i < conds.size(); ++i) { + apply_filter_project(*t1, remove, conds[i].get()); + } + remove[1] = 1; + for (unsigned i = 0; i < conds.size(); ++i) { + apply_filter_project(*t1, remove, conds[i].get()); + } + t1->deallocate(); + } + + + } + + void set_random(udoc_relation& r, unsigned num_vals) { + unsigned num_bits = r.get_dm().num_tbits(); + udoc_relation* full = mk_full(r.get_signature()); + rel_union union_fn = p.mk_union_fn(r, r, 0); + (*union_fn)(r, *full); + doc_manager& dm = r.get_dm(); + SASSERT(r.get_udoc().size() == 1); + doc& d0 = r.get_udoc()[0]; + SASSERT(dm.is_full(d0)); + for (unsigned i = 0; i < num_vals; ++i) { + unsigned idx = m_rand(num_bits); + unsigned val = m_rand(2); + tbit b = (val == 0)?BIT_0:BIT_1; + dm.set(d0, idx, b); + } + } + + void apply_filter_neg(udoc_relation& t1, udoc_relation& t2, + unsigned_vector const& cols1, unsigned_vector const& cols2) { + + relation_signature const& sig = t1.get_signature(); + scoped_ptr negf; + negf = p.mk_filter_by_negation_fn(t1, t2, cols1.size(), cols1.c_ptr(), cols2.c_ptr()); + expr_ref fml1(m), fml2(m), fml3(m); + t1.to_formula(fml1); + t2.to_formula(fml2); + (*negf)(t1, t2); + t1.to_formula(fml3); + std::cout << fml1 << "\n"; + std::cout << fml2 << "\n"; + std::cout << fml3 << "\n"; + expr_ref_vector eqs(m); + expr_ref_vector sub(m); + for (unsigned i = 0; i < sig.size(); ++i) { + sub.push_back(m.mk_var(i+sig.size(),sig[i])); + } + var_subst subst(m, false); + subst(fml2, sub.size(), sub.c_ptr(), fml2); + eqs.push_back(fml2); + for (unsigned i = 0; i < cols1.size(); ++i) { + var_ref v1(m), v2(m); + unsigned c1 = cols1[i]; + unsigned c2 = cols2[i]; + v1 = m.mk_var(c1, sig[c1]); + v2 = m.mk_var(sig.size() + c2, sig[c2]); + eqs.push_back(m.mk_eq(v1,v2)); + } + fml2 = mk_and(m, eqs.size(), eqs.c_ptr()); + for (unsigned i = 0; i < sub.size(); ++i) { + project_var(sig.size() + i, m.get_sort(sub[i].get()), fml2); + } + fml1 = m.mk_and(fml1, fml2); + + expr_ref_vector vars(m); + for (unsigned i = 0; i < sig.size(); ++i) { + std::stringstream strm; + strm << "x" << i; + vars.push_back(m.mk_const(symbol(strm.str().c_str()), sig[i])); + } + + subst(fml1, vars.size(), vars.c_ptr(), fml1); + subst(fml3, vars.size(), vars.c_ptr(), fml3); + + check_equiv(fml1, fml3); + /* + + tgt_1:={ x: x\in tgt_0 && ! \exists y: + ( y \in neg & pi_c1(x)= pi_d1(y) & ... & pi_cN(x)= pi_dN(y) ) } + */ } expr_ref ex(unsigned hi, unsigned lo, expr* e) { @@ -334,6 +452,74 @@ public: return result; } + void apply_filter_project(udoc_relation& t, unsigned_vector const& rm, app* cond) { + scoped_ptr rt; + rt = p.mk_filter_interpreted_and_project_fn(t, cond, rm.size(), rm.c_ptr()); + udoc_relation* full = mk_full(t.get_signature()); + rel_union union_fn = p.mk_union_fn(t, *full, 0); + (*union_fn)(t, *full, 0); + datalog::relation_base* result = (*rt)(t); + + for (unsigned i = 0; i < rm.size(); ++i) { + std::cout << rm[i] << " "; + } + std::cout << mk_pp(cond, m) << "\n"; + t.display(std::cout); + result->display(std::cout); + result->deallocate(); + full->deallocate(); + } + + void verify_filter_project(udoc_relation const& r, unsigned_vector const& rm, app* cond) { + expr_ref fml(m), cfml(m); + r.to_formula(fml); + cfml = cond; + relation_signature const& sig = r.get_signature(); + expr_ref_vector vars(m); + for (unsigned i = 0, j = 0, k = 0; i < sig.size(); ++i) { + if (j < rm.size() && rm[j] == i) { + project_var(i, sig[i], cfml); + ++j; + } + else { + vars.push_back(m.mk_var(k, sig[i])); + ++k; + } + } + + + check_equiv(fml, cfml); + } + + void check_equiv(expr* fml1, expr* fml2) { + TRACE("doc", tout << mk_pp(fml1, m) << "\n"; + tout << mk_pp(fml2, m) << "\n";); + smt_params fp; + smt::kernel solver(m, fp); + expr_ref tmp(m); + tmp = m.mk_not(m.mk_eq(fml1, fml2)); + solver.assert_expr(tmp); + lbool res = solver.check(); + SASSERT(res == l_false); + } + + void project_var(unsigned i, sort* s, expr_ref& fml) { + var_ref v(m); + v = m.mk_var(i, s); + unsigned num_bits = bv.get_bv_size(s); + unsigned p = 1 << num_bits; + expr_ref_vector disj(m); + expr_ref tmp(m); + for (unsigned i = 0; i < p; ++i) { + expr_safe_replace repl(m); + repl.insert(v, bv.mk_numeral(rational(i), s)); + tmp = fml; + repl(tmp); + disj.push_back(tmp); + } + fml = mk_or(m, disj.size(), disj.c_ptr()); + } + void apply_filter(udoc_relation& t, app* cond) { udoc_relation* full = mk_full(t.get_signature()); rel_union union_fn = p.mk_union_fn(t, *full, 0); From 2552c1530b09fca4480196467a35ab58d31f3bae Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 20 Sep 2014 10:19:54 -0700 Subject: [PATCH 560/925] doc unit tests pass Signed-off-by: Nikolaj Bjorner --- src/muz/rel/doc.cpp | 5 +- src/muz/rel/doc.h | 15 ++-- src/muz/rel/udoc_relation.cpp | 154 ++++++++++++++++++++++------------ src/muz/rel/udoc_relation.h | 6 +- src/test/udoc_relation.cpp | 84 +++++++++++-------- 5 files changed, 166 insertions(+), 98 deletions(-) diff --git a/src/muz/rel/doc.cpp b/src/muz/rel/doc.cpp index 6cf719fd2..1db1ac2b7 100644 --- a/src/muz/rel/doc.cpp +++ b/src/muz/rel/doc.cpp @@ -192,14 +192,15 @@ void doc_manager::set(doc& d, unsigned idx, tbit value) { // bool doc_manager::merge( doc& d, unsigned lo, unsigned length, - subset_ints& equalities, bit_vector const& discard_cols) { + subset_ints const& equalities, bit_vector const& discard_cols) { for (unsigned i = 0; i < length; ++i) { unsigned idx = lo + i; if (!merge(d, lo + i, equalities, discard_cols)) return false; } return true; } -bool doc_manager::merge(doc& d, unsigned idx, subset_ints& equalities, bit_vector const& discard_cols) { +bool doc_manager::merge(doc& d, unsigned idx, subset_ints const& equalities, + bit_vector const& discard_cols) { unsigned root = equalities.find(idx); idx = root; unsigned num_x = 0; diff --git a/src/muz/rel/doc.h b/src/muz/rel/doc.h index 510ee8bef..e56196026 100644 --- a/src/muz/rel/doc.h +++ b/src/muz/rel/doc.h @@ -69,11 +69,11 @@ public: unsigned num_tbits() const { return m.num_tbits(); } doc* project(doc_manager& dstm, unsigned n, bool const* to_delete, doc const& src); bool well_formed(doc const& d) const; - bool merge(doc& d, unsigned lo, unsigned length, subset_ints& equalities, bit_vector const& discard_cols); + bool merge(doc& d, unsigned lo, unsigned length, subset_ints const& equalities, bit_vector const& discard_cols); void set(doc& d, unsigned idx, tbit value); private: unsigned diff_by_012(tbv const& pos, tbv const& neg, unsigned& index); - bool merge(doc& d, unsigned idx, subset_ints& equalities, bit_vector const& discard_cols); + bool merge(doc& d, unsigned idx, subset_ints const& equalities, bit_vector const& discard_cols); bool can_project_neg(tbv const& pos, unsigned n, bool const* to_delete, tbv const& neg); }; @@ -233,7 +233,7 @@ public: std::swap(*this, result); } - void merge(M& m, unsigned lo, unsigned length, subset_ints & equalities, bit_vector const& discard_cols) { + void merge(M& m, unsigned lo, unsigned length, subset_ints const& equalities, bit_vector const& discard_cols) { for (unsigned i = 0; i < size(); ++i) { if (!m.merge(*m_elems[i], lo, length, equalities, discard_cols)) { erase(m, i); @@ -254,9 +254,12 @@ public: merge(m, lo1, length, equalities, discard_cols); } - -private: - + void merge(M& m, unsigned_vector const& roots, subset_ints const& equalities, + bit_vector const& discard_cols) { + for (unsigned i = 0; i < roots.size(); ++i) { + merge(m, roots[i], equalities, discard_cols); + } + } }; diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index ebebe4063..874885e5f 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -116,6 +116,7 @@ namespace datalog { break; case BIT_x: if (!is_x) { + SASSERT(p.bv.is_bv_sort(get_signature()[i])); conjs.push_back(m.mk_eq(p.bv.mk_extract(j-1-lo,lo1-lo,v), p.bv.mk_numeral(r,j-lo1))); } @@ -185,6 +186,23 @@ namespace datalog { } return *r; } + bool udoc_relation::is_var_range(expr* e, unsigned& hi, unsigned& lo, unsigned& v) const { + udoc_plugin& p = get_plugin(); + if (is_var(e)) { + v = to_var(e)->get_idx(); + hi = p.num_sort_bits(e)-1; + lo = 0; + return true; + } + expr* e2; + if (p.bv.is_extract(e, lo, hi, e2) && is_var(e2)) { + v = to_var(e2)->get_idx(); + SASSERT(lo <= hi); + return true; + } + return false; + } + expr* udoc_plugin::mk_numeral(rational const& r, sort* s) { if (bv.is_bv_sort(s)) { return bv.mk_numeral(r, s); @@ -576,16 +594,14 @@ namespace datalog { udoc_plugin& p = get_plugin(); ast_manager& m = p.get_ast_manager(); bv_util& bv = p.bv; - expr* e1, *e2, *e3; - unsigned hi, lo; + expr* e1, *e2; + unsigned hi, lo, v; if (m.is_and(g) || m.is_or(g) || m.is_not(g) || m.is_true(g) || m.is_false(g)) { return is_guard(to_app(g)->get_num_args(), to_app(g)->get_args()); } if (m.is_eq(g, e1, e2) && bv.is_bv(e1)) { - if (is_var(e1) && is_ground(e2)) return true; - if (is_var(e2) && is_ground(e1)) return true; - if (bv.is_extract(e1, lo, hi, e3) && is_var(e3) && is_ground(e2)) return true; - if (bv.is_extract(e2, lo, hi, e3) && is_var(e3) && is_ground(e1)) return true; + if (is_var_range(e1, hi, lo, v) && is_ground(e2)) return true; + if (is_var_range(e2, hi, lo, v) && is_ground(e1)) return true; } if (is_var(g)) { return true; @@ -611,6 +627,37 @@ namespace datalog { guard = mk_and(m, guards.size(), guards.c_ptr()); rest = mk_and(m, rests.size(), rests.c_ptr()); } + void udoc_relation::extract_equalities(expr* g, expr_ref& rest, subset_ints& equalities, + unsigned_vector& roots) const { + rest.reset(); + ast_manager& m = get_plugin().get_ast_manager(); + expr_ref_vector conds(m); + conds.push_back(g); + qe::flatten_and(conds); + expr* e1, *e2; + unsigned v1, v2, lo1, lo2, hi1, hi2; + for (unsigned i = 0; i < conds.size(); ++i) { + expr* g = conds[i].get(); + if (m.is_eq(g, e1, e2) && + is_var_range(e1, hi1, lo1, v1) && + is_var_range(e2, hi2, lo2, v2)) { + unsigned col1 = column_idx(v1); + lo1 += col1; + hi1 += col1; + unsigned col2 = column_idx(v2); + lo2 += col2; + hi2 += col2; + for (unsigned j = 0; j <= hi1-lo1; ++j) { + roots.push_back(lo1 + j); + equalities.merge(lo1 + j, lo2 + j); + } + conds[i] = conds.back(); + conds.pop_back(); + --i; + } + } + rest = mk_and(m, conds.size(), conds.c_ptr()); + } void udoc_relation::compile_guard(expr* g, udoc& d, bit_vector const& discard_cols) const { d.reset(dm); d.push_back(dm.allocateX()); @@ -625,12 +672,11 @@ namespace datalog { } apply_guard(g, result, equalities, discard_cols); } - bool udoc_relation::apply_eq(expr* g, udoc& result, var* v, unsigned hi, unsigned lo, expr* c) const { + bool udoc_relation::apply_eq(expr* g, udoc& result, unsigned v, unsigned hi, unsigned lo, expr* c) const { udoc_plugin& p = get_plugin(); unsigned num_bits; rational r; - unsigned idx = v->get_idx(); - unsigned col = column_idx(idx); + unsigned col = column_idx(v); lo += col; hi += col; if (p.is_numeral(c, r, num_bits)) { @@ -644,7 +690,7 @@ namespace datalog { } void udoc_relation::apply_guard( - expr* g, udoc& result, subset_ints& equalities, bit_vector const& discard_cols) const { + expr* g, udoc& result, subset_ints const& equalities, bit_vector const& discard_cols) const { ast_manager& m = get_plugin().get_ast_manager(); bv_util& bv = get_plugin().bv; expr* e1, *e2; @@ -660,16 +706,16 @@ namespace datalog { // the equivalence class to collapse. // It seems the current organization with fix_eq_bits // will merge the equivalence class as a side-effect. - TRACE("doc", result.display(dm, tout << "result0:") << "\n";); udoc sub; sub.push_back(dm.allocateX()); apply_guard(e1, sub, equalities, discard_cols); - TRACE("doc", sub.display(dm, tout << "sub:") << "\n";); + TRACE("doc", + result.display(dm, tout << "result0:") << "\n"; + sub.display(dm, tout << "sub:") << "\n";); result.subtract(dm, sub); result.simplify(dm); sub.reset(dm); TRACE("doc", result.display(dm, tout << "result:") << "\n";); - } else if (m.is_or(g)) { udoc sub; @@ -717,36 +763,20 @@ namespace datalog { diff2.reset(dm); } else if (m.is_eq(g, e1, e2) && bv.is_bv(e1)) { - unsigned hi, lo, lo1, lo2, hi1, hi2; - expr* e3, *e4; - if (is_var(e1) && is_ground(e2) && - apply_eq(g, result, to_var(e1), bv.get_bv_size(e1)-1, 0, e2)) { + unsigned hi, lo, lo1, lo2, hi1, hi2, v, v1, v2; + if (is_var_range(e1, hi, lo, v) && is_ground(e2) && + apply_eq(g, result, v, hi, lo, e2)) { } - else if (is_var(e2) && is_ground(e1) && - apply_eq(g, result, to_var(e2), bv.get_bv_size(e2)-1, 0, e1)) { + else if (is_var_range(e2, hi, lo, v) && is_ground(e1) && + apply_eq(g, result, v, hi, lo, e1)) { } - else if (bv.is_extract(e1, lo, hi, e3) && is_var(e3) && is_ground(e2) && - apply_eq(g, result, to_var(e3), hi, lo, e2)) { - } - else if (bv.is_extract(e2, lo, hi, e3) && is_var(e3) && is_ground(e1) && - apply_eq(g, result, to_var(e3), hi, lo, e1)) { - } - else if (is_var(e1) && is_var(e2)) { - var* v1 = to_var(e1); - var* v2 = to_var(e2); - unsigned idx1 = column_idx(v1->get_idx()); - unsigned idx2 = column_idx(v2->get_idx()); - unsigned length = column_num_bits(v1->get_idx()); + else if (is_var_range(e1, hi1, lo1, v1) && + is_var_range(e2, hi2, lo2, v2)) { + unsigned idx1 = lo1 + column_idx(v1); + unsigned idx2 = lo2 + column_idx(v2); + unsigned length = hi1-lo1+1; result.merge(dm, idx1, idx2, length, discard_cols); } - else if (bv.is_extract(e1, lo1, hi1, e3) && is_var(e3) && - bv.is_extract(e2, lo2, hi2, e4) && is_var(e4)) { - var* v1 = to_var(e3); - var* v2 = to_var(e4); - unsigned idx1 = lo1 + column_idx(v1->get_idx()); - unsigned idx2 = lo2 + column_idx(v2->get_idx()); - result.merge(dm, idx1, idx2, hi1-lo1+1, discard_cols); - } else { goto failure_case; } @@ -760,16 +790,24 @@ namespace datalog { } class udoc_plugin::filter_interpreted_fn : public relation_mutator_fn { + union_find_default_ctx union_ctx; doc_manager& dm; expr_ref m_condition; udoc m_udoc; bit_vector m_empty_bv; + subset_ints m_equalities; + public: filter_interpreted_fn(const udoc_relation & t, ast_manager& m, app *condition) : dm(t.get_dm()), - m_condition(m) { - m_empty_bv.resize(t.get_num_bits(), false); - expr_ref guard(m), rest(m); + m_condition(m), + m_equalities(union_ctx) { + unsigned num_bits = t.get_num_bits(); + m_empty_bv.resize(num_bits, false); + expr_ref guard(m); + for (unsigned i = 0; i < num_bits; ++i) { + m_equalities.mk_var(); + } t.extract_guard(condition, guard, m_condition); t.compile_guard(guard, m_udoc, m_empty_bv); if (m.is_true(m_condition)) { @@ -790,7 +828,7 @@ namespace datalog { udoc& u = t.get_udoc(); u.intersect(dm, m_udoc); if (m_condition && !u.is_empty()) { - t.apply_guard(m_condition, u, m_empty_bv); + t.apply_guard(m_condition, u, m_equalities, m_empty_bv); } u.simplify(dm); TRACE("doc", tout << "final size: " << t.get_size_estimate_rows() << '\n';); @@ -821,7 +859,7 @@ namespace datalog { bool done_i = false; for (unsigned j = 0; !done_i && j < neg.size(); ++j) { bool done_j = false; - for (unsigned c = 0; !done_i && !done_j && c < m_t_cols.size(); ++c) { + for (unsigned c = 0; !done_j && c < m_t_cols.size(); ++c) { unsigned t_col = m_t_cols[c]; unsigned n_col = m_neg_cols[c]; unsigned num_bits = t.column_num_bits(t_col); @@ -837,12 +875,12 @@ namespace datalog { } if (done_j) { result.push_back(&dst[i]); - } - else { - dm.deallocate(&dst[i]); done_i = true; } } + if (!done_i) { + dm.deallocate(&dst[i]); + } } std::swap(dst, result); if (dst.is_empty()) { @@ -859,6 +897,7 @@ namespace datalog { renamed_neg.push_back(newD.detach()); } dst.subtract(t.get_dm(), renamed_neg); + renamed_neg.reset(t.get_dm()); } void copy_column( doc& dst, doc const& src, @@ -886,19 +925,28 @@ namespace datalog { } class udoc_plugin::filter_proj_fn : public convenient_relation_project_fn { + union_find_default_ctx union_ctx; doc_manager& dm; expr_ref m_condition; udoc m_udoc; bit_vector m_col_list; // map: col idx -> bool (whether the column is to be removed) svector m_to_delete; // same + subset_ints m_equalities; + unsigned_vector m_roots; + public: filter_proj_fn(const udoc_relation & t, ast_manager& m, app *condition, unsigned col_cnt, const unsigned * removed_cols) : convenient_relation_project_fn(t.get_signature(), col_cnt, removed_cols), dm(t.get_dm()), - m_condition(m) { + m_condition(m), + m_equalities(union_ctx) { t.expand_column_vector(m_removed_cols); - m_col_list.resize(t.get_num_bits(), false); + unsigned num_bits = t.get_num_bits(); + m_col_list.resize(num_bits, false); + for (unsigned i = 0; i < num_bits; ++i) { + m_equalities.mk_var(); + } for (unsigned i = 0; i < m_removed_cols.size(); ++i) { m_col_list.set(m_removed_cols[i], true); } @@ -906,8 +954,9 @@ namespace datalog { for (unsigned i = 0; i < m_removed_cols.size(); ++i) { m_to_delete[m_removed_cols[i]] = true; } - expr_ref guard(m), rest(m); - t.extract_guard(condition, guard, m_condition); + expr_ref guard(m), non_eq_cond(m); + t.extract_equalities(condition, non_eq_cond, m_equalities, m_roots); + t.extract_guard(non_eq_cond, guard, m_condition); t.compile_guard(guard, m_udoc, m_col_list); if (m.is_true(m_condition)) { m_condition = 0; @@ -924,8 +973,9 @@ namespace datalog { udoc u2; u2.copy(dm, u1); u2.intersect(dm, m_udoc); + u2.merge(dm, m_roots, m_equalities, m_col_list); if (m_condition && !u2.is_empty()) { - t.apply_guard(m_condition, u2, m_col_list); + t.apply_guard(m_condition, u2, m_equalities, m_col_list); } udoc_relation* r = get(t.get_plugin().mk_empty(get_result_signature())); doc_manager& dm2 = r->get_dm(); diff --git a/src/muz/rel/udoc_relation.h b/src/muz/rel/udoc_relation.h index 4befa228a..697928d60 100644 --- a/src/muz/rel/udoc_relation.h +++ b/src/muz/rel/udoc_relation.h @@ -65,9 +65,11 @@ namespace datalog { bool is_guard(expr* g) const; bool is_guard(unsigned n, expr* const *g) const; void compile_guard(expr* g, udoc& result, bit_vector const& discard_cols) const; + void extract_equalities(expr* g, expr_ref& rest, subset_ints& equalities, unsigned_vector& roots) const; void apply_guard(expr* g, udoc& result, bit_vector const& discard_cols) const; - void apply_guard(expr* g, udoc& result, subset_ints& equalities, bit_vector const& discard_cols) const; - bool apply_eq(expr* g, udoc& result, var* v, unsigned hi, unsigned lo, expr* c) const; + void apply_guard(expr* g, udoc& result, subset_ints const& equalities, bit_vector const& discard_cols) const; + bool apply_eq(expr* g, udoc& result, unsigned v, unsigned hi, unsigned lo, expr* c) const; + bool is_var_range(expr* e, unsigned& hi, unsigned& lo, unsigned& v) const; }; class udoc_plugin : public relation_plugin { diff --git a/src/test/udoc_relation.cpp b/src/test/udoc_relation.cpp index 67a008688..13623aeeb 100644 --- a/src/test/udoc_relation.cpp +++ b/src/test/udoc_relation.cpp @@ -88,41 +88,7 @@ public: udoc_relation* t1, *t2, *t3; expr_ref fml(m); - // filter_by_negation - - /* - The filter_by_negation postcondition: - filter_by_negation(tgt, neg, columns in tgt: c1,...,cN, - corresponding columns in neg: d1,...,dN): - tgt_1:={x: x\in tgt_0 && ! \exists y: ( y \in neg & pi_c1(x)= pi_d1(y) & ... & pi_cN(x)= pi_dN(y) ) } - */ - { - relation_signature sig4; - sig4.push_back(bv.mk_sort(1)); - sig4.push_back(bv.mk_sort(1)); - sig4.push_back(bv.mk_sort(1)); - t1 = mk_empty(sig4); - t2 = mk_empty(sig4); - unsigned_vector cols1, cols2; - unsigned num_bits = t1->get_dm().num_tbits(); - - cols1.push_back(0); - cols2.push_back(1); - for (unsigned i = 0; i < 100; ++i) { - set_random(*t1, 2*num_bits/3); - set_random(*t2, 2*num_bits/3); - apply_filter_neg(*t1,*t2, cols1, cols2); - } - cols1.push_back(1); - cols2.push_back(2); - for (unsigned i = 0; i < 100; ++i) { - set_random(*t1, 2*num_bits/3); - set_random(*t2, 2*num_bits/3); - apply_filter_neg(*t1,*t2, cols1, cols2); - } - t1->deallocate(); - t2->deallocate(); - } + test_filter_neg(); // empty { @@ -328,6 +294,7 @@ public: cond1 = m.mk_eq(ex(2,1,v0),bv.mk_numeral(rational(3),2)); conds.push_back(cond1); conds.push_back(m.mk_or(cond1,m.mk_eq(v3,v4))); + conds.push_back(m.mk_eq(ex(2,1,v3),ex(1,0,v4))); conds.push_back(m.mk_or(cond1,m.mk_eq(ex(2,1,v3),ex(1,0,v4)))); conds.push_back(m.mk_or(m.mk_eq(v0,v2),m.mk_eq(v0,v4))); conds.push_back(m.mk_or(m.mk_eq(v0,v2),m.mk_eq(v3,v4))); @@ -375,6 +342,43 @@ public: } + /* + The filter_by_negation postcondition: + filter_by_negation(tgt, neg, columns in tgt: c1,...,cN, + corresponding columns in neg: d1,...,dN): + tgt_1:={x: x\in tgt_0 && ! \exists y: ( y \in neg & pi_c1(x)= pi_d1(y) & ... & pi_cN(x)= pi_dN(y) ) } + */ + + void test_filter_neg() { + // filter_by_negation + + relation_signature sig4; + sig4.push_back(bv.mk_sort(1)); + sig4.push_back(bv.mk_sort(1)); + sig4.push_back(bv.mk_sort(1)); + udoc_relation* t1 = mk_empty(sig4); + udoc_relation* t2 = mk_empty(sig4); + unsigned_vector cols1, cols2; + unsigned num_bits = t1->get_dm().num_tbits(); + + cols1.push_back(0); + cols2.push_back(1); + for (unsigned i = 0; i < 100; ++i) { + set_random(*t1, 2*num_bits/3); + set_random(*t2, 2*num_bits/3); + apply_filter_neg(*t1,*t2, cols1, cols2); + } + cols1.push_back(1); + cols2.push_back(2); + for (unsigned i = 0; i < 200; ++i) { + set_random(*t1, 2*num_bits/3); + set_random(*t2, 2*num_bits/3); + apply_filter_neg(*t1,*t2, cols1, cols2); + } + t1->deallocate(); + t2->deallocate(); + } + void set_random(udoc_relation& r, unsigned num_vals) { unsigned num_bits = r.get_dm().num_tbits(); udoc_relation* full = mk_full(r.get_signature()); @@ -390,6 +394,7 @@ public: tbit b = (val == 0)?BIT_0:BIT_1; dm.set(d0, idx, b); } + full->deallocate(); } void apply_filter_neg(udoc_relation& t1, udoc_relation& t2, @@ -401,7 +406,14 @@ public: expr_ref fml1(m), fml2(m), fml3(m); t1.to_formula(fml1); t2.to_formula(fml2); + for (unsigned i = 0; i < cols1.size(); ++i) { + std::cout << cols1[i] << " = " << cols2[i] << " "; + } + std::cout << "\n"; + t1.display(std::cout); std::cout << "\n"; + t2.display(std::cout); std::cout << "\n"; (*negf)(t1, t2); + t1.display(std::cout); std::cout << "\n"; t1.to_formula(fml3); std::cout << fml1 << "\n"; std::cout << fml2 << "\n"; @@ -426,7 +438,7 @@ public: for (unsigned i = 0; i < sub.size(); ++i) { project_var(sig.size() + i, m.get_sort(sub[i].get()), fml2); } - fml1 = m.mk_and(fml1, fml2); + fml1 = m.mk_and(fml1, m.mk_not(fml2)); expr_ref_vector vars(m); for (unsigned i = 0; i < sig.size(); ++i) { From a50cbef877c0f6e79012d87c4a994173f5b746d4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 20 Sep 2014 19:01:15 -0700 Subject: [PATCH 561/925] testing doc Signed-off-by: Nikolaj Bjorner --- src/muz/rel/dl_instruction.cpp | 21 ++++++ src/muz/rel/dl_instruction.h | 2 + src/muz/rel/doc.cpp | 23 ++++--- src/muz/rel/doc.h | 48 +++++++++----- src/muz/rel/tbv.cpp | 3 +- src/muz/rel/udoc_relation.cpp | 75 +++++++++++++++++++-- src/test/tbv.cpp | 15 +++++ src/test/udoc_relation.cpp | 115 +++++++++++++++++++++++++++------ src/util/fixed_bit_vector.cpp | 3 +- src/util/fixed_bit_vector.h | 81 +++++++++++------------ 10 files changed, 291 insertions(+), 95 deletions(-) diff --git a/src/muz/rel/dl_instruction.cpp b/src/muz/rel/dl_instruction.cpp index a702c27ce..1dfdf96b9 100644 --- a/src/muz/rel/dl_instruction.cpp +++ b/src/muz/rel/dl_instruction.cpp @@ -154,6 +154,10 @@ namespace datalog { display_body_impl(ctx, out, indentation); } + void instruction::log_verbose(execution_context& ctx) { + IF_VERBOSE(2, display(ctx.get_rel_context(), verbose_stream());); + } + class instr_io : public instruction { bool m_store; func_decl_ref m_pred; @@ -162,6 +166,7 @@ namespace datalog { instr_io(bool store, func_decl_ref pred, reg_idx reg) : m_store(store), m_pred(pred), m_reg(reg) {} virtual bool perform(execution_context & ctx) { + log_verbose(ctx); if (m_store) { if (ctx.reg(m_reg)) { ctx.get_rel_context().store_relation(m_pred, ctx.release_reg(m_reg)); @@ -237,6 +242,7 @@ namespace datalog { instr_clone_move(bool clone, reg_idx src, reg_idx tgt) : m_clone(clone), m_src(src), m_tgt(tgt) {} virtual bool perform(execution_context & ctx) { + log_verbose(ctx); ctx.make_empty(m_tgt); if (m_clone) { ctx.set_reg(m_tgt, ctx.reg(m_src) ? ctx.reg(m_src)->clone() : 0); @@ -296,6 +302,7 @@ namespace datalog { dealloc(m_body); } virtual bool perform(execution_context & ctx) { + log_verbose(ctx); TRACE("dl", tout << "loop entered\n";); unsigned count = 0; while (!control_is_empty(ctx)) { @@ -339,6 +346,7 @@ namespace datalog { : m_rel1(rel1), m_rel2(rel2), m_cols1(col_cnt, cols1), m_cols2(col_cnt, cols2), m_res(result) {} virtual bool perform(execution_context & ctx) { + log_verbose(ctx); ctx.make_empty(m_res); if (!ctx.reg(m_rel1) || !ctx.reg(m_rel2)) { return true; @@ -400,6 +408,7 @@ namespace datalog { instr_filter_equal(ast_manager & m, reg_idx reg, const relation_element & value, unsigned col) : m_reg(reg), m_value(value, m), m_col(col) {} virtual bool perform(execution_context & ctx) { + log_verbose(ctx); if (!ctx.reg(m_reg)) { return true; } @@ -447,6 +456,7 @@ namespace datalog { instr_filter_identical(reg_idx reg, unsigned col_cnt, const unsigned * identical_cols) : m_reg(reg), m_cols(col_cnt, identical_cols) {} virtual bool perform(execution_context & ctx) { + log_verbose(ctx); if (!ctx.reg(m_reg)) { return true; } @@ -493,6 +503,7 @@ namespace datalog { if (!ctx.reg(m_reg)) { return true; } + log_verbose(ctx); relation_mutator_fn * fn; relation_base & r = *ctx.reg(m_reg); @@ -543,6 +554,7 @@ namespace datalog { m_res(result) {} virtual bool perform(execution_context & ctx) { + log_verbose(ctx); if (!ctx.reg(m_src)) { ctx.make_empty(m_res); return true; @@ -601,6 +613,7 @@ namespace datalog { instr_union(reg_idx src, reg_idx tgt, reg_idx delta, bool widen) : m_src(src), m_tgt(tgt), m_delta(delta), m_widen(widen) {} virtual bool perform(execution_context & ctx) { + log_verbose(ctx); TRACE("dl", tout << "union " << m_src << " into " << m_tgt << " " << ctx.reg(m_src) << " " << ctx.reg(m_tgt) << "\n";); if (!ctx.reg(m_src)) { @@ -713,6 +726,7 @@ namespace datalog { reg_idx tgt) : m_projection(projection), m_src(src), m_cols(col_cnt, cols), m_tgt(tgt) {} virtual bool perform(execution_context & ctx) { + log_verbose(ctx); ctx.make_empty(m_tgt); if (!ctx.reg(m_src)) { return true; @@ -778,6 +792,7 @@ namespace datalog { m_cols2(joined_col_cnt, cols2), m_removed_cols(removed_col_cnt, removed_cols), m_res(result) { } virtual bool perform(execution_context & ctx) { + log_verbose(ctx); ctx.make_empty(m_res); if (!ctx.reg(m_rel1) || !ctx.reg(m_rel2)) { return true; @@ -839,6 +854,7 @@ namespace datalog { } virtual bool perform(execution_context & ctx) { + log_verbose(ctx); if (!ctx.reg(m_src)) { ctx.make_empty(m_result); return true; @@ -893,6 +909,7 @@ namespace datalog { const unsigned * cols2) : m_tgt(tgt), m_neg_rel(neg_rel), m_cols1(col_cnt, cols1), m_cols2(col_cnt, cols2) {} virtual bool perform(execution_context & ctx) { + log_verbose(ctx); if (!ctx.reg(m_tgt) || !ctx.reg(m_neg_rel)) { return true; } @@ -948,6 +965,7 @@ namespace datalog { m_fact.push_back(val); } virtual bool perform(execution_context & ctx) { + log_verbose(ctx); ctx.make_empty(m_tgt); relation_base * rel = ctx.get_rel_context().get_rmanager().mk_empty_relation(m_sig, m_pred); rel->add_fact(m_fact); @@ -980,6 +998,7 @@ namespace datalog { public: instr_mk_total(const relation_signature & sig, func_decl* p, reg_idx tgt) : m_sig(sig), m_pred(p), m_tgt(tgt) {} virtual bool perform(execution_context & ctx) { + log_verbose(ctx); ctx.make_empty(m_tgt); ctx.set_reg(m_tgt, ctx.get_rel_context().get_rmanager().mk_full_relation(m_sig, m_pred)); return true; @@ -1006,6 +1025,7 @@ namespace datalog { instr_mark_saturated(ast_manager & m, func_decl * pred) : m_pred(pred, m) {} virtual bool perform(execution_context & ctx) { + log_verbose(ctx); ctx.get_rel_context().get_rmanager().mark_saturated(m_pred); return true; } @@ -1027,6 +1047,7 @@ namespace datalog { instr_assert_signature(const relation_signature & s, reg_idx tgt) : m_sig(s), m_tgt(tgt) {} virtual bool perform(execution_context & ctx) { + log_verbose(ctx); if (ctx.reg(m_tgt)) { SASSERT(ctx.reg(m_tgt)->get_signature()==m_sig); } diff --git a/src/muz/rel/dl_instruction.h b/src/muz/rel/dl_instruction.h index fa705a172..b816f9e55 100644 --- a/src/muz/rel/dl_instruction.h +++ b/src/muz/rel/dl_instruction.h @@ -222,6 +222,8 @@ namespace datalog { Each line must be prepended by \c indentation and ended by a newline character. */ virtual void display_body_impl(rel_context const & ctx, std::ostream & out, std::string indentation) const {} + void log_verbose(execution_context& ctx); + public: typedef execution_context::reg_type reg_type; typedef execution_context::reg_idx reg_idx; diff --git a/src/muz/rel/doc.cpp b/src/muz/rel/doc.cpp index 1db1ac2b7..6ddc5b6b4 100644 --- a/src/muz/rel/doc.cpp +++ b/src/muz/rel/doc.cpp @@ -50,6 +50,7 @@ doc* doc_manager::allocate(doc const& src) { return r; } doc* doc_manager::allocate(tbv* t) { + SASSERT(t); void* mm = m_alloc.allocate(sizeof(doc)); return new (mm) doc(t); } @@ -85,9 +86,7 @@ void doc_manager::copy(doc& dst, doc const& src) { for (unsigned i = 0; i < n; ++i) { m.copy(dst.neg()[i], src.neg()[i]); } - for (unsigned i = n; i < dst.neg().size(); ++i) { - dst.neg().erase(m, dst.neg().size()-1); - } + dst.neg().reset(m); for (unsigned i = n; i < src.neg().size(); ++i) { dst.neg().push_back(m.allocate(src.neg()[i])); } @@ -110,12 +109,7 @@ doc& doc_manager::fillX(doc& src) { bool doc_manager::set_and(doc& dst, doc const& src) { // (A \ B) & (C \ D) = (A & C) \ (B u D) if (!m.set_and(dst.pos(), src.pos())) return false; - for (unsigned i = 0; i < dst.neg().size(); ++i) { - if (!m.set_and(dst.neg()[i], dst.pos())) { - dst.neg().erase(m, i); - --i; - } - } + dst.neg().intersect(m, src.pos()); tbv_ref t(m); for (unsigned i = 0; i < src.neg().size(); ++i) { t = m.allocate(src.neg()[i]); @@ -279,6 +273,7 @@ bool doc_manager::intersect(doc const& A, doc const& B, doc& result) { doc* doc_manager::project(doc_manager& dstm, unsigned n, bool const* to_delete, doc const& src) { tbv_manager& dstt = dstm.m; doc* r = dstm.allocate(dstt.project(n, to_delete, src.pos())); + SASSERT(r); if (src.neg().is_empty()) { return r; @@ -405,13 +400,21 @@ void doc_manager::complement(doc const& src, ptr_vector& result) { result.push_back(allocate(src.neg()[i])); } } +// (A \ {A1}) \ (B \ {B1}) +// (A & !A1 & & !B) | (A & B1 & !A1) +// A \ {A1 u B} u (A & B1) \ {A1} void doc_manager::subtract(doc const& A, doc const& B, ptr_vector& result) { doc_ref r(*this), r2(*this); + tbv_ref t(m); r = allocate(A); - if (r->neg().insert(m, m.allocate(B.pos()))) { + t = m.allocate(B.pos()); + if (m.set_and(*t, A.pos()) && r->neg().insert(m, t.detach())) { result.push_back(r.detach()); r = allocate(A); } + else { + result.push_back(allocate(A)); + } for (unsigned i = 0; i < B.neg().size(); ++i) { r2 = allocate(B.neg()[i]); if (set_and(*r, *r2)) { diff --git a/src/muz/rel/doc.h b/src/muz/rel/doc.h index e56196026..b29ecb7c6 100644 --- a/src/muz/rel/doc.h +++ b/src/muz/rel/doc.h @@ -111,12 +111,16 @@ public: } void push_back(T* t) { + SASSERT(t); m_elems.push_back(t); } void erase(M& m, unsigned idx) { - T* t = m_elems[idx]; - m_elems.erase(t); - m.deallocate(t); + m.deallocate(m_elems[idx]); + unsigned sz = m_elems.size(); + for (unsigned i = idx+1; i < sz; ++i) { + m_elems[i-1] = m_elems[i]; + } + m_elems.resize(sz-1); } void reset(M& m) { for (unsigned i = 0; i < m_elems.size(); ++i) { @@ -125,21 +129,20 @@ public: m_elems.reset(); } bool insert(M& m, T* t) { + SASSERT(t); unsigned sz = size(), j = 0; bool found = false; for (unsigned i = 0; i < sz; ++i, ++j) { + if (m.contains(*m_elems[i], *t)) { + found = true; + } if (!found && m.contains(*t, *m_elems[i])) { m.deallocate(m_elems[i]); --j; } - else { - if (m.contains(*m_elems[i], *t)) { - found = true; - } - if (i != j) { - m_elems[j] = m_elems[i]; - } - } + else if (i != j) { + m_elems[j] = m_elems[i]; + } } if (j != sz) m_elems.resize(j); if (found) { @@ -150,7 +153,7 @@ public: } return !found; } - void intersect(M& m, T& t) { + void intersect(M& m, T const& t) { unsigned sz = size(); unsigned j = 0; for (unsigned i = 0; i < sz; ++i, ++j) { @@ -159,7 +162,7 @@ public: --j; } else if (i != j) { - m_elems[i] = m_elems[j]; + m_elems[j] = m_elems[i]; } } if (j != sz) m_elems.resize(j); @@ -233,13 +236,26 @@ public: std::swap(*this, result); } - void merge(M& m, unsigned lo, unsigned length, subset_ints const& equalities, bit_vector const& discard_cols) { + bool well_formed(M& m) const { for (unsigned i = 0; i < size(); ++i) { + if (!m.well_formed(*m_elems[i])) return false; + } + return true; + } + + void merge(M& m, unsigned lo, unsigned length, subset_ints const& equalities, bit_vector const& discard_cols) { + unsigned j = 0; + unsigned sz = size(); + for (unsigned i = 0; i < sz; ++i, ++j) { if (!m.merge(*m_elems[i], lo, length, equalities, discard_cols)) { - erase(m, i); - --i; + --j; + m.deallocate(m_elems[i]); + } + else if (i != j) { + m_elems[j] = m_elems[i]; } } + if (j != sz) m_elems.resize(j); } void merge(M& m, unsigned lo1, unsigned lo2, unsigned length, bit_vector const& discard_cols) { diff --git a/src/muz/rel/tbv.cpp b/src/muz/rel/tbv.cpp index 23745f333..458aea9d0 100644 --- a/src/muz/rel/tbv.cpp +++ b/src/muz/rel/tbv.cpp @@ -92,7 +92,8 @@ tbv* tbv_manager::allocate(uint64 val, unsigned hi, unsigned lo) { } tbv* tbv_manager::allocate(tbv const& bv, unsigned const* permutation) { tbv* r = allocate(); - for (unsigned i = 0; i < num_tbits(); ++i) { + unsigned sz = num_tbits(); + for (unsigned i = 0; i < sz; ++i) { r->set(permutation[i], bv[i]); } return r; diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 874885e5f..17b2ded0c 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -373,6 +373,7 @@ namespace datalog { } } TRACE("doc", result->display(tout << "result:\n");); + SASSERT(r.well_formed(result->get_dm())); return result; } }; @@ -412,6 +413,7 @@ namespace datalog { ud2.push_back(d2.detach()); } TRACE("doc", tout << "final size: " << r->get_size_estimate_rows() << '\n';); + SASSERT(ud2.well_formed(dm2)); return r; } }; @@ -431,20 +433,60 @@ namespace datalog { rename_fn(udoc_relation const& t, unsigned cycle_len, const unsigned * cycle) : convenient_relation_rename_fn(t.get_signature(), cycle_len, cycle) { udoc_plugin& p = t.get_plugin(); + ast_manager& m = p.get_ast_manager(); + relation_signature const& sig1 = t.get_signature(); + relation_signature const& sig2 = get_result_signature(); + unsigned_vector permutation0, column_info; for (unsigned i = 0; i < t.get_num_bits(); ++i) { m_permutation.push_back(i); } - unsigned len = t.column_num_bits(cycle[0]); + for (unsigned i = 0; i < sig1.size(); ++i) { + permutation0.push_back(i); + } for (unsigned i = 0; i < cycle_len; ++i) { unsigned j = (i + 1)%cycle_len; unsigned col1 = cycle[i]; unsigned col2 = cycle[j]; - unsigned lo1 = t.column_idx(col1); - unsigned lo2 = t.column_idx(col2); + permutation0[col2] = col1; + } + unsigned column = 0; + for (unsigned i = 0; i < sig2.size(); ++i) { + column_info.push_back(column); + column += p.num_sort_bits(sig2[i]); + } + column_info.push_back(column); + SASSERT(column == t.get_num_bits()); + + TRACE("doc", + sig1.output(m, tout << "sig1: "); tout << "\n"; + sig2.output(m, tout << "sig2: "); tout << "\n"; + tout << "permute: "; + for (unsigned i = 0; i < permutation0.size(); ++i) { + tout << permutation0[i] << " "; + } + tout << "\n"; + tout << "cycle: "; + for (unsigned i = 0; i < cycle_len; ++i) { + tout << cycle[i] << " "; + } + tout << "\n"; + ); + + + // 0 -> 2 + // [3:2:1] -> [1:2:3] + // [3,4,5,1,2,0] + + for (unsigned i = 0; i < sig1.size(); ++i) { + unsigned len = t.column_num_bits(i); + unsigned lo1 = t.column_idx(i); + unsigned col2 = permutation0[i]; + unsigned lo2 = column_info[col2]; + SASSERT(lo2 + len <= t.get_num_bits()); + SASSERT(lo1 + len <= t.get_num_bits()); for (unsigned k = 0; k < len; ++k) { m_permutation[k + lo1] = k + lo2; } - SASSERT(t.column_num_bits(col1) == t.column_num_bits(col2)); } } @@ -457,10 +499,12 @@ namespace datalog { udoc const& src = r.get_udoc(); udoc& dst = result->get_udoc(); doc_manager& dm = r.get_dm(); + SASSERT(&result->get_dm() == &dm); for (unsigned i = 0; i < src.size(); ++i) { dst.push_back(dm.allocate(src[i], m_permutation.c_ptr())); } TRACE("doc", result->display(tout << "result:\n");); + SASSERT(dst.well_formed(dm)); return result; } }; @@ -488,6 +532,8 @@ namespace datalog { if (d) d1 = &d->get_udoc(); if (d1) d1->reset(dm); r.get_plugin().mk_union(dm, r.get_udoc(), src.get_udoc(), d1); + SASSERT(r.get_udoc().well_formed(dm)); + SASSERT(!d1 || d1->well_formed(dm)); TRACE("doc", _r.display(tout << "dst':\n"); ); } }; @@ -547,6 +593,7 @@ namespace datalog { udoc& d = r.get_udoc(); doc_manager& dm = r.get_dm(); d.merge(dm, m_cols[0], m_size, m_equalities, m_empty_bv); + SASSERT(d.well_formed(dm)); TRACE("doc", tout << "final size: " << r.get_size_estimate_rows() << '\n';); } }; @@ -575,6 +622,7 @@ namespace datalog { virtual void operator()(relation_base & tb) { udoc_relation & t = get(tb); t.get_udoc().intersect(dm, *m_filter); + SASSERT(t.get_udoc().well_formed(t.get_dm())); } }; relation_mutator_fn * udoc_plugin::mk_filter_equal_fn( @@ -826,11 +874,15 @@ namespace datalog { virtual void operator()(relation_base & tb) { udoc_relation & t = get(tb); udoc& u = t.get_udoc(); + SASSERT(u.well_formed(dm)); u.intersect(dm, m_udoc); + SASSERT(u.well_formed(dm)); if (m_condition && !u.is_empty()) { t.apply_guard(m_condition, u, m_equalities, m_empty_bv); + SASSERT(u.well_formed(dm)); } u.simplify(dm); + SASSERT(u.well_formed(dm)); TRACE("doc", tout << "final size: " << t.get_size_estimate_rows() << '\n';); } }; @@ -896,7 +948,12 @@ namespace datalog { } renamed_neg.push_back(newD.detach()); } - dst.subtract(t.get_dm(), renamed_neg); + TRACE("doc", dst.display(dm, tout) << "\n"; + renamed_neg.display(dm, tout) << "\n"; + ); + dst.subtract(dm, renamed_neg); + TRACE("doc", dst.display(dm, tout) << "\n";); + SASSERT(dst.well_formed(dm)); renamed_neg.reset(t.get_dm()); } void copy_column( @@ -971,17 +1028,23 @@ namespace datalog { udoc const& u1 = t.get_udoc(); doc_manager& dm = t.get_dm(); udoc u2; + SASSERT(u1.well_formed(dm)); u2.copy(dm, u1); + SASSERT(u2.well_formed(dm)); u2.intersect(dm, m_udoc); - u2.merge(dm, m_roots, m_equalities, m_col_list); + SASSERT(u2.well_formed(dm)); + u2.merge(dm, m_roots, m_equalities, m_col_list); + SASSERT(u2.well_formed(dm)); if (m_condition && !u2.is_empty()) { t.apply_guard(m_condition, u2, m_equalities, m_col_list); + SASSERT(u2.well_formed(dm)); } udoc_relation* r = get(t.get_plugin().mk_empty(get_result_signature())); doc_manager& dm2 = r->get_dm(); for (unsigned i = 0; i < u2.size(); ++i) { doc* d = dm.project(dm2, m_to_delete.size(), m_to_delete.c_ptr(), u2[i]); r->get_udoc().insert(dm2, d); + SASSERT(r->get_udoc().well_formed(dm2)); } u2.reset(dm); return r; diff --git a/src/test/tbv.cpp b/src/test/tbv.cpp index d56fcd84a..7fab0b56c 100644 --- a/src/test/tbv.cpp +++ b/src/test/tbv.cpp @@ -40,7 +40,22 @@ static void tst1(unsigned num_bits) { m.deallocate(bN); } +static void tst0() { + tbv_manager m(0); + + tbv_ref t1(m), t2(m), t3(m); + t1 = m.allocate1(); + t2 = m.allocate0(); + t3 = m.allocateX(); + m.display(std::cout, *t1) << "\n"; + m.display(std::cout, *t2) << "\n"; + m.display(std::cout, *t3) << "\n"; + SASSERT(m.equals(*t1, *t2)); + SASSERT(m.equals(*t1, *t3)); +} + void tst_tbv() { + tst0(); tst1(31); tst1(11); tst1(15); diff --git a/src/test/udoc_relation.cpp b/src/test/udoc_relation.cpp index 13623aeeb..197186bbf 100644 --- a/src/test/udoc_relation.cpp +++ b/src/test/udoc_relation.cpp @@ -88,8 +88,10 @@ public: udoc_relation* t1, *t2, *t3; expr_ref fml(m); + test_rename(); test_filter_neg(); + // empty { std::cout << "empty\n"; @@ -168,26 +170,6 @@ public: t1->deallocate(); } - // rename - { - t1 = mk_empty(sig); - unsigned_vector cycle; - cycle.push_back(0); - cycle.push_back(2); - datalog::relation_transformer_fn* rename = p.mk_rename_fn(*t1, cycle.size(), cycle.c_ptr()); - - t1->add_fact(fact1); - t1->add_fact(fact2); - t1->add_fact(fact3); - t = (*rename)(*t1); - t1->display(std::cout); std::cout << "\n"; - t->display(std::cout); std::cout << "\n"; - t->deallocate(); - - dealloc(rename); - t1->deallocate(); - } - // union { t1 = mk_empty(sig); @@ -342,6 +324,98 @@ public: } + void test_rename() { + udoc_relation* t1; + // rename + datalog::relation_signature sig; + sig.push_back(bv.mk_sort(12)); + sig.push_back(bv.mk_sort(6)); + sig.push_back(bv.mk_sort(2)); + datalog::relation_fact fact1(m); + fact1.push_back(bv.mk_numeral(rational(1), 12)); + fact1.push_back(bv.mk_numeral(rational(6), 6)); + fact1.push_back(bv.mk_numeral(rational(3), 2)); + t1 = mk_empty(sig); + t1->add_fact(fact1); + unsigned_vector cycle; + cycle.push_back(0); + cycle.push_back(2); + check_permutation(t1, cycle); + + sig.reset(); + sig.push_back(bv.mk_sort(2)); + sig.push_back(bv.mk_sort(6)); + sig.push_back(bv.mk_sort(12)); + fact1.reset(); + fact1.push_back(bv.mk_numeral(rational(3), 2)); + fact1.push_back(bv.mk_numeral(rational(6), 6)); + fact1.push_back(bv.mk_numeral(rational(1), 12)); + t1 = mk_empty(sig); + t1->add_fact(fact1); + cycle.reset(); + cycle.push_back(0); + cycle.push_back(2); + check_permutation(t1, cycle); + + t1 = mk_empty(sig); + t1->add_fact(fact1); + cycle.reset(); + cycle.push_back(0); + cycle.push_back(1); + cycle.push_back(2); + check_permutation(t1, cycle); + } + + void check_permutation(relation_base* t1, unsigned_vector const& cycle) { + scoped_ptr rename; + rename = p.mk_rename_fn(*t1, cycle.size(), cycle.c_ptr()); + relation_base* t = (*rename)(*t1); + verify_permutation(*t1,*t, cycle); + t1->display(std::cout); std::cout << "\n"; + t->display(std::cout); std::cout << "\n"; + t->deallocate(); + t1->deallocate(); + } + + void verify_permutation(relation_base const& src, relation_base const& dst, + unsigned_vector const& cycle) { + unsigned_vector perm; + relation_signature const& sig1 = src.get_signature(); + relation_signature const& sig2 = dst.get_signature(); + for (unsigned i = 0; i < sig1.size(); ++i) { + perm.push_back(i); + } + for (unsigned i = 0; i < cycle.size(); ++i) { + unsigned j = (i + 1)%cycle.size(); + unsigned col1 = cycle[i]; + unsigned col2 = cycle[j]; + perm[col2] = col1; + } + for (unsigned i = 0; i < perm.size(); ++i) { + SASSERT(sig2[perm[i]] == sig1[i]); + } + expr_ref_vector sub(m); + for (unsigned i = 0; i < perm.size(); ++i) { + sub.push_back(m.mk_var(perm[i], sig1[i])); + } + var_subst subst(m, false); + expr_ref fml1(m), fml2(m); + src.to_formula(fml1); + dst.to_formula(fml2); + subst(fml1, sub.size(), sub.c_ptr(), fml1); + expr_ref_vector vars(m); + for (unsigned i = 0; i < sig2.size(); ++i) { + std::stringstream strm; + strm << "x" << i; + vars.push_back(m.mk_const(symbol(strm.str().c_str()), sig2[i])); + } + + subst(fml1, vars.size(), vars.c_ptr(), fml1); + subst(fml2, vars.size(), vars.c_ptr(), fml2); + + check_equiv(fml1, fml2); + } + /* The filter_by_negation postcondition: filter_by_negation(tgt, neg, columns in tgt: c1,...,cN, @@ -499,7 +573,6 @@ public: } } - check_equiv(fml, cfml); } diff --git a/src/util/fixed_bit_vector.cpp b/src/util/fixed_bit_vector.cpp index f2af843c7..3711ef5eb 100644 --- a/src/util/fixed_bit_vector.cpp +++ b/src/util/fixed_bit_vector.cpp @@ -37,6 +37,7 @@ fixed_bit_vector_manager::fixed_bit_vector_manager(unsigned num_bits): fixed_bit_vector* fixed_bit_vector_manager::allocate() { + if (m_num_bytes == 0) return &m_0; return static_cast(m_alloc.allocate(m_num_bytes)); } @@ -59,7 +60,7 @@ fixed_bit_vector* fixed_bit_vector_manager::allocate(fixed_bit_vector const& bv) } void fixed_bit_vector_manager::deallocate(fixed_bit_vector* bv) { - m_alloc.deallocate(m_num_bytes, bv); + if (m_num_bytes > 0) m_alloc.deallocate(m_num_bytes, bv); } diff --git a/src/util/fixed_bit_vector.h b/src/util/fixed_bit_vector.h index 1ac3363d4..11cb91fef 100644 --- a/src/util/fixed_bit_vector.h +++ b/src/util/fixed_bit_vector.h @@ -25,46 +25,6 @@ Revision History: #include"debug.h" #include"small_object_allocator.h" -class fixed_bit_vector; -class fixed_bit_vector_manager { - friend class fixed_bit_vector; - small_object_allocator m_alloc; - unsigned m_num_bits; - unsigned m_num_bytes; - unsigned m_num_words; - unsigned m_mask; - - static unsigned num_words(unsigned num_bits) { - return (num_bits + 31) / 32; - } - -public: - fixed_bit_vector_manager(unsigned num_bits); - - void reset() { m_alloc.reset(); } - fixed_bit_vector* allocate(); - fixed_bit_vector* allocate1(); - fixed_bit_vector* allocate0(); - fixed_bit_vector* allocate(fixed_bit_vector const& bv); - void deallocate(fixed_bit_vector* bv); - - void copy(fixed_bit_vector& dst, fixed_bit_vector const& src) const; - unsigned num_words() const { return m_num_words; } - unsigned num_bytes() const { return m_num_bytes; } - unsigned num_bits() const { return m_num_bits; } - fixed_bit_vector& reset(fixed_bit_vector& bv) const { return fill0(bv); } - fixed_bit_vector& fill0(fixed_bit_vector& bv) const; - fixed_bit_vector& fill1(fixed_bit_vector& bv) const; - fixed_bit_vector& set_and(fixed_bit_vector& dst, fixed_bit_vector const& src) const; - fixed_bit_vector& set_or(fixed_bit_vector& dst, fixed_bit_vector const& src) const; - fixed_bit_vector& set_neg(fixed_bit_vector& dst) const; - unsigned last_word(fixed_bit_vector const& bv) const; - bool equals(fixed_bit_vector const& a, fixed_bit_vector const& b) const; - unsigned hash(fixed_bit_vector const& src) const; - bool contains(fixed_bit_vector const& a, fixed_bit_vector const& b) const; - std::ostream& display(std::ostream& out, fixed_bit_vector const& b) const; -}; - class fixed_bit_vector { friend class fixed_bit_vector_manager; friend class tbv_manager; @@ -114,6 +74,47 @@ public: }; +class fixed_bit_vector_manager { + friend class fixed_bit_vector; + small_object_allocator m_alloc; + unsigned m_num_bits; + unsigned m_num_bytes; + unsigned m_num_words; + unsigned m_mask; + fixed_bit_vector m_0; + + static unsigned num_words(unsigned num_bits) { + return (num_bits + 31) / 32; + } + +public: + fixed_bit_vector_manager(unsigned num_bits); + + void reset() { m_alloc.reset(); } + fixed_bit_vector* allocate(); + fixed_bit_vector* allocate1(); + fixed_bit_vector* allocate0(); + fixed_bit_vector* allocate(fixed_bit_vector const& bv); + void deallocate(fixed_bit_vector* bv); + + void copy(fixed_bit_vector& dst, fixed_bit_vector const& src) const; + unsigned num_words() const { return m_num_words; } + unsigned num_bytes() const { return m_num_bytes; } + unsigned num_bits() const { return m_num_bits; } + fixed_bit_vector& reset(fixed_bit_vector& bv) const { return fill0(bv); } + fixed_bit_vector& fill0(fixed_bit_vector& bv) const; + fixed_bit_vector& fill1(fixed_bit_vector& bv) const; + fixed_bit_vector& set_and(fixed_bit_vector& dst, fixed_bit_vector const& src) const; + fixed_bit_vector& set_or(fixed_bit_vector& dst, fixed_bit_vector const& src) const; + fixed_bit_vector& set_neg(fixed_bit_vector& dst) const; + unsigned last_word(fixed_bit_vector const& bv) const; + bool equals(fixed_bit_vector const& a, fixed_bit_vector const& b) const; + unsigned hash(fixed_bit_vector const& src) const; + bool contains(fixed_bit_vector const& a, fixed_bit_vector const& b) const; + std::ostream& display(std::ostream& out, fixed_bit_vector const& b) const; +}; + + #endif /* _FIXED_BIT_VECTOR_H_ */ From 22808a039da18b6990bb53ec1027a9e814568ca8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 21 Sep 2014 20:25:11 -0700 Subject: [PATCH 562/925] working on udoc Signed-off-by: Nikolaj Bjorner --- src/muz/base/dl_context.cpp | 9 ++-- src/muz/base/dl_context.h | 3 +- src/muz/base/fixedpoint_params.pyg | 3 -- src/muz/rel/dl_base.h | 8 ++++ src/muz/rel/dl_instruction.cpp | 56 +++++++++++++++++------ src/muz/rel/dl_instruction.h | 29 ++++++++---- src/muz/rel/dl_relation_manager.cpp | 2 +- src/muz/rel/doc.cpp | 28 ++++++++++++ src/muz/rel/doc.h | 1 + src/muz/rel/rel_context.cpp | 12 +++++ src/muz/rel/rel_context.h | 3 ++ src/muz/rel/tbv.cpp | 13 +++++- src/muz/rel/udoc_relation.cpp | 13 +++++- src/muz/rel/udoc_relation.h | 6 ++- src/muz/transforms/dl_mk_rule_inliner.cpp | 3 +- src/test/tbv.cpp | 20 ++++++++ src/util/fixed_bit_vector.h | 1 + 17 files changed, 171 insertions(+), 39 deletions(-) diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index d37e9cca8..9e8789aa6 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -233,7 +233,7 @@ namespace datalog { m_engine_type(LAST_ENGINE), m_cancel(false) { re.set_context(this); - m_generate_proof_trace = m_params->generate_proof_trace(); + updt_params(pa); } context::~context() { @@ -285,7 +285,8 @@ namespace datalog { unsigned context::dl_profile_milliseconds_threshold() const { return m_params->datalog_profile_timeout_milliseconds(); } bool context::all_or_nothing_deltas() const { return m_params->datalog_all_or_nothing_deltas(); } bool context::compile_with_widening() const { return m_params->datalog_compile_with_widening(); } - bool context::unbound_compressor() const { return m_params->datalog_unbound_compressor(); } + bool context::unbound_compressor() const { return m_unbound_compressor; } + void context::set_unbound_compressor(bool f) { m_unbound_compressor = f; } bool context::similarity_compressor() const { return m_params->datalog_similarity_compressor(); } unsigned context::similarity_compressor_threshold() const { return m_params->datalog_similarity_compressor_threshold(); } unsigned context::soft_timeout() const { return m_fparams.m_soft_timeout; } @@ -293,8 +294,7 @@ namespace datalog { bool context::generate_explanations() const { return m_params->datalog_generate_explanations(); } bool context::explanations_on_relation_level() const { return m_params->datalog_explanations_on_relation_level(); } bool context::magic_sets_for_queries() const { return m_params->datalog_magic_sets_for_queries(); } - bool context::eager_emptiness_checking() const { return m_params->datalog_eager_emptiness_checking(); } - + bool context::bit_blast() const { return m_params->xform_bit_blast(); } bool context::karr() const { return m_params->xform_karr(); } bool context::scale() const { return m_params->xform_scale(); } @@ -839,6 +839,7 @@ namespace datalog { m_params_ref.copy(p); if (m_engine.get()) m_engine->updt_params(); m_generate_proof_trace = m_params->generate_proof_trace(); + m_unbound_compressor = m_params->datalog_unbound_compressor(); } expr_ref context::get_background_assertion() { diff --git a/src/muz/base/dl_context.h b/src/muz/base/dl_context.h index fb49f02bc..0b9c623c4 100644 --- a/src/muz/base/dl_context.h +++ b/src/muz/base/dl_context.h @@ -172,6 +172,7 @@ namespace datalog { params_ref m_params_ref; fixedpoint_params* m_params; bool m_generate_proof_trace; + bool m_unbound_compressor; dl_decl_util m_decl_util; th_rewriter m_rewriter; var_subst m_var_subst; @@ -256,6 +257,7 @@ namespace datalog { bool all_or_nothing_deltas() const; bool compile_with_widening() const; bool unbound_compressor() const; + void set_unbound_compressor(bool f); bool similarity_compressor() const; unsigned similarity_compressor_threshold() const; unsigned soft_timeout() const; @@ -263,7 +265,6 @@ namespace datalog { bool generate_explanations() const; bool explanations_on_relation_level() const; bool magic_sets_for_queries() const; - bool eager_emptiness_checking() const; bool bit_blast() const; bool karr() const; bool scale() const; diff --git a/src/muz/base/fixedpoint_params.pyg b/src/muz/base/fixedpoint_params.pyg index d61c442d3..7951a62bc 100644 --- a/src/muz/base/fixedpoint_params.pyg +++ b/src/muz/base/fixedpoint_params.pyg @@ -33,9 +33,6 @@ def_module_params('fixedpoint', "updated relation was modified or not"), ('datalog.compile_with_widening', BOOL, False, "widening will be used to compile recursive rules"), - ('datalog.eager_emptiness_checking', BOOL, True, - "emptiness of affected relations will be checked after each instruction, " + - "so that we may ommit unnecessary instructions"), ('datalog.default_table_checked', BOOL, False, "if true, the detault " + 'table will be default_table inside a wrapper that checks that its results ' + 'are the same as of default_table_checker table'), diff --git a/src/muz/rel/dl_base.h b/src/muz/rel/dl_base.h index d03c94154..e53dae88a 100644 --- a/src/muz/rel/dl_base.h +++ b/src/muz/rel/dl_base.h @@ -465,6 +465,14 @@ namespace datalog { relation_manager & get_manager() const { return get_plugin().get_manager(); } virtual bool empty() const = 0; + /** + \brief fast emptiness check. This may be partial. + The requirement is that if fast_empty returns true + then the table or relation is in fact empty. + It is allowed to return false even if the relation is non-empty. + */ + virtual bool fast_empty() const { return empty(); } + virtual void add_fact(const fact & f) = 0; /** \brief Like \c add_fact, only here the caller guarantees that the fact is not present in diff --git a/src/muz/rel/dl_instruction.cpp b/src/muz/rel/dl_instruction.cpp index 1dfdf96b9..f8eadfed3 100644 --- a/src/muz/rel/dl_instruction.cpp +++ b/src/muz/rel/dl_instruction.cpp @@ -37,8 +37,7 @@ namespace datalog { execution_context::execution_context(context & context) : m_context(context), m_stopwatch(0), - m_timelimit_ms(0), - m_eager_emptiness_checking(context.eager_emptiness_checking()) {} + m_timelimit_ms(0) {} execution_context::~execution_context() { reset(); @@ -122,6 +121,22 @@ namespace datalog { m_timelimit_ms < static_cast(1000*m_stopwatch->get_current_seconds())); } + void execution_context::collect_statistics(statistics& st) const { + st.update("dl.joins", m_stats.m_join); + st.update("dl.project", m_stats.m_project); + st.update("dl.filter", m_stats.m_filter); + st.update("dl.total", m_stats.m_total); + st.update("dl.unary_singleton", m_stats.m_unary_singleton); + st.update("dl.filter_by_negation", m_stats.m_filter_by_negation); + st.update("dl.select_equal_project", m_stats.m_select_equal_project); + st.update("dl.join_project", m_stats.m_join_project); + st.update("dl.project_rename", m_stats.m_project_rename); + st.update("dl.union", m_stats.m_union); + st.update("dl.filter_interpreted_project", m_stats.m_filter_interp_project); + st.update("dl.filter_id", m_stats.m_filter_id); + st.update("dl.filter_eq", m_stats.m_filter_eq); + } + // ----------------------------------- // @@ -182,7 +197,7 @@ namespace datalog { } else { relation_base& rel = ctx.get_rel_context().get_relation(m_pred); - if ((!ctx.eager_emptiness_checking() || !rel.empty())) { + if (!rel.fast_empty()) { ctx.set_reg(m_reg, rel.clone()); } else { @@ -348,6 +363,7 @@ namespace datalog { virtual bool perform(execution_context & ctx) { log_verbose(ctx); ctx.make_empty(m_res); + ++ctx.m_stats.m_join; if (!ctx.reg(m_rel1) || !ctx.reg(m_rel2)) { return true; } @@ -375,7 +391,7 @@ namespace datalog { ctx.reg(m_res)->get_signature().output(ctx.get_rel_context().get_manager(), tout); tout<<":"<get_size_estimate_rows()<<"\n";); - if (ctx.eager_emptiness_checking() && ctx.reg(m_res)->empty()) { + if (ctx.reg(m_res)->fast_empty()) { ctx.make_empty(m_res); } return true; @@ -409,6 +425,7 @@ namespace datalog { : m_reg(reg), m_value(value, m), m_col(col) {} virtual bool perform(execution_context & ctx) { log_verbose(ctx); + ++ctx.m_stats.m_filter_eq; if (!ctx.reg(m_reg)) { return true; } @@ -426,7 +443,7 @@ namespace datalog { } (*fn)(r); - if (ctx.eager_emptiness_checking() && r.empty()) { + if (r.fast_empty()) { ctx.make_empty(m_reg); } return true; @@ -457,6 +474,7 @@ namespace datalog { : m_reg(reg), m_cols(col_cnt, identical_cols) {} virtual bool perform(execution_context & ctx) { log_verbose(ctx); + ++ctx.m_stats.m_filter_id; if (!ctx.reg(m_reg)) { return true; } @@ -474,7 +492,7 @@ namespace datalog { } (*fn)(r); - if (ctx.eager_emptiness_checking() && r.empty()) { + if (r.fast_empty()) { ctx.make_empty(m_reg); } return true; @@ -504,6 +522,7 @@ namespace datalog { return true; } log_verbose(ctx); + ++ctx.m_stats.m_filter; relation_mutator_fn * fn; relation_base & r = *ctx.reg(m_reg); @@ -519,7 +538,7 @@ namespace datalog { } (*fn)(r); - if (ctx.eager_emptiness_checking() && r.empty()) { + if (r.fast_empty()) { ctx.make_empty(m_reg); } TRACE("dl_verbose", r.display(tout <<"post-filter-interpreted:\n");); @@ -559,6 +578,7 @@ namespace datalog { ctx.make_empty(m_res); return true; } + ++ctx.m_stats.m_filter_interp_project; relation_transformer_fn * fn; relation_base & reg = *ctx.reg(m_src); @@ -575,7 +595,7 @@ namespace datalog { ctx.set_reg(m_res, (*fn)(reg)); - if (ctx.eager_emptiness_checking() && ctx.reg(m_res)->empty()) { + if (ctx.reg(m_res)->fast_empty()) { ctx.make_empty(m_res); } TRACE("dl_verbose", reg.display(tout << "post-filter-interpreted-and-project:\n");); @@ -613,12 +633,13 @@ namespace datalog { instr_union(reg_idx src, reg_idx tgt, reg_idx delta, bool widen) : m_src(src), m_tgt(tgt), m_delta(delta), m_widen(widen) {} virtual bool perform(execution_context & ctx) { - log_verbose(ctx); TRACE("dl", tout << "union " << m_src << " into " << m_tgt << " " << ctx.reg(m_src) << " " << ctx.reg(m_tgt) << "\n";); if (!ctx.reg(m_src)) { return true; } + log_verbose(ctx); + ++ctx.m_stats.m_union; relation_base & r_src = *ctx.reg(m_src); if (!ctx.reg(m_tgt)) { relation_base * new_tgt = r_src.get_plugin().mk_empty(r_src); @@ -682,7 +703,7 @@ namespace datalog { r_delta->display(tout <<"delta:"); }); - if (ctx.eager_emptiness_checking() && r_delta && r_delta->empty()) { + if (r_delta && r_delta->fast_empty()) { ctx.make_empty(m_delta); } @@ -726,11 +747,12 @@ namespace datalog { reg_idx tgt) : m_projection(projection), m_src(src), m_cols(col_cnt, cols), m_tgt(tgt) {} virtual bool perform(execution_context & ctx) { - log_verbose(ctx); ctx.make_empty(m_tgt); if (!ctx.reg(m_src)) { return true; } + log_verbose(ctx); + ++ctx.m_stats.m_project_rename; relation_transformer_fn * fn; relation_base & r_src = *ctx.reg(m_src); @@ -797,6 +819,7 @@ namespace datalog { if (!ctx.reg(m_rel1) || !ctx.reg(m_rel2)) { return true; } + ++ctx.m_stats.m_join_project; relation_join_fn * fn; const relation_base & r1 = *ctx.reg(m_rel1); const relation_base & r2 = *ctx.reg(m_rel2); @@ -811,7 +834,7 @@ namespace datalog { TRACE("dl", tout<\n";); ctx.set_reg(m_res, (*fn)(r1, r2)); TRACE("dl", tout<get_size_estimate_rows()<<"\n";); - if (ctx.eager_emptiness_checking() && ctx.reg(m_res)->empty()) { + if (ctx.reg(m_res)->fast_empty()) { ctx.make_empty(m_res); } return true; @@ -855,6 +878,7 @@ namespace datalog { virtual bool perform(execution_context & ctx) { log_verbose(ctx); + ++ctx.m_stats.m_select_equal_project; if (!ctx.reg(m_src)) { ctx.make_empty(m_result); return true; @@ -873,7 +897,7 @@ namespace datalog { } ctx.set_reg(m_result, (*fn)(r)); - if (ctx.eager_emptiness_checking() && ctx.reg(m_result)->empty()) { + if (ctx.reg(m_result)->fast_empty()) { ctx.make_empty(m_result); } return true; @@ -913,6 +937,8 @@ namespace datalog { if (!ctx.reg(m_tgt) || !ctx.reg(m_neg_rel)) { return true; } + ++ctx.m_stats.m_filter_by_negation; + relation_intersection_filter_fn * fn; relation_base & r1 = *ctx.reg(m_tgt); const relation_base & r2 = *ctx.reg(m_neg_rel); @@ -928,7 +954,7 @@ namespace datalog { } (*fn)(r1, r2); - if (ctx.eager_emptiness_checking() && r1.empty()) { + if (r1.fast_empty()) { ctx.make_empty(m_tgt); } return true; @@ -966,6 +992,7 @@ namespace datalog { } virtual bool perform(execution_context & ctx) { log_verbose(ctx); + ++ctx.m_stats.m_unary_singleton; ctx.make_empty(m_tgt); relation_base * rel = ctx.get_rel_context().get_rmanager().mk_empty_relation(m_sig, m_pred); rel->add_fact(m_fact); @@ -999,6 +1026,7 @@ namespace datalog { instr_mk_total(const relation_signature & sig, func_decl* p, reg_idx tgt) : m_sig(sig), m_pred(p), m_tgt(tgt) {} virtual bool perform(execution_context & ctx) { log_verbose(ctx); + ++ctx.m_stats.m_total; ctx.make_empty(m_tgt); ctx.set_reg(m_tgt, ctx.get_rel_context().get_rmanager().mk_full_relation(m_sig, m_pred)); return true; diff --git a/src/muz/rel/dl_instruction.h b/src/muz/rel/dl_instruction.h index b816f9e55..87f9df19f 100644 --- a/src/muz/rel/dl_instruction.h +++ b/src/muz/rel/dl_instruction.h @@ -66,14 +66,6 @@ namespace datalog { reg_annotations m_reg_annotation; stopwatch * m_stopwatch; unsigned m_timelimit_ms; //zero means no limit - /** - \brief If true, after every operation that may result in an empty relation, a check - for emptiness will be performed, and if a relation is empty, it will be deleted - and replaced by zero. This allows us to avoid performing operations that would have - no effect due to relation emptiness, but if the check for emptiness is expensive, its - cost may overcome the gains. - */ - bool m_eager_emptiness_checking; public: execution_context(context & context); ~execution_context(); @@ -86,7 +78,26 @@ namespace datalog { void reset_timelimit(); bool should_terminate(); - bool eager_emptiness_checking() const { return m_eager_emptiness_checking; } + struct stats { + unsigned m_join; + unsigned m_project; + unsigned m_filter; + unsigned m_total; + unsigned m_unary_singleton; + unsigned m_filter_by_negation; + unsigned m_select_equal_project; + unsigned m_join_project; + unsigned m_project_rename; + unsigned m_union; + unsigned m_filter_interp_project; + unsigned m_filter_id; + unsigned m_filter_eq; + stats() { reset(); } + void reset() { memset(this, 0, sizeof(*this)); } + }; + stats m_stats; + + void collect_statistics(statistics& st) const; /** \brief Return reference to \c i -th register that contains pointer to a relation. diff --git a/src/muz/rel/dl_relation_manager.cpp b/src/muz/rel/dl_relation_manager.cpp index a4c254272..e227e469a 100644 --- a/src/muz/rel/dl_relation_manager.cpp +++ b/src/muz/rel/dl_relation_manager.cpp @@ -538,7 +538,7 @@ namespace datalog { for(; it!=end; ++it) { func_decl * pred = *it; relation_base * rel = try_get_relation(pred); - if(!rel) { + if (!rel) { out << "Tuples in " << pred->get_name() << ": \n"; continue; } diff --git a/src/muz/rel/doc.cpp b/src/muz/rel/doc.cpp index 6ddc5b6b4..927eed283 100644 --- a/src/muz/rel/doc.cpp +++ b/src/muz/rel/doc.cpp @@ -434,6 +434,34 @@ bool doc_manager::equals(doc const& a, doc const& b) const { bool doc_manager::is_full(doc const& src) const { return src.neg().is_empty() && m.equals(src.pos(), *m_full); } +bool doc_manager::is_empty(doc const& src) { + if (src.neg().size() == 0) return false; + if (src.neg().size() == 1) { + return m.equals(src.pos(), src.neg()[0]); + } + tbv_ref pos(m, m.allocate(src.pos())); + for (unsigned i = 0; i < src.neg().size(); ++i) { + bool found = false; + for (unsigned j = 0; !found && j < num_tbits(); ++j) { + tbit b1 = (*pos)[j]; + tbit b2 = src.neg()[i][j]; + found = (b1 != BIT_x && b2 != BIT_x && b1 != b2); + } + for (unsigned j = 0; !found && j < num_tbits(); ++j) { + tbit b1 = (*pos)[j]; + tbit b2 = src.neg()[i][j]; + found = (b1 == BIT_x && b2 != BIT_x); + if (found) { + pos->set(j, neg(b2)); + } + } + if (!found) { + return false; // TBD make complete SAT check. + } + } + return true; +} + unsigned doc_manager::hash(doc const& src) const { unsigned r = 0; for (unsigned i = 0; i < src.neg().size(); ++i) { diff --git a/src/muz/rel/doc.h b/src/muz/rel/doc.h index b29ecb7c6..bf2cdc229 100644 --- a/src/muz/rel/doc.h +++ b/src/muz/rel/doc.h @@ -57,6 +57,7 @@ public: doc& fill1(doc& src); doc& fillX(doc& src); bool is_full(doc const& src) const; + bool is_empty(doc const& src); bool set_and(doc& dst, doc const& src); bool fold_neg(doc& dst); bool intersect(doc const& A, doc const& B, doc& result); diff --git a/src/muz/rel/rel_context.cpp b/src/muz/rel/rel_context.cpp index 920a0924a..13aecbe09 100644 --- a/src/muz/rel/rel_context.cpp +++ b/src/muz/rel/rel_context.cpp @@ -222,6 +222,7 @@ namespace datalog { } lbool rel_context::query(unsigned num_rels, func_decl * const* rels) { + setup_default_relation(); get_rmanager().reset_saturated_marks(); scoped_query _scoped_query(m_context); for (unsigned i = 0; i < num_rels; ++i) { @@ -307,6 +308,7 @@ namespace datalog { } lbool rel_context::query(expr* query) { + setup_default_relation(); get_rmanager().reset_saturated_marks(); scoped_query _scoped_query(m_context); rule_manager& rm = m_context.get_rule_manager(); @@ -495,6 +497,12 @@ namespace datalog { get_rmanager().set_cancel(f); } + void rel_context::setup_default_relation() { + if (m_context.default_relation() == symbol("doc")) { + m_context.set_unbound_compressor(false); + } + } + relation_plugin & rel_context::get_ordinary_relation_plugin(symbol relation_name) { relation_plugin * plugin = get_rmanager().get_relation_plugin(relation_name); if (!plugin) { @@ -553,6 +561,10 @@ namespace datalog { get_rmanager().store_relation(pred, rel); } + void rel_context::collect_statistics(statistics& st) const { + m_ectx.collect_statistics(st); + } + void rel_context::inherit_predicate_kind(func_decl* new_pred, func_decl* orig_pred) { if (orig_pred) { family_id target_kind = get_rmanager().get_requested_predicate_kind(orig_pred); diff --git a/src/muz/rel/rel_context.h b/src/muz/rel/rel_context.h index 84b100415..5e26718d6 100644 --- a/src/muz/rel/rel_context.h +++ b/src/muz/rel/rel_context.h @@ -52,6 +52,8 @@ namespace datalog { void set_cancel(bool f); + void setup_default_relation(); + public: rel_context(context& ctx); @@ -77,6 +79,7 @@ namespace datalog { virtual void inherit_predicate_kind(func_decl* new_pred, func_decl* orig_pred); + virtual void collect_statistics(statistics& st) const; virtual void cancel() { set_cancel(true); } virtual void cleanup() { set_cancel(false);} diff --git a/src/muz/rel/tbv.cpp b/src/muz/rel/tbv.cpp index 458aea9d0..0dcbcade9 100644 --- a/src/muz/rel/tbv.cpp +++ b/src/muz/rel/tbv.cpp @@ -191,8 +191,17 @@ bool tbv_manager::set_and(tbv& dst, tbv const& src) const { } bool tbv_manager::is_well_formed(tbv const& dst) const { - for (unsigned i = 0; i < num_tbits(); ++i) { - if (dst[i] == BIT_z) return false; + unsigned nw = m.num_words(); + unsigned w; + for (unsigned i = 0; i + 1 < nw; ++i) { + w = dst.get_word(i); + w = w | (w << 1) | 0x55555555; + if (w != 0xFFFFFFFF) return false; + } + if (nw > 0) { + w = m.last_word(dst); + w = w | (w << 1) | 0x55555555 | ~m.get_mask(); + if (w != 0xFFFFFFFF) return false; } return true; } diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 17b2ded0c..205d52416 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -57,6 +57,16 @@ namespace datalog { doc* d = fact2doc(f); m_elems.insert(dm, d); } + void udoc_relation::add_new_fact(const relation_fact & f) { + m_elems.push_back(fact2doc(f)); + } + bool udoc_relation::empty() const { + // TBD: make this a complete check + for (unsigned i = 0; i < m_elems.size(); ++i) { + if (!dm.is_empty(m_elems[i])) return false; + } + return true; + } bool udoc_relation::contains_fact(const relation_fact & f) const { doc_ref d(dm, fact2doc(f)); return m_elems.contains(dm, *d); @@ -240,9 +250,8 @@ namespace datalog { unsigned num_bits = 0; if (bv.is_bv_sort(s)) return bv.get_bv_size(s); - if (m.is_bool(s)) { + if (m.is_bool(s)) return 1; - } uint64 sz; if (dl.try_get_size(s, sz)) { while (sz > 0) ++num_bits, sz /= 2; diff --git a/src/muz/rel/udoc_relation.h b/src/muz/rel/udoc_relation.h index 697928d60..c3ce8d2c4 100644 --- a/src/muz/rel/udoc_relation.h +++ b/src/muz/rel/udoc_relation.h @@ -32,7 +32,7 @@ namespace datalog { class udoc_relation : public relation_base { friend class udoc_plugin; doc_manager& dm; - udoc m_elems; + mutable udoc m_elems; unsigned_vector m_column_info; doc* fact2doc(relation_fact const& f) const; expr_ref to_formula(tbv const& t) const; @@ -42,12 +42,14 @@ namespace datalog { virtual ~udoc_relation(); virtual void reset(); virtual void add_fact(const relation_fact & f); + virtual void add_new_fact(const relation_fact & f); virtual bool contains_fact(const relation_fact & f) const; virtual udoc_relation * clone() const; virtual udoc_relation * complement(func_decl*) const; virtual void to_formula(expr_ref& fml) const; udoc_plugin& get_plugin() const; - virtual bool empty() const { return m_elems.is_empty(); } + virtual bool fast_empty() const { return m_elems.is_empty(); } + virtual bool empty() const; virtual void display(std::ostream& out) const; virtual bool is_precise() const { return true; } virtual unsigned get_size_estimate_rows() const { return m_elems.size(); } diff --git a/src/muz/transforms/dl_mk_rule_inliner.cpp b/src/muz/transforms/dl_mk_rule_inliner.cpp index d3eb24b9a..7dabece2f 100644 --- a/src/muz/transforms/dl_mk_rule_inliner.cpp +++ b/src/muz/transforms/dl_mk_rule_inliner.cpp @@ -644,7 +644,8 @@ namespace datalog { tout << " num unifiers: " << m_unifiers.size(); tout << " num positions: " << m_positions.find(e).size() << "\n"; output_predicate(m_context, to_app(e), tout); tout << "\n";); - return true; + // stop visitor when we have more than 1 unifier, since that's all we want. + return m_unifiers.size() <= 1; } void mk_rule_inliner::visitor::reset(unsigned sz) { diff --git a/src/test/tbv.cpp b/src/test/tbv.cpp index 7fab0b56c..5714c444a 100644 --- a/src/test/tbv.cpp +++ b/src/test/tbv.cpp @@ -38,6 +38,7 @@ static void tst1(unsigned num_bits) { m.deallocate(b1); m.deallocate(bX); m.deallocate(bN); + } static void tst0() { @@ -54,11 +55,30 @@ static void tst0() { SASSERT(m.equals(*t1, *t3)); } +static void tst2(unsigned num_bits) { + tbv_manager m(num_bits); + tbv_ref t(m), t2(m); + for (unsigned i = 0; i < 55; ++i) { + t = m.allocate(i); + SASSERT(m.is_well_formed(*t)); + t2 = m.allocate(i+1); + VERIFY(!m.set_and(*t2, *t)); + SASSERT(!m.is_well_formed(*t2)); + } +} + void tst_tbv() { tst0(); + tst1(31); tst1(11); tst1(15); tst1(16); tst1(17); + + tst2(31); + tst2(11); + tst2(15); + tst2(16); + tst2(17); } diff --git a/src/util/fixed_bit_vector.h b/src/util/fixed_bit_vector.h index 11cb91fef..4ada982d0 100644 --- a/src/util/fixed_bit_vector.h +++ b/src/util/fixed_bit_vector.h @@ -108,6 +108,7 @@ public: fixed_bit_vector& set_or(fixed_bit_vector& dst, fixed_bit_vector const& src) const; fixed_bit_vector& set_neg(fixed_bit_vector& dst) const; unsigned last_word(fixed_bit_vector const& bv) const; + unsigned get_mask() const { return m_mask; } bool equals(fixed_bit_vector const& a, fixed_bit_vector const& b) const; unsigned hash(fixed_bit_vector const& src) const; bool contains(fixed_bit_vector const& a, fixed_bit_vector const& b) const; From 816119e8aea92b0d215a4d00e7affc00f2db1f02 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 22 Sep 2014 01:37:11 -0700 Subject: [PATCH 563/925] fix bug in contains check Signed-off-by: Nikolaj Bjorner --- src/muz/rel/doc.cpp | 2 +- src/muz/rel/udoc_relation.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/muz/rel/doc.cpp b/src/muz/rel/doc.cpp index 927eed283..4f950973c 100644 --- a/src/muz/rel/doc.cpp +++ b/src/muz/rel/doc.cpp @@ -480,7 +480,7 @@ bool doc_manager::contains(doc const& a, doc const& b) const { for (unsigned i = 0; i < a.neg().size(); ++i) { bool found = false; for (unsigned j = 0; !found && j < b.neg().size(); ++j) { - found = m.contains(b.neg()[i],a.neg()[j]); + found = m.contains(b.neg()[j],a.neg()[i]); } if (!found) return false; } diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 205d52416..2f4cd2801 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -887,6 +887,7 @@ namespace datalog { u.intersect(dm, m_udoc); SASSERT(u.well_formed(dm)); if (m_condition && !u.is_empty()) { + std::cout << "Apply: " << m_condition << "\n"; t.apply_guard(m_condition, u, m_equalities, m_empty_bv); SASSERT(u.well_formed(dm)); } From 3203b6e2dbbabb01054815c69ecd814f012534e3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 22 Sep 2014 01:42:14 -0700 Subject: [PATCH 564/925] fix bug in contains check Signed-off-by: Nikolaj Bjorner --- src/muz/rel/udoc_relation.cpp | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 2f4cd2801..7ef3df3c2 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -867,12 +867,10 @@ namespace datalog { } t.extract_guard(condition, guard, m_condition); t.compile_guard(guard, m_udoc, m_empty_bv); - if (m.is_true(m_condition)) { - m_condition = 0; - } + TRACE("doc", - tout << "condition: " << mk_pp(condition, m) << "\n"; - if (m_condition) tout << m_condition << "\n"; + tout << "original condition: " << mk_pp(condition, m) << "\n"; + tout << "remaining condition: " << m_condition << "\n"; m_udoc.display(dm, tout) << "\n";); } @@ -883,11 +881,11 @@ namespace datalog { virtual void operator()(relation_base & tb) { udoc_relation & t = get(tb); udoc& u = t.get_udoc(); + ast_manager& m = m_condition.get_manager(); SASSERT(u.well_formed(dm)); u.intersect(dm, m_udoc); SASSERT(u.well_formed(dm)); - if (m_condition && !u.is_empty()) { - std::cout << "Apply: " << m_condition << "\n"; + if (!m.is_true(m_condition) && !u.is_empty()) { t.apply_guard(m_condition, u, m_equalities, m_empty_bv); SASSERT(u.well_formed(dm)); } @@ -1025,9 +1023,6 @@ namespace datalog { t.extract_equalities(condition, non_eq_cond, m_equalities, m_roots); t.extract_guard(non_eq_cond, guard, m_condition); t.compile_guard(guard, m_udoc, m_col_list); - if (m.is_true(m_condition)) { - m_condition = 0; - } } virtual ~filter_proj_fn() { @@ -1037,6 +1032,7 @@ namespace datalog { udoc_relation const & t = get(tb); udoc const& u1 = t.get_udoc(); doc_manager& dm = t.get_dm(); + ast_manager& m = m_condition.get_manager(); udoc u2; SASSERT(u1.well_formed(dm)); u2.copy(dm, u1); @@ -1045,7 +1041,7 @@ namespace datalog { SASSERT(u2.well_formed(dm)); u2.merge(dm, m_roots, m_equalities, m_col_list); SASSERT(u2.well_formed(dm)); - if (m_condition && !u2.is_empty()) { + if (!m.is_true(m_condition) && !u2.is_empty()) { t.apply_guard(m_condition, u2, m_equalities, m_col_list); SASSERT(u2.well_formed(dm)); } From 8c34cfca3189c605171fda4a2e8a23c650dc5f72 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 22 Sep 2014 01:54:51 -0700 Subject: [PATCH 565/925] streamline condition, fix bugs in doc::subtract Signed-off-by: Nikolaj Bjorner --- src/muz/rel/doc.cpp | 14 +++++++++----- src/muz/rel/doc.h | 1 + src/muz/rel/udoc_relation.cpp | 26 +++++++++----------------- 3 files changed, 19 insertions(+), 22 deletions(-) diff --git a/src/muz/rel/doc.cpp b/src/muz/rel/doc.cpp index 4f950973c..7cad5ffe8 100644 --- a/src/muz/rel/doc.cpp +++ b/src/muz/rel/doc.cpp @@ -119,6 +119,12 @@ bool doc_manager::set_and(doc& dst, doc const& src) { } return (src.neg().is_empty() || fold_neg(dst)); } +bool doc_manager::set_and(doc& dst, tbv const& src) { + // (A \ B) & C = (A & C) \ B + if (!m.set_and(dst.pos(), src)) return false; + dst.neg().intersect(m, src); + return true; +} bool doc_manager::well_formed(doc const& d) const { if (!m.is_well_formed(d.pos())) return false; @@ -404,23 +410,21 @@ void doc_manager::complement(doc const& src, ptr_vector& result) { // (A & !A1 & & !B) | (A & B1 & !A1) // A \ {A1 u B} u (A & B1) \ {A1} void doc_manager::subtract(doc const& A, doc const& B, ptr_vector& result) { - doc_ref r(*this), r2(*this); + doc_ref r(*this); tbv_ref t(m); r = allocate(A); t = m.allocate(B.pos()); if (m.set_and(*t, A.pos()) && r->neg().insert(m, t.detach())) { result.push_back(r.detach()); - r = allocate(A); } else { result.push_back(allocate(A)); } for (unsigned i = 0; i < B.neg().size(); ++i) { - r2 = allocate(B.neg()[i]); - if (set_and(*r, *r2)) { + r = allocate(A); + if (set_and(*r, B.neg()[i])) { result.push_back(r.detach()); } - r = allocate(A); } } bool doc_manager::equals(doc const& a, doc const& b) const { diff --git a/src/muz/rel/doc.h b/src/muz/rel/doc.h index bf2cdc229..3c2b9091d 100644 --- a/src/muz/rel/doc.h +++ b/src/muz/rel/doc.h @@ -59,6 +59,7 @@ public: bool is_full(doc const& src) const; bool is_empty(doc const& src); bool set_and(doc& dst, doc const& src); + bool set_and(doc& dst, tbv const& src); bool fold_neg(doc& dst); bool intersect(doc const& A, doc const& B, doc& result); void complement(doc const& src, ptr_vector& result); diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 7ef3df3c2..1d0da90dd 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -753,16 +753,17 @@ namespace datalog { expr* e1, *e2; if (result.is_empty()) { } + else if (m.is_true(g)) { + } + else if (m.is_false(g)) { + result.reset(dm); + } else if (m.is_and(g)) { for (unsigned i = 0; !result.is_empty() && i < to_app(g)->get_num_args(); ++i) { apply_guard(to_app(g)->get_arg(i), result, equalities, discard_cols); } } else if (m.is_not(g, e1)) { - // REVIEW: (not (= x y)) should not cause - // the equivalence class to collapse. - // It seems the current organization with fix_eq_bits - // will merge the equivalence class as a side-effect. udoc sub; sub.push_back(dm.allocateX()); apply_guard(e1, sub, equalities, discard_cols); @@ -789,11 +790,6 @@ namespace datalog { result.display(dm, tout << "result:") << "\n";); sub.reset(dm); } - else if (m.is_true(g)) { - } - else if (m.is_false(g)) { - result.reset(dm); - } else if (is_var(g)) { SASSERT(m.is_bool(g)); unsigned v = to_var(g)->get_idx(); @@ -885,10 +881,8 @@ namespace datalog { SASSERT(u.well_formed(dm)); u.intersect(dm, m_udoc); SASSERT(u.well_formed(dm)); - if (!m.is_true(m_condition) && !u.is_empty()) { - t.apply_guard(m_condition, u, m_equalities, m_empty_bv); - SASSERT(u.well_formed(dm)); - } + t.apply_guard(m_condition, u, m_equalities, m_empty_bv); + SASSERT(u.well_formed(dm)); u.simplify(dm); SASSERT(u.well_formed(dm)); TRACE("doc", tout << "final size: " << t.get_size_estimate_rows() << '\n';); @@ -1041,10 +1035,8 @@ namespace datalog { SASSERT(u2.well_formed(dm)); u2.merge(dm, m_roots, m_equalities, m_col_list); SASSERT(u2.well_formed(dm)); - if (!m.is_true(m_condition) && !u2.is_empty()) { - t.apply_guard(m_condition, u2, m_equalities, m_col_list); - SASSERT(u2.well_formed(dm)); - } + t.apply_guard(m_condition, u2, m_equalities, m_col_list); + SASSERT(u2.well_formed(dm)); udoc_relation* r = get(t.get_plugin().mk_empty(get_result_signature())); doc_manager& dm2 = r->get_dm(); for (unsigned i = 0; i < u2.size(); ++i) { From 75b11d2b7504297e8fa51c23b8af97207ca43630 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 22 Sep 2014 03:22:26 -0700 Subject: [PATCH 566/925] fix bugs in doc Signed-off-by: Nikolaj Bjorner --- src/muz/rel/doc.cpp | 6 ++- src/muz/rel/doc.h | 21 ++++----- src/muz/rel/udoc_relation.cpp | 3 ++ src/test/doc.cpp | 87 ++++++++++++++++++++++++++++++++++- 4 files changed, 102 insertions(+), 15 deletions(-) diff --git a/src/muz/rel/doc.cpp b/src/muz/rel/doc.cpp index 7cad5ffe8..36717adf3 100644 --- a/src/muz/rel/doc.cpp +++ b/src/muz/rel/doc.cpp @@ -109,7 +109,7 @@ doc& doc_manager::fillX(doc& src) { bool doc_manager::set_and(doc& dst, doc const& src) { // (A \ B) & (C \ D) = (A & C) \ (B u D) if (!m.set_and(dst.pos(), src.pos())) return false; - dst.neg().intersect(m, src.pos()); + dst.neg().intersect(m, dst.pos()); tbv_ref t(m); for (unsigned i = 0; i < src.neg().size(); ++i) { t = m.allocate(src.neg()[i]); @@ -117,6 +117,7 @@ bool doc_manager::set_and(doc& dst, doc const& src) { dst.neg().insert(m, t.detach()); } } + SASSERT(well_formed(dst)); return (src.neg().is_empty() || fold_neg(dst)); } bool doc_manager::set_and(doc& dst, tbv const& src) { @@ -150,11 +151,12 @@ bool doc_manager::fold_neg(doc& dst) { } else { // count == 1: dst.pos().set(index, neg(dst.neg()[i][index])); - dst.neg().erase(tbvm(), i); + dst.neg().intersect(tbvm(), dst.pos()); goto start_over; } } } + SASSERT(well_formed(dst)); return true; } diff --git a/src/muz/rel/doc.h b/src/muz/rel/doc.h index 3c2b9091d..58850f812 100644 --- a/src/muz/rel/doc.h +++ b/src/muz/rel/doc.h @@ -175,20 +175,17 @@ public: } } void intersect(M& m, union_bvec const& other) { - union_bvec result; - unsigned sz1 = size(); - unsigned sz2 = other.size(); - T* inter = m.allocate(); - for (unsigned i = 0; i < sz1; ++i) { - for (unsigned j = 0; j < sz2; ++j) { - if (m.intersect(*m_elems[i], other[j], *inter)) { - result.push_back(inter); - inter = m.allocate(); - } + unsigned sz = other.size(); + union_bvec tmp, result; + for (unsigned i = 0; i < sz; ++i) { + tmp.copy(m, *this); + tmp.intersect(m, other[i]); + for (unsigned j = 0; j < tmp.size(); ++j) { + result.push_back(tmp.m_elems[j]); } + tmp.m_elems.reset(); } - m.deallocate(inter); - std::swap(result, *this); + std::swap(*this, result); result.reset(m); } void subtract(M& m, union_bvec const& other) { diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 1d0da90dd..8abcd9050 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -382,6 +382,7 @@ namespace datalog { } } TRACE("doc", result->display(tout << "result:\n");); + IF_VERBOSE(3, result->display(verbose_stream() << "join result:\n");); SASSERT(r.well_formed(result->get_dm())); return result; } @@ -544,6 +545,7 @@ namespace datalog { SASSERT(r.get_udoc().well_formed(dm)); SASSERT(!d1 || d1->well_formed(dm)); TRACE("doc", _r.display(tout << "dst':\n"); ); + IF_VERBOSE(3, _r.display(verbose_stream() << "union result:\n");); } }; void udoc_plugin::mk_union(doc_manager& dm, udoc& dst, udoc const& src, udoc* delta) { @@ -1045,6 +1047,7 @@ namespace datalog { SASSERT(r->get_udoc().well_formed(dm2)); } u2.reset(dm); + IF_VERBOSE(3, r->display(verbose_stream() << "filter result:\n");); return r; } }; diff --git a/src/test/doc.cpp b/src/test/doc.cpp index 6bd7e50b9..45206d4ca 100644 --- a/src/test/doc.cpp +++ b/src/test/doc.cpp @@ -113,6 +113,47 @@ class test_doc_cls { default : return BIT_x; } } + + tbv* mk_rand_tbv() { + tbv* result = dm.tbvm().allocate(); + for (unsigned i = 0; i < dm.num_tbits(); ++i) { + (*result).set(i, choose_tbit()); + } + return result; + } + + tbv* mk_rand_tbv(tbv const& pos) { + tbv* result = dm.tbvm().allocate(); + for (unsigned i = 0; i < dm.num_tbits(); ++i) { + if (pos[i] == BIT_x) { + (*result).set(i, choose_tbit()); + } + else { + (*result).set(i, pos[i]); + } + } + return result; + } + + doc* mk_rand_doc(unsigned num_diff) { + tbv_ref t(dm.tbvm()); + t = mk_rand_tbv(); + doc* result = dm.allocate(*t); + SASSERT(dm.tbvm().equals(*t, result->pos())); + for (unsigned i = 0; i < num_diff; ++i) { + result->neg().push_back(mk_rand_tbv(result->pos())); + } + SASSERT(dm.well_formed(*result)); + return result; + } + + void mk_rand_udoc(unsigned num_elems, unsigned num_diff, udoc& result) { + result.reset(dm); + for (unsigned i = 0; i < num_elems; ++i) { + result.push_back(mk_rand_doc(num_diff)); + } + } + expr_ref mk_conj(tbv& t) { expr_ref result(m); expr_ref_vector conjs(m); @@ -284,6 +325,12 @@ class test_doc_cls { fml = m.mk_not(m.mk_eq(fml1, fml2)); solver.assert_expr(fml); lbool res = solver.check(); + if (res != l_false) { + TRACE("doc", + tout << mk_pp(fml1, m) << "\n"; + tout << mk_pp(fml2, m) << "\n"; + ); + } SASSERT(res == l_false); } @@ -349,6 +396,43 @@ public: ds2.reset(dm); //sub:{xxx \ {1x0, 0x1}} //result:{100} + + for (unsigned i = 0; i < 1000; ++i) { + udoc d1, d2; + mk_rand_udoc(3, 3, d1); + mk_rand_udoc(3, 3, d2); + fml1 = to_formula(d1, dm, to_delete.c_ptr()); + fml2 = to_formula(d2, dm, to_delete.c_ptr()); + d1.subtract(dm, d2); + fml3 = to_formula(d1, dm, to_delete.c_ptr()); + fml1 = m.mk_and(fml1, m.mk_not(fml2)); + check_equiv(fml1, fml3); + d1.reset(dm); + d2.reset(dm); + } + } + + void test_intersect() { + expr_ref fml1(m), fml2(m), fml3(m); + svector to_delete(m_vars.size(), false); + for (unsigned i = 0; i < 10000; ++i) { + udoc d1, d2; + mk_rand_udoc(3, 3, d1); + mk_rand_udoc(3, 3, d2); + fml1 = to_formula(d1, dm, to_delete.c_ptr()); + fml2 = to_formula(d2, dm, to_delete.c_ptr()); + TRACE("doc", + d1.display(dm, tout) << "\n"; + d2.display(dm, tout) << "\n";); + d1.intersect(dm, d2); + TRACE("doc", d1.display(dm, tout) << "\n";); + SASSERT(d1.well_formed(dm)); + fml3 = to_formula(d1, dm, to_delete.c_ptr()); + fml1 = m.mk_and(fml1, fml2); + check_equiv(fml1, fml3); + d1.reset(dm); + d2.reset(dm); + } } }; @@ -356,7 +440,8 @@ public: void tst_doc() { - test_doc_cls tp(4); + test_doc_cls tp(4); + tp.test_intersect(); tp.test_subtract(); tp.test_merge(200,7); tp.test_project(200,7); From 4cf8905a8f0e8be2b8396fa36430dc41e665f9e0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 22 Sep 2014 11:08:23 -0700 Subject: [PATCH 567/925] fixing join Signed-off-by: Nikolaj Bjorner --- src/muz/rel/udoc_relation.cpp | 54 ++++++++------ src/test/udoc_relation.cpp | 130 ++++++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+), 21 deletions(-) diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 8abcd9050..f4b758c5e 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -304,13 +304,16 @@ namespace datalog { } void join(doc const& d1, doc const& d2, udoc& result) { - doc* d = dm.allocateX(); + doc_ref d(dm); + tbv_ref t(dm.tbvm()); + d = dm.allocateX(); tbv& pos = d->pos(); utbv& neg = d->neg(); unsigned mid = dm1.num_tbits(); unsigned hi = dm.num_tbits(); pos.set(d1.pos(), mid-1, 0); pos.set(d2.pos(), hi-1, mid); + SASSERT(dm.well_formed(*d)); // first fix bits for (unsigned i = 0; i < m_cols1.size(); ++i) { unsigned idx1 = m_cols1[i]; @@ -321,13 +324,15 @@ namespace datalog { if (v1 == BIT_x) { if (v2 != BIT_x) pos.set(idx1, v2); - } else if (v2 == BIT_x) { + } + else if (v2 == BIT_x) { pos.set(idx2, v1); - } else if (v1 != v2) { - dm.deallocate(d); + } + else if (v1 != v2) { // columns don't match return; } + SASSERT(dm.well_formed(*d)); } // fix equality of don't care columns for (unsigned i = 0; i < m_cols1.size(); ++i) { @@ -338,32 +343,39 @@ namespace datalog { if (v1 == BIT_x && v2 == BIT_x) { // add to subtracted TBVs: 1xx0 and 0xx1 - tbv* r = dm.tbvm().allocate(pos); - r->set(idx1, BIT_0); - r->set(idx2, BIT_1); - neg.push_back(r); - - r = dm.tbvm().allocate(pos); - r->set(idx1, BIT_1); - r->set(idx2, BIT_0); - neg.push_back(r); + t = dm.tbvm().allocate(pos); + t->set(idx1, BIT_0); + t->set(idx2, BIT_1); + neg.push_back(t.detach()); + t = dm.tbvm().allocate(pos); + t->set(idx1, BIT_1); + t->set(idx2, BIT_0); + neg.push_back(t.detach()); } + SASSERT(dm.well_formed(*d)); } // handle subtracted TBVs: 1010 -> 1010xxx for (unsigned i = 0; i < d1.neg().size(); ++i) { - tbv* t = dm.tbvm().allocate(); - t->set(d1.neg()[i], mid-1, 0); - t->set(d2.pos(), hi - 1, mid); - neg.push_back(t); + t = dm.tbvm().allocate(); + t->set(d1.neg()[i], mid - 1, 0); + t->set(d2.pos(), hi - 1, mid); + if (dm.tbvm().set_and(*t, pos)) { + neg.push_back(t.detach()); + } + SASSERT(dm.well_formed(*d)); } for (unsigned i = 0; i < d2.neg().size(); ++i) { - tbv* t = dm.tbvm().allocate(); - t->set(d1.pos(), mid-1, 0); + t = dm.tbvm().allocate(); + t->set(d1.pos(), mid- 1, 0); t->set(d2.neg()[i], hi - 1, mid); - neg.push_back(t); + if (dm.tbvm().set_and(*t, pos)) { + neg.push_back(t.detach()); + } + SASSERT(dm.well_formed(*d)); } - result.insert(dm, d); + SASSERT(dm.well_formed(*d)); + result.insert(dm, d.detach()); } virtual relation_base * operator()(const relation_base & _r1, const relation_base & _r2) { diff --git a/src/test/udoc_relation.cpp b/src/test/udoc_relation.cpp index 197186bbf..4942164e2 100644 --- a/src/test/udoc_relation.cpp +++ b/src/test/udoc_relation.cpp @@ -16,6 +16,7 @@ #include "rel_context.h" #include "bv_decl_plugin.h" + class udoc_tester { typedef datalog::relation_base relation_base; typedef datalog::udoc_relation udoc_relation; @@ -40,6 +41,56 @@ class udoc_tester { datalog::context m_ctx; datalog::rel_context rc; udoc_plugin& p; + + + tbit choose_tbit() { + switch (m_rand(3)) { + case 0: return BIT_0; + case 1: return BIT_1; + default : return BIT_x; + } + } + + tbv* mk_rand_tbv(doc_manager& dm) { + tbv* result = dm.tbvm().allocate(); + for (unsigned i = 0; i < dm.num_tbits(); ++i) { + (*result).set(i, choose_tbit()); + } + return result; + } + + tbv* mk_rand_tbv(doc_manager& dm, tbv const& pos) { + tbv* result = dm.tbvm().allocate(); + for (unsigned i = 0; i < dm.num_tbits(); ++i) { + if (pos[i] == BIT_x) { + (*result).set(i, choose_tbit()); + } + else { + (*result).set(i, pos[i]); + } + } + return result; + } + + doc* mk_rand_doc(doc_manager& dm, unsigned num_diff) { + tbv_ref t(dm.tbvm()); + t = mk_rand_tbv(dm); + doc* result = dm.allocate(*t); + SASSERT(dm.tbvm().equals(*t, result->pos())); + for (unsigned i = 0; i < num_diff; ++i) { + result->neg().push_back(mk_rand_tbv(dm, result->pos())); + } + SASSERT(dm.well_formed(*result)); + return result; + } + + void mk_rand_udoc(doc_manager& dm, unsigned num_elems, unsigned num_diff, udoc& result) { + result.reset(dm); + for (unsigned i = 0; i < num_elems; ++i) { + result.push_back(mk_rand_doc(dm, num_diff)); + } + } + public: udoc_tester(): m_init(m), bv(m), m_vars(m), m_ctx(m, m_reg, m_smt_params), rc(m_ctx), p(dynamic_cast(*rc.get_rmanager().get_relation_plugin(symbol("doc")))) @@ -88,6 +139,8 @@ public: udoc_relation* t1, *t2, *t3; expr_ref fml(m); + test_join(1000); + test_rename(); test_filter_neg(); @@ -366,6 +419,83 @@ public: check_permutation(t1, cycle); } + void test_join(unsigned num_rounds) { + for (unsigned i = 0; i < num_rounds; ++i) { + test_join(); + } + } + + void test_join() { + relation_signature sig; + sig.push_back(bv.mk_sort(2)); + sig.push_back(bv.mk_sort(3)); + udoc_relation* t1, *t2; + relation_base* t; + + t1 = mk_rand(sig); + t2 = mk_rand(sig); + + unsigned_vector jc1, jc2; + jc1.push_back(0); + jc2.push_back(0); + scoped_ptr join_fn; + + join_fn = p.mk_join_fn(*t1, *t2, jc1.size(), jc1.c_ptr(), jc2.c_ptr()); + t = (*join_fn)(*t1, *t2); + + verify_join(*t1, *t2, *t, jc1.size(), jc1.c_ptr(), jc2.c_ptr()); + t1->display(std::cout); + t2->display(std::cout); + t->display(std::cout); + std::cout << "\n"; + t1->deallocate(); + t2->deallocate(); + t->deallocate(); + } + + udoc_relation* mk_rand(relation_signature const& sig) { + udoc_relation* t = mk_empty(sig); + mk_rand_udoc(t->get_dm(), 3, 3, t->get_udoc()); + return t; + } + + void verify_join(relation_base const& t1, relation_base& t2, relation_base& t, + unsigned sz, unsigned const* cols1, unsigned const* cols2) { + relation_signature const& sig1 = t1.get_signature(); + relation_signature const& sig2 = t2.get_signature(); + relation_signature const& sig = t.get_signature(); + expr_ref fml1(m), fml2(m), fml3(m); + var_ref var1(m), var2(m); + t1.to_formula(fml1); + t2.to_formula(fml2); + t.to_formula(fml3); + var_subst sub(m, false); + expr_ref_vector vars(m); + for (unsigned i = 0; i < sig2.size(); ++i) { + vars.push_back(m.mk_var(i + sig1.size(), sig2[i])); + } + sub(fml2, vars.size(), vars.c_ptr(), fml2); + fml1 = m.mk_and(fml1, fml2); + for (unsigned i = 0; i < sz; ++i) { + unsigned v1 = cols1[i]; + unsigned v2 = cols2[i]; + var1 = m.mk_var(v1, sig1[v1]); + var2 = m.mk_var(v2 + sig1.size(), sig2[v2]); + fml1 = m.mk_and(m.mk_eq(var1, var2), fml1); + } + vars.reset(); + for (unsigned i = 0; i < sig.size(); ++i) { + std::stringstream strm; + strm << "x" << i; + vars.push_back(m.mk_const(symbol(strm.str().c_str()), sig[i])); + } + sub(fml1, vars.size(), vars.c_ptr(), fml1); + sub(fml3, vars.size(), vars.c_ptr(), fml3); + check_equiv(fml1, fml3); + } + + + void check_permutation(relation_base* t1, unsigned_vector const& cycle) { scoped_ptr rename; rename = p.mk_rename_fn(*t1, cycle.size(), cycle.c_ptr()); From 83e7107485b29b6fdc3e4d25692620bf72e4642d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 22 Sep 2014 17:45:01 -0700 Subject: [PATCH 568/925] fix bugs in doc Signed-off-by: Nikolaj Bjorner --- src/muz/rel/doc.cpp | 217 +++++++++++++++++++++------------- src/muz/rel/doc.h | 21 +++- src/muz/rel/tbv.cpp | 4 +- src/muz/rel/udoc_relation.cpp | 28 +++-- src/muz/rel/udoc_relation.h | 2 +- src/test/doc.cpp | 153 ++++++++++++++---------- src/util/fixed_bit_vector.cpp | 16 +++ src/util/fixed_bit_vector.h | 3 + 8 files changed, 287 insertions(+), 157 deletions(-) diff --git a/src/muz/rel/doc.cpp b/src/muz/rel/doc.cpp index 36717adf3..4018441a1 100644 --- a/src/muz/rel/doc.cpp +++ b/src/muz/rel/doc.cpp @@ -82,12 +82,8 @@ void doc_manager::deallocate(doc* src) { } void doc_manager::copy(doc& dst, doc const& src) { m.copy(dst.pos(), src.pos()); - unsigned n = std::min(src.neg().size(), dst.neg().size()); - for (unsigned i = 0; i < n; ++i) { - m.copy(dst.neg()[i], src.neg()[i]); - } dst.neg().reset(m); - for (unsigned i = n; i < src.neg().size(); ++i) { + for (unsigned i = 0; i < src.neg().size(); ++i) { dst.neg().push_back(m.allocate(src.neg()[i])); } } @@ -109,16 +105,17 @@ doc& doc_manager::fillX(doc& src) { bool doc_manager::set_and(doc& dst, doc const& src) { // (A \ B) & (C \ D) = (A & C) \ (B u D) if (!m.set_and(dst.pos(), src.pos())) return false; - dst.neg().intersect(m, dst.pos()); + dst.neg().intersect(m, dst.pos()); tbv_ref t(m); for (unsigned i = 0; i < src.neg().size(); ++i) { t = m.allocate(src.neg()[i]); if (m.set_and(*t, dst.pos())) { + if (m.equals(*t, dst.pos())) return false; dst.neg().insert(m, t.detach()); } } SASSERT(well_formed(dst)); - return (src.neg().is_empty() || fold_neg(dst)); + return fold_neg(dst); } bool doc_manager::set_and(doc& dst, tbv const& src) { // (A \ B) & C = (A & C) \ B @@ -279,80 +276,60 @@ bool doc_manager::intersect(doc const& A, doc const& B, doc& result) { // doc* doc_manager::project(doc_manager& dstm, unsigned n, bool const* to_delete, doc const& src) { - tbv_manager& dstt = dstm.m; - doc* r = dstm.allocate(dstt.project(n, to_delete, src.pos())); + tbv_manager& dstt = dstm.m; + tbv_ref t(dstt); + t = dstt.project(n, to_delete, src.pos()); + doc* r = dstm.allocate(t.detach()); SASSERT(r); if (src.neg().is_empty()) { return r; } - if (src.neg().size() == 1) { - r->neg().push_back(dstt.project(n, to_delete, src.neg()[0])); - return r; - } - - // - // All negations can be projected if they are sign compatible. - // - tbv_ref bits(tbvm(), tbvm().allocateX()); - for (unsigned i = 0; i < src.neg().size(); ++i) { - tbvm().set_and(*bits, src.neg()[i]); - } - bool can_project_const = true; - for (unsigned i = 0; can_project_const && i < n; ++i) { - can_project_const = !to_delete[i] || (*bits)[i] == BIT_x; - } - if (can_project_const) { - for (unsigned i = 0; i < src.neg().size(); ++i) { - r->neg().push_back(dstt.project(n, to_delete, src.neg()[i])); - } - return r; - } // // A negation can be projected directly if it does not constrain // deleted variables. // - ptr_vector todo; + tbv_vector todo, new_todo; for (unsigned i = 0; i < src.neg().size(); ++i) { - if (can_project_neg(src.pos(), n, to_delete, src.neg()[i])) { - r->neg().push_back(dstt.project(n, to_delete, src.neg()[i])); - } - else { - todo.push_back(tbvm().allocate(src.neg()[i])); - } + todo.push_back(tbvm().allocate(src.neg()[i])); } - if (todo.empty()) { - return r; - } - ptr_vector new_todo; - utbv pos, neg; - tbv_ref t1(tbvm()), t2(tbvm()); - for (unsigned i = 0; i < n; ++i) { - if (to_delete[i] && (*bits)[i] != BIT_x) { - TRACE("doc", tout << "delete " << i << " "; - for (unsigned j = 0; j < todo.size(); ++j) { - tbvm().display(tout, *todo[j]) << " "; - } - tout << "\n";); - SASSERT(pos.is_empty()); - SASSERT(neg.is_empty()); - SASSERT(new_todo.empty()); - while (!todo.empty()) { - tbv* t = todo.back(); - todo.pop_back(); - switch((*t)[i]) { - case BIT_x: new_todo.push_back(t); break; - case BIT_0: neg.push_back(t); break; - case BIT_1: pos.push_back(t); break; - default: UNREACHABLE(); break; + unsigned idx; + bool done = false; + while (!todo.empty() && !done) { + switch(pick_resolvent(src.pos(), todo, to_delete, idx)) { + case project_is_empty: + t = dstt.allocate(r->pos()); + r->neg().push_back(t.detach()); + done = true; + break; + case project_monolithic: + done = true; + break; + case project_neg: + case project_pos: + for (unsigned i = 0; i < todo.size(); ++i) { + tbv& tx = *todo[i]; + if (tx[idx] == BIT_x) { + new_todo.push_back(&tx); + } + else { + m.deallocate(&tx); } } - if (pos.is_empty() || neg.is_empty()) { - std::swap(new_todo, todo); - pos.reset(tbvm()); - neg.reset(tbvm()); - continue; + std::swap(new_todo, todo); + new_todo.reset(); + break; + case project_resolve: { + utbv pos, neg; + for (unsigned i = 0; i < todo.size(); ++i) { + tbv& tx = *todo[i]; + switch(tx[idx]) { + case BIT_x: new_todo.push_back(&tx); break; + case BIT_0: neg.push_back(&tx); break; + case BIT_1: pos.push_back(&tx); break; + default: UNREACHABLE(); break; + } } TRACE("doc", tout << "pos: "; @@ -365,38 +342,120 @@ doc* doc_manager::project(doc_manager& dstm, unsigned n, bool const* to_delete, } tout << "\n"; ); - + SASSERT(pos.size() > 0 && neg.size() > 0); + tbv_ref t1(m); for (unsigned j = 0; j < pos.size(); ++j) { for (unsigned k = 0; k < neg.size(); ++k) { - t1 = tbvm().allocate(pos[j]); - (*t1).set(i, BIT_x); + t1 = m.allocate(pos[j]); + (*t1).set(idx, BIT_x); if (tbvm().set_and(*t1, neg[k])) { - (*t1).set(i, BIT_x); + (*t1).set(idx, BIT_x); new_todo.push_back(t1.detach()); } - } - } - pos.reset(tbvm()); - neg.reset(tbvm()); + } + } + pos.reset(m); + neg.reset(m); std::swap(todo, new_todo); + new_todo.reset(); + break; + } + case project_done: { + for (unsigned i = 0; i < todo.size(); ++i) { + t = dstt.project(n, to_delete, *todo[i]); + if (dstt.equals(r->pos(), *t)) { + r->neg().reset(dstt); + r->neg().push_back(t.detach()); + break; + } + if (r->neg().size() > 0 && dstt.equals(r->neg()[0], *t)) { + continue; + } + r->neg().push_back(t.detach()); + } + done = true; + break; + } } } for (unsigned i = 0; i < todo.size(); ++i) { - r->neg().push_back(dstt.project(n, to_delete, *todo[i])); - tbvm().deallocate(todo[i]); + m.deallocate(todo[i]); } return r; } +#if 0 bool doc_manager::can_project_neg(tbv const& pos, unsigned n, bool const* to_delete, tbv const& neg) { for (unsigned i = 0; i < n; ++i) { if (to_delete[i] && BIT_x != neg[i] && BIT_x == pos[i]) return false; } return true; } +#endif + +doc_manager::project_action_t +doc_manager::pick_resolvent( + tbv const& pos, tbv_vector const& neg, bool const* to_delete, unsigned& idx) { + if (neg.empty()) return project_done; + for (unsigned j = 0; j < neg.size(); ++j) { + if (m.equals(pos, *neg[j])) return project_is_empty; + } + + unsigned best_pos = UINT_MAX; + unsigned best_neg = UINT_MAX; + unsigned best_idx = UINT_MAX; + for (unsigned i = 0; i < num_tbits(); ++i) { + if (!to_delete[i]) continue; + if (pos[i] != BIT_x) continue; + unsigned num_pos = 0, num_neg = 0; + tbit b1 = (*neg[0])[i]; + if (b1 == BIT_0) num_neg++; + if (b1 == BIT_1) num_pos++; + bool monolithic = true; + for (unsigned j = 1; j < neg.size(); ++j) { + tbit b2 = (*neg[j])[i]; + if (b1 != b2) { + monolithic = false; + } + if (b2 == BIT_0) num_neg++; + if (b2 == BIT_1) num_pos++; + } + if (monolithic && b1 != BIT_x) { + idx = i; + return project_monolithic; + } + if (monolithic && b1 == BIT_x) { + continue; + } + SASSERT(!monolithic); + if (num_pos == 0) { + SASSERT(num_neg > 0); + idx = i; + return project_neg; + } + if (num_neg == 0) { + SASSERT(num_pos > 0); + idx = i; + return project_pos; + } + if ((best_pos >= num_pos && best_neg >= num_neg) || + num_neg == 1 || num_pos == 1) { + best_pos = num_pos; + best_neg = num_neg; + best_idx = i; + } + } + if (best_idx != UINT_MAX) { + idx = best_idx; + return project_resolve; + } + else { + return project_done; + } +} -void doc_manager::complement(doc const& src, ptr_vector& result) { +void doc_manager::complement(doc const& src, doc_vector& result) { result.reset(); if (is_full(src)) { return; @@ -411,7 +470,7 @@ void doc_manager::complement(doc const& src, ptr_vector& result) { // (A \ {A1}) \ (B \ {B1}) // (A & !A1 & & !B) | (A & B1 & !A1) // A \ {A1 u B} u (A & B1) \ {A1} -void doc_manager::subtract(doc const& A, doc const& B, ptr_vector& result) { +void doc_manager::subtract(doc const& A, doc const& B, doc_vector& result) { doc_ref r(*this); tbv_ref t(m); r = allocate(A); diff --git a/src/muz/rel/doc.h b/src/muz/rel/doc.h index 58850f812..30858bbbd 100644 --- a/src/muz/rel/doc.h +++ b/src/muz/rel/doc.h @@ -25,16 +25,30 @@ Revision History: #include "tbv.h" #include "union_find.h" +#include "buffer.h" class doc; template class union_bvec; typedef union_find<> subset_ints; +typedef union_bvec utbv; +typedef buffer tbv_vector; +typedef buffer doc_vector; class doc_manager { tbv_manager m; tbv* m_full; small_object_allocator m_alloc; + enum project_action_t { + project_is_empty, + project_done, + project_monolithic, + project_neg, + project_pos, + project_resolve + }; + project_action_t pick_resolvent( + tbv const& pos, tbv_vector const& neg, bool const* to_delete, unsigned& idx); public: doc_manager(unsigned num_bits); ~doc_manager(); @@ -62,8 +76,8 @@ public: bool set_and(doc& dst, tbv const& src); bool fold_neg(doc& dst); bool intersect(doc const& A, doc const& B, doc& result); - void complement(doc const& src, ptr_vector& result); - void subtract(doc const& A, doc const& B, ptr_vector& result); + void complement(doc const& src, doc_vector& result); + void subtract(doc const& A, doc const& B, doc_vector& result); bool equals(doc const& a, doc const& b) const; unsigned hash(doc const& src) const; bool contains(doc const& a, doc const& b) const; @@ -83,7 +97,7 @@ private: // union of tbv*, union of doc* template class union_bvec { - ptr_vector m_elems; // TBD: reuse allocator of M + buffer m_elems; // TBD: reuse allocator of M enum fix_bit_result_t { e_row_removed, // = 1 @@ -278,7 +292,6 @@ public: }; -typedef union_bvec utbv; class doc { // pos \ (neg_0 \/ ... \/ neg_n) diff --git a/src/muz/rel/tbv.cpp b/src/muz/rel/tbv.cpp index 0dcbcade9..6f175f8de 100644 --- a/src/muz/rel/tbv.cpp +++ b/src/muz/rel/tbv.cpp @@ -130,9 +130,7 @@ void tbv::set(rational const& r, unsigned hi, unsigned lo) { } void tbv::set(tbv const& other, unsigned hi, unsigned lo) { - for (unsigned i = 0; i < hi - lo + 1; ++i) { - set(lo + i, other[i]); - } + fixed_bit_vector::set(other, 2*hi+1, 2*lo); } diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index f4b758c5e..110c75ef4 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -743,7 +743,7 @@ namespace datalog { } apply_guard(g, result, equalities, discard_cols); } - bool udoc_relation::apply_eq(expr* g, udoc& result, unsigned v, unsigned hi, unsigned lo, expr* c) const { + bool udoc_relation::apply_eq(expr* g, doc_ref& d, unsigned v, unsigned hi, unsigned lo, expr* c) const { udoc_plugin& p = get_plugin(); unsigned num_bits; rational r; @@ -751,9 +751,8 @@ namespace datalog { lo += col; hi += col; if (p.is_numeral(c, r, num_bits)) { - doc_ref d(dm, dm.allocateX()); + d = dm.allocateX(); d->pos().set(r, hi, lo); - result.intersect(dm, *d); return true; } // other cases? @@ -764,7 +763,9 @@ namespace datalog { expr* g, udoc& result, subset_ints const& equalities, bit_vector const& discard_cols) const { ast_manager& m = get_plugin().get_ast_manager(); bv_util& bv = get_plugin().bv; - expr* e1, *e2; + expr *e0, *e1, *e2; + unsigned hi, lo, lo1, lo2, hi1, hi2, v, v1, v2; + doc_ref d(get_dm()); if (result.is_empty()) { } else if (m.is_true(g)) { @@ -777,6 +778,18 @@ namespace datalog { apply_guard(to_app(g)->get_arg(i), result, equalities, discard_cols); } } + else if (m.is_not(g, e0) && + m.is_eq(e0, e1, e2) && bv.is_bv(e1) && + is_var_range(e1, hi, lo, v) && is_ground(e2) && + apply_eq(g, d, v, hi, lo, e2)) { + result.subtract(dm, *d); + } + else if (m.is_not(g, e0) && + m.is_eq(e0, e2, e1) && bv.is_bv(e1) && + is_var_range(e1, hi, lo, v) && is_ground(e2) && + apply_eq(g, d, v, hi, lo, e2)) { + result.subtract(dm, *d); + } else if (m.is_not(g, e1)) { udoc sub; sub.push_back(dm.allocateX()); @@ -830,12 +843,13 @@ namespace datalog { diff2.reset(dm); } else if (m.is_eq(g, e1, e2) && bv.is_bv(e1)) { - unsigned hi, lo, lo1, lo2, hi1, hi2, v, v1, v2; if (is_var_range(e1, hi, lo, v) && is_ground(e2) && - apply_eq(g, result, v, hi, lo, e2)) { + apply_eq(g, d, v, hi, lo, e2)) { + result.intersect(dm, *d); } else if (is_var_range(e2, hi, lo, v) && is_ground(e1) && - apply_eq(g, result, v, hi, lo, e1)) { + apply_eq(g, d, v, hi, lo, e1)) { + result.intersect(dm, *d); } else if (is_var_range(e1, hi1, lo1, v1) && is_var_range(e2, hi2, lo2, v2)) { diff --git a/src/muz/rel/udoc_relation.h b/src/muz/rel/udoc_relation.h index c3ce8d2c4..1d14062e6 100644 --- a/src/muz/rel/udoc_relation.h +++ b/src/muz/rel/udoc_relation.h @@ -70,7 +70,7 @@ namespace datalog { void extract_equalities(expr* g, expr_ref& rest, subset_ints& equalities, unsigned_vector& roots) const; void apply_guard(expr* g, udoc& result, bit_vector const& discard_cols) const; void apply_guard(expr* g, udoc& result, subset_ints const& equalities, bit_vector const& discard_cols) const; - bool apply_eq(expr* g, udoc& result, unsigned v, unsigned hi, unsigned lo, expr* c) const; + bool apply_eq(expr* g, doc_ref& d, unsigned v, unsigned hi, unsigned lo, expr* c) const; bool is_var_range(expr* e, unsigned& hi, unsigned& lo, unsigned& v) const; }; diff --git a/src/test/doc.cpp b/src/test/doc.cpp index 45206d4ca..409debfb0 100644 --- a/src/test/doc.cpp +++ b/src/test/doc.cpp @@ -170,49 +170,47 @@ class test_doc_cls { return result; } - expr_ref to_formula(tbv const& t, doc_manager& m2, bool const* to_delete) { + expr_ref to_formula(tbv const& t, doc_manager& m2) { expr_ref result(m); expr_ref_vector conjs(m); unsigned n = m2.num_tbits(); tbv_manager& tm = m2.tbvm(); - for (unsigned i = 0, j = 0; i < m_vars.size(); ++i) { - if (!to_delete[i]) { - switch (t[j]) { - case BIT_x: - break; - case BIT_1: - conjs.push_back(m_vars[i].get()); - break; - case BIT_0: - conjs.push_back(m.mk_not(m_vars[i].get())); - break; - default: - UNREACHABLE(); - break; - } - ++j; + SASSERT(n <= m_vars.size()); + for (unsigned i = 0; i < n; ++i) { + switch (t[i]) { + case BIT_x: + break; + case BIT_1: + conjs.push_back(m_vars[i].get()); + break; + case BIT_0: + conjs.push_back(m.mk_not(m_vars[i].get())); + break; + default: + UNREACHABLE(); + break; } } result = mk_and(m, conjs.size(), conjs.c_ptr()); return result; } - expr_ref to_formula(doc const& d, doc_manager& m2, bool const* to_delete) { + expr_ref to_formula(doc const& d, doc_manager& m2) { expr_ref result(m); expr_ref_vector conjs(m); - conjs.push_back(to_formula(d.pos(), m2, to_delete)); + conjs.push_back(to_formula(d.pos(), m2)); for (unsigned i = 0; i < d.neg().size(); ++i) { - conjs.push_back(m.mk_not(to_formula(d.neg()[i], m2, to_delete))); + conjs.push_back(m.mk_not(to_formula(d.neg()[i], m2))); } result = mk_and(m, conjs.size(), conjs.c_ptr()); return result; } - expr_ref to_formula(udoc const& ud, doc_manager& m2, bool const* to_delete) { + expr_ref to_formula(udoc const& ud, doc_manager& m2) { expr_ref result(m); expr_ref_vector disjs(m); for (unsigned i = 0; i < ud.size(); ++i) { - disjs.push_back(to_formula(ud[i], m2, to_delete)); + disjs.push_back(to_formula(ud[i], m2)); } result = mk_or(m, disjs.size(), disjs.c_ptr()); return result; @@ -230,17 +228,12 @@ class test_doc_cls { ); } + void test_project(unsigned num_clauses) { - doc_ref d(dm, dm.allocateX()); - expr_ref_vector fmls(m); - th_rewriter rw(m); + doc_ref d(dm); + d = mk_rand_doc(3); expr_ref fml1(m), fml2(m), fml3(m), tmp1(m), tmp2(m), fml(m); - for (unsigned i = 0; i < num_clauses; ++i) { - tbv* t = dm.tbvm().allocate(); - fmls.push_back(m.mk_not(mk_conj(*t))); - d->neg().push_back(t); - } - fml1 = mk_and(m, fmls.size(), fmls.c_ptr()); + fml1 = to_formula(*d, dm); svector to_delete(m_vars.size(), false); unsigned num_bits = 1; for (unsigned i = 1; i < to_delete.size(); ++i) { @@ -250,33 +243,43 @@ class test_doc_cls { doc_manager m2(num_bits); doc_ref result(m2); project(*d, m2, to_delete.c_ptr(), result); - fml2 = to_formula(*result, m2, to_delete.c_ptr()); - rw(fml2); - + TRACE("doc", + dm.display(tout, *d) << "\n"; + m2.display(tout, *result) << "\n";); + fml2 = to_formula(*result, m2); + project_expand(fml1, to_delete.c_ptr()); + project_rename(fml2, to_delete.c_ptr()); + check_equiv(fml1, fml2); + } + + void project_expand(expr_ref& fml, bool const* to_delete) { + expr_ref tmp1(m), tmp2(m); for (unsigned i = 0; i < m_vars.size(); ++i) { if (to_delete[i]) { expr_safe_replace rep1(m), rep2(m); rep1.insert(m_vars[i].get(), m.mk_true()); - rep1(fml1, tmp1); + rep1(fml, tmp1); rep2.insert(m_vars[i].get(), m.mk_false()); - rep2(fml1, tmp2); - fml1 = m.mk_or(tmp1, tmp2); + rep2(fml, tmp2); + fml = m.mk_or(tmp1, tmp2); } } - rw(fml1); - smt_params fp; - smt::kernel solver(m, fp); - TRACE("doc", tout << "manual project:\n" << fml1 << "\nautomatic project: \n" << fml2 << "\n";); - fml = m.mk_not(m.mk_eq(fml1, fml2)); - solver.assert_expr(fml); - lbool res = solver.check(); - SASSERT(res == l_false); + } + + void project_rename(expr_ref& fml, bool const* to_delete) { + expr_safe_replace rep(m); + for (unsigned i = 0, j = 0; i < m_vars.size(); ++i) { + if (!to_delete[i]) { + rep.insert(m_vars[j].get(), m_vars[i].get()); + ++j; + } + } + rep(fml); } void test_merge(unsigned num_clauses) { doc_ref d(dm, dm.allocateX()); expr_ref_vector fmls(m), eqs(m); - th_rewriter rw(m); unsigned N = m_vars.size(); expr_ref fml1(m), fml2(m), fml3(m), tmp1(m), tmp2(m), fml(m); for (unsigned i = 0; i < num_clauses; ++i) { @@ -305,20 +308,21 @@ class test_doc_cls { eqs.push_back(m.mk_eq(m_vars[i].get(), m_vars[lo].get())); } } - eqs.push_back(to_formula(*d, dm, to_delete.c_ptr())); + eqs.push_back(to_formula(*d, dm)); fml1 = mk_and(m, eqs.size(), eqs.c_ptr()); if (dm.merge(*d, lo, 1, equalities, discard_cols)) { - fml2 = to_formula(*d, dm, to_delete.c_ptr()); + fml2 = to_formula(*d, dm); } else { fml2 = m.mk_false(); } - rw(fml1); - rw(fml2); check_equiv(fml1, fml2); } - void check_equiv(expr* fml1, expr* fml2) { + void check_equiv(expr_ref& fml1, expr_ref& fml2) { + th_rewriter rw(m); + rw(fml1); + rw(fml2); smt_params fp; smt::kernel solver(m, fp); expr_ref fml(m); @@ -355,6 +359,29 @@ public: } } + void test_project1() { + expr_ref fml1(m), fml2(m); + doc_ref d(dm, dm.allocateX()); + tbv_ref t(dm.tbvm(), dm.tbvm().allocateX()); + t->set(0, BIT_0); + d->neg().push_back(t.detach()); + unsigned num_bits = dm.num_tbits(); + svector to_delete(num_bits, false); + fml1 = to_formula(*d, dm); + to_delete[0] = true; + doc_manager m2(num_bits-1); + doc_ref result(m2); + project(*d, m2, to_delete.c_ptr(), result); + dm.display(std::cout, *d) << "\n"; + m2.display(std::cout, *result) << "\n"; + fml2 = to_formula(*result, m2); + project_rename(fml2, to_delete.c_ptr()); + project_expand(fml1, to_delete.c_ptr()); + std::cout << fml1 << " " << fml2 << "\n"; + check_equiv(fml1, fml2); + } + + void test_subtract() { doc_ref d1(dm); doc_ref d2(dm); @@ -384,12 +411,11 @@ public: ds2.push_back(d1.detach()); ds1.display(dm, std::cout) << "\n"; ds2.display(dm, std::cout) << "\n"; - svector to_delete(m_vars.size(), false); - expr_ref fml1 = to_formula(ds1, dm, to_delete.c_ptr()); - expr_ref fml2 = to_formula(ds2, dm, to_delete.c_ptr()); + expr_ref fml1 = to_formula(ds1, dm); + expr_ref fml2 = to_formula(ds2, dm); ds1.subtract(dm, ds2); ds1.display(dm, std::cout) << "\n"; - expr_ref fml3 = to_formula(ds1, dm, to_delete.c_ptr()); + expr_ref fml3 = to_formula(ds1, dm); fml1 = m.mk_and(fml1, m.mk_not(fml2)); check_equiv(fml1, fml3); ds1.reset(dm); @@ -401,10 +427,10 @@ public: udoc d1, d2; mk_rand_udoc(3, 3, d1); mk_rand_udoc(3, 3, d2); - fml1 = to_formula(d1, dm, to_delete.c_ptr()); - fml2 = to_formula(d2, dm, to_delete.c_ptr()); + fml1 = to_formula(d1, dm); + fml2 = to_formula(d2, dm); d1.subtract(dm, d2); - fml3 = to_formula(d1, dm, to_delete.c_ptr()); + fml3 = to_formula(d1, dm); fml1 = m.mk_and(fml1, m.mk_not(fml2)); check_equiv(fml1, fml3); d1.reset(dm); @@ -414,20 +440,19 @@ public: void test_intersect() { expr_ref fml1(m), fml2(m), fml3(m); - svector to_delete(m_vars.size(), false); for (unsigned i = 0; i < 10000; ++i) { udoc d1, d2; mk_rand_udoc(3, 3, d1); mk_rand_udoc(3, 3, d2); - fml1 = to_formula(d1, dm, to_delete.c_ptr()); - fml2 = to_formula(d2, dm, to_delete.c_ptr()); + fml1 = to_formula(d1, dm); + fml2 = to_formula(d2, dm); TRACE("doc", d1.display(dm, tout) << "\n"; d2.display(dm, tout) << "\n";); d1.intersect(dm, d2); TRACE("doc", d1.display(dm, tout) << "\n";); SASSERT(d1.well_formed(dm)); - fml3 = to_formula(d1, dm, to_delete.c_ptr()); + fml3 = to_formula(d1, dm); fml1 = m.mk_and(fml1, fml2); check_equiv(fml1, fml3); d1.reset(dm); @@ -441,10 +466,12 @@ public: void tst_doc() { test_doc_cls tp(4); + tp.test_project1(); + tp.test_project(200,7); + tp.test_intersect(); tp.test_subtract(); tp.test_merge(200,7); - tp.test_project(200,7); tst_doc1(5); tst_doc1(10); diff --git a/src/util/fixed_bit_vector.cpp b/src/util/fixed_bit_vector.cpp index 3711ef5eb..78196f568 100644 --- a/src/util/fixed_bit_vector.cpp +++ b/src/util/fixed_bit_vector.cpp @@ -24,6 +24,22 @@ Revision History: #include"trace.h" #include"hash.h" +void fixed_bit_vector::set(fixed_bit_vector const& other, unsigned hi, unsigned lo) { + if ((lo % 32) == 0) { + unsigned sz32 = (hi+1)/32; + unsigned lo32 = lo/32; + for (unsigned i = 0; i < sz32; ++i) { + m_data[lo32 + i] = other.m_data[i]; + } + for (unsigned i = sz32*32; i < hi - lo + 1; ++i) { + set(lo + i, other.get(i)); + } + return; + } + for (unsigned i = 0; i < hi - lo + 1; ++i) { + set(lo + i, other.get(i)); + } +} fixed_bit_vector_manager::fixed_bit_vector_manager(unsigned num_bits): m_alloc("fixed_bit_vector") { diff --git a/src/util/fixed_bit_vector.h b/src/util/fixed_bit_vector.h index 4ada982d0..fb7ed38e9 100644 --- a/src/util/fixed_bit_vector.h +++ b/src/util/fixed_bit_vector.h @@ -72,6 +72,9 @@ public: get_bit_word(bit_idx) ^= (-_val ^ get_bit_word(bit_idx)) & get_pos_mask(bit_idx); } + // assign bits this[lo:hi] := other[0:hi-lo+1] + void set(fixed_bit_vector const& other, unsigned hi, unsigned lo); + }; class fixed_bit_vector_manager { From b57353eff2794716439099a1f5b90e1c761058e6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 22 Sep 2014 18:06:18 -0700 Subject: [PATCH 569/925] fix bounds bug Signed-off-by: Nikolaj Bjorner --- src/util/fixed_bit_vector.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/fixed_bit_vector.cpp b/src/util/fixed_bit_vector.cpp index 78196f568..8843db736 100644 --- a/src/util/fixed_bit_vector.cpp +++ b/src/util/fixed_bit_vector.cpp @@ -26,7 +26,7 @@ Revision History: void fixed_bit_vector::set(fixed_bit_vector const& other, unsigned hi, unsigned lo) { if ((lo % 32) == 0) { - unsigned sz32 = (hi+1)/32; + unsigned sz32 = (hi-lo+1)/32; unsigned lo32 = lo/32; for (unsigned i = 0; i < sz32; ++i) { m_data[lo32 + i] = other.m_data[i]; From 54506408f904c28871ac7c7678c7582873cba9cf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 22 Sep 2014 22:03:59 -0700 Subject: [PATCH 570/925] fix overflow bugs in doc Signed-off-by: Nikolaj Bjorner --- src/muz/rel/doc.cpp | 24 ++++---- src/muz/rel/tbv.cpp | 43 +++++++++------ src/muz/rel/tbv.h | 14 ++--- src/muz/rel/udoc_relation.cpp | 100 +++++++++++++++++++++++----------- src/muz/rel/udoc_relation.h | 3 +- src/test/doc.cpp | 18 +++--- src/test/fixed_bit_vector.cpp | 32 +++++------ src/test/tbv.cpp | 4 +- src/test/udoc_relation.cpp | 6 +- src/util/fixed_bit_vector.h | 21 +++++++ 10 files changed, 164 insertions(+), 101 deletions(-) diff --git a/src/muz/rel/doc.cpp b/src/muz/rel/doc.cpp index 4018441a1..bb9e0e649 100644 --- a/src/muz/rel/doc.cpp +++ b/src/muz/rel/doc.cpp @@ -147,7 +147,7 @@ bool doc_manager::fold_neg(doc& dst) { --i; } else { // count == 1: - dst.pos().set(index, neg(dst.neg()[i][index])); + m.set(dst.pos(), index, neg(dst.neg()[i][index])); dst.neg().intersect(tbvm(), dst.pos()); goto start_over; } @@ -179,9 +179,9 @@ unsigned doc_manager::diff_by_012(tbv const& pos, tbv const& neg, unsigned& inde } void doc_manager::set(doc& d, unsigned idx, tbit value) { - d.pos().set(idx, value); + m.set(d.pos(), idx, value); for (unsigned i = 0; i < d.neg().size(); ++i) { - d.neg()[i].set(idx, value); + m.set(d.neg()[i], idx, value); } } @@ -243,13 +243,13 @@ bool doc_manager::merge(doc& d, unsigned idx, subset_ints const& equalities, else { do { if (!discard_cols.get(idx) && idx != root1) { - tbv* t = tbvm().allocate(d.pos()); - t->set(idx, BIT_0); - t->set(root1, BIT_1); + tbv* t = m.allocate(d.pos()); + m.set(*t, idx, BIT_0); + m.set(*t, root1, BIT_1); d.neg().insert(tbvm(), t); - t = tbvm().allocate(d.pos()); - t->set(idx, BIT_1); - t->set(root1, BIT_0); + t = m.allocate(d.pos()); + m.set(*t, idx, BIT_1); + m.set(*t, root1, BIT_0); d.neg().insert(tbvm(), t); } idx = equalities.next(idx); @@ -347,9 +347,9 @@ doc* doc_manager::project(doc_manager& dstm, unsigned n, bool const* to_delete, for (unsigned j = 0; j < pos.size(); ++j) { for (unsigned k = 0; k < neg.size(); ++k) { t1 = m.allocate(pos[j]); - (*t1).set(idx, BIT_x); + m.set(*t1, idx, BIT_x); if (tbvm().set_and(*t1, neg[k])) { - (*t1).set(idx, BIT_x); + m.set(*t1, idx, BIT_x); new_todo.push_back(t1.detach()); } } @@ -517,7 +517,7 @@ bool doc_manager::is_empty(doc const& src) { tbit b2 = src.neg()[i][j]; found = (b1 == BIT_x && b2 != BIT_x); if (found) { - pos->set(j, neg(b2)); + m.set(*pos, j, neg(b2)); } } if (!found) { diff --git a/src/muz/rel/tbv.cpp b/src/muz/rel/tbv.cpp index 6f175f8de..23a96981d 100644 --- a/src/muz/rel/tbv.cpp +++ b/src/muz/rel/tbv.cpp @@ -76,9 +76,9 @@ tbv* tbv_manager::allocate(uint64 val) { for (unsigned bit = num_tbits(); bit > 0;) { --bit; if (val & (1ULL << bit)) { - v->set(bit, BIT_1); + set(*v, bit, BIT_1); } else { - v->set(bit, BIT_0); + set(*v, bit, BIT_0); } } return v; @@ -87,14 +87,14 @@ tbv* tbv_manager::allocate(uint64 val) { tbv* tbv_manager::allocate(uint64 val, unsigned hi, unsigned lo) { tbv* v = allocateX(); SASSERT(64 >= num_tbits() && num_tbits() > hi && hi >= lo); - v->set(val, hi, lo); + set(*v, val, hi, lo); return v; } tbv* tbv_manager::allocate(tbv const& bv, unsigned const* permutation) { tbv* r = allocate(); unsigned sz = num_tbits(); for (unsigned i = 0; i < sz; ++i) { - r->set(permutation[i], bv[i]); + set(*r, permutation[i], bv[i]); } return r; } @@ -103,7 +103,7 @@ tbv* tbv_manager::project(unsigned n, bool const* to_delete, tbv const& src) { unsigned i, j; for (i = 0, j = 0; i < n; ++i) { if (!to_delete[i]) { - r->set(j, src[i]); + set(*r, j, src[i]); ++j; } } @@ -111,26 +111,35 @@ tbv* tbv_manager::project(unsigned n, bool const* to_delete, tbv const& src) { return r; } -void tbv::set(uint64 val, unsigned hi, unsigned lo) { +void tbv_manager::set(tbv& dst, unsigned index, tbit value) { + SASSERT(index < num_tbits()); + m.set(dst, 2*index, (value & 2) != 0); + m.set(dst, 2*index+1, (value & 1) != 0); +} + + +void tbv_manager::set(tbv& dst, uint64 val, unsigned hi, unsigned lo) { + SASSERT(lo <= hi && hi < num_tbits()); for (unsigned i = 0; i < hi - lo + 1; ++i) { - set(lo + i, (val & (1ULL << i))?BIT_1:BIT_0); + set(dst, lo + i, (val & (1ULL << i))?BIT_1:BIT_0); } } -void tbv::set(rational const& r, unsigned hi, unsigned lo) { +void tbv_manager::set(tbv& dst, rational const& r, unsigned hi, unsigned lo) { + SASSERT(lo <= hi && hi < num_tbits()); if (r.is_uint64()) { - set(r.get_uint64(), hi, lo); + set(dst, r.get_uint64(), hi, lo); return; } for (unsigned i = 0; i < hi - lo + 1; ++i) { if (bitwise_and(r, rational::power_of_two(i)).is_zero()) - set(lo + i, BIT_0); + set(dst, lo + i, BIT_0); else - set(lo + i, BIT_1); + set(dst, lo + i, BIT_1); } } -void tbv::set(tbv const& other, unsigned hi, unsigned lo) { - fixed_bit_vector::set(other, 2*hi+1, 2*lo); +void tbv_manager::set(tbv& dst, tbv const& other, unsigned hi, unsigned lo) { + dst.set(other, 2*hi+1, 2*lo); } @@ -142,9 +151,9 @@ tbv* tbv_manager::allocate(rational const& r) { for (unsigned bit = num_tbits(); bit > 0; ) { --bit; if (bitwise_and(r, rational::power_of_two(bit)).is_zero()) { - v->set(bit, BIT_0); + set(*v, bit, BIT_0); } else { - v->set(bit, BIT_1); + set(*v, bit, BIT_1); } } return v; @@ -211,12 +220,12 @@ void tbv_manager::complement(tbv const& src, ptr_vector& result) { switch (src.get(i)) { case BIT_0: r = allocate(src); - r->set(i, BIT_1); + set(*r, i, BIT_1); result.push_back(r); break; case BIT_1: r = allocate(src); - r->set(i, BIT_0); + set(*r, i, BIT_0); result.push_back(r); break; default: diff --git a/src/muz/rel/tbv.h b/src/muz/rel/tbv.h index 90965f7d0..e701efcbe 100644 --- a/src/muz/rel/tbv.h +++ b/src/muz/rel/tbv.h @@ -73,6 +73,11 @@ public: std::ostream& display(std::ostream& out, tbv const& b) const; tbv* project(unsigned n, bool const* to_delete, tbv const& src); bool is_well_formed(tbv const& b) const; // - does not contain BIT_z; + void set(tbv& dst, uint64 n, unsigned hi, unsigned lo); + void set(tbv& dst, rational const& r, unsigned hi, unsigned lo); + void set(tbv& dst, tbv const& other, unsigned hi, unsigned lo); + void set(tbv& dst, unsigned index, tbit value); + static void debug_alloc(); }; @@ -99,20 +104,13 @@ public: } }; - void set(uint64 n, unsigned hi, unsigned lo); - void set(rational const& r, unsigned hi, unsigned lo); - void set(tbv const& other, unsigned hi, unsigned lo); tbit operator[](unsigned idx) const { return (tbit)get(idx); } - void set(unsigned index, tbit value) { - SASSERT(value <= 3); - fixed_bit_vector::set(2*index, (value & 2) != 0); - fixed_bit_vector::set(2*index+1, (value & 1) != 0); - } private: + unsigned get(unsigned index) const { index *= 2; return (fixed_bit_vector::get(index) << 1) | (unsigned)fixed_bit_vector::get(index+1); diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 110c75ef4..fd3bf1415 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -49,7 +49,7 @@ namespace datalog { SASSERT(bv_size == column_num_bits(i)); unsigned lo = column_idx(i); unsigned hi = column_idx(i + 1); - d->pos().set(val, hi, lo); + dm.tbvm().set(d->pos(),val, hi-1, lo); } return d; } @@ -311,8 +311,8 @@ namespace datalog { utbv& neg = d->neg(); unsigned mid = dm1.num_tbits(); unsigned hi = dm.num_tbits(); - pos.set(d1.pos(), mid-1, 0); - pos.set(d2.pos(), hi-1, mid); + dm.tbvm().set(pos,d1.pos(), mid-1, 0); + dm.tbvm().set(pos,d2.pos(), hi-1, mid); SASSERT(dm.well_formed(*d)); // first fix bits for (unsigned i = 0; i < m_cols1.size(); ++i) { @@ -323,10 +323,10 @@ namespace datalog { if (v1 == BIT_x) { if (v2 != BIT_x) - pos.set(idx1, v2); + dm.tbvm().set(pos, idx1, v2); } else if (v2 == BIT_x) { - pos.set(idx2, v1); + dm.tbvm().set(pos, idx2, v1); } else if (v1 != v2) { // columns don't match @@ -344,12 +344,12 @@ namespace datalog { if (v1 == BIT_x && v2 == BIT_x) { // add to subtracted TBVs: 1xx0 and 0xx1 t = dm.tbvm().allocate(pos); - t->set(idx1, BIT_0); - t->set(idx2, BIT_1); + dm.tbvm().set(*t, idx1, BIT_0); + dm.tbvm().set(*t, idx2, BIT_1); neg.push_back(t.detach()); t = dm.tbvm().allocate(pos); - t->set(idx1, BIT_1); - t->set(idx2, BIT_0); + dm.tbvm().set(*t, idx1, BIT_1); + dm.tbvm().set(*t, idx2, BIT_0); neg.push_back(t.detach()); } SASSERT(dm.well_formed(*d)); @@ -358,8 +358,8 @@ namespace datalog { // handle subtracted TBVs: 1010 -> 1010xxx for (unsigned i = 0; i < d1.neg().size(); ++i) { t = dm.tbvm().allocate(); - t->set(d1.neg()[i], mid - 1, 0); - t->set(d2.pos(), hi - 1, mid); + dm.tbvm().set(*t, d1.neg()[i], mid - 1, 0); + dm.tbvm().set(*t, d2.pos(), hi - 1, mid); if (dm.tbvm().set_and(*t, pos)) { neg.push_back(t.detach()); } @@ -367,8 +367,8 @@ namespace datalog { } for (unsigned i = 0; i < d2.neg().size(); ++i) { t = dm.tbvm().allocate(); - t->set(d1.pos(), mid- 1, 0); - t->set(d2.neg()[i], hi - 1, mid); + dm.tbvm().set(*t, d1.pos(), mid- 1, 0); + dm.tbvm().set(*t, d2.neg()[i], hi - 1, mid); if (dm.tbvm().set_and(*t, pos)) { neg.push_back(t.detach()); } @@ -637,7 +637,7 @@ namespace datalog { unsigned lo = t.column_idx(col); unsigned hi = t.column_idx(col+1); SASSERT(num_bits == hi - lo); - m_filter->pos().set(r, hi-1, lo); + dm.tbvm().set(m_filter->pos(), r, hi-1, lo); } virtual ~filter_equal_fn() { dm.deallocate(m_filter); @@ -743,7 +743,7 @@ namespace datalog { } apply_guard(g, result, equalities, discard_cols); } - bool udoc_relation::apply_eq(expr* g, doc_ref& d, unsigned v, unsigned hi, unsigned lo, expr* c) const { + bool udoc_relation::apply_ground_eq(doc_ref& d, unsigned v, unsigned hi, unsigned lo, expr* c) const { udoc_plugin& p = get_plugin(); unsigned num_bits; rational r; @@ -752,19 +752,65 @@ namespace datalog { hi += col; if (p.is_numeral(c, r, num_bits)) { d = dm.allocateX(); - d->pos().set(r, hi, lo); + dm.tbvm().set(d->pos(), r, hi, lo); return true; } // other cases? return false; } + bool udoc_relation::apply_bv_eq( + expr* e1, expr* e2, bit_vector const& discard_cols, udoc& result) const { + udoc_plugin& p = get_plugin(); + ast_manager& m = p.get_ast_manager(); + bv_util& bv = p.bv; + th_rewriter rw(m); + doc_ref d(get_dm()); + unsigned hi, lo, lo1, lo2, hi1, hi2, v, v1, v2; + if (bv.is_concat(e2)) { + std::swap(e1, e2); + } + if (bv.is_concat(e1)) { + expr_ref e3(m); + app* a1 = to_app(e1); + hi = p.num_sort_bits(e1)-1; + unsigned n = a1->get_num_args(); + for (unsigned i = 0; i < n; ++i) { + expr* e = a1->get_arg(i); + unsigned sz = p.num_sort_bits(e); + e3 = bv.mk_extract(hi, hi-sz+1, e2); + rw(e3); + if (!apply_bv_eq(e, e3, discard_cols, result)) return false; + hi -= sz; + } + return true; + } + if (is_ground(e1)) { + std::swap(e1, e2); + } + if (is_var_range(e1, hi, lo, v) && is_ground(e2) && + apply_ground_eq(d, v, hi, lo, e2)) { + result.intersect(dm, *d); + return true; + } + if (is_var_range(e1, hi1, lo1, v1) && + is_var_range(e2, hi2, lo2, v2)) { + unsigned idx1 = lo1 + column_idx(v1); + unsigned idx2 = lo2 + column_idx(v2); + unsigned length = hi1-lo1+1; + result.merge(dm, idx1, idx2, length, discard_cols); + return true; + } + + return false; + } + void udoc_relation::apply_guard( expr* g, udoc& result, subset_ints const& equalities, bit_vector const& discard_cols) const { ast_manager& m = get_plugin().get_ast_manager(); bv_util& bv = get_plugin().bv; expr *e0, *e1, *e2; - unsigned hi, lo, lo1, lo2, hi1, hi2, v, v1, v2; + unsigned hi, lo, v; doc_ref d(get_dm()); if (result.is_empty()) { } @@ -781,13 +827,13 @@ namespace datalog { else if (m.is_not(g, e0) && m.is_eq(e0, e1, e2) && bv.is_bv(e1) && is_var_range(e1, hi, lo, v) && is_ground(e2) && - apply_eq(g, d, v, hi, lo, e2)) { + apply_ground_eq(d, v, hi, lo, e2)) { result.subtract(dm, *d); } else if (m.is_not(g, e0) && m.is_eq(e0, e2, e1) && bv.is_bv(e1) && is_var_range(e1, hi, lo, v) && is_ground(e2) && - apply_eq(g, d, v, hi, lo, e2)) { + apply_ground_eq(d, v, hi, lo, e2)) { result.subtract(dm, *d); } else if (m.is_not(g, e1)) { @@ -843,21 +889,9 @@ namespace datalog { diff2.reset(dm); } else if (m.is_eq(g, e1, e2) && bv.is_bv(e1)) { - if (is_var_range(e1, hi, lo, v) && is_ground(e2) && - apply_eq(g, d, v, hi, lo, e2)) { - result.intersect(dm, *d); + if (apply_bv_eq(e1, e2, discard_cols, result)) { + // done } - else if (is_var_range(e2, hi, lo, v) && is_ground(e1) && - apply_eq(g, d, v, hi, lo, e1)) { - result.intersect(dm, *d); - } - else if (is_var_range(e1, hi1, lo1, v1) && - is_var_range(e2, hi2, lo2, v2)) { - unsigned idx1 = lo1 + column_idx(v1); - unsigned idx2 = lo2 + column_idx(v2); - unsigned length = hi1-lo1+1; - result.merge(dm, idx1, idx2, length, discard_cols); - } else { goto failure_case; } diff --git a/src/muz/rel/udoc_relation.h b/src/muz/rel/udoc_relation.h index 1d14062e6..64ced8e83 100644 --- a/src/muz/rel/udoc_relation.h +++ b/src/muz/rel/udoc_relation.h @@ -70,7 +70,8 @@ namespace datalog { void extract_equalities(expr* g, expr_ref& rest, subset_ints& equalities, unsigned_vector& roots) const; void apply_guard(expr* g, udoc& result, bit_vector const& discard_cols) const; void apply_guard(expr* g, udoc& result, subset_ints const& equalities, bit_vector const& discard_cols) const; - bool apply_eq(expr* g, doc_ref& d, unsigned v, unsigned hi, unsigned lo, expr* c) const; + bool apply_ground_eq(doc_ref& d, unsigned v, unsigned hi, unsigned lo, expr* c) const; + bool apply_bv_eq(expr* e1, expr* e2, bit_vector const& discard_cols, udoc& result) const; bool is_var_range(expr* e, unsigned& hi, unsigned& lo, unsigned& v) const; }; diff --git a/src/test/doc.cpp b/src/test/doc.cpp index 409debfb0..2921f52c9 100644 --- a/src/test/doc.cpp +++ b/src/test/doc.cpp @@ -117,7 +117,7 @@ class test_doc_cls { tbv* mk_rand_tbv() { tbv* result = dm.tbvm().allocate(); for (unsigned i = 0; i < dm.num_tbits(); ++i) { - (*result).set(i, choose_tbit()); + dm.tbvm().set(*result, i, choose_tbit()); } return result; } @@ -126,10 +126,10 @@ class test_doc_cls { tbv* result = dm.tbvm().allocate(); for (unsigned i = 0; i < dm.num_tbits(); ++i) { if (pos[i] == BIT_x) { - (*result).set(i, choose_tbit()); + dm.tbvm().set(*result, i, choose_tbit()); } else { - (*result).set(i, pos[i]); + dm.tbvm().set(*result, i, pos[i]); } } return result; @@ -159,7 +159,7 @@ class test_doc_cls { expr_ref_vector conjs(m); for (unsigned i = 0; i < m_vars.size(); ++i) { tbit b = choose_tbit(); - t.set(i, b); + dm.tbvm().set(t, i, b); switch (b) { case BIT_1: conjs.push_back(m_vars[i].get()); break; case BIT_0: conjs.push_back(m.mk_not(m_vars[i].get())); break; @@ -363,7 +363,7 @@ public: expr_ref fml1(m), fml2(m); doc_ref d(dm, dm.allocateX()); tbv_ref t(dm.tbvm(), dm.tbvm().allocateX()); - t->set(0, BIT_0); + dm.tbvm().set(*t, 0, BIT_0); d->neg().push_back(t.detach()); unsigned num_bits = dm.num_tbits(); svector to_delete(num_bits, false); @@ -402,10 +402,10 @@ public: tbv_ref t2(dm.tbvm()); t1 = dm.tbvm().allocateX(); t2 = dm.tbvm().allocateX(); - t1->set(0, BIT_1); - t1->set(2, BIT_0); - t2->set(0, BIT_0); - t2->set(2, BIT_1); + dm.tbvm().set(*t1, 0, BIT_1); + dm.tbvm().set(*t1, 2, BIT_0); + dm.tbvm().set(*t2, 0, BIT_0); + dm.tbvm().set(*t2, 2, BIT_1); d1->neg().push_back(t1.detach()); d1->neg().push_back(t2.detach()); ds2.push_back(d1.detach()); diff --git a/src/test/fixed_bit_vector.cpp b/src/test/fixed_bit_vector.cpp index 01d60c347..7bd9e62c3 100644 --- a/src/test/fixed_bit_vector.cpp +++ b/src/test/fixed_bit_vector.cpp @@ -28,9 +28,9 @@ static void tst1() { fixed_bit_vector_manager m(30); fixed_bit_vector *b; b = m.allocate0(); - b->set(0, true); - b->set(1, false); - b->set(2, true); + m.set(*b, 0, true); + m.set(*b, 1, false); + m.set(*b, 2, true); SASSERT(b->get(0) == true); SASSERT(b->get(1) == false); SASSERT(b->get(2) == true); @@ -46,19 +46,19 @@ static void tst_or() { b1 = m.allocate0(); b2 = m.allocate0(); - b1->set(4); - b2->set(8); - b2->set(3); - b2->set(2); - b2->set(1); + m.set(*b1, 4); + m.set(*b2, 8); + m.set(*b2, 3); + m.set(*b2, 2); + m.set(*b2, 1); m.display(std::cout, *b1) << "\n"; m.display(std::cout, *b2) << "\n"; m.set_or(*b1, *b2); m.display(std::cout, *b1) << "\n"; SASSERT(!m.equals(*b1, *b2)); - b1->unset(4); + m.unset(*b1, 4); SASSERT(m.equals(*b1, *b2)); - b1->unset(3); + m.unset(*b1, 3); SASSERT(!m.equals(*b1, *b2)); m.deallocate(b1); m.deallocate(b2); @@ -77,16 +77,16 @@ static void tst_eq(unsigned num_bits) { fixed_bit_vector* b2 = m.allocate0(); fixed_bit_vector* b3 = m.allocate0(); - b1->set(3, true); + m.set(*b1, 3, true); SASSERT(!m.equals(*b1, *b2)); SASSERT(m.equals(*b2, *b3)); - b3->set(3, true); + m.set(*b3, 3, true); SASSERT(m.equals(*b1, *b3)); - b2->set(num_bits-1, true); - b3->set(num_bits-1); - b3->unset(3); + m.set(*b2, num_bits-1, true); + m.set(*b3, num_bits-1); + m.unset(*b3, 3); SASSERT(m.equals(*b2, *b3)); m.fill0(*b1); m.set_neg(*b1); @@ -94,7 +94,7 @@ static void tst_eq(unsigned num_bits) { SASSERT(m.equals(*b1, *b2)); m.fill0(*b1); for (unsigned i = 0; i < num_bits; ++i) { - b1->set(i, true); + m.set(*b1, i, true); } SASSERT(m.equals(*b1, *b2)); m.deallocate(b1); diff --git a/src/test/tbv.cpp b/src/test/tbv.cpp index 5714c444a..70a07d3f5 100644 --- a/src/test/tbv.cpp +++ b/src/test/tbv.cpp @@ -29,8 +29,8 @@ static void tst1(unsigned num_bits) { tbv_manager m2(num_bits-2); to_delete[1] = true; to_delete[3] = true; - (*b1).set(2, BIT_0); - (*b1).set(4, BIT_x); + m.set(*b1, 2, BIT_0); + m.set(*b1, 4, BIT_x); tbv_ref b2(m2, m2.project(num_bits, to_delete.c_ptr(), *b1)); m.display(std::cout, *b1) << " -> "; m2.display(std::cout, *b2) << "\n"; diff --git a/src/test/udoc_relation.cpp b/src/test/udoc_relation.cpp index 4942164e2..dbe8d9b83 100644 --- a/src/test/udoc_relation.cpp +++ b/src/test/udoc_relation.cpp @@ -54,7 +54,7 @@ class udoc_tester { tbv* mk_rand_tbv(doc_manager& dm) { tbv* result = dm.tbvm().allocate(); for (unsigned i = 0; i < dm.num_tbits(); ++i) { - (*result).set(i, choose_tbit()); + dm.tbvm().set(*result, i, choose_tbit()); } return result; } @@ -63,10 +63,10 @@ class udoc_tester { tbv* result = dm.tbvm().allocate(); for (unsigned i = 0; i < dm.num_tbits(); ++i) { if (pos[i] == BIT_x) { - (*result).set(i, choose_tbit()); + dm.tbvm().set(*result, i, choose_tbit()); } else { - (*result).set(i, pos[i]); + dm.tbvm().set(*result, i, pos[i]); } } return result; diff --git a/src/util/fixed_bit_vector.h b/src/util/fixed_bit_vector.h index fb7ed38e9..933299925 100644 --- a/src/util/fixed_bit_vector.h +++ b/src/util/fixed_bit_vector.h @@ -59,6 +59,7 @@ public: return (get_bit_word(bit_idx) & get_pos_mask(bit_idx)) != 0; } +private: void set(unsigned bit_idx) { get_bit_word(bit_idx) |= get_pos_mask(bit_idx); } @@ -116,6 +117,26 @@ public: unsigned hash(fixed_bit_vector const& src) const; bool contains(fixed_bit_vector const& a, fixed_bit_vector const& b) const; std::ostream& display(std::ostream& out, fixed_bit_vector const& b) const; + void set(fixed_bit_vector& dst, unsigned bit_idx) { + SASSERT(bit_idx < num_bits()); + dst.set(bit_idx); + } + void unset(fixed_bit_vector& dst, unsigned bit_idx) { + SASSERT(bit_idx < num_bits()); + dst.unset(bit_idx); + } + + void set(fixed_bit_vector& dst, unsigned bit_idx, bool val) { + SASSERT(bit_idx < num_bits()); + dst.set(bit_idx, val); + } + + // assign bits this[lo:hi] := other[0:hi-lo+1] + void set(fixed_bit_vector& dst, fixed_bit_vector const& other, unsigned hi, unsigned lo) { + SASSERT(lo <= hi && hi < num_bits()); + dst.set(other, hi, lo); + } + }; From 1111c0494fa3d95267a73f3741a8fa52f1a2d383 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 23 Sep 2014 17:10:00 -0700 Subject: [PATCH 571/925] adding validation code to doc/udoc Signed-off-by: Nikolaj Bjorner --- src/muz/rel/dl_instruction.cpp | 19 +++- src/muz/rel/dl_instruction.h | 10 +- src/muz/rel/doc.cpp | 89 +++++++++++++++-- src/muz/rel/doc.h | 9 +- src/muz/rel/rel_context.cpp | 12 ++- src/muz/rel/rel_context.h | 1 + src/muz/rel/tbv.cpp | 24 +++++ src/muz/rel/tbv.h | 3 + src/muz/rel/udoc_relation.cpp | 178 +++++++++++++++++++++++++++++---- src/muz/rel/udoc_relation.h | 9 ++ src/test/doc.cpp | 7 +- src/test/udoc_relation.cpp | 70 +------------ src/util/stopwatch.h | 1 + 13 files changed, 328 insertions(+), 104 deletions(-) diff --git a/src/muz/rel/dl_instruction.cpp b/src/muz/rel/dl_instruction.cpp index f8eadfed3..4122811ac 100644 --- a/src/muz/rel/dl_instruction.cpp +++ b/src/muz/rel/dl_instruction.cpp @@ -156,6 +156,14 @@ namespace datalog { process_costs(); } + void instruction::collect_statistics(statistics& st) const { + costs c; + get_total_cost(c); + st.update("instruction", c.instructions); + st.update("instruction-time", c.milliseconds); + } + + void instruction::display_indented(rel_context_base const & _ctx, std::ostream & out, std::string indentation) const { out << indentation; rel_context const& ctx = dynamic_cast(_ctx); @@ -257,7 +265,7 @@ namespace datalog { instr_clone_move(bool clone, reg_idx src, reg_idx tgt) : m_clone(clone), m_src(src), m_tgt(tgt) {} virtual bool perform(execution_context & ctx) { - log_verbose(ctx); + if (ctx.reg(m_src)) log_verbose(ctx); ctx.make_empty(m_tgt); if (m_clone) { ctx.set_reg(m_tgt, ctx.reg(m_src) ? ctx.reg(m_src)->clone() : 0); @@ -1145,6 +1153,15 @@ namespace datalog { } } + + void instruction_block::collect_statistics(statistics& st) const { + instr_seq_type::const_iterator it = m_data.begin(); + instr_seq_type::const_iterator end = m_data.end(); + for(; it!=end; ++it) { + (*it)->collect_statistics(st); + } + } + void instruction_block::make_annotations(execution_context & ctx) { instr_seq_type::iterator it = m_data.begin(); instr_seq_type::iterator end = m_data.end(); diff --git a/src/muz/rel/dl_instruction.h b/src/muz/rel/dl_instruction.h index 87f9df19f..331b153e8 100644 --- a/src/muz/rel/dl_instruction.h +++ b/src/muz/rel/dl_instruction.h @@ -232,7 +232,7 @@ namespace datalog { Each line must be prepended by \c indentation and ended by a newline character. */ - virtual void display_body_impl(rel_context const & ctx, std::ostream & out, std::string indentation) const {} + virtual void display_body_impl(rel_context_base const & ctx, std::ostream & out, std::string indentation) const {} void log_verbose(execution_context& ctx); public: @@ -301,6 +301,8 @@ namespace datalog { static instruction * mk_assert_signature(const relation_signature & s, reg_idx tgt); + void collect_statistics(statistics& st) const; + }; @@ -327,7 +329,7 @@ namespace datalog { void push_back(instruction * i) { m_data.push_back(i); - if(m_observer) { + if (m_observer) { m_observer->notify(i); } } @@ -336,6 +338,8 @@ namespace datalog { m_observer = o; } + void collect_statistics(statistics& st) const; + /** \brief Perform instructions in the block. If the run was interrupted before completion, return false; otherwise return true. @@ -353,6 +357,8 @@ namespace datalog { display_indented(ctx, out, ""); } void display_indented(rel_context_base const & ctx, std::ostream & out, std::string indentation) const; + + unsigned num_instructions() const { return m_data.size(); } }; diff --git a/src/muz/rel/doc.cpp b/src/muz/rel/doc.cpp index bb9e0e649..917eeb655 100644 --- a/src/muz/rel/doc.cpp +++ b/src/muz/rel/doc.cpp @@ -21,6 +21,10 @@ Revision History: --*/ #include "doc.h" +#include "smt_kernel.h" +#include "expr_safe_replace.h" +#include "smt_params.h" +#include "ast_util.h" doc_manager::doc_manager(unsigned n): m(n), m_alloc("doc") { m_full = m.allocateX(); @@ -384,15 +388,6 @@ doc* doc_manager::project(doc_manager& dstm, unsigned n, bool const* to_delete, return r; } -#if 0 -bool doc_manager::can_project_neg(tbv const& pos, unsigned n, bool const* to_delete, tbv const& neg) { - for (unsigned i = 0; i < n; ++i) { - if (to_delete[i] && BIT_x != neg[i] && BIT_x == pos[i]) return false; - } - return true; -} -#endif - doc_manager::project_action_t doc_manager::pick_resolvent( tbv const& pos, tbv_vector const& neg, bool const* to_delete, unsigned& idx) { @@ -453,7 +448,8 @@ doc_manager::pick_resolvent( return project_done; } } - + + void doc_manager::complement(doc const& src, doc_vector& result) { result.reset(); @@ -504,6 +500,9 @@ bool doc_manager::is_empty(doc const& src) { if (src.neg().size() == 1) { return m.equals(src.pos(), src.neg()[0]); } + return false; +#if 0 + // buggy: tbv_ref pos(m, m.allocate(src.pos())); for (unsigned i = 0; i < src.neg().size(); ++i) { bool found = false; @@ -525,6 +524,7 @@ bool doc_manager::is_empty(doc const& src) { } } return true; +#endif } unsigned doc_manager::hash(doc const& src) const { @@ -559,3 +559,72 @@ std::ostream& doc_manager::display(std::ostream& out, doc const& b) const { return out; } + +void doc_manager::verify_project(ast_manager& m, doc_manager& dstm, bool const* to_delete, doc const& src, doc const& dst) { + expr_ref fml1 = to_formula(m, src); + expr_ref fml2 = dstm.to_formula(m, dst); + project_rename(fml2, to_delete); + project_expand(fml1, to_delete); + check_equiv(m, fml1, fml2); +} + +void doc_manager::check_equiv(ast_manager& m, expr* fml1, expr* fml2) { + smt_params fp; + smt::kernel solver(m, fp); + expr_ref fml(m); + fml = m.mk_not(m.mk_eq(fml1, fml2)); + solver.assert_expr(fml); + lbool res = solver.check(); + if (res != l_false) { + TRACE("doc", + tout << mk_pp(fml1, m) << "\n"; + tout << mk_pp(fml2, m) << "\n"; + ); + UNREACHABLE(); + throw 0; + } + SASSERT(res == l_false); +} + +expr_ref doc_manager::to_formula(ast_manager& m, doc const& src) { + expr_ref result(m); + expr_ref_vector conj(m); + conj.push_back(tbvm().to_formula(m, src.pos())); + for (unsigned i = 0; i < src.neg().size(); ++i) { + conj.push_back(m.mk_not(tbvm().to_formula(m, src.neg()[i]))); + } + result = mk_and(m, conj.size(), conj.c_ptr()); + return result; +} + +void doc_manager::project_expand(expr_ref& fml, bool const* to_delete) { + ast_manager& m = fml.get_manager(); + expr_ref tmp1(m), tmp2(m); + for (unsigned i = 0; i < num_tbits(); ++i) { + if (to_delete[i]) { + expr_safe_replace rep1(m), rep2(m); + rep1.insert(tbvm().mk_var(m, i), m.mk_true()); + rep1(fml, tmp1); + rep2.insert(tbvm().mk_var(m, i), m.mk_false()); + rep2(fml, tmp2); + if (tmp1 == tmp2) { + fml = tmp1; + } + else { + fml = m.mk_or(tmp1, tmp2); + } + } + } +} + +void doc_manager::project_rename(expr_ref& fml, bool const* to_delete) { + ast_manager& m = fml.get_manager(); + expr_safe_replace rep(m); + for (unsigned i = 0, j = 0; i < num_tbits(); ++i) { + if (!to_delete[i]) { + rep.insert(tbvm().mk_var(m, j), tbvm().mk_var(m, i)); + ++j; + } + } + rep(fml); +} diff --git a/src/muz/rel/doc.h b/src/muz/rel/doc.h index 30858bbbd..86849ba72 100644 --- a/src/muz/rel/doc.h +++ b/src/muz/rel/doc.h @@ -87,10 +87,15 @@ public: bool well_formed(doc const& d) const; bool merge(doc& d, unsigned lo, unsigned length, subset_ints const& equalities, bit_vector const& discard_cols); void set(doc& d, unsigned idx, tbit value); + + void verify_project(ast_manager& m, doc_manager& dstm, bool const* to_delete, doc const& src, doc const& dst); private: unsigned diff_by_012(tbv const& pos, tbv const& neg, unsigned& index); bool merge(doc& d, unsigned idx, subset_ints const& equalities, bit_vector const& discard_cols); - bool can_project_neg(tbv const& pos, unsigned n, bool const* to_delete, tbv const& neg); + void project_rename(expr_ref& fml, bool const* to_delete); + void project_expand(expr_ref& fml, bool const* to_delete); + expr_ref to_formula(ast_manager& m, doc const& src); + void check_equiv(ast_manager& m, expr* fml1, expr* fml2); }; @@ -185,7 +190,7 @@ public: } void insert(M& m, union_bvec const& other) { for (unsigned i = 0; i < other.size(); ++i) { - insert(m, other[i]); + insert(m, &other[i]); } } void intersect(M& m, union_bvec const& other) { diff --git a/src/muz/rel/rel_context.cpp b/src/muz/rel/rel_context.cpp index 13aecbe09..371e14353 100644 --- a/src/muz/rel/rel_context.cpp +++ b/src/muz/rel/rel_context.cpp @@ -21,6 +21,7 @@ Revision History: #include"rel_context.h" +#include"stopwatch.h" #include"dl_context.h" #include"dl_compiler.h" #include"dl_instruction.h" @@ -97,7 +98,8 @@ namespace datalog { m_rmanager(ctx), m_answer(m), m_last_result_relation(0), - m_ectx(ctx) { + m_ectx(ctx), + m_sw(0) { // register plugins for builtin tables @@ -162,6 +164,9 @@ namespace datalog { exit(0); } + ::stopwatch sw; + sw.start(); + compiler::compile(m_context, m_context.get_rules(), m_code, termination_code); TRACE("dl", m_code.display(*this, tout); ); @@ -180,6 +185,9 @@ namespace datalog { VERIFY( termination_code.perform(m_ectx) || m_context.canceled()); m_code.process_all_costs(); + sw.stop(); + m_sw += sw.get_seconds(); + IF_VERBOSE(10, m_ectx.report_big_relations(1000, verbose_stream());); @@ -562,6 +570,8 @@ namespace datalog { } void rel_context::collect_statistics(statistics& st) const { + st.update("saturation time", m_sw); + m_code.collect_statistics(st); m_ectx.collect_statistics(st); } diff --git a/src/muz/rel/rel_context.h b/src/muz/rel/rel_context.h index 5e26718d6..8cdee2766 100644 --- a/src/muz/rel/rel_context.h +++ b/src/muz/rel/rel_context.h @@ -41,6 +41,7 @@ namespace datalog { fact_vector m_table_facts; execution_context m_ectx; instruction_block m_code; + double m_sw; class scoped_query; diff --git a/src/muz/rel/tbv.cpp b/src/muz/rel/tbv.cpp index 23a96981d..391445215 100644 --- a/src/muz/rel/tbv.cpp +++ b/src/muz/rel/tbv.cpp @@ -20,6 +20,7 @@ Revision History: #include "tbv.h" #include "hashtable.h" +#include "ast_util.h" static bool s_debug_alloc = false; @@ -269,3 +270,26 @@ std::ostream& tbv_manager::display(std::ostream& out, tbv const& b) const { } return out; } + +expr_ref tbv_manager::to_formula(ast_manager& m, tbv const& src) { + expr_ref result(m); + expr_ref_vector conj(m); + for (unsigned i = 0; i < num_tbits(); ++i) { + switch (src[i]) { + case BIT_0: + conj.push_back(m.mk_not(m.mk_const(symbol(i), m.mk_bool_sort()))); + break; + case BIT_1: + conj.push_back(m.mk_const(symbol(i), m.mk_bool_sort())); + break; + default: + break; + } + } + result = mk_and(m, conj.size(), conj.c_ptr()); + return result; +} + +expr_ref tbv_manager::mk_var(ast_manager& m, unsigned i) { + return expr_ref(m.mk_const(symbol(i), m.mk_bool_sort()), m); +} diff --git a/src/muz/rel/tbv.h b/src/muz/rel/tbv.h index e701efcbe..454cbae37 100644 --- a/src/muz/rel/tbv.h +++ b/src/muz/rel/tbv.h @@ -23,6 +23,7 @@ Revision History: #include "fixed_bit_vector.h" #include "rational.h" +#include "ast.h" class tbv; @@ -80,6 +81,8 @@ public: static void debug_alloc(); + expr_ref to_formula(ast_manager& m, tbv const& src); + expr_ref mk_var(ast_manager& m, unsigned i); }; class tbv: private fixed_bit_vector { diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index fd3bf1415..b5af52701 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -2,6 +2,8 @@ #include "dl_relation_manager.h" #include "qe_util.h" #include "ast_util.h" +#include "smt_kernel.h" + namespace datalog { @@ -292,13 +294,17 @@ namespace datalog { doc_manager& dm; doc_manager& dm1; doc_manager& dm2; + unsigned_vector m_orig_cols1; + unsigned_vector m_orig_cols2; public: join_fn(udoc_plugin& p, udoc_relation const& t1, udoc_relation const& t2, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) : convenient_relation_join_fn(t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2), dm(p.dm(get_result_signature())), dm1(t1.get_dm()), - dm2(t2.get_dm()) { + dm2(t2.get_dm()), + m_orig_cols1(m_cols1), + m_orig_cols2(m_cols2) { t1.expand_column_vector(m_cols1); t2.expand_column_vector(m_cols2); } @@ -396,9 +402,12 @@ namespace datalog { TRACE("doc", result->display(tout << "result:\n");); IF_VERBOSE(3, result->display(verbose_stream() << "join result:\n");); SASSERT(r.well_formed(result->get_dm())); + DEBUG_CODE(p.verify_join(r1, r2, *result, m_orig_cols1.size(), m_orig_cols1.c_ptr(), m_orig_cols2.c_ptr());); return result; } }; + + relation_join_fn * udoc_plugin::mk_join_fn( const relation_base & t1, const relation_base & t2, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { @@ -407,6 +416,7 @@ namespace datalog { } return alloc(join_fn, *this, get(t1), get(t2), col_cnt, cols1, cols2); } + class udoc_plugin::project_fn : public convenient_relation_project_fn { svector m_to_delete; public: @@ -550,6 +560,9 @@ namespace datalog { udoc_relation const& src = get(_src); udoc_relation* d = get(_delta); doc_manager& dm = r.get_dm(); + ast_manager& m = r.get_plugin().get_ast_manager(); + expr_ref fml0(m); + DEBUG_CODE(r.to_formula(fml0);); udoc* d1 = 0; if (d) d1 = &d->get_udoc(); if (d1) d1->reset(dm); @@ -557,7 +570,9 @@ namespace datalog { SASSERT(r.get_udoc().well_formed(dm)); SASSERT(!d1 || d1->well_formed(dm)); TRACE("doc", _r.display(tout << "dst':\n"); ); - IF_VERBOSE(3, _r.display(verbose_stream() << "union result:\n");); + IF_VERBOSE(3, r.display(verbose_stream() << "union: ");); + IF_VERBOSE(3, if (d) d->display(verbose_stream() << "delta: ");); + DEBUG_CODE(r.get_plugin().verify_union(fml0, src, r, d);); } }; void udoc_plugin::mk_union(doc_manager& dm, udoc& dst, udoc const& src, udoc* delta) { @@ -907,7 +922,8 @@ namespace datalog { class udoc_plugin::filter_interpreted_fn : public relation_mutator_fn { union_find_default_ctx union_ctx; doc_manager& dm; - expr_ref m_condition; + expr_ref m_original_condition; + expr_ref m_reduced_condition; udoc m_udoc; bit_vector m_empty_bv; subset_ints m_equalities; @@ -915,7 +931,8 @@ namespace datalog { public: filter_interpreted_fn(const udoc_relation & t, ast_manager& m, app *condition) : dm(t.get_dm()), - m_condition(m), + m_original_condition(condition, m), + m_reduced_condition(m), m_equalities(union_ctx) { unsigned num_bits = t.get_num_bits(); m_empty_bv.resize(num_bits, false); @@ -923,12 +940,12 @@ namespace datalog { for (unsigned i = 0; i < num_bits; ++i) { m_equalities.mk_var(); } - t.extract_guard(condition, guard, m_condition); + t.extract_guard(condition, guard, m_reduced_condition); t.compile_guard(guard, m_udoc, m_empty_bv); TRACE("doc", tout << "original condition: " << mk_pp(condition, m) << "\n"; - tout << "remaining condition: " << m_condition << "\n"; + tout << "remaining condition: " << m_reduced_condition << "\n"; m_udoc.display(dm, tout) << "\n";); } @@ -936,18 +953,22 @@ namespace datalog { m_udoc.reset(dm); } - virtual void operator()(relation_base & tb) { + virtual void operator()(relation_base & tb) { udoc_relation & t = get(tb); udoc& u = t.get_udoc(); - ast_manager& m = m_condition.get_manager(); + ast_manager& m = m_reduced_condition.get_manager(); + expr_ref fml0(m); + DEBUG_CODE(t.to_formula(fml0);); SASSERT(u.well_formed(dm)); u.intersect(dm, m_udoc); SASSERT(u.well_formed(dm)); - t.apply_guard(m_condition, u, m_equalities, m_empty_bv); + t.apply_guard(m_reduced_condition, u, m_equalities, m_empty_bv); SASSERT(u.well_formed(dm)); u.simplify(dm); SASSERT(u.well_formed(dm)); TRACE("doc", tout << "final size: " << t.get_size_estimate_rows() << '\n';); + IF_VERBOSE(3, t.display(verbose_stream());); + DEBUG_CODE(t.get_plugin().verify_filter(fml0, t, m_original_condition);); } }; relation_mutator_fn * udoc_plugin::mk_filter_interpreted_fn(const relation_base & t, app * condition) { @@ -1048,7 +1069,8 @@ namespace datalog { class udoc_plugin::filter_proj_fn : public convenient_relation_project_fn { union_find_default_ctx union_ctx; doc_manager& dm; - expr_ref m_condition; + expr_ref m_original_condition; + expr_ref m_reduced_condition; udoc m_udoc; bit_vector m_col_list; // map: col idx -> bool (whether the column is to be removed) svector m_to_delete; // same @@ -1060,7 +1082,8 @@ namespace datalog { unsigned col_cnt, const unsigned * removed_cols) : convenient_relation_project_fn(t.get_signature(), col_cnt, removed_cols), dm(t.get_dm()), - m_condition(m), + m_original_condition(condition, m), + m_reduced_condition(m), m_equalities(union_ctx) { t.expand_column_vector(m_removed_cols); unsigned num_bits = t.get_num_bits(); @@ -1075,9 +1098,9 @@ namespace datalog { for (unsigned i = 0; i < m_removed_cols.size(); ++i) { m_to_delete[m_removed_cols[i]] = true; } - expr_ref guard(m), non_eq_cond(m); + expr_ref guard(m), non_eq_cond(condition, m); t.extract_equalities(condition, non_eq_cond, m_equalities, m_roots); - t.extract_guard(non_eq_cond, guard, m_condition); + t.extract_guard(non_eq_cond, guard, m_reduced_condition); t.compile_guard(guard, m_udoc, m_col_list); } @@ -1088,26 +1111,31 @@ namespace datalog { udoc_relation const & t = get(tb); udoc const& u1 = t.get_udoc(); doc_manager& dm = t.get_dm(); - ast_manager& m = m_condition.get_manager(); + ast_manager& m = m_reduced_condition.get_manager(); udoc u2; - SASSERT(u1.well_formed(dm)); u2.copy(dm, u1); - SASSERT(u2.well_formed(dm)); u2.intersect(dm, m_udoc); - SASSERT(u2.well_formed(dm)); u2.merge(dm, m_roots, m_equalities, m_col_list); - SASSERT(u2.well_formed(dm)); - t.apply_guard(m_condition, u2, m_equalities, m_col_list); - SASSERT(u2.well_formed(dm)); + t.apply_guard(m_reduced_condition, u2, m_equalities, m_col_list); + SASSERT(u2.well_formed(dm)); + DEBUG_CODE( + expr_ref fml0(m); + udoc_relation* r_test = get(t.get_plugin().mk_empty(t.get_signature())); + r_test->get_udoc().insert(dm, u2); + t.to_formula(fml0); + t.get_plugin().verify_filter(fml0, *r_test, m_original_condition); + r_test->deallocate();); udoc_relation* r = get(t.get_plugin().mk_empty(get_result_signature())); doc_manager& dm2 = r->get_dm(); + // std::cout << "Size of union: " << u2.size() << "\n"; for (unsigned i = 0; i < u2.size(); ++i) { doc* d = dm.project(dm2, m_to_delete.size(), m_to_delete.c_ptr(), u2[i]); + dm.verify_project(m, dm2, m_to_delete.c_ptr(), u2[i], *d); r->get_udoc().insert(dm2, d); SASSERT(r->get_udoc().well_formed(dm2)); } u2.reset(dm); - IF_VERBOSE(3, r->display(verbose_stream() << "filter result:\n");); + IF_VERBOSE(3, r->display(verbose_stream() << "filter project result:\n");); return r; } }; @@ -1117,5 +1145,113 @@ namespace datalog { return check_kind(t)?alloc(filter_proj_fn, get(t), get_ast_manager(), condition, removed_col_cnt, removed_cols):0; } + // TBD: move this to relation validation module like table_checker. + void udoc_plugin::verify_join(relation_base const& t1, relation_base const& t2, relation_base const& t, + unsigned sz, unsigned const* cols1, unsigned const* cols2) { + ast_manager& m = get_ast_manager(); + expr_ref fml1(m), fml2(m), fml3(m); + + relation_signature const& sig1 = t1.get_signature(); + relation_signature const& sig2 = t2.get_signature(); + relation_signature const& sig = t.get_signature(); + var_ref var1(m), var2(m); + t1.to_formula(fml1); + t2.to_formula(fml2); + t.to_formula(fml3); + var_subst sub(m, false); + expr_ref_vector vars(m); + for (unsigned i = 0; i < sig2.size(); ++i) { + vars.push_back(m.mk_var(i + sig1.size(), sig2[i])); + } + sub(fml2, vars.size(), vars.c_ptr(), fml2); + fml1 = m.mk_and(fml1, fml2); + for (unsigned i = 0; i < sz; ++i) { + unsigned v1 = cols1[i]; + unsigned v2 = cols2[i]; + var1 = m.mk_var(v1, sig1[v1]); + var2 = m.mk_var(v2 + sig1.size(), sig2[v2]); + fml1 = m.mk_and(m.mk_eq(var1, var2), fml1); + } + vars.reset(); + for (unsigned i = 0; i < sig.size(); ++i) { + std::stringstream strm; + strm << "x" << i; + vars.push_back(m.mk_const(symbol(strm.str().c_str()), sig[i])); + } + sub(fml1, vars.size(), vars.c_ptr(), fml1); + sub(fml3, vars.size(), vars.c_ptr(), fml3); + check_equiv(fml1, fml3); + } + + void udoc_plugin::verify_filter(expr* fml0, relation_base const& t, expr* cond) { + expr_ref fml1(m), fml2(m); + fml1 = m.mk_and(fml0, cond); + t.to_formula(fml2); + + relation_signature const& sig = t.get_signature(); + expr_ref_vector vars(m); + var_subst sub(m, false); + for (unsigned i = 0; i < sig.size(); ++i) { + std::stringstream strm; + strm << "x" << i; + vars.push_back(m.mk_const(symbol(strm.str().c_str()), sig[i])); + } + sub(fml1, vars.size(), vars.c_ptr(), fml1); + sub(fml2, vars.size(), vars.c_ptr(), fml2); + check_equiv(fml1, fml2); + } + + void udoc_plugin::check_equiv(expr* fml1, expr* fml2) { + TRACE("doc", tout << mk_pp(fml1, m) << "\n"; + tout << mk_pp(fml2, m) << "\n";); + smt_params fp; + smt::kernel solver(m, fp); + expr_ref tmp(m); + tmp = m.mk_not(m.mk_eq(fml1, fml2)); + solver.assert_expr(tmp); + lbool res = solver.check(); + IF_VERBOSE(3, verbose_stream() << "result of verification: " << res << "\n";); + if (res != l_false) { + throw 0; + } + SASSERT(res == l_false); + } + + void udoc_plugin::verify_union(expr* fml0, relation_base const& src, relation_base const& dst, relation_base const* delta) { + expr_ref fml1(m), fml2(m), fml3(m); + src.to_formula(fml1); + dst.to_formula(fml2); + fml1 = m.mk_or(fml1, fml0); + relation_signature const& sig = dst.get_signature(); + expr_ref_vector vars(m); + var_subst sub(m, false); + for (unsigned i = 0; i < sig.size(); ++i) { + std::stringstream strm; + strm << "x" << i; + vars.push_back(m.mk_const(symbol(strm.str().c_str()), sig[i])); + } + sub(fml1, vars.size(), vars.c_ptr(), fml1); + sub(fml2, vars.size(), vars.c_ptr(), fml2); + + check_equiv(fml1, fml2); + + if (delta) { + delta->to_formula(fml3); + // dst >= delta >= dst \ fml0 + // dst \ fml0 == delta & dst & \ fml0 + // dst & delta = delta + expr_ref fml4(m), fml5(m); + fml4 = m.mk_and(fml2, m.mk_not(fml0)); + fml5 = m.mk_and(fml3, fml4); + sub(fml4, vars.size(), vars.c_ptr(), fml4); + sub(fml5, vars.size(), vars.c_ptr(), fml5); + check_equiv(fml4, fml5); + fml4 = m.mk_and(fml3, fml2); + sub(fml3, vars.size(), vars.c_ptr(), fml3); + sub(fml4, vars.size(), vars.c_ptr(), fml4); + check_equiv(fml3, fml4); + } + } + } diff --git a/src/muz/rel/udoc_relation.h b/src/muz/rel/udoc_relation.h index 64ced8e83..6b7a218b5 100644 --- a/src/muz/rel/udoc_relation.h +++ b/src/muz/rel/udoc_relation.h @@ -133,6 +133,15 @@ namespace datalog { virtual relation_transformer_fn * mk_filter_interpreted_and_project_fn( const relation_base & t, app * condition, unsigned removed_col_cnt, const unsigned * removed_cols); + + void verify_join(relation_base const& t1, relation_base const& t2, relation_base const& t, + unsigned sz, unsigned const* cols1, unsigned const* cols2); + + void verify_filter(expr* fml0, relation_base const& t, expr* cond); + + void verify_union(expr* fml0, relation_base const& src, relation_base const& dst, relation_base const* delta); + + void check_equiv(expr* f1, expr* f2); }; }; diff --git a/src/test/doc.cpp b/src/test/doc.cpp index 2921f52c9..ad62893d8 100644 --- a/src/test/doc.cpp +++ b/src/test/doc.cpp @@ -261,7 +261,12 @@ class test_doc_cls { rep1(fml, tmp1); rep2.insert(m_vars[i].get(), m.mk_false()); rep2(fml, tmp2); - fml = m.mk_or(tmp1, tmp2); + if (tmp1 == tmp2) { + fml1 = tmp1; + } + else { + fml = m.mk_or(tmp1, tmp2); + } } } } diff --git a/src/test/udoc_relation.cpp b/src/test/udoc_relation.cpp index dbe8d9b83..5c25c8ee7 100644 --- a/src/test/udoc_relation.cpp +++ b/src/test/udoc_relation.cpp @@ -443,7 +443,7 @@ public: join_fn = p.mk_join_fn(*t1, *t2, jc1.size(), jc1.c_ptr(), jc2.c_ptr()); t = (*join_fn)(*t1, *t2); - verify_join(*t1, *t2, *t, jc1.size(), jc1.c_ptr(), jc2.c_ptr()); + p.verify_join(*t1, *t2, *t, jc1.size(), jc1.c_ptr(), jc2.c_ptr()); t1->display(std::cout); t2->display(std::cout); t->display(std::cout); @@ -459,43 +459,6 @@ public: return t; } - void verify_join(relation_base const& t1, relation_base& t2, relation_base& t, - unsigned sz, unsigned const* cols1, unsigned const* cols2) { - relation_signature const& sig1 = t1.get_signature(); - relation_signature const& sig2 = t2.get_signature(); - relation_signature const& sig = t.get_signature(); - expr_ref fml1(m), fml2(m), fml3(m); - var_ref var1(m), var2(m); - t1.to_formula(fml1); - t2.to_formula(fml2); - t.to_formula(fml3); - var_subst sub(m, false); - expr_ref_vector vars(m); - for (unsigned i = 0; i < sig2.size(); ++i) { - vars.push_back(m.mk_var(i + sig1.size(), sig2[i])); - } - sub(fml2, vars.size(), vars.c_ptr(), fml2); - fml1 = m.mk_and(fml1, fml2); - for (unsigned i = 0; i < sz; ++i) { - unsigned v1 = cols1[i]; - unsigned v2 = cols2[i]; - var1 = m.mk_var(v1, sig1[v1]); - var2 = m.mk_var(v2 + sig1.size(), sig2[v2]); - fml1 = m.mk_and(m.mk_eq(var1, var2), fml1); - } - vars.reset(); - for (unsigned i = 0; i < sig.size(); ++i) { - std::stringstream strm; - strm << "x" << i; - vars.push_back(m.mk_const(symbol(strm.str().c_str()), sig[i])); - } - sub(fml1, vars.size(), vars.c_ptr(), fml1); - sub(fml3, vars.size(), vars.c_ptr(), fml3); - check_equiv(fml1, fml3); - } - - - void check_permutation(relation_base* t1, unsigned_vector const& cycle) { scoped_ptr rename; rename = p.mk_rename_fn(*t1, cycle.size(), cycle.c_ptr()); @@ -739,41 +702,16 @@ public: udoc_relation* full = mk_full(t.get_signature()); rel_union union_fn = p.mk_union_fn(t, *full, 0); (*union_fn)(t, *full, 0); + expr_ref fml0(m); + t.to_formula(fml0); rel_mut fint = p.mk_filter_interpreted_fn(t, cond); (*fint)(t); t.display(std::cout << "filter: " << mk_pp(cond, m) << " "); std::cout << "\n"; - verify_filter(t, cond); + t.get_plugin().verify_filter(fml0, t, cond); full->deallocate(); } - void verify_filter(udoc_relation& r, expr* fml2) { - expr_ref fml1(m), tmp(m); - r.to_formula(fml1); - tmp = m.mk_not(m.mk_eq(fml1, fml2)); - relation_signature const& sig = r.get_signature(); - expr_ref_vector vars(m); - var_subst sub(m, false); - for (unsigned i = 0; i < sig.size(); ++i) { - std::stringstream strm; - strm << "x" << i; - vars.push_back(m.mk_const(symbol(strm.str().c_str()), sig[i])); - } - sub(tmp, vars.size(), vars.c_ptr(), tmp); - - smt_params fp; - smt::kernel solver(m, fp); - TRACE("doc", - tout << "Original formula:\n"; - tout << mk_pp(fml2, m) << "\n"; - tout << "Filtered formula: \n"; - tout << mk_pp(fml1,m) << "\n"; - tout << tmp << "\n"; - ); - solver.assert_expr(tmp); - lbool res = solver.check(); - SASSERT(res == l_false); - } }; void tst_udoc_relation() { diff --git a/src/util/stopwatch.h b/src/util/stopwatch.h index 661d3762b..b0edc2626 100644 --- a/src/util/stopwatch.h +++ b/src/util/stopwatch.h @@ -69,6 +69,7 @@ public: #undef ARRAYSIZE #define ARRAYSIZE ARRAYSIZE_TEMP #undef max +#undef min #elif defined(__APPLE__) && defined (__MACH__) // Mac OS X From 16f80fce929c9b7ed82c601d75e8915fabecfc65 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 24 Sep 2014 01:06:58 -0700 Subject: [PATCH 572/925] add check_relation for integrity checking of relational operations Signed-off-by: Nikolaj Bjorner --- src/muz/base/dl_context.cpp | 6 +- src/muz/base/dl_context.h | 5 +- src/muz/base/fixedpoint_params.pyg | 2 + src/muz/rel/check_relation.cpp | 641 +++++++++++++++++++++++++++++ src/muz/rel/check_relation.h | 147 +++++++ src/muz/rel/dl_base.h | 1 + src/muz/rel/dl_instruction.cpp | 7 +- src/muz/rel/dl_relation_manager.h | 1 + src/muz/rel/doc.cpp | 1 + src/muz/rel/rel_context.cpp | 20 + src/muz/rel/rel_context.h | 1 + src/muz/rel/udoc_relation.cpp | 118 ------ src/muz/rel/udoc_relation.h | 9 - src/test/doc.cpp | 2 +- src/test/udoc_relation.cpp | 15 +- 15 files changed, 837 insertions(+), 139 deletions(-) create mode 100644 src/muz/rel/check_relation.cpp create mode 100644 src/muz/rel/check_relation.h diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 9e8789aa6..05135a44f 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -278,7 +278,9 @@ namespace datalog { bool context::use_map_names() const { return m_params->datalog_use_map_names(); } bool context::fix_unbound_vars() const { return m_params->xform_fix_unbound_vars(); } symbol context::default_table() const { return m_params->datalog_default_table(); } - symbol context::default_relation() const { return m_params->datalog_default_relation(); } // external_relation_plugin::get_name()); + symbol context::default_relation() const { return m_default_relation; } + void context::set_default_relation(symbol const& s) { m_default_relation = s; } + symbol context::check_relation() const { return m_params->datalog_check_relation(); } symbol context::default_table_checker() const { return m_params->datalog_default_table_checker(); } bool context::default_table_checked() const { return m_params->datalog_default_table_checked(); } bool context::dbg_fpr_nonempty_relation_signature() const { return m_params->datalog_dbg_fpr_nonempty_relation_signature(); } @@ -840,6 +842,7 @@ namespace datalog { if (m_engine.get()) m_engine->updt_params(); m_generate_proof_trace = m_params->generate_proof_trace(); m_unbound_compressor = m_params->datalog_unbound_compressor(); + m_default_relation = m_params->datalog_default_relation(); } expr_ref context::get_background_assertion() { @@ -1005,6 +1008,7 @@ namespace datalog { void context::ensure_engine() { if (!m_engine.get()) { m_engine = m_register_engine.mk_engine(get_engine()); + m_engine->updt_params(); // break abstraction. if (get_engine() == DATALOG_ENGINE) { diff --git a/src/muz/base/dl_context.h b/src/muz/base/dl_context.h index 0b9c623c4..67520d94f 100644 --- a/src/muz/base/dl_context.h +++ b/src/muz/base/dl_context.h @@ -173,6 +173,7 @@ namespace datalog { fixedpoint_params* m_params; bool m_generate_proof_trace; bool m_unbound_compressor; + symbol m_default_relation; dl_decl_util m_decl_util; th_rewriter m_rewriter; var_subst m_var_subst; @@ -250,7 +251,9 @@ namespace datalog { bool fix_unbound_vars() const; symbol default_table() const; symbol default_relation() const; - symbol default_table_checker() const; + void set_default_relation(symbol const& s); + symbol default_table_checker() const; + symbol check_relation() const; bool default_table_checked() const; bool dbg_fpr_nonempty_relation_signature() const; unsigned dl_profile_milliseconds_threshold() const; diff --git a/src/muz/base/fixedpoint_params.pyg b/src/muz/base/fixedpoint_params.pyg index 7951a62bc..3e31c9e48 100644 --- a/src/muz/base/fixedpoint_params.pyg +++ b/src/muz/base/fixedpoint_params.pyg @@ -37,6 +37,8 @@ def_module_params('fixedpoint', 'table will be default_table inside a wrapper that checks that its results ' + 'are the same as of default_table_checker table'), ('datalog.default_table_checker', SYMBOL, 'null', "see default_table_checked"), + ('datalog.check_relation',SYMBOL,'null', "name of default relation to check. " + + "operations on the default relation will be verified using SMT solving"), ('datalog.initial_restart_timeout', UINT, 0, "length of saturation run before the first restart (in ms), " + "zero means no restarts"), diff --git a/src/muz/rel/check_relation.cpp b/src/muz/rel/check_relation.cpp new file mode 100644 index 000000000..beafc7c3e --- /dev/null +++ b/src/muz/rel/check_relation.cpp @@ -0,0 +1,641 @@ +#include "check_relation.h" +#include "dl_relation_manager.h" +#include "qe_util.h" +#include "ast_util.h" +#include "smt_kernel.h" + + +namespace datalog { + + check_relation::check_relation(check_relation_plugin& p, relation_signature const& sig, relation_base* r): + relation_base(p, sig), + m(p.get_ast_manager()), + m_relation(r), + m_fml(m) { + m_relation->to_formula(m_fml); + } + check_relation::~check_relation() { + m_relation->deallocate(); + } + void check_relation::check_equiv(expr* f1, expr* f2) const { + get_plugin().check_equiv(f1, f2); + } + void check_relation::consistent_formula() { + expr_ref fml(m); + m_relation->to_formula(fml); + if (m_fml != fml) { + IF_VERBOSE(0, display(verbose_stream() << "relation does not have a consistent formula");); + } + } + expr_ref check_relation::mk_eq(relation_fact const& f) const { + relation_signature const& sig = get_signature(); + expr_ref_vector conjs(m); + for (unsigned i = 0; i < sig.size(); ++i) { + conjs.push_back(m.mk_eq(m.mk_var(i, sig[i]), f[i])); + } + return expr_ref(mk_and(m, conjs.size(), conjs.c_ptr()), m); + } + + expr_ref check_relation::ground(expr* fml) const { + relation_signature const& sig = get_signature(); + var_subst sub(m, false); + expr_ref_vector vars(m); + for (unsigned i = 0; i < sig.size(); ++i) { + vars.push_back(m.mk_const(symbol(i), sig[i])); + } + expr_ref result(m); + sub(fml, vars.size(), vars.c_ptr(), result); + return result; + } + + void check_relation::add_fact(const relation_fact & f) { + expr_ref fml1(m); + m_relation->add_fact(f); + m_relation->to_formula(fml1); + m_fml = m.mk_or(m_fml, mk_eq(f)); + check_equiv(ground(m_fml), ground(fml1)); + m_fml = fml1; + } + void check_relation::add_new_fact(const relation_fact & f) { + expr_ref fml1(m); + m_relation->add_new_fact(f); + m_relation->to_formula(fml1); + m_fml = m.mk_or(m_fml, mk_eq(f)); + check_equiv(ground(m_fml), ground(fml1)); + m_fml = fml1; + } + bool check_relation::empty() const { + bool result = m_relation->empty(); + if (result && !m.is_false(m_fml)) { + check_equiv(m.mk_false(), ground(m_fml)); + } + return result; + } + bool check_relation::fast_empty() const { + bool result = m_relation->fast_empty(); + if (result && !m.is_false(m_fml)) { + check_equiv(m.mk_false(), ground(m_fml)); + } + return result; + } + void check_relation::reset() { + m_relation->reset(); + m_fml = m.mk_false(); + } + + bool check_relation::contains_fact(const relation_fact & f) const { + bool result = m_relation->contains_fact(f); + expr_ref fml1(m), fml2(m); + fml1 = mk_eq(f); + fml2 = m.mk_and(m_fml, fml1); + if (result) { + check_equiv(ground(fml1), ground(fml2)); + } + else if (!m.is_false(m_fml)) { + check_equiv(ground(fml2), m.mk_false()); + } + return result; + } + check_relation * check_relation::clone() const { + check_relation* result = check_relation_plugin::get(get_plugin().mk_empty(get_signature())); + result->m_relation->deallocate(); + result->m_relation = m_relation->clone(); + result->m_relation->to_formula(result->m_fml); + if (m_fml != result->m_fml) { + check_equiv(ground(m_fml), ground(result->m_fml)); + } + return result; + } + check_relation * check_relation::complement(func_decl* f) const { + check_relation* result = check_relation_plugin::get(get_plugin().mk_empty(get_signature())); + result->m_relation->deallocate(); + result->m_relation = m_relation->complement(f); + result->m_relation->to_formula(result->m_fml); + expr_ref fml(m); + fml = m.mk_not(m_fml); + check_equiv(ground(fml), ground(result->m_fml)); + return result; + } + void check_relation::to_formula(expr_ref& fml) const { + fml = m_fml; + } + + check_relation_plugin& check_relation::get_plugin() const { + return static_cast(relation_base::get_plugin()); + } + + void check_relation::display(std::ostream& out) const { + m_relation->display(out); + out << m_fml << "\n"; + } + + // ------------- + + check_relation_plugin::check_relation_plugin(relation_manager& rm): + relation_plugin(check_relation_plugin::get_name(), rm), + m(rm.get_context().get_manager()), + m_base(0) { + } + check_relation_plugin::~check_relation_plugin() { + } + check_relation& check_relation_plugin::get(relation_base& r) { + return dynamic_cast(r); + } + check_relation* check_relation_plugin::get(relation_base* r) { + return r?dynamic_cast(r):0; + } + check_relation const & check_relation_plugin::get(relation_base const& r) { + return dynamic_cast(r); + } + + bool check_relation_plugin::can_handle_signature(const relation_signature & sig) { + return m_base->can_handle_signature(sig); + } + relation_base * check_relation_plugin::mk_empty(const relation_signature & sig) { + relation_base* r = m_base->mk_empty(sig); + return alloc(check_relation, *this, sig, r); + } + relation_base * check_relation_plugin::mk_full(func_decl* p, const relation_signature & s) { + relation_base* r = m_base->mk_full(p, s); + return alloc(check_relation, *this, s, r); + } + + class check_relation_plugin::join_fn : public convenient_relation_join_fn { + scoped_ptr m_join; + public: + join_fn(relation_join_fn* j, + const relation_signature & o1_sig, const relation_signature & o2_sig, unsigned col_cnt, + const unsigned * cols1, const unsigned * cols2) + : convenient_join_fn(o1_sig, o2_sig, col_cnt, cols1, cols2), m_join(j) + {} + virtual ~join_fn() {} + virtual relation_base * operator()(const relation_base & r1, const relation_base & r2) { + check_relation const& t1 = get(r1); + check_relation const& t2 = get(r2); + check_relation_plugin& p = t1.get_plugin(); + relation_base* r = (*m_join)(t1.rb(), t2.rb()); + p.verify_join(r1, r2, *r, m_cols1.size(), m_cols1.c_ptr(), m_cols2.c_ptr()); + return alloc(check_relation, p, r->get_signature(), r); + } + }; + + relation_join_fn * check_relation_plugin::mk_join_fn( + const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { + relation_join_fn* j = m_base->mk_join_fn(get(t1).rb(), get(t2).rb(), col_cnt, cols1, cols2); + return j?alloc(join_fn, j, t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2):0; + } + + void check_relation_plugin::verify_filter_project( + relation_base const& src, relation_base const& dst, + app* cond, unsigned_vector const& removed_cols) { + expr_ref fml1(m), fml2(m); + src.to_formula(fml1); + dst.to_formula(fml2); + fml1 = m.mk_and(cond, fml1); + verify_project(src, fml1, dst, fml2, removed_cols); + } + + void check_relation_plugin::verify_project( + relation_base const& src, + relation_base const& dst, + unsigned_vector const& removed_cols) { + expr_ref fml1(m), fml2(m); + src.to_formula(fml1); + dst.to_formula(fml2); + verify_project(src, fml1, dst, fml2, removed_cols); + } + void check_relation_plugin::verify_project( + relation_base const& src, expr* f1, + relation_base const& dst, expr* f2, + unsigned_vector const& removed_cols) { + expr_ref fml1(m); + expr_ref fml2(m); + expr_ref_vector vars1(m), vars2(m); + ptr_vector bound; + svector names; + relation_signature const& sig1 = src.get_signature(); + relation_signature const& sig2 = dst.get_signature(); + for (unsigned i = 0; i < sig2.size(); ++i) { + vars2.push_back(m.mk_const(symbol(i), sig2[i])); + } + for (unsigned i = 0, j = 0, k = 0; i < sig1.size(); ++i) { + if (j < removed_cols.size() && removed_cols[j] == i) { + std::ostringstream strm; + strm << "x" << j; + bound.push_back(sig1[i]); + names.push_back(symbol(strm.str().c_str())); + vars1.push_back(m.mk_var(j, sig1[i])); + ++j; + } + else { + vars1.push_back(vars2[k].get()); + SASSERT(m.get_sort(vars2[k].get()) == sig1[i]); + ++k; + } + } + var_subst sub(m, false); + sub(f1, vars1.size(), vars1.c_ptr(), fml1); + sub(f2, vars2.size(), vars2.c_ptr(), fml2); + bound.reverse(); + fml1 = m.mk_exists(bound.size(), bound.c_ptr(), names.c_ptr(), fml1); + check_equiv(fml1, fml2); + } + + void check_relation_plugin::verify_permutation( + relation_base const& src, relation_base const& dst, + unsigned_vector const& cycle) { + unsigned_vector perm; + relation_signature const& sig1 = src.get_signature(); + relation_signature const& sig2 = dst.get_signature(); + for (unsigned i = 0; i < sig1.size(); ++i) { + perm.push_back(i); + } + for (unsigned i = 0; i < cycle.size(); ++i) { + unsigned j = (i + 1)%cycle.size(); + unsigned col1 = cycle[i]; + unsigned col2 = cycle[j]; + perm[col2] = col1; + } + for (unsigned i = 0; i < perm.size(); ++i) { + SASSERT(sig2[perm[i]] == sig1[i]); + } + expr_ref_vector sub(m); + for (unsigned i = 0; i < perm.size(); ++i) { + sub.push_back(m.mk_var(perm[i], sig1[i])); + } + var_subst subst(m, false); + expr_ref fml1(m), fml2(m); + src.to_formula(fml1); + dst.to_formula(fml2); + subst(fml1, sub.size(), sub.c_ptr(), fml1); + expr_ref_vector vars(m); + for (unsigned i = 0; i < sig2.size(); ++i) { + vars.push_back(m.mk_const(symbol(i), sig2[i])); + } + + subst(fml1, vars.size(), vars.c_ptr(), fml1); + subst(fml2, vars.size(), vars.c_ptr(), fml2); + + check_equiv(fml1, fml2); + } + + void check_relation_plugin::verify_join(relation_base const& t1, relation_base const& t2, relation_base const& t, + unsigned sz, unsigned const* cols1, unsigned const* cols2) { + ast_manager& m = get_ast_manager(); + expr_ref fml1(m), fml2(m), fml3(m); + + relation_signature const& sig1 = t1.get_signature(); + relation_signature const& sig2 = t2.get_signature(); + relation_signature const& sig = t.get_signature(); + var_ref var1(m), var2(m); + t1.to_formula(fml1); + t2.to_formula(fml2); + t.to_formula(fml3); + var_subst sub(m, false); + expr_ref_vector vars(m); + for (unsigned i = 0; i < sig2.size(); ++i) { + vars.push_back(m.mk_var(i + sig1.size(), sig2[i])); + } + sub(fml2, vars.size(), vars.c_ptr(), fml2); + fml1 = m.mk_and(fml1, fml2); + for (unsigned i = 0; i < sz; ++i) { + unsigned v1 = cols1[i]; + unsigned v2 = cols2[i]; + var1 = m.mk_var(v1, sig1[v1]); + var2 = m.mk_var(v2 + sig1.size(), sig2[v2]); + fml1 = m.mk_and(m.mk_eq(var1, var2), fml1); + } + vars.reset(); + for (unsigned i = 0; i < sig.size(); ++i) { + std::stringstream strm; + strm << "x" << i; + vars.push_back(m.mk_const(symbol(strm.str().c_str()), sig[i])); + } + sub(fml1, vars.size(), vars.c_ptr(), fml1); + sub(fml3, vars.size(), vars.c_ptr(), fml3); + check_equiv(fml1, fml3); + } + + void check_relation_plugin::verify_filter(expr* fml0, relation_base const& t, expr* cond) { + expr_ref fml1(m), fml2(m); + fml1 = m.mk_and(fml0, cond); + t.to_formula(fml2); + + relation_signature const& sig = t.get_signature(); + expr_ref_vector vars(m); + var_subst sub(m, false); + for (unsigned i = 0; i < sig.size(); ++i) { + std::stringstream strm; + strm << "x" << i; + vars.push_back(m.mk_const(symbol(strm.str().c_str()), sig[i])); + } + sub(fml1, vars.size(), vars.c_ptr(), fml1); + sub(fml2, vars.size(), vars.c_ptr(), fml2); + check_equiv(fml1, fml2); + } + + void check_relation_plugin::check_equiv(expr* fml1, expr* fml2) { + TRACE("doc", tout << mk_pp(fml1, m) << "\n"; + tout << mk_pp(fml2, m) << "\n";); + smt_params fp; + smt::kernel solver(m, fp); + expr_ref tmp(m); + tmp = m.mk_not(m.mk_eq(fml1, fml2)); + solver.assert_expr(tmp); + lbool res = solver.check(); + if (res == l_false) { + IF_VERBOSE(3, verbose_stream() << "verified\n";); + } + else { + IF_VERBOSE(3, verbose_stream() << "NOT verified " << res << "\n"; + verbose_stream() << mk_pp(fml1, m) << "\n"; + verbose_stream() << mk_pp(fml2, m) << "\n";); + throw 0; + } + } + + void check_relation_plugin::verify_union(expr* fml0, relation_base const& src, relation_base const& dst, relation_base const* delta) { + expr_ref fml1(m), fml2(m), fml3(m); + src.to_formula(fml1); + dst.to_formula(fml2); + fml1 = m.mk_or(fml1, fml0); + relation_signature const& sig = dst.get_signature(); + expr_ref_vector vars(m); + var_subst sub(m, false); + for (unsigned i = 0; i < sig.size(); ++i) { + std::stringstream strm; + strm << "x" << i; + vars.push_back(m.mk_const(symbol(strm.str().c_str()), sig[i])); + } + sub(fml1, vars.size(), vars.c_ptr(), fml1); + sub(fml2, vars.size(), vars.c_ptr(), fml2); + + check_equiv(fml1, fml2); + + if (delta) { + delta->to_formula(fml3); + // dst >= delta >= dst \ fml0 + // dst \ fml0 == delta & dst & \ fml0 + // dst & delta = delta + expr_ref fml4(m), fml5(m); + fml4 = m.mk_and(fml2, m.mk_not(fml0)); + fml5 = m.mk_and(fml3, fml4); + sub(fml4, vars.size(), vars.c_ptr(), fml4); + sub(fml5, vars.size(), vars.c_ptr(), fml5); + check_equiv(fml4, fml5); + fml4 = m.mk_and(fml3, fml2); + sub(fml3, vars.size(), vars.c_ptr(), fml3); + sub(fml4, vars.size(), vars.c_ptr(), fml4); + check_equiv(fml3, fml4); + } + } + + class check_relation_plugin::union_fn : public relation_union_fn { + scoped_ptr m_union; + public: + union_fn(relation_union_fn* m): m_union(m) {} + + virtual void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) { + TRACE("doc", _r.display(tout << "dst:\n"); _src.display(tout << "src:\n");); + check_relation& r = get(_r); + check_relation const& src = get(_src); + check_relation* d = get(_delta); + expr_ref fml0 = r.m_fml; + (*m_union)(r.rb(), src.rb(), d?(&d->rb()):0); + r.get_plugin().verify_union(fml0, src.rb(), r.rb(), d?(&d->rb()):0); + r.rb().to_formula(r.m_fml); + if (d) d->rb().to_formula(d->m_fml); + } + }; + relation_union_fn * check_relation_plugin::mk_union_fn( + const relation_base & tgt, const relation_base & src, + const relation_base * delta) { + relation_base const* d1 = delta?(&(get(*delta).rb())):0; + relation_union_fn* u = m_base->mk_union_fn(get(tgt).rb(), get(src).rb(), d1); + return u?alloc(union_fn, u):0; + } + relation_union_fn * check_relation_plugin::mk_widen_fn( + const relation_base & tgt, const relation_base & src, + const relation_base * delta) { + relation_base const* d1 = delta?(&(get(*delta).rb())):0; + relation_union_fn* u = m_base->mk_widen_fn(get(tgt).rb(), get(src).rb(), d1); + return u?alloc(union_fn, u):0; + } + + class check_relation_plugin::filter_identical_fn : public relation_mutator_fn { + unsigned_vector m_cols; + scoped_ptr m_filter; + public: + filter_identical_fn(relation_mutator_fn* f, unsigned col_cnt, const unsigned *identical_cols) + : m_cols(col_cnt, identical_cols), + m_filter(f) { + } + + virtual ~filter_identical_fn() {} + + virtual void operator()(relation_base & _r) { + check_relation& r = get(_r); + check_relation_plugin& p = r.get_plugin(); + ast_manager& m = p.m; + expr_ref cond(m); + relation_signature const& sig = r.get_signature(); + expr_ref_vector conds(m); + unsigned c1 = m_cols[0]; + for (unsigned i = 1; i < m_cols.size(); ++i) { + unsigned c2 = m_cols[i]; + conds.push_back(m.mk_eq(m.mk_var(c1, sig[c1]), m.mk_var(c2, sig[c2]))); + } + cond = mk_and(m, conds.size(), conds.c_ptr()); + r.consistent_formula(); + (*m_filter)(r.rb()); + p.verify_filter(r.m_fml, r.rb(), cond); + r.rb().to_formula(r.m_fml); + } + }; + relation_mutator_fn * check_relation_plugin::mk_filter_identical_fn( + const relation_base & t, unsigned col_cnt, const unsigned * identical_cols) { + relation_mutator_fn* r = m_base->mk_filter_identical_fn(get(t).rb(), col_cnt, identical_cols); + return r?alloc(filter_identical_fn, r, col_cnt, identical_cols):0; + } + + class check_relation_plugin::filter_interpreted_fn : public relation_mutator_fn { + scoped_ptr m_mutator; + app_ref m_condition; + public: + filter_interpreted_fn(relation_mutator_fn* r, app_ref& condition) : + m_mutator(r), + m_condition(condition) { + } + + virtual ~filter_interpreted_fn() {} + + virtual void operator()(relation_base & tb) { + check_relation& r = get(tb); + check_relation_plugin& p = r.get_plugin(); + expr_ref fml = r.m_fml; + (*m_mutator)(r.rb()); + p.verify_filter(fml, r.rb(), m_condition); + r.rb().to_formula(r.m_fml); + } + }; + relation_mutator_fn * check_relation_plugin::mk_filter_interpreted_fn(const relation_base & t, app * condition) { + relation_mutator_fn* r = m_base->mk_filter_interpreted_fn(get(t).rb(), condition); + app_ref cond(condition, m); + return r?alloc(filter_interpreted_fn, r, cond):0; + } + + class check_relation_plugin::project_fn : public convenient_relation_project_fn { + scoped_ptr m_project; + public: + project_fn(relation_transformer_fn* p, + relation_base const & t, + unsigned removed_col_cnt, const unsigned * removed_cols) + : convenient_relation_project_fn(t.get_signature(), removed_col_cnt, removed_cols), + m_project(p) { + } + + virtual ~project_fn() {} + + virtual relation_base * operator()(const relation_base & tb) { + check_relation const& t = get(tb); + check_relation_plugin& p = t.get_plugin(); + relation_base* r = (*m_project)(t.rb()); + p.verify_project(tb, *r, m_removed_cols); + return alloc(check_relation, p, r->get_signature(), r); + } + }; + + + relation_transformer_fn * check_relation_plugin::mk_project_fn( + const relation_base & t, unsigned col_cnt, + const unsigned * removed_cols) { + relation_transformer_fn* p = m_base->mk_project_fn(get(t).rb(), col_cnt, removed_cols); + return p?alloc(project_fn, p, t, col_cnt, removed_cols):0; + } + + class check_relation_plugin::rename_fn : public convenient_relation_rename_fn { + scoped_ptr m_permute; + public: + rename_fn(relation_transformer_fn* permute, + relation_base const& t, unsigned cycle_len, const unsigned * cycle) + : convenient_relation_rename_fn(t.get_signature(), cycle_len, cycle), + m_permute(permute) { + } + + virtual ~rename_fn() {} + + virtual relation_base * operator()(const relation_base & _t) { + check_relation const& t = get(_t); + check_relation_plugin& p = t.get_plugin(); + relation_signature const& sig = get_result_signature(); + relation_base* r = (*m_permute)(t.rb()); + p.verify_permutation(t.rb(), *r, m_cycle); + return alloc(check_relation, p, sig, r); + } + }; + relation_transformer_fn * check_relation_plugin::mk_rename_fn( + const relation_base & r, + unsigned cycle_len, const unsigned * permutation_cycle) { + relation_transformer_fn* p = m_base->mk_rename_fn(get(r).rb(), cycle_len, permutation_cycle); + return p?alloc(rename_fn, p, r, cycle_len, permutation_cycle):0; + } + + class check_relation_plugin::filter_equal_fn : public relation_mutator_fn { + scoped_ptr m_filter; + relation_element m_val; + unsigned m_col; + public: + filter_equal_fn(relation_mutator_fn* filter, relation_base const& t, + const relation_element val, unsigned col): + m_filter(filter), + m_val(val), + m_col(col) + {} + virtual ~filter_equal_fn() { } + virtual void operator()(relation_base & tb) { + check_relation & t = get(tb); + check_relation_plugin& p = t.get_plugin(); + (*m_filter)(t.rb()); + expr_ref fml = t.m_fml; + t.rb().to_formula(t.m_fml); + fml = p.m.mk_and(fml, p.m.mk_eq(p.m.mk_var(m_col, t.get_signature()[m_col]), m_val)); + p.check_equiv(t.ground(fml), t.ground(t.m_fml)); + } + }; + relation_mutator_fn * check_relation_plugin::mk_filter_equal_fn( + const relation_base & t, const relation_element & value, unsigned col) { + relation_mutator_fn* r = m_base->mk_filter_equal_fn(get(t).rb(), value, col); + return r?alloc(filter_equal_fn, r, t, value, col):0; + } + + + + + class check_relation_plugin::negation_filter_fn : public relation_intersection_filter_fn { + scoped_ptr m_filter; + const unsigned_vector m_t_cols; + const unsigned_vector m_neg_cols; + public: + negation_filter_fn( + relation_intersection_filter_fn* filter, + unsigned joined_col_cnt, const unsigned *t_cols, const unsigned *neg_cols) + : m_filter(filter), + m_t_cols(joined_col_cnt, t_cols), m_neg_cols(joined_col_cnt, neg_cols) { + SASSERT(joined_col_cnt > 0); + } + + virtual void operator()(relation_base& tb, const relation_base& negb) { + check_relation& t = get(tb); + check_relation const& n = get(negb); + check_relation_plugin& p = t.get_plugin(); + (*m_filter)(t.rb(), n.rb()); + IF_VERBOSE(0, verbose_stream() << "TBD: verify filter_negation\n";); + t.rb().to_formula(t.m_fml); + } + }; + + relation_intersection_filter_fn * check_relation_plugin::mk_filter_by_negation_fn( + const relation_base& t, + const relation_base& neg, unsigned joined_col_cnt, const unsigned *t_cols, + const unsigned *negated_cols) { + relation_intersection_filter_fn* f = mk_filter_by_negation_fn(get(t).rb(), get(neg).rb(), joined_col_cnt, t_cols, negated_cols); + return f?alloc(negation_filter_fn, f, joined_col_cnt, t_cols, negated_cols):0; + } + + + class check_relation_plugin::filter_proj_fn : public convenient_relation_project_fn { + app_ref m_cond; + scoped_ptr m_xform; + public: + filter_proj_fn(relation_transformer_fn* xform, + relation_base const& t, app_ref& cond, + unsigned col_cnt, const unsigned * removed_cols) : + convenient_relation_project_fn(t.get_signature(), col_cnt, removed_cols), + m_cond(cond), + m_xform(xform) + {} + + virtual ~filter_proj_fn() {} + + virtual relation_base* operator()(const relation_base & tb) { + check_relation const & t = get(tb); + check_relation_plugin& p = t.get_plugin(); + relation_base* r = (*m_xform)(t.rb()); + p.verify_filter_project(t.rb(), *r, m_cond, m_removed_cols); + relation_signature const& sig = get_result_signature(); + return alloc(check_relation, p, sig, r); + } + }; + relation_transformer_fn * check_relation_plugin::mk_filter_interpreted_and_project_fn( + const relation_base & t, app * condition, + unsigned removed_col_cnt, const unsigned * removed_cols) { + relation_transformer_fn* r = m_base->mk_filter_interpreted_and_project_fn(get(t).rb(), condition, removed_col_cnt, removed_cols); + app_ref cond(condition, m); + return r?alloc(filter_proj_fn, r, t, cond, removed_col_cnt, removed_cols):0; + } + + + + +} diff --git a/src/muz/rel/check_relation.h b/src/muz/rel/check_relation.h new file mode 100644 index 000000000..2856bf3a0 --- /dev/null +++ b/src/muz/rel/check_relation.h @@ -0,0 +1,147 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + check_relation.h + +Abstract: + + Checked relation. + Each operation on an underlying relation is checked for correctness. + +Author: + + Nikolaj Bjorner (nbjorner) 2014-09-23 + +Revision History: + + +--*/ + +#ifndef _CHECK_RELATION_H_ +#define _CHECK_RELATION_H_ + +#include "doc.h" +#include "dl_base.h" + +namespace datalog { + class check_relation_plugin; + class check_relation; + + class check_relation : public relation_base { + friend class check_relation_plugin; + ast_manager& m; + relation_base* m_relation; + expr_ref m_fml; + void check_equiv(expr* f1, expr* f2) const; + expr_ref mk_eq(relation_fact const& f) const; + public: + check_relation(check_relation_plugin& p, relation_signature const& s, relation_base* r); + virtual ~check_relation(); + virtual void reset(); + virtual void add_fact(const relation_fact & f); + virtual void add_new_fact(const relation_fact & f); + virtual bool contains_fact(const relation_fact & f) const; + virtual check_relation * clone() const; + virtual check_relation * complement(func_decl*) const; + virtual void to_formula(expr_ref& fml) const; + check_relation_plugin& get_plugin() const; + virtual bool fast_empty() const; + virtual bool empty() const; + virtual void display(std::ostream& out) const; + virtual bool is_precise() const { return m_relation->is_precise(); } + virtual unsigned get_size_estimate_rows() const { return m_relation->get_size_estimate_rows(); } + relation_base& rb() { return *m_relation; } + relation_base const& rb() const { return *m_relation; } + expr_ref ground(expr* fml) const; + void consistent_formula(); + }; + + class check_relation_plugin : public relation_plugin { + friend class check_relation; + + class join_fn; + class project_fn; + class union_fn; + class rename_fn; + class filter_equal_fn; + class filter_identical_fn; + class filter_interpreted_fn; + class filter_by_negation_fn; + class filter_by_union_fn; + class filter_proj_fn; + class negation_filter_fn; + ast_manager& m; + relation_plugin* m_base; + static check_relation& get(relation_base& r); + static check_relation* get(relation_base* r); + static check_relation const & get(relation_base const& r); + public: + check_relation_plugin(relation_manager& rm); + ~check_relation_plugin(); + void set_plugin(relation_plugin* p) { m_base = p; } + + virtual bool can_handle_signature(const relation_signature & s); + static symbol get_name() { return symbol("check_relation"); } + virtual relation_base * mk_empty(const relation_signature & s); + virtual relation_base * mk_full(func_decl* p, const relation_signature & s); + virtual relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); + virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, + const unsigned * removed_cols); + virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle); + virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta); + virtual relation_union_fn * mk_widen_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta); + virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, + const unsigned * identical_cols); + virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, + unsigned col); + virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); + virtual relation_intersection_filter_fn * mk_filter_by_negation_fn( + const relation_base& t, + const relation_base& neg, unsigned joined_col_cnt, const unsigned *t_cols, + const unsigned *negated_cols); + virtual relation_transformer_fn * mk_filter_interpreted_and_project_fn( + const relation_base & t, app * condition, + unsigned removed_col_cnt, const unsigned * removed_cols); + + void verify_join(relation_base const& t1, relation_base const& t2, relation_base const& t, + unsigned sz, unsigned const* cols1, unsigned const* cols2); + + void verify_filter(expr* fml0, relation_base const& t, expr* cond); + + void verify_union(expr* fml0, relation_base const& src, relation_base const& dst, + relation_base const* delta); + + void verify_permutation( + relation_base const& src, relation_base const& dst, + unsigned_vector const& cycle); + + void verify_project( + relation_base const& src, expr* f1, + relation_base const& dst, expr* f2, + unsigned_vector const& removed_cols); + + void verify_project( + relation_base const& src, + relation_base const& dst, + unsigned_vector const& removed_cols); + + void verify_filter_project( + relation_base const& src, relation_base const& dst, + app* cond, unsigned_vector const& removed_cols); + + + + void check_equiv(expr* f1, expr* f2); + + + }; +}; + +#endif /* _CHECK_RELATION_H_ */ + diff --git a/src/muz/rel/dl_base.h b/src/muz/rel/dl_base.h index e53dae88a..fa9bc84ee 100644 --- a/src/muz/rel/dl_base.h +++ b/src/muz/rel/dl_base.h @@ -248,6 +248,7 @@ namespace datalog { class plugin_object { friend class relation_manager; friend class check_table_plugin; + friend class check_relation_plugin; family_id m_kind; symbol m_name; diff --git a/src/muz/rel/dl_instruction.cpp b/src/muz/rel/dl_instruction.cpp index 4122811ac..bf2f09d56 100644 --- a/src/muz/rel/dl_instruction.cpp +++ b/src/muz/rel/dl_instruction.cpp @@ -759,9 +759,9 @@ namespace datalog { if (!ctx.reg(m_src)) { return true; } + log_verbose(ctx); ++ctx.m_stats.m_project_rename; - relation_transformer_fn * fn; relation_base & r_src = *ctx.reg(m_src); if (!find_fn(r_src, fn)) { @@ -885,13 +885,12 @@ namespace datalog { } virtual bool perform(execution_context & ctx) { - log_verbose(ctx); - ++ctx.m_stats.m_select_equal_project; if (!ctx.reg(m_src)) { ctx.make_empty(m_result); return true; } - + log_verbose(ctx); + ++ctx.m_stats.m_select_equal_project; relation_transformer_fn * fn; relation_base & r = *ctx.reg(m_src); if (!find_fn(r, fn)) { diff --git a/src/muz/rel/dl_relation_manager.h b/src/muz/rel/dl_relation_manager.h index be81a7afa..530538df5 100644 --- a/src/muz/rel/dl_relation_manager.h +++ b/src/muz/rel/dl_relation_manager.h @@ -176,6 +176,7 @@ namespace datalog { table_plugin * get_table_plugin(symbol const& s); relation_plugin * get_relation_plugin(symbol const& s); relation_plugin & get_relation_plugin(family_id kind); + void set_favourite_plugin(relation_plugin* p) { m_favourite_relation_plugin = p; } table_relation_plugin & get_table_relation_plugin(table_plugin & tp); bool try_get_finite_product_relation_plugin(const relation_plugin & inner, finite_product_relation_plugin * & res); diff --git a/src/muz/rel/doc.cpp b/src/muz/rel/doc.cpp index 917eeb655..938f39aed 100644 --- a/src/muz/rel/doc.cpp +++ b/src/muz/rel/doc.cpp @@ -25,6 +25,7 @@ Revision History: #include "expr_safe_replace.h" #include "smt_params.h" #include "ast_util.h" +#include "ast_pp.h" doc_manager::doc_manager(unsigned n): m(n), m_alloc("doc") { m_full = m.allocateX(); diff --git a/src/muz/rel/rel_context.cpp b/src/muz/rel/rel_context.cpp index 371e14353..62932a901 100644 --- a/src/muz/rel/rel_context.cpp +++ b/src/muz/rel/rel_context.cpp @@ -34,6 +34,7 @@ Revision History: #include"dl_finite_product_relation.h" #include"product_set.h" #include"udoc_relation.h" +#include"check_relation.h" #include"dl_lazy_table.h" #include"dl_sparse_table.h" #include"dl_table.h" @@ -118,6 +119,7 @@ namespace datalog { rm.register_plugin(alloc(karr_relation_plugin, rm)); rm.register_plugin(alloc(product_set_plugin, rm)); rm.register_plugin(alloc(udoc_plugin, rm)); + rm.register_plugin(alloc(check_relation_plugin, rm)); } rel_context::~rel_context() { @@ -575,6 +577,24 @@ namespace datalog { m_ectx.collect_statistics(st); } + void rel_context::updt_params() { + if (m_context.check_relation() != symbol::null) { + symbol cr("check_relation"); + m_context.set_default_relation(cr); + relation_plugin* p = get_rmanager().get_relation_plugin(cr); + SASSERT(p); + check_relation_plugin* p1 = dynamic_cast(p); + relation_plugin* p2 = get_rmanager().get_relation_plugin(m_context.check_relation()); + SASSERT(p2); + SASSERT(p1 != p2); + p1->set_plugin(p2); + get_rmanager().set_favourite_plugin(p1); + if (m_context.check_relation() == symbol("doc")) { + m_context.set_unbound_compressor(false); + } + } + } + void rel_context::inherit_predicate_kind(func_decl* new_pred, func_decl* orig_pred) { if (orig_pred) { family_id target_kind = get_rmanager().get_requested_predicate_kind(orig_pred); diff --git a/src/muz/rel/rel_context.h b/src/muz/rel/rel_context.h index 8cdee2766..e445c926f 100644 --- a/src/muz/rel/rel_context.h +++ b/src/muz/rel/rel_context.h @@ -84,6 +84,7 @@ namespace datalog { virtual void cancel() { set_cancel(true); } virtual void cleanup() { set_cancel(false);} + virtual void updt_params(); /** \brief Restrict the set of used predicates to \c res. diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index b5af52701..2bdec8e01 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -402,7 +402,6 @@ namespace datalog { TRACE("doc", result->display(tout << "result:\n");); IF_VERBOSE(3, result->display(verbose_stream() << "join result:\n");); SASSERT(r.well_formed(result->get_dm())); - DEBUG_CODE(p.verify_join(r1, r2, *result, m_orig_cols1.size(), m_orig_cols1.c_ptr(), m_orig_cols2.c_ptr());); return result; } }; @@ -572,7 +571,6 @@ namespace datalog { TRACE("doc", _r.display(tout << "dst':\n"); ); IF_VERBOSE(3, r.display(verbose_stream() << "union: ");); IF_VERBOSE(3, if (d) d->display(verbose_stream() << "delta: ");); - DEBUG_CODE(r.get_plugin().verify_union(fml0, src, r, d);); } }; void udoc_plugin::mk_union(doc_manager& dm, udoc& dst, udoc const& src, udoc* delta) { @@ -957,8 +955,6 @@ namespace datalog { udoc_relation & t = get(tb); udoc& u = t.get_udoc(); ast_manager& m = m_reduced_condition.get_manager(); - expr_ref fml0(m); - DEBUG_CODE(t.to_formula(fml0);); SASSERT(u.well_formed(dm)); u.intersect(dm, m_udoc); SASSERT(u.well_formed(dm)); @@ -968,7 +964,6 @@ namespace datalog { SASSERT(u.well_formed(dm)); TRACE("doc", tout << "final size: " << t.get_size_estimate_rows() << '\n';); IF_VERBOSE(3, t.display(verbose_stream());); - DEBUG_CODE(t.get_plugin().verify_filter(fml0, t, m_original_condition);); } }; relation_mutator_fn * udoc_plugin::mk_filter_interpreted_fn(const relation_base & t, app * condition) { @@ -1118,13 +1113,6 @@ namespace datalog { u2.merge(dm, m_roots, m_equalities, m_col_list); t.apply_guard(m_reduced_condition, u2, m_equalities, m_col_list); SASSERT(u2.well_formed(dm)); - DEBUG_CODE( - expr_ref fml0(m); - udoc_relation* r_test = get(t.get_plugin().mk_empty(t.get_signature())); - r_test->get_udoc().insert(dm, u2); - t.to_formula(fml0); - t.get_plugin().verify_filter(fml0, *r_test, m_original_condition); - r_test->deallocate();); udoc_relation* r = get(t.get_plugin().mk_empty(get_result_signature())); doc_manager& dm2 = r->get_dm(); // std::cout << "Size of union: " << u2.size() << "\n"; @@ -1145,113 +1133,7 @@ namespace datalog { return check_kind(t)?alloc(filter_proj_fn, get(t), get_ast_manager(), condition, removed_col_cnt, removed_cols):0; } - // TBD: move this to relation validation module like table_checker. - void udoc_plugin::verify_join(relation_base const& t1, relation_base const& t2, relation_base const& t, - unsigned sz, unsigned const* cols1, unsigned const* cols2) { - ast_manager& m = get_ast_manager(); - expr_ref fml1(m), fml2(m), fml3(m); - - relation_signature const& sig1 = t1.get_signature(); - relation_signature const& sig2 = t2.get_signature(); - relation_signature const& sig = t.get_signature(); - var_ref var1(m), var2(m); - t1.to_formula(fml1); - t2.to_formula(fml2); - t.to_formula(fml3); - var_subst sub(m, false); - expr_ref_vector vars(m); - for (unsigned i = 0; i < sig2.size(); ++i) { - vars.push_back(m.mk_var(i + sig1.size(), sig2[i])); - } - sub(fml2, vars.size(), vars.c_ptr(), fml2); - fml1 = m.mk_and(fml1, fml2); - for (unsigned i = 0; i < sz; ++i) { - unsigned v1 = cols1[i]; - unsigned v2 = cols2[i]; - var1 = m.mk_var(v1, sig1[v1]); - var2 = m.mk_var(v2 + sig1.size(), sig2[v2]); - fml1 = m.mk_and(m.mk_eq(var1, var2), fml1); - } - vars.reset(); - for (unsigned i = 0; i < sig.size(); ++i) { - std::stringstream strm; - strm << "x" << i; - vars.push_back(m.mk_const(symbol(strm.str().c_str()), sig[i])); - } - sub(fml1, vars.size(), vars.c_ptr(), fml1); - sub(fml3, vars.size(), vars.c_ptr(), fml3); - check_equiv(fml1, fml3); - } - void udoc_plugin::verify_filter(expr* fml0, relation_base const& t, expr* cond) { - expr_ref fml1(m), fml2(m); - fml1 = m.mk_and(fml0, cond); - t.to_formula(fml2); - - relation_signature const& sig = t.get_signature(); - expr_ref_vector vars(m); - var_subst sub(m, false); - for (unsigned i = 0; i < sig.size(); ++i) { - std::stringstream strm; - strm << "x" << i; - vars.push_back(m.mk_const(symbol(strm.str().c_str()), sig[i])); - } - sub(fml1, vars.size(), vars.c_ptr(), fml1); - sub(fml2, vars.size(), vars.c_ptr(), fml2); - check_equiv(fml1, fml2); - } - - void udoc_plugin::check_equiv(expr* fml1, expr* fml2) { - TRACE("doc", tout << mk_pp(fml1, m) << "\n"; - tout << mk_pp(fml2, m) << "\n";); - smt_params fp; - smt::kernel solver(m, fp); - expr_ref tmp(m); - tmp = m.mk_not(m.mk_eq(fml1, fml2)); - solver.assert_expr(tmp); - lbool res = solver.check(); - IF_VERBOSE(3, verbose_stream() << "result of verification: " << res << "\n";); - if (res != l_false) { - throw 0; - } - SASSERT(res == l_false); - } - - void udoc_plugin::verify_union(expr* fml0, relation_base const& src, relation_base const& dst, relation_base const* delta) { - expr_ref fml1(m), fml2(m), fml3(m); - src.to_formula(fml1); - dst.to_formula(fml2); - fml1 = m.mk_or(fml1, fml0); - relation_signature const& sig = dst.get_signature(); - expr_ref_vector vars(m); - var_subst sub(m, false); - for (unsigned i = 0; i < sig.size(); ++i) { - std::stringstream strm; - strm << "x" << i; - vars.push_back(m.mk_const(symbol(strm.str().c_str()), sig[i])); - } - sub(fml1, vars.size(), vars.c_ptr(), fml1); - sub(fml2, vars.size(), vars.c_ptr(), fml2); - - check_equiv(fml1, fml2); - - if (delta) { - delta->to_formula(fml3); - // dst >= delta >= dst \ fml0 - // dst \ fml0 == delta & dst & \ fml0 - // dst & delta = delta - expr_ref fml4(m), fml5(m); - fml4 = m.mk_and(fml2, m.mk_not(fml0)); - fml5 = m.mk_and(fml3, fml4); - sub(fml4, vars.size(), vars.c_ptr(), fml4); - sub(fml5, vars.size(), vars.c_ptr(), fml5); - check_equiv(fml4, fml5); - fml4 = m.mk_and(fml3, fml2); - sub(fml3, vars.size(), vars.c_ptr(), fml3); - sub(fml4, vars.size(), vars.c_ptr(), fml4); - check_equiv(fml3, fml4); - } - } } diff --git a/src/muz/rel/udoc_relation.h b/src/muz/rel/udoc_relation.h index 6b7a218b5..64ced8e83 100644 --- a/src/muz/rel/udoc_relation.h +++ b/src/muz/rel/udoc_relation.h @@ -133,15 +133,6 @@ namespace datalog { virtual relation_transformer_fn * mk_filter_interpreted_and_project_fn( const relation_base & t, app * condition, unsigned removed_col_cnt, const unsigned * removed_cols); - - void verify_join(relation_base const& t1, relation_base const& t2, relation_base const& t, - unsigned sz, unsigned const* cols1, unsigned const* cols2); - - void verify_filter(expr* fml0, relation_base const& t, expr* cond); - - void verify_union(expr* fml0, relation_base const& src, relation_base const& dst, relation_base const* delta); - - void check_equiv(expr* f1, expr* f2); }; }; diff --git a/src/test/doc.cpp b/src/test/doc.cpp index ad62893d8..3dcf57613 100644 --- a/src/test/doc.cpp +++ b/src/test/doc.cpp @@ -262,7 +262,7 @@ class test_doc_cls { rep2.insert(m_vars[i].get(), m.mk_false()); rep2(fml, tmp2); if (tmp1 == tmp2) { - fml1 = tmp1; + fml = tmp1; } else { fml = m.mk_or(tmp1, tmp2); diff --git a/src/test/udoc_relation.cpp b/src/test/udoc_relation.cpp index 5c25c8ee7..523d4e4db 100644 --- a/src/test/udoc_relation.cpp +++ b/src/test/udoc_relation.cpp @@ -15,6 +15,7 @@ #include "dl_register_engine.h" #include "rel_context.h" #include "bv_decl_plugin.h" +#include "check_relation.h" class udoc_tester { @@ -41,6 +42,7 @@ class udoc_tester { datalog::context m_ctx; datalog::rel_context rc; udoc_plugin& p; + datalog::check_relation_plugin& cr; tbit choose_tbit() { @@ -92,9 +94,12 @@ class udoc_tester { } public: - udoc_tester(): m_init(m), bv(m), m_vars(m), m_ctx(m, m_reg, m_smt_params), rc(m_ctx), - p(dynamic_cast(*rc.get_rmanager().get_relation_plugin(symbol("doc")))) - { + udoc_tester(): + m_init(m), bv(m), m_vars(m), m_ctx(m, m_reg, m_smt_params), rc(m_ctx), + p(dynamic_cast(*rc.get_rmanager().get_relation_plugin(symbol("doc")))), + cr(dynamic_cast(*rc.get_rmanager().get_relation_plugin(symbol("check_relation")))) + { + cr.set_plugin(&p); } udoc_relation* mk_empty(relation_signature const& sig) { @@ -443,7 +448,7 @@ public: join_fn = p.mk_join_fn(*t1, *t2, jc1.size(), jc1.c_ptr(), jc2.c_ptr()); t = (*join_fn)(*t1, *t2); - p.verify_join(*t1, *t2, *t, jc1.size(), jc1.c_ptr(), jc2.c_ptr()); + cr.verify_join(*t1, *t2, *t, jc1.size(), jc1.c_ptr(), jc2.c_ptr()); t1->display(std::cout); t2->display(std::cout); t->display(std::cout); @@ -707,7 +712,7 @@ public: rel_mut fint = p.mk_filter_interpreted_fn(t, cond); (*fint)(t); t.display(std::cout << "filter: " << mk_pp(cond, m) << " "); std::cout << "\n"; - t.get_plugin().verify_filter(fml0, t, cond); + cr.verify_filter(fml0, t, cond); full->deallocate(); } From 918d52f1b001fdcfbc67950d7623a68438e77910 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 24 Sep 2014 09:20:21 -0700 Subject: [PATCH 573/925] tune and fix doc Signed-off-by: Nikolaj Bjorner --- src/muz/base/dl_context.cpp | 4 +- src/muz/base/dl_rule.cpp | 80 +++++------------ src/muz/base/dl_rule.h | 62 +++++++++++++- src/muz/base/hnf.cpp | 32 ++++++- src/muz/bmc/dl_bmc_engine.cpp | 2 +- src/muz/rel/check_relation.cpp | 2 +- src/muz/rel/doc.h | 2 +- src/muz/rel/rel_context.cpp | 4 +- src/muz/rel/udoc_relation.cpp | 85 +++++++++++++------ src/muz/rel/udoc_relation.h | 5 +- .../dl_mk_interp_tail_simplifier.cpp | 5 +- .../dl_mk_quantifier_instantiation.cpp | 3 +- src/muz/transforms/dl_mk_slice.cpp | 5 +- 13 files changed, 188 insertions(+), 103 deletions(-) diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 05135a44f..2b3b70a41 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -574,7 +574,7 @@ namespace datalog { void context::check_uninterpreted_free(rule& r) { func_decl* f = 0; - if (r.has_uninterpreted_non_predicates(m, f)) { + if (get_rule_manager().has_uninterpreted_non_predicates(r, f)) { std::stringstream stm; stm << "Uninterpreted '" << f->get_name() @@ -585,7 +585,7 @@ namespace datalog { } void context::check_quantifier_free(rule& r) { - if (r.has_quantifiers()) { + if (get_rule_manager().has_quantifiers(r)) { std::stringstream stm; stm << "cannot process quantifiers in rule "; r.display(*this, stm); diff --git a/src/muz/base/dl_rule.cpp b/src/muz/base/dl_rule.cpp index 6296717da..2015d4eea 100644 --- a/src/muz/base/dl_rule.cpp +++ b/src/muz/base/dl_rule.cpp @@ -56,7 +56,8 @@ namespace datalog { m_hnf(m), m_qe(m), m_cfg(m), - m_rwr(m, false, m_cfg) {} + m_rwr(m, false, m_cfg), + m_ufproc(m) {} void rule_manager::inc_ref(rule * r) { if (r) { @@ -911,83 +912,40 @@ namespace datalog { return false; } - struct uninterpreted_function_finder_proc { - ast_manager& m; - datatype_util m_dt; - bool m_found; - func_decl* m_func; - uninterpreted_function_finder_proc(ast_manager& m): - m(m), m_dt(m), m_found(false), m_func(0) {} - void operator()(var * n) { } - void operator()(quantifier * n) { } - void operator()(app * n) { - if (is_uninterp(n)) { - m_found = true; - m_func = n->get_decl(); - } - else if (m_dt.is_accessor(n)) { - sort* s = m.get_sort(n->get_arg(0)); - SASSERT(m_dt.is_datatype(s)); - if (m_dt.get_datatype_constructors(s)->size() > 1) { - m_found = true; - m_func = n->get_decl(); - } - } - } - - bool found(func_decl*& f) const { f = m_func; return m_found; } - }; // // non-predicates may appear only in the interpreted tail, it is therefore // sufficient only to check the tail. // - bool rule::has_uninterpreted_non_predicates(ast_manager& m, func_decl*& f) const { - unsigned sz = get_tail_size(); - uninterpreted_function_finder_proc proc(m); - expr_mark visited; - for (unsigned i = get_uninterpreted_tail_size(); i < sz && !proc.found(f); ++i) { - for_each_expr(proc, visited, get_tail(i)); + bool rule_manager::has_uninterpreted_non_predicates(rule const& r, func_decl*& f) const { + unsigned sz = r.get_tail_size(); + m_ufproc.reset(); + m_visited.reset(); + for (unsigned i = r.get_uninterpreted_tail_size(); i < sz && !m_ufproc.found(f); ++i) { + for_each_expr_core(m_ufproc, m_visited, r.get_tail(i)); } - return proc.found(f); + return m_ufproc.found(f); } - struct quantifier_finder_proc { - bool m_exist; - bool m_univ; - quantifier_finder_proc() : m_exist(false), m_univ(false) {} - void operator()(var * n) { } - void operator()(quantifier * n) { - if (n->is_forall()) { - m_univ = true; - } - else { - SASSERT(n->is_exists()); - m_exist = true; - } - } - void operator()(app * n) { } - }; - // // Quantifiers may appear only in the interpreted tail, it is therefore // sufficient only to check the interpreted tail. // - void rule::has_quantifiers(bool& existential, bool& universal) const { - unsigned sz = get_tail_size(); - quantifier_finder_proc proc; - expr_mark visited; - for (unsigned i = get_uninterpreted_tail_size(); i < sz; ++i) { - for_each_expr(proc, visited, get_tail(i)); + void rule_manager::has_quantifiers(rule const& r, bool& existential, bool& universal) const { + unsigned sz = r.get_tail_size(); + m_qproc.reset(); + m_visited.reset(); + for (unsigned i = r.get_uninterpreted_tail_size(); i < sz; ++i) { + for_each_expr_core(m_qproc, m_visited, r.get_tail(i)); } - existential = proc.m_exist; - universal = proc.m_univ; + existential = m_qproc.m_exist; + universal = m_qproc.m_univ; } - bool rule::has_quantifiers() const { + bool rule_manager::has_quantifiers(rule const& r) const { bool exist, univ; - has_quantifiers(exist, univ); + has_quantifiers(r, exist, univ); return exist || univ; } diff --git a/src/muz/base/dl_rule.h b/src/muz/base/dl_rule.h index e90edefa1..50211e1d9 100644 --- a/src/muz/base/dl_rule.h +++ b/src/muz/base/dl_rule.h @@ -31,6 +31,7 @@ Revision History: #include"hnf.h" #include"qe_lite.h" #include"var_subst.h" +#include"datatype_decl_plugin.h" namespace datalog { @@ -43,6 +44,57 @@ namespace datalog { typedef obj_ref rule_ref; typedef ref_vector rule_ref_vector; typedef ptr_vector rule_vector; + + + struct quantifier_finder_proc { + bool m_exist; + bool m_univ; + quantifier_finder_proc() : m_exist(false), m_univ(false) {} + void operator()(var * n) { } + void operator()(quantifier * n) { + if (n->is_forall()) { + m_univ = true; + } + else { + SASSERT(n->is_exists()); + m_exist = true; + } + } + void operator()(app * n) { } + void reset() { m_exist = m_univ = false; } + }; + + struct uninterpreted_function_finder_proc { + ast_manager& m; + datatype_util m_dt; + bool m_found; + func_decl* m_func; + uninterpreted_function_finder_proc(ast_manager& m): + m(m), m_dt(m), m_found(false), m_func(0) {} + + void reset() { m_found = false; m_func = 0; } + + void operator()(var * n) { } + void operator()(quantifier * n) { } + void operator()(app * n) { + if (is_uninterp(n)) { + m_found = true; + m_func = n->get_decl(); + } + else if (m_dt.is_accessor(n)) { + sort* s = m.get_sort(n->get_arg(0)); + SASSERT(m_dt.is_datatype(s)); + if (m_dt.get_datatype_constructors(s)->size() > 1) { + m_found = true; + m_func = n->get_decl(); + } + } + } + + bool found(func_decl*& f) const { f = m_func; return m_found; } + }; + + /** \brief Manager for the \c rule class @@ -75,6 +127,9 @@ namespace datalog { qe_lite m_qe; remove_label_cfg m_cfg; rewriter_tpl m_rwr; + mutable uninterpreted_function_finder_proc m_ufproc; + mutable quantifier_finder_proc m_qproc; + mutable expr_sparse_mark m_visited; // only the context can create a rule_manager @@ -220,6 +275,10 @@ namespace datalog { std::ostream& display_smt2(rule const& r, std::ostream & out); + bool has_uninterpreted_non_predicates(rule const& r, func_decl*& f) const; + void has_quantifiers(rule const& r, bool& existential, bool& universal) const; + bool has_quantifiers(rule const& r) const; + }; class rule : public accounted_object { @@ -295,9 +354,6 @@ namespace datalog { */ bool is_in_tail(const func_decl * p, bool only_positive=false) const; - bool has_uninterpreted_non_predicates(ast_manager& m, func_decl*& f) const; - void has_quantifiers(bool& existential, bool& universal) const; - bool has_quantifiers() const; bool has_negation() const; /** diff --git a/src/muz/base/hnf.cpp b/src/muz/base/hnf.cpp index c30ca8b0e..a0dbe9518 100644 --- a/src/muz/base/hnf.cpp +++ b/src/muz/base/hnf.cpp @@ -88,6 +88,7 @@ class hnf::imp { proof_ref_vector m_defs; contains_predicate_proc m_proc; expr_free_vars m_free_vars; + ast_fast_mark1 m_mark1; public: @@ -106,10 +107,37 @@ public: m_proc(*this) { } + bool is_horn(expr* n) { + expr* n1, *n2; + while (is_forall(n)) n = to_quantifier(n)->get_expr(); + if (m.is_implies(n, n1, n2) && is_predicate(n2)) { + app* a1 = to_app(n1); + if (m.is_and(a1)) { + for (unsigned i = 0; i < a1->get_num_args(); ++i) { + if (!is_predicate(a1->get_arg(i)) && + contains_predicate(a1->get_arg(i))) { + return false; + } + } + } + else if (!is_predicate(a1) && contains_predicate(a1)) { + return false; + } + return true; + } + + return false; + } + void operator()(expr * n, proof* p, expr_ref_vector& result, proof_ref_vector& ps) { + if (is_horn(n)) { + result.push_back(n); + ps.push_back(p); + return; + } expr_ref fml(m); proof_ref pr(m); m_todo.reset(); @@ -184,9 +212,11 @@ private: bool contains_predicate(expr* fml) { try { - quick_for_each_expr(m_proc, fml); + quick_for_each_expr(m_proc, m_mark1, fml); + m_mark1.reset(); } catch (contains_predicate_proc::found) { + m_mark1.reset(); return true; } return false; diff --git a/src/muz/bmc/dl_bmc_engine.cpp b/src/muz/bmc/dl_bmc_engine.cpp index 1d1a59e5f..2b970e4fa 100644 --- a/src/muz/bmc/dl_bmc_engine.cpp +++ b/src/muz/bmc/dl_bmc_engine.cpp @@ -1500,7 +1500,7 @@ namespace datalog { if (m_rules.get_rule(i)->get_uninterpreted_tail_size() > 1) { return false; } - if (m_rules.get_rule(i)->has_quantifiers()) { + if (m_rules.get_rule_manager().has_quantifiers(*m_rules.get_rule(i))) { return false; } } diff --git a/src/muz/rel/check_relation.cpp b/src/muz/rel/check_relation.cpp index beafc7c3e..98a0635fe 100644 --- a/src/muz/rel/check_relation.cpp +++ b/src/muz/rel/check_relation.cpp @@ -149,7 +149,7 @@ namespace datalog { } bool check_relation_plugin::can_handle_signature(const relation_signature & sig) { - return m_base->can_handle_signature(sig); + return m_base && m_base->can_handle_signature(sig); } relation_base * check_relation_plugin::mk_empty(const relation_signature & sig) { relation_base* r = m_base->mk_empty(sig); diff --git a/src/muz/rel/doc.h b/src/muz/rel/doc.h index 86849ba72..3be31ead7 100644 --- a/src/muz/rel/doc.h +++ b/src/muz/rel/doc.h @@ -291,7 +291,7 @@ public: void merge(M& m, unsigned_vector const& roots, subset_ints const& equalities, bit_vector const& discard_cols) { for (unsigned i = 0; i < roots.size(); ++i) { - merge(m, roots[i], equalities, discard_cols); + merge(m, roots[i], 1, equalities, discard_cols); } } diff --git a/src/muz/rel/rel_context.cpp b/src/muz/rel/rel_context.cpp index 62932a901..6454da2a2 100644 --- a/src/muz/rel/rel_context.cpp +++ b/src/muz/rel/rel_context.cpp @@ -578,7 +578,9 @@ namespace datalog { } void rel_context::updt_params() { - if (m_context.check_relation() != symbol::null) { + if (m_context.check_relation() != symbol::null && + m_context.check_relation() != symbol("null")) { + std::cout << m_context.check_relation() << "\n"; symbol cr("check_relation"); m_context.set_default_relation(cr); relation_plugin* p = get_rmanager().get_relation_plugin(cr); diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 2bdec8e01..89bf2ef54 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -63,6 +63,7 @@ namespace datalog { m_elems.push_back(fact2doc(f)); } bool udoc_relation::empty() const { + if (get_signature().empty()) return false; // TBD: make this a complete check for (unsigned i = 0; i < m_elems.size(); ++i) { if (!dm.is_empty(m_elems[i])) return false; @@ -719,29 +720,60 @@ namespace datalog { conds.push_back(g); qe::flatten_and(conds); expr* e1, *e2; - unsigned v1, v2, lo1, lo2, hi1, hi2; for (unsigned i = 0; i < conds.size(); ++i) { expr* g = conds[i].get(); - if (m.is_eq(g, e1, e2) && - is_var_range(e1, hi1, lo1, v1) && - is_var_range(e2, hi2, lo2, v2)) { - unsigned col1 = column_idx(v1); - lo1 += col1; - hi1 += col1; - unsigned col2 = column_idx(v2); - lo2 += col2; - hi2 += col2; - for (unsigned j = 0; j <= hi1-lo1; ++j) { - roots.push_back(lo1 + j); - equalities.merge(lo1 + j, lo2 + j); - } + if (m.is_eq(g, e1, e2)) { + extract_equalities(e1, e2, conds, equalities, roots); conds[i] = conds.back(); conds.pop_back(); - --i; } } rest = mk_and(m, conds.size(), conds.c_ptr()); } + + void udoc_relation::extract_equalities( + expr* e1, expr* e2, expr_ref_vector& conds, + subset_ints& equalities, unsigned_vector& roots) const { + udoc_plugin& p = get_plugin(); + ast_manager& m = p.get_ast_manager(); + bv_util& bv = p.bv; + th_rewriter rw(m); + unsigned hi, lo1, lo2, hi1, hi2, v1, v2; + if (bv.is_concat(e2)) { + std::swap(e1, e2); + } + if (bv.is_concat(e1)) { + expr_ref e3(m); + app* a1 = to_app(e1); + hi = p.num_sort_bits(e1)-1; + unsigned n = a1->get_num_args(); + for (unsigned i = 0; i < n; ++i) { + expr* e = a1->get_arg(i); + unsigned sz = p.num_sort_bits(e); + e3 = bv.mk_extract(hi, hi-sz+1, e2); + rw(e3); + extract_equalities(e, e3, conds, equalities, roots); + hi -= sz; + } + return; + } + if (is_var_range(e1, hi1, lo1, v1) && + is_var_range(e2, hi2, lo2, v2)) { + unsigned col1 = column_idx(v1); + lo1 += col1; + hi1 += col1; + unsigned col2 = column_idx(v2); + lo2 += col2; + hi2 += col2; + for (unsigned j = 0; j <= hi1-lo1; ++j) { + roots.push_back(lo1 + j); + equalities.merge(lo1 + j, lo2 + j); + } + return; + } + conds.push_back(m.mk_eq(e1, e2)); + } + void udoc_relation::compile_guard(expr* g, udoc& d, bit_vector const& discard_cols) const { d.reset(dm); d.push_back(dm.allocateX()); @@ -772,6 +804,9 @@ namespace datalog { return false; } + + + bool udoc_relation::apply_bv_eq( expr* e1, expr* e2, bit_vector const& discard_cols, udoc& result) const { udoc_plugin& p = get_plugin(); @@ -1067,6 +1102,7 @@ namespace datalog { expr_ref m_original_condition; expr_ref m_reduced_condition; udoc m_udoc; + udoc m_udoc2; bit_vector m_col_list; // map: col idx -> bool (whether the column is to be removed) svector m_to_delete; // same subset_ints m_equalities; @@ -1107,22 +1143,19 @@ namespace datalog { udoc const& u1 = t.get_udoc(); doc_manager& dm = t.get_dm(); ast_manager& m = m_reduced_condition.get_manager(); - udoc u2; - u2.copy(dm, u1); - u2.intersect(dm, m_udoc); - u2.merge(dm, m_roots, m_equalities, m_col_list); - t.apply_guard(m_reduced_condition, u2, m_equalities, m_col_list); - SASSERT(u2.well_formed(dm)); + m_udoc2.copy(dm, u1); + m_udoc2.intersect(dm, m_udoc); + t.apply_guard(m_reduced_condition, m_udoc2, m_equalities, m_col_list); + m_udoc2.merge(dm, m_roots, m_equalities, m_col_list); + SASSERT(m_udoc2.well_formed(dm)); udoc_relation* r = get(t.get_plugin().mk_empty(get_result_signature())); doc_manager& dm2 = r->get_dm(); - // std::cout << "Size of union: " << u2.size() << "\n"; - for (unsigned i = 0; i < u2.size(); ++i) { - doc* d = dm.project(dm2, m_to_delete.size(), m_to_delete.c_ptr(), u2[i]); - dm.verify_project(m, dm2, m_to_delete.c_ptr(), u2[i], *d); + for (unsigned i = 0; i < m_udoc2.size(); ++i) { + doc* d = dm.project(dm2, m_to_delete.size(), m_to_delete.c_ptr(), m_udoc2[i]); r->get_udoc().insert(dm2, d); SASSERT(r->get_udoc().well_formed(dm2)); } - u2.reset(dm); + m_udoc2.reset(dm); IF_VERBOSE(3, r->display(verbose_stream() << "filter project result:\n");); return r; } diff --git a/src/muz/rel/udoc_relation.h b/src/muz/rel/udoc_relation.h index 64ced8e83..0adc61b64 100644 --- a/src/muz/rel/udoc_relation.h +++ b/src/muz/rel/udoc_relation.h @@ -48,7 +48,7 @@ namespace datalog { virtual udoc_relation * complement(func_decl*) const; virtual void to_formula(expr_ref& fml) const; udoc_plugin& get_plugin() const; - virtual bool fast_empty() const { return m_elems.is_empty(); } + virtual bool fast_empty() const { return !get_signature().empty() && m_elems.is_empty(); } virtual bool empty() const; virtual void display(std::ostream& out) const; virtual bool is_precise() const { return true; } @@ -68,6 +68,9 @@ namespace datalog { bool is_guard(unsigned n, expr* const *g) const; void compile_guard(expr* g, udoc& result, bit_vector const& discard_cols) const; void extract_equalities(expr* g, expr_ref& rest, subset_ints& equalities, unsigned_vector& roots) const; + void extract_equalities( + expr* e1, expr* e2, expr_ref_vector& conds, + subset_ints& equalities, unsigned_vector& roots) const; void apply_guard(expr* g, udoc& result, bit_vector const& discard_cols) const; void apply_guard(expr* g, udoc& result, subset_ints const& equalities, bit_vector const& discard_cols) const; bool apply_ground_eq(doc_ref& d, unsigned v, unsigned hi, unsigned lo, expr* c) const; diff --git a/src/muz/transforms/dl_mk_interp_tail_simplifier.cpp b/src/muz/transforms/dl_mk_interp_tail_simplifier.cpp index b01b4326c..ca3042ff5 100644 --- a/src/muz/transforms/dl_mk_interp_tail_simplifier.cpp +++ b/src/muz/transforms/dl_mk_interp_tail_simplifier.cpp @@ -491,9 +491,10 @@ namespace datalog { bool mk_interp_tail_simplifier::transform_rule(rule * r0, rule_ref & res) { - rule_ref r(r0, m_context.get_rule_manager()); + rule_manager& rm = m_context.get_rule_manager(); + rule_ref r(r0, rm); - if (r->has_quantifiers()) { + if (rm.has_quantifiers(*r)) { res = r; return true; } diff --git a/src/muz/transforms/dl_mk_quantifier_instantiation.cpp b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp index afb22e55f..95d3e8e73 100644 --- a/src/muz/transforms/dl_mk_quantifier_instantiation.cpp +++ b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp @@ -252,9 +252,10 @@ namespace datalog { } bool has_quantifiers = false; unsigned sz = source.get_num_rules(); + rule_manager& rm = m_ctx.get_rule_manager(); for (unsigned i = 0; !has_quantifiers && i < sz; ++i) { rule& r = *source.get_rule(i); - has_quantifiers = has_quantifiers || r.has_quantifiers(); + has_quantifiers = has_quantifiers || rm.has_quantifiers(r); if (r.has_negation()) { return 0; } diff --git a/src/muz/transforms/dl_mk_slice.cpp b/src/muz/transforms/dl_mk_slice.cpp index f162d550f..2a49d534e 100644 --- a/src/muz/transforms/dl_mk_slice.cpp +++ b/src/muz/transforms/dl_mk_slice.cpp @@ -813,9 +813,10 @@ namespace datalog { } } - rule_set * mk_slice::operator()(rule_set const & src) { + rule_set * mk_slice::operator()(rule_set const & src) { + rule_manager& rm = m_ctx.get_rule_manager(); for (unsigned i = 0; i < src.get_num_rules(); ++i) { - if (src.get_rule(i)->has_quantifiers()) { + if (rm.has_quantifiers(*src.get_rule(i))) { return 0; } } From 6457654e2e63deb7debb75bdc5029f85265789bd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 24 Sep 2014 14:30:30 -0700 Subject: [PATCH 574/925] make self-contained bind-variables Signed-off-by: Nikolaj Bjorner --- src/muz/base/bind_variables.cpp | 154 ++++++++++++++++++++++++++++++++ src/muz/base/bind_variables.h | 51 +++++++++++ src/muz/base/dl_context.cpp | 37 +------- src/muz/base/dl_context.h | 7 +- src/muz/base/hnf.h | 43 +++++---- 5 files changed, 231 insertions(+), 61 deletions(-) create mode 100644 src/muz/base/bind_variables.cpp create mode 100644 src/muz/base/bind_variables.h diff --git a/src/muz/base/bind_variables.cpp b/src/muz/base/bind_variables.cpp new file mode 100644 index 000000000..0cc50625e --- /dev/null +++ b/src/muz/base/bind_variables.cpp @@ -0,0 +1,154 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + bind_variables.cpp + +Abstract: + + Utility to find constants that are declared as variables. + +Author: + + Nikolaj Bjorner (nbjorner) 9-24-2014 + +Notes: + + +--*/ + +#include "bind_variables.h" + +bind_variables::bind_variables(ast_manager & m): + m(m), + m_vars(m), + m_pinned(m) +{} + +bind_variables::~bind_variables() { +} + +expr_ref bind_variables::operator()(expr* fml, bool is_forall) { + if (m_vars.empty()) { + return expr_ref(fml, m); + } + SASSERT(m_pinned.empty()); + expr_ref result = abstract(fml, m_cache, 0); + if (!m_names.empty()) { + m_bound.reverse(); + m_names.reverse(); + result = m.mk_quantifier(is_forall, m_bound.size(), m_bound.c_ptr(), m_names.c_ptr(), result); + } + m_pinned.reset(); + m_cache.reset(); + m_names.reset(); + m_bound.reset(); + for (var2bound::iterator it = m_var2bound.begin(); it != m_var2bound.end(); ++it) { + it->m_value = 0; + } + return result; +} + + +expr_ref bind_variables::abstract(expr* term, cache_t& cache, unsigned scope) { + unsigned sz = m_todo.size(); + m_todo.push_back(term); + m_args.reset(); + expr* b, *arg; + while (m_todo.size() > sz) { + expr* e = m_todo.back(); + if (cache.contains(e)) { + m_todo.pop_back(); + continue; + } + switch(e->get_kind()) { + case AST_VAR: { + SASSERT(to_var(e)->get_idx() < scope); + // mixing bound variables and free is possible for the caller, + // but not proper use. + // So we assert here even though we don't check for it. + cache.insert(e, e); + m_todo.pop_back(); + break; + } + case AST_APP: { + app* a = to_app(e); + var2bound::obj_map_entry* w = m_var2bound.find_core(a); + if (w) { + var* v = w->get_data().m_value; + if (!v) { + // allocate a bound index. + v = m.mk_var(m_names.size(), m.get_sort(a)); + m_names.push_back(a->get_decl()->get_name()); + m_bound.push_back(m.get_sort(a)); + w->get_data().m_value = v; + m_pinned.push_back(v); + } + if (scope == 0) { + cache.insert(e, v); + } + else { + var* v1 = m.mk_var(scope + v->get_idx(), m.get_sort(v)); + m_pinned.push_back(v1); + cache.insert(e, v1); + } + m_todo.pop_back(); + break; + } + bool all_visited = true; + bool some_diff = false; + m_args.reset(); + for (unsigned i = 0; i < a->get_num_args(); ++i) { + arg = a->get_arg(i); + if (!cache.find(arg, b)) { + m_todo.push_back(arg); + all_visited = false; + } + else if (all_visited) { + m_args.push_back(b); + if (b != arg) { + some_diff = true; + } + } + } + if (all_visited) { + if (some_diff) { + b = m.mk_app(a->get_decl(), m_args.size(), m_args.c_ptr()); + m_pinned.push_back(b); + } + else { + b = a; + } + cache.insert(e, b); + m_todo.pop_back(); + } + break; + } + case AST_QUANTIFIER: { + quantifier* q = to_quantifier(e); + expr_ref_buffer patterns(m); + expr_ref result1(m); + unsigned new_scope = scope + q->get_num_decls(); + cache_t new_cache; + for (unsigned i = 0; i < q->get_num_patterns(); ++i) { + patterns.push_back(abstract(q->get_pattern(i), new_cache, new_scope)); + } + result1 = abstract(q->get_expr(), new_cache, new_scope); + b = m.update_quantifier(q, patterns.size(), patterns.c_ptr(), result1.get()); + m_pinned.push_back(b); + cache.insert(e, b); + m_todo.pop_back(); + break; + } + default: + UNREACHABLE(); + } + } + return expr_ref(cache.find(term), m); +} + +void bind_variables::add_var(app* v) { + m_vars.push_back(v); + m_var2bound.insert(v, 0); +} diff --git a/src/muz/base/bind_variables.h b/src/muz/base/bind_variables.h new file mode 100644 index 000000000..87b2f186b --- /dev/null +++ b/src/muz/base/bind_variables.h @@ -0,0 +1,51 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + bind_variables.h + +Abstract: + + Utility to find constants that are declard as varaibles. + +Author: + + Nikolaj Bjorner (nbjorner) 9-24-2014 + +Notes: + + +--*/ + +#ifndef _BIND_VARIABLES_H_ +#define _BIND_VARIABLES_H_ + +#include"ast.h" + +class bind_variables { + typedef obj_map var2bound; + typedef obj_map cache_t; + ast_manager& m; + app_ref_vector m_vars; + obj_map m_cache; + var2bound m_var2bound; + expr_ref_vector m_pinned; + ptr_vector m_bound; + svector m_names; + ptr_vector m_todo; + ptr_vector m_args; + + + + expr_ref abstract(expr* fml, cache_t& cache, unsigned scope); +public: + bind_variables(ast_manager & m); + ~bind_variables(); + + expr_ref operator()(expr* fml, bool is_forall); + + void add_var(app* v); +}; + +#endif /* _BIND_VARIABLES_H_ */ diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 2b3b70a41..f79a65705 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -210,14 +210,12 @@ namespace datalog { m_rewriter(m), m_var_subst(m), m_rule_manager(*this), - m_elim_unused_vars(m), - m_abstractor(m), m_contains_p(*this), m_check_pred(m_contains_p, m), m_transf(*this), m_trail(*this), m_pinned(m), - m_vars(m), + m_bind_variables(m), m_rule_set(*this), m_transformed_rule_set(*this), m_rule_fmls_head(0), @@ -323,40 +321,11 @@ namespace datalog { } void context::register_variable(func_decl* var) { - m_vars.push_back(m.mk_const(var)); + m_bind_variables.add_var(m.mk_const(var)); } expr_ref context::bind_variables(expr* fml, bool is_forall) { - expr_ref result(m); - app_ref_vector const & vars = m_vars; - rule_manager& rm = get_rule_manager(); - if (vars.empty()) { - result = fml; - } - else { - m_names.reset(); - m_abstractor(0, vars.size(), reinterpret_cast(vars.c_ptr()), fml, result); - m_free_vars(result); - if (m_free_vars.empty()) { - result = fml; - } - else { - m_free_vars.set_default_sort(m.mk_bool_sort()); - for (unsigned i = 0; i < m_free_vars.size(); ++i) { - if (i < vars.size()) { - m_names.push_back(vars[i]->get_decl()->get_name()); - } - else { - m_names.push_back(symbol(i)); - } - } - quantifier_ref q(m); - m_free_vars.reverse(); - q = m.mk_quantifier(is_forall, m_free_vars.size(), m_free_vars.c_ptr(), m_names.c_ptr(), result); - m_elim_unused_vars(q, result); - } - } - return result; + return m_bind_variables(fml, is_forall); } void context::register_predicate(func_decl * decl, bool named) { diff --git a/src/muz/base/dl_context.h b/src/muz/base/dl_context.h index 67520d94f..85d4b7c0e 100644 --- a/src/muz/base/dl_context.h +++ b/src/muz/base/dl_context.h @@ -39,9 +39,9 @@ Revision History: #include"model2expr.h" #include"smt_params.h" #include"dl_rule_transformer.h" -#include"expr_abstract.h" #include"expr_functors.h" #include"dl_engine_base.h" +#include"bind_variables.h" struct fixedpoint_params; @@ -178,15 +178,12 @@ namespace datalog { th_rewriter m_rewriter; var_subst m_var_subst; rule_manager m_rule_manager; - unused_vars_eliminator m_elim_unused_vars; - expr_abstractor m_abstractor; contains_pred m_contains_p; check_pred m_check_pred; rule_transformer m_transf; trail_stack m_trail; ast_ref_vector m_pinned; - app_ref_vector m_vars; - svector m_names; + bind_variables m_bind_variables; sort_domain_map m_sorts; func_decl_set m_preds; sym2decl m_preds_by_name; diff --git a/src/muz/base/hnf.h b/src/muz/base/hnf.h index 37339540b..9dc7cccd9 100644 --- a/src/muz/base/hnf.h +++ b/src/muz/base/hnf.h @@ -1,37 +1,36 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - hnf.h - -Abstract: - - Horn normal form convertion. -Author: - - -Notes: - - Very similar to NNF. +/*-- + Module Name: + + hnf.h + + Abstract: + + Horn normal form convertion. + Author: + + + Notes: + + Very similar to NNF. + --*/ - + #ifndef _HNF_H_ #define _HNF_H_ - + #include"ast.h" #include"params.h" #include"defined_names.h" #include"proof_converter.h" - + class hnf { class imp; imp * m_imp; -public: + public: hnf(ast_manager & m); ~hnf(); - + void operator()(expr * n, // [IN] expression that should be put into Horn NF proof* p, // [IN] proof of n expr_ref_vector & rs, // [OUT] resultant (conjunction) of expressions @@ -45,5 +44,5 @@ public: void reset(); func_decl_ref_vector const& get_fresh_predicates(); }; - + #endif /* _HNF_H_ */ From 979d1f913a336a98a804ef6108b4704eb25effb1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 24 Sep 2014 16:46:00 -0700 Subject: [PATCH 575/925] fix bug in union_fn: delta should not be reset, it is shared among several union computations Signed-off-by: Nikolaj Bjorner --- src/muz/rel/check_relation.cpp | 65 ++++++++++++++------------ src/muz/rel/check_relation.h | 4 +- src/muz/rel/dl_compiler.cpp | 84 +++++++++++++++++----------------- src/muz/rel/dl_instruction.cpp | 2 +- src/muz/rel/rel_context.cpp | 2 +- src/muz/rel/udoc_relation.cpp | 6 +-- 6 files changed, 86 insertions(+), 77 deletions(-) diff --git a/src/muz/rel/check_relation.cpp b/src/muz/rel/check_relation.cpp index 98a0635fe..f67c5be3c 100644 --- a/src/muz/rel/check_relation.cpp +++ b/src/muz/rel/check_relation.cpp @@ -17,8 +17,8 @@ namespace datalog { check_relation::~check_relation() { m_relation->deallocate(); } - void check_relation::check_equiv(expr* f1, expr* f2) const { - get_plugin().check_equiv(f1, f2); + void check_relation::check_equiv(char const* objective, expr* f1, expr* f2) const { + get_plugin().check_equiv(objective, f1, f2); } void check_relation::consistent_formula() { expr_ref fml(m); @@ -53,7 +53,7 @@ namespace datalog { m_relation->add_fact(f); m_relation->to_formula(fml1); m_fml = m.mk_or(m_fml, mk_eq(f)); - check_equiv(ground(m_fml), ground(fml1)); + check_equiv("add_fact", ground(m_fml), ground(fml1)); m_fml = fml1; } void check_relation::add_new_fact(const relation_fact & f) { @@ -61,20 +61,20 @@ namespace datalog { m_relation->add_new_fact(f); m_relation->to_formula(fml1); m_fml = m.mk_or(m_fml, mk_eq(f)); - check_equiv(ground(m_fml), ground(fml1)); + check_equiv("add_fact", ground(m_fml), ground(fml1)); m_fml = fml1; } bool check_relation::empty() const { bool result = m_relation->empty(); if (result && !m.is_false(m_fml)) { - check_equiv(m.mk_false(), ground(m_fml)); + check_equiv("empty", m.mk_false(), ground(m_fml)); } return result; } bool check_relation::fast_empty() const { bool result = m_relation->fast_empty(); if (result && !m.is_false(m_fml)) { - check_equiv(m.mk_false(), ground(m_fml)); + check_equiv("fast_empty", m.mk_false(), ground(m_fml)); } return result; } @@ -89,10 +89,10 @@ namespace datalog { fml1 = mk_eq(f); fml2 = m.mk_and(m_fml, fml1); if (result) { - check_equiv(ground(fml1), ground(fml2)); + check_equiv("contains fact", ground(fml1), ground(fml2)); } else if (!m.is_false(m_fml)) { - check_equiv(ground(fml2), m.mk_false()); + check_equiv("contains fact", ground(fml2), m.mk_false()); } return result; } @@ -102,7 +102,7 @@ namespace datalog { result->m_relation = m_relation->clone(); result->m_relation->to_formula(result->m_fml); if (m_fml != result->m_fml) { - check_equiv(ground(m_fml), ground(result->m_fml)); + check_equiv("clone", ground(m_fml), ground(result->m_fml)); } return result; } @@ -113,7 +113,7 @@ namespace datalog { result->m_relation->to_formula(result->m_fml); expr_ref fml(m); fml = m.mk_not(m_fml); - check_equiv(ground(fml), ground(result->m_fml)); + check_equiv("complement", ground(fml), ground(result->m_fml)); return result; } void check_relation::to_formula(expr_ref& fml) const { @@ -153,11 +153,19 @@ namespace datalog { } relation_base * check_relation_plugin::mk_empty(const relation_signature & sig) { relation_base* r = m_base->mk_empty(sig); - return alloc(check_relation, *this, sig, r); + check_relation* result = alloc(check_relation, *this, sig, r); + if (result->m_fml != m.mk_false()) { + check_equiv("mk_empty", result->ground(result->m_fml), m.mk_false()); + } + return result; } relation_base * check_relation_plugin::mk_full(func_decl* p, const relation_signature & s) { relation_base* r = m_base->mk_full(p, s); - return alloc(check_relation, *this, s, r); + check_relation* result = alloc(check_relation, *this, s, r); + if (result->m_fml != m.mk_true()) { + check_equiv("mk_full", result->ground(result->m_fml), m.mk_true()); + } + return result; } class check_relation_plugin::join_fn : public convenient_relation_join_fn { @@ -239,7 +247,7 @@ namespace datalog { sub(f2, vars2.size(), vars2.c_ptr(), fml2); bound.reverse(); fml1 = m.mk_exists(bound.size(), bound.c_ptr(), names.c_ptr(), fml1); - check_equiv(fml1, fml2); + check_equiv("project", fml1, fml2); } void check_relation_plugin::verify_permutation( @@ -277,7 +285,7 @@ namespace datalog { subst(fml1, vars.size(), vars.c_ptr(), fml1); subst(fml2, vars.size(), vars.c_ptr(), fml2); - check_equiv(fml1, fml2); + check_equiv("permutation", fml1, fml2); } void check_relation_plugin::verify_join(relation_base const& t1, relation_base const& t2, relation_base const& t, @@ -314,7 +322,7 @@ namespace datalog { } sub(fml1, vars.size(), vars.c_ptr(), fml1); sub(fml3, vars.size(), vars.c_ptr(), fml3); - check_equiv(fml1, fml3); + check_equiv("join", fml1, fml3); } void check_relation_plugin::verify_filter(expr* fml0, relation_base const& t, expr* cond) { @@ -332,10 +340,10 @@ namespace datalog { } sub(fml1, vars.size(), vars.c_ptr(), fml1); sub(fml2, vars.size(), vars.c_ptr(), fml2); - check_equiv(fml1, fml2); + check_equiv("filter", fml1, fml2); } - void check_relation_plugin::check_equiv(expr* fml1, expr* fml2) { + void check_relation_plugin::check_equiv(char const* objective, expr* fml1, expr* fml2) { TRACE("doc", tout << mk_pp(fml1, m) << "\n"; tout << mk_pp(fml2, m) << "\n";); smt_params fp; @@ -345,7 +353,7 @@ namespace datalog { solver.assert_expr(tmp); lbool res = solver.check(); if (res == l_false) { - IF_VERBOSE(3, verbose_stream() << "verified\n";); + IF_VERBOSE(3, verbose_stream() << objective << " verified\n";); } else { IF_VERBOSE(3, verbose_stream() << "NOT verified " << res << "\n"; @@ -371,23 +379,24 @@ namespace datalog { sub(fml1, vars.size(), vars.c_ptr(), fml1); sub(fml2, vars.size(), vars.c_ptr(), fml2); - check_equiv(fml1, fml2); + check_equiv("union", fml1, fml2); if (delta) { delta->to_formula(fml3); - // dst >= delta >= dst \ fml0 + IF_VERBOSE(3, verbose_stream() << "verify delta\n"; + verbose_stream() << fml3 << "\n";); + // delta >= dst \ fml0 // dst \ fml0 == delta & dst & \ fml0 - // dst & delta = delta expr_ref fml4(m), fml5(m); fml4 = m.mk_and(fml2, m.mk_not(fml0)); fml5 = m.mk_and(fml3, fml4); sub(fml4, vars.size(), vars.c_ptr(), fml4); sub(fml5, vars.size(), vars.c_ptr(), fml5); - check_equiv(fml4, fml5); - fml4 = m.mk_and(fml3, fml2); - sub(fml3, vars.size(), vars.c_ptr(), fml3); - sub(fml4, vars.size(), vars.c_ptr(), fml4); - check_equiv(fml3, fml4); + check_equiv("union delta low", fml4, fml5); + //fml4 = m.mk_and(fml3, fml2); + //sub(fml3, vars.size(), vars.c_ptr(), fml3); + //sub(fml4, vars.size(), vars.c_ptr(), fml4); + //check_equiv("union delta high", fml3, fml4); } } @@ -560,7 +569,7 @@ namespace datalog { expr_ref fml = t.m_fml; t.rb().to_formula(t.m_fml); fml = p.m.mk_and(fml, p.m.mk_eq(p.m.mk_var(m_col, t.get_signature()[m_col]), m_val)); - p.check_equiv(t.ground(fml), t.ground(t.m_fml)); + p.check_equiv("filter_equal", t.ground(fml), t.ground(t.m_fml)); } }; relation_mutator_fn * check_relation_plugin::mk_filter_equal_fn( @@ -586,11 +595,11 @@ namespace datalog { } virtual void operator()(relation_base& tb, const relation_base& negb) { + IF_VERBOSE(0, verbose_stream() << "TBD: verify filter_negation\n";); check_relation& t = get(tb); check_relation const& n = get(negb); check_relation_plugin& p = t.get_plugin(); (*m_filter)(t.rb(), n.rb()); - IF_VERBOSE(0, verbose_stream() << "TBD: verify filter_negation\n";); t.rb().to_formula(t.m_fml); } }; diff --git a/src/muz/rel/check_relation.h b/src/muz/rel/check_relation.h index 2856bf3a0..9a59772ef 100644 --- a/src/muz/rel/check_relation.h +++ b/src/muz/rel/check_relation.h @@ -34,7 +34,7 @@ namespace datalog { ast_manager& m; relation_base* m_relation; expr_ref m_fml; - void check_equiv(expr* f1, expr* f2) const; + void check_equiv(char const* objective, expr* f1, expr* f2) const; expr_ref mk_eq(relation_fact const& f) const; public: check_relation(check_relation_plugin& p, relation_signature const& s, relation_base* r); @@ -137,7 +137,7 @@ namespace datalog { - void check_equiv(expr* f1, expr* f2); + void check_equiv(char const* objective, expr* f1, expr* f2); }; diff --git a/src/muz/rel/dl_compiler.cpp b/src/muz/rel/dl_compiler.cpp index 4f8be942d..705644340 100644 --- a/src/muz/rel/dl_compiler.cpp +++ b/src/muz/rel/dl_compiler.cpp @@ -589,49 +589,8 @@ namespace datalog { dealloc = true; } - //enforce negative predicates - unsigned ut_len=r->get_uninterpreted_tail_size(); - for(unsigned i=pt_len; iget_tail(i); - func_decl * neg_pred = neg_tail->get_decl(); - variable_intersection neg_intersection(m_context.get_manager()); - neg_intersection.populate(single_res_expr, neg_tail); - unsigned_vector t_cols(neg_intersection.size(), neg_intersection.get_cols1()); - unsigned_vector neg_cols(neg_intersection.size(), neg_intersection.get_cols2()); - - unsigned neg_len = neg_tail->get_num_args(); - for(unsigned i=0; iget_arg(i); - if(is_var(e)) { - continue; - } - SASSERT(is_app(e)); - relation_sort arg_sort; - m_context.get_rel_context()->get_rmanager().from_predicate(neg_pred, i, arg_sort); - reg_idx new_reg; - bool new_dealloc; - make_add_constant_column(head_pred, filtered_res, arg_sort, to_app(e), new_reg, new_dealloc, acc); - - if (dealloc) - make_dealloc_non_void(filtered_res, acc); - dealloc = new_dealloc; - filtered_res = new_reg; // here filtered_res value gets changed !! - - t_cols.push_back(single_res_expr.size()); - neg_cols.push_back(i); - single_res_expr.push_back(e); - } - SASSERT(t_cols.size()==neg_cols.size()); - - reg_idx neg_reg = m_pred_regs.find(neg_pred); - if (!dealloc) - make_clone(filtered_res, filtered_res, acc); - acc.push_back(instruction::mk_filter_by_negation(filtered_res, neg_reg, t_cols.size(), - t_cols.c_ptr(), neg_cols.c_ptr())); - dealloc = true; - } - // enforce interpreted tail predicates + unsigned ut_len=r->get_uninterpreted_tail_size(); unsigned ft_len = r->get_tail_size(); // full tail ptr_vector tail; for (unsigned tail_index = ut_len; tail_index < ft_len; ++tail_index) { @@ -737,6 +696,47 @@ namespace datalog { dealloc = true; } + //enforce negative predicates + for (unsigned i = pt_len; iget_tail(i); + func_decl * neg_pred = neg_tail->get_decl(); + variable_intersection neg_intersection(m_context.get_manager()); + neg_intersection.populate(single_res_expr, neg_tail); + unsigned_vector t_cols(neg_intersection.size(), neg_intersection.get_cols1()); + unsigned_vector neg_cols(neg_intersection.size(), neg_intersection.get_cols2()); + + unsigned neg_len = neg_tail->get_num_args(); + for (unsigned i = 0; iget_arg(i); + if (is_var(e)) { + continue; + } + SASSERT(is_app(e)); + relation_sort arg_sort; + m_context.get_rel_context()->get_rmanager().from_predicate(neg_pred, i, arg_sort); + reg_idx new_reg; + bool new_dealloc; + make_add_constant_column(head_pred, filtered_res, arg_sort, to_app(e), new_reg, new_dealloc, acc); + + if (dealloc) + make_dealloc_non_void(filtered_res, acc); + dealloc = new_dealloc; + filtered_res = new_reg; // here filtered_res value gets changed !! + + t_cols.push_back(single_res_expr.size()); + neg_cols.push_back(i); + single_res_expr.push_back(e); + } + SASSERT(t_cols.size() == neg_cols.size()); + + reg_idx neg_reg = m_pred_regs.find(neg_pred); + if (!dealloc) + make_clone(filtered_res, filtered_res, acc); + acc.push_back(instruction::mk_filter_by_negation(filtered_res, neg_reg, t_cols.size(), + t_cols.c_ptr(), neg_cols.c_ptr())); + dealloc = true; + } + #if 0 // this version is potentially better for non-symbolic tables, // since it constraints each unbound column at a time (reducing the diff --git a/src/muz/rel/dl_instruction.cpp b/src/muz/rel/dl_instruction.cpp index bf2f09d56..fc8ceadce 100644 --- a/src/muz/rel/dl_instruction.cpp +++ b/src/muz/rel/dl_instruction.cpp @@ -346,7 +346,7 @@ namespace datalog { print_container(m_controls, out); } virtual void display_body_impl(rel_context_base const & ctx, std::ostream & out, std::string indentation) const { - m_body->display_indented(ctx, out, indentation+" "); + // m_body->display_indented(ctx, out, indentation+" "); } }; diff --git a/src/muz/rel/rel_context.cpp b/src/muz/rel/rel_context.cpp index 6454da2a2..36ba98781 100644 --- a/src/muz/rel/rel_context.cpp +++ b/src/muz/rel/rel_context.cpp @@ -157,6 +157,7 @@ namespace datalog { break; } TRACE("dl", m_context.display(tout);); + //IF_VERBOSE(3, m_context.display_smt2(0,0,verbose_stream());); if (m_context.get_params().print_aig().size()) { const char *filename = static_cast(m_context.get_params().print_aig().c_ptr()); @@ -580,7 +581,6 @@ namespace datalog { void rel_context::updt_params() { if (m_context.check_relation() != symbol::null && m_context.check_relation() != symbol("null")) { - std::cout << m_context.check_relation() << "\n"; symbol cr("check_relation"); m_context.set_default_relation(cr); relation_plugin* p = get_rmanager().get_relation_plugin(cr); diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 89bf2ef54..5f3d6288d 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -561,11 +561,9 @@ namespace datalog { udoc_relation* d = get(_delta); doc_manager& dm = r.get_dm(); ast_manager& m = r.get_plugin().get_ast_manager(); - expr_ref fml0(m); - DEBUG_CODE(r.to_formula(fml0);); udoc* d1 = 0; if (d) d1 = &d->get_udoc(); - if (d1) d1->reset(dm); + IF_VERBOSE(3, r.display(verbose_stream() << "orig: ");); r.get_plugin().mk_union(dm, r.get_udoc(), src.get_udoc(), d1); SASSERT(r.get_udoc().well_formed(dm)); SASSERT(!d1 || d1->well_formed(dm)); @@ -1051,6 +1049,7 @@ namespace datalog { } std::swap(dst, result); if (dst.is_empty()) { + IF_VERBOSE(3, tb.display(verbose_stream());); return; } @@ -1070,6 +1069,7 @@ namespace datalog { TRACE("doc", dst.display(dm, tout) << "\n";); SASSERT(dst.well_formed(dm)); renamed_neg.reset(t.get_dm()); + IF_VERBOSE(3, tb.display(verbose_stream());); } void copy_column( doc& dst, doc const& src, From 9cea3a1c021ec580c76eaac36232d77731f9488d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 24 Sep 2014 22:08:49 -0700 Subject: [PATCH 576/925] last? bug-fix to new udoc_relation for feature parity Signed-off-by: Nikolaj Bjorner --- src/muz/rel/check_relation.cpp | 110 +++++++++++++++++++++++++++------ src/muz/rel/check_relation.h | 13 ++-- src/muz/rel/doc.cpp | 26 +++++++- src/muz/rel/doc.h | 13 +++- src/muz/rel/tbv.cpp | 27 +++++++- src/muz/rel/tbv.h | 4 ++ src/muz/rel/udoc_relation.cpp | 110 ++++++++++++++++++++++----------- 7 files changed, 240 insertions(+), 63 deletions(-) diff --git a/src/muz/rel/check_relation.cpp b/src/muz/rel/check_relation.cpp index f67c5be3c..e779a42c4 100644 --- a/src/muz/rel/check_relation.cpp +++ b/src/muz/rel/check_relation.cpp @@ -3,6 +3,7 @@ #include "qe_util.h" #include "ast_util.h" #include "smt_kernel.h" +#include namespace datalog { @@ -343,6 +344,12 @@ namespace datalog { check_equiv("filter", fml1, fml2); } + void check_relation_plugin::check_contains(char const* objective, expr* fml1, expr* fml2) { + expr_ref fml0(m); + fml0 = m.mk_and(fml1, fml2); + check_equiv(objective, fml0, fml2); + } + void check_relation_plugin::check_equiv(char const* objective, expr* fml1, expr* fml2) { TRACE("doc", tout << mk_pp(fml1, m) << "\n"; tout << mk_pp(fml2, m) << "\n";); @@ -358,16 +365,20 @@ namespace datalog { else { IF_VERBOSE(3, verbose_stream() << "NOT verified " << res << "\n"; verbose_stream() << mk_pp(fml1, m) << "\n"; - verbose_stream() << mk_pp(fml2, m) << "\n";); + verbose_stream() << mk_pp(fml2, m) << "\n"; + verbose_stream().flush(); + ); throw 0; } } - void check_relation_plugin::verify_union(expr* fml0, relation_base const& src, relation_base const& dst, relation_base const* delta) { - expr_ref fml1(m), fml2(m), fml3(m); + void check_relation_plugin::verify_union(expr* dst0, relation_base const& src, + relation_base const& dst, + expr* delta0, relation_base const* delta) { + expr_ref fml1(m), fml2(m); src.to_formula(fml1); dst.to_formula(fml2); - fml1 = m.mk_or(fml1, fml0); + fml1 = m.mk_or(fml1, dst0); relation_signature const& sig = dst.get_signature(); expr_ref_vector vars(m); var_subst sub(m, false); @@ -382,21 +393,30 @@ namespace datalog { check_equiv("union", fml1, fml2); if (delta) { - delta->to_formula(fml3); - IF_VERBOSE(3, verbose_stream() << "verify delta\n"; - verbose_stream() << fml3 << "\n";); - // delta >= dst \ fml0 - // dst \ fml0 == delta & dst & \ fml0 + expr_ref d0(m), d(m); + delta->to_formula(d); + IF_VERBOSE(3, verbose_stream() << "verify delta " << d << "\n";); + // delta >= dst \ dst0 + // dst \ dst0 == delta & dst & \ dst0 expr_ref fml4(m), fml5(m); - fml4 = m.mk_and(fml2, m.mk_not(fml0)); - fml5 = m.mk_and(fml3, fml4); + fml4 = m.mk_and(fml2, m.mk_not(dst0)); + sub(fml4, vars.size(), vars.c_ptr(), fml4); + sub(d, vars.size(), vars.c_ptr(), d); + check_contains("union_delta low", d, fml4); + // + // delta >= delta0 + // + sub(delta0, vars.size(), vars.c_ptr(), d0); + check_contains("union delta0", d, d0); + + // + // dst u delta0 = delta u dst0 + // + fml4 = m.mk_or(fml2, delta0); + fml5 = m.mk_or(d, dst0); sub(fml4, vars.size(), vars.c_ptr(), fml4); sub(fml5, vars.size(), vars.c_ptr(), fml5); - check_equiv("union delta low", fml4, fml5); - //fml4 = m.mk_and(fml3, fml2); - //sub(fml3, vars.size(), vars.c_ptr(), fml3); - //sub(fml4, vars.size(), vars.c_ptr(), fml4); - //check_equiv("union delta high", fml3, fml4); + check_equiv("union no overflow", fml4, fml5); } } @@ -411,8 +431,10 @@ namespace datalog { check_relation const& src = get(_src); check_relation* d = get(_delta); expr_ref fml0 = r.m_fml; + expr_ref delta0(r.m_fml.get_manager()); + if (d) d->to_formula(delta0); (*m_union)(r.rb(), src.rb(), d?(&d->rb()):0); - r.get_plugin().verify_union(fml0, src.rb(), r.rb(), d?(&d->rb()):0); + r.get_plugin().verify_union(fml0, src.rb(), r.rb(), delta0, d?(&d->rb()):0); r.rb().to_formula(r.m_fml); if (d) d->rb().to_formula(d->m_fml); } @@ -595,12 +617,15 @@ namespace datalog { } virtual void operator()(relation_base& tb, const relation_base& negb) { - IF_VERBOSE(0, verbose_stream() << "TBD: verify filter_negation\n";); check_relation& t = get(tb); check_relation const& n = get(negb); check_relation_plugin& p = t.get_plugin(); + ast_manager& m = p.get_ast_manager(); + expr_ref dst0(m); + t.to_formula(dst0); (*m_filter)(t.rb(), n.rb()); t.rb().to_formula(t.m_fml); + p.verify_filter_by_negation(dst0, t, n, m_t_cols, m_neg_cols); } }; @@ -608,10 +633,57 @@ namespace datalog { const relation_base& t, const relation_base& neg, unsigned joined_col_cnt, const unsigned *t_cols, const unsigned *negated_cols) { - relation_intersection_filter_fn* f = mk_filter_by_negation_fn(get(t).rb(), get(neg).rb(), joined_col_cnt, t_cols, negated_cols); + relation_intersection_filter_fn* f = m_base->mk_filter_by_negation_fn(get(t).rb(), get(neg).rb(), joined_col_cnt, t_cols, negated_cols); return f?alloc(negation_filter_fn, f, joined_col_cnt, t_cols, negated_cols):0; } + /* + The filter_by_negation postcondition: + filter_by_negation(tgt, neg, columns in tgt: c1,...,cN, + corresponding columns in neg: d1,...,dN): + tgt_1:={x: x\in tgt_0 && ! \exists y: ( y \in neg & pi_c1(x)= pi_d1(y) & ... & pi_cN(x)= pi_dN(y) ) } + */ + + void check_relation_plugin::verify_filter_by_negation( + expr* dst0, + check_relation const& dst, + check_relation const& neg, + unsigned_vector const& cols1, + unsigned_vector const& cols2) { + relation_signature const& sig1 = dst.get_signature(); + relation_signature const& sig2 = neg.get_signature(); + expr_ref dstf(m), negf(m); + std::cout << mk_pp(dst0, m) << "\n"; + expr_ref_vector eqs(m); + dst.to_formula(dstf); + std::cout << mk_pp(dstf, m) << "\n"; + dst.to_formula(negf); + std::cout << mk_pp(negf, m) << "\n"; + eqs.push_back(negf); + for (unsigned i = 0; i < cols1.size(); ++i) { + var_ref v1(m), v2(m); + unsigned c1 = cols1[i]; + unsigned c2 = cols2[i]; + SASSERT(sig1[c1] == sig2[c2]); + v1 = m.mk_var(sig2.size() + c1, sig1[c1]); + v2 = m.mk_var(c2, sig2[c2]); + eqs.push_back(m.mk_eq(v1, v2)); + } + negf = mk_and(m, eqs.size(), eqs.c_ptr()); + ptr_vector rev_sig2(sig2.size(), sig2.c_ptr()); + rev_sig2.reverse(); + svector names; + for (unsigned i = 0; i < sig2.size(); ++i) { + names.push_back(symbol(i)); + } + negf = m.mk_exists(rev_sig2.size(), rev_sig2.c_ptr(), names.c_ptr(), negf); + negf = m.mk_and(dst0, m.mk_not(negf)); + negf = dst.ground(negf); + dstf = dst.ground(dstf); + std::cout << negf << "\n"; + std::cout << dstf << "\n"; + check_equiv("filter by negation", dstf, negf); + } class check_relation_plugin::filter_proj_fn : public convenient_relation_project_fn { app_ref m_cond; diff --git a/src/muz/rel/check_relation.h b/src/muz/rel/check_relation.h index 9a59772ef..016751184 100644 --- a/src/muz/rel/check_relation.h +++ b/src/muz/rel/check_relation.h @@ -115,7 +115,7 @@ namespace datalog { void verify_filter(expr* fml0, relation_base const& t, expr* cond); void verify_union(expr* fml0, relation_base const& src, relation_base const& dst, - relation_base const* delta); + expr* delta0, relation_base const* delta); void verify_permutation( relation_base const& src, relation_base const& dst, @@ -135,11 +135,16 @@ namespace datalog { relation_base const& src, relation_base const& dst, app* cond, unsigned_vector const& removed_cols); - - void check_equiv(char const* objective, expr* f1, expr* f2); - + void check_contains(char const* objective, expr* f1, expr* f2); + + void verify_filter_by_negation( + expr* dst0, + check_relation const& dst, + check_relation const& neg, + unsigned_vector const& dst_eq, + unsigned_vector const& neg_eq); }; }; diff --git a/src/muz/rel/doc.cpp b/src/muz/rel/doc.cpp index 938f39aed..e2c0ab162 100644 --- a/src/muz/rel/doc.cpp +++ b/src/muz/rel/doc.cpp @@ -552,11 +552,33 @@ bool doc_manager::contains(doc const& a, doc const& b) const { } return true; } + +bool doc_manager::contains( + unsigned offset_a, doc const& a, + doc_manager const& dm_b, + unsigned offset_b, doc const& b, + unsigned length) const { + if (!m.contains(offset_a, a.pos(), dm_b.tbvm(), offset_b, b.pos(), length)) return false; + for (unsigned i = 0; i < a.neg().size(); ++i) { + bool found = false; + for (unsigned j = 0; !found && j < b.neg().size(); ++j) { + found = dm_b.tbvm().contains(offset_b, b.neg()[j], tbvm(), offset_a, a.neg()[i], length); + } + if (!found) return false; + } + return true; +} + std::ostream& doc_manager::display(std::ostream& out, doc const& b) const { - m.display(out, b.pos()); + if (num_tbits() == 0) return out << "[]"; + return display(out, b, num_tbits()-1, 0); +} + +std::ostream& doc_manager::display(std::ostream& out, doc const& b, unsigned hi, unsigned lo) const { + m.display(out, b.pos(), hi, lo); if (b.neg().is_empty()) return out; out << " \\ "; - b.neg().display(m, out); + b.neg().display(m, out, hi, lo); return out; } diff --git a/src/muz/rel/doc.h b/src/muz/rel/doc.h index 3be31ead7..16e7c5f28 100644 --- a/src/muz/rel/doc.h +++ b/src/muz/rel/doc.h @@ -53,6 +53,7 @@ public: doc_manager(unsigned num_bits); ~doc_manager(); tbv_manager& tbvm() { return m; } + tbv_manager const& tbvm() const { return m; } doc* allocate(); doc* allocate1(); doc* allocate0(); @@ -81,7 +82,11 @@ public: bool equals(doc const& a, doc const& b) const; unsigned hash(doc const& src) const; bool contains(doc const& a, doc const& b) const; + bool contains(unsigned offset_a, doc const& a, + doc_manager const& dm_b, unsigned offset_b, doc const& b, + unsigned length) const; std::ostream& display(std::ostream& out, doc const& b) const; + std::ostream& display(std::ostream& out, doc const& b, unsigned hi, unsigned lo) const; unsigned num_tbits() const { return m.num_tbits(); } doc* project(doc_manager& dstm, unsigned n, bool const* to_delete, doc const& src); bool well_formed(doc const& d) const; @@ -123,10 +128,16 @@ public: return false; } std::ostream& display(M const& m, std::ostream& out) const { + if (m.num_tbits() == 0) return out << "[]"; + return display(m, out, m.num_tbits()-1, 0); + } + std::ostream& display(M const& m, std::ostream& out, unsigned hi, unsigned lo) const { out << "{"; + if (size() + m.num_tbits() > 10) out << "\n "; for (unsigned i = 0; i < size(); ++i) { - m.display(out, *m_elems[i]); + m.display(out, *m_elems[i], hi, lo); if (i + 1 < size()) out << ", "; + if (i + 1 < size() && m.num_tbits() > 10) out << "\n "; } return out << "}"; } diff --git a/src/muz/rel/tbv.cpp b/src/muz/rel/tbv.cpp index 391445215..739443ea0 100644 --- a/src/muz/rel/tbv.cpp +++ b/src/muz/rel/tbv.cpp @@ -244,13 +244,31 @@ unsigned tbv_manager::hash(tbv const& src) const { bool tbv_manager::contains(tbv const& a, tbv const& b) const { return m.contains(a, b); } + +bool tbv_manager::contains(unsigned offset_a, tbv const& a, + tbv_manager const& dm_b, unsigned offset_b, tbv const& b, + unsigned length) const { + if (this == &dm_b && length == num_tbits()) { + SASSERT(offset_a == 0); + SASSERT(offset_b == 0); + return m.contains(a, b); + } + for (unsigned i = 0; i < length; ++i) { + tbit bit_a = a[offset_a + i]; + if (bit_a == BIT_x) continue; + if (bit_a != b[offset_b + i]) return false; + } + return true; +} + bool tbv_manager::intersect(tbv const& a, tbv const& b, tbv& result) { copy(result, a); return set_and(result, b); } -std::ostream& tbv_manager::display(std::ostream& out, tbv const& b) const { - for (unsigned i = 0; i < num_tbits(); ++i) { +std::ostream& tbv_manager::display(std::ostream& out, tbv const& b, unsigned hi, unsigned lo) const { + SASSERT(lo <= hi && hi < num_tbits()); + for (unsigned i = lo; i <= hi; ++i) { switch (b.get(i)) { case BIT_0: out << '0'; @@ -271,6 +289,11 @@ std::ostream& tbv_manager::display(std::ostream& out, tbv const& b) const { return out; } +std::ostream& tbv_manager::display(std::ostream& out, tbv const& b) const { + if (num_tbits() == 0) return out << "[]"; + return display(out, b, num_tbits()-1, 0); +} + expr_ref tbv_manager::to_formula(ast_manager& m, tbv const& src) { expr_ref result(m); expr_ref_vector conj(m); diff --git a/src/muz/rel/tbv.h b/src/muz/rel/tbv.h index 454cbae37..9663f7d04 100644 --- a/src/muz/rel/tbv.h +++ b/src/muz/rel/tbv.h @@ -70,8 +70,12 @@ public: bool equals(tbv const& a, tbv const& b) const; unsigned hash(tbv const& src) const; bool contains(tbv const& a, tbv const& b) const; + bool contains(unsigned offset_a, tbv const& a, + tbv_manager const& dm_b, unsigned offset_b, tbv const& b, + unsigned length) const; bool intersect(tbv const& a, tbv const& b, tbv& result); std::ostream& display(std::ostream& out, tbv const& b) const; + std::ostream& display(std::ostream& out, tbv const& b, unsigned hi, unsigned lo) const; tbv* project(unsigned n, bool const* to_delete, tbv const& src); bool is_well_formed(tbv const& b) const; // - does not contain BIT_z; void set(tbv& dst, uint64 n, unsigned hi, unsigned lo); diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 5f3d6288d..b862781b7 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -1003,9 +1003,18 @@ namespace datalog { return check_kind(t)?alloc(filter_interpreted_fn, get(t), get_ast_manager(), condition):0; } + // + // Notes: + // 1. this code could use some cleanup and simplification. + // 2. It is also not very efficient in the copy routines. + // They fall back to copying each bit instead of a chunk. + // 3. Argument about correctness is needed as comments. + // 4. Unit/stress test cases are needed. + // class udoc_plugin::negation_filter_fn : public relation_intersection_filter_fn { const unsigned_vector m_t_cols; const unsigned_vector m_neg_cols; + public: negation_filter_fn(const udoc_relation & r, const udoc_relation & neg, unsigned joined_col_cnt, const unsigned *t_cols, const unsigned *neg_cols) @@ -1018,72 +1027,103 @@ namespace datalog { udoc_relation const& n = get(negb); udoc & dst = t.get_udoc(); udoc const & neg = n.get_udoc(); - doc_manager& dm = t.get_dm(); + doc_manager& dmt = t.get_dm(); + doc_manager& dmn = n.get_dm(); + IF_VERBOSE(3, t.display(verbose_stream() << "dst:");); + IF_VERBOSE(3, n.display(verbose_stream() << "neg:");); + udoc result; for (unsigned i = 0; i < dst.size(); ++i) { - bool done_i = false; - for (unsigned j = 0; !done_i && j < neg.size(); ++j) { - bool done_j = false; - for (unsigned c = 0; !done_j && c < m_t_cols.size(); ++c) { + for (unsigned j = 0; j < neg.size(); ++j) { + for (unsigned c = 0; c < m_t_cols.size(); ++c) { unsigned t_col = m_t_cols[c]; unsigned n_col = m_neg_cols[c]; unsigned num_bits = t.column_num_bits(t_col); SASSERT(num_bits == n.column_num_bits(n_col)); unsigned t_idx = t.column_idx(t_col); unsigned n_idx = n.column_idx(n_col); - for (unsigned k = 0; !done_j && k < num_bits; ++k) { - tbit n_bit = neg[j][n_idx + k]; - tbit d_bit = dst[i][t_idx + k]; - // neg does not contain dst. - done_j = (n_bit != BIT_x && n_bit != d_bit); + bool cont = dmn.contains(n_idx, neg[j], dmt, t_idx, dst[i], num_bits); + IF_VERBOSE( + 3, + dmt.display(verbose_stream() << "dst:", dst[i], t_idx+num_bits-1,t_idx) << "\n"; + dmn.display(verbose_stream() << "neg:", neg[j], n_idx+num_bits-1,n_idx) << "\n"; + verbose_stream() << "contains: " << (cont?"true":"false") << "\n";); + if (!cont) { + goto next_neg_disj; } } - if (done_j) { - result.push_back(&dst[i]); - done_i = true; - } - } - if (!done_i) { - dm.deallocate(&dst[i]); + dmt.deallocate(&dst[i]); + goto next_disj; + next_neg_disj:; } + result.push_back(&dst[i]); + next_disj:; } std::swap(dst, result); if (dst.is_empty()) { - IF_VERBOSE(3, tb.display(verbose_stream());); + IF_VERBOSE(3, tb.display(verbose_stream() << "fast empty");); return; } // slow case udoc renamed_neg; for (unsigned i = 0; i < neg.size(); ++i) { - doc_ref newD(dm, dm.allocateX()); - for (unsigned j = 0; j < m_neg_cols.size(); ++j) { - copy_column(*newD, neg[i], m_t_cols[j], m_neg_cols[j], t, n); + doc& neg_i = neg[i]; + doc_ref newD(dmt, dmt.allocateX()); + copy_columns(newD->pos(), neg_i.pos(), t, n); + bool is_empty = false; + for (unsigned j = 0; !is_empty && j < neg_i.neg().size(); ++j) { + tbv_ref newT(dmt.tbvm(), dmt.tbvm().allocateX()); + copy_columns(*newT, neg_i.neg()[j], t, n); + if (dmt.tbvm().equals(newD->pos(), *newT)) { + is_empty = true; + } + else { + newD->neg().push_back(newT.detach()); + } + } + if (!is_empty) { + IF_VERBOSE(3, + dmn.display(verbose_stream() << "copy neg: ", neg_i) << "\n"; + dmt.display(verbose_stream() << "to dst: ", *newD) << "\n";); + renamed_neg.push_back(newD.detach()); } - renamed_neg.push_back(newD.detach()); } - TRACE("doc", dst.display(dm, tout) << "\n"; - renamed_neg.display(dm, tout) << "\n"; + TRACE("doc", dst.display(dmt, tout) << "\n"; + renamed_neg.display(dmt, tout) << "\n"; ); - dst.subtract(dm, renamed_neg); - TRACE("doc", dst.display(dm, tout) << "\n";); - SASSERT(dst.well_formed(dm)); - renamed_neg.reset(t.get_dm()); - IF_VERBOSE(3, tb.display(verbose_stream());); + dst.subtract(dmt, renamed_neg); + // TBD: double check semantics + TRACE("doc", dst.display(dmt, tout) << "\n";); + SASSERT(dst.well_formed(dmt)); + renamed_neg.reset(dmt); + IF_VERBOSE(3, tb.display(verbose_stream() << "slow case:");); + } + void copy_columns( + tbv& dst, tbv const& src, + udoc_relation const& dstt, + udoc_relation const& srct) + { + unsigned num_cols = m_t_cols.size(); + for (unsigned i = 0; i < num_cols; ++i) { + copy_column(dst, src, m_t_cols[i], m_neg_cols[i], dstt, srct); + } } void copy_column( - doc& dst, doc const& src, + tbv& dst, tbv const& src, unsigned col_dst, unsigned col_src, udoc_relation const& dstt, udoc_relation const& srct) { - doc_manager& dm = dstt.get_dm(); + tbv_manager& dm = dstt.get_dm().tbvm(); unsigned idx_dst = dstt.column_idx(col_dst); unsigned idx_src = srct.column_idx(col_src); - unsigned num_bits = dstt.column_num_bits(col_dst); + unsigned num_tbits = dstt.column_num_bits(col_dst); SASSERT(num_bits == srct.column_num_bits(col_src)); - for (unsigned i = 0; i < num_bits; ++i) { - dm.set(dst, idx_dst+i, src[idx_src+i]); - } + IF_VERBOSE(3, verbose_stream() << "copy column " << idx_src + << " to " << idx_dst << " " << num_tbits << "\n";); + for (unsigned i = 0; i < num_tbits; ++i) { + dm.set(dst, idx_dst + i, src[idx_src + i]); + } } }; From 4a710cf86d7075f5d667726398a1df5ca5e5dccf Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 17 Sep 2014 16:33:27 +0100 Subject: [PATCH 577/925] sync with unstable (port bugfix) Signed-off-by: Nuno Lopes --- src/muz/rel/dl_compiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/rel/dl_compiler.cpp b/src/muz/rel/dl_compiler.cpp index 705644340..c512598a0 100644 --- a/src/muz/rel/dl_compiler.cpp +++ b/src/muz/rel/dl_compiler.cpp @@ -590,7 +590,7 @@ namespace datalog { } // enforce interpreted tail predicates - unsigned ut_len=r->get_uninterpreted_tail_size(); + unsigned ut_len = r->get_uninterpreted_tail_size(); unsigned ft_len = r->get_tail_size(); // full tail ptr_vector tail; for (unsigned tail_index = ut_len; tail_index < ft_len; ++tail_index) { From 41d7c50e29912289f8065ff68b913ddce17d6d25 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 25 Sep 2014 14:10:17 +0100 Subject: [PATCH 578/925] fix debug build Signed-off-by: Nuno Lopes --- src/muz/rel/udoc_relation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index b862781b7..75fb03c9e 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -1118,7 +1118,7 @@ namespace datalog { unsigned idx_dst = dstt.column_idx(col_dst); unsigned idx_src = srct.column_idx(col_src); unsigned num_tbits = dstt.column_num_bits(col_dst); - SASSERT(num_bits == srct.column_num_bits(col_src)); + SASSERT(num_tbits == srct.column_num_bits(col_src)); IF_VERBOSE(3, verbose_stream() << "copy column " << idx_src << " to " << idx_dst << " " << num_tbits << "\n";); for (unsigned i = 0; i < num_tbits; ++i) { From 84a61b54543d798015ce83df4d50e03ad1f1a67f Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 25 Sep 2014 14:36:37 +0100 Subject: [PATCH 579/925] reenable datalog while loop priting Signed-off-by: Nuno Lopes --- src/muz/rel/dl_instruction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/rel/dl_instruction.cpp b/src/muz/rel/dl_instruction.cpp index fc8ceadce..bf2f09d56 100644 --- a/src/muz/rel/dl_instruction.cpp +++ b/src/muz/rel/dl_instruction.cpp @@ -346,7 +346,7 @@ namespace datalog { print_container(m_controls, out); } virtual void display_body_impl(rel_context_base const & ctx, std::ostream & out, std::string indentation) const { - // m_body->display_indented(ctx, out, indentation+" "); + m_body->display_indented(ctx, out, indentation+" "); } }; From aaa931e0d53533665db4814fd1bb238014ee409b Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 25 Sep 2014 15:56:01 +0100 Subject: [PATCH 580/925] fix build with gcc Signed-off-by: Nuno Lopes --- src/muz/base/dl_context.cpp | 4 ++-- src/muz/base/dl_context.h | 2 +- src/muz/base/dl_rule.cpp | 2 +- src/muz/fp/dl_cmds.cpp | 4 ++-- src/muz/rel/product_set.h | 1 - src/smt/theory_arith_core.h | 2 +- 6 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index f79a65705..aa415d187 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -324,7 +324,7 @@ namespace datalog { m_bind_variables.add_var(m.mk_const(var)); } - expr_ref context::bind_variables(expr* fml, bool is_forall) { + expr_ref context::bind_vars(expr* fml, bool is_forall) { return m_bind_variables(fml, is_forall); } @@ -1078,7 +1078,7 @@ namespace datalog { void context::get_raw_rule_formulas(expr_ref_vector& rules, svector& names){ for (unsigned i = 0; i < m_rule_fmls.size(); ++i) { - expr_ref r = bind_variables(m_rule_fmls[i].get(), true); + expr_ref r = bind_vars(m_rule_fmls[i].get(), true); rules.push_back(r.get()); // rules.push_back(m_rule_fmls[i].get()); names.push_back(m_rule_names[i]); diff --git a/src/muz/base/dl_context.h b/src/muz/base/dl_context.h index 85d4b7c0e..e96752721 100644 --- a/src/muz/base/dl_context.h +++ b/src/muz/base/dl_context.h @@ -287,7 +287,7 @@ namespace datalog { universal (if is_forall is true) or existential quantifier. */ - expr_ref bind_variables(expr* fml, bool is_forall); + expr_ref bind_vars(expr* fml, bool is_forall); /** Register datalog relation. diff --git a/src/muz/base/dl_rule.cpp b/src/muz/base/dl_rule.cpp index 2015d4eea..c4a14845d 100644 --- a/src/muz/base/dl_rule.cpp +++ b/src/muz/base/dl_rule.cpp @@ -370,7 +370,7 @@ namespace datalog { } void rule_manager::bind_variables(expr* fml, bool is_forall, expr_ref& result) { - result = m_ctx.bind_variables(fml, is_forall); + result = m_ctx.bind_vars(fml, is_forall); } void rule_manager::flatten_body(app_ref_vector& body) { diff --git a/src/muz/fp/dl_cmds.cpp b/src/muz/fp/dl_cmds.cpp index 9807cec4a..bb9a1bc10 100644 --- a/src/muz/fp/dl_cmds.cpp +++ b/src/muz/fp/dl_cmds.cpp @@ -103,7 +103,7 @@ struct dl_context { void add_rule(expr * rule, symbol const& name) { init(); if (m_collected_cmds) { - expr_ref rl = m_context->bind_variables(rule, true); + expr_ref rl = m_context->bind_vars(rule, true); m_collected_cmds->m_rules.push_back(rl); m_collected_cmds->m_names.push_back(name); m_trail.push(push_back_vector(m_collected_cmds->m_rules)); @@ -116,7 +116,7 @@ struct dl_context { bool collect_query(expr* q) { if (m_collected_cmds) { - expr_ref qr = m_context->bind_variables(q, false); + expr_ref qr = m_context->bind_vars(q, false); m_collected_cmds->m_queries.push_back(qr); m_trail.push(push_back_vector(m_collected_cmds->m_queries)); return true; diff --git a/src/muz/rel/product_set.h b/src/muz/rel/product_set.h index ebfe339fe..238a33d8a 100644 --- a/src/muz/rel/product_set.h +++ b/src/muz/rel/product_set.h @@ -248,7 +248,6 @@ namespace datalog { class product_set_factory { - friend class product_set_factory; unsigned char m_data[0]; public: enum initial_t { diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 9dae2d0c4..d2e0c27a4 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -959,7 +959,7 @@ namespace smt { typename atoms::iterator hi_inf1 = begin2, hi_sup1 = begin2; bool flo_inf, fhi_inf, flo_sup, fhi_sup; // std::cout << atoms.size() << "\n"; - ptr_addr_hashtable visited; + ptr_addr_hashtable visited; for (unsigned i = 0; i < atoms.size(); ++i) { atom* a1 = atoms[i]; lo_inf1 = next_inf(a1, A_LOWER, lo_inf, end, flo_inf); From b7397b696716008d2552566597e66da2144958e5 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 25 Sep 2014 16:27:20 +0100 Subject: [PATCH 581/925] relations with no columns are not always non-empty. fix that in the udoc datalog backend Signed-off-by: Nuno Lopes --- src/muz/rel/udoc_relation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 75fb03c9e..1e448f861 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -63,7 +63,7 @@ namespace datalog { m_elems.push_back(fact2doc(f)); } bool udoc_relation::empty() const { - if (get_signature().empty()) return false; + if (m_elems.is_empty()) return true; // TBD: make this a complete check for (unsigned i = 0; i < m_elems.size(); ++i) { if (!dm.is_empty(m_elems[i])) return false; From a2d8fd4c4b5f415edc35dd0d3e71181b52da862e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 25 Sep 2014 09:33:12 -0700 Subject: [PATCH 582/925] local opts Signed-off-by: Nikolaj Bjorner --- src/muz/base/dl_context.cpp | 50 +++++++++++++++++++++++++++++++++++++ src/muz/base/dl_rule.cpp | 11 ++++---- 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index f79a65705..a3ab9a1c2 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -639,6 +639,56 @@ namespace datalog { } } +#if 0 + void context::check_rules(rule_set& r) { + switch(get_engine()) { + case DATALOG_ENGINE: + collect_properties(r); + check_quantifier_free(r); + check_uninterpreted_free(r); + check_existential_tail(r); + break; + case PDR_ENGINE: + check_existential_tail(r); + check_positive_predicates(r); + check_uninterpreted_free(r); + break; + case QPDR_ENGINE: + check_positive_predicates(r); + check_uninterpreted_free(r); + break; + case BMC_ENGINE: + check_positive_predicates(r); + break; + case QBMC_ENGINE: + check_existential_tail(r); + check_positive_predicates(r); + break; + case TAB_ENGINE: + check_existential_tail(r); + check_positive_predicates(r); + break; + case DUALITY_ENGINE: + check_existential_tail(r); + check_positive_predicates(r); + break; + case CLP_ENGINE: + check_existential_tail(r); + check_positive_predicates(r); + break; + case DDNF_ENGINE: + break; + case LAST_ENGINE: + default: + UNREACHABLE(); + break; + } + if (generate_proof_trace() && !r.get_proof()) { + m_rule_manager.mk_rule_asserted_proof(r); + } + } +#endif + void context::check_rule(rule& r) { switch(get_engine()) { case DATALOG_ENGINE: diff --git a/src/muz/base/dl_rule.cpp b/src/muz/base/dl_rule.cpp index 2015d4eea..ee14898ab 100644 --- a/src/muz/base/dl_rule.cpp +++ b/src/muz/base/dl_rule.cpp @@ -252,17 +252,16 @@ namespace datalog { unsigned rule_manager::extract_horn(expr* fml, app_ref_vector& body, app_ref& head) { expr* e1, *e2; - unsigned index = m_counter.get_next_var(fml); if (::is_forall(fml)) { - index += to_quantifier(fml)->get_num_decls(); fml = to_quantifier(fml)->get_expr(); } + unsigned index = m_counter.get_next_var(fml); if (m.is_implies(fml, e1, e2)) { - expr_ref_vector es(m); + m_args.reset(); head = ensure_app(e2); - qe::flatten_and(e1, es); - for (unsigned i = 0; i < es.size(); ++i) { - body.push_back(ensure_app(es[i].get())); + qe::flatten_and(e1, m_args); + for (unsigned i = 0; i < m_args.size(); ++i) { + body.push_back(ensure_app(m_args[i].get())); } } else { From 74053275cf466fbc1e8d80455f8df89f740d3156 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 25 Sep 2014 19:05:49 -0700 Subject: [PATCH 583/925] consolidate rule checking in separate class Signed-off-by: Nikolaj Bjorner --- src/muz/base/dl_context.cpp | 209 +++++-------------------------- src/muz/base/dl_context.h | 32 +++-- src/muz/base/rule_properties.cpp | 189 ++++++++++++++++++++++++++++ src/muz/base/rule_properties.h | 60 +++++++++ src/test/dl_query.cpp | 5 +- 5 files changed, 297 insertions(+), 198 deletions(-) create mode 100644 src/muz/base/rule_properties.cpp create mode 100644 src/muz/base/rule_properties.h diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index c2e58a9e7..f19fae369 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -211,7 +211,7 @@ namespace datalog { m_var_subst(m), m_rule_manager(*this), m_contains_p(*this), - m_check_pred(m_contains_p, m), + m_rule_properties(m, m_rule_manager, *this, m_contains_p), m_transf(*this), m_trail(*this), m_pinned(m), @@ -452,10 +452,7 @@ namespace datalog { rm.mk_rule(fml, p, m_rule_set, m_rule_names[m_rule_fmls_head]); ++m_rule_fmls_head; } - rule_set::iterator it = m_rule_set.begin(), end = m_rule_set.end(); - for (; it != end; ++it) { - check_rule(*(*it)); - } + check_rules(m_rule_set); } // @@ -541,140 +538,49 @@ namespace datalog { m_engine->add_cover(level, pred, property); } - void context::check_uninterpreted_free(rule& r) { - func_decl* f = 0; - if (get_rule_manager().has_uninterpreted_non_predicates(r, f)) { - std::stringstream stm; - stm << "Uninterpreted '" - << f->get_name() - << "' in "; - r.display(*this, stm); - throw default_exception(stm.str()); - } - } - - void context::check_quantifier_free(rule& r) { - if (get_rule_manager().has_quantifiers(r)) { - std::stringstream stm; - stm << "cannot process quantifiers in rule "; - r.display(*this, stm); - throw default_exception(stm.str()); - } - } - - - void context::check_existential_tail(rule& r) { - unsigned ut_size = r.get_uninterpreted_tail_size(); - unsigned t_size = r.get_tail_size(); - - TRACE("dl", get_rule_manager().display_smt2(r, tout); tout << "\n";); - for (unsigned i = ut_size; i < t_size; ++i) { - app* t = r.get_tail(i); - TRACE("dl", tout << "checking: " << mk_ismt2_pp(t, get_manager()) << "\n";); - if (m_check_pred(t)) { - std::ostringstream out; - out << "interpreted body " << mk_ismt2_pp(t, get_manager()) << " contains recursive predicate"; - throw default_exception(out.str()); - } - } - } - - void context::check_positive_predicates(rule& r) { - ast_mark visited; - ptr_vector todo, tocheck; - unsigned ut_size = r.get_uninterpreted_tail_size(); - unsigned t_size = r.get_tail_size(); - for (unsigned i = 0; i < ut_size; ++i) { - if (r.is_neg_tail(i)) { - tocheck.push_back(r.get_tail(i)); - } - } - ast_manager& m = get_manager(); - contains_pred contains_p(*this); - check_pred check_pred(contains_p, get_manager()); - - for (unsigned i = ut_size; i < t_size; ++i) { - todo.push_back(r.get_tail(i)); - } - while (!todo.empty()) { - expr* e = todo.back(), *e1, *e2; - todo.pop_back(); - if (visited.is_marked(e)) { - continue; - } - visited.mark(e, true); - if (is_predicate(e)) { - } - else if (m.is_and(e) || m.is_or(e)) { - todo.append(to_app(e)->get_num_args(), to_app(e)->get_args()); - } - else if (m.is_implies(e, e1, e2)) { - tocheck.push_back(e1); - todo.push_back(e2); - } - else if (is_quantifier(e)) { - todo.push_back(to_quantifier(e)->get_expr()); - } - else if ((m.is_eq(e, e1, e2) || m.is_iff(e, e1, e2)) && - m.is_true(e1)) { - todo.push_back(e2); - } - else if ((m.is_eq(e, e1, e2) || m.is_iff(e, e1, e2)) && - m.is_true(e2)) { - todo.push_back(e1); - } - else { - tocheck.push_back(e); - } - } - for (unsigned i = 0; i < tocheck.size(); ++i) { - expr* e = tocheck[i]; - if (check_pred(e)) { - std::ostringstream out; - out << "recursive predicate " << mk_ismt2_pp(e, get_manager()) << " occurs nested in body"; - r.display(*this, out << "\n"); - throw default_exception(out.str()); - - } - } - } - -#if 0 void context::check_rules(rule_set& r) { + m_rule_properties.set_generate_proof(generate_proof_trace()); switch(get_engine()) { - case DATALOG_ENGINE: - collect_properties(r); - check_quantifier_free(r); - check_uninterpreted_free(r); - check_existential_tail(r); + case DATALOG_ENGINE: + m_rule_properties.collect(r); + m_rule_properties.check_quantifier_free(); + m_rule_properties.check_uninterpreted_free(); + m_rule_properties.check_nested_free(); break; case PDR_ENGINE: - check_existential_tail(r); - check_positive_predicates(r); - check_uninterpreted_free(r); + m_rule_properties.collect(r); + m_rule_properties.check_existential_tail(); + m_rule_properties.check_for_negated_predicates(); + m_rule_properties.check_uninterpreted_free(); break; case QPDR_ENGINE: - check_positive_predicates(r); - check_uninterpreted_free(r); + m_rule_properties.collect(r); + m_rule_properties.check_for_negated_predicates(); + m_rule_properties.check_uninterpreted_free(); break; case BMC_ENGINE: - check_positive_predicates(r); + m_rule_properties.collect(r); + m_rule_properties.check_for_negated_predicates(); break; case QBMC_ENGINE: - check_existential_tail(r); - check_positive_predicates(r); + m_rule_properties.collect(r); + m_rule_properties.check_existential_tail(); + m_rule_properties.check_for_negated_predicates(); break; case TAB_ENGINE: - check_existential_tail(r); - check_positive_predicates(r); + m_rule_properties.collect(r); + m_rule_properties.check_existential_tail(); + m_rule_properties.check_for_negated_predicates(); break; case DUALITY_ENGINE: - check_existential_tail(r); - check_positive_predicates(r); + m_rule_properties.collect(r); + m_rule_properties.check_existential_tail(); + m_rule_properties.check_for_negated_predicates(); break; case CLP_ENGINE: - check_existential_tail(r); - check_positive_predicates(r); + m_rule_properties.collect(r); + m_rule_properties.check_existential_tail(); + m_rule_properties.check_for_negated_predicates(); break; case DDNF_ENGINE: break; @@ -683,57 +589,6 @@ namespace datalog { UNREACHABLE(); break; } - if (generate_proof_trace() && !r.get_proof()) { - m_rule_manager.mk_rule_asserted_proof(r); - } - } -#endif - - void context::check_rule(rule& r) { - switch(get_engine()) { - case DATALOG_ENGINE: - check_quantifier_free(r); - check_uninterpreted_free(r); - check_existential_tail(r); - break; - case PDR_ENGINE: - check_existential_tail(r); - check_positive_predicates(r); - check_uninterpreted_free(r); - break; - case QPDR_ENGINE: - check_positive_predicates(r); - check_uninterpreted_free(r); - break; - case BMC_ENGINE: - check_positive_predicates(r); - break; - case QBMC_ENGINE: - check_existential_tail(r); - check_positive_predicates(r); - break; - case TAB_ENGINE: - check_existential_tail(r); - check_positive_predicates(r); - break; - case DUALITY_ENGINE: - check_existential_tail(r); - check_positive_predicates(r); - break; - case CLP_ENGINE: - check_existential_tail(r); - check_positive_predicates(r); - break; - case DDNF_ENGINE: - break; - case LAST_ENGINE: - default: - UNREACHABLE(); - break; - } - if (generate_proof_trace() && !r.get_proof()) { - m_rule_manager.mk_rule_asserted_proof(r); - } } void context::add_rule(rule_ref& r) { @@ -984,11 +839,7 @@ namespace datalog { // TODO: what? if(get_engine() != DUALITY_ENGINE) { new_query(); - rule_set::iterator it = m_rule_set.begin(), end = m_rule_set.end(); - rule_ref r(m_rule_manager); - for (; it != end; ++it) { - check_rule(*(*it)); - } + check_rules(m_rule_set); } #endif m_mc = mk_skip_model_converter(); diff --git a/src/muz/base/dl_context.h b/src/muz/base/dl_context.h index e96752721..285726026 100644 --- a/src/muz/base/dl_context.h +++ b/src/muz/base/dl_context.h @@ -42,6 +42,7 @@ Revision History: #include"expr_functors.h" #include"dl_engine_base.h" #include"bind_variables.h" +#include"rule_properties.h" struct fixedpoint_params; @@ -141,6 +142,17 @@ namespace datalog { SK_UINT64, SK_SYMBOL }; + class contains_pred : public i_expr_pred { + context const& ctx; + public: + contains_pred(context& ctx): ctx(ctx) {} + virtual ~contains_pred() {} + + virtual bool operator()(expr* e) { + return ctx.is_predicate(e); + } + }; + private: class sort_domain; @@ -154,17 +166,6 @@ namespace datalog { typedef obj_map > pred2syms; typedef obj_map sort_domain_map; - class contains_pred : public i_expr_pred { - context const& ctx; - public: - contains_pred(context& ctx): ctx(ctx) {} - virtual ~contains_pred() {} - - virtual bool operator()(expr* e) { - return ctx.is_predicate(e); - } - }; - ast_manager & m; register_engine_base& m_register_engine; @@ -179,7 +180,7 @@ namespace datalog { var_subst m_var_subst; rule_manager m_rule_manager; contains_pred m_contains_p; - check_pred m_check_pred; + rule_properties m_rule_properties; rule_transformer m_transf; trail_stack m_trail; ast_ref_vector m_pinned; @@ -419,7 +420,7 @@ namespace datalog { /** \brief Check if rule is well-formed according to engine. */ - void check_rule(rule& r); + void check_rules(rule_set& r); /** \brief Return true if facts to \c pred can be added using the \c add_table_fact() function. @@ -565,11 +566,6 @@ namespace datalog { void ensure_engine(); - void check_quantifier_free(rule& r); - void check_uninterpreted_free(rule& r); - void check_existential_tail(rule& r); - void check_positive_predicates(rule& r); - // auxilary functions for SMT2 pretty-printer. void declare_vars(expr_ref_vector& rules, mk_fresh_name& mk_fresh, std::ostream& out); diff --git a/src/muz/base/rule_properties.cpp b/src/muz/base/rule_properties.cpp new file mode 100644 index 000000000..7f019c74e --- /dev/null +++ b/src/muz/base/rule_properties.cpp @@ -0,0 +1,189 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + rule_properties.cpp + +Abstract: + + Collect properties of rules. + +Author: + + Nikolaj Bjorner (nbjorner) 9-25-2014 + +Notes: + + +--*/ + +#include"expr_functors.h" +#include"rule_properties.h" +#include"dl_rule_set.h" +#include"for_each_expr.h" +#include"dl_context.h" + +using namespace datalog; +rule_properties::rule_properties(ast_manager & m, rule_manager& rm, context& ctx, i_expr_pred& p): + m(m), rm(rm), m_ctx(ctx), m_is_predicate(p), m_dt(m), m_generate_proof(false) {} + +rule_properties::~rule_properties() {} + +void rule_properties::collect(rule_set const& rules) { + reset(); + rule_set::iterator it = rules.begin(), end = rules.end(); + expr_sparse_mark visited; + for (; it != end; ++it) { + rule* r = *it; + m_rule = r; + unsigned ut_size = r->get_uninterpreted_tail_size(); + unsigned t_size = r->get_tail_size(); + if (r->has_negation()) { + m_negative_rules.push_back(r); + } + for (unsigned i = ut_size; i < t_size; ++i) { + for_each_expr_core(*this, visited, r->get_tail(i)); + } + if (m_generate_proof && !r->get_proof()) { + rm.mk_rule_asserted_proof(*r); + } + } +} + +void rule_properties::check_quantifier_free() { + if (!m_quantifiers.empty()) { + quantifier* q = m_quantifiers.begin()->m_key; + rule* r = m_quantifiers.begin()->m_value; + std::stringstream stm; + stm << "cannot process quantifier in rule "; + r->display(m_ctx, stm); + throw default_exception(stm.str()); + } +} + +void rule_properties::check_for_negated_predicates() { + if (!m_negative_rules.empty()) { + rule* r = m_negative_rules[0]; + std::stringstream stm; + stm << "Rule contains negative predicate "; + r->display(m_ctx, stm); + throw default_exception(stm.str()); + } +} + + +void rule_properties::check_uninterpreted_free() { + if (!m_uninterp_funs.empty()) { + func_decl* f = m_uninterp_funs.begin()->m_key; + rule* r = m_uninterp_funs.begin()->m_value; + std::stringstream stm; + stm << "Uninterpreted '" + << f->get_name() + << "' in "; + r->display(m_ctx, stm); + throw default_exception(stm.str()); + } +} + +void rule_properties::check_nested_free() { + if (!m_interp_pred.empty()) { + std::stringstream stm; + rule* r = m_interp_pred[0]; + stm << "Rule contains nested predicates "; + r->display(m_ctx, stm); + throw default_exception(stm.str()); + + } +} + +void rule_properties::check_existential_tail() { + ast_mark visited; + ptr_vector todo, tocheck; + for (unsigned i = 0; i < m_interp_pred.size(); ++i) { + rule& r = *m_interp_pred[i]; + unsigned ut_size = r.get_uninterpreted_tail_size(); + unsigned t_size = r.get_tail_size(); + for (unsigned i = ut_size; i < t_size; ++i) { + todo.push_back(r.get_tail(i)); + } + } + context::contains_pred contains_p(m_ctx); + check_pred check_pred(contains_p, m); + + while (!todo.empty()) { + expr* e = todo.back(), *e1, *e2; + todo.pop_back(); + if (visited.is_marked(e)) { + continue; + } + visited.mark(e, true); + if (m_is_predicate(e)) { + } + else if (m.is_and(e) || m.is_or(e)) { + todo.append(to_app(e)->get_num_args(), to_app(e)->get_args()); + } + else if (m.is_implies(e, e1, e2)) { + tocheck.push_back(e1); + todo.push_back(e2); + } + else if (is_quantifier(e)) { + todo.push_back(to_quantifier(e)->get_expr()); + } + else if ((m.is_eq(e, e1, e2) || m.is_iff(e, e1, e2)) && + m.is_true(e1)) { + todo.push_back(e2); + } + else if ((m.is_eq(e, e1, e2) || m.is_iff(e, e1, e2)) && + m.is_true(e2)) { + todo.push_back(e1); + } + else { + tocheck.push_back(e); + } + } + for (unsigned i = 0; i < tocheck.size(); ++i) { + expr* e = tocheck[i]; + if (check_pred(e)) { + std::ostringstream out; + out << "recursive predicate " << mk_ismt2_pp(e, m) << " occurs nested in the body of a rule"; + throw default_exception(out.str()); + } + } +} + + +void rule_properties::insert(ptr_vector& rules, rule* r) { + if (rules.empty() || rules.back() != r) { + rules.push_back(r); + } +} + +void rule_properties::operator()(var* n) { } + +void rule_properties::operator()(quantifier* n) { + m_quantifiers.insert(n, m_rule); +} +void rule_properties::operator()(app* n) { + if (m_is_predicate(n)) { + insert(m_interp_pred, m_rule); + } + else if (is_uninterp(n)) { + m_uninterp_funs.insert(n->get_decl(), m_rule); + } + else if (m_dt.is_accessor(n)) { + sort* s = m.get_sort(n->get_arg(0)); + SASSERT(m_dt.is_datatype(s)); + if (m_dt.get_datatype_constructors(s)->size() > 1) { + m_uninterp_funs.insert(n->get_decl(), m_rule); + } + } +} + +void rule_properties::reset() { + m_quantifiers.reset(); + m_uninterp_funs.reset(); + m_interp_pred.reset(); + m_negative_rules.reset(); +} + diff --git a/src/muz/base/rule_properties.h b/src/muz/base/rule_properties.h new file mode 100644 index 000000000..bfff8cbe4 --- /dev/null +++ b/src/muz/base/rule_properties.h @@ -0,0 +1,60 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + rule_properties.h + +Abstract: + + Collect properties of rules. + +Author: + + Nikolaj Bjorner (nbjorner) 9-25-2014 + +Notes: + + +--*/ + +#ifndef _RULE_PROPERTIES_H_ +#define _RULE_PROPERTIES_H_ + +#include"ast.h" +#include"datatype_decl_plugin.h" +#include"dl_rule.h" + +namespace datalog { + class rule_properties { + ast_manager& m; + rule_manager& rm; + context& m_ctx; + i_expr_pred& m_is_predicate; + datatype_util m_dt; + bool m_generate_proof; + rule* m_rule; + obj_map m_quantifiers; + obj_map m_uninterp_funs; + ptr_vector m_interp_pred; + ptr_vector m_negative_rules; + + void insert(ptr_vector& rules, rule* r); + public: + rule_properties(ast_manager & m, rule_manager& rm, context& ctx, i_expr_pred& is_predicate); + ~rule_properties(); + void set_generate_proof(bool generate_proof) { m_generate_proof = generate_proof; } + void collect(rule_set const& r); + void check_quantifier_free(); + void check_uninterpreted_free(); + void check_existential_tail(); + void check_for_negated_predicates(); + void check_nested_free(); + void operator()(var* n); + void operator()(quantifier* n); + void operator()(app* n); + void reset(); + }; +} + +#endif /* _RULE_PROPERTIES_H_ */ diff --git a/src/test/dl_query.cpp b/src/test/dl_query.cpp index bb991c65f..4aba180f6 100644 --- a/src/test/dl_query.cpp +++ b/src/test/dl_query.cpp @@ -143,8 +143,11 @@ void dl_query_test_wpa(smt_params & fparams, params_ref& params) { ctx.updt_params(params); { wpa_parser* p = wpa_parser::create(ctx, m); - TRUSTME( p->parse_directory(problem_dir) ); + bool = ok = p->parse_directory(problem_dir); dealloc(p); + if (!ok) { + std::cout << "Could not parse: " << problem_dir << "\n"; + } } const unsigned attempts = 10; From 061a18efcf5c6c39503e2e0b74508d953fb0eb9c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 26 Sep 2014 08:22:25 -0700 Subject: [PATCH 584/925] move some configuration parameters into dl_context, add notes to udoc_relation Signed-off-by: Nikolaj Bjorner --- src/muz/base/dl_context.cpp | 6 ++- src/muz/base/dl_context.h | 11 +++-- src/muz/bmc/dl_bmc_engine.cpp | 3 +- src/muz/fp/horn_tactic.cpp | 4 +- src/muz/pdr/pdr_context.cpp | 2 +- src/muz/pdr/pdr_prop_solver.cpp | 5 +-- src/muz/pdr/pdr_prop_solver.h | 3 +- src/muz/rel/rel_context.cpp | 9 ++-- src/muz/rel/udoc_relation.cpp | 62 ++++++++++++++++++++++++++ src/muz/tab/tab_context.cpp | 2 +- src/muz/transforms/dl_mk_bit_blast.cpp | 2 +- 11 files changed, 86 insertions(+), 23 deletions(-) diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index f19fae369..1271532db 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -278,6 +278,7 @@ namespace datalog { symbol context::default_table() const { return m_params->datalog_default_table(); } symbol context::default_relation() const { return m_default_relation; } void context::set_default_relation(symbol const& s) { m_default_relation = s; } + symbol context::print_aig() const { return m_params->print_aig(); } symbol context::check_relation() const { return m_params->datalog_check_relation(); } symbol context::default_table_checker() const { return m_params->datalog_default_table_checker(); } bool context::default_table_checked() const { return m_params->datalog_default_table_checked(); } @@ -294,8 +295,9 @@ namespace datalog { bool context::generate_explanations() const { return m_params->datalog_generate_explanations(); } bool context::explanations_on_relation_level() const { return m_params->datalog_explanations_on_relation_level(); } bool context::magic_sets_for_queries() const { return m_params->datalog_magic_sets_for_queries(); } - - bool context::bit_blast() const { return m_params->xform_bit_blast(); } + symbol context::tab_selection() const { return m_params->tab_selection(); } + bool context::xform_slice() const { return m_params->xform_slice(); } + bool context::xform_bit_blast() const { return m_params->xform_bit_blast(); } bool context::karr() const { return m_params->xform_karr(); } bool context::scale() const { return m_params->xform_scale(); } bool context::magic() const { return m_params->xform_magic(); } diff --git a/src/muz/base/dl_context.h b/src/muz/base/dl_context.h index 285726026..10b93a4c1 100644 --- a/src/muz/base/dl_context.h +++ b/src/muz/base/dl_context.h @@ -172,9 +172,9 @@ namespace datalog { smt_params & m_fparams; params_ref m_params_ref; fixedpoint_params* m_params; - bool m_generate_proof_trace; - bool m_unbound_compressor; - symbol m_default_relation; + bool m_generate_proof_trace; // cached configuration parameter + bool m_unbound_compressor; // cached configuration parameter + symbol m_default_relation; // cached configuration parameter dl_decl_util m_decl_util; th_rewriter m_rewriter; var_subst m_var_subst; @@ -260,18 +260,21 @@ namespace datalog { bool unbound_compressor() const; void set_unbound_compressor(bool f); bool similarity_compressor() const; + symbol print_aig() const; + symbol tab_selection() const; unsigned similarity_compressor_threshold() const; unsigned soft_timeout() const; unsigned initial_restart_timeout() const; bool generate_explanations() const; bool explanations_on_relation_level() const; bool magic_sets_for_queries() const; - bool bit_blast() const; bool karr() const; bool scale() const; bool magic() const; bool quantify_arrays() const; bool instantiate_quantifiers() const; + bool xform_bit_blast() const; + bool xform_slice() const; void register_finite_sort(sort * s, sort_kind k); diff --git a/src/muz/bmc/dl_bmc_engine.cpp b/src/muz/bmc/dl_bmc_engine.cpp index 2b970e4fa..57e4ba8cb 100644 --- a/src/muz/bmc/dl_bmc_engine.cpp +++ b/src/muz/bmc/dl_bmc_engine.cpp @@ -32,7 +32,6 @@ Revision History: #include "dl_transforms.h" #include "dl_mk_rule_inliner.h" #include "scoped_proof.h" -#include"fixedpoint_params.hpp" namespace datalog { @@ -1444,7 +1443,7 @@ namespace datalog { expr_ref bg_assertion = m_ctx.get_background_assertion(); apply_default_transformation(m_ctx); - if (m_ctx.get_params().xform_slice()) { + if (m_ctx.xform_slice()) { datalog::rule_transformer transformer(m_ctx); datalog::mk_slice* slice = alloc(datalog::mk_slice, m_ctx); transformer.register_plugin(slice); diff --git a/src/muz/fp/horn_tactic.cpp b/src/muz/fp/horn_tactic.cpp index a1c556baf..6032b3f02 100644 --- a/src/muz/fp/horn_tactic.cpp +++ b/src/muz/fp/horn_tactic.cpp @@ -190,7 +190,7 @@ class horn_tactic : public tactic { bool produce_proofs = g->proofs_enabled(); if (produce_proofs) { - if (!m_ctx.get_params().generate_proof_trace()) { + if (!m_ctx.generate_proof_trace()) { params_ref params = m_ctx.get_params().p; params.set_bool("generate_proof_trace", true); updt_params(params); @@ -316,7 +316,7 @@ class horn_tactic : public tactic { m_ctx.get_rules(); // flush adding rules. apply_default_transformation(m_ctx); - if (m_ctx.get_params().xform_slice()) { + if (m_ctx.xform_slice()) { datalog::rule_transformer transformer(m_ctx); datalog::mk_slice* slice = alloc(datalog::mk_slice, m_ctx); transformer.register_plugin(slice); diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index 722661e38..ea8eca6f4 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -80,7 +80,7 @@ namespace pdr { pred_transformer::pred_transformer(context& ctx, manager& pm, func_decl* head): pm(pm), m(pm.get_manager()), ctx(ctx), m_head(head, m), - m_sig(m), m_solver(pm, ctx.get_params(), head->get_name()), + m_sig(m), m_solver(pm, ctx.get_params().pdr_try_minimize_core(), head->get_name()), m_invariants(m), m_transition(m), m_initial_state(m), m_reachable(pm, (datalog::PDR_CACHE_MODE)ctx.get_params().pdr_cache_mode()) {} diff --git a/src/muz/pdr/pdr_prop_solver.cpp b/src/muz/pdr/pdr_prop_solver.cpp index 06f858608..a7d0a02bf 100644 --- a/src/muz/pdr/pdr_prop_solver.cpp +++ b/src/muz/pdr/pdr_prop_solver.cpp @@ -30,7 +30,6 @@ Revision History: #include "pdr_farkas_learner.h" #include "ast_smt2_pp.h" #include "expr_replacer.h" -#include "fixedpoint_params.hpp" // // Auxiliary structure to introduce propositional names for assumptions that are not @@ -226,12 +225,12 @@ namespace pdr { }; - prop_solver::prop_solver(manager& pm, fixedpoint_params const& p, symbol const& name) : + prop_solver::prop_solver(manager& pm, bool try_minimize_core, symbol const& name) : m_fparams(pm.get_fparams()), m(pm.get_manager()), m_pm(pm), m_name(name), - m_try_minimize_core(p.pdr_try_minimize_core()), + m_try_minimize_core(try_minimize_core), m_ctx(pm.mk_fresh()), m_pos_level_atoms(m), m_neg_level_atoms(m), diff --git a/src/muz/pdr/pdr_prop_solver.h b/src/muz/pdr/pdr_prop_solver.h index a63ec2bf4..d7f13a603 100644 --- a/src/muz/pdr/pdr_prop_solver.h +++ b/src/muz/pdr/pdr_prop_solver.h @@ -31,7 +31,6 @@ Revision History: #include "pdr_manager.h" #include "pdr_smt_context_manager.h" -struct fixedpoint_params; namespace pdr { class prop_solver { @@ -75,7 +74,7 @@ namespace pdr { public: - prop_solver(pdr::manager& pm, fixedpoint_params const& p, symbol const& name); + prop_solver(pdr::manager& pm, bool try_minimize_core, symbol const& name); /** return true is s is a symbol introduced by prop_solver */ bool is_aux_symbol(func_decl * s) const { diff --git a/src/muz/rel/rel_context.cpp b/src/muz/rel/rel_context.cpp index 36ba98781..4b099c9b4 100644 --- a/src/muz/rel/rel_context.cpp +++ b/src/muz/rel/rel_context.cpp @@ -51,7 +51,6 @@ Revision History: #include"dl_mk_interp_tail_simplifier.h" #include"dl_mk_bit_blast.h" #include"dl_mk_separate_negated_tails.h" -#include"fixedpoint_params.hpp" namespace datalog { @@ -159,8 +158,8 @@ namespace datalog { TRACE("dl", m_context.display(tout);); //IF_VERBOSE(3, m_context.display_smt2(0,0,verbose_stream());); - if (m_context.get_params().print_aig().size()) { - const char *filename = static_cast(m_context.get_params().print_aig().c_ptr()); + if (m_context.print_aig().size()) { + const char *filename = static_cast(m_context.print_aig().c_ptr()); aig_exporter aig(m_context.get_rules(), get_context(), &m_table_facts); std::ofstream strm(filename, std::ios_base::binary); aig(strm); @@ -300,7 +299,7 @@ namespace datalog { transf.register_plugin(alloc(mk_interp_tail_simplifier, m_context)); transf.register_plugin(alloc(mk_separate_negated_tails, m_context)); - if (m_context.get_params().xform_bit_blast()) { + if (m_context.xform_bit_blast()) { transf.register_plugin(alloc(mk_bit_blast, m_context, 22000)); transf.register_plugin(alloc(mk_interp_tail_simplifier, m_context, 21000)); } @@ -541,7 +540,7 @@ namespace datalog { void rel_context::add_fact(func_decl* pred, relation_fact const& fact) { get_rmanager().reset_saturated_marks(); get_relation(pred).add_fact(fact); - if (m_context.get_params().print_aig().size()) { + if (m_context.print_aig().size()) { m_table_facts.push_back(std::make_pair(pred, fact)); } } diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 1e448f861..f23dfbf70 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -1,3 +1,65 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + udoc_relation.cpp + +Abstract: + + Relation based on union of DOCs. + +Author: + + Nuno Lopes (a-nlopes) 2013-03-01 + Nikolaj Bjorner (nbjorner) 2014-09-15 + +Revision History: + + Revised version of dl_hassel_diff facilities. + +Notes: + + Current pending items: + - Fix the incomplete non-emptiness check in doc.cpp + It can fall back to a sat_solver call in the worst case. + The sat_solver.h interface gives a way to add clauses to a sat solver + and check for satisfiability. It can be used from scratch each time. + - Profile and fix bottlnecks: + - Potential bottleneck in projection exercised in some benchmarks. + Projection is asymptotically very expensive. We are here interested in + handling common/cheap cases efficiently. + - Simplification of udoc and utbv (from negated tails) after operations such as join and union. + - The current simplification is between cheap and expensive. Some low-cost simplification + based on sorting + coallescing and detecting empty docs could be used. + - There are several places where code copies a sequence of bits from one vector to another. + Any such places in udoc_relation should be shifted down to 'doc_manager'. Loops in 'doc_manager' + should be shifted down to 'tbv_manager' and loops there should be moved to 'fixed_bitvector_manager'. + Finally, more efficient and general implementations of non-aligned copies are useful where such + bottlnecks show up on the radar. + - Fix filter_by_negated. + Current implementation seems incorrect. The fast path seems right, but the slow path does not. + Recall the semantics: + filter_by_negation(tgt, neg, columns in tgt: c1,...,cN, + corresponding columns in neg: d1,...,dN): + tgt := {x: x\in tgt_0 && ! \exists y: ( y \in neg & pi_c1(x)= pi_d1(y) & ... & pi_cN(x)= pi_dN(y) ) } + We are given tgt, and neg as two udocs. + The fast pass removes doc's t from tgt where we can establish + that for every x in t there is a n in neg and a y in n, + such that projections(x) = projections(y). + This is claimed to be the case if projections(n) contains projections(t). + + The slow pass uses the projection to create a doc n' from each n that has the same signature as tgt. + It then subtracts each n'. The way n' is created is by copying bits from n. + This seems wrong, for example if the projection contains overlapping regions. + Here is a possible corrected version: + define join_project(tgt, neg, c1, .., cN, d1, .. , dN) as + exists y : y \in neg & x in tgt & pi_c1(x)= pi_d1(y) & ... & pi_cN(x)= pi_dN(y) ) + return tgt \ join_project(tgt, neg, c1, .., cN, d1, .. , dN) + We have most of the facilities required for a join project operation. + For example, the filter_project function uses both equalities and deleted columns. + +--*/ #include "udoc_relation.h" #include "dl_relation_manager.h" #include "qe_util.h" diff --git a/src/muz/tab/tab_context.cpp b/src/muz/tab/tab_context.cpp index d75ebe20e..3175d1622 100644 --- a/src/muz/tab/tab_context.cpp +++ b/src/muz/tab/tab_context.cpp @@ -765,7 +765,7 @@ namespace tb { m_weight_multiply(1.0), m_update_frequency(20), m_next_update(20) { - set_strategy(ctx.get_params().tab_selection()); + set_strategy(ctx.tab_selection()); } void init(rules const& rs) { diff --git a/src/muz/transforms/dl_mk_bit_blast.cpp b/src/muz/transforms/dl_mk_bit_blast.cpp index fcd20d78f..8f4c840eb 100644 --- a/src/muz/transforms/dl_mk_bit_blast.cpp +++ b/src/muz/transforms/dl_mk_bit_blast.cpp @@ -262,7 +262,7 @@ namespace datalog { rule_set * operator()(rule_set const & source) { // TODO pc - if (!m_context.bit_blast()) { + if (!m_context.xform_bit_blast()) { return 0; } rule_manager& rm = m_context.get_rule_manager(); From 08ef9f34bc4a6aaa841cce7c463119a708cafa24 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 26 Sep 2014 08:46:14 -0700 Subject: [PATCH 585/925] add lipstick note Signed-off-by: Nikolaj Bjorner --- src/muz/rel/udoc_relation.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index f23dfbf70..51e4c33af 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -58,7 +58,9 @@ Notes: return tgt \ join_project(tgt, neg, c1, .., cN, d1, .. , dN) We have most of the facilities required for a join project operation. For example, the filter_project function uses both equalities and deleted columns. - + - Lipstick service: + - filter_proj_fn uses both a bit_vector and a svector for representing removed bits. + This is due to underlying routines using different types for the same purpose. --*/ #include "udoc_relation.h" #include "dl_relation_manager.h" @@ -1218,17 +1220,15 @@ namespace datalog { m_original_condition(condition, m), m_reduced_condition(m), m_equalities(union_ctx) { - t.expand_column_vector(m_removed_cols); unsigned num_bits = t.get_num_bits(); - m_col_list.resize(num_bits, false); + t.expand_column_vector(m_removed_cols); + m_col_list.resize(num_bits, false); + m_to_delete.resize(num_bits, false); for (unsigned i = 0; i < num_bits; ++i) { m_equalities.mk_var(); } for (unsigned i = 0; i < m_removed_cols.size(); ++i) { m_col_list.set(m_removed_cols[i], true); - } - m_to_delete.resize(t.get_num_bits(), false); - for (unsigned i = 0; i < m_removed_cols.size(); ++i) { m_to_delete[m_removed_cols[i]] = true; } expr_ref guard(m), non_eq_cond(condition, m); From 1392dc020f9df6eb442d5a4f10e3cafc8a66967b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 27 Sep 2014 09:58:43 -0700 Subject: [PATCH 586/925] local debug update Signed-off-by: Nikolaj Bjorner --- src/muz/rel/udoc_relation.cpp | 2 +- src/opt/inc_sat_solver.cpp | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index b862781b7..75fb03c9e 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -1118,7 +1118,7 @@ namespace datalog { unsigned idx_dst = dstt.column_idx(col_dst); unsigned idx_src = srct.column_idx(col_src); unsigned num_tbits = dstt.column_num_bits(col_dst); - SASSERT(num_bits == srct.column_num_bits(col_src)); + SASSERT(num_tbits == srct.column_num_bits(col_src)); IF_VERBOSE(3, verbose_stream() << "copy column " << idx_src << " to " << idx_dst << " " << num_tbits << "\n";); for (unsigned i = 0; i < num_tbits; ++i) { diff --git a/src/opt/inc_sat_solver.cpp b/src/opt/inc_sat_solver.cpp index 41e4d12de..8ec385f9d 100644 --- a/src/opt/inc_sat_solver.cpp +++ b/src/opt/inc_sat_solver.cpp @@ -318,6 +318,18 @@ private: asm2dep.insert(it->m_value.index(), it->m_key); } sat::literal_vector const& core = m_solver.get_core(); + TRACE("opt", + dep2asm_t::iterator it = dep2asm.begin(); + dep2asm_t::iterator end = dep2asm.end(); + for (; it != end; ++it) { + tout << mk_pp(it->m_key, m) << " |-> " << sat::literal(it->m_value) << "\n"; + } + tout << "core: "; + for (unsigned i = 0; i < core.size(); ++i) { + tout << core[i] << " "; + } + tout << "\n"; + ); m_core.reset(); for (unsigned i = 0; i < core.size(); ++i) { @@ -325,18 +337,6 @@ private: VERIFY (asm2dep.find(core[i].index(), e)); m_core.push_back(e); } - TRACE("opt", - dep2asm_t::iterator it = dep2asm.begin(); - dep2asm_t::iterator end = dep2asm.end(); - for (; it != end; ++it) { - tout << mk_pp(it->m_key, m) << " |-> " << it->m_value << "\n"; - } - tout << "core: "; - for (unsigned i = 0; i < core.size(); ++i) { - tout << core[i] << ": " << mk_pp(m_core[i].get(), m) << " "; - } - tout << "\n"; - ); } From 08dcd51594b332f47337e3839fa089528e0b1405 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 27 Sep 2014 12:04:54 -0700 Subject: [PATCH 587/925] fix bugs in incremental operation of sat solver Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Context.cs | 2 +- src/api/dotnet/Fixedpoint.cs | 1 + src/api/dotnet/Optimize.cs | 32 ++++++++++++++++++++++++++++++-- src/opt/inc_sat_solver.cpp | 25 ++++++++++++++++--------- src/opt/maxres.cpp | 12 ++++++------ src/opt/maxsmt.cpp | 35 +++++++++++++++++------------------ src/opt/maxsmt.h | 8 +++----- src/opt/mus.cpp | 10 ++-------- src/opt/opt_context.cpp | 2 +- src/sat/sat_solver.cpp | 15 +++++++-------- 10 files changed, 84 insertions(+), 58 deletions(-) diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 6fc59351a..1c0f20233 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -2266,7 +2266,7 @@ namespace Microsoft.Z3 } /// - /// Create a pseudo-Boolean <= constraint. + /// Create a pseudo-Boolean less-or-equal constraint. /// public BoolExpr MkPBLe(int[] coeffs, BoolExpr[] args, int k) { diff --git a/src/api/dotnet/Fixedpoint.cs b/src/api/dotnet/Fixedpoint.cs index afd6c11dd..6d75235c6 100644 --- a/src/api/dotnet/Fixedpoint.cs +++ b/src/api/dotnet/Fixedpoint.cs @@ -316,6 +316,7 @@ namespace Microsoft.Z3 } } + /// /// Parse an SMT-LIB2 file with fixedpoint rules. /// Add the rules to the current fixedpoint context. /// Return the set of queries in the file. diff --git a/src/api/dotnet/Optimize.cs b/src/api/dotnet/Optimize.cs index ddbebcfa6..a9499570b 100644 --- a/src/api/dotnet/Optimize.cs +++ b/src/api/dotnet/Optimize.cs @@ -97,8 +97,16 @@ namespace Microsoft.Z3 Symbol s = Context.MkSymbol(group); return Native.Z3_optimize_assert_soft(Context.nCtx, NativeObject, constraint.NativeObject, weight.ToString(), s.NativeObject); } + - public Status Check() { + /// + /// + /// Check satisfiability of asserted constraints. + /// Produce a model that (when the objectives are bounded and + /// don't use strict inequalities) meets the objectives. + /// + /// + public Status Check() { Z3_lbool r = (Z3_lbool)Native.Z3_optimize_check(Context.nCtx, NativeObject); switch (r) { @@ -149,27 +157,47 @@ namespace Microsoft.Z3 return new Model(Context, x); } } - + + /// + /// Declare an arithmetical maximization objective. + /// Return a handle to the objective. The handle is used as + /// an argument to GetLower and GetUpper. + /// public uint MkMaximize(ArithExpr e) { return Native.Z3_optimize_maximize(Context.nCtx, NativeObject, e.NativeObject); } + /// + /// Declare an arithmetical minimization objective. + /// Similar to MkMaximize. + /// public uint MkMinimize(ArithExpr e) { return Native.Z3_optimize_minimize(Context.nCtx, NativeObject, e.NativeObject); } + /// + /// Retrieve a lower bound for the objective handle. + /// public ArithExpr GetLower(uint index) { return (ArithExpr)Expr.Create(Context, Native.Z3_optimize_get_lower(Context.nCtx, NativeObject, index)); } + + /// + /// Retrieve an upper bound for the objective handle. + /// public ArithExpr GetUpper(uint index) { return (ArithExpr)Expr.Create(Context, Native.Z3_optimize_get_upper(Context.nCtx, NativeObject, index)); } + + /// + /// Print the context to a string (SMT-LIB parseable benchmark). + /// public override string ToString() { return Native.Z3_optimize_to_string(Context.nCtx, NativeObject); diff --git a/src/opt/inc_sat_solver.cpp b/src/opt/inc_sat_solver.cpp index a4ec5f380..5eecf42d7 100644 --- a/src/opt/inc_sat_solver.cpp +++ b/src/opt/inc_sat_solver.cpp @@ -39,8 +39,9 @@ class inc_sat_solver : public solver { params_ref m_params; bool m_optimize_model; // parameter expr_ref_vector m_fmls; - expr_ref_vector m_current_fmls; unsigned_vector m_fmls_lim; + unsigned_vector m_fmls_head_lim; + unsigned m_fmls_head; expr_ref_vector m_core; atom2bool_var m_map; model_ref m_model; @@ -61,7 +62,10 @@ public: inc_sat_solver(ast_manager& m, params_ref const& p): m(m), m_solver(p,0), m_params(p), m_optimize_model(false), - m_fmls(m), m_current_fmls(m), m_core(m), m_map(m), + m_fmls(m), + m_fmls_head(0), + m_core(m), + m_map(m), m_num_scopes(0), m_dep_core(m), m_soft(m) { @@ -127,9 +131,11 @@ public: if (f) m_preprocess->cancel(); else m_preprocess->reset_cancel(); } virtual void push() { + internalize_formulas(); m_solver.user_push(); ++m_num_scopes; - m_fmls_lim.push_back(m_current_fmls.size()); + m_fmls_lim.push_back(m_fmls.size()); + m_fmls_head_lim.push_back(m_fmls_head); } virtual void pop(unsigned n) { if (n < m_num_scopes) { // allow inc_sat_solver to @@ -139,8 +145,10 @@ public: m_solver.user_pop(n); m_num_scopes -= n; while (n > 0) { - m_current_fmls.resize(m_fmls_lim.back()); + m_fmls_head = m_fmls_head_lim.back(); + m_fmls.resize(m_fmls_lim.back()); m_fmls_lim.pop_back(); + m_fmls_head_lim.pop_back(); --n; } } @@ -156,8 +164,8 @@ public: } } virtual void assert_expr(expr * t) { + TRACE("opt", tout << mk_pp(t, m) << "\n";); m_fmls.push_back(t); - m_current_fmls.push_back(t); } virtual void set_produce_models(bool f) {} virtual void collect_param_descrs(param_descrs & r) { @@ -291,15 +299,14 @@ private: } lbool internalize_formulas() { - if (m_fmls.empty()) { + if (m_fmls_head == m_fmls.size()) { return l_true; } dep2asm_t dep2asm; goal_ref g = alloc(goal, m, true, false); // models, maybe cores are enabled - for (unsigned i = 0; i < m_fmls.size(); ++i) { - g->assert_expr(m_fmls[i].get()); + for (; m_fmls_head < m_fmls.size(); ++m_fmls_head) { + g->assert_expr(m_fmls[m_fmls_head].get()); } - m_fmls.reset(); return internalize_goal(g, dep2asm); } diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index e032cb80e..79c0ccd72 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -63,7 +63,7 @@ Notes: #include "opt_context.h" #include "pb_decl_plugin.h" #include "opt_params.hpp" - +#include "ast_util.h" using namespace opt; @@ -101,8 +101,8 @@ public: strategy_t st): maxsmt_solver_base(c, ws, soft), m_B(m), m_asms(m), - m_mus(m_s, m), - m_mss(m_s, m), + m_mus(c.get_solver(), m), + m_mss(c.get_solver(), m), m_trail(m), m_st(st), m_hill_climb(true), @@ -519,7 +519,7 @@ public: rational w = split_core(core); TRACE("opt", display_vec(tout << "minimized core: ", core.size(), core.c_ptr());); max_resolve(core, w); - fml = m.mk_not(m.mk_and(m_B.size(), m_B.c_ptr())); + fml = mk_not(m, mk_and(m, m_B.size(), m_B.c_ptr())); s().assert_expr(fml); m_lower += w; trace_bounds("maxres"); @@ -811,7 +811,7 @@ public: expr_ref_vector nsoft(m); expr_ref fml(m); for (unsigned i = 0; i < m_soft.size(); ++i) { - nsoft.push_back(m.mk_not(m_soft[i].get())); + nsoft.push_back(mk_not(m, m_soft[i].get())); } fml = u.mk_lt(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper); s().assert_expr(fml); @@ -880,7 +880,7 @@ public: for (unsigned i = 0; i < m_soft.size(); ++i) { n = m_soft[i].get(); if (!m_assignment[i]) { - n = m.mk_not(n); + n = mk_not(m, n); } sat_solver->assert_expr(n); } diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 24c82feb0..d8bc1073f 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -29,13 +29,13 @@ Notes: #include "uint_set.h" #include "opt_context.h" #include "theory_wmaxsat.h" +#include "ast_util.h" namespace opt { maxsmt_solver_base::maxsmt_solver_base( context& c, vector const& ws, expr_ref_vector const& soft): - m_s(c.get_solver()), m(c.get_manager()), m_c(c), m_cancel(false), m_soft(m), @@ -50,6 +50,10 @@ namespace opt { m_params.copy(p); } + solver& maxsmt_solver_base::s() { + return m_c.get_solver(); + } + void maxsmt_solver_base::init_soft(vector const& weights, expr_ref_vector const& soft) { m_weights.reset(); m_soft.reset(); @@ -78,19 +82,10 @@ namespace opt { tout << "\n";); } - expr* maxsmt_solver_base::mk_not(expr* e) { - if (m.is_not(e, e)) { - return e; - } - else { - return m.mk_not(e); - } - } - void maxsmt_solver_base::set_mus(bool f) { params_ref p; p.set_bool("minimize_core", f); - m_s.updt_params(p); + s().updt_params(p); } void maxsmt_solver_base::enable_sls(expr_ref_vector const& soft, vector const& ws) { @@ -149,10 +144,10 @@ namespace opt { maxsmt::maxsmt(context& c): - m_s(c.get_solver()), m(c.get_manager()), m_c(c), m_cancel(false), + m(c.get_manager()), m_c(c), m_cancel(false), m_soft_constraints(m), m_answer(m) {} - lbool maxsmt::operator()(solver* s) { + lbool maxsmt::operator()() { lbool is_sat; m_msolver = 0; symbol const& maxsat_engine = m_c.maxsat_engine(); @@ -161,7 +156,7 @@ namespace opt { if (m_soft_constraints.empty()) { TRACE("opt", tout << "no constraints\n";); m_msolver = 0; - is_sat = m_s.check_sat(0, 0); + is_sat = s().check_sat(0, 0); } else if (maxsat_engine == symbol("maxres")) { m_msolver = mk_maxres(m_c, m_weights, m_soft_constraints); @@ -222,9 +217,9 @@ namespace opt { // TBD: have to use a different solver // because we don't push local scope any longer. return; - solver::scoped_push _sp(m_s); + solver::scoped_push _sp(s()); commit_assignment(); - if (l_true != m_s.check_sat(0,0)) { + if (l_true != s().check_sat(0,0)) { IF_VERBOSE(0, verbose_stream() << "could not verify assignment\n";); UNREACHABLE(); } @@ -274,10 +269,10 @@ namespace opt { expr_ref tmp(m); tmp = m_soft_constraints[i].get(); if (!get_assignment(i)) { - tmp = m.mk_not(tmp); + tmp = mk_not(m, tmp); } TRACE("opt", tout << "committing: " << tmp << "\n";); - m_s.assert_expr(tmp); + s().assert_expr(tmp); } } @@ -327,5 +322,9 @@ namespace opt { } } + solver& maxsmt::s() { + return m_c.get_solver(); + } + }; diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 3bef5bebe..6341d0756 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -58,7 +58,6 @@ namespace opt { // class maxsmt_solver_base : public maxsmt_solver { protected: - solver& m_s; ast_manager& m; context& m_c; volatile bool m_cancel; @@ -84,9 +83,8 @@ namespace opt { void set_model() { s().get_model(m_model); } virtual void updt_params(params_ref& p); virtual void init_soft(weights_t& weights, expr_ref_vector const& soft); - solver& s() { return m_s; } + solver& s(); void init(); - expr* mk_not(expr* e); void set_mus(bool f); app* mk_fresh_bool(char const* name); @@ -115,7 +113,6 @@ namespace opt { class maxsmt { ast_manager& m; - solver& m_s; context& m_c; scoped_ptr m_msolver; volatile bool m_cancel; @@ -129,7 +126,7 @@ namespace opt { params_ref m_params; public: maxsmt(context& c); - lbool operator()(solver* s); + lbool operator()(); void set_cancel(bool f); void updt_params(params_ref& p); void add(expr* f, rational const& w); @@ -150,6 +147,7 @@ namespace opt { private: bool is_maxsat_problem(weights_t& ws) const; void verify_assignment(); + solver& s(); }; }; diff --git a/src/opt/mus.cpp b/src/opt/mus.cpp index abb0b326e..0cf9786b2 100644 --- a/src/opt/mus.cpp +++ b/src/opt/mus.cpp @@ -22,6 +22,7 @@ Notes: #include "smt_literal.h" #include "mus.h" #include "ast_pp.h" +#include "ast_util.h" using namespace opt; @@ -60,13 +61,6 @@ struct mus::imp { TRACE("opt", tout << idx << ": " << mk_pp(cls, m) << "\n";); return idx; } - - expr* mk_not(expr* e) { - if (m.is_not(e, e)) { - return e; - } - return m.mk_not(e); - } lbool get_mus(unsigned_vector& mus) { // SASSERT: mus does not have duplicates. @@ -92,7 +86,7 @@ struct mus::imp { core.pop_back(); expr* cls = m_cls2expr[cls_id].get(); expr_ref not_cls(m); - not_cls = mk_not(cls); + not_cls = mk_not(m, cls); unsigned sz = assumptions.size(); assumptions.push_back(not_cls); add_core(core, assumptions); diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 9c720ad97..5004ceb32 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -267,7 +267,7 @@ namespace opt { model_ref tmp; maxsmt& ms = *m_maxsmts.find(id); if (scoped) get_solver().push(); - lbool result = ms(m_solver.get()); + lbool result = ms(); if (result != l_false && (ms.get_model(tmp), tmp.get())) ms.get_model(m_model); if (scoped) get_solver().pop(1); if (result == l_true && committed) ms.commit_assignment(); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 082a4a4b4..b81f07e95 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -911,21 +911,20 @@ namespace sat { } m_mc.display(tout); ); -#define _INSERT_LIT(_l_) \ - SASSERT(is_external((_l_).var())); \ - m_assumption_set.insert(_l_); \ - m_assumptions.push_back(_l_); \ - assign(_l_, justification()); \ -// propagate(false); \ for (unsigned i = 0; !inconsistent() && i < m_user_scope_literals.size(); ++i) { literal nlit = ~m_user_scope_literals[i]; - _INSERT_LIT(nlit); + assign(nlit, justification()); + // propagate(false); } for (unsigned i = 0; !inconsistent() && i < num_lits; ++i) { literal lit = lits[i]; - _INSERT_LIT(lit); + SASSERT(is_external((lit).var())); + m_assumption_set.insert(lit); + m_assumptions.push_back(lit); + assign(lit, justification()); + // propagate(false); } } From 989569b154eb337b39b0d31c05b03c20c0cf408d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 29 Sep 2014 10:57:31 -0700 Subject: [PATCH 588/925] add bceq experiment Signed-off-by: Nikolaj Bjorner --- src/ast/ast_trail.h | 76 +++++++ src/ast/trail.h | 404 --------------------------------- src/sat/sat_simplifier.cpp | 9 + src/sat/sat_solver.h | 1 + src/smt/theory_array_full.h | 3 +- src/{smt => util}/union_find.h | 6 +- 6 files changed, 93 insertions(+), 406 deletions(-) create mode 100644 src/ast/ast_trail.h delete mode 100644 src/ast/trail.h rename src/{smt => util}/union_find.h (96%) diff --git a/src/ast/ast_trail.h b/src/ast/ast_trail.h new file mode 100644 index 000000000..94039875e --- /dev/null +++ b/src/ast/ast_trail.h @@ -0,0 +1,76 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + ast_trail.h + +Abstract: + + + +Author: + + Leonardo de Moura (leonardo) 2008-06-02. + +Revision History: + + Extracted AST specific features from trail.h + nbjorner 2014-9-28 + +--*/ +#ifndef _AST_TRAIL_H_ +#define _AST_TRAIL_H_ + +#include"ast.h" +#include"trail.h" + + +template +class ast2ast_trailmap { + ref_vector m_domain; + ref_vector m_range; + obj_map m_map; +public: + ast2ast_trailmap(ast_manager& m): + m_domain(m), + m_range(m), + m_map() + {} + + bool find(S* s, T*& t) { + return m_map.find(s,t); + } + + void insert(S* s, T* t) { + SASSERT(!m_map.contains(s)); + m_domain.push_back(s); + m_range.push_back(t); + m_map.insert(s,t); + } + + void pop() { + SASSERT(!m_domain.empty()); + m_map.remove(m_domain.back()); + m_domain.pop_back(); + m_range.pop_back(); + } +}; + +template +class ast2ast_trail : public trail { + ast2ast_trailmap& m_map; +public: + ast2ast_trail(ast2ast_trailmap& m, S* s, T* t) : + m_map(m) { + m.insert(s,t); + } + + virtual void undo(Ctx& ctx) { + m_map.pop(); + } +}; + + +#endif /* _AST_TRAIL_H_ */ + diff --git a/src/ast/trail.h b/src/ast/trail.h deleted file mode 100644 index ac03f9fce..000000000 --- a/src/ast/trail.h +++ /dev/null @@ -1,404 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - trail.h - -Abstract: - - - -Author: - - Leonardo de Moura (leonardo) 2008-06-02. - -Revision History: - ---*/ -#ifndef _TRAIL_H_ -#define _TRAIL_H_ - -#include"ast.h" -#include"obj_hashtable.h" -#include"region.h" - -template -class trail { -public: - virtual ~trail() { - } - virtual void undo(Ctx & ctx) = 0; -}; - -template -class value_trail : public trail { - T & m_value; - T m_old_value; - -public: - value_trail(T & value): - m_value(value), - m_old_value(value) { - } - - virtual ~value_trail() { - } - - virtual void undo(Ctx & ctx) { - m_value = m_old_value; - } -}; - -template -class reset_flag_trail : public trail { - bool & m_value; -public: - reset_flag_trail(bool & value): - m_value(value) { - } - - virtual ~reset_flag_trail() { - } - - virtual void undo(Ctx & ctx) { - m_value = false; - } -}; - -template -class set_ptr_trail : public trail { - T * & m_ptr; -public: - set_ptr_trail(T * & ptr): - m_ptr(ptr) { - SASSERT(m_ptr == 0); - } - - virtual void undo(Ctx & ctx) { - m_ptr = 0; - } -}; - -template -class restore_size_trail : public trail { - vector & m_vector; - unsigned m_old_size; -public: - restore_size_trail(vector & v, unsigned sz): - m_vector(v), - m_old_size(sz) { - } - restore_size_trail(vector & v): - m_vector(v), - m_old_size(v.size()) { - } - virtual ~restore_size_trail() { - } - virtual void undo(Ctx & ctx) { - m_vector.shrink(m_old_size); - } -}; - -template -class vector_value_trail : public trail { - vector & m_vector; - unsigned m_idx; - T m_old_value; -public: - vector_value_trail(vector & v, unsigned idx): - m_vector(v), - m_idx(idx), - m_old_value(v[idx]) { - } - - virtual ~vector_value_trail() { - } - - virtual void undo(Ctx & ctx) { - m_vector[m_idx] = m_old_value; - } -}; - - -template -class insert_obj_map : public trail { - obj_map& m_map; - D* m_obj; -public: - insert_obj_map(obj_map& t, D* o) : m_map(t), m_obj(o) {} - virtual ~insert_obj_map() {} - virtual void undo(Ctx & ctx) { m_map.remove(m_obj); } -}; - -template -class insert_map : public trail { - M& m_map; - D m_obj; -public: - insert_map(M& t, D o) : m_map(t), m_obj(o) {} - virtual ~insert_map() {} - virtual void undo(Ctx & ctx) { m_map.remove(m_obj); } -}; - - - -template -class push_back_vector : public trail { - V & m_vector; -public: - push_back_vector(V & v): - m_vector(v) { - } - - virtual void undo(Ctx & ctx) { - m_vector.pop_back(); - } -}; - -template -class set_vector_idx_trail : public trail { - ptr_vector & m_vector; - unsigned m_idx; -public: - set_vector_idx_trail(ptr_vector & v, unsigned idx): - m_vector(v), - m_idx(idx) { - } - - virtual ~set_vector_idx_trail() { - } - - virtual void undo(Ctx & ctx) { - m_vector[m_idx] = 0; - } -}; - -template -class pop_back_trail : public trail { - vector & m_vector; - T m_value; -public: - pop_back_trail(vector & v): - m_vector(v), - m_value(m_vector.back()) { - } - - virtual void undo(Ctx & ctx) { - m_vector.push_back(m_value); - } -}; - -template -class pop_back2_trail : public trail { - vector & m_vector; - typedef vector, true> vector_t; - unsigned m_index; - T m_value; -public: - pop_back2_trail(vector & v, unsigned index): - m_vector(v), - m_index(index), - m_value(m_vector[index].back()) { - } - - virtual void undo(Ctx & ctx) { - m_vector[m_index].push_back(m_value); - } -}; - - -template -class ast2ast_trailmap { - ref_vector m_domain; - ref_vector m_range; - obj_map m_map; -public: - ast2ast_trailmap(ast_manager& m): - m_domain(m), - m_range(m), - m_map() - {} - - bool find(S* s, T*& t) { - return m_map.find(s,t); - } - - void insert(S* s, T* t) { - SASSERT(!m_map.contains(s)); - m_domain.push_back(s); - m_range.push_back(t); - m_map.insert(s,t); - } - - void pop() { - SASSERT(!m_domain.empty()); - m_map.remove(m_domain.back()); - m_domain.pop_back(); - m_range.pop_back(); - } -}; - -template -class ast2ast_trail : public trail { - ast2ast_trailmap& m_map; -public: - ast2ast_trail(ast2ast_trailmap& m, S* s, T* t) : - m_map(m) { - m.insert(s,t); - } - - virtual void undo(Ctx& ctx) { - m_map.pop(); - } -}; - -template -class push_back_trail : public trail { - vector & m_vector; -public: - push_back_trail(vector & v): - m_vector(v) { - } - - virtual void undo(Ctx & ctx) { - m_vector.pop_back(); - } -}; - -template -class push_back2_trail : public trail { - typedef vector, true> vector_t; - vector_t & m_vector; - unsigned m_index; -public: - push_back2_trail(vector_t & v, unsigned index) : - m_vector(v), - m_index(index) { - } - - virtual void undo(Ctx & ctx) { - m_vector[m_index].pop_back(); - } -}; - -template -class set_bitvector_trail : public trail { - svector & m_vector; - unsigned m_idx; -public: - set_bitvector_trail(svector & v, unsigned idx): - m_vector(v), - m_idx(idx) { - SASSERT(m_vector[m_idx] == false); - m_vector[m_idx] = true; - } - - virtual void undo(Ctx & ctx) { - m_vector[m_idx] = false; - } -}; - -template -class new_obj_trail : public trail { - T * m_obj; -public: - new_obj_trail(T * obj): - m_obj(obj) { - } - - virtual void undo(Ctx & ctx) { - dealloc(m_obj); - } -}; - -template -class obj_ref_trail : public trail { - obj_ref m_obj; -public: - obj_ref_trail(obj_ref& obj): - m_obj(obj) { - } - - virtual void undo(Ctx & ctx) { - m_obj.reset(); - } -}; - -template -class insert_obj_trail : public trail { - obj_hashtable& m_table; - T* m_obj; -public: - insert_obj_trail(obj_hashtable& t, T* o) : m_table(t), m_obj(o) {} - virtual ~insert_obj_trail() {} - virtual void undo(Ctx & ctx) { m_table.remove(m_obj); } -}; - - - -template -class remove_obj_trail : public trail { - obj_hashtable& m_table; - T* m_obj; -public: - remove_obj_trail(obj_hashtable& t, T* o) : m_table(t), m_obj(o) {} - virtual ~remove_obj_trail() {} - virtual void undo(Ctx & ctx) { m_table.insert(m_obj); } -}; - - -template -void undo_trail_stack(Ctx & ctx, ptr_vector > & s, unsigned old_size) { - SASSERT(old_size <= s.size()); - typename ptr_vector >::iterator begin = s.begin() + old_size; - typename ptr_vector >::iterator it = s.end(); - while (it != begin) { - --it; - (*it)->undo(ctx); - } - s.shrink(old_size); -} - -template -class trail_stack { - Ctx & m_ctx; - ptr_vector > m_trail_stack; - unsigned_vector m_scopes; - region m_region; -public: - trail_stack(Ctx & c):m_ctx(c) {} - - ~trail_stack() {} - - region & get_region() { return m_region; } - - void reset() { - pop_scope(m_scopes.size()); - // Undo trail objects stored at lvl 0 (avoid memory leaks if lvl 0 contains new_obj_trail objects). - undo_trail_stack(m_ctx, m_trail_stack, 0); - } - - void push_ptr(trail * t) { m_trail_stack.push_back(t); } - - template - void push(TrailObject const & obj) { m_trail_stack.push_back(new (m_region) TrailObject(obj)); } - - unsigned get_num_scopes() const { return m_scopes.size(); } - - void push_scope() { m_region.push_scope(); m_scopes.push_back(m_trail_stack.size()); } - - void pop_scope(unsigned num_scopes) { - if (num_scopes == 0) return; - unsigned lvl = m_scopes.size(); - SASSERT(num_scopes <= lvl); - unsigned new_lvl = lvl - num_scopes; - unsigned old_size = m_scopes[new_lvl]; - undo_trail_stack(m_ctx, m_trail_stack, old_size); - m_scopes.shrink(new_lvl); - m_region.pop_scope(num_scopes); - } -}; - -#endif /* _TRAIL_H_ */ - diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 76d3a1730..3bb914ad0 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -21,6 +21,7 @@ Revision History: #include"sat_simplifier.h" #include"sat_simplifier_params.hpp" #include"sat_solver.h" +#include"sat_bceq.h" #include"stopwatch.h" #include"trace.h" @@ -156,6 +157,14 @@ namespace sat { if (!learned && (m_elim_blocked_clauses || m_elim_blocked_clauses_at == m_num_calls)) elim_blocked_clauses(); +#if 0 + // experiment is disabled. + if (!learned) { // && m_equality_inference + bceq bc(s); + bc(); + } +#endif + if (!learned) m_num_calls++; diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index f2602ff25..edc3a3509 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -141,6 +141,7 @@ namespace sat { friend class mus; friend class sls; friend class wsls; + friend class bceq; friend struct mk_stat; public: solver(params_ref const & p, extension * ext); diff --git a/src/smt/theory_array_full.h b/src/smt/theory_array_full.h index 5a80b7fae..7c066f765 100644 --- a/src/smt/theory_array_full.h +++ b/src/smt/theory_array_full.h @@ -19,8 +19,9 @@ Revision History: #ifndef _THEORY_ARRAY_FULL_H_ #define _THEORY_ARRAY_FULL_H_ -#include"theory_array.h" +#include "theory_array.h" #include "simplifier.h" +#include "ast_trail.h" namespace smt { diff --git a/src/smt/union_find.h b/src/util/union_find.h similarity index 96% rename from src/smt/union_find.h rename to src/util/union_find.h index cb2ce68c8..a5c897656 100644 --- a/src/smt/union_find.h +++ b/src/util/union_find.h @@ -20,6 +20,7 @@ Revision History: #define _UNION_FIND_H_ #include "trail.h" +#include "trace.h" class union_find_default_ctx { public: @@ -98,6 +99,7 @@ public: unsigned get_num_vars() const { return m_find.size(); } + unsigned find(unsigned v) const { while (true) { unsigned new_v = m_find[v]; @@ -109,6 +111,8 @@ public: unsigned next(unsigned v) const { return m_next[v]; } + unsigned size(unsigned v) const { return m_size[find(v)]; } + bool is_root(unsigned v) const { return m_find[v] == v; } void merge(unsigned v1, unsigned v2) { @@ -131,7 +135,7 @@ public: void display(std::ostream & out) const { unsigned num = get_num_vars(); for (unsigned v = 0; v < num; v++) { - out << "v" << v << " --> v" << m_find[v] << "\n"; + out << "v" << v << " --> v" << m_find[v] << " (" << size(v) << ")\n"; } } From 2cfa4dcb53c9f7deb0c0759a2553cbb77595c204 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 29 Sep 2014 10:58:31 -0700 Subject: [PATCH 589/925] add bceq experiment Signed-off-by: Nikolaj Bjorner --- src/sat/sat_bceq.cpp | 377 +++++++++++++++++++++++++++++++++++++++++++ src/sat/sat_bceq.h | 75 +++++++++ 2 files changed, 452 insertions(+) create mode 100644 src/sat/sat_bceq.cpp create mode 100644 src/sat/sat_bceq.h diff --git a/src/sat/sat_bceq.cpp b/src/sat/sat_bceq.cpp new file mode 100644 index 000000000..54e8d086a --- /dev/null +++ b/src/sat/sat_bceq.cpp @@ -0,0 +1,377 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + sat_bceq.cpp + +Abstract: + + Find equivalent literals based on blocked clause decomposition. + +Author: + + Nikolaj Bjorner (nbjorner) 2014-09-27. + + +Revision History: + +--*/ +#include"sat_bceq.h" +#include"sat_solver.h" +#include"trace.h" +#include"bit_vector.h" +#include"map.h" + +namespace sat { + + bceq::bceq(solver & s): + m_solver(s) { + } + + void bceq::register_clause(clause* cls) { + m_clauses.setx(cls->id(), cls, 0); + } + + void bceq::unregister_clause(clause* cls) { + m_clauses.setx(cls->id(), 0, 0); + } + + void bceq::init() { + m_clauses.reset(); + m_bin_clauses.reset(); + m_L.reset(); + m_R.reset(); + m_L_blits.reset(); + m_R_blits.reset(); + clause * const* it = m_solver.begin_clauses(); + clause * const* end = m_solver.end_clauses(); + for (; it != end; ++it) { + clause* cls = *it; + if (!cls->was_removed()) { + m_use_list->insert(*cls); + register_clause(cls); + } + } + bin_clauses bc; + m_solver.collect_bin_clauses(bc, false); + literal lits[2]; + for (unsigned i = 0; i < bc.size(); ++i) { + lits[0] = bc[i].first; + lits[1] = bc[i].second; + clause* cls = m_solver.m_cls_allocator.mk_clause(2, lits, false); + m_use_list->insert(*cls); + m_bin_clauses.push_back(cls); + register_clause(cls); + } + } + + void bceq::pure_decompose() { + // while F != empty + // pick a clause and variable x in clause. + // get use list U1 of x and U2 of ~x + // assume |U1| >= |U2| + // add U1 to clause set. + for (unsigned i = 0; i < m_clauses.size(); ++i) { + clause* cls = m_clauses[i]; + if (cls) { + SASSERT(i == cls->id()); + pure_decompose((*cls)[0]); + SASSERT(!m_clauses[i]); + } + } + m_L.reverse(); + m_L_blits.reverse(); + } + + void bceq::pure_decompose(literal lit) { + clause_use_list& pos = m_use_list->get(lit); + clause_use_list& neg = m_use_list->get(~lit); + unsigned sz1 = m_L.size(); + unsigned sz2 = m_R.size(); + pure_decompose(pos, m_L); + pure_decompose(neg, m_R); + unsigned delta1 = m_L.size() - sz1; + unsigned delta2 = m_R.size() - sz2; + if (delta1 < delta2) { + m_L_blits.resize(sz1+delta2, ~lit); + m_R_blits.resize(sz2+delta1, lit); + for (unsigned i = 0; i < delta1; ++i) { + std::swap(m_L[sz1 + i], m_R[sz2 + i]); + } + for (unsigned i = delta1; i < delta2; ++i) { + m_L.push_back(m_R[sz2 + i]); + } + m_R.resize(sz2 + delta1); + std::swap(delta1, delta2); + } + else { + m_L_blits.resize(sz1+delta1, lit); + m_R_blits.resize(sz2+delta2, ~lit); + } + std::cout << lit << " " << "pos: " << delta1 << " " << "neg: " << delta2 << "\n"; + } + + void bceq::pure_decompose(clause_use_list& uses, svector& clauses) { + clause_use_list::iterator it = uses.mk_iterator(); + while (!it.at_end()) { + clause& cls = it.curr(); + if (!cls.was_removed() && m_clauses[cls.id()]) { + clauses.push_back(&cls); + m_clauses[cls.id()] = 0; + } + it.next(); + } + } + + void bceq::post_decompose() { + m_marked.reset(); + m_marked.resize(2*m_solver.num_vars(), false); + use_list ul; + use_list* save = m_use_list; + m_use_list = &ul; + ul.init(m_solver.num_vars()); + for (unsigned i = 0; i < m_L.size(); ++i) { + ul.insert(*m_L[i]); + } + for (unsigned i = 0; i < m_R.size(); ++i) { + literal lit = find_blocked(*m_R[i]); + if (lit != null_literal) { + m_L.push_back(m_R[i]); + m_L_blits.push_back(lit); + ul.insert(*m_R[i]); + m_R[i] = m_R.back(); + m_R_blits[i] = m_R_blits.back(); + m_R.pop_back(); + m_R_blits.pop_back(); + --i; + } + } + m_use_list = save; + } + + literal bceq::find_blocked(clause const& cls) { + std::cout << "find blocker for: " << cls << "\n"; + + unsigned sz = cls.size(); + for (unsigned i = 0; i < sz; ++i) { + m_marked[(~cls[i]).index()] = true; + } + literal result = null_literal; + for (unsigned i = 0; i < sz; ++i) { + literal lit = cls[i]; + if (is_blocked(lit)) { + std::cout << "is blocked " << lit << " : " << cls << "\n"; + result = lit; + break; + } + } + for (unsigned i = 0; i < sz; ++i) { + m_marked[(~cls[i]).index()] = false; + } + return result; + } + + bool bceq::is_blocked(literal lit) const { + clause_use_list& uses = m_use_list->get(~lit); + clause_use_list::iterator it = uses.mk_iterator(); + while (!it.at_end()) { + clause const& cls = it.curr(); + unsigned sz = cls.size(); + bool is_axiom = false; + for (unsigned i = 0; !is_axiom && i < sz; ++i) { + is_axiom = m_marked[cls[i].index()] && cls[i] != ~lit; + } + + std::cout << "resolvent " << lit << " : " << cls << " " << (is_axiom?"axiom":"non-axiom") << "\n"; + if (!is_axiom) { + return false; + } + it.next(); + } + return true; + } + + + void bceq::init_rbits() { + m_rbits.reset(); + for (unsigned i = 0; i < m_solver.num_vars(); ++i) { + uint64 lo = m_rand() + (m_rand() << 16); + uint64 hi = m_rand() + (m_rand() << 16); + m_rbits.push_back(lo + (hi << 32ULL)); + } + } + + void bceq::init_reconstruction_stack() { + m_rstack.reset(); + m_bstack.reset(); + // decomposition already creates a blocked stack in the proper order. + m_rstack.append(m_L); + m_bstack.append(m_L_blits); + } + + uint64 bceq::eval_clause(clause const& cls) const { + uint64 b = 0; + unsigned sz = cls.size(); + for (unsigned i = 0; i < sz; ++i) { + literal lit = cls[i]; + uint64 val = m_rbits[lit.var()]; + if (lit.sign()) { + val = ~val; + } + b |= val; + } + return b; + } + + void bceq::sat_sweep() { + init_rbits(); + init_reconstruction_stack(); + for (unsigned i = 0; i < m_rstack.size(); ++i) { + clause const& cls = *m_rstack[i]; + literal block_lit = m_bstack[i]; + uint64 b = eval_clause(cls); + // std::cout << "Eval: " << block_lit << " " << std::hex << " "; + // std::cout << m_rbits[block_lit.var()] << " " << b << std::dec << "\n"; + // v = 0, b = 0 -> v := 1 + // v = 0, b = 1 -> v := 0 + // v = 1, b = 0 -> v := 0 + // v = 1, b = 1 -> v := 1 + m_rbits[block_lit.var()] ^= ~b; + + } + DEBUG_CODE(verify_sweep();); + } + + void bceq::verify_sweep() { + for (unsigned i = 0; i < m_L.size(); ++i) { + uint64 b = eval_clause(*m_L[i]); + SASSERT((~b) == 0); + } + } + + struct u64_hash { unsigned operator()(uint64 u) const { return (unsigned)u; } }; + + struct u64_eq { bool operator()(uint64 u1, uint64 u2) const { return u1 == u2; } }; + + void bceq::extract_partition() { + unsigned num_vars = m_solver.num_vars(); + map table; + union_find<> union_find(m_union_find_ctx); + for (unsigned i = 0; i < num_vars; ++i) { + m_s->mk_var(true, true); + union_find.mk_var(); + } + for (unsigned i = 0; i < m_L.size(); ++i) { + m_s->mk_clause(m_L[i]->size(), m_L[i]->begin()); + } + for (unsigned i = 0; i < num_vars; ++i) { + uint64 val = m_rbits[i]; + unsigned index; + if (table.find(val, index)) { + union_find.merge(i, index); + } + else if (table.find(~val, index)) { + union_find.merge(i, index); + } + else { + table.insert(val, i); + } + } + union_find.display(std::cout); + + // + // Preliminary version: + // A more appropriate is to walk each pair, + // and refine partition based on SAT results. + // + for (unsigned i = 0; i < num_vars; ++i) { + if (!union_find.is_root(i)) continue; + unsigned v = union_find.next(i); + unsigned last_v = UINT_MAX; + if (!m_solver.was_eliminated(i)) { + last_v = i; + } + while (v != i) { + if (!m_solver.was_eliminated(v)) { + if (last_v != UINT_MAX) { + check_equality(v, last_v); + } + last_v = v; + } + v = union_find.next(v); + } + } + } + + void bceq::check_equality(unsigned v1, unsigned v2) { + std::cout << "check: " << v1 << " = " << v2 << "\n"; + uint64 val1 = m_rbits[v1]; + uint64 val2 = m_rbits[v2]; + literal l1 = literal(v1, false); + literal l2 = literal(v2, false); + if (val1 != val2) { + SASSERT(val1 == ~val2); + l2.neg(); + } + if (is_equiv(l1, l2)) { + std::cout << "Already equivalent: " << l1 << " " << l2 << "\n"; + return; + } + + literal lits[2]; + lits[0] = l1; + lits[1] = ~l2; + lbool is_sat = m_s->check(2, lits); + if (is_sat == l_false) { + lits[0] = ~l1; + lits[1] = l2; + is_sat = m_s->check(2, lits); + } + if (is_sat == l_false) { + std::cout << "Found equivalent: " << l1 << " " << l2 << "\n"; + } + else { + std::cout << "Not equivalent\n"; + } + } + + bool bceq::is_equiv(literal l1, literal l2) { + watch_list const& w1 = m_solver.get_wlist(l1); + bool found = false; + for (unsigned i = 0; !found && i < w1.size(); ++i) { + watched const& w = w1[i]; + found = w.is_binary_clause() && w.get_literal() == ~l2; + } + if (!found) return false; + found = true; + watch_list const& w2 = m_solver.get_wlist(~l1); + for (unsigned i = 0; !found && i < w2.size(); ++i) { + watched const& w = w2[i]; + found = w.is_binary_clause() && w.get_literal() == l2; + } + return found; + } + + + void bceq::cleanup() { + m_solver.del_clauses(m_bin_clauses.begin(), m_bin_clauses.end()); + m_bin_clauses.reset(); + } + + + void bceq::operator()() { + use_list ul; + solver s(m_solver.m_params, 0); + m_use_list = &ul; + m_s = &s; + ul.init(m_solver.num_vars()); + init(); + pure_decompose(); + post_decompose(); + std::cout << m_L.size() << " vs " << m_R.size() << "\n"; + sat_sweep(); + extract_partition(); + cleanup(); + } +}; diff --git a/src/sat/sat_bceq.h b/src/sat/sat_bceq.h new file mode 100644 index 000000000..7e9a1f632 --- /dev/null +++ b/src/sat/sat_bceq.h @@ -0,0 +1,75 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + sat_bceq.h + +Abstract: + + Find equivalent literals based on blocked clause decomposition. + +Author: + + Nikolaj Bjorner (nbjorner) 2014-09-27. + +Revision History: + +--*/ +#ifndef _SAT_BCEQ_H_ +#define _SAT_BCEQ_H_ + +#include"sat_types.h" +#include "union_find.h" + + +namespace sat { + class solver; + class use_list; + class clause_use_list; + + class bceq { + typedef std::pair bin_clause; + typedef svector bin_clauses; + solver & m_solver; + use_list* m_use_list; + solver* m_s; + random_gen m_rand; + svector m_clauses; + svector m_L; + svector m_R; + literal_vector m_L_blits; + literal_vector m_R_blits; + svector m_bin_clauses; + svector m_rbits; + svector m_rstack; // stack of blocked clauses + literal_vector m_bstack; // stack of blocking literals + svector m_marked; + union_find_default_ctx m_union_find_ctx; + + void init(); + void register_clause(clause* cls); + void unregister_clause(clause* cls); + void pure_decompose(); + void pure_decompose(literal lit); + void pure_decompose(clause_use_list& uses, svector& clauses); + void post_decompose(); + literal find_blocked(clause const& cls); + bool is_blocked(literal lit) const; + void init_rbits(); + void init_reconstruction_stack(); + void sat_sweep(); + void cleanup(); + uint64 eval_clause(clause const& cls) const; + void verify_sweep(); + void extract_partition(); + void check_equality(unsigned v1, unsigned v2); + bool is_equiv(literal l1, literal l2); + public: + bceq(solver & s); + void operator()(); + }; + +}; + +#endif From 5dc2afa33f6f51dc18b751c36025cc951e332b66 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 29 Sep 2014 10:59:22 -0700 Subject: [PATCH 590/925] add bceq experiment Signed-off-by: Nikolaj Bjorner --- src/util/trail.h | 360 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 360 insertions(+) create mode 100644 src/util/trail.h diff --git a/src/util/trail.h b/src/util/trail.h new file mode 100644 index 000000000..116b3241e --- /dev/null +++ b/src/util/trail.h @@ -0,0 +1,360 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + trail.h + +Abstract: + + + +Author: + + Leonardo de Moura (leonardo) 2008-06-02. + +Revision History: + +--*/ +#ifndef _TRAIL_H_ +#define _TRAIL_H_ + +#include"obj_hashtable.h" +#include"region.h" +#include"obj_ref.h" + +template +class trail { +public: + virtual ~trail() { + } + virtual void undo(Ctx & ctx) = 0; +}; + +template +class value_trail : public trail { + T & m_value; + T m_old_value; + +public: + value_trail(T & value): + m_value(value), + m_old_value(value) { + } + + virtual ~value_trail() { + } + + virtual void undo(Ctx & ctx) { + m_value = m_old_value; + } +}; + +template +class reset_flag_trail : public trail { + bool & m_value; +public: + reset_flag_trail(bool & value): + m_value(value) { + } + + virtual ~reset_flag_trail() { + } + + virtual void undo(Ctx & ctx) { + m_value = false; + } +}; + +template +class set_ptr_trail : public trail { + T * & m_ptr; +public: + set_ptr_trail(T * & ptr): + m_ptr(ptr) { + SASSERT(m_ptr == 0); + } + + virtual void undo(Ctx & ctx) { + m_ptr = 0; + } +}; + +template +class restore_size_trail : public trail { + vector & m_vector; + unsigned m_old_size; +public: + restore_size_trail(vector & v, unsigned sz): + m_vector(v), + m_old_size(sz) { + } + restore_size_trail(vector & v): + m_vector(v), + m_old_size(v.size()) { + } + virtual ~restore_size_trail() { + } + virtual void undo(Ctx & ctx) { + m_vector.shrink(m_old_size); + } +}; + +template +class vector_value_trail : public trail { + vector & m_vector; + unsigned m_idx; + T m_old_value; +public: + vector_value_trail(vector & v, unsigned idx): + m_vector(v), + m_idx(idx), + m_old_value(v[idx]) { + } + + virtual ~vector_value_trail() { + } + + virtual void undo(Ctx & ctx) { + m_vector[m_idx] = m_old_value; + } +}; + + +template +class insert_obj_map : public trail { + obj_map& m_map; + D* m_obj; +public: + insert_obj_map(obj_map& t, D* o) : m_map(t), m_obj(o) {} + virtual ~insert_obj_map() {} + virtual void undo(Ctx & ctx) { m_map.remove(m_obj); } +}; + +template +class insert_map : public trail { + M& m_map; + D m_obj; +public: + insert_map(M& t, D o) : m_map(t), m_obj(o) {} + virtual ~insert_map() {} + virtual void undo(Ctx & ctx) { m_map.remove(m_obj); } +}; + + + +template +class push_back_vector : public trail { + V & m_vector; +public: + push_back_vector(V & v): + m_vector(v) { + } + + virtual void undo(Ctx & ctx) { + m_vector.pop_back(); + } +}; + +template +class set_vector_idx_trail : public trail { + ptr_vector & m_vector; + unsigned m_idx; +public: + set_vector_idx_trail(ptr_vector & v, unsigned idx): + m_vector(v), + m_idx(idx) { + } + + virtual ~set_vector_idx_trail() { + } + + virtual void undo(Ctx & ctx) { + m_vector[m_idx] = 0; + } +}; + +template +class pop_back_trail : public trail { + vector & m_vector; + T m_value; +public: + pop_back_trail(vector & v): + m_vector(v), + m_value(m_vector.back()) { + } + + virtual void undo(Ctx & ctx) { + m_vector.push_back(m_value); + } +}; + +template +class pop_back2_trail : public trail { + vector & m_vector; + typedef vector, true> vector_t; + unsigned m_index; + T m_value; +public: + pop_back2_trail(vector & v, unsigned index): + m_vector(v), + m_index(index), + m_value(m_vector[index].back()) { + } + + virtual void undo(Ctx & ctx) { + m_vector[m_index].push_back(m_value); + } +}; + + + +template +class push_back_trail : public trail { + vector & m_vector; +public: + push_back_trail(vector & v): + m_vector(v) { + } + + virtual void undo(Ctx & ctx) { + m_vector.pop_back(); + } +}; + +template +class push_back2_trail : public trail { + typedef vector, true> vector_t; + vector_t & m_vector; + unsigned m_index; +public: + push_back2_trail(vector_t & v, unsigned index) : + m_vector(v), + m_index(index) { + } + + virtual void undo(Ctx & ctx) { + m_vector[m_index].pop_back(); + } +}; + +template +class set_bitvector_trail : public trail { + svector & m_vector; + unsigned m_idx; +public: + set_bitvector_trail(svector & v, unsigned idx): + m_vector(v), + m_idx(idx) { + SASSERT(m_vector[m_idx] == false); + m_vector[m_idx] = true; + } + + virtual void undo(Ctx & ctx) { + m_vector[m_idx] = false; + } +}; + +template +class new_obj_trail : public trail { + T * m_obj; +public: + new_obj_trail(T * obj): + m_obj(obj) { + } + + virtual void undo(Ctx & ctx) { + dealloc(m_obj); + } +}; + +template +class obj_ref_trail : public trail { + obj_ref m_obj; +public: + obj_ref_trail(obj_ref& obj): + m_obj(obj) { + } + + virtual void undo(Ctx & ctx) { + m_obj.reset(); + } +}; + +template +class insert_obj_trail : public trail { + obj_hashtable& m_table; + T* m_obj; +public: + insert_obj_trail(obj_hashtable& t, T* o) : m_table(t), m_obj(o) {} + virtual ~insert_obj_trail() {} + virtual void undo(Ctx & ctx) { m_table.remove(m_obj); } +}; + + + +template +class remove_obj_trail : public trail { + obj_hashtable& m_table; + T* m_obj; +public: + remove_obj_trail(obj_hashtable& t, T* o) : m_table(t), m_obj(o) {} + virtual ~remove_obj_trail() {} + virtual void undo(Ctx & ctx) { m_table.insert(m_obj); } +}; + + +template +void undo_trail_stack(Ctx & ctx, ptr_vector > & s, unsigned old_size) { + SASSERT(old_size <= s.size()); + typename ptr_vector >::iterator begin = s.begin() + old_size; + typename ptr_vector >::iterator it = s.end(); + while (it != begin) { + --it; + (*it)->undo(ctx); + } + s.shrink(old_size); +} + +template +class trail_stack { + Ctx & m_ctx; + ptr_vector > m_trail_stack; + unsigned_vector m_scopes; + region m_region; +public: + trail_stack(Ctx & c):m_ctx(c) {} + + ~trail_stack() {} + + region & get_region() { return m_region; } + + void reset() { + pop_scope(m_scopes.size()); + // Undo trail objects stored at lvl 0 (avoid memory leaks if lvl 0 contains new_obj_trail objects). + undo_trail_stack(m_ctx, m_trail_stack, 0); + } + + void push_ptr(trail * t) { m_trail_stack.push_back(t); } + + template + void push(TrailObject const & obj) { m_trail_stack.push_back(new (m_region) TrailObject(obj)); } + + unsigned get_num_scopes() const { return m_scopes.size(); } + + void push_scope() { m_region.push_scope(); m_scopes.push_back(m_trail_stack.size()); } + + void pop_scope(unsigned num_scopes) { + if (num_scopes == 0) return; + unsigned lvl = m_scopes.size(); + SASSERT(num_scopes <= lvl); + unsigned new_lvl = lvl - num_scopes; + unsigned old_size = m_scopes[new_lvl]; + undo_trail_stack(m_ctx, m_trail_stack, old_size); + m_scopes.shrink(new_lvl); + m_region.pop_scope(num_scopes); + } +}; + +#endif /* _TRAIL_H_ */ + From 60d7872cc810767a261ca026c4dc06ab3e21f573 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 29 Sep 2014 18:00:34 -0700 Subject: [PATCH 591/925] adding simple BCE Signed-off-by: Nikolaj Bjorner --- src/sat/sat_bceq.cpp | 116 +++++++++++++++++++++++++++++++------ src/sat/sat_bceq.h | 2 + src/sat/sat_simplifier.cpp | 2 +- src/sat/sat_solver.cpp | 2 + src/util/union_find.h | 12 ++++ 5 files changed, 115 insertions(+), 19 deletions(-) diff --git a/src/sat/sat_bceq.cpp b/src/sat/sat_bceq.cpp index 54e8d086a..de050525f 100644 --- a/src/sat/sat_bceq.cpp +++ b/src/sat/sat_bceq.cpp @@ -64,6 +64,11 @@ namespace sat { m_bin_clauses.push_back(cls); register_clause(cls); } + TRACE("sat", + for (unsigned i = 0; i < m_clauses.size(); ++i) { + clause const* cls = m_clauses[i]; + if (cls) tout << *cls << "\n"; + }); } void bceq::pure_decompose() { @@ -109,7 +114,7 @@ namespace sat { m_L_blits.resize(sz1+delta1, lit); m_R_blits.resize(sz2+delta2, ~lit); } - std::cout << lit << " " << "pos: " << delta1 << " " << "neg: " << delta2 << "\n"; + TRACE("bceq", tout << lit << " " << "pos: " << delta1 << " " << "neg: " << delta2 << "\n";); } void bceq::pure_decompose(clause_use_list& uses, svector& clauses) { @@ -134,24 +139,88 @@ namespace sat { for (unsigned i = 0; i < m_L.size(); ++i) { ul.insert(*m_L[i]); } +#define MOVE_R_TO_L \ + + // cheap pass: add clauses from R in order + // such that they are blocked with respect to + // predecessors. + m_removed.reset(); for (unsigned i = 0; i < m_R.size(); ++i) { literal lit = find_blocked(*m_R[i]); if (lit != null_literal) { - m_L.push_back(m_R[i]); - m_L_blits.push_back(lit); - ul.insert(*m_R[i]); + m_L.push_back(m_R[i]); + m_L_blits.push_back(lit); + ul.insert(*m_R[i]); + m_R[i] = m_R.back(); + m_R_blits[i] = m_R_blits.back(); + m_R.pop_back(); + m_R_blits.pop_back(); + --i; + } + } + // expensive pass: add clauses from R as long + // as BCE produces the empty set of clauses. + for (unsigned i = 0; i < m_R.size(); ++i) { + if (bce(*m_R[i])) { m_R[i] = m_R.back(); m_R_blits[i] = m_R_blits.back(); m_R.pop_back(); m_R_blits.pop_back(); --i; } - } + } m_use_list = save; } + bool bceq::bce(clause& cls) { + svector live_clauses; + use_list ul; + use_list* save = m_use_list; + m_use_list = &ul; + ul.init(m_solver.num_vars()); + for (unsigned i = 0; i < m_L.size(); ++i) { + ul.insert(*m_L[i]); + } + ul.insert(cls); + svector clauses(m_L), new_clauses; + literal_vector blits(m_L_blits), new_blits; + clauses.push_back(&cls); + blits.push_back(null_literal); + bool removed = false; + m_removed.reset(); + do { + removed = false; + for (unsigned i = 0; i < clauses.size(); ++i) { + clause& cls = *clauses[i]; + literal lit = find_blocked(cls); + if (lit != null_literal) { + m_removed.setx(cls.id(), true, false); + new_clauses.push_back(&cls); + new_blits.push_back(lit); + removed = true; + clauses[i] = clauses.back(); + blits[i] = blits.back(); + clauses.pop_back(); + blits.pop_back(); + --i; + } + } + } + while (removed); + if (clauses.empty()) { + m_L.reset(); + m_L_blits.reset(); + new_clauses.reverse(); + new_blits.reverse(); + m_L.append(new_clauses); + m_L_blits.append(new_blits); + } + std::cout << "Number left after BCE: " << clauses.size() << "\n"; + return clauses.empty(); + } + literal bceq::find_blocked(clause const& cls) { - std::cout << "find blocker for: " << cls << "\n"; + TRACE("bceq", tout << cls << "\n";); unsigned sz = cls.size(); for (unsigned i = 0; i < sz; ++i) { @@ -161,7 +230,7 @@ namespace sat { for (unsigned i = 0; i < sz; ++i) { literal lit = cls[i]; if (is_blocked(lit)) { - std::cout << "is blocked " << lit << " : " << cls << "\n"; + TRACE("bceq", tout << "is blocked " << lit << " : " << cls << "\n";); result = lit; break; } @@ -178,12 +247,12 @@ namespace sat { while (!it.at_end()) { clause const& cls = it.curr(); unsigned sz = cls.size(); - bool is_axiom = false; + bool is_axiom = m_removed.get(cls.id(), false); for (unsigned i = 0; !is_axiom && i < sz; ++i) { is_axiom = m_marked[cls[i].index()] && cls[i] != ~lit; } - std::cout << "resolvent " << lit << " : " << cls << " " << (is_axiom?"axiom":"non-axiom") << "\n"; + TRACE("bceq", tout << "resolvent " << lit << " : " << cls << " " << (is_axiom?"axiom":"non-axiom") << "\n";); if (!is_axiom) { return false; } @@ -231,8 +300,6 @@ namespace sat { clause const& cls = *m_rstack[i]; literal block_lit = m_bstack[i]; uint64 b = eval_clause(cls); - // std::cout << "Eval: " << block_lit << " " << std::hex << " "; - // std::cout << m_rbits[block_lit.var()] << " " << b << std::dec << "\n"; // v = 0, b = 0 -> v := 1 // v = 0, b = 1 -> v := 0 // v = 1, b = 0 -> v := 0 @@ -278,7 +345,7 @@ namespace sat { table.insert(val, i); } } - union_find.display(std::cout); + TRACE("sat", union_find.display(tout);); // // Preliminary version: @@ -305,7 +372,7 @@ namespace sat { } void bceq::check_equality(unsigned v1, unsigned v2) { - std::cout << "check: " << v1 << " = " << v2 << "\n"; + TRACE("sat", tout << "check: " << v1 << " = " << v2 << "\n";); uint64 val1 = m_rbits[v1]; uint64 val2 = m_rbits[v2]; literal l1 = literal(v1, false); @@ -315,7 +382,7 @@ namespace sat { l2.neg(); } if (is_equiv(l1, l2)) { - std::cout << "Already equivalent: " << l1 << " " << l2 << "\n"; + TRACE("sat", tout << "Already equivalent: " << l1 << " " << l2 << "\n";); return; } @@ -329,10 +396,10 @@ namespace sat { is_sat = m_s->check(2, lits); } if (is_sat == l_false) { - std::cout << "Found equivalent: " << l1 << " " << l2 << "\n"; + TRACE("sat", tout << "Found equivalent: " << l1 << " " << l2 << "\n";); } else { - std::cout << "Not equivalent\n"; + TRACE("sat", tout << "Not equivalent: " << l1 << " " << l2 << "\n";); } } @@ -344,7 +411,7 @@ namespace sat { found = w.is_binary_clause() && w.get_literal() == ~l2; } if (!found) return false; - found = true; + found = false; watch_list const& w2 = m_solver.get_wlist(~l1); for (unsigned i = 0; !found && i < w2.size(); ++i) { watched const& w = w2[i]; @@ -369,7 +436,20 @@ namespace sat { init(); pure_decompose(); post_decompose(); - std::cout << m_L.size() << " vs " << m_R.size() << "\n"; + std::cout << "Decomposed set " << m_L.size() << "\n"; + + TRACE("sat", + tout << "Decomposed set " << m_L.size() << "\n"; + for (unsigned i = 0; i < m_L.size(); ++i) { + clause const* cls = m_L[i]; + if (cls) tout << *cls << "\n"; + } + tout << "remainder " << m_R.size() << "\n"; + for (unsigned i = 0; i < m_R.size(); ++i) { + clause const* cls = m_R[i]; + if (cls) tout << *cls << "\n"; + } + ); sat_sweep(); extract_partition(); cleanup(); diff --git a/src/sat/sat_bceq.h b/src/sat/sat_bceq.h index 7e9a1f632..5552fb255 100644 --- a/src/sat/sat_bceq.h +++ b/src/sat/sat_bceq.h @@ -45,6 +45,7 @@ namespace sat { svector m_rstack; // stack of blocked clauses literal_vector m_bstack; // stack of blocking literals svector m_marked; + svector m_removed; // set of clauses removed (not considered in clause set during BCE) union_find_default_ctx m_union_find_ctx; void init(); @@ -55,6 +56,7 @@ namespace sat { void pure_decompose(clause_use_list& uses, svector& clauses); void post_decompose(); literal find_blocked(clause const& cls); + bool bce(clause& cls); bool is_blocked(literal lit) const; void init_rbits(); void init_reconstruction_stack(); diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 3bb914ad0..937c7735f 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -157,7 +157,7 @@ namespace sat { if (!learned && (m_elim_blocked_clauses || m_elim_blocked_clauses_at == m_num_calls)) elim_blocked_clauses(); -#if 0 +#if 1 // experiment is disabled. if (!learned) { // && m_equality_inference bceq bc(s); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index b81f07e95..d97ebed46 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -20,6 +20,7 @@ Revision History: #include"sat_integrity_checker.h" #include"luby.h" #include"trace.h" +#include"sat_bceq.h" // define to update glue during propagation #define UPDATE_GLUE @@ -959,6 +960,7 @@ namespace sat { m_stopwatch.start(); m_core.reset(); TRACE("sat", display(tout);); + } /** diff --git a/src/util/union_find.h b/src/util/union_find.h index a5c897656..c98ca3fce 100644 --- a/src/util/union_find.h +++ b/src/util/union_find.h @@ -132,6 +132,18 @@ public: CASSERT("union_find", check_invariant()); } + // dissolve equivalence class of v + // this method cannot be used with backtracking. + void dissolve(unsigned v) { + do { + w = next(v); + m_size[v] = 1; + m_find[v] = v; + m_next[v] = v; + } + while (w != v); + } + void display(std::ostream & out) const { unsigned num = get_num_vars(); for (unsigned v = 0; v < num; v++) { From 83a0611cb952167884654baedc267ab0e30a8e8f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 29 Sep 2014 22:15:24 -0700 Subject: [PATCH 592/925] adding option to selectively enable bcd Signed-off-by: Nikolaj Bjorner --- src/sat/sat_bceq.cpp | 2 ++ src/sat/sat_config.cpp | 1 + src/sat/sat_config.h | 1 + src/sat/sat_params.pyg | 1 + 4 files changed, 5 insertions(+) diff --git a/src/sat/sat_bceq.cpp b/src/sat/sat_bceq.cpp index de050525f..65377caed 100644 --- a/src/sat/sat_bceq.cpp +++ b/src/sat/sat_bceq.cpp @@ -428,6 +428,8 @@ namespace sat { void bceq::operator()() { + if (!m_solver.m_config.m_bcd) return; + flet _disable_bcd(m_solver.m_config.m_bcd, false); use_list ul; solver s(m_solver.m_params, 0); m_use_list = &ul; diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 17eda1707..d2a662b64 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -107,6 +107,7 @@ namespace sat { m_minimize_core = p.minimize_core(); m_minimize_core_partial = p.minimize_core_partial(); m_optimize_model = p.optimize_model(); + m_bcd = p.bcd(); m_dyn_sub_res = p.dyn_sub_res(); } diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 044c91989..021810f3d 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -71,6 +71,7 @@ namespace sat { bool m_minimize_core; bool m_minimize_core_partial; bool m_optimize_model; + bool m_bcd; symbol m_always_true; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index b0be62eef..1e2551740 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -21,4 +21,5 @@ def_module_params('sat', ('minimize_core', BOOL, False, 'minimize computed core'), ('minimize_core_partial', BOOL, False, 'apply partial (cheap) core minimization'), ('optimize_model', BOOL, False, 'enable optimization of soft constraints'), + ('bcd', BOOL, False, 'enable blocked clause decomposition for equality extraction'), ('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'))) From 5176cbeefb93d74d99a5b3fa0ef520938ad6b9f7 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 30 Sep 2014 11:26:49 +0100 Subject: [PATCH 593/925] fix printing of TBVs Signed-off-by: Nuno Lopes --- src/muz/rel/tbv.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/rel/tbv.cpp b/src/muz/rel/tbv.cpp index 739443ea0..4ea8f48f6 100644 --- a/src/muz/rel/tbv.cpp +++ b/src/muz/rel/tbv.cpp @@ -268,7 +268,7 @@ bool tbv_manager::intersect(tbv const& a, tbv const& b, tbv& result) { std::ostream& tbv_manager::display(std::ostream& out, tbv const& b, unsigned hi, unsigned lo) const { SASSERT(lo <= hi && hi < num_tbits()); - for (unsigned i = lo; i <= hi; ++i) { + for (unsigned i = hi+1; i-- > lo; ) { switch (b.get(i)) { case BIT_0: out << '0'; From 938a5adafa4d9cda95274fefc64d5ba73af92441 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 30 Sep 2014 13:00:29 +0100 Subject: [PATCH 594/925] DoC: make fold_neg detect empty TBVs Signed-off-by: Nuno Lopes --- src/muz/rel/doc.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/muz/rel/doc.cpp b/src/muz/rel/doc.cpp index e2c0ab162..817317f9f 100644 --- a/src/muz/rel/doc.cpp +++ b/src/muz/rel/doc.cpp @@ -110,12 +110,11 @@ doc& doc_manager::fillX(doc& src) { bool doc_manager::set_and(doc& dst, doc const& src) { // (A \ B) & (C \ D) = (A & C) \ (B u D) if (!m.set_and(dst.pos(), src.pos())) return false; - dst.neg().intersect(m, dst.pos()); + dst.neg().intersect(m, dst.pos()); tbv_ref t(m); for (unsigned i = 0; i < src.neg().size(); ++i) { t = m.allocate(src.neg()[i]); if (m.set_and(*t, dst.pos())) { - if (m.equals(*t, dst.pos())) return false; dst.neg().insert(m, t.detach()); } } @@ -123,10 +122,10 @@ bool doc_manager::set_and(doc& dst, doc const& src) { return fold_neg(dst); } bool doc_manager::set_and(doc& dst, tbv const& src) { - // (A \ B) & C = (A & C) \ B + // (A \ B) & C = (A & C) \ (B & C) if (!m.set_and(dst.pos(), src)) return false; dst.neg().intersect(m, src); - return true; + return fold_neg(dst); } bool doc_manager::well_formed(doc const& d) const { @@ -141,6 +140,9 @@ bool doc_manager::well_formed(doc const& d) const { bool doc_manager::fold_neg(doc& dst) { start_over: for (unsigned i = 0; i < dst.neg().size(); ++i) { + if (m.contains(dst.neg()[i], dst.pos())) + return false; + unsigned index; unsigned count = diff_by_012(dst.pos(), dst.neg()[i], index); if (count != 2) { @@ -498,9 +500,6 @@ bool doc_manager::is_full(doc const& src) const { } bool doc_manager::is_empty(doc const& src) { if (src.neg().size() == 0) return false; - if (src.neg().size() == 1) { - return m.equals(src.pos(), src.neg()[0]); - } return false; #if 0 // buggy: From 1606359dc9ca77091926c00d33ff18eb88a82e4b Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 30 Sep 2014 15:58:38 +0100 Subject: [PATCH 595/925] DoC: add slow path to emptiness detection that uses SMT solving Signed-off-by: Nuno Lopes --- src/muz/rel/dl_instruction.cpp | 2 +- src/muz/rel/dl_relation_manager.cpp | 2 +- src/muz/rel/doc.cpp | 36 ++++++++--------------------- src/muz/rel/doc.h | 13 ++++++++--- src/muz/rel/rel_context.cpp | 4 ++-- src/muz/rel/udoc_relation.cpp | 11 +-------- 6 files changed, 25 insertions(+), 43 deletions(-) diff --git a/src/muz/rel/dl_instruction.cpp b/src/muz/rel/dl_instruction.cpp index bf2f09d56..b2837c710 100644 --- a/src/muz/rel/dl_instruction.cpp +++ b/src/muz/rel/dl_instruction.cpp @@ -307,7 +307,7 @@ namespace datalog { idx_vector::const_iterator end=m_controls.end(); for(; it != end; ++it) { reg_idx r = *it; - if (ctx.reg(r) && !ctx.reg(r)->empty()) { + if (ctx.reg(r) && !ctx.reg(r)->fast_empty()) { return false; } } diff --git a/src/muz/rel/dl_relation_manager.cpp b/src/muz/rel/dl_relation_manager.cpp index e227e469a..a2b16bcf9 100644 --- a/src/muz/rel/dl_relation_manager.cpp +++ b/src/muz/rel/dl_relation_manager.cpp @@ -122,7 +122,7 @@ namespace datalog { relation_map::iterator it = m_relations.begin(); relation_map::iterator end = m_relations.end(); for(; it!=end; ++it) { - if(!it->m_value->empty()) { + if(!it->m_value->fast_empty()) { res.insert(it->m_key); } } diff --git a/src/muz/rel/doc.cpp b/src/muz/rel/doc.cpp index 817317f9f..cc35227cd 100644 --- a/src/muz/rel/doc.cpp +++ b/src/muz/rel/doc.cpp @@ -83,7 +83,6 @@ void doc_manager::deallocate(doc* src) { m.deallocate(&src->pos()); src->neg().reset(m); m_alloc.deallocate(sizeof(doc), src); - // dealloc(src); } void doc_manager::copy(doc& dst, doc const& src) { m.copy(dst.pos(), src.pos()); @@ -118,7 +117,6 @@ bool doc_manager::set_and(doc& dst, doc const& src) { dst.neg().insert(m, t.detach()); } } - SASSERT(well_formed(dst)); return fold_neg(dst); } bool doc_manager::set_and(doc& dst, tbv const& src) { @@ -498,33 +496,19 @@ bool doc_manager::equals(doc const& a, doc const& b) const { bool doc_manager::is_full(doc const& src) const { return src.neg().is_empty() && m.equals(src.pos(), *m_full); } -bool doc_manager::is_empty(doc const& src) { +bool doc_manager::is_empty_complete(ast_manager& m, doc const& src) { if (src.neg().size() == 0) return false; - return false; -#if 0 - // buggy: - tbv_ref pos(m, m.allocate(src.pos())); - for (unsigned i = 0; i < src.neg().size(); ++i) { - bool found = false; - for (unsigned j = 0; !found && j < num_tbits(); ++j) { - tbit b1 = (*pos)[j]; - tbit b2 = src.neg()[i][j]; - found = (b1 != BIT_x && b2 != BIT_x && b1 != b2); - } - for (unsigned j = 0; !found && j < num_tbits(); ++j) { - tbit b1 = (*pos)[j]; - tbit b2 = src.neg()[i][j]; - found = (b1 == BIT_x && b2 != BIT_x); - if (found) { - m.set(*pos, j, neg(b2)); - } - } - if (!found) { - return false; // TBD make complete SAT check. - } + + smt_params fp; + smt::kernel s(m, fp); + expr_ref fml = to_formula(m, src); + s.assert_expr(fml); + lbool res = s.check(); + if (res == l_true) { + return false; } + SASSERT(res == l_false); return true; -#endif } unsigned doc_manager::hash(doc const& src) const { diff --git a/src/muz/rel/doc.h b/src/muz/rel/doc.h index 16e7c5f28..eccdd75b0 100644 --- a/src/muz/rel/doc.h +++ b/src/muz/rel/doc.h @@ -72,7 +72,7 @@ public: doc& fill1(doc& src); doc& fillX(doc& src); bool is_full(doc const& src) const; - bool is_empty(doc const& src); + bool is_empty_complete(ast_manager& m, doc const& src); bool set_and(doc& dst, doc const& src); bool set_and(doc& dst, tbv const& src); bool fold_neg(doc& dst); @@ -119,10 +119,17 @@ class union_bvec { public: unsigned size() const { return m_elems.size(); } T& operator[](unsigned idx) const { return *m_elems[idx]; } - bool is_empty() const { return m_elems.empty(); } + bool is_empty() const { return m_elems.empty(); } + bool is_empty_complete(ast_manager& m, doc_manager& dm) const { + for (unsigned i = 0; i < size(); ++i) { + if (!dm.is_empty_complete(m, *m_elems[i])) + return false; + } + return true; + } bool is_full(M& m) const { return size() == 1 && m.is_full(*m_elems[0]); } bool contains(M& m, T& t) const { - for (unsigned i = 0; i < m_elems.size(); ++i) { + for (unsigned i = 0; i < size(); ++i) { if (m.contains(*m_elems[i], t)) return true; } return false; diff --git a/src/muz/rel/rel_context.cpp b/src/muz/rel/rel_context.cpp index 4b099c9b4..c5c4d6d95 100644 --- a/src/muz/rel/rel_context.cpp +++ b/src/muz/rel/rel_context.cpp @@ -375,7 +375,7 @@ namespace datalog { for (; it != end; ++it) { func_decl* pred = *it; relation_base & rel = get_relation(pred); - if (!rel.empty()) { + if (!rel.fast_empty()) { non_empty = true; break; } @@ -449,7 +449,7 @@ namespace datalog { bool rel_context::is_empty_relation(func_decl* pred) const { relation_base* rb = try_get_relation(pred); - return !rb || rb->empty(); + return !rb || rb->fast_empty(); } relation_manager & rel_context::get_rmanager() { return m_rmanager; } diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 51e4c33af..4e46a463f 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -21,10 +21,6 @@ Revision History: Notes: Current pending items: - - Fix the incomplete non-emptiness check in doc.cpp - It can fall back to a sat_solver call in the worst case. - The sat_solver.h interface gives a way to add clauses to a sat solver - and check for satisfiability. It can be used from scratch each time. - Profile and fix bottlnecks: - Potential bottleneck in projection exercised in some benchmarks. Projection is asymptotically very expensive. We are here interested in @@ -127,12 +123,7 @@ namespace datalog { m_elems.push_back(fact2doc(f)); } bool udoc_relation::empty() const { - if (m_elems.is_empty()) return true; - // TBD: make this a complete check - for (unsigned i = 0; i < m_elems.size(); ++i) { - if (!dm.is_empty(m_elems[i])) return false; - } - return true; + return m_elems.is_empty_complete(get_plugin().m, dm); } bool udoc_relation::contains_fact(const relation_fact & f) const { doc_ref d(dm, fact2doc(f)); From 8d1177bf3f972f038a6e116574942d8beda9fe68 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 30 Sep 2014 16:24:59 +0100 Subject: [PATCH 596/925] DoC: compact result of substract and maintain invariant Signed-off-by: Nuno Lopes --- src/muz/rel/doc.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/muz/rel/doc.cpp b/src/muz/rel/doc.cpp index cc35227cd..03f69bf5f 100644 --- a/src/muz/rel/doc.cpp +++ b/src/muz/rel/doc.cpp @@ -472,15 +472,15 @@ void doc_manager::subtract(doc const& A, doc const& B, doc_vector& result) { tbv_ref t(m); r = allocate(A); t = m.allocate(B.pos()); - if (m.set_and(*t, A.pos()) && r->neg().insert(m, t.detach())) { - result.push_back(r.detach()); - } - else { - result.push_back(allocate(A)); + if (m.set_and(*t, A.pos())) { + r->neg().insert(m, t.detach()); } + result.push_back(r.detach()); + for (unsigned i = 0; i < B.neg().size(); ++i) { r = allocate(A); if (set_and(*r, B.neg()[i])) { + r->neg().intersect(m, r->pos()); result.push_back(r.detach()); } } From 115ab12ade507eab412fd4c9d2a343b455d43b59 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 30 Sep 2014 17:16:14 +0100 Subject: [PATCH 597/925] DoC: code cleanups Signed-off-by: Nuno Lopes --- src/muz/rel/doc.cpp | 17 ++++++++--------- src/muz/rel/doc.h | 17 ++++++++++------- src/muz/rel/tbv.cpp | 4 ++-- src/muz/rel/tbv.h | 2 +- src/muz/rel/udoc_relation.cpp | 24 +++++++++--------------- 5 files changed, 30 insertions(+), 34 deletions(-) diff --git a/src/muz/rel/doc.cpp b/src/muz/rel/doc.cpp index 03f69bf5f..c8cef5c95 100644 --- a/src/muz/rel/doc.cpp +++ b/src/muz/rel/doc.cpp @@ -280,7 +280,7 @@ bool doc_manager::intersect(doc const& A, doc const& B, doc& result) { // indices where BIT_0 is set are positive. // -doc* doc_manager::project(doc_manager& dstm, unsigned n, bool const* to_delete, doc const& src) { +doc* doc_manager::project(doc_manager& dstm, unsigned n, bit_vector const& to_delete, doc const& src) { tbv_manager& dstt = dstm.m; tbv_ref t(dstt); t = dstt.project(n, to_delete, src.pos()); @@ -391,7 +391,7 @@ doc* doc_manager::project(doc_manager& dstm, unsigned n, bool const* to_delete, doc_manager::project_action_t doc_manager::pick_resolvent( - tbv const& pos, tbv_vector const& neg, bool const* to_delete, unsigned& idx) { + tbv const& pos, tbv_vector const& neg, bit_vector const& to_delete, unsigned& idx) { if (neg.empty()) return project_done; for (unsigned j = 0; j < neg.size(); ++j) { if (m.equals(pos, *neg[j])) return project_is_empty; @@ -401,7 +401,7 @@ doc_manager::pick_resolvent( unsigned best_neg = UINT_MAX; unsigned best_idx = UINT_MAX; for (unsigned i = 0; i < num_tbits(); ++i) { - if (!to_delete[i]) continue; + if (!to_delete.get(i)) continue; if (pos[i] != BIT_x) continue; unsigned num_pos = 0, num_neg = 0; tbit b1 = (*neg[0])[i]; @@ -480,7 +480,6 @@ void doc_manager::subtract(doc const& A, doc const& B, doc_vector& result) { for (unsigned i = 0; i < B.neg().size(); ++i) { r = allocate(A); if (set_and(*r, B.neg()[i])) { - r->neg().intersect(m, r->pos()); result.push_back(r.detach()); } } @@ -566,7 +565,7 @@ std::ostream& doc_manager::display(std::ostream& out, doc const& b, unsigned hi, } -void doc_manager::verify_project(ast_manager& m, doc_manager& dstm, bool const* to_delete, doc const& src, doc const& dst) { +void doc_manager::verify_project(ast_manager& m, doc_manager& dstm, bit_vector const& to_delete, doc const& src, doc const& dst) { expr_ref fml1 = to_formula(m, src); expr_ref fml2 = dstm.to_formula(m, dst); project_rename(fml2, to_delete); @@ -603,11 +602,11 @@ expr_ref doc_manager::to_formula(ast_manager& m, doc const& src) { return result; } -void doc_manager::project_expand(expr_ref& fml, bool const* to_delete) { +void doc_manager::project_expand(expr_ref& fml, bit_vector const& to_delete) { ast_manager& m = fml.get_manager(); expr_ref tmp1(m), tmp2(m); for (unsigned i = 0; i < num_tbits(); ++i) { - if (to_delete[i]) { + if (to_delete.get(i)) { expr_safe_replace rep1(m), rep2(m); rep1.insert(tbvm().mk_var(m, i), m.mk_true()); rep1(fml, tmp1); @@ -623,11 +622,11 @@ void doc_manager::project_expand(expr_ref& fml, bool const* to_delete) { } } -void doc_manager::project_rename(expr_ref& fml, bool const* to_delete) { +void doc_manager::project_rename(expr_ref& fml, bit_vector const& to_delete) { ast_manager& m = fml.get_manager(); expr_safe_replace rep(m); for (unsigned i = 0, j = 0; i < num_tbits(); ++i) { - if (!to_delete[i]) { + if (!to_delete.get(i)) { rep.insert(tbvm().mk_var(m, j), tbvm().mk_var(m, i)); ++j; } diff --git a/src/muz/rel/doc.h b/src/muz/rel/doc.h index eccdd75b0..145f8d456 100644 --- a/src/muz/rel/doc.h +++ b/src/muz/rel/doc.h @@ -48,7 +48,7 @@ class doc_manager { project_resolve }; project_action_t pick_resolvent( - tbv const& pos, tbv_vector const& neg, bool const* to_delete, unsigned& idx); + tbv const& pos, tbv_vector const& neg, bit_vector const& to_delete, unsigned& idx); public: doc_manager(unsigned num_bits); ~doc_manager(); @@ -88,17 +88,17 @@ public: std::ostream& display(std::ostream& out, doc const& b) const; std::ostream& display(std::ostream& out, doc const& b, unsigned hi, unsigned lo) const; unsigned num_tbits() const { return m.num_tbits(); } - doc* project(doc_manager& dstm, unsigned n, bool const* to_delete, doc const& src); + doc* project(doc_manager& dstm, unsigned n, bit_vector const& to_delete, doc const& src); bool well_formed(doc const& d) const; bool merge(doc& d, unsigned lo, unsigned length, subset_ints const& equalities, bit_vector const& discard_cols); void set(doc& d, unsigned idx, tbit value); - void verify_project(ast_manager& m, doc_manager& dstm, bool const* to_delete, doc const& src, doc const& dst); + void verify_project(ast_manager& m, doc_manager& dstm, bit_vector const& to_delete, doc const& src, doc const& dst); private: unsigned diff_by_012(tbv const& pos, tbv const& neg, unsigned& index); bool merge(doc& d, unsigned idx, subset_ints const& equalities, bit_vector const& discard_cols); - void project_rename(expr_ref& fml, bool const* to_delete); - void project_expand(expr_ref& fml, bool const* to_delete); + void project_rename(expr_ref& fml, bit_vector const& to_delete); + void project_expand(expr_ref& fml, bit_vector const& to_delete); expr_ref to_formula(ast_manager& m, doc const& src); void check_equiv(ast_manager& m, expr* fml1, expr* fml2); }; @@ -171,11 +171,13 @@ public: SASSERT(t); unsigned sz = size(), j = 0; bool found = false; - for (unsigned i = 0; i < sz; ++i, ++j) { + unsigned i = 0; + for ( ; i < sz; ++i, ++j) { if (m.contains(*m_elems[i], *t)) { found = true; + break; } - if (!found && m.contains(*t, *m_elems[i])) { + if (m.contains(*t, *m_elems[i])) { m.deallocate(m_elems[i]); --j; } @@ -185,6 +187,7 @@ public: } if (j != sz) m_elems.resize(j); if (found) { + SASSERT(j == i); m.deallocate(t); } else { diff --git a/src/muz/rel/tbv.cpp b/src/muz/rel/tbv.cpp index 4ea8f48f6..8e213fadc 100644 --- a/src/muz/rel/tbv.cpp +++ b/src/muz/rel/tbv.cpp @@ -99,11 +99,11 @@ tbv* tbv_manager::allocate(tbv const& bv, unsigned const* permutation) { } return r; } -tbv* tbv_manager::project(unsigned n, bool const* to_delete, tbv const& src) { +tbv* tbv_manager::project(unsigned n, bit_vector const& to_delete, tbv const& src) { tbv* r = allocate(); unsigned i, j; for (i = 0, j = 0; i < n; ++i) { - if (!to_delete[i]) { + if (!to_delete.get(i)) { set(*r, j, src[i]); ++j; } diff --git a/src/muz/rel/tbv.h b/src/muz/rel/tbv.h index 9663f7d04..39067c64c 100644 --- a/src/muz/rel/tbv.h +++ b/src/muz/rel/tbv.h @@ -76,7 +76,7 @@ public: bool intersect(tbv const& a, tbv const& b, tbv& result); std::ostream& display(std::ostream& out, tbv const& b) const; std::ostream& display(std::ostream& out, tbv const& b, unsigned hi, unsigned lo) const; - tbv* project(unsigned n, bool const* to_delete, tbv const& src); + tbv* project(unsigned n, bit_vector const& to_delete, tbv const& src); bool is_well_formed(tbv const& b) const; // - does not contain BIT_z; void set(tbv& dst, uint64 n, unsigned hi, unsigned lo); void set(tbv& dst, rational const& r, unsigned hi, unsigned lo); diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 4e46a463f..459b94101 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -54,9 +54,6 @@ Notes: return tgt \ join_project(tgt, neg, c1, .., cN, d1, .. , dN) We have most of the facilities required for a join project operation. For example, the filter_project function uses both equalities and deleted columns. - - Lipstick service: - - filter_proj_fn uses both a bit_vector and a svector for representing removed bits. - This is due to underlying routines using different types for the same purpose. --*/ #include "udoc_relation.h" #include "dl_relation_manager.h" @@ -473,7 +470,7 @@ namespace datalog { } class udoc_plugin::project_fn : public convenient_relation_project_fn { - svector m_to_delete; + bit_vector m_to_delete; public: project_fn(udoc_relation const & t, unsigned removed_col_cnt, const unsigned * removed_cols) : convenient_relation_project_fn(t.get_signature(), removed_col_cnt, removed_cols) { @@ -481,7 +478,7 @@ namespace datalog { unsigned n = t.get_dm().num_tbits(); m_to_delete.resize(n, false); for (unsigned i = 0; i < m_removed_cols.size(); ++i) { - m_to_delete[m_removed_cols[i]] = true; + m_to_delete.set(m_removed_cols[i], true); } } @@ -496,7 +493,7 @@ namespace datalog { udoc const& ud1 = t.get_udoc(); udoc& ud2 = r->get_udoc(); for (unsigned i = 0; i < ud1.size(); ++i) { - d2 = dm1.project(dm2, m_to_delete.size(), m_to_delete.c_ptr(), ud1[i]); + d2 = dm1.project(dm2, m_to_delete.size(), m_to_delete, ud1[i]); ud2.push_back(d2.detach()); } TRACE("doc", tout << "final size: " << r->get_size_estimate_rows() << '\n';); @@ -1198,8 +1195,7 @@ namespace datalog { expr_ref m_reduced_condition; udoc m_udoc; udoc m_udoc2; - bit_vector m_col_list; // map: col idx -> bool (whether the column is to be removed) - svector m_to_delete; // same + bit_vector m_to_delete; // map: col idx -> bool (whether the column is to be removed) subset_ints m_equalities; unsigned_vector m_roots; @@ -1213,19 +1209,17 @@ namespace datalog { m_equalities(union_ctx) { unsigned num_bits = t.get_num_bits(); t.expand_column_vector(m_removed_cols); - m_col_list.resize(num_bits, false); m_to_delete.resize(num_bits, false); for (unsigned i = 0; i < num_bits; ++i) { m_equalities.mk_var(); } for (unsigned i = 0; i < m_removed_cols.size(); ++i) { - m_col_list.set(m_removed_cols[i], true); - m_to_delete[m_removed_cols[i]] = true; + m_to_delete.set(m_removed_cols[i], true); } expr_ref guard(m), non_eq_cond(condition, m); t.extract_equalities(condition, non_eq_cond, m_equalities, m_roots); t.extract_guard(non_eq_cond, guard, m_reduced_condition); - t.compile_guard(guard, m_udoc, m_col_list); + t.compile_guard(guard, m_udoc, m_to_delete); } virtual ~filter_proj_fn() { @@ -1238,13 +1232,13 @@ namespace datalog { ast_manager& m = m_reduced_condition.get_manager(); m_udoc2.copy(dm, u1); m_udoc2.intersect(dm, m_udoc); - t.apply_guard(m_reduced_condition, m_udoc2, m_equalities, m_col_list); - m_udoc2.merge(dm, m_roots, m_equalities, m_col_list); + t.apply_guard(m_reduced_condition, m_udoc2, m_equalities, m_to_delete); + m_udoc2.merge(dm, m_roots, m_equalities, m_to_delete); SASSERT(m_udoc2.well_formed(dm)); udoc_relation* r = get(t.get_plugin().mk_empty(get_result_signature())); doc_manager& dm2 = r->get_dm(); for (unsigned i = 0; i < m_udoc2.size(); ++i) { - doc* d = dm.project(dm2, m_to_delete.size(), m_to_delete.c_ptr(), m_udoc2[i]); + doc* d = dm.project(dm2, m_to_delete.size(), m_to_delete, m_udoc2[i]); r->get_udoc().insert(dm2, d); SASSERT(r->get_udoc().well_formed(dm2)); } From cbe23c428fd3cd9340b07e6fe96fd67f0bcb90a9 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 1 Oct 2014 16:08:44 +0100 Subject: [PATCH 598/925] fix build of unit tests Signed-off-by: Nuno Lopes --- src/test/doc.cpp | 51 +++++++++++++++++++++++++----------------------- src/test/tbv.cpp | 9 +++++---- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/src/test/doc.cpp b/src/test/doc.cpp index 3dcf57613..731bc100f 100644 --- a/src/test/doc.cpp +++ b/src/test/doc.cpp @@ -73,23 +73,24 @@ static void tst_doc1(unsigned n) { m.display(std::cout, *d1) << "\n"; - svector to_delete(n, false); - to_delete[1] = true; - to_delete[3] = true; + bit_vector to_delete; + to_delete.resize(n, false); + to_delete.set(1); + to_delete.set(3); doc_manager m1(n-2); - doc_ref d1_1(m1, m.project(m1, n, to_delete.c_ptr(), *d1)); + doc_ref d1_1(m1, m.project(m1, n, to_delete, *d1)); doc_ref d1_2(m1, m1.allocate1()); m.display(std::cout, *d1) << " -> "; m1.display(std::cout, *d1_1) << "\n"; SASSERT(m1.equals(*d1_1,*d1_2)); m.set(*d1,2,BIT_x); m.set(*d1,4,BIT_x); - d1_1 = m.project(m1, n, to_delete.c_ptr(), *d1); + d1_1 = m.project(m1, n, to_delete, *d1); m.display(std::cout, *d1) << " -> "; m1.display(std::cout, *d1_1) << "\n"; d1->neg().push_back(m.tbvm().allocate1()); SASSERT(m.well_formed(*d1)); - d1_1 = m.project(m1, n, to_delete.c_ptr(), *d1); + d1_1 = m.project(m1, n, to_delete, *d1); m.display(std::cout, *d1) << " -> "; m1.display(std::cout, *d1_1) << "\n"; } @@ -216,11 +217,11 @@ class test_doc_cls { return result; } - void project(doc const& d, doc_manager& m2, bool const* to_delete, doc_ref& result) { + void project(doc const& d, doc_manager& m2, const bit_vector& to_delete, doc_ref& result) { result = dm.project(m2, m_vars.size(), to_delete, d); TRACE("doc", for (unsigned i = 0; i < m_vars.size(); ++i) { - tout << (to_delete[i]?"0":"1"); + tout << (to_delete.get(i)?"0":"1"); } tout << " "; dm.display(tout, d) << " -> "; @@ -234,28 +235,29 @@ class test_doc_cls { d = mk_rand_doc(3); expr_ref fml1(m), fml2(m), fml3(m), tmp1(m), tmp2(m), fml(m); fml1 = to_formula(*d, dm); - svector to_delete(m_vars.size(), false); + bit_vector to_delete; + to_delete.reserve(m_vars.size(), false); unsigned num_bits = 1; for (unsigned i = 1; i < to_delete.size(); ++i) { - to_delete[i] = (m_ran(2) == 0); - if (!to_delete[i]) ++num_bits; + to_delete.set(i, m_ran(2) == 0); + if (!to_delete.get(i)) ++num_bits; } doc_manager m2(num_bits); doc_ref result(m2); - project(*d, m2, to_delete.c_ptr(), result); + project(*d, m2, to_delete, result); TRACE("doc", dm.display(tout, *d) << "\n"; m2.display(tout, *result) << "\n";); fml2 = to_formula(*result, m2); - project_expand(fml1, to_delete.c_ptr()); - project_rename(fml2, to_delete.c_ptr()); + project_expand(fml1, to_delete); + project_rename(fml2, to_delete); check_equiv(fml1, fml2); } - void project_expand(expr_ref& fml, bool const* to_delete) { + void project_expand(expr_ref& fml, bit_vector const& to_delete) { expr_ref tmp1(m), tmp2(m); for (unsigned i = 0; i < m_vars.size(); ++i) { - if (to_delete[i]) { + if (to_delete.get(i)) { expr_safe_replace rep1(m), rep2(m); rep1.insert(m_vars[i].get(), m.mk_true()); rep1(fml, tmp1); @@ -271,10 +273,10 @@ class test_doc_cls { } } - void project_rename(expr_ref& fml, bool const* to_delete) { + void project_rename(expr_ref& fml, bit_vector const& to_delete) { expr_safe_replace rep(m); for (unsigned i = 0, j = 0; i < m_vars.size(); ++i) { - if (!to_delete[i]) { + if (!to_delete.get(i)) { rep.insert(m_vars[j].get(), m_vars[i].get()); ++j; } @@ -293,7 +295,7 @@ class test_doc_cls { d->neg().push_back(t); } fml1 = mk_and(m, fmls.size(), fmls.c_ptr()); - svector to_merge(N, false), to_delete(N, false); + svector to_merge(N, false); bit_vector discard_cols; discard_cols.resize(N, false); unsigned num_bits = 1; @@ -371,17 +373,18 @@ public: dm.tbvm().set(*t, 0, BIT_0); d->neg().push_back(t.detach()); unsigned num_bits = dm.num_tbits(); - svector to_delete(num_bits, false); + bit_vector to_delete; + to_delete.reserve(num_bits, false); fml1 = to_formula(*d, dm); - to_delete[0] = true; + to_delete.set(0, true); doc_manager m2(num_bits-1); doc_ref result(m2); - project(*d, m2, to_delete.c_ptr(), result); + project(*d, m2, to_delete, result); dm.display(std::cout, *d) << "\n"; m2.display(std::cout, *result) << "\n"; fml2 = to_formula(*result, m2); - project_rename(fml2, to_delete.c_ptr()); - project_expand(fml1, to_delete.c_ptr()); + project_rename(fml2, to_delete); + project_expand(fml1, to_delete); std::cout << fml1 << " " << fml2 << "\n"; check_equiv(fml1, fml2); } diff --git a/src/test/tbv.cpp b/src/test/tbv.cpp index 70a07d3f5..dc2867f58 100644 --- a/src/test/tbv.cpp +++ b/src/test/tbv.cpp @@ -25,13 +25,14 @@ static void tst1(unsigned num_bits) { SASSERT(m.equals(*b0, *bN)); VERIFY(!m.intersect(*b0,*b1,*bN)); m.fill1(*b1); - svector to_delete(num_bits, false); + bit_vector to_delete; + to_delete.reserve(num_bits, false); tbv_manager m2(num_bits-2); - to_delete[1] = true; - to_delete[3] = true; + to_delete.set(1); + to_delete.set(3); m.set(*b1, 2, BIT_0); m.set(*b1, 4, BIT_x); - tbv_ref b2(m2, m2.project(num_bits, to_delete.c_ptr(), *b1)); + tbv_ref b2(m2, m2.project(num_bits, to_delete, *b1)); m.display(std::cout, *b1) << " -> "; m2.display(std::cout, *b2) << "\n"; m.deallocate(b0); From 5211e9aa1a4dc41900680eefb4e8709120c44703 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 1 Oct 2014 17:10:35 +0100 Subject: [PATCH 599/925] DoC: compact result of subtract Signed-off-by: Nuno Lopes --- src/muz/rel/doc.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/muz/rel/doc.cpp b/src/muz/rel/doc.cpp index c8cef5c95..9668039cf 100644 --- a/src/muz/rel/doc.cpp +++ b/src/muz/rel/doc.cpp @@ -475,7 +475,8 @@ void doc_manager::subtract(doc const& A, doc const& B, doc_vector& result) { if (m.set_and(*t, A.pos())) { r->neg().insert(m, t.detach()); } - result.push_back(r.detach()); + if (fold_neg(*r)) + result.push_back(r.detach()); for (unsigned i = 0; i < B.neg().size(); ++i) { r = allocate(A); From 04b5d436b3f0df6f512f25606dfac3735eede2b5 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 1 Oct 2014 18:03:59 +0100 Subject: [PATCH 600/925] DoC: fix fast path of filter_negated Signed-off-by: Nuno Lopes --- src/muz/rel/doc.cpp | 13 +++++---- src/muz/rel/doc.h | 5 ++-- src/muz/rel/tbv.cpp | 16 ++++------- src/muz/rel/tbv.h | 5 ++-- src/muz/rel/udoc_relation.cpp | 34 ++++++++---------------- src/test/udoc_relation.cpp | 50 +++++++++++++++++++++++++++++++++++ 6 files changed, 76 insertions(+), 47 deletions(-) diff --git a/src/muz/rel/doc.cpp b/src/muz/rel/doc.cpp index 9668039cf..e5a6fd97f 100644 --- a/src/muz/rel/doc.cpp +++ b/src/muz/rel/doc.cpp @@ -536,16 +536,15 @@ bool doc_manager::contains(doc const& a, doc const& b) const { return true; } -bool doc_manager::contains( - unsigned offset_a, doc const& a, - doc_manager const& dm_b, - unsigned offset_b, doc const& b, - unsigned length) const { - if (!m.contains(offset_a, a.pos(), dm_b.tbvm(), offset_b, b.pos(), length)) return false; +bool doc_manager::contains(doc const& a, unsigned_vector const& colsa, + doc const& b, unsigned_vector const& colsb) const { + if (!m.contains(a.pos(), colsa, b.pos(), colsb)) + return false; + for (unsigned i = 0; i < a.neg().size(); ++i) { bool found = false; for (unsigned j = 0; !found && j < b.neg().size(); ++j) { - found = dm_b.tbvm().contains(offset_b, b.neg()[j], tbvm(), offset_a, a.neg()[i], length); + found = m.contains(b.neg()[j], colsb, a.neg()[i], colsa); } if (!found) return false; } diff --git a/src/muz/rel/doc.h b/src/muz/rel/doc.h index 145f8d456..75b4e9499 100644 --- a/src/muz/rel/doc.h +++ b/src/muz/rel/doc.h @@ -82,9 +82,8 @@ public: bool equals(doc const& a, doc const& b) const; unsigned hash(doc const& src) const; bool contains(doc const& a, doc const& b) const; - bool contains(unsigned offset_a, doc const& a, - doc_manager const& dm_b, unsigned offset_b, doc const& b, - unsigned length) const; + bool contains(doc const& a, unsigned_vector const& colsa, + doc const& b, unsigned_vector const& colsb) const; std::ostream& display(std::ostream& out, doc const& b) const; std::ostream& display(std::ostream& out, doc const& b, unsigned hi, unsigned lo) const; unsigned num_tbits() const { return m.num_tbits(); } diff --git a/src/muz/rel/tbv.cpp b/src/muz/rel/tbv.cpp index 8e213fadc..9c71b826c 100644 --- a/src/muz/rel/tbv.cpp +++ b/src/muz/rel/tbv.cpp @@ -245,18 +245,12 @@ bool tbv_manager::contains(tbv const& a, tbv const& b) const { return m.contains(a, b); } -bool tbv_manager::contains(unsigned offset_a, tbv const& a, - tbv_manager const& dm_b, unsigned offset_b, tbv const& b, - unsigned length) const { - if (this == &dm_b && length == num_tbits()) { - SASSERT(offset_a == 0); - SASSERT(offset_b == 0); - return m.contains(a, b); - } - for (unsigned i = 0; i < length; ++i) { - tbit bit_a = a[offset_a + i]; +bool tbv_manager::contains(tbv const& a, unsigned_vector const& colsa, + tbv const& b, unsigned_vector const& colsb) const { + for (unsigned i = 0; i < colsa.size(); ++i) { + tbit bit_a = a[colsa[i]]; if (bit_a == BIT_x) continue; - if (bit_a != b[offset_b + i]) return false; + if (bit_a != b[colsb[i]]) return false; } return true; } diff --git a/src/muz/rel/tbv.h b/src/muz/rel/tbv.h index 39067c64c..941853a1b 100644 --- a/src/muz/rel/tbv.h +++ b/src/muz/rel/tbv.h @@ -70,9 +70,8 @@ public: bool equals(tbv const& a, tbv const& b) const; unsigned hash(tbv const& src) const; bool contains(tbv const& a, tbv const& b) const; - bool contains(unsigned offset_a, tbv const& a, - tbv_manager const& dm_b, unsigned offset_b, tbv const& b, - unsigned length) const; + bool contains(tbv const& a, unsigned_vector const& colsa, + tbv const& b, unsigned_vector const& colsb) const; bool intersect(tbv const& a, tbv const& b, tbv& result); std::ostream& display(std::ostream& out, tbv const& b) const; std::ostream& display(std::ostream& out, tbv const& b, unsigned hi, unsigned lo) const; diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 459b94101..10c01ccdd 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -1064,14 +1064,16 @@ namespace datalog { // 4. Unit/stress test cases are needed. // class udoc_plugin::negation_filter_fn : public relation_intersection_filter_fn { - const unsigned_vector m_t_cols; - const unsigned_vector m_neg_cols; + unsigned_vector m_t_cols; + unsigned_vector m_neg_cols; public: negation_filter_fn(const udoc_relation & r, const udoc_relation & neg, unsigned joined_col_cnt, const unsigned *t_cols, const unsigned *neg_cols) : m_t_cols(joined_col_cnt, t_cols), m_neg_cols(joined_col_cnt, neg_cols) { SASSERT(joined_col_cnt > 0); + r.expand_column_vector(m_t_cols); + neg.expand_column_vector(m_neg_cols); } virtual void operator()(relation_base& tb, const relation_base& negb) { @@ -1086,30 +1088,16 @@ namespace datalog { udoc result; for (unsigned i = 0; i < dst.size(); ++i) { + bool subsumed = false; for (unsigned j = 0; j < neg.size(); ++j) { - for (unsigned c = 0; c < m_t_cols.size(); ++c) { - unsigned t_col = m_t_cols[c]; - unsigned n_col = m_neg_cols[c]; - unsigned num_bits = t.column_num_bits(t_col); - SASSERT(num_bits == n.column_num_bits(n_col)); - unsigned t_idx = t.column_idx(t_col); - unsigned n_idx = n.column_idx(n_col); - bool cont = dmn.contains(n_idx, neg[j], dmt, t_idx, dst[i], num_bits); - IF_VERBOSE( - 3, - dmt.display(verbose_stream() << "dst:", dst[i], t_idx+num_bits-1,t_idx) << "\n"; - dmn.display(verbose_stream() << "neg:", neg[j], n_idx+num_bits-1,n_idx) << "\n"; - verbose_stream() << "contains: " << (cont?"true":"false") << "\n";); - if (!cont) { - goto next_neg_disj; - } + if (dmn.contains(neg[j], m_neg_cols, dst[i], m_t_cols)) { + dmt.deallocate(&dst[i]); + subsumed = true; + break; } - dmt.deallocate(&dst[i]); - goto next_disj; - next_neg_disj:; } - result.push_back(&dst[i]); - next_disj:; + if (!subsumed) + result.push_back(&dst[i]); } std::swap(dst, result); if (dst.is_empty()) { diff --git a/src/test/udoc_relation.cpp b/src/test/udoc_relation.cpp index 523d4e4db..094e755ac 100644 --- a/src/test/udoc_relation.cpp +++ b/src/test/udoc_relation.cpp @@ -148,6 +148,7 @@ public: test_rename(); test_filter_neg(); + test_filter_neg2(); // empty @@ -551,6 +552,55 @@ public: t2->deallocate(); } + void test_filter_neg2() { + // filter_by_negation + relation_signature sig4; + sig4.push_back(bv.mk_sort(1)); + sig4.push_back(bv.mk_sort(1)); + sig4.push_back(bv.mk_sort(1)); + unsigned_vector cols, allcols; + + cols.push_back(0); + cols.push_back(2); + allcols.push_back(0); + allcols.push_back(1); + allcols.push_back(2); + + /// xxx \ 1x0 + udoc_relation* t1 = mk_full(sig4); + { + udoc_relation* neg = mk_full(sig4); + doc& n = neg->get_udoc()[0]; + neg->get_dm().set(n, 0, BIT_1); + neg->get_dm().set(n, 2, BIT_0); + apply_filter_neg(*t1, *neg, allcols, allcols); + neg->deallocate(); + } + + /// xxx \ (1x1 u 0x0) + udoc_relation* t2 = mk_full(sig4); + { + udoc_relation* neg = mk_full(sig4); + doc& n = neg->get_udoc()[0]; + neg->get_dm().set(n, 0, BIT_0); + neg->get_dm().set(n, 2, BIT_0); + apply_filter_neg(*t2, *neg, allcols, allcols); + neg->deallocate(); + } + { + udoc_relation* neg = mk_full(sig4); + doc& n = neg->get_udoc()[0]; + neg->get_dm().set(n, 0, BIT_1); + neg->get_dm().set(n, 2, BIT_1); + apply_filter_neg(*t2, *neg, allcols, allcols); + neg->deallocate(); + } + + apply_filter_neg(*t2, *t1, cols, cols); + t1->deallocate(); + t2->deallocate(); + } + void set_random(udoc_relation& r, unsigned num_vals) { unsigned num_bits = r.get_dm().num_tbits(); udoc_relation* full = mk_full(r.get_signature()); From cce287eed1e7d3162e655c651c2e5c0b3cb57473 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 1 Oct 2014 12:51:40 -0700 Subject: [PATCH 601/925] fix bug in Shannon decomposition for translating PB constraints into formulas Signed-off-by: Nikolaj Bjorner --- .../rewriter/bit_blaster/bit_blaster_rewriter.cpp | 3 +++ src/smt/smt_context.cpp | 3 ++- src/tactic/arith/card2bv_tactic.cpp | 14 +++++++++++--- src/tactic/tactic.cpp | 6 ++++-- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp index 63843d31e..42d51e706 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp +++ b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp @@ -335,6 +335,9 @@ MK_PARAMETRIC_UNARY_REDUCE(reduce_sign_extend, mk_sign_extend); SASSERT(num == 2); if (butil().is_bv(args[0])) { reduce_eq(args[0], args[1], result); + std::cout << "reduce eq: " << mk_pp(args[0], m()) << "\n" << mk_pp(args[1], m()) << "\n"; + std::cout << mk_pp(result, m()) << "\n"; + return BR_DONE; } return BR_FAILED; diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index d86b2da77..f68df30ab 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -2872,7 +2872,7 @@ namespace smt { // mark_as_relevant(l); <<< not needed // internalize_assertion marked l as relevant. SASSERT(is_relevant(l)); - TRACE("assumptions", tout << mk_pp(curr_assumption, m_manager) << "\n";); + TRACE("assumptions", tout << l << ":" << mk_pp(curr_assumption, m_manager) << "\n";); if (m_manager.proofs_enabled()) assign(l, mk_justification(justification_proof_wrapper(*this, pr))); else @@ -2907,6 +2907,7 @@ namespace smt { literal l = *it; TRACE("unsat_core_bug", tout << "answer literal: " << l << "\n";); SASSERT(get_bdata(l.var()).m_assumption); + if (!m_literal2assumption.contains(l.index())) l.neg(); SASSERT(m_literal2assumption.contains(l.index())); expr * a = m_literal2assumption[l.index()]; if (!already_found_assumptions.contains(a)) { diff --git a/src/tactic/arith/card2bv_tactic.cpp b/src/tactic/arith/card2bv_tactic.cpp index 5f9f28898..e5f699eaa 100644 --- a/src/tactic/arith/card2bv_tactic.cpp +++ b/src/tactic/arith/card2bv_tactic.cpp @@ -221,6 +221,7 @@ namespace pb { default: UNREACHABLE(); } + TRACE("card2bv", tout << result << "\n";); } struct argc_t { @@ -268,6 +269,8 @@ namespace pb { SASSERT(argcs[i].m_coeff >= argcs[i+1].m_coeff); } ); + result = m.mk_app(f, sz, args); + TRACE("card2bv", tout << result << "\n";); argc_cache cache; expr_ref_vector trail(m); vector todo_k; @@ -277,7 +280,7 @@ namespace pb { decl_kind kind = f->get_decl_kind(); argc_entry entry1; while (!todo_i.empty()) { - + SASSERT(todo_i.size() == todo_k.size()); if (cache.size() > max_clauses) { return BR_FAILED; } @@ -307,13 +310,17 @@ namespace pb { break; case OP_AT_LEAST_K: case OP_PB_GE: - if (coeff < k) { + if (k.is_zero()) { + entry.m_value = m.mk_true(); + } + else if (coeff < k) { entry.m_value = m.mk_false(); } else if (coeff.is_zero()) { entry.m_value = m.mk_true(); } else { + SASSERT(coeff >= k && k.is_pos()); entry.m_value = arg; } break; @@ -345,7 +352,7 @@ namespace pb { todo_k.push_back(k); } entry.m_k -= coeff; - if (kind != OP_PB_EQ && entry.m_k.is_neg()) { + if (kind != OP_PB_EQ && !entry.m_k.is_pos()) { switch (kind) { case OP_AT_MOST_K: case OP_PB_LE: @@ -379,6 +386,7 @@ namespace pb { argc_entry entry(0, pb.get_k(f)); VERIFY(cache.find(entry, entry)); result = entry.m_value; + TRACE("card2bv", tout << result << "\n";); return BR_DONE; } diff --git a/src/tactic/tactic.cpp b/src/tactic/tactic.cpp index 198872cf5..9b4f42a71 100644 --- a/src/tactic/tactic.cpp +++ b/src/tactic/tactic.cpp @@ -41,11 +41,13 @@ struct tactic_report::imp { goal const & m_goal; stopwatch m_watch; double m_start_memory; + unsigned m_start_exprs; imp(char const * id, goal const & g): m_id(id), m_goal(g), - m_start_memory(static_cast(memory::get_allocation_size())/static_cast(1024*1024)) { + m_start_memory(static_cast(memory::get_allocation_size())/static_cast(1024*1024)), + m_start_exprs(g.num_exprs()){ m_watch.start(); } @@ -53,7 +55,7 @@ struct tactic_report::imp { m_watch.stop(); double end_memory = static_cast(memory::get_allocation_size())/static_cast(1024*1024); verbose_stream() << "(" << m_id - << " :num-exprs " << m_goal.num_exprs() + << " :num-exprs " << m_start_exprs << " -> " << m_goal.num_exprs() << " :num-asts " << m_goal.m().get_num_asts() << " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << " :before-memory " << std::fixed << std::setprecision(2) << m_start_memory From 0914748184e468935819200f5fbf1a77c9da62b5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 1 Oct 2014 12:56:00 -0700 Subject: [PATCH 602/925] revert changes to tactic.cpp Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp | 3 --- src/tactic/tactic.cpp | 6 ++---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp index 42d51e706..63843d31e 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp +++ b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp @@ -335,9 +335,6 @@ MK_PARAMETRIC_UNARY_REDUCE(reduce_sign_extend, mk_sign_extend); SASSERT(num == 2); if (butil().is_bv(args[0])) { reduce_eq(args[0], args[1], result); - std::cout << "reduce eq: " << mk_pp(args[0], m()) << "\n" << mk_pp(args[1], m()) << "\n"; - std::cout << mk_pp(result, m()) << "\n"; - return BR_DONE; } return BR_FAILED; diff --git a/src/tactic/tactic.cpp b/src/tactic/tactic.cpp index 9b4f42a71..198872cf5 100644 --- a/src/tactic/tactic.cpp +++ b/src/tactic/tactic.cpp @@ -41,13 +41,11 @@ struct tactic_report::imp { goal const & m_goal; stopwatch m_watch; double m_start_memory; - unsigned m_start_exprs; imp(char const * id, goal const & g): m_id(id), m_goal(g), - m_start_memory(static_cast(memory::get_allocation_size())/static_cast(1024*1024)), - m_start_exprs(g.num_exprs()){ + m_start_memory(static_cast(memory::get_allocation_size())/static_cast(1024*1024)) { m_watch.start(); } @@ -55,7 +53,7 @@ struct tactic_report::imp { m_watch.stop(); double end_memory = static_cast(memory::get_allocation_size())/static_cast(1024*1024); verbose_stream() << "(" << m_id - << " :num-exprs " << m_start_exprs << " -> " << m_goal.num_exprs() + << " :num-exprs " << m_goal.num_exprs() << " :num-asts " << m_goal.m().get_num_asts() << " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << " :before-memory " << std::fixed << std::setprecision(2) << m_start_memory From 0b1c180808472b615148f65f266778f623d78ccb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 1 Oct 2014 13:49:23 -0700 Subject: [PATCH 603/925] fix lexicographic product for MaxSMT Signed-off-by: Nikolaj Bjorner --- src/opt/bcd2.cpp | 6 +-- src/opt/fu_malik.cpp | 104 ++++++++++++++-------------------------- src/opt/fu_malik.h | 17 +------ src/opt/maxhs.cpp | 8 ++-- src/opt/maxres.cpp | 32 ++++++++++--- src/opt/maxsls.cpp | 2 +- src/opt/maxsmt.cpp | 42 ++++++++-------- src/opt/maxsmt.h | 8 ++-- src/opt/opt_context.cpp | 5 +- src/opt/wmax.cpp | 2 +- 10 files changed, 96 insertions(+), 130 deletions(-) diff --git a/src/opt/bcd2.cpp b/src/opt/bcd2.cpp index bf041a6bd..766e0d84a 100644 --- a/src/opt/bcd2.cpp +++ b/src/opt/bcd2.cpp @@ -187,7 +187,7 @@ namespace opt { expr_ref fml(m); expr* r = m_soft_aux[i].get(); m_soft2index.insert(r, i); - fml = m.mk_or(r, m_soft[i].get()); + fml = m.mk_or(r, m_soft[i]); m_soft_constraints.push_back(fml); m_asm_set.insert(r); SASSERT(m_weights[i].is_int()); @@ -233,7 +233,7 @@ namespace opt { new_assignment.reset(); s().get_model(model); for (unsigned i = 0; i < m_soft.size(); ++i) { - VERIFY(model->eval(m_soft[i].get(), val)); + VERIFY(model->eval(m_soft[i], val)); new_assignment.push_back(m.is_true(val)); if (!new_assignment[i]) { new_upper += m_weights[i]; @@ -393,7 +393,7 @@ namespace opt { out << "[" << c.m_lower << ":" << c.m_mid << ":" << c.m_upper << "]\n"; } for (unsigned i = 0; i < m_soft.size(); ++i) { - out << mk_pp(m_soft[i].get(), m) << " " << m_weights[i] << "\n"; + out << mk_pp(m_soft[i], m) << " " << m_weights[i] << "\n"; } } }; diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index b410a102e..6d2386b96 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -43,34 +43,24 @@ Notes: */ namespace opt { - struct fu_malik::imp { - ast_manager& m; - solver& m_s; + class fu_malik : public maxsmt_solver_base { filter_model_converter& m_fm; - expr_ref_vector m_soft; - expr_ref_vector m_orig_soft; + expr_ref_vector m_aux_soft; expr_ref_vector m_aux; - svector m_assignment; - unsigned m_upper; - unsigned m_lower; model_ref m_model; - imp(context& c, expr_ref_vector const& soft): - m(c.get_manager()), - m_s(c.get_solver()), + public: + fu_malik(context& c, weights_t& ws, expr_ref_vector const& soft): + maxsmt_solver_base(c, ws, soft), m_fm(c.fm()), - m_soft(soft), - m_orig_soft(soft), - m_aux(m), - m_upper(0), - m_lower(0) + m_aux_soft(soft), + m_aux(m) { - m_upper = m_soft.size() + 1; - m_assignment.resize(m_soft.size(), false); + m_upper = rational(m_aux_soft.size() + 1); + m_lower.reset(); + m_assignment.resize(m_aux_soft.size(), false); } - solver& s() { return m_s; } - /** \brief One step of the Fu&Malik algorithm. @@ -96,9 +86,8 @@ namespace opt { } } - void collect_statistics(statistics& st) const { - st.update("opt-fm-num-steps", m_soft.size() + 2 - m_upper); + st.update("opt-fm-num-steps", m_aux_soft.size() + 2 - m_upper.get_unsigned()); } void set_union(expr_set const& set1, expr_set const& set2, expr_set & set) const { @@ -115,9 +104,9 @@ namespace opt { } lbool step() { - IF_VERBOSE(1, verbose_stream() << "(opt.max_sat step " << m_soft.size() + 2 - m_upper << ")\n";); + IF_VERBOSE(1, verbose_stream() << "(opt.max_sat step " << m_aux_soft.size() + 2 - m_upper.get_unsigned() << ")\n";); expr_ref_vector assumptions(m), block_vars(m); - for (unsigned i = 0; i < m_soft.size(); ++i) { + for (unsigned i = 0; i < m_aux_soft.size(); ++i) { assumptions.push_back(m.mk_not(m_aux[i].get())); } lbool is_sat = s().check_sat(assumptions.size(), assumptions.c_ptr()); @@ -131,7 +120,7 @@ namespace opt { SASSERT(!core.empty()); // Update soft-constraints and aux_vars - for (unsigned i = 0; i < m_soft.size(); ++i) { + for (unsigned i = 0; i < m_aux_soft.size(); ++i) { bool found = false; for (unsigned j = 0; !found && j < core.size(); ++j) { @@ -145,14 +134,14 @@ namespace opt { m_aux[i] = m.mk_fresh_const("aux", m.mk_bool_sort()); m_fm.insert(block_var->get_decl()); m_fm.insert(to_app(m_aux[i].get())->get_decl()); - m_soft[i] = m.mk_or(m_soft[i].get(), block_var); + m_aux_soft[i] = m.mk_or(m_aux_soft[i].get(), block_var); block_vars.push_back(block_var); - tmp = m.mk_or(m_soft[i].get(), m_aux[i].get()); + tmp = m.mk_or(m_aux_soft[i].get(), m_aux[i].get()); s().assert_expr(tmp); } SASSERT (!block_vars.empty()); assert_at_most_one(block_vars); - IF_VERBOSE(1, verbose_stream() << "(opt.max_sat # of non-blocked soft constraints: " << m_soft.size() - block_vars.size() << ")\n";); + IF_VERBOSE(1, verbose_stream() << "(opt.max_sat # of non-blocked soft constraints: " << m_aux_soft.size() - block_vars.size() << ")\n";); return l_false; } @@ -181,9 +170,9 @@ namespace opt { // TBD: bug when cancel flag is set, fu_malik returns is_sat == l_true instead of l_undef - lbool operator()() { + virtual lbool operator()() { lbool is_sat = l_true; - if (m_soft.empty()) { + if (m_aux_soft.empty()) { return is_sat; } solver::scoped_push _sp(s()); @@ -191,14 +180,14 @@ namespace opt { TRACE("opt", tout << "soft constraints:\n"; - for (unsigned i = 0; i < m_soft.size(); ++i) { - tout << mk_pp(m_soft[i].get(), m) << "\n"; + for (unsigned i = 0; i < m_aux_soft.size(); ++i) { + tout << mk_pp(m_aux_soft[i].get(), m) << "\n"; }); - for (unsigned i = 0; i < m_soft.size(); ++i) { + for (unsigned i = 0; i < m_aux_soft.size(); ++i) { m_aux.push_back(m.mk_fresh_const("p", m.mk_bool_sort())); m_fm.insert(to_app(m_aux.back())->get_decl()); - tmp = m.mk_or(m_soft[i].get(), m_aux[i].get()); + tmp = m.mk_or(m_aux_soft[i].get(), m_aux[i].get()); s().assert_expr(tmp); } @@ -209,13 +198,13 @@ namespace opt { while (is_sat == l_false); if (is_sat == l_true) { - // Get a list satisfying m_soft + // Get a list satisfying m_aux_soft s().get_model(m_model); m_lower = m_upper; m_assignment.reset(); - for (unsigned i = 0; i < m_orig_soft.size(); ++i) { + for (unsigned i = 0; i < m_soft.size(); ++i) { expr_ref val(m); - VERIFY(m_model->eval(m_orig_soft[i].get(), val)); + VERIFY(m_model->eval(m_soft[i], val)); TRACE("opt", tout << val << "\n";); m_assignment.push_back(m.is_true(val)); } @@ -227,43 +216,22 @@ namespace opt { return is_sat; } - void get_model(model_ref& mdl) { + virtual void get_model(model_ref& mdl) { mdl = m_model.get(); } + virtual rational get_lower() const { + return rational(m_aux_soft.size())-m_upper; + } + + virtual rational get_upper() const { + return rational(m_aux_soft.size())-m_lower; + } }; - fu_malik::fu_malik(context& c, expr_ref_vector& soft_constraints) { - m_imp = alloc(imp, c, soft_constraints); - } - fu_malik::~fu_malik() { - dealloc(m_imp); - } - - lbool fu_malik::operator()() { - return (*m_imp)(); - } - rational fu_malik::get_lower() const { - return rational(m_imp->m_soft.size()-m_imp->m_upper); - } - rational fu_malik::get_upper() const { - return rational(m_imp->m_soft.size()-m_imp->m_lower); - } - bool fu_malik::get_assignment(unsigned idx) const { - return m_imp->m_assignment[idx]; - } - void fu_malik::set_cancel(bool f) { - // no-op - } - void fu_malik::collect_statistics(statistics& st) const { - m_imp->collect_statistics(st); - } - void fu_malik::get_model(model_ref& m) { - m_imp->get_model(m); + maxsmt_solver_base* mk_fu_malik(context& c, weights_t & ws, expr_ref_vector const& soft) { + return alloc(fu_malik, c, ws, soft); } - void fu_malik::updt_params(params_ref& p) { - // no-op - } }; diff --git a/src/opt/fu_malik.h b/src/opt/fu_malik.h index 8eb363cb6..5eea9fc49 100644 --- a/src/opt/fu_malik.h +++ b/src/opt/fu_malik.h @@ -29,21 +29,8 @@ Notes: namespace opt { - class fu_malik : public maxsmt_solver { - struct imp; - imp* m_imp; - public: - fu_malik(context& c, expr_ref_vector& soft_constraints); - virtual ~fu_malik(); - virtual lbool operator()(); - virtual rational get_lower() const; - virtual rational get_upper() const; - virtual bool get_assignment(unsigned idx) const; - virtual void set_cancel(bool f); - virtual void collect_statistics(statistics& st) const; - virtual void get_model(model_ref& m); - virtual void updt_params(params_ref& p); - }; + maxsmt_solver_base* mk_fu_malik(context& c, weights_t & ws, expr_ref_vector const& soft); + }; diff --git a/src/opt/maxhs.cpp b/src/opt/maxhs.cpp index a7425b22e..6d4a7b8bf 100644 --- a/src/opt/maxhs.cpp +++ b/src/opt/maxhs.cpp @@ -162,7 +162,7 @@ namespace opt { m_aux2index.reset(); m_core_activity.reset(); for (unsigned i = 0; i < sz; ++i) { - bool tt = is_true(m_model, m_soft[i].get()); + bool tt = is_true(m_model, m_soft[i]); m_seed.push_back(tt); m_aux. push_back(mk_fresh(m.mk_bool_sort())); m_aux_active.push_back(false); @@ -380,7 +380,7 @@ namespace opt { if (m_seed[i]) { // already an assumption } - else if (is_true(mdl, m_soft[i].get())) { + else if (is_true(mdl, m_soft[i])) { m_seed[i] = true; m_asms.push_back(m_aux[i].get()); } @@ -420,7 +420,7 @@ namespace opt { } DEBUG_CODE( for (unsigned i = 0; i < num_soft(); ++i) { - SASSERT(is_true(mdl, m_soft[i].get()) == m_seed[i]); + SASSERT(is_true(mdl, m_soft[i]) == m_seed[i]); }); return true; @@ -545,7 +545,7 @@ namespace opt { void ensure_active(unsigned i) { if (!is_active(i)) { expr_ref fml(m); - fml = m.mk_implies(m_aux[i].get(), m_soft[i].get()); + fml = m.mk_implies(m_aux[i].get(), m_soft[i]); s().assert_expr(fml); m_aux_active[i] = true; } diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 79c0ccd72..86c0efb8f 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -84,6 +84,7 @@ private: expr_ref_vector m_trail; strategy_t m_st; rational m_max_upper; + bool m_found_feasible_optimum; bool m_hill_climb; // prefer large weight soft clauses for cores bool m_add_upper_bound_block; // restrict upper bound with constraint unsigned m_max_num_cores; // max number of cores per round. @@ -105,6 +106,7 @@ public: m_mss(c.get_solver(), m), m_trail(m), m_st(st), + m_found_feasible_optimum(false), m_hill_climb(true), m_add_upper_bound_block(false), m_max_num_cores(UINT_MAX), @@ -122,6 +124,8 @@ public: (m.is_not(l, l) && is_uninterp_const(l)); } + + void add_soft(expr* e, rational const& w) { TRACE("opt", tout << mk_pp(e, m) << "\n";); expr_ref asum(m), fml(m); @@ -372,13 +376,14 @@ public: SASSERT(is_true(m_asms[i].get())); }); for (unsigned i = 0; i < m_soft.size(); ++i) { - m_assignment[i] = is_true(m_soft[i].get()); + m_assignment[i] = is_true(m_soft[i]); } m_upper = m_lower; + m_found_feasible_optimum = true; } - lbool operator()() { + virtual lbool operator()() { switch(m_st) { case s_mus: return mus_solver(); @@ -781,7 +786,7 @@ public: rational upper(0); expr_ref tmp(m); for (unsigned i = 0; i < m_soft.size(); ++i) { - expr* n = m_soft[i].get(); + expr* n = m_soft[i]; VERIFY(mdl->eval(n, tmp)); if (!m.is_true(tmp)) { upper += m_weights[i]; @@ -796,7 +801,7 @@ public: m_model = mdl; for (unsigned i = 0; i < m_soft.size(); ++i) { - m_assignment[i] = is_true(m_soft[i].get()); + m_assignment[i] = is_true(m_soft[i]); } m_upper = upper; // verify_assignment(); @@ -811,7 +816,7 @@ public: expr_ref_vector nsoft(m); expr_ref fml(m); for (unsigned i = 0; i < m_soft.size(); ++i) { - nsoft.push_back(mk_not(m, m_soft[i].get())); + nsoft.push_back(mk_not(m, m_soft[i])); } fml = u.mk_lt(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper); s().assert_expr(fml); @@ -864,12 +869,25 @@ public: m_lower.reset(); m_trail.reset(); for (unsigned i = 0; i < m_soft.size(); ++i) { - add_soft(m_soft[i].get(), m_weights[i]); + add_soft(m_soft[i], m_weights[i]); } m_max_upper = m_upper; + m_found_feasible_optimum = false; add_upper_bound_block(); } + virtual void commit_assignment() { + if (m_found_feasible_optimum) { + TRACE("opt", tout << "Committing feasible solution\n";); + for (unsigned i = 0; i < m_asms.size(); ++i) { + s().assert_expr(m_asms[i].get()); + } + } + else { + maxsmt_solver_base::commit_assignment(); + } + } + void verify_assignment() { IF_VERBOSE(0, verbose_stream() << "verify assignment\n";); ref sat_solver = mk_inc_sat_solver(m, m_params); @@ -878,7 +896,7 @@ public: } expr_ref n(m); for (unsigned i = 0; i < m_soft.size(); ++i) { - n = m_soft[i].get(); + n = m_soft[i]; if (!m_assignment[i]) { n = mk_not(m, n); } diff --git a/src/opt/maxsls.cpp b/src/opt/maxsls.cpp index 1c6e745a4..fc9c71607 100644 --- a/src/opt/maxsls.cpp +++ b/src/opt/maxsls.cpp @@ -41,7 +41,7 @@ namespace opt { m_upper.reset(); for (unsigned i = 0; i < m_soft.size(); ++i) { expr_ref tmp(m); - m_model->eval(m_soft[i].get(), tmp, true); + m_model->eval(m_soft[i], tmp, true); m_assignment[i] = m.is_true(tmp); if (!m_assignment[i]) { m_upper += m_weights[i]; diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index d8bc1073f..46b782dfd 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -30,6 +30,7 @@ Notes: #include "opt_context.h" #include "theory_wmaxsat.h" #include "ast_util.h" +#include "pb_decl_plugin.h" namespace opt { @@ -38,12 +39,13 @@ namespace opt { context& c, vector const& ws, expr_ref_vector const& soft): m(c.get_manager()), m_c(c), - m_cancel(false), m_soft(m), + m_cancel(false), + m_soft(soft), + m_weights(ws), m_assertions(m) { c.get_base_model(m_model); SASSERT(m_model); updt_params(c.params()); - init_soft(ws, soft); } void maxsmt_solver_base::updt_params(params_ref& p) { @@ -54,11 +56,17 @@ namespace opt { return m_c.get_solver(); } - void maxsmt_solver_base::init_soft(vector const& weights, expr_ref_vector const& soft) { - m_weights.reset(); - m_soft.reset(); - m_weights.append(weights); - m_soft.append(soft); + void maxsmt_solver_base::commit_assignment() { + expr_ref tmp(m); + rational k(0); + for (unsigned i = 0; i < m_soft.size(); ++i) { + if (get_assignment(i)) { + k += m_weights[i]; + } + } + pb_util pb(m); + tmp = pb.mk_ge(m_weights.size(), m_weights.c_ptr(), m_soft.c_ptr(), k); + s().assert_expr(tmp); } void maxsmt_solver_base::init() { @@ -67,7 +75,7 @@ namespace opt { m_assignment.reset(); for (unsigned i = 0; i < m_weights.size(); ++i) { expr_ref val(m); - VERIFY(m_model->eval(m_soft[i].get(), val)); + VERIFY(m_model->eval(m_soft[i], val)); m_assignment.push_back(m.is_true(val)); if (!m_assignment.back()) { m_upper += m_weights[i]; @@ -178,7 +186,7 @@ namespace opt { m_msolver = mk_sls(m_c, m_weights, m_soft_constraints); } else if (is_maxsat_problem(m_weights) && maxsat_engine == symbol("fu_malik")) { - m_msolver = alloc(fu_malik, m_c, m_soft_constraints); + m_msolver = mk_fu_malik(m_c, m_weights, m_soft_constraints); } else { if (maxsat_engine != symbol::null && maxsat_engine != symbol("wmax")) { @@ -217,12 +225,6 @@ namespace opt { // TBD: have to use a different solver // because we don't push local scope any longer. return; - solver::scoped_push _sp(s()); - commit_assignment(); - if (l_true != s().check_sat(0,0)) { - IF_VERBOSE(0, verbose_stream() << "could not verify assignment\n";); - UNREACHABLE(); - } } bool maxsmt::get_assignment(unsigned idx) const { @@ -265,14 +267,8 @@ namespace opt { } void maxsmt::commit_assignment() { - for (unsigned i = 0; i < m_soft_constraints.size(); ++i) { - expr_ref tmp(m); - tmp = m_soft_constraints[i].get(); - if (!get_assignment(i)) { - tmp = mk_not(m, tmp); - } - TRACE("opt", tout << "committing: " << tmp << "\n";); - s().assert_expr(tmp); + if (m_msolver) { + m_msolver->commit_assignment(); } } diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 6341d0756..6a19a223b 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -61,9 +61,9 @@ namespace opt { ast_manager& m; context& m_c; volatile bool m_cancel; - expr_ref_vector m_soft; - expr_ref_vector m_assertions; + const expr_ref_vector m_soft; vector m_weights; + expr_ref_vector m_assertions; rational m_lower; rational m_upper; model_ref m_model; @@ -80,9 +80,9 @@ namespace opt { virtual void set_cancel(bool f) { m_cancel = f; if (f) s().cancel(); else s().reset_cancel(); } virtual void collect_statistics(statistics& st) const { } virtual void get_model(model_ref& mdl) { mdl = m_model.get(); } + virtual void commit_assignment(); void set_model() { s().get_model(m_model); } virtual void updt_params(params_ref& p); - virtual void init_soft(weights_t& weights, expr_ref_vector const& soft); solver& s(); void init(); void set_mus(bool f); @@ -114,7 +114,7 @@ namespace opt { class maxsmt { ast_manager& m; context& m_c; - scoped_ptr m_msolver; + scoped_ptr m_msolver; volatile bool m_cancel; expr_ref_vector m_soft_constraints; expr_ref_vector m_answer; diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 5004ceb32..7fcbe918b 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -1204,10 +1204,7 @@ namespace opt { maxsmt& ms = *m_maxsmts.find(obj.m_id); for (unsigned i = 0; i < obj.m_terms.size(); ++i) { VERIFY(m_model->eval(obj.m_terms[i], val)); - CTRACE("opt",ms.get_assignment(i) != (m.mk_true() == val), - tout << mk_pp(obj.m_terms[i], m) << " evaluates to " << val << "\n"; - model_smt2_pp(tout, m, *m_model, 0);); - SASSERT(ms.get_assignment(i) == (m.mk_true() == val)); + // TBD: check that optimal was not changed. } break; } diff --git a/src/opt/wmax.cpp b/src/opt/wmax.cpp index 78675387c..48d46a6c9 100644 --- a/src/opt/wmax.cpp +++ b/src/opt/wmax.cpp @@ -43,7 +43,7 @@ namespace opt { lbool is_sat = l_true; bool was_sat = false; for (unsigned i = 0; i < m_soft.size(); ++i) { - wth().assert_weighted(m_soft[i].get(), m_weights[i]); + wth().assert_weighted(m_soft[i], m_weights[i]); } while (l_true == is_sat) { is_sat = s().check_sat(0,0); From d8e62cac94cb36d12fc4c7d1ec3d197f089f1858 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 1 Oct 2014 14:51:14 -0700 Subject: [PATCH 604/925] enable flattening even if som is set by default Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/poly_rewriter_def.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ast/rewriter/poly_rewriter_def.h b/src/ast/rewriter/poly_rewriter_def.h index 036221f96..12da0069d 100644 --- a/src/ast/rewriter/poly_rewriter_def.h +++ b/src/ast/rewriter/poly_rewriter_def.h @@ -34,6 +34,8 @@ void poly_rewriter::updt_params(params_ref const & _p) { m_hoist_mul = p.hoist_mul(); m_hoist_cmul = p.hoist_cmul(); m_som_blowup = p.som_blowup(); + if (!m_flat) m_som = false; + if (m_som) m_hoist_mul = false; } template From bb15ddbf15e5abc8e8bd17c491022ddcd48047e1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 1 Oct 2014 15:21:42 -0700 Subject: [PATCH 605/925] update unit tests to use filter_by_negation verifier from check_relation Signed-off-by: Nikolaj Bjorner --- src/muz/rel/check_relation.cpp | 16 ++++++---- src/muz/rel/check_relation.h | 5 +-- src/test/udoc_relation.cpp | 56 ++++------------------------------ 3 files changed, 19 insertions(+), 58 deletions(-) diff --git a/src/muz/rel/check_relation.cpp b/src/muz/rel/check_relation.cpp index e779a42c4..a526ffc1b 100644 --- a/src/muz/rel/check_relation.cpp +++ b/src/muz/rel/check_relation.cpp @@ -38,7 +38,11 @@ namespace datalog { } expr_ref check_relation::ground(expr* fml) const { - relation_signature const& sig = get_signature(); + return get_plugin().ground(*this, fml); + } + + expr_ref check_relation_plugin::ground(relation_base const& dst, expr* fml) const { + relation_signature const& sig = dst.get_signature(); var_subst sub(m, false); expr_ref_vector vars(m); for (unsigned i = 0; i < sig.size(); ++i) { @@ -625,7 +629,7 @@ namespace datalog { t.to_formula(dst0); (*m_filter)(t.rb(), n.rb()); t.rb().to_formula(t.m_fml); - p.verify_filter_by_negation(dst0, t, n, m_t_cols, m_neg_cols); + p.verify_filter_by_negation(dst0, t.rb(), n.rb(), m_t_cols, m_neg_cols); } }; @@ -646,8 +650,8 @@ namespace datalog { void check_relation_plugin::verify_filter_by_negation( expr* dst0, - check_relation const& dst, - check_relation const& neg, + relation_base const& dst, + relation_base const& neg, unsigned_vector const& cols1, unsigned_vector const& cols2) { relation_signature const& sig1 = dst.get_signature(); @@ -678,8 +682,8 @@ namespace datalog { } negf = m.mk_exists(rev_sig2.size(), rev_sig2.c_ptr(), names.c_ptr(), negf); negf = m.mk_and(dst0, m.mk_not(negf)); - negf = dst.ground(negf); - dstf = dst.ground(dstf); + negf = ground(dst, negf); + dstf = ground(dst, dstf); std::cout << negf << "\n"; std::cout << dstf << "\n"; check_equiv("filter by negation", dstf, negf); diff --git a/src/muz/rel/check_relation.h b/src/muz/rel/check_relation.h index 016751184..580ce3dd4 100644 --- a/src/muz/rel/check_relation.h +++ b/src/muz/rel/check_relation.h @@ -77,6 +77,7 @@ namespace datalog { static check_relation& get(relation_base& r); static check_relation* get(relation_base* r); static check_relation const & get(relation_base const& r); + expr_ref ground(relation_base const& rb, expr* fml) const; public: check_relation_plugin(relation_manager& rm); ~check_relation_plugin(); @@ -141,8 +142,8 @@ namespace datalog { void verify_filter_by_negation( expr* dst0, - check_relation const& dst, - check_relation const& neg, + relation_base const& dst, + relation_base const& neg, unsigned_vector const& dst_eq, unsigned_vector const& neg_eq); }; diff --git a/src/test/udoc_relation.cpp b/src/test/udoc_relation.cpp index 094e755ac..9824c481d 100644 --- a/src/test/udoc_relation.cpp +++ b/src/test/udoc_relation.cpp @@ -619,60 +619,16 @@ public: full->deallocate(); } - void apply_filter_neg(udoc_relation& t1, udoc_relation& t2, + void apply_filter_neg(udoc_relation& dst, udoc_relation& neg, unsigned_vector const& cols1, unsigned_vector const& cols2) { - relation_signature const& sig = t1.get_signature(); scoped_ptr negf; - negf = p.mk_filter_by_negation_fn(t1, t2, cols1.size(), cols1.c_ptr(), cols2.c_ptr()); - expr_ref fml1(m), fml2(m), fml3(m); - t1.to_formula(fml1); - t2.to_formula(fml2); - for (unsigned i = 0; i < cols1.size(); ++i) { - std::cout << cols1[i] << " = " << cols2[i] << " "; - } - std::cout << "\n"; - t1.display(std::cout); std::cout << "\n"; - t2.display(std::cout); std::cout << "\n"; - (*negf)(t1, t2); - t1.display(std::cout); std::cout << "\n"; - t1.to_formula(fml3); - std::cout << fml1 << "\n"; - std::cout << fml2 << "\n"; - std::cout << fml3 << "\n"; - expr_ref_vector eqs(m); - expr_ref_vector sub(m); - for (unsigned i = 0; i < sig.size(); ++i) { - sub.push_back(m.mk_var(i+sig.size(),sig[i])); - } - var_subst subst(m, false); - subst(fml2, sub.size(), sub.c_ptr(), fml2); - eqs.push_back(fml2); - for (unsigned i = 0; i < cols1.size(); ++i) { - var_ref v1(m), v2(m); - unsigned c1 = cols1[i]; - unsigned c2 = cols2[i]; - v1 = m.mk_var(c1, sig[c1]); - v2 = m.mk_var(sig.size() + c2, sig[c2]); - eqs.push_back(m.mk_eq(v1,v2)); - } - fml2 = mk_and(m, eqs.size(), eqs.c_ptr()); - for (unsigned i = 0; i < sub.size(); ++i) { - project_var(sig.size() + i, m.get_sort(sub[i].get()), fml2); - } - fml1 = m.mk_and(fml1, m.mk_not(fml2)); - - expr_ref_vector vars(m); - for (unsigned i = 0; i < sig.size(); ++i) { - std::stringstream strm; - strm << "x" << i; - vars.push_back(m.mk_const(symbol(strm.str().c_str()), sig[i])); - } + negf = p.mk_filter_by_negation_fn(dst, neg, cols1.size(), cols1.c_ptr(), cols2.c_ptr()); + expr_ref dst0(m); + dst.to_formula(dst0); + (*negf)(dst, neg); + cr.verify_filter_by_negation(dst0, dst, neg, cols1, cols2); - subst(fml1, vars.size(), vars.c_ptr(), fml1); - subst(fml3, vars.size(), vars.c_ptr(), fml3); - - check_equiv(fml1, fml3); /* tgt_1:={ x: x\in tgt_0 && ! \exists y: From 9828b26379013990df2702ebdf15ccfd1c9514e7 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 2 Oct 2014 09:56:06 +0100 Subject: [PATCH 606/925] DoC: fix slow path of filter_by_negation when columns are repeated in tgt relation Signed-off-by: Nuno Lopes --- src/muz/rel/check_relation.cpp | 2 +- src/muz/rel/udoc_relation.cpp | 25 ++++++++++++++++++------- src/test/udoc_relation.cpp | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 8 deletions(-) diff --git a/src/muz/rel/check_relation.cpp b/src/muz/rel/check_relation.cpp index a526ffc1b..46d1171d0 100644 --- a/src/muz/rel/check_relation.cpp +++ b/src/muz/rel/check_relation.cpp @@ -661,7 +661,7 @@ namespace datalog { expr_ref_vector eqs(m); dst.to_formula(dstf); std::cout << mk_pp(dstf, m) << "\n"; - dst.to_formula(negf); + neg.to_formula(negf); std::cout << mk_pp(negf, m) << "\n"; eqs.push_back(negf); for (unsigned i = 0; i < cols1.size(); ++i) { diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 10c01ccdd..269780a94 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -1110,11 +1110,16 @@ namespace datalog { for (unsigned i = 0; i < neg.size(); ++i) { doc& neg_i = neg[i]; doc_ref newD(dmt, dmt.allocateX()); - copy_columns(newD->pos(), neg_i.pos(), t, n); + if (!copy_columns(newD->pos(), neg_i.pos(), t, n)) + continue; + bool is_empty = false; for (unsigned j = 0; !is_empty && j < neg_i.neg().size(); ++j) { tbv_ref newT(dmt.tbvm(), dmt.tbvm().allocateX()); - copy_columns(*newT, neg_i.neg()[j], t, n); + if (!copy_columns(*newT, neg_i.neg()[j], t, n) || + !dmt.tbvm().set_and(*newT, newD->pos())) { + continue; + } if (dmt.tbvm().equals(newD->pos(), *newT)) { is_empty = true; } @@ -1139,17 +1144,19 @@ namespace datalog { renamed_neg.reset(dmt); IF_VERBOSE(3, tb.display(verbose_stream() << "slow case:");); } - void copy_columns( + bool copy_columns( tbv& dst, tbv const& src, udoc_relation const& dstt, udoc_relation const& srct) { unsigned num_cols = m_t_cols.size(); for (unsigned i = 0; i < num_cols; ++i) { - copy_column(dst, src, m_t_cols[i], m_neg_cols[i], dstt, srct); + if (!copy_column(dst, src, m_t_cols[i], m_neg_cols[i], dstt, srct)) + return false; } + return true; } - void copy_column( + bool copy_column( tbv& dst, tbv const& src, unsigned col_dst, unsigned col_src, udoc_relation const& dstt, @@ -1162,8 +1169,12 @@ namespace datalog { IF_VERBOSE(3, verbose_stream() << "copy column " << idx_src << " to " << idx_dst << " " << num_tbits << "\n";); for (unsigned i = 0; i < num_tbits; ++i) { - dm.set(dst, idx_dst + i, src[idx_src + i]); - } + tbit bit = (tbit)(dst[idx_dst + i] & src[idx_src + i]); + if (bit == BIT_z) + return false; + dm.set(dst, idx_dst + i, bit); + } + return true; } }; diff --git a/src/test/udoc_relation.cpp b/src/test/udoc_relation.cpp index 9824c481d..26858c12c 100644 --- a/src/test/udoc_relation.cpp +++ b/src/test/udoc_relation.cpp @@ -149,6 +149,7 @@ public: test_rename(); test_filter_neg(); test_filter_neg2(); + test_filter_neg3(); // empty @@ -601,6 +602,39 @@ public: t2->deallocate(); } + void test_filter_neg3() { + // filter_by_negation + relation_signature sig; + sig.push_back(bv.mk_sort(1)); + sig.push_back(bv.mk_sort(1)); + sig.push_back(bv.mk_sort(1)); + unsigned_vector cols1, cols2; + + cols1.push_back(0); + cols1.push_back(0); + cols2.push_back(0); + cols2.push_back(1); + + /// 1xx + udoc_relation* t1 = mk_full(sig); + { + doc& d = t1->get_udoc()[0]; + t1->get_dm().set(d, 0, BIT_1); + } + + /// 10x + udoc_relation* t2 = mk_full(sig); + { + doc& d = t2->get_udoc()[0]; + t1->get_dm().set(d, 0, BIT_1); + t1->get_dm().set(d, 1, BIT_0); + } + + apply_filter_neg(*t1, *t2, cols1, cols2); + t1->deallocate(); + t2->deallocate(); + } + void set_random(udoc_relation& r, unsigned num_vals) { unsigned num_bits = r.get_dm().num_tbits(); udoc_relation* full = mk_full(r.get_signature()); From 7d599fa047e20172cdcba36d6d4049b11c20bb86 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 2 Oct 2014 11:54:53 +0100 Subject: [PATCH 607/925] DoC: fix bug I previously introduced in insert Signed-off-by: Nuno Lopes --- src/muz/rel/doc.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/muz/rel/doc.h b/src/muz/rel/doc.h index 75b4e9499..5fdfe6297 100644 --- a/src/muz/rel/doc.h +++ b/src/muz/rel/doc.h @@ -174,7 +174,6 @@ public: for ( ; i < sz; ++i, ++j) { if (m.contains(*m_elems[i], *t)) { found = true; - break; } if (m.contains(*t, *m_elems[i])) { m.deallocate(m_elems[i]); From e778f3e65b0d91712dc3e4c2069e32aa20ec8d2a Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 2 Oct 2014 12:49:38 +0100 Subject: [PATCH 608/925] DoC: fix bug in insertion when inserting an element equal to on on the disjunction already Signed-off-by: Nuno Lopes --- src/muz/rel/doc.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/muz/rel/doc.h b/src/muz/rel/doc.h index 5fdfe6297..2a4b3ead7 100644 --- a/src/muz/rel/doc.h +++ b/src/muz/rel/doc.h @@ -175,17 +175,17 @@ public: if (m.contains(*m_elems[i], *t)) { found = true; } - if (m.contains(*t, *m_elems[i])) { + else if (m.contains(*t, *m_elems[i])) { m.deallocate(m_elems[i]); --j; + continue; } - else if (i != j) { + if (i != j) { m_elems[j] = m_elems[i]; } } if (j != sz) m_elems.resize(j); if (found) { - SASSERT(j == i); m.deallocate(t); } else { From 504709f0a1297db74dabfbc476fc5b87d9a9507d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Oct 2014 09:07:39 -0700 Subject: [PATCH 609/925] change implementation of shl to use log(n)*n intermediary bits instead of n^2/2 Signed-off-by: Nikolaj Bjorner --- .../bit_blaster/bit_blaster_tpl_def.h | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h index b41aa2238..285493690 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h +++ b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h @@ -911,18 +911,21 @@ void bit_blaster_tpl::mk_shl(unsigned sz, expr * const * a_bits, expr * con out_bits.push_back(a_bits[i]); } else { - expr_ref_vector eqs(m()); - mk_eqs(sz, b_bits, eqs); - for (unsigned i = 0; i < sz; i++) { - checkpoint(); - expr_ref out(m()); - mk_ite(eqs.get(i), a_bits[0], m().mk_false(), out); - for (unsigned j = 1; j <= i; j++) { + out_bits.append(sz, a_bits); + expr_ref_vector new_out_bits(m()); + + for (unsigned i = 0; i < sz; ++i) { + unsigned shift_i = 1 << i; + for (unsigned j = 0; j < sz; ++j) { expr_ref new_out(m()); - mk_ite(eqs.get(i - j), a_bits[j], out, new_out); - out = new_out; + expr* a_j = m().mk_false(); + if (shift_i <= j) a_j = a_bits[j-shift_i]; + mk_ite(b_bits[i], a_j, out_bits[j].get(), new_out); + new_out_bits.push_back(new_out); } - out_bits.push_back(out); + out_bits.reset(); + out_bits.append(new_out_bits); + if (shift_i > sz) break; } } } From 8929c578c124ad0a835f74c22dc222d590cf7d20 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Oct 2014 09:29:49 -0700 Subject: [PATCH 610/925] fix bug in mk_shl Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h index 285493690..a11d7fd1a 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h +++ b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h @@ -912,9 +912,9 @@ void bit_blaster_tpl::mk_shl(unsigned sz, expr * const * a_bits, expr * con } else { out_bits.append(sz, a_bits); - expr_ref_vector new_out_bits(m()); for (unsigned i = 0; i < sz; ++i) { + expr_ref_vector new_out_bits(m()); unsigned shift_i = 1 << i; for (unsigned j = 0; j < sz; ++j) { expr_ref new_out(m()); @@ -925,7 +925,7 @@ void bit_blaster_tpl::mk_shl(unsigned sz, expr * const * a_bits, expr * con } out_bits.reset(); out_bits.append(new_out_bits); - if (shift_i > sz) break; + if (shift_i >= sz) break; } } } From 2c70e8d79fe538370254ff9ca0e3ca4273af6b34 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Oct 2014 09:41:53 -0700 Subject: [PATCH 611/925] port logarithmic encoding to shr, add review comment on rotate Signed-off-by: Nikolaj Bjorner --- .../bit_blaster/bit_blaster_tpl_def.h | 51 +++++++++++-------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h index a11d7fd1a..a836f040c 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h +++ b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h @@ -914,6 +914,7 @@ void bit_blaster_tpl::mk_shl(unsigned sz, expr * const * a_bits, expr * con out_bits.append(sz, a_bits); for (unsigned i = 0; i < sz; ++i) { + checkpoint(); expr_ref_vector new_out_bits(m()); unsigned shift_i = 1 << i; for (unsigned j = 0; j < sz; ++j) { @@ -942,19 +943,21 @@ void bit_blaster_tpl::mk_lshr(unsigned sz, expr * const * a_bits, expr * co out_bits.push_back(m().mk_false()); } else { - expr_ref_vector eqs(m()); - mk_eqs(sz, b_bits, eqs); - out_bits.resize(sz); - for (unsigned i = 0; i < sz; i++) { + out_bits.append(sz, a_bits); + for (unsigned i = 0; i < sz; ++i) { checkpoint(); - expr_ref out(m()); - mk_ite(eqs.get(i), a_bits[sz-1], m().mk_false(), out); - for (unsigned j = 1; j <= i; j++) { + expr_ref_vector new_out_bits(m()); + unsigned shift_i = 1 << i; + for (unsigned j = 0; j < sz; ++j) { expr_ref new_out(m()); - mk_ite(eqs.get(i - j), a_bits[sz - j - 1], out, new_out); - out = new_out; + expr* a_j = m().mk_false(); + if (shift_i + j < sz) a_j = a_bits[j+shift_i]; + mk_ite(b_bits[i], a_j, out_bits[j].get(), new_out); + new_out_bits.push_back(new_out); } - out_bits.set(sz - i - 1, out); + out_bits.reset(); + out_bits.append(new_out_bits); + if (shift_i >= sz) break; } } } @@ -971,20 +974,21 @@ void bit_blaster_tpl::mk_ashr(unsigned sz, expr * const * a_bits, expr * co out_bits.push_back(a_bits[sz-1]); } else { - expr_ref_vector eqs(m()); - mk_eqs(sz, b_bits, eqs); - out_bits.resize(sz); - for (unsigned i = 0; i < sz; i++) { + out_bits.append(sz, a_bits); + for (unsigned i = 0; i < sz; ++i) { checkpoint(); - expr_ref out(m()); - out = a_bits[sz-1]; - for (unsigned j = 1; j <= i; j++) { + expr_ref_vector new_out_bits(m()); + unsigned shift_i = 1 << i; + for (unsigned j = 0; j < sz; ++j) { expr_ref new_out(m()); - mk_ite(eqs.get(i - j), a_bits[sz - j - 1], out, new_out); - out = new_out; + expr* a_j = a_bits[sz-1]; + if (shift_i + j < sz) a_j = a_bits[j+shift_i]; + mk_ite(b_bits[i], a_j, out_bits[j].get(), new_out); + new_out_bits.push_back(new_out); } - TRACE("bit_blaster", tout << (sz - i - 1) << " :\n" << mk_pp(out, m()) << "\n";); - out_bits.set(sz - i - 1, out); + out_bits.reset(); + out_bits.append(new_out_bits); + if (shift_i >= sz) break; } } } @@ -1000,6 +1004,11 @@ void bit_blaster_tpl::mk_ext_rotate_left_right(unsigned sz, expr * const * mk_rotate_right(sz, a_bits, static_cast(k.get_uint64()), out_bits); } else { + // + // Review: a better tuned implementation is possible by using shifts by power of two. + // e.g., looping over the bits of b_bits, then rotate by a power of two depending + // on the bit-position. This would get rid of the mk_urem. + // expr_ref_vector sz_bits(m()); expr_ref_vector masked_b_bits(m()); expr_ref_vector eqs(m()); From 93a757f45bdb552158ad1239a2de5c965af37d8b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Oct 2014 10:38:43 -0700 Subject: [PATCH 612/925] add two failing test cases Signed-off-by: Nikolaj Bjorner --- src/muz/rel/udoc_relation.cpp | 32 ++++++++++++++++++++++---------- src/muz/rel/udoc_relation.h | 9 ++++++--- src/test/udoc_relation.cpp | 27 +++++++++++++++++++++++++-- 3 files changed, 53 insertions(+), 15 deletions(-) diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 269780a94..d3c1f929d 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -221,7 +221,8 @@ namespace datalog { relation_plugin(udoc_plugin::get_name(), rm), m(rm.get_context().get_manager()), bv(m), - dl(m) { + dl(m), + m_disable_fast_pass(false) { } udoc_plugin::~udoc_plugin() { u_map::iterator it = m_dms.begin(), end = m_dms.end(); @@ -1079,13 +1080,22 @@ namespace datalog { virtual void operator()(relation_base& tb, const relation_base& negb) { udoc_relation& t = get(tb); udoc_relation const& n = get(negb); + udoc_plugin& p = t.get_plugin(); + IF_VERBOSE(3, t.display(verbose_stream() << "dst:");); + IF_VERBOSE(3, n.display(verbose_stream() << "neg:");); + if (!t.fast_empty() && !n.fast_empty() && !p.m_disable_fast_pass) { + fast_pass(t, n); + } + if (!t.fast_empty() && !n.fast_empty()) { + slow_pass(t, n); + } + } + + void fast_pass(udoc_relation& t, const udoc_relation& n) { udoc & dst = t.get_udoc(); udoc const & neg = n.get_udoc(); doc_manager& dmt = t.get_dm(); doc_manager& dmn = n.get_dm(); - IF_VERBOSE(3, t.display(verbose_stream() << "dst:");); - IF_VERBOSE(3, n.display(verbose_stream() << "neg:");); - udoc result; for (unsigned i = 0; i < dst.size(); ++i) { bool subsumed = false; @@ -1100,12 +1110,13 @@ namespace datalog { result.push_back(&dst[i]); } std::swap(dst, result); - if (dst.is_empty()) { - IF_VERBOSE(3, tb.display(verbose_stream() << "fast empty");); - return; - } + } - // slow case + void slow_pass(udoc_relation& t, udoc_relation const& n) { + udoc & dst = t.get_udoc(); + udoc const & neg = n.get_udoc(); + doc_manager& dmt = t.get_dm(); + doc_manager& dmn = n.get_dm(); udoc renamed_neg; for (unsigned i = 0; i < neg.size(); ++i) { doc& neg_i = neg[i]; @@ -1142,8 +1153,9 @@ namespace datalog { TRACE("doc", dst.display(dmt, tout) << "\n";); SASSERT(dst.well_formed(dmt)); renamed_neg.reset(dmt); - IF_VERBOSE(3, tb.display(verbose_stream() << "slow case:");); + IF_VERBOSE(3, t.display(verbose_stream() << "slow case:");); } + bool copy_columns( tbv& dst, tbv const& src, udoc_relation const& dstt, diff --git a/src/muz/rel/udoc_relation.h b/src/muz/rel/udoc_relation.h index 0adc61b64..f040e4745 100644 --- a/src/muz/rel/udoc_relation.h +++ b/src/muz/rel/udoc_relation.h @@ -91,10 +91,12 @@ namespace datalog { class filter_by_union_fn; class filter_proj_fn; class negation_filter_fn; - ast_manager& m; - bv_util bv; - dl_decl_util dl; + ast_manager& m; + bv_util bv; + dl_decl_util dl; u_map m_dms; + bool m_disable_fast_pass; + doc_manager& dm(unsigned sz); doc_manager& dm(relation_signature const& sig); static udoc_relation& get(relation_base& r); @@ -136,6 +138,7 @@ namespace datalog { virtual relation_transformer_fn * mk_filter_interpreted_and_project_fn( const relation_base & t, app * condition, unsigned removed_col_cnt, const unsigned * removed_cols); + void disable_fast_pass() { m_disable_fast_pass = true; } }; }; diff --git a/src/test/udoc_relation.cpp b/src/test/udoc_relation.cpp index 26858c12c..dd77db9f8 100644 --- a/src/test/udoc_relation.cpp +++ b/src/test/udoc_relation.cpp @@ -144,13 +144,17 @@ public: udoc_relation* t1, *t2, *t3; expr_ref fml(m); - test_join(1000); + test_filter_neg4(false); + test_filter_neg4(true); - test_rename(); test_filter_neg(); test_filter_neg2(); test_filter_neg3(); + test_join(1000); + + test_rename(); + // empty { @@ -635,6 +639,25 @@ public: t2->deallocate(); } + void test_filter_neg4(bool disable_fast) { + relation_signature sig1, sig2; + sig1.push_back(bv.mk_sort(2)); + sig1.push_back(bv.mk_sort(2)); + sig2.push_back(bv.mk_sort(2)); + unsigned_vector cols1, cols2; + + cols1.push_back(0); + cols1.push_back(1); + cols2.push_back(0); + cols2.push_back(0); + udoc_relation* tgt = mk_full(sig1); + udoc_relation* neg = mk_full(sig2); + if (disable_fast) p.disable_fast_pass(); + apply_filter_neg(*tgt, *neg, cols1, cols2); + tgt->deallocate(); + neg->deallocate(); + } + void set_random(udoc_relation& r, unsigned num_vals) { unsigned num_bits = r.get_dm().num_tbits(); udoc_relation* full = mk_full(r.get_signature()); From 4a286cfd1eb726a0046f9aec58857f5de589850e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Oct 2014 16:02:40 -0700 Subject: [PATCH 613/925] fix two bugs in logarithmic shift operations Signed-off-by: Nikolaj Bjorner --- .../bit_blaster/bit_blaster_tpl_def.h | 54 +++++++++++++++---- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h index a836f040c..b762817e4 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h +++ b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h @@ -913,20 +913,32 @@ void bit_blaster_tpl::mk_shl(unsigned sz, expr * const * a_bits, expr * con else { out_bits.append(sz, a_bits); - for (unsigned i = 0; i < sz; ++i) { + unsigned i = 0; + expr_ref_vector new_out_bits(m()); + for (; i < sz; ++i) { checkpoint(); - expr_ref_vector new_out_bits(m()); unsigned shift_i = 1 << i; + if (shift_i >= sz) break; for (unsigned j = 0; j < sz; ++j) { expr_ref new_out(m()); expr* a_j = m().mk_false(); - if (shift_i <= j) a_j = a_bits[j-shift_i]; + if (shift_i <= j) a_j = out_bits[j-shift_i].get(); mk_ite(b_bits[i], a_j, out_bits[j].get(), new_out); new_out_bits.push_back(new_out); } out_bits.reset(); out_bits.append(new_out_bits); - if (shift_i >= sz) break; + new_out_bits.reset(); + } + expr_ref is_large(m()); + is_large = m().mk_false(); + for (; i < sz; ++i) { + mk_or(is_large, b_bits[i], is_large); + } + for (unsigned j = 0; j < sz; ++j) { + expr_ref new_out(m()); + mk_ite(is_large, m().mk_false(), out_bits[j].get(), new_out); + out_bits[j] = new_out; } } } @@ -944,20 +956,31 @@ void bit_blaster_tpl::mk_lshr(unsigned sz, expr * const * a_bits, expr * co } else { out_bits.append(sz, a_bits); - for (unsigned i = 0; i < sz; ++i) { + unsigned i = 0; + for (; i < sz; ++i) { checkpoint(); expr_ref_vector new_out_bits(m()); unsigned shift_i = 1 << i; + if (shift_i >= sz) break; for (unsigned j = 0; j < sz; ++j) { expr_ref new_out(m()); expr* a_j = m().mk_false(); - if (shift_i + j < sz) a_j = a_bits[j+shift_i]; + if (shift_i + j < sz) a_j = out_bits[j+shift_i].get(); mk_ite(b_bits[i], a_j, out_bits[j].get(), new_out); new_out_bits.push_back(new_out); } out_bits.reset(); out_bits.append(new_out_bits); - if (shift_i >= sz) break; + } + expr_ref is_large(m()); + is_large = m().mk_false(); + for (; i < sz; ++i) { + mk_or(is_large, b_bits[i], is_large); + } + for (unsigned j = 0; j < sz; ++j) { + expr_ref new_out(m()); + mk_ite(is_large, m().mk_false(), out_bits[j].get(), new_out); + out_bits[j] = new_out; } } } @@ -975,20 +998,31 @@ void bit_blaster_tpl::mk_ashr(unsigned sz, expr * const * a_bits, expr * co } else { out_bits.append(sz, a_bits); - for (unsigned i = 0; i < sz; ++i) { + unsigned i = 0; + for (; i < sz; ++i) { checkpoint(); expr_ref_vector new_out_bits(m()); unsigned shift_i = 1 << i; + if (shift_i >= sz) break; for (unsigned j = 0; j < sz; ++j) { expr_ref new_out(m()); expr* a_j = a_bits[sz-1]; - if (shift_i + j < sz) a_j = a_bits[j+shift_i]; + if (shift_i + j < sz) a_j = out_bits[j+shift_i].get(); mk_ite(b_bits[i], a_j, out_bits[j].get(), new_out); new_out_bits.push_back(new_out); } out_bits.reset(); out_bits.append(new_out_bits); - if (shift_i >= sz) break; + } + expr_ref is_large(m()); + is_large = m().mk_false(); + for (; i < sz; ++i) { + mk_or(is_large, b_bits[i], is_large); + } + for (unsigned j = 0; j < sz; ++j) { + expr_ref new_out(m()); + mk_ite(is_large, a_bits[sz-1], out_bits[j].get(), new_out); + out_bits[j] = new_out; } } } From cb88968588b15433ea6453e0828f24dabedd9469 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Oct 2014 17:10:51 -0700 Subject: [PATCH 614/925] tuning maxres Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 3 +- src/sat/sat_mus.cpp | 82 +++++++++++++++++++++++++++++------------ src/sat/sat_mus.h | 2 + 3 files changed, 62 insertions(+), 25 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 7fcbe918b..2afba62a9 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -454,7 +454,8 @@ namespace opt { m_maxsat_engine != symbol("sls")) { return; } - m_params.set_bool("minimize_core_partial", true); + m_params.set_bool("minimize_core_partial", true); // false); + m_params.set_bool("minimize_core", true); m_sat_solver = mk_inc_sat_solver(m, m_params); unsigned sz = get_solver().get_num_assertions(); for (unsigned i = 0; i < sz; ++i) { diff --git a/src/sat/sat_mus.cpp b/src/sat/sat_mus.cpp index 4468f5b34..a504a5fe2 100644 --- a/src/sat/sat_mus.cpp +++ b/src/sat/sat_mus.cpp @@ -42,26 +42,22 @@ namespace sat { } lbool mus::operator()() { - bool minimize_partial = s.m_config.m_minimize_core_partial; flet _disable_min(s.m_config.m_minimize_core, false); flet _disable_min_partial(s.m_config.m_minimize_core_partial, false); flet _disable_opt(s.m_config.m_optimize_model, false); flet _is_active(m_is_active, true); - TRACE("sat", tout << "old core: " << s.get_core() << "\n";); IF_VERBOSE(2, verbose_stream() << "(sat.mus " << s.get_core() << ")\n";); reset(); - literal_vector& core = m_core; + return mus1(); + } + + lbool mus::mus1() { + bool minimize_partial = s.m_config.m_minimize_core_partial; + TRACE("sat", tout << "old core: " << s.get_core() << "\n";); + literal_vector& core = get_core(); literal_vector& mus = m_mus; - core.append(s.get_core()); - for (unsigned i = 0; i < core.size(); ++i) { - if (s.m_user_scope_literals.contains(core[i])) { - mus.push_back(core[i]); - core[i] = core.back(); - core.pop_back(); - --i; - } - } unsigned delta_time = 0; + unsigned core_miss = 0; while (!core.empty()) { IF_VERBOSE(2, verbose_stream() << "(opt.mus reducing core: " << core.size() << " new core: " << mus.size() << ")\n";); TRACE("sat", @@ -72,7 +68,7 @@ namespace sat { set_core(); return l_undef; } - if (minimize_partial && delta_time > 4) { + if (minimize_partial && 3*delta_time > core.size() && core.size() < mus.size()) { break; } unsigned num_literals = core.size() + mus.size(); @@ -81,7 +77,9 @@ namespace sat { core.pop_back(); unsigned sz = mus.size(); mus.append(core); - mus.push_back(~lit); // TBD: measure + if (true || core_miss < 2) { + mus.push_back(~lit); // TBD: measure + } lbool is_sat = s.check(mus.size(), mus.c_ptr()); TRACE("sat", tout << "mus: " << mus << "\n";); switch (is_sat) { @@ -111,17 +109,20 @@ namespace sat { } case l_false: literal_vector const& new_core = s.get_core(); - if (new_core.contains(~lit)) { - mus.resize(sz); - break; - } mus.resize(sz); - TRACE("sat", tout << "new core: " << new_core << "\n";); - core.reset(); - for (unsigned i = 0; i < new_core.size(); ++i) { - literal lit = new_core[i]; - if (!mus.contains(lit)) { - core.push_back(lit); + if (new_core.contains(~lit)) { + IF_VERBOSE(2, verbose_stream() << "miss core " << lit << "\n";); + ++core_miss; + } + else { + core_miss = 0; + TRACE("sat", tout << "new core: " << new_core << "\n";); + core.reset(); + for (unsigned i = 0; i < new_core.size(); ++i) { + literal lit = new_core[i]; + if (!mus.contains(lit)) { + core.push_back(lit); + } } } break; @@ -141,6 +142,39 @@ namespace sat { return l_true; } + // bisection search. + lbool mus::mus2() { + literal_vector& core = get_core(); + literal_vector& mus = m_mus; + while (true) { + +#if 0 + unsigned start = 0; + unsigned len = core.size(); + SASSERT(start < len); + unsigned mid = (len-start+1)/2; + mus.append(mid, core.c_ptr() + start); + start = start + mid; +#endif + } + return l_undef; + } + + literal_vector& mus::get_core() { + m_core.reset(); + literal_vector& core = m_core; + core.append(s.get_core()); + for (unsigned i = 0; i < core.size(); ++i) { + if (s.m_user_scope_literals.contains(core[i])) { + m_mus.push_back(core[i]); + core[i] = core.back(); + core.pop_back(); + --i; + } + } + return core; + } + void mus::mr() { sls sls(s); literal_vector tabu; diff --git a/src/sat/sat_mus.h b/src/sat/sat_mus.h index eede15c63..ed7b8b13e 100644 --- a/src/sat/sat_mus.h +++ b/src/sat/sat_mus.h @@ -36,10 +36,12 @@ namespace sat { bool is_active() const { return m_is_active; } model const& get_model() const { return m_model; } private: + lbool mus1(); lbool mus2(); void mr(); void reset(); void set_core(); + literal_vector & get_core(); }; }; From 2bf0b5f33f388c57cb6eea322ff3a1adc2aff2f2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 3 Oct 2014 13:05:54 -0700 Subject: [PATCH 615/925] include selected deprecated facilities for easier experimentation with consequence finding over .NET Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Deprecated.cs | 105 +++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 src/api/dotnet/Deprecated.cs diff --git a/src/api/dotnet/Deprecated.cs b/src/api/dotnet/Deprecated.cs new file mode 100644 index 000000000..7282796ec --- /dev/null +++ b/src/api/dotnet/Deprecated.cs @@ -0,0 +1,105 @@ +/*++ +Copyright (c) 2012 Microsoft Corporation + +Module Name: + + Deprecated.cs + +Abstract: + + Expose deprecated features for use from the managed API + those who use them for experiments. + +Author: + + Christoph Wintersteiger (cwinter) 2012-03-15 + +Notes: + +--*/ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Diagnostics.Contracts; + +namespace Microsoft.Z3 +{ + /// + /// The main interaction with Z3 happens via the Context. + /// + [ContractVerification(true)] + public class Deprecated + { + + /// + /// Creates a backtracking point. + /// + /// + public static void Push(Context ctx) { + Native.Z3_push(ctx.nCtx); + } + + /// + /// Backtracks backtracking points. + /// + /// Note that an exception is thrown if is not smaller than NumScopes + /// + public static void Pop(Context ctx, uint n = 1) { + Native.Z3_pop(ctx.nCtx, n); + } + + /// + /// Assert a constraint (or multiple) into the solver. + /// + public static void Assert(Context ctx, params BoolExpr[] constraints) + { + Contract.Requires(constraints != null); + Contract.Requires(Contract.ForAll(constraints, c => c != null)); + + ctx.CheckContextMatch(constraints); + foreach (BoolExpr a in constraints) + { + Native.Z3_assert_cnstr(ctx.nCtx, a.NativeObject); + } + } + /// + /// Checks whether the assertions in the context are consistent or not. + /// + public static Status Check(Context ctx, List core, params Expr[] assumptions) + { + Z3_lbool r; + core = null; + if (assumptions == null || assumptions.Length == 0) + r = (Z3_lbool)Native.Z3_check(ctx.nCtx); + else { + IntPtr model = IntPtr.Zero, proof = IntPtr.Zero; + uint core_size = 0; + IntPtr[] native_core = new IntPtr[assumptions.Length]; + r = (Z3_lbool)Native.Z3_check_assumptions(ctx.nCtx, + (uint)assumptions.Length, AST.ArrayToNative(assumptions), + ref model, ref proof, ref core_size, native_core); + + for (uint i = 0; i < core_size; i++) + core.Add((BoolExpr)Expr.Create(ctx, native_core[i])); + + } + switch (r) + { + case Z3_lbool.Z3_L_TRUE: return Status.SATISFIABLE; + case Z3_lbool.Z3_L_FALSE: return Status.UNSATISFIABLE; + default: return Status.UNKNOWN; + } + } + + /// + /// Retrieves an assignment to atomic propositions for a satisfiable context. + /// + /// + public static BoolExpr GetAssignment(Context ctx) + { + IntPtr x = Native.Z3_get_context_assignment(ctx.nCtx); + return (BoolExpr)Expr.Create(ctx, x); + } + + } +} \ No newline at end of file From f3d2535b46800b0232fb851545ca5419d65dc969 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 3 Oct 2014 16:58:46 -0700 Subject: [PATCH 616/925] another unit test for Nuno Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Deprecated.cs | 1 - src/opt/maxres.cpp | 2 +- src/test/udoc_relation.cpp | 31 +++++++++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/api/dotnet/Deprecated.cs b/src/api/dotnet/Deprecated.cs index 7282796ec..7dc524834 100644 --- a/src/api/dotnet/Deprecated.cs +++ b/src/api/dotnet/Deprecated.cs @@ -94,7 +94,6 @@ namespace Microsoft.Z3 /// /// Retrieves an assignment to atomic propositions for a satisfiable context. /// - /// public static BoolExpr GetAssignment(Context ctx) { IntPtr x = Native.Z3_get_context_assignment(ctx.nCtx); diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 86c0efb8f..be39a05d5 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -356,9 +356,9 @@ public: while (index < asms.size() && is_sat == l_true) { while (asms.size() > 20*(index - last_index) && index < asms.size()) { index = next_index(asms, index); - //std::cout << "weight: " << get_weight(asms[index-1].get()) << "\n"; //break; } + IF_VERBOSE(3, verbose_stream() << "weight: " << get_weight(asms[0].get()) << " " << get_weight(asms[index-1].get()) << "\n";); last_index = index; is_sat = s().check_sat(index, asms.c_ptr()); } diff --git a/src/test/udoc_relation.cpp b/src/test/udoc_relation.cpp index dd77db9f8..31908a41d 100644 --- a/src/test/udoc_relation.cpp +++ b/src/test/udoc_relation.cpp @@ -146,6 +146,8 @@ public: test_filter_neg4(false); test_filter_neg4(true); + test_filter_neg6(false); + test_filter_neg6(true); test_filter_neg(); test_filter_neg2(); @@ -658,6 +660,35 @@ public: neg->deallocate(); } + void test_filter_neg5(bool disable_fast) { + relation_signature sig1, sig2; + sig1.push_back(bv.mk_sort(2)); + sig1.push_back(bv.mk_sort(2)); + sig2.push_back(bv.mk_sort(2)); + sig2.push_back(bv.mk_sort(2)); + sig2.push_back(bv.mk_sort(2)); + unsigned_vector cols1, cols2, cols3; + + cols1.push_back(0); + cols1.push_back(1); + cols2.push_back(0); + cols2.push_back(2); + cols3.push_back(0); + cols3.push_back(1); + cols3.push_back(2); + udoc_relation* tgt = mk_full(sig1); + udoc_relation* neg = mk_full(sig2); + rel_mut filter_id = p.mk_filter_identical_fn(*tgt, cols3.size(), cols3.c_ptr()); + (*filter_id)(*tgt); + if (disable_fast) p.disable_fast_pass(); + apply_filter_neg(*tgt, *neg, cols1, cols2); + tgt->deallocate(); + neg->deallocate(); + } + + // TBD: unit test to expose similar bug as projection had. + // you can't just remove columns when there are side-constraints in neg. + void set_random(udoc_relation& r, unsigned num_vals) { unsigned num_bits = r.get_dm().num_tbits(); udoc_relation* full = mk_full(r.get_signature()); From db20b2502d5379a3efb12b8ab8c7ad5723a17f07 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 4 Oct 2014 19:50:42 -0700 Subject: [PATCH 617/925] try qx Signed-off-by: Nikolaj Bjorner --- src/muz/rel/udoc_relation.cpp | 15 ++++ src/muz/rel/udoc_relation.h | 6 ++ src/opt/inc_sat_solver.cpp | 11 ++- src/opt/maxres.cpp | 66 ++++++++++----- src/sat/sat_bceq.cpp | 52 ++++++++++-- src/sat/sat_bceq.h | 5 +- src/sat/sat_mus.cpp | 149 ++++++++++++++++++++++++++-------- src/sat/sat_mus.h | 22 +++++ src/sat/sat_simplifier.cpp | 34 +++----- src/sat/sat_solver.cpp | 10 ++- src/sat/sat_types.h | 60 ++++++++++++++ 11 files changed, 338 insertions(+), 92 deletions(-) diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index d3c1f929d..4d1fdf1d2 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -1264,6 +1264,21 @@ namespace datalog { return check_kind(t)?alloc(filter_proj_fn, get(t), get_ast_manager(), condition, removed_col_cnt, removed_cols):0; } + relation_join_fn * udoc_plugin::mk_join_project_fn( + relation_base const& t1, relation_base const& t2, + unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, + unsigned removed_col_cnt, const unsigned * removed_cols) { + if (check_kind(t1) && check_kind(t2)) + return 0; +#if 0 + return alloc(join_proj_fn, get(t1), ge(t2), + joined_col_cnt, cols1, cols2, + removed_col_cnt, removed_cols); +#endif + else + return 0; + } + diff --git a/src/muz/rel/udoc_relation.h b/src/muz/rel/udoc_relation.h index f040e4745..596a1f0dd 100644 --- a/src/muz/rel/udoc_relation.h +++ b/src/muz/rel/udoc_relation.h @@ -81,6 +81,7 @@ namespace datalog { class udoc_plugin : public relation_plugin { friend class udoc_relation; class join_fn; + class join_project_fn; class project_fn; class union_fn; class rename_fn; @@ -138,6 +139,11 @@ namespace datalog { virtual relation_transformer_fn * mk_filter_interpreted_and_project_fn( const relation_base & t, app * condition, unsigned removed_col_cnt, const unsigned * removed_cols); + virtual relation_join_fn * mk_join_project_fn( + relation_base const& t1, relation_base const& t2, + unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, + unsigned removed_col_cnt, const unsigned * removed_cols); + void disable_fast_pass() { m_disable_fast_pass = true; } }; }; diff --git a/src/opt/inc_sat_solver.cpp b/src/opt/inc_sat_solver.cpp index 5eecf42d7..1c450bbef 100644 --- a/src/opt/inc_sat_solver.cpp +++ b/src/opt/inc_sat_solver.cpp @@ -316,6 +316,7 @@ private: for (; it != end; ++it) { asms.push_back(it->m_value); } + //IF_VERBOSE(0, verbose_stream() << asms << "\n";); } void extract_core(dep2asm_t& dep2asm) { @@ -341,7 +342,7 @@ private: m_core.reset(); for (unsigned i = 0; i < core.size(); ++i) { expr* e; - VERIFY (asm2dep.find(core[i].index(), e)); + VERIFY(asm2dep.find(core[i].index(), e)); m_core.push_back(e); } @@ -397,6 +398,14 @@ private: SASSERT(m_model); // IF_VERBOSE(0, model_smt2_pp(verbose_stream(), m, *(m_model.get()), 0);); + DEBUG_CODE( + for (unsigned i = 0; i < m_fmls.size(); ++i) { + expr_ref tmp(m); + VERIFY(m_model->eval(m_fmls[i].get(), tmp)); + CTRACE("opt", !m.is_true(tmp), + tout << "Evaluation failed: " << mk_pp(m_fmls[i].get(), m) << "\n";); + SASSERT(m.is_true(tmp)); + }); } }; diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 86c0efb8f..63397664a 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -64,6 +64,7 @@ Notes: #include "pb_decl_plugin.h" #include "opt_params.hpp" #include "ast_util.h" +#include "smt_solver.h" using namespace opt; @@ -150,6 +151,7 @@ public: } void new_assumption(expr* e, rational const& w) { + IF_VERBOSE(3, verbose_stream() << "new assumption " << mk_pp(e, m) << " " << w << "\n";); TRACE("opt", tout << "insert: " << mk_pp(e, m) << " : " << w << "\n";); m_asm2weight.insert(e, w); m_asms.push_back(e); @@ -171,7 +173,6 @@ public: if (m_cancel) { return l_undef; } - model_ref mdl; switch (is_sat) { case l_true: found_optimum(); @@ -179,7 +180,6 @@ public: case l_false: is_sat = process_unsat(); if (is_sat != l_true) return is_sat; - get_mus_model(mdl); break; case l_undef: return l_undef; @@ -187,6 +187,7 @@ public: break; } } + trace_bounds("maxres"); return l_true; } @@ -370,6 +371,7 @@ public: } void found_optimum() { + IF_VERBOSE(1, verbose_stream() << "found optimum\n";); s().get_model(m_model); DEBUG_CODE( for (unsigned i = 0; i < m_asms.size(); ++i) { @@ -404,6 +406,9 @@ public: while (is_sat == l_false) { core.reset(); s().get_unsat_core(core); + //verify_core(core); + model_ref mdl; + get_mus_model(mdl); is_sat = minimize_core(core); if (is_sat != l_true) { break; @@ -420,18 +425,12 @@ public: break; } remove_soft(core, asms); - TRACE("opt", - display_vec(tout << "core: ", core.size(), core.c_ptr()); - display_vec(tout << "assumptions: ", asms.size(), asms.c_ptr());); is_sat = check_sat_hill_climb(asms); } TRACE("opt", tout << "num cores: " << cores.size() << "\n"; for (unsigned i = 0; i < cores.size(); ++i) { - for (unsigned j = 0; j < cores[i].size(); ++j) { - tout << mk_pp(cores[i][j], m) << " "; - } - tout << "\n"; + display_vec(tout, cores[i].size(), cores[i].c_ptr()); } tout << "num satisfying: " << asms.size() << "\n";); @@ -535,6 +534,7 @@ public: if (m_c.sat_enabled()) { // SAT solver core extracts some model // during unsat core computation. + mdl = 0; s().get_model(mdl); } else { @@ -601,10 +601,7 @@ public: // find the minimal weight: rational w = get_weight(core[0]); for (unsigned i = 1; i < core.size(); ++i) { - rational w2 = get_weight(core[i]); - if (w2 < w) { - w = w2; - } + w = std::min(w, get_weight(core[i])); } // add fresh soft clauses for weights that are above w. for (unsigned i = 0; i < core.size(); ++i) { @@ -614,6 +611,7 @@ public: new_assumption(core[i], w3); } } + return w; } @@ -754,6 +752,7 @@ public: case l_false: core.reset(); s().get_unsat_core(core); + DEBUG_CODE(verify_core(core);); is_sat = minimize_core(core); if (is_sat != l_true) { break; @@ -786,14 +785,9 @@ public: rational upper(0); expr_ref tmp(m); for (unsigned i = 0; i < m_soft.size(); ++i) { - expr* n = m_soft[i]; - VERIFY(mdl->eval(n, tmp)); - if (!m.is_true(tmp)) { + if (!is_true(mdl, m_soft[i])) { upper += m_weights[i]; } - TRACE("opt", tout << mk_pp(n, m) << " |-> " << mk_pp(tmp, m) << "\n";); - CTRACE("opt", !m.is_true(tmp) && !m.is_false(tmp), - tout << mk_pp(n, m) << " |-> " << mk_pp(tmp, m) << "\n";); } if (upper >= m_upper) { return; @@ -804,7 +798,7 @@ public: m_assignment[i] = is_true(m_soft[i]); } m_upper = upper; - // verify_assignment(); + DEBUG_CODE(verify_assignment();); trace_bounds("maxres"); add_upper_bound_block(); @@ -888,6 +882,38 @@ public: } } + void verify_core(exprs const& core) { + IF_VERBOSE(3, verbose_stream() << "verify core\n";); + ref sat_solver = mk_inc_sat_solver(m, m_params); + + for (unsigned i = 0; i < s().get_num_assertions(); ++i) { + sat_solver->assert_expr(s().get_assertion(i)); + } + expr_ref n(m); + for (unsigned i = 0; i < core.size(); ++i) { + IF_VERBOSE(1, verbose_stream() << mk_pp(core[i],m) << " ";); + sat_solver->assert_expr(core[i]); + } + IF_VERBOSE(1, verbose_stream() << "\n";); + lbool is_sat = sat_solver->check_sat(0, 0); + if (is_sat != l_false) { + IF_VERBOSE(0, verbose_stream() << "!!!not a core\n";); + } + + sat_solver = mk_smt_solver(m, m_params, symbol()); + for (unsigned i = 0; i < s().get_num_assertions(); ++i) { + sat_solver->assert_expr(s().get_assertion(i)); + } + for (unsigned i = 0; i < core.size(); ++i) { + sat_solver->assert_expr(core[i]); + } + is_sat = sat_solver->check_sat(0, 0); + if (is_sat == l_true) { + IF_VERBOSE(0, verbose_stream() << "not a core\n";); + } + + } + void verify_assignment() { IF_VERBOSE(0, verbose_stream() << "verify assignment\n";); ref sat_solver = mk_inc_sat_solver(m, m_params); diff --git a/src/sat/sat_bceq.cpp b/src/sat/sat_bceq.cpp index 65377caed..7ad0ec837 100644 --- a/src/sat/sat_bceq.cpp +++ b/src/sat/sat_bceq.cpp @@ -22,6 +22,7 @@ Revision History: #include"trace.h" #include"bit_vector.h" #include"map.h" +#include"sat_elim_eqs.h" namespace sat { @@ -54,7 +55,7 @@ namespace sat { } } bin_clauses bc; - m_solver.collect_bin_clauses(bc, false); + m_solver.collect_bin_clauses(bc, false); // exclude roots. literal lits[2]; for (unsigned i = 0; i < bc.size(); ++i) { lits[0] = bc[i].first; @@ -215,7 +216,7 @@ namespace sat { m_L.append(new_clauses); m_L_blits.append(new_blits); } - std::cout << "Number left after BCE: " << clauses.size() << "\n"; + if (!clauses.empty()) std::cout << "Number left after BCE: " << clauses.size() << "\n"; return clauses.empty(); } @@ -362,7 +363,13 @@ namespace sat { while (v != i) { if (!m_solver.was_eliminated(v)) { if (last_v != UINT_MAX) { - check_equality(v, last_v); + if (check_equality(v, last_v)) { + // last_v was eliminated. + + } + else { + // TBD: refine partition. + } } last_v = v; } @@ -371,7 +378,7 @@ namespace sat { } } - void bceq::check_equality(unsigned v1, unsigned v2) { + bool bceq::check_equality(unsigned v1, unsigned v2) { TRACE("sat", tout << "check: " << v1 << " = " << v2 << "\n";); uint64 val1 = m_rbits[v1]; uint64 val2 = m_rbits[v2]; @@ -381,9 +388,9 @@ namespace sat { SASSERT(val1 == ~val2); l2.neg(); } - if (is_equiv(l1, l2)) { + if (is_already_equiv(l1, l2)) { TRACE("sat", tout << "Already equivalent: " << l1 << " " << l2 << "\n";); - return; + return false; } literal lits[2]; @@ -397,13 +404,16 @@ namespace sat { } if (is_sat == l_false) { TRACE("sat", tout << "Found equivalent: " << l1 << " " << l2 << "\n";); + assert_equality(l1, l2); } else { TRACE("sat", tout << "Not equivalent: " << l1 << " " << l2 << "\n";); + // TBD: if is_sat == l_true, then refine partition. } + return is_sat == l_false; } - bool bceq::is_equiv(literal l1, literal l2) { + bool bceq::is_already_equiv(literal l1, literal l2) { watch_list const& w1 = m_solver.get_wlist(l1); bool found = false; for (unsigned i = 0; !found && i < w1.size(); ++i) { @@ -420,6 +430,24 @@ namespace sat { return found; } + void bceq::assert_equality(literal l1, literal l2) { + if (l2.sign()) { + l1.neg(); + l2.neg(); + } + literal_vector roots; + bool_var_vector vars; + for (unsigned i = 0; i < m_solver.num_vars(); ++i) { + roots.push_back(literal(i, false)); + } + roots[l2.var()] = l1; + vars.push_back(l2.var()); + elim_eqs elim(m_solver); + for (unsigned i = 0; i < vars.size(); ++i) { + std::cout << "var: " << vars[i] << " root: " << roots[vars[i]] << "\n"; + } + elim(roots, vars); + } void bceq::cleanup() { m_solver.del_clauses(m_bin_clauses.begin(), m_bin_clauses.end()); @@ -430,15 +458,23 @@ namespace sat { void bceq::operator()() { if (!m_solver.m_config.m_bcd) return; flet _disable_bcd(m_solver.m_config.m_bcd, false); + flet _disable_min(m_solver.m_config.m_minimize_core, false); + flet _disable_opt(m_solver.m_config.m_optimize_model, false); + flet _bound_maxc(m_solver.m_config.m_max_conflicts, 1500); + use_list ul; solver s(m_solver.m_params, 0); + s.m_config.m_bcd = false; + s.m_config.m_minimize_core = false; + s.m_config.m_optimize_model = false; + s.m_config.m_max_conflicts = 1500; m_use_list = &ul; m_s = &s; ul.init(m_solver.num_vars()); init(); pure_decompose(); post_decompose(); - std::cout << "Decomposed set " << m_L.size() << "\n"; + std::cout << "Decomposed set " << m_L.size() << " rest: " << m_R.size() << "\n"; TRACE("sat", tout << "Decomposed set " << m_L.size() << "\n"; diff --git a/src/sat/sat_bceq.h b/src/sat/sat_bceq.h index 5552fb255..0b05c45cd 100644 --- a/src/sat/sat_bceq.h +++ b/src/sat/sat_bceq.h @@ -65,8 +65,9 @@ namespace sat { uint64 eval_clause(clause const& cls) const; void verify_sweep(); void extract_partition(); - void check_equality(unsigned v1, unsigned v2); - bool is_equiv(literal l1, literal l2); + bool check_equality(unsigned v1, unsigned v2); + bool is_already_equiv(literal l1, literal l2); + void assert_equality(literal l1, literal l2); public: bceq(solver & s); void operator()(); diff --git a/src/sat/sat_mus.cpp b/src/sat/sat_mus.cpp index a504a5fe2..c66f8ef6f 100644 --- a/src/sat/sat_mus.cpp +++ b/src/sat/sat_mus.cpp @@ -7,7 +7,7 @@ Module Name: Abstract: - Faster MUS extraction based on Belov et.al. HYB (Algorithm 3, 4) + Faster MUS extraction Author: @@ -33,12 +33,27 @@ namespace sat { m_mus.reset(); m_model.reset(); m_best_value = 0; + m_max_restarts = 10; + m_restart = s.m_stats.m_restart; } - void mus::set_core() { - m_core.append(m_mus); + void mus::set_core() { + m_mus.append(m_core); s.m_core.reset(); - s.m_core.append(m_core); + s.m_core.append(m_mus); + } + + void mus::update_model() { + double new_value = s.m_wsls.evaluate_model(s.m_model); + if (m_model.empty()) { + m_model.append(s.m_model); + m_best_value = new_value; + } + else if (m_best_value > new_value) { + m_model.reset(); + m_model.append(s.m_model); + m_best_value = new_value; + } } lbool mus::operator()() { @@ -56,6 +71,9 @@ namespace sat { TRACE("sat", tout << "old core: " << s.get_core() << "\n";); literal_vector& core = get_core(); literal_vector& mus = m_mus; + if (core.size() > 64) { + return mus2(); + } unsigned delta_time = 0; unsigned core_miss = 0; while (!core.empty()) { @@ -75,41 +93,31 @@ namespace sat { literal lit = core.back(); core.pop_back(); - unsigned sz = mus.size(); - mus.append(core); - if (true || core_miss < 2) { - mus.push_back(~lit); // TBD: measure + lbool is_sat; + { + scoped_append _sa(mus, core); + if (true || core_miss < 2) { + mus.push_back(~lit); // TBD: measure + } + is_sat = s.check(mus.size(), mus.c_ptr()); + TRACE("sat", tout << "mus: " << mus << "\n";); } - lbool is_sat = s.check(mus.size(), mus.c_ptr()); - TRACE("sat", tout << "mus: " << mus << "\n";); switch (is_sat) { case l_undef: - mus.resize(sz); core.push_back(lit); set_core(); return l_undef; case l_true: { SASSERT(value_at(lit, s.get_model()) == l_false); - mus.resize(sz); mus.push_back(lit); + update_model(); if (!core.empty()) { // mr(); // TBD: measure } - double new_value = s.m_wsls.evaluate_model(s.m_model); - if (m_model.empty()) { - m_model.append(s.m_model); - m_best_value = new_value; - } - else if (m_best_value > new_value) { - m_model.reset(); - m_model.append(s.m_model); - m_best_value = new_value; - } break; } case l_false: literal_vector const& new_core = s.get_core(); - mus.resize(sz); if (new_core.contains(~lit)) { IF_VERBOSE(2, verbose_stream() << "miss core " << lit << "\n";); ++core_miss; @@ -141,27 +149,93 @@ namespace sat { IF_VERBOSE(2, verbose_stream() << "(sat.mus.new " << core << ")\n";); return l_true; } + // bisection search. lbool mus::mus2() { - literal_vector& core = get_core(); - literal_vector& mus = m_mus; - while (true) { + literal_set core(get_core()); + literal_set support; + lbool is_sat = qx(core, support, false); + s.m_core.reset(); + s.m_core.append(core.to_vector()); + IF_VERBOSE(2, verbose_stream() << "(sat.mus.new " << s.m_core << ")\n";); + return is_sat; + } -#if 0 - unsigned start = 0; - unsigned len = core.size(); - SASSERT(start < len); - unsigned mid = (len-start+1)/2; - mus.append(mid, core.c_ptr() + start); - start = start + mid; -#endif + lbool mus::qx(literal_set& assignment, literal_set& support, bool has_support) { + lbool is_sat = l_true; + if (s.m_stats.m_restart - m_restart > m_max_restarts) { + IF_VERBOSE(1, verbose_stream() << "restart budget exceeded\n";); + return l_true; } - return l_undef; + if (has_support) { + scoped_append _sa(m_mus, support.to_vector()); + is_sat = s.check(m_mus.size(), m_mus.c_ptr()); + switch (is_sat) { + case l_false: { + literal_set core(s.get_core()); + support &= core; + assignment.reset(); + return l_true; + } + case l_undef: + return l_undef; + case l_true: + update_model(); + break; + default: + break; + } + } + if (assignment.size() == 1) { + return l_true; + } + literal_set assign2; + split(assignment, assign2); + support |= assignment; + is_sat = qx(assign2, support, !assignment.empty()); + unsplit(support, assignment); + if (is_sat != l_true) return is_sat; + support |= assign2; + is_sat = qx(assignment, support, !assign2.empty()); + assignment |= assign2; + unsplit(support, assign2); + return is_sat; + } + + void mus::unsplit(literal_set& A, literal_set& B) { + literal_set A1, B1; + literal_set::iterator it = A.begin(), end = A.end(); + for (; it != end; ++it) { + if (B.contains(*it)) { + B1.insert(*it); + } + else { + A1.insert(*it); + } + } + A = A1; + B = B1; + } + + void mus::split(literal_set& lits1, literal_set& lits2) { + unsigned half = lits1.size()/2; + literal_set lits3; + literal_set::iterator it = lits1.begin(), end = lits1.end(); + for (unsigned i = 0; it != end; ++it, ++i) { + if (i < half) { + lits3.insert(*it); + } + else { + lits2.insert(*it); + } + } + lits1 = lits3; } literal_vector& mus::get_core() { m_core.reset(); + m_mus.reset(); literal_vector& core = m_core; core.append(s.get_core()); for (unsigned i = 0; i < core.size(); ++i) { @@ -175,6 +249,11 @@ namespace sat { return core; } + void mus::verify_core(literal_vector const& core) { + lbool is_sat = s.check(core.size(), core.c_ptr()); + IF_VERBOSE(3, verbose_stream() << "core verification: " << is_sat << " " << core << "\n";); + } + void mus::mr() { sls sls(s); literal_vector tabu; diff --git a/src/sat/sat_mus.h b/src/sat/sat_mus.h index ed7b8b13e..944cceffb 100644 --- a/src/sat/sat_mus.h +++ b/src/sat/sat_mus.h @@ -26,6 +26,8 @@ namespace sat { bool m_is_active; model m_model; // model obtained during minimal unsat core double m_best_value; + unsigned m_restart; + unsigned m_max_restarts; solver& s; @@ -38,10 +40,30 @@ namespace sat { private: lbool mus1(); lbool mus2(); + lbool qx(literal_set& assignment, literal_set& support, bool has_support); void mr(); void reset(); void set_core(); + void update_model(); literal_vector & get_core(); + void verify_core(literal_vector const& lits); + void split(literal_set& src, literal_set& dst); + void intersect(literal_set& dst, literal_set const& src); + void unsplit(literal_set& A, literal_set& B); + class scoped_append { + unsigned m_size; + literal_vector& m_lits; + public: + scoped_append(literal_vector& lits, literal_vector const& other): + m_size(lits.size()), + m_lits(lits) { + m_lits.append(other); + } + ~scoped_append() { + m_lits.resize(m_size); + } + + }; }; }; diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 937c7735f..0fa88d629 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -21,7 +21,6 @@ Revision History: #include"sat_simplifier.h" #include"sat_simplifier_params.hpp" #include"sat_solver.h" -#include"sat_bceq.h" #include"stopwatch.h" #include"trace.h" @@ -138,8 +137,10 @@ namespace sat { return; if (!m_subsumption && !m_elim_blocked_clauses && !m_resolution) return; + CASSERT("sat_solver", s.check_invariant()); TRACE("before_simplifier", s.display(tout);); + s.m_cleaner(true); m_last_sub_trail_sz = s.m_trail.size(); TRACE("after_cleanup", s.display(tout);); @@ -157,13 +158,6 @@ namespace sat { if (!learned && (m_elim_blocked_clauses || m_elim_blocked_clauses_at == m_num_calls)) elim_blocked_clauses(); -#if 1 - // experiment is disabled. - if (!learned) { // && m_equality_inference - bceq bc(s); - bc(); - } -#endif if (!learned) m_num_calls++; @@ -188,23 +182,21 @@ namespace sat { bool vars_eliminated = m_num_elim_vars > old_num_elim_vars; - if (!m_need_cleanup) { + if (m_need_cleanup) { + TRACE("after_simplifier", tout << "cleanning watches...\n";); + cleanup_watches(); + cleanup_clauses(s.m_learned, true, vars_eliminated, learned_in_use_lists); + cleanup_clauses(s.m_clauses, false, vars_eliminated, true); + } + else { TRACE("after_simplifier", tout << "skipping cleanup...\n";); if (vars_eliminated) { // must remove learned clauses with eliminated variables cleanup_clauses(s.m_learned, true, true, learned_in_use_lists); } - CASSERT("sat_solver", s.check_invariant()); - TRACE("after_simplifier", s.display(tout); tout << "model_converter:\n"; s.m_mc.display(tout);); - free_memory(); - return; } - TRACE("after_simplifier", tout << "cleanning watches...\n";); - cleanup_watches(); - cleanup_clauses(s.m_learned, true, vars_eliminated, learned_in_use_lists); - cleanup_clauses(s.m_clauses, false, vars_eliminated, true); - TRACE("after_simplifier", s.display(tout); tout << "model_converter:\n"; s.m_mc.display(tout);); CASSERT("sat_solver", s.check_invariant()); + TRACE("after_simplifier", s.display(tout); tout << "model_converter:\n"; s.m_mc.display(tout);); free_memory(); } @@ -926,10 +918,9 @@ namespace sat { void process(literal l) { TRACE("blocked_clause", tout << "processing: " << l << "\n";); - if (s.is_external(l.var()) || s.was_eliminated(l.var())) { - return; - } model_converter::entry * new_entry = 0; + if (s.is_external(l.var()) || s.was_eliminated(l.var())) + return; { m_to_remove.reset(); { @@ -1186,7 +1177,6 @@ namespace sat { continue; m_visited[l2.index()] = false; } - return res; } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index d97ebed46..86c81f071 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -483,7 +483,6 @@ namespace sat { void solver::set_conflict(justification c, literal not_l) { if (m_inconsistent) return; - TRACE("sat", tout << "conflict: " << not_l << "\n";); m_inconsistent = true; m_conflict = c; m_not_l = not_l; @@ -960,7 +959,11 @@ namespace sat { m_stopwatch.start(); m_core.reset(); TRACE("sat", display(tout);); - + + if (m_config.m_bcd) { + bceq bc(*this); + bc(); + } } /** @@ -1737,11 +1740,10 @@ namespace sat { // TBD: // apply optional clause minimization by detecting subsumed literals. // initial experiment suggests it has no effect. - m_mus(); // ignore return value on cancelation. m_model.reset(); m_model.append(m_mus.get_model()); - m_model_is_current = true; + m_model_is_current = !m_model.empty(); } } diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index db8de94a9..075c88fa1 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -160,6 +160,12 @@ namespace sat { m_in_set[v] = true; m_set.push_back(v); } + + uint_set& operator=(uint_set const& other) { + m_in_set = other.m_in_set; + m_set = other.m_set; + return *this; + } bool contains(unsigned v) const { return v < m_in_set.size() && m_in_set[v] != 0; @@ -177,10 +183,31 @@ namespace sat { m_in_set[v] = false; return v; } + unsigned size() const { return m_set.size(); } iterator begin() const { return m_set.begin(); } iterator end() const { return m_set.end(); } void reset() { m_set.reset(); m_in_set.reset(); } void cleanup() { m_set.finalize(); m_in_set.finalize(); } + uint_set& operator&=(uint_set const& other) { + unsigned j = 0; + for (unsigned i = 0; i < m_set.size(); ++i) { + if (other.contains(m_set[i])) { + m_set[j] = m_set[i]; + ++j; + } + else { + m_in_set[m_set[i]] = false; + } + } + m_set.resize(j); + return *this; + } + uint_set& operator|=(uint_set const& other) { + for (unsigned i = 0; i < other.m_set.size(); ++i) { + insert(other.m_set[i]); + } + return *this; + } }; typedef uint_set bool_var_set; @@ -188,11 +215,44 @@ namespace sat { class literal_set { uint_set m_set; public: + literal_set(literal_vector const& v) { + for (unsigned i = 0; i < v.size(); ++i) insert(v[i]); + } + literal_set() {} + literal_vector to_vector() const { + literal_vector result; + iterator it = begin(), e = end(); + for (; it != e; ++it) { + result.push_back(*it); + } + return result; + } void insert(literal l) { m_set.insert(l.index()); } bool contains(literal l) const { return m_set.contains(l.index()); } bool empty() const { return m_set.empty(); } + unsigned size() const { return m_set.size(); } void reset() { m_set.reset(); } void cleanup() { m_set.cleanup(); } + class iterator { + uint_set::iterator m_it; + public: + iterator(uint_set::iterator it):m_it(it) {} + literal operator*() const { return to_literal(*m_it); } + iterator& operator++() { ++m_it; return *this; } + iterator operator++(int) { iterator tmp = *this; ++m_it; return tmp; } + bool operator==(iterator const& it) const { return m_it == it.m_it; } + bool operator!=(iterator const& it) const { return m_it != it.m_it; } + }; + iterator begin() const { return iterator(m_set.begin()); } + iterator end() const { return iterator(m_set.end()); } + literal_set& operator&=(literal_set const& other) { + m_set &= other.m_set; + return *this; + } + literal_set& operator|=(literal_set const& other) { + m_set |= other.m_set; + return *this; + } }; struct mem_stat { From 0ccd56b8470b6535368175eadb8dfbb4e3f5d4cc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 5 Oct 2014 18:33:20 -0700 Subject: [PATCH 618/925] fix qe on undef Signed-off-by: Nikolaj Bjorner --- src/qe/qe.cpp | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/qe/qe.cpp b/src/qe/qe.cpp index 17a1ccb1d..7275ff71f 100644 --- a/src/qe/qe.cpp +++ b/src/qe/qe.cpp @@ -1449,11 +1449,19 @@ namespace qe { m_solver.assert_expr(m_fml); if (assumption) m_solver.assert_expr(assumption); - bool is_sat = false; - while (l_true == m_solver.check()) { - is_sat = true; + bool is_sat = false; + lbool res = l_true; + while (res == l_true) { + res = m_solver.check(); + if (res == l_true) is_sat = true; final_check(); } + if (res == l_undef) { + free_vars.append(num_vars, vars); + reset(); + m_solver.pop(1); + return; + } if (!is_sat) { fml = m.mk_false(); @@ -1484,12 +1492,13 @@ namespace qe { ); free_vars.append(m_free_vars); - SASSERT(!m_free_vars.empty() || m_solver.inconsistent()); + if (!m_free_vars.empty() || m_solver.inconsistent()) { - if (m_fml.get() != m_subfml.get()) { - scoped_ptr rp = mk_default_expr_replacer(m); - rp->apply_substitution(to_app(m_subfml.get()), fml, m_fml); - fml = m_fml; + if (m_fml.get() != m_subfml.get()) { + scoped_ptr rp = mk_default_expr_replacer(m); + rp->apply_substitution(to_app(m_subfml.get()), fml, m_fml); + fml = m_fml; + } } reset(); m_solver.pop(1); From 6191c3ff6e2ae9e541b2357b6a74ba9c02b4085f Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 6 Oct 2014 13:46:55 +0100 Subject: [PATCH 619/925] Bugfix (codeplex issue 132). Thanks to George Karpenov for catching this one! Signed-off-by: Christoph M. Wintersteiger --- src/api/z3_api.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 57e4d3ec1..397be7684 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -6023,7 +6023,7 @@ END_MLAPI_EXCLUDE \param a - arithmetical term def_API('Z3_optimize_maximize', UINT, (_in(CONTEXT), _in(OPTIMIZE), _in(AST))) */ - unsigned Z3_API Z3_optimize_maximize(Z3_context, Z3_optimize o, Z3_ast t); + unsigned Z3_API Z3_optimize_maximize(Z3_context c, Z3_optimize o, Z3_ast t); /** \brief Add a minimization constraint. @@ -6033,7 +6033,7 @@ END_MLAPI_EXCLUDE def_API('Z3_optimize_minimize', UINT, (_in(CONTEXT), _in(OPTIMIZE), _in(AST))) */ - unsigned Z3_API Z3_optimize_minimize(Z3_context, Z3_optimize o, Z3_ast t); + unsigned Z3_API Z3_optimize_minimize(Z3_context c, Z3_optimize o, Z3_ast t); /** From e363f1547f3a16e54383c241c75b436fbb2341f6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 Oct 2014 08:37:34 -0700 Subject: [PATCH 620/925] avoid re-declaration of contains_pred Signed-off-by: Nikolaj Bjorner --- src/muz/base/dl_context.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/muz/base/dl_context.h b/src/muz/base/dl_context.h index cfd4dfc3b..8e335f269 100644 --- a/src/muz/base/dl_context.h +++ b/src/muz/base/dl_context.h @@ -160,7 +160,6 @@ namespace datalog { class symbol_sort_domain; class uint64_sort_domain; class restore_rules; - class contains_pred; typedef hashtable symbol_set; typedef map sym2decl; From 4e686693ee61d7751210e3c854dd8851b2d0f24c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 Oct 2014 08:39:48 -0700 Subject: [PATCH 621/925] add declaration for w Signed-off-by: Nikolaj Bjorner --- src/util/union_find.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/union_find.h b/src/util/union_find.h index c98ca3fce..32de6846a 100644 --- a/src/util/union_find.h +++ b/src/util/union_find.h @@ -135,6 +135,7 @@ public: // dissolve equivalence class of v // this method cannot be used with backtracking. void dissolve(unsigned v) { + unsigned w; do { w = next(v); m_size[v] = 1; From 19e291f47979643b2f91c6d3f4d1832c6c744f7f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 Oct 2014 08:43:35 -0700 Subject: [PATCH 622/925] qe fix Signed-off-by: Nikolaj Bjorner --- src/qe/qe.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/qe/qe.cpp b/src/qe/qe.cpp index 7275ff71f..aa6287030 100644 --- a/src/qe/qe.cpp +++ b/src/qe/qe.cpp @@ -1453,8 +1453,13 @@ namespace qe { lbool res = l_true; while (res == l_true) { res = m_solver.check(); - if (res == l_true) is_sat = true; - final_check(); + if (res == l_true) { + is_sat = true; + final_check(); + } + else { + break; + } } if (res == l_undef) { free_vars.append(num_vars, vars); From 893d51eae8039e8f2b92d4bae3e6905e7698498b Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 6 Oct 2014 18:10:03 +0100 Subject: [PATCH 623/925] DoC: implement slow path of filter_negated using join+project. disable fast path since it's broken Signed-off-by: Nuno Lopes --- src/muz/rel/udoc_relation.cpp | 94 +++++++++-------------------------- src/test/udoc_relation.cpp | 12 ++--- 2 files changed, 30 insertions(+), 76 deletions(-) diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 4d1fdf1d2..1c7a78b09 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -1067,14 +1067,23 @@ namespace datalog { class udoc_plugin::negation_filter_fn : public relation_intersection_filter_fn { unsigned_vector m_t_cols; unsigned_vector m_neg_cols; + unsigned_vector m_remove_cols; + join_fn joiner; public: negation_filter_fn(const udoc_relation & r, const udoc_relation & neg, unsigned joined_col_cnt, const unsigned *t_cols, const unsigned *neg_cols) - : m_t_cols(joined_col_cnt, t_cols), m_neg_cols(joined_col_cnt, neg_cols) { + : m_t_cols(joined_col_cnt, t_cols), m_neg_cols(joined_col_cnt, neg_cols), + joiner(r.get_plugin(), r, neg, joined_col_cnt, t_cols, neg_cols) { SASSERT(joined_col_cnt > 0); r.expand_column_vector(m_t_cols); neg.expand_column_vector(m_neg_cols); + + unsigned num_neg_cols = get(neg).get_num_cols(); + unsigned num_r_cols = get(r).get_num_cols(); + for (unsigned i = 0; i < num_neg_cols; ++i) { + m_remove_cols.push_back(num_r_cols + i); + } } virtual void operator()(relation_base& tb, const relation_base& negb) { @@ -1092,6 +1101,8 @@ namespace datalog { } void fast_pass(udoc_relation& t, const udoc_relation& n) { + /* + // FIXME: this code doesn't take aliased columns into account udoc & dst = t.get_udoc(); udoc const & neg = n.get_udoc(); doc_manager& dmt = t.get_dm(); @@ -1110,83 +1121,26 @@ namespace datalog { result.push_back(&dst[i]); } std::swap(dst, result); + */ } void slow_pass(udoc_relation& t, udoc_relation const& n) { udoc & dst = t.get_udoc(); - udoc const & neg = n.get_udoc(); doc_manager& dmt = t.get_dm(); - doc_manager& dmn = n.get_dm(); - udoc renamed_neg; - for (unsigned i = 0; i < neg.size(); ++i) { - doc& neg_i = neg[i]; - doc_ref newD(dmt, dmt.allocateX()); - if (!copy_columns(newD->pos(), neg_i.pos(), t, n)) - continue; + udoc_relation *joined = get(joiner(t, n)); + if (joined->fast_empty()) { + return; + } + + project_fn projector(*joined, m_remove_cols.size(), m_remove_cols.c_ptr()); + udoc_relation *neg_projected = get(projector(*joined)); + joined->deallocate(); - bool is_empty = false; - for (unsigned j = 0; !is_empty && j < neg_i.neg().size(); ++j) { - tbv_ref newT(dmt.tbvm(), dmt.tbvm().allocateX()); - if (!copy_columns(*newT, neg_i.neg()[j], t, n) || - !dmt.tbvm().set_and(*newT, newD->pos())) { - continue; - } - if (dmt.tbvm().equals(newD->pos(), *newT)) { - is_empty = true; - } - else { - newD->neg().push_back(newT.detach()); - } - } - if (!is_empty) { - IF_VERBOSE(3, - dmn.display(verbose_stream() << "copy neg: ", neg_i) << "\n"; - dmt.display(verbose_stream() << "to dst: ", *newD) << "\n";); - renamed_neg.push_back(newD.detach()); - } - } TRACE("doc", dst.display(dmt, tout) << "\n"; - renamed_neg.display(dmt, tout) << "\n"; + neg_projected->get_udoc().display(dmt, tout) << "\n"; ); - dst.subtract(dmt, renamed_neg); - // TBD: double check semantics - TRACE("doc", dst.display(dmt, tout) << "\n";); - SASSERT(dst.well_formed(dmt)); - renamed_neg.reset(dmt); - IF_VERBOSE(3, t.display(verbose_stream() << "slow case:");); - } - - bool copy_columns( - tbv& dst, tbv const& src, - udoc_relation const& dstt, - udoc_relation const& srct) - { - unsigned num_cols = m_t_cols.size(); - for (unsigned i = 0; i < num_cols; ++i) { - if (!copy_column(dst, src, m_t_cols[i], m_neg_cols[i], dstt, srct)) - return false; - } - return true; - } - bool copy_column( - tbv& dst, tbv const& src, - unsigned col_dst, unsigned col_src, - udoc_relation const& dstt, - udoc_relation const& srct) { - tbv_manager& dm = dstt.get_dm().tbvm(); - unsigned idx_dst = dstt.column_idx(col_dst); - unsigned idx_src = srct.column_idx(col_src); - unsigned num_tbits = dstt.column_num_bits(col_dst); - SASSERT(num_tbits == srct.column_num_bits(col_src)); - IF_VERBOSE(3, verbose_stream() << "copy column " << idx_src - << " to " << idx_dst << " " << num_tbits << "\n";); - for (unsigned i = 0; i < num_tbits; ++i) { - tbit bit = (tbit)(dst[idx_dst + i] & src[idx_src + i]); - if (bit == BIT_z) - return false; - dm.set(dst, idx_dst + i, bit); - } - return true; + dst.subtract(dmt, neg_projected->get_udoc()); + neg_projected->deallocate(); } }; diff --git a/src/test/udoc_relation.cpp b/src/test/udoc_relation.cpp index 31908a41d..3fc727d14 100644 --- a/src/test/udoc_relation.cpp +++ b/src/test/udoc_relation.cpp @@ -146,8 +146,8 @@ public: test_filter_neg4(false); test_filter_neg4(true); - test_filter_neg6(false); - test_filter_neg6(true); + test_filter_neg5(false); + test_filter_neg5(true); test_filter_neg(); test_filter_neg2(); @@ -657,6 +657,10 @@ public: if (disable_fast) p.disable_fast_pass(); apply_filter_neg(*tgt, *neg, cols1, cols2); tgt->deallocate(); + + tgt = mk_full(sig1); + apply_filter_neg(*neg, *tgt, cols2, cols1); + tgt->deallocate(); neg->deallocate(); } @@ -675,7 +679,6 @@ public: cols2.push_back(2); cols3.push_back(0); cols3.push_back(1); - cols3.push_back(2); udoc_relation* tgt = mk_full(sig1); udoc_relation* neg = mk_full(sig2); rel_mut filter_id = p.mk_filter_identical_fn(*tgt, cols3.size(), cols3.c_ptr()); @@ -686,9 +689,6 @@ public: neg->deallocate(); } - // TBD: unit test to expose similar bug as projection had. - // you can't just remove columns when there are side-constraints in neg. - void set_random(udoc_relation& r, unsigned num_vals) { unsigned num_bits = r.get_dm().num_tbits(); udoc_relation* full = mk_full(r.get_signature()); From 83c60437419d6394dac31e1276dd0cb891408faf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 Oct 2014 10:13:10 -0700 Subject: [PATCH 624/925] undef max/min on apple to avoid warning Signed-off-by: Nikolaj Bjorner --- src/util/mpff.cpp | 2 +- src/util/trace.h | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/util/mpff.cpp b/src/util/mpff.cpp index 7678a051e..ab016ae40 100644 --- a/src/util/mpff.cpp +++ b/src/util/mpff.cpp @@ -22,7 +22,7 @@ Revision History: #include #include"mpff.h" #include"mpn.h" -#include"mpz.h" +#include"mpz.h"g #include"mpq.h" #include"bit_util.h" #include"trace.h" diff --git a/src/util/trace.h b/src/util/trace.h index 0c8c2e5b6..e92eb9d44 100644 --- a/src/util/trace.h +++ b/src/util/trace.h @@ -24,6 +24,10 @@ Revision History: #undef max #undef min #endif +#ifdef __APPLE__ +#undef max +#undef min +#endif #include #ifdef _TRACE From fdc1452ac635146eb69abbe763f5b66aabcb80c2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 Oct 2014 10:13:31 -0700 Subject: [PATCH 625/925] undef max/min on apple to avoid warning Signed-off-by: Nikolaj Bjorner --- src/util/mpff.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/mpff.cpp b/src/util/mpff.cpp index ab016ae40..7678a051e 100644 --- a/src/util/mpff.cpp +++ b/src/util/mpff.cpp @@ -22,7 +22,7 @@ Revision History: #include #include"mpff.h" #include"mpn.h" -#include"mpz.h"g +#include"mpz.h" #include"mpq.h" #include"bit_util.h" #include"trace.h" From 7ef311acd365a1bd61f616295113a252df680970 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 Oct 2014 13:05:53 -0700 Subject: [PATCH 626/925] updated check_relation test for join-project Signed-off-by: Nikolaj Bjorner --- src/muz/rel/check_relation.cpp | 161 ++++++++++++++++++++++----------- src/muz/rel/check_relation.h | 21 ++++- src/test/udoc_relation.cpp | 2 +- 3 files changed, 131 insertions(+), 53 deletions(-) diff --git a/src/muz/rel/check_relation.cpp b/src/muz/rel/check_relation.cpp index 46d1171d0..c1b840c61 100644 --- a/src/muz/rel/check_relation.cpp +++ b/src/muz/rel/check_relation.cpp @@ -41,6 +41,12 @@ namespace datalog { return get_plugin().ground(*this, fml); } + expr_ref check_relation_plugin::ground(relation_base const& dst) const { + expr_ref fml(m); + dst.to_formula(fml); + return ground(dst, fml); + } + expr_ref check_relation_plugin::ground(relation_base const& dst, expr* fml) const { relation_signature const& sig = dst.get_signature(); var_subst sub(m, false); @@ -187,7 +193,7 @@ namespace datalog { check_relation const& t2 = get(r2); check_relation_plugin& p = t1.get_plugin(); relation_base* r = (*m_join)(t1.rb(), t2.rb()); - p.verify_join(r1, r2, *r, m_cols1.size(), m_cols1.c_ptr(), m_cols2.c_ptr()); + p.verify_join(r1, r2, *r, m_cols1, m_cols2); return alloc(check_relation, p, r->get_signature(), r); } }; @@ -199,6 +205,38 @@ namespace datalog { return j?alloc(join_fn, j, t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2):0; } + class check_relation_plugin::join_project_fn : public convenient_relation_join_project_fn { + scoped_ptr m_join; + public: + join_project_fn( + relation_join_fn* j, + const relation_signature & o1_sig, const relation_signature & o2_sig, unsigned col_cnt, + const unsigned * cols1, const unsigned * cols2, + unsigned removed_col_cnt, const unsigned* removed_cols) + : convenient_join_project_fn(o1_sig, o2_sig, col_cnt, cols1, cols2, + removed_col_cnt, removed_cols), m_join(j) + {} + virtual ~join_project_fn() {} + virtual relation_base * operator()(const relation_base & r1, const relation_base & r2) { + check_relation const& t1 = get(r1); + check_relation const& t2 = get(r2); + check_relation_plugin& p = t1.get_plugin(); + relation_base* r = (*m_join)(t1.rb(), t2.rb()); + p.verify_join_project(r1, r2, *r, m_cols1, m_cols2, m_removed_cols); + return alloc(check_relation, p, r->get_signature(), r); + } + }; + + relation_join_fn * check_relation_plugin::mk_join_project_fn( + const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, + unsigned removed_col_cnt, const unsigned * removed_cols) { + relation_join_fn* j = m_base->mk_join_project_fn(get(t1).rb(), get(t2).rb(), col_cnt, cols1, cols2, + removed_col_cnt, removed_cols); + return j?alloc(join_project_fn, j, t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2, + removed_col_cnt, removed_cols):0; + } + void check_relation_plugin::verify_filter_project( relation_base const& src, relation_base const& dst, app* cond, unsigned_vector const& removed_cols) { @@ -222,39 +260,88 @@ namespace datalog { relation_base const& src, expr* f1, relation_base const& dst, expr* f2, unsigned_vector const& removed_cols) { + expr_ref fml1 = ground(dst, mk_project(src.get_signature(), f1, removed_cols)); + expr_ref fml2 = ground(dst, f2); + check_equiv("project", fml1, fml2); + } + expr_ref check_relation_plugin::mk_project( + relation_signature const& sig, + expr* fml, unsigned_vector const& removed_cols) { expr_ref fml1(m); - expr_ref fml2(m); - expr_ref_vector vars1(m), vars2(m); ptr_vector bound; svector names; - relation_signature const& sig1 = src.get_signature(); - relation_signature const& sig2 = dst.get_signature(); - for (unsigned i = 0; i < sig2.size(); ++i) { - vars2.push_back(m.mk_const(symbol(i), sig2[i])); - } - for (unsigned i = 0, j = 0, k = 0; i < sig1.size(); ++i) { - if (j < removed_cols.size() && removed_cols[j] == i) { + expr_ref_vector vars(m); + unsigned rm_cnt = removed_cols.size(); + for (unsigned i = 0, j = 0, k = 0; i < sig.size(); ++i) { + if (j < rm_cnt && removed_cols[j] == i) { std::ostringstream strm; strm << "x" << j; - bound.push_back(sig1[i]); + bound.push_back(sig[i]); names.push_back(symbol(strm.str().c_str())); - vars1.push_back(m.mk_var(j, sig1[i])); + vars.push_back(m.mk_var(j, sig[i])); ++j; } else { - vars1.push_back(vars2[k].get()); - SASSERT(m.get_sort(vars2[k].get()) == sig1[i]); + vars.push_back(m.mk_var(k + rm_cnt, sig[i])); ++k; } } var_subst sub(m, false); - sub(f1, vars1.size(), vars1.c_ptr(), fml1); - sub(f2, vars2.size(), vars2.c_ptr(), fml2); + sub(fml, vars.size(), vars.c_ptr(), fml1); bound.reverse(); fml1 = m.mk_exists(bound.size(), bound.c_ptr(), names.c_ptr(), fml1); - check_equiv("project", fml1, fml2); + return fml1; } + void check_relation_plugin::verify_join_project( + relation_base const& t1, relation_base const& t2, relation_base const& t, + unsigned_vector const& cols1, unsigned_vector const& cols2, unsigned_vector const& rm_cols) { + ast_manager& m = get_ast_manager(); + relation_signature const& sig2 = t.get_signature(); + relation_signature const& sigA = t1.get_signature(); + relation_signature const& sigB = t2.get_signature(); + relation_signature sig1; + sig1.append(sigA); + sig1.append(sigB); + + expr_ref fml1 = mk_join(t1, t2, cols1, cols2); + fml1 = mk_project(sig1, fml1, rm_cols); + fml1 = ground(t, fml1); + expr_ref fml2(m); + t.to_formula(fml2); + fml2 = ground(t, fml2); + check_equiv("join_project", fml1, fml2); + } + + expr_ref check_relation_plugin::mk_join( + relation_base const& t1, relation_base const& t2, + unsigned_vector const& cols1, unsigned_vector const& cols2) { + ast_manager& m = get_ast_manager(); + expr_ref fml1(m), fml2(m), fml3(m); + + relation_signature const& sig1 = t1.get_signature(); + relation_signature const& sig2 = t2.get_signature(); + var_ref var1(m), var2(m); + t1.to_formula(fml1); + t2.to_formula(fml2); + var_subst sub(m, false); + expr_ref_vector vars(m); + for (unsigned i = 0; i < sig2.size(); ++i) { + vars.push_back(m.mk_var(i + sig1.size(), sig2[i])); + } + sub(fml2, vars.size(), vars.c_ptr(), fml2); + fml1 = m.mk_and(fml1, fml2); + for (unsigned i = 0; i < cols1.size(); ++i) { + unsigned v1 = cols1[i]; + unsigned v2 = cols2[i]; + var1 = m.mk_var(v1, sig1[v1]); + var2 = m.mk_var(v2 + sig1.size(), sig2[v2]); + fml1 = m.mk_and(m.mk_eq(var1, var2), fml1); + } + return fml1; + } + + void check_relation_plugin::verify_permutation( relation_base const& src, relation_base const& dst, unsigned_vector const& cycle) { @@ -293,41 +380,13 @@ namespace datalog { check_equiv("permutation", fml1, fml2); } - void check_relation_plugin::verify_join(relation_base const& t1, relation_base const& t2, relation_base const& t, - unsigned sz, unsigned const* cols1, unsigned const* cols2) { + void check_relation_plugin::verify_join( + relation_base const& t1, relation_base const& t2, relation_base const& t, + unsigned_vector const& cols1, unsigned_vector const& cols2) { ast_manager& m = get_ast_manager(); - expr_ref fml1(m), fml2(m), fml3(m); - - relation_signature const& sig1 = t1.get_signature(); - relation_signature const& sig2 = t2.get_signature(); - relation_signature const& sig = t.get_signature(); - var_ref var1(m), var2(m); - t1.to_formula(fml1); - t2.to_formula(fml2); - t.to_formula(fml3); - var_subst sub(m, false); - expr_ref_vector vars(m); - for (unsigned i = 0; i < sig2.size(); ++i) { - vars.push_back(m.mk_var(i + sig1.size(), sig2[i])); - } - sub(fml2, vars.size(), vars.c_ptr(), fml2); - fml1 = m.mk_and(fml1, fml2); - for (unsigned i = 0; i < sz; ++i) { - unsigned v1 = cols1[i]; - unsigned v2 = cols2[i]; - var1 = m.mk_var(v1, sig1[v1]); - var2 = m.mk_var(v2 + sig1.size(), sig2[v2]); - fml1 = m.mk_and(m.mk_eq(var1, var2), fml1); - } - vars.reset(); - for (unsigned i = 0; i < sig.size(); ++i) { - std::stringstream strm; - strm << "x" << i; - vars.push_back(m.mk_const(symbol(strm.str().c_str()), sig[i])); - } - sub(fml1, vars.size(), vars.c_ptr(), fml1); - sub(fml3, vars.size(), vars.c_ptr(), fml3); - check_equiv("join", fml1, fml3); + expr_ref fml1 = ground(t, mk_join(t1, t2, cols1, cols2)); + expr_ref fml2 = ground(t); + check_equiv("join", fml1, fml2); } void check_relation_plugin::verify_filter(expr* fml0, relation_base const& t, expr* cond) { diff --git a/src/muz/rel/check_relation.h b/src/muz/rel/check_relation.h index 580ce3dd4..8000a2c72 100644 --- a/src/muz/rel/check_relation.h +++ b/src/muz/rel/check_relation.h @@ -62,6 +62,7 @@ namespace datalog { friend class check_relation; class join_fn; + class join_project_fn; class project_fn; class union_fn; class rename_fn; @@ -78,6 +79,15 @@ namespace datalog { static check_relation* get(relation_base* r); static check_relation const & get(relation_base const& r); expr_ref ground(relation_base const& rb, expr* fml) const; + expr_ref ground(relation_base const& rb) const; + + expr_ref mk_project( + relation_signature const& sig, + expr* fml, unsigned_vector const& removed_cols); + + expr_ref mk_join( + relation_base const& t1, relation_base const& t2, + unsigned_vector const& cols1, unsigned_vector const& cols2); public: check_relation_plugin(relation_manager& rm); ~check_relation_plugin(); @@ -89,6 +99,10 @@ namespace datalog { virtual relation_base * mk_full(func_decl* p, const relation_signature & s); virtual relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); + virtual relation_join_fn * mk_join_project_fn( + const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, + unsigned removed_col_cnt, const unsigned * removed_cols); virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, const unsigned * removed_cols); virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, @@ -111,7 +125,8 @@ namespace datalog { unsigned removed_col_cnt, const unsigned * removed_cols); void verify_join(relation_base const& t1, relation_base const& t2, relation_base const& t, - unsigned sz, unsigned const* cols1, unsigned const* cols2); + unsigned_vector const& cols1, unsigned_vector const& cols2); + void verify_filter(expr* fml0, relation_base const& t, expr* cond); @@ -136,6 +151,10 @@ namespace datalog { relation_base const& src, relation_base const& dst, app* cond, unsigned_vector const& removed_cols); + void verify_join_project( + relation_base const& t1, relation_base const& t2, relation_base const& t, + unsigned_vector const& cols1, unsigned_vector const& cols2, unsigned_vector const& rm_cols); + void check_equiv(char const* objective, expr* f1, expr* f2); void check_contains(char const* objective, expr* f1, expr* f2); diff --git a/src/test/udoc_relation.cpp b/src/test/udoc_relation.cpp index 3fc727d14..24ccb34b0 100644 --- a/src/test/udoc_relation.cpp +++ b/src/test/udoc_relation.cpp @@ -456,7 +456,7 @@ public: join_fn = p.mk_join_fn(*t1, *t2, jc1.size(), jc1.c_ptr(), jc2.c_ptr()); t = (*join_fn)(*t1, *t2); - cr.verify_join(*t1, *t2, *t, jc1.size(), jc1.c_ptr(), jc2.c_ptr()); + cr.verify_join(*t1, *t2, *t, jc1, jc2); t1->display(std::cout); t2->display(std::cout); t->display(std::cout); From 10c40d64b6066a897b5ae2dbbea23fae92d165df Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 Oct 2014 15:56:49 -0700 Subject: [PATCH 627/925] streamline filter-by-negation Signed-off-by: Nikolaj Bjorner --- src/muz/rel/udoc_relation.cpp | 133 +++++++++++++++++++++++----------- 1 file changed, 90 insertions(+), 43 deletions(-) diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 1c7a78b09..ea04e4263 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -1056,6 +1056,52 @@ namespace datalog { return check_kind(t)?alloc(filter_interpreted_fn, get(t), get_ast_manager(), condition):0; } + class udoc_plugin::join_project_fn : convenient_relation_join_project_fn { + udoc_plugin::join_fn m_joiner; + public: + join_project_fn( + udoc_relation const& t1, udoc_relation const& t2, unsigned col_cnt, + const unsigned * cols1, const unsigned * cols2, + unsigned removed_col_cnt, unsigned const* removed_cols) + : convenient_relation_join_project_fn( + t1.get_signature(), t2.get_signature(), + col_cnt, cols1, cols2, + removed_col_cnt, removed_cols), + m_joiner(t1.get_plugin(), t1, t2, col_cnt, cols1, cols2) + { + } + + virtual relation_base* operator()(relation_base const& t1, relation_base const& t2) { + udoc_relation *joined = get(m_joiner(t1, t2)); + relation_base* result = 0; + if (joined->fast_empty()) { + result = t1.get_plugin().mk_empty(get_result_signature()); + } + else { + project_fn projector(*joined, m_removed_cols.size(), m_removed_cols.c_ptr()); + result = projector(*joined); + } + joined->deallocate(); + return result; + } + }; + + relation_join_fn * udoc_plugin::mk_join_project_fn( + relation_base const& t1, relation_base const& t2, + unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, + unsigned removed_col_cnt, const unsigned * removed_cols) { + if (check_kind(t1) && check_kind(t2)) + return 0; +#if 0 + return alloc(join_project_fn, get(t1), ge(t2), + joined_col_cnt, cols1, cols2, + removed_col_cnt, removed_cols); +#endif + else + return 0; + } + + // // Notes: // 1. this code could use some cleanup and simplification. @@ -1065,25 +1111,43 @@ namespace datalog { // 4. Unit/stress test cases are needed. // class udoc_plugin::negation_filter_fn : public relation_intersection_filter_fn { + struct mk_remove_cols { + mk_remove_cols(relation_base const& t1, relation_base const& t2, unsigned_vector& remove_cols) { + unsigned sz1 = t1.get_signature().size(); + unsigned sz2 = t2.get_signature().size(); + for (unsigned i = 0; i < sz2; ++i) { + remove_cols.push_back(sz1 + i); + } + } + }; unsigned_vector m_t_cols; unsigned_vector m_neg_cols; unsigned_vector m_remove_cols; - join_fn joiner; - + mk_remove_cols m_mk_remove_cols; + join_project_fn m_join_project; + bool m_is_subtract; + bool m_is_aliased; public: negation_filter_fn(const udoc_relation & r, const udoc_relation & neg, unsigned joined_col_cnt, const unsigned *t_cols, const unsigned *neg_cols) - : m_t_cols(joined_col_cnt, t_cols), m_neg_cols(joined_col_cnt, neg_cols), - joiner(r.get_plugin(), r, neg, joined_col_cnt, t_cols, neg_cols) { + : m_t_cols(joined_col_cnt, t_cols), + m_neg_cols(joined_col_cnt, neg_cols), + m_mk_remove_cols(r, neg, m_remove_cols), + m_join_project(r, neg, joined_col_cnt, t_cols, neg_cols, + m_remove_cols.size(), m_remove_cols.c_ptr()), + m_is_subtract(false), + m_is_aliased(true) { SASSERT(joined_col_cnt > 0); + if (joined_col_cnt == r.get_signature().size()) { + m_is_subtract = true; + svector found(joined_col_cnt, false); + for (unsigned i = 0; m_is_subtract && i < joined_col_cnt; ++i) { + m_is_subtract = !found[t_cols[i]] && (t_cols[i] == neg_cols[i]); + found[t_cols[i]] = true; + } + } r.expand_column_vector(m_t_cols); neg.expand_column_vector(m_neg_cols); - - unsigned num_neg_cols = get(neg).get_num_cols(); - unsigned num_r_cols = get(r).get_num_cols(); - for (unsigned i = 0; i < num_neg_cols; ++i) { - m_remove_cols.push_back(num_r_cols + i); - } } virtual void operator()(relation_base& tb, const relation_base& negb) { @@ -1092,17 +1156,22 @@ namespace datalog { udoc_plugin& p = t.get_plugin(); IF_VERBOSE(3, t.display(verbose_stream() << "dst:");); IF_VERBOSE(3, n.display(verbose_stream() << "neg:");); - if (!t.fast_empty() && !n.fast_empty() && !p.m_disable_fast_pass) { - fast_pass(t, n); + if (!m_is_aliased && !t.fast_empty() && !n.fast_empty() && !p.m_disable_fast_pass) { + // fast_pass(t, n); + } + if (m_is_subtract && !t.fast_empty() && !n.fast_empty()) { + t.get_udoc().subtract(t.get_dm(), n.get_udoc()); + return; } if (!t.fast_empty() && !n.fast_empty()) { slow_pass(t, n); } } + private: + void fast_pass(udoc_relation& t, const udoc_relation& n) { - /* - // FIXME: this code doesn't take aliased columns into account + SASSERT(!m_is_aliased); udoc & dst = t.get_udoc(); udoc const & neg = n.get_udoc(); doc_manager& dmt = t.get_dm(); @@ -1121,26 +1190,16 @@ namespace datalog { result.push_back(&dst[i]); } std::swap(dst, result); - */ } void slow_pass(udoc_relation& t, udoc_relation const& n) { - udoc & dst = t.get_udoc(); doc_manager& dmt = t.get_dm(); - udoc_relation *joined = get(joiner(t, n)); - if (joined->fast_empty()) { - return; + udoc_relation* jp = get(m_join_project(t, n)); + if (!jp->fast_empty()) { + t.get_udoc().subtract(dmt, jp->get_udoc()); } - - project_fn projector(*joined, m_remove_cols.size(), m_remove_cols.c_ptr()); - udoc_relation *neg_projected = get(projector(*joined)); - joined->deallocate(); - - TRACE("doc", dst.display(dmt, tout) << "\n"; - neg_projected->get_udoc().display(dmt, tout) << "\n"; - ); - dst.subtract(dmt, neg_projected->get_udoc()); - neg_projected->deallocate(); + TRACE("doc", t.display(tout); tout << "\n"; jp->display(tout); tout << "\n";); + jp->deallocate(); } }; @@ -1153,6 +1212,8 @@ namespace datalog { return alloc(negation_filter_fn, get(t), get(neg), joined_col_cnt, t_cols, negated_cols); } + + class udoc_plugin::filter_proj_fn : public convenient_relation_project_fn { union_find_default_ctx union_ctx; doc_manager& dm; @@ -1218,20 +1279,6 @@ namespace datalog { return check_kind(t)?alloc(filter_proj_fn, get(t), get_ast_manager(), condition, removed_col_cnt, removed_cols):0; } - relation_join_fn * udoc_plugin::mk_join_project_fn( - relation_base const& t1, relation_base const& t2, - unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, - unsigned removed_col_cnt, const unsigned * removed_cols) { - if (check_kind(t1) && check_kind(t2)) - return 0; -#if 0 - return alloc(join_proj_fn, get(t1), ge(t2), - joined_col_cnt, cols1, cols2, - removed_col_cnt, removed_cols); -#endif - else - return 0; - } From 5287089be219d95600edd510f373eae491a041ce Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 7 Oct 2014 04:31:24 -0700 Subject: [PATCH 628/925] sketch tuned join-project Signed-off-by: Nikolaj Bjorner --- src/muz/rel/udoc_relation.cpp | 102 ++++++++++++++++++++++++++++++---- 1 file changed, 91 insertions(+), 11 deletions(-) diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index ea04e4263..28c9bb9a4 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -1057,20 +1057,50 @@ namespace datalog { } class udoc_plugin::join_project_fn : convenient_relation_join_project_fn { - udoc_plugin::join_fn m_joiner; + udoc_plugin::join_fn m_joiner; + union_find_default_ctx union_ctx; + bit_vector m_to_delete; + subset_ints m_equalities; + unsigned_vector m_roots; + public: join_project_fn( udoc_relation const& t1, udoc_relation const& t2, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, - unsigned removed_col_cnt, unsigned const* removed_cols) + unsigned removed_col_cnt, unsigned const* rm_cols) : convenient_relation_join_project_fn( t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2, - removed_col_cnt, removed_cols), - m_joiner(t1.get_plugin(), t1, t2, col_cnt, cols1, cols2) + removed_col_cnt, rm_cols), + m_joiner(t1.get_plugin(), t1, t2, col_cnt, cols1, cols2), + m_equalities(union_ctx) { + udoc_plugin& p = t1.get_plugin(); + udoc_relation* res = get(p.mk_empty(get_result_signature())); + unsigned num_bits = res->get_num_bits(); + unsigned num_bits1 = t1.get_num_bits(); + unsigned_vector removed_cols(removed_col_cnt, rm_cols); + unsigned_vector expcols1(col_cnt, cols1); + unsigned_vector expcols2(col_cnt, cols2); + res->expand_column_vector(removed_cols); + t1.expand_column_vector(expcols1); + t2.expand_column_vector(expcols2); + m_to_delete.resize(num_bits, false); + for (unsigned i = 0; i < num_bits; ++i) { + m_equalities.mk_var(); + } + for (unsigned i = 0; i < removed_cols.size(); ++i) { + m_to_delete.set(removed_cols[i], true); + } + for (unsigned i = 0; i < expcols1.size(); ++i) { + m_equalities.merge(expcols1[i], expcols2[i] + num_bits1); + } + m_roots.append(expcols1); + res->deallocate(); } + + // TBD: replace this by "join" given below. virtual relation_base* operator()(relation_base const& t1, relation_base const& t2) { udoc_relation *joined = get(m_joiner(t1, t2)); relation_base* result = 0; @@ -1084,6 +1114,57 @@ namespace datalog { joined->deallocate(); return result; } + private: + + udoc_relation* join(udoc_relation const& t1, udoc_relation const& t2) { + relation_signature prod_signature; + prod_signature.append(t1.get_signature()); + prod_signature.append(t2.get_signature()); + udoc prod; + udoc const& d1 = t1.get_udoc(); + udoc const& d2 = t2.get_udoc(); + doc_manager& dm1 = t1.get_dm(); + udoc_plugin& p = t1.get_plugin(); + doc_manager& dm_prod = p.dm(prod_signature); + udoc_relation* result = get(p.mk_empty(get_result_signature())); + udoc& res = result->get_udoc(); + doc_manager& dm_res = result->get_dm(); + for (unsigned i = 0; i < d1.size(); ++i) { + for (unsigned j = 0; j < d2.size(); ++j) { + prod.push_back(xprod(dm_prod, dm1, d1[i], d2[j])); + } + } + prod.merge(dm_prod, m_roots, m_equalities, m_to_delete); + for (unsigned i = 0; i < prod.size(); ++i) { + res.insert(dm_res, dm_prod.project(dm_res, m_to_delete.size(), m_to_delete, prod[i])); + } + prod.reset(dm_prod); + return result; + } + doc* xprod(doc_manager& dm, doc_manager& dm1, doc const& d1, doc const& d2) { + tbv_manager& tbm = dm.tbvm(); + doc_ref d(dm); + tbv_ref t(tbm); + d = dm.allocateX(); + tbv& pos = d->pos(); + utbv& neg = d->neg(); + unsigned mid = dm1.num_tbits(); + unsigned hi = dm.num_tbits(); + tbm.set(pos,d1.pos(), mid-1, 0); + tbm.set(pos,d2.pos(), hi-1, mid); + for (unsigned i = 0; i < d1.neg().size(); ++i) { + t = tbm.allocateX(); + tbm.set(*t, d1.neg()[i], mid-1, 0); + neg.push_back(t.detach()); + } + for (unsigned i = 0; i < d2.neg().size(); ++i) { + t = tbm.allocateX(); + tbm.set(*t, d2.neg()[i], hi-1, mid); + neg.push_back(t.detach()); + } + return d.detach(); + } + }; relation_join_fn * udoc_plugin::mk_join_project_fn( @@ -1138,13 +1219,12 @@ namespace datalog { m_is_subtract(false), m_is_aliased(true) { SASSERT(joined_col_cnt > 0); - if (joined_col_cnt == r.get_signature().size()) { - m_is_subtract = true; - svector found(joined_col_cnt, false); - for (unsigned i = 0; m_is_subtract && i < joined_col_cnt; ++i) { - m_is_subtract = !found[t_cols[i]] && (t_cols[i] == neg_cols[i]); - found[t_cols[i]] = true; - } + m_is_subtract = (joined_col_cnt == r.get_signature().size()); + m_is_subtract &= (joined_col_cnt == neg.get_signature().size()); + svector found(joined_col_cnt, false); + for (unsigned i = 0; m_is_subtract && i < joined_col_cnt; ++i) { + m_is_subtract = !found[t_cols[i]] && (t_cols[i] == neg_cols[i]); + found[t_cols[i]] = true; } r.expand_column_vector(m_t_cols); neg.expand_column_vector(m_neg_cols); From 528bb507b287c23447866d10c102d39a61735174 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 7 Oct 2014 13:01:35 +0100 Subject: [PATCH 629/925] DoC: fix memory leak Signed-off-by: Nuno Lopes --- src/muz/rel/doc.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/muz/rel/doc.cpp b/src/muz/rel/doc.cpp index e5a6fd97f..adc7e959a 100644 --- a/src/muz/rel/doc.cpp +++ b/src/muz/rel/doc.cpp @@ -82,6 +82,7 @@ void doc_manager::deallocate(doc* src) { if (!src) return; m.deallocate(&src->pos()); src->neg().reset(m); + src->~doc(); m_alloc.deallocate(sizeof(doc), src); } void doc_manager::copy(doc& dst, doc const& src) { From 06c7f3f246fb01075aca841a744152d2c7ff112d Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 7 Oct 2014 14:33:23 +0100 Subject: [PATCH 630/925] DoC: fix bugs in the new join_project Signed-off-by: Nuno Lopes --- src/muz/rel/udoc_relation.cpp | 8 +++----- src/muz/rel/udoc_relation.h | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 28c9bb9a4..1ea185530 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -80,7 +80,7 @@ namespace datalog { void udoc_relation::reset() { m_elems.reset(dm); } - void udoc_relation::expand_column_vector(unsigned_vector& v, udoc_relation* other) const { + void udoc_relation::expand_column_vector(unsigned_vector& v, const udoc_relation* other) const { unsigned_vector orig; orig.swap(v); for (unsigned i = 0; i < orig.size(); ++i) { @@ -1076,13 +1076,12 @@ namespace datalog { m_equalities(union_ctx) { udoc_plugin& p = t1.get_plugin(); - udoc_relation* res = get(p.mk_empty(get_result_signature())); - unsigned num_bits = res->get_num_bits(); unsigned num_bits1 = t1.get_num_bits(); + unsigned num_bits = num_bits1 + t2.get_num_bits(); unsigned_vector removed_cols(removed_col_cnt, rm_cols); unsigned_vector expcols1(col_cnt, cols1); unsigned_vector expcols2(col_cnt, cols2); - res->expand_column_vector(removed_cols); + t1.expand_column_vector(removed_cols, &t2); t1.expand_column_vector(expcols1); t2.expand_column_vector(expcols2); m_to_delete.resize(num_bits, false); @@ -1096,7 +1095,6 @@ namespace datalog { m_equalities.merge(expcols1[i], expcols2[i] + num_bits1); } m_roots.append(expcols1); - res->deallocate(); } diff --git a/src/muz/rel/udoc_relation.h b/src/muz/rel/udoc_relation.h index 596a1f0dd..7934521a8 100644 --- a/src/muz/rel/udoc_relation.h +++ b/src/muz/rel/udoc_relation.h @@ -62,7 +62,7 @@ namespace datalog { unsigned get_num_cols() const { return m_column_info.size()-1; } unsigned column_idx(unsigned col) const { return m_column_info[col]; } unsigned column_num_bits(unsigned col) const { return m_column_info[col+1] - m_column_info[col]; } - void expand_column_vector(unsigned_vector& v, udoc_relation* other = 0) const; + void expand_column_vector(unsigned_vector& v, const udoc_relation* other = 0) const; void extract_guard(expr* condition, expr_ref& guard, expr_ref& rest) const; bool is_guard(expr* g) const; bool is_guard(unsigned n, expr* const *g) const; From a3a008bdde5de33c819de8d9965d8a098acbcfb8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 7 Oct 2014 19:54:04 -0700 Subject: [PATCH 631/925] update Deprecated API to avoid memory leak and crash when there is a core, ensure invariant in new code Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Deprecated.cs | 15 +++++++++++---- src/muz/rel/udoc_relation.cpp | 7 +++++-- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/api/dotnet/Deprecated.cs b/src/api/dotnet/Deprecated.cs index 7dc524834..aa6dffb45 100644 --- a/src/api/dotnet/Deprecated.cs +++ b/src/api/dotnet/Deprecated.cs @@ -65,22 +65,29 @@ namespace Microsoft.Z3 /// /// Checks whether the assertions in the context are consistent or not. /// - public static Status Check(Context ctx, List core, params Expr[] assumptions) + public static Status Check(Context ctx, List core, ref Model model, ref Expr proof, params Expr[] assumptions) { Z3_lbool r; - core = null; + model = null; + proof = null; if (assumptions == null || assumptions.Length == 0) r = (Z3_lbool)Native.Z3_check(ctx.nCtx); else { - IntPtr model = IntPtr.Zero, proof = IntPtr.Zero; + IntPtr mdl = IntPtr.Zero, prf = IntPtr.Zero; uint core_size = 0; IntPtr[] native_core = new IntPtr[assumptions.Length]; r = (Z3_lbool)Native.Z3_check_assumptions(ctx.nCtx, (uint)assumptions.Length, AST.ArrayToNative(assumptions), - ref model, ref proof, ref core_size, native_core); + ref mdl, ref prf, ref core_size, native_core); for (uint i = 0; i < core_size; i++) core.Add((BoolExpr)Expr.Create(ctx, native_core[i])); + if (mdl != IntPtr.Zero) { + model = new Model(ctx, mdl); + } + if (prf != IntPtr.Zero) { + proof = Expr.Create(ctx, prf); + } } switch (r) diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 1ea185530..16aaaf9b1 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -1148,18 +1148,21 @@ namespace datalog { utbv& neg = d->neg(); unsigned mid = dm1.num_tbits(); unsigned hi = dm.num_tbits(); - tbm.set(pos,d1.pos(), mid-1, 0); - tbm.set(pos,d2.pos(), hi-1, mid); + tbm.set(pos, d1.pos(), mid-1, 0); + tbm.set(pos, d2.pos(), hi-1, mid); for (unsigned i = 0; i < d1.neg().size(); ++i) { t = tbm.allocateX(); tbm.set(*t, d1.neg()[i], mid-1, 0); + VERIFY(tbm.set_and(*t, pos)); neg.push_back(t.detach()); } for (unsigned i = 0; i < d2.neg().size(); ++i) { t = tbm.allocateX(); tbm.set(*t, d2.neg()[i], hi-1, mid); + VERIFY(tbm.set_and(*t, pos)); neg.push_back(t.detach()); } + SASSERT(dm.well_formed(*d)); return d.detach(); } From 0cf04589ff82c021bf43872381d1282caf8034f7 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 8 Oct 2014 09:58:02 +0100 Subject: [PATCH 632/925] DoC: enable filter_project Signed-off-by: Nuno Lopes --- src/muz/rel/udoc_relation.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 16aaaf9b1..5df2fed80 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -1056,7 +1056,7 @@ namespace datalog { return check_kind(t)?alloc(filter_interpreted_fn, get(t), get_ast_manager(), condition):0; } - class udoc_plugin::join_project_fn : convenient_relation_join_project_fn { + class udoc_plugin::join_project_fn : public convenient_relation_join_project_fn { udoc_plugin::join_fn m_joiner; union_find_default_ctx union_ctx; bit_vector m_to_delete; @@ -1172,15 +1172,11 @@ namespace datalog { relation_base const& t1, relation_base const& t2, unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, const unsigned * removed_cols) { - if (check_kind(t1) && check_kind(t2)) - return 0; -#if 0 - return alloc(join_project_fn, get(t1), ge(t2), - joined_col_cnt, cols1, cols2, - removed_col_cnt, removed_cols); -#endif - else + if (!check_kind(t1) || !check_kind(t2)) return 0; + return alloc(join_project_fn, get(t1), get(t2), + joined_col_cnt, cols1, cols2, + removed_col_cnt, removed_cols); } From 985ad30349b1770ae33cadd840372bfdf0e3d89a Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 8 Oct 2014 10:06:39 +0100 Subject: [PATCH 633/925] DoC: reuse code in unit tests from relation checker Signed-off-by: Nuno Lopes --- src/test/udoc_relation.cpp | 85 +------------------------------------- 1 file changed, 2 insertions(+), 83 deletions(-) diff --git a/src/test/udoc_relation.cpp b/src/test/udoc_relation.cpp index 24ccb34b0..834ce1bba 100644 --- a/src/test/udoc_relation.cpp +++ b/src/test/udoc_relation.cpp @@ -476,52 +476,13 @@ public: scoped_ptr rename; rename = p.mk_rename_fn(*t1, cycle.size(), cycle.c_ptr()); relation_base* t = (*rename)(*t1); - verify_permutation(*t1,*t, cycle); + cr.verify_permutation(*t1,*t, cycle); t1->display(std::cout); std::cout << "\n"; t->display(std::cout); std::cout << "\n"; t->deallocate(); t1->deallocate(); } - void verify_permutation(relation_base const& src, relation_base const& dst, - unsigned_vector const& cycle) { - unsigned_vector perm; - relation_signature const& sig1 = src.get_signature(); - relation_signature const& sig2 = dst.get_signature(); - for (unsigned i = 0; i < sig1.size(); ++i) { - perm.push_back(i); - } - for (unsigned i = 0; i < cycle.size(); ++i) { - unsigned j = (i + 1)%cycle.size(); - unsigned col1 = cycle[i]; - unsigned col2 = cycle[j]; - perm[col2] = col1; - } - for (unsigned i = 0; i < perm.size(); ++i) { - SASSERT(sig2[perm[i]] == sig1[i]); - } - expr_ref_vector sub(m); - for (unsigned i = 0; i < perm.size(); ++i) { - sub.push_back(m.mk_var(perm[i], sig1[i])); - } - var_subst subst(m, false); - expr_ref fml1(m), fml2(m); - src.to_formula(fml1); - dst.to_formula(fml2); - subst(fml1, sub.size(), sub.c_ptr(), fml1); - expr_ref_vector vars(m); - for (unsigned i = 0; i < sig2.size(); ++i) { - std::stringstream strm; - strm << "x" << i; - vars.push_back(m.mk_const(symbol(strm.str().c_str()), sig2[i])); - } - - subst(fml1, vars.size(), vars.c_ptr(), fml1); - subst(fml2, vars.size(), vars.c_ptr(), fml2); - - check_equiv(fml1, fml2); - } - /* The filter_by_negation postcondition: filter_by_negation(tgt, neg, columns in tgt: c1,...,cN, @@ -733,51 +694,9 @@ public: void apply_filter_project(udoc_relation& t, unsigned_vector const& rm, app* cond) { scoped_ptr rt; rt = p.mk_filter_interpreted_and_project_fn(t, cond, rm.size(), rm.c_ptr()); - udoc_relation* full = mk_full(t.get_signature()); - rel_union union_fn = p.mk_union_fn(t, *full, 0); - (*union_fn)(t, *full, 0); datalog::relation_base* result = (*rt)(t); - - for (unsigned i = 0; i < rm.size(); ++i) { - std::cout << rm[i] << " "; - } - std::cout << mk_pp(cond, m) << "\n"; - t.display(std::cout); - result->display(std::cout); + cr.verify_filter_project(t, *result, cond, rm); result->deallocate(); - full->deallocate(); - } - - void verify_filter_project(udoc_relation const& r, unsigned_vector const& rm, app* cond) { - expr_ref fml(m), cfml(m); - r.to_formula(fml); - cfml = cond; - relation_signature const& sig = r.get_signature(); - expr_ref_vector vars(m); - for (unsigned i = 0, j = 0, k = 0; i < sig.size(); ++i) { - if (j < rm.size() && rm[j] == i) { - project_var(i, sig[i], cfml); - ++j; - } - else { - vars.push_back(m.mk_var(k, sig[i])); - ++k; - } - } - - check_equiv(fml, cfml); - } - - void check_equiv(expr* fml1, expr* fml2) { - TRACE("doc", tout << mk_pp(fml1, m) << "\n"; - tout << mk_pp(fml2, m) << "\n";); - smt_params fp; - smt::kernel solver(m, fp); - expr_ref tmp(m); - tmp = m.mk_not(m.mk_eq(fml1, fml2)); - solver.assert_expr(tmp); - lbool res = solver.check(); - SASSERT(res == l_false); } void project_var(unsigned i, sort* s, expr_ref& fml) { From de73a4d8939a8e6c2c6118b21bf7afac473cf4ba Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 8 Oct 2014 11:12:41 +0100 Subject: [PATCH 634/925] DoC: fix bug in filter_project with '(not (= c1 c2))' style constraints Signed-off-by: Nuno Lopes --- src/muz/rel/udoc_relation.cpp | 13 +++++++++---- src/test/udoc_relation.cpp | 18 +++++++++++++++++- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 5df2fed80..6143f4085 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -938,12 +938,17 @@ namespace datalog { else if (m.is_not(g, e1)) { udoc sub; sub.push_back(dm.allocateX()); - apply_guard(e1, sub, equalities, discard_cols); - TRACE("doc", - result.display(dm, tout << "result0:") << "\n"; - sub.display(dm, tout << "sub:") << "\n";); + // TODO: right now we state that no columns are discarded to avoid + // silent column merging. This can be optimized if the set of merged + // columns is returned so that here we remove different columns. + bit_vector empty; + empty.resize(discard_cols.size(), false); + apply_guard(e1, sub, equalities, empty); result.subtract(dm, sub); result.simplify(dm); + TRACE("doc", + result.display(dm, tout << "result0:") << "\n"; + sub.display(dm, tout << "sub:") << "\n";); sub.reset(dm); TRACE("doc", result.display(dm, tout << "result:") << "\n";); } diff --git a/src/test/udoc_relation.cpp b/src/test/udoc_relation.cpp index 834ce1bba..d7f83f0aa 100644 --- a/src/test/udoc_relation.cpp +++ b/src/test/udoc_relation.cpp @@ -376,15 +376,31 @@ public: unsigned_vector remove; remove.push_back(0); remove.push_back(2); + t1 = mk_full(sig2); + apply_filter(*t1, conds[2].get()); + apply_filter_project(*t1, remove, conds[2].get()); + apply_filter_project(*t1, remove, conds[3].get()); + t1->deallocate(); + + t1 = mk_full(sig2); + apply_filter(*t1, conds[3].get()); + apply_filter_project(*t1, remove, conds[2].get()); + apply_filter_project(*t1, remove, conds[3].get()); + t1->deallocate(); + for (unsigned i = 0; i < conds.size(); ++i) { + t1 = mk_full(sig2); apply_filter_project(*t1, remove, conds[i].get()); + t1->deallocate(); } + remove[1] = 1; for (unsigned i = 0; i < conds.size(); ++i) { + t1 = mk_full(sig2); apply_filter_project(*t1, remove, conds[i].get()); + t1->deallocate(); } - t1->deallocate(); } From 00555def4d00073a76a05444c3966c7882f18bfd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 8 Oct 2014 11:05:38 -0700 Subject: [PATCH 635/925] improve error handling of parameters and remove work notes from udoc_relation Signed-off-by: Nikolaj Bjorner --- src/muz/rel/udoc_relation.cpp | 34 ---------------------------------- src/tactic/tactical.cpp | 3 +++ src/util/params.cpp | 17 +++++++++++++---- 3 files changed, 16 insertions(+), 38 deletions(-) diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 1ea185530..3e01a8ba6 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -20,40 +20,6 @@ Revision History: Notes: - Current pending items: - - Profile and fix bottlnecks: - - Potential bottleneck in projection exercised in some benchmarks. - Projection is asymptotically very expensive. We are here interested in - handling common/cheap cases efficiently. - - Simplification of udoc and utbv (from negated tails) after operations such as join and union. - - The current simplification is between cheap and expensive. Some low-cost simplification - based on sorting + coallescing and detecting empty docs could be used. - - There are several places where code copies a sequence of bits from one vector to another. - Any such places in udoc_relation should be shifted down to 'doc_manager'. Loops in 'doc_manager' - should be shifted down to 'tbv_manager' and loops there should be moved to 'fixed_bitvector_manager'. - Finally, more efficient and general implementations of non-aligned copies are useful where such - bottlnecks show up on the radar. - - Fix filter_by_negated. - Current implementation seems incorrect. The fast path seems right, but the slow path does not. - Recall the semantics: - filter_by_negation(tgt, neg, columns in tgt: c1,...,cN, - corresponding columns in neg: d1,...,dN): - tgt := {x: x\in tgt_0 && ! \exists y: ( y \in neg & pi_c1(x)= pi_d1(y) & ... & pi_cN(x)= pi_dN(y) ) } - We are given tgt, and neg as two udocs. - The fast pass removes doc's t from tgt where we can establish - that for every x in t there is a n in neg and a y in n, - such that projections(x) = projections(y). - This is claimed to be the case if projections(n) contains projections(t). - - The slow pass uses the projection to create a doc n' from each n that has the same signature as tgt. - It then subtracts each n'. The way n' is created is by copying bits from n. - This seems wrong, for example if the projection contains overlapping regions. - Here is a possible corrected version: - define join_project(tgt, neg, c1, .., cN, d1, .. , dN) as - exists y : y \in neg & x in tgt & pi_c1(x)= pi_d1(y) & ... & pi_cN(x)= pi_dN(y) ) - return tgt \ join_project(tgt, neg, c1, .., cN, d1, .. , dN) - We have most of the facilities required for a join project operation. - For example, the filter_project function uses both equalities and deleted columns. --*/ #include "udoc_relation.h" #include "dl_relation_manager.h" diff --git a/src/tactic/tactical.cpp b/src/tactic/tactical.cpp index cfb4ec194..87974ea60 100644 --- a/src/tactic/tactical.cpp +++ b/src/tactic/tactical.cpp @@ -1229,6 +1229,9 @@ class using_params_tactical : public unary_tactical { params_ref m_params; public: using_params_tactical(tactic * t, params_ref const & p):unary_tactical(t), m_params(p) { + param_descrs r; + collect_param_descrs(r); + p.validate(r); t->updt_params(p); } diff --git a/src/util/params.cpp b/src/util/params.cpp index 7d517fb10..130b18cc9 100644 --- a/src/util/params.cpp +++ b/src/util/params.cpp @@ -302,10 +302,19 @@ public: svector::const_iterator end = m_entries.end(); for (; it != end; ++it) { param_kind expected = p.get_kind(it->first); - if (expected == CPK_INVALID) - throw default_exception("unknown parameter '%s'", it->first.str().c_str()); - if (it->second.m_kind != expected) - throw default_exception("parameter kind mismatch '%s'", it->first.str().c_str()); + if (expected == CPK_INVALID) { + std::stringstream strm; + strm << "unknown parameter '" << it->first.str() << "'\n"; + strm << "Legal parameters are:\n"; + p.display(strm, 2, false, false); + throw default_exception(strm.str()); + } + if (it->second.m_kind != expected) { + std::stringstream strm; + strm << "Parameter " << it->first.str() << " was given argument of type "; + strm << it->second.m_kind << ", expected " << expected; + throw default_exception(strm.str()); + } } } From adb9117a9eeb08d1c16a62de85c51e1a222909be Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 8 Oct 2014 13:32:25 -0700 Subject: [PATCH 636/925] move parameter checking to API Signed-off-by: Nikolaj Bjorner --- src/api/api_tactic.cpp | 3 +++ src/api/python/z3.py | 2 +- src/tactic/smtlogics/nra_tactic.cpp | 4 ++-- src/tactic/smtlogics/qfnra_tactic.cpp | 4 ++-- src/tactic/tactical.cpp | 3 --- src/util/params.cpp | 3 ++- 6 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/api/api_tactic.cpp b/src/api/api_tactic.cpp index 911360047..7dce33971 100644 --- a/src/api/api_tactic.cpp +++ b/src/api/api_tactic.cpp @@ -222,6 +222,9 @@ extern "C" { Z3_TRY; LOG_Z3_tactic_using_params(c, t, p); RESET_ERROR_CODE(); + param_descrs r; + to_tactic_ref(t)->collect_param_descrs(r); + to_param_ref(p).validate(r); tactic * new_t = using_params(to_tactic_ref(t), to_param_ref(p)); RETURN_TACTIC(new_t); Z3_CATCH_RETURN(0); diff --git a/src/api/python/z3.py b/src/api/python/z3.py index afd61dba1..5a1a6c36d 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -4467,7 +4467,7 @@ def args2params(arguments, keywords, ctx=None): A ':' is added to the keywords, and '_' is replaced with '-' >>> args2params(['model', True, 'relevancy', 2], {'elim_and' : True}) - (params model 1 relevancy 2 elim_and 1) + (params model true relevancy 2 elim_and true) """ if __debug__: _z3_assert(len(arguments) % 2 == 0, "Argument list must have an even number of elements.") diff --git a/src/tactic/smtlogics/nra_tactic.cpp b/src/tactic/smtlogics/nra_tactic.cpp index 845b6bfec..619664a74 100644 --- a/src/tactic/smtlogics/nra_tactic.cpp +++ b/src/tactic/smtlogics/nra_tactic.cpp @@ -27,10 +27,10 @@ Notes: tactic * mk_nra_tactic(ast_manager & m, params_ref const& p) { params_ref p1 = p; - p1.set_uint("seed", 11); + p1.set_uint("random_seed", 11); p1.set_bool("factor", false); params_ref p2 = p; - p2.set_uint("seed", 13); + p2.set_uint("random_seed", 13); p2.set_bool("factor", false); return and_then(mk_simplify_tactic(m, p), diff --git a/src/tactic/smtlogics/qfnra_tactic.cpp b/src/tactic/smtlogics/qfnra_tactic.cpp index 716b4868b..c2053fcd3 100644 --- a/src/tactic/smtlogics/qfnra_tactic.cpp +++ b/src/tactic/smtlogics/qfnra_tactic.cpp @@ -34,10 +34,10 @@ static tactic * mk_qfnra_sat_solver(ast_manager& m, params_ref const& p, unsigne tactic * mk_qfnra_tactic(ast_manager & m, params_ref const& p) { params_ref p1 = p; - p1.set_uint("seed", 11); + p1.set_uint("random_seed", 11); p1.set_bool("factor", false); params_ref p2 = p; - p2.set_uint("seed", 13); + p2.set_uint("random_seed", 13); p2.set_bool("factor", false); return and_then(mk_simplify_tactic(m, p), diff --git a/src/tactic/tactical.cpp b/src/tactic/tactical.cpp index 87974ea60..cfb4ec194 100644 --- a/src/tactic/tactical.cpp +++ b/src/tactic/tactical.cpp @@ -1229,9 +1229,6 @@ class using_params_tactical : public unary_tactical { params_ref m_params; public: using_params_tactical(tactic * t, params_ref const & p):unary_tactical(t), m_params(p) { - param_descrs r; - collect_param_descrs(r); - p.validate(r); t->updt_params(p); } diff --git a/src/util/params.cpp b/src/util/params.cpp index 130b18cc9..a2609f840 100644 --- a/src/util/params.cpp +++ b/src/util/params.cpp @@ -309,7 +309,8 @@ public: p.display(strm, 2, false, false); throw default_exception(strm.str()); } - if (it->second.m_kind != expected) { + if (it->second.m_kind != expected && + !(it->second.m_kind == CPK_UINT && expected == CPK_NUMERAL)) { std::stringstream strm; strm << "Parameter " << it->first.str() << " was given argument of type "; strm << it->second.m_kind << ", expected " << expected; From 7b944118ddd9bc2e3baaa08cc22b9ca27245baf9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 8 Oct 2014 13:36:35 -0700 Subject: [PATCH 637/925] revert to 'seed' Signed-off-by: Nikolaj Bjorner --- src/tactic/smtlogics/nra_tactic.cpp | 4 ++-- src/tactic/smtlogics/qfnra_tactic.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tactic/smtlogics/nra_tactic.cpp b/src/tactic/smtlogics/nra_tactic.cpp index 619664a74..845b6bfec 100644 --- a/src/tactic/smtlogics/nra_tactic.cpp +++ b/src/tactic/smtlogics/nra_tactic.cpp @@ -27,10 +27,10 @@ Notes: tactic * mk_nra_tactic(ast_manager & m, params_ref const& p) { params_ref p1 = p; - p1.set_uint("random_seed", 11); + p1.set_uint("seed", 11); p1.set_bool("factor", false); params_ref p2 = p; - p2.set_uint("random_seed", 13); + p2.set_uint("seed", 13); p2.set_bool("factor", false); return and_then(mk_simplify_tactic(m, p), diff --git a/src/tactic/smtlogics/qfnra_tactic.cpp b/src/tactic/smtlogics/qfnra_tactic.cpp index c2053fcd3..716b4868b 100644 --- a/src/tactic/smtlogics/qfnra_tactic.cpp +++ b/src/tactic/smtlogics/qfnra_tactic.cpp @@ -34,10 +34,10 @@ static tactic * mk_qfnra_sat_solver(ast_manager& m, params_ref const& p, unsigne tactic * mk_qfnra_tactic(ast_manager & m, params_ref const& p) { params_ref p1 = p; - p1.set_uint("random_seed", 11); + p1.set_uint("seed", 11); p1.set_bool("factor", false); params_ref p2 = p; - p2.set_uint("random_seed", 13); + p2.set_uint("seed", 13); p2.set_bool("factor", false); return and_then(mk_simplify_tactic(m, p), From 2362e01a9f05fd0eac4cc95653d8a374c65dabc1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 8 Oct 2014 17:17:14 -0700 Subject: [PATCH 638/925] add unit test for join-project Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 2 +- src/muz/rel/udoc_relation.cpp | 4 +++ src/test/udoc_relation.cpp | 33 ++++++++++++++++++ src/util/params.cpp | 66 +++++++++++++++++++++++++++-------- src/util/params.h | 7 ++-- 5 files changed, 94 insertions(+), 18 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 411fdd1e1..4641a7b1b 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1801,7 +1801,7 @@ def def_module_params(module_name, export, params, class_name=None, description= out.write(' {}\n') out.write(' static void collect_param_descrs(param_descrs & d) {\n') for param in params: - out.write(' d.insert("%s", %s, "%s", "%s");\n' % (param[0], TYPE2CPK[param[1]], param[3], pyg_default(param))) + out.write(' d.insert("%s", %s, "%s", "%s","%s");\n' % (param[0], TYPE2CPK[param[1]], param[3], pyg_default(param), module_name)) out.write(' }\n') if export: out.write(' /*\n') diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 07ca511a6..7f0a61da9 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -1071,6 +1071,9 @@ namespace datalog { // TBD: replace this by "join" given below. virtual relation_base* operator()(relation_base const& t1, relation_base const& t2) { +#if 0 + return join(get(t1), get(t2)); +#else udoc_relation *joined = get(m_joiner(t1, t2)); relation_base* result = 0; if (joined->fast_empty()) { @@ -1082,6 +1085,7 @@ namespace datalog { } joined->deallocate(); return result; +#endif } private: diff --git a/src/test/udoc_relation.cpp b/src/test/udoc_relation.cpp index d7f83f0aa..af80a6d5c 100644 --- a/src/test/udoc_relation.cpp +++ b/src/test/udoc_relation.cpp @@ -144,6 +144,8 @@ public: udoc_relation* t1, *t2, *t3; expr_ref fml(m); + test_join_project(); + test_filter_neg4(false); test_filter_neg4(true); test_filter_neg5(false); @@ -406,6 +408,37 @@ public: } + void test_join_project() + { + datalog::relation_signature sig; + sig.push_back(bv.mk_sort(3)); + sig.push_back(bv.mk_sort(3)); + sig.push_back(bv.mk_sort(3)); + + unsigned_vector jc1, jc2, pc; + jc1.push_back(0); + jc2.push_back(0); + pc.push_back(1); + pc.push_back(3); + pc.push_back(4); + udoc_relation* t1, *t2; + relation_base* t; + + scoped_ptr join_project_fn; + + for (unsigned i = 0; i < 20; ++i) { + t1 = mk_rand(sig); + t2 = mk_rand(sig); + join_project_fn = p.mk_join_project_fn(*t1, *t2, jc1.size(), jc1.c_ptr(), jc2.c_ptr(), pc.size(), pc.c_ptr()); + t = (*join_project_fn)(*t1, *t2); + t->display(std::cout); + cr.verify_join_project(*t1, *t2, *t, jc1, jc2, pc); + t->deallocate(); + t1->deallocate(); + t2->deallocate(); + } + } + void test_rename() { udoc_relation* t1; // rename diff --git a/src/util/params.cpp b/src/util/params.cpp index a2609f840..cbb2b2acc 100644 --- a/src/util/params.cpp +++ b/src/util/params.cpp @@ -51,31 +51,34 @@ struct param_descrs::imp { param_kind m_kind; char const * m_descr; char const * m_default; + char const * m_module; - info(param_kind k, char const * descr, char const * def): + info(param_kind k, char const * descr, char const * def, char const* module): m_kind(k), m_descr(descr), - m_default(def) { + m_default(def), + m_module(module) { } info(): m_kind(CPK_INVALID), m_descr(0), - m_default(0) { + m_default(0), + m_module(0) { } }; dictionary m_info; svector m_names; - void insert(symbol const & name, param_kind k, char const * descr, char const * def) { + void insert(symbol const & name, param_kind k, char const * descr, char const * def, char const* module) { SASSERT(!name.is_numerical()); info i; if (m_info.find(name, i)) { SASSERT(i.m_kind == k); return; } - m_info.insert(name, info(k, descr, def)); + m_info.insert(name, info(k, descr, def, module)); m_names.push_back(name); } @@ -94,6 +97,13 @@ struct param_descrs::imp { return CPK_INVALID; } + char const* get_module(symbol const& name) const { + info i; + if (m_info.find(name, i)) + return i.m_module; + return 0; + } + char const * get_descr(symbol const & name) const { info i; if (m_info.find(name, i)) @@ -162,7 +172,7 @@ struct param_descrs::imp { dictionary::iterator it = other.m_imp->m_info.begin(); dictionary::iterator end = other.m_imp->m_info.end(); for (; it != end; ++it) { - insert(it->m_key, it->m_value.m_kind, it->m_value.m_descr, it->m_value.m_default); + insert(it->m_key, it->m_value.m_kind, it->m_value.m_descr, it->m_value.m_default, it->m_value.m_module); } } @@ -180,12 +190,12 @@ void param_descrs::copy(param_descrs & other) { m_imp->copy(other); } -void param_descrs::insert(symbol const & name, param_kind k, char const * descr, char const * def) { - m_imp->insert(name, k, descr, def); +void param_descrs::insert(symbol const & name, param_kind k, char const * descr, char const * def, char const* module) { + m_imp->insert(name, k, descr, def, module); } -void param_descrs::insert(char const * name, param_kind k, char const * descr, char const * def) { - insert(symbol(name), k, descr, def); +void param_descrs::insert(char const * name, param_kind k, char const * descr, char const * def, char const* module) { + insert(symbol(name), k, descr, def, module); } bool param_descrs::contains(char const * name) const { @@ -236,6 +246,10 @@ symbol param_descrs::get_param_name(unsigned i) const { return m_imp->get_param_name(i); } +char const* param_descrs::get_module(symbol const& name) const { + return m_imp->get_module(name); +} + void param_descrs::display(std::ostream & out, unsigned indent, bool smt2_style, bool include_descr) const { return m_imp->display(out, indent, smt2_style, include_descr); } @@ -297,11 +311,35 @@ public: void reset(symbol const & k); void reset(char const * k); - void validate(param_descrs const & p) const { - svector::const_iterator it = m_entries.begin(); - svector::const_iterator end = m_entries.end(); + bool split_name(symbol const& name, symbol & prefix, symbol & suffix) { + if (name.is_numerical()) return false; + char const* str = name.bare_str(); + char const* period = strchr(str,'.'); + if (!period) return false; + svector prefix_((unsigned)(period-str), str); + prefix_.push_back(0); + prefix = symbol(prefix_.c_ptr()); + suffix = symbol(period + 1); + return true; + } + + void validate(param_descrs const & p) { + svector::iterator it = m_entries.begin(); + svector::iterator end = m_entries.end(); + symbol suffix, prefix; for (; it != end; ++it) { param_kind expected = p.get_kind(it->first); + if (expected == CPK_INVALID && split_name(it->first, prefix, suffix)) { + expected = p.get_kind(suffix); + if (expected != CPK_INVALID) { + if (symbol(p.get_module(suffix)) == prefix) { + it->first = suffix; + } + else { + expected = CPK_INVALID; + } + } + } if (expected == CPK_INVALID) { std::stringstream strm; strm << "unknown parameter '" << it->first.str() << "'\n"; @@ -490,7 +528,7 @@ void params_ref::display(std::ostream & out, symbol const & k) const { out << "default"; } -void params_ref::validate(param_descrs const & p) const { +void params_ref::validate(param_descrs const & p) { if (m_params) m_params->validate(p); } diff --git a/src/util/params.h b/src/util/params.h index 06be486bb..f11374775 100644 --- a/src/util/params.h +++ b/src/util/params.h @@ -92,7 +92,7 @@ public: void display(std::ostream & out) const; void display_smt2(std::ostream& out, char const* module, param_descrs& module_desc) const; - void validate(param_descrs const & p) const; + void validate(param_descrs const & p); /* \brief Display the value of the given parameter. @@ -115,8 +115,8 @@ public: param_descrs(); ~param_descrs(); void copy(param_descrs & other); - void insert(char const * name, param_kind k, char const * descr, char const * def = 0); - void insert(symbol const & name, param_kind k, char const * descr, char const * def = 0); + void insert(char const * name, param_kind k, char const * descr, char const * def = 0, char const* module = 0); + void insert(symbol const & name, param_kind k, char const * descr, char const * def = 0, char const* module = 0); bool contains(char const * name) const; bool contains(symbol const & name) const; void erase(char const * name); @@ -130,6 +130,7 @@ public: void display(std::ostream & out, unsigned indent = 0, bool smt2_style=false, bool include_descr=true) const; unsigned size() const; symbol get_param_name(unsigned idx) const; + char const * get_module(symbol const& name) const; }; void insert_max_memory(param_descrs & r); From d038c7bf89a31062d7099b3256c1c9ee84666454 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 8 Oct 2014 22:07:19 -0700 Subject: [PATCH 639/925] fixing udoc/adding tuned join_project Signed-off-by: Nikolaj Bjorner --- src/muz/rel/doc.cpp | 18 ++++++++++----- src/muz/rel/doc.h | 2 +- src/muz/rel/tbv.cpp | 3 ++- src/muz/rel/tbv.h | 2 +- src/muz/rel/udoc_relation.cpp | 31 +++++++++++++++++--------- src/test/doc.cpp | 8 +++---- src/test/tbv.cpp | 2 +- src/test/udoc_relation.cpp | 42 ++++++++++++++++++++++++++--------- 8 files changed, 74 insertions(+), 34 deletions(-) diff --git a/src/muz/rel/doc.cpp b/src/muz/rel/doc.cpp index adc7e959a..e87143482 100644 --- a/src/muz/rel/doc.cpp +++ b/src/muz/rel/doc.cpp @@ -187,7 +187,14 @@ unsigned doc_manager::diff_by_012(tbv const& pos, tbv const& neg, unsigned& inde void doc_manager::set(doc& d, unsigned idx, tbit value) { m.set(d.pos(), idx, value); for (unsigned i = 0; i < d.neg().size(); ++i) { - m.set(d.neg()[i], idx, value); + tbit b = d.neg()[i][idx]; + if (b != BIT_x && value != BIT_x && value != b) { + d.neg().erase(tbvm(), i); + --i; + } + else { + m.set(d.neg()[i], idx, value); + } } } @@ -234,6 +241,7 @@ bool doc_manager::merge(doc& d, unsigned idx, subset_ints const& equalities, } while (idx != root); + TRACE("doc", tout << "num_x: " << num_x << " value: " << value << "\n";); if (num_x == 0) { // nothing to do. } @@ -248,7 +256,7 @@ bool doc_manager::merge(doc& d, unsigned idx, subset_ints const& equalities, } else { do { - if (!discard_cols.get(idx) && idx != root1) { + if (/*!discard_cols.get(idx) &&*/ idx != root1) { tbv* t = m.allocate(d.pos()); m.set(*t, idx, BIT_0); m.set(*t, root1, BIT_1); @@ -281,10 +289,10 @@ bool doc_manager::intersect(doc const& A, doc const& B, doc& result) { // indices where BIT_0 is set are positive. // -doc* doc_manager::project(doc_manager& dstm, unsigned n, bit_vector const& to_delete, doc const& src) { +doc* doc_manager::project(doc_manager& dstm, bit_vector const& to_delete, doc const& src) { tbv_manager& dstt = dstm.m; tbv_ref t(dstt); - t = dstt.project(n, to_delete, src.pos()); + t = dstt.project(to_delete, src.pos()); doc* r = dstm.allocate(t.detach()); SASSERT(r); @@ -368,7 +376,7 @@ doc* doc_manager::project(doc_manager& dstm, unsigned n, bit_vector const& to_de } case project_done: { for (unsigned i = 0; i < todo.size(); ++i) { - t = dstt.project(n, to_delete, *todo[i]); + t = dstt.project(to_delete, *todo[i]); if (dstt.equals(r->pos(), *t)) { r->neg().reset(dstt); r->neg().push_back(t.detach()); diff --git a/src/muz/rel/doc.h b/src/muz/rel/doc.h index 2a4b3ead7..f78ce94ff 100644 --- a/src/muz/rel/doc.h +++ b/src/muz/rel/doc.h @@ -87,7 +87,7 @@ public: std::ostream& display(std::ostream& out, doc const& b) const; std::ostream& display(std::ostream& out, doc const& b, unsigned hi, unsigned lo) const; unsigned num_tbits() const { return m.num_tbits(); } - doc* project(doc_manager& dstm, unsigned n, bit_vector const& to_delete, doc const& src); + doc* project(doc_manager& dstm, bit_vector const& to_delete, doc const& src); bool well_formed(doc const& d) const; bool merge(doc& d, unsigned lo, unsigned length, subset_ints const& equalities, bit_vector const& discard_cols); void set(doc& d, unsigned idx, tbit value); diff --git a/src/muz/rel/tbv.cpp b/src/muz/rel/tbv.cpp index 9c71b826c..fc3c32390 100644 --- a/src/muz/rel/tbv.cpp +++ b/src/muz/rel/tbv.cpp @@ -99,9 +99,10 @@ tbv* tbv_manager::allocate(tbv const& bv, unsigned const* permutation) { } return r; } -tbv* tbv_manager::project(unsigned n, bit_vector const& to_delete, tbv const& src) { +tbv* tbv_manager::project(bit_vector const& to_delete, tbv const& src) { tbv* r = allocate(); unsigned i, j; + unsigned n = to_delete.size(); for (i = 0, j = 0; i < n; ++i) { if (!to_delete.get(i)) { set(*r, j, src[i]); diff --git a/src/muz/rel/tbv.h b/src/muz/rel/tbv.h index 941853a1b..d667ccaa2 100644 --- a/src/muz/rel/tbv.h +++ b/src/muz/rel/tbv.h @@ -75,7 +75,7 @@ public: bool intersect(tbv const& a, tbv const& b, tbv& result); std::ostream& display(std::ostream& out, tbv const& b) const; std::ostream& display(std::ostream& out, tbv const& b, unsigned hi, unsigned lo) const; - tbv* project(unsigned n, bit_vector const& to_delete, tbv const& src); + tbv* project(bit_vector const& to_delete, tbv const& src); bool is_well_formed(tbv const& b) const; // - does not contain BIT_z; void set(tbv& dst, uint64 n, unsigned hi, unsigned lo); void set(tbv& dst, rational const& r, unsigned hi, unsigned lo); diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 7f0a61da9..b3abf7998 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -460,7 +460,7 @@ namespace datalog { udoc const& ud1 = t.get_udoc(); udoc& ud2 = r->get_udoc(); for (unsigned i = 0; i < ud1.size(); ++i) { - d2 = dm1.project(dm2, m_to_delete.size(), m_to_delete, ud1[i]); + d2 = dm1.project(dm2, m_to_delete, ud1[i]); ud2.push_back(d2.detach()); } TRACE("doc", tout << "final size: " << r->get_size_estimate_rows() << '\n';); @@ -1071,7 +1071,7 @@ namespace datalog { // TBD: replace this by "join" given below. virtual relation_base* operator()(relation_base const& t1, relation_base const& t2) { -#if 0 +#if 1 return join(get(t1), get(t2)); #else udoc_relation *joined = get(m_joiner(t1, t2)); @@ -1097,6 +1097,7 @@ namespace datalog { udoc const& d1 = t1.get_udoc(); udoc const& d2 = t2.get_udoc(); doc_manager& dm1 = t1.get_dm(); + doc_manager& dm2 = t2.get_dm(); udoc_plugin& p = t1.get_plugin(); doc_manager& dm_prod = p.dm(prod_signature); udoc_relation* result = get(p.mk_empty(get_result_signature())); @@ -1104,17 +1105,21 @@ namespace datalog { doc_manager& dm_res = result->get_dm(); for (unsigned i = 0; i < d1.size(); ++i) { for (unsigned j = 0; j < d2.size(); ++j) { - prod.push_back(xprod(dm_prod, dm1, d1[i], d2[j])); + prod.push_back(xprod(dm_prod, dm1, dm2, d1[i], d2[j])); } } + TRACE("doc", prod.display(dm_prod, tout) << "\n";); prod.merge(dm_prod, m_roots, m_equalities, m_to_delete); + TRACE("doc", prod.display(dm_prod, tout) << "\n";); for (unsigned i = 0; i < prod.size(); ++i) { - res.insert(dm_res, dm_prod.project(dm_res, m_to_delete.size(), m_to_delete, prod[i])); + res.insert(dm_res, dm_prod.project(dm_res, m_to_delete, prod[i])); } + TRACE("doc", result->display(tout);); prod.reset(dm_prod); return result; } - doc* xprod(doc_manager& dm, doc_manager& dm1, doc const& d1, doc const& d2) { + doc* xprod(doc_manager& dm, doc_manager& dm1, doc_manager& dm2, + doc const& d1, doc const& d2) { tbv_manager& tbm = dm.tbvm(); doc_ref d(dm); tbv_ref t(tbm); @@ -1138,6 +1143,10 @@ namespace datalog { neg.push_back(t.detach()); } SASSERT(dm.well_formed(*d)); + TRACE("doc", + dm1.display(tout, d1) << "\n"; + dm2.display(tout, d2) << "\n"; + dm.display(tout, *d) << "\n";); return d.detach(); } @@ -1181,24 +1190,24 @@ namespace datalog { bool m_is_subtract; bool m_is_aliased; public: - negation_filter_fn(const udoc_relation & r, const udoc_relation & neg, unsigned joined_col_cnt, + negation_filter_fn(const udoc_relation & t, const udoc_relation & neg, unsigned joined_col_cnt, const unsigned *t_cols, const unsigned *neg_cols) : m_t_cols(joined_col_cnt, t_cols), m_neg_cols(joined_col_cnt, neg_cols), - m_mk_remove_cols(r, neg, m_remove_cols), - m_join_project(r, neg, joined_col_cnt, t_cols, neg_cols, + m_mk_remove_cols(t, neg, m_remove_cols), + m_join_project(t, neg, joined_col_cnt, t_cols, neg_cols, m_remove_cols.size(), m_remove_cols.c_ptr()), m_is_subtract(false), m_is_aliased(true) { SASSERT(joined_col_cnt > 0); - m_is_subtract = (joined_col_cnt == r.get_signature().size()); + m_is_subtract = (joined_col_cnt == t.get_signature().size()); m_is_subtract &= (joined_col_cnt == neg.get_signature().size()); svector found(joined_col_cnt, false); for (unsigned i = 0; m_is_subtract && i < joined_col_cnt; ++i) { m_is_subtract = !found[t_cols[i]] && (t_cols[i] == neg_cols[i]); found[t_cols[i]] = true; } - r.expand_column_vector(m_t_cols); + t.expand_column_vector(m_t_cols); neg.expand_column_vector(m_neg_cols); } @@ -1316,7 +1325,7 @@ namespace datalog { udoc_relation* r = get(t.get_plugin().mk_empty(get_result_signature())); doc_manager& dm2 = r->get_dm(); for (unsigned i = 0; i < m_udoc2.size(); ++i) { - doc* d = dm.project(dm2, m_to_delete.size(), m_to_delete, m_udoc2[i]); + doc* d = dm.project(dm2, m_to_delete, m_udoc2[i]); r->get_udoc().insert(dm2, d); SASSERT(r->get_udoc().well_formed(dm2)); } diff --git a/src/test/doc.cpp b/src/test/doc.cpp index 731bc100f..593d09cfe 100644 --- a/src/test/doc.cpp +++ b/src/test/doc.cpp @@ -78,19 +78,19 @@ static void tst_doc1(unsigned n) { to_delete.set(1); to_delete.set(3); doc_manager m1(n-2); - doc_ref d1_1(m1, m.project(m1, n, to_delete, *d1)); + doc_ref d1_1(m1, m.project(m1, to_delete, *d1)); doc_ref d1_2(m1, m1.allocate1()); m.display(std::cout, *d1) << " -> "; m1.display(std::cout, *d1_1) << "\n"; SASSERT(m1.equals(*d1_1,*d1_2)); m.set(*d1,2,BIT_x); m.set(*d1,4,BIT_x); - d1_1 = m.project(m1, n, to_delete, *d1); + d1_1 = m.project(m1, to_delete, *d1); m.display(std::cout, *d1) << " -> "; m1.display(std::cout, *d1_1) << "\n"; d1->neg().push_back(m.tbvm().allocate1()); SASSERT(m.well_formed(*d1)); - d1_1 = m.project(m1, n, to_delete, *d1); + d1_1 = m.project(m1, to_delete, *d1); m.display(std::cout, *d1) << " -> "; m1.display(std::cout, *d1_1) << "\n"; } @@ -218,7 +218,7 @@ class test_doc_cls { } void project(doc const& d, doc_manager& m2, const bit_vector& to_delete, doc_ref& result) { - result = dm.project(m2, m_vars.size(), to_delete, d); + result = dm.project(m2, to_delete, d); TRACE("doc", for (unsigned i = 0; i < m_vars.size(); ++i) { tout << (to_delete.get(i)?"0":"1"); diff --git a/src/test/tbv.cpp b/src/test/tbv.cpp index dc2867f58..c53eb3671 100644 --- a/src/test/tbv.cpp +++ b/src/test/tbv.cpp @@ -32,7 +32,7 @@ static void tst1(unsigned num_bits) { to_delete.set(3); m.set(*b1, 2, BIT_0); m.set(*b1, 4, BIT_x); - tbv_ref b2(m2, m2.project(num_bits, to_delete, *b1)); + tbv_ref b2(m2, m2.project(to_delete, *b1)); m.display(std::cout, *b1) << " -> "; m2.display(std::cout, *b2) << "\n"; m.deallocate(b0); diff --git a/src/test/udoc_relation.cpp b/src/test/udoc_relation.cpp index af80a6d5c..8b9fa3a80 100644 --- a/src/test/udoc_relation.cpp +++ b/src/test/udoc_relation.cpp @@ -76,20 +76,32 @@ class udoc_tester { doc* mk_rand_doc(doc_manager& dm, unsigned num_diff) { tbv_ref t(dm.tbvm()); + doc_ref result(dm); t = mk_rand_tbv(dm); - doc* result = dm.allocate(*t); + result = dm.allocate(*t); SASSERT(dm.tbvm().equals(*t, result->pos())); for (unsigned i = 0; i < num_diff; ++i) { - result->neg().push_back(mk_rand_tbv(dm, result->pos())); + t = mk_rand_tbv(dm, result->pos()); + if (dm.tbvm().equals(*t, result->pos())) { + return 0; + } + if (!result->neg().is_empty() && + dm.tbvm().equals(*t, result->neg()[0])) { + continue; + } + result->neg().push_back(t.detach()); } SASSERT(dm.well_formed(*result)); - return result; + return result.detach(); } void mk_rand_udoc(doc_manager& dm, unsigned num_elems, unsigned num_diff, udoc& result) { result.reset(dm); for (unsigned i = 0; i < num_elems; ++i) { - result.push_back(mk_rand_doc(dm, num_diff)); + doc* d = mk_rand_doc(dm, num_diff); + if (d) { + result.push_back(d); + } } } @@ -144,6 +156,8 @@ public: udoc_relation* t1, *t2, *t3; expr_ref fml(m); + test_filter_neg2(); + test_join_project(); test_filter_neg4(false); @@ -152,7 +166,6 @@ public: test_filter_neg5(true); test_filter_neg(); - test_filter_neg2(); test_filter_neg3(); test_join(1000); @@ -408,27 +421,34 @@ public: } + // {11xx \ {111x}, x011 \ {x011}, 0111} + // {xx11 \ {0011, 1111, x111}} + // 0111 + // {1x1x \ {1x1x}, 1111 \ {1111}, x1x1 \ {x1x1}} + void test_join_project() { datalog::relation_signature sig; - sig.push_back(bv.mk_sort(3)); - sig.push_back(bv.mk_sort(3)); - sig.push_back(bv.mk_sort(3)); + sig.push_back(bv.mk_sort(2)); + sig.push_back(bv.mk_sort(2)); + //sig.push_back(bv.mk_sort(3)); unsigned_vector jc1, jc2, pc; jc1.push_back(0); jc2.push_back(0); pc.push_back(1); pc.push_back(3); - pc.push_back(4); + //pc.push_back(4); udoc_relation* t1, *t2; relation_base* t; scoped_ptr join_project_fn; - for (unsigned i = 0; i < 20; ++i) { + for (unsigned i = 0; i < 200; ++i) { t1 = mk_rand(sig); t2 = mk_rand(sig); + t1->display(std::cout); + t2->display(std::cout); join_project_fn = p.mk_join_project_fn(*t1, *t2, jc1.size(), jc1.c_ptr(), jc2.c_ptr(), pc.size(), pc.c_ptr()); t = (*join_project_fn)(*t1, *t2); t->display(std::cout); @@ -612,6 +632,8 @@ public: apply_filter_neg(*t2, *neg, allcols, allcols); neg->deallocate(); } + t1->display(std::cout); + t2->display(std::cout); apply_filter_neg(*t2, *t1, cols, cols); t1->deallocate(); From 60aad7a6623182eddc63d949cee4fde98922c65d Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 9 Oct 2014 09:44:27 +0100 Subject: [PATCH 640/925] DoC: verify the result of a bunch of unit tests with SMT Signed-off-by: Nuno Lopes --- src/test/udoc_relation.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/test/udoc_relation.cpp b/src/test/udoc_relation.cpp index 8b9fa3a80..ef11e305e 100644 --- a/src/test/udoc_relation.cpp +++ b/src/test/udoc_relation.cpp @@ -204,15 +204,18 @@ public: datalog::relation_join_fn* join_fn = p.mk_join_fn(*t1, *t2, jc1.size(), jc1.c_ptr(), jc2.c_ptr()); SASSERT(join_fn); t = (*join_fn)(*t1, *t2); + cr.verify_join(*t1, *t2, *t, jc1, jc2); t->display(std::cout); std::cout << "\n"; t->deallocate(); t = (*join_fn)(*t1, *t3); + cr.verify_join(*t1, *t3, *t, jc1, jc2); SASSERT(t->empty()); t->display(std::cout); std::cout << "\n"; t->deallocate(); t = (*join_fn)(*t3, *t3); + cr.verify_join(*t3, *t3, *t, jc1, jc2); SASSERT(t->empty()); t->display(std::cout); std::cout << "\n"; t->deallocate(); @@ -231,11 +234,13 @@ public: pc.push_back(0); datalog::relation_transformer_fn* proj_fn = p.mk_project_fn(*t1, pc.size(), pc.c_ptr()); t = (*proj_fn)(*t1); + cr.verify_project(*t1, *t, pc); t->display(std::cout); std::cout << "\n"; t->deallocate(); t1->reset(); t = (*proj_fn)(*t1); + cr.verify_project(*t1, *t, pc); t->display(std::cout); std::cout << "\n"; t->deallocate(); @@ -243,6 +248,7 @@ public: t1->add_fact(fact2); t1->add_fact(fact3); t = (*proj_fn)(*t1); + cr.verify_project(*t1, *t, pc); t1->display(std::cout); std::cout << "\n"; t->display(std::cout); std::cout << "\n"; t->deallocate(); @@ -260,10 +266,15 @@ public: t2->add_fact(fact2); t1->add_fact(fact3); + expr_ref t10(m); + t1->to_formula(t10); + expr_ref delta0(m); + delta->to_formula(delta0); rel_union union_fn = p.mk_union_fn(*t1, *t2, 0); t1->display(std::cout << "t1 before:"); std::cout << "\n"; (*union_fn)(*t1, *t2, delta); + cr.verify_union(t10, *t2, *t1, delta0, delta); t1->display(std::cout << "t1 after:"); std::cout << "\n"; delta->display(std::cout << "delta:"); std::cout << "\n"; From e1e27f2c26474a15607e3aa92691e25949c3064f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 9 Oct 2014 10:17:20 -0700 Subject: [PATCH 641/925] optimize the merge function Signed-off-by: Nikolaj Bjorner --- src/muz/rel/doc.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/muz/rel/doc.cpp b/src/muz/rel/doc.cpp index e87143482..76098b0d3 100644 --- a/src/muz/rel/doc.cpp +++ b/src/muz/rel/doc.cpp @@ -255,8 +255,20 @@ bool doc_manager::merge(doc& d, unsigned idx, subset_ints const& equalities, while (idx != root); } else { + bool all_x = true; + if (!d.neg().is_empty()) { + idx = root; + do { + for (unsigned i = 0; all_x && i < d.neg().size(); ++i) { + all_x = (BIT_x == d.neg()[i][idx]); + } + idx = equalities.next(idx); + } + while (idx != root && all_x); + } + idx = root; do { - if (/*!discard_cols.get(idx) &&*/ idx != root1) { + if ((!discard_cols.get(idx) || !all_x) && idx != root1) { tbv* t = m.allocate(d.pos()); m.set(*t, idx, BIT_0); m.set(*t, root1, BIT_1); From d1a2e6122026573ab8d38ad86358677c0030d9b8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 9 Oct 2014 17:58:38 -0700 Subject: [PATCH 642/925] optimization example that parses obp and wcnf formats natively Signed-off-by: Nikolaj Bjorner --- examples/opt/opt.cpp | 397 ++++++++++++++++++++++++++++++++++++++++++ scripts/mk_project.py | 1 + 2 files changed, 398 insertions(+) create mode 100644 examples/opt/opt.cpp diff --git a/examples/opt/opt.cpp b/examples/opt/opt.cpp new file mode 100644 index 000000000..6f99efb54 --- /dev/null +++ b/examples/opt/opt.cpp @@ -0,0 +1,397 @@ +#include +#include +#include +#include +#include"z3++.h" +using namespace z3; + +static char const* g_input_file = 0; +static bool g_display_statistics = false; +static bool g_first_interrupt = true; +static int g_timeout = 0; +static bool g_display_model = false; +static context* g_context = 0; +static optimize* g_opt = 0; +static double g_start_time = 0; +static std::vector g_handles; + +class stream_buffer { + std::istream & m_stream; + int m_val; +public: + stream_buffer(std::istream & s): + m_stream(s) { + m_val = m_stream.get(); + } + int operator *() const { return m_val;} + void operator ++() { m_val = m_stream.get(); } + int ch() const { return m_val; } + void next() { m_val = m_stream.get(); } + bool eof() const { return ch() == EOF; } + void skip_whitespace() { + while ((ch() >= 9 && ch() <= 13) || ch() == 32) { + next(); + } + } + void skip_line() { + while(true) { + if (eof()) { + return; + } + if (ch() == '\n') { + next(); + return; + } + next(); + } + } + + bool parse_token(char const* token) { + skip_whitespace(); + char const* t = token; + while (ch() == *t) { + next(); + ++t; + } + return 0 == *t; + } + + int parse_int() { + int val = 0; + bool neg = false; + skip_whitespace(); + + if (ch() == '-') { + neg = true; + next(); + } + else if (ch() == '+') { + next(); + } + + if (ch() < '0' || ch() > '9') { + std::cerr << "(error, \"unexpected char: " << ((char)ch()) << "\")\n"; + exit(3); + } + + while (ch() >= '0' && ch() <= '9') { + val = val*10 + (ch() - '0'); + next(); + } + + return neg ? -val : val; + } + + + +}; + +typedef stream_buffer Buffer; + +class wcnf { + context& ctx; + optimize& opt; + stream_buffer& in; + + z3::expr read_clause(unsigned& weight) { + int parsed_lit; + int var; + parsed_lit = in.parse_int(); + weight = static_cast(parsed_lit); + expr result = ctx.bool_val(false); + bool has_result = false; + + while (true) { + parsed_lit = in.parse_int(); + if (parsed_lit == 0) + break; + var = abs(parsed_lit); + expr p = ctx.constant(ctx.int_symbol(var), ctx.bool_sort()); + if (parsed_lit < 0) p = !p; + if (has_result) { + result = result || p; + } + else { + result = p; + has_result = true; + } + } + return result; + } + + void parse_spec(int& num_vars, int& num_clauses, int& max_weight) { + in.parse_token("wcnf"); + num_vars = in.parse_int(); + num_clauses = in.parse_int(); + max_weight = in.parse_int(); + } + +public: + + wcnf(context& ctx, optimize& opt, stream_buffer& in): ctx(ctx), opt(opt), in(in) {} + + void parse() { + int num_vars = 0, num_clauses = 0, max_weight = 0; + while (true) { + in.skip_whitespace(); + if (in.eof()) { + break; + } + else if (*in == 'c') { + in.skip_line(); + } + else if (*in == 'p') { + ++in; + parse_spec(num_vars, num_clauses, max_weight); + } + else { + unsigned weight = 0; + expr cls = read_clause(weight); + if (weight == max_weight) { + opt.add(cls); + } + else { + optimize::handle h = opt.add(cls, weight); + if (g_handles.empty()) g_handles.push_back(h); + } + } + } + } +}; + + +class opb { + context& ctx; + optimize& opt; + stream_buffer& in; + + expr parse_id() { + bool negated = in.parse_token("~"); + if (!in.parse_token("x")) { + std::cerr << "expecting x, got: " << ((char)(*in)) << "\n"; + exit(3); + } + int id = in.parse_int(); + expr p = ctx.constant(ctx.int_symbol(id), ctx.bool_sort()); + if (negated) p = !p; + return p; + } + + expr parse_ids() { + expr result = parse_id(); + while (*in == '~' || *in == 'x') { + result = result && parse_id(); + } + return result; + } + + expr parse_coeff() { + in.skip_whitespace(); + std::vector num; + bool pos = true; + if (*in == '-') pos = false, ++in; + if (*in == '+') ++in; + if (!pos) num.push_back('-'); + in.skip_whitespace(); + while (*in >= '0' && *in <='9') num.push_back(*in), ++in; + num.push_back(0); + return ctx.int_val(&num[0]); + } + + expr parse_term() { + expr c = parse_coeff(); + expr e = parse_ids(); + return ite(e, c, ctx.int_val(0)); + } + + void parse_objective() { + expr t = parse_term(); + while (!in.parse_token(";") && !in.eof()) { + t = t + parse_term(); + } + g_handles.push_back(opt.minimize(t)); + } + + void parse_constraint() { + expr t = parse_term(); + while (!in.eof()) { + if (in.parse_token(">=")) { + expr c = parse_coeff(); + in.parse_token(";"); + t = t >= c; + break; + } + if (in.parse_token("=")) { + expr c = parse_coeff(); + in.parse_token(";"); + t = (t == c); + break; + } + t = t + parse_term(); + } + opt.add(t); + } +public: + opb(context& ctx, optimize& opt, stream_buffer& in): ctx(ctx), opt(opt), in(in) {} + + void parse() { + + while (true) { + in.skip_whitespace(); + if (in.eof()) { + break; + } + else if (*in == '*') { + in.skip_line(); + } + else if (in.parse_token("min:")) { + parse_objective(); + } + else { + parse_constraint(); + } + } + } +}; + + + +void display_statistics() { + if (g_display_statistics && g_opt) { + std::cout << g_opt->statistics() << "\n"; + double end_time = static_cast(clock()); + std::cout << "time: " << (end_time - g_start_time)/CLOCKS_PER_SEC << " secs\n"; + for (size_t i = 0; i < g_handles.size(); ++i) { + std::cout << " [" << g_opt->lower(g_handles[i]) << ":" << g_opt->upper(g_handles[i]) << "]\n"; + } + } +} + + +void display_usage() { + unsigned major, minor, build_number, revision_number; + Z3_get_version(&major, &minor, &build_number, &revision_number); + std::cout << "z3_opt [" << major << "." << minor << "." << build_number << "." << revision_number << "] (c) 2006-20**. Microsoft Corp.\n"; + std::cout << "Usage: z3_opt [options] [-file:]file\n"; + std::cout << " -h, -? prints this message.\n"; + std::cout << " -st, -statistics display statistics.\n"; + std::cout << " -t:timeout set timeout (in second).\n"; + std::cout << " -: configuration parameter and value.\n"; +} + + +void parse_cmd_line_args(int argc, char ** argv) { + g_input_file = 0; + int i = 1; + while (i < argc) { + char* arg = argv[i]; + char * eq = 0; + char * opt_arg = 0; + if (arg[0] == '-' || arg[0] == '/') { + ++arg; + while (*arg == '-') { + ++arg; + } + char * colon = strchr(arg, ':'); + if (colon) { + opt_arg = colon + 1; + *colon = 0; + } + if (!strcmp(arg,"h") || !strcmp(arg,"help") || !strcmp(arg,"?")) { + display_usage(); + exit(0); + } + else if (!strcmp(arg,"st") || !strcmp(arg,"statistics")) { + g_display_statistics = true; + } + else if (!strcmp(arg,"t") || !strcmp(arg,"timeout")) { + if (!opt_arg) { + display_usage(); + exit(0); + } + g_timeout = atoi(opt_arg); + } + else if (!strcmp(arg, "file")) { + g_input_file = opt_arg; + } + else if (opt_arg && arg[0] != '"') { + Z3_global_param_set(arg, opt_arg); + } + else { + std::cerr << "parameter " << arg << " was not recognized\n"; + display_usage(); + exit(0); + } + } + else { + g_input_file = arg; + } + ++i; + } + + if (!g_input_file) { + display_usage(); + exit(0); + } +} + + +static void on_ctrl_c(int) { + if (g_context && g_first_interrupt) { + Z3_interrupt(*g_context); + g_first_interrupt = false; + } + else { + signal (SIGINT, SIG_DFL); + display_statistics(); + raise(SIGINT); + } +} + +bool ends_with(char const* filename, char const* suffix) { + size_t l1 = strlen(filename); + size_t l2 = strlen(suffix); + if (l1 < l2) return false; + filename += (l1 - l2); + for (; *filename; ++filename, ++suffix) { + if (*filename != *suffix) return false; + } + return true; +} + +void main(int argc, char ** argv) { + g_start_time = static_cast(clock()); + signal(SIGINT, on_ctrl_c); + + parse_cmd_line_args(argc, argv); + context ctx; + optimize opt(ctx); + g_context = &ctx; + g_opt = &opt; + + std::ifstream in(g_input_file); + if (!in.bad() && !in.fail()) { + stream_buffer _in(in); + if (ends_with(g_input_file, "wcnf")) { + wcnf wcnf(ctx, opt, _in); + wcnf.parse(); + } + else if (ends_with(g_input_file, "opb")) { + opb opb(ctx, opt, _in); + opb.parse(); + } + else { + std::cout << "Suffix is not recognized: " << g_input_file << "\n"; + exit(3); + } + } + else { + std::cout << "Parsing file " << g_input_file << " failed\n"; + } + + check_result r = opt.check(); + std::cout << r << "\n"; + display_statistics(); + g_opt = 0; + g_context = 0; +} diff --git a/scripts/mk_project.py b/scripts/mk_project.py index f9f752a18..8e8054085 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -92,6 +92,7 @@ def init_project_def(): add_cpp_example('cpp_example', 'c++') add_cpp_example('iz3', 'interp') add_cpp_example('z3_tptp', 'tptp') + add_cpp_example('z3_opt', 'opt') add_c_example('c_example', 'c') add_c_example('maxsat') add_dotnet_example('dotnet_example', 'dotnet') From f651145b4c14896a577b7e2d95e7382e84732c7f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 10 Oct 2014 14:23:58 -0700 Subject: [PATCH 643/925] add optimization front-ends directly to the shell Signed-off-by: Nikolaj Bjorner --- examples/opt/opt.cpp | 6 + src/shell/dimacs_frontend.h | 2 +- src/shell/main.cpp | 21 ++- src/shell/opt_frontend.cpp | 332 ++++++++++++++++++++++++++++++++++++ src/shell/opt_frontend.h | 20 +++ 5 files changed, 379 insertions(+), 2 deletions(-) create mode 100644 src/shell/opt_frontend.cpp create mode 100644 src/shell/opt_frontend.h diff --git a/examples/opt/opt.cpp b/examples/opt/opt.cpp index 6f99efb54..1195fac38 100644 --- a/examples/opt/opt.cpp +++ b/examples/opt/opt.cpp @@ -304,6 +304,12 @@ void parse_cmd_line_args(int argc, char ** argv) { else if (!strcmp(arg,"st") || !strcmp(arg,"statistics")) { g_display_statistics = true; } + else if (strcmp(opt_name, "T") == 0) { + if (!opt_arg) + error("option argument (-T:timeout) is missing."); + long tm = strtol(opt_arg, 0, 10); + //set_timeout(tm * 1000); + } else if (!strcmp(arg,"t") || !strcmp(arg,"timeout")) { if (!opt_arg) { display_usage(); diff --git a/src/shell/dimacs_frontend.h b/src/shell/dimacs_frontend.h index 9521c8256..5448d1af0 100644 --- a/src/shell/dimacs_frontend.h +++ b/src/shell/dimacs_frontend.h @@ -21,5 +21,5 @@ Revision History: unsigned read_dimacs(char const * benchmark_file); -#endif /* _DATALOG_FRONTEND_H_ */ +#endif /* _DIMACS_FRONTEND_H_ */ diff --git a/src/shell/main.cpp b/src/shell/main.cpp index f23bc470c..10fc916ca 100644 --- a/src/shell/main.cpp +++ b/src/shell/main.cpp @@ -29,13 +29,14 @@ Revision History: #include"version.h" #include"dimacs_frontend.h" #include"datalog_frontend.h" +#include"opt_frontend.h" #include"timeout.h" #include"z3_exception.h" #include"error_codes.h" #include"gparams.h" #include"env_params.h" -typedef enum { IN_UNSPECIFIED, IN_SMTLIB, IN_SMTLIB_2, IN_DATALOG, IN_DIMACS, IN_Z3_LOG } input_kind; +typedef enum { IN_UNSPECIFIED, IN_SMTLIB, IN_SMTLIB_2, IN_DATALOG, IN_DIMACS, IN_WCNF, IN_PBO, IN_Z3_LOG } input_kind; std::string g_aux_input_file; char const * g_input_file = 0; @@ -168,6 +169,12 @@ void parse_cmd_line_args(int argc, char ** argv) { else if (strcmp(opt_name, "dimacs") == 0) { g_input_kind = IN_DIMACS; } + else if (strcmp(opt_name, "wcnf") == 0) { + g_input_kind = IN_WCNF; + } + else if (strcmp(opt_name, "bpo") == 0) { + g_input_kind = IN_PBO; + } else if (strcmp(opt_name, "log") == 0) { g_input_kind = IN_Z3_LOG; } @@ -306,6 +313,12 @@ int main(int argc, char ** argv) { else if (strcmp(ext, "dimacs") == 0 || strcmp(ext, "cnf") == 0) { g_input_kind = IN_DIMACS; } + else if (strcmp(ext, "wcnf") == 0) { + g_input_kind = IN_WCNF; + } + else if (strcmp(ext, "pbo") == 0) { + g_input_kind = IN_PBO; + } else if (strcmp(ext, "log") == 0) { g_input_kind = IN_Z3_LOG; } @@ -328,6 +341,12 @@ int main(int argc, char ** argv) { case IN_DIMACS: return_value = read_dimacs(g_input_file); break; + case IN_WCNF: + return_value = parse_opt(g_input_file, true); + break; + case IN_PBO: + return_value = parse_opt(g_input_file, false); + break; case IN_DATALOG: read_datalog(g_input_file); break; diff --git a/src/shell/opt_frontend.cpp b/src/shell/opt_frontend.cpp new file mode 100644 index 000000000..f00d111ad --- /dev/null +++ b/src/shell/opt_frontend.cpp @@ -0,0 +1,332 @@ +#include +#include +#include +#include"opt_context.h" +#include"ast_util.h" +#include"arith_decl_plugin.h" +#include"gparams.h" +#include"timeout.h" +#include"reg_decl_plugins.h" + +static bool g_display_statistics = false; +static bool g_first_interrupt = true; +static int g_timeout = 0; +static bool g_display_model = false; +static opt::context* g_opt = 0; +static double g_start_time = 0; +static unsigned_vector g_handles; + +class stream_buffer { + std::istream & m_stream; + int m_val; + unsigned m_lines; +public: + stream_buffer(std::istream & s): + m_stream(s), + m_lines(0) { + m_val = m_stream.get(); + } + int operator *() const { return m_val;} + void operator ++() { m_val = m_stream.get(); } + int ch() const { return m_val; } + void next() { m_val = m_stream.get(); } + bool eof() const { return ch() == EOF; } + unsigned line() const { return m_line; } + void skip_whitespace() { + while ((ch() >= 9 && ch() <= 13) || ch() == 32) { + if (ch() == 10) ++m_lines; + next(); + } + } + void skip_line() { + while(true) { + if (eof()) { + return; + } + if (ch() == '\n') { + ++m_lines; + next(); + return; + } + next(); + } + } + + bool parse_token(char const* token) { + skip_whitespace(); + char const* t = token; + while (ch() == *t) { + next(); + ++t; + } + return 0 == *t; + } + + int parse_int() { + int val = 0; + bool neg = false; + skip_whitespace(); + + if (ch() == '-') { + neg = true; + next(); + } + else if (ch() == '+') { + next(); + } + if (ch() < '0' || ch() > '9') { + std::cerr << "(error line " << line() << " \"unexpected char: " << ((char)ch()) << "\)\n"; + exit(3); + } + while (ch() >= '0' && ch() <= '9') { + val = val*10 + (ch() - '0'); + next(); + } + return neg ? -val : val; + } +}; + +class wcnf { + opt::context& opt; + ast_manager& m; + stream_buffer& in; + + app_ref read_clause(unsigned& weight) { + int parsed_lit; + int var; + parsed_lit = in.parse_int(); + weight = static_cast(parsed_lit); + app_ref result(m), p(m); + expr_ref_vector ors(m); + while (true) { + parsed_lit = in.parse_int(); + if (parsed_lit == 0) + break; + var = abs(parsed_lit); + p = m.mk_const(symbol(var), m.mk_bool_sort()); + if (parsed_lit < 0) p = m.mk_not(p); + ors.push_back(p); + } + result = to_app(mk_or(m, ors.size(), ors.c_ptr())); + return result; + } + + void parse_spec(int& num_vars, int& num_clauses, int& max_weight) { + in.parse_token("wcnf"); + num_vars = in.parse_int(); + num_clauses = in.parse_int(); + max_weight = in.parse_int(); + } + +public: + + wcnf(opt::context& opt, stream_buffer& in): opt(opt), m(opt.get_manager()), in(in) {} + + void parse() { + int num_vars = 0, num_clauses = 0, max_weight = 0; + while (true) { + in.skip_whitespace(); + if (in.eof()) { + break; + } + else if (*in == 'c') { + in.skip_line(); + } + else if (*in == 'p') { + ++in; + parse_spec(num_vars, num_clauses, max_weight); + } + else { + unsigned weight = 0; + app_ref cls = read_clause(weight); + if (weight == max_weight) { + opt.add_hard_constraint(cls); + } + else { + opt.add_soft_constraint(cls, rational(weight), symbol::null); + } + } + } + } +}; + + +class opb { + opt::context& opt; + ast_manager& m; + stream_buffer& in; + arith_util arith; + + app_ref parse_id() { + bool negated = in.parse_token("~"); + if (!in.parse_token("x")) { + std::cerr << "(error line " << in.line() << " \"unexpected char: " << ((char)in.ch()) << "\)\n"; + exit(3); + } + app_ref p(m); + int id = in.parse_int(); + p = m.mk_const(symbol(id), m.mk_bool_sort()); + if (negated) p = m.mk_not(p); + return p; + } + + app_ref parse_ids() { + app_ref result = parse_id(); + while (*in == '~' || *in == 'x') { + result = m.mk_and(result, parse_id()); + } + return result; + } + + app_ref parse_coeff() { + in.skip_whitespace(); + svector num; + bool pos = true; + if (*in == '-') pos = false, ++in; + if (*in == '+') ++in; + if (!pos) num.push_back('-'); + in.skip_whitespace(); + while (*in >= '0' && *in <='9') num.push_back(*in), ++in; + num.push_back(0); + return app_ref(arith.mk_numeral(rational(num.c_ptr()), true), m); + } + + app_ref parse_term() { + app_ref c = parse_coeff(); + app_ref e = parse_ids(); + return app_ref(m.mk_ite(e, c, arith.mk_numeral(rational(0), true)), m); + } + + void parse_objective() { + app_ref t = parse_term(); + while (!in.parse_token(";") && !in.eof()) { + t = arith.mk_add(t, parse_term()); + } + g_handles.push_back(opt.add_objective(t, false)); + } + + void parse_constraint() { + app_ref t = parse_term(); + while (!in.eof()) { + if (in.parse_token(">=")) { + t = arith.mk_ge(t, parse_coeff()); + in.parse_token(";"); + break; + } + if (in.parse_token("=")) { + t = m.mk_eq(t, parse_coeff()); + in.parse_token(";"); + break; + } + t = arith.mk_add(t, parse_term()); + } + opt.add_hard_constraint(t); + } +public: + opb(opt::context& opt, stream_buffer& in): + opt(opt), m(opt.get_manager()), + in(in), arith(m) {} + + void parse() { + + while (true) { + in.skip_whitespace(); + if (in.eof()) { + break; + } + else if (*in == '*') { + in.skip_line(); + } + else if (in.parse_token("min:")) { + parse_objective(); + } + else { + parse_constraint(); + } + } + } +}; + + + +static void display_statistics() { + if (g_display_statistics && g_opt) { + ::statistics stats; + g_opt->collect_statistics(stats); + stats.display(std::cout); + double end_time = static_cast(clock()); + std::cout << "time: " << (end_time - g_start_time)/CLOCKS_PER_SEC << " secs\n"; + for (unsigned i = 0; i < g_handles.size(); ++i) { + std::cout << " [" << g_opt->get_lower(g_handles[i]) << ":" << g_opt->get_upper(g_handles[i]) << "]\n"; + } + } +} + +static void on_ctrl_c(int) { + if (g_opt && g_first_interrupt) { + g_opt->set_cancel(true); + g_first_interrupt = false; + } + else { + signal (SIGINT, SIG_DFL); + #pragma omp critical (g_display_stats) + { + display_statistics(); + } + raise(SIGINT); + } +} + +static void on_timeout() { + #pragma omp critical (g_display_stats) + { + display_statistics(); + exit(0); + } +} + +static unsigned parse_opt(std::istream& in, bool is_wcnf) { + ast_manager m; + reg_decl_plugins(m); + opt::context opt(m); + g_opt = &opt; + params_ref p = gparams::get_module("opt"); + opt.updt_params(p); + stream_buffer _in(in); + if (is_wcnf) { + wcnf wcnf(opt, _in); + wcnf.parse(); + } + else { + opb opb(opt, _in); + opb.parse(); + } + lbool r = opt.optimize(); + std::cout << r << "\n"; + #pragma omp critical (g_display_stats) + { + display_statistics(); + register_on_timeout_proc(0); + g_opt = 0; + } + return 0; +} + +unsigned parse_opt(char const* file_name, bool is_wcnf) { + g_start_time = static_cast(clock()); + register_on_timeout_proc(on_timeout); + signal(SIGINT, on_ctrl_c); + unsigned result = 0; + if (file_name) { + std::ifstream in(file_name); + if (in.bad() || in.fail()) { + std::cerr << "(error \"failed to open file '" << file_name << "'\")" << std::endl; + exit(ERR_OPEN_FILE); + } + return parse_opt(in, is_wcnf); + } + else { + return parse_opt(std::cin, is_wcnf); + } +} + diff --git a/src/shell/opt_frontend.h b/src/shell/opt_frontend.h new file mode 100644 index 000000000..df6070378 --- /dev/null +++ b/src/shell/opt_frontend.h @@ -0,0 +1,20 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + opt_frontend.h + +Author: + + Nikolaj Bjorner (nbjorner) 2014-10-10. + +--*/ +#ifndef _OPT_FRONTEND_H_ +#define _OPT_FRONTEND_H_ + +unsigned parse_opt(char const* file_name, bool is_wcnf); + +#endif /* _OPT_FRONTEND_H_ */ + + From d4a5873dc8ecf4d42b0ef4a801d29718d3cb5c50 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 10 Oct 2014 14:31:37 -0700 Subject: [PATCH 644/925] fix lines Signed-off-by: Nikolaj Bjorner --- examples/opt/opt.cpp | 403 ------------------------------------- scripts/mk_project.py | 1 - src/shell/opt_frontend.cpp | 12 +- 3 files changed, 6 insertions(+), 410 deletions(-) delete mode 100644 examples/opt/opt.cpp diff --git a/examples/opt/opt.cpp b/examples/opt/opt.cpp deleted file mode 100644 index 1195fac38..000000000 --- a/examples/opt/opt.cpp +++ /dev/null @@ -1,403 +0,0 @@ -#include -#include -#include -#include -#include"z3++.h" -using namespace z3; - -static char const* g_input_file = 0; -static bool g_display_statistics = false; -static bool g_first_interrupt = true; -static int g_timeout = 0; -static bool g_display_model = false; -static context* g_context = 0; -static optimize* g_opt = 0; -static double g_start_time = 0; -static std::vector g_handles; - -class stream_buffer { - std::istream & m_stream; - int m_val; -public: - stream_buffer(std::istream & s): - m_stream(s) { - m_val = m_stream.get(); - } - int operator *() const { return m_val;} - void operator ++() { m_val = m_stream.get(); } - int ch() const { return m_val; } - void next() { m_val = m_stream.get(); } - bool eof() const { return ch() == EOF; } - void skip_whitespace() { - while ((ch() >= 9 && ch() <= 13) || ch() == 32) { - next(); - } - } - void skip_line() { - while(true) { - if (eof()) { - return; - } - if (ch() == '\n') { - next(); - return; - } - next(); - } - } - - bool parse_token(char const* token) { - skip_whitespace(); - char const* t = token; - while (ch() == *t) { - next(); - ++t; - } - return 0 == *t; - } - - int parse_int() { - int val = 0; - bool neg = false; - skip_whitespace(); - - if (ch() == '-') { - neg = true; - next(); - } - else if (ch() == '+') { - next(); - } - - if (ch() < '0' || ch() > '9') { - std::cerr << "(error, \"unexpected char: " << ((char)ch()) << "\")\n"; - exit(3); - } - - while (ch() >= '0' && ch() <= '9') { - val = val*10 + (ch() - '0'); - next(); - } - - return neg ? -val : val; - } - - - -}; - -typedef stream_buffer Buffer; - -class wcnf { - context& ctx; - optimize& opt; - stream_buffer& in; - - z3::expr read_clause(unsigned& weight) { - int parsed_lit; - int var; - parsed_lit = in.parse_int(); - weight = static_cast(parsed_lit); - expr result = ctx.bool_val(false); - bool has_result = false; - - while (true) { - parsed_lit = in.parse_int(); - if (parsed_lit == 0) - break; - var = abs(parsed_lit); - expr p = ctx.constant(ctx.int_symbol(var), ctx.bool_sort()); - if (parsed_lit < 0) p = !p; - if (has_result) { - result = result || p; - } - else { - result = p; - has_result = true; - } - } - return result; - } - - void parse_spec(int& num_vars, int& num_clauses, int& max_weight) { - in.parse_token("wcnf"); - num_vars = in.parse_int(); - num_clauses = in.parse_int(); - max_weight = in.parse_int(); - } - -public: - - wcnf(context& ctx, optimize& opt, stream_buffer& in): ctx(ctx), opt(opt), in(in) {} - - void parse() { - int num_vars = 0, num_clauses = 0, max_weight = 0; - while (true) { - in.skip_whitespace(); - if (in.eof()) { - break; - } - else if (*in == 'c') { - in.skip_line(); - } - else if (*in == 'p') { - ++in; - parse_spec(num_vars, num_clauses, max_weight); - } - else { - unsigned weight = 0; - expr cls = read_clause(weight); - if (weight == max_weight) { - opt.add(cls); - } - else { - optimize::handle h = opt.add(cls, weight); - if (g_handles.empty()) g_handles.push_back(h); - } - } - } - } -}; - - -class opb { - context& ctx; - optimize& opt; - stream_buffer& in; - - expr parse_id() { - bool negated = in.parse_token("~"); - if (!in.parse_token("x")) { - std::cerr << "expecting x, got: " << ((char)(*in)) << "\n"; - exit(3); - } - int id = in.parse_int(); - expr p = ctx.constant(ctx.int_symbol(id), ctx.bool_sort()); - if (negated) p = !p; - return p; - } - - expr parse_ids() { - expr result = parse_id(); - while (*in == '~' || *in == 'x') { - result = result && parse_id(); - } - return result; - } - - expr parse_coeff() { - in.skip_whitespace(); - std::vector num; - bool pos = true; - if (*in == '-') pos = false, ++in; - if (*in == '+') ++in; - if (!pos) num.push_back('-'); - in.skip_whitespace(); - while (*in >= '0' && *in <='9') num.push_back(*in), ++in; - num.push_back(0); - return ctx.int_val(&num[0]); - } - - expr parse_term() { - expr c = parse_coeff(); - expr e = parse_ids(); - return ite(e, c, ctx.int_val(0)); - } - - void parse_objective() { - expr t = parse_term(); - while (!in.parse_token(";") && !in.eof()) { - t = t + parse_term(); - } - g_handles.push_back(opt.minimize(t)); - } - - void parse_constraint() { - expr t = parse_term(); - while (!in.eof()) { - if (in.parse_token(">=")) { - expr c = parse_coeff(); - in.parse_token(";"); - t = t >= c; - break; - } - if (in.parse_token("=")) { - expr c = parse_coeff(); - in.parse_token(";"); - t = (t == c); - break; - } - t = t + parse_term(); - } - opt.add(t); - } -public: - opb(context& ctx, optimize& opt, stream_buffer& in): ctx(ctx), opt(opt), in(in) {} - - void parse() { - - while (true) { - in.skip_whitespace(); - if (in.eof()) { - break; - } - else if (*in == '*') { - in.skip_line(); - } - else if (in.parse_token("min:")) { - parse_objective(); - } - else { - parse_constraint(); - } - } - } -}; - - - -void display_statistics() { - if (g_display_statistics && g_opt) { - std::cout << g_opt->statistics() << "\n"; - double end_time = static_cast(clock()); - std::cout << "time: " << (end_time - g_start_time)/CLOCKS_PER_SEC << " secs\n"; - for (size_t i = 0; i < g_handles.size(); ++i) { - std::cout << " [" << g_opt->lower(g_handles[i]) << ":" << g_opt->upper(g_handles[i]) << "]\n"; - } - } -} - - -void display_usage() { - unsigned major, minor, build_number, revision_number; - Z3_get_version(&major, &minor, &build_number, &revision_number); - std::cout << "z3_opt [" << major << "." << minor << "." << build_number << "." << revision_number << "] (c) 2006-20**. Microsoft Corp.\n"; - std::cout << "Usage: z3_opt [options] [-file:]file\n"; - std::cout << " -h, -? prints this message.\n"; - std::cout << " -st, -statistics display statistics.\n"; - std::cout << " -t:timeout set timeout (in second).\n"; - std::cout << " -: configuration parameter and value.\n"; -} - - -void parse_cmd_line_args(int argc, char ** argv) { - g_input_file = 0; - int i = 1; - while (i < argc) { - char* arg = argv[i]; - char * eq = 0; - char * opt_arg = 0; - if (arg[0] == '-' || arg[0] == '/') { - ++arg; - while (*arg == '-') { - ++arg; - } - char * colon = strchr(arg, ':'); - if (colon) { - opt_arg = colon + 1; - *colon = 0; - } - if (!strcmp(arg,"h") || !strcmp(arg,"help") || !strcmp(arg,"?")) { - display_usage(); - exit(0); - } - else if (!strcmp(arg,"st") || !strcmp(arg,"statistics")) { - g_display_statistics = true; - } - else if (strcmp(opt_name, "T") == 0) { - if (!opt_arg) - error("option argument (-T:timeout) is missing."); - long tm = strtol(opt_arg, 0, 10); - //set_timeout(tm * 1000); - } - else if (!strcmp(arg,"t") || !strcmp(arg,"timeout")) { - if (!opt_arg) { - display_usage(); - exit(0); - } - g_timeout = atoi(opt_arg); - } - else if (!strcmp(arg, "file")) { - g_input_file = opt_arg; - } - else if (opt_arg && arg[0] != '"') { - Z3_global_param_set(arg, opt_arg); - } - else { - std::cerr << "parameter " << arg << " was not recognized\n"; - display_usage(); - exit(0); - } - } - else { - g_input_file = arg; - } - ++i; - } - - if (!g_input_file) { - display_usage(); - exit(0); - } -} - - -static void on_ctrl_c(int) { - if (g_context && g_first_interrupt) { - Z3_interrupt(*g_context); - g_first_interrupt = false; - } - else { - signal (SIGINT, SIG_DFL); - display_statistics(); - raise(SIGINT); - } -} - -bool ends_with(char const* filename, char const* suffix) { - size_t l1 = strlen(filename); - size_t l2 = strlen(suffix); - if (l1 < l2) return false; - filename += (l1 - l2); - for (; *filename; ++filename, ++suffix) { - if (*filename != *suffix) return false; - } - return true; -} - -void main(int argc, char ** argv) { - g_start_time = static_cast(clock()); - signal(SIGINT, on_ctrl_c); - - parse_cmd_line_args(argc, argv); - context ctx; - optimize opt(ctx); - g_context = &ctx; - g_opt = &opt; - - std::ifstream in(g_input_file); - if (!in.bad() && !in.fail()) { - stream_buffer _in(in); - if (ends_with(g_input_file, "wcnf")) { - wcnf wcnf(ctx, opt, _in); - wcnf.parse(); - } - else if (ends_with(g_input_file, "opb")) { - opb opb(ctx, opt, _in); - opb.parse(); - } - else { - std::cout << "Suffix is not recognized: " << g_input_file << "\n"; - exit(3); - } - } - else { - std::cout << "Parsing file " << g_input_file << " failed\n"; - } - - check_result r = opt.check(); - std::cout << r << "\n"; - display_statistics(); - g_opt = 0; - g_context = 0; -} diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 8e8054085..f9f752a18 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -92,7 +92,6 @@ def init_project_def(): add_cpp_example('cpp_example', 'c++') add_cpp_example('iz3', 'interp') add_cpp_example('z3_tptp', 'tptp') - add_cpp_example('z3_opt', 'opt') add_c_example('c_example', 'c') add_c_example('maxsat') add_dotnet_example('dotnet_example', 'dotnet') diff --git a/src/shell/opt_frontend.cpp b/src/shell/opt_frontend.cpp index f00d111ad..5269f51bc 100644 --- a/src/shell/opt_frontend.cpp +++ b/src/shell/opt_frontend.cpp @@ -19,11 +19,11 @@ static unsigned_vector g_handles; class stream_buffer { std::istream & m_stream; int m_val; - unsigned m_lines; + unsigned m_line; public: stream_buffer(std::istream & s): m_stream(s), - m_lines(0) { + m_line(0) { m_val = m_stream.get(); } int operator *() const { return m_val;} @@ -34,7 +34,7 @@ public: unsigned line() const { return m_line; } void skip_whitespace() { while ((ch() >= 9 && ch() <= 13) || ch() == 32) { - if (ch() == 10) ++m_lines; + if (ch() == 10) ++m_line; next(); } } @@ -44,7 +44,7 @@ public: return; } if (ch() == '\n') { - ++m_lines; + ++m_line; next(); return; } @@ -75,7 +75,7 @@ public: next(); } if (ch() < '0' || ch() > '9') { - std::cerr << "(error line " << line() << " \"unexpected char: " << ((char)ch()) << "\)\n"; + std::cerr << "(error line " << line() << " \"unexpected char: " << ((char)ch()) << "\" )\n"; exit(3); } while (ch() >= '0' && ch() <= '9') { @@ -160,7 +160,7 @@ class opb { app_ref parse_id() { bool negated = in.parse_token("~"); if (!in.parse_token("x")) { - std::cerr << "(error line " << in.line() << " \"unexpected char: " << ((char)in.ch()) << "\)\n"; + std::cerr << "(error line " << in.line() << " \"unexpected char: " << ((char)in.ch()) << "\")\n"; exit(3); } app_ref p(m); From 11fee1c8d0120d4c02140aef3973be9c8f2e43e2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 10 Oct 2014 14:57:39 -0700 Subject: [PATCH 645/925] fix opb Signed-off-by: Nikolaj Bjorner --- src/shell/main.cpp | 10 +++++----- src/shell/opt_frontend.cpp | 26 +++++++++++++++++++------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/shell/main.cpp b/src/shell/main.cpp index 10fc916ca..2a8ed5022 100644 --- a/src/shell/main.cpp +++ b/src/shell/main.cpp @@ -36,7 +36,7 @@ Revision History: #include"gparams.h" #include"env_params.h" -typedef enum { IN_UNSPECIFIED, IN_SMTLIB, IN_SMTLIB_2, IN_DATALOG, IN_DIMACS, IN_WCNF, IN_PBO, IN_Z3_LOG } input_kind; +typedef enum { IN_UNSPECIFIED, IN_SMTLIB, IN_SMTLIB_2, IN_DATALOG, IN_DIMACS, IN_WCNF, IN_OPB, IN_Z3_LOG } input_kind; std::string g_aux_input_file; char const * g_input_file = 0; @@ -173,7 +173,7 @@ void parse_cmd_line_args(int argc, char ** argv) { g_input_kind = IN_WCNF; } else if (strcmp(opt_name, "bpo") == 0) { - g_input_kind = IN_PBO; + g_input_kind = IN_OPB; } else if (strcmp(opt_name, "log") == 0) { g_input_kind = IN_Z3_LOG; @@ -316,8 +316,8 @@ int main(int argc, char ** argv) { else if (strcmp(ext, "wcnf") == 0) { g_input_kind = IN_WCNF; } - else if (strcmp(ext, "pbo") == 0) { - g_input_kind = IN_PBO; + else if (strcmp(ext, "opb") == 0) { + g_input_kind = IN_OPB; } else if (strcmp(ext, "log") == 0) { g_input_kind = IN_Z3_LOG; @@ -344,7 +344,7 @@ int main(int argc, char ** argv) { case IN_WCNF: return_value = parse_opt(g_input_file, true); break; - case IN_PBO: + case IN_OPB: return_value = parse_opt(g_input_file, false); break; case IN_DATALOG: diff --git a/src/shell/opt_frontend.cpp b/src/shell/opt_frontend.cpp index 5269f51bc..566a2c911 100644 --- a/src/shell/opt_frontend.cpp +++ b/src/shell/opt_frontend.cpp @@ -8,10 +8,8 @@ #include"timeout.h" #include"reg_decl_plugins.h" -static bool g_display_statistics = false; +extern bool g_display_statistics; static bool g_first_interrupt = true; -static int g_timeout = 0; -static bool g_display_model = false; static opt::context* g_opt = 0; static double g_start_time = 0; static unsigned_vector g_handles; @@ -143,7 +141,10 @@ public: opt.add_hard_constraint(cls); } else { - opt.add_soft_constraint(cls, rational(weight), symbol::null); + unsigned id = opt.add_soft_constraint(cls, rational(weight), symbol::null); + if (g_handles.empty()) { + g_handles.push_back(id); + } } } } @@ -255,9 +256,16 @@ static void display_statistics() { g_opt->collect_statistics(stats); stats.display(std::cout); double end_time = static_cast(clock()); - std::cout << "time: " << (end_time - g_start_time)/CLOCKS_PER_SEC << " secs\n"; + std::cout << "time: " << (end_time - g_start_time)/CLOCKS_PER_SEC << " secs\n"; for (unsigned i = 0; i < g_handles.size(); ++i) { - std::cout << " [" << g_opt->get_lower(g_handles[i]) << ":" << g_opt->get_upper(g_handles[i]) << "]\n"; + expr_ref lo = g_opt->get_lower(g_handles[i]); + expr_ref hi = g_opt->get_upper(g_handles[i]); + if (lo == hi) { + std::cout << " " << lo << "\n"; + } + else { + std::cout << " [" << lo << ":" << hi << "]\n"; + } } } } @@ -302,7 +310,11 @@ static unsigned parse_opt(std::istream& in, bool is_wcnf) { opb.parse(); } lbool r = opt.optimize(); - std::cout << r << "\n"; + switch (r) { + case l_true: std::cout << "sat\n"; break; + case l_false: std::cout << "unsat\n"; break; + case l_undef: std::cout << "unknown\n"; break; + } #pragma omp critical (g_display_stats) { display_statistics(); From 70f5eb4a9dbd7526262ff48cbefb643925704bce Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 10 Oct 2014 19:28:09 -0700 Subject: [PATCH 646/925] make using handles easier from python Signed-off-by: Nikolaj Bjorner --- src/api/python/z3.py | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index 5a1a6c36d..97a0ef549 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -6314,8 +6314,24 @@ class Fixedpoint(Z3PPObject): ######################################### class OptimizeObjective: - def __init__(self, value): - self.value = value + def __init__(self, opt, value, is_max): + self._opt = opt + self._value = value + self._is_max = is_max + + def lower(self): + opt = self._opt + return _to_expr_ref(Z3_optimize_get_lower(opt.ctx.ref(), opt.optimize, self._value), opt.ctx) + + def upper(self): + opt = self._opt + return _to_expr_ref(Z3_optimize_get_upper(opt.ctx.ref(), opt.optimize, self._value), opt.ctx) + + def value(self): + if self._is_max: + return self.upper() + else: + return self.lower() class Optimize(Z3PPObject): """Optimize API provides methods for solving using objective functions and weighted soft constraints""" @@ -6372,15 +6388,15 @@ class Optimize(Z3PPObject): id = "" id = to_symbol(id, self.ctx) v = Z3_optimize_assert_soft(self.ctx.ref(), self.optimize, arg.as_ast(), weight, id) - return OptimizeObjective(v) + return OptimizeObjective(self, v, False) def maximize(self, arg): """Add objective function to maximize.""" - return OptimizeObjective(Z3_optimize_maximize(self.ctx.ref(), self.optimize, arg.as_ast())) + return OptimizeObjective(self, Z3_optimize_maximize(self.ctx.ref(), self.optimize, arg.as_ast()), True) def minimize(self, arg): """Add objective function to minimize.""" - return OptimizeObjective(Z3_optimize_minimize(self.ctx.ref(), self.optimize, arg.as_ast())) + return OptimizeObjective(self, Z3_optimize_minimize(self.ctx.ref(), self.optimize, arg.as_ast()), False) def push(self): """create a backtracking point for added rules, facts and assertions""" @@ -6404,12 +6420,12 @@ class Optimize(Z3PPObject): def lower(self, obj): if not isinstance(obj, OptimizeObjective): raise Z3Exception("Expecting objective handle returned by maximize/minimize") - return _to_expr_ref(Z3_optimize_get_lower(self.ctx.ref(), self.optimize, obj.value), self.ctx) + return obj.lower() def upper(self, obj): if not isinstance(obj, OptimizeObjective): raise Z3Exception("Expecting objective handle returned by maximize/minimize") - return _to_expr_ref(Z3_optimize_get_upper(self.ctx.ref(), self.optimize, obj.value), self.ctx) + return obj.upper() def __repr__(self): """Return a formatted string with all added rules and constraints.""" From f7f4feaa474b6929fe707988b49111e20d0b9db0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 11 Oct 2014 01:05:30 -0700 Subject: [PATCH 647/925] fix lex bug for maxres case Signed-off-by: Nikolaj Bjorner --- src/ast/ast_smt2_pp.cpp | 11 +++++++ src/ast/ast_smt2_pp.h | 3 ++ src/opt/maxres.cpp | 70 +++++++++++++++++++++-------------------- src/opt/maxsmt.cpp | 8 ++--- src/opt/opt_context.cpp | 5 +++ 5 files changed, 57 insertions(+), 40 deletions(-) diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index af3bbc170..cf2c0478f 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -1140,6 +1140,17 @@ std::ostream& operator<<(std::ostream& out, app_ref const& e) { return out << mk_ismt2_pp(e.get(), e.get_manager()); } +std::ostream& operator<<(std::ostream& out, expr_ref_vector const& e) { + for (unsigned i = 0; i < e.size(); ++i) + out << mk_ismt2_pp(e[i], e.get_manager()) << "\n"; + return out; +} + +std::ostream& operator<<(std::ostream& out, app_ref_vector const& e) { + for (unsigned i = 0; i < e.size(); ++i) + out << mk_ismt2_pp(e[i], e.get_manager()) << "\n"; + return out; +} #ifdef Z3DEBUG void pp(expr const * n, ast_manager & m) { diff --git a/src/ast/ast_smt2_pp.h b/src/ast/ast_smt2_pp.h index 175ec9c4a..68d669a5e 100644 --- a/src/ast/ast_smt2_pp.h +++ b/src/ast/ast_smt2_pp.h @@ -113,4 +113,7 @@ std::ostream& operator<<(std::ostream& out, mk_ismt2_pp const & p); std::ostream& operator<<(std::ostream& out, expr_ref const& e); std::ostream& operator<<(std::ostream& out, app_ref const& e); +std::ostream& operator<<(std::ostream& out, expr_ref_vector const& e); +std::ostream& operator<<(std::ostream& out, app_ref_vector const& e); + #endif diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 65e026c07..d0694222a 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -78,6 +78,7 @@ public: private: expr_ref_vector m_B; expr_ref_vector m_asms; + expr_ref_vector m_defs; obj_map m_asm2weight; ptr_vector m_new_core; mus m_mus; @@ -102,7 +103,7 @@ public: weights_t& ws, expr_ref_vector const& soft, strategy_t st): maxsmt_solver_base(c, ws, soft), - m_B(m), m_asms(m), + m_B(m), m_asms(m), m_defs(m), m_mus(c.get_solver(), m), m_mss(c.get_solver(), m), m_trail(m), @@ -377,15 +378,19 @@ public: for (unsigned i = 0; i < m_asms.size(); ++i) { SASSERT(is_true(m_asms[i].get())); }); + rational upper(0); for (unsigned i = 0; i < m_soft.size(); ++i) { m_assignment[i] = is_true(m_soft[i]); + if (!m_assignment[i]) upper += m_weights[i]; } + SASSERT(upper == m_lower); m_upper = m_lower; m_found_feasible_optimum = true; } virtual lbool operator()() { + m_defs.reset(); switch(m_st) { case s_mus: return mus_solver(); @@ -635,7 +640,6 @@ public: app_ref cls(m), d(m), dd(m); m_B.reset(); m_B.append(core.size(), core.c_ptr()); - d = m.mk_true(); // // d_0 := true // d_i := b_{i-1} and d_{i-1} for i = 1...sz-1 @@ -651,23 +655,29 @@ public: for (unsigned i = 1; i < core.size(); ++i) { expr* b_i = m_B[i-1].get(); expr* b_i1 = m_B[i].get(); - if (i > 2) { + if (i == 1) { + d = to_app(b_i); + } + else if (i == 2) { + d = m.mk_and(b_i, d); + m_trail.push_back(d); + } + else { dd = mk_fresh_bool("d"); fml = m.mk_implies(dd, d); s().assert_expr(fml); + m_defs.push_back(fml); fml = m.mk_implies(dd, b_i); s().assert_expr(fml); + m_defs.push_back(fml); d = dd; } - else { - d = m.mk_and(b_i, d); - m_trail.push_back(d); - } asum = mk_fresh_bool("a"); cls = m.mk_or(b_i1, d); fml = m.mk_implies(asum, cls); new_assumption(asum, w); s().assert_expr(fml); + m_defs.push_back(fml); } } @@ -698,6 +708,7 @@ public: d = mk_fresh_bool("d"); fml = m.mk_implies(d, cls); s().assert_expr(fml); + m_defs.push_back(fml); } else { d = cls; @@ -705,8 +716,10 @@ public: asum = mk_fresh_bool("a"); fml = m.mk_implies(asum, b_i1); s().assert_expr(fml); + m_defs.push_back(fml); fml = m.mk_implies(asum, cls); s().assert_expr(fml); + m_defs.push_back(fml); new_assumption(asum, w); } fml = m.mk_or(m_B.size(), m_B.c_ptr()); @@ -872,7 +885,13 @@ public: virtual void commit_assignment() { if (m_found_feasible_optimum) { - TRACE("opt", tout << "Committing feasible solution\n";); + TRACE("opt", tout << "Committing feasible solution\n"; + tout << m_defs; + tout << m_asms; + ); + for (unsigned i = 0; i < m_defs.size(); ++i) { + s().assert_expr(m_defs[i].get()); + } for (unsigned i = 0; i < m_asms.size(); ++i) { s().assert_expr(m_asms[i].get()); } @@ -883,42 +902,25 @@ public: } void verify_core(exprs const& core) { - IF_VERBOSE(3, verbose_stream() << "verify core\n";); - ref sat_solver = mk_inc_sat_solver(m, m_params); - + IF_VERBOSE(3, verbose_stream() << "verify core\n";); + ref smt_solver = mk_smt_solver(m, m_params, symbol()); for (unsigned i = 0; i < s().get_num_assertions(); ++i) { - sat_solver->assert_expr(s().get_assertion(i)); - } - expr_ref n(m); - for (unsigned i = 0; i < core.size(); ++i) { - IF_VERBOSE(1, verbose_stream() << mk_pp(core[i],m) << " ";); - sat_solver->assert_expr(core[i]); - } - IF_VERBOSE(1, verbose_stream() << "\n";); - lbool is_sat = sat_solver->check_sat(0, 0); - if (is_sat != l_false) { - IF_VERBOSE(0, verbose_stream() << "!!!not a core\n";); - } - - sat_solver = mk_smt_solver(m, m_params, symbol()); - for (unsigned i = 0; i < s().get_num_assertions(); ++i) { - sat_solver->assert_expr(s().get_assertion(i)); + smt_solver->assert_expr(s().get_assertion(i)); } for (unsigned i = 0; i < core.size(); ++i) { - sat_solver->assert_expr(core[i]); + smt_solver->assert_expr(core[i]); } - is_sat = sat_solver->check_sat(0, 0); + lbool is_sat = smt_solver->check_sat(0, 0); if (is_sat == l_true) { IF_VERBOSE(0, verbose_stream() << "not a core\n";); } - } void verify_assignment() { IF_VERBOSE(0, verbose_stream() << "verify assignment\n";); - ref sat_solver = mk_inc_sat_solver(m, m_params); + ref smt_solver = mk_smt_solver(m, m_params, symbol()); for (unsigned i = 0; i < s().get_num_assertions(); ++i) { - sat_solver->assert_expr(s().get_assertion(i)); + smt_solver->assert_expr(s().get_assertion(i)); } expr_ref n(m); for (unsigned i = 0; i < m_soft.size(); ++i) { @@ -926,9 +928,9 @@ public: if (!m_assignment[i]) { n = mk_not(m, n); } - sat_solver->assert_expr(n); + smt_solver->assert_expr(n); } - lbool is_sat = sat_solver->check_sat(0, 0); + lbool is_sat = smt_solver->check_sat(0, 0); if (is_sat == l_false) { IF_VERBOSE(0, verbose_stream() << "assignment is infeasible\n";); } diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 46b782dfd..16e577021 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -66,6 +66,7 @@ namespace opt { } pb_util pb(m); tmp = pb.mk_ge(m_weights.size(), m_weights.c_ptr(), m_soft.c_ptr(), k); + TRACE("opt", tout << tmp << "\n";); s().assert_expr(tmp); } @@ -205,18 +206,13 @@ namespace opt { } } - // Infrastructure for displaying and storing solution is TBD. IF_VERBOSE(1, verbose_stream() << "is-sat: " << is_sat << "\n"; if (is_sat == l_true) { verbose_stream() << "Satisfying soft constraints\n"; display_answer(verbose_stream()); }); - DEBUG_CODE(if (is_sat == l_true) { - verify_assignment(); - }); - - // TBD: check that all extensions are unsat too + DEBUG_CODE(if (is_sat == l_true) verify_assignment();); return is_sat; } diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 2afba62a9..09d3a809a 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -1203,10 +1203,15 @@ namespace opt { } case O_MAXSMT: { maxsmt& ms = *m_maxsmts.find(obj.m_id); + rational value(0); for (unsigned i = 0; i < obj.m_terms.size(); ++i) { VERIFY(m_model->eval(obj.m_terms[i], val)); + if (!m.is_true(val)) { + value += obj.m_weights[i]; + } // TBD: check that optimal was not changed. } + TRACE("opt", tout << "value " << value << "\n";); break; } } From e774634217b00e8fec1c4ae8a72da361c27c78a5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 11 Oct 2014 18:10:38 -0700 Subject: [PATCH 648/925] improve interrupts Signed-off-by: Nikolaj Bjorner --- src/shell/opt_frontend.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/shell/opt_frontend.cpp b/src/shell/opt_frontend.cpp index 566a2c911..a9df2cd3d 100644 --- a/src/shell/opt_frontend.cpp +++ b/src/shell/opt_frontend.cpp @@ -309,11 +309,16 @@ static unsigned parse_opt(std::istream& in, bool is_wcnf) { opb opb(opt, _in); opb.parse(); } - lbool r = opt.optimize(); - switch (r) { - case l_true: std::cout << "sat\n"; break; - case l_false: std::cout << "unsat\n"; break; - case l_undef: std::cout << "unknown\n"; break; + try { + lbool r = opt.optimize(); + switch (r) { + case l_true: std::cout << "sat\n"; break; + case l_false: std::cout << "unsat\n"; break; + case l_undef: std::cout << "unknown\n"; break; + } + } + catch (z3_exception & ex) { + std::cerr << ex.msg() << "\n"; } #pragma omp critical (g_display_stats) { @@ -325,6 +330,7 @@ static unsigned parse_opt(std::istream& in, bool is_wcnf) { } unsigned parse_opt(char const* file_name, bool is_wcnf) { + g_first_interrupt = true; g_start_time = static_cast(clock()); register_on_timeout_proc(on_timeout); signal(SIGINT, on_ctrl_c); From a0cdeb2cfeb88580ac971cd8b2bbeb51f48e0b60 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 13 Oct 2014 14:20:53 -0700 Subject: [PATCH 649/925] add useful API for parameter setting Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Params.cs | 12 ++++++++++++ src/shell/opt_frontend.cpp | 12 ++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/api/dotnet/Params.cs b/src/api/dotnet/Params.cs index 56a7a891f..a1334e612 100644 --- a/src/api/dotnet/Params.cs +++ b/src/api/dotnet/Params.cs @@ -69,6 +69,7 @@ namespace Microsoft.Z3 Native.Z3_params_set_symbol(Context.nCtx, NativeObject, name.NativeObject, value.NativeObject); } + /// /// Adds a parameter setting. /// @@ -103,6 +104,17 @@ namespace Microsoft.Z3 Native.Z3_params_set_symbol(Context.nCtx, NativeObject, Context.MkSymbol(name).NativeObject, value.NativeObject); } + /// + /// Adds a parameter setting. + /// + public void Add(string name, string value) + { + Contract.Requires(name != null); + Contract.Requires(value != null); + + Native.Z3_params_set_symbol(Context.nCtx, NativeObject, Context.MkSymbol(name).NativeObject, Context.MkSymbol(value).NativeObject); + } + /// /// A string representation of the parameter set. /// diff --git a/src/shell/opt_frontend.cpp b/src/shell/opt_frontend.cpp index 566a2c911..cb1f75561 100644 --- a/src/shell/opt_frontend.cpp +++ b/src/shell/opt_frontend.cpp @@ -168,6 +168,7 @@ class opb { int id = in.parse_int(); p = m.mk_const(symbol(id), m.mk_bool_sort()); if (negated) p = m.mk_not(p); + in.skip_whitespace(); return p; } @@ -179,7 +180,7 @@ class opb { return result; } - app_ref parse_coeff() { + rational parse_coeff_r() { in.skip_whitespace(); svector num; bool pos = true; @@ -187,9 +188,13 @@ class opb { if (*in == '+') ++in; if (!pos) num.push_back('-'); in.skip_whitespace(); - while (*in >= '0' && *in <='9') num.push_back(*in), ++in; + while ('0' <= *in && *in <='9') num.push_back(*in), ++in; num.push_back(0); - return app_ref(arith.mk_numeral(rational(num.c_ptr()), true), m); + return rational(num.c_ptr()); + } + + app_ref parse_coeff() { + return app_ref(arith.mk_numeral(parse_coeff_r(), true), m); } app_ref parse_term() { @@ -229,7 +234,6 @@ public: in(in), arith(m) {} void parse() { - while (true) { in.skip_whitespace(); if (in.eof()) { From e46114819bb01ccf8657c6f53bd3666303e3cc90 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 13 Oct 2014 18:59:13 -0700 Subject: [PATCH 650/925] revamp API for acessing values of objectives Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Optimize.cs | 56 ++++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/src/api/dotnet/Optimize.cs b/src/api/dotnet/Optimize.cs index a9499570b..eb8281e5f 100644 --- a/src/api/dotnet/Optimize.cs +++ b/src/api/dotnet/Optimize.cs @@ -85,17 +85,55 @@ namespace Microsoft.Z3 Assert(constraints); } + /// + /// Handle to objectives returned by objective functions. + /// + public class Handle + { + Optimize opt; + uint handle; + internal Handle(Optimize opt, uint h) + { + this.opt = opt; + this.handle = h; + } + + /// + /// Retrieve a lower bound for the objective handle. + /// + public ArithExpr Lower() + { + return opt.GetLower(handle); + } + + /// + /// Retrieve an upper bound for the objective handle. + /// + public ArithExpr Upper() + { + return opt.GetUpper(handle); + } + + /// + /// Retrieve the value of an objective. + /// + public ArithExpr Value() + { + return Lower(); + } + } + /// /// Assert soft constraint /// /// /// Return an objective which associates with the group of constraints. /// - public uint AssertSoft(BoolExpr constraint, uint weight, string group) + public Handle AssertSoft(BoolExpr constraint, uint weight, string group) { Context.CheckContextMatch(constraint); Symbol s = Context.MkSymbol(group); - return Native.Z3_optimize_assert_soft(Context.nCtx, NativeObject, constraint.NativeObject, weight.ToString(), s.NativeObject); + return new Handle(this, Native.Z3_optimize_assert_soft(Context.nCtx, NativeObject, constraint.NativeObject, weight.ToString(), s.NativeObject)); } @@ -161,26 +199,26 @@ namespace Microsoft.Z3 /// /// Declare an arithmetical maximization objective. /// Return a handle to the objective. The handle is used as - /// an argument to GetLower and GetUpper. + /// to retrieve the values of objectives after calling Check. /// - public uint MkMaximize(ArithExpr e) + public Handle MkMaximize(ArithExpr e) { - return Native.Z3_optimize_maximize(Context.nCtx, NativeObject, e.NativeObject); + return new Handle(this, Native.Z3_optimize_maximize(Context.nCtx, NativeObject, e.NativeObject)); } /// /// Declare an arithmetical minimization objective. /// Similar to MkMaximize. /// - public uint MkMinimize(ArithExpr e) + public Handle MkMinimize(ArithExpr e) { - return Native.Z3_optimize_minimize(Context.nCtx, NativeObject, e.NativeObject); + return new Handle(this, Native.Z3_optimize_minimize(Context.nCtx, NativeObject, e.NativeObject)); } /// /// Retrieve a lower bound for the objective handle. /// - public ArithExpr GetLower(uint index) + private ArithExpr GetLower(uint index) { return (ArithExpr)Expr.Create(Context, Native.Z3_optimize_get_lower(Context.nCtx, NativeObject, index)); } @@ -189,7 +227,7 @@ namespace Microsoft.Z3 /// /// Retrieve an upper bound for the objective handle. /// - public ArithExpr GetUpper(uint index) + private ArithExpr GetUpper(uint index) { return (ArithExpr)Expr.Create(Context, Native.Z3_optimize_get_upper(Context.nCtx, NativeObject, index)); } From b050ac7c7c3a7814d2eed8a16716ad87ab6e23b1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 13 Oct 2014 19:11:20 -0700 Subject: [PATCH 651/925] using properties Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Optimize.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/api/dotnet/Optimize.cs b/src/api/dotnet/Optimize.cs index eb8281e5f..ed7d1d60a 100644 --- a/src/api/dotnet/Optimize.cs +++ b/src/api/dotnet/Optimize.cs @@ -101,25 +101,25 @@ namespace Microsoft.Z3 /// /// Retrieve a lower bound for the objective handle. /// - public ArithExpr Lower() + public ArithExpr Lower { - return opt.GetLower(handle); + get { return opt.GetLower(handle); } } /// /// Retrieve an upper bound for the objective handle. /// - public ArithExpr Upper() + public ArithExpr Upper { - return opt.GetUpper(handle); + get { return opt.GetUpper(handle); } } /// /// Retrieve the value of an objective. /// - public ArithExpr Value() + public ArithExpr Value { - return Lower(); + get { return Lower; } } } From 2c1c9321855bffa95da81897261b4f4813bdec2a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 14 Oct 2014 13:09:02 -0700 Subject: [PATCH 652/925] deal with compiler warning on unused field Signed-off-by: Nikolaj Bjorner --- src/muz/pdr/pdr_context.cpp | 2 +- src/muz/pdr/pdr_context.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index ea8eca6f4..042806d44 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -1286,7 +1286,7 @@ namespace pdr { m_pm(m_fparams, params.pdr_max_num_contexts(), m), m_query_pred(m), m_query(0), - m_search(m_params.pdr_bfs_model_search(), m), + m_search(m_params.pdr_bfs_model_search()), m_last_result(l_undef), m_inductive_lvl(0), m_expanded_lvl(0), diff --git a/src/muz/pdr/pdr_context.h b/src/muz/pdr/pdr_context.h index ddfe85484..2c83d216d 100644 --- a/src/muz/pdr/pdr_context.h +++ b/src/muz/pdr/pdr_context.h @@ -246,7 +246,6 @@ namespace pdr { class model_search { typedef ptr_vector model_nodes; - ast_manager& m; bool m_bfs; model_node* m_root; std::deque m_leaves; @@ -258,7 +257,7 @@ namespace pdr { void enqueue_leaf(model_node& n); // add leaf to priority queue. void update_models(); public: - model_search(bool bfs, ast_manager& m): m(m), m_bfs(bfs), m_root(0) {} + model_search(bool bfs): m_bfs(bfs), m_root(0) {} ~model_search(); void reset(); From 69a5634e7ed155387211dc87fa02f8272aff7619 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 14 Oct 2014 16:33:55 -0700 Subject: [PATCH 653/925] adding symba designated strategy (back?) to optsmt Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 11 ++++++ src/opt/opt_context.h | 1 + src/opt/opt_params.pyg | 2 +- src/opt/optsmt.cpp | 82 +++++++++++++++++++++++++++++++++++------ src/opt/optsmt.h | 4 +- src/smt/smt_setup.cpp | 7 +++- 6 files changed, 92 insertions(+), 15 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 09d3a809a..64978b39e 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -435,6 +435,7 @@ namespace opt { } void context::init_solver() { + setup_arith_solver(); #pragma omp critical (opt_context) { m_opt_solver = alloc(opt_solver, m, m_params, m_fm); @@ -443,6 +444,16 @@ namespace opt { } } + void context::setup_arith_solver() { + opt_params p(m_params); + if (p.optsmt_engine() == symbol("symba") || + p.optsmt_engine() == symbol("farkas")) { + std::stringstream strm; + strm << AS_OPTINF; + gparams::set("smt.arith.solver", strm.str().c_str()); + } + } + void context::update_solver() { if (!m_enable_sat || !probe_bv()) { return; diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index eb8dd6fc6..0a342e058 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -224,6 +224,7 @@ namespace opt { void init_solver(); void update_solver(); + void setup_arith_solver(); void add_maxsmt(symbol const& id); void set_simplify(tactic *simplify); void set_pareto(pareto_base* p); diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index 9d20dcb33..f84c6eebf 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -2,7 +2,7 @@ def_module_params('opt', description='optimization parameters', export=True, params=(('timeout', UINT, UINT_MAX, 'set timeout'), - ('engine', SYMBOL, 'basic', "select optimization engine: 'basic', 'farkas', 'symba'"), + ('optsmt_engine', SYMBOL, 'basic', "select optimization engine: 'basic', 'farkas', 'symba'"), ('maxsat_engine', SYMBOL, 'wmax', "select engine for maxsat: 'fu_malik', 'core_maxsat', 'wmax', 'pbmax', 'maxres', 'bcd2', 'wpm2', 'sls', 'maxhs'"), ('priority', SYMBOL, 'lex', "select how to priortize objectives: 'lex' (lexicographic), 'pareto', or 'box'"), ('dump_benchmarks', BOOL, False, 'dump benchmarks for profiling'), diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 6cc6eeeab..0d82e4410 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -107,6 +107,62 @@ namespace opt { return l_true; } + lbool optsmt::symba_opt() { + smt::theory_opt& opt = m_s->get_optimizer(); + + if (typeid(smt::theory_inf_arith) != typeid(opt)) { + return l_undef; + } + + + expr_ref_vector ors(m), disj(m); + expr_ref or(m), bound(m.mk_true(), m); + for (unsigned i = 0; i < m_upper.size(); ++i) { + ors.push_back(m_s->mk_ge(i, m_upper[i])); + } + { + solver::scoped_push _push(*m_s); + or = m.mk_or(ors.size(), ors.c_ptr()); + m_s->assert_expr(or); + lbool is_sat = l_true; + while (!m_cancel) { + is_sat = m_s->check_sat(0,0); + if (is_sat == l_true) { + disj.reset(); + m_s->maximize_objectives(disj); + m_s->get_model(m_model); + set_max(m_lower, m_s->get_objective_values()); + for (unsigned i = 0; i < ors.size(); ++i) { + expr_ref tmp(m); + m_model->eval(ors[i].get(), tmp); + if (m.is_true(tmp)) { + m_lower[i] = m_upper[i]; + ors[i] = m.mk_false(); + } + if (m.is_false(ors[i].get())) { + disj[i] = m.mk_false(); + } + } + or = m.mk_or(ors.size(), ors.c_ptr()); + bound = m.mk_or(disj.size(), disj.c_ptr()); + m_s->assert_expr(or); + } + else if (is_sat == l_undef) { + return l_undef; + } + else { + break; + } + } + } + m_s->assert_expr(bound); + + if (m_cancel) { + return l_undef; + } + return basic_opt(); + } + void optsmt::update_lower(unsigned idx, inf_eps const& v, bool override) { if (m_lower[idx] < v || override) { m_lower[idx] = v; @@ -124,13 +180,13 @@ namespace opt { m_s->maximize_objectives(disj); m_s->get_model(m_model); set_max(m_lower, m_s->get_objective_values()); - IF_VERBOSE(1, - for (unsigned i = 0; i < m_lower.size(); ++i) { - verbose_stream() << m_lower[i] << " "; - } - verbose_stream() << "\n"; - model_pp(verbose_stream(), *m_model); - ); + TRACE("opt", + for (unsigned i = 0; i < m_lower.size(); ++i) { + tout << m_lower[i] << " "; + } + tout << "\n"; + model_pp(tout, *m_model); + ); expr_ref constraint(m); constraint = m.mk_or(disj.size(), disj.c_ptr()); m_s->assert_expr(constraint); @@ -171,13 +227,13 @@ namespace opt { lbool is_sat = m_s->check_sat(1, bounds.c_ptr() + i); switch(is_sat) { case l_true: - IF_VERBOSE(2, verbose_stream() << "Setting lower bound for v" << m_vars[i] << " to " << m_upper[i] << "\n";); + IF_VERBOSE(2, verbose_stream() << "(optsmt lower bound for v" << m_vars[i] << " := " << m_upper[i] << ")\n";); m_lower[i] = mid[i]; th.enable_record_conflict(0); update_lower(); break; case l_false: - IF_VERBOSE(2, verbose_stream() << "conflict: " << th.conflict_minimize() << "\n";); + IF_VERBOSE(2, verbose_stream() << "(optsmt conflict: " << th.conflict_minimize() << ") \n";); if (!th.conflict_minimize().is_finite()) { // bounds is not in the core. The context is unsat. m_upper[i] = m_lower[i]; @@ -288,13 +344,15 @@ namespace opt { } // assertions added during search are temporary. solver::scoped_push _push(*m_s); - if (m_engine == symbol("farkas")) { + if (m_optsmt_engine == symbol("farkas")) { is_sat = farkas_opt(); } + else if (m_optsmt_engine == symbol("symba")) { + is_sat = symba_opt(); + } else { is_sat = basic_opt(); } - return is_sat; } @@ -337,7 +395,7 @@ namespace opt { void optsmt::updt_params(params_ref& p) { opt_params _p(p); - m_engine = _p.engine(); + m_optsmt_engine = _p.optsmt_engine(); } void optsmt::reset() { diff --git a/src/opt/optsmt.h b/src/opt/optsmt.h index 95e24a439..35e2a3d46 100644 --- a/src/opt/optsmt.h +++ b/src/opt/optsmt.h @@ -35,7 +35,7 @@ namespace opt { vector m_upper; app_ref_vector m_objs; svector m_vars; - symbol m_engine; + symbol m_optsmt_engine; model_ref m_model; public: optsmt(ast_manager& m): m(m), m_s(0), m_cancel(false), m_objs(m) {} @@ -67,6 +67,8 @@ namespace opt { lbool basic_opt(); + lbool symba_opt(); + lbool basic_lex(unsigned idx, bool is_maximize); lbool farkas_opt(); diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 092db9f1a..5eac22853 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -703,7 +703,12 @@ namespace smt { } void setup::setup_mi_arith() { - m_context.register_plugin(alloc(smt::theory_mi_arith, m_manager, m_params)); + if (m_params.m_arith_mode == AS_OPTINF) { + m_context.register_plugin(alloc(smt::theory_inf_arith, m_manager, m_params)); + } + else { + m_context.register_plugin(alloc(smt::theory_mi_arith, m_manager, m_params)); + } } void setup::setup_arith() { From ff69ee049b5f210633bd3938a34d6e8704028966 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 14 Oct 2014 16:45:54 -0700 Subject: [PATCH 654/925] fix non-termination Signed-off-by: Nikolaj Bjorner --- src/opt/optsmt.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 0d82e4410..37c7673df 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -187,6 +187,17 @@ namespace opt { tout << "\n"; model_pp(tout, *m_model); ); + IF_VERBOSE(2, verbose_stream() << "(optsmt.lower "; + for (unsigned i = 0; i < m_lower.size(); ++i) { + verbose_stream() << m_lower[i] << " "; + } + verbose_stream() << ")\n";); + for (unsigned i = 0; i < m_lower.size(); ++i) { + if (m_lower[i].is_pos() && !m_lower[i].is_finite()) { + disj[i] = m.mk_false(); + } + } + expr_ref constraint(m); constraint = m.mk_or(disj.size(), disj.c_ptr()); m_s->assert_expr(constraint); From 630a3d6ea8f945154d42b70fae2cbe14f76cd35a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 15 Oct 2014 15:11:31 -0700 Subject: [PATCH 655/925] integrate bounds from original model Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 9 ++++----- src/opt/optsmt.cpp | 16 ++++++---------- src/opt/optsmt.h | 4 ++-- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 64978b39e..e61289f02 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -843,7 +843,6 @@ namespace opt { void context::update_bound(bool is_lower) { expr_ref val(m); if (!m_model.get()) return; - bool override = true; for (unsigned i = 0; i < m_objectives.size(); ++i) { objective const& obj = m_objectives[i]; rational r; @@ -852,10 +851,10 @@ namespace opt { if (m_model->eval(obj.m_term, val) && is_numeral(val, r)) { inf_eps val = inf_eps(obj.m_adjust_value(r)); if (is_lower) { - m_optsmt.update_lower(obj.m_index, val, override); + m_optsmt.update_lower(obj.m_index, val); } else { - m_optsmt.update_upper(obj.m_index, val, override); + m_optsmt.update_upper(obj.m_index, val); } } break; @@ -863,10 +862,10 @@ namespace opt { if (m_model->eval(obj.m_term, val) && is_numeral(val, r)) { inf_eps val = inf_eps(obj.m_adjust_value(r)); if (is_lower) { - m_optsmt.update_lower(obj.m_index, val, override); + m_optsmt.update_lower(obj.m_index, val); } else { - m_optsmt.update_upper(obj.m_index, val, override); + m_optsmt.update_upper(obj.m_index, val); } } break; diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 90f410cf5..615acc61d 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -48,7 +48,7 @@ namespace opt { void optsmt::set_max(vector& dst, vector const& src, expr_ref_vector& fmls) { for (unsigned i = 0; i < src.size(); ++i) { - if (src[i] > dst[i]) { + if (src[i] >= dst[i]) { dst[i] = src[i]; m_lower_fmls[i] = fmls[i].get(); if (dst[i].is_pos() && !dst[i].is_finite()) { // review: likely done already. @@ -60,7 +60,6 @@ namespace opt { fmls[i] = m_lower_fmls[i].get(); } } - std::cout << "\n"; } /* @@ -170,16 +169,13 @@ namespace opt { return basic_opt(); } - void optsmt::update_lower(unsigned idx, inf_eps const& v, bool override) { - if (m_lower[idx] < v || override) { - m_lower[idx] = v; - } + void optsmt::update_lower(unsigned idx, inf_eps const& v) { + m_lower_fmls[idx] = m_s->mk_ge(idx, v); + m_lower[idx] = v; } - void optsmt::update_upper(unsigned idx, inf_eps const& v, bool override) { - if (m_upper[idx] > v || override) { - m_upper[idx] = v; - } + void optsmt::update_upper(unsigned idx, inf_eps const& v) { + m_upper[idx] = v; } void optsmt::update_lower() { diff --git a/src/opt/optsmt.h b/src/opt/optsmt.h index 4f982f695..7b8238992 100644 --- a/src/opt/optsmt.h +++ b/src/opt/optsmt.h @@ -60,8 +60,8 @@ namespace opt { inf_eps get_upper(unsigned index) const; void get_model(model_ref& mdl); - void update_lower(unsigned idx, inf_eps const& r, bool override); - void update_upper(unsigned idx, inf_eps const& r, bool override); + void update_lower(unsigned idx, inf_eps const& r); + void update_upper(unsigned idx, inf_eps const& r); void reset(); From 9d75babcda0570431442b350e573bfc2d3677bac Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 15 Oct 2014 21:33:29 -0700 Subject: [PATCH 656/925] add more information to error messages Signed-off-by: Nikolaj Bjorner --- src/api/api_config_params.cpp | 12 +++--------- src/cmd_context/context_params.cpp | 8 +++++++- src/smt/theory_arith_core.h | 6 ++++++ src/util/gparams.cpp | 21 +++++++++++++++------ 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/api/api_config_params.cpp b/src/api/api_config_params.cpp index 48c2df4a9..3875c0c9f 100644 --- a/src/api/api_config_params.cpp +++ b/src/api/api_config_params.cpp @@ -37,9 +37,7 @@ extern "C" { catch (z3_exception & ex) { // The error handler is only available for contexts // Just throw a warning. - std::ostringstream buffer; - buffer << "Error setting " << param_id << ", " << ex.msg(); - warning_msg(buffer.str().c_str()); + warning_msg(ex.msg()); } } @@ -64,9 +62,7 @@ extern "C" { catch (z3_exception & ex) { // The error handler is only available for contexts // Just throw a warning. - std::ostringstream buffer; - buffer << "Error setting " << param_id << ": " << ex.msg(); - warning_msg(buffer.str().c_str()); + warning_msg(ex.msg()); return Z3_FALSE; } } @@ -92,9 +88,7 @@ extern "C" { catch (z3_exception & ex) { // The error handler is only available for contexts // Just throw a warning. - std::ostringstream buffer; - buffer << "Error setting " << param_id << ": " << ex.msg(); - warning_msg(buffer.str().c_str()); + warning_msg(ex.msg()); } } diff --git a/src/cmd_context/context_params.cpp b/src/cmd_context/context_params.cpp index d796dc9b1..d1184fbc8 100644 --- a/src/cmd_context/context_params.cpp +++ b/src/cmd_context/context_params.cpp @@ -86,7 +86,13 @@ void context_params::set(char const * param, char const * value) { set_bool(m_smtlib2_compliant, param, value); } else { - throw default_exception("unknown parameter '%s'", p.c_str()); + param_descrs d; + collect_param_descrs(d); + std::stringstream strm; + strm << "unknown parameter '" << p << "'\n"; + strm << "Legal parameters are:\n"; + d.display(strm, 2, false, false); + throw default_exception(strm.str()); } } diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 89ce99524..aeb70752b 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -3225,11 +3225,13 @@ namespace smt { case QUASI_BASE: SASSERT(m_columns[v].size() == 1); del_row(get_var_row(v)); + TRACE("arith_make_feasible", tout << "del row v" << v << "\n";); break; case BASE: SASSERT(lazy_pivoting_lvl() != 0 || m_columns[v].size() == 1); if (lazy_pivoting_lvl() > 0) eliminate(v, false); + TRACE("arith_make_feasible", tout << "del row v" << v << "\n";); del_row(get_var_row(v)); break; case NON_BASE: { @@ -3241,6 +3243,10 @@ namespace smt { pivot(r.get_base_var(), v, r[entry->m_row_idx].m_coeff, false); SASSERT(is_base(v)); del_row(get_var_row(v)); + TRACE("arith_make_feasible", tout << "del row v" << v << "\n";); + } + else { + TRACE("arith_make_feasible", tout << "no row v" << v << "\n";); } break; } } diff --git a/src/util/gparams.cpp b/src/util/gparams.cpp index 1d9426390..04acf1ad9 100644 --- a/src/util/gparams.cpp +++ b/src/util/gparams.cpp @@ -201,7 +201,7 @@ public: } } - void throw_unknown_parameter(symbol const & param_name, symbol const & mod_name) { + void throw_unknown_parameter(symbol const & param_name, param_descrs const& d, symbol const & mod_name) { if (mod_name == symbol::null) { char const * new_name = get_new_param_name(param_name); if (new_name) { @@ -213,11 +213,20 @@ public: param_name.bare_str()); } else { - throw exception("unknown parameter '%s'", param_name.bare_str()); + std::stringstream strm; + strm << "unknown parameter '" << param_name << "'\n"; + strm << "Legal parameters are:\n"; + d.display(strm, 2, false, false); + throw default_exception(strm.str()); } } else { - throw exception("unknown parameter '%s' at module '%s'", param_name.bare_str(), mod_name.bare_str()); + std::stringstream strm; + strm << "unknown parameter '" << param_name << "' "; + strm << "at module '" << mod_name << "'\n"; + strm << "Legal parameters are:\n"; + d.display(strm, 2, false, false); + throw default_exception(strm.str()); } } @@ -225,7 +234,7 @@ public: param_kind k = d.get_kind(param_name); params_ref & ps = get_params(mod_name); if (k == CPK_INVALID) { - throw_unknown_parameter(param_name, mod_name); + throw_unknown_parameter(param_name, d, mod_name); } else if (k == CPK_UINT) { long val = strtol(value, 0, 10); @@ -312,7 +321,7 @@ public: std::string get_default(param_descrs const & d, symbol const & p, symbol const & m) { if (!d.contains(p)) { - throw_unknown_parameter(p, m); + throw_unknown_parameter(p, d, m); } char const * r = d.get_default(p); if (r == 0) @@ -478,7 +487,7 @@ public: throw exception("unknown module '%s'", m.bare_str()); } if (!d->contains(p)) - throw_unknown_parameter(p, m); + throw_unknown_parameter(p, *d, m); out << " name: " << p << "\n"; if (m != symbol::null) { out << " module: " << m << "\n"; From 301f441801a3c01bb41029a64c093610bbc88dea Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 22 Oct 2014 09:02:08 -0700 Subject: [PATCH 657/925] bypass simplifier if (m_is_clausal) { Signed-off-by: Nikolaj Bjorner --- src/api/api_solver.cpp | 2 +- src/opt/inc_sat_solver.cpp | 4 ++-- src/opt/maxres.cpp | 22 ++++++++++++++------- src/opt/opt_context.cpp | 5 +++++ src/opt/opt_context.h | 2 ++ src/opt/opt_solver.cpp | 8 -------- src/sat/sat_mus.cpp | 10 ++++++---- src/shell/opt_frontend.cpp | 4 +++- src/tactic/core/propagate_values_tactic.cpp | 4 ++++ src/util/gparams.cpp | 1 + 10 files changed, 39 insertions(+), 23 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index b9b3d8166..e57050e82 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -149,7 +149,7 @@ extern "C" { to_param_ref(p).validate(r); to_solver_ref(s)->updt_params(to_param_ref(p)); } - to_solver(s)->m_params = to_param_ref(p); + to_solver(s)->m_params.append(to_param_ref(p)); Z3_CATCH; } diff --git a/src/opt/inc_sat_solver.cpp b/src/opt/inc_sat_solver.cpp index 1c450bbef..1a3fc7ff5 100644 --- a/src/opt/inc_sat_solver.cpp +++ b/src/opt/inc_sat_solver.cpp @@ -81,8 +81,8 @@ public: simp2_p.set_bool("hoist_mul", false); // required by som m_preprocess = and_then(mk_card2bv_tactic(m, m_params), - mk_simplify_tactic(m), - mk_propagate_values_tactic(m), + //mk_simplify_tactic(m), + //mk_propagate_values_tactic(m), using_params(mk_simplify_tactic(m), simp2_p), mk_max_bv_sharing_tactic(m), mk_bit_blaster_tactic(m), diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index d0694222a..209601c78 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -88,6 +88,7 @@ private: rational m_max_upper; bool m_found_feasible_optimum; bool m_hill_climb; // prefer large weight soft clauses for cores + unsigned m_last_index; // last index used during hill-climbing bool m_add_upper_bound_block; // restrict upper bound with constraint unsigned m_max_num_cores; // max number of cores per round. unsigned m_max_core_size; // max core size per round. @@ -110,6 +111,7 @@ public: m_st(st), m_found_feasible_optimum(false), m_hill_climb(true), + m_last_index(0), m_add_upper_bound_block(false), m_max_num_cores(UINT_MAX), m_max_core_size(3), @@ -352,16 +354,21 @@ public: /** Give preference to cores that have large minmal values. */ - sort_assumptions(asms); - unsigned index = 0; - unsigned last_index = 0; + sort_assumptions(asms); + + m_last_index = std::min(m_last_index, asms.size()-1); + m_last_index = 0; + unsigned index = m_last_index>0?m_last_index-1:0; + m_last_index = 0; + bool first = index > 0; + SASSERT(index < asms.size() || asms.empty()); while (index < asms.size() && is_sat == l_true) { - while (asms.size() > 20*(index - last_index) && index < asms.size()) { + while (!first && asms.size() > 20*(index - m_last_index) && index < asms.size()) { index = next_index(asms, index); - //break; } - IF_VERBOSE(3, verbose_stream() << "weight: " << get_weight(asms[0].get()) << " " << get_weight(asms[index-1].get()) << "\n";); - last_index = index; + first = false; + IF_VERBOSE(3, verbose_stream() << "weight: " << get_weight(asms[0].get()) << " " << get_weight(asms[index-1].get()) << " num soft: " << index << "\n";); + m_last_index = index; is_sat = s().check_sat(index, asms.c_ptr()); } } @@ -880,6 +887,7 @@ public: } m_max_upper = m_upper; m_found_feasible_optimum = false; + m_last_index = 0; add_upper_bound_block(); } diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index e61289f02..d41277df9 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -123,6 +123,7 @@ namespace opt { m_objective_refs(m), m_enable_sat(false), m_enable_sls(false), + m_is_clausal(false), m_pp_neat(false) { params_ref p; @@ -553,6 +554,10 @@ namespace opt { } void context::simplify_fmls(expr_ref_vector& fmls) { + if (m_is_clausal) { + return; + } + goal_ref g(alloc(goal, m, true, false)); for (unsigned i = 0; i < fmls.size(); ++i) { g->assert_expr(fmls[i].get()); diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 0a342e058..5618efe7b 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -126,6 +126,7 @@ namespace opt { tactic_ref m_simplify; bool m_enable_sat; bool m_enable_sls; + bool m_is_clausal; bool m_pp_neat; symbol m_maxsat_engine; symbol m_logic; @@ -155,6 +156,7 @@ namespace opt { virtual void display_assignment(std::ostream& out); virtual bool is_pareto() { return m_pareto.get() != 0; } virtual void set_logic(symbol const& s) { m_logic = s; } + void set_clausal(bool f) { m_is_clausal = f; } void display(std::ostream& out); static void collect_param_descrs(param_descrs & r); diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 8b23a4e8a..d1136a636 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -161,17 +161,9 @@ namespace opt { void opt_solver::maximize_objectives(expr_ref_vector& blockers) { expr_ref blocker(m); - vector values; - for (unsigned i = 0; i < m_objective_vars.size(); ++i) { - values.push_back(current_objective_value(i)); - } for (unsigned i = 0; i < m_objective_vars.size(); ++i) { maximize_objective(i, blocker); blockers.push_back(blocker); - if (values[i] > m_objective_values[i]) { - std::cout << "local optimization produced a worse result\n"; - exit(0); - } } } diff --git a/src/sat/sat_mus.cpp b/src/sat/sat_mus.cpp index c66f8ef6f..65d776d84 100644 --- a/src/sat/sat_mus.cpp +++ b/src/sat/sat_mus.cpp @@ -90,15 +90,17 @@ namespace sat { break; } unsigned num_literals = core.size() + mus.size(); + if (num_literals <= 2) { + // IF_VERBOSE(0, verbose_stream() << "num literals: " << core << " " << mus << "\n";); + break; + } literal lit = core.back(); core.pop_back(); lbool is_sat; { scoped_append _sa(mus, core); - if (true || core_miss < 2) { - mus.push_back(~lit); // TBD: measure - } + mus.push_back(~lit); is_sat = s.check(mus.size(), mus.c_ptr()); TRACE("sat", tout << "mus: " << mus << "\n";); } @@ -146,7 +148,7 @@ namespace sat { } TRACE("sat", tout << "new core: " << mus << "\n";); set_core(); - IF_VERBOSE(2, verbose_stream() << "(sat.mus.new " << core << ")\n";); + IF_VERBOSE(2, verbose_stream() << "(sat.mus.new " << s.m_core << ")\n";); return l_true; } diff --git a/src/shell/opt_frontend.cpp b/src/shell/opt_frontend.cpp index 6f8143ff1..616fc1962 100644 --- a/src/shell/opt_frontend.cpp +++ b/src/shell/opt_frontend.cpp @@ -118,7 +118,9 @@ class wcnf { public: - wcnf(opt::context& opt, stream_buffer& in): opt(opt), m(opt.get_manager()), in(in) {} + wcnf(opt::context& opt, stream_buffer& in): opt(opt), m(opt.get_manager()), in(in) { + opt.set_clausal(true); + } void parse() { int num_vars = 0, num_clauses = 0, max_weight = 0; diff --git a/src/tactic/core/propagate_values_tactic.cpp b/src/tactic/core/propagate_values_tactic.cpp index 5873efd61..39df3b174 100644 --- a/src/tactic/core/propagate_values_tactic.cpp +++ b/src/tactic/core/propagate_values_tactic.cpp @@ -135,6 +135,7 @@ class propagate_values_tactic : public tactic { TRACE("shallow_context_simplifier_bug", tout << mk_ismt2_pp(curr, m()) << "\n---->\n" << mk_ismt2_pp(new_curr, m()) << "\n";); push_result(new_curr, new_pr); + if (new_curr != curr) m_modified = true; } @@ -160,6 +161,9 @@ class propagate_values_tactic : public tactic { if (m_goal->inconsistent()) goto end; + if (m_max_rounds == 0) + goto end; + m_subst = alloc(expr_substitution, m(), g->unsat_core_enabled(), g->proofs_enabled()); m_r.set_substitution(m_subst.get()); m_occs(*m_goal); diff --git a/src/util/gparams.cpp b/src/util/gparams.cpp index 04acf1ad9..197f65c10 100644 --- a/src/util/gparams.cpp +++ b/src/util/gparams.cpp @@ -230,6 +230,7 @@ public: } } + void set(param_descrs const & d, symbol const & param_name, char const * value, symbol const & mod_name) { param_kind k = d.get_kind(param_name); params_ref & ps = get_params(mod_name); From cee7dd39444c9060186df79c2a2c7f8845de415b Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 24 Oct 2014 23:52:40 +0100 Subject: [PATCH 658/925] fixed newline characters Signed-off-by: Christoph M. Wintersteiger --- examples/python/hamiltonian/hamiltonian.py | 176 ++++++++++----------- 1 file changed, 88 insertions(+), 88 deletions(-) diff --git a/examples/python/hamiltonian/hamiltonian.py b/examples/python/hamiltonian/hamiltonian.py index 32c911379..fc158b939 100644 --- a/examples/python/hamiltonian/hamiltonian.py +++ b/examples/python/hamiltonian/hamiltonian.py @@ -1,88 +1,88 @@ -############################################ -# Copyright (c) 2012 Ganesh Gopalakrishnan ganesh@cs.utah.edu -# -# Check if the given graph has a Hamiltonian cycle. -# -# Author: Ganesh Gopalakrishnan ganesh@cs.utah.edu -############################################ -from z3 import * - -def gencon(gr): - """ - Input a graph as an adjacency list, e.g. {0:[1,2], 1:[2], 2:[1,0]}. - Produces solver to check if the given graph has - a Hamiltonian cycle. Query the solver using s.check() and if sat, - then s.model() spells out the cycle. Two example graphs from - http://en.wikipedia.org/wiki/Hamiltonian_path are tested. - - ======================================================= - - Explanation: - - Generate a list of Int vars. Constrain the first Int var ("Node 0") to be 0. - Pick a node i, and attempt to number all nodes reachable from i to have a - number one higher (mod L) than assigned to node i (use an Or constraint). - - ======================================================= - """ - L = len(gr) - cv = [Int('cv%s'%i) for i in range(L)] - s = Solver() - s.add(cv[0]==0) - for i in range(L): - s.add(Or([cv[j]==(cv[i]+1)%L for j in gr[i]])) - return s - -def examples(): - # Example Graphs: The Dodecahedral graph from http://en.wikipedia.org/wiki/Hamiltonian_path - grdodec = { 0: [1, 4, 5], - 1: [0, 7, 2], - 2: [1, 9, 3], - 3: [2, 11, 4], - 4: [3, 13, 0], - 5: [0, 14, 6], - 6: [5, 16, 7], - 7: [6, 8, 1], - 8: [7, 17, 9], - 9: [8, 10, 2], - 10: [9, 18, 11], - 11: [10, 3, 12], - 12: [11, 19, 13], - 13: [12, 14, 4], - 14: [13, 15, 5], - 15: [14, 16, 19], - 16: [6, 17, 15], - 17: [16, 8, 18], - 18: [10, 19, 17], - 19: [18, 12, 15] } - import pprint - pp = pprint.PrettyPrinter(indent=4) - pp.pprint(grdodec) - - sdodec=gencon(grdodec) - print(sdodec.check()) - print(sdodec.model()) - # ======================================================= - # See http://en.wikipedia.org/wiki/Hamiltonian_path for the Herschel graph - # being the smallest possible polyhdral graph that does not have a Hamiltonian - # cycle. - # - grherschel = { 0: [1, 9, 10, 7], - 1: [0, 8, 2], - 2: [1, 9, 3], - 3: [2, 8, 4], - 4: [3, 9, 10, 5], - 5: [4, 8, 6], - 6: [5, 10, 7], - 7: [6, 8, 0], - 8: [1, 3, 5, 7], - 9: [2, 0, 4], - 10: [6, 4, 0] } - pp.pprint(grherschel) - sherschel=gencon(grherschel) - print(sherschel.check()) - # ======================================================= - -if __name__ == "__main__": - examples() - +############################################ +# Copyright (c) 2012 Ganesh Gopalakrishnan ganesh@cs.utah.edu +# +# Check if the given graph has a Hamiltonian cycle. +# +# Author: Ganesh Gopalakrishnan ganesh@cs.utah.edu +############################################ +from z3 import * + +def gencon(gr): + """ + Input a graph as an adjacency list, e.g. {0:[1,2], 1:[2], 2:[1,0]}. + Produces solver to check if the given graph has + a Hamiltonian cycle. Query the solver using s.check() and if sat, + then s.model() spells out the cycle. Two example graphs from + http://en.wikipedia.org/wiki/Hamiltonian_path are tested. + + ======================================================= + + Explanation: + + Generate a list of Int vars. Constrain the first Int var ("Node 0") to be 0. + Pick a node i, and attempt to number all nodes reachable from i to have a + number one higher (mod L) than assigned to node i (use an Or constraint). + + ======================================================= + """ + L = len(gr) + cv = [Int('cv%s'%i) for i in range(L)] + s = Solver() + s.add(cv[0]==0) + for i in range(L): + s.add(Or([cv[j]==(cv[i]+1)%L for j in gr[i]])) + return s + +def examples(): + # Example Graphs: The Dodecahedral graph from http://en.wikipedia.org/wiki/Hamiltonian_path + grdodec = { 0: [1, 4, 5], + 1: [0, 7, 2], + 2: [1, 9, 3], + 3: [2, 11, 4], + 4: [3, 13, 0], + 5: [0, 14, 6], + 6: [5, 16, 7], + 7: [6, 8, 1], + 8: [7, 17, 9], + 9: [8, 10, 2], + 10: [9, 18, 11], + 11: [10, 3, 12], + 12: [11, 19, 13], + 13: [12, 14, 4], + 14: [13, 15, 5], + 15: [14, 16, 19], + 16: [6, 17, 15], + 17: [16, 8, 18], + 18: [10, 19, 17], + 19: [18, 12, 15] } + import pprint + pp = pprint.PrettyPrinter(indent=4) + pp.pprint(grdodec) + + sdodec=gencon(grdodec) + print(sdodec.check()) + print(sdodec.model()) + # ======================================================= + # See http://en.wikipedia.org/wiki/Hamiltonian_path for the Herschel graph + # being the smallest possible polyhdral graph that does not have a Hamiltonian + # cycle. + # + grherschel = { 0: [1, 9, 10, 7], + 1: [0, 8, 2], + 2: [1, 9, 3], + 3: [2, 8, 4], + 4: [3, 9, 10, 5], + 5: [4, 8, 6], + 6: [5, 10, 7], + 7: [6, 8, 0], + 8: [1, 3, 5, 7], + 9: [2, 0, 4], + 10: [6, 4, 0] } + pp.pprint(grherschel) + sherschel=gencon(grherschel) + print(sherschel.check()) + # ======================================================= + +if __name__ == "__main__": + examples() + From 444879db5fc5690b3f78a76471246d4aa6ec12eb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 5 Nov 2014 13:51:27 +0100 Subject: [PATCH 659/925] fix bug reported on stackoverflow on crash for unconstrained variables Signed-off-by: Nikolaj Bjorner --- src/opt/opt_solver.cpp | 7 ++++++- src/smt/theory_arith_core.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index d1136a636..015ca1273 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -87,8 +87,13 @@ namespace opt { smt::theory_opt& opt_solver::get_optimizer() { smt::context& ctx = m_context.get_context(); smt::theory_id arith_id = m_context.m().get_family_id("arith"); - smt::theory* arith_theory = ctx.get_theory(arith_id); + smt::theory* arith_theory = ctx.get_theory(arith_id); + if (!arith_theory) { + ctx.register_plugin(alloc(smt::theory_mi_arith, m, m_params)); + arith_theory = ctx.get_theory(arith_id); + SASSERT(arith_theory); + } if (typeid(smt::theory_mi_arith) == typeid(*arith_theory)) { return dynamic_cast(*arith_theory); } diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index aeb70752b..a97c82369 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -870,6 +870,7 @@ namespace smt { atom_kind kind2 = a2->get_atom_kind(); bool v_is_int = is_int(v); SASSERT(v == a2->get_var()); + if (k1 == k2 && kind1 == kind2) return; SASSERT(k1 != k2 || kind1 != kind2); parameter coeffs[3] = { parameter(symbol("farkas")), parameter(rational(1)), parameter(rational(1)) }; From f71fd2afb5924d28d1d383f979bc052d35056205 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 24 Nov 2014 16:17:22 -0800 Subject: [PATCH 660/925] disable unconstrained elimination pre-processing Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index d41277df9..b85a4f21e 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -218,6 +218,7 @@ namespace opt { } IF_VERBOSE(1, verbose_stream() << "(optimize:sat)\n";); s.get_model(m_model); + TRACE("opt", model_smt2_pp(tout, m, *m_model, 0);); m_optsmt.setup(*m_opt_solver.get()); update_lower(); switch (m_objectives.size()) { @@ -566,7 +567,7 @@ namespace opt { and_then(mk_simplify_tactic(m), mk_propagate_values_tactic(m), mk_solve_eqs_tactic(m), - mk_elim_uncnstr_tactic(m), + // NB: mk_elim_uncstr_tactic(m) is not sound with soft constraints mk_simplify_tactic(m)); opt_params optp(m_params); tactic_ref tac2, tac3; From e9baaa090090602301ef4a962ba0316a9fd93a76 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 25 Nov 2014 10:23:41 -0800 Subject: [PATCH 661/925] rename 'or' to 'fml' toe mae gcc happy, reported by Geroge Karpenkov Signed-off-by: Nikolaj Bjorner --- src/opt/optsmt.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 615acc61d..7f940aca8 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -124,14 +124,14 @@ namespace opt { expr_ref_vector ors(m), disj(m); - expr_ref or(m), bound(m.mk_true(), m); + expr_ref fml(m), bound(m.mk_true(), m); for (unsigned i = 0; i < m_upper.size(); ++i) { ors.push_back(m_s->mk_ge(i, m_upper[i])); } { solver::scoped_push _push(*m_s); - or = m.mk_or(ors.size(), ors.c_ptr()); - m_s->assert_expr(or); + fml = m.mk_or(ors.size(), ors.c_ptr()); + m_s->assert_expr(fml); lbool is_sat = l_true; while (!m_cancel) { is_sat = m_s->check_sat(0,0); @@ -149,8 +149,8 @@ namespace opt { } } set_max(m_lower, m_s->get_objective_values(), disj); - or = m.mk_or(ors.size(), ors.c_ptr()); - m_s->assert_expr(or); + fml = m.mk_or(ors.size(), ors.c_ptr()); + m_s->assert_expr(fml); } else if (is_sat == l_undef) { return l_undef; From ae3d16bc50aebf8c1643549f444f486ee6f5f285 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 15 Dec 2014 16:18:09 -0800 Subject: [PATCH 662/925] fix overflow and integrality bugs reported by Phan Signed-off-by: Nikolaj Bjorner --- src/muz/base/rule_properties.cpp | 4 +-- src/muz/base/rule_properties.h | 1 + src/muz/rel/dl_mk_explanations.cpp | 4 +++ src/muz/rel/karr_relation.h | 2 +- src/muz/rel/rel_context.cpp | 2 +- src/smt/theory_arith_aux.h | 42 ++++++++++++++++-------------- 6 files changed, 32 insertions(+), 23 deletions(-) diff --git a/src/muz/base/rule_properties.cpp b/src/muz/base/rule_properties.cpp index 7f019c74e..f5cac29e5 100644 --- a/src/muz/base/rule_properties.cpp +++ b/src/muz/base/rule_properties.cpp @@ -26,7 +26,7 @@ Notes: using namespace datalog; rule_properties::rule_properties(ast_manager & m, rule_manager& rm, context& ctx, i_expr_pred& p): - m(m), rm(rm), m_ctx(ctx), m_is_predicate(p), m_dt(m), m_generate_proof(false) {} + m(m), rm(rm), m_ctx(ctx), m_is_predicate(p), m_dt(m), m_dl(m), m_generate_proof(false) {} rule_properties::~rule_properties() {} @@ -168,7 +168,7 @@ void rule_properties::operator()(app* n) { if (m_is_predicate(n)) { insert(m_interp_pred, m_rule); } - else if (is_uninterp(n)) { + else if (is_uninterp(n) && !m_dl.is_rule_sort(n->get_decl()->get_range())) { m_uninterp_funs.insert(n->get_decl(), m_rule); } else if (m_dt.is_accessor(n)) { diff --git a/src/muz/base/rule_properties.h b/src/muz/base/rule_properties.h index bfff8cbe4..a16f63507 100644 --- a/src/muz/base/rule_properties.h +++ b/src/muz/base/rule_properties.h @@ -32,6 +32,7 @@ namespace datalog { context& m_ctx; i_expr_pred& m_is_predicate; datatype_util m_dt; + dl_decl_util m_dl; bool m_generate_proof; rule* m_rule; obj_map m_quantifiers; diff --git a/src/muz/rel/dl_mk_explanations.cpp b/src/muz/rel/dl_mk_explanations.cpp index 60a10190a..e650b6e6b 100644 --- a/src/muz/rel/dl_mk_explanations.cpp +++ b/src/muz/rel/dl_mk_explanations.cpp @@ -434,6 +434,7 @@ namespace datalog { relation_union_fn * explanation_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src, const relation_base * delta) { + std::cout << "check kind: " << check_kind(tgt) << "\n"; if (!check_kind(tgt) || (delta && !check_kind(*delta))) { return 0; } @@ -854,7 +855,10 @@ namespace datalog { scoped_ptr product_fun = rmgr.mk_join_fn(orig_rel, *m_e_fact_relation, 0, 0, 0); SASSERT(product_fun); scoped_rel aux_extended_rel = (*product_fun)(orig_rel, *m_e_fact_relation); + TRACE("dl", tout << aux_extended_rel << " " << aux_extended_rel->get_plugin().get_name() << "\n"; + tout << e_rel.get_plugin().get_name() << "\n";); scoped_ptr union_fun = rmgr.mk_union_fn(e_rel, *aux_extended_rel); + TRACE("dl", tout << union_fun << "\n";); SASSERT(union_fun); (*union_fun)(e_rel, *aux_extended_rel); } diff --git a/src/muz/rel/karr_relation.h b/src/muz/rel/karr_relation.h index 00a92748a..72448f026 100644 --- a/src/muz/rel/karr_relation.h +++ b/src/muz/rel/karr_relation.h @@ -45,7 +45,7 @@ namespace datalog { {} virtual bool can_handle_signature(const relation_signature & sig) { - return true; + return get_manager().get_context().karr(); } static symbol get_name() { return symbol("karr_relation"); } diff --git a/src/muz/rel/rel_context.cpp b/src/muz/rel/rel_context.cpp index c5c4d6d95..0d07b7c81 100644 --- a/src/muz/rel/rel_context.cpp +++ b/src/muz/rel/rel_context.cpp @@ -115,7 +115,7 @@ namespace datalog { rm.register_plugin(alloc(bound_relation_plugin, rm)); rm.register_plugin(alloc(interval_relation_plugin, rm)); - rm.register_plugin(alloc(karr_relation_plugin, rm)); + if (m_context.karr()) rm.register_plugin(alloc(karr_relation_plugin, rm)); rm.register_plugin(alloc(product_set_plugin, rm)); rm.register_plugin(alloc(udoc_plugin, rm)); rm.register_plugin(alloc(check_relation_plugin, rm)); diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 15d1edee9..30c92feea 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -1377,11 +1377,11 @@ namespace smt { SASSERT(satisfy_bounds()); result = skipped_row?BEST_EFFORT:OPTIMIZED; break; - } + } if (x_i == null_theory_var) { // can increase/decrease x_j as much as we want. - if (inc && upper(x_j)) { + if (inc && upper(x_j) && !skipped_row) { update_value(x_j, upper_bound(x_j) - get_value(x_j)); TRACE("opt", tout << "moved v" << x_j << " to upper bound\n";); SASSERT(valid_row_assignment()); @@ -1389,7 +1389,7 @@ namespace smt { SASSERT(satisfy_integrality()); continue; } - if (!inc && lower(x_j)) { + if (!inc && lower(x_j) && !skipped_row) { update_value(x_j, lower_bound(x_j) - get_value(x_j)); TRACE("opt", tout << "moved v" << x_j << " to lower bound\n";); SASSERT(valid_row_assignment()); @@ -1463,6 +1463,7 @@ namespace smt { template bool theory_arith::move_to_bound(theory_var x_i, bool move_to_lower) { inf_numeral delta, delta_abs; + numeral lc(1); if (move_to_lower) { delta = lower_bound(x_i) - get_value(x_i); @@ -1475,7 +1476,7 @@ namespace smt { TRACE("opt", tout << "Original delta: " << delta << "\n";); - delta_abs = abs(delta); + delta_abs = abs(delta); // // Decrease absolute value of delta according to bounds on rows where x_i is used. // @@ -1483,28 +1484,31 @@ namespace smt { typename svector::iterator it = c.begin_entries(); typename svector::iterator end = c.end_entries(); for (; it != end && delta_abs.is_pos(); ++it) { - if (!it->is_dead()) { - row & r = m_rows[it->m_row_id]; - theory_var s = r.get_base_var(); - if (s != null_theory_var && !is_quasi_base(s)) { - numeral const & coeff = r[it->m_row_idx].m_coeff; - SASSERT(!coeff.is_zero()); - bool inc_s = coeff.is_pos() ? move_to_lower : !move_to_lower; // NSB: review this.. - bound * b = get_bound(s, inc_s); - if (b) { - inf_numeral delta2 = abs((get_value(s) - b->get_value())/coeff); - if (delta2 < delta_abs) { - delta_abs = delta2; - } + if (it->is_dead()) continue; + row & r = m_rows[it->m_row_id]; + theory_var s = r.get_base_var(); + if (s != null_theory_var && !is_quasi_base(s)) { + numeral const & coeff = r[it->m_row_idx].m_coeff; + SASSERT(!coeff.is_zero()); + bool inc_s = coeff.is_pos() ? move_to_lower : !move_to_lower; // NSB: review this.. + bound * b = get_bound(s, inc_s); + if (b) { + inf_numeral delta2 = abs((get_value(s) - b->get_value())/coeff); + if (delta2 < delta_abs) { + delta_abs = delta2; } } + if (is_int(x_i)) { + lc = lcm(lc, denominator(abs(coeff))); + } } } bool truncated = false; if (is_int(x_i)) { - truncated = !delta_abs.is_int(); - delta_abs = floor(delta_abs); + inf_numeral tmp = delta_abs/lc; + truncated = !tmp.is_int(); + delta_abs = lc*floor(tmp); } if (move_to_lower) { From 1d18934ddb2296b9029cb81222d8a9b96ca471de Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 15 Dec 2014 16:19:38 -0800 Subject: [PATCH 663/925] fix overflow and integrality bugs reported by Phan Signed-off-by: Nikolaj Bjorner --- src/muz/rel/dl_mk_explanations.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/muz/rel/dl_mk_explanations.cpp b/src/muz/rel/dl_mk_explanations.cpp index e650b6e6b..55c87f66e 100644 --- a/src/muz/rel/dl_mk_explanations.cpp +++ b/src/muz/rel/dl_mk_explanations.cpp @@ -434,7 +434,6 @@ namespace datalog { relation_union_fn * explanation_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src, const relation_base * delta) { - std::cout << "check kind: " << check_kind(tgt) << "\n"; if (!check_kind(tgt) || (delta && !check_kind(*delta))) { return 0; } From 21ea48bfd85dcb7d2e5c7bd03c87fb6e50ef8797 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 15 Dec 2014 16:27:35 -0800 Subject: [PATCH 664/925] epsilon should have real type, reported by GeorgeKarpenkov, codeplex issue 145 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 03f0f016f..a7f4d29b5 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -995,7 +995,7 @@ namespace opt { args.push_back(m_arith.mk_numeral(r, r.is_int())); } if (!eps.is_zero()) { - expr* ep = m.mk_const(symbol("epsilon"), m_arith.mk_int()); + expr* ep = m.mk_const(symbol("epsilon"), m_arith.mk_real()); if (eps.is_one()) { args.push_back(ep); } From a7c7b70e19a7d7b6b6b09d872161730f36bc6a3c Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 22 Dec 2014 12:49:31 +0000 Subject: [PATCH 665/925] muZ Datalog: be more aggressive when forming join_project --- src/muz/rel/dl_compiler.cpp | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/muz/rel/dl_compiler.cpp b/src/muz/rel/dl_compiler.cpp index c512598a0..648c91e4a 100644 --- a/src/muz/rel/dl_compiler.cpp +++ b/src/muz/rel/dl_compiler.cpp @@ -408,13 +408,14 @@ namespace datalog { void compiler::get_local_indexes_for_projection(app * t, var_counter & globals, unsigned ofs, unsigned_vector & res) { + // TODO: this can be optimized to avoid renames in some cases unsigned n = t->get_num_args(); for(unsigned i = 0; iget_arg(i); - if(!is_var(e) || globals.get(to_var(e)->get_idx())!=0) { - continue; + if (is_var(e) && globals.get(to_var(e)->get_idx()) > 0) { + globals.update(to_var(e)->get_idx(), -1); + res.push_back(i + ofs); } - res.push_back(i+ofs); } } @@ -422,11 +423,30 @@ namespace datalog { SASSERT(r->get_positive_tail_size()==2); ast_manager & m = m_context.get_manager(); rule_counter counter; - counter.count_rule_vars(m, r); + // leave one column copy per var in the head (avoids later duplication) + counter.count_vars(m, r->get_head(), -1); + + // take interp & neg preds into account (at least 1 column copy if referenced) + unsigned n = r->get_tail_size(); + if (n > 2) { + rule_counter counter_tail; + for (unsigned i = 2; i < n; ++i) { + counter_tail.count_vars(m, r->get_tail(i)); + } + + rule_counter::iterator I = counter_tail.begin(), E = counter_tail.end(); + for (; I != E; ++I) { + int& n = counter.get(I->m_key); + if (n == 0) + n = -1; + } + } + app * t1 = r->get_tail(0); app * t2 = r->get_tail(1); - counter.count_vars(m, t1, -1); - counter.count_vars(m, t2, -1); + counter.count_vars(m, t1); + counter.count_vars(m, t2); + get_local_indexes_for_projection(t1, counter, 0, res); get_local_indexes_for_projection(t2, counter, t1->get_num_args(), res); } From 4ee83c1774a86d973224241986f740b4947c2031 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 22 Dec 2014 12:53:35 +0000 Subject: [PATCH 666/925] Datalog/DoC: add fast path for join_project for the case 'h(X) :- f(X), g(X).' Signed-off-by: Nuno Lopes --- src/muz/rel/udoc_relation.cpp | 34 ++++++++++++++++++++++++++++++++++ src/muz/rel/udoc_relation.h | 1 + 2 files changed, 35 insertions(+) diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index b3abf7998..9d562b17a 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -1028,7 +1028,9 @@ namespace datalog { } class udoc_plugin::join_project_fn : public convenient_relation_join_project_fn { +#if 0 udoc_plugin::join_fn m_joiner; +#endif union_find_default_ctx union_ctx; bit_vector m_to_delete; subset_ints m_equalities; @@ -1043,7 +1045,9 @@ namespace datalog { t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2, removed_col_cnt, rm_cols), +#if 0 m_joiner(t1.get_plugin(), t1, t2, col_cnt, cols1, cols2), +#endif m_equalities(union_ctx) { udoc_plugin& p = t1.get_plugin(); @@ -1152,12 +1156,42 @@ namespace datalog { }; + + class udoc_plugin::join_project_and_fn : public convenient_relation_join_project_fn { + public: + join_project_and_fn(udoc_relation const& t1, udoc_relation const& t2, + unsigned col_cnt, const unsigned *cols1, const unsigned *cols2, + unsigned removed_col_cnt, unsigned const *rm_cols) + : convenient_relation_join_project_fn(t1.get_signature(), t2.get_signature(), + col_cnt, cols1, cols2, removed_col_cnt, rm_cols) {} + + virtual relation_base* operator()(relation_base const& t1, relation_base const& t2) { + udoc_relation *result = get(t1.clone()); + result->get_udoc().intersect(result->get_dm(), get(t2).get_udoc()); + return result; + } + }; + relation_join_fn * udoc_plugin::mk_join_project_fn( relation_base const& t1, relation_base const& t2, unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, const unsigned * removed_cols) { if (!check_kind(t1) || !check_kind(t2)) return 0; + // special case where we have h(X) :- f(X), g(X). + if (joined_col_cnt == removed_col_cnt && + t1.get_signature().size() == joined_col_cnt && + t2.get_signature().size() == joined_col_cnt) { + for (unsigned i = 0; i < removed_col_cnt; ++i) { + if (removed_cols[i] != i) + goto general_fn; + } + return alloc(join_project_and_fn, get(t1), get(t2), + joined_col_cnt, cols1, cols2, + removed_col_cnt, removed_cols); + } + + general_fn: return alloc(join_project_fn, get(t1), get(t2), joined_col_cnt, cols1, cols2, removed_col_cnt, removed_cols); diff --git a/src/muz/rel/udoc_relation.h b/src/muz/rel/udoc_relation.h index 7934521a8..7cad3b348 100644 --- a/src/muz/rel/udoc_relation.h +++ b/src/muz/rel/udoc_relation.h @@ -82,6 +82,7 @@ namespace datalog { friend class udoc_relation; class join_fn; class join_project_fn; + class join_project_and_fn; class project_fn; class union_fn; class rename_fn; From dddb31fc37c87de35e97aa90fcc54d7ac55afe31 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 22 Dec 2014 13:03:06 +0000 Subject: [PATCH 667/925] minor optimization to previous patch Signed-off-by: Nuno Lopes --- src/muz/rel/udoc_relation.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 9d562b17a..37cc91778 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -1157,13 +1157,9 @@ namespace datalog { }; - class udoc_plugin::join_project_and_fn : public convenient_relation_join_project_fn { + class udoc_plugin::join_project_and_fn : public relation_join_fn { public: - join_project_and_fn(udoc_relation const& t1, udoc_relation const& t2, - unsigned col_cnt, const unsigned *cols1, const unsigned *cols2, - unsigned removed_col_cnt, unsigned const *rm_cols) - : convenient_relation_join_project_fn(t1.get_signature(), t2.get_signature(), - col_cnt, cols1, cols2, removed_col_cnt, rm_cols) {} + join_project_and_fn() {} virtual relation_base* operator()(relation_base const& t1, relation_base const& t2) { udoc_relation *result = get(t1.clone()); @@ -1186,9 +1182,7 @@ namespace datalog { if (removed_cols[i] != i) goto general_fn; } - return alloc(join_project_and_fn, get(t1), get(t2), - joined_col_cnt, cols1, cols2, - removed_col_cnt, removed_cols); + return alloc(join_project_and_fn); } general_fn: From ee71c434b6a936d62f6fab43cdc31b31407baaf7 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 22 Dec 2014 14:17:07 +0000 Subject: [PATCH 668/925] muZ/datalog: remove a few spurious make_empty() calls from the instruction handlers Signed-off-by: Nuno Lopes --- src/muz/rel/dl_instruction.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/muz/rel/dl_instruction.cpp b/src/muz/rel/dl_instruction.cpp index b2837c710..7fbe2f5ad 100644 --- a/src/muz/rel/dl_instruction.cpp +++ b/src/muz/rel/dl_instruction.cpp @@ -266,7 +266,6 @@ namespace datalog { : m_clone(clone), m_src(src), m_tgt(tgt) {} virtual bool perform(execution_context & ctx) { if (ctx.reg(m_src)) log_verbose(ctx); - ctx.make_empty(m_tgt); if (m_clone) { ctx.set_reg(m_tgt, ctx.reg(m_src) ? ctx.reg(m_src)->clone() : 0); } @@ -370,9 +369,9 @@ namespace datalog { m_cols2(col_cnt, cols2), m_res(result) {} virtual bool perform(execution_context & ctx) { log_verbose(ctx); - ctx.make_empty(m_res); ++ctx.m_stats.m_join; if (!ctx.reg(m_rel1) || !ctx.reg(m_rel2)) { + ctx.make_empty(m_res); return true; } relation_join_fn * fn; @@ -755,8 +754,8 @@ namespace datalog { reg_idx tgt) : m_projection(projection), m_src(src), m_cols(col_cnt, cols), m_tgt(tgt) {} virtual bool perform(execution_context & ctx) { - ctx.make_empty(m_tgt); if (!ctx.reg(m_src)) { + ctx.make_empty(m_tgt); return true; } @@ -823,8 +822,8 @@ namespace datalog { } virtual bool perform(execution_context & ctx) { log_verbose(ctx); - ctx.make_empty(m_res); if (!ctx.reg(m_rel1) || !ctx.reg(m_rel2)) { + ctx.make_empty(m_res); return true; } ++ctx.m_stats.m_join_project; @@ -1000,7 +999,6 @@ namespace datalog { virtual bool perform(execution_context & ctx) { log_verbose(ctx); ++ctx.m_stats.m_unary_singleton; - ctx.make_empty(m_tgt); relation_base * rel = ctx.get_rel_context().get_rmanager().mk_empty_relation(m_sig, m_pred); rel->add_fact(m_fact); ctx.set_reg(m_tgt, rel); @@ -1034,7 +1032,6 @@ namespace datalog { virtual bool perform(execution_context & ctx) { log_verbose(ctx); ++ctx.m_stats.m_total; - ctx.make_empty(m_tgt); ctx.set_reg(m_tgt, ctx.get_rel_context().get_rmanager().mk_full_relation(m_sig, m_pred)); return true; } From d827713ce3e8e2be64b8d19ec9641735432db4bb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 22 Dec 2014 15:40:02 -0800 Subject: [PATCH 669/925] revert to SMT tactic on bv1_blaster_tactic - equalities are not removed, and conjunctions are not converted to NNF (or/not), so the formula still isn't sufficiently blasted Signed-off-by: Nikolaj Bjorner --- src/tactic/smtlogics/qfbv_tactic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tactic/smtlogics/qfbv_tactic.cpp b/src/tactic/smtlogics/qfbv_tactic.cpp index 916ae1386..b63cfcad3 100644 --- a/src/tactic/smtlogics/qfbv_tactic.cpp +++ b/src/tactic/smtlogics/qfbv_tactic.cpp @@ -105,7 +105,7 @@ tactic * mk_qfbv_tactic(ast_manager& m, params_ref const & p, tactic* sat, tacti cond(mk_is_qfbv_probe(), cond(mk_is_qfbv_eq_probe(), and_then(mk_bv1_blaster_tactic(m), - using_params(sat, solver_p)), + using_params(smt, solver_p)), and_then(mk_bit_blaster_tactic(m), when(mk_lt(mk_memory_probe(), mk_const_probe(MEMLIMIT)), and_then(using_params(and_then(mk_simplify_tactic(m), From a211fcfb9e9c8cae70d8c58011e51b45ea58007e Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Sun, 28 Dec 2014 17:05:17 +0000 Subject: [PATCH 670/925] muZ/datalog/udoc: fix bug in join_project The bug was that we could project out don't care columns and don't take copied bits into account. Bug reported by Ari Fogel Signed-off-by: Nuno Lopes --- src/muz/rel/doc.cpp | 5 ++-- src/test/udoc_relation.cpp | 49 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/muz/rel/doc.cpp b/src/muz/rel/doc.cpp index 76098b0d3..ccd332a42 100644 --- a/src/muz/rel/doc.cpp +++ b/src/muz/rel/doc.cpp @@ -216,7 +216,7 @@ bool doc_manager::merge(doc& d, unsigned idx, subset_ints const& equalities, unsigned root = equalities.find(idx); idx = root; unsigned num_x = 0; - unsigned root1; + unsigned root1 = root; tbit value = BIT_x; do { switch (d[idx]) { @@ -229,12 +229,13 @@ bool doc_manager::merge(doc& d, unsigned idx, subset_ints const& equalities, value = BIT_1; break; case BIT_x: + ++num_x; if (!discard_cols.get(idx)) { - ++num_x; root1 = idx; } break; default: + UNREACHABLE(); break; } idx = equalities.next(idx); diff --git a/src/test/udoc_relation.cpp b/src/test/udoc_relation.cpp index ef11e305e..7be048c73 100644 --- a/src/test/udoc_relation.cpp +++ b/src/test/udoc_relation.cpp @@ -159,6 +159,7 @@ public: test_filter_neg2(); test_join_project(); + test_join_project2(); test_filter_neg4(false); test_filter_neg4(true); @@ -470,6 +471,54 @@ public: } } + void test_join_project2() + { + relation_signature sig3; + sig3.push_back(bv.mk_sort(1)); + sig3.push_back(bv.mk_sort(1)); + sig3.push_back(bv.mk_sort(1)); + + /// xxx \ x11 + udoc_relation *t1 = mk_full(sig3); + { + udoc_relation *neg = mk_full(sig3); + doc& n = neg->get_udoc()[0]; + neg->get_dm().set(n, 1, BIT_1); + neg->get_dm().set(n, 2, BIT_1); + + unsigned_vector allcols; + allcols.push_back(0); + allcols.push_back(1); + allcols.push_back(2); + apply_filter_neg(*t1, *neg, allcols, allcols); + neg->deallocate(); + } + + // 11x + udoc_relation *t2 = mk_full(sig3); + { + doc& n = t2->get_udoc()[0]; + t2->get_dm().set(n, 0, BIT_1); + t2->get_dm().set(n, 1, BIT_1); + } + + unsigned_vector jc1, jc2, pc; + jc1.push_back(1); + jc1.push_back(2); + jc2.push_back(0); + jc2.push_back(1); + pc.push_back(1); + pc.push_back(2); + + scoped_ptr join_project_fn; + join_project_fn = p.mk_join_project_fn(*t1, *t2, jc1.size(), jc1.c_ptr(), jc2.c_ptr(), pc.size(), pc.c_ptr()); + relation_base *t = (*join_project_fn)(*t1, *t2); + cr.verify_join_project(*t1, *t2, *t, jc1, jc2, pc); + t->deallocate(); + t1->deallocate(); + t2->deallocate(); + } + void test_rename() { udoc_relation* t1; // rename From c54a19b0840867054eb65719af0b1a906886cb12 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 29 Dec 2014 12:57:02 -0800 Subject: [PATCH 671/925] generate proof justifications in theory_pb: codeplex issue 157 Signed-off-by: Nikolaj Bjorner --- src/ast/datatype_decl_plugin.cpp | 32 ++++++++++++++++--- src/ast/datatype_decl_plugin.h | 3 ++ src/smt/theory_pb.cpp | 54 +++++++++++++++++++++++--------- src/smt/theory_pb.h | 5 +++ 4 files changed, 76 insertions(+), 18 deletions(-) diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index ee3271b9b..5b29ec20b 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -521,6 +521,20 @@ func_decl * datatype_decl_plugin::mk_func_decl(decl_kind k, unsigned num_paramet return m_manager->mk_func_decl(a_name, arity, domain, a_type, info); } break; + case OP_DT_UPDATE_FIELD: + if (num_parameters != 2 || arity != 2 || domain[0] != datatype) { + m_manager->raise_exception("invalid parameters for datatype field update"); + return 0; + } + else { + symbol con_name = parameters[0].get_symbol(); + symbol acc_name = parameters[1].get_symbol(); + func_decl_info info(m_family_id, k, num_parameters, parameters); + info.m_private_parameters = true; + SASSERT(info.private_parameters()); + return m_manager->mk_func_decl(symbol("update_field"), arity, domain, datatype, info); + } + default: m_manager->raise_exception("invalid datatype operator kind"); return 0; @@ -672,6 +686,16 @@ bool datatype_decl_plugin::is_value(app * e) const { return true; } +void datatype_decl_plugin::get_op_names(svector & op_names, symbol const & logic) { +#if 0 + // disabled + if (logic == symbol::null) { + op_names.push_back(builtin_name("update_field", OP_DT_UPDATE_FIELD)); + } +#endif +} + + datatype_util::datatype_util(ast_manager & m): m_manager(m), m_family_id(m.mk_family_id("datatype")), @@ -919,9 +943,9 @@ void datatype_util::display_datatype(sort *s0, std::ostream& strm) { todo.push_back(s0); mark.mark(s0, true); while (!todo.empty()) { - sort* s = todo.back(); + sort* s = todo.back(); todo.pop_back(); - strm << s->get_name() << " =\n"; + strm << s->get_name() << " =\n"; ptr_vector const * cnstrs = get_datatype_constructors(s); for (unsigned i = 0; i < cnstrs->size(); ++i) { @@ -931,14 +955,14 @@ void datatype_util::display_datatype(sort *s0, std::ostream& strm) { ptr_vector const * accs = get_constructor_accessors(cns); for (unsigned j = 0; j < accs->size(); ++j) { func_decl* acc = (*accs)[j]; - sort* s1 = acc->get_range(); + sort* s1 = acc->get_range(); strm << "(" << acc->get_name() << ": " << s1->get_name() << ") "; if (is_datatype(s1) && are_siblings(s1, s0) && !mark.is_marked(s1)) { mark.mark(s1, true); todo.push_back(s1); } } - strm << "\n"; + strm << "\n"; } } diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index 96b678fb2..af7c689bc 100644 --- a/src/ast/datatype_decl_plugin.h +++ b/src/ast/datatype_decl_plugin.h @@ -32,6 +32,7 @@ enum datatype_op_kind { OP_DT_CONSTRUCTOR, OP_DT_RECOGNISER, OP_DT_ACCESSOR, + OP_DT_UPDATE_FIELD, LAST_DT_OP }; @@ -149,6 +150,8 @@ public: virtual bool is_unique_value(app * e) const { return is_value(e); } + virtual void get_op_names(svector & op_names, symbol const & logic); + private: bool is_value_visit(expr * arg, ptr_buffer & todo) const; }; diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index b8a5e7bd1..1eff86db4 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -321,7 +321,7 @@ namespace smt { m_simplex.get_upper(v, last_bound); if (m_mpq_inf_mgr.gt(bound, last_bound)) { literal lit = m_explain_upper.get(v, null_literal); - get_context().mk_clause(~lit, ~explain, 0); + get_context().mk_clause(~lit, ~explain, justify(~lit, ~explain)); return false; } } @@ -341,7 +341,7 @@ namespace smt { m_simplex.get_lower(v, last_bound); if (m_mpq_inf_mgr.gt(last_bound, bound)) { literal lit = m_explain_lower.get(v, null_literal); - get_context().mk_clause(~lit, ~explain, 0); + get_context().mk_clause(~lit, ~explain, justify(~lit, ~explain)); return false; } } @@ -358,6 +358,7 @@ namespace smt { }; bool theory_pb::check_feasible() { + context& ctx = get_context(); lbool is_sat = m_simplex.make_feasible(); if (l_false != is_sat) { return true; @@ -400,7 +401,10 @@ namespace smt { m_stats.m_num_conflicts++; justification* js = 0; - get_context().mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); + if (proofs_enabled()) { + js = alloc(theory_lemma_justification, get_id(), ctx, lits.size(), lits.c_ptr()); + } + ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); return false; } @@ -1143,12 +1147,14 @@ namespace smt { struct theory_pb::psort_expr { context& ctx; ast_manager& m; + theory_pb& th; typedef smt::literal literal; typedef smt::literal_vector literal_vector; - psort_expr(context& c): + psort_expr(context& c, theory_pb& th): ctx(c), - m(c.get_manager()) {} + m(c.get_manager()), + th(th) {} literal fresh() { app_ref y(m); @@ -1180,7 +1186,7 @@ namespace smt { void mk_clause(unsigned n, literal const* ls) { literal_vector tmp(n, ls); - ctx.mk_clause(n, tmp.c_ptr(), 0, CLS_AUX, 0); + ctx.mk_clause(n, tmp.c_ptr(), th.justify(tmp), CLS_AUX, 0); } literal mk_false() { return false_literal; } @@ -1192,7 +1198,9 @@ namespace smt { // for testing literal theory_pb::assert_ge(context& ctx, unsigned k, unsigned n, literal const* xs) { - psort_expr ps(ctx); + theory_pb_params p; + theory_pb th(ctx.get_manager(), p); + psort_expr ps(ctx, th); psort_nw sort(ps); return sort.ge(false, k, n, xs); } @@ -1249,21 +1257,21 @@ namespace smt { } if (ctx.get_assignment(thl) == l_true && ctx.get_assign_level(thl) == ctx.get_base_level()) { - psort_expr ps(ctx); + psort_expr ps(ctx, *this); psort_nw sortnw(ps); sortnw.m_stats.reset(); at_least_k = sortnw.ge(false, k, in.size(), in.c_ptr()); - ctx.mk_clause(~thl, at_least_k, 0); + ctx.mk_clause(~thl, at_least_k, justify(~thl, at_least_k)); m_stats.m_num_compiled_vars += sortnw.m_stats.m_num_compiled_vars; m_stats.m_num_compiled_clauses += sortnw.m_stats.m_num_compiled_clauses; } else { - psort_expr ps(ctx); + psort_expr ps(ctx, *this); psort_nw sortnw(ps); sortnw.m_stats.reset(); literal at_least_k = sortnw.ge(true, k, in.size(), in.c_ptr()); - ctx.mk_clause(~thl, at_least_k, 0); - ctx.mk_clause(~at_least_k, thl, 0); + ctx.mk_clause(~thl, at_least_k, justify(~thl, at_least_k)); + ctx.mk_clause(~at_least_k, thl, justify(thl, ~at_least_k)); m_stats.m_num_compiled_vars += sortnw.m_stats.m_num_compiled_vars; m_stats.m_num_compiled_clauses += sortnw.m_stats.m_num_compiled_clauses; } @@ -1432,7 +1440,9 @@ namespace smt { if (m_conflict_frequency == 0 || (m_conflict_frequency -1 == (c.m_num_propagations % m_conflict_frequency))) { resolve_conflict(c); } - + if (proofs_enabled()) { + js = alloc(theory_lemma_justification, get_id(), ctx, lits.size(), lits.c_ptr()); + } ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); } @@ -1739,7 +1749,7 @@ namespace smt { for (unsigned i = 0; i < m_ineq_literals.size(); ++i) { m_ineq_literals[i].neg(); } - ctx.mk_clause(m_ineq_literals.size(), m_ineq_literals.c_ptr(), 0, CLS_AUX_LEMMA, 0); + ctx.mk_clause(m_ineq_literals.size(), m_ineq_literals.c_ptr(), justify(m_ineq_literals), CLS_AUX_LEMMA, 0); break; default: { app_ref tmp = m_lemma.to_expr(false, ctx, get_manager()); @@ -1757,6 +1767,22 @@ namespace smt { return typeid(smt::justification_proof_wrapper) == typeid(j); } + justification* theory_pb::justify(literal l1, literal l2) { + literal lits[2] = { l1, l2 }; + justification* js = 0; + if (proofs_enabled()) { + js = alloc(theory_axiom_justification, get_id(), get_context().get_region(), 2, lits); + } + return js; + } + + justification* theory_pb::justify(literal_vector const& lits) { + justification* js = 0; + if (proofs_enabled()) { + js = alloc(theory_lemma_justification, get_id(), get_context(), lits.size(), lits.c_ptr()); + } + return js; + } void theory_pb::hoist_maximal_values() { for (unsigned i = 0; i < m_lemma.size(); ++i) { diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index b7922fbd0..b9fddba38 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -289,6 +289,11 @@ namespace smt { void validate_final_check(ineq& c); void validate_assign(ineq const& c, literal_vector const& lits, literal l) const; void validate_watch(ineq const& c) const; + + bool proofs_enabled() const { return get_manager().proofs_enabled(); } + justification* justify(literal l1, literal l2); + justification* justify(literal_vector const& lits); + public: theory_pb(ast_manager& m, theory_pb_params& p); From a296023823fbb94da7a80307edc96b326fe271dd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 29 Dec 2014 16:15:19 -0800 Subject: [PATCH 672/925] incorrect offset calculation in diff logic optimization. codeplex issue 156 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_diff_logic_def.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index 3b9993074..ee9823912 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -1237,7 +1237,7 @@ theory_diff_logic::maximize(theory_var v, expr_ref& blocker, bool& has_shar } } blocker = mk_gt(v, r); - return inf_eps(rational(0), r); + return inf_eps(rational(0), r + m_objective_consts[v]); } default: TRACE("opt", tout << "unbounded\n"; ); @@ -1295,7 +1295,7 @@ expr_ref theory_diff_logic::block_objective(theory_var v, inf_rational cons return f; } - inf_rational new_val = val - inf_rational(m_objective_consts[v]); + inf_rational new_val = val; // - inf_rational(m_objective_consts[v]); e = m_util.mk_numeral(new_val.get_rational(), m.get_sort(f)); if (new_val.get_infinitesimal().is_neg()) { From 129e048a1ba289b34a3a9189b670aae237db95a5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 3 Jan 2015 01:27:52 -0800 Subject: [PATCH 673/925] Adding field update feature Signed-off-by: Nikolaj Bjorner --- src/api/api_datatype.cpp | 21 ++++++ src/api/dotnet/Context.cs | 13 ++++ src/api/java/Context.java | 16 +++++ src/api/z3_api.h | 25 +++++++ src/ast/datatype_decl_plugin.cpp | 69 ++++++++++++++----- src/ast/datatype_decl_plugin.h | 6 ++ src/ast/rewriter/datatype_rewriter.cpp | 26 +++++++ .../simplifier/datatype_simplifier_plugin.cpp | 2 + src/smt/theory_datatype.cpp | 60 ++++++++++++++-- src/smt/theory_datatype.h | 7 +- 10 files changed, 221 insertions(+), 24 deletions(-) diff --git a/src/api/api_datatype.cpp b/src/api/api_datatype.cpp index f3a275508..fae8a21bc 100644 --- a/src/api/api_datatype.cpp +++ b/src/api/api_datatype.cpp @@ -618,4 +618,25 @@ extern "C" { Z3_CATCH_RETURN(0); } + Z3_ast Z3_datatype_update_field( + __in Z3_context c, __in Z3_func_decl f, __in Z3_ast t, __in Z3_ast v) { + Z3_TRY; + LOG_Z3_datatype_update_field(c, f, t, v); + RESET_ERROR_CODE(); + ast_manager & m = mk_c(c)->m(); + func_decl* _f = to_func_decl(f); + expr* _t = to_expr(t); + expr* _v = to_expr(v); + expr* args[2] = { _t, _v }; + sort* domain[2] = { m.get_sort(_t), m.get_sort(_v) }; + parameter param(_f); + func_decl * d = m.mk_func_decl(mk_c(c)->get_array_fid(), OP_DT_UPDATE_FIELD, 1, ¶m, 2, domain); + app* r = m.mk_app(d, 2, args); + mk_c(c)->save_ast_trail(r); + check_sorts(c, r); + RETURN_Z3(of_ast(r)); + Z3_CATCH_RETURN(0); + } + + }; diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 989d1d7d7..13e78e495 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -449,6 +449,19 @@ namespace Microsoft.Z3 return MkDatatypeSorts(MkSymbols(names), c); } + /// + /// Update a datatype field at expression t with value v. + /// The function performs a record update at t. The field + /// that is passed in as argument is updated with value v, + /// the remainig fields of t are unchanged. + /// + public Expr MkUpdateField(FuncDecl field, Expr t, Expr v) + { + return Expr.Create(this, Native.Z3_datatype_update_field( + nCtx, field.NativeObject, + t.NativeObject, v.NativeObject)); + } + #endregion #endregion diff --git a/src/api/java/Context.java b/src/api/java/Context.java index 4fbd79be2..d52edfb82 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -375,6 +375,22 @@ public class Context extends IDisposable return mkDatatypeSorts(MkSymbols(names), c); } + /** + * Update a datatype field at expression t with value v. + * The function performs a record update at t. The field + * that is passed in as argument is updated with value v, + * the remainig fields of t are unchanged. + **/ + public Expr MkUpdateField(FuncDecl field, Expr t, Expr v) + { + return Expr.Create + (this, + Native.datatypeUpdateField + (nCtx(), field.getNativeObject(), + t.getNativeObject(), v.getNativeObject())); + } + + /** * Creates a new function declaration. **/ diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 4550e7976..792174233 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -877,6 +877,8 @@ typedef enum - Z3_OP_DT_ACCESSOR: datatype accessor. + - Z3_OP_DT_UPDATE_FIELD: datatype field update. + - Z3_OP_PB_AT_MOST: Cardinality constraint. E.g., x + y + z <= 2 @@ -1066,6 +1068,7 @@ typedef enum { Z3_OP_DT_CONSTRUCTOR=0x800, Z3_OP_DT_RECOGNISER, Z3_OP_DT_ACCESSOR, + Z3_OP_DT_UPDATE_FIELD, // Pseudo Booleans Z3_OP_PB_AT_MOST=0x900, @@ -3751,6 +3754,28 @@ END_MLAPI_EXCLUDE Z3_func_decl Z3_API Z3_get_datatype_sort_constructor_accessor( __in Z3_context c, __in Z3_sort t, unsigned idx_c, unsigned idx_a); + /** + \brief Update record field with a value. + + This corresponds to the 'with' construct in OCaml. + It has the effect of updating a record field with a given value. + The remaining fields are left unchanged. It is the record + equivalent of an array store (see \sa Z3_mk_store). + If the datatype has more than one constructor, then the update function + behaves as identity if there is a miss-match between the accessor and + constructor. For example ((_ update-field car) nil 1) is nil, + while ((_ update-field car) (cons 2 nil) 1) is (cons 1 nil). + + + \pre Z3_get_sort_kind(Z3_get_sort(c, t)) == Z3_get_domain(c, field_access, 1) == Z3_DATATYPE_SORT + \pre Z3_get_sort(c, value) == Z3_get_range(c, field_access) + + + def_API('Z3_datatype_update_field', AST, (_in(CONTEXT), _in(FUNC_DECL), _in(AST), _in(AST))) + */ + Z3_ast Z3_API Z3_datatype_update_field( + __in Z3_context c, __in Z3_func_decl field_access, + __in Z3_ast t, __in Z3_ast value); /** \brief Return arity of relation. diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index 5b29ec20b..d707f0178 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -422,8 +422,55 @@ static sort * get_type(ast_manager & m, family_id datatype_fid, sort * source_da } } +func_decl * datatype_decl_plugin::mk_update_field( + unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) { + decl_kind k = OP_DT_UPDATE_FIELD; + ast_manager& m = *m_manager; + + if (num_parameters != 1 || !parameters[0].is_ast()) { + m.raise_exception("invalid parameters for datatype field update"); + return 0; + } + if (arity != 2) { + m.raise_exception("invalid number of arguments for datatype field update"); + return 0; + } + func_decl* acc = 0; + if (is_func_decl(parameters[0].get_ast())) { + acc = to_func_decl(parameters[0].get_ast()); + } + if (acc && !get_util().is_accessor(acc)) { + acc = 0; + } + if (!acc) { + m.raise_exception("datatype field update requires a datatype accessor as the second argument"); + return 0; + } + sort* dom = acc->get_domain(0); + sort* rng = acc->get_range(); + if (dom != domain[0]) { + m.raise_exception("first argument to field update should be a data-type"); + return 0; + } + if (rng != domain[1]) { + std::ostringstream buffer; + buffer << "second argument to field update should be " << mk_ismt2_pp(rng, m) + << " instead of " << mk_ismt2_pp(domain[1], m); + m.raise_exception(buffer.str().c_str()); + return 0; + } + range = domain[0]; + func_decl_info info(m_family_id, k, num_parameters, parameters); + return m.mk_func_decl(symbol("update_field"), arity, domain, range, info); +} + func_decl * datatype_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { + + if (k == OP_DT_UPDATE_FIELD) { + return mk_update_field(num_parameters, parameters, arity, domain, range); + } if (num_parameters < 2 || !parameters[0].is_ast() || !is_sort(parameters[0].get_ast())) { m_manager->raise_exception("invalid parameters for datatype operator"); return 0; @@ -521,20 +568,9 @@ func_decl * datatype_decl_plugin::mk_func_decl(decl_kind k, unsigned num_paramet return m_manager->mk_func_decl(a_name, arity, domain, a_type, info); } break; - case OP_DT_UPDATE_FIELD: - if (num_parameters != 2 || arity != 2 || domain[0] != datatype) { - m_manager->raise_exception("invalid parameters for datatype field update"); - return 0; - } - else { - symbol con_name = parameters[0].get_symbol(); - symbol acc_name = parameters[1].get_symbol(); - func_decl_info info(m_family_id, k, num_parameters, parameters); - info.m_private_parameters = true; - SASSERT(info.private_parameters()); - return m_manager->mk_func_decl(symbol("update_field"), arity, domain, datatype, info); - } - + case OP_DT_UPDATE_FIELD: + UNREACHABLE(); + return 0; default: m_manager->raise_exception("invalid datatype operator kind"); return 0; @@ -687,12 +723,9 @@ bool datatype_decl_plugin::is_value(app * e) const { } void datatype_decl_plugin::get_op_names(svector & op_names, symbol const & logic) { -#if 0 - // disabled if (logic == symbol::null) { - op_names.push_back(builtin_name("update_field", OP_DT_UPDATE_FIELD)); + op_names.push_back(builtin_name("update-field", OP_DT_UPDATE_FIELD)); } -#endif } diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index af7c689bc..2218963c3 100644 --- a/src/ast/datatype_decl_plugin.h +++ b/src/ast/datatype_decl_plugin.h @@ -154,6 +154,10 @@ public: private: bool is_value_visit(expr * arg, ptr_buffer & todo) const; + + func_decl * mk_update_field( + unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range); }; class datatype_util { @@ -184,9 +188,11 @@ public: bool is_constructor(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_CONSTRUCTOR); } bool is_recognizer(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_RECOGNISER); } bool is_accessor(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_ACCESSOR); } + bool is_update_field(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_UPDATE_FIELD); } bool is_constructor(app * f) const { return is_app_of(f, m_family_id, OP_DT_CONSTRUCTOR); } bool is_recognizer(app * f) const { return is_app_of(f, m_family_id, OP_DT_RECOGNISER); } bool is_accessor(app * f) const { return is_app_of(f, m_family_id, OP_DT_ACCESSOR); } + bool is_update_field(app * f) const { return is_app_of(f, m_family_id, OP_DT_UPDATE_FIELD); } ptr_vector const * get_datatype_constructors(sort * ty); unsigned get_datatype_num_constructors(sort * ty) { return get_datatype_constructors(ty)->size(); } unsigned get_constructor_idx(func_decl * f) const { SASSERT(is_constructor(f)); return f->get_parameter(1).get_int(); } diff --git a/src/ast/rewriter/datatype_rewriter.cpp b/src/ast/rewriter/datatype_rewriter.cpp index 8c55ba498..be198c3d9 100644 --- a/src/ast/rewriter/datatype_rewriter.cpp +++ b/src/ast/rewriter/datatype_rewriter.cpp @@ -60,6 +60,32 @@ br_status datatype_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr UNREACHABLE(); break; } + case OP_DT_UPDATE_FIELD: { + SASSERT(num_args == 2); + if (!is_app(args[0]) || !m_util.is_constructor(to_app(args[0]))) + return BR_FAILED; + app * a = to_app(args[0]); + func_decl * c_decl = a->get_decl(); + if (c_decl != m_util.get_accessor_constructor(f)) { + result = a; + return BR_DONE; + } + ptr_vector const * acc = m_util.get_constructor_accessors(c_decl); + SASSERT(acc && acc->size() == a->get_num_args()); + unsigned num = acc->size(); + ptr_buffer new_args; + for (unsigned i = 0; i < num; ++i) { + + if (f == (*acc)[i]) { + new_args.push_back(args[1]); + } + else { + new_args.push_back(a->get_arg(i)); + } + } + result = m().mk_app(c_decl, num, new_args.c_ptr()); + return BR_DONE; + } default: UNREACHABLE(); } diff --git a/src/ast/simplifier/datatype_simplifier_plugin.cpp b/src/ast/simplifier/datatype_simplifier_plugin.cpp index 129c0e34b..b434a8bd0 100644 --- a/src/ast/simplifier/datatype_simplifier_plugin.cpp +++ b/src/ast/simplifier/datatype_simplifier_plugin.cpp @@ -81,6 +81,8 @@ bool datatype_simplifier_plugin::reduce(func_decl * f, unsigned num_args, expr * } UNREACHABLE(); } + case OP_DT_UPDATE_FIELD: + return false; default: UNREACHABLE(); } diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index 8c6543eff..b5cdbcfe2 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -61,6 +61,13 @@ namespace smt { if (antecedent == null_literal) { ctx.assign_eq(lhs, ctx.get_enode(rhs), eq_justification::mk_axiom()); } + else if (ctx.get_assignment(antecedent) != l_true) { + literal l(mk_eq(lhs->get_owner(), rhs, true)); + ctx.mark_as_relevant(l); + ctx.mark_as_relevant(antecedent); + literal lits[2] = {l, ~antecedent}; + ctx.mk_th_axiom(get_id(), 2, lits); + } else { SASSERT(ctx.get_assignment(antecedent) == l_true); region & r = ctx.get_region(); @@ -143,6 +150,48 @@ namespace smt { ctx.set_conflict(ctx.mk_justification(ext_theory_conflict_justification(get_id(), reg, 1, &l, 1, &p))); } + /** + \brief Given a field update n := { r with field := v } for constructor C, assert the axioms: + (=> (is-C r) (= (acc_j n) (acc_j r))) for acc_j != field + (=> (is-C r) (= (field n) v)) for acc_j != field + (=> (not (is-C r)) (= n r)) + */ + void theory_datatype::assert_update_field_axioms(enode * n) { + m_stats.m_assert_update_field++; + SASSERT(is_update_field(n)); + context & ctx = get_context(); + ast_manager & m = get_manager(); + app* own = n->get_owner(); + expr* arg1 = own->get_arg(0); + expr* arg2 = own->get_arg(1); + func_decl * upd = n->get_decl(); + func_decl * acc = to_func_decl(upd->get_parameter(0).get_ast()); + func_decl * con = m_util.get_accessor_constructor(acc); + func_decl * rec = m_util.get_constructor_recognizer(con); + ptr_vector const * accessors = m_util.get_constructor_accessors(con); + ptr_vector::const_iterator it = accessors->begin(); + ptr_vector::const_iterator end = accessors->end(); + app_ref rec_app(m.mk_app(rec, arg1), m); + ctx.internalize(rec_app, false); + literal is_con(ctx.get_bool_var(rec_app)); + for (; it != end; ++it) { + enode* arg; + func_decl * acc1 = *it; + if (acc1 == acc) { + arg = n->get_arg(1); + } + else { + app* acc_app = m.mk_app(acc1, arg1); + ctx.internalize(acc_app, false); + arg = ctx.get_enode(acc_app); + } + app * acc_own = m.mk_app(acc1, own); + assert_eq_axiom(arg, acc_own, is_con); + } + // update_field is identity if 'n' is not created by a matching constructor. + assert_eq_axiom(n, arg1, ~is_con); + } + theory_var theory_datatype::mk_var(enode * n) { theory_var r = theory::mk_var(n); theory_var r2 = m_find.mk_var(); @@ -150,15 +199,17 @@ namespace smt { SASSERT(r == static_cast(m_var_data.size())); m_var_data.push_back(alloc(var_data)); var_data * d = m_var_data[r]; + context & ctx = get_context(); + ctx.attach_th_var(n, this, r); if (is_constructor(n)) { d->m_constructor = n; - get_context().attach_th_var(n, this, r); assert_accessor_axioms(n); } + else if (is_update_field(n)) { + assert_update_field_axioms(n); + } else { ast_manager & m = get_manager(); - context & ctx = get_context(); - ctx.attach_th_var(n, this, r); sort * s = m.get_sort(n->get_owner()); if (m_util.get_datatype_num_constructors(s) == 1) { func_decl * c = m_util.get_datatype_constructors(s)->get(0); @@ -192,7 +243,7 @@ namespace smt { ctx.set_var_theory(bv, get_id()); ctx.set_enode_flag(bv, true); } - if (is_constructor(term)) { + if (is_constructor(term) || is_update_field(term)) { SASSERT(!is_attached_to_var(e)); // *** We must create a theory variable for each argument that has sort datatype *** // @@ -478,6 +529,7 @@ namespace smt { st.update("datatype splits", m_stats.m_splits); st.update("datatype constructor ax", m_stats.m_assert_cnstr); st.update("datatype accessor ax", m_stats.m_assert_accessor); + st.update("datatype update ax", m_stats.m_assert_update_field); } void theory_datatype::display_var(std::ostream & out, theory_var v) const { diff --git a/src/smt/theory_datatype.h b/src/smt/theory_datatype.h index cf2f933ad..5ebfc220f 100644 --- a/src/smt/theory_datatype.h +++ b/src/smt/theory_datatype.h @@ -41,7 +41,7 @@ namespace smt { struct stats { unsigned m_occurs_check, m_splits; - unsigned m_assert_cnstr, m_assert_accessor; + unsigned m_assert_cnstr, m_assert_accessor, m_assert_update_field; void reset() { memset(this, 0, sizeof(stats)); } stats() { reset(); } }; @@ -58,14 +58,17 @@ namespace smt { bool is_constructor(app * f) const { return m_util.is_constructor(f); } bool is_recognizer(app * f) const { return m_util.is_recognizer(f); } bool is_accessor(app * f) const { return m_util.is_accessor(f); } - + bool is_update_field(app * f) const { return m_util.is_update_field(f); } + bool is_constructor(enode * n) const { return is_constructor(n->get_owner()); } bool is_recognizer(enode * n) const { return is_recognizer(n->get_owner()); } bool is_accessor(enode * n) const { return is_accessor(n->get_owner()); } + bool is_update_field(enode * n) const { return m_util.is_update_field(n->get_owner()); } void assert_eq_axiom(enode * lhs, expr * rhs, literal antecedent); void assert_is_constructor_axiom(enode * n, func_decl * c, literal antecedent); void assert_accessor_axioms(enode * n); + void assert_update_field_axioms(enode * n); void add_recognizer(theory_var v, enode * recognizer); void propagate_recognizer(theory_var v, enode * r); void sign_recognizer_conflict(enode * c, enode * r); From 2cd4669e2121009674025fe0d1a84aeb4070a820 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 3 Jan 2015 01:47:57 -0800 Subject: [PATCH 674/925] add DT translation Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 04265af15..0ab027f69 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1076,7 +1076,6 @@ extern "C" { case OP_BSREM_I: case OP_BUREM_I: case OP_BSMOD_I: - return Z3_OP_UNINTERPRETED; default: UNREACHABLE(); @@ -1085,9 +1084,10 @@ extern "C" { } if (mk_c(c)->get_dt_fid() == _d->get_family_id()) { switch(_d->get_decl_kind()) { - case OP_DT_CONSTRUCTOR: return Z3_OP_DT_CONSTRUCTOR; - case OP_DT_RECOGNISER: return Z3_OP_DT_RECOGNISER; - case OP_DT_ACCESSOR: return Z3_OP_DT_ACCESSOR; + case OP_DT_CONSTRUCTOR: return Z3_OP_DT_CONSTRUCTOR; + case OP_DT_RECOGNISER: return Z3_OP_DT_RECOGNISER; + case OP_DT_ACCESSOR: return Z3_OP_DT_ACCESSOR; + case OP_DT_UPDATE_FIELD: return Z3_OP_DT_UPDATE_FIELD; default: UNREACHABLE(); return Z3_OP_UNINTERPRETED; From 2f9e9e1a3c2aaf514e69d1bd944e22ce3fc3b264 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 3 Jan 2015 11:04:08 -0800 Subject: [PATCH 675/925] create proof object in elim01. Codeplex issue 158 Signed-off-by: Nikolaj Bjorner --- src/tactic/arith/elim01_tactic.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tactic/arith/elim01_tactic.cpp b/src/tactic/arith/elim01_tactic.cpp index 53fa948ce..dda3d8fc9 100644 --- a/src/tactic/arith/elim01_tactic.cpp +++ b/src/tactic/arith/elim01_tactic.cpp @@ -193,11 +193,14 @@ public: expr_ref new_curr(m), tmp_curr(m); proof_ref new_pr(m); - for (unsigned i = 0; i < g->size(); i++) { expr * curr = g->form(i); sub(curr, tmp_curr); m_rewriter(tmp_curr, new_curr); + if (m.proofs_enabled()) { + new_pr = m.mk_rewrite(curr, new_curr); + new_pr = m.mk_modus_ponens(g->pr(i), new_pr); + } g->update(i, new_curr, new_pr, g->dep(i)); } for (unsigned i = 0; i < axioms.size(); ++i) { From 061ac0f23e13e18f842d9afda13bc4d4108feb7a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 5 Jan 2015 16:44:33 -0800 Subject: [PATCH 676/925] populate proofs in opt specific tactics Signed-off-by: Nikolaj Bjorner --- src/duality/duality_rpfp.cpp | 2 +- src/tactic/arith/card2bv_tactic.cpp | 10 ++++++++-- src/tactic/arith/lia2card_tactic.cpp | 6 +++++- src/tactic/arith/lia2pb_tactic.cpp | 7 +++++-- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/duality/duality_rpfp.cpp b/src/duality/duality_rpfp.cpp index cdc8fb3b2..cb71bd99c 100755 --- a/src/duality/duality_rpfp.cpp +++ b/src/duality/duality_rpfp.cpp @@ -3147,7 +3147,7 @@ namespace Duality { } if(node->Annotation.IsEmpty() || eq(node->Annotation.Formula,prev_annot) || (repeated_case_count > 0 && !axioms_added) || (repeated_case_count >= 10)){ - looks_bad: +// looks_bad: if(!axioms_added){ // add the axioms in the off chance they are useful const std::vector &theory = ls->get_axioms(); diff --git a/src/tactic/arith/card2bv_tactic.cpp b/src/tactic/arith/card2bv_tactic.cpp index e5f699eaa..933b687b4 100644 --- a/src/tactic/arith/card2bv_tactic.cpp +++ b/src/tactic/arith/card2bv_tactic.cpp @@ -487,11 +487,17 @@ public: unsigned size = g->size(); expr_ref new_f1(m), new_f2(m); + proof_ref new_pr1(m), new_pr2(m); for (unsigned idx = 0; idx < size; idx++) { - m_rw1(g->form(idx), new_f1); + m_rw1(g->form(idx), new_f1, new_pr1); TRACE("card2bv", tout << "Rewriting " << mk_ismt2_pp(new_f1.get(), m) << std::endl;); m_rw2.rewrite(new_f1, new_f2); - g->update(idx, new_f2, g->pr(idx), g->dep(idx)); + if (m.proofs_enabled()) { + new_pr1 = m.mk_modus_ponens(g->pr(idx), new_pr1); + new_pr2 = m.mk_rewrite(new_f1, new_f2); + new_pr1 = m.mk_modus_ponens(new_pr1, new_pr2); + } + g->update(idx, new_f2, new_pr1, g->dep(idx)); } for (unsigned i = 0; i < m_rw2.lemmas().size(); ++i) { g->assert_expr(m_rw2.lemmas()[i].get()); diff --git a/src/tactic/arith/lia2card_tactic.cpp b/src/tactic/arith/lia2card_tactic.cpp index 7ed867155..0afbe62f1 100644 --- a/src/tactic/arith/lia2card_tactic.cpp +++ b/src/tactic/arith/lia2card_tactic.cpp @@ -89,7 +89,11 @@ public: for (unsigned i = 0; i < g->size(); i++) { expr * curr = g->form(i); - sub(curr, new_curr); + sub(curr, new_curr); + if (m.proofs_enabled()) { + new_pr = m.mk_rewrite(curr, new_curr); + new_pr = m.mk_modus_ponens(g->pr(i), new_pr); + } g->update(i, new_curr, new_pr, g->dep(i)); } g->inc_depth(); diff --git a/src/tactic/arith/lia2pb_tactic.cpp b/src/tactic/arith/lia2pb_tactic.cpp index 33d5f138e..8d200c80d 100644 --- a/src/tactic/arith/lia2pb_tactic.cpp +++ b/src/tactic/arith/lia2pb_tactic.cpp @@ -293,9 +293,12 @@ class lia2pb_tactic : public tactic { m_rw(curr, new_curr, new_pr); if (m_produce_unsat_cores) { dep = m.mk_join(m_rw.get_used_dependencies(), g->dep(idx)); - m_rw.reset_used_dependencies(); + m_rw.reset_used_dependencies(); } - g->update(idx, new_curr, 0, dep); + if (m.proofs_enabled()) { + new_pr = m.mk_modus_ponens(g->pr(idx), new_pr); + } + g->update(idx, new_curr, new_pr, dep); } g->inc_depth(); result.push_back(g.get()); From ef57e4abe55a3a29089a70734c1f995f6979e1ff Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 5 Jan 2015 19:42:06 -0800 Subject: [PATCH 677/925] extract theory symbols from Boolean objectives Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 61 +++++++++++++++++++++++++++++++++++++++++ src/opt/opt_context.h | 4 +++ src/opt/opt_solver.cpp | 1 + 3 files changed, 66 insertions(+) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index a7f4d29b5..141a2d425 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -39,6 +39,7 @@ Notes: #include "bv_decl_plugin.h" #include "pb_decl_plugin.h" #include "ast_smt_pp.h" +#include "filter_model_converter.h" namespace opt { @@ -533,6 +534,38 @@ namespace opt { return true; } + struct context::is_propositional_fn { + struct found {}; + ast_manager& m; + is_propositional_fn(ast_manager& m): m(m) {} + void operator()(var *) { throw found(); } + void operator()(quantifier *) { throw found(); } + void operator()(app *n) { + family_id fid = n->get_family_id(); + if (fid != m.get_basic_family_id() && + !is_uninterp_const(n)) { + throw found(); + } + } + }; + + bool context::is_propositional(expr* p) { + expr* np; + if (is_uninterp_const(p) || (m.is_not(p, np) && is_uninterp_const(np))) { + return true; + } + is_propositional_fn proc(m); + expr_fast_mark1 visited; + try { + quick_for_each_expr(proc, visited, p); + } + catch (is_propositional_fn::found) { + return false; + } + return true; + } + + void context::add_maxsmt(symbol const& id) { maxsmt* ms = alloc(maxsmt, *this); ms->updt_params(m_params); @@ -778,6 +811,7 @@ namespace opt { SASSERT(!m_maxsmts.contains(id)); add_maxsmt(id); } + mk_atomic(terms); SASSERT(obj.m_id == id); obj.m_terms.reset(); obj.m_terms.append(terms); @@ -799,6 +833,33 @@ namespace opt { } } + /** + To select the proper theory solver we have to ensure that all theory + symbols from soft constraints are reflected in the hard constraints. + + - filter "obj" from generated model. + */ + void context::mk_atomic(expr_ref_vector& terms) { + ref fm; + for (unsigned i = 0; i < terms.size(); ++i) { + expr_ref p(terms[i].get(), m); + app_ref q(m); + if (is_propositional(p)) { + terms[i] = p; + } + else { + q = m.mk_fresh_const("obj", m.mk_bool_sort()); + terms[i] = q; + m_hard_constraints.push_back(m.mk_iff(p, q)); + if (!fm) fm = alloc(filter_model_converter, m); + fm->insert(q->get_decl()); + } + } + if (fm) { + m_model_converter = concat(m_model_converter.get(), fm.get()); + } + } + void context::to_fmls(expr_ref_vector& fmls) { m_objective_fns.reset(); fmls.append(m_hard_constraints); diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 5618efe7b..5ebb4db3f 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -213,6 +213,7 @@ namespace opt { void to_fmls(expr_ref_vector& fmls); void from_fmls(expr_ref_vector const& fmls); void simplify_fmls(expr_ref_vector& fmls); + void mk_atomic(expr_ref_vector& terms); void update_lower() { update_bound(true); } void update_bound(bool is_lower); @@ -224,6 +225,9 @@ namespace opt { struct is_bv; bool probe_bv(); + struct is_propositional_fn; + bool is_propositional(expr* e); + void init_solver(); void update_solver(); void setup_arith_solver(); diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index b4ad89a6e..2f0fc4661 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -82,6 +82,7 @@ namespace opt { } void opt_solver::set_logic(symbol const& logic) { + m_logic = logic; m_context.set_logic(logic); } From 52c6f7c3b10cefb33b624cfbfb5d0fc79c965502 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 6 Jan 2015 15:22:40 -0800 Subject: [PATCH 678/925] refine the safety check for leaving basis. As long as all base variables are unbounded in compatible directions as the non-basic variable we can detect unbounded variables. This partial check fixes integer divergence in a case exposed by Karpenov. Establishing or converting this to a check that always identifies unbounded integer variables is left for further analysis. Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith.h | 2 +- src/smt/theory_arith_aux.h | 21 +++++++++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 5936ca3d3..99a36c463 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -874,7 +874,7 @@ namespace smt { void add_tmp_row(row & r1, numeral const & coeff, row const & r2); theory_var pick_var_to_leave(bool has_int, theory_var x_j, bool inc, numeral & a_ij, inf_numeral & gain, bool& skiped_row); - bool is_safe_to_leave(theory_var x, bool& has_int, bool& is_shared); + bool is_safe_to_leave(theory_var x, bool inc, bool& has_int, bool& is_shared); bool move_to_bound(theory_var x_i, bool inc); template void add_tmp_row_entry(row & r, numeral const & coeff, theory_var v); diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 30c92feea..d377fb7ad 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -928,7 +928,7 @@ namespace smt { */ template - bool theory_arith::is_safe_to_leave(theory_var x, bool& has_int, bool& shared) { + bool theory_arith::is_safe_to_leave(theory_var x, bool inc, bool& has_int, bool& shared) { context& ctx = get_context(); shared |= ctx.is_shared(get_enode(x)); @@ -936,6 +936,8 @@ namespace smt { typename svector::iterator it = c.begin_entries(); typename svector::iterator end = c.end_entries(); has_int = false; + bool unbounded = (inc && !upper(x)) || (!inc && !lower(x)); + bool was_unsafe = false; for (; it != end; ++it) { if (it->is_dead()) continue; row const & r = m_rows[it->m_row_id]; @@ -944,19 +946,22 @@ namespace smt { if (s != null_theory_var && is_int(s)) has_int = true; bool is_unsafe = (s != null_theory_var && is_int(s) && !coeff.is_int()); shared |= (s != null_theory_var && ctx.is_shared(get_enode(s))); + was_unsafe |= is_unsafe; + bool inc_s = coeff.is_neg() ? inc : !inc; + unbounded &= !get_bound(s, inc_s); TRACE("opt", tout << "is v" << x << " safe to leave for v" << s - << "? " << (is_unsafe?"no":"yes") << " " << (has_int?"int":"real") << "\n"; + << "? " << (is_unsafe?"no":"yes") << " " << (has_int?"int":"real") << " " << (unbounded?"unbounded":"bounded") << "\n"; display_row(tout, r, true);); - if (is_unsafe) return false; + if (was_unsafe && !unbounded) return false; } - return true; + return !was_unsafe || unbounded; } template - theory_var theory_arith::pick_var_to_leave( - bool has_int, theory_var x_j, bool inc, - numeral & a_ij, inf_numeral & gain, bool& skipped_row) { + theory_var theory_arith::pick_var_to_leave( + bool has_int, theory_var x_j, bool inc, + numeral & a_ij, inf_numeral & gain, bool& skipped_row) { TRACE("opt", tout << "selecting variable to replace v" << x_j << ", inc: " << inc << "\n";); theory_var x_i = null_theory_var; inf_numeral curr_gain; @@ -1335,7 +1340,7 @@ namespace smt { bool has_int = false; if ((curr_inc && at_upper(curr_x_j)) || (!curr_inc && at_lower(curr_x_j))) continue; // variable cannot be used for max/min. - if (!is_safe_to_leave(curr_x_j, has_int, has_shared)) { + if (!is_safe_to_leave(curr_x_j, curr_inc, has_int, has_shared)) { skipped_row = true; continue; } From bd879c101647c294d15412baabee331b2df0563f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 Jan 2015 15:43:16 -0800 Subject: [PATCH 679/925] improve logging diagnostics and tracing Signed-off-by: Nikolaj Bjorner --- src/api/z3_replayer.cpp | 94 +++++++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 41 deletions(-) diff --git a/src/api/z3_replayer.cpp b/src/api/z3_replayer.cpp index f13b2cbb8..dd18f865c 100644 --- a/src/api/z3_replayer.cpp +++ b/src/api/z3_replayer.cpp @@ -22,12 +22,14 @@ Notes: #include"stream_buffer.h" #include"symbol.h" #include"trace.h" +#include void register_z3_replayer_cmds(z3_replayer & in); + void throw_invalid_reference() { TRACE("z3_replayer", tout << "invalid argument reference\n";); - throw z3_replayer_exception("invalid argument reference"); + throw z3_replayer_exception("invalid argument reference1"); } struct z3_replayer::imp { @@ -46,6 +48,36 @@ struct z3_replayer::imp { enum value_kind { INT64, UINT64, DOUBLE, STRING, SYMBOL, OBJECT, UINT_ARRAY, INT_ARRAY, SYMBOL_ARRAY, OBJECT_ARRAY }; + char const* kind2string(value_kind k) const { + switch (k) { + case INT64: return "int64"; + case UINT64: return "uint64"; + case DOUBLE: return "double"; + case STRING: return "string"; + case SYMBOL: return "symbol"; + case OBJECT: return "object"; + case UINT_ARRAY: return "uint_array"; + case INT_ARRAY: return "int_array"; + case SYMBOL_ARRAY: return "symbol_array"; + case OBJECT_ARRAY: return "object_array"; + default: UNREACHABLE(); return "unknown"; + } + } + + + void check_arg(unsigned pos, value_kind k) const { + if (pos >= m_args.size()) { + TRACE("z3_replayer", tout << "too few arguments " << m_args.size() << " expecting " << kind2string(k) << "\n";); + throw z3_replayer_exception("invalid argument reference2"); + } + if (m_args[pos].m_kind != k) { + std::stringstream strm; + strm << "expecting " << kind2string(k) << " at position " + << pos << " but got " << kind2string(m_args[pos].m_kind); + throw z3_replayer_exception(strm.str().c_str()); + } + } + struct value { value_kind m_kind; union { @@ -467,8 +499,7 @@ struct z3_replayer::imp { next(); skip_blank(); read_ptr(); skip_blank(); read_uint64(); unsigned pos = static_cast(m_uint64); TRACE("z3_replayer", tout << "[" << m_line << "] " << "* " << m_ptr << " " << pos << "\n";); - if (pos >= m_args.size() || m_args[pos].m_kind != OBJECT) - throw_invalid_reference(); + check_arg(pos, OBJECT); m_heap.insert(m_ptr, m_args[pos].m_obj); break; } @@ -477,8 +508,7 @@ struct z3_replayer::imp { // @ obj_id array_pos idx next(); skip_blank(); read_ptr(); skip_blank(); read_uint64(); unsigned pos = static_cast(m_uint64); - if (pos >= m_args.size() || m_args[pos].m_kind != OBJECT_ARRAY) - throw_invalid_reference(); + check_arg(pos, OBJECT_ARRAY); unsigned aidx = static_cast(m_args[pos].m_uint); ptr_vector & v = m_obj_arrays[aidx]; skip_blank(); read_uint64(); @@ -503,77 +533,65 @@ struct z3_replayer::imp { } int get_int(unsigned pos) const { - if (pos >= m_args.size() || m_args[pos].m_kind != INT64) - throw_invalid_reference(); + check_arg(pos, INT64); return static_cast(m_args[pos].m_int); } __int64 get_int64(unsigned pos) const { - if (pos >= m_args.size() || m_args[pos].m_kind != INT64) - throw_invalid_reference(); + check_arg(pos, INT64); return m_args[pos].m_int; } unsigned get_uint(unsigned pos) const { - if (pos >= m_args.size() || m_args[pos].m_kind != UINT64) - throw_invalid_reference(); + check_arg(pos, UINT64); return static_cast(m_args[pos].m_uint); } __uint64 get_uint64(unsigned pos) const { - if (pos >= m_args.size() || m_args[pos].m_kind != UINT64) - throw_invalid_reference(); + check_arg(pos, UINT64); return m_args[pos].m_uint; } double get_double(unsigned pos) const { - if (pos >= m_args.size() || m_args[pos].m_kind != DOUBLE) - throw_invalid_reference(); + check_arg(pos, DOUBLE); return m_args[pos].m_double; } Z3_string get_str(unsigned pos) const { - if (pos >= m_args.size() || m_args[pos].m_kind != STRING) - throw_invalid_reference(); + check_arg(pos, STRING); return m_args[pos].m_str; } Z3_symbol get_symbol(unsigned pos) const { - if (pos >= m_args.size() || m_args[pos].m_kind != SYMBOL) - throw_invalid_reference(); + check_arg(pos, SYMBOL); return reinterpret_cast(const_cast(m_args[pos].m_str)); } void * get_obj(unsigned pos) const { - if (pos >= m_args.size() || m_args[pos].m_kind != OBJECT) - throw_invalid_reference(); + check_arg(pos, OBJECT); return m_args[pos].m_obj; } unsigned * get_uint_array(unsigned pos) const { - if (pos >= m_args.size() || m_args[pos].m_kind != UINT_ARRAY) - throw_invalid_reference(); + check_arg(pos, UINT_ARRAY); unsigned idx = static_cast(m_args[pos].m_uint); return m_unsigned_arrays[idx].c_ptr(); } int * get_int_array(unsigned pos) const { - if (pos >= m_args.size() || m_args[pos].m_kind != INT_ARRAY) - throw_invalid_reference(); + check_arg(pos, INT_ARRAY); unsigned idx = static_cast(m_args[pos].m_uint); return m_int_arrays[idx].c_ptr(); } Z3_symbol * get_symbol_array(unsigned pos) const { - if (pos >= m_args.size() || m_args[pos].m_kind != SYMBOL_ARRAY) - throw_invalid_reference(); + check_arg(pos, SYMBOL_ARRAY); unsigned idx = static_cast(m_args[pos].m_uint); return m_sym_arrays[idx].c_ptr(); } void ** get_obj_array(unsigned pos) const { - if (pos >= m_args.size() || m_args[pos].m_kind != OBJECT_ARRAY) - throw_invalid_reference(); + check_arg(pos, OBJECT_ARRAY); unsigned idx = static_cast(m_args[pos].m_uint); ptr_vector const & v = m_obj_arrays[idx]; TRACE("z3_replayer_bug", tout << "pos: " << pos << ", idx: " << idx << " size(): " << v.size() << "\n"; @@ -582,38 +600,32 @@ struct z3_replayer::imp { } int * get_int_addr(unsigned pos) { - if (pos >= m_args.size() || m_args[pos].m_kind != INT64) - throw_invalid_reference(); + check_arg(pos, INT64); return reinterpret_cast(&(m_args[pos].m_int)); } __int64 * get_int64_addr(unsigned pos) { - if (pos >= m_args.size() || m_args[pos].m_kind != INT64) - throw_invalid_reference(); + check_arg(pos, INT64); return &(m_args[pos].m_int); } unsigned * get_uint_addr(unsigned pos) { - if (pos >= m_args.size() || m_args[pos].m_kind != UINT64) - throw_invalid_reference(); + check_arg(pos, UINT64); return reinterpret_cast(&(m_args[pos].m_uint)); } __uint64 * get_uint64_addr(unsigned pos) { - if (pos >= m_args.size() || m_args[pos].m_kind != UINT64) - throw_invalid_reference(); + check_arg(pos, UINT64); return &(m_args[pos].m_uint); } Z3_string * get_str_addr(unsigned pos) { - if (pos >= m_args.size() || m_args[pos].m_kind != STRING) - throw_invalid_reference(); + check_arg(pos, STRING); return &(m_args[pos].m_str); } void ** get_obj_addr(unsigned pos) { - if (pos >= m_args.size() || m_args[pos].m_kind != OBJECT) - throw_invalid_reference(); + check_arg(pos, OBJECT); return &(m_args[pos].m_obj); } From e28701a64c13e1eaa20fa3d8352a1ee70ee80328 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 14 Jan 2015 22:09:48 +0530 Subject: [PATCH 680/925] add assertions to simplifier Signed-off-by: Nikolaj Bjorner --- src/ast/macros/macro_manager.cpp | 14 +- src/ast/pattern/pattern_inference.cpp | 96 ++++++------ src/ast/pattern/pattern_inference.h | 8 +- src/ast/simplifier/base_simplifier.h | 21 ++- src/ast/simplifier/bv_elim.cpp | 8 +- src/ast/simplifier/elim_bounds.cpp | 12 +- src/ast/simplifier/pull_ite_tree.cpp | 10 +- src/ast/simplifier/push_app_ite.cpp | 36 ++--- src/ast/simplifier/simplifier.cpp | 148 ++++++++++--------- src/ast/simplifier/simplifier.h | 2 +- src/qe/qe.cpp | 2 - src/smt/elim_term_ite.cpp | 40 ++--- src/smt/theory_arith.h | 2 + src/smt/theory_arith_aux.h | 205 +++++++++++++++++++++++--- 14 files changed, 391 insertions(+), 213 deletions(-) diff --git a/src/ast/macros/macro_manager.cpp b/src/ast/macros/macro_manager.cpp index abcc97882..75b4e55f4 100644 --- a/src/ast/macros/macro_manager.cpp +++ b/src/ast/macros/macro_manager.cpp @@ -255,9 +255,9 @@ bool macro_manager::macro_expander::get_subst(expr * _n, expr_ref & r, proof_ref app * n = to_app(_n); quantifier * q = 0; func_decl * d = n->get_decl(); - TRACE("macro_manager_bug", tout << "trying to expand:\n" << mk_pp(n, m_manager) << "\nd:\n" << d->get_name() << "\n";); + TRACE("macro_manager_bug", tout << "trying to expand:\n" << mk_pp(n, m) << "\nd:\n" << d->get_name() << "\n";); if (m_macro_manager.m_decl2macro.find(d, q)) { - TRACE("macro_manager", tout << "expanding: " << mk_pp(n, m_manager) << "\n";); + TRACE("macro_manager", tout << "expanding: " << mk_pp(n, m) << "\n";); app * head = 0; expr * def = 0; m_macro_manager.get_head_def(q, d, head, def); @@ -272,17 +272,17 @@ bool macro_manager::macro_expander::get_subst(expr * _n, expr_ref & r, proof_ref SASSERT(subst_args[nidx] == 0); subst_args[nidx] = n->get_arg(i); } - var_subst s(m_manager); + var_subst s(m); s(def, num, subst_args.c_ptr(), r); - if (m_manager.proofs_enabled()) { - expr_ref instance(m_manager); + if (m.proofs_enabled()) { + expr_ref instance(m); s(q->get_expr(), num, subst_args.c_ptr(), instance); - proof * qi_pr = m_manager.mk_quant_inst(m_manager.mk_or(m_manager.mk_not(q), instance), num, subst_args.c_ptr()); + proof * qi_pr = m.mk_quant_inst(m.mk_or(m.mk_not(q), instance), num, subst_args.c_ptr()); proof * q_pr = 0; m_macro_manager.m_decl2macro_pr.find(d, q_pr); SASSERT(q_pr != 0); proof * prs[2] = { qi_pr, q_pr }; - p = m_manager.mk_unit_resolution(2, prs); + p = m.mk_unit_resolution(2, prs); } else { p = 0; diff --git a/src/ast/pattern/pattern_inference.cpp b/src/ast/pattern/pattern_inference.cpp index 83362f5b3..b93dd7657 100644 --- a/src/ast/pattern/pattern_inference.cpp +++ b/src/ast/pattern/pattern_inference.cpp @@ -116,7 +116,7 @@ void pattern_inference::collect::operator()(expr * n, unsigned num_bindings) { n = e.m_node; unsigned delta = e.m_delta; TRACE("collect", tout << "processing: " << n->get_id() << " " << delta << " kind: " << n->get_kind() << "\n";); - TRACE("collect_info", tout << mk_pp(n, m_manager) << "\n";); + TRACE("collect_info", tout << mk_pp(n, m) << "\n";); if (visit_children(n, delta)) { m_todo.pop_back(); save_candidate(n, delta); @@ -170,9 +170,9 @@ void pattern_inference::collect::save_candidate(expr * n, unsigned delta) { free_vars.insert(idx); info * i = 0; if (delta == 0) - i = alloc(info, m_manager, n, free_vars, 1); + i = alloc(info, m, n, free_vars, 1); else - i = alloc(info, m_manager, m_manager.mk_var(idx, to_var(n)->get_sort()), free_vars, 1); + i = alloc(info, m, m.mk_var(idx, to_var(n)->get_sort()), free_vars, 1); save(n, delta, i); } else { @@ -189,7 +189,7 @@ void pattern_inference::collect::save_candidate(expr * n, unsigned delta) { } if (c->get_num_args() == 0) { - save(n, delta, alloc(info, m_manager, n, uint_set(), 1)); + save(n, delta, alloc(info, m, n, uint_set(), 1)); return; } @@ -219,10 +219,10 @@ void pattern_inference::collect::save_candidate(expr * n, unsigned delta) { app * new_node = 0; if (changed) - new_node = m_manager.mk_app(decl, buffer.size(), buffer.c_ptr()); + new_node = m.mk_app(decl, buffer.size(), buffer.c_ptr()); else new_node = to_app(n); - save(n, delta, alloc(info, m_manager, new_node, free_vars, size)); + save(n, delta, alloc(info, m, new_node, free_vars, size)); // Remark: arithmetic patterns are only used if they are nested inside other terms. // That is, we never consider x + 1 as pattern. On the other hand, f(x+1) can be a pattern // if arithmetic is not in the forbidden list. @@ -235,7 +235,7 @@ void pattern_inference::collect::save_candidate(expr * n, unsigned delta) { decl_kind k = c->get_decl_kind(); if (!free_vars.empty() && (fid != m_afid || (fid == m_afid && !m_owner.m_nested_arith_only && (k == OP_DIV || k == OP_IDIV || k == OP_MOD || k == OP_REM || k == OP_MUL)))) { - TRACE("pattern_inference", tout << "potential candidate: \n" << mk_pp(new_node, m_manager) << "\n";); + TRACE("pattern_inference", tout << "potential candidate: \n" << mk_pp(new_node, m) << "\n";); m_owner.add_candidate(new_node, free_vars, size); } return; @@ -338,7 +338,7 @@ bool pattern_inference::contains_subpattern::operator()(expr * n) { uint_set const & s2 = e->get_data().m_value.m_free_vars; SASSERT(s2.subset_of(s1)); if (s1 == s2) { - TRACE("pattern_inference", tout << mk_pp(n, m_owner.m_manager) << "\nis bigger than\n" << mk_pp(to_app(curr), m_owner.m_manager) << "\n";); + TRACE("pattern_inference", tout << mk_pp(n, m_owner.m) << "\nis bigger than\n" << mk_pp(to_app(curr), m_owner.m) << "\n";); return true; } } @@ -411,7 +411,7 @@ void pattern_inference::candidates2unary_patterns(ptr_vector const & candid expr2info::obj_map_entry * e = m_candidates_info.find_core(candidate); info const & i = e->get_data().m_value; if (i.m_free_vars.num_elems() == m_num_bindings) { - app * new_pattern = m_manager.mk_pattern(candidate); + app * new_pattern = m.mk_pattern(candidate); result.push_back(new_pattern); } else { @@ -435,7 +435,7 @@ void pattern_inference::candidates2multi_patterns(unsigned max_num_patterns, for (unsigned j = 0; j < m_pre_patterns.size(); j++) { pre_pattern * curr = m_pre_patterns[j]; if (curr->m_free_vars.num_elems() == m_num_bindings) { - app * new_pattern = m_manager.mk_pattern(curr->m_exprs.size(), curr->m_exprs.c_ptr()); + app * new_pattern = m.mk_pattern(curr->m_exprs.size(), curr->m_exprs.c_ptr()); result.push_back(new_pattern); if (result.size() >= max_num_patterns) return; @@ -489,7 +489,7 @@ bool pattern_inference::is_forbidden(app * n) const { // occur outside of the quantifier. That is, Z3 will never match this kind of // pattern. if (m_params.m_pi_avoid_skolems && decl->is_skolem()) { - CTRACE("pattern_inference_skolem", decl->is_skolem(), tout << "ignoring: " << mk_pp(n, m_manager) << "\n";); + CTRACE("pattern_inference_skolem", decl->is_skolem(), tout << "ignoring: " << mk_pp(n, m) << "\n";); return true; } if (is_forbidden(decl)) @@ -509,8 +509,8 @@ bool pattern_inference::has_preferred_patterns(ptr_vector & candidate_patte expr2info::obj_map_entry * e = m_candidates_info.find_core(candidate); info const & i = e->get_data().m_value; if (i.m_free_vars.num_elems() == m_num_bindings) { - TRACE("pattern_inference", tout << "found preferred pattern:\n" << mk_pp(candidate, m_manager) << "\n";); - app * p = m_manager.mk_pattern(candidate); + TRACE("pattern_inference", tout << "found preferred pattern:\n" << mk_pp(candidate, m) << "\n";); + app * p = m.mk_pattern(candidate); result.push_back(p); found = true; } @@ -531,11 +531,11 @@ void pattern_inference::mk_patterns(unsigned num_bindings, m_collect(n, num_bindings); TRACE("pattern_inference", - tout << mk_pp(n, m_manager); + tout << mk_pp(n, m); tout << "\ncandidates:\n"; unsigned num = m_candidates.size(); for (unsigned i = 0; i < num; i++) { - tout << mk_pp(m_candidates.get(i), m_manager) << "\n"; + tout << mk_pp(m_candidates.get(i), m) << "\n"; }); if (!m_candidates.empty()) { @@ -543,7 +543,7 @@ void pattern_inference::mk_patterns(unsigned num_bindings, filter_looping_patterns(m_tmp1); TRACE("pattern_inference", tout << "candidates after removing looping-patterns:\n"; - dump_app_vector(tout, m_tmp1, m_manager);); + dump_app_vector(tout, m_tmp1, m);); SASSERT(!m_tmp1.empty()); if (!has_preferred_patterns(m_tmp1, result)) { // continue if there are no preferred patterns @@ -552,7 +552,7 @@ void pattern_inference::mk_patterns(unsigned num_bindings, SASSERT(!m_tmp2.empty()); TRACE("pattern_inference", tout << "candidates after removing bigger patterns:\n"; - dump_app_vector(tout, m_tmp2, m_manager);); + dump_app_vector(tout, m_tmp2, m);); m_tmp1.reset(); candidates2unary_patterns(m_tmp2, m_tmp1, result); unsigned num_extra_multi_patterns = m_params.m_pi_max_multi_patterns; @@ -563,7 +563,7 @@ void pattern_inference::mk_patterns(unsigned num_bindings, std::stable_sort(m_tmp1.begin(), m_tmp1.end(), m_pattern_weight_lt); TRACE("pattern_inference", tout << "candidates after sorting:\n"; - dump_app_vector(tout, m_tmp1, m_manager);); + dump_app_vector(tout, m_tmp1, m);); candidates2multi_patterns(num_extra_multi_patterns, m_tmp1, result); } } @@ -577,7 +577,7 @@ void pattern_inference::mk_patterns(unsigned num_bindings, #include"database.h" // defines g_pattern_database void pattern_inference::reduce1_quantifier(quantifier * q) { - TRACE("pattern_inference", tout << "processing:\n" << mk_pp(q, m_manager) << "\n";); + TRACE("pattern_inference", tout << "processing:\n" << mk_pp(q, m) << "\n";); if (!q->is_forall()) { simplifier::reduce1_quantifier(q); return; @@ -587,27 +587,27 @@ void pattern_inference::reduce1_quantifier(quantifier * q) { if (m_params.m_pi_use_database) { m_database.initialize(g_pattern_database); - app_ref_vector new_patterns(m_manager); + app_ref_vector new_patterns(m); unsigned new_weight; if (m_database.match_quantifier(q, new_patterns, new_weight)) { #ifdef Z3DEBUG - for (unsigned i = 0; i < new_patterns.size(); i++) { SASSERT(is_well_sorted(m_manager, new_patterns.get(i))); } + for (unsigned i = 0; i < new_patterns.size(); i++) { SASSERT(is_well_sorted(m, new_patterns.get(i))); } #endif - quantifier_ref new_q(m_manager); + quantifier_ref new_q(m); if (q->get_num_patterns() > 0) { // just update the weight... - TRACE("pattern_inference", tout << "updating weight to: " << new_weight << "\n" << mk_pp(q, m_manager) << "\n";); - new_q = m_manager.update_quantifier_weight(q, new_weight); + TRACE("pattern_inference", tout << "updating weight to: " << new_weight << "\n" << mk_pp(q, m) << "\n";); + new_q = m.update_quantifier_weight(q, new_weight); } else { - quantifier_ref tmp(m_manager); - tmp = m_manager.update_quantifier(q, new_patterns.size(), (expr**) new_patterns.c_ptr(), q->get_expr()); - new_q = m_manager.update_quantifier_weight(tmp, new_weight); - TRACE("pattern_inference", tout << "found patterns in database, weight: " << new_weight << "\n" << mk_pp(new_q, m_manager) << "\n";); + quantifier_ref tmp(m); + tmp = m.update_quantifier(q, new_patterns.size(), (expr**) new_patterns.c_ptr(), q->get_expr()); + new_q = m.update_quantifier_weight(tmp, new_weight); + TRACE("pattern_inference", tout << "found patterns in database, weight: " << new_weight << "\n" << mk_pp(new_q, m) << "\n";); } proof * pr = 0; - if (m_manager.fine_grain_proofs()) - pr = m_manager.mk_rewrite(q, new_q); + if (m.fine_grain_proofs()) + pr = m.mk_rewrite(q, new_q); cache_result(q, new_q, pr); return; } @@ -635,7 +635,7 @@ void pattern_inference::reduce1_quantifier(quantifier * q) { new_no_patterns.push_back(new_pattern); } - app_ref_buffer new_patterns(m_manager); + app_ref_buffer new_patterns(m); if (m_params.m_pi_arith == AP_CONSERVATIVE) m_forbidden.push_back(m_afid); @@ -677,26 +677,26 @@ void pattern_inference::reduce1_quantifier(quantifier * q) { warning_msg("using non nested arith. pattern (quantifier id: %s), the weight was increased to %d (this value can be modified using PI_NON_NESTED_ARITH_WEIGHT=).", q->get_qid().str().c_str(), weight); } - // verbose_stream() << mk_pp(q, m_manager) << "\n"; + // verbose_stream() << mk_pp(q, m) << "\n"; } } } - quantifier_ref new_q(m_manager); - new_q = m_manager.update_quantifier(q, new_patterns.size(), (expr**) new_patterns.c_ptr(), new_body); + quantifier_ref new_q(m); + new_q = m.update_quantifier(q, new_patterns.size(), (expr**) new_patterns.c_ptr(), new_body); if (weight != q->get_weight()) - new_q = m_manager.update_quantifier_weight(new_q, weight); - proof_ref pr(m_manager); - if (m_manager.fine_grain_proofs()) { + new_q = m.update_quantifier_weight(new_q, weight); + proof_ref pr(m); + if (m.fine_grain_proofs()) { if (new_body_pr == 0) - new_body_pr = m_manager.mk_reflexivity(new_body); - pr = m_manager.mk_quant_intro(q, new_q, new_body_pr); + new_body_pr = m.mk_reflexivity(new_body); + pr = m.mk_quant_intro(q, new_q, new_body_pr); } if (new_patterns.empty() && m_params.m_pi_pull_quantifiers) { - pull_quant pull(m_manager); - expr_ref new_expr(m_manager); - proof_ref new_pr(m_manager); + pull_quant pull(m); + expr_ref new_expr(m); + proof_ref new_pr(m); pull(new_q, new_expr, new_pr); quantifier * new_new_q = to_quantifier(new_expr); if (new_new_q != new_q) { @@ -705,12 +705,12 @@ void pattern_inference::reduce1_quantifier(quantifier * q) { if (m_params.m_pi_warnings) { warning_msg("pulled nested quantifier to be able to find an useable pattern (quantifier id: %s)", q->get_qid().str().c_str()); } - new_q = m_manager.update_quantifier(new_new_q, new_patterns.size(), (expr**) new_patterns.c_ptr(), new_new_q->get_expr()); - if (m_manager.fine_grain_proofs()) { - pr = m_manager.mk_transitivity(pr, new_pr); - pr = m_manager.mk_transitivity(pr, m_manager.mk_quant_intro(new_new_q, new_q, m_manager.mk_reflexivity(new_q->get_expr()))); + new_q = m.update_quantifier(new_new_q, new_patterns.size(), (expr**) new_patterns.c_ptr(), new_new_q->get_expr()); + if (m.fine_grain_proofs()) { + pr = m.mk_transitivity(pr, new_pr); + pr = m.mk_transitivity(pr, m.mk_quant_intro(new_new_q, new_q, m.mk_reflexivity(new_q->get_expr()))); } - TRACE("pattern_inference", tout << "pulled quantifier:\n" << mk_pp(new_q, m_manager) << "\n";); + TRACE("pattern_inference", tout << "pulled quantifier:\n" << mk_pp(new_q, m) << "\n";); } } } @@ -719,7 +719,7 @@ void pattern_inference::reduce1_quantifier(quantifier * q) { if (m_params.m_pi_warnings) { warning_msg("failed to find a pattern for quantifier (quantifier id: %s)", q->get_qid().str().c_str()); } - TRACE("pi_failed", tout << mk_pp(q, m_manager) << "\n";); + TRACE("pi_failed", tout << mk_pp(q, m) << "\n";); } if (new_patterns.empty() && new_body == q->get_expr()) { diff --git a/src/ast/pattern/pattern_inference.h b/src/ast/pattern/pattern_inference.h index 97897835c..152f7f459 100644 --- a/src/ast/pattern/pattern_inference.h +++ b/src/ast/pattern/pattern_inference.h @@ -38,7 +38,7 @@ Revision History: every instance of f(g(X)) is also an instance of f(X). */ class smaller_pattern { - ast_manager & m_manager; + ast_manager & m; ptr_vector m_bindings; typedef std::pair expr_pair; @@ -54,7 +54,7 @@ class smaller_pattern { public: smaller_pattern(ast_manager & m): - m_manager(m) { + m(m) { } bool operator()(unsigned num_bindings, expr * p1, expr * p2); @@ -135,7 +135,7 @@ class pattern_inference : public simplifier { m_node(n, m), m_free_vars(vars), m_size(sz) {} }; - ast_manager & m_manager; + ast_manager & m; pattern_inference & m_owner; family_id m_afid; unsigned m_num_bindings; @@ -150,7 +150,7 @@ class pattern_inference : public simplifier { void save_candidate(expr * n, unsigned delta); void reset(); public: - collect(ast_manager & m, pattern_inference & o):m_manager(m), m_owner(o), m_afid(m.mk_family_id("arith")) {} + collect(ast_manager & m, pattern_inference & o):m(m), m_owner(o), m_afid(m.mk_family_id("arith")) {} void operator()(expr * n, unsigned num_bindings); }; diff --git a/src/ast/simplifier/base_simplifier.h b/src/ast/simplifier/base_simplifier.h index 4afe5c9d7..5ebcdc30e 100644 --- a/src/ast/simplifier/base_simplifier.h +++ b/src/ast/simplifier/base_simplifier.h @@ -26,11 +26,14 @@ Notes: */ class base_simplifier { protected: - ast_manager & m_manager; + ast_manager & m; expr_map m_cache; ptr_vector m_todo; - void cache_result(expr * n, expr * r, proof * p) { m_cache.insert(n, r, p); } + void cache_result(expr * n, expr * r, proof * p) { + m_cache.insert(n, r, p); + SASSERT(is_rewrite_proof(n, r, p)); + } void reset_cache() { m_cache.reset(); } void flush_cache() { m_cache.flush(); } void get_cached(expr * n, expr * & r, proof * & p) const { m_cache.get(n, r, p); } @@ -44,11 +47,21 @@ protected: public: base_simplifier(ast_manager & m): - m_manager(m), + m(m), m_cache(m, m.fine_grain_proofs()) { } bool is_cached(expr * n) const { return m_cache.contains(n); } - ast_manager & get_manager() { return m_manager; } + ast_manager & get_manager() { return m; } + + bool is_rewrite_proof(expr* n, expr* r, proof* p) { + if (p && + !(m.has_fact(p) && + (m.is_eq(m.get_fact(p)) || m.is_oeq(m.get_fact(p)) || m.is_iff(m.get_fact(p))) && + to_app(m.get_fact(p))->get_arg(0) == n && + to_app(m.get_fact(p))->get_arg(1) == r)) return false; + + return (!m.fine_grain_proofs() || p || (n == r)); + } }; #endif /* _BASE_SIMPLIFIER_H_ */ diff --git a/src/ast/simplifier/bv_elim.cpp b/src/ast/simplifier/bv_elim.cpp index 5c19a245e..fc4e7534b 100644 --- a/src/ast/simplifier/bv_elim.cpp +++ b/src/ast/simplifier/bv_elim.cpp @@ -100,11 +100,11 @@ bool bv_elim_star::visit_quantifier(quantifier* q) { } void bv_elim_star::reduce1_quantifier(quantifier* q) { - quantifier_ref r(m_manager); - proof_ref pr(m_manager); + quantifier_ref r(m); + proof_ref pr(m); m_bv_elim.elim(q, r); - if (m_manager.fine_grain_proofs()) { - pr = m_manager.mk_rewrite(q, r.get()); + if (m.fine_grain_proofs()) { + pr = m.mk_rewrite(q, r.get()); } else { pr = 0; diff --git a/src/ast/simplifier/elim_bounds.cpp b/src/ast/simplifier/elim_bounds.cpp index ce15d9eb1..41ce18549 100644 --- a/src/ast/simplifier/elim_bounds.cpp +++ b/src/ast/simplifier/elim_bounds.cpp @@ -203,20 +203,20 @@ void elim_bounds_star::reduce1_quantifier(quantifier * q) { cache_result(q, q, 0); return; } - quantifier_ref new_q(m_manager); + quantifier_ref new_q(m); expr * new_body = 0; proof * new_pr; get_cached(q->get_expr(), new_body, new_pr); - new_q = m_manager.update_quantifier(q, new_body); - expr_ref r(m_manager); + new_q = m.update_quantifier(q, new_body); + expr_ref r(m); m_elim(new_q, r); if (q == r.get()) { cache_result(q, q, 0); return; } - proof_ref pr(m_manager); - if (m_manager.fine_grain_proofs()) - pr = m_manager.mk_rewrite(q, r); // TODO: improve justification + proof_ref pr(m); + if (m.fine_grain_proofs()) + pr = m.mk_rewrite(q, r); // TODO: improve justification cache_result(q, r, pr); } diff --git a/src/ast/simplifier/pull_ite_tree.cpp b/src/ast/simplifier/pull_ite_tree.cpp index 080dd5545..05bb3d885 100644 --- a/src/ast/simplifier/pull_ite_tree.cpp +++ b/src/ast/simplifier/pull_ite_tree.cpp @@ -187,7 +187,7 @@ pull_ite_tree_star::pull_ite_tree_star(ast_manager & m, simplifier & s): bool pull_ite_tree_star::get_subst(expr * n, expr_ref & r, proof_ref & p) { if (is_app(n) && is_target(to_app(n))) { - app_ref tmp(m_manager); + app_ref tmp(m); m_proc(to_app(n), tmp, p); r = tmp; return true; @@ -199,10 +199,10 @@ bool pull_cheap_ite_tree_star::is_target(app * n) const { bool r = n->get_num_args() == 2 && n->get_family_id() != null_family_id && - m_manager.is_bool(n) && - (m_manager.is_value(n->get_arg(0)) || m_manager.is_value(n->get_arg(1))) && - (m_manager.is_term_ite(n->get_arg(0)) || m_manager.is_term_ite(n->get_arg(1))); - TRACE("pull_ite_target", tout << mk_pp(n, m_manager) << "\nresult: " << r << "\n";); + m.is_bool(n) && + (m.is_value(n->get_arg(0)) || m.is_value(n->get_arg(1))) && + (m.is_term_ite(n->get_arg(0)) || m.is_term_ite(n->get_arg(1))); + TRACE("pull_ite_target", tout << mk_pp(n, m) << "\nresult: " << r << "\n";); return r; } diff --git a/src/ast/simplifier/push_app_ite.cpp b/src/ast/simplifier/push_app_ite.cpp index cec84d1f5..e33f0d094 100644 --- a/src/ast/simplifier/push_app_ite.cpp +++ b/src/ast/simplifier/push_app_ite.cpp @@ -34,7 +34,7 @@ push_app_ite::~push_app_ite() { int push_app_ite::has_ite_arg(unsigned num_args, expr * const * args) { for (unsigned i = 0; i < num_args; i++) - if (m_manager.is_ite(args[i])) + if (m.is_ite(args[i])) return i; return -1; } @@ -53,10 +53,10 @@ void push_app_ite::apply(func_decl * decl, unsigned num_args, expr * const * arg expr ** args_prime = const_cast(args); expr * old = args_prime[ite_arg_idx]; args_prime[ite_arg_idx] = t; - expr_ref t_new(m_manager); + expr_ref t_new(m); apply(decl, num_args, args_prime, t_new); args_prime[ite_arg_idx] = e; - expr_ref e_new(m_manager); + expr_ref e_new(m); apply(decl, num_args, args_prime, e_new); args_prime[ite_arg_idx] = old; expr * new_args[3] = { c, t_new, e_new }; @@ -67,11 +67,11 @@ void push_app_ite::apply(func_decl * decl, unsigned num_args, expr * const * arg \brief Default (conservative) implementation. Return true if there one and only one ite-term argument. */ bool push_app_ite::is_target(func_decl * decl, unsigned num_args, expr * const * args) { - if (m_manager.is_ite(decl)) + if (m.is_ite(decl)) return false; bool found_ite = false; for (unsigned i = 0; i < num_args; i++) { - if (m_manager.is_ite(args[i]) && !m_manager.is_bool(args[i])) { + if (m.is_ite(args[i]) && !m.is_bool(args[i])) { if (found_ite) { if (m_conservative) return false; @@ -83,7 +83,7 @@ bool push_app_ite::is_target(func_decl * decl, unsigned num_args, expr * const * } CTRACE("push_app_ite", found_ite, tout << "found target for push app ite:\n"; tout << decl->get_name(); - for (unsigned i = 0; i < num_args; i++) tout << " " << mk_pp(args[i], m_manager); + for (unsigned i = 0; i < num_args; i++) tout << " " << mk_pp(args[i], m); tout << "\n";); return found_ite; } @@ -94,19 +94,19 @@ void push_app_ite::operator()(expr * s, expr_ref & r, proof_ref & p) { reduce_core(s); get_cached(s, result, result_proof); r = result; - switch (m_manager.proof_mode()) { + switch (m.proof_mode()) { case PGM_DISABLED: - p = m_manager.mk_undef_proof(); + p = m.mk_undef_proof(); break; case PGM_COARSE: if (result == s) - p = m_manager.mk_reflexivity(s); + p = m.mk_reflexivity(s); else - p = m_manager.mk_rewrite_star(s, result, 0, 0); + p = m.mk_rewrite_star(s, result, 0, 0); break; case PGM_FINE: if (result == s) - p = m_manager.mk_reflexivity(s); + p = m.mk_reflexivity(s); else p = result_proof; break; @@ -171,24 +171,24 @@ void push_app_ite::reduce1_app(app * n) { m_args.reset(); func_decl * decl = n->get_decl(); - proof_ref p1(m_manager); + proof_ref p1(m); get_args(n, m_args, p1); - expr_ref r(m_manager); + expr_ref r(m); if (is_target(decl, m_args.size(), m_args.c_ptr())) apply(decl, m_args.size(), m_args.c_ptr(), r); else mk_app(decl, m_args.size(), m_args.c_ptr(), r); - if (!m_manager.fine_grain_proofs()) + if (!m.fine_grain_proofs()) cache_result(n, r, 0); else { - expr * s = m_manager.mk_app(decl, m_args.size(), m_args.c_ptr()); + expr * s = m.mk_app(decl, m_args.size(), m_args.c_ptr()); proof * p; if (n == r) p = 0; else if (r != s) - p = m_manager.mk_transitivity(p1, m_manager.mk_rewrite(s, r)); + p = m.mk_transitivity(p1, m.mk_rewrite(s, r)); else p = p1; cache_result(n, r, p); @@ -200,8 +200,8 @@ void push_app_ite::reduce1_quantifier(quantifier * q) { proof * new_body_pr; get_cached(q->get_expr(), new_body, new_body_pr); - quantifier * new_q = m_manager.update_quantifier(q, new_body); - proof * p = q == new_q ? 0 : m_manager.mk_quant_intro(q, new_q, new_body_pr); + quantifier * new_q = m.update_quantifier(q, new_body); + proof * p = q == new_q ? 0 : m.mk_quant_intro(q, new_q, new_body_pr); cache_result(q, new_q, p); } diff --git a/src/ast/simplifier/simplifier.cpp b/src/ast/simplifier/simplifier.cpp index c9f72f4d5..fcd4e91b6 100644 --- a/src/ast/simplifier/simplifier.cpp +++ b/src/ast/simplifier/simplifier.cpp @@ -61,16 +61,17 @@ void simplifier::enable_ac_support(bool flag) { */ void simplifier::operator()(expr * s, expr_ref & r, proof_ref & p) { m_need_reset = true; + expr * s_orig = s; expr * old_s; expr * result; proof * result_proof; - switch (m_manager.proof_mode()) { + switch (m.proof_mode()) { case PGM_DISABLED: // proof generation is disabled. reduce_core(s); // after executing reduce_core, the result of the simplification is in the cache get_cached(s, result, result_proof); r = result; - p = m_manager.mk_undef_proof(); + p = m.mk_undef_proof(); break; case PGM_COARSE: // coarse proofs... in this case, we do not produce a step by step (fine grain) proof to show the equivalence (or equisatisfiability) of s an r. m_subst_proofs.reset(); // m_subst_proofs is an auxiliary vector that is used to justify substitutions. See comment on method get_subst. @@ -78,10 +79,10 @@ void simplifier::operator()(expr * s, expr_ref & r, proof_ref & p) { get_cached(s, result, result_proof); r = result; if (result == s) - p = m_manager.mk_reflexivity(s); + p = m.mk_reflexivity(s); else { remove_duplicates(m_subst_proofs); - p = m_manager.mk_rewrite_star(s, result, m_subst_proofs.size(), m_subst_proofs.c_ptr()); + p = m.mk_rewrite_star(s, result, m_subst_proofs.size(), m_subst_proofs.c_ptr()); } break; case PGM_FINE: // fine grain proofs... in this mode, every proof step (or most of them) is described. @@ -90,17 +91,20 @@ void simplifier::operator()(expr * s, expr_ref & r, proof_ref & p) { // keep simplyfing until no further simplifications are possible. while (s != old_s) { TRACE("simplifier", tout << "simplification pass... " << s->get_id() << "\n";); - TRACE("simplifier_loop", tout << mk_ll_pp(s, m_manager) << "\n";); + TRACE("simplifier_loop", tout << mk_ll_pp(s, m) << "\n";); reduce_core(s); get_cached(s, result, result_proof); - if (result_proof != 0) + SASSERT(is_rewrite_proof(s, result, result_proof)); + if (result_proof != 0) { m_proofs.push_back(result_proof); + } old_s = s; s = result; } SASSERT(s != 0); r = s; - p = m_proofs.empty() ? m_manager.mk_reflexivity(s) : m_manager.mk_transitivity(m_proofs.size(), m_proofs.c_ptr()); + p = m_proofs.empty() ? m.mk_reflexivity(s) : m.mk_transitivity(m_proofs.size(), m_proofs.c_ptr()); + SASSERT(is_rewrite_proof(s_orig, r, p)); break; default: UNREACHABLE(); @@ -259,9 +263,9 @@ void simplifier::reduce1(expr * n) { specific simplifications via plugins. */ void simplifier::reduce1_app(app * n) { - expr_ref r(m_manager); - proof_ref p(m_manager); - TRACE("reduce", tout << "reducing...\n" << mk_pp(n, m_manager) << "\n";); + expr_ref r(m); + proof_ref p(m); + TRACE("reduce", tout << "reducing...\n" << mk_pp(n, m) << "\n";); if (get_subst(n, r, p)) { TRACE("reduce", tout << "applying substitution...\n";); cache_result(n, r, p); @@ -279,7 +283,7 @@ void simplifier::reduce1_app(app * n) { void simplifier::reduce1_app_core(app * n) { m_args.reset(); func_decl * decl = n->get_decl(); - proof_ref p1(m_manager); + proof_ref p1(m); // Stores the new arguments of n in m_args. // Let n be of the form // (decl arg_0 ... arg_{n-1}) @@ -296,23 +300,23 @@ void simplifier::reduce1_app_core(app * n) { // If none of the arguments have been simplified, and n is not a theory symbol, // Then no simplification is possible, and we can cache the result of the simplification of n as n. if (has_new_args || decl->get_family_id() != null_family_id) { - expr_ref r(m_manager); - TRACE("reduce", tout << "reduce1_app\n"; for(unsigned i = 0; i < m_args.size(); i++) tout << mk_ll_pp(m_args[i], m_manager);); + expr_ref r(m); + TRACE("reduce", tout << "reduce1_app\n"; for(unsigned i = 0; i < m_args.size(); i++) tout << mk_ll_pp(m_args[i], m);); // the method mk_app invokes get_subst and plugins to simplify // (decl arg_0' ... arg_{n-1}') mk_app(decl, m_args.size(), m_args.c_ptr(), r); - if (!m_manager.fine_grain_proofs()) { + if (!m.fine_grain_proofs()) { cache_result(n, r, 0); } else { - expr * s = m_manager.mk_app(decl, m_args.size(), m_args.c_ptr()); + expr * s = m.mk_app(decl, m_args.size(), m_args.c_ptr()); proof * p; if (n == r) p = 0; else if (r != s) // we use a "theory rewrite generic proof" to justify the step // s = (decl arg_0' ... arg_{n-1}') --> r - p = m_manager.mk_transitivity(p1, m_manager.mk_rewrite(s, r)); + p = m.mk_transitivity(p1, m.mk_rewrite(s, r)); else p = p1; cache_result(n, r, p); @@ -354,11 +358,11 @@ bool is_ac_vector(app * n) { } void simplifier::reduce1_ac_app_core(app * n) { - app_ref n_c(m_manager); - proof_ref p1(m_manager); + app_ref n_c(m); + proof_ref p1(m); mk_ac_congruent_term(n, n_c, p1); - TRACE("ac", tout << "expr:\n" << mk_pp(n, m_manager) << "\ncongruent term:\n" << mk_pp(n_c, m_manager) << "\n";); - expr_ref r(m_manager); + TRACE("ac", tout << "expr:\n" << mk_pp(n, m) << "\ncongruent term:\n" << mk_pp(n_c, m) << "\n";); + expr_ref r(m); func_decl * decl = n->get_decl(); family_id fid = decl->get_family_id(); plugin * p = get_plugin(fid); @@ -376,7 +380,7 @@ void simplifier::reduce1_ac_app_core(app * n) { // done... } else { - r = m_manager.mk_app(decl, m_args.size(), m_args.c_ptr()); + r = m.mk_app(decl, m_args.size(), m_args.c_ptr()); } } else { @@ -385,7 +389,7 @@ void simplifier::reduce1_ac_app_core(app * n) { get_ac_args(n_c, m_args, m_mults); TRACE("ac", tout << "AC args:\n"; for (unsigned i = 0; i < m_args.size(); i++) { - tout << mk_pp(m_args[i], m_manager) << " * " << m_mults[i] << "\n"; + tout << mk_pp(m_args[i], m) << " * " << m_mults[i] << "\n"; }); if (p != 0 && p->reduce(decl, m_args.size(), m_mults.c_ptr(), m_args.c_ptr(), r)) { // done... @@ -393,12 +397,12 @@ void simplifier::reduce1_ac_app_core(app * n) { else { ptr_buffer new_args; expand_args(m_args.size(), m_mults.c_ptr(), m_args.c_ptr(), new_args); - r = m_manager.mk_app(decl, new_args.size(), new_args.c_ptr()); + r = m.mk_app(decl, new_args.size(), new_args.c_ptr()); } } - TRACE("ac", tout << "AC result:\n" << mk_pp(r, m_manager) << "\n";); + TRACE("ac", tout << "AC result:\n" << mk_pp(r, m) << "\n";); - if (!m_manager.fine_grain_proofs()) { + if (!m.fine_grain_proofs()) { cache_result(n, r, 0); } else { @@ -406,7 +410,7 @@ void simplifier::reduce1_ac_app_core(app * n) { if (n == r.get()) p = 0; else if (r.get() != n_c.get()) - p = m_manager.mk_transitivity(p1, m_manager.mk_rewrite(n_c, r)); + p = m.mk_transitivity(p1, m.mk_rewrite(n_c, r)); else p = p1; cache_result(n, r, p); @@ -416,8 +420,8 @@ void simplifier::reduce1_ac_app_core(app * n) { static unsigned g_rewrite_lemma_id = 0; void simplifier::dump_rewrite_lemma(func_decl * decl, unsigned num_args, expr * const * args, expr* result) { - expr_ref arg(m_manager); - arg = m_manager.mk_app(decl, num_args, args); + expr_ref arg(m); + arg = m.mk_app(decl, num_args, args); if (arg.get() != result) { char buffer[128]; #ifdef _WINDOWS @@ -425,11 +429,11 @@ void simplifier::dump_rewrite_lemma(func_decl * decl, unsigned num_args, expr * #else sprintf(buffer, "rewrite_lemma_%d.smt", g_rewrite_lemma_id); #endif - ast_smt_pp pp(m_manager); + ast_smt_pp pp(m); pp.set_benchmark_name("rewrite_lemma"); pp.set_status("unsat"); - expr_ref n(m_manager); - n = m_manager.mk_not(m_manager.mk_eq(arg.get(), result)); + expr_ref n(m); + n = m.mk_not(m.mk_eq(arg.get(), result)); std::ofstream out(buffer); pp.display(out, n); out.close(); @@ -445,14 +449,14 @@ void simplifier::dump_rewrite_lemma(func_decl * decl, unsigned num_args, expr * */ void simplifier::mk_app(func_decl * decl, unsigned num_args, expr * const * args, expr_ref & result) { m_need_reset = true; - if (m_manager.is_eq(decl)) { - sort * s = m_manager.get_sort(args[0]); + if (m.is_eq(decl)) { + sort * s = m.get_sort(args[0]); plugin * p = get_plugin(s->get_family_id()); if (p != 0 && p->reduce_eq(args[0], args[1], result)) return; } - else if (m_manager.is_distinct(decl)) { - sort * s = m_manager.get_sort(args[0]); + else if (m.is_distinct(decl)) { + sort * s = m.get_sort(args[0]); plugin * p = get_plugin(s->get_family_id()); if (p != 0 && p->reduce_distinct(num_args, args, result)) return; @@ -464,7 +468,7 @@ void simplifier::mk_app(func_decl * decl, unsigned num_args, expr * const * args //dump_rewrite_lemma(decl, num_args, args, result.get()); return; } - result = m_manager.mk_app(decl, num_args, args); + result = m.mk_app(decl, num_args, args); } /** @@ -484,7 +488,7 @@ void simplifier::mk_congruent_term(app * n, app_ref & r, proof_ref & p) { get_cached(arg, new_arg, arg_proof); CTRACE("simplifier_bug", (arg != new_arg) != (arg_proof != 0), - tout << mk_ll_pp(arg, m_manager) << "\n---->\n" << mk_ll_pp(new_arg, m_manager) << "\n"; + tout << mk_ll_pp(arg, m) << "\n---->\n" << mk_ll_pp(new_arg, m) << "\n"; tout << "#" << arg->get_id() << " #" << new_arg->get_id() << "\n"; tout << arg << " " << new_arg << "\n";); @@ -500,11 +504,11 @@ void simplifier::mk_congruent_term(app * n, app_ref & r, proof_ref & p) { args.push_back(new_arg); } if (has_new_args) { - r = m_manager.mk_app(n->get_decl(), args.size(), args.c_ptr()); + r = m.mk_app(n->get_decl(), args.size(), args.c_ptr()); if (m_use_oeq) - p = m_manager.mk_oeq_congruence(n, r, proofs.size(), proofs.c_ptr()); + p = m.mk_oeq_congruence(n, r, proofs.size(), proofs.c_ptr()); else - p = m_manager.mk_congruence(n, r, proofs.size(), proofs.c_ptr()); + p = m.mk_congruence(n, r, proofs.size(), proofs.c_ptr()); } else { r = n; @@ -523,8 +527,8 @@ void simplifier::mk_congruent_term(app * n, app_ref & r, proof_ref & p) { bool simplifier::get_args(app * n, ptr_vector & result, proof_ref & p) { bool has_new_args = false; unsigned num = n->get_num_args(); - if (m_manager.fine_grain_proofs()) { - app_ref r(m_manager); + if (m.fine_grain_proofs()) { + app_ref r(m); mk_congruent_term(n, r, p); result.append(r->get_num_args(), r->get_args()); SASSERT(n->get_num_args() == result.size()); @@ -582,7 +586,7 @@ void simplifier::mk_ac_congruent_term(app * n, app_ref & r, proof_ref & p) { new_args.push_back(new_arg); if (arg != new_arg) has_new_arg = true; - if (m_manager.fine_grain_proofs()) { + if (m.fine_grain_proofs()) { proof * pr = 0; m_ac_pr_cache.find(to_app(arg), pr); if (pr != 0) @@ -601,7 +605,7 @@ void simplifier::mk_ac_congruent_term(app * n, app_ref & r, proof_ref & p) { new_args.push_back(new_arg); if (arg != new_arg) has_new_arg = true; - if (m_manager.fine_grain_proofs() && pr != 0) + if (m.fine_grain_proofs() && pr != 0) new_arg_prs.push_back(pr); } } @@ -610,14 +614,14 @@ void simplifier::mk_ac_congruent_term(app * n, app_ref & r, proof_ref & p) { todo.pop_back(); if (!has_new_arg) { m_ac_cache.insert(curr, curr); - if (m_manager.fine_grain_proofs()) + if (m.fine_grain_proofs()) m_ac_pr_cache.insert(curr, 0); } else { - app * new_curr = m_manager.mk_app(f, new_args.size(), new_args.c_ptr()); + app * new_curr = m.mk_app(f, new_args.size(), new_args.c_ptr()); m_ac_cache.insert(curr, new_curr); - if (m_manager.fine_grain_proofs()) { - proof * p = m_manager.mk_congruence(curr, new_curr, new_arg_prs.size(), new_arg_prs.c_ptr()); + if (m.fine_grain_proofs()) { + proof * p = m.mk_congruence(curr, new_curr, new_arg_prs.size(), new_arg_prs.c_ptr()); m_ac_pr_cache.insert(curr, p); } } @@ -628,7 +632,7 @@ void simplifier::mk_ac_congruent_term(app * n, app_ref & r, proof_ref & p) { app * new_n = 0; m_ac_cache.find(n, new_n); r = new_n; - if (m_manager.fine_grain_proofs()) { + if (m.fine_grain_proofs()) { proof * new_pr = 0; m_ac_pr_cache.find(n, new_pr); p = new_pr; @@ -719,7 +723,7 @@ void simplifier::get_ac_args(app * n, ptr_vector & args, vector SASSERT(!sorted_exprs.empty()); SASSERT(sorted_exprs[sorted_exprs.size()-1] == n); - TRACE("ac", tout << mk_ll_pp(n, m_manager, true, false) << "#" << n->get_id() << "\nsorted expressions...\n"; + TRACE("ac", tout << mk_ll_pp(n, m, true, false) << "#" << n->get_id() << "\nsorted expressions...\n"; for (unsigned i = 0; i < sorted_exprs.size(); i++) { tout << "#" << sorted_exprs[i]->get_id() << " "; } @@ -754,10 +758,10 @@ void simplifier::get_ac_args(app * n, ptr_vector & args, vector void simplifier::reduce1_quantifier(quantifier * q) { expr * new_body; proof * new_body_pr; - SASSERT(is_well_sorted(m_manager, q)); + SASSERT(is_well_sorted(m, q)); get_cached(q->get_expr(), new_body, new_body_pr); - quantifier_ref q1(m_manager); + quantifier_ref q1(m); proof * p1 = 0; if (is_quantifier(new_body) && @@ -774,7 +778,7 @@ void simplifier::reduce1_quantifier(quantifier * q) { sorts.append(nested_q->get_num_decls(), nested_q->get_decl_sorts()); names.append(nested_q->get_num_decls(), nested_q->get_decl_names()); - q1 = m_manager.mk_quantifier(q->is_forall(), + q1 = m.mk_quantifier(q->is_forall(), sorts.size(), sorts.c_ptr(), names.c_ptr(), @@ -783,13 +787,13 @@ void simplifier::reduce1_quantifier(quantifier * q) { q->get_qid(), q->get_skid(), 0, 0, 0, 0); - SASSERT(is_well_sorted(m_manager, q1)); + SASSERT(is_well_sorted(m, q1)); - if (m_manager.fine_grain_proofs()) { - quantifier * q0 = m_manager.update_quantifier(q, new_body); - proof * p0 = q == q0 ? 0 : m_manager.mk_quant_intro(q, q0, new_body_pr); - p1 = m_manager.mk_pull_quant(q0, q1); - p1 = m_manager.mk_transitivity(p0, p1); + if (m.fine_grain_proofs()) { + quantifier * q0 = m.update_quantifier(q, new_body); + proof * p0 = q == q0 ? 0 : m.mk_quant_intro(q, q0, new_body_pr); + p1 = m.mk_pull_quant(q0, q1); + p1 = m.mk_transitivity(p0, p1); } } else { @@ -802,7 +806,7 @@ void simplifier::reduce1_quantifier(quantifier * q) { unsigned num = q->get_num_patterns(); for (unsigned i = 0; i < num; i++) { get_cached(q->get_pattern(i), new_pattern, new_pattern_pr); - if (m_manager.is_pattern(new_pattern)) { + if (m.is_pattern(new_pattern)) { new_patterns.push_back(new_pattern); } } @@ -815,7 +819,7 @@ void simplifier::reduce1_quantifier(quantifier * q) { remove_duplicates(new_patterns); remove_duplicates(new_no_patterns); - q1 = m_manager.mk_quantifier(q->is_forall(), + q1 = m.mk_quantifier(q->is_forall(), q->get_num_decls(), q->get_decl_sorts(), q->get_decl_names(), @@ -827,26 +831,26 @@ void simplifier::reduce1_quantifier(quantifier * q) { new_patterns.c_ptr(), new_no_patterns.size(), new_no_patterns.c_ptr()); - SASSERT(is_well_sorted(m_manager, q1)); + SASSERT(is_well_sorted(m, q1)); - TRACE("simplifier", tout << mk_pp(q, m_manager) << "\n" << mk_pp(q1, m_manager) << "\n";); - if (m_manager.fine_grain_proofs()) { + TRACE("simplifier", tout << mk_pp(q, m) << "\n" << mk_pp(q1, m) << "\n";); + if (m.fine_grain_proofs()) { if (q != q1 && !new_body_pr) { - new_body_pr = m_manager.mk_rewrite(q->get_expr(), new_body); + new_body_pr = m.mk_rewrite(q->get_expr(), new_body); } - p1 = q == q1 ? 0 : m_manager.mk_quant_intro(q, q1, new_body_pr); + p1 = q == q1 ? 0 : m.mk_quant_intro(q, q1, new_body_pr); } } - expr_ref r(m_manager); - elim_unused_vars(m_manager, q1, r); + expr_ref r(m); + elim_unused_vars(m, q1, r); proof * pr = 0; - if (m_manager.fine_grain_proofs()) { + if (m.fine_grain_proofs()) { proof * p2 = 0; if (q1.get() != r.get()) - p2 = m_manager.mk_elim_unused_vars(q1, r); - pr = m_manager.mk_transitivity(p1, p2); + p2 = m.mk_elim_unused_vars(q1, r); + pr = m.mk_transitivity(p1, p2); } cache_result(q, r, pr); @@ -892,7 +896,7 @@ bool subst_simplifier::get_subst(expr * n, expr_ref & r, proof_ref & p) { m_subst_map->get(n, _r, _p); r = _r; p = _p; - if (m_manager.coarse_grain_proofs()) + if (m.coarse_grain_proofs()) m_subst_proofs.push_back(p); return true; } diff --git a/src/ast/simplifier/simplifier.h b/src/ast/simplifier/simplifier.h index 7c5bc3102..78e28bea9 100644 --- a/src/ast/simplifier/simplifier.h +++ b/src/ast/simplifier/simplifier.h @@ -210,7 +210,7 @@ public: plugin * get_plugin(family_id fid) const { return m_plugins.get_plugin(fid); } - ast_manager & get_manager() { return m_manager; } + ast_manager & get_manager() { return m; } void borrow_plugins(simplifier const & s); void release_plugins(); diff --git a/src/qe/qe.cpp b/src/qe/qe.cpp index 48fff7f61..7372fdc2c 100644 --- a/src/qe/qe.cpp +++ b/src/qe/qe.cpp @@ -2435,7 +2435,6 @@ namespace qe { cache_result(q, q, 0); return; } - ast_manager& m = m_manager; quantifier_ref new_q(m); expr * new_body = 0; @@ -2461,7 +2460,6 @@ namespace qe { } void expr_quant_elim_star1::reduce_with_assumption(expr* ctx, expr* fml, expr_ref& result) { - ast_manager& m = m_manager; proof_ref pr(m); m_assumption = ctx; (*this)(fml, result, pr); diff --git a/src/smt/elim_term_ite.cpp b/src/smt/elim_term_ite.cpp index 2e1671f43..74b804c21 100644 --- a/src/smt/elim_term_ite.cpp +++ b/src/smt/elim_term_ite.cpp @@ -33,16 +33,16 @@ void elim_term_ite::operator()(expr * n, proof * pr2; get_cached(n, r2, pr2); r = r2; - switch (m_manager.proof_mode()) { + switch (m.proof_mode()) { case PGM_DISABLED: - pr = m_manager.mk_undef_proof(); + pr = m.mk_undef_proof(); break; case PGM_COARSE: remove_duplicates(m_coarse_proofs); - pr = n == r2 ? m_manager.mk_oeq_reflexivity(n) : m_manager.mk_apply_defs(n, r, m_coarse_proofs.size(), m_coarse_proofs.c_ptr()); + pr = n == r2 ? m.mk_oeq_reflexivity(n) : m.mk_apply_defs(n, r, m_coarse_proofs.size(), m_coarse_proofs.c_ptr()); break; case PGM_FINE: - pr = pr2 == 0 ? m_manager.mk_oeq_reflexivity(n) : pr2; + pr = pr2 == 0 ? m.mk_oeq_reflexivity(n) : pr2; break; } m_coarse_proofs.reset(); @@ -107,36 +107,36 @@ void elim_term_ite::reduce1_app(app * n) { m_args.reset(); func_decl * decl = n->get_decl(); - proof_ref p1(m_manager); + proof_ref p1(m); get_args(n, m_args, p1); - if (!m_manager.fine_grain_proofs()) + if (!m.fine_grain_proofs()) p1 = 0; - expr_ref r(m_manager); - r = m_manager.mk_app(decl, m_args.size(), m_args.c_ptr()); - if (m_manager.is_term_ite(r)) { - expr_ref new_def(m_manager); - proof_ref new_def_pr(m_manager); - app_ref new_r(m_manager); - proof_ref new_pr(m_manager); + expr_ref r(m); + r = m.mk_app(decl, m_args.size(), m_args.c_ptr()); + if (m.is_term_ite(r)) { + expr_ref new_def(m); + proof_ref new_def_pr(m); + app_ref new_r(m); + proof_ref new_pr(m); if (m_defined_names.mk_name(r, new_def, new_def_pr, new_r, new_pr)) { - CTRACE("elim_term_ite_bug", new_def.get() == 0, tout << mk_ismt2_pp(r, m_manager) << "\n";); + CTRACE("elim_term_ite_bug", new_def.get() == 0, tout << mk_ismt2_pp(r, m) << "\n";); SASSERT(new_def.get() != 0); m_new_defs->push_back(new_def); - if (m_manager.fine_grain_proofs()) { + if (m.fine_grain_proofs()) { m_new_def_proofs->push_back(new_def_pr); - new_pr = m_manager.mk_transitivity(p1, new_pr); + new_pr = m.mk_transitivity(p1, new_pr); } else { // [Leo] This looks fishy... why do we add 0 into m_coarse_proofs when fine_grain_proofs are disabled? new_pr = 0; - if (m_manager.proofs_enabled()) + if (m.proofs_enabled()) m_coarse_proofs.push_back(new_pr); } } else { SASSERT(new_def.get() == 0); - if (!m_manager.fine_grain_proofs()) + if (!m.fine_grain_proofs()) new_pr = 0; } cache_result(n, new_r, new_pr); @@ -151,8 +151,8 @@ void elim_term_ite::reduce1_quantifier(quantifier * q) { proof * new_body_pr; get_cached(q->get_expr(), new_body, new_body_pr); - quantifier * new_q = m_manager.update_quantifier(q, new_body); - proof * p = q == new_q ? 0 : m_manager.mk_oeq_quant_intro(q, new_q, new_body_pr); + quantifier * new_q = m.update_quantifier(q, new_body); + proof * p = q == new_q ? 0 : m.mk_oeq_quant_intro(q, new_q, new_body_pr); cache_result(q, new_q, p); } diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 99a36c463..1eb7c7de8 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -883,6 +883,8 @@ namespace smt { max_min_t max_min(row & r, bool max, bool& has_shared); bool max_min(svector const & vars); + max_min_t max_min_new(theory_var v, bool max, bool& has_shared); + // ----------------------------------- // // Non linear diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index d377fb7ad..f4d908a5c 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -905,28 +905,6 @@ namespace smt { r1.reset_var_pos(m_var_pos); } - /** - \brief Select tightest variable x_i to pivot with x_j. The goal - is to select a x_i such that the value of x_j is increased - (decreased) if inc = true (inc = false), and the tableau - remains feasible. Store the gain in x_j of the pivoting - operation in 'gain'. Note the gain can be too much. That is, - it may make x_i infeasible. In this case, instead of pivoting - we move x_j to its upper bound (lower bound) when inc = true (inc = false). - - If no x_i imposes a restriction on x_j, then return null_theory_var. - That is, x_j is free to move to its upper bound (lower bound). - - Get the equations for x_j: - - x_i1 = coeff_1 * x_j + rest_1 - ... - x_in = coeff_n * x_j + rest_n - - gain_k := (upper_bound(x_ik) - value(x_ik))/coeff_k - - - */ template bool theory_arith::is_safe_to_leave(theory_var x, bool inc, bool& has_int, bool& shared) { @@ -958,6 +936,29 @@ namespace smt { return !was_unsafe || unbounded; } + + /** + \brief Select tightest variable x_i to pivot with x_j. The goal + is to select a x_i such that the value of x_j is increased + (decreased) if inc = true (inc = false), and the tableau + remains feasible. Store the gain in x_j of the pivoting + operation in 'gain'. Note the gain can be too much. That is, + it may make x_i infeasible. In this case, instead of pivoting + we move x_j to its upper bound (lower bound) when inc = true (inc = false). + + If no x_i imposes a restriction on x_j, then return null_theory_var. + That is, x_j is free to move to its upper bound (lower bound). + + Get the equations for x_j: + + x_i1 = coeff_1 * x_j + rest_1 + ... + x_in = coeff_n * x_j + rest_n + + gain_k := (upper_bound(x_ik) - value(x_ik))/coeff_k + + */ + template theory_var theory_arith::pick_var_to_leave( bool has_int, theory_var x_j, bool inc, @@ -1458,6 +1459,166 @@ namespace smt { return result; } + +#if 0 + /** + \brief Maximize (Minimize) the given temporary row. + Return true if succeeded. + */ + template + typename theory_arith::max_min_t theory_arith::max_min_new(row & r, bool max, bool& has_shared) { + TRACE("max_min", tout << "max_min...\n";); + m_stats.m_max_min++; + bool skipped_row = false; + has_shared = false; + + SASSERT(valid_row_assignment()); + SASSERT(satisfy_bounds()); + + theory_var x_i = null_theory_var; + theory_var x_j = null_theory_var; + bool inc = false; + numeral a_ij, curr_a_ij, coeff, curr_coeff; + inf_numeral gain, curr_gain; +#ifdef _TRACE + unsigned i = 0; +#endif + max_min_t result = BEST_EFFORT; + while (true) { + x_j = null_theory_var; + x_i = null_theory_var; + gain.reset(); + TRACE("opt", tout << "i: " << i << ", max: " << max << "\n"; display_row(tout, r, true); tout << "state:\n"; display(tout); i++;); + typename vector::const_iterator it = r.begin_entries(); + typename vector::const_iterator end = r.end_entries(); + for (; it != end; ++it) { + if (it->is_dead()) continue; + theory_var curr_x_j = it->m_var; + SASSERT(is_non_base(curr_x_j)); + curr_coeff = it->m_coeff; + bool curr_inc = curr_coeff.is_pos() ? max : !max; + bool has_int = false; + if ((curr_inc && at_upper(curr_x_j)) || (!curr_inc && at_lower(curr_x_j))) + continue; // variable cannot be used for max/min. + if (!is_safe_to_leave(curr_x_j, curr_inc, has_int, has_shared)) { + skipped_row = true; + continue; + } + theory_var curr_x_i = pick_var_to_leave(has_int, curr_x_j, curr_inc, curr_a_ij, curr_gain, skipped_row); + if (curr_x_i == null_theory_var) { + TRACE("opt", tout << "unbounded\n";); + // we can increase/decrease curr_x_j as much as we want. + x_i = null_theory_var; // unbounded + x_j = curr_x_j; + inc = curr_inc; + break; + } + else if (curr_gain > gain) { + x_i = curr_x_i; + x_j = curr_x_j; + a_ij = curr_a_ij; + coeff = curr_coeff; + gain = curr_gain; + inc = curr_inc; + } + else if (curr_gain.is_zero() && (x_i == null_theory_var || curr_x_i < x_i)) { + x_i = curr_x_i; + x_j = curr_x_j; + a_ij = curr_a_ij; + coeff = curr_coeff; + gain = curr_gain; + inc = curr_inc; + // continue + } + } + + TRACE("opt", tout << "after traversing row:\nx_i: v" << x_i << ", x_j: v" << x_j << ", gain: " << gain << "\n"; + tout << "skipped row: " << (skipped_row?"yes":"no") << "\n"; + display(tout);); + + if (x_j == null_theory_var) { + TRACE("opt", tout << "row is " << (max ? "maximized" : "minimized") << "\n";); + SASSERT(valid_row_assignment()); + SASSERT(satisfy_bounds()); + result = skipped_row?BEST_EFFORT:OPTIMIZED; + break; + } + + if (x_i == null_theory_var) { + // can increase/decrease x_j as much as we want. + if (inc && upper(x_j) && !skipped_row) { + update_value(x_j, upper_bound(x_j) - get_value(x_j)); + TRACE("opt", tout << "moved v" << x_j << " to upper bound\n";); + SASSERT(valid_row_assignment()); + SASSERT(satisfy_bounds()); + SASSERT(satisfy_integrality()); + continue; + } + if (!inc && lower(x_j) && !skipped_row) { + update_value(x_j, lower_bound(x_j) - get_value(x_j)); + TRACE("opt", tout << "moved v" << x_j << " to lower bound\n";); + SASSERT(valid_row_assignment()); + SASSERT(satisfy_bounds()); + SASSERT(satisfy_integrality()); + continue; + } + result = skipped_row?BEST_EFFORT:UNBOUNDED; + break; + } + + if (!is_fixed(x_j) && is_bounded(x_j) && !skipped_row && (upper_bound(x_j) - lower_bound(x_j) <= gain)) { + // can increase/decrease x_j up to upper/lower bound. + if (inc) { + update_value(x_j, upper_bound(x_j) - get_value(x_j)); + TRACE("opt", tout << "moved v" << x_j << " to upper bound\n";); + } + else { + update_value(x_j, lower_bound(x_j) - get_value(x_j)); + TRACE("opt", tout << "moved v" << x_j << " to lower bound\n";); + } + SASSERT(valid_row_assignment()); + SASSERT(satisfy_bounds()); + SASSERT(satisfy_integrality()); + continue; + } + + TRACE("opt", tout << "max: " << max << ", x_i: v" << x_i << ", x_j: v" << x_j << ", a_ij: " << a_ij << ", coeff: " << coeff << "\n"; + if (upper(x_i)) tout << "upper x_i: " << upper_bound(x_i) << " "; + if (lower(x_i)) tout << "lower x_i: " << lower_bound(x_i) << " "; + tout << "value x_i: " << get_value(x_i) << "\n"; + if (upper(x_j)) tout << "upper x_j: " << upper_bound(x_j) << " "; + if (lower(x_j)) tout << "lower x_j: " << lower_bound(x_j) << " "; + tout << "value x_j: " << get_value(x_j) << "\n"; + ); + pivot(x_i, x_j, a_ij, false); + + + SASSERT(is_non_base(x_i)); + SASSERT(is_base(x_j)); + + bool move_xi_to_lower; + if (inc) + move_xi_to_lower = a_ij.is_pos(); + else + move_xi_to_lower = a_ij.is_neg(); + if (!move_to_bound(x_i, move_xi_to_lower)) { + result = BEST_EFFORT; + break; + } + + row & r2 = m_rows[get_var_row(x_j)]; + coeff.neg(); + add_tmp_row(r, coeff, r2); + SASSERT(r.get_idx_of(x_j) == -1); + SASSERT(valid_row_assignment()); + SASSERT(satisfy_bounds()); + SASSERT(satisfy_integrality()); + } + TRACE("opt", display(tout);); + return result; + } +#endif + /** Move the variable x_i maximally towards its bound as long as bounds of other variables are not violated. From 05b7aa3ebb6ce3bca4e849b5db150f3861e51c69 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 15 Jan 2015 14:32:18 +0530 Subject: [PATCH 681/925] flush cache when proof mode changes Signed-off-by: Nikolaj Bjorner --- src/api/python/z3.py | 26 +++++++++++++++++++++++++- src/ast/expr_map.h | 4 ++++ src/ast/simplifier/base_simplifier.h | 9 +++++++++ src/ast/simplifier/simplifier.cpp | 1 + src/muz/rel/rel_context.cpp | 13 ++++++++++++- src/smt/theory_arith.h | 2 +- 6 files changed, 52 insertions(+), 3 deletions(-) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index e803aece9..ca04c419b 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -553,6 +553,8 @@ def _to_sort_ref(s, ctx): return ArraySortRef(s, ctx) elif k == Z3_DATATYPE_SORT: return DatatypeSortRef(s, ctx) + elif k == Z3_FINITE_DOMAIN_SORT: + return FiniteDomainSortRef(s, ctx) return SortRef(s, ctx) def _sort(ctx, a): @@ -6179,7 +6181,7 @@ class Fixedpoint(Z3PPObject): """ query = _get_args(query) sz = len(query) - if sz >= 1 and isinstance(query[0], FuncDecl): + if sz >= 1 and isinstance(query[0], FuncDeclRef): _decls = (FuncDecl * sz)() i = 0 for q in query: @@ -6307,6 +6309,28 @@ class Fixedpoint(Z3PPObject): return Exists(self.vars, fml) +######################################### +# +# Finite domain sorts +# +######################################### + +class FiniteDomainSortRef(SortRef): + """Finite domain sort.""" + + def size(self): + """Return the size of the finite domain sort""" + r = (ctype.c_ulonglong * 1)() + if Z3_get_finite_domain_sort_size(self.ctx_ref(), self.ast(), r): + return r[0] + else: + raise Z3Exception("Failed to retrieve finite domain sort size") + +def FiniteDomainSort(name, sz, ctx=None): + """Create a named finite domain sort of a given size sz""" + ctx = _get_ctx(ctx) + return FiniteDomainSortRef(Z3_mk_finite_domain_sort(ctx.ref(), name, sz), ctx) + ######################################### # # Optimize diff --git a/src/ast/expr_map.h b/src/ast/expr_map.h index 5ab6545f8..3e6f71e86 100644 --- a/src/ast/expr_map.h +++ b/src/ast/expr_map.h @@ -44,6 +44,10 @@ public: void erase(expr * k); void reset(); void flush(); + void set_store_proofs(bool f) { + if (m_store_proofs != f) flush(); + m_store_proofs = f; + } }; #endif diff --git a/src/ast/simplifier/base_simplifier.h b/src/ast/simplifier/base_simplifier.h index 5ebcdc30e..26bb43838 100644 --- a/src/ast/simplifier/base_simplifier.h +++ b/src/ast/simplifier/base_simplifier.h @@ -20,6 +20,7 @@ Notes: #define _BASE_SIMPLIFIER_H_ #include"expr_map.h" +#include"ast_pp.h" /** \brief Implements basic functionality used by expression simplifiers. @@ -32,12 +33,19 @@ protected: void cache_result(expr * n, expr * r, proof * p) { m_cache.insert(n, r, p); + CTRACE("simplifier", !is_rewrite_proof(n, r, p), + tout << mk_pp(n, m) << "\n"; + tout << mk_pp(r, m) << "\n"; + tout << mk_pp(p, m) << "\n";); SASSERT(is_rewrite_proof(n, r, p)); } void reset_cache() { m_cache.reset(); } void flush_cache() { m_cache.flush(); } void get_cached(expr * n, expr * & r, proof * & p) const { m_cache.get(n, r, p); } + void reinitialize() { m_cache.set_store_proofs(m.fine_grain_proofs()); } + + void visit(expr * n, bool & visited) { if (!is_cached(n)) { m_todo.push_back(n); @@ -55,6 +63,7 @@ public: bool is_rewrite_proof(expr* n, expr* r, proof* p) { if (p && + !m.is_undef_proof(p) && !(m.has_fact(p) && (m.is_eq(m.get_fact(p)) || m.is_oeq(m.get_fact(p)) || m.is_iff(m.get_fact(p))) && to_app(m.get_fact(p))->get_arg(0) == n && diff --git a/src/ast/simplifier/simplifier.cpp b/src/ast/simplifier/simplifier.cpp index fcd4e91b6..5358e01e4 100644 --- a/src/ast/simplifier/simplifier.cpp +++ b/src/ast/simplifier/simplifier.cpp @@ -61,6 +61,7 @@ void simplifier::enable_ac_support(bool flag) { */ void simplifier::operator()(expr * s, expr_ref & r, proof_ref & p) { m_need_reset = true; + reinitialize(); expr * s_orig = s; expr * old_s; expr * result; diff --git a/src/muz/rel/rel_context.cpp b/src/muz/rel/rel_context.cpp index 0d07b7c81..5054bc192 100644 --- a/src/muz/rel/rel_context.cpp +++ b/src/muz/rel/rel_context.cpp @@ -51,6 +51,7 @@ Revision History: #include"dl_mk_interp_tail_simplifier.h" #include"dl_mk_bit_blast.h" #include"dl_mk_separate_negated_tails.h" +#include"ast_util.h" namespace datalog { @@ -258,11 +259,21 @@ namespace datalog { is_approx = true; } rel.to_formula(e); +#if 0 + // Alternative format: + // List the signature of the relation as + // part of the answer. + expr_ref_vector args(m); + for (unsigned j = 0; j < q->get_arity(); ++j) { + args.push_back(m.mk_var(j, q->get_domain(j))); + } + e = m.mk_implies(m.mk_app(q, args.size(), args.c_ptr()), e); +#endif ans.push_back(e); } SASSERT(!m_last_result_relation); if (some_non_empty) { - m_answer = m.mk_and(ans.size(), ans.c_ptr()); + m_answer = mk_and(m, ans.size(), ans.c_ptr()); if (is_approx) { res = l_undef; m_context.set_status(APPROX); diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 1eb7c7de8..ffdc82f86 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -883,7 +883,7 @@ namespace smt { max_min_t max_min(row & r, bool max, bool& has_shared); bool max_min(svector const & vars); - max_min_t max_min_new(theory_var v, bool max, bool& has_shared); + // max_min_t max_min_new(theory_var v, bool max, bool& has_shared); // ----------------------------------- // From 41ad1d50f9097b1c7c90fb84773702eacb946b2f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 16 Jan 2015 08:08:51 +0530 Subject: [PATCH 682/925] fix java compilation bug Signed-off-by: Nikolaj Bjorner --- src/api/java/Context.java | 2 +- src/smt/theory_arith_core.h | 7 ++-- src/smt/theory_arith_nl.h | 71 +++++++++++++++++++++++++------------ 3 files changed, 55 insertions(+), 25 deletions(-) diff --git a/src/api/java/Context.java b/src/api/java/Context.java index d52edfb82..a3b24c5d0 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -383,7 +383,7 @@ public class Context extends IDisposable **/ public Expr MkUpdateField(FuncDecl field, Expr t, Expr v) { - return Expr.Create + return Expr.create (this, Native.datatypeUpdateField (nCtx(), field.getNativeObject(), diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index a97c82369..264eb0f10 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -1270,7 +1270,9 @@ namespace smt { result = FC_GIVEUP; break; case FC_CONTINUE: - TRACE("final_check_arith", tout << "continue arith...\n";); + TRACE("final_check_arith", + tout << "continue arith..." + << (get_context().inconsistent()?"inconsistent\n":"\n");); return FC_CONTINUE; } } @@ -2333,7 +2335,8 @@ namespace smt { b2->push_justification(ante, numeral(1), coeffs_enabled()); set_conflict(ante.lits().size(), ante.lits().c_ptr(), ante.eqs().size(), ante.eqs().c_ptr(), ante, is_int(b1->get_var()), "farkas"); - TRACE("arith_conflict", tout << "bound conflict\n";); + TRACE("arith_conflict", tout << "bound conflict v" << b1->get_var() << "\n"; + tout << "bounds: " << b1 << " " << b2 << "\n";); } // ----------------------------------- diff --git a/src/smt/theory_arith_nl.h b/src/smt/theory_arith_nl.h index 6a7017a29..cace15db4 100644 --- a/src/smt/theory_arith_nl.h +++ b/src/smt/theory_arith_nl.h @@ -897,31 +897,54 @@ namespace smt { m_tmp_lit_set.reset(); m_tmp_eq_set.reset(); - bool found_zero = false; SASSERT(is_pure_monomial(m)); - for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) { - expr * arg = to_app(m)->get_arg(i); - if (!found_zero) { - theory_var _var = expr2var(arg); - if (is_fixed(_var)) { - bound * l = lower(_var); - bound * u = upper(_var); - if (l->get_value().is_zero()) { - /* if zero was found, then it is the explanation */ - SASSERT(k.is_zero()); - found_zero = true; - m_tmp_lit_set.reset(); - m_tmp_eq_set.reset(); - new_lower->m_lits.reset(); - new_lower->m_eqs.reset(); - } - accumulate_justification(*l, *new_lower, numeral::zero(), m_tmp_lit_set, m_tmp_eq_set); - accumulate_justification(*u, *new_lower, numeral::zero(), m_tmp_lit_set, m_tmp_eq_set); - } - } - } + bool found_zero = false; + for (unsigned i = 0; !found_zero && i < to_app(m)->get_num_args(); i++) { + expr * arg = to_app(m)->get_arg(i); + theory_var _var = expr2var(arg); + if (is_fixed(_var)) { + bound * l = lower(_var); + bound * u = upper(_var); + if (l->get_value().is_zero()) { + /* if zero was found, then it is the explanation */ + SASSERT(k.is_zero()); + found_zero = true; + m_tmp_lit_set.reset(); + m_tmp_eq_set.reset(); + new_lower->m_lits.reset(); + new_lower->m_eqs.reset(); + } + accumulate_justification(*l, *new_lower, numeral::zero(), m_tmp_lit_set, m_tmp_eq_set); + + TRACE("non_linear", + for (unsigned j = 0; j < new_lower->m_lits.size(); ++j) { + ctx.display_detailed_literal(tout, new_lower->m_lits[j]); + tout << " "; + } + tout << "\n";); + + accumulate_justification(*u, *new_lower, numeral::zero(), m_tmp_lit_set, m_tmp_eq_set); + + TRACE("non_linear", + for (unsigned j = 0; j < new_lower->m_lits.size(); ++j) { + ctx.display_detailed_literal(tout, new_lower->m_lits[j]); + tout << " "; + } + tout << "\n";); + + } + } new_upper->m_lits.append(new_lower->m_lits); new_upper->m_eqs.append(new_lower->m_eqs); + + TRACE("non_linear", + tout << "lower: " << new_lower << " upper: " << new_upper << "\n"; + for (unsigned j = 0; j < new_upper->m_lits.size(); ++j) { + ctx.display_detailed_literal(tout, new_upper->m_lits[j]); + tout << " "; + } + tout << "\n";); + return true; } @@ -1887,6 +1910,10 @@ namespace smt { derived_bound b(null_theory_var, inf_numeral(0), B_LOWER); dependency2new_bound(d, b); set_conflict(b.m_lits.size(), b.m_lits.c_ptr(), b.m_eqs.size(), b.m_eqs.c_ptr(), ante, is_lia, "arith_nl"); + TRACE("non_linear", + for (unsigned i = 0; i < b.m_lits.size(); ++i) { + tout << b.m_lits[i] << " "; + }); } /** From d45c7ce0824d9516ba1111fa056ae1a16ca589f9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Jan 2015 04:11:40 +0530 Subject: [PATCH 683/925] prepare revised primal phase Signed-off-by: Nikolaj Bjorner --- src/smt/old_interval.cpp | 8 +- src/smt/theory_arith.h | 20 +- src/smt/theory_arith_aux.h | 426 +++++++++++++++++++++++++++++-------- src/smt/theory_arith_inv.h | 9 + src/smt/theory_arith_nl.h | 17 +- src/smt/theory_arith_pp.h | 27 ++- 6 files changed, 411 insertions(+), 96 deletions(-) diff --git a/src/smt/old_interval.cpp b/src/smt/old_interval.cpp index ffc3331be..616b74ed6 100644 --- a/src/smt/old_interval.cpp +++ b/src/smt/old_interval.cpp @@ -72,7 +72,11 @@ ext_numeral & ext_numeral::operator-=(ext_numeral const & other) { } ext_numeral & ext_numeral::operator*=(ext_numeral const & other) { - if (is_zero() || other.is_zero()) { + if (is_zero()) { + m_kind = FINITE; + return *this; + } + if (other.is_zero()) { m_kind = FINITE; m_value.reset(); return *this; @@ -295,6 +299,8 @@ interval & interval::operator*=(interval const & other) { } if (other.is_zero()) { *this = other; + m_lower_dep = m_manager.mk_join(m_lower_dep, m_upper_dep); + m_upper_dep = m_lower_dep; return *this; } diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index ffdc82f86..cba6bf662 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -265,6 +265,7 @@ namespace smt { inf_numeral const & get_value() const { return m_value; } virtual bool has_justification() const { return false; } virtual void push_justification(antecedents& antecedents, numeral const& coeff, bool proofs_enabled) {} + virtual void display(theory_arith const& th, std::ostream& out) const; }; @@ -291,6 +292,7 @@ namespace smt { virtual void push_justification(antecedents& a, numeral const& coeff, bool proofs_enabled) { a.push_lit(literal(get_bool_var(), !m_is_true), coeff, proofs_enabled); } + virtual void display(theory_arith const& th, std::ostream& out) const; }; class eq_bound : public bound { @@ -309,6 +311,7 @@ namespace smt { SASSERT(m_lhs->get_root() == m_rhs->get_root()); a.push_eq(enode_pair(m_lhs, m_rhs), coeff, proofs_enabled); } + virtual void display(theory_arith const& th, std::ostream& out) const; }; class derived_bound : public bound { @@ -323,6 +326,7 @@ namespace smt { virtual void push_justification(antecedents& a, numeral const& coeff, bool proofs_enabled); virtual void push_lit(literal l, numeral const&) { m_lits.push_back(l); } virtual void push_eq(enode_pair const& p, numeral const&) { m_eqs.push_back(p); } + virtual void display(theory_arith const& th, std::ostream& out) const; }; class justified_derived_bound : public derived_bound { @@ -883,7 +887,18 @@ namespace smt { max_min_t max_min(row & r, bool max, bool& has_shared); bool max_min(svector const & vars); - // max_min_t max_min_new(theory_var v, bool max, bool& has_shared); + max_min_t max_min_new(row& r, bool max, bool& has_shared); + bool unbounded_gain(inf_numeral const & max_gain) const; + bool safe_gain(inf_numeral const& min_gain, inf_numeral const & max_gain) const; + void normalize_gain(numeral const& divisor, inf_numeral & max_gain) const; + void init_gains(theory_var x, bool inc, inf_numeral& min_gain, inf_numeral& max_gain); + bool update_gains(bool inc, theory_var x_i, numeral const& a_ij, + inf_numeral& min_gain, inf_numeral& max_gain); + bool move_to_bound_new(theory_var x_i, bool inc, bool& best_effort, bool& has_shared); + bool pick_var_to_leave( + theory_var x_j, bool inc, numeral & a_ij, + inf_numeral& min_gain, inf_numeral& max_gain, + bool& shared, theory_var& x_i); // ----------------------------------- // @@ -1064,6 +1079,8 @@ namespace smt { void display_bounds_in_smtlib() const; void display_nl_monomials(std::ostream & out) const; void display_coeff_exprs(std::ostream & out, sbuffer const & p) const; + void display_interval(std::ostream& out, interval const& i); + void display_deps(std::ostream& out, v_dependency* dep); protected: // ----------------------------------- @@ -1079,6 +1096,7 @@ namespace smt { bool wf_rows() const; bool wf_column(theory_var v) const; bool wf_columns() const; + bool valid_assignment() const; bool valid_row_assignment() const; bool valid_row_assignment(row const & r) const; bool satisfy_bounds() const; diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index f4d908a5c..7930dbec2 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -363,6 +363,19 @@ namespace smt { return m_params.c_ptr(); } + // ----------------------------------- + // + // Bounds + // + // ----------------------------------- + + + template + void theory_arith::bound::display(theory_arith const& th, std::ostream& out) const { + out << "v" << m_var << " " << get_bound_kind() << " " << get_value(); + } + + // ----------------------------------- // // Atoms @@ -401,6 +414,27 @@ namespace smt { } } + template + void theory_arith::atom::display(theory_arith const& th, std::ostream& out) const { + literal l(get_bool_var(), !m_is_true); + out << "v" << m_var << " " << get_bound_kind() << " " << get_k() << " "; + out << l << ":"; + th.get_context().display_detailed_literal(out, l); + } + + // ----------------------------------- + // + // eq_bound + // + // ----------------------------------- + + template + void theory_arith::eq_bound::display(theory_arith const& th, std::ostream& out) const { + ast_manager& m = th.get_manager(); + out << "#" << m_lhs->get_owner_id() << " " << mk_pp(m_lhs->get_owner(), m) << " = " + << "#" << m_rhs->get_owner_id() << " " << mk_pp(m_rhs->get_owner(), m); + } + // ----------------------------------- // // Auxiliary methods @@ -711,6 +745,24 @@ namespace smt { } } + template + void theory_arith::derived_bound::display(theory_arith const& th, std::ostream& out) const { + out << "v" << m_var << " " << get_bound_kind() << " " << get_value(); + + ast_manager& m = th.get_manager(); + for (unsigned i = 0; i < m_eqs.size(); ++i) { + enode* a = m_eqs[i].first; + enode* b = m_eqs[i].second; + out << " "; + out << "#" << a->get_owner_id() << " " << mk_pp(a->get_owner(), m) << " = " + << "#" << b->get_owner_id() << " " << mk_pp(b->get_owner(), m); + } + for (unsigned i = 0; i < m_lits.size(); ++i) { + literal l = m_lits[i]; + out << " " << l << ":"; th.get_context().display_detailed_literal(out, l); + } + } + template void theory_arith::justified_derived_bound::push_justification(antecedents& a, numeral const& coeff, bool proofs_enabled) { @@ -1313,8 +1365,8 @@ namespace smt { bool skipped_row = false; has_shared = false; - SASSERT(valid_row_assignment()); - SASSERT(satisfy_bounds()); + SASSERT(valid_assignment()); + theory_var x_i = null_theory_var; theory_var x_j = null_theory_var; @@ -1379,8 +1431,7 @@ namespace smt { if (x_j == null_theory_var) { TRACE("opt", tout << "row is " << (max ? "maximized" : "minimized") << "\n";); - SASSERT(valid_row_assignment()); - SASSERT(satisfy_bounds()); + SASSERT(valid_assignment()); result = skipped_row?BEST_EFFORT:OPTIMIZED; break; } @@ -1390,17 +1441,13 @@ namespace smt { if (inc && upper(x_j) && !skipped_row) { update_value(x_j, upper_bound(x_j) - get_value(x_j)); TRACE("opt", tout << "moved v" << x_j << " to upper bound\n";); - SASSERT(valid_row_assignment()); - SASSERT(satisfy_bounds()); - SASSERT(satisfy_integrality()); + SASSERT(valid_assignment()); continue; } if (!inc && lower(x_j) && !skipped_row) { update_value(x_j, lower_bound(x_j) - get_value(x_j)); TRACE("opt", tout << "moved v" << x_j << " to lower bound\n";); - SASSERT(valid_row_assignment()); - SASSERT(satisfy_bounds()); - SASSERT(satisfy_integrality()); + SASSERT(valid_assignment()); continue; } result = skipped_row?BEST_EFFORT:UNBOUNDED; @@ -1417,9 +1464,7 @@ namespace smt { update_value(x_j, lower_bound(x_j) - get_value(x_j)); TRACE("opt", tout << "moved v" << x_j << " to lower bound\n";); } - SASSERT(valid_row_assignment()); - SASSERT(satisfy_bounds()); - SASSERT(satisfy_integrality()); + SASSERT(valid_assignment()); continue; } @@ -1451,134 +1496,313 @@ namespace smt { coeff.neg(); add_tmp_row(r, coeff, r2); SASSERT(r.get_idx_of(x_j) == -1); - SASSERT(valid_row_assignment()); - SASSERT(satisfy_bounds()); - SASSERT(satisfy_integrality()); + SASSERT(valid_assignment()); } TRACE("opt", display(tout);); return result; } -#if 0 + /** + \brief Select tightest variable x_i to pivot with x_j. The goal + is to select a x_i such that the value of x_j is increased + (decreased) if inc = true (inc = false), and the tableau + remains feasible. Store the gain in x_j of the pivoting + operation in 'gain'. Note the gain can be too much. That is, + it may make x_i infeasible. In this case, instead of pivoting + we move x_j to its upper bound (lower bound) when inc = true (inc = false). + + If no x_i imposes a restriction on x_j, then return null_theory_var. + That is, x_j is free to move to its upper bound (lower bound). + + Get the equations for x_j: + + x_i1 = coeff_1 * x_j + rest_1 + ... + x_in = coeff_n * x_j + rest_n + + gain_k := (upper_bound(x_ik) - value(x_ik))/coeff_k + + */ + + + template + bool theory_arith::pick_var_to_leave( + theory_var x_j, // non-base variable to increment/decrement + bool inc, + numeral & a_ij, // coefficient of x_i + inf_numeral& min_gain, // minimal required gain on x_j (integral value on integers) + inf_numeral& max_gain, // maximal possible gain on x_j + bool& has_shared, // determine if pivot involves shared variable + theory_var& x_i) { // base variable to pivot with x_j + + + context& ctx = get_context(); + column & c = m_columns[x_j]; + typename svector::iterator it = c.begin_entries(); + typename svector::iterator end = c.end_entries(); + init_gains(x_j, inc, min_gain, max_gain); + has_shared |= ctx.is_shared(get_enode(x_j)); + for (; it != end; ++it) { + if (it->is_dead()) continue; + row const & r = m_rows[it->m_row_id]; + theory_var s = r.get_base_var(); + numeral const & coeff_ij = r[it->m_row_idx].m_coeff; + if (update_gains(inc, s, coeff_ij, min_gain, max_gain)) { + x_i = s; + } + has_shared |= ctx.is_shared(get_enode(s)); + } + if (safe_gain(min_gain, max_gain)) { + SASSERT(unbounded_gain(max_gain) == (x_i != null_theory_var)); + return true; + } + else { + return false; + } + } + + template + bool theory_arith::unbounded_gain(inf_numeral const & max_gain) const { + return max_gain.is_minus_one(); + } + + /* + A gain is 'safe' with respect to the tableau if: + - the selected variable is unbounded and every base variable where it occurs is unbounded + in the direction of the gain. max_gain == -1 is used to indicate unbounded variables. + - the selected variable is a rational (min_gain == -1, max_gain >= 0). + - + */ + template + bool theory_arith::safe_gain(inf_numeral const& min_gain, inf_numeral const & max_gain) const { + return + unbounded_gain(max_gain) || + min_gain <= max_gain; + } + + /** + \brief ensure that maximal gain is divisible by divisor. + */ + template + void theory_arith::normalize_gain(numeral const& divisor, inf_numeral & max_gain) const { + SASSERT(divisor.is_int()); + SASSERT(divisor.is_pos()); + if (!divisor.is_one()) { + max_gain = floor(max_gain/divisor)*divisor; + } + } + + /** + \brief initialize gains for x_j based on the bounds for x_j. + */ + template + void theory_arith::init_gains( + theory_var x, // non-base variable to increment/decrement + bool inc, + inf_numeral& min_gain, // min value to increment, -1 if rational + inf_numeral& max_gain) { // max value to decrement, -1 if unbounded + min_gain = -inf_numeral::one(); + max_gain = -inf_numeral::one(); + if (inc && upper(x)) { + max_gain = upper_bound(x) - get_value(x); + } + else if (!inc && lower(x)) { + max_gain = get_value(x) - lower_bound(x); + } + if (is_int(x)) { + min_gain = inf_numeral::one(); + } + SASSERT(max_gain.is_minus_one() || !max_gain.is_neg()); + SASSERT(min_gain.is_minus_one() || min_gain.is_one()); + SASSERT(!is_int(x) || max_gain.is_int()); + SASSERT(is_int(x) == min_gain.is_one()); + } + + template + bool theory_arith::update_gains( + bool inc, // increment/decrement x_j + theory_var x_i, // potential base variable to pivot + numeral const& a_ij, // coefficient of x_j in row where x_i is base. + inf_numeral& min_gain, // min value to increment, -1 if rational + inf_numeral& max_gain) { // max value to decrement, -1 if unbounded + + // x_i = row + a_ij*x_j + // a_ij > 0, inc -> decrement x_i + // a_ij < 0, !inc -> decrement x_i + // a_ij denominator + + if (!safe_gain(min_gain, max_gain)) return false; + + inf_numeral max_inc = inf_numeral::minus_one(); + bool decrement_x_i = (inc && a_ij.is_pos()) || (!inc && a_ij.is_neg()); + if (decrement_x_i && lower(x_i)) { + max_inc = abs((get_value(x_i) - lower_bound(x_i))/a_ij); + } + else if (!decrement_x_i && upper(x_i)) { + max_inc = abs((upper_bound(x_i) - get_value(x_i))/a_ij); + } + numeral den_aij(1); + bool is_tighter = false; + if (is_int(x_i)) den_aij = denominator(a_ij); + SASSERT(den_aij.is_pos() && den_aij.is_int()); + if (!max_inc.is_minus_one()) { + if (is_int(x_i)) { + normalize_gain(den_aij, max_inc); + } + if (unbounded_gain(max_gain)) { + max_gain = max_inc; + is_tighter = true; + } + else if (max_gain > max_inc) { + max_gain = max_inc; + is_tighter = true; + } + } + if (is_int(x_i)) { + SASSERT(min_gain.is_pos()); + if (!den_aij.is_one()) { + min_gain = inf_numeral(lcm(min_gain.get_rational(), den_aij)); + normalize_gain(den_aij, max_gain); + } + } + SASSERT(max_gain.is_minus_one() || !max_gain.is_neg()); + SASSERT(min_gain.is_minus_one() || !min_gain.is_neg()); + SASSERT(!is_int(x_i) || min_gain.is_pos()); + SASSERT(!is_int(x_i) || min_gain.is_int()); + SASSERT(!is_int(x_i) || max_gain.is_int()); + return is_tighter; + } + /** \brief Maximize (Minimize) the given temporary row. Return true if succeeded. */ template - typename theory_arith::max_min_t theory_arith::max_min_new(row & r, bool max, bool& has_shared) { + typename theory_arith::max_min_t theory_arith::max_min_new( + row & r, + bool max, + bool& has_shared) { TRACE("max_min", tout << "max_min...\n";); m_stats.m_max_min++; - bool skipped_row = false; - has_shared = false; + bool best_effort = false, inc = false; - SASSERT(valid_row_assignment()); - SASSERT(satisfy_bounds()); + SASSERT(valid_assignment()); - theory_var x_i = null_theory_var; - theory_var x_j = null_theory_var; - bool inc = false; numeral a_ij, curr_a_ij, coeff, curr_coeff; - inf_numeral gain, curr_gain; + inf_numeral min_gain, max_gain, curr_min_gain, curr_max_gain; #ifdef _TRACE - unsigned i = 0; + unsigned round = 0; #endif - max_min_t result = BEST_EFFORT; + max_min_t result = OPTIMIZED; + has_shared = false; while (true) { - x_j = null_theory_var; - x_i = null_theory_var; - gain.reset(); - TRACE("opt", tout << "i: " << i << ", max: " << max << "\n"; display_row(tout, r, true); tout << "state:\n"; display(tout); i++;); + theory_var x_j = null_theory_var; + theory_var x_i = null_theory_var; + max_gain.reset(); + min_gain.reset(); + TRACE("opt", tout << "round: " << (round++) << ", max: " << max << "\n"; display_row(tout, r, true); tout << "state:\n"; display(tout);); typename vector::const_iterator it = r.begin_entries(); typename vector::const_iterator end = r.end_entries(); for (; it != end; ++it) { if (it->is_dead()) continue; theory_var curr_x_j = it->m_var; + theory_var curr_x_i = null_theory_var; SASSERT(is_non_base(curr_x_j)); curr_coeff = it->m_coeff; - bool curr_inc = curr_coeff.is_pos() ? max : !max; - bool has_int = false; - if ((curr_inc && at_upper(curr_x_j)) || (!curr_inc && at_lower(curr_x_j))) - continue; // variable cannot be used for max/min. - if (!is_safe_to_leave(curr_x_j, curr_inc, has_int, has_shared)) { - skipped_row = true; + bool curr_inc = curr_coeff.is_pos() ? max : !max; + if ((curr_inc && at_upper(curr_x_j)) || (!curr_inc && at_lower(curr_x_j))) { + // variable cannot be used for max/min. + continue; + } + if (!pick_var_to_leave(curr_x_j, curr_inc, curr_a_ij, + curr_min_gain, curr_max_gain, + has_shared, curr_x_i)) { + best_effort = true; continue; } - theory_var curr_x_i = pick_var_to_leave(has_int, curr_x_j, curr_inc, curr_a_ij, curr_gain, skipped_row); + SASSERT(safe_gain(curr_min_gain, curr_max_gain)); if (curr_x_i == null_theory_var) { TRACE("opt", tout << "unbounded\n";); // we can increase/decrease curr_x_j as much as we want. x_i = null_theory_var; // unbounded x_j = curr_x_j; inc = curr_inc; + min_gain = curr_min_gain; + max_gain = curr_max_gain; break; } - else if (curr_gain > gain) { + else if (curr_max_gain > max_gain) { x_i = curr_x_i; x_j = curr_x_j; a_ij = curr_a_ij; coeff = curr_coeff; - gain = curr_gain; + max_gain = curr_max_gain; + min_gain = curr_min_gain; inc = curr_inc; } - else if (curr_gain.is_zero() && (x_i == null_theory_var || curr_x_i < x_i)) { + else if (curr_max_gain.is_zero() && (x_i == null_theory_var || curr_x_i < x_i)) { x_i = curr_x_i; x_j = curr_x_j; a_ij = curr_a_ij; coeff = curr_coeff; - gain = curr_gain; + max_gain = curr_max_gain; + min_gain = curr_min_gain; inc = curr_inc; // continue } } - TRACE("opt", tout << "after traversing row:\nx_i: v" << x_i << ", x_j: v" << x_j << ", gain: " << gain << "\n"; - tout << "skipped row: " << (skipped_row?"yes":"no") << "\n"; + TRACE("opt", tout << "after traversing row:\nx_i: v" << x_i << ", x_j: v" << x_j << ", gain: " << max_gain << "\n"; + tout << "skipped row: " << (best_effort?"yes":"no") << "\n"; display(tout);); if (x_j == null_theory_var) { TRACE("opt", tout << "row is " << (max ? "maximized" : "minimized") << "\n";); - SASSERT(valid_row_assignment()); - SASSERT(satisfy_bounds()); - result = skipped_row?BEST_EFFORT:OPTIMIZED; + SASSERT(valid_assignment()); + result = OPTIMIZED; break; } + if (min_gain.is_pos() && !min_gain.is_one()) { + best_effort = true; + } if (x_i == null_theory_var) { // can increase/decrease x_j as much as we want. - if (inc && upper(x_j) && !skipped_row) { - update_value(x_j, upper_bound(x_j) - get_value(x_j)); + + if (inc && upper(x_j)) { + SASSERT(!unbounded_gain(max_gain)); + update_value(x_j, max_gain); TRACE("opt", tout << "moved v" << x_j << " to upper bound\n";); - SASSERT(valid_row_assignment()); - SASSERT(satisfy_bounds()); - SASSERT(satisfy_integrality()); + SASSERT(valid_assignment()); continue; } - if (!inc && lower(x_j) && !skipped_row) { - update_value(x_j, lower_bound(x_j) - get_value(x_j)); + if (!inc && lower(x_j)) { + SASSERT(!unbounded_gain(max_gain)); + max_gain.neg(); + update_value(x_j, max_gain); TRACE("opt", tout << "moved v" << x_j << " to lower bound\n";); - SASSERT(valid_row_assignment()); - SASSERT(satisfy_bounds()); - SASSERT(satisfy_integrality()); + SASSERT(valid_assignment()); continue; } - result = skipped_row?BEST_EFFORT:UNBOUNDED; + SASSERT(unbounded_gain(max_gain)); + best_effort = false; + result = UNBOUNDED; break; } - if (!is_fixed(x_j) && is_bounded(x_j) && !skipped_row && (upper_bound(x_j) - lower_bound(x_j) <= gain)) { + if (!is_fixed(x_j) && is_bounded(x_j) && + (upper_bound(x_j) - lower_bound(x_j) == max_gain)) { // can increase/decrease x_j up to upper/lower bound. if (inc) { - update_value(x_j, upper_bound(x_j) - get_value(x_j)); TRACE("opt", tout << "moved v" << x_j << " to upper bound\n";); } else { - update_value(x_j, lower_bound(x_j) - get_value(x_j)); + max_gain.neg(); TRACE("opt", tout << "moved v" << x_j << " to lower bound\n";); } - SASSERT(valid_row_assignment()); - SASSERT(satisfy_bounds()); - SASSERT(satisfy_integrality()); + update_value(x_j, max_gain); + SASSERT(valid_assignment()); continue; } @@ -1591,33 +1815,66 @@ namespace smt { tout << "value x_j: " << get_value(x_j) << "\n"; ); pivot(x_i, x_j, a_ij, false); - - + SASSERT(is_non_base(x_i)); SASSERT(is_base(x_j)); - bool move_xi_to_lower; - if (inc) - move_xi_to_lower = a_ij.is_pos(); - else - move_xi_to_lower = a_ij.is_neg(); - if (!move_to_bound(x_i, move_xi_to_lower)) { - result = BEST_EFFORT; + bool inc_xi = inc?a_ij.is_neg():a_ij.is_pos(); + if (!move_to_bound_new(x_i, inc_xi, best_effort, has_shared)) { + best_effort = true; break; } - + row & r2 = m_rows[get_var_row(x_j)]; coeff.neg(); add_tmp_row(r, coeff, r2); SASSERT(r.get_idx_of(x_j) == -1); - SASSERT(valid_row_assignment()); - SASSERT(satisfy_bounds()); - SASSERT(satisfy_integrality()); + SASSERT(valid_assignment()); } TRACE("opt", display(tout);); - return result; + return best_effort?BEST_EFFORT:result; + } + + /** + Move the variable x_i maximally towards its bound as long as + bounds of other variables are not violated. + Returns false if an integer bound was truncated and no + progress was made. + */ + + template + bool theory_arith::move_to_bound_new( + theory_var x_i, // variable to move + bool inc, // increment variable or decrement + bool& best_effort, // is bound move a best effort? + bool& has_shared) { // does move include shared variables? + inf_numeral min_gain, max_gain; + init_gains(x_i, inc, min_gain, max_gain); + column & c = m_columns[x_i]; + typename svector::iterator it = c.begin_entries(); + typename svector::iterator end = c.end_entries(); + for (; it != end; ++it) { + if (it->is_dead()) continue; + row const & r = m_rows[it->m_row_id]; + theory_var s = r.get_base_var(); + numeral const & coeff = r[it->m_row_idx].m_coeff; + update_gains(inc, s, coeff, min_gain, max_gain); + has_shared |= get_context().is_shared(get_enode(s)); + } + if (safe_gain(min_gain, max_gain)) { + TRACE("opt", tout << "Safe delta: " << max_gain << "\n";); + SASSERT(!unbounded_gain(max_gain)); + if (!inc) { + max_gain.neg(); + } + update_value(x_i, max_gain); + best_effort = min_gain.is_pos() && !min_gain.is_one(); + return !max_gain.is_zero(); + } + else { + return false; + } } -#endif /** Move the variable x_i maximally towards its bound as long as @@ -1630,7 +1887,7 @@ namespace smt { bool theory_arith::move_to_bound(theory_var x_i, bool move_to_lower) { inf_numeral delta, delta_abs; numeral lc(1); - + if (move_to_lower) { delta = lower_bound(x_i) - get_value(x_i); SASSERT(!delta.is_pos()); @@ -1711,8 +1968,8 @@ namespace smt { template typename theory_arith::max_min_t theory_arith::max_min(theory_var v, bool max, bool& has_shared) { expr* e = get_enode(v)->get_owner(); - SASSERT(valid_row_assignment()); - SASSERT(satisfy_bounds()); + + SASSERT(valid_assignment()); SASSERT(!is_quasi_base(v)); if ((max && at_upper(v)) || (!max && at_lower(v))) { TRACE("opt", tout << "At bound: " << mk_pp(e, get_manager()) << "...\n";); @@ -1872,8 +2129,7 @@ namespace smt { bool theory_arith::try_to_imply_eq(theory_var v1, theory_var v2) { SASSERT(v1 != v2); SASSERT(get_value(v1) == get_value(v2)); - SASSERT(valid_row_assignment()); - SASSERT(satisfy_bounds()); + SASSERT(valid_assignment()); if (is_quasi_base(v1) || is_quasi_base(v2)) return false; m_tmp_row.reset(); diff --git a/src/smt/theory_arith_inv.h b/src/smt/theory_arith_inv.h index 99e4303ff..007c8025f 100644 --- a/src/smt/theory_arith_inv.h +++ b/src/smt/theory_arith_inv.h @@ -211,6 +211,15 @@ namespace smt { } return true; } + + template + bool theory_arith::valid_assignment() const { + return + valid_row_assignment() && + satisfy_bounds() && + satisfy_integrality(); + } + #endif }; diff --git a/src/smt/theory_arith_nl.h b/src/smt/theory_arith_nl.h index cace15db4..8ff122c1e 100644 --- a/src/smt/theory_arith_nl.h +++ b/src/smt/theory_arith_nl.h @@ -333,12 +333,15 @@ namespace smt { void theory_arith::mul_bound_of(expr * var, unsigned power, interval & target) { theory_var v = expr2var(var); interval i = mk_interval_for(v); - TRACE("non_linear", tout << "bound: " << i << "\n" << mk_pp(var, get_manager()) << "\n"; + + TRACE("non_linear", + display_interval(tout << "bound: ",i); tout << i << "\n"; + tout << mk_pp(var, get_manager()) << "\n"; tout << "power " << power << ": " << expt(i, power) << "\n"; - tout << "target before: " << target << "\n";); + display_interval(tout << "target before: ", target); tout << "\n";); i.expt(power); target *= i; - TRACE("non_linear", tout << "target after: " << target << "\n";); + TRACE("non_linear", display_interval(tout << "target after: ", target); tout << "\n";); } /** @@ -427,12 +430,12 @@ namespace smt { template void theory_arith::mk_derived_nl_bound(theory_var v, inf_numeral const & coeff, bound_kind k, v_dependency * dep) { inf_numeral coeff_norm = normalize_bound(v, coeff, k); - TRACE("buggy_bound", tout << "v" << v << " " << coeff << " " << coeff_norm << " " << k << "\n";); derived_bound * new_bound = alloc(derived_bound, v, coeff_norm, k); m_bounds_to_delete.push_back(new_bound); m_asserted_bounds.push_back(new_bound); // copy justification to new bound dependency2new_bound(dep, *new_bound); + TRACE("buggy_bound", new_bound->display(*this, tout); tout << "\n";); } /** @@ -449,7 +452,8 @@ namespace smt { new_lower += get_epsilon(v); bound * old_lower = lower(v); if (old_lower == 0 || new_lower > old_lower->get_value()) { - TRACE("non_linear", tout << "NEW lower bound for v" << v << " " << new_lower << "\n";); + TRACE("non_linear", tout << "NEW lower bound for v" << v << " " << new_lower << "\n"; + display_interval(tout, i); tout << "\n";); mk_derived_nl_bound(v, new_lower, B_LOWER, i.get_lower_dependencies()); r = true; } @@ -460,7 +464,8 @@ namespace smt { new_upper -= get_epsilon(v); bound * old_upper = upper(v); if (old_upper == 0 || new_upper < old_upper->get_value()) { - TRACE("non_linear", tout << "NEW upper bound for v" << v << " " << new_upper << "\n";); + TRACE("non_linear", tout << "NEW upper bound for v" << v << " " << new_upper << "\n"; + display_interval(tout, i); tout << "\n";); mk_derived_nl_bound(v, new_upper, B_UPPER, i.get_upper_dependencies()); r = true; } diff --git a/src/smt/theory_arith_pp.h b/src/smt/theory_arith_pp.h index 4eeb6a189..f954f082c 100644 --- a/src/smt/theory_arith_pp.h +++ b/src/smt/theory_arith_pp.h @@ -395,9 +395,30 @@ namespace smt { template void theory_arith::display_bound(std::ostream & out, bound * b, unsigned indent) const { for (unsigned i = 0; i < indent; i++) out << " "; - theory_var v = b->get_var(); - enode * e = get_enode(v); - out << "v" << v << " #" << e->get_owner_id() << " " << (b->get_bound_kind() == B_LOWER ? ">=" : "<=") << " " << b->get_value() << "\n"; + b->display(*this, out); + out << "\n"; + } + + template + void theory_arith::display_deps(std::ostream & out, v_dependency* dep) { + ptr_vector bounds; + m_dep_manager.linearize(dep, bounds); + m_tmp_lit_set.reset(); + m_tmp_eq_set.reset(); + ptr_vector::const_iterator it = bounds.begin(); + ptr_vector::const_iterator end = bounds.end(); + for (; it != end; ++it) { + bound * b = static_cast(*it); + out << " "; + b->display(*this, out); + } + } + + template + void theory_arith::display_interval(std::ostream & out, interval const& i) { + i.display(out); + display_deps(out << " lo:", i.get_lower_dependencies()); + display_deps(out << " hi:", i.get_upper_dependencies()); } template From 67827ede4c35b496a6d4e2c6ed09ffda47e4fdc2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Jan 2015 04:13:00 +0530 Subject: [PATCH 684/925] add 'throws' declaration Signed-off-by: Nikolaj Bjorner --- src/api/java/Context.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/api/java/Context.java b/src/api/java/Context.java index a3b24c5d0..5de82026f 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -382,6 +382,7 @@ public class Context extends IDisposable * the remainig fields of t are unchanged. **/ public Expr MkUpdateField(FuncDecl field, Expr t, Expr v) + throws Z3Exception { return Expr.create (this, From 4bb5302defd0393f14a99e444e9a2bb33066287e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Jan 2015 15:54:18 -0800 Subject: [PATCH 685/925] template args Signed-off-by: Nikolaj Bjorner --- src/shell/main.cpp | 2 +- src/smt/theory_arith.h | 2 +- src/smt/theory_arith_aux.h | 60 ++++++++++++++++++++++++-------------- 3 files changed, 40 insertions(+), 24 deletions(-) diff --git a/src/shell/main.cpp b/src/shell/main.cpp index bd5cbbd43..9d7857766 100644 --- a/src/shell/main.cpp +++ b/src/shell/main.cpp @@ -304,7 +304,7 @@ int main(int argc, char ** argv) { } if (g_input_kind == IN_UNSPECIFIED) { - g_input_kind = IN_SMTLIB; + g_input_kind = IN_SMTLIB_2; char const * ext = get_extension(g_input_file); if (ext) { if (strcmp(ext, "datalog") == 0 || strcmp(ext, "dl") == 0) { diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index cba6bf662..1dadeeca0 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -884,7 +884,7 @@ namespace smt { void add_tmp_row_entry(row & r, numeral const & coeff, theory_var v); enum max_min_t { UNBOUNDED, AT_BOUND, OPTIMIZED, BEST_EFFORT}; max_min_t max_min(theory_var v, bool max, bool& has_shared); - max_min_t max_min(row & r, bool max, bool& has_shared); + max_min_t max_min_orig(row & r, bool max, bool& has_shared); bool max_min(svector const & vars); max_min_t max_min_new(row& r, bool max, bool& has_shared); diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 7930dbec2..ffc8314e0 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -371,8 +371,8 @@ namespace smt { template - void theory_arith::bound::display(theory_arith const& th, std::ostream& out) const { - out << "v" << m_var << " " << get_bound_kind() << " " << get_value(); + void theory_arith::bound::display(theory_arith const& th, std::ostream& out) const { + out << "v" << get_var() << " " << get_bound_kind() << " " << get_value(); } @@ -415,9 +415,9 @@ namespace smt { } template - void theory_arith::atom::display(theory_arith const& th, std::ostream& out) const { + void theory_arith::atom::display(theory_arith const& th, std::ostream& out) const { literal l(get_bool_var(), !m_is_true); - out << "v" << m_var << " " << get_bound_kind() << " " << get_k() << " "; + out << "v" << get_var() << " " << get_bound_kind() << " " << get_k() << " "; out << l << ":"; th.get_context().display_detailed_literal(out, l); } @@ -429,7 +429,7 @@ namespace smt { // ----------------------------------- template - void theory_arith::eq_bound::display(theory_arith const& th, std::ostream& out) const { + void theory_arith::eq_bound::display(theory_arith const& th, std::ostream& out) const { ast_manager& m = th.get_manager(); out << "#" << m_lhs->get_owner_id() << " " << mk_pp(m_lhs->get_owner(), m) << " = " << "#" << m_rhs->get_owner_id() << " " << mk_pp(m_rhs->get_owner(), m); @@ -746,7 +746,7 @@ namespace smt { } template - void theory_arith::derived_bound::display(theory_arith const& th, std::ostream& out) const { + void theory_arith::derived_bound::display(theory_arith const& th, std::ostream& out) const { out << "v" << m_var << " " << get_bound_kind() << " " << get_value(); ast_manager& m = th.get_manager(); @@ -1359,8 +1359,7 @@ namespace smt { Return true if succeeded. */ template - typename theory_arith::max_min_t theory_arith::max_min(row & r, bool max, bool& has_shared) { - TRACE("max_min", tout << "max_min...\n";); + typename theory_arith::max_min_t theory_arith::max_min_orig(row & r, bool max, bool& has_shared) { m_stats.m_max_min++; bool skipped_row = false; has_shared = false; @@ -1536,7 +1535,7 @@ namespace smt { bool& has_shared, // determine if pivot involves shared variable theory_var& x_i) { // base variable to pivot with x_j - + x_i = null_theory_var; context& ctx = get_context(); column & c = m_columns[x_j]; typename svector::iterator it = c.begin_entries(); @@ -1548,18 +1547,26 @@ namespace smt { row const & r = m_rows[it->m_row_id]; theory_var s = r.get_base_var(); numeral const & coeff_ij = r[it->m_row_idx].m_coeff; - if (update_gains(inc, s, coeff_ij, min_gain, max_gain)) { + if (update_gains(inc, s, coeff_ij, min_gain, max_gain) || + (x_i == null_theory_var && !unbounded_gain(max_gain))) { x_i = s; + a_ij = coeff_ij; } has_shared |= ctx.is_shared(get_enode(s)); } - if (safe_gain(min_gain, max_gain)) { - SASSERT(unbounded_gain(max_gain) == (x_i != null_theory_var)); - return true; - } - else { - return false; - } + bool empty_column = (c.begin_entries() == end); + TRACE("opt", + tout << (safe_gain(min_gain, max_gain)?"safe":"unsafe") << "\n"; + tout << "min gain: " << min_gain; + tout << " max gain: " << max_gain << "\n"; + tout << "v" << x_i << " "; + tout << (has_shared?"shared":"not shared") << "\n";); + + SASSERT(!safe_gain(min_gain, max_gain) || + empty_column || + (unbounded_gain(max_gain) == (x_i == null_theory_var))); + + return !empty_column && safe_gain(min_gain, max_gain); } template @@ -1588,7 +1595,7 @@ namespace smt { void theory_arith::normalize_gain(numeral const& divisor, inf_numeral & max_gain) const { SASSERT(divisor.is_int()); SASSERT(divisor.is_pos()); - if (!divisor.is_one()) { + if (!divisor.is_one() && !max_gain.is_minus_one()) { max_gain = floor(max_gain/divisor)*divisor; } } @@ -1598,8 +1605,8 @@ namespace smt { */ template void theory_arith::init_gains( - theory_var x, // non-base variable to increment/decrement - bool inc, + theory_var x, // non-base variable to increment/decrement + bool inc, inf_numeral& min_gain, // min value to increment, -1 if rational inf_numeral& max_gain) { // max value to decrement, -1 if unbounded min_gain = -inf_numeral::one(); @@ -1617,6 +1624,11 @@ namespace smt { SASSERT(min_gain.is_minus_one() || min_gain.is_one()); SASSERT(!is_int(x) || max_gain.is_int()); SASSERT(is_int(x) == min_gain.is_one()); + TRACE("opt", + tout << "v" << x << " " + << "min gain: " << min_gain << " " + << "max gain: " << max_gain << "\n";); + } template @@ -1666,6 +1678,11 @@ namespace smt { normalize_gain(den_aij, max_gain); } } + TRACE("opt", + tout << "v" << x_i << " a_ij " << a_ij << " " + << "min gain: " << min_gain << " " + << "max gain: " << max_gain << " tighter: " + << (is_tighter?"true":"false") << "\n";); SASSERT(max_gain.is_minus_one() || !max_gain.is_neg()); SASSERT(min_gain.is_minus_one() || !min_gain.is_neg()); SASSERT(!is_int(x_i) || min_gain.is_pos()); @@ -1683,7 +1700,6 @@ namespace smt { row & r, bool max, bool& has_shared) { - TRACE("max_min", tout << "max_min...\n";); m_stats.m_max_min++; bool best_effort = false, inc = false; @@ -1988,7 +2004,7 @@ namespace smt { add_tmp_row_entry(m_tmp_row, it->m_coeff, it->m_var); } } - max_min_t r = max_min(m_tmp_row, max, has_shared); + max_min_t r = max_min_orig(m_tmp_row, max, has_shared); if (r == OPTIMIZED) { TRACE("opt", tout << mk_pp(e, get_manager()) << " " << (max ? "max" : "min") << " value is: " << get_value(v) << "\n"; display_row(tout, m_tmp_row, true); display_row_info(tout, m_tmp_row);); From 82f1e81ac24fe34d718a237fbc9df74ea847ba05 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Jan 2015 00:50:08 +0000 Subject: [PATCH 686/925] fix build errors on gcc Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith_aux.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index ffc8314e0..37cbf7bc0 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -417,7 +417,7 @@ namespace smt { template void theory_arith::atom::display(theory_arith const& th, std::ostream& out) const { literal l(get_bool_var(), !m_is_true); - out << "v" << get_var() << " " << get_bound_kind() << " " << get_k() << " "; + out << "v" << bound::get_var() << " " << bound::get_bound_kind() << " " << get_k() << " "; out << l << ":"; th.get_context().display_detailed_literal(out, l); } @@ -747,7 +747,7 @@ namespace smt { template void theory_arith::derived_bound::display(theory_arith const& th, std::ostream& out) const { - out << "v" << m_var << " " << get_bound_kind() << " " << get_value(); + out << "v" << bound::get_var() << " " << bound::get_bound_kind() << " " << bound::get_value(); ast_manager& m = th.get_manager(); for (unsigned i = 0; i < m_eqs.size(); ++i) { From f1d9228b943e40188720083ecb9bae7206722343 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Jan 2015 16:30:46 -0800 Subject: [PATCH 687/925] fix bug in context push/pop for sat solver Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 2 +- src/sat/sat_solver.cpp | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 209601c78..6bc0cfa9b 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -925,7 +925,7 @@ public: } void verify_assignment() { - IF_VERBOSE(0, verbose_stream() << "verify assignment\n";); + IF_VERBOSE(1, verbose_stream() << "verify assignment\n";); ref smt_solver = mk_smt_solver(m, m_params, symbol()); for (unsigned i = 0; i < s().get_num_assertions(); ++i) { smt_solver->assert_expr(s().get_assertion(i)); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index a2d39d3ea..817fb2c23 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -930,8 +930,11 @@ namespace sat { void solver::reinit_assumptions() { if (tracking_assumptions() && scope_lvl() == 0) { - TRACE("sat", tout << m_assumptions.size() << "\n";); + TRACE("sat", tout << m_assumptions << "\n";); push(); + for (unsigned i = 0; !inconsistent() && i < m_user_scope_literals.size(); ++i) { + assign(~m_user_scope_literals[i], justification()); + } for (unsigned i = 0; !inconsistent() && i < m_assumptions.size(); ++i) { assign(m_assumptions[i], justification()); } From e24db5665076f16de2d6a037ab1f89736ad4d697 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Jan 2015 16:38:45 -0800 Subject: [PATCH 688/925] integrating new integer primal loop Signed-off-by: Nikolaj Bjorner --- src/opt/inc_sat_solver.cpp | 6 ++- src/opt/maxsmt.cpp | 4 +- src/opt/opt_context.cpp | 43 ++++++++++++++---- src/opt/opt_context.h | 2 + src/opt/opt_pareto.cpp | 7 ++- src/opt/opt_pareto.h | 2 + src/opt/opt_solver.cpp | 18 ++++++-- src/opt/optsmt.cpp | 5 +++ src/smt/diff_logic.h | 4 ++ src/smt/smt_context.cpp | 2 + src/smt/theory_arith.h | 4 +- src/smt/theory_arith_aux.h | 63 +++++++++++++++------------ src/smt/theory_dense_diff_logic.h | 5 ++- src/smt/theory_dense_diff_logic_def.h | 36 ++++++++++++--- src/smt/theory_diff_logic.h | 4 +- src/smt/theory_diff_logic_def.h | 42 ++++++++++++++---- src/smt/theory_opt.h | 2 +- 17 files changed, 183 insertions(+), 66 deletions(-) diff --git a/src/opt/inc_sat_solver.cpp b/src/opt/inc_sat_solver.cpp index 1a3fc7ff5..6dd562f82 100644 --- a/src/opt/inc_sat_solver.cpp +++ b/src/opt/inc_sat_solver.cpp @@ -30,6 +30,7 @@ Notes: #include "simplify_tactic.h" #include "goal2sat.h" #include "ast_pp.h" +#include "model_smt2_pp.h" // incremental SAT solver. class inc_sat_solver : public solver { @@ -396,14 +397,15 @@ private: (*m_mc)(m_model); } SASSERT(m_model); - // IF_VERBOSE(0, model_smt2_pp(verbose_stream(), m, *(m_model.get()), 0);); DEBUG_CODE( for (unsigned i = 0; i < m_fmls.size(); ++i) { expr_ref tmp(m); VERIFY(m_model->eval(m_fmls[i].get(), tmp)); CTRACE("opt", !m.is_true(tmp), - tout << "Evaluation failed: " << mk_pp(m_fmls[i].get(), m) << "\n";); + tout << "Evaluation failed: " << mk_pp(m_fmls[i].get(), m) + << " to " << tmp << "\n"; + model_smt2_pp(tout, m, *(m_model.get()), 0);); SASSERT(m.is_true(tmp)); }); } diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 16e577021..b1bf015f9 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -251,11 +251,11 @@ namespace opt { } void maxsmt::update_lower(rational const& r) { - if (m_lower > r) m_lower = r; + m_lower = r; } void maxsmt::update_upper(rational const& r) { - if (m_upper < r) m_upper = r; + m_upper = r; } void maxsmt::get_model(model_ref& mdl) { diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 141a2d425..5cd2e1c1e 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -247,8 +247,7 @@ namespace opt { mdl = m_model; } - void context::get_model(model_ref& mdl) { - mdl = m_model; + void context::fix_model(model_ref& mdl) { if (mdl) { if (m_model_converter) { (*m_model_converter)(mdl, 0); @@ -257,6 +256,16 @@ namespace opt { } } + void context::set_model(model_ref& mdl) { + m_model = mdl; + fix_model(mdl); + } + + void context::get_model(model_ref& mdl) { + mdl = m_model; + fix_model(mdl); + } + lbool context::execute_min_max(unsigned index, bool committed, bool scoped, bool is_max) { if (scoped) get_solver().push(); lbool result = m_optsmt.lex(index, is_max); @@ -384,6 +393,9 @@ namespace opt { break; } } + TRACE("opt", + model_smt2_pp(tout << "Model:\n", m, *mdl, 0); + mdl->eval(term, val); tout << term << " " << val << "\n";); VERIFY(mdl->eval(term, val) && is_numeral(val, r)); } @@ -914,9 +926,12 @@ namespace opt { objective const& obj = m_objectives[i]; rational r; switch(obj.m_type) { - case O_MINIMIZE: - if (m_model->eval(obj.m_term, val) && is_numeral(val, r)) { + case O_MINIMIZE: { + bool evaluated = m_model->eval(obj.m_term, val); + TRACE("opt", tout << obj.m_term << " " << val << " " << evaluated << " " << is_numeral(val, r) << "\n";); + if (evaluated && is_numeral(val, r)) { inf_eps val = inf_eps(obj.m_adjust_value(r)); + TRACE("opt", tout << "adjusted value: " << val << "\n";); if (is_lower) { m_optsmt.update_lower(obj.m_index, val); } @@ -925,9 +940,13 @@ namespace opt { } } break; - case O_MAXIMIZE: - if (m_model->eval(obj.m_term, val) && is_numeral(val, r)) { + } + case O_MAXIMIZE: { + bool evaluated = m_model->eval(obj.m_term, val); + TRACE("opt", tout << obj.m_term << " " << val << "\n";); + if (evaluated && is_numeral(val, r)) { inf_eps val = inf_eps(obj.m_adjust_value(r)); + TRACE("opt", tout << "adjusted value: " << val << "\n";); if (is_lower) { m_optsmt.update_lower(obj.m_index, val); } @@ -936,10 +955,13 @@ namespace opt { } } break; + } case O_MAXSMT: { bool ok = true; for (unsigned j = 0; ok && j < obj.m_terms.size(); ++j) { - if (m_model->eval(obj.m_terms[j], val)) { + bool evaluated = m_model->eval(obj.m_terms[j], val); + TRACE("opt", tout << mk_pp(obj.m_terms[j], m) << " " << val << "\n";); + if (evaluated) { if (!m.is_true(val)) { r += obj.m_weights[j]; } @@ -949,11 +971,14 @@ namespace opt { } } if (ok) { + maxsmt& ms = *m_maxsmts.find(obj.m_id); if (is_lower) { - m_maxsmts.find(obj.m_id)->update_upper(r); + ms.update_upper(r); + TRACE("opt", tout << r << " " << ms.get_upper() << "\n";); } else { - m_maxsmts.find(obj.m_id)->update_lower(r); + ms.update_lower(r); + TRACE("opt", tout << r << " " << ms.get_lower() << "\n";); } } break; diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 5ebb4db3f..3d29c8fee 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -147,6 +147,8 @@ namespace opt { virtual void set_hard_constraints(ptr_vector & hard); virtual lbool optimize(); virtual void get_model(model_ref& m); + virtual void set_model(model_ref& m); + virtual void fix_model(model_ref& m); virtual void collect_statistics(statistics& stats) const; virtual proof* get_proof() { return 0; } virtual void get_labels(svector & r) {} diff --git a/src/opt/opt_pareto.cpp b/src/opt/opt_pareto.cpp index 2e0286945..e8b295d9f 100644 --- a/src/opt/opt_pareto.cpp +++ b/src/opt/opt_pareto.cpp @@ -38,7 +38,10 @@ namespace opt { return l_undef; } m_solver->get_model(m_model); - IF_VERBOSE(1, model_smt2_pp(verbose_stream() << "new model:\n", m, *m_model, 0);); + IF_VERBOSE(1, + model_ref mdl(m_model); + cb.fix_model(mdl); + model_smt2_pp(verbose_stream() << "new model:\n", m, *mdl, 0);); // TBD: we can also use local search to tune solution coordinate-wise. mk_dominates(); is_sat = m_solver->check_sat(0, 0); @@ -65,6 +68,7 @@ namespace opt { fmls.push_back(m.mk_or(gt.size(), gt.c_ptr())); fml = m.mk_and(fmls.size(), fmls.c_ptr()); IF_VERBOSE(10, verbose_stream() << "dominates: " << fml << "\n";); + TRACE("opt", tout << fml << "\n";); m_solver->assert_expr(fml); } @@ -77,6 +81,7 @@ namespace opt { } fml = m.mk_not(m.mk_and(le.size(), le.c_ptr())); IF_VERBOSE(10, verbose_stream() << "not dominated by: " << fml << "\n";); + TRACE("opt", tout << fml << "\n";); m_solver->assert_expr(fml); } diff --git a/src/opt/opt_pareto.h b/src/opt/opt_pareto.h index 84e0702aa..ce78e68f3 100644 --- a/src/opt/opt_pareto.h +++ b/src/opt/opt_pareto.h @@ -31,6 +31,8 @@ namespace opt { virtual expr_ref mk_gt(unsigned i, model_ref& model) = 0; virtual expr_ref mk_ge(unsigned i, model_ref& model) = 0; virtual expr_ref mk_le(unsigned i, model_ref& model) = 0; + virtual void set_model(model_ref& m) = 0; + virtual void fix_model(model_ref& m) = 0; }; class pareto_base { protected: diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 2f0fc4661..2a12818c5 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -194,6 +194,7 @@ namespace opt { inf_eps val = get_optimizer().maximize(v, blocker, has_shared); inf_eps val2; m_valid_objectives[i] = true; + TRACE("opt", tout << (has_shared?"has shared":"non-shared") << "\n";); if (m_context.get_context().update_model(has_shared)) { if (has_shared) { val2 = current_objective_value(i); @@ -302,20 +303,31 @@ namespace opt { if (typeid(smt::theory_inf_arith) == typeid(opt)) { smt::theory_inf_arith& th = dynamic_cast(opt); - return expr_ref(th.mk_ge(m_fm, v, val), m); + return th.mk_ge(m_fm, v, val); } if (typeid(smt::theory_mi_arith) == typeid(opt)) { smt::theory_mi_arith& th = dynamic_cast(opt); SASSERT(val.is_finite()); - return expr_ref(th.mk_ge(m_fm, v, val.get_numeral()), m); + return th.mk_ge(m_fm, v, val.get_numeral()); } if (typeid(smt::theory_i_arith) == typeid(opt)) { SASSERT(val.is_finite()); SASSERT(val.get_infinitesimal().is_zero()); smt::theory_i_arith& th = dynamic_cast(opt); - return expr_ref(th.mk_ge(m_fm, v, val.get_rational()), m); + return th.mk_ge(m_fm, v, val.get_rational()); + } + + if (typeid(smt::theory_idl) == typeid(opt)) { + smt::theory_idl& th = dynamic_cast(opt); + return th.mk_ge(m_fm, v, val.get_rational()); + } + + if (typeid(smt::theory_rdl) == typeid(opt) && + val.get_infinitesimal().is_zero()) { + smt::theory_rdl& th = dynamic_cast(opt); + return th.mk_ge(m_fm, v, val.get_rational()); } // difference logic? diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index f0ef78c77..1148e3411 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -170,11 +170,13 @@ namespace opt { } void optsmt::update_lower(unsigned idx, inf_eps const& v) { + TRACE("opt", tout << "v" << idx << " >= " << v << "\n";); m_lower_fmls[idx] = m_s->mk_ge(idx, v); m_lower[idx] = v; } void optsmt::update_upper(unsigned idx, inf_eps const& v) { + TRACE("opt", tout << "v" << idx << " <= " << v << "\n";); m_upper[idx] = v; } @@ -302,6 +304,9 @@ namespace opt { lbool is_sat = l_true; expr_ref block(m), tmp(m); + for (unsigned i = 0; i < obj_index; ++i) { + commit_assignment(i); + } while (is_sat == l_true && !m_cancel) { is_sat = m_s->check_sat(0, 0); if (is_sat != l_true) break; diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index 32f8111f0..0685bb90c 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -1193,6 +1193,10 @@ public: return m_assignment[v]; } + void set_assignment(dl_var v, numeral const & n) { + m_assignment[v] = n; + } + unsigned get_timestamp() const { return m_timestamp; } diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 8a355009a..adb17f6e2 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3944,10 +3944,12 @@ namespace smt { if (refinalize) { fcs = final_check(); } + TRACE("opt", tout << (refinalize?"refinalize":"no-op") << " " << fcs << "\n";); if (fcs == FC_DONE) { mk_proto_model(l_true); m_model = m_proto_model->mk_model(); } + return fcs == FC_DONE; } diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 1dadeeca0..a81be26f6 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -894,7 +894,7 @@ namespace smt { void init_gains(theory_var x, bool inc, inf_numeral& min_gain, inf_numeral& max_gain); bool update_gains(bool inc, theory_var x_i, numeral const& a_ij, inf_numeral& min_gain, inf_numeral& max_gain); - bool move_to_bound_new(theory_var x_i, bool inc, bool& best_effort, bool& has_shared); + bool move_to_bound_new(theory_var x_i, bool inc, unsigned& best_efforts, bool& has_shared); bool pick_var_to_leave( theory_var x_j, bool inc, numeral & a_ij, inf_numeral& min_gain, inf_numeral& max_gain, @@ -1036,7 +1036,7 @@ namespace smt { virtual inf_eps_rational maximize(theory_var v, expr_ref& blocker, bool& has_shared); virtual inf_eps_rational value(theory_var v); virtual theory_var add_objective(app* term); - virtual expr* mk_ge(filter_model_converter& fm, theory_var v, inf_numeral const& val); + virtual expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_numeral const& val); void enable_record_conflict(expr* bound); void record_conflict(unsigned num_lits, literal const * lits, unsigned num_eqs, enode_pair const * eqs, diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index ffc8314e0..d8c615547 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -1189,7 +1189,7 @@ namespace smt { This allows to handle inequalities with non-standard numbers. */ template - expr* theory_arith::mk_ge(filter_model_converter& fm, theory_var v, inf_numeral const& val) { + expr_ref theory_arith::mk_ge(filter_model_converter& fm, theory_var v, inf_numeral const& val) { ast_manager& m = get_manager(); context& ctx = get_context(); std::ostringstream strm; @@ -1208,7 +1208,7 @@ namespace smt { TRACE("arith", tout << mk_pp(b, m) << "\n"; display_atom(tout, a, false);); } - return b; + return expr_ref(b, m); } @@ -1658,9 +1658,17 @@ namespace smt { bool is_tighter = false; if (is_int(x_i)) den_aij = denominator(a_ij); SASSERT(den_aij.is_pos() && den_aij.is_int()); + + if (is_int(x_i) && !den_aij.is_one()) { + SASSERT(min_gain.is_pos()); + min_gain = inf_numeral(lcm(min_gain.get_rational(), den_aij)); + normalize_gain(min_gain.get_rational(), max_gain); + } + if (!max_inc.is_minus_one()) { if (is_int(x_i)) { - normalize_gain(den_aij, max_inc); + max_inc = floor(max_inc); + normalize_gain(min_gain.get_rational(), max_inc); } if (unbounded_gain(max_gain)) { max_gain = max_inc; @@ -1671,13 +1679,6 @@ namespace smt { is_tighter = true; } } - if (is_int(x_i)) { - SASSERT(min_gain.is_pos()); - if (!den_aij.is_one()) { - min_gain = inf_numeral(lcm(min_gain.get_rational(), den_aij)); - normalize_gain(den_aij, max_gain); - } - } TRACE("opt", tout << "v" << x_i << " a_ij " << a_ij << " " << "min gain: " << min_gain << " " @@ -1701,7 +1702,8 @@ namespace smt { bool max, bool& has_shared) { m_stats.m_max_min++; - bool best_effort = false, inc = false; + unsigned best_efforts = 0; + bool inc = false; SASSERT(valid_assignment()); @@ -1712,7 +1714,8 @@ namespace smt { #endif max_min_t result = OPTIMIZED; has_shared = false; - while (true) { + unsigned max_efforts = 10 + (get_context().get_random_value() % 20); + while (best_efforts < max_efforts) { theory_var x_j = null_theory_var; theory_var x_i = null_theory_var; max_gain.reset(); @@ -1734,10 +1737,11 @@ namespace smt { if (!pick_var_to_leave(curr_x_j, curr_inc, curr_a_ij, curr_min_gain, curr_max_gain, has_shared, curr_x_i)) { - best_effort = true; - continue; + best_efforts++; + } + else { + SASSERT(safe_gain(curr_min_gain, curr_max_gain)); } - SASSERT(safe_gain(curr_min_gain, curr_max_gain)); if (curr_x_i == null_theory_var) { TRACE("opt", tout << "unbounded\n";); // we can increase/decrease curr_x_j as much as we want. @@ -1770,7 +1774,7 @@ namespace smt { } TRACE("opt", tout << "after traversing row:\nx_i: v" << x_i << ", x_j: v" << x_j << ", gain: " << max_gain << "\n"; - tout << "skipped row: " << (best_effort?"yes":"no") << "\n"; + tout << "best efforts: " << best_efforts << "\n"; display(tout);); if (x_j == null_theory_var) { @@ -1781,7 +1785,7 @@ namespace smt { } if (min_gain.is_pos() && !min_gain.is_one()) { - best_effort = true; + ++best_efforts; } if (x_i == null_theory_var) { // can increase/decrease x_j as much as we want. @@ -1802,7 +1806,7 @@ namespace smt { continue; } SASSERT(unbounded_gain(max_gain)); - best_effort = false; + best_efforts = 0; result = UNBOUNDED; break; } @@ -1836,9 +1840,8 @@ namespace smt { SASSERT(is_base(x_j)); bool inc_xi = inc?a_ij.is_neg():a_ij.is_pos(); - if (!move_to_bound_new(x_i, inc_xi, best_effort, has_shared)) { - best_effort = true; - break; + if (!move_to_bound_new(x_i, inc_xi, best_efforts, has_shared)) { + // break; } row & r2 = m_rows[get_var_row(x_j)]; @@ -1848,7 +1851,7 @@ namespace smt { SASSERT(valid_assignment()); } TRACE("opt", display(tout);); - return best_effort?BEST_EFFORT:result; + return (best_efforts>0)?BEST_EFFORT:result; } /** @@ -1862,7 +1865,7 @@ namespace smt { bool theory_arith::move_to_bound_new( theory_var x_i, // variable to move bool inc, // increment variable or decrement - bool& best_effort, // is bound move a best effort? + unsigned& best_efforts, // is bound move a best effort? bool& has_shared) { // does move include shared variables? inf_numeral min_gain, max_gain; init_gains(x_i, inc, min_gain, max_gain); @@ -1877,6 +1880,7 @@ namespace smt { update_gains(inc, s, coeff, min_gain, max_gain); has_shared |= get_context().is_shared(get_enode(s)); } + bool result = false; if (safe_gain(min_gain, max_gain)) { TRACE("opt", tout << "Safe delta: " << max_gain << "\n";); SASSERT(!unbounded_gain(max_gain)); @@ -1884,12 +1888,15 @@ namespace smt { max_gain.neg(); } update_value(x_i, max_gain); - best_effort = min_gain.is_pos() && !min_gain.is_one(); - return !max_gain.is_zero(); + if (!min_gain.is_pos() || min_gain.is_one()) { + ++best_efforts; + } + result = !max_gain.is_zero(); } - else { - return false; + if (!result) { + ++best_efforts; } + return result; } /** @@ -2004,7 +2011,7 @@ namespace smt { add_tmp_row_entry(m_tmp_row, it->m_coeff, it->m_var); } } - max_min_t r = max_min_orig(m_tmp_row, max, has_shared); + max_min_t r = max_min_new(m_tmp_row, max, has_shared); if (r == OPTIMIZED) { TRACE("opt", tout << mk_pp(e, get_manager()) << " " << (max ? "max" : "min") << " value is: " << get_value(v) << "\n"; display_row(tout, m_tmp_row, true); display_row_info(tout, m_tmp_row);); diff --git a/src/smt/theory_dense_diff_logic.h b/src/smt/theory_dense_diff_logic.h index 4144d9c03..04e257889 100644 --- a/src/smt/theory_dense_diff_logic.h +++ b/src/smt/theory_dense_diff_logic.h @@ -198,6 +198,7 @@ namespace smt { void del_vars(unsigned old_num_vars); void init_model(); bool internalize_objective(expr * n, rational const& m, rational& r, objective_term & objective); + expr_ref mk_ineq(theory_var v, inf_rational const& val, bool is_strict); #ifdef Z3DEBUG bool check_vector_sizes() const; bool check_matrix() const; @@ -270,8 +271,8 @@ namespace smt { virtual inf_eps_rational value(theory_var v); virtual theory_var add_objective(app* term); virtual expr_ref mk_gt(theory_var v, inf_rational const& val); - virtual expr* mk_ge(theory_var v, inf_rational const& val) { return 0; } - + virtual expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_rational const& val); + // ----------------------------------- // // Main diff --git a/src/smt/theory_dense_diff_logic_def.h b/src/smt/theory_dense_diff_logic_def.h index 29684d987..89e23cd3f 100644 --- a/src/smt/theory_dense_diff_logic_def.h +++ b/src/smt/theory_dense_diff_logic_def.h @@ -1030,6 +1030,17 @@ namespace smt { template expr_ref theory_dense_diff_logic::mk_gt(theory_var v, inf_rational const& val) { + return mk_ineq(v, val, true); + } + + template + expr_ref theory_dense_diff_logic::mk_ge( + filter_model_converter& fm, theory_var v, inf_rational const& val) { + return mk_ineq(v, val, false); + } + + template + expr_ref theory_dense_diff_logic::mk_ineq(theory_var v, inf_rational const& val, bool is_strict) { ast_manager& m = get_manager(); objective_term const& t = m_objectives[v]; expr_ref e(m), f(m), f2(m); @@ -1052,19 +1063,32 @@ namespace smt { else { // expr_ref_vector const& core = m_objective_assignments[v]; - f = m.mk_not(m.mk_and(core.size(), core.c_ptr())); + f = m.mk_and(core.size(), core.c_ptr()); + if (is_strict) { + f = m.mk_not(f); + } TRACE("arith", tout << "block: " << f << "\n";); return f; } - inf_rational new_val = val - inf_rational(m_objective_consts[v]); - e = m_autil.mk_numeral(new_val.get_rational(), m.get_sort(f)); + e = m_autil.mk_numeral(val.get_rational(), m.get_sort(f)); - if (new_val.get_infinitesimal().is_neg()) { - f = m_autil.mk_ge(f, e); + if (val.get_infinitesimal().is_neg()) { + if (is_strict) { + f = m_autil.mk_ge(f, e); + } + else { + expr_ref_vector const& core = m_objective_assignments[v]; + f = m.mk_and(core.size(), core.c_ptr()); + } } else { - f = m_autil.mk_gt(f, e); + if (is_strict) { + f = m_autil.mk_gt(f, e); + } + else { + f = m_autil.mk_ge(f, e); + } } return f; } diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h index 0327298b3..8b5bb2b86 100644 --- a/src/smt/theory_diff_logic.h +++ b/src/smt/theory_diff_logic.h @@ -324,13 +324,13 @@ namespace smt { virtual inf_eps value(theory_var v); virtual theory_var add_objective(app* term); virtual expr_ref mk_gt(theory_var v, inf_rational const& val); - virtual expr* mk_ge(theory_var v, inf_rational const& val) { return 0; } + virtual expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_rational const& val); bool internalize_objective(expr * n, rational const& m, rational& r, objective_term & objective); private: - expr_ref block_objective(theory_var v, inf_rational const& val); + expr_ref mk_ineq(theory_var v, inf_rational const& val, bool is_strict); virtual void new_eq_eh(theory_var v1, theory_var v2, justification& j); diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index ee9823912..6c43c8d11 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -546,7 +546,7 @@ void theory_diff_logic::propagate_core() { template bool theory_diff_logic::propagate_atom(atom* a) { context& ctx = get_context(); - TRACE("arith", a->display(*this, tout); ); + TRACE("arith", a->display(*this, tout); tout << "\n";); if (ctx.inconsistent()) { return false; } @@ -1236,6 +1236,13 @@ theory_diff_logic::maximize(theory_var v, expr_ref& blocker, bool& has_shar core.push_back(tmp); } } + compute_delta(); + for (unsigned i = 0; i < m_graph.get_num_nodes(); ++i) { + unsigned w = node2simplex(i); + simplex::mpq_ext::eps_numeral const& val = S.get_value(w); + rational r = rational(val.first) + m_delta*rational(val.second); + m_graph.set_assignment(i, numeral(r)); + } blocker = mk_gt(v, r); return inf_eps(rational(0), r + m_objective_consts[v]); } @@ -1267,7 +1274,7 @@ theory_var theory_diff_logic::add_objective(app* term) { } template -expr_ref theory_diff_logic::block_objective(theory_var v, inf_rational const& val) { +expr_ref theory_diff_logic::mk_ineq(theory_var v, inf_rational const& val, bool is_strict) { ast_manager& m = get_manager(); objective_term const& t = m_objectives[v]; expr_ref e(m), f(m), f2(m); @@ -1290,7 +1297,10 @@ expr_ref theory_diff_logic::block_objective(theory_var v, inf_rational cons else { // expr_ref_vector const& core = m_objective_assignments[v]; - f = m.mk_not(m.mk_and(core.size(), core.c_ptr())); + f = m.mk_and(core.size(), core.c_ptr()); + if (is_strict) { + f = m.mk_not(f); + } TRACE("arith", tout << "block: " << f << "\n";); return f; } @@ -1299,18 +1309,35 @@ expr_ref theory_diff_logic::block_objective(theory_var v, inf_rational cons e = m_util.mk_numeral(new_val.get_rational(), m.get_sort(f)); if (new_val.get_infinitesimal().is_neg()) { - f = m_util.mk_ge(f, e); + if (is_strict) { + f = m_util.mk_ge(f, e); + } + else { + expr_ref_vector const& core = m_objective_assignments[v]; + f = m.mk_and(core.size(), core.c_ptr()); + } } else { - f = m_util.mk_gt(f, e); + if (is_strict) { + f = m_util.mk_gt(f, e); + } + else { + f = m_util.mk_ge(f, e); + } } return f; } template expr_ref theory_diff_logic::mk_gt(theory_var v, inf_rational const& val) { - expr_ref o = block_objective(v, val); - return o; + return mk_ineq(v, val, true); +} + +template +expr_ref theory_diff_logic::mk_ge(filter_model_converter& fm, theory_var v, inf_rational const& val) { + return mk_ineq(v, val, false); +} + #if 0 context & ctx = get_context(); model_ref mdl; @@ -1321,7 +1348,6 @@ expr_ref theory_diff_logic::mk_gt(theory_var v, inf_rational const& val) { expr_ref_vector implicants = impl_extractor.minimize_literals(formulas, mdl); return m.mk_and(o, m.mk_not(m.mk_and(implicants.size(), implicants.c_ptr()))); #endif -} template bool theory_diff_logic::internalize_objective(expr * n, rational const& m, rational& q, objective_term & objective) { diff --git a/src/smt/theory_opt.h b/src/smt/theory_opt.h index 9db05a438..61acfc381 100644 --- a/src/smt/theory_opt.h +++ b/src/smt/theory_opt.h @@ -33,7 +33,7 @@ namespace smt { virtual inf_eps value(theory_var) = 0; virtual inf_eps maximize(theory_var v, expr_ref& blocker, bool& has_shared) = 0; virtual theory_var add_objective(app* term) = 0; - virtual expr* mk_ge(filter_model_converter& fm, theory_var v, inf_eps const& val) { UNREACHABLE(); return 0; } + virtual expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_eps const& val) { UNREACHABLE(); return expr_ref(*((ast_manager*)0)); } bool is_linear(ast_manager& m, expr* term); bool is_numeral(arith_util& a, expr* term); }; From 18b137219932ccb7d8cd0f472015d7b79d05cdc0 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 23 Jan 2015 14:56:25 +0000 Subject: [PATCH 689/925] DoC: remove unused class fields in join operation --- src/muz/rel/udoc_relation.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 37cc91778..6868755e4 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -314,17 +314,13 @@ namespace datalog { doc_manager& dm; doc_manager& dm1; doc_manager& dm2; - unsigned_vector m_orig_cols1; - unsigned_vector m_orig_cols2; public: join_fn(udoc_plugin& p, udoc_relation const& t1, udoc_relation const& t2, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) : convenient_relation_join_fn(t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2), dm(p.dm(get_result_signature())), dm1(t1.get_dm()), - dm2(t2.get_dm()), - m_orig_cols1(m_cols1), - m_orig_cols2(m_cols2) { + dm2(t2.get_dm()) { t1.expand_column_vector(m_cols1); t2.expand_column_vector(m_cols2); } From 92f6dd4de43b568c74f1952fcb6bb4f439e30f0d Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 23 Jan 2015 16:55:02 +0000 Subject: [PATCH 690/925] DoC: factorize join and join_project code so that join_project learns need tricks (i.e., prune empty vectors upfront) --- src/muz/rel/doc.cpp | 75 +++++++++++++++++++ src/muz/rel/doc.h | 13 ++++ src/muz/rel/udoc_relation.cpp | 137 ++-------------------------------- 3 files changed, 96 insertions(+), 129 deletions(-) diff --git a/src/muz/rel/doc.cpp b/src/muz/rel/doc.cpp index ccd332a42..67e2f1e2b 100644 --- a/src/muz/rel/doc.cpp +++ b/src/muz/rel/doc.cpp @@ -411,6 +411,81 @@ doc* doc_manager::project(doc_manager& dstm, bit_vector const& to_delete, doc co return r; } +doc* doc_manager::join(const doc& d1, const doc& d2, doc_manager& dm1, + const unsigned_vector& cols1, + const unsigned_vector& cols2) { + doc_ref d(*this, allocateX()); + tbv_ref t(m); + tbv& pos = d->pos(); + utbv& neg = d->neg(); + unsigned mid = dm1.num_tbits(); + unsigned hi = num_tbits(); + m.set(pos, d1.pos(), mid - 1, 0); + m.set(pos, d2.pos(), hi - 1, mid); + SASSERT(well_formed(*d)); + + // first fix bits + for (unsigned i = 0; i < cols1.size(); ++i) { + unsigned idx1 = cols1[i]; + unsigned idx2 = mid + cols2[i]; + tbit v1 = pos[idx1]; + tbit v2 = pos[idx2]; + + if (v1 == BIT_x) { + if (v2 != BIT_x) + m.set(pos, idx1, v2); + } + else if (v2 == BIT_x) { + m.set(pos, idx2, v1); + } + else if (v1 != v2) { + // columns don't match + return 0; + } + SASSERT(well_formed(*d)); + } + + // fix equality of don't care columns + for (unsigned i = 0; i < cols1.size(); ++i) { + unsigned idx1 = cols1[i]; + unsigned idx2 = mid + cols2[i]; + unsigned v1 = pos[idx1]; + unsigned v2 = pos[idx2]; + + if (v1 == BIT_x && v2 == BIT_x) { + // add to subtracted TBVs: 1xx0 and 0xx1 + t = m.allocate(pos); + m.set(*t, idx1, BIT_0); + m.set(*t, idx2, BIT_1); + neg.push_back(t.detach()); + t = m.allocate(pos); + m.set(*t, idx1, BIT_1); + m.set(*t, idx2, BIT_0); + neg.push_back(t.detach()); + } + SASSERT(well_formed(*d)); + } + + // handle subtracted TBVs: 1010 -> 1010xxx + for (unsigned i = 0; i < d1.neg().size(); ++i) { + t = m.allocateX(); + m.set(*t, d1.neg()[i], mid - 1, 0); + if (m.set_and(*t, pos)) + neg.push_back(t.detach()); + SASSERT(well_formed(*d)); + } + for (unsigned i = 0; i < d2.neg().size(); ++i) { + t = m.allocateX(); + m.set(*t, d2.neg()[i], hi - 1, mid); + if (m.set_and(*t, pos)) + neg.push_back(t.detach()); + SASSERT(well_formed(*d)); + } + SASSERT(well_formed(*d)); + + return d.detach(); +} + doc_manager::project_action_t doc_manager::pick_resolvent( tbv const& pos, tbv_vector const& neg, bit_vector const& to_delete, unsigned& idx) { diff --git a/src/muz/rel/doc.h b/src/muz/rel/doc.h index f78ce94ff..fcb134d9e 100644 --- a/src/muz/rel/doc.h +++ b/src/muz/rel/doc.h @@ -91,6 +91,8 @@ public: bool well_formed(doc const& d) const; bool merge(doc& d, unsigned lo, unsigned length, subset_ints const& equalities, bit_vector const& discard_cols); void set(doc& d, unsigned idx, tbit value); + doc* join(const doc& a, const doc& b, doc_manager& dm1, + const unsigned_vector& cols1, const unsigned_vector& cols2); void verify_project(ast_manager& m, doc_manager& dstm, bit_vector const& to_delete, doc const& src, doc const& dst); private: @@ -314,6 +316,16 @@ public: } } + void join(const union_bvec& d1, const union_bvec& d2, M& dm, M& dm1, + const unsigned_vector& cols1, const unsigned_vector& cols2) { + for (unsigned i = 0; i < d1.size(); ++i) { + for (unsigned j = 0; j < d2.size(); ++j) { + if (T *d = dm.join(d1[i], d2[j], dm1, cols1, cols2)) + insert(dm, d); + } + } + } + }; @@ -367,6 +379,7 @@ public: doc& operator*() { return *d; } doc* operator->() { return d; } doc* detach() { doc* r = d; d = 0; return r; } + operator bool() const { return d != 0; } }; #endif /* _DOC_H_ */ diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 37cc91778..778440587 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -314,96 +314,17 @@ namespace datalog { doc_manager& dm; doc_manager& dm1; doc_manager& dm2; - unsigned_vector m_orig_cols1; - unsigned_vector m_orig_cols2; public: join_fn(udoc_plugin& p, udoc_relation const& t1, udoc_relation const& t2, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) : convenient_relation_join_fn(t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2), dm(p.dm(get_result_signature())), dm1(t1.get_dm()), - dm2(t2.get_dm()), - m_orig_cols1(m_cols1), - m_orig_cols2(m_cols2) { + dm2(t2.get_dm()) { t1.expand_column_vector(m_cols1); t2.expand_column_vector(m_cols2); } - void join(doc const& d1, doc const& d2, udoc& result) { - doc_ref d(dm); - tbv_ref t(dm.tbvm()); - d = dm.allocateX(); - tbv& pos = d->pos(); - utbv& neg = d->neg(); - unsigned mid = dm1.num_tbits(); - unsigned hi = dm.num_tbits(); - dm.tbvm().set(pos,d1.pos(), mid-1, 0); - dm.tbvm().set(pos,d2.pos(), hi-1, mid); - SASSERT(dm.well_formed(*d)); - // first fix bits - for (unsigned i = 0; i < m_cols1.size(); ++i) { - unsigned idx1 = m_cols1[i]; - unsigned idx2 = mid + m_cols2[i]; - tbit v1 = pos[idx1]; - tbit v2 = pos[idx2]; - - if (v1 == BIT_x) { - if (v2 != BIT_x) - dm.tbvm().set(pos, idx1, v2); - } - else if (v2 == BIT_x) { - dm.tbvm().set(pos, idx2, v1); - } - else if (v1 != v2) { - // columns don't match - return; - } - SASSERT(dm.well_formed(*d)); - } - // fix equality of don't care columns - for (unsigned i = 0; i < m_cols1.size(); ++i) { - unsigned idx1 = m_cols1[i]; - unsigned idx2 = mid + m_cols2[i]; - unsigned v1 = pos[idx1]; - unsigned v2 = pos[idx2]; - - if (v1 == BIT_x && v2 == BIT_x) { - // add to subtracted TBVs: 1xx0 and 0xx1 - t = dm.tbvm().allocate(pos); - dm.tbvm().set(*t, idx1, BIT_0); - dm.tbvm().set(*t, idx2, BIT_1); - neg.push_back(t.detach()); - t = dm.tbvm().allocate(pos); - dm.tbvm().set(*t, idx1, BIT_1); - dm.tbvm().set(*t, idx2, BIT_0); - neg.push_back(t.detach()); - } - SASSERT(dm.well_formed(*d)); - } - - // handle subtracted TBVs: 1010 -> 1010xxx - for (unsigned i = 0; i < d1.neg().size(); ++i) { - t = dm.tbvm().allocate(); - dm.tbvm().set(*t, d1.neg()[i], mid - 1, 0); - dm.tbvm().set(*t, d2.pos(), hi - 1, mid); - if (dm.tbvm().set_and(*t, pos)) { - neg.push_back(t.detach()); - } - SASSERT(dm.well_formed(*d)); - } - for (unsigned i = 0; i < d2.neg().size(); ++i) { - t = dm.tbvm().allocate(); - dm.tbvm().set(*t, d1.pos(), mid- 1, 0); - dm.tbvm().set(*t, d2.neg()[i], hi - 1, mid); - if (dm.tbvm().set_and(*t, pos)) { - neg.push_back(t.detach()); - } - SASSERT(dm.well_formed(*d)); - } - SASSERT(dm.well_formed(*d)); - result.insert(dm, d.detach()); - } - virtual relation_base * operator()(const relation_base & _r1, const relation_base & _r2) { udoc_relation const& r1 = get(_r1); udoc_relation const& r2 = get(_r2); @@ -414,11 +335,7 @@ namespace datalog { udoc const& d1 = r1.get_udoc(); udoc const& d2 = r2.get_udoc(); udoc& r = result->get_udoc(); - for (unsigned i = 0; i < d1.size(); ++i) { - for (unsigned j = 0; j < d2.size(); ++j) { - join(d1[i], d2[j], r); - } - } + r.join(d1, d2, dm, dm1, m_cols1, m_cols2); TRACE("doc", result->display(tout << "result:\n");); IF_VERBOSE(3, result->display(verbose_stream() << "join result:\n");); SASSERT(r.well_formed(result->get_dm())); @@ -1054,11 +971,9 @@ namespace datalog { unsigned num_bits1 = t1.get_num_bits(); unsigned num_bits = num_bits1 + t2.get_num_bits(); unsigned_vector removed_cols(removed_col_cnt, rm_cols); - unsigned_vector expcols1(col_cnt, cols1); - unsigned_vector expcols2(col_cnt, cols2); t1.expand_column_vector(removed_cols, &t2); - t1.expand_column_vector(expcols1); - t2.expand_column_vector(expcols2); + t1.expand_column_vector(m_cols1); + t2.expand_column_vector(m_cols2); m_to_delete.resize(num_bits, false); for (unsigned i = 0; i < num_bits; ++i) { m_equalities.mk_var(); @@ -1066,10 +981,10 @@ namespace datalog { for (unsigned i = 0; i < removed_cols.size(); ++i) { m_to_delete.set(removed_cols[i], true); } - for (unsigned i = 0; i < expcols1.size(); ++i) { - m_equalities.merge(expcols1[i], expcols2[i] + num_bits1); + for (unsigned i = 0; i < m_cols1.size(); ++i) { + m_equalities.merge(m_cols1[i], m_cols2[i] + num_bits1); } - m_roots.append(expcols1); + m_roots.append(m_cols1); } @@ -1107,11 +1022,7 @@ namespace datalog { udoc_relation* result = get(p.mk_empty(get_result_signature())); udoc& res = result->get_udoc(); doc_manager& dm_res = result->get_dm(); - for (unsigned i = 0; i < d1.size(); ++i) { - for (unsigned j = 0; j < d2.size(); ++j) { - prod.push_back(xprod(dm_prod, dm1, dm2, d1[i], d2[j])); - } - } + prod.join(d1, d2, dm_prod, dm1, m_cols1, m_cols2); TRACE("doc", prod.display(dm_prod, tout) << "\n";); prod.merge(dm_prod, m_roots, m_equalities, m_to_delete); TRACE("doc", prod.display(dm_prod, tout) << "\n";); @@ -1122,38 +1033,6 @@ namespace datalog { prod.reset(dm_prod); return result; } - doc* xprod(doc_manager& dm, doc_manager& dm1, doc_manager& dm2, - doc const& d1, doc const& d2) { - tbv_manager& tbm = dm.tbvm(); - doc_ref d(dm); - tbv_ref t(tbm); - d = dm.allocateX(); - tbv& pos = d->pos(); - utbv& neg = d->neg(); - unsigned mid = dm1.num_tbits(); - unsigned hi = dm.num_tbits(); - tbm.set(pos, d1.pos(), mid-1, 0); - tbm.set(pos, d2.pos(), hi-1, mid); - for (unsigned i = 0; i < d1.neg().size(); ++i) { - t = tbm.allocateX(); - tbm.set(*t, d1.neg()[i], mid-1, 0); - VERIFY(tbm.set_and(*t, pos)); - neg.push_back(t.detach()); - } - for (unsigned i = 0; i < d2.neg().size(); ++i) { - t = tbm.allocateX(); - tbm.set(*t, d2.neg()[i], hi-1, mid); - VERIFY(tbm.set_and(*t, pos)); - neg.push_back(t.detach()); - } - SASSERT(dm.well_formed(*d)); - TRACE("doc", - dm1.display(tout, d1) << "\n"; - dm2.display(tout, d2) << "\n"; - dm.display(tout, *d) << "\n";); - return d.detach(); - } - }; From 93db50ff6428eb4a98ef33383d5beb22aace4179 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 23 Jan 2015 17:04:09 +0000 Subject: [PATCH 691/925] DoC: further code simplifications --- src/muz/rel/udoc_relation.cpp | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 778440587..23f3a55f6 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -950,8 +950,6 @@ namespace datalog { #endif union_find_default_ctx union_ctx; bit_vector m_to_delete; - subset_ints m_equalities; - unsigned_vector m_roots; public: join_project_fn( @@ -961,11 +959,10 @@ namespace datalog { : convenient_relation_join_project_fn( t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2, - removed_col_cnt, rm_cols), + removed_col_cnt, rm_cols) #if 0 - m_joiner(t1.get_plugin(), t1, t2, col_cnt, cols1, cols2), + , m_joiner(t1.get_plugin(), t1, t2, col_cnt, cols1, cols2) #endif - m_equalities(union_ctx) { udoc_plugin& p = t1.get_plugin(); unsigned num_bits1 = t1.get_num_bits(); @@ -975,16 +972,9 @@ namespace datalog { t1.expand_column_vector(m_cols1); t2.expand_column_vector(m_cols2); m_to_delete.resize(num_bits, false); - for (unsigned i = 0; i < num_bits; ++i) { - m_equalities.mk_var(); - } for (unsigned i = 0; i < removed_cols.size(); ++i) { m_to_delete.set(removed_cols[i], true); } - for (unsigned i = 0; i < m_cols1.size(); ++i) { - m_equalities.merge(m_cols1[i], m_cols2[i] + num_bits1); - } - m_roots.append(m_cols1); } @@ -1024,8 +1014,6 @@ namespace datalog { doc_manager& dm_res = result->get_dm(); prod.join(d1, d2, dm_prod, dm1, m_cols1, m_cols2); TRACE("doc", prod.display(dm_prod, tout) << "\n";); - prod.merge(dm_prod, m_roots, m_equalities, m_to_delete); - TRACE("doc", prod.display(dm_prod, tout) << "\n";); for (unsigned i = 0; i < prod.size(); ++i) { res.insert(dm_res, dm_prod.project(dm_res, m_to_delete, prod[i])); } From 036a56e360d667d70bad6d4c497420964cfc1acd Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 23 Jan 2015 17:09:17 +0000 Subject: [PATCH 692/925] DoC: remove another unused variable --- src/muz/rel/udoc_relation.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 23f3a55f6..c527a9dba 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -948,7 +948,6 @@ namespace datalog { #if 0 udoc_plugin::join_fn m_joiner; #endif - union_find_default_ctx union_ctx; bit_vector m_to_delete; public: From 044f2a93e725585fe0e24d082da99f586cef0fa6 Mon Sep 17 00:00:00 2001 From: Andrey Rybalchenko Date: Fri, 23 Jan 2015 19:53:14 +0000 Subject: [PATCH 693/925] fix build with gcc --- src/muz/rel/product_set.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/rel/product_set.cpp b/src/muz/rel/product_set.cpp index e3c275c67..9c26ed189 100644 --- a/src/muz/rel/product_set.cpp +++ b/src/muz/rel/product_set.cpp @@ -30,7 +30,7 @@ namespace datalog { product_set::product_set( product_set_plugin& p, relation_signature const& s, initial_t init, T const& t): - vector_relation(p, s, false, t), m_refs(0) { + vector_relation(p, s, false, t), m_refs(0) { unsigned delta = 0; for (unsigned i = 0; i < s.size(); ++i) { unsigned sz = p.set_size(s[i]); From 552cbd840fdd76e7cfa4323438eb5e942c63b8aa Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 23 Jan 2015 13:06:11 -0800 Subject: [PATCH 694/925] adding soft-assertions Signed-off-by: Nikolaj Bjorner --- src/opt/maxsmt.cpp | 4 ++++ src/opt/maxsmt.h | 1 + src/opt/opt_context.cpp | 7 +++++++ src/opt/opt_context.h | 1 + src/sat/sat_config.cpp | 1 + src/sat/sat_config.h | 1 + src/sat/sat_params.pyg | 1 + src/sat/sat_solver.cpp | 19 ++++++++++++++----- 8 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index b1bf015f9..48d7e48bd 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -105,6 +105,10 @@ namespace opt { m_c.set_enable_sls(f); } + void maxsmt_solver_base::set_soft_assumptions() { + m_c.set_soft_assumptions() + } + app* maxsmt_solver_base::mk_fresh_bool(char const* name) { app* result = m.mk_fresh_const(name, m.mk_bool_sort()); m_c.fm().insert(result->get_decl()); diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 6a19a223b..356a2d50b 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -102,6 +102,7 @@ namespace opt { protected: void enable_sls(expr_ref_vector const& soft, weights_t& ws); void set_enable_sls(bool f); + void set_soft_assumptions(); void trace_bounds(char const* solver); }; diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 5cd2e1c1e..028cb4414 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -493,6 +493,13 @@ namespace opt { } } + void context::set_soft_assumptions() { + if (m_sat_solver.get()) { + m_params.set_bool("soft_assumptions", true); + m_sat_solver->updt_params(m_params); + } + } + void context::enable_sls(expr_ref_vector const& soft, vector const& weights) { SASSERT(soft.size() == weights.size()); if (m_sat_solver.get()) { diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 3d29c8fee..ee4ce467a 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -184,6 +184,7 @@ namespace opt { params_ref& params() { return m_params; } void enable_sls(expr_ref_vector const& soft, weights_t& weights); void set_enable_sls(bool f) { m_enable_sls = f; } + void set_soft_assumptions(); symbol const& maxsat_engine() const { return m_maxsat_engine; } void get_base_model(model_ref& m); diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index aff023b22..0c100aff2 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -110,6 +110,7 @@ namespace sat { m_minimize_core = p.minimize_core(); m_minimize_core_partial = p.minimize_core_partial(); m_optimize_model = p.optimize_model(); + m_soft_assumptions = p.soft_assumptions(); m_bcd = p.bcd(); m_dyn_sub_res = p.dyn_sub_res(); } diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 61ab71605..29ef25f03 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -72,6 +72,7 @@ namespace sat { bool m_minimize_core; bool m_minimize_core_partial; bool m_optimize_model; + bool m_soft_assumptions; bool m_bcd; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index c5ac97b4e..ed4f4910a 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -22,5 +22,6 @@ def_module_params('sat', ('minimize_core', BOOL, False, 'minimize computed core'), ('minimize_core_partial', BOOL, False, 'apply partial (cheap) core minimization'), ('optimize_model', BOOL, False, 'enable optimization of soft constraints'), + ('soft_assumptions', BOOL, False, 'disable assumptions that are forced during unit propagation'), ('bcd', BOOL, False, 'enable blocked clause decomposition for equality extraction'), ('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'))) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 817fb2c23..1915f363f 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -914,17 +914,26 @@ namespace sat { for (unsigned i = 0; !inconsistent() && i < m_user_scope_literals.size(); ++i) { literal nlit = ~m_user_scope_literals[i]; - assign(nlit, justification()); - // propagate(false); + assign(nlit, justification()); } for (unsigned i = 0; !inconsistent() && i < num_lits; ++i) { literal lit = lits[i]; SASSERT(is_external((lit).var())); m_assumption_set.insert(lit); - m_assumptions.push_back(lit); - assign(lit, justification()); - // propagate(false); + + if (m_config.soft_assumptions) { + if (value(lit) == l_undef) { + m_assumptions.push_back(lit); + assign(lit, justification()); + } + propagate(false); + } + else { + m_assumptions.push_back(lit); + assign(lit, justification()); + // propagate(false); + } } } From 761c7d9a40373f0e37b9d0786c27a48c2c414a40 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 25 Jan 2015 04:01:18 -0800 Subject: [PATCH 695/925] adding annotation to logging to show number of columns and rows, adding dual propagation sketch Signed-off-by: Nikolaj Bjorner --- src/muz/rel/dl_base.h | 1 + src/muz/rel/dl_instruction.cpp | 80 ++++---- src/muz/rel/dl_instruction.h | 13 +- src/muz/rel/rel_context.cpp | 2 +- src/opt/inc_sat_solver.cpp | 7 +- src/opt/maxres.cpp | 330 +++++++++------------------------ src/opt/maxres.h | 4 +- src/opt/maxsmt.cpp | 9 +- src/opt/opt_context.cpp | 3 +- src/opt/opt_params.pyg | 2 +- src/sat/sat_solver.cpp | 2 +- src/shell/datalog_frontend.cpp | 2 +- 12 files changed, 152 insertions(+), 303 deletions(-) diff --git a/src/muz/rel/dl_base.h b/src/muz/rel/dl_base.h index fa9bc84ee..2dffa04f6 100644 --- a/src/muz/rel/dl_base.h +++ b/src/muz/rel/dl_base.h @@ -506,6 +506,7 @@ namespace datalog { virtual unsigned get_size_estimate_rows() const { return UINT_MAX; } virtual unsigned get_size_estimate_bytes() const { return UINT_MAX; } virtual bool knows_exact_size() const { return false; } + unsigned num_columns() const { return get_signature().size(); } virtual void display(std::ostream & out) const = 0; }; diff --git a/src/muz/rel/dl_instruction.cpp b/src/muz/rel/dl_instruction.cpp index 7fbe2f5ad..ea25dfc59 100644 --- a/src/muz/rel/dl_instruction.cpp +++ b/src/muz/rel/dl_instruction.cpp @@ -62,6 +62,10 @@ namespace datalog { return dynamic_cast(*m_context.get_rel_context()); } + rel_context const& execution_context::get_rel_context() const { + return dynamic_cast(*m_context.get_rel_context()); + } + struct compare_size_proc { typedef std::pair pr; bool operator()(pr const& a, pr const& b) const { @@ -164,21 +168,21 @@ namespace datalog { } - void instruction::display_indented(rel_context_base const & _ctx, std::ostream & out, std::string indentation) const { + void instruction::display_indented(execution_context const & _ctx, std::ostream & out, std::string indentation) const { out << indentation; - rel_context const& ctx = dynamic_cast(_ctx); - display_head_impl(ctx, out); + rel_context const& ctx = _ctx.get_rel_context(); + display_head_impl(_ctx, out); if (ctx.output_profile()) { out << " {"; output_profile(out); out << '}'; } out << "\n"; - display_body_impl(ctx, out, indentation); + display_body_impl(_ctx, out, indentation); } void instruction::log_verbose(execution_context& ctx) { - IF_VERBOSE(2, display(ctx.get_rel_context(), verbose_stream());); + IF_VERBOSE(2, display(ctx, verbose_stream());); } class instr_io : public instruction { @@ -217,7 +221,7 @@ namespace datalog { virtual void make_annotations(execution_context & ctx) { ctx.set_register_annotation(m_reg, m_pred->get_name().bare_str()); } - virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { + virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { const char * rel_name = m_pred->get_name().bare_str(); if (m_store) { out << "store " << m_reg << " into " << rel_name; @@ -248,7 +252,7 @@ namespace datalog { virtual void make_annotations(execution_context & ctx) { ctx.set_register_annotation(m_reg, "alloc"); } - virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { + virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { out << "dealloc " << m_reg; } }; @@ -283,7 +287,7 @@ namespace datalog { ctx.set_register_annotation(m_src, str); } } - virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { + virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { out << (m_clone ? "clone " : "move ") << m_src << " into " << m_tgt; } }; @@ -340,11 +344,11 @@ namespace datalog { virtual void make_annotations(execution_context & ctx) { m_body->make_annotations(ctx); } - virtual void display_head_impl(rel_context const & ctx, std::ostream & out) const { + virtual void display_head_impl(execution_context const & ctx, std::ostream & out) const { out << "while"; print_container(m_controls, out); } - virtual void display_body_impl(rel_context_base const & ctx, std::ostream & out, std::string indentation) const { + virtual void display_body_impl(execution_context const & ctx, std::ostream & out, std::string indentation) const { m_body->display_indented(ctx, out, indentation+" "); } }; @@ -409,7 +413,7 @@ namespace datalog { ctx.get_register_annotation(m_rel1, a1); ctx.set_register_annotation(m_res, "join " + a1 + " " + a2); } - virtual void display_head_impl(rel_context const & ctx, std::ostream & out) const { + virtual void display_head_impl(execution_context const & ctx, std::ostream & out) const { out << "join " << m_rel1; print_container(m_cols1, out); out << " and " << m_rel2; @@ -460,9 +464,9 @@ namespace datalog { a << "filter_equal " << m_col << " val: " << ctx.get_rel_context().get_rmanager().to_nice_string(m_value); ctx.set_register_annotation(m_reg, a.str()); } - virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { + virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { out << "filter_equal " << m_reg << " col: " << m_col << " val: " - << ctx.get_rmanager().to_nice_string(m_value); + << ctx.get_rel_context().get_rmanager().to_nice_string(m_value); } }; @@ -504,7 +508,7 @@ namespace datalog { } return true; } - virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { + virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { out << "filter_identical " << m_reg << " "; print_container(m_cols, out); } @@ -552,7 +556,7 @@ namespace datalog { return true; } - virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { + virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { out << "filter_interpreted " << m_reg << " using " << mk_pp(m_cond, m_cond.get_manager()); } @@ -609,7 +613,7 @@ namespace datalog { return true; } - virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { + virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { out << "filter_interpreted_and_project " << m_src << " into " << m_res; out << " using " << mk_pp(m_cond, m_cond.get_manager()); out << " deleting columns "; @@ -726,7 +730,7 @@ namespace datalog { } ctx.set_register_annotation(m_delta, str); } - virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { + virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { out << (m_widen ? "widen " : "union ") << m_src << " into " << m_tgt; if (m_delta!=execution_context::void_register) { out << " with delta " << m_delta; @@ -782,7 +786,7 @@ namespace datalog { return true; } - virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { + virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { out << (m_projection ? "project " : "rename ") << m_src << " into " << m_tgt; out << (m_projection ? " deleting columns " : " with cycle "); print_container(m_cols, out); @@ -846,10 +850,20 @@ namespace datalog { } return true; } - virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { - out << "join_project " << m_rel1; + virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { + relation_base const* r1 = ctx.reg(m_rel1); + relation_base const* r2 = ctx.reg(m_rel2); + out << "join_project " << m_rel1; + if (r1) { + out << ":" << r1->num_columns(); + out << "-" << r1->get_size_estimate_rows(); + } print_container(m_cols1, out); out << " and " << m_rel2; + if (r2) { + out << ":" << r2->num_columns(); + out << "-" << r2->get_size_estimate_rows(); + } print_container(m_cols2, out); out << " into " << m_res << " removing columns "; print_container(m_removed_cols, out); @@ -908,9 +922,9 @@ namespace datalog { } return true; } - virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { + virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { out << "select_equal_and_project " << m_src <<" into " << m_result << " col: " << m_col - << " val: " << ctx.get_rmanager().to_nice_string(m_value); + << " val: " << ctx.get_rel_context().get_rmanager().to_nice_string(m_value); } virtual void make_annotations(execution_context & ctx) { std::stringstream s; @@ -965,7 +979,7 @@ namespace datalog { } return true; } - virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { + virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { out << "filter_by_negation on " << m_tgt; print_container(m_cols1, out); out << " with " << m_neg_rel; @@ -1004,10 +1018,10 @@ namespace datalog { ctx.set_reg(m_tgt, rel); return true; } - virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { + virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { out << "mk_unary_singleton into " << m_tgt << " sort:" - << ctx.get_rmanager().to_nice_string(m_sig[0]) << " val:" - << ctx.get_rmanager().to_nice_string(m_sig[0], m_fact[0]); + << ctx.get_rel_context().get_rmanager().to_nice_string(m_sig[0]) << " val:" + << ctx.get_rel_context().get_rmanager().to_nice_string(m_sig[0], m_fact[0]); } virtual void make_annotations(execution_context & ctx) { std::string s; @@ -1035,9 +1049,9 @@ namespace datalog { ctx.set_reg(m_tgt, ctx.get_rel_context().get_rmanager().mk_full_relation(m_sig, m_pred)); return true; } - virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { + virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { out << "mk_total into " << m_tgt << " sort:" - << ctx.get_rmanager().to_nice_string(m_sig); + << ctx.get_rel_context().get_rmanager().to_nice_string(m_sig); } virtual void make_annotations(execution_context & ctx) { std::string s; @@ -1061,7 +1075,7 @@ namespace datalog { ctx.get_rel_context().get_rmanager().mark_saturated(m_pred); return true; } - virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { + virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { out << "mark_saturated " << m_pred->get_name().bare_str(); } virtual void make_annotations(execution_context & ctx) { @@ -1085,7 +1099,7 @@ namespace datalog { } return true; } - virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { + virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { out << "instr_assert_signature of " << m_tgt << " signature:"; print_container(m_sig, out); } @@ -1166,14 +1180,14 @@ namespace datalog { } } - void instruction_block::display_indented(rel_context_base const& _ctx, std::ostream & out, std::string indentation) const { - rel_context const& ctx = dynamic_cast(_ctx); + void instruction_block::display_indented(execution_context const& _ctx, std::ostream & out, std::string indentation) const { + rel_context const& ctx = _ctx.get_rel_context(); instr_seq_type::const_iterator it = m_data.begin(); instr_seq_type::const_iterator end = m_data.end(); for(; it!=end; ++it) { instruction * i = (*it); if (i->passes_output_thresholds(ctx.get_context()) || i->being_recorded()) { - i->display_indented(ctx, out, indentation); + i->display_indented(_ctx, out, indentation); } } } diff --git a/src/muz/rel/dl_instruction.h b/src/muz/rel/dl_instruction.h index 331b153e8..3910f6d0b 100644 --- a/src/muz/rel/dl_instruction.h +++ b/src/muz/rel/dl_instruction.h @@ -73,6 +73,7 @@ namespace datalog { void reset(); rel_context & get_rel_context(); + rel_context const & get_rel_context() const; void set_timelimit(unsigned time_in_ms); void reset_timelimit(); @@ -224,7 +225,7 @@ namespace datalog { The newline character at the end should not be printed. */ - virtual void display_head_impl(rel_context const & ctx, std::ostream & out) const { + virtual void display_head_impl(execution_context const & ctx, std::ostream & out) const { out << ""; } /** @@ -232,7 +233,7 @@ namespace datalog { Each line must be prepended by \c indentation and ended by a newline character. */ - virtual void display_body_impl(rel_context_base const & ctx, std::ostream & out, std::string indentation) const {} + virtual void display_body_impl(execution_context const & ctx, std::ostream & out, std::string indentation) const {} void log_verbose(execution_context& ctx); public: @@ -245,10 +246,10 @@ namespace datalog { virtual void make_annotations(execution_context & ctx) = 0; - void display(rel_context_base const& ctx, std::ostream & out) const { + void display(execution_context const& ctx, std::ostream & out) const { display_indented(ctx, out, ""); } - void display_indented(rel_context_base const & ctx, std::ostream & out, std::string indentation) const; + void display_indented(execution_context const & ctx, std::ostream & out, std::string indentation) const; static instruction * mk_load(ast_manager & m, func_decl * pred, reg_idx tgt); /** @@ -353,10 +354,10 @@ namespace datalog { void make_annotations(execution_context & ctx); - void display(rel_context_base const & ctx, std::ostream & out) const { + void display(execution_context const & ctx, std::ostream & out) const { display_indented(ctx, out, ""); } - void display_indented(rel_context_base const & ctx, std::ostream & out, std::string indentation) const; + void display_indented(execution_context const & ctx, std::ostream & out, std::string indentation) const; unsigned num_instructions() const { return m_data.size(); } }; diff --git a/src/muz/rel/rel_context.cpp b/src/muz/rel/rel_context.cpp index 5054bc192..37d5a22f3 100644 --- a/src/muz/rel/rel_context.cpp +++ b/src/muz/rel/rel_context.cpp @@ -630,7 +630,7 @@ namespace datalog { out << "\n--------------\n"; out << "Instructions\n"; - m_code.display(*this, out); + m_code.display(m_ectx, out); out << "\n--------------\n"; out << "Big relations\n"; diff --git a/src/opt/inc_sat_solver.cpp b/src/opt/inc_sat_solver.cpp index 6dd562f82..65264e0d9 100644 --- a/src/opt/inc_sat_solver.cpp +++ b/src/opt/inc_sat_solver.cpp @@ -56,6 +56,7 @@ class inc_sat_solver : public solver { expr_dependency_ref m_dep_core; expr_ref_vector m_soft; vector m_weights; + bool m_soft_assumptions; typedef obj_map dep2asm_t; @@ -69,7 +70,8 @@ public: m_map(m), m_num_scopes(0), m_dep_core(m), - m_soft(m) { + m_soft(m), + m_soft_assumptions(false) { m_params.set_bool("elim_vars", false); m_solver.updt_params(m_params); params_ref simp2_p = p; @@ -177,6 +179,7 @@ public: m_params = p; m_params.set_bool("elim_vars", false); m_solver.updt_params(m_params); + m_soft_assumptions = m_params.get_bool("soft_assumptions", false); m_optimize_model = m_params.get_bool("optimize_model", false); } virtual void collect_statistics(statistics & st) const { @@ -355,7 +358,7 @@ private: dep2asm_t::iterator it = dep2asm.begin(), end = dep2asm.end(); for (; it != end; ++it) { sat::literal lit = it->m_value; - if (sat::value_at(lit, ll_m) != l_true) { + if (!m_soft_assumptions && sat::value_at(lit, ll_m) != l_true) { IF_VERBOSE(0, verbose_stream() << mk_pp(it->m_key, m) << " does not evaluate to true\n"; verbose_stream() << m_asms << "\n"; m_solver.display_assignment(verbose_stream()); diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 6bc0cfa9b..c9b52f370 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -11,7 +11,6 @@ Abstract: - mus: max-sat algorithm by Nina and Bacchus, AAAI 2014. - mus-mss: based on dual refinement of bounds. - - mss: based on maximal satisfying sets (only). MaxRes is a core-guided approach to maxsat. MusMssMaxRes extends the core-guided approach by @@ -71,11 +70,19 @@ using namespace opt; class maxres : public maxsmt_solver_base { public: enum strategy_t { - s_mus, - s_mus_mss, - s_mss + s_primal, + s_primal_dual }; private: + struct stats { + unsigned m_num_cores; + unsigned m_num_cs; + stats() { reset(); } + void reset() { + memset(this, 0, sizeof(*this)); + } + }; + stats m_stats; expr_ref_vector m_B; expr_ref_vector m_asms; expr_ref_vector m_defs; @@ -167,7 +174,7 @@ public: trace_bounds("maxres"); while (m_lower < m_upper) { TRACE("opt", - display_vec(tout, m_asms.size(), m_asms.c_ptr()); + display_vec(tout, m_asms); s().display(tout); tout << "\n"; display(tout); @@ -194,159 +201,51 @@ public: return l_true; } - - lbool mss_solver() { + lbool primal_dual_solver() { init(); init_local(); - sls(); - set_mus(false); - exprs mcs; + set_soft_assumptions(); lbool is_sat = l_true; - while (m_lower < m_upper && is_sat == l_true) { - trace_bounds("maxres"); - if (m_cancel) { - return l_undef; - } - vector cores; - exprs mss; - model_ref mdl; - expr_ref tmp(m); - mcs.reset(); - s().get_model(mdl); - update_assignment(mdl.get()); - - exprs cs; - get_current_correction_set(mdl.get(), cs); - process_sat(cs); - + trace_bounds("max_res"); + exprs cs; + while (m_lower < m_upper) { #if 0 - is_sat = get_mss(mdl.get(), cores, mss, mcs); - - switch (is_sat) { - case l_undef: - return l_undef; - case l_false: - m_lower = m_upper; - return l_true; - case l_true: - process_sat(mcs); - get_mss_model(); - break; - } + expr_ref_vector asms(m_asms); + sort_assumptions(asms); + is_sat = s().check_sat(asms.size(), asms.c_ptr()); +#else + is_sat = check_sat_hill_climb(m_asms); #endif - if (m_lower < m_upper) { - is_sat = s().check_sat(0, 0); - } - } - m_lower = m_upper; - return l_true; - } - - /** - Plan: - - Get maximal set of disjoint cores. - - Update the lower bound using the cores. - - As a side-effect find a satisfying assignment that has maximal weight. - (during core minimization several queries are bound to be SAT, - those can be used to boot-strap the MCS search). - - Use the best satisfying assignment from the MUS search to find an MCS of least weight. - - Update the upper bound using the MCS. - - Update the soft constraints using first the cores. - - Then update the resulting soft constraints using the evaluation of the MCS/MSS - - Add a cardinality constraint to force new satisfying assignments to improve - the new upper bound. - - In every iteration, the lower bound is improved using the cores. - - In every iteration, the upper bound is improved using the MCS. - - Optionally: add a cardinality constraint to prune the upper bound. - - What are the corner cases: - - suppose that cost of cores adds up to current upper bound. - -> it means that each core is a unit (?) - - TBD: - - Block upper bound using wmax or pb constraint, or in case of - unweighted constraints using incremental tricks. - - Throttle when correction set gets added based on its size. - Suppose correction set is huge. Do we really need it? - - */ - lbool mus_mss_solver() { - init(); - init_local(); - sls(); - vector cores; - m_mus.set_soft(m_soft.size(), m_soft.c_ptr(), m_weights.c_ptr()); - lbool is_sat = l_true; - while (m_lower < m_upper && is_sat == l_true) { - TRACE("opt", - display_vec(tout, m_asms.size(), m_asms.c_ptr()); - s().display(tout); - tout << "\n"; - display(tout); - ); - lbool is_sat = check_sat_hill_climb(m_asms); if (m_cancel) { return l_undef; } switch (is_sat) { case l_true: - found_optimum(); - return l_true; - case l_false: - is_sat = get_cores(cores); + get_current_correction_set(cs); + IF_VERBOSE(2, display_vec(verbose_stream() << "correction set: ", cs);); + if (cs.empty()) { + m_found_feasible_optimum = m_model.get() != 0; + m_lower = m_upper; + } + else { + process_sat(cs); + } break; + case l_false: + is_sat = process_unsat(); + if (is_sat != l_true) return is_sat; + break; + case l_undef: + return l_undef; default: break; } - if (is_sat == l_undef) { - return l_undef; - } - SASSERT((is_sat == l_false) == cores.empty()); - SASSERT((is_sat == l_true) == !cores.empty()); - if (cores.empty()) { - break; - } - - // - // There is a best model, retrieve - // it from the previous core calls. - // - model_ref mdl; - get_mus_model(mdl); - - // - // Extend the current model to a (maximal) - // assignment extracting the ss and cs. - // ss - satisfying subset - // cs - correction set (complement of ss). - // - if (m_maximize_assignment && mdl.get()) { - exprs ss, cs; - is_sat = get_mss(mdl.get(), cores, ss, cs); - if (is_sat != l_true) return is_sat; - get_mss_model(); - } - // - // block the hard constraints corresponding to the cores. - // block the soft constraints corresponding to the cs - // obtained from the current best model. - // - - exprs cs; - get_current_correction_set(mdl.get(), cs); - unsigned max_core = max_core_size(cores); - if (!cs.empty() && cs.size() < max_core) { - process_sat(cs); - } - else { - process_unsat(cores); - } } - - m_lower = m_upper; + trace_bounds("maxres"); return l_true; } + lbool check_sat_hill_climb(expr_ref_vector& asms1) { expr_ref_vector asms(asms1); lbool is_sat = l_true; @@ -399,16 +298,19 @@ public: virtual lbool operator()() { m_defs.reset(); switch(m_st) { - case s_mus: + case s_primal: return mus_solver(); - case s_mus_mss: - return mus_mss_solver(); - case s_mss: - return mss_solver(); + case s_primal_dual: + return primal_dual_solver(); } return l_undef; } + virtual void collect_statistics(statistics& st) const { + st.update("maxres-cores", m_stats.m_num_cores); + st.update("maxres-correction-sets", m_stats.m_num_cs); + } + lbool get_cores(vector& cores) { // assume m_s is unsat. lbool is_sat = l_false; @@ -422,12 +324,14 @@ public: model_ref mdl; get_mus_model(mdl); is_sat = minimize_core(core); + ++m_stats.m_num_cores; if (is_sat != l_true) { break; } if (core.empty()) { cores.reset(); - return l_false; + m_lower = m_upper; + return l_true; } cores.push_back(core); if (core.size() >= m_max_core_size) { @@ -442,22 +346,30 @@ public: TRACE("opt", tout << "num cores: " << cores.size() << "\n"; for (unsigned i = 0; i < cores.size(); ++i) { - display_vec(tout, cores[i].size(), cores[i].c_ptr()); + display_vec(tout, cores[i]); } tout << "num satisfying: " << asms.size() << "\n";); return is_sat; } + void get_current_correction_set(exprs& cs) { + model_ref mdl; + s().get_model(mdl); + update_assignment(mdl.get()); + get_current_correction_set(mdl.get(), cs); + } + void get_current_correction_set(model* mdl, exprs& cs) { + ++m_stats.m_num_cs; cs.reset(); if (!mdl) return; for (unsigned i = 0; i < m_asms.size(); ++i) { - if (!is_true(mdl, m_asms[i].get())) { + if (is_false(mdl, m_asms[i].get())) { cs.push_back(m_asms[i].get()); } } - TRACE("opt", display_vec(tout << "new correction set: ", cs.size(), cs.c_ptr());); + TRACE("opt", display_vec(tout << "new correction set: ", cs);); } struct compare_asm { @@ -492,7 +404,7 @@ public: void process_sat(exprs const& corr_set) { expr_ref fml(m), tmp(m); - TRACE("opt", display_vec(tout << "corr_set: ", corr_set.size(), corr_set.c_ptr());); + TRACE("opt", display_vec(tout << "corr_set: ", corr_set);); remove_core(corr_set); rational w = split_core(corr_set); cs_max_resolve(corr_set, w); @@ -533,7 +445,7 @@ public: remove_core(core); SASSERT(!core.empty()); rational w = split_core(core); - TRACE("opt", display_vec(tout << "minimized core: ", core.size(), core.c_ptr());); + TRACE("opt", display_vec(tout << "minimized core: ", core);); max_resolve(core, w); fml = mk_not(m, mk_and(m, m_B.size(), m_B.c_ptr())); s().assert_expr(fml); @@ -558,22 +470,6 @@ public: return 0 != mdl.get(); } - void get_mss_model() { - model_ref mdl; - m_mss.get_model(mdl); // last model is best way to reduce search space. - update_assignment(mdl.get()); - } - - lbool get_mss(model* mdl, vector const& cores, exprs& literals, exprs& mcs) { - literals.reset(); - mcs.reset(); - literals.append(m_asms.size(), m_asms.c_ptr()); - set_mus(false); - lbool is_sat = m_mss(mdl, cores, literals, mcs); - set_mus(true); - return is_sat; - } - lbool minimize_core(exprs& core) { if (m_c.sat_enabled() || core.empty()) { return l_true; @@ -622,12 +518,19 @@ public: rational w3 = w2 - w; new_assumption(core[i], w3); } - } - + } return w; } - void display_vec(std::ostream& out, unsigned sz, expr* const* args) { + void display_vec(std::ostream& out, exprs const& exprs) { + display_vec(out, exprs.size(), exprs.c_ptr()); + } + + void display_vec(std::ostream& out, expr_ref_vector const& exprs) { + display_vec(out, exprs.size(), exprs.c_ptr()); + } + + void display_vec(std::ostream& out, unsigned sz, expr* const* args) const { for (unsigned i = 0; i < sz; ++i) { out << mk_pp(args[i], m) << " : " << get_weight(args[i]) << " "; } @@ -691,7 +594,7 @@ public: // cs is a correction set (a complement of a (maximal) satisfying assignment). void cs_max_resolve(exprs const& cs, rational const& w) { if (cs.empty()) return; - TRACE("opt", display_vec(tout << "correction set: ", cs.size(), cs.c_ptr());); + TRACE("opt", display_vec(tout << "correction set: ", cs);); expr_ref fml(m), asum(m); app_ref cls(m), d(m), dd(m); m_B.reset(); @@ -733,74 +636,6 @@ public: s().assert_expr(fml); } - lbool try_improve_bound(vector& cores, exprs& mcs) { - cores.reset(); - mcs.reset(); - exprs core; - expr_ref_vector asms(m_asms); - while (true) { - rational upper = m_max_upper; - unsigned sz = 0; - for (unsigned i = 0; m_upper <= rational(2)*upper && i < asms.size(); ++i, ++sz) { - upper -= get_weight(asms[i].get()); - } - lbool is_sat = s().check_sat(sz, asms.c_ptr()); - switch (is_sat) { - case l_true: { - model_ref mdl; - s().get_model(mdl); // last model is best way to reduce search space. - update_assignment(mdl.get()); - exprs mss; - mss.append(asms.size(), asms.c_ptr()); - set_mus(false); - is_sat = m_mss(m_model.get(), cores, mss, mcs); - set_mus(true); - if (is_sat != l_true) { - return is_sat; - } - get_mss_model(); - if (!cores.empty() && mcs.size() > cores.back().size()) { - mcs.reset(); - } - else { - cores.reset(); - } - return l_true; - } - case l_undef: - return l_undef; - case l_false: - core.reset(); - s().get_unsat_core(core); - DEBUG_CODE(verify_core(core);); - is_sat = minimize_core(core); - if (is_sat != l_true) { - break; - } - if (core.empty()) { - cores.reset(); - mcs.reset(); - return l_false; - } - cores.push_back(core); - if (core.size() >= 3) { - return l_true; - } - // - // check arithmetic: cannot improve upper bound - // - if (m_upper <= upper) { - return l_true; - } - - remove_soft(core, asms); - break; - } - } - - return l_undef; - } - void update_assignment(model* mdl) { rational upper(0); expr_ref tmp(m); @@ -842,6 +677,12 @@ public: return m.is_true(tmp); } + bool is_false(model* mdl, expr* e) { + expr_ref tmp(m); + VERIFY(mdl->eval(e, tmp)); + return m.is_false(tmp); + } + bool is_true(expr* e) { return is_true(m_model.get(), e); } @@ -948,16 +789,11 @@ public: opt::maxsmt_solver_base* opt::mk_maxres( context& c, weights_t& ws, expr_ref_vector const& soft) { - return alloc(maxres, c, ws, soft, maxres::s_mus); + return alloc(maxres, c, ws, soft, maxres::s_primal); } -opt::maxsmt_solver_base* opt::mk_mus_mss_maxres( +opt::maxsmt_solver_base* opt::mk_primal_dual_maxres( context& c, weights_t& ws, expr_ref_vector const& soft) { - return alloc(maxres, c, ws, soft, maxres::s_mus_mss); -} - -opt::maxsmt_solver_base* opt::mk_mss_maxres( - context& c, weights_t& ws, expr_ref_vector const& soft) { - return alloc(maxres, c, ws, soft, maxres::s_mss); + return alloc(maxres, c, ws, soft, maxres::s_primal_dual); } diff --git a/src/opt/maxres.h b/src/opt/maxres.h index efe21c214..c942b655e 100644 --- a/src/opt/maxres.h +++ b/src/opt/maxres.h @@ -24,9 +24,7 @@ namespace opt { maxsmt_solver_base* mk_maxres(context& c, weights_t & ws, expr_ref_vector const& soft); - maxsmt_solver_base* mk_mus_mss_maxres(context& c, weights_t & ws, expr_ref_vector const& soft); - - maxsmt_solver_base* mk_mss_maxres(context& c, weights_t & ws, expr_ref_vector const& soft); + maxsmt_solver_base* mk_primal_dual_maxres(context& c, weights_t & ws, expr_ref_vector const& soft); }; diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 48d7e48bd..710f10d48 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -106,7 +106,7 @@ namespace opt { } void maxsmt_solver_base::set_soft_assumptions() { - m_c.set_soft_assumptions() + m_c.set_soft_assumptions(); } app* maxsmt_solver_base::mk_fresh_bool(char const* name) { @@ -174,11 +174,8 @@ namespace opt { else if (maxsat_engine == symbol("maxres")) { m_msolver = mk_maxres(m_c, m_weights, m_soft_constraints); } - else if (maxsat_engine == symbol("mus-mss-maxres")) { - m_msolver = mk_mus_mss_maxres(m_c, m_weights, m_soft_constraints); - } - else if (maxsat_engine == symbol("mss-maxres")) { - m_msolver = mk_mss_maxres(m_c, m_weights, m_soft_constraints); + else if (maxsat_engine == symbol("pd-maxres")) { + m_msolver = mk_primal_dual_maxres(m_c, m_weights, m_soft_constraints); } else if (maxsat_engine == symbol("bcd2")) { m_msolver = mk_bcd2(m_c, m_weights, m_soft_constraints); diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 028cb4414..5971cceb7 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -474,8 +474,7 @@ namespace opt { return; } if (m_maxsat_engine != symbol("maxres") && - m_maxsat_engine != symbol("mus-mss-maxres") && - m_maxsat_engine != symbol("mss-maxres") && + m_maxsat_engine != symbol("pd-maxres") && m_maxsat_engine != symbol("bcd2") && m_maxsat_engine != symbol("sls")) { return; diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index f84c6eebf..059ac0bd2 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -3,7 +3,7 @@ def_module_params('opt', export=True, params=(('timeout', UINT, UINT_MAX, 'set timeout'), ('optsmt_engine', SYMBOL, 'basic', "select optimization engine: 'basic', 'farkas', 'symba'"), - ('maxsat_engine', SYMBOL, 'wmax', "select engine for maxsat: 'fu_malik', 'core_maxsat', 'wmax', 'pbmax', 'maxres', 'bcd2', 'wpm2', 'sls', 'maxhs'"), + ('maxsat_engine', SYMBOL, 'wmax', "select engine for maxsat: 'fu_malik', 'core_maxsat', 'wmax', 'pbmax', 'maxres', 'pd-maxres', 'bcd2', 'wpm2', 'sls', 'maxhs'"), ('priority', SYMBOL, 'lex', "select how to priortize objectives: 'lex' (lexicographic), 'pareto', or 'box'"), ('dump_benchmarks', BOOL, False, 'dump benchmarks for profiling'), ('print_model', BOOL, False, 'display model for satisfiable constraints'), diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 1915f363f..6a5148192 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -922,7 +922,7 @@ namespace sat { SASSERT(is_external((lit).var())); m_assumption_set.insert(lit); - if (m_config.soft_assumptions) { + if (m_config.m_soft_assumptions) { if (value(lit) == l_undef) { m_assumptions.push_back(lit); assign(lit, justification()); diff --git a/src/shell/datalog_frontend.cpp b/src/shell/datalog_frontend.cpp index a487a99b4..affe299d8 100644 --- a/src/shell/datalog_frontend.cpp +++ b/src/shell/datalog_frontend.cpp @@ -77,7 +77,7 @@ static void display_statistics( out << "--------------\n"; out << "instructions \n"; - code.display(*ctx.get_rel_context(), out); + code.display(ex_ctx, out); out << "--------------\n"; out << "big relations \n"; From 37fca65517b2ad621bab8c0e85596ba0bb5cb2ba Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 25 Jan 2015 04:37:42 -0800 Subject: [PATCH 696/925] fuse join with projection avoiding double insert (but at cost of double projection) Signed-off-by: Nikolaj Bjorner --- src/muz/rel/udoc_relation.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index c527a9dba..369b4ab68 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -1001,7 +1001,6 @@ namespace datalog { relation_signature prod_signature; prod_signature.append(t1.get_signature()); prod_signature.append(t2.get_signature()); - udoc prod; udoc const& d1 = t1.get_udoc(); udoc const& d2 = t2.get_udoc(); doc_manager& dm1 = t1.get_dm(); @@ -1011,13 +1010,22 @@ namespace datalog { udoc_relation* result = get(p.mk_empty(get_result_signature())); udoc& res = result->get_udoc(); doc_manager& dm_res = result->get_dm(); - prod.join(d1, d2, dm_prod, dm1, m_cols1, m_cols2); - TRACE("doc", prod.display(dm_prod, tout) << "\n";); - for (unsigned i = 0; i < prod.size(); ++i) { - res.insert(dm_res, dm_prod.project(dm_res, m_to_delete, prod[i])); + + for (unsigned i = 0; i < d1.size(); ++i) { + for (unsigned j = 0; j < d2.size(); ++j) { + doc_ref d(dm_prod, dm_prod.join(d1[i], d2[j], dm1, m_cols1, m_cols2)); + if (d) { + res.insert(dm_res, dm_prod.project(dm_res, m_to_delete, *d)); + IF_VERBOSE(2, + if (res.size() > 0 && 0 == res.size() % 10000) { + verbose_stream() << "result size: " << res.size() + << " i:" << i << " j:" << j << " " + << 100*i/d1.size() << "% complete\n"; + }); + } + } } TRACE("doc", result->display(tout);); - prod.reset(dm_prod); return result; } }; From 6ab167f0c78e2e953340cb41b70dffd4980db98f Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Sun, 25 Jan 2015 18:31:04 +0000 Subject: [PATCH 697/925] fix debug build Signed-off-by: Nuno Lopes --- src/muz/rel/dl_compiler.cpp | 2 +- src/muz/rel/dl_instruction.cpp | 2 +- src/muz/rel/rel_context.cpp | 2 +- src/shell/datalog_frontend.cpp | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/muz/rel/dl_compiler.cpp b/src/muz/rel/dl_compiler.cpp index 648c91e4a..d3d0501e7 100644 --- a/src/muz/rel/dl_compiler.cpp +++ b/src/muz/rel/dl_compiler.cpp @@ -1355,7 +1355,7 @@ namespace datalog { acc.set_observer(0); - TRACE("dl", execution_code.display(*m_context.get_rel_context(), tout);); + TRACE("dl", execution_code.display(execution_context(m_context), tout);); } diff --git a/src/muz/rel/dl_instruction.cpp b/src/muz/rel/dl_instruction.cpp index ea25dfc59..7eb8d4375 100644 --- a/src/muz/rel/dl_instruction.cpp +++ b/src/muz/rel/dl_instruction.cpp @@ -1148,7 +1148,7 @@ namespace datalog { TRACE("dl", tout <<"% "; - instr->display_head_impl(ctx.get_rel_context(), tout); + instr->display_head_impl(ctx, tout); tout <<"\n";); success = !ctx.should_terminate() && instr->perform(ctx); } diff --git a/src/muz/rel/rel_context.cpp b/src/muz/rel/rel_context.cpp index 37d5a22f3..4fd9a8fe9 100644 --- a/src/muz/rel/rel_context.cpp +++ b/src/muz/rel/rel_context.cpp @@ -172,7 +172,7 @@ namespace datalog { compiler::compile(m_context, m_context.get_rules(), m_code, termination_code); - TRACE("dl", m_code.display(*this, tout); ); + TRACE("dl", m_code.display(m_ectx, tout); ); bool timeout_after_this_round = time_limit && (restart_time==0 || remaining_time_limit<=restart_time); diff --git a/src/shell/datalog_frontend.cpp b/src/shell/datalog_frontend.cpp index affe299d8..e802112b2 100644 --- a/src/shell/datalog_frontend.cpp +++ b/src/shell/datalog_frontend.cpp @@ -190,7 +190,7 @@ unsigned read_datalog(char const * file) { datalog::compiler::compile(ctx, ctx.get_rules(), rules_code, termination_code); - TRACE("dl_compiler", rules_code.display(*ctx.get_rel_context(), tout);); + TRACE("dl_compiler", rules_code.display(ex_ctx, tout);); rules_code.make_annotations(ex_ctx); @@ -230,7 +230,7 @@ unsigned read_datalog(char const * file) { TRACE("dl_compiler", ctx.display(tout); - rules_code.display(*ctx.get_rel_context(), tout);); + rules_code.display(ex_ctx, tout);); if (ctx.output_tuples()) { ctx.get_rel_context()->display_output_facts(ctx.get_rules(), std::cout); From 83bae6c8aa4379762b1712fc72f60f57b4c2c7c0 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 27 Jan 2015 13:42:14 +0000 Subject: [PATCH 698/925] DoC: fix bug filter_by_negation when negation table has 0 columns Signed-off-by: Nuno Lopes --- src/muz/rel/udoc_relation.cpp | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 369b4ab68..640c82f8a 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -1090,7 +1090,7 @@ namespace datalog { mk_remove_cols m_mk_remove_cols; join_project_fn m_join_project; bool m_is_subtract; - bool m_is_aliased; + //bool m_is_aliased; public: negation_filter_fn(const udoc_relation & t, const udoc_relation & neg, unsigned joined_col_cnt, const unsigned *t_cols, const unsigned *neg_cols) @@ -1099,9 +1099,9 @@ namespace datalog { m_mk_remove_cols(t, neg, m_remove_cols), m_join_project(t, neg, joined_col_cnt, t_cols, neg_cols, m_remove_cols.size(), m_remove_cols.c_ptr()), - m_is_subtract(false), - m_is_aliased(true) { - SASSERT(joined_col_cnt > 0); + m_is_subtract(false)//, + /*m_is_aliased(true) */{ + SASSERT(joined_col_cnt > 0 || neg.get_signature().size() == 0); m_is_subtract = (joined_col_cnt == t.get_signature().size()); m_is_subtract &= (joined_col_cnt == neg.get_signature().size()); svector found(joined_col_cnt, false); @@ -1119,20 +1119,24 @@ namespace datalog { udoc_plugin& p = t.get_plugin(); IF_VERBOSE(3, t.display(verbose_stream() << "dst:");); IF_VERBOSE(3, n.display(verbose_stream() << "neg:");); - if (!m_is_aliased && !t.fast_empty() && !n.fast_empty() && !p.m_disable_fast_pass) { + if (t.fast_empty() || n.fast_empty()) + return; + + /* TODO: double check + if (!m_is_aliased && !p.m_disable_fast_pass) { // fast_pass(t, n); } - if (m_is_subtract && !t.fast_empty() && !n.fast_empty()) { + */ + if (n.get_signature().size() == 0) + t.get_udoc().reset(t.get_dm()); + else if (m_is_subtract) t.get_udoc().subtract(t.get_dm(), n.get_udoc()); - return; - } - if (!t.fast_empty() && !n.fast_empty()) { + else slow_pass(t, n); - } } private: - + /* void fast_pass(udoc_relation& t, const udoc_relation& n) { SASSERT(!m_is_aliased); udoc & dst = t.get_udoc(); @@ -1154,6 +1158,7 @@ namespace datalog { } std::swap(dst, result); } + */ void slow_pass(udoc_relation& t, udoc_relation const& n) { doc_manager& dmt = t.get_dm(); From 9e447281ed6b3eefe3e6a03f961222d274742243 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 27 Jan 2015 14:21:34 +0000 Subject: [PATCH 699/925] Datalog: fix bug in compilation of negated queries that referenced vars not in the head. We will now first add unbounded columns for negation and for filtering do filter_negation, and finally filter_interpret(_project) --- src/muz/rel/dl_compiler.cpp | 95 +++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 46 deletions(-) diff --git a/src/muz/rel/dl_compiler.cpp b/src/muz/rel/dl_compiler.cpp index d3d0501e7..d73f8c4ad 100644 --- a/src/muz/rel/dl_compiler.cpp +++ b/src/muz/rel/dl_compiler.cpp @@ -609,7 +609,8 @@ namespace datalog { dealloc = true; } - // enforce interpreted tail predicates + + // add unbounded columns for interpreted filter unsigned ut_len = r->get_uninterpreted_tail_size(); unsigned ft_len = r->get_tail_size(); // full tail ptr_vector tail; @@ -617,15 +618,12 @@ namespace datalog { tail.push_back(r->get_tail(tail_index)); } + expr_ref_vector binding(m); if (!tail.empty()) { app_ref filter_cond(tail.size() == 1 ? to_app(tail.back()) : m.mk_and(tail.size(), tail.c_ptr()), m); - ptr_vector filter_vars; m_free_vars(filter_cond); - // create binding - expr_ref_vector binding(m); binding.resize(m_free_vars.size()+1); - for (unsigned v = 0; v < m_free_vars.size(); ++v) { if (!m_free_vars[v]) continue; @@ -655,6 +653,52 @@ namespace datalog { relation_sort var_sort = m_reg_signatures[filtered_res][src_col]; binding[m_free_vars.size()-v] = m.mk_var(src_col, var_sort); } + } + + //enforce negative predicates + for (unsigned i = pt_len; iget_tail(i); + func_decl * neg_pred = neg_tail->get_decl(); + variable_intersection neg_intersection(m_context.get_manager()); + neg_intersection.populate(single_res_expr, neg_tail); + unsigned_vector t_cols(neg_intersection.size(), neg_intersection.get_cols1()); + unsigned_vector neg_cols(neg_intersection.size(), neg_intersection.get_cols2()); + + unsigned neg_len = neg_tail->get_num_args(); + for (unsigned i = 0; iget_arg(i); + if (is_var(e)) { + continue; + } + SASSERT(is_app(e)); + relation_sort arg_sort; + m_context.get_rel_context()->get_rmanager().from_predicate(neg_pred, i, arg_sort); + reg_idx new_reg; + bool new_dealloc; + make_add_constant_column(head_pred, filtered_res, arg_sort, to_app(e), new_reg, new_dealloc, acc); + + if (dealloc) + make_dealloc_non_void(filtered_res, acc); + dealloc = new_dealloc; + filtered_res = new_reg; + + t_cols.push_back(single_res_expr.size()); + neg_cols.push_back(i); + single_res_expr.push_back(e); + } + SASSERT(t_cols.size() == neg_cols.size()); + + reg_idx neg_reg = m_pred_regs.find(neg_pred); + if (!dealloc) + make_clone(filtered_res, filtered_res, acc); + acc.push_back(instruction::mk_filter_by_negation(filtered_res, neg_reg, t_cols.size(), + t_cols.c_ptr(), neg_cols.c_ptr())); + dealloc = true; + } + + // enforce interpreted tail predicates + if (!tail.empty()) { + app_ref filter_cond(tail.size() == 1 ? to_app(tail.back()) : m.mk_and(tail.size(), tail.c_ptr()), m); // check if there are any columns to remove unsigned_vector remove_columns; @@ -716,47 +760,6 @@ namespace datalog { dealloc = true; } - //enforce negative predicates - for (unsigned i = pt_len; iget_tail(i); - func_decl * neg_pred = neg_tail->get_decl(); - variable_intersection neg_intersection(m_context.get_manager()); - neg_intersection.populate(single_res_expr, neg_tail); - unsigned_vector t_cols(neg_intersection.size(), neg_intersection.get_cols1()); - unsigned_vector neg_cols(neg_intersection.size(), neg_intersection.get_cols2()); - - unsigned neg_len = neg_tail->get_num_args(); - for (unsigned i = 0; iget_arg(i); - if (is_var(e)) { - continue; - } - SASSERT(is_app(e)); - relation_sort arg_sort; - m_context.get_rel_context()->get_rmanager().from_predicate(neg_pred, i, arg_sort); - reg_idx new_reg; - bool new_dealloc; - make_add_constant_column(head_pred, filtered_res, arg_sort, to_app(e), new_reg, new_dealloc, acc); - - if (dealloc) - make_dealloc_non_void(filtered_res, acc); - dealloc = new_dealloc; - filtered_res = new_reg; // here filtered_res value gets changed !! - - t_cols.push_back(single_res_expr.size()); - neg_cols.push_back(i); - single_res_expr.push_back(e); - } - SASSERT(t_cols.size() == neg_cols.size()); - - reg_idx neg_reg = m_pred_regs.find(neg_pred); - if (!dealloc) - make_clone(filtered_res, filtered_res, acc); - acc.push_back(instruction::mk_filter_by_negation(filtered_res, neg_reg, t_cols.size(), - t_cols.c_ptr(), neg_cols.c_ptr())); - dealloc = true; - } - #if 0 // this version is potentially better for non-symbolic tables, // since it constraints each unbound column at a time (reducing the From 1701af9dc97bf9bd29875ef2087c5cb85b097ad8 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 28 Jan 2015 11:38:26 +0000 Subject: [PATCH 700/925] DoC: fix fast_empty() for tables without columns Signed-off-by: Nuno Lopes --- src/muz/rel/udoc_relation.cpp | 2 +- src/muz/rel/udoc_relation.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 640c82f8a..90c3ec7c0 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -1127,7 +1127,7 @@ namespace datalog { // fast_pass(t, n); } */ - if (n.get_signature().size() == 0) + if (n.get_signature().empty()) t.get_udoc().reset(t.get_dm()); else if (m_is_subtract) t.get_udoc().subtract(t.get_dm(), n.get_udoc()); diff --git a/src/muz/rel/udoc_relation.h b/src/muz/rel/udoc_relation.h index 7cad3b348..a9d31e7d3 100644 --- a/src/muz/rel/udoc_relation.h +++ b/src/muz/rel/udoc_relation.h @@ -48,7 +48,7 @@ namespace datalog { virtual udoc_relation * complement(func_decl*) const; virtual void to_formula(expr_ref& fml) const; udoc_plugin& get_plugin() const; - virtual bool fast_empty() const { return !get_signature().empty() && m_elems.is_empty(); } + virtual bool fast_empty() const { return m_elems.is_empty(); } virtual bool empty() const; virtual void display(std::ostream& out) const; virtual bool is_precise() const { return true; } From 2e083ab9c22efa75b31efe259fd74ac565bc65f5 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 29 Jan 2015 08:50:12 +0000 Subject: [PATCH 701/925] DoC: specialize union for the case dst=empty and/or delta=empty this avoids O(n^2) insert and becomes O(n) Signed-off-by: Nuno Lopes --- src/muz/rel/udoc_relation.cpp | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 90c3ec7c0..ffb4b6e22 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -509,13 +509,27 @@ namespace datalog { } }; void udoc_plugin::mk_union(doc_manager& dm, udoc& dst, udoc const& src, udoc* delta) { - for (unsigned i = 0; i < src.size(); ++i) { - doc* d = dm.allocate(src[i]); - if (dst.insert(dm, d)) { + bool deltaempty = delta ? delta->is_empty() : false; + + if (dst.is_empty()) { + for (unsigned i = 0; i < src.size(); ++i) { + dst.push_back(dm.allocate(src[i])); if (delta) { - delta->insert(dm, dm.allocate(src[i])); + if (deltaempty) + delta->push_back(dm.allocate(src[i])); + else + delta->insert(dm, dm.allocate(src[i])); } - } + } + } else { + for (unsigned i = 0; i < src.size(); ++i) { + if (dst.insert(dm, dm.allocate(src[i])) && delta) { + if (deltaempty) + delta->push_back(dm.allocate(src[i])); + else + delta->insert(dm, dm.allocate(src[i])); + } + } } } relation_union_fn * udoc_plugin::mk_union_fn( From 4be2f608f1f7adb442e5e17883af013bfc1ca1e6 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 29 Jan 2015 13:00:44 +0000 Subject: [PATCH 702/925] Datalog: make the compiler reuse registers in simple cases. this also allows some code simplification dl_compiler.cpp | 133 +++++++++++++++++++------------------------------------- dl_compiler.h | 16 +++--- 2 files changed, 54 insertions(+), 95 deletions(-) Signed-off-by: Nuno Lopes --- src/muz/rel/dl_compiler.cpp | 133 +++++++++++++----------------------- src/muz/rel/dl_compiler.h | 16 ++--- 2 files changed, 54 insertions(+), 95 deletions(-) diff --git a/src/muz/rel/dl_compiler.cpp b/src/muz/rel/dl_compiler.cpp index d73f8c4ad..fa88a3316 100644 --- a/src/muz/rel/dl_compiler.cpp +++ b/src/muz/rel/dl_compiler.cpp @@ -33,7 +33,6 @@ namespace datalog { void compiler::reset() { m_pred_regs.reset(); - m_new_reg = 0; } void compiler::ensure_predicate_loaded(func_decl * pred, instruction_block & acc) { @@ -51,16 +50,16 @@ namespace datalog { } void compiler::make_join(reg_idx t1, reg_idx t2, const variable_intersection & vars, reg_idx & result, - instruction_block & acc) { + bool reuse_t1, instruction_block & acc) { relation_signature res_sig; relation_signature::from_join(m_reg_signatures[t1], m_reg_signatures[t2], vars.size(), vars.get_cols1(), vars.get_cols2(), res_sig); - result = get_fresh_register(res_sig); + result = get_register(res_sig, reuse_t1, t1); acc.push_back(instruction::mk_join(t1, t2, vars.size(), vars.get_cols1(), vars.get_cols2(), result)); } void compiler::make_join_project(reg_idx t1, reg_idx t2, const variable_intersection & vars, - const unsigned_vector & removed_cols, reg_idx & result, instruction_block & acc) { + const unsigned_vector & removed_cols, reg_idx & result, bool reuse_t1, instruction_block & acc) { relation_signature aux_sig; relation_signature sig1 = m_reg_signatures[t1]; relation_signature sig2 = m_reg_signatures[t2]; @@ -68,29 +67,29 @@ namespace datalog { relation_signature res_sig; relation_signature::from_project(aux_sig, removed_cols.size(), removed_cols.c_ptr(), res_sig); - result = get_fresh_register(res_sig); + result = get_register(res_sig, reuse_t1, t1); acc.push_back(instruction::mk_join_project(t1, t2, vars.size(), vars.get_cols1(), vars.get_cols2(), removed_cols.size(), removed_cols.c_ptr(), result)); } void compiler::make_filter_interpreted_and_project(reg_idx src, app_ref & cond, - const unsigned_vector & removed_cols, reg_idx & result, instruction_block & acc) { + const unsigned_vector & removed_cols, reg_idx & result, bool reuse, instruction_block & acc) { SASSERT(!removed_cols.empty()); relation_signature res_sig; relation_signature::from_project(m_reg_signatures[src], removed_cols.size(), removed_cols.c_ptr(), res_sig); - result = get_fresh_register(res_sig); + result = get_register(res_sig, reuse, src); acc.push_back(instruction::mk_filter_interpreted_and_project(src, cond, removed_cols.size(), removed_cols.c_ptr(), result)); } void compiler::make_select_equal_and_project(reg_idx src, const relation_element & val, unsigned col, - reg_idx & result, instruction_block & acc) { + reg_idx & result, bool reuse, instruction_block & acc) { relation_signature res_sig; relation_signature::from_project(m_reg_signatures[src], 1, &col, res_sig); - result = get_fresh_register(res_sig); + result = get_register(res_sig, reuse, src); acc.push_back(instruction::mk_select_equal_and_project(m_context.get_manager(), src, val, col, result)); } @@ -115,12 +114,12 @@ namespace datalog { } void compiler::make_projection(reg_idx src, unsigned col_cnt, const unsigned * removed_cols, - reg_idx & result, instruction_block & acc) { + reg_idx & result, bool reuse, instruction_block & acc) { SASSERT(col_cnt>0); relation_signature res_sig; relation_signature::from_project(m_reg_signatures[src], col_cnt, removed_cols, res_sig); - result = get_fresh_register(res_sig); + result = get_register(res_sig, reuse, src); acc.push_back(instruction::mk_projection(src, col_cnt, removed_cols, result)); } @@ -132,6 +131,14 @@ namespace datalog { return result; } + compiler::reg_idx compiler::get_register(const relation_signature & sig, bool reuse, compiler::reg_idx r) { + if (!reuse) + return get_fresh_register(sig); + SASSERT(r != execution_context::void_register); + m_reg_signatures[r] = sig; + return r; + } + compiler::reg_idx compiler::get_single_column_register(const relation_sort & s) { relation_signature singl_sig; singl_sig.push_back(s); @@ -169,11 +176,11 @@ namespace datalog { } if(src==execution_context::void_register) { result = singleton_table; - dealloc = false; + SASSERT(dealloc == false); } else { variable_intersection empty_vars(m_context.get_manager()); - make_join(src, singleton_table, empty_vars, result, acc); + make_join(src, singleton_table, empty_vars, result, dealloc, acc); dealloc = true; } } @@ -198,11 +205,11 @@ namespace datalog { } if(src == execution_context::void_register) { result = total_table; - dealloc = false; + SASSERT(dealloc == false); } else { variable_intersection empty_vars(m_context.get_manager()); - make_join(src, total_table, empty_vars, result, acc); + make_join(src, total_table, empty_vars, result, dealloc, acc); dealloc = true; } } @@ -221,7 +228,7 @@ namespace datalog { void compiler::make_duplicate_column(reg_idx src, unsigned col, reg_idx & result, - instruction_block & acc) { + bool reuse, instruction_block & acc) { relation_signature & src_sig = m_reg_signatures[src]; reg_idx single_col_reg; @@ -236,19 +243,20 @@ namespace datalog { removed_cols.push_back(i); } } - make_projection(src, removed_cols.size(), removed_cols.c_ptr(), single_col_reg, acc); + make_projection(src, removed_cols.size(), removed_cols.c_ptr(), single_col_reg, false, acc); } variable_intersection vi(m_context.get_manager()); vi.add_pair(col, 0); - make_join(src, single_col_reg, vi, result, acc); - make_dealloc_non_void(single_col_reg, acc); + make_join(src, single_col_reg, vi, result, reuse, acc); + if (src_col_cnt != 1) + make_dealloc_non_void(single_col_reg, acc); } void compiler::make_rename(reg_idx src, unsigned cycle_len, const unsigned * permutation_cycle, - reg_idx & result, instruction_block & acc) { + reg_idx & result, bool reuse, instruction_block & acc) { relation_signature res_sig; relation_signature::from_rename(m_reg_signatures[src], cycle_len, permutation_cycle, res_sig); - result = get_fresh_register(res_sig); + result = get_register(res_sig, reuse, src); acc.push_back(instruction::mk_rename(src, cycle_len, permutation_cycle, result)); } @@ -301,12 +309,8 @@ namespace datalog { new_src_col_offset.push_back(src_cols_to_remove.size()); } if(!src_cols_to_remove.empty()) { - reg_idx new_curr; - make_projection(curr, src_cols_to_remove.size(), src_cols_to_remove.c_ptr(), new_curr, acc); - if (dealloc) - make_dealloc_non_void(curr, acc); + make_projection(curr, src_cols_to_remove.size(), src_cols_to_remove.c_ptr(), curr, dealloc, acc); dealloc = true; - curr=new_curr; curr_sig = & m_reg_signatures[curr]; //update ACK_BOUND_VAR references @@ -325,21 +329,15 @@ namespace datalog { } unsigned bound_column_index; if(acis[i].kind!=ACK_UNBOUND_VAR || !handled_unbound.find(acis[i].var_index,bound_column_index)) { - reg_idx new_curr; - bool new_dealloc; bound_column_index=curr_sig->size(); if(acis[i].kind==ACK_CONSTANT) { - make_add_constant_column(head_pred, curr, acis[i].domain, acis[i].constant, new_curr, new_dealloc, acc); + make_add_constant_column(head_pred, curr, acis[i].domain, acis[i].constant, curr, dealloc, acc); } else { SASSERT(acis[i].kind==ACK_UNBOUND_VAR); - make_add_unbound_column(compiled_rule, i, head_pred, curr, acis[i].domain, new_curr, new_dealloc, acc); + make_add_unbound_column(compiled_rule, i, head_pred, curr, acis[i].domain, curr, dealloc, acc); handled_unbound.insert(acis[i].var_index,bound_column_index); } - if (dealloc) - make_dealloc_non_void(curr, acc); - dealloc = new_dealloc; - curr=new_curr; curr_sig = & m_reg_signatures[curr]; SASSERT(bound_column_index==curr_sig->size()-1); } @@ -357,12 +355,8 @@ namespace datalog { used_cols.insert(col); continue; } - reg_idx new_curr; - make_duplicate_column(curr, col, new_curr, acc); - if (dealloc) - make_dealloc_non_void(curr, acc); + make_duplicate_column(curr, col, curr, dealloc, acc); dealloc = true; - curr=new_curr; curr_sig = & m_reg_signatures[curr]; unsigned bound_column_index=curr_sig->size()-1; SASSERT((*curr_sig)[bound_column_index]==acis[i].domain); @@ -387,12 +381,8 @@ namespace datalog { SASSERT(permutation.size()<=col_cnt); //this should not be an infinite loop } while(next!=i); - reg_idx new_curr; - make_rename(curr, permutation.size(), permutation.c_ptr(), new_curr, acc); - if (dealloc) - make_dealloc_non_void(curr, acc); + make_rename(curr, permutation.size(), permutation.c_ptr(), curr, dealloc, acc); dealloc = true; - curr=new_curr; curr_sig = & m_reg_signatures[curr]; } @@ -491,10 +481,10 @@ namespace datalog { get_local_indexes_for_projection(r, removed_cols); if(removed_cols.empty()) { - make_join(t1_reg, t2_reg, a1a2, single_res, acc); + make_join(t1_reg, t2_reg, a1a2, single_res, false, acc); } else { - make_join_project(t1_reg, t2_reg, a1a2, removed_cols, single_res, acc); + make_join_project(t1_reg, t2_reg, a1a2, removed_cols, single_res, false, acc); } unsigned rem_index = 0; @@ -521,11 +511,11 @@ namespace datalog { SASSERT(rem_index==rem_sz); } else if(pt_len==1) { - reg_idx t_reg=tail_regs[0]; app * a = r->get_tail(0); - SASSERT(m_reg_signatures[t_reg].size()==a->get_num_args()); + single_res = tail_regs[0]; + dealloc = false; - single_res = t_reg; + SASSERT(m_reg_signatures[single_res].size() == a->get_num_args()); unsigned n=a->get_num_args(); for(unsigned i=0; iget_rmanager().from_predicate(neg_pred, i, arg_sort); - reg_idx new_reg; - bool new_dealloc; - make_add_constant_column(head_pred, filtered_res, arg_sort, to_app(e), new_reg, new_dealloc, acc); - - if (dealloc) - make_dealloc_non_void(filtered_res, acc); - dealloc = new_dealloc; - filtered_res = new_reg; + make_add_constant_column(head_pred, filtered_res, arg_sort, to_app(e), filtered_res, dealloc, acc); t_cols.push_back(single_res_expr.size()); neg_cols.push_back(i); @@ -750,12 +719,8 @@ namespace datalog { make_clone(filtered_res, filtered_res, acc); acc.push_back(instruction::mk_filter_interpreted(filtered_res, app_renamed)); } else { - reg_idx new_reg; std::sort(remove_columns.begin(), remove_columns.end()); - make_filter_interpreted_and_project(filtered_res, app_renamed, remove_columns, new_reg, acc); - if (dealloc) - make_dealloc_non_void(filtered_res, acc); - filtered_res = new_reg; + make_filter_interpreted_and_project(filtered_res, app_renamed, remove_columns, filtered_res, dealloc, acc); } dealloc = true; } @@ -921,13 +886,7 @@ namespace datalog { expr* e = it->m_value; if (!pos_vars.contains(v)) { single_res_expr.push_back(e); - reg_idx new_single_res; - bool new_dealloc; - make_add_unbound_column(r, v, pred, single_res, m.get_sort(e), new_single_res, new_dealloc, acc); - if (dealloc) - make_dealloc_non_void(single_res, acc); - dealloc = new_dealloc; - single_res = new_single_res; + make_add_unbound_column(r, v, pred, single_res, m.get_sort(e), single_res, dealloc, acc); TRACE("dl", tout << "Adding unbound column: " << mk_pp(e, m) << "\n";); } } diff --git a/src/muz/rel/dl_compiler.h b/src/muz/rel/dl_compiler.h index 92f50eb02..b498d7e61 100644 --- a/src/muz/rel/dl_compiler.h +++ b/src/muz/rel/dl_compiler.h @@ -111,7 +111,6 @@ namespace datalog { */ instruction_block & m_top_level_code; pred2idx m_pred_regs; - reg_idx m_new_reg; vector m_reg_signatures; obj_pair_map m_constant_registers; obj_pair_map m_total_registers; @@ -133,6 +132,7 @@ namespace datalog { bool compile_with_widening() const { return m_context.compile_with_widening(); } reg_idx get_fresh_register(const relation_signature & sig); + reg_idx get_register(const relation_signature & sig, bool reuse, reg_idx r); reg_idx get_single_column_register(const relation_sort & s); /** @@ -143,21 +143,21 @@ namespace datalog { void get_fresh_registers(const func_decl_set & preds, pred2idx & regs); void make_join(reg_idx t1, reg_idx t2, const variable_intersection & vars, reg_idx & result, - instruction_block & acc); + bool reuse_t1, instruction_block & acc); void make_join_project(reg_idx t1, reg_idx t2, const variable_intersection & vars, - const unsigned_vector & removed_cols, reg_idx & result, instruction_block & acc); + const unsigned_vector & removed_cols, reg_idx & result, bool reuse_t1, instruction_block & acc); void make_filter_interpreted_and_project(reg_idx src, app_ref & cond, - const unsigned_vector & removed_cols, reg_idx & result, instruction_block & acc); + const unsigned_vector & removed_cols, reg_idx & result, bool reuse, instruction_block & acc); void make_select_equal_and_project(reg_idx src, const relation_element & val, unsigned col, - reg_idx & result, instruction_block & acc); + reg_idx & result, bool reuse, instruction_block & acc); /** \brief Create add an union or widen operation and put it into \c acc. */ void make_union(reg_idx src, reg_idx tgt, reg_idx delta, bool widening, instruction_block & acc); void make_projection(reg_idx src, unsigned col_cnt, const unsigned * removed_cols, - reg_idx & result, instruction_block & acc); + reg_idx & result, bool reuse, instruction_block & acc); void make_rename(reg_idx src, unsigned cycle_len, const unsigned * permutation_cycle, - reg_idx & result, instruction_block & acc); + reg_idx & result, bool reuse, instruction_block & acc); void make_clone(reg_idx src, reg_idx & result, instruction_block & acc); /** @@ -183,7 +183,7 @@ namespace datalog { void add_unbound_columns_for_negation(rule* compiled_rule, func_decl* pred, reg_idx& single_res, expr_ref_vector& single_res_expr, bool & dealloc, instruction_block& acc); - void make_duplicate_column(reg_idx src, unsigned col, reg_idx & result, instruction_block & acc); + void make_duplicate_column(reg_idx src, unsigned col, reg_idx & result, bool reuse, instruction_block & acc); void ensure_predicate_loaded(func_decl * pred, instruction_block & acc); From 6017dcace39749888644862c9f7fccd2e8e0279e Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 29 Jan 2015 20:41:22 +0000 Subject: [PATCH 703/925] datalog: fix compilation for rules like a(X) :- not b(X). Signed-off-by: Nuno Lopes --- src/muz/rel/dl_compiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/rel/dl_compiler.cpp b/src/muz/rel/dl_compiler.cpp index fa88a3316..42805d1a4 100644 --- a/src/muz/rel/dl_compiler.cpp +++ b/src/muz/rel/dl_compiler.cpp @@ -857,7 +857,7 @@ namespace datalog { ast_manager& m = m_context.get_manager(); unsigned pt_len = r->get_positive_tail_size(); unsigned ut_len = r->get_uninterpreted_tail_size(); - if (pt_len == ut_len || pt_len == 0) { + if (pt_len == ut_len) { return; } // populate negative variables: From c0e0b39a1d872c86ea34af439446d92a380aed96 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 2 Feb 2015 10:34:19 +0000 Subject: [PATCH 704/925] Datalog: save memory in the compiler by using a union Signed-off-by: Nuno Lopes --- src/muz/rel/dl_compiler.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/muz/rel/dl_compiler.h b/src/muz/rel/dl_compiler.h index b498d7e61..8c33f987c 100644 --- a/src/muz/rel/dl_compiler.h +++ b/src/muz/rel/dl_compiler.h @@ -82,9 +82,11 @@ namespace datalog { relation_sort domain; // domain of the column assembling_column_kind kind; // "instruction" tag - unsigned source_column; // for ACK_BOUND_VAR - unsigned var_index; // for ACK_UNBOUND_VAR - relation_element constant; // for ACK_CONSTANT + union { + unsigned source_column; // for ACK_BOUND_VAR + unsigned var_index; // for ACK_UNBOUND_VAR + relation_element constant; // for ACK_CONSTANT + }; }; class instruction_observer : public instruction_block::instruction_observer { From 2444440edcd66edabd4c019f0522d4cd8bcade16 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 2 Feb 2015 11:28:57 +0000 Subject: [PATCH 705/925] DoC: implement get_size_estimate_bytes() Signed-off-by: Nuno Lopes --- src/muz/rel/doc.cpp | 7 +++++++ src/muz/rel/doc.h | 8 ++++++++ src/muz/rel/rel_context.cpp | 7 ------- src/muz/rel/tbv.h | 2 ++ src/muz/rel/udoc_relation.cpp | 4 ++++ src/muz/rel/udoc_relation.h | 1 + 6 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/muz/rel/doc.cpp b/src/muz/rel/doc.cpp index 67e2f1e2b..a27d20c56 100644 --- a/src/muz/rel/doc.cpp +++ b/src/muz/rel/doc.cpp @@ -107,6 +107,13 @@ doc& doc_manager::fillX(doc& src) { m.fillX(src.pos()); return src; } + +unsigned doc_manager::get_size_estimate_bytes(const doc& d) const { + return m.get_size_estimate_bytes(d.pos()) + + d.neg().get_size_estimate_bytes(m) + + sizeof(doc); +} + bool doc_manager::set_and(doc& dst, doc const& src) { // (A \ B) & (C \ D) = (A & C) \ (B u D) if (!m.set_and(dst.pos(), src.pos())) return false; diff --git a/src/muz/rel/doc.h b/src/muz/rel/doc.h index fcb134d9e..ca5af005b 100644 --- a/src/muz/rel/doc.h +++ b/src/muz/rel/doc.h @@ -87,6 +87,7 @@ public: std::ostream& display(std::ostream& out, doc const& b) const; std::ostream& display(std::ostream& out, doc const& b, unsigned hi, unsigned lo) const; unsigned num_tbits() const { return m.num_tbits(); } + unsigned get_size_estimate_bytes(const doc& d) const; doc* project(doc_manager& dstm, bit_vector const& to_delete, doc const& src); bool well_formed(doc const& d) const; bool merge(doc& d, unsigned lo, unsigned length, subset_ints const& equalities, bit_vector const& discard_cols); @@ -326,6 +327,13 @@ public: } } + unsigned get_size_estimate_bytes(const M& m) const { + unsigned sz = sizeof(T*) * size(); + for (unsigned i = 0; i < size(); ++i) { + sz += m.get_size_estimate_bytes(*m_elems[i]); + } + return sz; + } }; diff --git a/src/muz/rel/rel_context.cpp b/src/muz/rel/rel_context.cpp index 4fd9a8fe9..9fa7eadd0 100644 --- a/src/muz/rel/rel_context.cpp +++ b/src/muz/rel/rel_context.cpp @@ -172,8 +172,6 @@ namespace datalog { compiler::compile(m_context, m_context.get_rules(), m_code, termination_code); - TRACE("dl", m_code.display(m_ectx, tout); ); - bool timeout_after_this_round = time_limit && (restart_time==0 || remaining_time_limit<=restart_time); if (time_limit || restart_time!=0) { @@ -628,11 +626,6 @@ namespace datalog { m_code.make_annotations(m_ectx); m_code.process_all_costs(); - out << "\n--------------\n"; - out << "Instructions\n"; - m_code.display(m_ectx, out); - - out << "\n--------------\n"; out << "Big relations\n"; m_ectx.report_big_relations(1000, out); diff --git a/src/muz/rel/tbv.h b/src/muz/rel/tbv.h index d667ccaa2..ad98b8095 100644 --- a/src/muz/rel/tbv.h +++ b/src/muz/rel/tbv.h @@ -57,6 +57,8 @@ public: tbv* allocate(tbv const& bv, unsigned const* permutation); void deallocate(tbv* bv); + + unsigned get_size_estimate_bytes(const tbv&) const { return m.num_bytes(); } void copy(tbv& dst, tbv const& src) const; unsigned num_tbits() const { return m.num_bits()/2; } diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index ffb4b6e22..8e971ac1e 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -181,6 +181,10 @@ namespace datalog { m_elems.display(dm, out); out << "\n"; } + unsigned udoc_relation::get_size_estimate_bytes() const { + return sizeof(*this) + m_elems.get_size_estimate_bytes(dm); + } + // ------------- udoc_plugin::udoc_plugin(relation_manager& rm): diff --git a/src/muz/rel/udoc_relation.h b/src/muz/rel/udoc_relation.h index a9d31e7d3..40f2222fc 100644 --- a/src/muz/rel/udoc_relation.h +++ b/src/muz/rel/udoc_relation.h @@ -53,6 +53,7 @@ namespace datalog { virtual void display(std::ostream& out) const; virtual bool is_precise() const { return true; } virtual unsigned get_size_estimate_rows() const { return m_elems.size(); } + virtual unsigned get_size_estimate_bytes() const; doc_manager& get_dm() const { return dm; } udoc const& get_udoc() const { return m_elems; } From 5548ecc853eaf1b1ea6a09e6bea10f47500d08da Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 2 Feb 2015 11:29:49 +0000 Subject: [PATCH 706/925] Datalog: fix bug with the following 2 scenarios: A(#x00) :- not B(). A() :- not B(). The first case can be further optimized, but committing this for correctness Signed-off-by: Nuno Lopes --- src/muz/rel/dl_compiler.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/muz/rel/dl_compiler.cpp b/src/muz/rel/dl_compiler.cpp index 42805d1a4..860add434 100644 --- a/src/muz/rel/dl_compiler.cpp +++ b/src/muz/rel/dl_compiler.cpp @@ -631,6 +631,16 @@ namespace datalog { } } + // add at least one column for the negative filter + if (pt_len != ut_len && filtered_res == execution_context::void_register) { + relation_signature & head_sig = m_reg_signatures[head_reg]; + if (head_sig.empty()) { + make_full_relation(head_pred, m_reg_signatures[head_reg], filtered_res, acc); + } else { + make_add_unbound_column(r, 0, head_pred, filtered_res, head_sig[0], filtered_res, dealloc, acc); + } + } + //enforce negative predicates for (unsigned i = pt_len; iget_tail(i); From 0c4d82de58ec40c5c09143f79ea1a4f364938a18 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 2 Feb 2015 11:49:58 +0000 Subject: [PATCH 707/925] datalog: optimize previous commit Signed-off-by: Nuno Lopes --- src/muz/rel/dl_compiler.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/muz/rel/dl_compiler.cpp b/src/muz/rel/dl_compiler.cpp index 860add434..204a8f316 100644 --- a/src/muz/rel/dl_compiler.cpp +++ b/src/muz/rel/dl_compiler.cpp @@ -633,12 +633,8 @@ namespace datalog { // add at least one column for the negative filter if (pt_len != ut_len && filtered_res == execution_context::void_register) { - relation_signature & head_sig = m_reg_signatures[head_reg]; - if (head_sig.empty()) { - make_full_relation(head_pred, m_reg_signatures[head_reg], filtered_res, acc); - } else { - make_add_unbound_column(r, 0, head_pred, filtered_res, head_sig[0], filtered_res, dealloc, acc); - } + relation_signature empty_signature; + make_full_relation(head_pred, empty_signature, filtered_res, acc); } //enforce negative predicates From bbefc54bf5c122a9f1dfd72588150994bf964fff Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 5 Feb 2015 09:51:05 +0000 Subject: [PATCH 708/925] add implementation of UNREACHABLE for MSVC in release mode. This reduces code size of Z3 by 0.1% \o/ Signed-off-by: Nuno Lopes --- src/util/debug.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/util/debug.h b/src/util/debug.h index a36743f73..f7383511b 100644 --- a/src/util/debug.h +++ b/src/util/debug.h @@ -58,12 +58,18 @@ bool is_debug_enabled(const char * tag); #define CASSERT(TAG, COND) DEBUG_CODE(if (assertions_enabled() && is_debug_enabled(TAG) && !(COND)) { notify_assertion_violation(__FILE__, __LINE__, #COND); INVOKE_DEBUGGER(); }) #define XASSERT(COND, EXTRA_CODE) DEBUG_CODE(if (assertions_enabled() && !(COND)) { notify_assertion_violation(__FILE__, __LINE__, #COND); { EXTRA_CODE } INVOKE_DEBUGGER(); }) +#ifdef Z3DEBUG +# define UNREACHABLE() DEBUG_CODE(notify_assertion_violation(__FILE__, __LINE__, "UNREACHABLE CODE WAS REACHED."); INVOKE_DEBUGGER();) +#else #if (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 405)) || __has_builtin(__builtin_unreachable) // only available in gcc >= 4.5 and in newer versions of clang # define UNREACHABLE() __builtin_unreachable() +#elif defined(_MSC_VER) +# define UNREACHABLE() __assume(0) #else #define UNREACHABLE() DEBUG_CODE(notify_assertion_violation(__FILE__, __LINE__, "UNREACHABLE CODE WAS REACHED."); INVOKE_DEBUGGER();) #endif +#endif #define NOT_IMPLEMENTED_YET() { std::cerr << "NOT IMPLEMENTED YET!\n"; UNREACHABLE(); exit(ERR_NOT_IMPLEMENTED_YET); } ((void) 0) From 8141dadc89d08c1a710b67fbc89d8437cdddca67 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Feb 2015 10:22:06 +0100 Subject: [PATCH 709/925] break on small cores Signed-off-by: Nikolaj Bjorner --- src/api/api_interp.cpp | 6 +++--- src/math/simplex/simplex.h | 2 +- src/math/simplex/sparse_matrix.h | 4 ++-- src/opt/inc_sat_solver.cpp | 12 ++++++------ src/opt/mus.cpp | 23 ++++++++++++++++++++++- src/opt/opt_context.h | 8 ++++---- src/opt/opt_solver.h | 2 +- src/sat/sat_solver.cpp | 21 ++++++++++++++++++++- src/smt/smt_conflict_resolution.cpp | 17 +++++++++++++---- src/smt/smt_context_pp.cpp | 4 ++-- src/tactic/horn_subsume_model_converter.h | 2 +- src/tactic/replace_proof_converter.h | 4 ++-- src/util/dependency.h | 4 ++-- src/util/mpf.h | 2 +- 14 files changed, 80 insertions(+), 31 deletions(-) diff --git a/src/api/api_interp.cpp b/src/api/api_interp.cpp index dd689dcb0..123d84ee5 100644 --- a/src/api/api_interp.cpp +++ b/src/api/api_interp.cpp @@ -291,10 +291,10 @@ extern "C" { } } else { - model_ref _m; - m_solver.get()->get_model(_m); + model_ref mr; + m_solver.get()->get_model(mr); Z3_model_ref *crap = alloc(Z3_model_ref); - crap->m_model = _m.get(); + crap->m_model = mr.get(); mk_c(c)->save_object(crap); *model = of_model(crap); } diff --git a/src/math/simplex/simplex.h b/src/math/simplex/simplex.h index 9685af589..d1d6320fc 100644 --- a/src/math/simplex/simplex.h +++ b/src/math/simplex/simplex.h @@ -141,7 +141,7 @@ namespace simplex { void unset_upper(var_t var); void set_value(var_t var, eps_numeral const& b); void set_cancel(bool f) { m_cancel = f; } - void set_max_iterations(unsigned m) { m_max_iterations = m; } + void set_max_iterations(unsigned n) { m_max_iterations = n; } void reset(); lbool make_feasible(); lbool minimize(var_t var); diff --git a/src/math/simplex/sparse_matrix.h b/src/math/simplex/sparse_matrix.h index 80454a52c..ee28e1475 100644 --- a/src/math/simplex/sparse_matrix.h +++ b/src/math/simplex/sparse_matrix.h @@ -100,7 +100,7 @@ namespace simplex { _row_entry & add_row_entry(unsigned & pos_idx); void del_row_entry(unsigned idx); void compress(manager& m, vector & cols); - void compress_if_needed(manager& m, vector & cols); + void compress_if_needed(manager& _m, vector & cols); void save_var_pos(svector & result_map, unsigned_vector& idxs) const; //bool is_coeff_of(var_t v, numeral const & expected) const; int get_idx_of(var_t v) const; @@ -143,7 +143,7 @@ namespace simplex { public: - sparse_matrix(manager& m): m(m) {} + sparse_matrix(manager& _m): m(_m) {} ~sparse_matrix(); void reset(); diff --git a/src/opt/inc_sat_solver.cpp b/src/opt/inc_sat_solver.cpp index 65264e0d9..0dfb0aa5e 100644 --- a/src/opt/inc_sat_solver.cpp +++ b/src/opt/inc_sat_solver.cpp @@ -190,11 +190,11 @@ public: r.reset(); r.append(m_core.size(), m_core.c_ptr()); } - virtual void get_model(model_ref & m) { + virtual void get_model(model_ref & mdl) { if (!m_model.get()) { extract_model(); } - m = m_model; + mdl = m_model; } virtual proof * get_proof() { UNREACHABLE(); @@ -331,10 +331,10 @@ private: } sat::literal_vector const& core = m_solver.get_core(); TRACE("opt", - dep2asm_t::iterator it = dep2asm.begin(); - dep2asm_t::iterator end = dep2asm.end(); - for (; it != end; ++it) { - tout << mk_pp(it->m_key, m) << " |-> " << sat::literal(it->m_value) << "\n"; + dep2asm_t::iterator it2 = dep2asm.begin(); + dep2asm_t::iterator end2 = dep2asm.end(); + for (; it2 != end2; ++it2) { + tout << mk_pp(it2->m_key, m) << " |-> " << sat::literal(it2->m_value) << "\n"; } tout << "core: "; for (unsigned i = 0; i < core.size(); ++i) { diff --git a/src/opt/mus.cpp b/src/opt/mus.cpp index 0cf9786b2..f9190911a 100644 --- a/src/opt/mus.cpp +++ b/src/opt/mus.cpp @@ -58,7 +58,8 @@ struct mus::imp { unsigned idx = m_cls2expr.size(); m_expr2cls.insert(cls, idx); m_cls2expr.push_back(cls); - TRACE("opt", tout << idx << ": " << mk_pp(cls, m) << "\n";); + TRACE("opt", tout << idx << ": " << mk_pp(cls, m) << "\n"; + display_vec(tout, m_cls2expr);); return idx; } @@ -113,6 +114,11 @@ struct mus::imp { core.push_back(cls_id); } } + TRACE("opt", display_vec(tout << "core exprs:", core_exprs); + display_vec(tout << "core:", core); + display_vec(tout << "mus:", mus); + ); + } break; } @@ -144,6 +150,21 @@ struct mus::imp { out << "\n"; } + void display_vec(std::ostream& out, expr_ref_vector const& v) const { + for (unsigned i = 0; i < v.size(); ++i) { + out << mk_pp(v[i], m) << " "; + } + out << "\n"; + } + + + void display_vec(std::ostream& out, ptr_vector const& v) const { + for (unsigned i = 0; i < v.size(); ++i) { + out << mk_pp(v[i], m) << " "; + } + out << "\n"; + } + void set_soft(unsigned sz, expr* const* soft, rational const* weights) { m_model.reset(); m_weight.reset(); diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index ee4ce467a..2284f427b 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -146,9 +146,9 @@ namespace opt { virtual void cancel() { set_cancel(true); } virtual void set_hard_constraints(ptr_vector & hard); virtual lbool optimize(); - virtual void get_model(model_ref& m); - virtual void set_model(model_ref& m); - virtual void fix_model(model_ref& m); + virtual void get_model(model_ref& _m); + virtual void set_model(model_ref& _m); + virtual void fix_model(model_ref& _m); virtual void collect_statistics(statistics& stats) const; virtual proof* get_proof() { return 0; } virtual void get_labels(svector & r) {} @@ -186,7 +186,7 @@ namespace opt { void set_enable_sls(bool f) { m_enable_sls = f; } void set_soft_assumptions(); symbol const& maxsat_engine() const { return m_maxsat_engine; } - void get_base_model(model_ref& m); + void get_base_model(model_ref& _m); private: diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 986136d7b..f9702705f 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -94,7 +94,7 @@ namespace opt { virtual void pop_core(unsigned n); virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions); virtual void get_unsat_core(ptr_vector & r); - virtual void get_model(model_ref & m); + virtual void get_model(model_ref & _m); virtual proof * get_proof(); virtual std::string reason_unknown() const; virtual void get_labels(svector & r); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 6a5148192..1a089977a 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -923,9 +923,28 @@ namespace sat { m_assumption_set.insert(lit); if (m_config.m_soft_assumptions) { - if (value(lit) == l_undef) { + switch(value(lit)) { + case l_undef: m_assumptions.push_back(lit); assign(lit, justification()); + break; + case l_false: { + set_conflict(lit); + flet _min1(m_config.m_minimize_core, false); + flet _min2(m_config.m_minimize_core_partial, false); + resolve_conflict_for_unsat_core(); + SASSERT(m_core.size() <= m_assumptions.size()); + if (m_core.size() <= 3 || + m_core.size() <= i - m_assumptions.size() + 1) { + return; + } + else { + m_inconsistent = false; + } + break; + } + case l_true: + break; } propagate(false); } diff --git a/src/smt/smt_conflict_resolution.cpp b/src/smt/smt_conflict_resolution.cpp index ec62efa1c..1e5b4b81f 100644 --- a/src/smt/smt_conflict_resolution.cpp +++ b/src/smt/smt_conflict_resolution.cpp @@ -370,7 +370,12 @@ namespace smt { tout << "conflict_lvl: " << m_conflict_lvl << " scope_lvl: " << m_ctx.get_scope_level() << " base_lvl: " << m_ctx.get_base_level() << " search_lvl: " << m_ctx.get_search_level() << "\n"; tout << "js.kind: " << js.get_kind() << "\n"; - m_ctx.display_literal(tout, consequent); tout << "\n";); + tout << "consequent: " << consequent << "\n"; + for (unsigned i = 0; i < m_assigned_literals.size(); ++i) { + tout << m_assigned_literals[i] << " "; + } + tout << "\n"; + ); // m_conflict_lvl can be smaller than m_ctx.get_search_level() when: // there are user level scopes created using the Z3 API, and @@ -1310,8 +1315,11 @@ namespace smt { } void conflict_resolution::process_antecedent_for_unsat_core(literal antecedent) { - TRACE("conflict", tout << "processing antecedent: "; m_ctx.display_literal(tout, antecedent); tout << "\n";); bool_var var = antecedent.var(); + TRACE("conflict", tout << "processing antecedent: "; + m_ctx.display_literal_info(tout << antecedent << " ", antecedent); + tout << (m_ctx.is_marked(var)?"marked":"not marked"); + tout << "\n";); if (!m_ctx.is_marked(var)) { m_ctx.set_mark(var); @@ -1341,13 +1349,14 @@ namespace smt { b_justification js = conflict; literal consequent = false_literal; - if (not_l != null_literal) + if (not_l != null_literal) { consequent = ~not_l; + } int idx = skip_literals_above_conflict_level(); if (not_l != null_literal) - process_antecedent_for_unsat_core(not_l); + process_antecedent_for_unsat_core(consequent); if (m_assigned_literals.empty()) { goto end_unsat_core; diff --git a/src/smt/smt_context_pp.cpp b/src/smt/smt_context_pp.cpp index 305e84518..3dca6a70b 100644 --- a/src/smt/smt_context_pp.cpp +++ b/src/smt/smt_context_pp.cpp @@ -103,9 +103,9 @@ namespace smt { void context::display_literal_info(std::ostream & out, literal l) const { l.display_compact(out, m_bool_var2expr.c_ptr()); if (l.sign()) - out << " (not " << mk_bounded_pp(bool_var2expr(l.var()), m_manager, 10) << ")\n"; + out << " (not " << mk_bounded_pp(bool_var2expr(l.var()), m_manager, 10) << ") "; else - out << " " << mk_bounded_pp(bool_var2expr(l.var()), m_manager, 10) << "\n"; + out << " " << mk_bounded_pp(bool_var2expr(l.var()), m_manager, 10) << " "; out << "relevant: " << is_relevant(bool_var2expr(l.var())) << ", val: " << get_assignment(l) << "\n"; } diff --git a/src/tactic/horn_subsume_model_converter.h b/src/tactic/horn_subsume_model_converter.h index 993f29cc9..8bad28e3d 100644 --- a/src/tactic/horn_subsume_model_converter.h +++ b/src/tactic/horn_subsume_model_converter.h @@ -72,7 +72,7 @@ public: void insert(func_decl* p, expr* body) { m_funcs.push_back(p); m_bodies.push_back(body); } - virtual void operator()(model_ref& m); + virtual void operator()(model_ref& _m); virtual model_converter * translate(ast_translation & translator); diff --git a/src/tactic/replace_proof_converter.h b/src/tactic/replace_proof_converter.h index cb97810f8..7fee27612 100644 --- a/src/tactic/replace_proof_converter.h +++ b/src/tactic/replace_proof_converter.h @@ -30,11 +30,11 @@ class replace_proof_converter : public proof_converter { proof_ref_vector m_proofs; public: - replace_proof_converter(ast_manager& m): m(m), m_proofs(m) {} + replace_proof_converter(ast_manager& _m): m(_m), m_proofs(m) {} virtual ~replace_proof_converter() {} - virtual void operator()(ast_manager & m, unsigned num_source, proof * const * source, proof_ref & result); + virtual void operator()(ast_manager & _m, unsigned num_source, proof * const * source, proof_ref & result); virtual proof_converter * translate(ast_translation & translator); diff --git a/src/util/dependency.h b/src/util/dependency.h index 6ce9b2025..33a0e4d22 100644 --- a/src/util/dependency.h +++ b/src/util/dependency.h @@ -171,7 +171,7 @@ public: m_todo.push_back(d); unsigned qhead = 0; while (qhead < m_todo.size()) { - dependency * d = m_todo[qhead]; + d = m_todo[qhead]; qhead++; if (d->is_leaf()) { if (to_leaf(d)->m_value == v) { @@ -201,7 +201,7 @@ public: m_todo.push_back(d); unsigned qhead = 0; while (qhead < m_todo.size()) { - dependency * d = m_todo[qhead]; + d = m_todo[qhead]; qhead++; if (d->is_leaf()) { vs.push_back(to_leaf(d)->m_value); diff --git a/src/util/mpf.h b/src/util/mpf.h index 83646f9f3..ba4f237bd 100644 --- a/src/util/mpf.h +++ b/src/util/mpf.h @@ -46,7 +46,7 @@ class mpf { mpz significand; mpf_exp_t exponent; mpf & operator=(mpf const & other) { UNREACHABLE(); return *this; } - void set(unsigned ebits, unsigned sbits); + void set(unsigned _ebits, unsigned _sbits); public: mpf(); mpf(unsigned ebits, unsigned sbits); From 911ffc370a0769091548a261f91c5089b2bcd2d4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 16 Feb 2015 09:11:28 +0100 Subject: [PATCH 710/925] separate MaxSMT functionality to enable using this independently (and incrementally) of overall context Signed-off-by: Nikolaj Bjorner --- src/opt/bcd2.cpp | 4 +-- src/opt/bcd2.h | 2 +- src/opt/fu_malik.cpp | 4 +-- src/opt/fu_malik.h | 2 +- src/opt/maxhs.cpp | 4 +-- src/opt/maxhs.h | 2 +- src/opt/maxres.cpp | 6 ++-- src/opt/maxres.h | 4 +-- src/opt/maxsls.cpp | 4 +-- src/opt/maxsls.h | 2 +- src/opt/maxsmt.cpp | 4 +-- src/opt/maxsmt.h | 10 +++--- src/opt/opt_context.h | 56 ++++++++++++++++++++++------- src/opt/wmax.cpp | 4 +-- src/opt/wmax.h | 2 +- src/smt/smt_conflict_resolution.cpp | 2 +- 16 files changed, 72 insertions(+), 40 deletions(-) diff --git a/src/opt/bcd2.cpp b/src/opt/bcd2.cpp index 766e0d84a..e69275b27 100644 --- a/src/opt/bcd2.cpp +++ b/src/opt/bcd2.cpp @@ -99,7 +99,7 @@ namespace opt { } public: - bcd2(context& c, + bcd2(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft): maxsmt_solver_base(c, ws, soft), pb(m), @@ -399,7 +399,7 @@ namespace opt { }; maxsmt_solver_base* mk_bcd2( - context& c, weights_t& ws, expr_ref_vector const& soft) { + maxsat_context& c, weights_t& ws, expr_ref_vector const& soft) { return alloc(bcd2, c, ws, soft); } diff --git a/src/opt/bcd2.h b/src/opt/bcd2.h index 79d528e20..bd9c3d344 100644 --- a/src/opt/bcd2.h +++ b/src/opt/bcd2.h @@ -23,6 +23,6 @@ Notes: #include "maxsmt.h" namespace opt { - maxsmt_solver_base* mk_bcd2(context& c, weights_t& ws, expr_ref_vector const& soft); + maxsmt_solver_base* mk_bcd2(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft); } #endif diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp index 6d2386b96..7a3f685e6 100644 --- a/src/opt/fu_malik.cpp +++ b/src/opt/fu_malik.cpp @@ -50,7 +50,7 @@ namespace opt { model_ref m_model; public: - fu_malik(context& c, weights_t& ws, expr_ref_vector const& soft): + fu_malik(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft): maxsmt_solver_base(c, ws, soft), m_fm(c.fm()), m_aux_soft(soft), @@ -229,7 +229,7 @@ namespace opt { } }; - maxsmt_solver_base* mk_fu_malik(context& c, weights_t & ws, expr_ref_vector const& soft) { + maxsmt_solver_base* mk_fu_malik(maxsat_context& c, weights_t & ws, expr_ref_vector const& soft) { return alloc(fu_malik, c, ws, soft); } diff --git a/src/opt/fu_malik.h b/src/opt/fu_malik.h index 5eea9fc49..7c6369f6a 100644 --- a/src/opt/fu_malik.h +++ b/src/opt/fu_malik.h @@ -29,7 +29,7 @@ Notes: namespace opt { - maxsmt_solver_base* mk_fu_malik(context& c, weights_t & ws, expr_ref_vector const& soft); + maxsmt_solver_base* mk_fu_malik(maxsat_context& c, weights_t & ws, expr_ref_vector const& soft); }; diff --git a/src/opt/maxhs.cpp b/src/opt/maxhs.cpp index 6d4a7b8bf..9ce9844b5 100644 --- a/src/opt/maxhs.cpp +++ b/src/opt/maxhs.cpp @@ -75,7 +75,7 @@ namespace opt { public: - maxhs(context& c, weights_t& ws, expr_ref_vector const& soft): + maxhs(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft): maxsmt_solver_base(c, ws, soft), m_aux(m), m_at_lower_bound(false) { @@ -554,7 +554,7 @@ namespace opt { }; maxsmt_solver_base* mk_maxhs( - context& c, weights_t& ws, expr_ref_vector const& soft) { + maxsat_context& c, weights_t& ws, expr_ref_vector const& soft) { return alloc(maxhs, c, ws, soft); } diff --git a/src/opt/maxhs.h b/src/opt/maxhs.h index f31cbce9f..ed59bf625 100644 --- a/src/opt/maxhs.h +++ b/src/opt/maxhs.h @@ -23,7 +23,7 @@ Notes: #include "maxsmt.h" namespace opt { - maxsmt_solver_base* mk_maxhs(context& c, + maxsmt_solver_base* mk_maxhs(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft); } #endif diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index c9b52f370..ddd238156 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -107,7 +107,7 @@ private: typedef ptr_vector exprs; public: - maxres(context& c, + maxres(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft, strategy_t st): maxsmt_solver_base(c, ws, soft), @@ -788,12 +788,12 @@ public: }; opt::maxsmt_solver_base* opt::mk_maxres( - context& c, weights_t& ws, expr_ref_vector const& soft) { + maxsat_context& c, weights_t& ws, expr_ref_vector const& soft) { return alloc(maxres, c, ws, soft, maxres::s_primal); } opt::maxsmt_solver_base* opt::mk_primal_dual_maxres( - context& c, weights_t& ws, expr_ref_vector const& soft) { + maxsat_context& c, weights_t& ws, expr_ref_vector const& soft) { return alloc(maxres, c, ws, soft, maxres::s_primal_dual); } diff --git a/src/opt/maxres.h b/src/opt/maxres.h index c942b655e..bb280cb29 100644 --- a/src/opt/maxres.h +++ b/src/opt/maxres.h @@ -22,9 +22,9 @@ Notes: namespace opt { - maxsmt_solver_base* mk_maxres(context& c, weights_t & ws, expr_ref_vector const& soft); + maxsmt_solver_base* mk_maxres(maxsat_context& c, weights_t & ws, expr_ref_vector const& soft); - maxsmt_solver_base* mk_primal_dual_maxres(context& c, weights_t & ws, expr_ref_vector const& soft); + maxsmt_solver_base* mk_primal_dual_maxres(maxsat_context& c, weights_t & ws, expr_ref_vector const& soft); }; diff --git a/src/opt/maxsls.cpp b/src/opt/maxsls.cpp index fc9c71607..d5ddb6623 100644 --- a/src/opt/maxsls.cpp +++ b/src/opt/maxsls.cpp @@ -26,7 +26,7 @@ namespace opt { class sls : public maxsmt_solver_base { public: - sls(context& c, weights_t& ws, expr_ref_vector const& soft): + sls(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft): maxsmt_solver_base(c, ws, soft) { } virtual ~sls() {} @@ -54,7 +54,7 @@ namespace opt { }; maxsmt_solver_base* mk_sls( - context& c, weights_t& ws, expr_ref_vector const& soft) { + maxsat_context& c, weights_t& ws, expr_ref_vector const& soft) { return alloc(sls, c, ws, soft); } diff --git a/src/opt/maxsls.h b/src/opt/maxsls.h index c4314171f..f344c1564 100644 --- a/src/opt/maxsls.h +++ b/src/opt/maxsls.h @@ -27,7 +27,7 @@ Notes: namespace opt { - maxsmt_solver_base* mk_sls(context& c, weights_t& ws, expr_ref_vector const& soft); + maxsmt_solver_base* mk_sls(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft); }; diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 710f10d48..92dac9474 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -36,7 +36,7 @@ Notes: namespace opt { maxsmt_solver_base::maxsmt_solver_base( - context& c, vector const& ws, expr_ref_vector const& soft): + maxsat_context& c, vector const& ws, expr_ref_vector const& soft): m(c.get_manager()), m_c(c), m_cancel(false), @@ -156,7 +156,7 @@ namespace opt { - maxsmt::maxsmt(context& c): + maxsmt::maxsmt(maxsat_context& c): m(c.get_manager()), m_c(c), m_cancel(false), m_soft_constraints(m), m_answer(m) {} diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 356a2d50b..a2881ad21 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -33,7 +33,7 @@ namespace opt { typedef vector const weights_t; - class context; + class maxsat_context; class maxsmt_solver { protected: @@ -59,7 +59,7 @@ namespace opt { class maxsmt_solver_base : public maxsmt_solver { protected: ast_manager& m; - context& m_c; + maxsat_context& m_c; volatile bool m_cancel; const expr_ref_vector m_soft; vector m_weights; @@ -71,7 +71,7 @@ namespace opt { params_ref m_params; // config public: - maxsmt_solver_base(context& c, weights_t& ws, expr_ref_vector const& soft); + maxsmt_solver_base(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft); virtual ~maxsmt_solver_base() {} virtual rational get_lower() const { return m_lower; } @@ -114,7 +114,7 @@ namespace opt { class maxsmt { ast_manager& m; - context& m_c; + maxsat_context& m_c; scoped_ptr m_msolver; volatile bool m_cancel; expr_ref_vector m_soft_constraints; @@ -126,7 +126,7 @@ namespace opt { model_ref m_model; params_ref m_params; public: - maxsmt(context& c); + maxsmt(maxsat_context& c); lbool operator()(); void set_cancel(bool f); void updt_params(params_ref& p); diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 2284f427b..3b764aaf5 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -34,8 +34,40 @@ namespace opt { class opt_solver; + /** + \brief base class required by MaxSMT solvers. + By implementing a base class, you can invoke the MaxSMT solvers + independent of the overall optimization infrastructure. + The caller has to supply a solver object that encapsulates + an incremental SAT or SMT solver. The MaxSMT solvers may assume that + the solver object should be in a satisfiable state and contain an initial model. + */ - class context : public opt_wrapper, public pareto_callback { + class maxsat_context { + public: + virtual filter_model_converter& fm() = 0; // converter that removes fresh names introduced by simplification. + virtual bool sat_enabled() const = 0; // is using th SAT solver core enabled? + virtual solver& get_solver() = 0; // retrieve solver object (SAT or SMT solver) + virtual ast_manager& get_manager() = 0; + virtual params_ref& params() = 0; + virtual void enable_sls(expr_ref_vector const& soft, weights_t& weights) = 0; // stochastic local search + virtual void set_enable_sls(bool f) = 0; // overwrite whether SLS is enabled. + virtual void set_soft_assumptions() = 0; // configure SAT solver to skip assumptions assigned by unit-propagation + virtual symbol const& maxsat_engine() const = 0; // retrieve maxsat engine configuration parameter. + virtual void get_base_model(model_ref& _m) = 0; // retrieve model from initial satisfiability call. + virtual smt::context& smt_context() = 0; // access SMT context for SMT based MaxSMT solver (wmax requires SMT core) + }; + + /** + \brief main context object for optimization. + Hard and soft assertions, and objectives are registered with this context. + It handles combinations of objectives. + */ + + class context : + public opt_wrapper, + public pareto_callback, + public maxsat_context { struct free_func_visitor; typedef map map_t; typedef map map_id; @@ -176,17 +208,17 @@ namespace opt { virtual expr_ref mk_ge(unsigned i, model_ref& model); virtual expr_ref mk_le(unsigned i, model_ref& model); - smt::context& smt_context() { return m_opt_solver->get_context(); } - filter_model_converter& fm() { return m_fm; } - bool sat_enabled() const { return 0 != m_sat_solver.get(); } - solver& get_solver(); - ast_manager& get_manager() { return this->m; } - params_ref& params() { return m_params; } - void enable_sls(expr_ref_vector const& soft, weights_t& weights); - void set_enable_sls(bool f) { m_enable_sls = f; } - void set_soft_assumptions(); - symbol const& maxsat_engine() const { return m_maxsat_engine; } - void get_base_model(model_ref& _m); + virtual smt::context& smt_context() { return m_opt_solver->get_context(); } + virtual filter_model_converter& fm() { return m_fm; } + virtual bool sat_enabled() const { return 0 != m_sat_solver.get(); } + virtual solver& get_solver(); + virtual ast_manager& get_manager() { return this->m; } + virtual params_ref& params() { return m_params; } + virtual void enable_sls(expr_ref_vector const& soft, weights_t& weights); + virtual void set_enable_sls(bool f) { m_enable_sls = f; } + virtual void set_soft_assumptions(); + virtual symbol const& maxsat_engine() const { return m_maxsat_engine; } + virtual void get_base_model(model_ref& _m); private: diff --git a/src/opt/wmax.cpp b/src/opt/wmax.cpp index 48d46a6c9..5f7f76f25 100644 --- a/src/opt/wmax.cpp +++ b/src/opt/wmax.cpp @@ -33,7 +33,7 @@ namespace opt { class wmax : public maxsmt_solver_base { public: - wmax(context& c, weights_t& ws, expr_ref_vector const& soft): + wmax(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft): maxsmt_solver_base(c, ws, soft) {} virtual ~wmax() {} @@ -76,7 +76,7 @@ namespace opt { } }; - maxsmt_solver_base* mk_wmax(context& c, weights_t& ws, expr_ref_vector const& soft) { + maxsmt_solver_base* mk_wmax(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft) { return alloc(wmax, c, ws, soft); } diff --git a/src/opt/wmax.h b/src/opt/wmax.h index bb1be1b4e..9d44c88cf 100644 --- a/src/opt/wmax.h +++ b/src/opt/wmax.h @@ -23,7 +23,7 @@ Notes: #include "maxsmt.h" namespace opt { - maxsmt_solver_base* mk_wmax(context& c, weights_t & ws, expr_ref_vector const& soft); + maxsmt_solver_base* mk_wmax(maxsat_context& c, weights_t & ws, expr_ref_vector const& soft); } #endif diff --git a/src/smt/smt_conflict_resolution.cpp b/src/smt/smt_conflict_resolution.cpp index 1e5b4b81f..a68d4d820 100644 --- a/src/smt/smt_conflict_resolution.cpp +++ b/src/smt/smt_conflict_resolution.cpp @@ -372,7 +372,7 @@ namespace smt { tout << "js.kind: " << js.get_kind() << "\n"; tout << "consequent: " << consequent << "\n"; for (unsigned i = 0; i < m_assigned_literals.size(); ++i) { - tout << m_assigned_literals[i] << " "; + tout << m_assigned_literals[i] << " "; } tout << "\n"; ); From 49483fdc28292789c60b267475aae2b0fa40a170 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 21 Feb 2015 02:08:00 -0800 Subject: [PATCH 711/925] take conflicts during restart into account. reported by Arie Gurfinkel Signed-off-by: Nikolaj Bjorner --- .../simplifier/array_simplifier_plugin.cpp | 29 +++++++++++++------ src/smt/arith_eq_adapter.cpp | 3 +- src/smt/smt_context.cpp | 11 +++++-- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/ast/simplifier/array_simplifier_plugin.cpp b/src/ast/simplifier/array_simplifier_plugin.cpp index 065f8bd96..0a8aefa93 100644 --- a/src/ast/simplifier/array_simplifier_plugin.cpp +++ b/src/ast/simplifier/array_simplifier_plugin.cpp @@ -327,16 +327,20 @@ void array_simplifier_plugin::get_stores(expr* n, unsigned& arity, expr*& m, ptr } lbool array_simplifier_plugin::eq_default(expr* def, unsigned arity, unsigned num_st, expr*const* const* st) { + bool all_diseq = m_manager.is_unique_value(def) && num_st > 0; + bool all_eq = true; for (unsigned i = 0; i < num_st; ++i) { - if (st[i][arity] == def) { - continue; - } - if (m_manager.is_unique_value(st[i][arity]) && m_manager.is_unique_value(def)) { - return l_false; - } - return l_undef; + all_eq &= (st[i][arity] == def); + all_diseq &= m_manager.is_unique_value(st[i][arity]) && (st[i][arity] != def); + TRACE("array_simplifier", tout << m_manager.is_unique_value(st[i][arity]) << " " << mk_pp(st[i][arity], m_manager) << "\n";); } - return l_true; + if (all_eq) { + return l_true; + } + if (all_diseq) { + return l_false; + } + return l_undef; } bool array_simplifier_plugin::insert_table(expr* def, unsigned arity, unsigned num_st, expr*const* const* st, arg_table& table) { @@ -346,6 +350,12 @@ bool array_simplifier_plugin::insert_table(expr* def, unsigned arity, unsigned n return false; } } + TRACE("array_simplifier", tout << "inserting: "; + for (unsigned j = 0; j < arity; ++j) { + tout << mk_pp(st[i][j], m_manager) << " "; + } + tout << " |-> " << mk_pp(def, m_manager) << "\n"; + ); args_entry e(arity, st[i]); table.insert_if_not_there(e); } @@ -419,7 +429,8 @@ bool array_simplifier_plugin::reduce_eq(expr * lhs, expr * rhs, expr_ref & resul lbool eq = eq_stores(c1, arity, st1.size(), st1.c_ptr(), st2.size(), st2.c_ptr()); TRACE("array_simplifier", tout << mk_pp(lhs, m_manager) << " = " - << mk_pp(rhs, m_manager) << " := " << eq << "\n";); + << mk_pp(rhs, m_manager) << " := " << eq << "\n"; + tout << "arity: " << arity << "\n";); switch(eq) { case l_false: result = m_manager.mk_false(); diff --git a/src/smt/arith_eq_adapter.cpp b/src/smt/arith_eq_adapter.cpp index 53227d0cc..74e3d573a 100644 --- a/src/smt/arith_eq_adapter.cpp +++ b/src/smt/arith_eq_adapter.cpp @@ -287,12 +287,13 @@ namespace smt { } void arith_eq_adapter::restart_eh() { + context & ctx = get_context(); TRACE("arith_eq_adapter", tout << "restart\n";); svector tmp(m_restart_pairs); svector::iterator it = tmp.begin(); svector::iterator end = tmp.end(); m_restart_pairs.reset(); - for (; it != end; ++it) { + for (; it != end && !ctx.inconsistent(); ++it) { TRACE("arith_eq_adapter", tout << "creating arith_eq_adapter axioms at the base level #" << it->first->get_owner_id() << " #" << it->second->get_owner_id() << "\n";); mk_axioms(it->first, it->second); diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index adb17f6e2..f5d99325b 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3236,10 +3236,17 @@ namespace smt { } ptr_vector::iterator it = m_theory_set.begin(); ptr_vector::iterator end = m_theory_set.end(); - for (; it != end; ++it) + for (; it != end && !inconsistent(); ++it) (*it)->restart_eh(); TRACE("mbqi_bug_detail", tout << "before instantiating quantifiers...\n";); - m_qmanager->restart_eh(); + if (!inconsistent()) { + m_qmanager->restart_eh(); + } + if (inconsistent()) { + VERIFY(!resolve_conflict()); + status = l_false; + break; + } } if (m_fparams.m_simplify_clauses) simplify_clauses(); From c3232693f074af8dc11c0db896cd662a57e87c0f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 22 Feb 2015 09:46:21 -0800 Subject: [PATCH 712/925] use PB solver instead of full arithmetic for bouding Pareto fronts so that difference logic theory isn't broken. Codeplex issue 175 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 92 ++++++++++++++++++----------------------- src/opt/opt_context.h | 2 +- src/opt/opt_pareto.cpp | 2 +- src/opt/opt_solver.cpp | 8 ++++ src/opt/opt_solver.h | 1 + 5 files changed, 51 insertions(+), 54 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 5971cceb7..f22ce479e 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -327,78 +327,66 @@ namespace opt { expr_ref context::mk_le(unsigned i, model_ref& mdl) { objective const& obj = m_objectives[i]; - expr_ref val(m), result(m), term(m); - mk_term_val(mdl, obj, term, val); - switch (obj.m_type) { - case O_MINIMIZE: - result = mk_ge(term, val); - break; - case O_MAXSMT: - result = mk_ge(term, val); - break; - case O_MAXIMIZE: - result = mk_ge(val, term); - break; - } - return result; + return mk_cmp(false, mdl, obj); } expr_ref context::mk_ge(unsigned i, model_ref& mdl) { objective const& obj = m_objectives[i]; - expr_ref val(m), result(m), term(m); - mk_term_val(mdl, obj, term, val); - switch (obj.m_type) { - case O_MINIMIZE: - result = mk_ge(val, term); - break; - case O_MAXSMT: - result = mk_ge(val, term); - break; - case O_MAXIMIZE: - result = mk_ge(term, val); - break; - } - return result; + return mk_cmp(true, mdl, obj); } + expr_ref context::mk_gt(unsigned i, model_ref& mdl) { expr_ref result = mk_le(i, mdl); result = m.mk_not(result); return result; } - - void context::mk_term_val(model_ref& mdl, objective const& obj, expr_ref& term, expr_ref& val) { - rational r; + + expr_ref context::mk_cmp(bool is_ge, model_ref& mdl, objective const& obj) { + rational k(0); + expr_ref val(m), result(m); switch (obj.m_type) { case O_MINIMIZE: + is_ge = !is_ge; case O_MAXIMIZE: - term = obj.m_term; - break; - case O_MAXSMT: { - unsigned sz = obj.m_terms.size(); - expr_ref_vector sum(m); - expr_ref zero(m); - zero = m_arith.mk_numeral(rational(0), false); - for (unsigned i = 0; i < sz; ++i) { - expr* t = obj.m_terms[i]; - rational const& w = obj.m_weights[i]; - sum.push_back(m.mk_ite(t, m_arith.mk_numeral(w, false), zero)); - } - if (sum.empty()) { - term = zero; + VERIFY(mdl->eval(obj.m_term, val) && is_numeral(val, k)); + if (is_ge) { + result = mk_ge(obj.m_term, val); } else { - term = m_arith.mk_add(sum.size(), sum.c_ptr()); - } + result = mk_ge(val, obj.m_term); + } + break; + case O_MAXSMT: { + m_opt_solver->ensure_pb(); + pb_util pb(m); + unsigned sz = obj.m_terms.size(); + ptr_vector terms; + vector coeffs; + for (unsigned i = 0; i < sz; ++i) { + terms.push_back(obj.m_terms[i]); + coeffs.push_back(obj.m_weights[i]); + VERIFY(mdl->eval(obj.m_terms[i], val)); + if (m.is_true(val)) { + k += obj.m_weights[i]; + } + } + if (is_ge) { + result = pb.mk_ge(sz, coeffs.c_ptr(), terms.c_ptr(), k); + } + else { + result = pb.mk_le(sz, coeffs.c_ptr(), terms.c_ptr(), k); + } break; } } TRACE("opt", - model_smt2_pp(tout << "Model:\n", m, *mdl, 0); - mdl->eval(term, val); tout << term << " " << val << "\n";); - VERIFY(mdl->eval(term, val) && is_numeral(val, r)); - } - + tout << (is_ge?">= ":"<= ") << k << "\n"; + display_objective(tout, obj); + tout << "\n"; + tout << result << "\n";); + return result; + } expr_ref context::mk_ge(expr* t, expr* s) { expr_ref result(m); diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 3b764aaf5..001dd1b62 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -282,7 +282,7 @@ namespace opt { // pareto void yield(); expr_ref mk_ge(expr* t, expr* s); - void mk_term_val(model_ref& mdl, objective const& obj, expr_ref& term, expr_ref& val); + expr_ref mk_cmp(bool is_ge, model_ref& mdl, objective const& obj); }; diff --git a/src/opt/opt_pareto.cpp b/src/opt/opt_pareto.cpp index e8b295d9f..5e1d4b269 100644 --- a/src/opt/opt_pareto.cpp +++ b/src/opt/opt_pareto.cpp @@ -68,7 +68,7 @@ namespace opt { fmls.push_back(m.mk_or(gt.size(), gt.c_ptr())); fml = m.mk_and(fmls.size(), fmls.c_ptr()); IF_VERBOSE(10, verbose_stream() << "dominates: " << fml << "\n";); - TRACE("opt", tout << fml << "\n";); + TRACE("opt", tout << fml << "\n"; model_smt2_pp(tout, m, *m_model, 0);); m_solver->assert_expr(fml); } diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 2a12818c5..08bc20004 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -86,6 +86,14 @@ namespace opt { m_context.set_logic(logic); } + void opt_solver::ensure_pb() { + smt::theory_id th_id = m.get_family_id("pb"); + smt::theory* th = get_context().get_theory(th_id); + if (!th) { + get_context().register_plugin(alloc(smt::theory_pb, m, m_params)); + } + } + smt::theory_opt& opt_solver::get_optimizer() { smt::context& ctx = m_context.get_context(); smt::theory_id arith_id = m_context.m().get_family_id("arith"); diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index f9702705f..e45f4be91 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -122,6 +122,7 @@ namespace opt { bool dump_benchmarks(); smt::context& get_context() { return m_context.get_context(); } // used by weighted maxsat. + void ensure_pb(); smt::theory_opt& get_optimizer(); From fcb4962016bab1064dd98ff094a5227346fe6951 Mon Sep 17 00:00:00 2001 From: nikolajbjorner Date: Mon, 23 Feb 2015 11:18:24 -0800 Subject: [PATCH 713/925] add patch suggested by Arie Gurfinkel Signed-off-by: nikolajbjorner --- src/muz/base/proof_utils.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/muz/base/proof_utils.cpp b/src/muz/base/proof_utils.cpp index 87ecf9985..d4a8ab22b 100644 --- a/src/muz/base/proof_utils.cpp +++ b/src/muz/base/proof_utils.cpp @@ -156,12 +156,22 @@ public: SASSERT(m.get_num_parents(p) == 1); tmp = m.get_parent(p, 0); elim(tmp); - get_literals(m.get_fact(p)); expr_set* hyps = m_hypmap.find(tmp); expr_set* new_hyps = 0; if (hyps) { new_hyps = alloc(expr_set, *hyps); } + expr* fact = m.get_fact(p); + // when hypothesis is a single literal of the form + // (or A B), and the fact of p is (or A B). + if (hyps && hyps->size() == 1 && in_hypotheses(fact, hyps)) { + m_literals.reset(); + m_literals.push_back(fact); + } + else { + get_literals(fact); + } + for (unsigned i = 0; i < m_literals.size(); ++i) { expr* e = m_literals[i]; if (!in_hypotheses(e, hyps)) { From fbf8289394f4e4d78ef9c360e4b4b47d9bd961b4 Mon Sep 17 00:00:00 2001 From: nikolajbjorner Date: Tue, 24 Feb 2015 14:02:23 -0800 Subject: [PATCH 714/925] probe also hard constraints before enabling SAT solver. Bug reported by Zvonimir Pavlinovic Signed-off-by: nikolajbjorner --- src/opt/opt_context.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index f22ce479e..b98343013 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -533,6 +533,9 @@ namespace opt { for (unsigned i = 0; i < sz; i++) { quick_for_each_expr(proc, visited, get_solver().get_assertion(i)); } + for (unsigned i = 0; i < m_hard_constraints.size(); ++i) { + quick_for_each_expr(proc, visited, m_hard_constraints[i].get()); + } } catch (is_bv::found) { return false; From b8fbc326899a2ba7a8f7e2c8c2bc45be2b4acb02 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 24 Feb 2015 17:03:34 -0800 Subject: [PATCH 715/925] fix crash in explanation generation. Codeplex issue 181 Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.cpp | 1 + src/muz/base/dl_context.cpp | 2 ++ src/muz/rel/dl_mk_explanations.cpp | 4 +++- src/muz/rel/dl_relation_manager.cpp | 2 +- 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 4a51da9b0..1a8e42704 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1199,6 +1199,7 @@ void cmd_context::reset(bool finalize) { restore_assertions(0); if (m_solver) m_solver = 0; + m_scopes.reset(); m_opt = 0; m_pp_env = 0; m_dt_eh = 0; diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 6aa6d5ea5..6d1f6664a 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -335,6 +335,7 @@ namespace datalog { if (!is_predicate(decl)) { m_pinned.push_back(decl); m_preds.insert(decl); + TRACE("dl", tout << mk_pp(decl, m) << "\n";); if (named) { m_preds_by_name.insert(decl->get_name(), decl); } @@ -345,6 +346,7 @@ namespace datalog { m_preds.reset(); func_decl_set::iterator it = preds.begin(), end = preds.end(); for (; it != end; ++it) { + TRACE("dl", tout << mk_pp(*it, m) << "\n";); m_preds.insert(*it); } } diff --git a/src/muz/rel/dl_mk_explanations.cpp b/src/muz/rel/dl_mk_explanations.cpp index 55c87f66e..b108df1bc 100644 --- a/src/muz/rel/dl_mk_explanations.cpp +++ b/src/muz/rel/dl_mk_explanations.cpp @@ -828,11 +828,13 @@ namespace datalog { SASSERT(&expl_singleton->get_plugin()==m_er_plugin); m_e_fact_relation = static_cast(expl_singleton); } - func_decl_set const& predicates = m_context.get_predicates(); + func_decl_set predicates(m_context.get_predicates()); + decl_set::iterator it = predicates.begin(); decl_set::iterator end = predicates.end(); for (; it!=end; ++it) { func_decl * orig_decl = *it; + TRACE("dl", tout << mk_pp(orig_decl, m_manager) << "\n";); func_decl * e_decl = get_e_decl(orig_decl); if (!rmgr.try_get_relation(orig_decl) && diff --git a/src/muz/rel/dl_relation_manager.cpp b/src/muz/rel/dl_relation_manager.cpp index a2b16bcf9..0dd62b544 100644 --- a/src/muz/rel/dl_relation_manager.cpp +++ b/src/muz/rel/dl_relation_manager.cpp @@ -755,7 +755,7 @@ namespace datalog { relation_union_fn * relation_manager::mk_union_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta) { + const relation_base * delta) { relation_union_fn * res = tgt.get_plugin().mk_union_fn(tgt, src, delta); if(!res && &tgt.get_plugin()!=&src.get_plugin()) { res = src.get_plugin().mk_union_fn(tgt, src, delta); From fe6af38d971fd5525c3e620f926195391d52609d Mon Sep 17 00:00:00 2001 From: nikolajbjorner Date: Tue, 10 Mar 2015 20:57:01 -0700 Subject: [PATCH 716/925] debugging assertion violation Signed-off-by: nikolajbjorner --- src/opt/mus.cpp | 2 +- src/smt/theory_arith_core.h | 25 +++++++++++++++++++------ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/opt/mus.cpp b/src/opt/mus.cpp index f9190911a..7f265ab0f 100644 --- a/src/opt/mus.cpp +++ b/src/opt/mus.cpp @@ -78,7 +78,7 @@ struct mus::imp { expr_ref_vector assumptions(m); ptr_vector core_exprs; while (!core.empty()) { - IF_VERBOSE(1, verbose_stream() << "(opt.mus reducing core: " << core.size() << " new core: " << mus.size() << ")\n";); + IF_VERBOSE(2, verbose_stream() << "(opt.mus reducing core: " << core.size() << " new core: " << mus.size() << ")\n";); unsigned cls_id = core.back(); TRACE("opt", display_vec(tout << "core: ", core); diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 264eb0f10..3ac70d372 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -72,6 +72,7 @@ namespace smt { m_value .push_back(inf_numeral()); } m_old_value .push_back(inf_numeral()); + SASSERT(m_var_occs.size() == r); m_var_occs .push_back(atoms()); m_unassigned_atoms .push_back(0); m_var_pos .push_back(-1); @@ -85,6 +86,7 @@ namespace smt { if (is_pure_monomial(n->get_owner())) m_nl_monomials.push_back(r); SASSERT(check_vector_sizes()); + SASSERT(m_var_occs[r].empty()); TRACE("mk_arith_var", tout << "#" << n->get_owner_id() << " :=\n" << mk_ll_pp(n->get_owner(), get_manager()) << "\n"; tout << "is_attached_to_var: " << is_attached_to_var(n) << ", var: " << n->get_th_var(get_id()) << "\n";); @@ -812,6 +814,7 @@ namespace smt { void theory_arith::mk_bound_axioms(atom * a1) { theory_var v = a1->get_var(); atoms & occs = m_var_occs[v]; + TRACE("mk_bound_axioms", tout << "add bound axioms for v" << v << " " << a1 << "\n";); if (!get_context().is_searching()) { // // NB. We make an assumption that user push calls propagation @@ -823,7 +826,7 @@ namespace smt { } inf_numeral const & k1(a1->get_k()); atom_kind kind1 = a1->get_atom_kind(); - TRACE("mk_bound_axioms", tout << "making bound axioms for v" << v << " " << kind1 << " " << k1 << "\n";); + TRACE("mk_bound_axioms", tout << "making bound axioms for v" << v << " " << kind1 << " " << k1 << " " << a1 << "\n";); typename atoms::iterator it = occs.begin(); typename atoms::iterator end = occs.end(); @@ -833,6 +836,12 @@ namespace smt { atom * a2 = *it; inf_numeral const & k2(a2->get_k()); atom_kind kind2 = a2->get_atom_kind(); + CTRACE("mk_bound_axioms", k1 == k2 && kind1 == kind2, + display_atom(tout << a1 << " ", a1, true); + display_atom(tout << a2 << " ", a2, true); + tout << &occs << " " << &m_var_occs[v] << "\n"; + ); + SASSERT(k1 != k2 || kind1 != kind2); if (kind2 == A_LOWER) { if (k2 < k1) { @@ -861,6 +870,7 @@ namespace smt { template void theory_arith::mk_bound_axiom(atom* a1, atom* a2) { + TRACE("mk_bound_axioms", tout << a1 << " " << a2 << "\n";); theory_var v = a1->get_var(); literal l1(a1->get_bool_var()); literal l2(a2->get_bool_var()); @@ -1090,7 +1100,8 @@ namespace smt { occs.push_back(a); m_atoms.push_back(a); insert_bv2a(bv, a); - TRACE("arith_internalize", tout << "succeeded... v: " << v << " " << kind << " " << k << "\n";); + TRACE("arith_internalize", tout << "succeeded... v" << v << " " << kind << " " << k << "\n"; + for (unsigned i = 0; i + 1 < occs.size(); ++i) tout << occs[i] << "\n";); return true; } @@ -2062,7 +2073,7 @@ namespace smt { continue; SASSERT(curr_error > inf_numeral(0)); if (best == null_theory_var || (!least && curr_error > best_error) || (least && curr_error < best_error)) { - TRACE("select_pivot", tout << "best: " << best << " v: " << v + TRACE("select_pivot", tout << "best: " << best << " v" << v << ", best_error: " << best_error << ", curr_error: " << curr_error << "\n";); best = v; best_error = curr_error; @@ -2619,9 +2630,9 @@ namespace smt { << limit_k1 << " delta: " << delta << " coeff: " << coeff << "\n";); inf_numeral k_2 = k_1; atom * new_atom = 0; - atoms & as = m_var_occs[it->m_var]; - typename atoms::iterator it = as.begin(); - typename atoms::iterator end = as.end(); + atoms const & as = m_var_occs[it->m_var]; + typename atoms::const_iterator it = as.begin(); + typename atoms::const_iterator end = as.end(); for (; it != end; ++it) { atom * a = *it; if (a == b) @@ -3200,6 +3211,7 @@ namespace smt { erase_bv2a(bv); SASSERT(m_var_occs[v].back() == a); m_var_occs[v].pop_back(); + TRACE("mk_bound_axioms", tout << a << "\n";); dealloc(a); } m_atoms.shrink(old_size); @@ -3269,6 +3281,7 @@ namespace smt { m_bounds[1] .shrink(old_num_vars); SASSERT(check_vector_sizes()); } + SASSERT(m_var_occs.size() == old_num_vars); } template From 51267f3aba31031bf966a6ccd75234f6b6559245 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 11 Mar 2015 00:26:49 -0700 Subject: [PATCH 717/925] take into account that bound from optimization may create atom that clashes with inequality bound from term Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith_aux.h | 3 ++- src/smt/theory_arith_core.h | 21 +++++++++++---------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index b4ebd9622..b0b57d256 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -1200,7 +1200,8 @@ namespace smt { bool_var bv = ctx.mk_bool_var(b); ctx.set_var_theory(bv, get_id()); // ctx.set_enode_flag(bv, true); - atom* a = alloc(atom, bv, v, val, A_LOWER); + atom* a = alloc(atom, bv, v, val, A_LOWER); + mk_bound_axioms(a); m_unassigned_atoms[v]++; m_var_occs[v].push_back(a); m_atoms.push_back(a); diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 3ac70d372..eb1b98507 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -74,6 +74,7 @@ namespace smt { m_old_value .push_back(inf_numeral()); SASSERT(m_var_occs.size() == r); m_var_occs .push_back(atoms()); + SASSERT(m_var_occs.back().empty()); m_unassigned_atoms .push_back(0); m_var_pos .push_back(-1); m_bounds[0] .push_back(0); @@ -91,6 +92,7 @@ namespace smt { tout << "#" << n->get_owner_id() << " :=\n" << mk_ll_pp(n->get_owner(), get_manager()) << "\n"; tout << "is_attached_to_var: " << is_attached_to_var(n) << ", var: " << n->get_th_var(get_id()) << "\n";); get_context().attach_th_var(n, this, r); + SASSERT(m_var_occs.back().empty()); return r; } @@ -826,7 +828,7 @@ namespace smt { } inf_numeral const & k1(a1->get_k()); atom_kind kind1 = a1->get_atom_kind(); - TRACE("mk_bound_axioms", tout << "making bound axioms for v" << v << " " << kind1 << " " << k1 << " " << a1 << "\n";); + TRACE("mk_bound_axioms", display_atom(tout << "making bound axioms for " << a1 << " ", a1, true); tout << "\n";); typename atoms::iterator it = occs.begin(); typename atoms::iterator end = occs.end(); @@ -836,11 +838,11 @@ namespace smt { atom * a2 = *it; inf_numeral const & k2(a2->get_k()); atom_kind kind2 = a2->get_atom_kind(); - CTRACE("mk_bound_axioms", k1 == k2 && kind1 == kind2, - display_atom(tout << a1 << " ", a1, true); - display_atom(tout << a2 << " ", a2, true); - tout << &occs << " " << &m_var_occs[v] << "\n"; - ); + TRACE("mk_bound_axioms", display_atom(tout << "compare " << a2 << " ", a2, true); tout << "\n";); + + if (k1 == k2 && kind1 == kind2) { + continue; + } SASSERT(k1 != k2 || kind1 != kind2); if (kind2 == A_LOWER) { @@ -2687,12 +2689,12 @@ namespace smt { template void theory_arith::mk_implied_bound(row const & r, unsigned idx, bool is_lower, theory_var v, bound_kind kind, inf_numeral const & k) { - atoms & as = m_var_occs[v]; + atoms const & as = m_var_occs[v]; antecedents& ante = get_antecedents(); inf_numeral const & epsilon = get_epsilon(v); inf_numeral delta; - typename atoms::iterator it = as.begin(); - typename atoms::iterator end = as.end(); + typename atoms::const_iterator it = as.begin(); + typename atoms::const_iterator end = as.end(); for (; it != end; ++it) { atom * a = *it; bool_var bv = a->get_bool_var(); @@ -3211,7 +3213,6 @@ namespace smt { erase_bv2a(bv); SASSERT(m_var_occs[v].back() == a); m_var_occs[v].pop_back(); - TRACE("mk_bound_axioms", tout << a << "\n";); dealloc(a); } m_atoms.shrink(old_size); From f47cc702362d8d64ab5462ade705a4426ed21a85 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 11 Mar 2015 11:48:52 -0700 Subject: [PATCH 718/925] use of regions for AUX lemmas from pb solver Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 1eff86db4..20800b0b3 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1771,7 +1771,7 @@ namespace smt { literal lits[2] = { l1, l2 }; justification* js = 0; if (proofs_enabled()) { - js = alloc(theory_axiom_justification, get_id(), get_context().get_region(), 2, lits); + js = get_context().mk_justification(theory_axiom_justification(get_id(), get_context().get_region(), 2, lits)); } return js; } @@ -1779,7 +1779,7 @@ namespace smt { justification* theory_pb::justify(literal_vector const& lits) { justification* js = 0; if (proofs_enabled()) { - js = alloc(theory_lemma_justification, get_id(), get_context(), lits.size(), lits.c_ptr()); + js = get_context().mk_justification(theory_axiom_justification(get_id(), get_context(), lits.size(), lits.c_ptr())); } return js; } From 4145b92136294e07604048a3d588de6d9bc3e77c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 11 Mar 2015 11:52:07 -0700 Subject: [PATCH 719/925] use of regions for AUX lemmas from pb solver Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 20800b0b3..7be53ff86 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1779,7 +1779,7 @@ namespace smt { justification* theory_pb::justify(literal_vector const& lits) { justification* js = 0; if (proofs_enabled()) { - js = get_context().mk_justification(theory_axiom_justification(get_id(), get_context(), lits.size(), lits.c_ptr())); + js = get_context().mk_justification(theory_axiom_justification(get_id(), get_context().get_region(), lits.size(), lits.c_ptr())); } return js; } From 10cdbb881f014b67fcbcc93a0e39c6ac5aee9eb1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 25 Mar 2015 12:13:57 -0700 Subject: [PATCH 720/925] enable canceling simplex on interrupt, investigating PDR inconsistency Signed-off-by: Nikolaj Bjorner --- src/muz/base/dl_context.cpp | 17 ++++++++--------- src/muz/base/dl_context.h | 3 +++ src/muz/pdr/pdr_context.cpp | 1 + src/muz/transforms/dl_mk_array_blast.cpp | 11 +++++++---- src/muz/transforms/dl_transforms.cpp | 2 ++ src/smt/theory_arith_core.h | 6 ++++++ 6 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 6d1f6664a..fc4abc91b 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -226,6 +226,7 @@ namespace datalog { m_engine(0), m_closed(false), m_saturation_was_run(false), + m_enable_bind_variables(true), m_last_status(OK), m_last_answer(m), m_engine_type(LAST_ENGINE), @@ -328,7 +329,12 @@ namespace datalog { } expr_ref context::bind_vars(expr* fml, bool is_forall) { - return m_bind_variables(fml, is_forall); + if (m_enable_bind_variables) { + return m_bind_variables(fml, is_forall); + } + else { + return expr_ref(fml, m); + } } void context::register_predicate(func_decl * decl, bool named) { @@ -680,6 +686,7 @@ namespace datalog { } void context::transform_rules(rule_transformer::plugin* plugin) { + flet _enable_bv(m_enable_bind_variables, false); rule_transformer transformer(*this); transformer.register_plugin(plugin); transform_rules(transformer); @@ -841,13 +848,6 @@ namespace datalog { } lbool context::query(expr* query) { -#if 0 - // TODO: what? - if(get_engine() != DUALITY_ENGINE) { - new_query(); - check_rules(m_rule_set); - } -#endif m_mc = mk_skip_model_converter(); m_last_status = OK; m_last_answer = 0; @@ -990,7 +990,6 @@ namespace datalog { for (unsigned i = 0; i < m_rule_fmls.size(); ++i) { expr_ref r = bind_vars(m_rule_fmls[i].get(), true); rules.push_back(r.get()); - // rules.push_back(m_rule_fmls[i].get()); names.push_back(m_rule_names[i]); bounds.push_back(m_rule_bounds[i]); } diff --git a/src/muz/base/dl_context.h b/src/muz/base/dl_context.h index 52b3cbaf2..9da4700e6 100644 --- a/src/muz/base/dl_context.h +++ b/src/muz/base/dl_context.h @@ -205,6 +205,7 @@ namespace datalog { bool m_closed; bool m_saturation_was_run; + bool m_enable_bind_variables; execution_result m_last_status; expr_ref m_last_answer; DL_ENGINE m_engine_type; @@ -294,6 +295,8 @@ namespace datalog { */ expr_ref bind_vars(expr* fml, bool is_forall); + bool& bind_vars_enabled() { return m_enable_bind_variables; } + /** Register datalog relation. diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index 042806d44..177b87820 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -729,6 +729,7 @@ namespace pdr { obj_map::iterator it = other.m_prop2level.begin(); obj_map::iterator end = other.m_prop2level.end(); for (; it != end; ++it) { + IF_VERBOSE(2, verbose_stream() << "(pdr-inherit: " << mk_pp(it->m_key, m) << ")\n";); add_property(it->m_key, it->m_value); } } diff --git a/src/muz/transforms/dl_mk_array_blast.cpp b/src/muz/transforms/dl_mk_array_blast.cpp index fb860f2ac..bc3b0cc38 100644 --- a/src/muz/transforms/dl_mk_array_blast.cpp +++ b/src/muz/transforms/dl_mk_array_blast.cpp @@ -266,11 +266,13 @@ namespace datalog { } else { m_rewriter(e, tmp); - change = change || (tmp != e); new_conjs.push_back(tmp); } } - + if (!inserted) { + rules.add_rule(&r); + return false; + } expr_ref fml1(m), fml2(m), body(m), head(m); body = m.mk_and(new_conjs.size(), new_conjs.c_ptr()); head = r.get_head(); @@ -278,8 +280,8 @@ namespace datalog { m_rewriter(body); sub(head); m_rewriter(head); - change = ackermanize(r, body, head) || change; - if (!inserted && !change) { + change = ackermanize(r, body, head); + if (!change) { rules.add_rule(&r); return false; } @@ -287,6 +289,7 @@ namespace datalog { fml2 = m.mk_implies(body, head); proof_ref p(m); rule_set new_rules(m_ctx); + TRACE("dl", tout << fml2 << "\n";); rm.mk_rule(fml2, p, new_rules, r.name()); diff --git a/src/muz/transforms/dl_transforms.cpp b/src/muz/transforms/dl_transforms.cpp index db62c2ec6..81f9d6f64 100644 --- a/src/muz/transforms/dl_transforms.cpp +++ b/src/muz/transforms/dl_transforms.cpp @@ -38,6 +38,8 @@ Revision History: namespace datalog { void apply_default_transformation(context& ctx) { + flet _enable_bv(ctx.bind_vars_enabled(), false); + rule_transformer transf(ctx); ctx.ensure_closed(); transf.reset(); diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index eb1b98507..48f6def5c 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -1376,6 +1376,9 @@ namespace smt { failed(); return false; } + if (get_context().get_cancel_flag()) { + return true; + } CASSERT("arith", satisfy_bounds()); discard_update_trail(); @@ -2145,6 +2148,9 @@ namespace smt { return false; } TRACE("arith_make_feasible_detail", display(tout);); + if (get_context().get_cancel_flag()) { + return true; + } } TRACE("arith_make_feasible", tout << "make_feasible: sat\n"; display(tout);); CASSERT("arith", wf_rows()); From ae74b97c77dbf56e8f124e5f4a23de7315db5781 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Thu, 26 Mar 2015 11:22:09 -0700 Subject: [PATCH 721/925] Move to MIT License --- LICENSE.txt | 46 ++++++---------------------------------------- 1 file changed, 6 insertions(+), 40 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index 72d85818f..91c8070d0 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,41 +1,7 @@ -Microsoft Research License Agreement -Non-Commercial Use Only Z3 -_____________________________________________________________________ -This Microsoft Research License Agreement, including all exhibits ("MSR-LA") is a legal agreement between you and Microsoft Corporation ("Microsoft" or "we") for the data identified above, which may include associated materials, text or speech files, associated media and "online" or electronic documentation and any updates we provide in our discretion (together, the "Software"). - -By installing, copying, or otherwise using this Software, you agree to be bound by the terms of this MSR-LA. If you do not agree, do not install copy or use the Software. The Software is protected by copyright and other intellectual property laws and is licensed, not sold. - -SCOPE OF RIGHTS: -You may use, copy, reproduce, and distribute this Software for any non-commercial purpose, subject to the restrictions in this MSR-LA. Some purposes which can be non-commercial are teaching, academic research, public demonstrations and personal experimentation. You may also distribute this Software with books or other teaching materials, or publish the Software on websites, that are intended to teach the use of the Software for academic or other non-commercial purposes. - -You may not use or distribute this Software or any derivative works in any form for commercial purposes. Examples of commercial purposes would be running business operations, licensing, leasing, or selling the Software, distributing the Software for use with commercial products, using the Software in the creation or use of commercial products or any other activity which purpose is to procure a commercial gain to you or others. - -You may create derivative works of the Software source code and distribute the modified Software solely for non-commercial academic purposes, as provided herein. If you distribute the Software or any derivative works of the Software, you will distribute them under the same terms and conditions as in this license, and you will not grant other rights to the Software or derivative works that are different from those provided by this MSR-LA. - -If you have created derivative works of the Software, and distribute such derivative works, you will cause the modified files to carry prominent notices so that recipients know that they are not receiving the original Software. Such notices must state: (i) that you have changed the Software; and (ii) the date of any changes. -In return, we simply require that you agree: - -1. That you will not remove any copyright or other notices from the Software. - -2. That if any of the Software is in binary format, you will not attempt to modify such portions of the Software, or to reverse engineer or decompile them, except and only to the extent authorized by applicable law. - -3. That Microsoft is granted back, without any restrictions or limitations, a non-exclusive, perpetual, irrevocable, royalty-free, assignable and sub-licensable license, to reproduce, publicly perform or display, install, use, modify, post, distribute, make and have made, sell and transfer your modifications to and/or derivative works of the Software source code or data, for any purpose. - -4. That any feedback about the Software provided by you to us is voluntarily given, and Microsoft shall be free to use the feedback as it sees fit without obligation or restriction of any kind, even if the feedback is designated by you as confidential. - -5. THAT THE SOFTWARE COMES "AS IS", WITH NO WARRANTIES. THIS MEANS NO EXPRESS, IMPLIED OR STATUTORY WARRANTY, INCLUDING WITHOUT LIMITATION, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ANY WARRANTY AGAINST INTERFERENCE WITH YOUR ENJOYMENT OF THE SOFTWARE OR ANY WARRANTY OF TITLE OR NON-INFRINGEMENT. THERE IS NO WARRANTY THAT THIS SOFTWARE WILL FULFILL ANY OF YOUR PARTICULAR PURPOSES OR NEEDS. ALSO, YOU MUST PASS THIS DISCLAIMER ON WHENEVER YOU DISTRIBUTE THE SOFTWARE OR DERIVATIVE WORKS. - -6. THAT NEITHER MICROSOFT NOR ANY CONTRIBUTOR TO THE SOFTWARE WILL BE LIABLE FOR ANY DAMAGES RELATED TO THE SOFTWARE OR THIS MSR-LA, INCLUDING DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL OR INCIDENTAL DAMAGES, TO THE MAXIMUM EXTENT THE LAW PERMITS, NO MATTER WHAT LEGAL THEORY IT IS BASED ON. ALSO, YOU MUST PASS THIS LIMITATION OF LIABILITY ON WHENEVER YOU DISTRIBUTE THE SOFTWARE OR DERIVATIVE WORKS. - -7. That we have no duty of reasonable care or lack of negligence, and we are not obligated to (and will not) provide technical support for the Software. - -8. That if you breach this MSR-LA or if you sue anyone over patents that you think may apply to or read on the Software or anyone's use of the Software, this MSR-LA (and your license and rights obtained herein) terminate automatically. Upon any such termination, you shall destroy all of your copies of the Software immediately. Sections 3, 4, 5, 6, 7, 8, 11 and 12 of this MSR-LA shall survive any termination of this MSR-LA. - -9. That the patent rights, if any, granted to you in this MSR-LA only apply to the Software, not to any derivative works you make. - -10. That the Software may be subject to U.S. export jurisdiction at the time it is licensed to you, and it may be subject to additional export or import laws in other places. You agree to comply with all such laws and regulations that may apply to the Software after delivery of the Software to you. - -11. That all rights not expressly granted to you in this MSR-LA are reserved. - -12. That this MSR-LA shall be construed and controlled by the laws of the State of Washington, USA, without regard to conflicts of law. If any provision of this MSR-LA shall be deemed unenforceable or contrary to law, the rest of this MSR-LA shall remain in full effect and interpreted in an enforceable manner that most nearly captures the intent of the original language. +Copyright (c) Microsoft Corporation +All rights reserved. +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. From 437a69b258581f779ff2fc7273d11f0bd705f275 Mon Sep 17 00:00:00 2001 From: NikolajBjorner Date: Thu, 26 Mar 2015 11:31:34 -0700 Subject: [PATCH 722/925] Update README change reference to license --- README | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README b/README index ad136e5f6..f07f88ebd 100644 --- a/README +++ b/README @@ -1,6 +1,5 @@ Z3 is a theorem prover from Microsoft Research. -Z3 is licensed under MSR-LA (Microsoft Research License Agreement). -See http://z3.codeplex.com/license for more information about this license. +Z3 is licensed under the MIT license. Z3 can be built using Visual Studio Command Prompt and make/g++. 1) Building Z3 on Windows using Visual Studio Command Prompt From 9c55be14fb3f5030eae446387bf673b6d44a35fd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 1 Apr 2015 10:56:40 -0700 Subject: [PATCH 723/925] change print parameters to use hyphen instead of namespace dots Signed-off-by: Nikolaj Bjorner --- src/muz/base/fixedpoint_params.pyg | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/muz/base/fixedpoint_params.pyg b/src/muz/base/fixedpoint_params.pyg index 87fd4e2af..dc3eefc14 100644 --- a/src/muz/base/fixedpoint_params.pyg +++ b/src/muz/base/fixedpoint_params.pyg @@ -101,23 +101,23 @@ def_module_params('fixedpoint', ('pdr.try_minimize_core', BOOL, False, "try to reduce core size (before inductive minimization)"), ('pdr.utvpi', BOOL, True, 'Enable UTVPI strategy'), - ('print.fixedpoint_extensions', BOOL, True, + ('print_fixedpoint_extensions', BOOL, True, "use SMT-LIB2 fixedpoint extensions, instead of pure SMT2, " + "when printing rules"), - ('print.low_level_smt2', BOOL, False, + ('print_low_level_smt2', BOOL, False, "use (faster) low-level SMT2 printer (the printer is scalable " + "but the result may not be as readable)"), - ('print.with_variable_declarations', BOOL, True, + ('print_with_variable_declarations', BOOL, True, "use variable declarations when displaying rules " + "(instead of attempting to use original names)"), - ('print.answer', BOOL, False, 'print answer instance(s) to query'), - ('print.certificate', BOOL, False, + ('print_answer', BOOL, False, 'print answer instance(s) to query'), + ('print_certificate', BOOL, False, 'print certificate for reachability or non-reachability'), - ('print.boogie_certificate', BOOL, False, + ('print_boogie_certificate', BOOL, False, 'print certificate for reachability or non-reachability using a ' + 'format understood by Boogie'), - ('print.statistics', BOOL, False, 'print statistics'), - ('print.aig', SYMBOL, '', + ('print_statistics', BOOL, False, 'print statistics'), + ('print_aig', SYMBOL, '', 'Dump clauses in AIG text format (AAG) to the given file name'), ('tab.selection', SYMBOL, 'weight', 'selection method for tabular strategy: weight (default), first, var-use'), From f8d04118d8eb4b020fa3b9ea821b2c2897fbf7f0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 1 Apr 2015 16:21:56 -0700 Subject: [PATCH 724/925] switch models for multiple box objectives. Feature request at codeplex issue 194, George Karpenov. Usage model is same as Pareto fronts you call check-sat multiple times until retrieving unsat Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 24 +++++++++++++++++++++++- src/opt/opt_context.h | 2 ++ src/opt/opt_solver.cpp | 9 +++++++-- src/opt/opt_solver.h | 4 +++- src/opt/optsmt.cpp | 4 +++- src/opt/optsmt.h | 2 ++ 6 files changed, 40 insertions(+), 5 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index b98343013..6718f401e 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -118,6 +118,7 @@ namespace opt { m_bv(m), m_hard_constraints(m), m_solver(0), + m_box_index(UINT_MAX), m_optsmt(m), m_scoped_state(m), m_fm(m), @@ -199,6 +200,9 @@ namespace opt { if (m_pareto) { return execute_pareto(); } + if (m_box_index != UINT_MAX) { + return execute_box(); + } init_solver(); import_scoped_state(); normalize(); @@ -313,13 +317,31 @@ namespace opt { } lbool context::execute_box() { + if (m_box_index < m_objectives.size()) { + m_model = m_box_models[m_box_index]; + ++m_box_index; + return l_true; + } + if (m_box_index != UINT_MAX && m_box_index >= m_objectives.size()) { + m_box_index = UINT_MAX; + return l_false; + } + m_box_index = 1; lbool r = m_optsmt.box(); - for (unsigned i = 0; r == l_true && i < m_objectives.size(); ++i) { + for (unsigned i = 0, j = 0; r == l_true && i < m_objectives.size(); ++i) { objective const& obj = m_objectives[i]; if (obj.m_type == O_MAXSMT) { solver::scoped_push _sp(get_solver()); r = execute(obj, false, false); + if (r == l_true) m_box_models.push_back(m_model.get()); } + else { + m_box_models.push_back(m_optsmt.get_model(j)); + ++j; + } + } + if (r == l_true && m_objectives.size() > 0) { + m_model = m_box_models[0]; } return r; } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 001dd1b62..0815e0061 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -144,6 +144,8 @@ namespace opt { ref m_solver; ref m_sat_solver; scoped_ptr m_pareto; + sref_vector m_box_models; + unsigned m_box_index; params_ref m_params; optsmt m_optsmt; map_t m_maxsmts; diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 08bc20004..4556cd080 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -219,9 +219,13 @@ namespace opt { } m_objective_values[i] = val; - TRACE("opt", { model_ref mdl; tout << m_objective_values[i] << "\n"; + model_ref mdl; + get_model(mdl); + m_models.set(i, mdl.get()); + + TRACE("opt", { tout << m_objective_values[i] << "\n"; tout << blocker << "\n"; - get_model(mdl); model_smt2_pp(tout << "update model:\n", m, *mdl, 0); }); + model_smt2_pp(tout << "update model:\n", m, *mdl, 0); }); } void opt_solver::decrement_value(unsigned i, inf_eps& val) { @@ -288,6 +292,7 @@ namespace opt { m_objective_values.push_back(inf_eps(rational(-1), inf_rational())); m_objective_sorts.push_back(m.get_sort(term)); m_valid_objectives.push_back(true); + m_models.push_back(0); return v; } diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index e45f4be91..9ceee89a7 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -76,6 +76,7 @@ namespace opt { bool m_objective_enabled; svector m_objective_vars; vector m_objective_values; + sref_vector m_models; sort_ref_vector m_objective_sorts; svector m_valid_objectives; bool m_dump_benchmarks; @@ -94,7 +95,7 @@ namespace opt { virtual void pop_core(unsigned n); virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions); virtual void get_unsat_core(ptr_vector & r); - virtual void get_model(model_ref & _m); + virtual void get_model(model_ref & _m); virtual proof * get_proof(); virtual std::string reason_unknown() const; virtual void get_labels(svector & r); @@ -111,6 +112,7 @@ namespace opt { void maximize_objectives(expr_ref_vector& blockers); inf_eps const & saved_objective_value(unsigned obj_index); inf_eps current_objective_value(unsigned obj_index); + model* get_model(unsigned obj_index) { return m_models[obj_index]; } bool objective_is_model_valid(unsigned obj_index) const { return m_valid_objectives[obj_index]; } diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 1148e3411..d64730335 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -50,6 +50,7 @@ namespace opt { for (unsigned i = 0; i < src.size(); ++i) { if (src[i] >= dst[i]) { dst[i] = src[i]; + m_models.set(i, m_s->get_model(i)); m_lower_fmls[i] = fmls[i].get(); if (dst[i].is_pos() && !dst[i].is_finite()) { // review: likely done already. m_lower_fmls[i] = m.mk_false(); @@ -57,7 +58,7 @@ namespace opt { } } else if (src[i] < dst[i] && !m.is_true(m_lower_fmls[i].get())) { - fmls[i] = m_lower_fmls[i].get(); + fmls[i] = m_lower_fmls[i].get(); } } } @@ -410,6 +411,7 @@ namespace opt { m_lower.push_back(inf_eps(rational(-1),inf_rational(0))); m_upper.push_back(inf_eps(rational(1), inf_rational(0))); m_lower_fmls.push_back(m.mk_true()); + m_models.push_back(0); return m_objs.size()-1; } diff --git a/src/opt/optsmt.h b/src/opt/optsmt.h index 8ec35c98e..0a6882b24 100644 --- a/src/opt/optsmt.h +++ b/src/opt/optsmt.h @@ -38,6 +38,7 @@ namespace opt { svector m_vars; symbol m_optsmt_engine; model_ref m_model; + sref_vector m_models; public: optsmt(ast_manager& m): m(m), m_s(0), m_cancel(false), m_objs(m), m_lower_fmls(m) {} @@ -60,6 +61,7 @@ namespace opt { inf_eps get_upper(unsigned index) const; bool objective_is_model_valid(unsigned index) const; void get_model(model_ref& mdl); + model* get_model(unsigned index) const { return m_models[index]; } void update_lower(unsigned idx, inf_eps const& r); void update_upper(unsigned idx, inf_eps const& r); From 9978cba5a8beab2d5e3ee4e24f4fd5357e1e58d3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 1 Apr 2015 16:27:15 -0700 Subject: [PATCH 725/925] Codeplex issue 191: inconsistent results from PDR engine. The report exposed bugs in the implementation of the priority queue leaving unexplored leaves durin search. The priority queue has now been revised to address the exposed bugs Signed-off-by: Nikolaj Bjorner --- src/muz/pdr/pdr_context.cpp | 242 ++++++++++++++++++++++++++++-------- src/muz/pdr/pdr_context.h | 48 ++++--- src/test/main.cpp | 1 + src/test/pdr.cpp | 116 +++++++++++++++++ 4 files changed, 339 insertions(+), 68 deletions(-) create mode 100644 src/test/pdr.cpp diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index 177b87820..3b7d5c056 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -622,14 +622,14 @@ namespace pdr { m_rule2transition.insert(&rule, fml.get()); rules.push_back(&rule); } - m_rule2inst.insert(&rule,&var_reprs); + m_rule2inst.insert(&rule, &var_reprs); m_rule2vars.insert(&rule, aux_vars); TRACE("pdr", tout << rule.get_decl()->get_name() << "\n"; for (unsigned i = 0; i < var_reprs.size(); ++i) { tout << mk_pp(var_reprs[i].get(), m) << " "; } - tout << "\n";); + if (!var_reprs.empty()) tout << "\n";); } bool pred_transformer::check_filled(app_ref_vector const& v) const { @@ -742,9 +742,26 @@ namespace pdr { m_closed = true; } - void model_node::reopen() { + void model_node::set_open() { SASSERT(m_closed); m_closed = false; + model_node* p = parent(); + while (p && p->is_closed()) { + p->m_closed = false; + p = p->parent(); + } + } + + void model_node::check_pre_closed() { + for (unsigned i = 0; i < children().size(); ++i) { + if (children()[i]->is_open()) return; + } + set_pre_closed(); + model_node* p = parent(); + while (p && p->is_1closed()) { + p->set_pre_closed(); + p = p->parent(); + } } static bool is_ini(datalog::rule const& r) { @@ -852,22 +869,66 @@ namespace pdr { } + void model_node::dequeue(model_node*& root) { + TRACE("pdr", tout << this << " " << state() << "\n";); + if (!m_next && !m_prev) return; + SASSERT(m_next); + SASSERT(m_prev); + SASSERT(children().empty()); + if (this == m_next) { + SASSERT(root == this); + root = 0; + } + else { + m_next->m_prev = m_prev; + m_prev->m_next = m_next; + if (this == root) { + root = m_next; + } + } + TRACE("pdr", tout << "new root: " << root << "\n";); + m_prev = 0; + m_next = 0; + } + + + void model_node::enqueue(model_node* n) { + TRACE("pdr", tout << n << " " << n->state() << "\n";); + SASSERT(!n->m_next); + SASSERT(!n->m_prev); + if (this == n) { + m_next = n; + m_prev = n; + } + else { + n->m_next = m_next; + m_next->m_prev = n; + m_next = n; + n->m_prev = this; + } + } // ---------------- // model_search + /** + \brief Dequeue the next goal. + */ model_node* model_search::next() { - if (m_leaves.empty()) { + if (!m_goal) { return 0; } - model_node* result = m_leaves.back(); - m_leaves.pop_back(); - return result; + else { + model_node* result = m_goal; + result->dequeue(m_goal); + return result; + } } bool model_search::is_repeated(model_node& n) const { model_node* p = n.parent(); while (p) { if (p->state() == n.state()) { + TRACE("pdr", tout << "repeated\n";); return true; } p = p->parent(); @@ -876,10 +937,15 @@ namespace pdr { } void model_search::add_leaf(model_node& n) { + SASSERT(n.children().empty()); model_nodes ns; model_nodes& nodes = cache(n).insert_if_not_there2(n.state(), ns)->get_data().m_value; + if (nodes.contains(&n)) { + return; + } nodes.push_back(&n); - if (nodes.size() == 1 || is_repeated(n)) { + TRACE("pdr_verbose", tout << "add: " << n.level() << ": " << &n << " " << n.state() << "\n";); + if (nodes.size() == 1) { set_leaf(n); } else { @@ -890,15 +956,21 @@ namespace pdr { void model_search::set_leaf(model_node& n) { erase_children(n, true); SASSERT(n.is_open()); - enqueue_leaf(n); + enqueue_leaf(&n); } - void model_search::enqueue_leaf(model_node& n) { - if (m_bfs) { - m_leaves.push_front(&n); + void model_search::enqueue_leaf(model_node* n) { + TRACE("pdr_verbose", tout << n << " " << n->state() << " goal: " << m_goal << "\n";); + SASSERT(n->is_open()); + if (!m_goal) { + m_goal = n; + m_goal->enqueue(n); + } + else if (m_bfs) { + m_goal->enqueue(n); } else { - m_leaves.push_back(&n); + m_goal->next()->enqueue(n); } } @@ -921,56 +993,132 @@ namespace pdr { void model_search::erase_children(model_node& n, bool backtrack) { ptr_vector todo, nodes; todo.append(n.children()); - erase_leaf(n); + remove_goal(n); n.reset(); while (!todo.empty()) { model_node* m = todo.back(); todo.pop_back(); nodes.push_back(m); todo.append(m->children()); - erase_leaf(*m); remove_node(*m, backtrack); } std::for_each(nodes.begin(), nodes.end(), delete_proc()); } void model_search::remove_node(model_node& n, bool backtrack) { + TRACE("pdr_verbose", tout << "remove: " << n.level() << ": " << &n << " " << n.state() << "\n";); model_nodes& nodes = cache(n).find(n.state()); nodes.erase(&n); - if (nodes.size() > 0 && n.is_open() && backtrack) { - for (unsigned i = 0; i < nodes.size(); ++i) { - nodes[i]->reopen(); - } + bool is_goal = n.is_goal(); + remove_goal(n); + if (!nodes.empty() && is_goal && backtrack) { + TRACE("pdr_verbose", for (unsigned i = 0; i < nodes.size(); ++i) n.display(tout << &n << "\n", 2);); + model_node* n1 = nodes[0]; + n1->set_open(); + SASSERT(n1->children().empty()); + enqueue_leaf(n1); } if (nodes.empty()) { cache(n).remove(n.state()); } } - void model_search::erase_leaf(model_node& n) { - if (n.children().empty() && n.is_open()) { - std::deque::iterator - it = m_leaves.begin(), - end = m_leaves.end(); - for (; it != end; ++it) { - if (*it == &n) { - m_leaves.erase(it); - break; + void model_search::remove_goal(model_node& n) { + n.dequeue(m_goal); + } + + void model_search::well_formed() { + // each open leaf is in the set of m_goal. + ptr_vector nodes; + nodes.push_back(&get_root()); + for (unsigned i = 0; i < nodes.size(); ++i) { + model_node* n = nodes[i]; + if (!n->children().empty()) { + nodes.append(n->children()); + } + else if (n->is_open() && !n->is_goal() && n->parent()) { + TRACE("pdr", n->display(tout << "node " << n << " not found among leaves\n", 0); display(tout);); + UNREACHABLE(); + return; + } + } + if (m_goal) { + model_node* n = m_goal; + do { + if (!n->is_open() || !n->children().empty()) { + TRACE("pdr", n->display(tout << "invalid leaf\n", 0); + display(tout);); + UNREACHABLE(); + return; + } + n = n->next(); + } + while (m_goal != n); + } + + // each state appears in at most one goal per level. + bool found = true; + for (unsigned l = 0; m_goal && found; ++l) { + found = false; + obj_hashtable open_states; + model_node* n = m_goal; + do { + if (n->level() == l) { + found = true; + if (n->is_open()) { + if (open_states.contains(n->state())) { + TRACE("pdr", n->display(tout << "repeated leaf\n", 0); display(tout);); + UNREACHABLE(); + } + open_states.insert(n->state()); + } + } + n = n->next(); + } + while (m_goal != n); + } + // a node is open if and only if it contains an + // open child which is a goal. + for (unsigned i = 0; i < nodes.size(); ++i) { + model_node* n = nodes[i]; + if (!n->children().empty() && n->parent()) { + found = false; + for (unsigned j = 0; !found && j < n->children().size(); ++j) { + found = n->children()[j]->is_open(); + } + if (n->is_open() != found) { + TRACE("pdr", n->display(tout << "node in inconsistent state\n", 0); display(tout);); + UNREACHABLE(); } } } } + unsigned model_search::num_goals() const { + model_node* n = m_goal; + unsigned num = 0; + if (n) { + do { + ++num; + n = n->next(); + } + while (n != m_goal); + } + return num; + } + std::ostream& model_search::display(std::ostream& out) const { if (m_root) { m_root->display(out, 0); } - out << "goals\n"; - std::deque::const_iterator - it = m_leaves.begin(), - end = m_leaves.end(); - for (; it != end; ++it) { - (*it)->display(out, 1); + out << "goals " << num_goals() << "\n"; + model_node* n = m_goal; + if (n) { + do { + n->display(out, 1); + n = n->next(); + } + while (n != m_goal); } return out; } @@ -1253,8 +1401,8 @@ namespace pdr { remove_node(*m_root, false); dealloc(m_root); m_root = 0; - m_cache.reset(); } + m_cache.reset(); } void model_search::backtrack_level(bool uses_level, model_node& n) { @@ -1262,7 +1410,7 @@ namespace pdr { if (uses_level && m_root->level() > n.level()) { IF_VERBOSE(2, verbose_stream() << "Increase level " << n.level() << "\n";); n.increase_level(); - enqueue_leaf(n); + enqueue_leaf(&n); } else { model_node* p = n.parent(); @@ -1270,15 +1418,16 @@ namespace pdr { set_leaf(*p); } } + DEBUG_CODE(well_formed();); } // ---------------- // context context::context( - smt_params& fparams, - fixedpoint_params const& params, - ast_manager& m + smt_params& fparams, + fixedpoint_params const& params, + ast_manager& m ) : m_fparams(fparams), m_params(params), @@ -1862,17 +2011,6 @@ namespace pdr { } } - void context::check_pre_closed(model_node& n) { - for (unsigned i = 0; i < n.children().size(); ++i) { - if (!n.children()[i]->is_closed()) return; - } - n.set_pre_closed(); - model_node* p = n.parent(); - while (p && p->is_1closed()) { - p->set_pre_closed(); - p = p->parent(); - } - } void context::expand_node(model_node& n) { SASSERT(n.is_open()); @@ -2143,10 +2281,10 @@ namespace pdr { model_node* child = alloc(model_node, &n, n_cube, pt, n.level()-1); ++m_stats.m_num_nodes; m_search.add_leaf(*child); - IF_VERBOSE(3, verbose_stream() << "Predecessor: " << mk_pp(o_cube, m) << "\n";); + IF_VERBOSE(2, verbose_stream() << "Predecessor: " << mk_pp(n_cube, m) << " " << (child->is_closed()?"closed":"open") << "\n";); m_stats.m_max_depth = std::max(m_stats.m_max_depth, child->depth()); } - check_pre_closed(n); + n.check_pre_closed(); TRACE("pdr", m_search.display(tout);); } diff --git a/src/muz/pdr/pdr_context.h b/src/muz/pdr/pdr_context.h index 44fba03d8..070a80ca4 100644 --- a/src/muz/pdr/pdr_context.h +++ b/src/muz/pdr/pdr_context.h @@ -186,6 +186,8 @@ namespace pdr { // structure for counter-example search. class model_node { model_node* m_parent; + model_node* m_next; + model_node* m_prev; pred_transformer& m_pt; expr_ref m_state; model_ref m_model; @@ -197,13 +199,17 @@ namespace pdr { datalog::rule const* m_rule; public: model_node(model_node* parent, expr_ref& state, pred_transformer& pt, unsigned level): - m_parent(parent), m_pt(pt), m_state(state), m_model(0), - m_level(level), m_orig_level(level), m_depth(0), m_closed(false), m_rule(0) { - if (m_parent) { - m_parent->m_children.push_back(this); - SASSERT(m_parent->m_level == level+1); - SASSERT(m_parent->m_level > 0); - m_depth = m_parent->m_depth+1; + m_parent(parent), m_next(0), m_prev(0), m_pt(pt), m_state(state), m_model(0), + m_level(level), m_orig_level(level), m_depth(0), m_closed(false), m_rule(0) { + model_node* p = m_parent; + if (p) { + p->m_children.push_back(this); + SASSERT(p->m_level == level+1); + SASSERT(p->m_level > 0); + m_depth = p->m_depth+1; + if (p && p->is_closed()) { + p->set_open(); + } } } void set_model(model_ref& m) { m_model = m; } @@ -211,7 +217,7 @@ namespace pdr { unsigned orig_level() const { return m_orig_level; } unsigned depth() const { return m_depth; } void increase_level() { ++m_level; } - expr* state() const { return m_state; } + expr_ref const& state() const { return m_state; } ptr_vector const& children() { return m_children; } pred_transformer& pt() const { return m_pt; } model_node* parent() const { return m_parent; } @@ -231,8 +237,9 @@ namespace pdr { return true; } + void check_pre_closed(); void set_closed(); - void reopen(); + void set_open(); void set_pre_closed() { m_closed = true; } void reset() { m_children.reset(); } @@ -242,36 +249,45 @@ namespace pdr { void mk_instantiate(datalog::rule_ref& r0, datalog::rule_ref& r1, expr_ref_vector& binding); std::ostream& display(std::ostream& out, unsigned indent); + + void dequeue(model_node*& root); + void enqueue(model_node* n); + model_node* next() const { return m_next; } + bool is_goal() const { return 0 != next(); } }; class model_search { typedef ptr_vector model_nodes; bool m_bfs; model_node* m_root; - std::deque m_leaves; + model_node* m_goal; vector > m_cache; obj_map& cache(model_node const& n); void erase_children(model_node& n, bool backtrack); - void erase_leaf(model_node& n); void remove_node(model_node& n, bool backtrack); - void enqueue_leaf(model_node& n); // add leaf to priority queue. + void enqueue_leaf(model_node* n); // add leaf to priority queue. void update_models(); + void set_leaf(model_node& n); // Set node as leaf, remove children. + bool is_repeated(model_node& n) const; + unsigned num_goals() const; + public: - model_search(bool bfs): m_bfs(bfs), m_root(0) {} + model_search(bool bfs): m_bfs(bfs), m_root(0), m_goal(0) {} ~model_search(); void reset(); model_node* next(); - bool is_repeated(model_node& n) const; void add_leaf(model_node& n); // add fresh node. - void set_leaf(model_node& n); // Set node as leaf, remove children. - + void set_root(model_node* n); model_node& get_root() const { return *m_root; } std::ostream& display(std::ostream& out) const; expr_ref get_trace(context const& ctx); proof_ref get_proof_trace(context const& ctx); void backtrack_level(bool uses_level, model_node& n); + void remove_goal(model_node& n); + + void well_formed(); }; struct model_exception { }; diff --git a/src/test/main.cpp b/src/test/main.cpp index d5608a7d4..7b01e35c1 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -224,6 +224,7 @@ int main(int argc, char ** argv) { TST(theory_pb); TST(simplex); TST(sat_user_scope); + TST(pdr); //TST_ARGV(hs); } diff --git a/src/test/pdr.cpp b/src/test/pdr.cpp new file mode 100644 index 000000000..82448e6f5 --- /dev/null +++ b/src/test/pdr.cpp @@ -0,0 +1,116 @@ +#include "pdr_context.h" +#include "reg_decl_plugins.h" + + +using namespace pdr; + +static expr_ref mk_state(expr_ref_vector const& states, random_gen& rand) { + expr_ref result(states.get_manager()); + result = states[rand(states.size())]; + return result; +} + + +struct test_model_search { + struct init_test { + init_test(func_decl_ref& fn) { + ast_manager& m = fn.get_manager(); + reg_decl_plugins(m); + fn = m.mk_const_decl(symbol("f"), m.mk_bool_sort()); + } + }; + + ast_manager m; + smt_params smt_params; + fixedpoint_params fp_params; + context ctx; + manager pm; + func_decl_ref fn; + init_test initt; + pred_transformer pt; + random_gen rand; + model_search search; + expr_ref_vector states; + + + test_model_search(): + ctx(smt_params, fp_params, m), + pm(smt_params, 10, m), + fn(m), + initt(fn), + pt(ctx, pm, fn), + rand(10), + search(true), + states(m) { + } + + void add_tree(model_node* parent, bool force_goal) { + unsigned level = parent->level(); + search.add_leaf(*parent); + if (level > 0 && (force_goal || parent->is_goal())) { + search.remove_goal(*parent); + add_tree(alloc(model_node, parent, mk_state(states, rand), pt, level-1), false); + add_tree(alloc(model_node, parent, mk_state(states, rand), pt, level-1), false); + parent->check_pre_closed(); + } + } + + bool mutate() { + model_node* leaf = search.next(); + if (!leaf) return false; + unsigned level = leaf->level(); + if (level == 0) { + if (rand(2) == 0) { + leaf->display(std::cout << "backtrack to grandparent\n", 1); + search.backtrack_level(false, *leaf->parent()); + } + else { + leaf->display(std::cout << "backtrack to parent\n", 1); + search.backtrack_level(false, *leaf); + } + } + else { + leaf->display(std::cout << "grow tree\n", 1); + add_tree(leaf, true); + } + return true; + } + + void init() { + std::cout << "pdr state-hash search tree\n"; + + expr_ref state(m); + func_decl_ref fn(m); + for (unsigned i = 0; i < 10; ++i) { + std::ostringstream strm; + strm << "s" << i; + state = m.mk_const(symbol(strm.str().c_str()), m.mk_bool_sort()); + fn = to_app(state)->get_decl(); + states.push_back(state); + } + state = states[0].get(); + unsigned level = 4; + for(unsigned n = 0; n < 100; ++n) { + model_node* root = alloc(model_node, 0, mk_state(states, rand), pt, level); + search.set_root(root); + add_tree(root, false); + search.display(std::cout); + + while (true) { + search.well_formed(); + if (!mutate()) break; + search.display(std::cout); + } + search.reset(); + //++level; + } + search.reset(); + } + +}; + +void tst_pdr() { + test_model_search test; + + test.init(); +} From fc36d861a7e451cc1793242b8e0d8eb719c8aaad Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 1 Apr 2015 19:32:50 -0700 Subject: [PATCH 726/925] update default to maxres for MaxSAT, reset pareto and box state on every constraint update Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 16 +++++++++++----- src/opt/opt_context.h | 1 + src/opt/opt_params.pyg | 2 +- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 6718f401e..0503fa664 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -154,7 +154,7 @@ namespace opt { for (unsigned i = 0; i < n; ++i) { m_scoped_state.pop(); } - m_model.reset(); + clear_state(); reset_maxsmts(); m_optsmt.reset(); m_hard_constraints.reset(); @@ -162,21 +162,21 @@ namespace opt { void context::set_hard_constraints(ptr_vector& fmls) { m_scoped_state.set(fmls); - m_model.reset(); + clear_state(); } void context::add_hard_constraint(expr* f) { m_scoped_state.add(f); - m_model.reset(); + clear_state(); } unsigned context::add_soft_constraint(expr* f, rational const& w, symbol const& id) { - m_model.reset(); + clear_state(); return m_scoped_state.add(f, w, id); } unsigned context::add_objective(app* t, bool is_max) { - m_model.reset(); + clear_state(); return m_scoped_state.add(t, is_max); } @@ -1122,6 +1122,12 @@ namespace opt { } } + void context::clear_state() { + set_pareto(0); + m_box_index = UINT_MAX; + m_model.reset(); + } + void context::set_pareto(pareto_base* p) { #pragma omp critical (opt_context) { diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 0815e0061..1b5671113 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -271,6 +271,7 @@ namespace opt { void add_maxsmt(symbol const& id); void set_simplify(tactic *simplify); void set_pareto(pareto_base* p); + void clear_state(); bool is_numeral(expr* e, rational& n) const; diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index 059ac0bd2..13049986a 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -3,7 +3,7 @@ def_module_params('opt', export=True, params=(('timeout', UINT, UINT_MAX, 'set timeout'), ('optsmt_engine', SYMBOL, 'basic', "select optimization engine: 'basic', 'farkas', 'symba'"), - ('maxsat_engine', SYMBOL, 'wmax', "select engine for maxsat: 'fu_malik', 'core_maxsat', 'wmax', 'pbmax', 'maxres', 'pd-maxres', 'bcd2', 'wpm2', 'sls', 'maxhs'"), + ('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'fu_malik', 'core_maxsat', 'wmax', 'pbmax', 'maxres', 'pd-maxres', 'bcd2', 'wpm2', 'sls', 'maxhs'"), ('priority', SYMBOL, 'lex', "select how to priortize objectives: 'lex' (lexicographic), 'pareto', or 'box'"), ('dump_benchmarks', BOOL, False, 'dump benchmarks for profiling'), ('print_model', BOOL, False, 'display model for satisfiable constraints'), From e944f89505748a4d685491f039741a12857d0995 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Apr 2015 02:36:01 -0700 Subject: [PATCH 727/925] fix bug introduced when clearing state between calls to Pareto/Box Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 14 +++++++++++--- src/opt/opt_context.h | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 0503fa664..11ea9c93b 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -75,9 +75,14 @@ namespace opt { m_hard.push_back(hard); } - void context::scoped_state::set(ptr_vector & hard) { + bool context::scoped_state::set(ptr_vector & hard) { + bool eq = hard.size() == m_hard.size(); + for (unsigned i = 0; eq && i < hard.size(); ++i) { + eq = hard[i] == m_hard[i].get(); + } m_hard.reset(); m_hard.append(hard.size(), hard.c_ptr()); + return !eq; } unsigned context::scoped_state::add(expr* f, rational const& w, symbol const& id) { @@ -161,8 +166,9 @@ namespace opt { } void context::set_hard_constraints(ptr_vector& fmls) { - m_scoped_state.set(fmls); - clear_state(); + if (m_scoped_state.set(fmls)) { + clear_state(); + } } void context::add_hard_constraint(expr* f) { @@ -203,6 +209,7 @@ namespace opt { if (m_box_index != UINT_MAX) { return execute_box(); } + clear_state(); init_solver(); import_scoped_state(); normalize(); @@ -327,6 +334,7 @@ namespace opt { return l_false; } m_box_index = 1; + m_box_models.reset(); lbool r = m_optsmt.box(); for (unsigned i = 0, j = 0; r == l_true && i < m_objectives.size(); ++i) { objective const& obj = m_objectives[i]; diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 1b5671113..59868dd1e 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -131,7 +131,7 @@ namespace opt { void push(); void pop(); void add(expr* hard); - void set(ptr_vector & hard); + bool set(ptr_vector & hard); unsigned add(expr* soft, rational const& weight, symbol const& id); unsigned add(app* obj, bool is_max); }; From 6b995c4077b959f02ebae5f0fdb31b69ab30d284 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Apr 2015 02:56:40 -0700 Subject: [PATCH 728/925] disable wrong fix for simplification Signed-off-by: Nikolaj Bjorner --- src/smt/asserted_formulas.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index faf5ce0ef..1acfcdf57 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -603,7 +603,7 @@ void asserted_formulas::propagate_values() { proof_ref_vector new_prs1(m_manager); expr_ref_vector new_exprs2(m_manager); proof_ref_vector new_prs2(m_manager); - unsigned i = 0; + unsigned i = m_asserted_qhead; unsigned sz = m_asserted_formulas.size(); for (; i < sz; i++) { expr * n = m_asserted_formulas.get(i); From dca0fb77c2a7d66c31adc7b9ceab2203ca8277af Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Apr 2015 15:22:32 -0700 Subject: [PATCH 729/925] use same defaults as unstable branch for difference logic configuration Signed-off-by: Nikolaj Bjorner --- src/smt/smt_setup.cpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 13259ed0e..800bcaaed 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -362,9 +362,6 @@ namespace smt { m_context.register_plugin(alloc(smt::theory_dense_i, m_manager, m_params)); } - else if (!m_params.m_arith_auto_config_simplex && !is_dense(st)) { - m_context.register_plugin(alloc(smt::theory_idl, m_manager, m_params)); - } else { // if (st.m_arith_k_sum < rational(INT_MAX / 8)) { // TRACE("setup", tout << "using small integer simplex...\n";); @@ -416,15 +413,6 @@ namespace smt { return; } } -#if 0 - switch (m_params.m_arith_mode) { - case AS_DIFF_LOGIC: - case AS_DENSE_DIFF_LOGIC: - case AS_UTVPI: - setup_arith(); - return; - } -#endif m_params.m_arith_eq_bounds = true; m_params.m_phase_selection = PS_ALWAYS_FALSE; m_params.m_restart_strategy = RS_GEOMETRIC; From bd162588b28c1ca38980bfd0df040539df176370 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Apr 2015 17:09:01 -0700 Subject: [PATCH 730/925] enable SAT solver by default for MaxSAT constraints Signed-off-by: Nikolaj Bjorner --- src/opt/opt_params.pyg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index 13049986a..ef92af54b 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -8,7 +8,7 @@ def_module_params('opt', ('dump_benchmarks', BOOL, False, 'dump benchmarks for profiling'), ('print_model', BOOL, False, 'display model for satisfiable constraints'), ('enable_sls', BOOL, False, 'enable SLS tuning during weighted maxsast'), - ('enable_sat', BOOL, False, 'enable the new SAT core for propositional constraints'), + ('enable_sat', BOOL, True, 'enable the new SAT core for propositional constraints'), ('elim_01', BOOL, True, 'eliminate 01 variables'), ('pp.neat', BOOL, True, 'use neat (as opposed to less readable, but faster) pretty printer when displaying context'), ('pb.compile_equality', BOOL, False, 'compile arithmetical equalities into pseudo-Boolean equality (instead of two inequalites)'), From ffc3a36dcba6609f221d458cbf470506c741533e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 23 Apr 2015 19:59:33 +0200 Subject: [PATCH 731/925] checked ite-expressions as shared for bounds detection Signed-off-by: Nikolaj Bjorner --- src/muz/rel/dl_product_relation.cpp | 25 ++- src/smt/smt_context.cpp | 6 +- src/smt/theory_arith.h | 6 +- src/smt/theory_arith_aux.h | 242 ++-------------------------- 4 files changed, 35 insertions(+), 244 deletions(-) diff --git a/src/muz/rel/dl_product_relation.cpp b/src/muz/rel/dl_product_relation.cpp index b66e4d47d..f1dbc589c 100644 --- a/src/muz/rel/dl_product_relation.cpp +++ b/src/muz/rel/dl_product_relation.cpp @@ -956,20 +956,17 @@ namespace datalog { void product_relation::ensure_correct_kind() { unsigned rel_cnt = m_relations.size(); //the rel_cnt==0 part makes us to update the kind also when the relation is newly created - bool spec_changed = rel_cnt!=m_spec.size() || rel_cnt==0; - if(spec_changed) { + bool spec_changed = rel_cnt != m_spec.size() || rel_cnt==0; + if (spec_changed) { m_spec.resize(rel_cnt); } - for(unsigned i=0;iget_kind(); - if(spec_changed || m_spec[i]!=rkind) { - spec_changed = true; - m_spec[i]=rkind; - } + for (unsigned i = 0; i < rel_cnt; i++) { + family_id rkind = m_relations[i]->get_kind(); + spec_changed |= (m_spec[i] != rkind); + m_spec[i] = rkind; } - if(spec_changed) { - family_id new_kind = get_plugin().get_relation_kind(*this); - set_kind(new_kind); + if (spec_changed) { + set_kind(get_plugin().get_relation_kind(*this)); } } @@ -978,7 +975,7 @@ namespace datalog { func_decl* p = 0; const relation_signature & sig = get_signature(); family_id new_kind = get_plugin().get_relation_kind(sig, spec); - if(new_kind==get_kind()) { + if(new_kind == get_kind()) { return; } @@ -1001,7 +998,7 @@ namespace datalog { } } if(!irel) { - if(old_sz==0 && m_default_empty) { + if(old_sz == 0 && m_default_empty) { //The relation didn't contain any inner relations but it was empty, //so we make the newly added relations empty as well. irel = get_manager().mk_empty_relation(sig, new_kind); @@ -1018,7 +1015,7 @@ namespace datalog { set_kind(new_kind); DEBUG_CODE( ensure_correct_kind(); - SASSERT(get_kind()==new_kind); + SASSERT(get_kind() == new_kind); ); } diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 28f24e646..36311af7e 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3879,9 +3879,13 @@ namespace smt { bool context::is_shared(enode * n) const { n = n->get_root(); unsigned num_th_vars = n->get_num_th_vars(); + if (m_manager.is_ite(n->get_owner())) { + return true; + } switch (num_th_vars) { - case 0: + case 0: { return false; + } case 1: { if (m_qmanager->is_shared(n)) return true; diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index a81be26f6..826d95ef0 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -879,22 +879,20 @@ namespace smt { void add_tmp_row(row & r1, numeral const & coeff, row const & r2); theory_var pick_var_to_leave(bool has_int, theory_var x_j, bool inc, numeral & a_ij, inf_numeral & gain, bool& skiped_row); bool is_safe_to_leave(theory_var x, bool inc, bool& has_int, bool& is_shared); - bool move_to_bound(theory_var x_i, bool inc); template void add_tmp_row_entry(row & r, numeral const & coeff, theory_var v); enum max_min_t { UNBOUNDED, AT_BOUND, OPTIMIZED, BEST_EFFORT}; max_min_t max_min(theory_var v, bool max, bool& has_shared); - max_min_t max_min_orig(row & r, bool max, bool& has_shared); bool max_min(svector const & vars); - max_min_t max_min_new(row& r, bool max, bool& has_shared); + max_min_t max_min(row& r, bool max, bool& has_shared); bool unbounded_gain(inf_numeral const & max_gain) const; bool safe_gain(inf_numeral const& min_gain, inf_numeral const & max_gain) const; void normalize_gain(numeral const& divisor, inf_numeral & max_gain) const; void init_gains(theory_var x, bool inc, inf_numeral& min_gain, inf_numeral& max_gain); bool update_gains(bool inc, theory_var x_i, numeral const& a_ij, inf_numeral& min_gain, inf_numeral& max_gain); - bool move_to_bound_new(theory_var x_i, bool inc, unsigned& best_efforts, bool& has_shared); + bool move_to_bound(theory_var x_i, bool inc, unsigned& best_efforts, bool& has_shared); bool pick_var_to_leave( theory_var x_j, bool inc, numeral & a_ij, inf_numeral& min_gain, inf_numeral& max_gain, diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index b0b57d256..d1f7abcbc 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -961,6 +961,7 @@ namespace smt { bool theory_arith::is_safe_to_leave(theory_var x, bool inc, bool& has_int, bool& shared) { context& ctx = get_context(); + ast_manager& m = get_manager(); shared |= ctx.is_shared(get_enode(x)); column & c = m_columns[x]; typename svector::iterator it = c.begin_entries(); @@ -1355,154 +1356,6 @@ namespace smt { } - /** - \brief Maximize (Minimize) the given temporary row. - Return true if succeeded. - */ - template - typename theory_arith::max_min_t theory_arith::max_min_orig(row & r, bool max, bool& has_shared) { - m_stats.m_max_min++; - bool skipped_row = false; - has_shared = false; - - SASSERT(valid_assignment()); - - - theory_var x_i = null_theory_var; - theory_var x_j = null_theory_var; - bool inc = false; - numeral a_ij, curr_a_ij, coeff, curr_coeff; - inf_numeral gain, curr_gain; -#ifdef _TRACE - unsigned i = 0; -#endif - max_min_t result; - while (true) { - x_j = null_theory_var; - x_i = null_theory_var; - gain.reset(); - TRACE("opt", tout << "i: " << i << ", max: " << max << "\n"; display_row(tout, r, true); tout << "state:\n"; display(tout); i++;); - typename vector::const_iterator it = r.begin_entries(); - typename vector::const_iterator end = r.end_entries(); - for (; it != end; ++it) { - if (!it->is_dead()) { - theory_var curr_x_j = it->m_var; - SASSERT(is_non_base(curr_x_j)); - curr_coeff = it->m_coeff; - bool curr_inc = curr_coeff.is_pos() ? max : !max; - bool has_int = false; - if ((curr_inc && at_upper(curr_x_j)) || (!curr_inc && at_lower(curr_x_j))) - continue; // variable cannot be used for max/min. - if (!is_safe_to_leave(curr_x_j, curr_inc, has_int, has_shared)) { - skipped_row = true; - continue; - } - theory_var curr_x_i = pick_var_to_leave(has_int, curr_x_j, curr_inc, curr_a_ij, curr_gain, skipped_row); - if (curr_x_i == null_theory_var) { - TRACE("opt", tout << "unbounded\n";); - // we can increase/decrease curr_x_j as much as we want. - x_i = null_theory_var; // unbounded - x_j = curr_x_j; - inc = curr_inc; - break; - } - else if (curr_gain > gain) { - x_i = curr_x_i; - x_j = curr_x_j; - a_ij = curr_a_ij; - coeff = curr_coeff; - gain = curr_gain; - inc = curr_inc; - } - else if (curr_gain.is_zero() && (x_i == null_theory_var || curr_x_i < x_i)) { - x_i = curr_x_i; - x_j = curr_x_j; - a_ij = curr_a_ij; - coeff = curr_coeff; - gain = curr_gain; - inc = curr_inc; - // continue - } - } - } - TRACE("opt", tout << "after traversing row:\nx_i: v" << x_i << ", x_j: v" << x_j << ", gain: " << gain << "\n"; - tout << "skipped row: " << (skipped_row?"yes":"no") << "\n"; - display(tout);); - - if (x_j == null_theory_var) { - TRACE("opt", tout << "row is " << (max ? "maximized" : "minimized") << "\n";); - SASSERT(valid_assignment()); - result = skipped_row?BEST_EFFORT:OPTIMIZED; - break; - } - - if (x_i == null_theory_var) { - // can increase/decrease x_j as much as we want. - if (inc && upper(x_j) && !skipped_row) { - update_value(x_j, upper_bound(x_j) - get_value(x_j)); - TRACE("opt", tout << "moved v" << x_j << " to upper bound\n";); - SASSERT(valid_assignment()); - continue; - } - if (!inc && lower(x_j) && !skipped_row) { - update_value(x_j, lower_bound(x_j) - get_value(x_j)); - TRACE("opt", tout << "moved v" << x_j << " to lower bound\n";); - SASSERT(valid_assignment()); - continue; - } - result = skipped_row?BEST_EFFORT:UNBOUNDED; - break; - } - - if (!is_fixed(x_j) && is_bounded(x_j) && !skipped_row && (upper_bound(x_j) - lower_bound(x_j) <= gain)) { - // can increase/decrease x_j up to upper/lower bound. - if (inc) { - update_value(x_j, upper_bound(x_j) - get_value(x_j)); - TRACE("opt", tout << "moved v" << x_j << " to upper bound\n";); - } - else { - update_value(x_j, lower_bound(x_j) - get_value(x_j)); - TRACE("opt", tout << "moved v" << x_j << " to lower bound\n";); - } - SASSERT(valid_assignment()); - continue; - } - - TRACE("opt", tout << "max: " << max << ", x_i: v" << x_i << ", x_j: v" << x_j << ", a_ij: " << a_ij << ", coeff: " << coeff << "\n"; - if (upper(x_i)) tout << "upper x_i: " << upper_bound(x_i) << " "; - if (lower(x_i)) tout << "lower x_i: " << lower_bound(x_i) << " "; - tout << "value x_i: " << get_value(x_i) << "\n"; - if (upper(x_j)) tout << "upper x_j: " << upper_bound(x_j) << " "; - if (lower(x_j)) tout << "lower x_j: " << lower_bound(x_j) << " "; - tout << "value x_j: " << get_value(x_j) << "\n"; - ); - pivot(x_i, x_j, a_ij, false); - - - SASSERT(is_non_base(x_i)); - SASSERT(is_base(x_j)); - - bool move_xi_to_lower; - if (inc) - move_xi_to_lower = a_ij.is_pos(); - else - move_xi_to_lower = a_ij.is_neg(); - if (!move_to_bound(x_i, move_xi_to_lower)) { - result = BEST_EFFORT; - break; - } - - row & r2 = m_rows[get_var_row(x_j)]; - coeff.neg(); - add_tmp_row(r, coeff, r2); - SASSERT(r.get_idx_of(x_j) == -1); - SASSERT(valid_assignment()); - } - TRACE("opt", display(tout);); - return result; - } - - /** \brief Select tightest variable x_i to pivot with x_j. The goal is to select a x_i such that the value of x_j is increased @@ -1698,13 +1551,14 @@ namespace smt { Return true if succeeded. */ template - typename theory_arith::max_min_t theory_arith::max_min_new( + typename theory_arith::max_min_t theory_arith::max_min( row & r, bool max, bool& has_shared) { m_stats.m_max_min++; unsigned best_efforts = 0; bool inc = false; + context& ctx = get_context(); SASSERT(valid_assignment()); @@ -1715,7 +1569,7 @@ namespace smt { #endif max_min_t result = OPTIMIZED; has_shared = false; - unsigned max_efforts = 10 + (get_context().get_random_value() % 20); + unsigned max_efforts = 10 + (ctx.get_random_value() % 20); while (best_efforts < max_efforts) { theory_var x_j = null_theory_var; theory_var x_i = null_theory_var; @@ -1806,8 +1660,13 @@ namespace smt { SASSERT(valid_assignment()); continue; } - SASSERT(unbounded_gain(max_gain)); - best_efforts = 0; + if (ctx.is_shared(get_enode(x_j))) { + ++best_efforts; + } + else { + SASSERT(unbounded_gain(max_gain)); + best_efforts = 0; + } result = UNBOUNDED; break; } @@ -1841,8 +1700,10 @@ namespace smt { SASSERT(is_base(x_j)); bool inc_xi = inc?a_ij.is_neg():a_ij.is_pos(); - if (!move_to_bound_new(x_i, inc_xi, best_efforts, has_shared)) { - // break; + if (!move_to_bound(x_i, inc_xi, best_efforts, has_shared)) { + TRACE("opt", tout << "can't move bound fully\n";); + // break; // break; + } row & r2 = m_rows[get_var_row(x_j)]; @@ -1863,7 +1724,7 @@ namespace smt { */ template - bool theory_arith::move_to_bound_new( + bool theory_arith::move_to_bound( theory_var x_i, // variable to move bool inc, // increment variable or decrement unsigned& best_efforts, // is bound move a best effort? @@ -1900,75 +1761,6 @@ namespace smt { return result; } - /** - Move the variable x_i maximally towards its bound as long as - bounds of other variables are not violated. - Returns false if an integer bound was truncated and no - progress was made. - */ - - template - bool theory_arith::move_to_bound(theory_var x_i, bool move_to_lower) { - inf_numeral delta, delta_abs; - numeral lc(1); - - if (move_to_lower) { - delta = lower_bound(x_i) - get_value(x_i); - SASSERT(!delta.is_pos()); - } - else { - delta = upper_bound(x_i) - get_value(x_i); - SASSERT(!delta.is_neg()); - } - - TRACE("opt", tout << "Original delta: " << delta << "\n";); - - delta_abs = abs(delta); - // - // Decrease absolute value of delta according to bounds on rows where x_i is used. - // - column & c = m_columns[x_i]; - typename svector::iterator it = c.begin_entries(); - typename svector::iterator end = c.end_entries(); - for (; it != end && delta_abs.is_pos(); ++it) { - if (it->is_dead()) continue; - row & r = m_rows[it->m_row_id]; - theory_var s = r.get_base_var(); - if (s != null_theory_var && !is_quasi_base(s)) { - numeral const & coeff = r[it->m_row_idx].m_coeff; - SASSERT(!coeff.is_zero()); - bool inc_s = coeff.is_pos() ? move_to_lower : !move_to_lower; // NSB: review this.. - bound * b = get_bound(s, inc_s); - if (b) { - inf_numeral delta2 = abs((get_value(s) - b->get_value())/coeff); - if (delta2 < delta_abs) { - delta_abs = delta2; - } - } - if (is_int(x_i)) { - lc = lcm(lc, denominator(abs(coeff))); - } - } - } - - bool truncated = false; - if (is_int(x_i)) { - inf_numeral tmp = delta_abs/lc; - truncated = !tmp.is_int(); - delta_abs = lc*floor(tmp); - } - - if (move_to_lower) { - delta = -delta_abs; - } - else { - delta = delta_abs; - } - - TRACE("opt", tout << "Safe delta: " << delta << "\n";); - update_value(x_i, delta); - return !truncated || !delta.is_zero(); - } /** \brief Add an entry to a temporary row. @@ -2012,7 +1804,7 @@ namespace smt { add_tmp_row_entry(m_tmp_row, it->m_coeff, it->m_var); } } - max_min_t r = max_min_new(m_tmp_row, max, has_shared); + max_min_t r = max_min(m_tmp_row, max, has_shared); if (r == OPTIMIZED) { TRACE("opt", tout << mk_pp(e, get_manager()) << " " << (max ? "max" : "min") << " value is: " << get_value(v) << "\n"; display_row(tout, m_tmp_row, true); display_row_info(tout, m_tmp_row);); From b58d3f4335714ad32c323bd0f84b394940636ea9 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 25 Apr 2015 14:26:18 +0100 Subject: [PATCH 732/925] Bugfix for MPF unpacking --- src/util/mpf.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index c96ba594e..9de56773a 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -1475,6 +1475,9 @@ void mpf_manager::mk_ninf(unsigned ebits, unsigned sbits, mpf & o) { void mpf_manager::unpack(mpf & o, bool normalize) { // Insert the hidden bit or adjust the exponent of denormal numbers. + if (is_zero(o)) + return; + if (is_normal(o)) m_mpz_manager.add(o.significand, m_powers2(o.sbits-1), o.significand); else { From 4768a360f8428a2b880928de7016176efa2432dd Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 25 Apr 2015 15:01:20 +0100 Subject: [PATCH 733/925] FP: Fix for conversion functions from non-FP 0 to +0.0 even when the rounding mode is ToNegative. --- src/ast/fpa/fpa2bv_converter.cpp | 195 +++++++++++++++++-------------- 1 file changed, 106 insertions(+), 89 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 69b661589..932451ff5 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -2096,79 +2096,89 @@ void fpa2bv_converter::mk_to_fp_real(func_decl * f, sort * s, expr * rm, expr * bool is_int; m_util.au().is_numeral(x, q, is_int); - scoped_mpf v(m_mpf_manager); - m_util.fm().set(v, ebits, sbits, rm, q.to_mpq()); + if (q.is_zero()) + return mk_pzero(f, result); + else { + scoped_mpf v(m_mpf_manager); + m_util.fm().set(v, ebits, sbits, rm, q.to_mpq()); - expr_ref sgn(m), s(m), e(m), unbiased_exp(m); - sgn = m_bv_util.mk_numeral((m_util.fm().sgn(v)) ? 1 : 0, 1); - s = m_bv_util.mk_numeral(m_util.fm().sig(v), sbits - 1); - unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v), ebits); - mk_bias(unbiased_exp, e); - mk_fp(sgn, e, s, result); + + expr_ref sgn(m), s(m), e(m), unbiased_exp(m); + sgn = m_bv_util.mk_numeral((m_util.fm().sgn(v)) ? 1 : 0, 1); + s = m_bv_util.mk_numeral(m_util.fm().sig(v), sbits - 1); + unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v), ebits); + mk_bias(unbiased_exp, e); + + mk_fp(sgn, e, s, result); + } } else if (m_util.au().is_numeral(x)) { rational q; bool is_int; m_util.au().is_numeral(x, q, is_int); - expr_ref rm_nta(m), rm_nte(m), rm_tp(m), rm_tn(m), rm_tz(m); - mk_is_rm(rm, BV_RM_TIES_TO_AWAY, rm_nta); - mk_is_rm(rm, BV_RM_TIES_TO_EVEN, rm_nte); - mk_is_rm(rm, BV_RM_TO_POSITIVE, rm_tp); - mk_is_rm(rm, BV_RM_TO_NEGATIVE, rm_tn); - mk_is_rm(rm, BV_RM_TO_ZERO, rm_tz); + if (m_util.au().is_zero(x)) + mk_pzero(f, result); + else { + expr_ref rm_nta(m), rm_nte(m), rm_tp(m), rm_tn(m), rm_tz(m); + mk_is_rm(rm, BV_RM_TIES_TO_AWAY, rm_nta); + mk_is_rm(rm, BV_RM_TIES_TO_EVEN, rm_nte); + mk_is_rm(rm, BV_RM_TO_POSITIVE, rm_tp); + mk_is_rm(rm, BV_RM_TO_NEGATIVE, rm_tn); + mk_is_rm(rm, BV_RM_TO_ZERO, rm_tz); - scoped_mpf v_nta(m_mpf_manager), v_nte(m_mpf_manager), v_tp(m_mpf_manager); - scoped_mpf v_tn(m_mpf_manager), v_tz(m_mpf_manager); - m_util.fm().set(v_nta, ebits, sbits, MPF_ROUND_NEAREST_TAWAY, q.to_mpq()); - m_util.fm().set(v_nte, ebits, sbits, MPF_ROUND_NEAREST_TEVEN, q.to_mpq()); - m_util.fm().set(v_tp, ebits, sbits, MPF_ROUND_TOWARD_POSITIVE, q.to_mpq()); - m_util.fm().set(v_tn, ebits, sbits, MPF_ROUND_TOWARD_NEGATIVE, q.to_mpq()); - m_util.fm().set(v_tz, ebits, sbits, MPF_ROUND_TOWARD_ZERO, q.to_mpq()); + scoped_mpf v_nta(m_mpf_manager), v_nte(m_mpf_manager), v_tp(m_mpf_manager); + scoped_mpf v_tn(m_mpf_manager), v_tz(m_mpf_manager); + m_util.fm().set(v_nta, ebits, sbits, MPF_ROUND_NEAREST_TAWAY, q.to_mpq()); + m_util.fm().set(v_nte, ebits, sbits, MPF_ROUND_NEAREST_TEVEN, q.to_mpq()); + m_util.fm().set(v_tp, ebits, sbits, MPF_ROUND_TOWARD_POSITIVE, q.to_mpq()); + m_util.fm().set(v_tn, ebits, sbits, MPF_ROUND_TOWARD_NEGATIVE, q.to_mpq()); + m_util.fm().set(v_tz, ebits, sbits, MPF_ROUND_TOWARD_ZERO, q.to_mpq()); - expr_ref v1(m), v2(m), v3(m), v4(m); + expr_ref v1(m), v2(m), v3(m), v4(m); - expr_ref sgn(m), s(m), e(m), unbiased_exp(m); - sgn = m_bv_util.mk_numeral((m_util.fm().sgn(v_nta)) ? 1 : 0, 1); - s = m_bv_util.mk_numeral(m_util.fm().sig(v_nta), sbits - 1); - unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v_nta), ebits); - mk_bias(unbiased_exp, e); - mk_fp(sgn, e, s, v1); + expr_ref sgn(m), s(m), e(m), unbiased_exp(m); + sgn = m_bv_util.mk_numeral((m_util.fm().sgn(v_nta)) ? 1 : 0, 1); + s = m_bv_util.mk_numeral(m_util.fm().sig(v_nta), sbits - 1); + unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v_nta), ebits); + mk_bias(unbiased_exp, e); + mk_fp(sgn, e, s, v1); - sgn = m_bv_util.mk_numeral((m_util.fm().sgn(v_nte)) ? 1 : 0, 1); - s = m_bv_util.mk_numeral(m_util.fm().sig(v_nte), sbits - 1); - unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v_nte), ebits); - mk_bias(unbiased_exp, e); - mk_fp(sgn, e, s, v2); + sgn = m_bv_util.mk_numeral((m_util.fm().sgn(v_nte)) ? 1 : 0, 1); + s = m_bv_util.mk_numeral(m_util.fm().sig(v_nte), sbits - 1); + unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v_nte), ebits); + mk_bias(unbiased_exp, e); + mk_fp(sgn, e, s, v2); - sgn = m_bv_util.mk_numeral((m_util.fm().sgn(v_tp)) ? 1 : 0, 1); - s = m_bv_util.mk_numeral(m_util.fm().sig(v_tp), sbits - 1); - unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v_tp), ebits); - mk_bias(unbiased_exp, e); - mk_fp(sgn, e, s, v3); + sgn = m_bv_util.mk_numeral((m_util.fm().sgn(v_tp)) ? 1 : 0, 1); + s = m_bv_util.mk_numeral(m_util.fm().sig(v_tp), sbits - 1); + unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v_tp), ebits); + mk_bias(unbiased_exp, e); + mk_fp(sgn, e, s, v3); - sgn = m_bv_util.mk_numeral((m_util.fm().sgn(v_tn)) ? 1 : 0, 1); - s = m_bv_util.mk_numeral(m_util.fm().sig(v_tn), sbits - 1); - unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v_tn), ebits); - mk_bias(unbiased_exp, e); - mk_fp(sgn, e, s, v4); + sgn = m_bv_util.mk_numeral((m_util.fm().sgn(v_tn)) ? 1 : 0, 1); + s = m_bv_util.mk_numeral(m_util.fm().sig(v_tn), sbits - 1); + unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v_tn), ebits); + mk_bias(unbiased_exp, e); + mk_fp(sgn, e, s, v4); - sgn = m_bv_util.mk_numeral((m_util.fm().sgn(v_tp)) ? 1 : 0, 1); - s = m_bv_util.mk_numeral(m_util.fm().sig(v_tp), sbits - 1); - unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v_tp), ebits); - mk_bias(unbiased_exp, e); - - mk_fp(sgn, e, s, result); - mk_ite(rm_tn, v4, result, result); - mk_ite(rm_tp, v3, result, result); - mk_ite(rm_nte, v2, result, result); - mk_ite(rm_nta, v1, result, result); + sgn = m_bv_util.mk_numeral((m_util.fm().sgn(v_tp)) ? 1 : 0, 1); + s = m_bv_util.mk_numeral(m_util.fm().sig(v_tp), sbits - 1); + unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v_tp), ebits); + mk_bias(unbiased_exp, e); + + mk_fp(sgn, e, s, result); + mk_ite(rm_tn, v4, result, result); + mk_ite(rm_tp, v3, result, result); + mk_ite(rm_nte, v2, result, result); + mk_ite(rm_nta, v1, result, result); + } } else { bv_util & bu = m_bv_util; arith_util & au = m_arith_util; - + expr_ref bv0(m), bv1(m), zero(m), two(m); bv0 = bu.mk_numeral(0, 1); bv1 = bu.mk_numeral(1, 1); @@ -2182,6 +2192,10 @@ void fpa2bv_converter::mk_to_fp_real(func_decl * f, sort * s, expr * rm, expr * expr_ref rme(rm, m); round(s, rme, sgn, sig, exp, result); + + expr_ref c0(m); + mk_is_zero(x, c0); + mk_ite(c0, x, result, result); expr * e = m.mk_eq(m_util.mk_to_real(result), x); m_extra_assertions.push_back(e); @@ -2209,38 +2223,43 @@ void fpa2bv_converter::mk_to_fp_real_int(func_decl * f, unsigned num, expr * con SASSERT(e.is_int64()); SASSERT(m_mpz_manager.eq(e.to_mpq().denominator(), 1)); - scoped_mpf nte(m_mpf_manager), nta(m_mpf_manager), tp(m_mpf_manager), tn(m_mpf_manager), tz(m_mpf_manager); - m_mpf_manager.set(nte, ebits, sbits, MPF_ROUND_NEAREST_TEVEN, q.to_mpq(), e.to_mpq().numerator()); - m_mpf_manager.set(nta, ebits, sbits, MPF_ROUND_NEAREST_TAWAY, q.to_mpq(), e.to_mpq().numerator()); - m_mpf_manager.set(tp, ebits, sbits, MPF_ROUND_TOWARD_POSITIVE, q.to_mpq(), e.to_mpq().numerator()); - m_mpf_manager.set(tn, ebits, sbits, MPF_ROUND_TOWARD_NEGATIVE, q.to_mpq(), e.to_mpq().numerator()); - m_mpf_manager.set(tz, ebits, sbits, MPF_ROUND_TOWARD_ZERO, q.to_mpq(), e.to_mpq().numerator()); + if (q.is_zero()) + return mk_pzero(f, result); + else { + scoped_mpf nte(m_mpf_manager), nta(m_mpf_manager), tp(m_mpf_manager), tn(m_mpf_manager), tz(m_mpf_manager); + m_mpf_manager.set(nte, ebits, sbits, MPF_ROUND_NEAREST_TEVEN, q.to_mpq(), e.to_mpq().numerator()); + m_mpf_manager.set(nta, ebits, sbits, MPF_ROUND_NEAREST_TAWAY, q.to_mpq(), e.to_mpq().numerator()); + m_mpf_manager.set(tp, ebits, sbits, MPF_ROUND_TOWARD_POSITIVE, q.to_mpq(), e.to_mpq().numerator()); + m_mpf_manager.set(tn, ebits, sbits, MPF_ROUND_TOWARD_NEGATIVE, q.to_mpq(), e.to_mpq().numerator()); + m_mpf_manager.set(tz, ebits, sbits, MPF_ROUND_TOWARD_ZERO, q.to_mpq(), e.to_mpq().numerator()); - app_ref a_nte(m), a_nta(m), a_tp(m), a_tn(m), a_tz(m); - a_nte = m_plugin->mk_numeral(nte); - a_nta = m_plugin->mk_numeral(nta); - a_tp = m_plugin->mk_numeral(tp); - a_tn = m_plugin->mk_numeral(tn); - a_tz = m_plugin->mk_numeral(tz); + app_ref a_nte(m), a_nta(m), a_tp(m), a_tn(m), a_tz(m); + a_nte = m_plugin->mk_numeral(nte); + a_nta = m_plugin->mk_numeral(nta); + a_tp = m_plugin->mk_numeral(tp); + a_tn = m_plugin->mk_numeral(tn); + a_tz = m_plugin->mk_numeral(tz); - expr_ref bv_nte(m), bv_nta(m), bv_tp(m), bv_tn(m), bv_tz(m); - mk_numeral(a_nte->get_decl(), 0, 0, bv_nte); - mk_numeral(a_nta->get_decl(), 0, 0, bv_nta); - mk_numeral(a_tp->get_decl(), 0, 0, bv_tp); - mk_numeral(a_tn->get_decl(), 0, 0, bv_tn); - mk_numeral(a_tz->get_decl(), 0, 0, bv_tz); + expr_ref bv_nte(m), bv_nta(m), bv_tp(m), bv_tn(m), bv_tz(m); + mk_numeral(a_nte->get_decl(), 0, 0, bv_nte); + mk_numeral(a_nta->get_decl(), 0, 0, bv_nta); + mk_numeral(a_tp->get_decl(), 0, 0, bv_tp); + mk_numeral(a_tn->get_decl(), 0, 0, bv_tn); + mk_numeral(a_tz->get_decl(), 0, 0, bv_tz); - expr_ref c1(m), c2(m), c3(m), c4(m); - c1 = m.mk_eq(rm, m_bv_util.mk_numeral(BV_RM_TO_POSITIVE, 3)); - c2 = m.mk_eq(rm, m_bv_util.mk_numeral(BV_RM_TO_POSITIVE, 3)); - c3 = m.mk_eq(rm, m_bv_util.mk_numeral(BV_RM_TIES_TO_AWAY, 3)); - c4 = m.mk_eq(rm, m_bv_util.mk_numeral(BV_RM_TIES_TO_EVEN, 3)); + expr_ref c1(m), c2(m), c3(m), c4(m); + c1 = m.mk_eq(rm, m_bv_util.mk_numeral(BV_RM_TO_POSITIVE, 3)); + c2 = m.mk_eq(rm, m_bv_util.mk_numeral(BV_RM_TO_POSITIVE, 3)); + c3 = m.mk_eq(rm, m_bv_util.mk_numeral(BV_RM_TIES_TO_AWAY, 3)); + c4 = m.mk_eq(rm, m_bv_util.mk_numeral(BV_RM_TIES_TO_EVEN, 3)); - mk_ite(c1, bv_tn, bv_tz, result); - mk_ite(c2, bv_tp, result, result); - mk_ite(c3, bv_nta, result, result); - mk_ite(c4, bv_nte, result, result); + mk_ite(c1, bv_tn, bv_tz, result); + mk_ite(c2, bv_tp, result, result); + mk_ite(c3, bv_nta, result, result); + mk_ite(c4, bv_nte, result, result); + } } + void fpa2bv_converter::mk_to_real(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { TRACE("fpa2bv_to_real", for (unsigned i = 0; i < num; i++) tout << "arg" << i << " = " << mk_ismt2_pp(args[i], m) << std::endl;); @@ -2367,10 +2386,9 @@ void fpa2bv_converter::mk_to_fp_signed(func_decl * f, unsigned num, expr * const mk_pinf(f, pinf); // Special case: x == 0 -> p/n zero - expr_ref c1(m), v1(m), rm_is_to_neg(m); - c1 = is_zero; - mk_is_rm(rm, BV_RM_TO_NEGATIVE, rm_is_to_neg); - mk_ite(rm_is_to_neg, nzero, pzero, v1); + expr_ref c1(m), v1(m); + c1 = is_zero; + v1 = pzero; // Special case: x != 0 expr_ref is_neg_bit(m), exp_too_large(m), sig_4(m), exp_2(m); @@ -2508,10 +2526,9 @@ void fpa2bv_converter::mk_to_fp_unsigned(func_decl * f, unsigned num, expr * con mk_pinf(f, pinf); // Special case: x == 0 -> p/n zero - expr_ref c1(m), v1(m), rm_is_to_neg(m); + expr_ref c1(m), v1(m); c1 = is_zero; - mk_is_rm(rm, BV_RM_TO_NEGATIVE, rm_is_to_neg); - mk_ite(rm_is_to_neg, nzero, pzero, v1); + v1 = pzero; // Special case: x != 0 expr_ref exp_too_large(m), sig_4(m), exp_2(m); @@ -3182,7 +3199,7 @@ void fpa2bv_converter::unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref m_simp.mk_ite(m.mk_or(is_normal, is_sig_zero), zero_e, lz_d, lz); dbg_decouple("fpa2bv_unpack_lz", lz); - expr_ref shift(m); + expr_ref shift(m); m_simp.mk_ite(is_sig_zero, zero_e, lz, shift); dbg_decouple("fpa2bv_unpack_shift", shift); SASSERT(is_well_sorted(m, is_sig_zero)); From abe73db7028faa08dfcecc50be813344d94d58b5 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 25 Apr 2015 15:19:48 +0100 Subject: [PATCH 734/925] FP: bugfix for get_some_value which couldn't produce rounding-mode values. --- src/ast/fpa_decl_plugin.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/ast/fpa_decl_plugin.cpp b/src/ast/fpa_decl_plugin.cpp index 48b7adb8b..e559ee179 100644 --- a/src/ast/fpa_decl_plugin.cpp +++ b/src/ast/fpa_decl_plugin.cpp @@ -879,12 +879,20 @@ void fpa_decl_plugin::get_sort_names(svector & sort_names, symbol } expr * fpa_decl_plugin::get_some_value(sort * s) { - SASSERT(s->is_sort_of(m_family_id, FLOATING_POINT_SORT)); - mpf tmp; - m_fm.mk_nan(s->get_parameter(0).get_int(), s->get_parameter(1).get_int(), tmp); - expr * res = this->mk_numeral(tmp); - m_fm.del(tmp); - return res; + if (s->is_sort_of(m_family_id, FLOATING_POINT_SORT)) { + mpf tmp; + m_fm.mk_nan(s->get_parameter(0).get_int(), s->get_parameter(1).get_int(), tmp); + expr * res = mk_numeral(tmp); + m_fm.del(tmp); + return res; + } + else if (s->is_sort_of(m_family_id, ROUNDING_MODE_SORT)) { + func_decl * f = mk_rm_const_decl(OP_FPA_RM_TOWARD_ZERO, 0, 0, 0, 0, s); + return m_manager->mk_const(f); + } + + UNREACHABLE(); + return 0; } bool fpa_decl_plugin::is_value(app * e) const { From f7d9438e7b3270893af5711a7a2ab787f2d68307 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 27 Apr 2015 17:44:38 +0100 Subject: [PATCH 735/925] add failing test for issue #62 (mk_distinct doesnt type check) Signed-off-by: Nuno Lopes --- src/test/api.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/test/api.cpp b/src/test/api.cpp index a09371f01..6230528a1 100644 --- a/src/test/api.cpp +++ b/src/test/api.cpp @@ -447,9 +447,27 @@ void test_bvneg() { Z3_del_context(ctx); } +static bool cb_called = false; +static void my_cb(Z3_context, Z3_error_code) { + cb_called = true; +} + +static void test_mk_distinct() { + Z3_config cfg = Z3_mk_config(); + Z3_context ctx = Z3_mk_context(cfg); + Z3_set_error_handler(ctx, my_cb); + + Z3_sort bv8 = Z3_mk_bv_sort(ctx, 8); + Z3_sort bv32 = Z3_mk_bv_sort(ctx, 32); + Z3_ast args[] = { Z3_mk_int64(ctx, 0, bv8), Z3_mk_int64(ctx, 0, bv32) }; + Z3_mk_distinct(ctx, 2, args); + SASSERT(cb_called); +} + void tst_api() { test_apps(); test_bvneg(); + test_mk_distinct(); // bv_invariant(); } #else From 620c11932b10d5218069668c2ef766ffe7c6b84f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 27 Apr 2015 11:10:37 -0700 Subject: [PATCH 736/925] type check distinct operator. fixes #62 Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 11 +++++++++++ src/ast/ast.h | 2 +- src/test/api.cpp | 3 ++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 6780145d9..3a6275e33 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1043,6 +1043,13 @@ func_decl * basic_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters case OP_DISTINCT: { func_decl_info info(m_family_id, OP_DISTINCT); info.set_pairwise(); + for (unsigned i = 1; i < arity; i++) { + if (domain[i] != domain[0]) { + std::ostringstream buffer; + buffer << "Sort mismatch between first argument and argument " << (i+1); + throw ast_exception(buffer.str().c_str()); + } + } return m_manager->mk_func_decl(symbol("distinct"), arity, domain, m_bool_sort, info); } default: @@ -2338,6 +2345,10 @@ quantifier * ast_manager::update_quantifier(quantifier * q, bool is_forall, unsi num_patterns == 0 ? q->get_no_patterns() : 0); } +app * ast_manager::mk_distinct(unsigned num_args, expr * const * args) { + return mk_app(m_basic_family_id, OP_DISTINCT, num_args, args); +} + app * ast_manager::mk_distinct_expanded(unsigned num_args, expr * const * args) { if (num_args < 2) return mk_true(); diff --git a/src/ast/ast.h b/src/ast/ast.h index 93f456965..a5f5c286f 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -2000,7 +2000,7 @@ public: app * mk_and(expr * arg1, expr * arg2, expr * arg3) { return mk_app(m_basic_family_id, OP_AND, arg1, arg2, arg3); } app * mk_implies(expr * arg1, expr * arg2) { return mk_app(m_basic_family_id, OP_IMPLIES, arg1, arg2); } app * mk_not(expr * n) { return mk_app(m_basic_family_id, OP_NOT, n); } - app * mk_distinct(unsigned num_args, expr * const * args) { return mk_app(m_basic_family_id, OP_DISTINCT, num_args, args); } + app * mk_distinct(unsigned num_args, expr * const * args); app * mk_distinct_expanded(unsigned num_args, expr * const * args); app * mk_true() { return m_true; } app * mk_false() { return m_false; } diff --git a/src/test/api.cpp b/src/test/api.cpp index 6230528a1..234d1192c 100644 --- a/src/test/api.cpp +++ b/src/test/api.cpp @@ -460,8 +460,9 @@ static void test_mk_distinct() { Z3_sort bv8 = Z3_mk_bv_sort(ctx, 8); Z3_sort bv32 = Z3_mk_bv_sort(ctx, 32); Z3_ast args[] = { Z3_mk_int64(ctx, 0, bv8), Z3_mk_int64(ctx, 0, bv32) }; - Z3_mk_distinct(ctx, 2, args); + Z3_ast d = Z3_mk_distinct(ctx, 2, args); SASSERT(cb_called); + } void tst_api() { From 1abeb825a35a620ff27a409a8d09d676e1395d95 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 28 Apr 2015 14:58:58 +0100 Subject: [PATCH 737/925] Fixed python 3.x problems. Signed-off-by: Christoph M. Wintersteiger --- scripts/mk_win_dist.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/scripts/mk_win_dist.py b/scripts/mk_win_dist.py index 33d7a3eab..db4cc48e3 100644 --- a/scripts/mk_win_dist.py +++ b/scripts/mk_win_dist.py @@ -47,16 +47,16 @@ def set_build_dir(path): mk_dir(BUILD_X64_DIR) def display_help(): - print "mk_win_dist.py: Z3 Windows distribution generator\n" - print "This script generates the zip files containing executables, dlls, header files for Windows." - print "It must be executed from the Z3 root directory." - print "\nOptions:" - print " -h, --help display this message." - print " -s, --silent do not print verbose messages." - print " -b , --build= subdirectory where x86 and x64 Z3 versions will be built (default: build-dist)." - print " -f, --force force script to regenerate Makefiles." - print " --nojava do not include Java bindings in the binary distribution files." - print " --githash include git hash in the Zip file." + print("mk_win_dist.py: Z3 Windows distribution generator\n") + print("This script generates the zip files containing executables, dlls, header files for Windows.") + print("It must be executed from the Z3 root directory.") + print("\nOptions:") + print(" -h, --help display this message.") + print(" -s, --silent do not print verbose messages.") + print(" -b , --build= subdirectory where x86 and x64 Z3 versions will be built (default: build-dist).") + print(" -f, --force force script to regenerate Makefiles.") + print(" --nojava do not include Java bindings in the binary distribution files.") + print(" --githash include git hash in the Zip file.") exit(0) # Parse configuration option for mk_make script @@ -180,7 +180,7 @@ def mk_dist_dir_core(x64): mk_util.JAVA_ENABLED = JAVA_ENABLED mk_win_dist(build_path, dist_path) if is_verbose(): - print "Generated %s distribution folder at '%s'" % (platform, dist_path) + print("Generated %s distribution folder at '%s'") % (platform, dist_path) def mk_dist_dir(): mk_dist_dir_core(False) @@ -208,7 +208,7 @@ def mk_zip_core(x64): ZIPOUT = zipfile.ZipFile(zfname, 'w', zipfile.ZIP_DEFLATED) os.path.walk(dist_path, mk_zip_visitor, '*') if is_verbose(): - print "Generated '%s'" % zfname + print("Generated '%s'") % zfname except: pass ZIPOUT = None @@ -253,7 +253,7 @@ def cp_vs_runtime_core(x64): for f in VS_RUNTIME_FILES: shutil.copy(f, bin_dist_path) if is_verbose(): - print "Copied '%s' to '%s'" % (f, bin_dist_path) + print("Copied '%s' to '%s'") % (f, bin_dist_path) def cp_vs_runtime(): cp_vs_runtime_core(True) From a0f0b53686ac52ac9cc287671ab59c838836b831 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 28 Apr 2015 14:48:59 -0700 Subject: [PATCH 738/925] fixes to #52, #53 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 7 +++- src/opt/opt_solver.cpp | 53 +++++++++++++++++----------- src/opt/opt_solver.h | 3 +- src/opt/optsmt.cpp | 45 +++++++++++++++-------- src/opt/optsmt.h | 2 +- src/smt/params/smt_params_helper.pyg | 12 +++---- src/tactic/bv/bit_blaster_tactic.cpp | 3 +- 7 files changed, 80 insertions(+), 45 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 11ea9c93b..3cae51bc2 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -388,7 +388,6 @@ namespace opt { } break; case O_MAXSMT: { - m_opt_solver->ensure_pb(); pb_util pb(m); unsigned sz = obj.m_terms.size(); ptr_vector terms; @@ -475,6 +474,9 @@ namespace opt { m_opt_solver->set_logic(m_logic); m_solver = m_opt_solver.get(); } + if (opt_params(m_params).priority() == symbol("pareto")) { + m_opt_solver->ensure_pb(); + } } void context::setup_arith_solver() { @@ -497,6 +499,9 @@ namespace opt { m_maxsat_engine != symbol("sls")) { return; } + if (opt_params(m_params).priority() == symbol("pareto")) { + return; + } m_params.set_bool("minimize_core_partial", true); // false); m_params.set_bool("minimize_core", true); m_sat_solver = mk_inc_sat_solver(m, m_params); diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 4556cd080..4f268268d 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -204,38 +204,52 @@ namespace opt { m_valid_objectives[i] = true; TRACE("opt", tout << (has_shared?"has shared":"non-shared") << "\n";); if (m_context.get_context().update_model(has_shared)) { - if (has_shared) { - val2 = current_objective_value(i); - if (val2 != val) { - decrement_value(i, val); - } + if (has_shared && val != current_objective_value(i)) { + decrement_value(i, val); + } + else { + set_model(i); } } else { SASSERT(has_shared); - // model is not final. We set the current objective to - // close to the optimal (ignoring types). - decrement_value(i, val); + decrement_value(i, val); } m_objective_values[i] = val; + TRACE("opt", { tout << val << "\n"; + tout << blocker << "\n"; + model_smt2_pp(tout << "update model:\n", m, *m_models[i], 0); }); + } + void opt_solver::set_model(unsigned i) { model_ref mdl; get_model(mdl); m_models.set(i, mdl.get()); - - TRACE("opt", { tout << m_objective_values[i] << "\n"; - tout << blocker << "\n"; - model_smt2_pp(tout << "update model:\n", m, *mdl, 0); }); } - void opt_solver::decrement_value(unsigned i, inf_eps& val) { - if (arith_util(m).is_real(m_objective_sorts[i].get())) { - val -= inf_eps(inf_rational(rational(0),true)); + lbool opt_solver::decrement_value(unsigned i, inf_eps& val) { + push_core(); + expr_ref ge = mk_ge(i, val); + TRACE("opt", tout << ge << "\n";); + assert_expr(ge); + lbool is_sat = m_context.check(0, 0); + if (is_sat == l_true) { + set_model(i); } - else { - val -= inf_eps(inf_rational(rational(1))); + pop_core(1); + TRACE("opt", tout << is_sat << "\n";); + if (is_sat != l_true) { + // cop-out approximation + if (arith_util(m).is_real(m_objective_sorts[i].get())) { + val -= inf_eps(inf_rational(rational(0), true)); + } + else { + val -= inf_eps(inf_rational(rational(1))); + } + m_valid_objectives[i] = false; } - m_valid_objectives[i] = false; + return is_sat; + } @@ -308,8 +322,7 @@ namespace opt { smt::theory_var v = m_objective_vars[i]; return get_optimizer().value(v); } - - + expr_ref opt_solver::mk_ge(unsigned var, inf_eps const& val) { smt::theory_opt& opt = get_optimizer(); smt::theory_var v = m_objective_vars[var]; diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 9ceee89a7..f3a4099d0 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -134,7 +134,8 @@ namespace opt { char const * logic = "", char const * status = "unknown", char const * attributes = ""); private: - void decrement_value(unsigned i, inf_eps& val); + lbool decrement_value(unsigned i, inf_eps& val); + void set_model(unsigned i); }; } diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index d64730335..6b061f9cd 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -69,10 +69,19 @@ namespace opt { lbool optsmt::basic_opt() { lbool is_sat = l_true; + expr_ref bound(m.mk_true(), m), tmp(m); + expr* vars[1]; + + solver::scoped_push _push(*m_s); while (is_sat == l_true && !m_cancel) { - is_sat = m_s->check_sat(0, 0); + + tmp = m.mk_fresh_const("b", m.mk_bool_sort()); + vars[0] = tmp; + bound = m.mk_implies(tmp, bound); + m_s->assert_expr(bound); + is_sat = m_s->check_sat(1, vars); if (is_sat == l_true) { - update_lower(); + bound = update_lower(); } } @@ -125,17 +134,23 @@ namespace opt { expr_ref_vector ors(m), disj(m); - expr_ref fml(m), bound(m.mk_true(), m); - for (unsigned i = 0; i < m_upper.size(); ++i) { - ors.push_back(m_s->mk_ge(i, m_upper[i])); - } + expr_ref fml(m), bound(m.mk_true(), m), tmp(m); + expr* vars[1]; { - solver::scoped_push _push(*m_s); + for (unsigned i = 0; i < m_upper.size(); ++i) { + ors.push_back(m_s->mk_ge(i, m_upper[i])); + } + fml = m.mk_or(ors.size(), ors.c_ptr()); - m_s->assert_expr(fml); + tmp = m.mk_fresh_const("b", m.mk_bool_sort()); + fml = m.mk_implies(tmp, fml); + vars[0] = tmp; lbool is_sat = l_true; + + solver::scoped_push _push(*m_s); while (!m_cancel) { - is_sat = m_s->check_sat(0,0); + m_s->assert_expr(fml); + is_sat = m_s->check_sat(1,vars); if (is_sat == l_true) { disj.reset(); m_s->maximize_objectives(disj); @@ -151,7 +166,9 @@ namespace opt { } set_max(m_lower, m_s->get_objective_values(), disj); fml = m.mk_or(ors.size(), ors.c_ptr()); - m_s->assert_expr(fml); + tmp = m.mk_fresh_const("b", m.mk_bool_sort()); + fml = m.mk_implies(tmp, fml); + vars[0] = tmp; } else if (is_sat == l_undef) { return l_undef; @@ -181,7 +198,7 @@ namespace opt { m_upper[idx] = v; } - void optsmt::update_lower() { + expr_ref optsmt::update_lower() { expr_ref_vector disj(m); m_s->get_model(m_model); m_s->maximize_objectives(disj); @@ -201,9 +218,7 @@ namespace opt { IF_VERBOSE(3, verbose_stream() << disj << "\n";); IF_VERBOSE(3, model_pp(verbose_stream(), *m_model);); - expr_ref constraint(m); - constraint = m.mk_or(disj.size(), disj.c_ptr()); - m_s->assert_expr(constraint); + return expr_ref(m.mk_or(disj.size(), disj.c_ptr()), m); } lbool optsmt::update_upper() { @@ -243,7 +258,7 @@ namespace opt { IF_VERBOSE(2, verbose_stream() << "(optsmt lower bound for v" << m_vars[i] << " := " << m_upper[i] << ")\n";); m_lower[i] = mid[i]; th.enable_record_conflict(0); - update_lower(); + m_s->assert_expr(update_lower()); break; case l_false: IF_VERBOSE(2, verbose_stream() << "(optsmt conflict: " << th.conflict_minimize() << ") \n";); diff --git a/src/opt/optsmt.h b/src/opt/optsmt.h index 0a6882b24..ff970556a 100644 --- a/src/opt/optsmt.h +++ b/src/opt/optsmt.h @@ -80,7 +80,7 @@ namespace opt { void set_max(vector& dst, vector const& src, expr_ref_vector& fmls); - void update_lower(); + expr_ref update_lower(); lbool update_upper(); diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 6b40d3a62..240d45f15 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -51,10 +51,10 @@ def_module_params(module_name='smt', ('pb.enable_simplex', BOOL, False, 'enable simplex to check rational feasibility'), ('array.weak', BOOL, False, 'weak array theory'), ('array.extensional', BOOL, True, 'extensional array theory'), - ('dack', UINT, 1, '0 - disable dynamic ackermannization, 1 - expand Leibniz\'s axiom if a congruence is the root of a conflict, 2 - expand Leibniz\'s axiom if a congruence is used during conflict resolution'), - ('dack.eq', BOOL, False, 'enable dynamic ackermannization for transtivity of equalities'), - ('dack.factor', DOUBLE, 0.1, 'number of instance per conflict'), - ('dack.gc', UINT, 2000, 'Dynamic ackermannization garbage collection frequency (per conflict)'), - ('dack.gc_inv_decay', DOUBLE, 0.8, 'Dynamic ackermannization garbage collection decay'), - ('dack.threshold', UINT, 10, ' number of times the congruence rule must be used before Leibniz\'s axiom is expanded') + ('dack', UINT, 1, '0 - disable dynamic ackermannization, 1 - expand Leibniz\'s axiom if a congruence is the root of a conflict, 2 - expand Leibniz\'s axiom if a congruence is used during conflict resolution'), + ('dack.eq', BOOL, False, 'enable dynamic ackermannization for transtivity of equalities'), + ('dack.factor', DOUBLE, 0.1, 'number of instance per conflict'), + ('dack.gc', UINT, 2000, 'Dynamic ackermannization garbage collection frequency (per conflict)'), + ('dack.gc_inv_decay', DOUBLE, 0.8, 'Dynamic ackermannization garbage collection decay'), + ('dack.threshold', UINT, 10, ' number of times the congruence rule must be used before Leibniz\'s axiom is expanded') )) diff --git a/src/tactic/bv/bit_blaster_tactic.cpp b/src/tactic/bv/bit_blaster_tactic.cpp index 5dbfc4ebd..0391aad51 100644 --- a/src/tactic/bv/bit_blaster_tactic.cpp +++ b/src/tactic/bv/bit_blaster_tactic.cpp @@ -19,7 +19,7 @@ Notes: #include"tactical.h" #include"bit_blaster_model_converter.h" #include"bit_blaster_rewriter.h" -#include"ast_smt2_pp.h" +#include"ast_pp.h" #include"model_pp.h" #include"rewriter_types.h" @@ -82,6 +82,7 @@ class bit_blaster_tactic : public tactic { } if (curr != new_curr) { change = true; + TRACE("bit_blaster", tout << mk_pp(curr, m()) << " -> " << mk_pp(new_curr, m()) << "\n";); g->update(idx, new_curr, new_pr, g->dep(idx)); } } From 78cc1e0703bac20f6cf4eb2f0c1e26992f347afc Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 29 Apr 2015 15:15:57 +0100 Subject: [PATCH 739/925] Remove temporary files created during configuration tests. --- scripts/mk_util.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 547379aec..e40a549a1 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -227,7 +227,13 @@ def test_openmp(cc): t.add('#include\nint main() { return omp_in_parallel() ? 1 : 0; }\n') t.commit() if IS_WINDOWS: - return exec_compiler_cmd([cc, CPPFLAGS, 'tstomp.cpp', LDFLAGS, '/openmp']) == 0 + r = exec_compiler_cmd([cc, CPPFLAGS, 'tstomp.cpp', LDFLAGS, '/openmp']) == 0 + try: + rmf('tstomp.obj') + rmf('tstomp.exe') + except: + pass + return r else: return exec_compiler_cmd([cc, CPPFLAGS, 'tstomp.cpp', LDFLAGS, '-fopenmp']) == 0 @@ -357,10 +363,14 @@ def check_ml(): r = exec_cmd([OCAMLOPT, '-o', 'a.out', 'hello.ml']) if r != 0: raise MKException('Failed testing ocamlopt compiler. Set environment variable OCAMLOPT with the path to the Ocaml native compiler. Note that ocamlopt may require flexlink to be in your path.') - rmf('hello.cmi') - rmf('hello.cmo') - rmf('hello.cmx') - rmf('a.out') + try: + rmf('hello.cmi') + rmf('hello.cmo') + rmf('hello.cmx') + rmf('a.out') + rmf('hello.o') + except: + pass find_ml_lib() find_ocaml_find() From 4e082eae6e591bd6cdb745637b2e9c983b2ef073 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 29 Apr 2015 15:16:25 +0100 Subject: [PATCH 740/925] Version number adjustment. --- RELEASE_NOTES | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index afa613f57..2c7e2e0fb 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -1,6 +1,6 @@ RELEASE NOTES -Version 4.4 +Version 4.4.0 ============= - New feature: Support for the theory of floating-point numbers. This comes in the form of logics (QF_FP and QF_FPBV), tactics (qffp and qffpbv), as well as a theory plugin that allows theory combinations. Z3 supports the official SMT theory definition of FP (see http://smtlib.cs.uiowa.edu/theories/FloatingPoint.smt2) in SMT2 files, as well as all APIs. From 8c9afa423b3eac210ea7e4ec974286f03c052725 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 29 Apr 2015 17:22:24 +0100 Subject: [PATCH 741/925] Bumped version number to 4.4.1 in unstable. Signed-off-by: Christoph M. Wintersteiger --- scripts/mk_project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 1e21ff810..556b06098 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -9,7 +9,7 @@ from mk_util import * # Z3 Project definition def init_project_def(): - set_version(4, 4, 0, 0) + set_version(4, 4, 1, 0) add_lib('util', []) add_lib('polynomial', ['util'], 'math/polynomial') add_lib('sat', ['util']) From c0dc08ee9c78b0a5f1d58072b90b747635baaa5a Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 30 Apr 2015 17:17:44 +0100 Subject: [PATCH 742/925] Added configuration checks for floating-point build flags. --- scripts/mk_util.py | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index e40a549a1..72d432eab 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -86,6 +86,9 @@ VS_PAR_NUM=8 GPROF=False GIT_HASH=False +FPMATH="Default" +FPMATH_FLAGS="-mfpmath=sse -msse -msse2" + def check_output(cmd): return str(subprocess.Popen(cmd, stdout=subprocess.PIPE).communicate()[0]).rstrip('\r\n') @@ -237,6 +240,27 @@ def test_openmp(cc): else: return exec_compiler_cmd([cc, CPPFLAGS, 'tstomp.cpp', LDFLAGS, '-fopenmp']) == 0 +def test_fpmath(cc): + global FPMATH_FLAGS + if is_verbose(): + print("Testing floating point support...") + t = TempFile('tstsse.cpp') + t.add('int main() { return 42; }\n') + t.commit() + if exec_compiler_cmd([cc, CPPFLAGS, 'tstsse.cpp', LDFLAGS, '-mfpmath=sse -msse -msse2']) == 0: + FPMATH_FLAGS="-mfpmath=sse -msse -msse2" + return "SSE2-GCC" + elif exec_compiler_cmd([cc, CPPFLAGS, 'tstsse.cpp', LDFLAGS, '-msse -msse2']) == 0: + FPMATH_FLAGS="-msse -msse2" + return "SSE2-CLANG" + elif exec_compiler_cmd([cc, CPPFLAGS, 'tstsse.cpp', LDFLAGS, '-mfpu=vfp -mfloat-abi=hard']) == 0: + FPMATH_FLAGS="-mfpu=vfp -mfloat-abi=hard" + return "ARM-VFP" + else: + FPMATH_FLAGS="" + return "UNKNOWN" + + def find_jni_h(path): for root, dirs, files in os.walk(path): for f in files: @@ -1787,7 +1811,7 @@ def mk_config(): print('OCaml Native: %s' % OCAMLOPT) print('OCaml Library: %s' % OCAML_LIB) else: - global CXX, CC, GMP, FOCI2, CPPFLAGS, CXXFLAGS, LDFLAGS, EXAMP_DEBUG_FLAG + global CXX, CC, GMP, FOCI2, CPPFLAGS, CXXFLAGS, LDFLAGS, EXAMP_DEBUG_FLAG, FPMATH_FLAGS OS_DEFINES = "" ARITH = "internal" check_ar() @@ -1816,9 +1840,11 @@ def mk_config(): if GIT_HASH: CPPFLAGS = '%s -DZ3GITHASH=%s' % (CPPFLAGS, GIT_HASH) CXXFLAGS = '%s -fvisibility=hidden -c' % CXXFLAGS + FPMATH = test_fpmath(CXX) + CXXFLAGS = '%s %s' % (CXXFLAGS, FPMATH_FLAGS) HAS_OMP = test_openmp(CXX) if HAS_OMP: - CXXFLAGS = '%s -fopenmp -mfpmath=sse' % CXXFLAGS + CXXFLAGS = '%s -fopenmp' % CXXFLAGS LDFLAGS = '%s -fopenmp' % LDFLAGS SLIBEXTRAFLAGS = '%s -fopenmp' % SLIBEXTRAFLAGS else: @@ -1871,7 +1897,6 @@ def mk_config(): CPPFLAGS = '%s -DZ3DEBUG' % CPPFLAGS if TRACE or DEBUG_MODE: CPPFLAGS = '%s -D_TRACE' % CPPFLAGS - CXXFLAGS = '%s -msse -msse2' % CXXFLAGS config.write('PREFIX=%s\n' % PREFIX) config.write('CC=%s\n' % CC) config.write('CXX=%s\n' % CXX) @@ -1902,6 +1927,7 @@ def mk_config(): print('OpenMP: %s' % HAS_OMP) print('Prefix: %s' % PREFIX) print('64-bit: %s' % is64()) + print('FP math: %s' % FPMATH) if GPROF: print('gprof: enabled') print('Python version: %s' % distutils.sysconfig.get_python_version()) From 57af3a4c6ed81b9348c7ce4ceec93f44f0d8e2c0 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 4 May 2015 13:46:34 +0100 Subject: [PATCH 743/925] FPA min/max refactoring and fixes. Fixes #68 Signed-off-by: Christoph M. Wintersteiger --- src/ast/fpa/fpa2bv_converter.cpp | 86 +++++++++++-------------------- src/ast/rewriter/fpa_rewriter.cpp | 40 +++++++++----- 2 files changed, 56 insertions(+), 70 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 932451ff5..60120bea2 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -1041,80 +1041,54 @@ void fpa2bv_converter::mk_min(func_decl * f, unsigned num, expr * const * args, split_fp(x, x_sgn, x_exp, x_sig); split_fp(y, y_sgn, y_exp, y_sig); - expr_ref c1(m), c2(m), x_is_nan(m), y_is_nan(m), x_is_zero(m), y_is_zero(m), c1_and(m); + expr_ref x_is_nan(m), y_is_nan(m), x_is_zero(m), y_is_zero(m), both_zero(m), pzero(m); mk_is_zero(x, x_is_zero); mk_is_zero(y, y_is_zero); - m_simp.mk_and(x_is_zero, y_is_zero, c1_and); - mk_is_nan(x, x_is_nan); - m_simp.mk_or(x_is_nan, c1_and, c1); - + m_simp.mk_and(x_is_zero, y_is_zero, both_zero); + mk_is_nan(x, x_is_nan); mk_is_nan(y, y_is_nan); - c2 = y_is_nan; + mk_pzero(f, pzero); + + expr_ref lt(m); + mk_float_lt(f, num, args, lt); - expr_ref c3(m); - mk_float_lt(f, num, args, c3); + result = y; + mk_ite(lt, x, result, result); + mk_ite(both_zero, pzero, result, result); + mk_ite(y_is_nan, x, result, result); + mk_ite(x_is_nan, y, result, result); - expr_ref r_sgn(m), r_sig(m), r_exp(m); - - expr_ref c3xy(m), c2c3(m); - m_simp.mk_ite(c3, x_sgn, y_sgn, c3xy); - m_simp.mk_ite(c2, x_sgn, c3xy, c2c3); - m_simp.mk_ite(c1, y_sgn, c2c3, r_sgn); - - expr_ref c3xy_sig(m), c2c3_sig(m); - m_simp.mk_ite(c3, x_sig, y_sig, c3xy_sig); - m_simp.mk_ite(c2, x_sig, c3xy_sig, c2c3_sig); - m_simp.mk_ite(c1, y_sig, c2c3_sig, r_sig); - - expr_ref c3xy_exp(m), c2c3_exp(m); - m_simp.mk_ite(c3, x_exp, y_exp, c3xy_exp); - m_simp.mk_ite(c2, x_exp, c3xy_exp, c2c3_exp); - m_simp.mk_ite(c1, y_exp, c2c3_exp, r_exp); - - mk_fp(r_sgn, r_exp, r_sig, result); + SASSERT(is_well_sorted(m, result)); } void fpa2bv_converter::mk_max(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 2); - - expr * x = args[0], * y = args[1]; - expr * x_sgn, * x_sig, * x_exp; - expr * y_sgn, * y_sig, * y_exp; + expr * x = args[0], *y = args[1]; + + expr * x_sgn, *x_sig, *x_exp; + expr * y_sgn, *y_sig, *y_exp; split_fp(x, x_sgn, x_exp, x_sig); split_fp(y, y_sgn, y_exp, y_sig); - expr_ref c1(m), c2(m), x_is_nan(m), y_is_nan(m), y_is_zero(m), x_is_zero(m), c1_and(m); - mk_is_zero(y, y_is_zero); + expr_ref x_is_nan(m), y_is_nan(m), x_is_zero(m), y_is_zero(m), both_zero(m), pzero(m); mk_is_zero(x, x_is_zero); - m_simp.mk_and(y_is_zero, x_is_zero, c1_and); - mk_is_nan(x, x_is_nan); - m_simp.mk_or(x_is_nan, c1_and, c1); - + mk_is_zero(y, y_is_zero); + m_simp.mk_and(x_is_zero, y_is_zero, both_zero); + mk_is_nan(x, x_is_nan); mk_is_nan(y, y_is_nan); - c2 = y_is_nan; - - expr_ref c3(m); - mk_float_gt(f, num, args, c3); + mk_pzero(f, pzero); - expr_ref r_sgn(m), r_sig(m), r_exp(m); - - expr_ref c3xy_sgn(m), c2c3_sgn(m); - m_simp.mk_ite(c3, x_sgn, y_sgn, c3xy_sgn); - m_simp.mk_ite(c2, x_sgn, c3xy_sgn, c2c3_sgn); - m_simp.mk_ite(c1, y_sgn, c2c3_sgn, r_sgn); + expr_ref gt(m); + mk_float_gt(f, num, args, gt); - expr_ref c3xy_sig(m), c2c3_sig(m); - m_simp.mk_ite(c3, x_sig, y_sig, c3xy_sig); - m_simp.mk_ite(c2, x_sig, c3xy_sig, c2c3_sig); - m_simp.mk_ite(c1, y_sig, c2c3_sig, r_sig); + result = y; + mk_ite(gt, x, result, result); + mk_ite(both_zero, pzero, result, result); + mk_ite(y_is_nan, x, result, result); + mk_ite(x_is_nan, y, result, result); - expr_ref c3xy_exp(m), c2c3_exp(m); - m_simp.mk_ite(c3, x_exp, y_exp, c3xy_exp); - m_simp.mk_ite(c2, x_exp, c3xy_exp, c2c3_exp); - m_simp.mk_ite(c1, y_exp, c2c3_exp, r_exp); - - mk_fp(r_sgn, r_exp, r_sig, result); + SASSERT(is_well_sorted(m, result)); } void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { diff --git a/src/ast/rewriter/fpa_rewriter.cpp b/src/ast/rewriter/fpa_rewriter.cpp index 6aee683ff..5fb9dfd37 100644 --- a/src/ast/rewriter/fpa_rewriter.cpp +++ b/src/ast/rewriter/fpa_rewriter.cpp @@ -411,14 +411,20 @@ br_status fpa_rewriter::mk_min(expr * arg1, expr * arg2, expr_ref & result) { result = arg1; return BR_DONE; } - // expand as using ite's - result = m().mk_ite(m().mk_or(mk_eq_nan(arg1), m().mk_and(m_util.mk_is_zero(arg1), m_util.mk_is_zero(arg2))), + if (m_util.is_zero(arg1) && m_util.is_zero(arg2)) { + result = m_util.mk_pzero(m().get_sort(arg1)); + return BR_DONE; + } + + result = m().mk_ite(mk_eq_nan(arg1), arg2, - m().mk_ite(mk_eq_nan(arg2), - arg1, - m().mk_ite(m_util.mk_lt(arg1, arg2), - arg1, - arg2))); + m().mk_ite(mk_eq_nan(arg2), + arg1, + m().mk_ite(m().mk_and(m_util.mk_is_zero(arg1), m_util.mk_is_zero(arg2)), + m_util.mk_pzero(m().get_sort(arg1)), + m().mk_ite(m_util.mk_lt(arg1, arg2), + arg1, + arg2)))); return BR_REWRITE_FULL; } @@ -431,14 +437,20 @@ br_status fpa_rewriter::mk_max(expr * arg1, expr * arg2, expr_ref & result) { result = arg1; return BR_DONE; } - // expand as using ite's - result = m().mk_ite(m().mk_or(mk_eq_nan(arg1), m().mk_and(m_util.mk_is_zero(arg1), m_util.mk_is_zero(arg2))), + if (m_util.is_zero(arg1) && m_util.is_zero(arg2)) { + result = m_util.mk_pzero(m().get_sort(arg1)); + return BR_DONE; + } + + result = m().mk_ite(mk_eq_nan(arg1), arg2, - m().mk_ite(mk_eq_nan(arg2), - arg1, - m().mk_ite(m_util.mk_gt(arg1, arg2), - arg1, - arg2))); + m().mk_ite(mk_eq_nan(arg2), + arg1, + m().mk_ite(m().mk_and(m_util.mk_is_zero(arg1), m_util.mk_is_zero(arg2)), + m_util.mk_pzero(m().get_sort(arg1)), + m().mk_ite(m_util.mk_gt(arg1, arg2), + arg1, + arg2)))); return BR_REWRITE_FULL; } From 73eb7cbf5c04869c171f190d00125449333ea095 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 5 May 2015 23:53:33 +0100 Subject: [PATCH 744/925] Bugfix for mpf roundToIntegral. Partially fixes #69 --- src/ast/rewriter/fpa_rewriter.cpp | 4 +- src/ast/rewriter/fpa_rewriter.h | 2 +- src/util/mpf.cpp | 92 +++++++++++++++++++++++++++---- src/util/mpf.h | 4 +- 4 files changed, 87 insertions(+), 15 deletions(-) diff --git a/src/ast/rewriter/fpa_rewriter.cpp b/src/ast/rewriter/fpa_rewriter.cpp index 5fb9dfd37..40021e330 100644 --- a/src/ast/rewriter/fpa_rewriter.cpp +++ b/src/ast/rewriter/fpa_rewriter.cpp @@ -70,7 +70,7 @@ br_status fpa_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con case OP_FPA_MAX: SASSERT(num_args == 2); st = mk_max(args[0], args[1], result); break; case OP_FPA_FMA: SASSERT(num_args == 4); st = mk_fma(args[0], args[1], args[2], args[3], result); break; case OP_FPA_SQRT: SASSERT(num_args == 2); st = mk_sqrt(args[0], args[1], result); break; - case OP_FPA_ROUND_TO_INTEGRAL: SASSERT(num_args == 2); st = mk_round(args[0], args[1], result); break; + case OP_FPA_ROUND_TO_INTEGRAL: SASSERT(num_args == 2); st = mk_round_to_integral(args[0], args[1], result); break; case OP_FPA_EQ: SASSERT(num_args == 2); st = mk_float_eq(args[0], args[1], result); break; case OP_FPA_LT: SASSERT(num_args == 2); st = mk_lt(args[0], args[1], result); break; @@ -484,7 +484,7 @@ br_status fpa_rewriter::mk_sqrt(expr * arg1, expr * arg2, expr_ref & result) { return BR_FAILED; } -br_status fpa_rewriter::mk_round(expr * arg1, expr * arg2, expr_ref & result) { +br_status fpa_rewriter::mk_round_to_integral(expr * arg1, expr * arg2, expr_ref & result) { mpf_rounding_mode rm; if (m_util.is_rm_numeral(arg1, rm)) { scoped_mpf v2(m_fm); diff --git a/src/ast/rewriter/fpa_rewriter.h b/src/ast/rewriter/fpa_rewriter.h index 2c76fad6a..2da839718 100644 --- a/src/ast/rewriter/fpa_rewriter.h +++ b/src/ast/rewriter/fpa_rewriter.h @@ -57,7 +57,7 @@ public: br_status mk_max(expr * arg1, expr * arg2, expr_ref & result); br_status mk_fma(expr * arg1, expr * arg2, expr * arg3, expr * arg4, expr_ref & result); br_status mk_sqrt(expr * arg1, expr * arg2, expr_ref & result); - br_status mk_round(expr * arg1, expr * arg2, expr_ref & result); + br_status mk_round_to_integral(expr * arg1, expr * arg2, expr_ref & result); br_status mk_float_eq(expr * arg1, expr * arg2, expr_ref & result); br_status mk_lt(expr * arg1, expr * arg2, expr_ref & result); br_status mk_gt(expr * arg1, expr * arg2, expr_ref & result); diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 9de56773a..9b6db5213 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -1003,9 +1003,30 @@ void mpf_manager::round_to_integral(mpf_rounding_mode rm, mpf const & x, mpf & o mk_nan(x.ebits, x.sbits, o); else if (is_inf(x)) set(o, x); - else if (x.exponent < 0) + else if (is_zero(x)) mk_zero(x.ebits, x.sbits, x.sign, o); - else if (x.exponent >= x.sbits-1) + else if (x.exponent < 0) { + if (rm == MPF_ROUND_TOWARD_ZERO || + rm == MPF_ROUND_TOWARD_NEGATIVE) + mk_pzero(x.ebits, x.sbits, o); + else if (rm == MPF_ROUND_NEAREST_TEVEN || + rm == MPF_ROUND_NEAREST_TAWAY) { + bool tie = m_mpz_manager.is_zero(x.significand) && x.exponent == -1; + if (tie && rm == MPF_ROUND_NEAREST_TEVEN) + mk_pzero(x.ebits, x.sbits, o); + else if (tie && rm == MPF_ROUND_NEAREST_TAWAY) + mk_one(x.ebits, x.sbits, o); + else if (x.exponent < -1 || m_mpz_manager.lt(x.significand, m_powers2(x.sbits-2))) + mk_pzero(x.ebits, x.sbits, o); + else + mk_one(x.ebits, x.sbits, o); + } + else { + SASSERT(rm == MPF_ROUND_TOWARD_POSITIVE); + mk_one(x.ebits, x.sbits, o); + } + } + else if (x.exponent >= x.sbits - 1) set(o, x); else { SASSERT(x.exponent >= 0 && x.exponent < x.sbits-1); @@ -1016,21 +1037,62 @@ void mpf_manager::round_to_integral(mpf_rounding_mode rm, mpf const & x, mpf & o scoped_mpf a(*this); set(a, x); - unpack(a, true); + unpack(a, true); // A includes hidden bit TRACE("mpf_dbg", tout << "A = " << to_string(a) << std::endl;); - + + SASSERT(m_mpz_manager.lt(a.significand(), m_powers2(x.sbits))); + SASSERT(m_mpz_manager.ge(a.significand(), m_powers2(x.sbits - 1))); + o.exponent = a.exponent(); m_mpz_manager.set(o.significand, a.significand()); - unsigned q = (unsigned) o.exponent; - unsigned shift = o.sbits-q-1; - TRACE("mpf_dbg", tout << "Q = " << q << " shift=" << shift << std::endl;); - m_mpz_manager.machine_div2k(o.significand, shift); - m_mpz_manager.mul2k(o.significand, shift+3); + unsigned shift = o.sbits - ((unsigned)o.exponent) - 1; + const mpz & shift_p = m_powers2(shift); + TRACE("mpf_dbg", tout << "shift=" << shift << std::endl;); + + scoped_mpz div(m_mpz_manager), rem(m_mpz_manager); + m_mpz_manager.machine_div_rem(o.significand, shift_p, div, rem); + TRACE("mpf_dbg", tout << "div=" << m_mpz_manager.to_string(div) << " rem=" << m_mpz_manager.to_string(rem) << std::endl;); - round(rm, o); - } + switch (rm) { + case MPF_ROUND_NEAREST_TEVEN: + case MPF_ROUND_NEAREST_TAWAY: { + scoped_mpz t(m_mpz_manager); + m_mpz_manager.mul2k(rem, 1, t); + bool tie = m_mpz_manager.eq(t, shift_p); + if (tie && + (rm == MPF_ROUND_NEAREST_TEVEN && m_mpz_manager.is_odd(div)) || + (rm == MPF_ROUND_NEAREST_TAWAY && m_mpz_manager.is_even(div))) + m_mpz_manager.inc(div); + else if (m_mpz_manager.gt(t, shift_p)) + m_mpz_manager.inc(div); + break; + } + case MPF_ROUND_TOWARD_POSITIVE: + if (!m_mpz_manager.is_zero(rem) && !o.sign) + m_mpz_manager.inc(div); + break; + case MPF_ROUND_TOWARD_NEGATIVE: + if (!m_mpz_manager.is_zero(rem) && o.sign) + m_mpz_manager.inc(div); + break; + case MPF_ROUND_TOWARD_ZERO: + default: + /* nothing */; + } + + m_mpz_manager.mul2k(div, shift, o.significand); + SASSERT(m_mpz_manager.ge(o.significand, m_powers2(o.sbits - 1))); + + // re-normalize + while (m_mpz_manager.ge(o.significand, m_powers2(o.sbits))) { + m_mpz_manager.machine_div2k(o.significand, 1); + o.exponent++; + } + + m_mpz_manager.sub(o.significand, m_powers2(o.sbits - 1), o.significand); // strip hidden bit + } TRACE("mpf_dbg", tout << "INTEGRAL = " << to_string(o) << std::endl;); } @@ -1449,6 +1511,14 @@ void mpf_manager::mk_nan(unsigned ebits, unsigned sbits, mpf & o) { o.sign = false; } +void mpf_manager::mk_one(unsigned ebits, unsigned sbits, mpf & o) const { + o.sbits = sbits; + o.ebits = ebits; + o.sign = false; + m_mpz_manager.set(o.significand, 0); + o.exponent = 0; +} + void mpf_manager::mk_max_value(unsigned ebits, unsigned sbits, bool sign, mpf & o) { o.sbits = sbits; o.ebits = ebits; diff --git a/src/util/mpf.h b/src/util/mpf.h index bac502c58..533944172 100644 --- a/src/util/mpf.h +++ b/src/util/mpf.h @@ -208,7 +208,9 @@ public: void to_sbv_mpq(mpf_rounding_mode rm, const mpf & x, scoped_mpq & o); -protected: +protected: + void mk_one(unsigned ebits, unsigned sbits, mpf & o) const; + bool has_bot_exp(mpf const & x); bool has_top_exp(mpf const & x); From 53b479e1c3dd79e4bdc64f96ea1a960132d9fae3 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 6 May 2015 12:24:18 +0100 Subject: [PATCH 745/925] Bugfix for fp.rem(0, 0). Fixes #70. --- src/ast/fpa/fpa2bv_converter.cpp | 12 ++++++------ src/util/mpf.cpp | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 60120bea2..1543ce629 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -959,14 +959,14 @@ void fpa2bv_converter::mk_rem(func_decl * f, unsigned num, expr * const * args, c3 = y_is_inf; v3 = x; - // (x is 0) -> x - c4 = x_is_zero; - v4 = pzero; - // (y is 0) -> NaN. - c5 = y_is_zero; - v5 = nan; + c4 = y_is_zero; + v4 = nan; + // (x is 0) -> x + c5 = x_is_zero; + v5 = pzero; + // else the actual remainder. unsigned ebits = m_util.get_ebits(f->get_range()); unsigned sbits = m_util.get_sbits(f->get_range()); diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 9b6db5213..428cfb318 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -1161,10 +1161,10 @@ void mpf_manager::rem(mpf const & x, mpf const & y, mpf & o) { mk_nan(x.ebits, x.sbits, o); else if (is_inf(y)) set(o, x); - else if (is_zero(x)) - set(o, x); else if (is_zero(y)) mk_nan(x.ebits, x.sbits, o); + else if (is_zero(x)) + set(o, x); else { o.ebits = x.ebits; o.sbits = x.sbits; From a63481de85d1237c5084d80479fc26b1f5ccafb9 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 6 May 2015 19:18:29 +0100 Subject: [PATCH 746/925] New implementations of fp.roundToIntegral in mpf and fpa2bv. Partially fixes #69 --- src/ast/fpa/fpa2bv_converter.cpp | 189 ++++++++++++++++++++++++------- src/ast/fpa/fpa2bv_converter.h | 4 +- src/util/mpf.cpp | 31 ++--- src/util/mpf.h | 2 +- 4 files changed, 168 insertions(+), 58 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 1543ce629..cc189f462 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -359,6 +359,17 @@ void fpa2bv_converter::mk_pzero(func_decl *f, expr_ref & result) { result); } +void fpa2bv_converter::mk_one(func_decl *f, expr_ref sign, expr_ref & result) { + sort * srt = f->get_range(); + SASSERT(is_float(srt)); + unsigned sbits = m_util.get_sbits(srt); + unsigned ebits = m_util.get_ebits(srt); + mk_fp(sign, + m_bv_util.mk_numeral(fu().fm().m_powers2.m1(ebits-1), ebits), + m_bv_util.mk_numeral(0, sbits-1), + result); +} + void fpa2bv_converter::add_core(unsigned sbits, unsigned ebits, expr_ref & rm, expr_ref & c_sgn, expr_ref & c_sig, expr_ref & c_exp, expr_ref & d_sgn, expr_ref & d_sig, expr_ref & d_exp, expr_ref & res_sgn, expr_ref & res_sig, expr_ref & res_exp) @@ -828,7 +839,7 @@ void fpa2bv_converter::mk_div(func_decl * f, unsigned num, expr * const * args, mk_is_ninf(y, c5); mk_ite(x_is_inf, nan, xy_zero, v5); - // (y is 0) -> if (x is 0) then NaN else inf with xor sign. + // (y is 0) -> if (x is 0) then NaN else inf with xor sign. c6 = y_is_zero; expr_ref sgn_inf(m); mk_ite(signs_xor, ninf, pinf, sgn_inf); @@ -1556,10 +1567,17 @@ void fpa2bv_converter::mk_round_to_integral(func_decl * f, unsigned num, expr * rm = args[0]; x = args[1]; + expr_ref rm_is_rta(m), rm_is_rte(m), rm_is_rtp(m), rm_is_rtn(m), rm_is_rtz(m); + mk_is_rm(rm, BV_RM_TIES_TO_AWAY, rm_is_rta); + mk_is_rm(rm, BV_RM_TIES_TO_EVEN, rm_is_rte); + mk_is_rm(rm, BV_RM_TO_POSITIVE, rm_is_rtp); + mk_is_rm(rm, BV_RM_TO_NEGATIVE, rm_is_rtn); + mk_is_rm(rm, BV_RM_TO_ZERO, rm_is_rtz); + expr_ref nan(m), nzero(m), pzero(m), ninf(m), pinf(m); mk_nan(f, nan); mk_nzero(f, nzero); - mk_pzero(f, pzero); + mk_pzero(f, pzero); expr_ref x_is_zero(m), x_is_pos(m); mk_is_zero(x, x_is_zero); @@ -1568,74 +1586,161 @@ void fpa2bv_converter::mk_round_to_integral(func_decl * f, unsigned num, expr * dbg_decouple("fpa2bv_r2i_x_is_zero", x_is_zero); dbg_decouple("fpa2bv_r2i_x_is_pos", x_is_pos); - expr_ref c1(m), c2(m), c3(m), c4(m); - expr_ref v1(m), v2(m), v3(m), v4(m), v5(m); + expr_ref c1(m), c2(m), c3(m), c4(m), c5(m); + expr_ref v1(m), v2(m), v3(m), v4(m), v5(m), v6(m); + // (x is NaN) -> NaN mk_is_nan(x, c1); v1 = nan; + // (x is +-oo) -> x mk_is_inf(x, c2); v2 = x; + + // (x is +-0) -> x ; -0.0 -> -0.0, says IEEE754, Sec 5.9. + mk_is_zero(x, c3); + v3 = x; + + + expr_ref one_1(m), zero_1(m); + one_1 = m_bv_util.mk_numeral(1, 1); + zero_1 = m_bv_util.mk_numeral(0, 1); unsigned ebits = m_util.get_ebits(f->get_range()); unsigned sbits = m_util.get_sbits(f->get_range()); expr_ref a_sgn(m), a_sig(m), a_exp(m), a_lz(m); unpack(x, a_sgn, a_sig, a_exp, a_lz, true); - + dbg_decouple("fpa2bv_r2i_unpacked_sig", a_sig); dbg_decouple("fpa2bv_r2i_unpacked_exp", a_exp); - expr_ref exp_is_small(m), exp_h(m), one_1(m); - exp_h = m_bv_util.mk_extract(ebits-1, ebits-1, a_exp); - one_1 = m_bv_util.mk_numeral(1, 1); - m_simp.mk_eq(exp_h, one_1, exp_is_small); - dbg_decouple("fpa2bv_r2i_exp_is_small", exp_is_small); - c3 = exp_is_small; - mk_ite(x_is_pos, pzero, nzero, v3); + expr_ref xzero(m); + mk_ite(m.mk_eq(a_sgn, one_1), nzero, pzero, xzero); + + // exponent < 0 -> 0/1 + expr_ref exp_lt_zero(m), exp_h(m); + exp_h = m_bv_util.mk_extract(ebits-1, ebits-1, a_exp); + m_simp.mk_eq(exp_h, one_1, exp_lt_zero); + dbg_decouple("fpa2bv_r2i_exp_lt_zero", exp_lt_zero); + c4 = exp_lt_zero; + + expr_ref pone(m), none(m), xone(m), c421(m), c422(m), c423(m), t1(m), t2(m), tie(m), v42(m), exp_lt_m1(m); + mk_one(f, zero_1, pone); + mk_one(f, one_1, none); + mk_ite(m.mk_eq(a_sgn, one_1), none, pone, xone); + m_simp.mk_eq(a_sig, m_bv_util.mk_numeral(fu().fm().m_powers2(sbits-1), sbits), t1); + m_simp.mk_eq(a_exp, m_bv_util.mk_numeral(-1, ebits), t2); + m_simp.mk_and(t1, t2, tie); + dbg_decouple("fpa2bv_r2i_c42_tie", tie); + + m_simp.mk_and(tie, rm_is_rte, c421); + m_simp.mk_and(tie, rm_is_rta, c422); + c423 = m_bv_util.mk_sle(a_exp, m_bv_util.mk_numeral(-2, ebits)); + + dbg_decouple("fpa2bv_r2i_c421", c421); + dbg_decouple("fpa2bv_r2i_c422", c422); + dbg_decouple("fpa2bv_r2i_c423", c423); + + v42 = xone; + mk_ite(c423, xzero, v42, v42); + mk_ite(c422, xone, v42, v42); + mk_ite(c421, xzero, v42, v42); + + mk_ite(m.mk_eq(a_sgn, one_1), nzero, pone, v4); + mk_ite(m.mk_or(rm_is_rte, rm_is_rta), v42, v4, v4); + mk_ite(m.mk_or(rm_is_rtz, rm_is_rtn), xzero, v4, v4); + + SASSERT(is_well_sorted(m, v4)); + + // exponent >= sbits-1 expr_ref exp_is_large(m); exp_is_large = m_bv_util.mk_sle(m_bv_util.mk_numeral(sbits-1, ebits), a_exp); dbg_decouple("fpa2bv_r2i_exp_is_large", exp_is_large); - c4 = exp_is_large; - v4 = x; + c5 = exp_is_large; + v5 = x; + + // Actual conversion with rounding. + // x.exponent >= 0 && x.exponent < x.sbits - 1 - // The actual rounding. expr_ref res_sgn(m), res_sig(m), res_exp(m); res_sgn = a_sgn; - res_exp = m_bv_util.mk_concat(m_bv_util.mk_numeral(0, 2), a_exp); + res_exp = a_exp; - expr_ref shift(m), r_shifted(m), l_shifted(m); - shift = m_bv_util.mk_bv_sub(m_bv_util.mk_numeral(sbits-1, ebits+1), - m_bv_util.mk_sign_extend(1, a_exp)); - if (sbits > (ebits+1)) - r_shifted = m_bv_util.mk_bv_lshr(a_sig, m_bv_util.mk_zero_extend(sbits-(ebits+1), shift)); - else if (sbits < (ebits+1)) - r_shifted = m_bv_util.mk_extract(ebits, ebits-sbits+1, m_bv_util.mk_bv_lshr(m_bv_util.mk_zero_extend(ebits+1-sbits, a_sig), shift)); - else // sbits == ebits+1 - r_shifted = m_bv_util.mk_bv_lshr(a_sig, shift); - SASSERT(is_well_sorted(m, r_shifted)); - SASSERT(m_bv_util.get_bv_size(r_shifted) == sbits); + expr_ref shift(m), rshift(m), div(m), rem(m); + shift = m_bv_util.mk_bv_sub(m_bv_util.mk_numeral(sbits - 1, sbits + 1), + m_bv_util.mk_sign_extend(sbits - ebits + 1, a_exp)); + rshift = m_bv_util.mk_bv_sub(m_bv_util.mk_numeral(sbits, sbits + 1), shift); + div = m_bv_util.mk_bv_lshr(m_bv_util.mk_zero_extend(1, a_sig), shift); + rem = m_bv_util.mk_bv_lshr(m_bv_util.mk_bv_shl(m_bv_util.mk_zero_extend(1, a_sig), rshift), rshift); - if (sbits > (ebits+1)) - l_shifted = m_bv_util.mk_bv_shl(r_shifted, m_bv_util.mk_zero_extend(sbits-(ebits+1), shift)); - else if (sbits < (ebits+1)) - l_shifted = m_bv_util.mk_extract(ebits, ebits-sbits+1, m_bv_util.mk_bv_shl(m_bv_util.mk_zero_extend(ebits+1-sbits, r_shifted), shift)); - else // sbits == ebits+1 - l_shifted = m_bv_util.mk_bv_shl(r_shifted, shift); - SASSERT(is_well_sorted(m, l_shifted)); - SASSERT(m_bv_util.get_bv_size(l_shifted) == sbits); + SASSERT(is_well_sorted(m, div)); + SASSERT(is_well_sorted(m, rem)); + SASSERT(m_bv_util.get_bv_size(div) == sbits + 1); + SASSERT(m_bv_util.get_bv_size(rem) == sbits + 1); - res_sig = m_bv_util.mk_concat(m_bv_util.mk_numeral(0, 1), - m_bv_util.mk_concat(l_shifted, - m_bv_util.mk_numeral(0, 3))); + dbg_decouple("fpa2bv_r2i_shift", shift); + dbg_decouple("fpa2bv_r2i_rshift", rshift); + dbg_decouple("fpa2bv_r2i_div", div); + dbg_decouple("fpa2bv_r2i_rem", rem); - SASSERT(m_bv_util.get_bv_size(res_sig) == (sbits + 4)); + expr_ref div_p1(m); + div_p1 = m_bv_util.mk_bv_add(div, m_bv_util.mk_numeral(1, sbits+1)); - round(f->get_range(), rm, res_sgn, res_sig, res_exp, v5); + expr_ref tie2(m), tie2_c(m), div_last(m), v51(m), rem_shl(m); + rem_shl = m_bv_util.mk_concat(m_bv_util.mk_extract(sbits - 1, 0, rem), zero_1); + m_simp.mk_eq(rem_shl, + m_bv_util.mk_bv_shl(m_bv_util.mk_numeral(1, sbits+1), shift), + tie2); + div_last = m_bv_util.mk_extract(0, 0, div); + tie2_c = m.mk_or(m.mk_and(tie2, + m.mk_or(m.mk_and(rm_is_rte, m.mk_eq(div_last, one_1)), + m.mk_and(rm_is_rta, m.mk_eq(div_last, zero_1)))), + m.mk_xor(m.mk_eq(a_sgn, one_1), + m_bv_util.mk_sle(m_bv_util.mk_bv_shl(m_bv_util.mk_numeral(1, sbits + 1), shift), + rem_shl))); + m_simp.mk_ite(tie2_c, div_p1, div, v51); + + dbg_decouple("fpa2bv_r2i_v51", v51); + dbg_decouple("fpa2bv_r2i_tie2", tie2); + + SASSERT(is_well_sorted(m, tie2)); + SASSERT(is_well_sorted(m, tie2_c)); + SASSERT(is_well_sorted(m, v51)); + + expr_ref c521(m), v52(m); + m_simp.mk_not(m.mk_eq(rem, m_bv_util.mk_numeral(0, sbits+1)), c521); + m_simp.mk_and(c521, m.mk_eq(res_sgn, zero_1), c521); + m_simp.mk_ite(c521, div_p1, div, v52); + + expr_ref c531(m), v53(m); + m_simp.mk_not(m.mk_eq(rem, m_bv_util.mk_numeral(0, sbits+1)), c531); + m_simp.mk_and(c531, m.mk_eq(res_sgn, one_1), c531); + m_simp.mk_ite(c531, div_p1, div, v53); + + expr_ref c51(m), c52(m), c53(m); + c51 = m.mk_or(rm_is_rte, rm_is_rta); + c52 = rm_is_rtp; + c53 = rm_is_rtn; + + res_sig = div; + m_simp.mk_ite(c53, v53, res_sig, res_sig); + m_simp.mk_ite(c52, v52, res_sig, res_sig); + m_simp.mk_ite(c51, v51, res_sig, res_sig); + res_sig = m_bv_util.mk_concat(res_sig, m_bv_util.mk_numeral(0, 3)); // rounding bits are all 0. + res_exp = m_bv_util.mk_bv_add(m_bv_util.mk_zero_extend(2, res_exp), m_bv_util.mk_extract(ebits+1, 0, shift)); + + SASSERT(m_bv_util.get_bv_size(res_sgn) == 1); + SASSERT(m_bv_util.get_bv_size(res_sig) == sbits+4); + SASSERT(m_bv_util.get_bv_size(res_exp) == ebits+2); + + // CMW: We use the rounder for normalization. + round(f->get_range(), rm, res_sgn, res_sig, res_exp, v6); // And finally, we tie them together. - mk_ite(c4, v4, v5, result); + mk_ite(c5, v5, v6, result); + mk_ite(c4, v4, result, result); mk_ite(c3, v3, result, result); mk_ite(c2, v2, result, result); mk_ite(c1, v1, result, result); @@ -3239,7 +3344,7 @@ void fpa2bv_converter::mk_rounding_mode(func_decl * f, expr_ref & result) void fpa2bv_converter::dbg_decouple(const char * prefix, expr_ref & e) { #ifdef Z3DEBUG - return; + // return; // CMW: This works only for quantifier-free formulas. expr_ref new_e(m); new_e = m.mk_fresh_const(prefix, m.get_sort(e)); diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index fa797b610..4b3c1a6ca 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -92,7 +92,7 @@ public: void mk_ninf(func_decl * f, expr_ref & result); void mk_nan(func_decl * f, expr_ref & result); void mk_nzero(func_decl *f, expr_ref & result); - void mk_pzero(func_decl *f, expr_ref & result); + void mk_pzero(func_decl *f, expr_ref & result); void mk_add(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_sub(func_decl * f, unsigned num, expr * const * args, expr_ref & result); @@ -151,6 +151,8 @@ public: expr_ref_vector m_extra_assertions; protected: + void mk_one(func_decl *f, expr_ref sign, expr_ref & result); + void mk_is_nan(expr * e, expr_ref & result); void mk_is_inf(expr * e, expr_ref & result); void mk_is_pinf(expr * e, expr_ref & result); diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 428cfb318..4940fa448 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -1004,26 +1004,29 @@ void mpf_manager::round_to_integral(mpf_rounding_mode rm, mpf const & x, mpf & o else if (is_inf(x)) set(o, x); else if (is_zero(x)) - mk_zero(x.ebits, x.sbits, x.sign, o); + mk_zero(x.ebits, x.sbits, x.sign, o); // -0.0 -> -0.0, says IEEE754, Sec 5.9. else if (x.exponent < 0) { if (rm == MPF_ROUND_TOWARD_ZERO || rm == MPF_ROUND_TOWARD_NEGATIVE) - mk_pzero(x.ebits, x.sbits, o); + mk_zero(x.ebits, x.sbits, x.sign, o); else if (rm == MPF_ROUND_NEAREST_TEVEN || rm == MPF_ROUND_NEAREST_TAWAY) { bool tie = m_mpz_manager.is_zero(x.significand) && x.exponent == -1; if (tie && rm == MPF_ROUND_NEAREST_TEVEN) - mk_pzero(x.ebits, x.sbits, o); + mk_zero(x.ebits, x.sbits, x.sign, o); else if (tie && rm == MPF_ROUND_NEAREST_TAWAY) - mk_one(x.ebits, x.sbits, o); - else if (x.exponent < -1 || m_mpz_manager.lt(x.significand, m_powers2(x.sbits-2))) - mk_pzero(x.ebits, x.sbits, o); + mk_one(x.ebits, x.sbits, x.sign, o); + else if (x.exponent < -1) + mk_zero(x.ebits, x.sbits, x.sign, o); else - mk_one(x.ebits, x.sbits, o); + mk_one(x.ebits, x.sbits, x.sign, o); } else { SASSERT(rm == MPF_ROUND_TOWARD_POSITIVE); - mk_one(x.ebits, x.sbits, o); + if (x.sign) + mk_nzero(x.ebits, x.sbits, o); + else + mk_one(x.ebits, x.sbits, false, o); } } else if (x.exponent >= x.sbits - 1) @@ -1049,7 +1052,7 @@ void mpf_manager::round_to_integral(mpf_rounding_mode rm, mpf const & x, mpf & o unsigned shift = o.sbits - ((unsigned)o.exponent) - 1; const mpz & shift_p = m_powers2(shift); - TRACE("mpf_dbg", tout << "shift=" << shift << std::endl;); + TRACE("mpf_dbg", tout << "shift=" << shift << std::endl;); scoped_mpz div(m_mpz_manager), rem(m_mpz_manager); m_mpz_manager.machine_div_rem(o.significand, shift_p, div, rem); @@ -1065,16 +1068,16 @@ void mpf_manager::round_to_integral(mpf_rounding_mode rm, mpf const & x, mpf & o (rm == MPF_ROUND_NEAREST_TEVEN && m_mpz_manager.is_odd(div)) || (rm == MPF_ROUND_NEAREST_TAWAY && m_mpz_manager.is_even(div))) m_mpz_manager.inc(div); - else if (m_mpz_manager.gt(t, shift_p)) + else if (x.sign ^ m_mpz_manager.gt(t, shift_p)) m_mpz_manager.inc(div); break; } case MPF_ROUND_TOWARD_POSITIVE: - if (!m_mpz_manager.is_zero(rem) && !o.sign) + if (!m_mpz_manager.is_zero(rem) && o.sign) m_mpz_manager.inc(div); break; case MPF_ROUND_TOWARD_NEGATIVE: - if (!m_mpz_manager.is_zero(rem) && o.sign) + if (!m_mpz_manager.is_zero(rem) && !o.sign) m_mpz_manager.inc(div); break; case MPF_ROUND_TOWARD_ZERO: @@ -1511,10 +1514,10 @@ void mpf_manager::mk_nan(unsigned ebits, unsigned sbits, mpf & o) { o.sign = false; } -void mpf_manager::mk_one(unsigned ebits, unsigned sbits, mpf & o) const { +void mpf_manager::mk_one(unsigned ebits, unsigned sbits, bool sign, mpf & o) const { o.sbits = sbits; o.ebits = ebits; - o.sign = false; + o.sign = sign; m_mpz_manager.set(o.significand, 0); o.exponent = 0; } diff --git a/src/util/mpf.h b/src/util/mpf.h index 533944172..ef87ca0b7 100644 --- a/src/util/mpf.h +++ b/src/util/mpf.h @@ -209,7 +209,7 @@ public: void to_sbv_mpq(mpf_rounding_mode rm, const mpf & x, scoped_mpq & o); protected: - void mk_one(unsigned ebits, unsigned sbits, mpf & o) const; + void mk_one(unsigned ebits, unsigned sbits, bool sign, mpf & o) const; bool has_bot_exp(mpf const & x); bool has_top_exp(mpf const & x); From 99861ffc3296637e60cda392903b7f4277c9d196 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 May 2015 21:32:02 -0700 Subject: [PATCH 747/925] allow coercion from Boolean to Integers and reals Signed-off-by: Nikolaj Bjorner --- src/api/python/z3.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index ce1cc2103..92640b2d9 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -1228,6 +1228,15 @@ class BoolSortRef(SortRef): _z3_assert(self.eq(val.sort()), "Value cannot be converted into a Z3 Boolean value") return val + def subsort(self, other): + return isinstance(other, ArithSortRef) + + def is_int(self): + return True + + def is_bool(self): + return True + class BoolRef(ExprRef): """All Boolean expressions are instances of this class.""" def sort(self): @@ -1900,6 +1909,10 @@ class ArithSortRef(SortRef): return val if val_s.is_int() and self.is_real(): return ToReal(val) + if val_s.is_bool() and self.is_int(): + return If(val, 1, 0) + if val_s.is_bool() and self.is_real(): + return ToReal(If(val, 1, 0)) if __debug__: _z3_assert(False, "Z3 Integer/Real expression expected" ) else: From 45eda4bee78c3e95cbdfbc71e8aa27b967639ab9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 May 2015 21:33:36 -0700 Subject: [PATCH 748/925] allow coercion from Boolean to Int/Real, fixes #78 Signed-off-by: Nikolaj Bjorner --- src/api/python/z3.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index 92640b2d9..7cda4bf83 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -1237,6 +1237,7 @@ class BoolSortRef(SortRef): def is_bool(self): return True + class BoolRef(ExprRef): """All Boolean expressions are instances of this class.""" def sort(self): From ad39811dc0a9ebd11b62b59693142a5c9518d6f9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 May 2015 21:36:37 -0700 Subject: [PATCH 749/925] allow coercion from Boolean to Int/Real, fixes #78 Signed-off-by: Nikolaj Bjorner --- src/api/python/z3.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index 7cda4bf83..c1bdf2713 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -1229,13 +1229,13 @@ class BoolSortRef(SortRef): return val def subsort(self, other): - return isinstance(other, ArithSortRef) + return isinstance(other, ArithSortRef) def is_int(self): - return True + return True def is_bool(self): - return True + return True class BoolRef(ExprRef): @@ -1910,10 +1910,10 @@ class ArithSortRef(SortRef): return val if val_s.is_int() and self.is_real(): return ToReal(val) - if val_s.is_bool() and self.is_int(): - return If(val, 1, 0) - if val_s.is_bool() and self.is_real(): - return ToReal(If(val, 1, 0)) + if val_s.is_bool() and self.is_int(): + return If(val, 1, 0) + if val_s.is_bool() and self.is_real(): + return ToReal(If(val, 1, 0)) if __debug__: _z3_assert(False, "Z3 Integer/Real expression expected" ) else: From 901d8a9f5b8d623982fd90caa3a0ff65026c4192 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 May 2015 00:38:26 -0700 Subject: [PATCH 750/925] change exception test to take into account new coercion operation Signed-off-by: Nikolaj Bjorner --- src/api/python/z3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index c1bdf2713..b46f5a9ef 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -32,7 +32,7 @@ sat Z3 exceptions: >>> try: -... x = Int('x') +... x = BitVec('x', 32) ... y = Bool('y') ... # the expression x + y is type incorrect ... n = x + y From 31e78cd17805c5efa36bbf6c526c466488585264 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 6 May 2015 12:24:18 +0100 Subject: [PATCH 751/925] Bugfix for fp.rem(0, 0). Fixes #70. --- src/ast/fpa/fpa2bv_converter.cpp | 12 ++++++------ src/util/mpf.cpp | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 60120bea2..1543ce629 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -959,14 +959,14 @@ void fpa2bv_converter::mk_rem(func_decl * f, unsigned num, expr * const * args, c3 = y_is_inf; v3 = x; - // (x is 0) -> x - c4 = x_is_zero; - v4 = pzero; - // (y is 0) -> NaN. - c5 = y_is_zero; - v5 = nan; + c4 = y_is_zero; + v4 = nan; + // (x is 0) -> x + c5 = x_is_zero; + v5 = pzero; + // else the actual remainder. unsigned ebits = m_util.get_ebits(f->get_range()); unsigned sbits = m_util.get_sbits(f->get_range()); diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 9de56773a..490a8792f 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -1099,10 +1099,10 @@ void mpf_manager::rem(mpf const & x, mpf const & y, mpf & o) { mk_nan(x.ebits, x.sbits, o); else if (is_inf(y)) set(o, x); - else if (is_zero(x)) - set(o, x); else if (is_zero(y)) mk_nan(x.ebits, x.sbits, o); + else if (is_zero(x)) + set(o, x); else { o.ebits = x.ebits; o.sbits = x.sbits; From 4a9d97bd02e1faba9dad80c8b725bb85b4901c59 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 May 2015 21:29:48 -0700 Subject: [PATCH 752/925] add concat to z3++, codeplex request Signed-off-by: Nikolaj Bjorner --- examples/c++/example.cpp | 3 +++ src/api/c++/z3++.h | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/examples/c++/example.cpp b/examples/c++/example.cpp index 9f4f9431c..ce15bf37d 100644 --- a/examples/c++/example.cpp +++ b/examples/c++/example.cpp @@ -205,6 +205,9 @@ void bitvector_example1() { // using unsigned <= prove(ule(x - 10, 0) == ule(x, 10)); + + expr y = c.bv_const("y", 32); + prove(implies(concat(x, y) == concat(y, x), x == y)); } /** diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index f43ba83e5..ca93d28d9 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -655,6 +655,7 @@ namespace z3 { friend expr ite(expr const & c, expr const & t, expr const & e); friend expr distinct(expr_vector const& args); + friend expr concat(expr const& a, expr const& b); friend expr operator==(expr const & a, expr const & b) { check_context(a, b); @@ -1108,6 +1109,12 @@ namespace z3 { ctx.check_error(); return expr(ctx, r); } + + inline expr concat(expr const& a, expr const& b) { + Z3_ast r = Z3_mk_concat(ctx, (Z3_app) a, (Z3_app) b); + ctx.check_error(); + return expr(ctx, r); + } class func_entry : public object { Z3_func_entry m_entry; From 839e3fbb7cfe34d388aba4966bad2c5853f9f24d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 May 2015 19:40:34 -0700 Subject: [PATCH 753/925] add ddnf tests, add facility to solve QF_NRA + QF_UF(and other theories) in joint solver to allow broader use of QF_NRA core Signed-off-by: Nikolaj Bjorner --- examples/tptp/tptp5.cpp | 2 +- scripts/mk_project.py | 3 +- src/muz/ddnf/ddnf.cpp | 86 ++- src/muz/ddnf/ddnf.h | 25 + src/muz/rel/tbv.cpp | 14 + src/muz/rel/tbv.h | 1 + src/smt/tactic/smt_tactic.cpp | 9 +- src/tactic/arith/probe_arith.cpp | 63 ++ src/tactic/arith/probe_arith.h | 2 + src/tactic/nlsat_smt/nl_purify_tactic.cpp | 667 ++++++++++++++++++ src/tactic/nlsat_smt/nl_purify_tactic.h | 35 + src/tactic/portfolio/default_tactic.cpp | 4 +- src/tactic/portfolio/smt_strategic_solver.cpp | 3 + src/tactic/smtlogics/qfufnra_tactic.cpp | 46 ++ src/tactic/smtlogics/qfufnra_tactic.h | 31 + src/tactic/tactic.cpp | 2 +- src/tactic/tactical.cpp | 4 + src/tactic/tactical.h | 1 + src/test/ddnf.cpp | 167 +++++ src/test/main.cpp | 1 + 20 files changed, 1158 insertions(+), 8 deletions(-) create mode 100644 src/tactic/nlsat_smt/nl_purify_tactic.cpp create mode 100644 src/tactic/nlsat_smt/nl_purify_tactic.h create mode 100644 src/tactic/smtlogics/qfufnra_tactic.cpp create mode 100644 src/tactic/smtlogics/qfufnra_tactic.h create mode 100644 src/test/ddnf.cpp diff --git a/examples/tptp/tptp5.cpp b/examples/tptp/tptp5.cpp index 00d03a8b0..2a90b5a3f 100644 --- a/examples/tptp/tptp5.cpp +++ b/examples/tptp/tptp5.cpp @@ -2083,7 +2083,7 @@ bool parse_is_sat_line(char const* line, bool& is_sat) { return true; } return false; -} + bool parse_is_sat(char const* filename, bool& is_sat) { std::ifstream is(filename); diff --git a/scripts/mk_project.py b/scripts/mk_project.py index f0c1f8e2f..01d5cfa97 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -69,7 +69,8 @@ def init_project_def(): add_lib('ddnf', ['muz', 'transforms', 'rel'], 'muz/ddnf') add_lib('duality_intf', ['muz', 'transforms', 'duality'], 'muz/duality') add_lib('fp', ['muz', 'pdr', 'clp', 'tab', 'rel', 'bmc', 'duality_intf', 'ddnf'], 'muz/fp') - add_lib('smtlogic_tactics', ['arith_tactics', 'bv_tactics', 'nlsat_tactic', 'smt_tactic', 'aig_tactic', 'fp', 'muz','qe'], 'tactic/smtlogics') + add_lib('nlsat_smt_tactic', ['nlsat_tactic', 'smt_tactic'], 'tactic/nlsat_smt') + add_lib('smtlogic_tactics', ['arith_tactics', 'bv_tactics', 'nlsat_tactic', 'smt_tactic', 'aig_tactic', 'fp', 'muz','qe','nlsat_smt_tactic'], 'tactic/smtlogics') add_lib('ufbv_tactic', ['normal_forms', 'core_tactics', 'macros', 'smt_tactic', 'rewriter'], 'tactic/ufbv') add_lib('portfolio', ['smtlogic_tactics', 'ufbv_tactic', 'fpa_tactics', 'aig_tactic', 'fp', 'qe','sls_tactic', 'subpaving_tactic'], 'tactic/portfolio') add_lib('smtparser', ['portfolio'], 'parsers/smt') diff --git a/src/muz/ddnf/ddnf.cpp b/src/muz/ddnf/ddnf.cpp index 6c4f79f7c..82cb9d1fa 100644 --- a/src/muz/ddnf/ddnf.cpp +++ b/src/muz/ddnf/ddnf.cpp @@ -123,6 +123,13 @@ namespace datalog { class ddnf_mgr { + struct stats { + unsigned m_num_inserts; + unsigned m_num_comparisons; + stats() { reset(); } + void reset() { memset(this, 0, sizeof(*this)); } + }; + unsigned m_num_bits; ddnf_node* m_root; ddnf_node_vector m_noderefs; @@ -131,6 +138,8 @@ namespace datalog { ddnf_node::hash m_hash; ddnf_node::eq m_eq; ddnf_nodes m_nodes; + svector m_marked; + stats m_stats; public: ddnf_mgr(unsigned n): m_num_bits(n), m_noderefs(*this), m_internalized(false), m_tbv(n), m_hash(m_tbv), m_eq(m_tbv), @@ -154,6 +163,31 @@ namespace datalog { n->dec_ref(); } + void reset_accumulate() { + m_marked.resize(m_nodes.size()); + for (unsigned i = 0; i < m_marked.size(); ++i) { + m_marked[i] = false; + } + } + + void accumulate(tbv const& t, unsigned_vector& acc) { + ddnf_node* n = find(t); + ptr_vector todo; + todo.push_back(n); + while (!todo.empty()) { + n = todo.back(); + todo.pop_back(); + unsigned id = n->get_id(); + if (m_marked[id]) continue; + acc.push_back(id); + m_marked[id] = true; + unsigned sz = n->num_children(); + for (unsigned i = 0; i < sz; ++i) { + todo.push_back((*n)[i]); + } + } + } + ddnf_node* insert(tbv const& t) { SASSERT(!m_internalized); ptr_vector new_tbvs; @@ -173,6 +207,9 @@ namespace datalog { return m_tbv.allocate(v, hi, lo); } + tbv_manager& get_tbv_manager() { + return m_tbv; + } unsigned size() const { return m_noderefs.size(); @@ -183,13 +220,21 @@ namespace datalog { return find(t)->descendants(); } - void display(std::ostream& out) const { + void display_statistics(std::ostream& out) const { + std::cout << "Number of insertions: " << m_stats.m_num_inserts << "\n"; + std::cout << "Number of comparisons: " << m_stats.m_num_comparisons << "\n"; + std::cout << "Number of nodes: " << size() << "\n"; + } + + void display(std::ostream& out) const { for (unsigned i = 0; i < m_noderefs.size(); ++i) { m_noderefs[i]->display(out); out << "\n"; } } + + private: ddnf_node* find(tbv const& t) { @@ -207,9 +252,11 @@ namespace datalog { SASSERT(m_tbv.contains(root.get_tbv(), new_tbv)); if (&root == new_n) return; + ++m_stats.m_num_inserts; bool inserted = false; for (unsigned i = 0; i < root.num_children(); ++i) { ddnf_node& child = *(root[i]); + ++m_stats.m_num_comparisons; if (m_tbv.contains(child.get_tbv(), new_tbv)) { inserted = true; insert(child, new_n, new_intersections); @@ -227,11 +274,16 @@ namespace datalog { // checking for subset if (m_tbv.contains(new_tbv, child.get_tbv())) { subset_children.push_back(&child); + ++m_stats.m_num_comparisons; } else if (m_tbv.intersect(child.get_tbv(), new_tbv, *intr)) { // this means there is a non-full intersection new_intersections.push_back(intr); intr = m_tbv.allocate(); + m_stats.m_num_comparisons += 2; + } + else { + m_stats.m_num_comparisons += 2; } } m_tbv.deallocate(intr); @@ -284,10 +336,38 @@ namespace datalog { for (; it != end; ++it) { dst.insert(*it); } - } - + } }; + ddnf_core::ddnf_core(unsigned n) { + m_imp = alloc(ddnf_mgr, n); + } + ddnf_core::~ddnf_core() { + dealloc(m_imp); + } + ddnf_node* ddnf_core::insert(tbv const& t) { + return m_imp->insert(t); + } + tbv_manager& ddnf_core::get_tbv_manager() { + return m_imp->get_tbv_manager(); + } + unsigned ddnf_core::size() const { + return m_imp->size(); + } + void ddnf_core::reset_accumulate() { + return m_imp->reset_accumulate(); + } + void ddnf_core::accumulate(tbv const& t, unsigned_vector& acc) { + return m_imp->accumulate(t, acc); + } + void ddnf_core::display(std::ostream& out) const { + m_imp->display(out); + } + void ddnf_core::display_statistics(std::ostream& out) const { + m_imp->display_statistics(out); + } + + void ddnf_node::add_child(ddnf_node* n) { //SASSERT(!m_tbv.is_subset(n->m_tbv)); m_children.push_back(n); diff --git a/src/muz/ddnf/ddnf.h b/src/muz/ddnf/ddnf.h index 8121dc090..1e5e912ba 100644 --- a/src/muz/ddnf/ddnf.h +++ b/src/muz/ddnf/ddnf.h @@ -24,6 +24,9 @@ Revision History: #include "statistics.h" #include "dl_engine_base.h" +class tbv; +class tbv_manager; + namespace datalog { class context; @@ -41,6 +44,28 @@ namespace datalog { virtual void display_certificate(std::ostream& out) const; virtual expr_ref get_answer(); }; + + class ddnf_node; + class ddnf_mgr; + class ddnf_core { + ddnf_mgr* m_imp; + public: + ddnf_core(unsigned n); + ~ddnf_core(); + ddnf_node* insert(tbv const& t); + tbv_manager& get_tbv_manager(); + unsigned size() const; + + // + // accumulate labels covered by the stream of tbvs, + // such that labels that are covered by the current + // tbv but not the previous tbvs are included. + // + void reset_accumulate(); + void accumulate(tbv const& t, unsigned_vector& labels); + void display(std::ostream& out) const; + void display_statistics(std::ostream& out) const; + }; }; #endif diff --git a/src/muz/rel/tbv.cpp b/src/muz/rel/tbv.cpp index fc3c32390..577817e69 100644 --- a/src/muz/rel/tbv.cpp +++ b/src/muz/rel/tbv.cpp @@ -99,6 +99,20 @@ tbv* tbv_manager::allocate(tbv const& bv, unsigned const* permutation) { } return r; } +tbv* tbv_manager::allocate(char const* bv) { + tbv* result = allocateX(); + unsigned i = 0, sz = num_tbits(); + while(*bv && i < sz) { + if (*bv == '0') set(*result, i++, tbit::BIT_0); + else if (*bv == '1') set(*result, i++, tbit::BIT_1); + else if (*bv == '*') i++; + else if (i == 0 && (*bv == ' ' || *bv == '\t')) ; + else break; + ++bv; + } + return result; +} + tbv* tbv_manager::project(bit_vector const& to_delete, tbv const& src) { tbv* r = allocate(); unsigned i, j; diff --git a/src/muz/rel/tbv.h b/src/muz/rel/tbv.h index ad98b8095..7d20d035c 100644 --- a/src/muz/rel/tbv.h +++ b/src/muz/rel/tbv.h @@ -55,6 +55,7 @@ public: tbv* allocate(rational const& r); tbv* allocate(uint64 n, unsigned hi, unsigned lo); tbv* allocate(tbv const& bv, unsigned const* permutation); + tbv* allocate(char const* bv); void deallocate(tbv* bv); diff --git a/src/smt/tactic/smt_tactic.cpp b/src/smt/tactic/smt_tactic.cpp index 95b150a8c..a83b4a035 100644 --- a/src/smt/tactic/smt_tactic.cpp +++ b/src/smt/tactic/smt_tactic.cpp @@ -22,6 +22,7 @@ Notes: #include"smt_params.h" #include"smt_params_helper.hpp" #include"rewriter_types.h" +#include"filter_model_converter.h" class smt_tactic : public tactic { smt_params m_params; @@ -150,6 +151,7 @@ public: scoped_ptr dep2bool; scoped_ptr bool2dep; ptr_vector assumptions; + ref fmc; if (in->unsat_core_enabled()) { if (in->proofs_enabled()) throw tactic_exception("smt tactic does not support simultaneous generation of proofs and unsat cores"); @@ -191,6 +193,10 @@ public: dep2bool->insert(d, b); bool2dep->insert(b, d); assumptions.push_back(b); + if (!fmc) { + fmc = alloc(filter_model_converter, m); + } + fmc->insert(to_app(b)->get_decl()); } clause.push_back(m.mk_not(b)); } @@ -229,11 +235,12 @@ public: // the empty assertion set is trivially satifiable. in->reset(); result.push_back(in.get()); - // store the model in a do nothin model converter. + // store the model in a no-op model converter, and filter fresh Booleans if (in->models_enabled()) { model_ref md; m_ctx->get_model(md); mc = model2model_converter(md.get()); + mc = concat(fmc.get(), mc.get()); } pc = 0; core = 0; diff --git a/src/tactic/arith/probe_arith.cpp b/src/tactic/arith/probe_arith.cpp index 770281923..ae287e2b5 100644 --- a/src/tactic/arith/probe_arith.cpp +++ b/src/tactic/arith/probe_arith.cpp @@ -513,6 +513,53 @@ static bool is_lira(goal const & g) { return !test(g, p); } + +struct is_non_qfufnra_functor { + struct found {}; + ast_manager & m; + arith_util u; + + is_non_qfufnra_functor(ast_manager & _m): m(_m), u(m) {} + + void throw_found() { + throw found(); + } + + void operator()(var * x) { + throw_found(); + } + void operator()(quantifier *) { + throw_found(); + } + void operator()(app * n) { + family_id fid = n->get_family_id(); + if (fid == m.get_basic_family_id()) + return; + if (fid == u.get_family_id()) { + switch (n->get_decl_kind()) { + case OP_LE: case OP_GE: case OP_LT: case OP_GT: + case OP_ADD: case OP_UMINUS: case OP_SUB: case OP_ABS: + case OP_NUM: case OP_MUL: + case OP_IRRATIONAL_ALGEBRAIC_NUM: + return; + case OP_IDIV: case OP_DIV: case OP_REM: case OP_MOD: + case OP_POWER: + if (!u.is_numeral(n->get_arg(1))) + throw_found(); + return; + case OP_IS_INT: + case OP_TO_INT: + case OP_TO_REAL: + throw_found(); + return; + default: + throw_found(); + } + } + } +}; + + class is_qfnia_probe : public probe { public: virtual result operator()(goal const & g) { @@ -569,6 +616,18 @@ public: } }; +static bool is_qfufnra(goal const& g) { + is_non_qfufnra_functor p(g.m()); + return !test(g, p); +} + +class is_qfufnra_probe : public probe { +public: + virtual result operator()(goal const & g) { + return is_qfufnra(g); + } +}; + probe * mk_is_qfnia_probe() { return alloc(is_qfnia_probe); } @@ -600,3 +659,7 @@ probe * mk_is_lra_probe() { probe * mk_is_lira_probe() { return alloc(is_lira_probe); } + +probe* mk_is_qfufnra_probe() { + return alloc(is_qfufnra_probe); +} diff --git a/src/tactic/arith/probe_arith.h b/src/tactic/arith/probe_arith.h index 83179098d..ba95a2837 100644 --- a/src/tactic/arith/probe_arith.h +++ b/src/tactic/arith/probe_arith.h @@ -55,6 +55,7 @@ probe * mk_is_nira_probe(); probe * mk_is_lia_probe(); probe * mk_is_lra_probe(); probe * mk_is_lira_probe(); +probe * mk_is_qfufnra_probe(); /* ADD_PROBE("is-qfnia", "true if the goal is in QF_NIA (quantifier-free nonlinear integer arithmetic).", "mk_is_qfnia_probe()") @@ -65,5 +66,6 @@ probe * mk_is_lira_probe(); ADD_PROBE("is-lia", "true if the goal is in LIA (linear integer arithmetic, formula may have quantifiers).", "mk_is_lia_probe()") ADD_PROBE("is-lra", "true if the goal is in LRA (linear real arithmetic, formula may have quantifiers).", "mk_is_lra_probe()") ADD_PROBE("is-lira", "true if the goal is in LIRA (linear integer and real arithmetic, formula may have quantifiers).", "mk_is_lira_probe()") + ADD_PROBE("is-qfufnra", "true if the goal is QF_UFNRA (quantifier-free nonlinear real arithmetic with other theories).", mk_is_qfufnra_probe()"); */ #endif diff --git a/src/tactic/nlsat_smt/nl_purify_tactic.cpp b/src/tactic/nlsat_smt/nl_purify_tactic.cpp new file mode 100644 index 000000000..ec3419d2b --- /dev/null +++ b/src/tactic/nlsat_smt/nl_purify_tactic.cpp @@ -0,0 +1,667 @@ +/*++ +Copyright (c) 2011 Microsoft Corporation + +Module Name: + + nl_purify_tactic.cpp + +Abstract: + + Tactic for purifying quantifier-free formulas that mix QF_NRA and other theories. + It is designed to allow cooprating between the nlsat solver and other theories + in a decoupled way. + + Let goal be formula F. + Let NL goal be formula G. + Assume F is in NNF. + Assume F does not contain mix of real/integers. + Assume F is quantifier-free (please, otherwise we need to reprocess from instantiated satisfiable formula) + + For each atomic nl formula f, + - introduce a propositional variable p + - replace f by p + - add clauses p => f to G + + For each interface term t, + - introduce interface variable v (or use t if it is already a variable) + - replace t by v + + Check satisfiability of G. + If satisfiable, then check assignment to p and interface equalities on F + If unsat: + Retrieve core and add core to G. + else: + For interface equalities from model of F that are not equal in G, add + For interface variables that are equal under one model, but not the other model, + create interface predicate p_vw => v = w, add to both F, G. + Add interface equations to assumptions, recheck F. + If unsat retrieve core add to G. + +Author: + + Nikolaj Bjorner (nbjorner) 2015-5-5. + +Revision History: + +- check for input assumptions +- check for proof mode +- check for quantifiers +- add applicability filter +- add to smtlogics + +--*/ +#include "tactical.h" +#include "nl_purify_tactic.h" +#include "smt_tactic.h" +#include "rewriter.h" +#include "nlsat_tactic.h" +#include "filter_model_converter.h" +#include "obj_pair_hashtable.h" +#include "rewriter_def.h" +#include "ast_pp.h" +#include "trace.h" +#include "smt_solver.h" +#include "solver.h" + +class nl_purify_tactic : public tactic { + + enum polarity_t { + pol_pos, + pol_neg, + pol_dual + }; + + ast_manager & m; + arith_util m_util; + params_ref m_params; + bool m_produce_proofs; + ref m_fmc; + bool m_cancel; + tactic_ref m_nl_tac; // nlsat tactic + ref m_solver; // SMT solver + expr_ref_vector m_eq_preds; // predicates for equality between pairs of interface variables + svector m_eq_values; // truth value of the equality predicates in nlsat + app_ref_vector m_new_reals; // interface real variables + app_ref_vector m_new_preds; // abstraction predicates for smt_solver (hide real constraints) + expr_ref_vector m_asms; // assumptions to pass to SMT solver + obj_pair_map m_eq_pairs; // map pairs of interface variables to auxiliary predicates + obj_map m_interface_cache; // map of compound real expression to interface variable. + obj_map m_polarities; // polarities of sub-expressions + +public: + struct rw_cfg : public default_rewriter_cfg { + enum mode_t { + mode_interface_var, + mode_bool_preds + }; + ast_manager& m; + nl_purify_tactic & m_owner; + app_ref_vector& m_new_reals; + app_ref_vector& m_new_preds; + obj_map& m_polarities; + obj_map& m_interface_cache; + expr_ref_vector m_nl_cnstrs; + proof_ref_vector m_nl_cnstr_prs; + expr_ref_vector m_args; + mode_t m_mode; + + rw_cfg(nl_purify_tactic & o): + m(o.m), + m_owner(o), + m_new_reals(o.m_new_reals), + m_new_preds(o.m_new_preds), + m_polarities(o.m_polarities), + m_interface_cache(o.m_interface_cache), + m_nl_cnstrs(m), + m_nl_cnstr_prs(m), + m_args(m), + m_mode(mode_interface_var) { + } + + virtual ~rw_cfg() {} + + arith_util & u() { return m_owner.m_util; } + + bool produce_proofs() const { return m_owner.m_produce_proofs; } + + expr * mk_interface_var(expr* arg) { + expr* r; + if (m_interface_cache.find(arg, r)) { + return r; + } + if (is_uninterp_const(arg)) { + m_interface_cache.insert(arg, arg); + return arg; + } + r = m.mk_fresh_const(0, u().mk_real()); + m_new_reals.push_back(to_app(r)); + m_interface_cache.insert(arg, r); + return r; + } + + void mk_interface_bool(func_decl * f, unsigned num, expr* const* args, expr_ref& result) { + expr_ref old_pred(m.mk_app(f, num, args), m); + polarity_t pol; + TRACE("nlsat_smt", tout << old_pred << "\n";); + VERIFY(m_polarities.find(old_pred, pol)); + result = m.mk_fresh_const(0, m.mk_bool_sort()); + m_polarities.insert(result, pol); + m_new_preds.push_back(to_app(result)); + if (pol != pol_neg) { + m_nl_cnstrs.push_back(m.mk_or(m.mk_not(result), m.mk_app(f, num, args))); + } + if (pol != pol_pos) { + m_nl_cnstrs.push_back(m.mk_or(result, m.mk_not(m.mk_app(f, num, args)))); + } + TRACE("nlsat_smt", tout << result << " : " << mk_pp(m_nl_cnstrs.back(), m) << "\n";); + } + + bool reduce_quantifier(quantifier * old_q, + expr * new_body, + expr * const * new_patterns, + expr * const * new_no_patterns, + expr_ref & result, + proof_ref & result_pr) { + throw tactic_exception("quantifiers are not supported in mixed-mode nlsat engine"); + } + + br_status reduce_app_bool(func_decl * f, unsigned num, expr* const* args, expr_ref& result, proof_ref & pr) { + if (f->get_family_id() == m.get_basic_family_id()) { + // TBD: do we have negated inequalities for strict? + // maybe equalities are already deleted by pre-processor stage, but why depend on this? + if (f->get_decl_kind() == OP_EQ && u().is_real(args[0])) { + mk_interface_bool(f, num, args, result); + return BR_DONE; + } + else { + return BR_FAILED; + } + } + if (f->get_family_id() == u().get_family_id()) { + switch (f->get_decl_kind()) { + case OP_LE: + case OP_GE: + case OP_LT: + case OP_GT: + // these are the only real cases of non-linear atomic formulas besides equality. + mk_interface_bool(f, num, args, result); + return BR_DONE; + default: + return BR_FAILED; + } + } + return BR_FAILED; + } + + br_status reduce_app_real(func_decl * f, unsigned num, expr* const* args, expr_ref& result, proof_ref & pr) { + m_args.reset(); + bool has_interface = false; + for (unsigned i = 0; i < num; ++i) { + expr* arg = args[i]; + if (u().is_real(arg)) { + has_interface = true; + m_args.push_back(mk_interface_var(arg)); + } + else { + m_args.push_back(arg); + } + } + if (has_interface) { + result = m.mk_app(f, num, m_args.c_ptr()); + TRACE("nlsat_smt", tout << result << "\n";); + return BR_DONE; + } + else { + return BR_FAILED; + } + } + + br_status reduce_app(func_decl * f, unsigned num, expr* const* args, expr_ref& result, proof_ref & pr) { + if (m_mode == mode_bool_preds) { + return reduce_app_bool(f, num, args, result, pr); + } + else { + return reduce_app_real(f, num, args, result, pr); + } + } + }; +private: + class rw : public rewriter_tpl { + rw_cfg m_cfg; + public: + rw(nl_purify_tactic & o): + rewriter_tpl(o.m, o.m_produce_proofs, m_cfg), + m_cfg(o) { + } + expr_ref_vector const& nl_cnstrs() const { + return m_cfg.m_nl_cnstrs; + } + void set_bool_mode() { + m_cfg.m_mode = rw_cfg::mode_bool_preds; + } + void set_interface_var_mode() { + m_cfg.m_mode = rw_cfg::mode_interface_var; + } + + }; + + arith_util & u() { return m_util; } + + void check_point() { + if (m_cancel) { + throw tactic_exception("canceled"); + } + } + + void display_result(std::ostream& out, goal_ref_buffer const& result) { + for (unsigned i = 0; i < result.size(); ++i) { + result[i]->display(tout << "goal\n"); + } + } + + void update_eq_values(model_ref& mdl) { + expr_ref tmp(m); + for (unsigned i = 0; i < m_eq_preds.size(); ++i) { + expr* pred = m_eq_preds[i].get(); + m_eq_values[i] = l_undef; + if (mdl->eval(pred, tmp)) { + if (m.is_true(tmp)) { + m_eq_values[i] = l_true; + } + else if (m.is_false(tmp)) { + m_eq_values[i] = l_false; + } + } + } + } + + void solve(goal_ref const& nl_g, + goal_ref_buffer& result, + model_converter_ref& mc) { + + while (true) { + check_point(); + TRACE("nlsat_smt", m_solver->display(tout << "SMT:\n"); nl_g->display(tout << "\nNL:\n"); ); + goal_ref tmp_nl = alloc(goal, m, true, false); + model_converter_ref nl_mc; + proof_converter_ref nl_pc; + expr_dependency_ref nl_core(m); + result.reset(); + tmp_nl->copy_from(*nl_g.get()); + (*m_nl_tac)(tmp_nl, result, nl_mc, nl_pc, nl_core); + + if (is_decided_unsat(result)) { + TRACE("nlsat_smt", tout << "unsat\n";); + break; + } + if (!is_decided_sat(result)) { + TRACE("nlsat_smt", tout << "not a unit\n";); + break; + } + // extract evaluation on interface variables. + // assert booleans that evaluate to true. + // assert equalities between equal interface real variables. + + model_ref mdl_nl, mdl_smt; + model_converter2model(m, nl_mc.get(), mdl_nl); + update_eq_values(mdl_nl); + enforce_equalities(mdl_nl, nl_g); + + setup_assumptions(mdl_nl); + + TRACE("nlsat_smt", m_solver->display(tout << "smt goal:\n"); ); + + result.reset(); + lbool r = m_solver->check_sat(m_asms.size(), m_asms.c_ptr()); + if (r == l_false) { + // extract the core from the result + ptr_vector core; + m_solver->get_unsat_core(core); + if (core.empty()) { + goal_ref g = alloc(goal, m); + g->assert_expr(m.mk_false()); + result.push_back(g.get()); + break; + } + expr_ref_vector clause(m); + expr_ref fml(m); + expr* e; + for (unsigned i = 0; i < core.size(); ++i) { + clause.push_back(m.is_not(core[i], e)?e:m.mk_not(core[i])); + } + fml = m.mk_or(clause.size(), clause.c_ptr()); + nl_g->assert_expr(fml); + continue; + } + else if (r == l_true) { + m_solver->get_model(mdl_smt); + if (enforce_equalities(mdl_smt, nl_g)) { + // SMT enforced a new equality that wasn't true for nlsat. + continue; + } + TRACE("nlsat_smt", + m_fmc->display(tout << "joint state is sat\n"); + nl_mc->display(tout << "nl\n");); + merge_models(*mdl_nl.get(), mdl_smt); + mc = m_fmc.get(); + apply(mc, mdl_smt, 0); + mc = model2model_converter(mdl_smt.get()); + result.push_back(alloc(goal, m)); + } + else { + TRACE("nlsat_smt", tout << "unknown\n";); + } + break; + } + TRACE("nlsat_smt", display_result(tout, result);); + } + + void setup_assumptions(model_ref& mdl) { + m_asms.reset(); + app_ref_vector const& fresh_preds = m_new_preds; + expr_ref tmp(m); + for (unsigned i = 0; i < fresh_preds.size(); ++i) { + expr* pred = fresh_preds[i]; + if (mdl->eval(pred, tmp)) { + TRACE("nlsat_smt", tout << "pred: " << mk_pp(pred, m) << "\n";); + polarity_t pol = m_polarities.find(pred); + if (pol != pol_neg && m.is_true(tmp)) { + m_asms.push_back(pred); + } + else if (pol != pol_pos && m.is_false(tmp)) { + m_asms.push_back(m.mk_not(pred)); + } + } + } + for (unsigned i = 0; i < m_eq_preds.size(); ++i) { + expr* pred = m_eq_preds[i].get(); + switch(m_eq_values[i]) { + case l_true: + m_asms.push_back(pred); + break; + case l_false: + m_asms.push_back(m.mk_not(pred)); + break; + default: + break; + } + } + } + + bool enforce_equalities(model_ref& mdl, goal_ref const& nl_g) { + TRACE("nlsat_smt", tout << "Enforce equalities " << m_interface_cache.size() << "\n";); + bool new_equality = false; + expr_ref_vector nums(m); + obj_map num2var; + obj_map::iterator it = m_interface_cache.begin(), end = m_interface_cache.end(); + for (; it != end; ++it) { + expr_ref r(m); + expr* v, *w, *pred; + w = it->m_value; + VERIFY(mdl->eval(w, r)); + TRACE("nlsat_smt", tout << mk_pp(w, m) << " |-> " << r << "\n";); + nums.push_back(r); + if (num2var.find(r, v)) { + if (!m_eq_pairs.find(v, w, pred)) { + pred = m.mk_fresh_const(0, m.mk_bool_sort()); + m_eq_preds.push_back(pred); + m_eq_values.push_back(l_true); + m_fmc->insert(to_app(pred)->get_decl()); + nl_g->assert_expr(m.mk_or(m.mk_not(pred), m.mk_eq(w, v))); + nl_g->assert_expr(m.mk_or(pred, m.mk_not(m.mk_eq(w, v)))); + m_solver->assert_expr(m.mk_iff(pred, m.mk_eq(w, v))); + new_equality = true; + m_eq_pairs.insert(v, w, pred); + } + else { + // interface equality is already enforced. + } + } + else { + num2var.insert(r, w); + } + } + return new_equality; + } + + void merge_models(model const& mdl_nl, model_ref& mdl_smt) { + obj_map num2num; + expr_ref result(m), val2(m); + expr_ref_vector args(m), trail(m); + unsigned sz = mdl_nl.get_num_constants(); + for (unsigned i = 0; i < sz; ++i) { + func_decl* v = mdl_nl.get_constant(i); + if (u().is_real(v->get_range())) { + expr* val = mdl_nl.get_const_interp(v); + if (mdl_smt->eval(v, val2)) { + if (val != val2) { + num2num.insert(val2, val); + trail.push_back(val2); + } + } + } + } + sz = mdl_smt->get_num_functions(); + for (unsigned i = 0; i < sz; ++i) { + func_decl* f = mdl_smt->get_function(i); + if (has_real(f)) { + unsigned arity = f->get_arity(); + func_interp* f1 = mdl_smt->get_func_interp(f); + func_interp* f2 = alloc(func_interp, m, f->get_arity()); + for (unsigned j = 0; j < f1->num_entries(); ++j) { + args.reset(); + func_entry const* entry = f1->get_entry(j); + for (unsigned k = 0; k < arity; ++k) { + args.push_back(translate(num2num, entry->get_arg(k))); + } + result = translate(num2num, entry->get_result()); + f2->insert_entry(args.c_ptr(), result); + } + expr* e = f1->get_else(); + result = translate(num2num, e); + f2->set_else(result); + mdl_smt->register_decl(f, f2); + } + } + mdl_smt->copy_const_interps(mdl_nl); + } + + bool has_real(func_decl* f) { + for (unsigned i = 0; i < f->get_arity(); ++i) { + if (u().is_real(f->get_domain(i))) return true; + } + return u().is_real(f->get_range()); + } + + expr* translate(obj_map const& num2num, expr* e) { + if (!e || !u().is_real(e)) return e; + expr* result = 0; + if (num2num.find(e, result)) return result; + return e; + } + + void get_polarities(goal const& g) { + ptr_vector forms; + svector pols; + unsigned sz = g.size(); + for (unsigned i = 0; i < sz; ++i) { + forms.push_back(g.form(i)); + pols.push_back(pol_pos); + } + polarity_t p, q; + while (!forms.empty()) { + expr* e = forms.back(); + p = pols.back(); + forms.pop_back(); + pols.pop_back(); + if (m_polarities.find(e, q)) { + if (p == q || q == pol_dual) continue; + p = pol_dual; + } + TRACE("nlsat_smt", tout << mk_pp(e, m) << "\n";); + m_polarities.insert(e, p); + if (is_quantifier(e) || is_var(e)) { + throw tactic_exception("nl-purify tactic does not support quantifiers"); + } + SASSERT(is_app(e)); + app* a = to_app(e); + func_decl* f = a->get_decl(); + if (f->get_family_id() == m.get_basic_family_id() && p != pol_dual) { + switch(f->get_decl_kind()) { + case OP_NOT: + p = neg(p); + break; + case OP_AND: + case OP_OR: + break; + default: + p = pol_dual; + break; + } + } + else { + p = pol_dual; + } + for (unsigned i = 0; i < a->get_num_args(); ++i) { + forms.push_back(a->get_arg(i)); + pols.push_back(p); + } + } + } + + polarity_t neg(polarity_t p) { + switch (p) { + case pol_pos: return pol_neg; + case pol_neg: return pol_pos; + case pol_dual: return pol_dual; + } + return pol_dual; + } + + polarity_t join(polarity_t p, polarity_t q) { + if (p == q) return p; + return pol_dual; + } + + void rewrite_goal(rw& r, goal_ref const& g) { + expr_ref new_curr(m); + proof_ref new_pr(m); + unsigned sz = g->size(); + for (unsigned i = 0; i < sz; i++) { + expr * curr = g->form(i); + r(curr, new_curr, new_pr); + if (m_produce_proofs) { + proof * pr = g->pr(i); + new_pr = m.mk_modus_ponens(pr, new_pr); + } + g->update(i, new_curr, new_pr, g->dep(i)); + } + } + + +public: + nl_purify_tactic(ast_manager & m, params_ref const& p): + m(m), + m_util(m), + m_params(p), + m_nl_tac(mk_nlsat_tactic(m, p)), + m_solver(mk_smt_solver(m, p, symbol::null)), + m_fmc(0), + m_cancel(false), + m_eq_preds(m), + m_new_reals(m), + m_new_preds(m), + m_asms(m) + {} + + virtual ~nl_purify_tactic() {} + + virtual void updt_params(params_ref const & p) { + m_params = p; + } + + virtual tactic * translate(ast_manager& m) { + return alloc(nl_purify_tactic, m, m_params); + } + + virtual void set_cancel(bool f) { + if (f) { + m_nl_tac->cancel(); + m_solver->cancel(); + } + else { + m_solver->reset_cancel(); + m_nl_tac->reset_cancel(); + } + m_cancel = f; + } + + virtual void cleanup() { + m_solver = mk_smt_solver(m, m_params, symbol::null); + m_nl_tac->cleanup(); + m_eq_preds.reset(); + m_eq_values.reset(); + m_new_reals.reset(); + m_new_preds.reset(); + m_eq_pairs.reset(); + m_polarities.reset(); + } + + virtual void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) { + + tactic_report report("qfufnl-purify", *g); + m_produce_proofs = g->proofs_enabled(); + mc = 0; pc = 0; core = 0; + + fail_if_proof_generation("qfufnra-purify", g); + fail_if_unsat_core_generation("qfufnra-purify", g); + rw r(*this); + goal_ref nlg = alloc(goal, m, true, false); + + TRACE("nlsat_smt", g->display(tout);); + + // first hoist interface variables, + // then annotate subformulas by polarities, + // finally extract polynomial inequalities by + // creating a place-holder predicate inside the + // original goal and extracing pure nlsat clauses. + r.set_interface_var_mode(); + rewrite_goal(r, g); + get_polarities(*g.get()); + r.set_bool_mode(); + rewrite_goal(r, g); + + m_fmc = alloc(filter_model_converter, m); + app_ref_vector const& vars1 = m_new_reals; + for (unsigned i = 0; i < vars1.size(); ++i) { + SASSERT(is_uninterp_const(vars1[i])); + m_fmc->insert(vars1[i]->get_decl()); + } + app_ref_vector const& vars2 = m_new_preds; + for (unsigned i = 0; i < vars2.size(); ++i) { + SASSERT(is_uninterp_const(vars2[i])); + m_fmc->insert(vars2[i]->get_decl()); + } + + // add constraints to nlg. + unsigned sz = r.nl_cnstrs().size(); + for (unsigned i = 0; i < sz; i++) { + nlg->assert_expr(r.nl_cnstrs()[i], m_produce_proofs ? r.cfg().m_nl_cnstr_prs.get(i) : 0, 0); + } + g->inc_depth(); + for (unsigned i = 0; i < g->size(); ++i) { + m_solver->assert_expr(g->form(i)); + } + g->inc_depth(); + solve(nlg, result, mc); + } +}; + + +tactic * mk_nl_purify_tactic(ast_manager& m, params_ref const& p) { + return alloc(nl_purify_tactic, m, p); +} diff --git a/src/tactic/nlsat_smt/nl_purify_tactic.h b/src/tactic/nlsat_smt/nl_purify_tactic.h new file mode 100644 index 000000000..9ffc99676 --- /dev/null +++ b/src/tactic/nlsat_smt/nl_purify_tactic.h @@ -0,0 +1,35 @@ +/*++ +Copyright (c) 2011 Microsoft Corporation + +Module Name: + + nl_purify_tactic.h + +Abstract: + + Tactic for purifying quantifier-free formulas that mix QF_NRA and other theories. + It is designed to allow cooprating between the nlsat solver and other theories + in a decoubled way. + +Author: + + Nikolaj Bjorner (nbjorner) 2015-5-5. + +Revision History: + +--*/ +#ifndef _NL_PURIFY_TACTIC_H_ +#define _NL_PURIFY_TACTIC_H_ + +#include"params.h" +class ast_manager; +class tactic; + +tactic * mk_nl_purify_tactic(ast_manager & m, params_ref const & p = params_ref()); + +/* + ADD_TACTIC("nl-purify", "Decompose goal into pure NL-sat formula and formula over other theories.", "mk_nl_purify_tactic(m, p)") +*/ + +#endif + diff --git a/src/tactic/portfolio/default_tactic.cpp b/src/tactic/portfolio/default_tactic.cpp index 5a18e0830..ad811cc70 100644 --- a/src/tactic/portfolio/default_tactic.cpp +++ b/src/tactic/portfolio/default_tactic.cpp @@ -30,6 +30,7 @@ Notes: #include"qffp_tactic.h" #include"qfaufbv_tactic.h" #include"qfauflia_tactic.h" +#include"qfufnra_tactic.h" tactic * mk_default_tactic(ast_manager & m, params_ref const & p) { tactic * st = using_params(and_then(mk_simplify_tactic(m), @@ -43,7 +44,8 @@ tactic * mk_default_tactic(ast_manager & m, params_ref const & p) { cond(mk_is_nra_probe(), mk_nra_tactic(m), cond(mk_is_lira_probe(), mk_lira_tactic(m, p), cond(mk_is_qffp_probe(), mk_qffp_tactic(m, p), - mk_smt_tactic()))))))))))), + cond(mk_is_qfufnra_probe(), mk_qfufnra_tactic(m, p), + mk_smt_tactic())))))))))))), p); return st; } diff --git a/src/tactic/portfolio/smt_strategic_solver.cpp b/src/tactic/portfolio/smt_strategic_solver.cpp index dea1081b3..b28c8cf3d 100644 --- a/src/tactic/portfolio/smt_strategic_solver.cpp +++ b/src/tactic/portfolio/smt_strategic_solver.cpp @@ -34,6 +34,7 @@ Notes: #include"default_tactic.h" #include"ufbv_tactic.h" #include"qffp_tactic.h" +#include"qfufnra_tactic.h" #include"horn_tactic.h" #include"smt_solver.h" @@ -84,6 +85,8 @@ tactic * mk_tactic_for_logic(ast_manager & m, params_ref const & p, symbol const return mk_qffpbv_tactic(m, p); else if (logic=="HORN") return mk_horn_tactic(m, p); + else if (logic=="QF_UFNRA") + return mk_qfufnra_tactic(m, p); else return mk_default_tactic(m, p); } diff --git a/src/tactic/smtlogics/qfufnra_tactic.cpp b/src/tactic/smtlogics/qfufnra_tactic.cpp new file mode 100644 index 000000000..838573a19 --- /dev/null +++ b/src/tactic/smtlogics/qfufnra_tactic.cpp @@ -0,0 +1,46 @@ +/*++ +Copyright (c) 2015 Microsoft Corporation + +Module Name: + + qfufnra_tactic.cpp + +Abstract: + + Tactic for QF_UFNRA + +Author: + + Nikolaj (nbjorner) 2015-05-05 + +Notes: + +--*/ +#include"tactical.h" +#include"simplify_tactic.h" +#include"propagate_values_tactic.h" +#include"nl_purify_tactic.h" +#include"qfufnra_tactic.h" +#include"purify_arith_tactic.h" +#include"solve_eqs_tactic.h" +#include"elim_term_ite_tactic.h" +#include"elim_uncnstr_tactic.h" +#include"simplify_tactic.h" +#include"nnf_tactic.h" + + +tactic * mk_qfufnra_tactic(ast_manager & m, params_ref const& p) { + + return and_then(and_then(mk_simplify_tactic(m, p), + mk_purify_arith_tactic(m, p), + mk_propagate_values_tactic(m, p), + mk_solve_eqs_tactic(m, p), + mk_elim_uncnstr_tactic(m, p)), + and_then(mk_elim_term_ite_tactic(m, p), + mk_solve_eqs_tactic(m, p), + mk_simplify_tactic(m, p), + mk_nnf_tactic(m, p), + mk_nl_purify_tactic(m, p))); +} + + diff --git a/src/tactic/smtlogics/qfufnra_tactic.h b/src/tactic/smtlogics/qfufnra_tactic.h new file mode 100644 index 000000000..a2ac9b1ea --- /dev/null +++ b/src/tactic/smtlogics/qfufnra_tactic.h @@ -0,0 +1,31 @@ +/*++ +Copyright (c) 2012 Microsoft Corporation + +Module Name: + + qfufnra_tactic.h + +Abstract: + + Tactic for QF_UFNRA + +Author: + + Leonardo (leonardo) 2012-02-28 + +Notes: + +--*/ +#ifndef _QFUFNRA_TACTIC_ +#define _QFUFNRA_TACTIC_ + +#include"params.h" +class ast_manager; +class tactic; + +tactic * mk_qfufnra_tactic(ast_manager & m, params_ref const & p = params_ref()); +/* + ADD_TACTIC("qfufnra", "builtin strategy for solving QF_UNFRA problems.", "mk_qfufnra_tactic(m, p)") +*/ + +#endif diff --git a/src/tactic/tactic.cpp b/src/tactic/tactic.cpp index 198872cf5..5025b4449 100644 --- a/src/tactic/tactic.cpp +++ b/src/tactic/tactic.cpp @@ -207,7 +207,7 @@ lbool check_sat(tactic & t, goal_ref & g, model_ref & md, proof_ref & pr, expr_d TRACE("tactic_mc", mc->display(tout);); TRACE("tactic_check_sat", tout << "r.size(): " << r.size() << "\n"; - for (unsigned i = 0; i < r.size(); i++) r[0]->display(tout);); + for (unsigned i = 0; i < r.size(); i++) r[i]->display(tout);); if (is_decided_sat(r)) { if (models_enabled) { diff --git a/src/tactic/tactical.cpp b/src/tactic/tactical.cpp index cfb4ec194..9765bced5 100644 --- a/src/tactic/tactical.cpp +++ b/src/tactic/tactical.cpp @@ -283,6 +283,10 @@ tactic * and_then(tactic * t1, tactic * t2, tactic * t3, tactic * t4, tactic * t return and_then(t1, and_then(t2, t3, t4, t5, t6, t7, t8, t9, t10)); } +tactic * and_then(tactic * t1, tactic * t2, tactic * t3, tactic * t4, tactic * t5, tactic * t6, tactic * t7, tactic * t8, tactic * t9, tactic * t10, tactic * t11) { + return and_then(t1, and_then(t2, t3, t4, t5, t6, t7, t8, t9, t10, t11)); +} + tactic * and_then(unsigned num, tactic * const * ts) { SASSERT(num > 0); unsigned i = num - 1; diff --git a/src/tactic/tactical.h b/src/tactic/tactical.h index 4ceff2031..e291e6864 100644 --- a/src/tactic/tactical.h +++ b/src/tactic/tactical.h @@ -32,6 +32,7 @@ tactic * and_then(tactic * t1, tactic * t2, tactic * t3, tactic * t4, tactic * t tactic * and_then(tactic * t1, tactic * t2, tactic * t3, tactic * t4, tactic * t5, tactic * t6, tactic * t7, tactic * t8); tactic * and_then(tactic * t1, tactic * t2, tactic * t3, tactic * t4, tactic * t5, tactic * t6, tactic * t7, tactic * t8, tactic * t9); tactic * and_then(tactic * t1, tactic * t2, tactic * t3, tactic * t4, tactic * t5, tactic * t6, tactic * t7, tactic * t8, tactic * t9, tactic * t10); +tactic * and_then(tactic * t1, tactic * t2, tactic * t3, tactic * t4, tactic * t5, tactic * t6, tactic * t7, tactic * t8, tactic * t9, tactic * t10, tactic * t11); tactic * or_else(unsigned num, tactic * const * ts); tactic * or_else(tactic * t1, tactic * t2); diff --git a/src/test/ddnf.cpp b/src/test/ddnf.cpp new file mode 100644 index 000000000..3f8014128 --- /dev/null +++ b/src/test/ddnf.cpp @@ -0,0 +1,167 @@ +#include "ddnf.h" +#include "tbv.h" +#include +#include +#include +#include +#include +#include +#include +#include + +/* +TBD: count number of nodes, number of operations accross all insertions +*/ + +void read_nums(std::istream& is, unsigned & x, unsigned& y) { + x = 0; y = 0; + is >> x; + is >> y; + std::string line; + std::getline(is, line); +} + +static bool g_verbose = false; +static char const* g_file = 0; + + +void create_forwarding(char const* file, datalog::ddnf_core& ddnf, ptr_vector& tbvs) { + + if (g_verbose) { + std::cout << "creating (and forgetting) forwarding index\n"; + } + std::ifstream is(file); + if (is.bad() || is.fail()) { + std::cout << "could not load " << file << "\n"; + exit(0); + } + + std::string line; + unsigned W, M; + read_nums(is, W, M); + tbv_manager& tbvm = ddnf.get_tbv_manager(); + tbv* tX = tbvm.allocateX(); + unsigned_vector forwarding_set; + for (unsigned r = 0; r < M; ++r) { + unsigned P, K; + read_nums(is, K, P); + ddnf.reset_accumulate(); + unsigned p; + unsigned_vector forwarding_index; + forwarding_index.resize(ddnf.size()); + for (unsigned g = 0; g < K; ++g) { + is >> p; + std::getline(is, line); + tbv* t = tbvm.allocate(line.c_str()); + if (p > P) { + std::cout << "port number " << p << " too big " << P << "\n"; + tbvm.display(std::cout, *t) << " " << line << "\n"; + exit(0); + } + forwarding_set.reset(); + ddnf.accumulate(*t, forwarding_set); + for (unsigned i = 0; i < forwarding_set.size(); ++i) { + forwarding_index[forwarding_set[i]] = p; + } + tbvs.push_back(t); + if (p == 0 && tbvm.equals(*t, *tX)) break; + } + } + tbvm.deallocate(tX); +} + +datalog::ddnf_core* populate_ddnf(char const* file, ptr_vector& tbvs) { + + if (g_verbose) { + std::cout << "populate ddnf\n"; + } + + std::ifstream is(file); + if (is.bad() || is.fail()) { + std::cout << "could not load " << file << "\n"; + exit(0); + } + + std::string line; + unsigned W, M; + read_nums(is, W, M); + datalog::ddnf_core* ddnf = alloc(datalog::ddnf_core, W); + tbv_manager& tbvm = ddnf->get_tbv_manager(); + tbv* tX = tbvm.allocateX(); + for (unsigned r = 0; r < M; ++r) { + unsigned P, K; + read_nums(is, K, P); + if (g_verbose) { + std::cout << K << " " << P << "\n"; + } + unsigned p; + for (unsigned g = 0; g < K; ++g) { + is >> p; + std::getline(is, line); + tbv* t = tbvm.allocate(line.c_str()); + ddnf->insert(*t); + //tbvm.display(std::cout << line << " ", *t) << "\n"; + tbvs.push_back(t); + if (p > P) { + std::cout << "port number " << p << " too big " << P << "\n"; + tbvm.display(std::cout, *t) << " " << line << "\n"; + exit(0); + } + if (p == 0 && tbvm.equals(*t, *tX)) break; + } + } + + tbvm.deallocate(tX); + + return ddnf; +} + + +static void read_args(char ** argv, int argc) { + if (argc == 3) { + g_file = argv[2]; + return; + } + + for (int i = 2; i < argc; ++i) { + if (argv[i] == "v") { + g_verbose = true; + } + else { + g_file = argv[i]; + } + } + + if (!g_file) { + std::cout << "Need routing table file as argument. Arguments provided: "; + for (int i = 0; i < argc; ++i) { + std::cout << argv[i] << " "; + } + std::cout << "\n"; + exit(0); + } + +} + +void tst_ddnf(char ** argv, int argc, int& i) { + read_args(argv, argc); + ptr_vector tbvs; + datalog::ddnf_core* ddnf = populate_ddnf(g_file, tbvs); + create_forwarding(g_file, *ddnf, tbvs); + std::cout << "resulting size: " << ddnf->size() << "\n"; + ddnf->display_statistics(std::cout); + if (g_verbose) { + ddnf->display(std::cout); + } + std::cout.flush(); + + tbv_manager& tbvm = ddnf->get_tbv_manager(); + for (unsigned i = 0; i < tbvs.size(); ++i) { + tbvm.deallocate(tbvs[i]); + } + dealloc(ddnf); +} + + + + diff --git a/src/test/main.cpp b/src/test/main.cpp index 7b01e35c1..be12286fb 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -225,6 +225,7 @@ int main(int argc, char ** argv) { TST(simplex); TST(sat_user_scope); TST(pdr); + TST_ARGV(ddnf); //TST_ARGV(hs); } From e5716501e8f936100c2844242fdb1d2f9762da4f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 May 2015 19:47:00 -0700 Subject: [PATCH 754/925] add ddnf tests, add facility to solve QF_NRA + QF_UF(and other theories) in joint solver to allow broader use of QF_NRA core Signed-off-by: Nikolaj Bjorner --- src/tactic/arith/probe_arith.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tactic/arith/probe_arith.h b/src/tactic/arith/probe_arith.h index ba95a2837..0ff64a0ba 100644 --- a/src/tactic/arith/probe_arith.h +++ b/src/tactic/arith/probe_arith.h @@ -66,6 +66,6 @@ probe * mk_is_qfufnra_probe(); ADD_PROBE("is-lia", "true if the goal is in LIA (linear integer arithmetic, formula may have quantifiers).", "mk_is_lia_probe()") ADD_PROBE("is-lra", "true if the goal is in LRA (linear real arithmetic, formula may have quantifiers).", "mk_is_lra_probe()") ADD_PROBE("is-lira", "true if the goal is in LIRA (linear integer and real arithmetic, formula may have quantifiers).", "mk_is_lira_probe()") - ADD_PROBE("is-qfufnra", "true if the goal is QF_UFNRA (quantifier-free nonlinear real arithmetic with other theories).", mk_is_qfufnra_probe()"); + ADD_PROBE("is-qfufnra", "true if the goal is QF_UFNRA (quantifier-free nonlinear real arithmetic with other theories).", "mk_is_qfufnra_probe()") */ #endif From c807ad09273cd066b5137a9122be1b4c1ff3907e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 May 2015 21:28:26 -0700 Subject: [PATCH 755/925] add ddnf tests, add facility to solve QF_NRA + QF_UF(and other theories) in joint solver to allow broader use of QF_NRA core Signed-off-by: Nikolaj Bjorner --- src/tactic/nlsat_smt/nl_purify_tactic.cpp | 54 +++++++++++------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/tactic/nlsat_smt/nl_purify_tactic.cpp b/src/tactic/nlsat_smt/nl_purify_tactic.cpp index ec3419d2b..ef2e881dc 100644 --- a/src/tactic/nlsat_smt/nl_purify_tactic.cpp +++ b/src/tactic/nlsat_smt/nl_purify_tactic.cpp @@ -1,5 +1,5 @@ /*++ -Copyright (c) 2011 Microsoft Corporation +Copyright (c) 2015 Microsoft Corporation Module Name: @@ -43,12 +43,6 @@ Author: Revision History: -- check for input assumptions -- check for proof mode -- check for quantifiers -- add applicability filter -- add to smtlogics - --*/ #include "tactical.h" #include "nl_purify_tactic.h" @@ -165,10 +159,17 @@ public: throw tactic_exception("quantifiers are not supported in mixed-mode nlsat engine"); } + br_status reduce_app(func_decl * f, unsigned num, expr* const* args, expr_ref& result, proof_ref & pr) { + if (m_mode == mode_bool_preds) { + return reduce_app_bool(f, num, args, result, pr); + } + else { + return reduce_app_real(f, num, args, result, pr); + } + } + br_status reduce_app_bool(func_decl * f, unsigned num, expr* const* args, expr_ref& result, proof_ref & pr) { if (f->get_family_id() == m.get_basic_family_id()) { - // TBD: do we have negated inequalities for strict? - // maybe equalities are already deleted by pre-processor stage, but why depend on this? if (f->get_decl_kind() == OP_EQ && u().is_real(args[0])) { mk_interface_bool(f, num, args, result); return BR_DONE; @@ -179,23 +180,30 @@ public: } if (f->get_family_id() == u().get_family_id()) { switch (f->get_decl_kind()) { - case OP_LE: - case OP_GE: - case OP_LT: - case OP_GT: + case OP_LE: case OP_GE: case OP_LT: case OP_GT: // these are the only real cases of non-linear atomic formulas besides equality. mk_interface_bool(f, num, args, result); return BR_DONE; default: return BR_FAILED; } - } + } return BR_FAILED; } br_status reduce_app_real(func_decl * f, unsigned num, expr* const* args, expr_ref& result, proof_ref & pr) { - m_args.reset(); bool has_interface = false; + if (f->get_family_id() == u().get_family_id()) { + switch (f->get_decl_kind()) { + case OP_NUM: case OP_IRRATIONAL_ALGEBRAIC_NUM: + case OP_ADD: case OP_MUL: case OP_SUB: + case OP_UMINUS: case OP_ABS: case OP_POWER: + return BR_FAILED; + default: + break; + } + } + m_args.reset(); for (unsigned i = 0; i < num; ++i) { expr* arg = args[i]; if (u().is_real(arg)) { @@ -215,17 +223,10 @@ public: return BR_FAILED; } } - - br_status reduce_app(func_decl * f, unsigned num, expr* const* args, expr_ref& result, proof_ref & pr) { - if (m_mode == mode_bool_preds) { - return reduce_app_bool(f, num, args, result, pr); - } - else { - return reduce_app_real(f, num, args, result, pr); - } - } }; + private: + class rw : public rewriter_tpl { rw_cfg m_cfg; public: @@ -242,7 +243,6 @@ private: void set_interface_var_mode() { m_cfg.m_mode = rw_cfg::mode_interface_var; } - }; arith_util & u() { return m_util; } @@ -375,7 +375,7 @@ private: } for (unsigned i = 0; i < m_eq_preds.size(); ++i) { expr* pred = m_eq_preds[i].get(); - switch(m_eq_values[i]) { + switch (m_eq_values[i]) { case l_true: m_asms.push_back(pred); break; @@ -558,8 +558,8 @@ private: } } - public: + nl_purify_tactic(ast_manager & m, params_ref const& p): m(m), m_util(m), From f5c048775ba14493a2e206c4601c4528b08b2fb1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 10 May 2015 09:42:11 -0700 Subject: [PATCH 756/925] add facility to solve QF_NRA + QF_UF(and other theories) in joint solver to allow broader use of QF_NRA core Signed-off-by: Nikolaj Bjorner --- src/tactic/arith/probe_arith.cpp | 25 +++++++++++++++++++---- src/tactic/nlsat_smt/nl_purify_tactic.cpp | 13 ++++++++++++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/tactic/arith/probe_arith.cpp b/src/tactic/arith/probe_arith.cpp index ae287e2b5..327b074b9 100644 --- a/src/tactic/arith/probe_arith.cpp +++ b/src/tactic/arith/probe_arith.cpp @@ -518,13 +518,19 @@ struct is_non_qfufnra_functor { struct found {}; ast_manager & m; arith_util u; + bool m_has_nonlinear; - is_non_qfufnra_functor(ast_manager & _m): m(_m), u(m) {} + is_non_qfufnra_functor(ast_manager & _m): + m(_m), u(m), m_has_nonlinear(false) {} void throw_found() { throw found(); } + bool has_nonlinear() const { + return m_has_nonlinear; + } + void operator()(var * x) { throw_found(); } @@ -539,14 +545,25 @@ struct is_non_qfufnra_functor { switch (n->get_decl_kind()) { case OP_LE: case OP_GE: case OP_LT: case OP_GT: case OP_ADD: case OP_UMINUS: case OP_SUB: case OP_ABS: - case OP_NUM: case OP_MUL: + case OP_NUM: case OP_IRRATIONAL_ALGEBRAIC_NUM: return; + case OP_MUL: + if (n->get_num_args() == 2 || + (!u.is_numeral(n->get_arg(0)) && + !u.is_numeral(n->get_arg(1)))) { + m_has_nonlinear = true; + } + return; case OP_IDIV: case OP_DIV: case OP_REM: case OP_MOD: - case OP_POWER: if (!u.is_numeral(n->get_arg(1))) throw_found(); return; + case OP_POWER: + if (!u.is_numeral(n->get_arg(1))) + throw_found(); + m_has_nonlinear = true; + return; case OP_IS_INT: case OP_TO_INT: case OP_TO_REAL: @@ -618,7 +635,7 @@ public: static bool is_qfufnra(goal const& g) { is_non_qfufnra_functor p(g.m()); - return !test(g, p); + return !test(g, p) && p.has_nonlinear(); } class is_qfufnra_probe : public probe { diff --git a/src/tactic/nlsat_smt/nl_purify_tactic.cpp b/src/tactic/nlsat_smt/nl_purify_tactic.cpp index ef2e881dc..dd0a76f15 100644 --- a/src/tactic/nlsat_smt/nl_purify_tactic.cpp +++ b/src/tactic/nlsat_smt/nl_purify_tactic.cpp @@ -130,9 +130,22 @@ public: r = m.mk_fresh_const(0, u().mk_real()); m_new_reals.push_back(to_app(r)); m_interface_cache.insert(arg, r); + expr_ref eq(m); + eq = m.mk_eq(r, arg); + if (is_real_expression(arg)) { + m_nl_cnstrs.push_back(eq); + m_nl_cnstr_prs.push_back(m.mk_oeq(r, arg)); + } + else { + m_owner.m_solver->assert_expr(eq); + } return r; } + bool is_real_expression(expr* e) { + return is_app(e) && (to_app(e)->get_family_id() == u().get_family_id()); + } + void mk_interface_bool(func_decl * f, unsigned num, expr* const* args, expr_ref& result) { expr_ref old_pred(m.mk_app(f, num, args), m); polarity_t pol; From 6163085ff82df93dd0eb9b81be11b315c5dbd8d3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 10 May 2015 10:02:44 -0700 Subject: [PATCH 757/925] add facility to solve QF_NRA + QF_UF(and other theories) in joint solver to allow broader use of QF_NRA core Signed-off-by: Nikolaj Bjorner --- src/tactic/nlsat_smt/nl_purify_tactic.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tactic/nlsat_smt/nl_purify_tactic.cpp b/src/tactic/nlsat_smt/nl_purify_tactic.cpp index dd0a76f15..312e26ad0 100644 --- a/src/tactic/nlsat_smt/nl_purify_tactic.cpp +++ b/src/tactic/nlsat_smt/nl_purify_tactic.cpp @@ -182,6 +182,7 @@ public: } br_status reduce_app_bool(func_decl * f, unsigned num, expr* const* args, expr_ref& result, proof_ref & pr) { + TRACE("nlsat_smt", { expr_ref tmp(m); tmp = m.mk_app(f, num, args); tout << "reduce: " << tmp << "\n";}); if (f->get_family_id() == m.get_basic_family_id()) { if (f->get_decl_kind() == OP_EQ && u().is_real(args[0])) { mk_interface_bool(f, num, args, result); @@ -557,6 +558,7 @@ private: } void rewrite_goal(rw& r, goal_ref const& g) { + r.reset(); expr_ref new_curr(m); proof_ref new_pr(m); unsigned sz = g->size(); From 5063a2cdb6f0e8a87eef938642f0e995d30bcfd6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 10 May 2015 11:53:36 -0700 Subject: [PATCH 758/925] add facility to solve QF_NRA + QF_UF(and other theories) in joint solver to allow broader use of QF_NRA core Signed-off-by: Nikolaj Bjorner --- src/tactic/nlsat_smt/nl_purify_tactic.cpp | 164 +++++++++++++--------- src/tactic/smtlogics/qfufnra_tactic.cpp | 14 +- 2 files changed, 110 insertions(+), 68 deletions(-) diff --git a/src/tactic/nlsat_smt/nl_purify_tactic.cpp b/src/tactic/nlsat_smt/nl_purify_tactic.cpp index 312e26ad0..6ff149580 100644 --- a/src/tactic/nlsat_smt/nl_purify_tactic.cpp +++ b/src/tactic/nlsat_smt/nl_purify_tactic.cpp @@ -56,6 +56,8 @@ Revision History: #include "trace.h" #include "smt_solver.h" #include "solver.h" +#include "model_smt2_pp.h" +#include "expr_safe_replace.h" class nl_purify_tactic : public tactic { @@ -72,6 +74,7 @@ class nl_purify_tactic : public tactic { ref m_fmc; bool m_cancel; tactic_ref m_nl_tac; // nlsat tactic + goal_ref m_nl_g; // nlsat goal ref m_solver; // SMT solver expr_ref_vector m_eq_preds; // predicates for equality between pairs of interface variables svector m_eq_values; // truth value of the equality predicates in nlsat @@ -94,8 +97,6 @@ public: app_ref_vector& m_new_preds; obj_map& m_polarities; obj_map& m_interface_cache; - expr_ref_vector m_nl_cnstrs; - proof_ref_vector m_nl_cnstr_prs; expr_ref_vector m_args; mode_t m_mode; @@ -106,8 +107,6 @@ public: m_new_preds(o.m_new_preds), m_polarities(o.m_polarities), m_interface_cache(o.m_interface_cache), - m_nl_cnstrs(m), - m_nl_cnstr_prs(m), m_args(m), m_mode(mode_interface_var) { } @@ -129,12 +128,12 @@ public: } r = m.mk_fresh_const(0, u().mk_real()); m_new_reals.push_back(to_app(r)); + m_owner.m_fmc->insert(to_app(r)->get_decl()); m_interface_cache.insert(arg, r); expr_ref eq(m); eq = m.mk_eq(r, arg); if (is_real_expression(arg)) { - m_nl_cnstrs.push_back(eq); - m_nl_cnstr_prs.push_back(m.mk_oeq(r, arg)); + m_owner.m_nl_g->assert_expr(eq); // m.mk_oeq(r, arg) } else { m_owner.m_solver->assert_expr(eq); @@ -149,18 +148,18 @@ public: void mk_interface_bool(func_decl * f, unsigned num, expr* const* args, expr_ref& result) { expr_ref old_pred(m.mk_app(f, num, args), m); polarity_t pol; - TRACE("nlsat_smt", tout << old_pred << "\n";); VERIFY(m_polarities.find(old_pred, pol)); result = m.mk_fresh_const(0, m.mk_bool_sort()); m_polarities.insert(result, pol); m_new_preds.push_back(to_app(result)); + m_owner.m_fmc->insert(to_app(result)->get_decl()); if (pol != pol_neg) { - m_nl_cnstrs.push_back(m.mk_or(m.mk_not(result), m.mk_app(f, num, args))); + m_owner.m_nl_g->assert_expr(m.mk_or(m.mk_not(result), m.mk_app(f, num, args))); } if (pol != pol_pos) { - m_nl_cnstrs.push_back(m.mk_or(result, m.mk_not(m.mk_app(f, num, args)))); + m_owner.m_nl_g->assert_expr(m.mk_or(result, m.mk_not(m.mk_app(f, num, args)))); } - TRACE("nlsat_smt", tout << result << " : " << mk_pp(m_nl_cnstrs.back(), m) << "\n";); + TRACE("nlsat_smt", tout << old_pred << " : " << result << "\n";); } bool reduce_quantifier(quantifier * old_q, @@ -182,7 +181,6 @@ public: } br_status reduce_app_bool(func_decl * f, unsigned num, expr* const* args, expr_ref& result, proof_ref & pr) { - TRACE("nlsat_smt", { expr_ref tmp(m); tmp = m.mk_app(f, num, args); tout << "reduce: " << tmp << "\n";}); if (f->get_family_id() == m.get_basic_family_id()) { if (f->get_decl_kind() == OP_EQ && u().is_real(args[0])) { mk_interface_bool(f, num, args, result); @@ -248,9 +246,6 @@ private: rewriter_tpl(o.m, o.m_produce_proofs, m_cfg), m_cfg(o) { } - expr_ref_vector const& nl_cnstrs() const { - return m_cfg.m_nl_cnstrs; - } void set_bool_mode() { m_cfg.m_mode = rw_cfg::mode_bool_preds; } @@ -289,19 +284,18 @@ private: } } - void solve(goal_ref const& nl_g, - goal_ref_buffer& result, + void solve(goal_ref_buffer& result, model_converter_ref& mc) { while (true) { check_point(); - TRACE("nlsat_smt", m_solver->display(tout << "SMT:\n"); nl_g->display(tout << "\nNL:\n"); ); + TRACE("nlsat_smt", m_solver->display(tout << "SMT:\n"); m_nl_g->display(tout << "\nNL:\n"); ); goal_ref tmp_nl = alloc(goal, m, true, false); model_converter_ref nl_mc; proof_converter_ref nl_pc; expr_dependency_ref nl_core(m); result.reset(); - tmp_nl->copy_from(*nl_g.get()); + tmp_nl->copy_from(*m_nl_g.get()); (*m_nl_tac)(tmp_nl, result, nl_mc, nl_pc, nl_core); if (is_decided_unsat(result)) { @@ -319,11 +313,13 @@ private: model_ref mdl_nl, mdl_smt; model_converter2model(m, nl_mc.get(), mdl_nl); update_eq_values(mdl_nl); - enforce_equalities(mdl_nl, nl_g); + enforce_equalities(mdl_nl, m_nl_g); setup_assumptions(mdl_nl); - TRACE("nlsat_smt", m_solver->display(tout << "smt goal:\n"); ); + TRACE("nlsat_smt", + model_smt2_pp(tout << "nl model\n", m, *mdl_nl.get(), 0); + m_solver->display(tout << "smt goal:\n"); tout << "\n";); result.reset(); lbool r = m_solver->check_sat(m_asms.size(), m_asms.c_ptr()); @@ -344,12 +340,12 @@ private: clause.push_back(m.is_not(core[i], e)?e:m.mk_not(core[i])); } fml = m.mk_or(clause.size(), clause.c_ptr()); - nl_g->assert_expr(fml); + m_nl_g->assert_expr(fml); continue; } else if (r == l_true) { m_solver->get_model(mdl_smt); - if (enforce_equalities(mdl_smt, nl_g)) { + if (enforce_equalities(mdl_smt, m_nl_g)) { // SMT enforced a new equality that wasn't true for nlsat. continue; } @@ -370,6 +366,7 @@ private: TRACE("nlsat_smt", display_result(tout, result);); } + void setup_assumptions(model_ref& mdl) { m_asms.reset(); app_ref_vector const& fresh_preds = m_new_preds; @@ -377,16 +374,17 @@ private: for (unsigned i = 0; i < fresh_preds.size(); ++i) { expr* pred = fresh_preds[i]; if (mdl->eval(pred, tmp)) { - TRACE("nlsat_smt", tout << "pred: " << mk_pp(pred, m) << "\n";); polarity_t pol = m_polarities.find(pred); - if (pol != pol_neg && m.is_true(tmp)) { - m_asms.push_back(pred); - } - else if (pol != pol_pos && m.is_false(tmp)) { + // if assumptinon literals are used to satisfy NL state, + // we have to assume them when satisfying SMT state + if (pol != pol_neg && m.is_false(tmp)) { m_asms.push_back(m.mk_not(pred)); } + else if (pol != pol_pos && m.is_true(tmp)) { + m_asms.push_back(pred); + } } - } + } for (unsigned i = 0; i < m_eq_preds.size(); ++i) { expr* pred = m_eq_preds[i].get(); switch (m_eq_values[i]) { @@ -400,6 +398,11 @@ private: break; } } + TRACE("nlsat_smt", + tout << "assumptions:\n"; + for (unsigned i = 0; i < m_asms.size(); ++i) { + tout << mk_pp(m_asms[i].get(), m) << "\n"; + }); } bool enforce_equalities(model_ref& mdl, goal_ref const& nl_g) { @@ -439,9 +442,9 @@ private: } void merge_models(model const& mdl_nl, model_ref& mdl_smt) { - obj_map num2num; + expr_safe_replace num2num(m); expr_ref result(m), val2(m); - expr_ref_vector args(m), trail(m); + expr_ref_vector args(m); unsigned sz = mdl_nl.get_num_constants(); for (unsigned i = 0; i < sz; ++i) { func_decl* v = mdl_nl.get_constant(i); @@ -450,7 +453,6 @@ private: if (mdl_smt->eval(v, val2)) { if (val != val2) { num2num.insert(val2, val); - trail.push_back(val2); } } } @@ -466,13 +468,13 @@ private: args.reset(); func_entry const* entry = f1->get_entry(j); for (unsigned k = 0; k < arity; ++k) { - args.push_back(translate(num2num, entry->get_arg(k))); + translate(num2num, entry->get_arg(k), result); + args.push_back(result); } - result = translate(num2num, entry->get_result()); + translate(num2num, entry->get_result(), result); f2->insert_entry(args.c_ptr(), result); } - expr* e = f1->get_else(); - result = translate(num2num, e); + translate(num2num, f1->get_else(), result); f2->set_else(result); mdl_smt->register_decl(f, f2); } @@ -487,11 +489,11 @@ private: return u().is_real(f->get_range()); } - expr* translate(obj_map const& num2num, expr* e) { - if (!e || !u().is_real(e)) return e; - expr* result = 0; - if (num2num.find(e, result)) return result; - return e; + void translate(expr_safe_replace& num2num, expr* e, expr_ref& result) { + result = 0; + if (e) { + num2num(e, result); + } } void get_polarities(goal const& g) { @@ -512,7 +514,7 @@ private: if (p == q || q == pol_dual) continue; p = pol_dual; } - TRACE("nlsat_smt", tout << mk_pp(e, m) << "\n";); + TRACE("nlsat_smt_verbose", tout << mk_pp(e, m) << "\n";); m_polarities.insert(e, p); if (is_quantifier(e) || is_var(e)) { throw tactic_exception("nl-purify tactic does not support quantifiers"); @@ -573,6 +575,56 @@ private: } } + void remove_pure_arith(goal_ref const& g) { + obj_map is_pure; + unsigned sz = g->size(); + for (unsigned i = 0; i < sz; i++) { + expr * curr = g->form(i); + if (is_pure_arithmetic(is_pure, curr)) { + m_nl_g->assert_expr(curr, g->pr(i), g->dep(i)); + g->update(i, m.mk_true()); + } + } + } + + bool is_pure_arithmetic(obj_map& is_pure, expr* e0) { + ptr_vector todo; + todo.push_back(e0); + while (!todo.empty()) { + expr* e = todo.back(); + if (is_pure.contains(e)) { + todo.pop_back(); + continue; + } + if (!is_app(e)) { + todo.pop_back(); + is_pure.insert(e, false); + continue; + } + app* a = to_app(e); + bool pure = false, all_found = true, p; + pure |= (a->get_family_id() == u().get_family_id()) && u().is_real(a); + pure |= (m.is_eq(e) && u().is_real(a->get_arg(0))); + pure |= (a->get_family_id() == u().get_family_id()) && m.is_bool(a) && u().is_real(a->get_arg(0)); + pure |= (a->get_family_id() == m.get_basic_family_id()); + pure |= is_uninterp_const(a) && u().is_real(a); + for (unsigned i = 0; i < a->get_num_args(); ++i) { + if (!is_pure.find(a->get_arg(i), p)) { + todo.push_back(a->get_arg(i)); + all_found = false; + } + else { + pure &= p; + } + } + if (all_found) { + is_pure.insert(e, pure); + todo.pop_back(); + } + } + return is_pure.find(e0); + } + public: nl_purify_tactic(ast_manager & m, params_ref const& p): @@ -580,6 +632,7 @@ public: m_util(m), m_params(p), m_nl_tac(mk_nlsat_tactic(m, p)), + m_nl_g(0), m_solver(mk_smt_solver(m, p, symbol::null)), m_fmc(0), m_cancel(false), @@ -629,15 +682,16 @@ public: expr_dependency_ref & core) { tactic_report report("qfufnl-purify", *g); + TRACE("nlsat_smt", g->display(tout);); + m_produce_proofs = g->proofs_enabled(); mc = 0; pc = 0; core = 0; fail_if_proof_generation("qfufnra-purify", g); fail_if_unsat_core_generation("qfufnra-purify", g); rw r(*this); - goal_ref nlg = alloc(goal, m, true, false); - - TRACE("nlsat_smt", g->display(tout);); + m_nl_g = alloc(goal, m, true, false); + m_fmc = alloc(filter_model_converter, m); // first hoist interface variables, // then annotate subformulas by polarities, @@ -645,34 +699,18 @@ public: // creating a place-holder predicate inside the // original goal and extracing pure nlsat clauses. r.set_interface_var_mode(); - rewrite_goal(r, g); + rewrite_goal(r, g); + remove_pure_arith(g); get_polarities(*g.get()); r.set_bool_mode(); rewrite_goal(r, g); - m_fmc = alloc(filter_model_converter, m); - app_ref_vector const& vars1 = m_new_reals; - for (unsigned i = 0; i < vars1.size(); ++i) { - SASSERT(is_uninterp_const(vars1[i])); - m_fmc->insert(vars1[i]->get_decl()); - } - app_ref_vector const& vars2 = m_new_preds; - for (unsigned i = 0; i < vars2.size(); ++i) { - SASSERT(is_uninterp_const(vars2[i])); - m_fmc->insert(vars2[i]->get_decl()); - } - - // add constraints to nlg. - unsigned sz = r.nl_cnstrs().size(); - for (unsigned i = 0; i < sz; i++) { - nlg->assert_expr(r.nl_cnstrs()[i], m_produce_proofs ? r.cfg().m_nl_cnstr_prs.get(i) : 0, 0); - } g->inc_depth(); for (unsigned i = 0; i < g->size(); ++i) { m_solver->assert_expr(g->form(i)); } g->inc_depth(); - solve(nlg, result, mc); + solve(result, mc); } }; diff --git a/src/tactic/smtlogics/qfufnra_tactic.cpp b/src/tactic/smtlogics/qfufnra_tactic.cpp index 838573a19..4ca241e19 100644 --- a/src/tactic/smtlogics/qfufnra_tactic.cpp +++ b/src/tactic/smtlogics/qfufnra_tactic.cpp @@ -27,19 +27,23 @@ Notes: #include"elim_uncnstr_tactic.h" #include"simplify_tactic.h" #include"nnf_tactic.h" - +#include"tseitin_cnf_tactic.h" tactic * mk_qfufnra_tactic(ast_manager & m, params_ref const& p) { - - return and_then(and_then(mk_simplify_tactic(m, p), + params_ref main_p = p; + main_p.set_bool("elim_and", true); + main_p.set_bool("blast_distinct", true); + + return and_then(and_then(using_params(mk_simplify_tactic(m, p), main_p), mk_purify_arith_tactic(m, p), mk_propagate_values_tactic(m, p), mk_solve_eqs_tactic(m, p), mk_elim_uncnstr_tactic(m, p)), and_then(mk_elim_term_ite_tactic(m, p), mk_solve_eqs_tactic(m, p), - mk_simplify_tactic(m, p), - mk_nnf_tactic(m, p), + using_params(mk_simplify_tactic(m, p), main_p), + mk_tseitin_cnf_core_tactic(m, p), + using_params(mk_simplify_tactic(m, p), main_p), mk_nl_purify_tactic(m, p))); } From 1a4e8f89bde8bd0843262415d0adf2900157d071 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 10 May 2015 14:53:05 -0700 Subject: [PATCH 759/925] fix release build failure Signed-off-by: Nikolaj Bjorner --- src/tactic/nlsat_smt/nl_purify_tactic.cpp | 2 +- src/test/ddnf.cpp | 27 ++++------------------- 2 files changed, 5 insertions(+), 24 deletions(-) diff --git a/src/tactic/nlsat_smt/nl_purify_tactic.cpp b/src/tactic/nlsat_smt/nl_purify_tactic.cpp index 6ff149580..5f0163077 100644 --- a/src/tactic/nlsat_smt/nl_purify_tactic.cpp +++ b/src/tactic/nlsat_smt/nl_purify_tactic.cpp @@ -264,7 +264,7 @@ private: void display_result(std::ostream& out, goal_ref_buffer const& result) { for (unsigned i = 0; i < result.size(); ++i) { - result[i]->display(tout << "goal\n"); + result[i]->display(out << "goal\n"); } } diff --git a/src/test/ddnf.cpp b/src/test/ddnf.cpp index 3f8014128..5ab395e20 100644 --- a/src/test/ddnf.cpp +++ b/src/test/ddnf.cpp @@ -21,15 +21,12 @@ void read_nums(std::istream& is, unsigned & x, unsigned& y) { std::getline(is, line); } -static bool g_verbose = false; static char const* g_file = 0; void create_forwarding(char const* file, datalog::ddnf_core& ddnf, ptr_vector& tbvs) { - if (g_verbose) { - std::cout << "creating (and forgetting) forwarding index\n"; - } + IF_VERBOSE(1, verbose_stream() << "creating (and forgetting) forwarding index\n";); std::ifstream is(file); if (is.bad() || is.fail()) { std::cout << "could not load " << file << "\n"; @@ -72,9 +69,7 @@ void create_forwarding(char const* file, datalog::ddnf_core& ddnf, ptr_vector& tbvs) { - if (g_verbose) { - std::cout << "populate ddnf\n"; - } + IF_VERBOSE(1, verbose_stream() << "populate ddnf\n";); std::ifstream is(file); if (is.bad() || is.fail()) { @@ -91,9 +86,7 @@ datalog::ddnf_core* populate_ddnf(char const* file, ptr_vector& tbvs) { for (unsigned r = 0; r < M; ++r) { unsigned P, K; read_nums(is, K, P); - if (g_verbose) { - std::cout << K << " " << P << "\n"; - } + IF_VERBOSE(1, verbose_stream() << K << " " << P << "\n";); unsigned p; for (unsigned g = 0; g < K; ++g) { is >> p; @@ -123,15 +116,6 @@ static void read_args(char ** argv, int argc) { return; } - for (int i = 2; i < argc; ++i) { - if (argv[i] == "v") { - g_verbose = true; - } - else { - g_file = argv[i]; - } - } - if (!g_file) { std::cout << "Need routing table file as argument. Arguments provided: "; for (int i = 0; i < argc; ++i) { @@ -150,10 +134,7 @@ void tst_ddnf(char ** argv, int argc, int& i) { create_forwarding(g_file, *ddnf, tbvs); std::cout << "resulting size: " << ddnf->size() << "\n"; ddnf->display_statistics(std::cout); - if (g_verbose) { - ddnf->display(std::cout); - } - std::cout.flush(); + IF_VERBOSE(1, ddnf->display(verbose_stream());); tbv_manager& tbvm = ddnf->get_tbv_manager(); for (unsigned i = 0; i < tbvs.size(); ++i) { From 2e627e78bc37003fd8070c3219088f6d2a9d7f7f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 10 May 2015 14:55:28 -0700 Subject: [PATCH 760/925] filter tactic on proofs and cores Signed-off-by: Nikolaj Bjorner --- src/tactic/arith/probe_arith.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tactic/arith/probe_arith.cpp b/src/tactic/arith/probe_arith.cpp index 327b074b9..e276d1792 100644 --- a/src/tactic/arith/probe_arith.cpp +++ b/src/tactic/arith/probe_arith.cpp @@ -635,7 +635,7 @@ public: static bool is_qfufnra(goal const& g) { is_non_qfufnra_functor p(g.m()); - return !test(g, p) && p.has_nonlinear(); + return !g.proofs_enabled() && !g.unsat_core_enabled() && !test(g, p) && p.has_nonlinear(); } class is_qfufnra_probe : public probe { From 6645358fedb36e7966e3d1a8d22d834d04430e6d Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Sun, 10 May 2015 22:30:07 +0000 Subject: [PATCH 761/925] fix issue #57: undefined behavior in bit_vector.h --- src/util/bit_vector.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/util/bit_vector.h b/src/util/bit_vector.h index 6738ba0aa..43b0e9619 100644 --- a/src/util/bit_vector.h +++ b/src/util/bit_vector.h @@ -75,8 +75,11 @@ public: bit_vector(bit_vector const & source): m_num_bits(source.m_num_bits), m_capacity(source.m_capacity), - m_data(alloc_svect(unsigned, source.m_capacity)) { - memcpy(m_data, source.m_data, source.m_capacity * sizeof(unsigned)); + m_data(0) { + if (source.m_data) { + m_data = alloc_svect(unsigned, m_capacity); + memcpy(m_data, source.m_data, m_capacity * sizeof(unsigned)); + } } bit_vector(unsigned const * source, int num_bits): @@ -183,6 +186,9 @@ public: bool operator!=(bit_vector const & other) const { return !operator==(other); } bit_vector & operator=(bit_vector const & source) { + if (!source.m_data) + return *this; + m_num_bits = source.m_num_bits; if (m_capacity < source.m_capacity) { dealloc_svect(m_data); From 091ae37c06eb8875f4cf939d676ac15fd455cd0d Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 11 May 2015 04:44:11 +0100 Subject: [PATCH 762/925] Fix bug in my previous patch in bit_vector::operator=() Signed-off-by: Nuno Lopes --- src/util/bit_vector.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/bit_vector.h b/src/util/bit_vector.h index 43b0e9619..f7af2019d 100644 --- a/src/util/bit_vector.h +++ b/src/util/bit_vector.h @@ -186,10 +186,10 @@ public: bool operator!=(bit_vector const & other) const { return !operator==(other); } bit_vector & operator=(bit_vector const & source) { + m_num_bits = source.m_num_bits; if (!source.m_data) return *this; - m_num_bits = source.m_num_bits; if (m_capacity < source.m_capacity) { dealloc_svect(m_data); m_data = alloc_svect(unsigned, source.m_capacity); From 379ce66391a2d1de57424b8b99dfa22dc290130b Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 11 May 2015 06:30:24 +0100 Subject: [PATCH 763/925] fix a few undefined behaviors exposed by the unit tests Signed-off-by: Nuno Lopes --- src/util/bit_util.cpp | 2 +- src/util/mpff.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/util/bit_util.cpp b/src/util/bit_util.cpp index 0f1fd294d..fde66b054 100644 --- a/src/util/bit_util.cpp +++ b/src/util/bit_util.cpp @@ -351,7 +351,7 @@ bool has_one_at_first_k_bits(unsigned sz, unsigned const * data, unsigned k) { } if (word_sz < sz) { unsigned bit_sz = k % (8 * sizeof(unsigned)); - unsigned mask = (1 << bit_sz) - 1; + unsigned mask = (1u << bit_sz) - 1; return (data[word_sz] & mask) != 0; } return false; diff --git a/src/util/mpff.cpp b/src/util/mpff.cpp index b979b32ff..14c67e7c0 100644 --- a/src/util/mpff.cpp +++ b/src/util/mpff.cpp @@ -255,7 +255,7 @@ void mpff_manager::set(mpff & n, int64 v) { } else { if (v < 0) { - set(n, static_cast(-v)); + set(n, -static_cast(v)); n.m_sign = 1; } else { @@ -680,7 +680,7 @@ void mpff_manager::add_sub(bool is_sub, mpff const & a, mpff const & b, mpff & c // Make sure that a and b have the same exponent. if (exp_a > exp_b) { - unsigned shift = exp_a - exp_b; + unsigned shift = (unsigned)exp_a - (unsigned)exp_b; n_sig_b = m_buffers[0].c_ptr(); shr(m_precision, sig_b, shift, m_precision, n_sig_b); if (sgn_b != m_to_plus_inf && has_one_at_first_k_bits(m_precision, sig_b, shift)) { From e53462c1c1b6c4231714cab7e48f9fbc69a3dd61 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 11 May 2015 17:11:21 -0700 Subject: [PATCH 764/925] update ddnf experiment code Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/ddnf.cpp | 43 +++++++++++++++++++++++++++++++++++++++---- src/muz/ddnf/ddnf.h | 2 ++ src/test/ddnf.cpp | 3 +++ 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/src/muz/ddnf/ddnf.cpp b/src/muz/ddnf/ddnf.cpp index 82cb9d1fa..14f4a2b75 100644 --- a/src/muz/ddnf/ddnf.cpp +++ b/src/muz/ddnf/ddnf.cpp @@ -194,6 +194,7 @@ namespace datalog { new_tbvs.push_back(&t); for (unsigned i = 0; i < new_tbvs.size(); ++i) { tbv const& nt = *new_tbvs[i]; + IF_VERBOSE(10, m_tbv.display(verbose_stream() << "insert: ", nt); verbose_stream() << "\n";); if (contains(nt)) continue; ddnf_node* n = alloc(ddnf_node, *this, m_tbv, nt, m_noderefs.size()); m_noderefs.push_back(n); @@ -233,6 +234,37 @@ namespace datalog { } } + bool contains(tbv const& t) { + ddnf_node dummy(*this, m_tbv, t, 0); + return m_nodes.contains(&dummy); + } + + bool well_formed() { + ptr_vector todo; + todo.push_back(m_root); + reset_accumulate(); + while (!todo.empty()) { + ddnf_node* n = todo.back(); + todo.pop_back(); + if (m_marked[n->get_id()]) continue; + m_marked[n->get_id()] = true; + unsigned sz = n->num_children(); + for (unsigned i = 0; i < sz; ++i) { + ddnf_node* child = (*n)[i]; + if (!m_tbv.contains(n->get_tbv(), child->get_tbv())) { + IF_VERBOSE(0, + m_tbv.display(verbose_stream() << "parent ", n->get_tbv()); + m_tbv.display(verbose_stream() << " does not contains child: ", child->get_tbv()); + display(verbose_stream()); + ); + return false; + } + todo.push_back(child); + } + + } + return true; + } private: @@ -242,10 +274,6 @@ namespace datalog { return *(m_nodes.find(&dummy)); } - bool contains(tbv const& t) { - ddnf_node dummy(*this, m_tbv, t, 0); - return m_nodes.contains(&dummy); - } void insert(ddnf_node& root, ddnf_node* new_n, ptr_vector& new_intersections) { tbv const& new_tbv = new_n->get_tbv(); @@ -354,6 +382,13 @@ namespace datalog { unsigned ddnf_core::size() const { return m_imp->size(); } + bool ddnf_core::contains(tbv const& t) { + return m_imp->contains(t); + } + bool ddnf_core::well_formed() { + return m_imp->well_formed(); + } + void ddnf_core::reset_accumulate() { return m_imp->reset_accumulate(); } diff --git a/src/muz/ddnf/ddnf.h b/src/muz/ddnf/ddnf.h index 1e5e912ba..79c79ed9d 100644 --- a/src/muz/ddnf/ddnf.h +++ b/src/muz/ddnf/ddnf.h @@ -55,6 +55,8 @@ namespace datalog { ddnf_node* insert(tbv const& t); tbv_manager& get_tbv_manager(); unsigned size() const; + bool contains(tbv const& t); + bool well_formed(); // // accumulate labels covered by the stream of tbvs, diff --git a/src/test/ddnf.cpp b/src/test/ddnf.cpp index 5ab395e20..27eec9f45 100644 --- a/src/test/ddnf.cpp +++ b/src/test/ddnf.cpp @@ -101,6 +101,7 @@ datalog::ddnf_core* populate_ddnf(char const* file, ptr_vector& tbvs) { exit(0); } if (p == 0 && tbvm.equals(*t, *tX)) break; + // std::cout << ddnf->well_formed() << "\n"; } } @@ -131,10 +132,12 @@ void tst_ddnf(char ** argv, int argc, int& i) { read_args(argv, argc); ptr_vector tbvs; datalog::ddnf_core* ddnf = populate_ddnf(g_file, tbvs); + IF_VERBOSE(1, ddnf->display(verbose_stream());); create_forwarding(g_file, *ddnf, tbvs); std::cout << "resulting size: " << ddnf->size() << "\n"; ddnf->display_statistics(std::cout); IF_VERBOSE(1, ddnf->display(verbose_stream());); + std::cout << ddnf->well_formed() << "\n"; tbv_manager& tbvm = ddnf->get_tbv_manager(); for (unsigned i = 0; i < tbvs.size(); ++i) { From bf6ab3fc036bdf09c8cc9527e1bb9ff4a6d7346d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 11 May 2015 17:11:52 -0700 Subject: [PATCH 765/925] local state Signed-off-by: Nikolaj Bjorner --- src/muz/rel/tbv.cpp | 1 + src/test/ddnf.cpp | 15 ++++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/muz/rel/tbv.cpp b/src/muz/rel/tbv.cpp index 577817e69..9c740b726 100644 --- a/src/muz/rel/tbv.cpp +++ b/src/muz/rel/tbv.cpp @@ -106,6 +106,7 @@ tbv* tbv_manager::allocate(char const* bv) { if (*bv == '0') set(*result, i++, tbit::BIT_0); else if (*bv == '1') set(*result, i++, tbit::BIT_1); else if (*bv == '*') i++; + else if (*bv == 'x') i++; else if (i == 0 && (*bv == ' ' || *bv == '\t')) ; else break; ++bv; diff --git a/src/test/ddnf.cpp b/src/test/ddnf.cpp index 5ab395e20..8919c7fe9 100644 --- a/src/test/ddnf.cpp +++ b/src/test/ddnf.cpp @@ -93,7 +93,7 @@ datalog::ddnf_core* populate_ddnf(char const* file, ptr_vector& tbvs) { std::getline(is, line); tbv* t = tbvm.allocate(line.c_str()); ddnf->insert(*t); - //tbvm.display(std::cout << line << " ", *t) << "\n"; + IF_VERBOSE(2, tbvm.display(verbose_stream() << line << " ", *t) << "\n";); tbvs.push_back(t); if (p > P) { std::cout << "port number " << p << " too big " << P << "\n"; @@ -110,16 +110,17 @@ datalog::ddnf_core* populate_ddnf(char const* file, ptr_vector& tbvs) { } -static void read_args(char ** argv, int argc) { - if (argc == 3) { - g_file = argv[2]; +static void read_args(char ** argv, int argc, int& i) { + if (argc = i + 2) { + g_file = argv[i + 1]; + ++i; return; } if (!g_file) { std::cout << "Need routing table file as argument. Arguments provided: "; - for (int i = 0; i < argc; ++i) { - std::cout << argv[i] << " "; + for (int j = i; j < argc; ++j) { + std::cout << argv[j] << " "; } std::cout << "\n"; exit(0); @@ -128,7 +129,7 @@ static void read_args(char ** argv, int argc) { } void tst_ddnf(char ** argv, int argc, int& i) { - read_args(argv, argc); + read_args(argv, argc, i); ptr_vector tbvs; datalog::ddnf_core* ddnf = populate_ddnf(g_file, tbvs); create_forwarding(g_file, *ddnf, tbvs); From 4d3d9f7602b682564f6a2c6ef65d2e8fea492aec Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 11 May 2015 20:32:39 -0700 Subject: [PATCH 766/925] include compression Signed-off-by: Nikolaj Bjorner --- src/test/ddnf.cpp | 60 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 6 deletions(-) diff --git a/src/test/ddnf.cpp b/src/test/ddnf.cpp index 52d5bb630..024f1bb0f 100644 --- a/src/test/ddnf.cpp +++ b/src/test/ddnf.cpp @@ -24,7 +24,11 @@ void read_nums(std::istream& is, unsigned & x, unsigned& y) { static char const* g_file = 0; -void create_forwarding(char const* file, datalog::ddnf_core& ddnf, ptr_vector& tbvs) { +void create_forwarding( + char const* file, + datalog::ddnf_core& ddnf, + ptr_vector& tbvs, + vector& fwd_indices) { IF_VERBOSE(1, verbose_stream() << "creating (and forgetting) forwarding index\n";); std::ifstream is(file); @@ -44,7 +48,8 @@ void create_forwarding(char const* file, datalog::ddnf_core& ddnf, ptr_vector> p; @@ -129,17 +134,60 @@ static void read_args(char ** argv, int argc, int& i) { } +typedef std::pair u_pair; + +struct uu_eq { bool operator()(u_pair u1, u_pair u2) const { return u1 == u2; } }; + +typedef map, uu_eq > pair_table; + +static unsigned refine_forwarding( + unsigned_vector& p, + unsigned_vector const& q) { + unsigned sz = p.size(); + unsigned n = 0, m = 0; + pair_table tbl; + for (unsigned i = 0; i < sz; ++i) { + u_pair pr = std::make_pair(p[i], q[i]); + if (tbl.find(pr, m)) { + p[i] = m; + } + else { + p[i] = n; + tbl.insert(pr, n++); + } + } + return n; +} + +static void refine_forwarding( + datalog::ddnf_core& ddnf, + vector const& fwd_indices) { + unsigned_vector roots; + roots.resize(ddnf.size()); + for (unsigned i = 0; i < roots.size(); ++i) { + roots[i] = 0; + } + unsigned max_class = 1; + for (unsigned i = 0; i < fwd_indices.size(); ++i) { + unsigned_vector const& fwd = fwd_indices[i]; + max_class = refine_forwarding(roots, fwd); + } + std::cout << "num classes: " << max_class << "\n"; +} + void tst_ddnf(char ** argv, int argc, int& i) { read_args(argv, argc, i); ptr_vector tbvs; datalog::ddnf_core* ddnf = populate_ddnf(g_file, tbvs); IF_VERBOSE(1, ddnf->display(verbose_stream());); - create_forwarding(g_file, *ddnf, tbvs); + vector fwd_indices; + create_forwarding(g_file, *ddnf, tbvs, fwd_indices); + refine_forwarding(*ddnf, fwd_indices); std::cout << "resulting size: " << ddnf->size() << "\n"; ddnf->display_statistics(std::cout); - IF_VERBOSE(1, ddnf->display(verbose_stream());); - std::cout << ddnf->well_formed() << "\n"; - + IF_VERBOSE(1, ddnf->display(verbose_stream()); + verbose_stream() << ddnf->well_formed() << "\n";); + tbv_manager& tbvm = ddnf->get_tbv_manager(); for (unsigned i = 0; i < tbvs.size(); ++i) { tbvm.deallocate(tbvs[i]); From b882a94f6ada2cc2ab63bf3e6341e16dab013bd9 Mon Sep 17 00:00:00 2001 From: "U-EUROPE\\t-alexh" Date: Tue, 12 May 2015 10:23:04 +0100 Subject: [PATCH 767/925] Fix g++ compile-time error Signed-off-by: U-EUROPE\t-alexh --- src/muz/rel/tbv.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/muz/rel/tbv.cpp b/src/muz/rel/tbv.cpp index 577817e69..1dfa04992 100644 --- a/src/muz/rel/tbv.cpp +++ b/src/muz/rel/tbv.cpp @@ -103,8 +103,8 @@ tbv* tbv_manager::allocate(char const* bv) { tbv* result = allocateX(); unsigned i = 0, sz = num_tbits(); while(*bv && i < sz) { - if (*bv == '0') set(*result, i++, tbit::BIT_0); - else if (*bv == '1') set(*result, i++, tbit::BIT_1); + if (*bv == '0') set(*result, i++, BIT_0); + else if (*bv == '1') set(*result, i++, BIT_1); else if (*bv == '*') i++; else if (i == 0 && (*bv == ' ' || *bv == '\t')) ; else break; From 043f441a4c1c37cbbc253a6d41446cbeca74040f Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 12 May 2015 10:29:37 +0100 Subject: [PATCH 768/925] Python 3.x compatibility. Fixes problems reported in comments to 1abeb825a35a620ff27a409a8d09d676e1395d95 --- scripts/mk_win_dist.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/mk_win_dist.py b/scripts/mk_win_dist.py index db4cc48e3..fb42750e3 100644 --- a/scripts/mk_win_dist.py +++ b/scripts/mk_win_dist.py @@ -180,7 +180,7 @@ def mk_dist_dir_core(x64): mk_util.JAVA_ENABLED = JAVA_ENABLED mk_win_dist(build_path, dist_path) if is_verbose(): - print("Generated %s distribution folder at '%s'") % (platform, dist_path) + print("Generated %s distribution folder at '%s'" % (platform, dist_path)) def mk_dist_dir(): mk_dist_dir_core(False) @@ -208,7 +208,7 @@ def mk_zip_core(x64): ZIPOUT = zipfile.ZipFile(zfname, 'w', zipfile.ZIP_DEFLATED) os.path.walk(dist_path, mk_zip_visitor, '*') if is_verbose(): - print("Generated '%s'") % zfname + print("Generated '%s'" % zfname) except: pass ZIPOUT = None @@ -253,7 +253,7 @@ def cp_vs_runtime_core(x64): for f in VS_RUNTIME_FILES: shutil.copy(f, bin_dist_path) if is_verbose(): - print("Copied '%s' to '%s'") % (f, bin_dist_path) + print("Copied '%s' to '%s'" % (f, bin_dist_path)) def cp_vs_runtime(): cp_vs_runtime_core(True) From 0f78238b7e6f6a71b509230d6e8574e811c65855 Mon Sep 17 00:00:00 2001 From: Alex Horn Date: Tue, 12 May 2015 13:18:51 +0100 Subject: [PATCH 769/925] Fix typo in documentation Signed-off-by: Alex Horn --- src/muz/base/dl_context.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/base/dl_context.h b/src/muz/base/dl_context.h index 9da4700e6..9f94bd869 100644 --- a/src/muz/base/dl_context.h +++ b/src/muz/base/dl_context.h @@ -300,7 +300,7 @@ namespace datalog { /** Register datalog relation. - If names is true, we associate the predicate with its name, so that it can be + If named is true, we associate the predicate with its name, so that it can be retrieved by the try_get_predicate_decl() function. Auxiliary predicates introduced e.g. by rule transformations do not need to be named. */ From efaba8eb408e69f0b345a74ed44f9966fa9b6576 Mon Sep 17 00:00:00 2001 From: Alex Horn Date: Tue, 12 May 2015 14:22:32 +0100 Subject: [PATCH 770/925] Fix negation in documentation Signed-off-by: Alex Horn --- src/muz/rel/dl_base.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/rel/dl_base.h b/src/muz/rel/dl_base.h index 2dffa04f6..c14977c04 100644 --- a/src/muz/rel/dl_base.h +++ b/src/muz/rel/dl_base.h @@ -470,7 +470,7 @@ namespace datalog { \brief fast emptiness check. This may be partial. The requirement is that if fast_empty returns true then the table or relation is in fact empty. - It is allowed to return false even if the relation is non-empty. + It is allowed to return false even if the relation is empty. */ virtual bool fast_empty() const { return empty(); } From e576ca50bf425a0f3a612db8447fef8fa45b785a Mon Sep 17 00:00:00 2001 From: Alex Horn Date: Tue, 12 May 2015 14:24:59 +0100 Subject: [PATCH 771/925] Fix typo in documentation Signed-off-by: Alex Horn --- src/muz/rel/dl_base.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/rel/dl_base.h b/src/muz/rel/dl_base.h index c14977c04..268cc602e 100644 --- a/src/muz/rel/dl_base.h +++ b/src/muz/rel/dl_base.h @@ -88,7 +88,7 @@ namespace datalog { typedef typename Traits::signature signature; //this must be a vector-like type /** - The client submits an initial class to be used as a base for signature. Then we excend it by + The client submits an initial class to be used as a base for signature. Then we extend it by the common signature methods into a signature_base class which then the client inherits from to obtain the actual signature class. */ From ce749240d7f1951244131e2365276813b04db2d8 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 12 May 2015 18:43:51 +0100 Subject: [PATCH 772/925] more fixes for python 3 Signed-off-by: Nuno Lopes --- scripts/mk_util.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 72d432eab..207ac4c8c 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -248,16 +248,16 @@ def test_fpmath(cc): t.add('int main() { return 42; }\n') t.commit() if exec_compiler_cmd([cc, CPPFLAGS, 'tstsse.cpp', LDFLAGS, '-mfpmath=sse -msse -msse2']) == 0: - FPMATH_FLAGS="-mfpmath=sse -msse -msse2" + FPMATH_FLAGS="-mfpmath=sse -msse -msse2" return "SSE2-GCC" elif exec_compiler_cmd([cc, CPPFLAGS, 'tstsse.cpp', LDFLAGS, '-msse -msse2']) == 0: - FPMATH_FLAGS="-msse -msse2" + FPMATH_FLAGS="-msse -msse2" return "SSE2-CLANG" elif exec_compiler_cmd([cc, CPPFLAGS, 'tstsse.cpp', LDFLAGS, '-mfpu=vfp -mfloat-abi=hard']) == 0: - FPMATH_FLAGS="-mfpu=vfp -mfloat-abi=hard" + FPMATH_FLAGS="-mfpu=vfp -mfloat-abi=hard" return "ARM-VFP" else: - FPMATH_FLAGS="" + FPMATH_FLAGS="" return "UNKNOWN" @@ -1841,7 +1841,7 @@ def mk_config(): CPPFLAGS = '%s -DZ3GITHASH=%s' % (CPPFLAGS, GIT_HASH) CXXFLAGS = '%s -fvisibility=hidden -c' % CXXFLAGS FPMATH = test_fpmath(CXX) - CXXFLAGS = '%s %s' % (CXXFLAGS, FPMATH_FLAGS) + CXXFLAGS = '%s %s' % (CXXFLAGS, FPMATH_FLAGS) HAS_OMP = test_openmp(CXX) if HAS_OMP: CXXFLAGS = '%s -fopenmp' % CXXFLAGS From 2d1a0b010ddcfc965f6cd8064b2a48ba2fefdc04 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 14 May 2015 13:44:39 +0100 Subject: [PATCH 773/925] Bugfix for AIG tactic. --- src/tactic/aig/aig_tactic.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tactic/aig/aig_tactic.cpp b/src/tactic/aig/aig_tactic.cpp index dc577eb73..f1f1c7330 100644 --- a/src/tactic/aig/aig_tactic.cpp +++ b/src/tactic/aig/aig_tactic.cpp @@ -78,13 +78,13 @@ public: mk_aig_manager mk(*this, g->m()); if (m_aig_per_assertion) { - unsigned size = g->size(); - for (unsigned i = 0; i < size; i++) { + for (unsigned i = 0; i < g->size(); i++) { aig_ref r = m_aig_manager->mk_aig(g->form(i)); m_aig_manager->max_sharing(r); expr_ref new_f(g->m()); m_aig_manager->to_formula(r, new_f); - g->update(i, new_f, 0, g->dep(i)); + expr_dependency * ed = g->dep(i); + g->update(i, new_f, 0, ed); } } else { From c82319b358b366b42bab196b384883600211f110 Mon Sep 17 00:00:00 2001 From: Matthias Schlaipfer Date: Wed, 13 May 2015 19:15:59 +0100 Subject: [PATCH 774/925] Refactor count_vars and count_rule_vars ast_manager m was not used --- src/ast/rewriter/ast_counter.cpp | 2 +- src/ast/rewriter/ast_counter.h | 2 +- src/muz/base/dl_rule.cpp | 4 ++-- src/muz/base/dl_util.cpp | 6 ++--- src/muz/base/dl_util.h | 2 +- src/muz/rel/dl_compiler.cpp | 9 ++++--- src/muz/rel/dl_mk_explanations.cpp | 2 +- src/muz/rel/dl_mk_similarity_compressor.cpp | 2 +- src/muz/rel/dl_mk_simple_joins.cpp | 24 +++++++++---------- .../transforms/dl_mk_unbound_compressor.cpp | 4 ++-- 10 files changed, 28 insertions(+), 29 deletions(-) diff --git a/src/ast/rewriter/ast_counter.cpp b/src/ast/rewriter/ast_counter.cpp index f1ec03528..f2c8cabf7 100644 --- a/src/ast/rewriter/ast_counter.cpp +++ b/src/ast/rewriter/ast_counter.cpp @@ -86,7 +86,7 @@ int counter::get_max_counter_value() const { return res; } -void var_counter::count_vars(ast_manager & m, const app * pred, int coef) { +void var_counter::count_vars(const app * pred, int coef) { unsigned n = pred->get_num_args(); for (unsigned i = 0; i < n; i++) { m_fv(pred->get_arg(i)); diff --git a/src/ast/rewriter/ast_counter.h b/src/ast/rewriter/ast_counter.h index 8b3ec3bbd..a362c235b 100644 --- a/src/ast/rewriter/ast_counter.h +++ b/src/ast/rewriter/ast_counter.h @@ -76,7 +76,7 @@ protected: unsigned get_max_var(bool & has_var); public: var_counter() {} - void count_vars(ast_manager & m, const app * t, int coef = 1); + void count_vars(const app * t, int coef = 1); unsigned get_max_var(expr* e); unsigned get_next_var(expr* e); }; diff --git a/src/muz/base/dl_rule.cpp b/src/muz/base/dl_rule.cpp index b846bc06a..eabe1d551 100644 --- a/src/muz/base/dl_rule.cpp +++ b/src/muz/base/dl_rule.cpp @@ -682,11 +682,11 @@ namespace datalog { svector tail_neg; app_ref head(r->get_head(), m); - vctr.count_vars(m, head); + vctr.count_vars(head); for (unsigned i = 0; i < ut_len; i++) { app * t = r->get_tail(i); - vctr.count_vars(m, t); + vctr.count_vars(t); tail.push_back(t); tail_neg.push_back(r->is_neg_tail(i)); } diff --git a/src/muz/base/dl_util.cpp b/src/muz/base/dl_util.cpp index 2f60ddec8..0f254ee0a 100644 --- a/src/muz/base/dl_util.cpp +++ b/src/muz/base/dl_util.cpp @@ -256,12 +256,12 @@ namespace datalog { } - void rule_counter::count_rule_vars(ast_manager & m, const rule * r, int coef) { + void rule_counter::count_rule_vars(const rule * r, int coef) { reset(); - count_vars(m, r->get_head(), 1); + count_vars(r->get_head(), 1); unsigned n = r->get_tail_size(); for (unsigned i = 0; i < n; i++) { - count_vars(m, r->get_tail(i), coef); + count_vars(r->get_tail(i), coef); } } diff --git a/src/muz/base/dl_util.h b/src/muz/base/dl_util.h index bf5c225ef..513add584 100644 --- a/src/muz/base/dl_util.h +++ b/src/muz/base/dl_util.h @@ -347,7 +347,7 @@ namespace datalog { class rule_counter : public var_counter { public: rule_counter(){} - void count_rule_vars(ast_manager & m, const rule * r, int coef = 1); + void count_rule_vars(const rule * r, int coef = 1); unsigned get_max_rule_var(const rule& r); }; diff --git a/src/muz/rel/dl_compiler.cpp b/src/muz/rel/dl_compiler.cpp index 204a8f316..9e8ead241 100644 --- a/src/muz/rel/dl_compiler.cpp +++ b/src/muz/rel/dl_compiler.cpp @@ -411,17 +411,16 @@ namespace datalog { void compiler::get_local_indexes_for_projection(rule * r, unsigned_vector & res) { SASSERT(r->get_positive_tail_size()==2); - ast_manager & m = m_context.get_manager(); rule_counter counter; // leave one column copy per var in the head (avoids later duplication) - counter.count_vars(m, r->get_head(), -1); + counter.count_vars(r->get_head(), -1); // take interp & neg preds into account (at least 1 column copy if referenced) unsigned n = r->get_tail_size(); if (n > 2) { rule_counter counter_tail; for (unsigned i = 2; i < n; ++i) { - counter_tail.count_vars(m, r->get_tail(i)); + counter_tail.count_vars(r->get_tail(i)); } rule_counter::iterator I = counter_tail.begin(), E = counter_tail.end(); @@ -434,8 +433,8 @@ namespace datalog { app * t1 = r->get_tail(0); app * t2 = r->get_tail(1); - counter.count_vars(m, t1); - counter.count_vars(m, t2); + counter.count_vars(t1); + counter.count_vars(t2); get_local_indexes_for_projection(t1, counter, 0, res); get_local_indexes_for_projection(t2, counter, t1->get_num_args(), res); diff --git a/src/muz/rel/dl_mk_explanations.cpp b/src/muz/rel/dl_mk_explanations.cpp index 0e788ebff..1338a6de6 100644 --- a/src/muz/rel/dl_mk_explanations.cpp +++ b/src/muz/rel/dl_mk_explanations.cpp @@ -705,7 +705,7 @@ namespace datalog { rule * mk_explanations::get_e_rule(rule * r) { rule_counter ctr; - ctr.count_rule_vars(m_manager, r); + ctr.count_rule_vars(r); unsigned max_var; unsigned next_var = ctr.get_max_positive(max_var) ? (max_var+1) : 0; unsigned head_var = next_var++; diff --git a/src/muz/rel/dl_mk_similarity_compressor.cpp b/src/muz/rel/dl_mk_similarity_compressor.cpp index aa2fe8ab9..75caba6ae 100644 --- a/src/muz/rel/dl_mk_similarity_compressor.cpp +++ b/src/muz/rel/dl_mk_similarity_compressor.cpp @@ -381,7 +381,7 @@ namespace datalog { } rule_counter ctr; - ctr.count_rule_vars(m_manager, r); + ctr.count_rule_vars(r); unsigned max_var_idx, new_var_idx_base; if (ctr.get_max_positive(max_var_idx)) { new_var_idx_base = max_var_idx+1; diff --git a/src/muz/rel/dl_mk_simple_joins.cpp b/src/muz/rel/dl_mk_simple_joins.cpp index e33de8c6d..e76b3a25b 100644 --- a/src/muz/rel/dl_mk_simple_joins.cpp +++ b/src/muz/rel/dl_mk_simple_joins.cpp @@ -316,7 +316,7 @@ namespace datalog { void register_rule(rule * r) { rule_counter counter; - counter.count_rule_vars(m, r, 1); + counter.count_rule_vars(r, 1); ptr_vector & rule_content = m_rules_content.insert_if_not_there2(r, ptr_vector())->get_data().m_value; @@ -329,19 +329,19 @@ namespace datalog { for(unsigned i=0; i+1 < pos_tail_size; i++) { app * t1 = r->get_tail(i); var_idx_set t1_vars = rm.collect_vars(t1); - counter.count_vars(m, t1, -1); //temporarily remove t1 variables from counter + counter.count_vars(t1, -1); //temporarily remove t1 variables from counter for(unsigned j=i+1; jget_tail(j); - counter.count_vars(m, t2, -1); //temporarily remove t2 variables from counter + counter.count_vars(t2, -1); //temporarily remove t2 variables from counter var_idx_set scope_vars = rm.collect_vars(t2); scope_vars |= t1_vars; var_idx_set non_local_vars; counter.collect_positive(non_local_vars); - counter.count_vars(m, t2, 1); //restore t2 variables in counter + counter.count_vars(t2, 1); //restore t2 variables in counter set_intersection(non_local_vars, scope_vars); register_pair(t1, t2, r, non_local_vars); } - counter.count_vars(m, t1, 1); //restore t1 variables in counter + counter.count_vars(t1, 1); //restore t1 variables in counter } } @@ -460,16 +460,16 @@ namespace datalog { app * head = r->get_head(); var_counter counter; - counter.count_vars(m, head, 1); + counter.count_vars(head, 1); unsigned tail_size=r->get_tail_size(); unsigned pos_tail_size=r->get_positive_tail_size(); for(unsigned i=pos_tail_size; iget_tail(i), 1); + counter.count_vars(r->get_tail(i), 1); } for(unsigned i=0; iget_arity(); rm.get_counter().reset(); - rm.get_counter().count_vars(m, head, 1); + rm.get_counter().count_vars(head, 1); for (unsigned i=0; iget_arg(i); @@ -125,7 +125,7 @@ namespace datalog { unsigned head_arity = head_pred->get_arity(); rm.get_counter().reset(); - rm.get_counter().count_vars(m, head); + rm.get_counter().count_vars(head); unsigned arg_index; for (arg_index = 0; arg_index < head_arity; arg_index++) { From 1dc17db56a7aad95ba0d9cd9462a644dffddbd23 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 15 May 2015 09:01:56 +0100 Subject: [PATCH 775/925] Fix concat() in c++ api Signed-off-by: Nuno Lopes --- src/api/c++/z3++.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 11c80a2be..0c5b34fb1 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1111,9 +1111,10 @@ namespace z3 { } inline expr concat(expr const& a, expr const& b) { - Z3_ast r = Z3_mk_concat(ctx, (Z3_app) a, (Z3_app) b); - ctx.check_error(); - return expr(ctx, r); + check_context(a, b); + Z3_ast r = Z3_mk_concat(a.ctx(), a, b); + a.ctx().check_error(); + return expr(a.ctx(), r); } class func_entry : public object { From 1702a55018e8e9b2b7b1b5a7c583918b912da4fd Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 15 May 2015 13:50:55 +0100 Subject: [PATCH 776/925] Introduced return value classes for interpolation functions. Fixes #82. --- src/api/java/InterpolationContext.java | 64 ++++++++++++++++++-------- 1 file changed, 45 insertions(+), 19 deletions(-) diff --git a/src/api/java/InterpolationContext.java b/src/api/java/InterpolationContext.java index 897c0e9e9..667c91a53 100644 --- a/src/api/java/InterpolationContext.java +++ b/src/api/java/InterpolationContext.java @@ -87,6 +87,13 @@ public class InterpolationContext extends Context return res; } + public class ComputeInterpolantResult + { + public Z3_lbool status = Z3_lbool.Z3_L_UNDEF; + public ASTVector interp = null; + public Model model = null; + }; + /** * Computes an interpolant. * Remarks: For more information on interpolation please refer @@ -94,17 +101,18 @@ public class InterpolationContext extends Context * well documented. * @throws Z3Exception **/ - public Z3_lbool ComputeInterpolant(Expr pat, Params p, ASTVector interp, Model model) + public ComputeInterpolantResult ComputeInterpolant(Expr pat, Params p) { checkContextMatch(pat); checkContextMatch(p); + ComputeInterpolantResult res = new ComputeInterpolantResult(); Native.LongPtr n_i = new Native.LongPtr(); Native.LongPtr n_m = new Native.LongPtr(); - int r = Native.computeInterpolant(nCtx(), pat.getNativeObject(), p.getNativeObject(), n_i, n_m); - interp = new ASTVector(this, n_i.value); - model = new Model(this, n_m.value); - return Z3_lbool.fromInt(r); + res.status =Z3_lbool.fromInt(Native.computeInterpolant(nCtx(), pat.getNativeObject(), p.getNativeObject(), n_i, n_m)); + if (res.status == Z3_lbool.Z3_L_FALSE) res.interp = new ASTVector(this, n_i.value); + if (res.status == Z3_lbool.Z3_L_TRUE) res.model = new Model(this, n_m.value); + return res; } /// @@ -118,16 +126,23 @@ public class InterpolationContext extends Context return Native.interpolationProfile(nCtx()); } + public class CheckInterpolantResult + { + public int return_value = 0; + public String error = null; + } + /// /// Checks the correctness of an interpolant. /// /// Remarks: For more information on interpolation please refer /// too the function Z3_check_interpolant in the C/C++ API, which is /// well documented. - public int CheckInterpolant(Expr[] cnsts, int[] parents, Expr[] interps, String error, Expr[] theory) + public CheckInterpolantResult CheckInterpolant(Expr[] cnsts, int[] parents, Expr[] interps, String error, Expr[] theory) { + CheckInterpolantResult res = new CheckInterpolantResult(); Native.StringPtr n_err_str = new Native.StringPtr(); - int r = Native.checkInterpolant(nCtx(), + res.return_value = Native.checkInterpolant(nCtx(), cnsts.length, Expr.arrayToNative(cnsts), parents, @@ -135,41 +150,52 @@ public class InterpolationContext extends Context n_err_str, theory.length, Expr.arrayToNative(theory)); - error = n_err_str.value; - return r; + res.error = n_err_str.value; + return res; } + public class ReadInterpolationProblemResult + { + public int return_value = 0; + public Expr[] cnsts; + public int[] parents; + public String error; + public Expr[] theory; + }; + /// /// Reads an interpolation problem from a file. /// /// Remarks: For more information on interpolation please refer /// too the function Z3_read_interpolation_problem in the C/C++ API, which is /// well documented. - public int ReadInterpolationProblem(String filename, Expr[] cnsts, int[] parents, String error, Expr[] theory) + public ReadInterpolationProblemResult ReadInterpolationProblem(String filename, Expr[] cnsts, int[] parents, String error, Expr[] theory) { + ReadInterpolationProblemResult res = new ReadInterpolationProblemResult(); + Native.IntPtr n_num = new Native.IntPtr(); Native.IntPtr n_num_theory = new Native.IntPtr(); Native.ObjArrayPtr n_cnsts = new Native.ObjArrayPtr(); Native.UIntArrayPtr n_parents = new Native.UIntArrayPtr(); Native.ObjArrayPtr n_theory = new Native.ObjArrayPtr(); Native.StringPtr n_err_str = new Native.StringPtr(); - int r = Native.readInterpolationProblem(nCtx(), n_num, n_cnsts, n_parents, filename, n_err_str, n_num_theory, n_theory); + res.return_value = Native.readInterpolationProblem(nCtx(), n_num, n_cnsts, n_parents, filename, n_err_str, n_num_theory, n_theory); int num = n_num.value; int num_theory = n_num_theory.value; - error = n_err_str.value; - cnsts = new Expr[num]; - parents = new int[num]; + res.error = n_err_str.value; + res.cnsts = new Expr[num]; + res.parents = new int[num]; theory = new Expr[num_theory]; for (int i = 0; i < num; i++) { - cnsts[i] = Expr.create(this, n_cnsts.value[i]); - parents[i] = n_parents.value[i]; + res.cnsts[i] = Expr.create(this, n_cnsts.value[i]); + res.parents[i] = n_parents.value[i]; } for (int i = 0; i < num_theory; i++) - theory[i] = Expr.create(this, n_theory.value[i]); - return r; + res.theory[i] = Expr.create(this, n_theory.value[i]); + return res; } - + /// /// Writes an interpolation problem to a file. /// From 0e32c87dc385d086382227b1b9470fa0b750b4a0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 May 2015 15:43:05 +0100 Subject: [PATCH 777/925] fix examples and C++ API - build failure Signed-off-by: Nikolaj Bjorner --- examples/tptp/tptp5.cpp | 2 +- src/api/c++/z3++.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/tptp/tptp5.cpp b/examples/tptp/tptp5.cpp index 2a90b5a3f..d40aa93e9 100644 --- a/examples/tptp/tptp5.cpp +++ b/examples/tptp/tptp5.cpp @@ -2083,7 +2083,7 @@ bool parse_is_sat_line(char const* line, bool& is_sat) { return true; } return false; - +} bool parse_is_sat(char const* filename, bool& is_sat) { std::ifstream is(filename); diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 11c80a2be..3c925e95c 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1111,7 +1111,8 @@ namespace z3 { } inline expr concat(expr const& a, expr const& b) { - Z3_ast r = Z3_mk_concat(ctx, (Z3_app) a, (Z3_app) b); + context& ctx = a.ctx(); + Z3_ast r = Z3_mk_concat(ctx, (Z3_ast) a, (Z3_ast) b); ctx.check_error(); return expr(ctx, r); } From e6b8af402f4e7c614e27c03fdd20da5d7d0cf280 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 May 2015 15:56:21 +0100 Subject: [PATCH 778/925] fix build warnings Signed-off-by: Nikolaj Bjorner --- src/opt/hitting_sets.cpp | 6 +++--- src/util/mpff.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/opt/hitting_sets.cpp b/src/opt/hitting_sets.cpp index 37b800428..8c10d3640 100644 --- a/src/opt/hitting_sets.cpp +++ b/src/opt/hitting_sets.cpp @@ -122,7 +122,7 @@ namespace opt { bool m_enable_simplex; struct compare_scores { imp* m_imp; - compare_scores(imp* i):m_imp(i) {} + compare_scores():m_imp(0) {} bool operator()(int v1, int v2) const { return m_imp->m_scored_weights[v1] > m_imp->m_scored_weights[v2]; } @@ -154,10 +154,10 @@ namespace opt { m_scope_lvl(0), m_conflict_j(justification(justification::AXIOM)), m_inconsistent(false), - m_compare_scores(this), + m_compare_scores(), m_heap(0, m_compare_scores) { m_enable_simplex = true; - + m_compare_scores.m_imp = this; } ~imp() { for (unsigned i = 0; i < m_T.size(); ++i) { diff --git a/src/util/mpff.cpp b/src/util/mpff.cpp index 14c67e7c0..e5d3cf24c 100644 --- a/src/util/mpff.cpp +++ b/src/util/mpff.cpp @@ -255,7 +255,7 @@ void mpff_manager::set(mpff & n, int64 v) { } else { if (v < 0) { - set(n, -static_cast(v)); + set(n, 1 + static_cast(-(1+v))); n.m_sign = 1; } else { From 7ae68f003a622a98d55950a0758654e155804133 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 15 May 2015 19:20:57 +0100 Subject: [PATCH 779/925] dont use /LTCG on windows debug builds Signed-off-by: Nuno Lopes --- scripts/mk_util.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 207ac4c8c..ac9122335 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1746,7 +1746,6 @@ def mk_config(): 'OBJ_EXT=.obj\n' 'LIB_EXT=.lib\n' 'AR=lib\n' - 'AR_FLAGS=/nologo /LTCG\n' 'AR_OUTFLAG=/OUT:\n' 'EXE_EXT=.exe\n' 'LINK=cl\n' @@ -1765,23 +1764,25 @@ def mk_config(): extra_opt = ' %s /D Z3GITHASH=%s' % (extra_opt, GIT_HASH) if DEBUG_MODE: config.write( + 'AR_FLAGS=/nologo\n' 'LINK_FLAGS=/nologo /MDd\n' 'SLINK_FLAGS=/nologo /LDd\n') if not VS_X64: config.write( - 'CXXFLAGS=/c /GL /Zi /nologo /W3 /WX- /Od /Oy- /D WIN32 /D _DEBUG /D Z3DEBUG %s /D _CONSOLE /D _TRACE /D _WINDOWS /Gm- /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /analyze- /arch:SSE2\n' % extra_opt) + 'CXXFLAGS=/c /Zi /nologo /W3 /WX- /Od /Oy- /D WIN32 /D _DEBUG /D Z3DEBUG %s /D _CONSOLE /D _TRACE /D _WINDOWS /Gm- /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /analyze- /arch:SSE2\n' % extra_opt) config.write( - 'LINK_EXTRA_FLAGS=/link /LTCG /DEBUG /MACHINE:X86 /SUBSYSTEM:CONSOLE /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE /NXCOMPAT\n' - 'SLINK_EXTRA_FLAGS=/link /LTCG /DEBUG /MACHINE:X86 /SUBSYSTEM:WINDOWS /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE:NO\n') + 'LINK_EXTRA_FLAGS=/link /DEBUG /MACHINE:X86 /SUBSYSTEM:CONSOLE /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE /NXCOMPAT\n' + 'SLINK_EXTRA_FLAGS=/link /DEBUG /MACHINE:X86 /SUBSYSTEM:WINDOWS /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE:NO\n') else: config.write( - 'CXXFLAGS=/c /GL /Zi /nologo /W3 /WX- /Od /Oy- /D WIN32 /D _AMD64_ /D _DEBUG /D Z3DEBUG %s /D _CONSOLE /D _TRACE /D _WINDOWS /Gm- /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /analyze-\n' % extra_opt) + 'CXXFLAGS=/c /Zi /nologo /W3 /WX- /Od /Oy- /D WIN32 /D _AMD64_ /D _DEBUG /D Z3DEBUG %s /D _CONSOLE /D _TRACE /D _WINDOWS /Gm- /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /analyze-\n' % extra_opt) config.write( - 'LINK_EXTRA_FLAGS=/link /LTCG /DEBUG /MACHINE:X64 /SUBSYSTEM:CONSOLE /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE /NXCOMPAT\n' - 'SLINK_EXTRA_FLAGS=/link /LTCG /DEBUG /MACHINE:X64 /SUBSYSTEM:WINDOWS /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE:NO\n') + 'LINK_EXTRA_FLAGS=/link /DEBUG /MACHINE:X64 /SUBSYSTEM:CONSOLE /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE /NXCOMPAT\n' + 'SLINK_EXTRA_FLAGS=/link /DEBUG /MACHINE:X64 /SUBSYSTEM:WINDOWS /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE:NO\n') else: # Windows Release mode config.write( + 'AR_FLAGS=/nologo /LTCG\n' 'LINK_FLAGS=/nologo /MD\n' 'SLINK_FLAGS=/nologo /LD\n') if TRACE: From 6c22edc98830bafa91305010174b283a163d2fad Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Sat, 16 May 2015 11:44:58 +0100 Subject: [PATCH 780/925] fix assorted compiler warnings Signed-off-by: Nuno Lopes --- src/math/polynomial/upolynomial_factorization.cpp | 3 +-- src/muz/ddnf/ddnf.cpp | 5 +---- src/muz/fp/datalog_parser.cpp | 4 ++-- src/muz/pdr/pdr_context.cpp | 7 ++----- src/muz/pdr/pdr_prop_solver.cpp | 3 +-- src/muz/pdr/pdr_prop_solver.h | 3 +-- src/opt/hitting_sets.cpp | 7 +++---- src/opt/opt_context.cpp | 1 - src/opt/opt_solver.cpp | 2 +- src/opt/opt_solver.h | 1 - src/shell/opt_frontend.cpp | 1 - src/tactic/nlsat_smt/nl_purify_tactic.cpp | 4 ++-- src/util/inf_rational.h | 5 +---- src/util/rational.cpp | 12 +++++++++--- 14 files changed, 24 insertions(+), 34 deletions(-) diff --git a/src/math/polynomial/upolynomial_factorization.cpp b/src/math/polynomial/upolynomial_factorization.cpp index 7d5a23d99..0b2977a22 100644 --- a/src/math/polynomial/upolynomial_factorization.cpp +++ b/src/math/polynomial/upolynomial_factorization.cpp @@ -719,12 +719,11 @@ void hensel_lift_quadratic(z_manager& upm, numeral_vector const & C, // we create a new Z_p manager, since we'll be changing the input one zp_manager zp_upm(nm); zp_upm.set_zp(zpe_upm.m().p()); - zp_numeral_manager & zp_nm = zp_upm.m(); // get the U, V, such that A*U + B*V = 1 (mod p) scoped_mpz_vector U(nm), V(nm), D(nm); zp_upm.ext_gcd(A.size(), A.c_ptr(), B.size(), B.c_ptr(), U, V, D); - SASSERT(D.size() == 1 && zp_nm.is_one(D[0])); + SASSERT(D.size() == 1 && zp_upm.m().is_one(D[0])); // we start lifting from (a = p, b = p, r = p) scoped_mpz_vector A_lifted(nm), B_lifted(nm); diff --git a/src/muz/ddnf/ddnf.cpp b/src/muz/ddnf/ddnf.cpp index 14f4a2b75..6545d4282 100644 --- a/src/muz/ddnf/ddnf.cpp +++ b/src/muz/ddnf/ddnf.cpp @@ -54,7 +54,6 @@ namespace datalog { typedef ptr_hashtable ddnf_nodes; private: - ddnf_mgr& m; tbv_manager& tbvm; tbv const& m_tbv; ddnf_node_vector m_children; @@ -68,7 +67,6 @@ namespace datalog { public: ddnf_node(ddnf_mgr& m, tbv_manager& tbvm, tbv const& tbv, unsigned id): - m(m), tbvm(tbvm), m_tbv(tbv), m_children(m), @@ -130,7 +128,6 @@ namespace datalog { void reset() { memset(this, 0, sizeof(*this)); } }; - unsigned m_num_bits; ddnf_node* m_root; ddnf_node_vector m_noderefs; bool m_internalized; @@ -141,7 +138,7 @@ namespace datalog { svector m_marked; stats m_stats; public: - ddnf_mgr(unsigned n): m_num_bits(n), m_noderefs(*this), m_internalized(false), m_tbv(n), + ddnf_mgr(unsigned n): m_noderefs(*this), m_internalized(false), m_tbv(n), m_hash(m_tbv), m_eq(m_tbv), m_nodes(DEFAULT_HASHTABLE_INITIAL_CAPACITY, m_hash, m_eq) { tbv* bX = m_tbv.allocateX(); diff --git a/src/muz/fp/datalog_parser.cpp b/src/muz/fp/datalog_parser.cpp index 1567dff4f..58bc79e7a 100644 --- a/src/muz/fp/datalog_parser.cpp +++ b/src/muz/fp/datalog_parser.cpp @@ -89,8 +89,8 @@ public: :m_eof(false), m_eof_behind_buffer(false), m_next_index(0), - m_data_size(0), - m_ok(true) { + m_ok(true), + m_data_size(0) { m_data.resize(2*s_expansion_step); resize_data(0); #if _WINDOWS diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index 3b7d5c056..134c0746d 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -80,7 +80,7 @@ namespace pdr { pred_transformer::pred_transformer(context& ctx, manager& pm, func_decl* head): pm(pm), m(pm.get_manager()), ctx(ctx), m_head(head, m), - m_sig(m), m_solver(pm, ctx.get_params().pdr_try_minimize_core(), head->get_name()), + m_sig(m), m_solver(pm, head->get_name()), m_invariants(m), m_transition(m), m_initial_state(m), m_reachable(pm, (datalog::PDR_CACHE_MODE)ctx.get_params().pdr_cache_mode()) {} @@ -150,9 +150,9 @@ namespace pdr { } datalog::rule const& pred_transformer::find_rule(model_core const& model) const { - datalog::rule_manager& rm = ctx.get_context().get_rule_manager(); obj_map::iterator it = m_tag2rule.begin(), end = m_tag2rule.end(); TRACE("pdr_verbose", + datalog::rule_manager& rm = ctx.get_context().get_rule_manager(); for (; it != end; ++it) { expr* pred = it->m_key; tout << mk_pp(pred, m) << ":\n"; @@ -1137,9 +1137,6 @@ namespace pdr { if (n->get_model_ptr()) { models.insert(n->state(), n->get_model_ptr()); rules.insert(n->state(), n->get_rule()); - pred_transformer& pt = n->pt(); - context& ctx = pt.get_context(); - datalog::context& dctx = ctx.get_context(); } todo.pop_back(); todo.append(n->children().size(), n->children().c_ptr()); diff --git a/src/muz/pdr/pdr_prop_solver.cpp b/src/muz/pdr/pdr_prop_solver.cpp index a7d0a02bf..9ba976254 100644 --- a/src/muz/pdr/pdr_prop_solver.cpp +++ b/src/muz/pdr/pdr_prop_solver.cpp @@ -225,12 +225,11 @@ namespace pdr { }; - prop_solver::prop_solver(manager& pm, bool try_minimize_core, symbol const& name) : + prop_solver::prop_solver(manager& pm, symbol const& name) : m_fparams(pm.get_fparams()), m(pm.get_manager()), m_pm(pm), m_name(name), - m_try_minimize_core(try_minimize_core), m_ctx(pm.mk_fresh()), m_pos_level_atoms(m), m_neg_level_atoms(m), diff --git a/src/muz/pdr/pdr_prop_solver.h b/src/muz/pdr/pdr_prop_solver.h index d7f13a603..a44ac7e5a 100644 --- a/src/muz/pdr/pdr_prop_solver.h +++ b/src/muz/pdr/pdr_prop_solver.h @@ -40,7 +40,6 @@ namespace pdr { ast_manager& m; manager& m_pm; symbol m_name; - bool m_try_minimize_core; scoped_ptr m_ctx; decl_vector m_level_preds; app_ref_vector m_pos_level_atoms; // atoms used to identify level @@ -74,7 +73,7 @@ namespace pdr { public: - prop_solver(pdr::manager& pm, bool try_minimize_core, symbol const& name); + prop_solver(pdr::manager& pm, symbol const& name); /** return true is s is a symbol introduced by prop_solver */ bool is_aux_symbol(func_decl * s) const { diff --git a/src/opt/hitting_sets.cpp b/src/opt/hitting_sets.cpp index 8c10d3640..30ed1287a 100644 --- a/src/opt/hitting_sets.cpp +++ b/src/opt/hitting_sets.cpp @@ -149,13 +149,12 @@ namespace opt { m_max_weight(0), m_denominator(1), m_alloc("hitting-sets"), - m_weights_var(0), m_qhead(0), - m_scope_lvl(0), m_conflict_j(justification(justification::AXIOM)), m_inconsistent(false), - m_compare_scores(), - m_heap(0, m_compare_scores) { + m_scope_lvl(0), + m_heap(0, m_compare_scores), + m_weights_var(0) { m_enable_simplex = true; m_compare_scores.m_imp = this; } diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 3cae51bc2..857b57296 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -1343,7 +1343,6 @@ namespace opt { break; } case O_MAXSMT: { - maxsmt& ms = *m_maxsmts.find(obj.m_id); rational value(0); for (unsigned i = 0; i < obj.m_terms.size(); ++i) { VERIFY(m_model->eval(obj.m_terms[i], val)); diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 4f268268d..d505a9ffb 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -41,9 +41,9 @@ namespace opt { m_params(p), m_context(mgr, m_params), m(mgr), - m_dump_benchmarks(false), m_fm(fm), m_objective_sorts(m), + m_dump_benchmarks(false), m_first(true) { m_params.updt_params(p); m_params.m_relevancy_lvl = 0; diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index f3a4099d0..19205ddd9 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -73,7 +73,6 @@ namespace opt { filter_model_converter& m_fm; progress_callback * m_callback; symbol m_logic; - bool m_objective_enabled; svector m_objective_vars; vector m_objective_values; sref_vector m_models; diff --git a/src/shell/opt_frontend.cpp b/src/shell/opt_frontend.cpp index 616fc1962..a7b4f807e 100644 --- a/src/shell/opt_frontend.cpp +++ b/src/shell/opt_frontend.cpp @@ -340,7 +340,6 @@ unsigned parse_opt(char const* file_name, bool is_wcnf) { g_start_time = static_cast(clock()); register_on_timeout_proc(on_timeout); signal(SIGINT, on_ctrl_c); - unsigned result = 0; if (file_name) { std::ifstream in(file_name); if (in.bad() || in.fail()) { diff --git a/src/tactic/nlsat_smt/nl_purify_tactic.cpp b/src/tactic/nlsat_smt/nl_purify_tactic.cpp index 5f0163077..9b84654b9 100644 --- a/src/tactic/nlsat_smt/nl_purify_tactic.cpp +++ b/src/tactic/nlsat_smt/nl_purify_tactic.cpp @@ -631,11 +631,11 @@ public: m(m), m_util(m), m_params(p), + m_fmc(0), + m_cancel(false), m_nl_tac(mk_nlsat_tactic(m, p)), m_nl_g(0), m_solver(mk_smt_solver(m, p, symbol::null)), - m_fmc(0), - m_cancel(false), m_eq_preds(m), m_new_reals(m), m_new_preds(m), diff --git a/src/util/inf_rational.h b/src/util/inf_rational.h index 2da99cca5..e1060a7b0 100644 --- a/src/util/inf_rational.h +++ b/src/util/inf_rational.h @@ -63,10 +63,7 @@ class inf_rational { return s; } - inf_rational(): - m_first(rational()), - m_second(rational()) - {} + inf_rational() {} inf_rational(const inf_rational & r): m_first(r.m_first), diff --git a/src/util/rational.cpp b/src/util/rational.cpp index 122db7217..743038972 100644 --- a/src/util/rational.cpp +++ b/src/util/rational.cpp @@ -24,9 +24,9 @@ Revision History: #endif synch_mpq_manager * rational::g_mpq_manager = 0; -rational rational::m_zero(0); -rational rational::m_one(1); -rational rational::m_minus_one(-1); +rational rational::m_zero; +rational rational::m_one; +rational rational::m_minus_one; vector rational::m_powers_of_two; void mk_power_up_to(vector & pws, unsigned n) { @@ -56,11 +56,17 @@ rational rational::power_of_two(unsigned k) { void rational::initialize() { if (!g_mpq_manager) { g_mpq_manager = alloc(synch_mpq_manager); + m().set(m_zero.m_val, 0); + m().set(m_one.m_val, 1); + m().set(m_minus_one.m_val, -1); } } void rational::finalize() { m_powers_of_two.finalize(); + m_zero.~rational(); + m_one.~rational(); + m_minus_one.~rational(); dealloc(g_mpq_manager); g_mpq_manager = 0; } From 64bd62b17e37b357fede79d7497a4c366dc40fa0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 16 May 2015 11:56:04 +0100 Subject: [PATCH 781/925] fix gcc compiler warnings Signed-off-by: Nikolaj Bjorner --- src/muz/base/rule_properties.cpp | 1 - src/muz/ddnf/ddnf.cpp | 5 +- src/muz/pdr/pdr_context.cpp | 8 +- src/muz/pdr/pdr_prop_solver.cpp | 3 +- src/muz/pdr/pdr_prop_solver.h | 3 +- src/muz/rel/check_relation.cpp | 2 - src/muz/rel/doc.cpp | 2 +- src/muz/rel/doc.h | 1 - src/muz/rel/product_set.cpp | 788 ---------------------- src/muz/rel/product_set.h | 284 -------- src/muz/rel/rel_context.cpp | 2 - src/muz/rel/udoc_relation.cpp | 7 - src/opt/hitting_sets.cpp | 6 +- src/opt/opt_solver.h | 1 - src/sat/sat_bceq.cpp | 1 - src/sat/sat_mus.cpp | 2 +- src/sat/sat_mus.h | 2 +- src/sat/sat_sls.cpp | 1 - src/sat/sat_solver.cpp | 1 - src/shell/opt_frontend.cpp | 1 - src/smt/theory_arith_aux.h | 1 - src/smt/theory_datatype.cpp | 1 - src/tactic/nlsat_smt/nl_purify_tactic.cpp | 5 +- src/util/mpf.cpp | 4 +- 24 files changed, 18 insertions(+), 1114 deletions(-) delete mode 100644 src/muz/rel/product_set.cpp delete mode 100644 src/muz/rel/product_set.h diff --git a/src/muz/base/rule_properties.cpp b/src/muz/base/rule_properties.cpp index f5cac29e5..7cb1c6241 100644 --- a/src/muz/base/rule_properties.cpp +++ b/src/muz/base/rule_properties.cpp @@ -53,7 +53,6 @@ void rule_properties::collect(rule_set const& rules) { void rule_properties::check_quantifier_free() { if (!m_quantifiers.empty()) { - quantifier* q = m_quantifiers.begin()->m_key; rule* r = m_quantifiers.begin()->m_value; std::stringstream stm; stm << "cannot process quantifier in rule "; diff --git a/src/muz/ddnf/ddnf.cpp b/src/muz/ddnf/ddnf.cpp index 14f4a2b75..6545d4282 100644 --- a/src/muz/ddnf/ddnf.cpp +++ b/src/muz/ddnf/ddnf.cpp @@ -54,7 +54,6 @@ namespace datalog { typedef ptr_hashtable ddnf_nodes; private: - ddnf_mgr& m; tbv_manager& tbvm; tbv const& m_tbv; ddnf_node_vector m_children; @@ -68,7 +67,6 @@ namespace datalog { public: ddnf_node(ddnf_mgr& m, tbv_manager& tbvm, tbv const& tbv, unsigned id): - m(m), tbvm(tbvm), m_tbv(tbv), m_children(m), @@ -130,7 +128,6 @@ namespace datalog { void reset() { memset(this, 0, sizeof(*this)); } }; - unsigned m_num_bits; ddnf_node* m_root; ddnf_node_vector m_noderefs; bool m_internalized; @@ -141,7 +138,7 @@ namespace datalog { svector m_marked; stats m_stats; public: - ddnf_mgr(unsigned n): m_num_bits(n), m_noderefs(*this), m_internalized(false), m_tbv(n), + ddnf_mgr(unsigned n): m_noderefs(*this), m_internalized(false), m_tbv(n), m_hash(m_tbv), m_eq(m_tbv), m_nodes(DEFAULT_HASHTABLE_INITIAL_CAPACITY, m_hash, m_eq) { tbv* bX = m_tbv.allocateX(); diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index 3b7d5c056..30509d6bf 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -80,7 +80,7 @@ namespace pdr { pred_transformer::pred_transformer(context& ctx, manager& pm, func_decl* head): pm(pm), m(pm.get_manager()), ctx(ctx), m_head(head, m), - m_sig(m), m_solver(pm, ctx.get_params().pdr_try_minimize_core(), head->get_name()), + m_sig(m), m_solver(pm, head->get_name()), m_invariants(m), m_transition(m), m_initial_state(m), m_reachable(pm, (datalog::PDR_CACHE_MODE)ctx.get_params().pdr_cache_mode()) {} @@ -1137,9 +1137,9 @@ namespace pdr { if (n->get_model_ptr()) { models.insert(n->state(), n->get_model_ptr()); rules.insert(n->state(), n->get_rule()); - pred_transformer& pt = n->pt(); - context& ctx = pt.get_context(); - datalog::context& dctx = ctx.get_context(); + //pred_transformer& pt = n->pt(); + //context& ctx = pt.get_context(); + //datalog::context& dctx = ctx.get_context(); } todo.pop_back(); todo.append(n->children().size(), n->children().c_ptr()); diff --git a/src/muz/pdr/pdr_prop_solver.cpp b/src/muz/pdr/pdr_prop_solver.cpp index a7d0a02bf..9ba976254 100644 --- a/src/muz/pdr/pdr_prop_solver.cpp +++ b/src/muz/pdr/pdr_prop_solver.cpp @@ -225,12 +225,11 @@ namespace pdr { }; - prop_solver::prop_solver(manager& pm, bool try_minimize_core, symbol const& name) : + prop_solver::prop_solver(manager& pm, symbol const& name) : m_fparams(pm.get_fparams()), m(pm.get_manager()), m_pm(pm), m_name(name), - m_try_minimize_core(try_minimize_core), m_ctx(pm.mk_fresh()), m_pos_level_atoms(m), m_neg_level_atoms(m), diff --git a/src/muz/pdr/pdr_prop_solver.h b/src/muz/pdr/pdr_prop_solver.h index d7f13a603..a44ac7e5a 100644 --- a/src/muz/pdr/pdr_prop_solver.h +++ b/src/muz/pdr/pdr_prop_solver.h @@ -40,7 +40,6 @@ namespace pdr { ast_manager& m; manager& m_pm; symbol m_name; - bool m_try_minimize_core; scoped_ptr m_ctx; decl_vector m_level_preds; app_ref_vector m_pos_level_atoms; // atoms used to identify level @@ -74,7 +73,7 @@ namespace pdr { public: - prop_solver(pdr::manager& pm, bool try_minimize_core, symbol const& name); + prop_solver(pdr::manager& pm, symbol const& name); /** return true is s is a symbol introduced by prop_solver */ bool is_aux_symbol(func_decl * s) const { diff --git a/src/muz/rel/check_relation.cpp b/src/muz/rel/check_relation.cpp index c1b840c61..20364d5d5 100644 --- a/src/muz/rel/check_relation.cpp +++ b/src/muz/rel/check_relation.cpp @@ -297,7 +297,6 @@ namespace datalog { relation_base const& t1, relation_base const& t2, relation_base const& t, unsigned_vector const& cols1, unsigned_vector const& cols2, unsigned_vector const& rm_cols) { ast_manager& m = get_ast_manager(); - relation_signature const& sig2 = t.get_signature(); relation_signature const& sigA = t1.get_signature(); relation_signature const& sigB = t2.get_signature(); relation_signature sig1; @@ -383,7 +382,6 @@ namespace datalog { void check_relation_plugin::verify_join( relation_base const& t1, relation_base const& t2, relation_base const& t, unsigned_vector const& cols1, unsigned_vector const& cols2) { - ast_manager& m = get_ast_manager(); expr_ref fml1 = ground(t, mk_join(t1, t2, cols1, cols2)); expr_ref fml2 = ground(t); check_equiv("join", fml1, fml2); diff --git a/src/muz/rel/doc.cpp b/src/muz/rel/doc.cpp index a27d20c56..e73395bc9 100644 --- a/src/muz/rel/doc.cpp +++ b/src/muz/rel/doc.cpp @@ -214,7 +214,7 @@ bool doc_manager::merge( subset_ints const& equalities, bit_vector const& discard_cols) { for (unsigned i = 0; i < length; ++i) { unsigned idx = lo + i; - if (!merge(d, lo + i, equalities, discard_cols)) return false; + if (!merge(d, idx, equalities, discard_cols)) return false; } return true; } diff --git a/src/muz/rel/doc.h b/src/muz/rel/doc.h index ca5af005b..6ffefaf88 100644 --- a/src/muz/rel/doc.h +++ b/src/muz/rel/doc.h @@ -238,7 +238,6 @@ public: } void subtract(M& m, T& t) { unsigned sz = size(); - bool found = false; union_bvec result; for (unsigned i = 0; i < sz; ++i) { m.subtract(*m_elems[i], t, result.m_elems); diff --git a/src/muz/rel/product_set.cpp b/src/muz/rel/product_set.cpp deleted file mode 100644 index 9c26ed189..000000000 --- a/src/muz/rel/product_set.cpp +++ /dev/null @@ -1,788 +0,0 @@ -/*++ -Copyright (c) 2014 Microsoft Corporation - -Module Name: - - product_set.cpp - -Abstract: - - Product set. - -Author: - - Nikolaj Bjorner (nbjorner) 2014-08-23 - -Revision History: - ---*/ - -#include "product_set.h" -#include "bv_decl_plugin.h" -#include "dl_relation_manager.h" -#include "bool_rewriter.h" - -namespace datalog { - - static unsigned s_ps_num_bits = 0; - static unsigned s_num_ps = 0; - - product_set::product_set( - product_set_plugin& p, relation_signature const& s, - initial_t init, T const& t): - vector_relation(p, s, false, t), m_refs(0) { - unsigned delta = 0; - for (unsigned i = 0; i < s.size(); ++i) { - unsigned sz = p.set_size(s[i]); - (*this)[i].resize(sz); - if (init == FULL_t) { - (*this)[i].neg(); - } - delta += sz; - } - s_ps_num_bits += delta; - s_num_ps ++; - if ((s_num_ps % 1000) == 0) { - std::cout << s_num_ps << " " << s_ps_num_bits << " " << delta << "\n"; - } - } - - product_set::~product_set() { - relation_signature const& s = get_signature(); - product_set_plugin& p = dynamic_cast(get_plugin()); - for (unsigned i = 0; i < s.size(); ++i) { - unsigned sz = p.set_size(s[i]); - s_ps_num_bits -= sz; - } - --s_num_ps; - } - - unsigned product_set::get_hash() const { - unsigned hash = 0; - for (unsigned i = 0; i < get_signature().size(); ++i) { - hash ^= (*this)[i].get_hash(); - } - return hash; - } - - bool product_set::operator==(product_set const& p) const { - for (unsigned i = 0; i < get_signature().size(); ++i) { - if ((*this)[i] != p[i]) return false; - } - return true; - } - bool product_set::contains(product_set const& p) const { - for (unsigned i = 0; i < get_signature().size(); ++i) { - if ((*this)[i].contains(p[i])) return false; - } - return true; - } - void product_set::reset() { - for (unsigned i = 0; i < get_signature().size(); ++i) { - (*this)[i].fill0(); - } - } - void product_set::add_fact(const relation_fact & f) { - UNREACHABLE(); - } - bool product_set::contains_fact(const relation_fact & f) const { - UNREACHABLE(); - return false; - } - relation_base * product_set::clone() const { - product_set* result = alloc(product_set, dynamic_cast(get_plugin()), get_signature(), EMPTY_t); - result->copy(*this); - return result; - } - relation_base * product_set::complement(func_decl*) const { - product_set* result = alloc(product_set, dynamic_cast(get_plugin()), get_signature(), EMPTY_t); - result->copy(*this); - result->complement(); - return result; - } - - void product_set::complement() { - for (unsigned i = 0; i < get_signature().size(); ++i) { - (*this)[i].neg(); - } - } - void product_set::to_formula(expr_ref& fml) const { - ast_manager& m = fml.get_manager(); - bv_util bv(m); - expr_ref_vector conjs(m), disjs(m); - relation_signature const& sig = get_signature(); - if (m_empty) { - fml = m.mk_false(); - return; - } - for (unsigned i = 0; i < sig.size(); ++i) { - sort* ty = sig[i]; - expr_ref var(m.mk_var(i, ty), m); - unsigned j = find(i); - if (i != j) { - conjs.push_back(m.mk_eq(var, m.mk_var(j, sig[j]))); - continue; - } - T const& t = (*this)[i]; - disjs.reset(); - for (j = 0; j < t.size(); ++j) { - if (t.get(j)) { - disjs.push_back(m.mk_eq(var, bv.mk_numeral(rational(j), ty))); - } - } - if (disjs.empty()) { - UNREACHABLE(); - fml = m.mk_false(); - return; - } - if (disjs.size() == 1) { - conjs.push_back(disjs[0].get()); - } - else { - conjs.push_back(m.mk_or(disjs.size(), disjs.c_ptr())); - } - } - bool_rewriter br(m); - br.mk_and(conjs.size(), conjs.c_ptr(), fml); - } - void product_set::display_index(unsigned i, const T& t, std::ostream& out) const { - out << i << ":"; - t.display(out); - } - bool product_set::mk_intersect(unsigned idx, T const& t) { - if (!m_empty) { - (*this)[idx] &= t; - m_empty = is_empty(idx, (*this)[idx]); - } - return !m_empty; - } - - // product_set_relation - - - product_set_relation::product_set_relation(product_set_plugin& p, relation_signature const& s): - relation_base(p, s) { - } - - product_set_relation::~product_set_relation() { - reset(); - } - - class product_set_plugin::filter_interpreted_fn : public relation_mutator_fn { - app_ref m_condition; - public: - filter_interpreted_fn(ast_manager& m, app* condition): m_condition(condition, m) { - - }; - virtual ~filter_interpreted_fn() {} - - virtual void operator()(relation_base & _r) { - ast_manager& m = m_condition.get_manager(); - if (m.is_false(m_condition)) { - product_set_relation & r = get(_r); - r.reset(); - return; - } - if (m.is_true(m_condition)) { - return; - } - product_set_relation & r = get(_r); - product_set_plugin & p = r.get_plugin(); - NOT_IMPLEMENTED_YET(); - } - }; - - void product_set_relation::add_fact(const relation_fact & f) { - ast_manager& m = get_plugin().get_ast_manager(); - bv_util bv(m); - product_set* s = alloc(product_set, get_plugin(), get_signature(), product_set::EMPTY_t); - rational v; - unsigned bv_size; - // the bit-vector sets are empty at this point so they need to be primed. - for (unsigned i = 0; i < f.size(); ++i) { - VERIFY(bv.is_numeral(f[i], v, bv_size)); - SASSERT(v.is_unsigned()); - (*s)[i].set(v.get_unsigned(), true); - } - // s->display(std::cout << "fact"); - if (m_elems.contains(s)) { - dealloc(s); - } - else { - s->inc_ref(); - m_elems.insert(s); - } - - } - bool product_set_relation::contains_fact(const relation_fact & f) const { - std::cout << "contains fact\n"; - NOT_IMPLEMENTED_YET(); - return false; - } - product_set_relation * product_set_relation::clone() const { - product_set_relation* r = alloc(product_set_relation, get_plugin(), get_signature()); - product_sets::iterator it = m_elems.begin(), end = m_elems.end(); - for (; it != end; ++it) { - product_set* ps = dynamic_cast((*it)->clone()); - ps->inc_ref(); - r->m_elems.insert(ps); - } - return r; - } - void product_set_relation::reset() { - product_sets::iterator it = m_elems.begin(), end = m_elems.end(); - for (; it != end; ++it) { - (*it)->dec_ref(); - } - m_elems.reset(); - } - product_set_relation * product_set_relation::complement(func_decl*) const { - std::cout << "complement\n"; - NOT_IMPLEMENTED_YET(); - return 0; - } - void product_set_relation::to_formula(expr_ref& fml) const { - product_sets::iterator it = m_elems.begin(), end = m_elems.end(); - ast_manager& m = get_plugin().get_manager().get_context().get_manager(); - expr_ref_vector disjs(m); - for (; it != end; ++it) { - (*it)->to_formula(fml); - disjs.push_back(fml); - } - fml = m.mk_or(disjs.size(), disjs.c_ptr()); - } - product_set_plugin& product_set_relation::get_plugin() const { - return static_cast(relation_base::get_plugin()); - } - - void product_set_relation::display(std::ostream& out) const { - product_sets::iterator it = m_elems.begin(), end = m_elems.end(); - for (; it != end; ++it) { - (*it)->display(out); - } - } - - // product_set_plugin - - product_set_plugin::product_set_plugin(relation_manager& rm): - relation_plugin(product_set_plugin::get_name(), rm), - m(rm.get_context().get_manager()), - bv(m) { - } - - bool product_set_plugin::can_handle_signature(const relation_signature & sig) { - bv_util bv(get_manager().get_context().get_manager()); - for (unsigned i = 0; i < sig.size(); ++i) { - if (!bv.is_bv_sort(sig[i])) return false; - } - return true; - } - - product_set_relation& product_set_plugin::get(relation_base& r) { - return dynamic_cast(r); - } - product_set_relation* product_set_plugin::get(relation_base* r) { - return r?dynamic_cast(r):0; - } - product_set_relation const & product_set_plugin::get(relation_base const& r) { - return dynamic_cast(r); - } - relation_base * product_set_plugin::mk_empty(const relation_signature & s) { - return alloc(product_set_relation, *this, s); - } - relation_base * product_set_plugin::mk_full(func_decl* p, const relation_signature & sig) { - product_set_relation* result = alloc(product_set_relation, *this, sig); - product_set* s = alloc(product_set, *this, sig, product_set::FULL_t); - s->inc_ref(); - result->m_elems.insert(s); - return result; - } - product_set* product_set_plugin::insert(product_set* s, product_set_relation* r) { - if (s->empty()) { - s->reset(); - s->complement(); - } - else if (r->m_elems.contains(s)) { - s->reset(); - s->complement(); - } - else { - s->inc_ref(); - r->m_elems.insert(s); - s = alloc(product_set, *this, r->get_signature(), product_set::FULL_t); - } - return s; - } - - unsigned product_set_plugin::set_size(sort* ty) { - bv_util bv(get_ast_manager()); - unsigned bv_size = bv.get_bv_size(ty); - SASSERT(bv_size <= 16); - if (bv_size > 16) { - throw default_exception("bit-vector based sets are not suitable for this domain size"); - } - return 1 << bv_size; - } - - class product_set_plugin::join_fn : public convenient_relation_join_fn { - public: - join_fn(const relation_signature & o1_sig, const relation_signature & o2_sig, unsigned col_cnt, - const unsigned * cols1, const unsigned * cols2) - : convenient_relation_join_fn(o1_sig, o2_sig, col_cnt, cols1, cols2){ - } - - virtual relation_base * operator()(const relation_base & _r1, const relation_base & _r2) { - product_set_relation const& r1 = get(_r1); - product_set_relation const& r2 = get(_r2); - product_set_plugin& p = r1.get_plugin(); - relation_signature const& sig = get_result_signature(); - product_set_relation * result = alloc(product_set_relation, p, sig); - product_set* s = alloc(product_set, p, sig, product_set::FULL_t); - product_sets::iterator it1 = r1.m_elems.begin(), end1 = r1.m_elems.end(); - for (; it1 != end1; ++it1) { - product_sets::iterator it2 = r2.m_elems.begin(), end2 = r2.m_elems.end(); - for (; it2 != end2; ++it2) { - s->mk_join(*(*it1), *(*it2), m_cols1.size(), m_cols1.c_ptr(), m_cols2.c_ptr()); - s = p.insert(s, result); - } - } - dealloc(s); - std::cout << "join " << result->m_elems.size() << "\n"; - return result; - } - }; - relation_join_fn * product_set_plugin::mk_join_fn( - const relation_base & r1, const relation_base & r2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { - if (!check_kind(r1) || !check_kind(r2)) { - return 0; - } - return alloc(join_fn, r1.get_signature(), r2.get_signature(), col_cnt, cols1, cols2); - } - - class product_set_plugin::project_fn : public convenient_relation_project_fn { - public: - project_fn(const relation_signature & orig_sig, unsigned removed_col_cnt, - const unsigned * removed_cols) - : convenient_relation_project_fn(orig_sig, removed_col_cnt, removed_cols) { - } - - virtual relation_base * operator()(const relation_base & _r) { - product_set_relation const& r = get(_r); - product_set_plugin& p = r.get_plugin(); - relation_signature const& sig = get_result_signature(); - product_set_relation* result = alloc(product_set_relation, p, sig); - product_set* s = alloc(product_set, p, sig, product_set::FULL_t); - product_sets::iterator it = r.m_elems.begin(), end = r.m_elems.end(); - for (; it != end; ++it) { - s->mk_project(*(*it), m_removed_cols.size(), m_removed_cols.c_ptr()); - s = p.insert(s, result); - } - dealloc(s); - return result; - } - }; - relation_transformer_fn * product_set_plugin::mk_project_fn( - const relation_base & r, unsigned col_cnt, - const unsigned * removed_cols) { - if (check_kind(r)) { - return alloc(project_fn, r.get_signature(), col_cnt, removed_cols); - } - else { - return 0; - } - } - class product_set_plugin::rename_fn : public convenient_relation_rename_fn { - public: - rename_fn(const relation_signature & orig_sig, unsigned cycle_len, const unsigned * cycle) - : convenient_relation_rename_fn(orig_sig, cycle_len, cycle) { - } - - virtual relation_base * operator()(const relation_base & _r) { - product_set_relation const& r = get(_r); - product_set_plugin& p = r.get_plugin(); - relation_signature const& sig = get_result_signature(); - product_set_relation* result = alloc(product_set_relation, p, sig); - product_set* s = alloc(product_set, p, sig, product_set::FULL_t); - product_sets::iterator it = r.m_elems.begin(), end = r.m_elems.end(); - for (; it != end; ++it) { - s->mk_rename(*(*it), m_cycle.size(), m_cycle.c_ptr()); - s = p.insert(s, result); - } - dealloc(s); - return result; - } - }; - - relation_transformer_fn * product_set_plugin::mk_rename_fn(const relation_base & r, - unsigned cycle_len, const unsigned * permutation_cycle) { - if (check_kind(r)) { - return alloc(rename_fn, r.get_signature(), cycle_len, permutation_cycle); - } - else { - return 0; - } - } - - class product_set_plugin::union_fn : public relation_union_fn { - public: - union_fn() {} - - virtual void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) { - - TRACE("dl", _r.display(tout << "dst:\n"); _src.display(tout << "src:\n");); - - product_set_relation& r = get(_r); - product_set_relation const& src = get(_src); - product_set_relation* d = get(_delta); - r.get_plugin().mk_union(r, src, d); - std::cout << "union: " << r.m_elems.size() << "\n"; - } - }; - void product_set_plugin::mk_union( - product_set_relation& dst, product_set_relation const& src, product_set_relation* delta) { - product_sets::iterator it = src.m_elems.begin(), end = src.m_elems.end(); - for (; it != end; ++it) { - product_set* ps = *it; - if (!dst.m_elems.contains(ps)) { - ps->inc_ref(); - dst.m_elems.insert(ps); - if (delta) { - ps->inc_ref(); - delta->m_elems.insert(ps); - } - } - } - } - relation_union_fn * product_set_plugin::mk_union_fn( - const relation_base & tgt, const relation_base & src, - const relation_base * delta) { - if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) { - return 0; - } - return alloc(union_fn); - } - relation_union_fn * product_set_plugin::mk_widen_fn( - const relation_base & tgt, const relation_base & src, - const relation_base * delta) { - return mk_union_fn(tgt, src, delta); - } - - - class product_set_plugin::filter_identical_fn : public relation_mutator_fn { - unsigned_vector m_identical_cols; - public: - filter_identical_fn(unsigned col_cnt, const unsigned * identical_cols) - : m_identical_cols(col_cnt, identical_cols) {} - - virtual void operator()(relation_base & _r) { - product_set_relation & r = get(_r); - product_set_plugin& p = r.get_plugin(); - ptr_vector elems; - product_sets::iterator it = r.m_elems.begin(), end = r.m_elems.end(); - for (; it != end; ++it) { - elems.push_back(*it); - } - r.m_elems.reset(); - for (unsigned i = 0; i < elems.size(); ++i) { - product_set* s = elems[i]; - if (equate(*s)) { - r.m_elems.insert(s); - } - else { - s->dec_ref(); - } - } - } - private: - bool equate(product_set& dst) { - for (unsigned i = 1; !dst.empty() && i < m_identical_cols.size(); ++i) { - unsigned c1 = m_identical_cols[0]; - unsigned c2 = m_identical_cols[i]; - dst.equate(c1, c2); - } - return !dst.empty(); - } - }; - relation_mutator_fn * product_set_plugin::mk_filter_identical_fn( - const relation_base & t, unsigned col_cnt, const unsigned * identical_cols) { - return check_kind(t)?alloc(filter_identical_fn, col_cnt, identical_cols):0; - } - - - class product_set_plugin::filter_mask_fn : public relation_mutator_fn { - unsigned m_col; - bit_vector m_mask; - public: - filter_mask_fn(product_set_plugin& p, bit_vector const& mask, unsigned col) - : m_col(col), m_mask(mask) { - } - - virtual void operator()(relation_base & _r) { - product_set_relation & r = get(_r); - product_set_plugin & p = r.get_plugin(); - - ptr_vector elems; - product_sets::iterator it = r.m_elems.begin(), end = r.m_elems.end(); - for (; it != end; ++it) { - elems.push_back(*it); - } - r.m_elems.reset(); - for (unsigned i = 0; i < elems.size(); ++i) { - product_set* s = elems[i]; - - if (s->mk_intersect(m_col, m_mask)) { - r.m_elems.insert(s); - } - else { - s->dec_ref(); - } - } - } - }; - - relation_mutator_fn * product_set_plugin::mk_filter_equal_fn(const relation_base & r, - const relation_element & value, unsigned col) { - bit_vector mask; - expr* v = value; - extract_mask(1, &v, mask); - return check_kind(r)?alloc(filter_mask_fn, *this, mask, col):0; - } - - class product_set_plugin::filter_by_union_fn : public relation_mutator_fn { - ptr_vector m_mutators; - public: - filter_by_union_fn(unsigned n, relation_mutator_fn ** mutators): - m_mutators(n, mutators) { - } - virtual ~filter_by_union_fn() { - std::for_each(m_mutators.begin(), m_mutators.end(), delete_proc()); - } - - virtual void operator()(relation_base& _r) { - product_set_relation & r = get(_r); - product_set_plugin & p = r.get_plugin(); - - SASSERT(!m_mutators.empty()); - if (m_mutators.size() == 1) { - (*(m_mutators[0]))(r); - return; - } - product_set_relation src(p, r.get_signature()); - for (unsigned i = 1; i < m_mutators.size(); ++i) { - product_set_relation* r1 = r.clone(); - (*(m_mutators[i]))(*r1); - p.mk_union(src, *r1, 0); - r1->deallocate(); - } - (*(m_mutators[0]))(r); - p.mk_union(r, src, 0); - } - }; - - product_set_plugin::decomp_t product_set_plugin::decompose(expr* condition, expr_ref_vector& args, unsigned& col) { - args.reset(); - expr* e1, *e2; - app* value; - if (m.is_not(condition, e1) && m.is_not(e1, e2)) { - return decompose(e2, args, col); - } - if (m.is_not(condition, e1) && m.is_and(e1)) { - expr_ref tmp(m); - app* a = to_app(e1); - unsigned sz = a->get_num_args(); - for (unsigned i = 0; i < sz; ++i) { - args.push_back(mk_not(a->get_arg(i))); - } - tmp = m.mk_or(args.size(), args.c_ptr()); - return decompose(tmp, args, col); - } - if (m.is_not(condition, e1) && m.is_or(e1)) { - expr_ref tmp(m); - app* a = to_app(e1); - unsigned sz = a->get_num_args(); - for (unsigned i = 0; i < sz; ++i) { - args.push_back(mk_not(a->get_arg(i))); - } - tmp = m.mk_and(args.size(), args.c_ptr()); - return decompose(tmp, args, col); - } - if (m.is_and(condition)) { - app* a = to_app(condition); - unsigned sz = a->get_num_args(); - args.append(sz, a->get_args()); - return AND_d; - } - if (is_setof(condition, args, col)) { - SASSERT(!args.empty()); - return SET_d; - } - if (m.is_or(condition)) { - app* a = to_app(condition); - unsigned sz = a->get_num_args(); - args.append(sz, a->get_args()); - return OR_d; - } - if (is_value_ne(condition, value, col)) { - args.push_back(value); - return NE_d; - } - if (is_value_eq(condition, value, col)) { - args.push_back(value); - return EQ_d; - } - if (m.is_not(condition, e1) && m.is_true(e1)) { - return F_d; - } - if (m.is_false(condition)) { - return F_d; - } - if (m.is_not(condition, e1) && m.is_false(e1)) { - return T_d; - } - if (m.is_true(condition)) { - return T_d; - } - return UNHANDLED_d; - } - - bool product_set_plugin::mk_filter_interpreted( - const relation_base & t, expr_ref_vector const& args, - ptr_vector& mutators) { - unsigned sz = args.size(); - - for (unsigned i = 0; i < sz; ++i) { - expr* arg = args[i]; - if (!is_app(arg)) { - break; - } - relation_mutator_fn* mut = mk_filter_interpreted_fn(t, to_app(arg)); - if (!mut) { - break; - } - mutators.push_back(mut); - } - if (mutators.size() < sz) { - std::for_each(mutators.begin(), mutators.end(), delete_proc()); - return false; - } - else { - return true; - } - } - relation_mutator_fn * product_set_plugin::mk_filter_interpreted_fn( - const relation_base & t, app * condition) { - if (!check_kind(t)) return 0; - unsigned col; - ptr_vector mutators; - expr_ref_vector args(m); - bit_vector mask; - switch (decompose(condition, args, col)) { - case NE_d: - SASSERT(args.size() == 1); - extract_mask(1, args.c_ptr(), mask); - mask.neg(); - return alloc(filter_mask_fn, *this, mask, col); - case EQ_d: - SASSERT(args.size() == 1); - extract_mask(1, args.c_ptr(), mask); - return alloc(filter_mask_fn, *this, mask, col); - case AND_d: - if (!mk_filter_interpreted(t, args, mutators)) { - return 0; - } - return get_manager().mk_apply_sequential_fn(mutators.size(), mutators.c_ptr()); - case OR_d: - if (!mk_filter_interpreted(t, args, mutators)) { - return 0; - } - return alloc(filter_by_union_fn, mutators.size(), mutators.c_ptr()); - case F_d: - return alloc(filter_interpreted_fn, m, m.mk_false()); - case T_d: - return alloc(filter_interpreted_fn, m, m.mk_true()); - case SET_d: - extract_mask(args.size(), args.c_ptr(), mask); - return alloc(filter_mask_fn, *this, mask, col); - case UNHANDLED_d: - std::cout << "filter interpreted unhandled '" << mk_pp(condition, m) << "'\n"; - NOT_IMPLEMENTED_YET(); - return 0; - default: - UNREACHABLE(); - } - return 0; - } - - void product_set_plugin::extract_mask(unsigned n, expr* const* values, bit_vector& mask) { - SASSERT(n > 0); - unsigned sz = set_size(m.get_sort(values[0])); - mask.resize(sz, false); - rational v; - unsigned bv_size; - for (unsigned i = 0; i < n; ++i) { - expr* value = values[i]; - VERIFY(bv.is_numeral(value, v, bv_size)); - SASSERT(v.is_unsigned()); - unsigned w = v.get_unsigned(); - SASSERT(w < sz); - mask.set(w, true); - } - } - - bool product_set_plugin::is_setof(expr* condition, expr_ref_vector& values, unsigned & col) { - if (!m.is_or(condition)) return false; - unsigned sz = to_app(condition)->get_num_args(); - col = UINT_MAX; - unsigned col1; - if (sz == 0) return false; - values.reset(); - app* value; - for (unsigned i = 0; i < sz; ++i) { - expr* arg = to_app(condition)->get_arg(i); - if (is_value_eq(arg, value, col1)) { - if (col == UINT_MAX) { - col = col1; - values.push_back(value); - } - else if (col != col1) { - return false; - } - else { - values.push_back(value); - } - } - else { - return false; - } - } - return true; - } - - bool product_set_plugin::is_value_eq(expr* e, app*& value, unsigned& col) { - expr* e1, *e2; - rational val; - unsigned bv_size; - if (!m.is_eq(e, e1, e2)) return false; - if (!is_var(e1)) std::swap(e1, e2); - if (!is_var(e1)) return false; - if (!bv.is_numeral(e2, val, bv_size)) return false; - if (!val.is_unsigned()) return false; - value = to_app(e2); - col = to_var(e1)->get_idx(); - return true; - } - - bool product_set_plugin::is_value_ne(expr* condition, relation_element& value, unsigned& col) { - expr* e; - if (m.is_not(condition, e)) { - return is_value_eq(e, value, col); - } - else { - return false; - } - } - - -}; - diff --git a/src/muz/rel/product_set.h b/src/muz/rel/product_set.h deleted file mode 100644 index 238a33d8a..000000000 --- a/src/muz/rel/product_set.h +++ /dev/null @@ -1,284 +0,0 @@ -/*++ -Copyright (c) 2014 Microsoft Corporation - -Module Name: - - product_set.h - -Abstract: - - Product set relation. - A product set is a tuple of sets. - The meaning of a product set is the set of - elements in the cross-product. - A product set relation is a set of product sets, - and the meaning of this relation is the union of - all elements from the products. - It is to be used when computing over product sets is - (much) cheaper than over the space of tuples. - -Author: - - Nikolaj Bjorner (nbjorner) 2014-08-23 - -Revision History: - ---*/ -#ifndef _DL_PRODUCT_SET__H_ -#define _DL_PRODUCT_SET__H_ - -#include "util.h" -#include "bit_vector.h" -#include "dl_base.h" -#include "dl_vector_relation.h" - -namespace datalog { - - class product_set_plugin; - - class product_set : public vector_relation { - typedef bit_vector T; - unsigned m_refs; - public: - enum initial_t { - EMPTY_t, - FULL_t - }; - product_set(product_set_plugin& p, relation_signature const& s, initial_t init, T const& t = T()); - - virtual ~product_set(); - unsigned get_hash() const; - bool operator==(product_set const& p) const; - bool contains(product_set const& p) const; - - void inc_ref() { ++m_refs; } - void dec_ref() { --m_refs; if (0 == m_refs) dealloc(this); } - unsigned ref_count() const { return m_refs; } - - struct eq { - bool operator()(product_set const* s1, product_set const* s2) const { - return *s1 == *s2; - } - }; - - struct hash { - unsigned operator()(product_set const* s) const { - return s->get_hash(); - } - }; - - virtual void add_fact(const relation_fact & f); - virtual bool contains_fact(const relation_fact & f) const; - virtual relation_base * clone() const; - virtual relation_base * complement(func_decl*) const; - virtual void reset(); - virtual void to_formula(expr_ref& fml) const; - - bool mk_intersect(unsigned idx, T const& t); - void complement(); - - private: - virtual void display_index(unsigned i, const T&, std::ostream& out) const; - virtual T mk_intersect(T const& t1, T const& t2, bool& _is_empty) const { - T result(t1); - result &= t2; - _is_empty = is_empty(0, result); - return result; - } - - virtual T mk_widen(T const& t1, T const& t2) const { - UNREACHABLE(); - return t1; - } - - virtual T mk_unite(T const& t1, T const& t2) const { - UNREACHABLE(); - return t1; - } - - virtual bool is_subset_of(T const& t1, T const& t2) const { - return t2.contains(t1); - } - - virtual bool is_full(T const& t) const { - for (unsigned j = 0; j < t.size(); ++j) { - if (!t.get(j)) return false; - } - return true; - } - - virtual bool is_empty(unsigned i, T const& t) const { - for (unsigned j = 0; j < t.size(); ++j) { - if (t.get(j)) return false; - } - return true; - } - - virtual void mk_rename_elem(T& t, unsigned col_cnt, unsigned const* cycle) { - // no-op. - } - - virtual T mk_eq(union_find<> const& old_eqs, union_find<> const& neq_eqs, T const& t) const { - UNREACHABLE(); - return t; - } - }; - - - typedef ptr_hashtable product_sets; - - class product_set_relation : public relation_base { - friend class product_set_plugin; - product_sets m_elems; - public: - product_set_relation(product_set_plugin& p, relation_signature const& s); - virtual ~product_set_relation(); - virtual void reset(); - virtual void add_fact(const relation_fact & f); - virtual bool contains_fact(const relation_fact & f) const; - virtual product_set_relation * clone() const; - virtual product_set_relation * complement(func_decl*) const; - virtual void to_formula(expr_ref& fml) const; - product_set_plugin& get_plugin() const; - virtual bool empty() const { return m_elems.empty(); } - virtual void display(std::ostream& out) const; - - virtual bool is_precise() const { return true; } - }; - - class product_set_plugin : public relation_plugin { - friend class product_set_relation; - class join_fn; - class project_fn; - class union_fn; - class rename_fn; - class filter_mask_fn; - class filter_identical_fn; - class filter_interpreted_fn; - class filter_by_negation_fn; - class filter_by_union_fn; - ast_manager& m; - bv_util bv; - - public: - product_set_plugin(relation_manager& rm); - virtual bool can_handle_signature(const relation_signature & s); - static symbol get_name() { return symbol("product_set"); } - virtual relation_base * mk_empty(const relation_signature & s); - virtual relation_base * mk_full(func_decl* p, const relation_signature & s); - virtual relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); - virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, - const unsigned * removed_cols); - virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle); - virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta); - virtual relation_union_fn * mk_widen_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta); - virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, - const unsigned * identical_cols); - virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, - unsigned col); - virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); - - unsigned set_size(sort* ty); - - private: - static product_set_relation& get(relation_base& r); - static product_set_relation* get(relation_base* r); - static product_set_relation const & get(relation_base const& r); - product_set* insert(product_set* s, product_set_relation* r); - - enum decomp_t { - AND_d, // conjunction - OR_d, // disjunction - EQ_d, // value = col - NE_d, // value != col - F_d, // false - T_d, // true - SET_d, // disjunction value_i = col - UNHANDLED_d - }; - - decomp_t decompose(expr* condition, expr_ref_vector& args, unsigned& col); - - bool is_value_ne(expr* condition, relation_element& value, unsigned& col); - bool is_value_eq(expr* condition, relation_element& value, unsigned& col); - bool is_setof(expr* condition, expr_ref_vector& values, unsigned& col); - expr* mk_not(expr* e) { return m.is_not(e,e)?e:m.mk_not(e); } - void mk_union(product_set_relation& dst, product_set_relation const& src, product_set_relation* delta); - void extract_mask(unsigned sz, expr* const* values, bit_vector& mask); - bool mk_filter_interpreted( - const relation_base & t, expr_ref_vector const& args, - ptr_vector& mutators); - }; - - class product_set_factory; - - - class product_set2 { - friend class product_set_factory; - unsigned char m_data[0]; - public: - enum initial_t { - EMPTY_t, - FULL_t - }; - product_set2(product_set_factory& fac, initial_t init); - ~product_set2(); - unsigned get_hash(product_set_factory& fac) const; - bool equals(product_set_factory& fac, product_set2 const& other) const; - void add_fact(product_set_factory& fac, const relation_fact & f); - bool contains_fact(product_set_factory& fac, const relation_fact & f) const; - relation_base * clone(product_set_factory& fac) const; - void reset(product_set_factory& fac); - void mk_join(product_set_factory& fac, product_set2 const& r1, product_set2 const& r2, - unsigned num_cols, unsigned const* cols1, unsigned const* cols2); - void mk_project(product_set_factory& fac, - product_set2 const& r, unsigned col_cnt, unsigned const* removed_cols); - void mk_rename(product_set_factory& fac, - product_set2 const& r, unsigned col_cnt, unsigned const* cycle); - void mk_union(product_set_factory& fac, - product_set2 const& src, product_set2* delta, bool is_widen); - unsigned find(product_set_factory& fac, unsigned i); - void merge(product_set_factory& fac, unsigned i, unsigned j); - void display(product_set_factory& fac, std::ostream& out) const; - }; - - - class product_set_factory { - unsigned char m_data[0]; - public: - enum initial_t { - EMPTY_t, - FULL_t - }; - product_set_factory(product_set_plugin& p, relation_signature const& sig); - ~product_set_factory(); - product_set2* create(); - void retire(product_set2*); - - unsigned get_hash(product_set2& ps) const; - bool equals(product_set2 const& p1, product_set2 const& p2); - void add_fact(product_set2& p, const relation_fact & f); - bool contains_fact(product_set2& p, const relation_fact & f) const; - relation_base * clone(product_set2& p) const; - void reset(product_set2& p); - void mk_join(product_set2& p, product_set2 const& r1, product_set2 const& r2, - unsigned num_cols, unsigned const* cols1, unsigned const* cols2); - void mk_project(product_set2& p, - product_set2 const& r, unsigned col_cnt, unsigned const* removed_cols); - void mk_rename(product_set2& p, - product_set2 const& r, unsigned col_cnt, unsigned const* cycle); - void mk_union(product_set2& p, - product_set2 const& src, product_set2* delta, bool is_widen); - unsigned find(product_set2& p, unsigned i); - void merge(product_set2& p, unsigned i, unsigned j); - void display(product_set2& p, std::ostream& out) const; - }; - - -}; - -#endif diff --git a/src/muz/rel/rel_context.cpp b/src/muz/rel/rel_context.cpp index a2519137c..f3ac4bf84 100644 --- a/src/muz/rel/rel_context.cpp +++ b/src/muz/rel/rel_context.cpp @@ -32,7 +32,6 @@ Revision History: #include"dl_interval_relation.h" #include"karr_relation.h" #include"dl_finite_product_relation.h" -#include"product_set.h" #include"udoc_relation.h" #include"check_relation.h" #include"dl_lazy_table.h" @@ -117,7 +116,6 @@ namespace datalog { rm.register_plugin(alloc(bound_relation_plugin, rm)); rm.register_plugin(alloc(interval_relation_plugin, rm)); if (m_context.karr()) rm.register_plugin(alloc(karr_relation_plugin, rm)); - rm.register_plugin(alloc(product_set_plugin, rm)); rm.register_plugin(alloc(udoc_plugin, rm)); rm.register_plugin(alloc(check_relation_plugin, rm)); } diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 8e971ac1e..b6fa339ff 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -500,7 +500,6 @@ namespace datalog { udoc_relation const& src = get(_src); udoc_relation* d = get(_delta); doc_manager& dm = r.get_dm(); - ast_manager& m = r.get_plugin().get_ast_manager(); udoc* d1 = 0; if (d) d1 = &d->get_udoc(); IF_VERBOSE(3, r.display(verbose_stream() << "orig: ");); @@ -561,7 +560,6 @@ namespace datalog { : m_cols(col_cnt), m_equalities(union_ctx) { udoc_relation const& r = get(_r); doc_manager& dm = r.get_dm(); - unsigned num_bits = dm.num_tbits(); m_size = r.column_num_bits(identical_cols[0]); m_empty_bv.resize(r.get_num_bits(), false); for (unsigned i = 0; i < col_cnt; ++i) { @@ -946,7 +944,6 @@ namespace datalog { virtual void operator()(relation_base & tb) { udoc_relation & t = get(tb); udoc& u = t.get_udoc(); - ast_manager& m = m_reduced_condition.get_manager(); SASSERT(u.well_formed(dm)); u.intersect(dm, m_udoc); SASSERT(u.well_formed(dm)); @@ -981,7 +978,6 @@ namespace datalog { , m_joiner(t1.get_plugin(), t1, t2, col_cnt, cols1, cols2) #endif { - udoc_plugin& p = t1.get_plugin(); unsigned num_bits1 = t1.get_num_bits(); unsigned num_bits = num_bits1 + t2.get_num_bits(); unsigned_vector removed_cols(removed_col_cnt, rm_cols); @@ -1022,7 +1018,6 @@ namespace datalog { udoc const& d1 = t1.get_udoc(); udoc const& d2 = t2.get_udoc(); doc_manager& dm1 = t1.get_dm(); - doc_manager& dm2 = t2.get_dm(); udoc_plugin& p = t1.get_plugin(); doc_manager& dm_prod = p.dm(prod_signature); udoc_relation* result = get(p.mk_empty(get_result_signature())); @@ -1134,7 +1129,6 @@ namespace datalog { virtual void operator()(relation_base& tb, const relation_base& negb) { udoc_relation& t = get(tb); udoc_relation const& n = get(negb); - udoc_plugin& p = t.get_plugin(); IF_VERBOSE(3, t.display(verbose_stream() << "dst:");); IF_VERBOSE(3, n.display(verbose_stream() << "neg:");); if (t.fast_empty() || n.fast_empty()) @@ -1241,7 +1235,6 @@ namespace datalog { udoc_relation const & t = get(tb); udoc const& u1 = t.get_udoc(); doc_manager& dm = t.get_dm(); - ast_manager& m = m_reduced_condition.get_manager(); m_udoc2.copy(dm, u1); m_udoc2.intersect(dm, m_udoc); t.apply_guard(m_reduced_condition, m_udoc2, m_equalities, m_to_delete); diff --git a/src/opt/hitting_sets.cpp b/src/opt/hitting_sets.cpp index 8c10d3640..54ecaf35b 100644 --- a/src/opt/hitting_sets.cpp +++ b/src/opt/hitting_sets.cpp @@ -149,13 +149,13 @@ namespace opt { m_max_weight(0), m_denominator(1), m_alloc("hitting-sets"), - m_weights_var(0), m_qhead(0), - m_scope_lvl(0), m_conflict_j(justification(justification::AXIOM)), m_inconsistent(false), + m_scope_lvl(0), m_compare_scores(), - m_heap(0, m_compare_scores) { + m_heap(0, m_compare_scores), + m_weights_var(0) { m_enable_simplex = true; m_compare_scores.m_imp = this; } diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index f3a4099d0..19205ddd9 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -73,7 +73,6 @@ namespace opt { filter_model_converter& m_fm; progress_callback * m_callback; symbol m_logic; - bool m_objective_enabled; svector m_objective_vars; vector m_objective_values; sref_vector m_models; diff --git a/src/sat/sat_bceq.cpp b/src/sat/sat_bceq.cpp index 7ad0ec837..e3613515f 100644 --- a/src/sat/sat_bceq.cpp +++ b/src/sat/sat_bceq.cpp @@ -176,7 +176,6 @@ namespace sat { bool bceq::bce(clause& cls) { svector live_clauses; use_list ul; - use_list* save = m_use_list; m_use_list = &ul; ul.init(m_solver.num_vars()); for (unsigned i = 0; i < m_L.size(); ++i) { diff --git a/src/sat/sat_mus.cpp b/src/sat/sat_mus.cpp index 65d776d84..4a811741f 100644 --- a/src/sat/sat_mus.cpp +++ b/src/sat/sat_mus.cpp @@ -24,7 +24,7 @@ Notes: namespace sat { - mus::mus(solver& s):s(s), m_is_active(false) {} + mus::mus(solver& s):s(s), m_is_active(false), m_best_value(0), m_restart(0), m_max_restarts(0) {} mus::~mus() {} diff --git a/src/sat/sat_mus.h b/src/sat/sat_mus.h index 944cceffb..12cff4cec 100644 --- a/src/sat/sat_mus.h +++ b/src/sat/sat_mus.h @@ -21,6 +21,7 @@ Notes: namespace sat { class mus { + solver& s; literal_vector m_core; literal_vector m_mus; bool m_is_active; @@ -30,7 +31,6 @@ namespace sat { unsigned m_max_restarts; - solver& s; public: mus(solver& s); ~mus(); diff --git a/src/sat/sat_sls.cpp b/src/sat/sat_sls.cpp index bd0f8855a..0744ef37a 100644 --- a/src/sat/sat_sls.cpp +++ b/src/sat/sat_sls.cpp @@ -365,7 +365,6 @@ namespace sat { m_clause_weights.resize(m_clauses.size(), 1); m_sscore.resize(s.num_vars(), 0.0); m_hscore.resize(s.num_vars(), 0); - unsigned num_violated = 0; for (unsigned i = 0; i < m_soft.size(); ++i) { literal lit = m_soft[i]; m_sscore[lit.var()] = m_weights[i]; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index b1bcaa07f..40d02ebbb 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1637,7 +1637,6 @@ namespace sat { void solver::process_antecedent_for_unsat_core(literal antecedent) { bool_var var = antecedent.var(); - unsigned var_lvl = lvl(var); SASSERT(var < num_vars()); TRACE("sat", tout << antecedent << " " << (is_marked(var)?"+":"-") << "\n";); if (!is_marked(var)) { diff --git a/src/shell/opt_frontend.cpp b/src/shell/opt_frontend.cpp index 616fc1962..a7b4f807e 100644 --- a/src/shell/opt_frontend.cpp +++ b/src/shell/opt_frontend.cpp @@ -340,7 +340,6 @@ unsigned parse_opt(char const* file_name, bool is_wcnf) { g_start_time = static_cast(clock()); register_on_timeout_proc(on_timeout); signal(SIGINT, on_ctrl_c); - unsigned result = 0; if (file_name) { std::ifstream in(file_name); if (in.bad() || in.fail()) { diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index d1f7abcbc..0e4eba822 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -961,7 +961,6 @@ namespace smt { bool theory_arith::is_safe_to_leave(theory_var x, bool inc, bool& has_int, bool& shared) { context& ctx = get_context(); - ast_manager& m = get_manager(); shared |= ctx.is_shared(get_enode(x)); column & c = m_columns[x]; typename svector::iterator it = c.begin_entries(); diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index b5cdbcfe2..a004da666 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -163,7 +163,6 @@ namespace smt { ast_manager & m = get_manager(); app* own = n->get_owner(); expr* arg1 = own->get_arg(0); - expr* arg2 = own->get_arg(1); func_decl * upd = n->get_decl(); func_decl * acc = to_func_decl(upd->get_parameter(0).get_ast()); func_decl * con = m_util.get_accessor_constructor(acc); diff --git a/src/tactic/nlsat_smt/nl_purify_tactic.cpp b/src/tactic/nlsat_smt/nl_purify_tactic.cpp index 5f0163077..971c7af57 100644 --- a/src/tactic/nlsat_smt/nl_purify_tactic.cpp +++ b/src/tactic/nlsat_smt/nl_purify_tactic.cpp @@ -631,11 +631,12 @@ public: m(m), m_util(m), m_params(p), + m_produce_proofs(false), + m_fmc(0), + m_cancel(false), m_nl_tac(mk_nlsat_tactic(m, p)), m_nl_g(0), m_solver(mk_smt_solver(m, p, symbol::null)), - m_fmc(0), - m_cancel(false), m_eq_preds(m), m_new_reals(m), m_new_preds(m), diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 4940fa448..994083834 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -1065,8 +1065,8 @@ void mpf_manager::round_to_integral(mpf_rounding_mode rm, mpf const & x, mpf & o m_mpz_manager.mul2k(rem, 1, t); bool tie = m_mpz_manager.eq(t, shift_p); if (tie && - (rm == MPF_ROUND_NEAREST_TEVEN && m_mpz_manager.is_odd(div)) || - (rm == MPF_ROUND_NEAREST_TAWAY && m_mpz_manager.is_even(div))) + ((rm == MPF_ROUND_NEAREST_TEVEN && m_mpz_manager.is_odd(div)) || + (rm == MPF_ROUND_NEAREST_TAWAY && m_mpz_manager.is_even(div)))) m_mpz_manager.inc(div); else if (x.sign ^ m_mpz_manager.gt(t, shift_p)) m_mpz_manager.inc(div); From e8811748d39aac2b6f4797dc5a3ac4b8f895a2ff Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 16 May 2015 19:08:37 +0100 Subject: [PATCH 782/925] fix regressions in nl/smt Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 12 ++++++++--- src/smt/theory_arith.h | 4 ++-- src/smt/theory_arith_aux.h | 25 ++++++++++++----------- src/smt/theory_arith_inv.h | 9 +++++--- src/smt/theory_arith_nl.h | 2 +- src/tactic/arith/probe_arith.cpp | 7 ++++--- src/tactic/nlsat_smt/nl_purify_tactic.cpp | 25 +++++++++++++---------- 7 files changed, 49 insertions(+), 35 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index ac9122335..b51143ff2 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -85,6 +85,7 @@ VS_PAR=False VS_PAR_NUM=8 GPROF=False GIT_HASH=False +OPTIMIZE=False FPMATH="Default" FPMATH_FLAGS="-mfpmath=sse -msse -msse2" @@ -551,6 +552,8 @@ def display_help(exit_code): print(" -v, --vsproj generate Visual Studio Project Files.") if IS_WINDOWS: print(" -n, --nodotnet do not generate Microsoft.Z3.dll make rules.") + if IS_WINDOWS: + print(" --optimize generate optimized code during linking.") print(" -j, --java generate Java bindings.") print(" --ml generate OCaml bindings.") print(" --staticlib build Z3 static library.") @@ -577,13 +580,13 @@ def display_help(exit_code): def parse_options(): global VERBOSE, DEBUG_MODE, IS_WINDOWS, VS_X64, ONLY_MAKEFILES, SHOW_CPPS, VS_PROJ, TRACE, VS_PAR, VS_PAR_NUM global DOTNET_ENABLED, JAVA_ENABLED, ML_ENABLED, STATIC_LIB, PREFIX, GMP, FOCI2, FOCI2LIB, PYTHON_PACKAGE_DIR, GPROF, GIT_HASH - global LINUX_X64 + global LINUX_X64, OPTIMIZE try: options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:df:sxhmcvtnp:gj', ['build=', 'debug', 'silent', 'x64', 'help', 'makefiles', 'showcpp', 'vsproj', 'trace', 'nodotnet', 'staticlib', 'prefix=', 'gmp', 'foci2=', 'java', 'parallel=', 'gprof', - 'githash=', 'x86', 'ml']) + 'githash=', 'x86', 'ml', 'optimize']) except: print("ERROR: Invalid command line option") display_help(1) @@ -618,6 +621,8 @@ def parse_options(): DOTNET_ENABLED = False elif opt in ('--staticlib'): STATIC_LIB = True + elif opt in ('--optimize'): + OPTIMIZE = True elif not IS_WINDOWS and opt in ('-p', '--prefix'): PREFIX = arg PYTHON_PACKAGE_DIR = os.path.join(PREFIX, 'lib', 'python%s' % distutils.sysconfig.get_python_version(), 'dist-packages') @@ -1781,8 +1786,9 @@ def mk_config(): 'SLINK_EXTRA_FLAGS=/link /DEBUG /MACHINE:X64 /SUBSYSTEM:WINDOWS /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE:NO\n') else: # Windows Release mode + if OPTIMIZE: + config.write('AR_FLAGS=/nologo /LTCG\n') config.write( - 'AR_FLAGS=/nologo /LTCG\n' 'LINK_FLAGS=/nologo /MD\n' 'SLINK_FLAGS=/nologo /LD\n') if TRACE: diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 826d95ef0..660a11faa 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -882,10 +882,10 @@ namespace smt { template void add_tmp_row_entry(row & r, numeral const & coeff, theory_var v); enum max_min_t { UNBOUNDED, AT_BOUND, OPTIMIZED, BEST_EFFORT}; - max_min_t max_min(theory_var v, bool max, bool& has_shared); + max_min_t max_min(theory_var v, bool max, bool maintain_integrality, bool& has_shared); bool max_min(svector const & vars); - max_min_t max_min(row& r, bool max, bool& has_shared); + max_min_t max_min(row& r, bool max, bool maintain_integrality, bool& has_shared); bool unbounded_gain(inf_numeral const & max_gain) const; bool safe_gain(inf_numeral const& min_gain, inf_numeral const & max_gain) const; void normalize_gain(numeral const& divisor, inf_numeral & max_gain) const; diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 0e4eba822..91ee6def5 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -1133,7 +1133,7 @@ namespace smt { inf_eps_rational theory_arith::maximize(theory_var v, expr_ref& blocker, bool& has_shared) { TRACE("bound_bug", display_var(tout, v); display(tout);); has_shared = false; - max_min_t r = max_min(v, true, has_shared); + max_min_t r = max_min(v, true, true, has_shared); if (r == UNBOUNDED) { has_shared = false; blocker = get_manager().mk_false(); @@ -1553,13 +1553,14 @@ namespace smt { typename theory_arith::max_min_t theory_arith::max_min( row & r, bool max, + bool maintain_integrality, bool& has_shared) { m_stats.m_max_min++; unsigned best_efforts = 0; bool inc = false; context& ctx = get_context(); - SASSERT(valid_assignment()); + SASSERT(!maintain_integrality || valid_assignment()); numeral a_ij, curr_a_ij, coeff, curr_coeff; inf_numeral min_gain, max_gain, curr_min_gain, curr_max_gain; @@ -1633,7 +1634,7 @@ namespace smt { if (x_j == null_theory_var) { TRACE("opt", tout << "row is " << (max ? "maximized" : "minimized") << "\n";); - SASSERT(valid_assignment()); + SASSERT(!maintain_integrality || valid_assignment()); result = OPTIMIZED; break; } @@ -1648,7 +1649,7 @@ namespace smt { SASSERT(!unbounded_gain(max_gain)); update_value(x_j, max_gain); TRACE("opt", tout << "moved v" << x_j << " to upper bound\n";); - SASSERT(valid_assignment()); + SASSERT(!maintain_integrality || valid_assignment()); continue; } if (!inc && lower(x_j)) { @@ -1656,7 +1657,7 @@ namespace smt { max_gain.neg(); update_value(x_j, max_gain); TRACE("opt", tout << "moved v" << x_j << " to lower bound\n";); - SASSERT(valid_assignment()); + SASSERT(!maintain_integrality || valid_assignment()); continue; } if (ctx.is_shared(get_enode(x_j))) { @@ -1681,7 +1682,7 @@ namespace smt { TRACE("opt", tout << "moved v" << x_j << " to lower bound\n";); } update_value(x_j, max_gain); - SASSERT(valid_assignment()); + SASSERT(!maintain_integrality || valid_assignment()); continue; } @@ -1709,7 +1710,7 @@ namespace smt { coeff.neg(); add_tmp_row(r, coeff, r2); SASSERT(r.get_idx_of(x_j) == -1); - SASSERT(valid_assignment()); + SASSERT(!maintain_integrality || valid_assignment()); } TRACE("opt", display(tout);); return (best_efforts>0)?BEST_EFFORT:result; @@ -1781,10 +1782,10 @@ namespace smt { \brief Maximize/Minimize the given variable. The bounds of v are update if procedure succeeds. */ template - typename theory_arith::max_min_t theory_arith::max_min(theory_var v, bool max, bool& has_shared) { + typename theory_arith::max_min_t theory_arith::max_min(theory_var v, bool max, bool maintain_integrality, bool& has_shared) { expr* e = get_enode(v)->get_owner(); - SASSERT(valid_assignment()); + SASSERT(!maintain_integrality || valid_assignment()); SASSERT(!is_quasi_base(v)); if ((max && at_upper(v)) || (!max && at_lower(v))) { TRACE("opt", tout << "At bound: " << mk_pp(e, get_manager()) << "...\n";); @@ -1803,7 +1804,7 @@ namespace smt { add_tmp_row_entry(m_tmp_row, it->m_coeff, it->m_var); } } - max_min_t r = max_min(m_tmp_row, max, has_shared); + max_min_t r = max_min(m_tmp_row, max, maintain_integrality, has_shared); if (r == OPTIMIZED) { TRACE("opt", tout << mk_pp(e, get_manager()) << " " << (max ? "max" : "min") << " value is: " << get_value(v) << "\n"; display_row(tout, m_tmp_row, true); display_row_info(tout, m_tmp_row);); @@ -1830,9 +1831,9 @@ namespace smt { svector::const_iterator it = vars.begin(); svector::const_iterator end = vars.end(); for (; it != end; ++it) { - if (max_min(*it, true, has_shared) == OPTIMIZED && !has_shared) + if (max_min(*it, true, false, has_shared) == OPTIMIZED && !has_shared) succ = true; - if (max_min(*it, false, has_shared) == OPTIMIZED && !has_shared) + if (max_min(*it, false, false, has_shared) == OPTIMIZED && !has_shared) succ = true; } if (succ) { diff --git a/src/smt/theory_arith_inv.h b/src/smt/theory_arith_inv.h index 007c8025f..9c56ea367 100644 --- a/src/smt/theory_arith_inv.h +++ b/src/smt/theory_arith_inv.h @@ -214,10 +214,13 @@ namespace smt { template bool theory_arith::valid_assignment() const { - return - valid_row_assignment() && + if (valid_row_assignment() && satisfy_bounds() && - satisfy_integrality(); + satisfy_integrality()) { + return true; + } + TRACE("arith", display(tout);); + return false; } #endif diff --git a/src/smt/theory_arith_nl.h b/src/smt/theory_arith_nl.h index 8ff122c1e..c2322fce2 100644 --- a/src/smt/theory_arith_nl.h +++ b/src/smt/theory_arith_nl.h @@ -2371,7 +2371,7 @@ namespace smt { return FC_CONTINUE; } - if (!max_min_nl_vars()) + if (!max_min_nl_vars()) return FC_CONTINUE; if (check_monomial_assignments()) { diff --git a/src/tactic/arith/probe_arith.cpp b/src/tactic/arith/probe_arith.cpp index e276d1792..9c02b5f0f 100644 --- a/src/tactic/arith/probe_arith.cpp +++ b/src/tactic/arith/probe_arith.cpp @@ -549,9 +549,10 @@ struct is_non_qfufnra_functor { case OP_IRRATIONAL_ALGEBRAIC_NUM: return; case OP_MUL: - if (n->get_num_args() == 2 || - (!u.is_numeral(n->get_arg(0)) && - !u.is_numeral(n->get_arg(1)))) { + if (n->get_num_args() == 2 && + u.is_real(n->get_arg(0)) && + !u.is_numeral(n->get_arg(0)) && + !u.is_numeral(n->get_arg(1))) { m_has_nonlinear = true; } return; diff --git a/src/tactic/nlsat_smt/nl_purify_tactic.cpp b/src/tactic/nlsat_smt/nl_purify_tactic.cpp index 9b84654b9..ec150453d 100644 --- a/src/tactic/nlsat_smt/nl_purify_tactic.cpp +++ b/src/tactic/nlsat_smt/nl_purify_tactic.cpp @@ -311,16 +311,17 @@ private: // assert equalities between equal interface real variables. model_ref mdl_nl, mdl_smt; - model_converter2model(m, nl_mc.get(), mdl_nl); - update_eq_values(mdl_nl); - enforce_equalities(mdl_nl, m_nl_g); - - setup_assumptions(mdl_nl); - - TRACE("nlsat_smt", - model_smt2_pp(tout << "nl model\n", m, *mdl_nl.get(), 0); - m_solver->display(tout << "smt goal:\n"); tout << "\n";); - + if (mdl_nl.get()) { + model_converter2model(m, nl_mc.get(), mdl_nl); + update_eq_values(mdl_nl); + enforce_equalities(mdl_nl, m_nl_g); + + setup_assumptions(mdl_nl); + + TRACE("nlsat_smt", + model_smt2_pp(tout << "nl model\n", m, *mdl_nl.get(), 0); + m_solver->display(tout << "smt goal:\n"); tout << "\n";); + } result.reset(); lbool r = m_solver->check_sat(m_asms.size(), m_asms.c_ptr()); if (r == l_false) { @@ -352,7 +353,9 @@ private: TRACE("nlsat_smt", m_fmc->display(tout << "joint state is sat\n"); nl_mc->display(tout << "nl\n");); - merge_models(*mdl_nl.get(), mdl_smt); + if (mdl_nl.get()) { + merge_models(*mdl_nl.get(), mdl_smt); + } mc = m_fmc.get(); apply(mc, mdl_smt, 0); mc = model2model_converter(mdl_smt.get()); From afea50e6318072ee2d12537d960b1a1ff6256311 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 17 May 2015 22:49:59 +0100 Subject: [PATCH 783/925] remove assertion from integer constructor, rely on exceptions for API abuse Signed-off-by: Nikolaj Bjorner --- src/ast/arith_decl_plugin.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ast/arith_decl_plugin.cpp b/src/ast/arith_decl_plugin.cpp index 5245b9685..9d1f4343f 100644 --- a/src/ast/arith_decl_plugin.cpp +++ b/src/ast/arith_decl_plugin.cpp @@ -417,7 +417,6 @@ inline decl_kind arith_decl_plugin::fix_kind(decl_kind k, unsigned arity) { app * arith_decl_plugin::mk_numeral(rational const & val, bool is_int) { if (is_int && !val.is_int()) { - SASSERT(false); m_manager->raise_exception("invalid rational value passed as an integer"); } if (val.is_unsigned()) { From 552bba2c8cef2a2cad1f2bb5f001dbc6cd107620 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 17 May 2015 22:59:11 +0100 Subject: [PATCH 784/925] decongest critical section in lia2card-tactic Signed-off-by: Nikolaj Bjorner --- src/tactic/arith/lia2card_tactic.cpp | 36 +++++++++++++++++----------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/src/tactic/arith/lia2card_tactic.cpp b/src/tactic/arith/lia2card_tactic.cpp index 0afbe62f1..7d9efd44b 100644 --- a/src/tactic/arith/lia2card_tactic.cpp +++ b/src/tactic/arith/lia2card_tactic.cpp @@ -31,18 +31,22 @@ public: arith_util a; params_ref m_params; pb_util m_pb; - mutable ptr_vector m_todo; - expr_set m_01s; + mutable ptr_vector* m_todo; + expr_set* m_01s; bool m_compile_equality; lia2card_tactic(ast_manager & _m, params_ref const & p): m(_m), a(m), m_pb(m), + m_todo(alloc(ptr_vector)), + m_01s(alloc(expr_set)), m_compile_equality(false) { } virtual ~lia2card_tactic() { + dealloc(m_todo); + dealloc(m_01s); } void set_cancel(bool f) { @@ -60,7 +64,7 @@ public: expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); mc = 0; pc = 0; core = 0; - m_01s.reset(); + m_01s->reset(); tactic_report report("cardinality-intro", *g); @@ -76,7 +80,7 @@ public: if (a.is_int(x) && bounds.has_lower(x, lo, s1) && !s1 && lo.is_zero() && bounds.has_upper(x, hi, s2) && !s2 && hi.is_one()) { - m_01s.insert(x); + m_01s->insert(x); TRACE("pb", tout << "add bound " << mk_pp(x, m) << "\n";); } } @@ -114,11 +118,11 @@ public: void extract_pb_substitution(ast_mark& mark, expr* fml, expr_safe_replace& sub) { expr_ref tmp(m); - m_todo.reset(); - m_todo.push_back(fml); - while (!m_todo.empty()) { - expr* e = m_todo.back(); - m_todo.pop_back(); + m_todo->reset(); + m_todo->push_back(fml); + while (!m_todo->empty()) { + expr* e = m_todo->back(); + m_todo->pop_back(); if (mark.is_marked(e) || !is_app(e)) { continue; } @@ -128,13 +132,13 @@ public: continue; } app* ap = to_app(e); - m_todo.append(ap->get_num_args(), ap->get_args()); + m_todo->append(ap->get_num_args(), ap->get_args()); } } bool is_01var(expr* x) const { - return m_01s.contains(x); + return m_01s->contains(x); } expr_ref mk_01(expr* x) { @@ -282,12 +286,16 @@ public: "(default:false) compile equalities into pseudo-Boolean equality"); } - virtual void cleanup() { + virtual void cleanup() { + expr_set* d = alloc(expr_set); + ptr_vector* todo = alloc(ptr_vector); #pragma omp critical (tactic_cancel) { - m_01s.reset(); - m_todo.reset(); + std::swap(m_01s, d); + std::swap(m_todo, todo); } + dealloc(d); + dealloc(todo); } }; From ef32aaaf12bbaac939c66161cfa9ad4bbdecec68 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 18 May 2015 16:37:20 +0100 Subject: [PATCH 785/925] don't use -fPIC on cygwin 64 Signed-off-by: Nuno Lopes --- scripts/mk_util.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index b51143ff2..5b7c10605 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1892,7 +1892,8 @@ def mk_config(): else: raise MKException('Unsupported platform: %s' % sysname) if is64(): - CXXFLAGS = '%s -fPIC' % CXXFLAGS + if sysname[:6] != 'CYGWIN': + CXXFLAGS = '%s -fPIC' % CXXFLAGS CPPFLAGS = '%s -D_AMD64_' % CPPFLAGS if sysname == 'Linux': CPPFLAGS = '%s -D_USE_THREAD_LOCAL' % CPPFLAGS From c36df1c34ad09b6e7d95765b8698c46d4ffcc066 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 May 2015 12:43:55 -0700 Subject: [PATCH 786/925] fix openmp nested critical section Signed-off-by: Nikolaj Bjorner --- src/tactic/nlsat_smt/nl_purify_tactic.cpp | 3 +-- src/tactic/tactic.h | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tactic/nlsat_smt/nl_purify_tactic.cpp b/src/tactic/nlsat_smt/nl_purify_tactic.cpp index ec150453d..91c462486 100644 --- a/src/tactic/nlsat_smt/nl_purify_tactic.cpp +++ b/src/tactic/nlsat_smt/nl_purify_tactic.cpp @@ -656,13 +656,12 @@ public: } virtual void set_cancel(bool f) { + m_nl_tac->set_cancel(f); if (f) { - m_nl_tac->cancel(); m_solver->cancel(); } else { m_solver->reset_cancel(); - m_nl_tac->reset_cancel(); } m_cancel = f; } diff --git a/src/tactic/tactic.h b/src/tactic/tactic.h index 8b4f9f576..cab93f1ea 100644 --- a/src/tactic/tactic.h +++ b/src/tactic/tactic.h @@ -95,10 +95,11 @@ public: // translate tactic to the given manager virtual tactic * translate(ast_manager & m) = 0; -private: +protected: friend class nary_tactical; friend class binary_tactical; friend class unary_tactical; + friend class nl_purify_tactic; virtual void set_cancel(bool f) {} From 203c5015c8522656ebaa3a0db02333a653f5949d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 May 2015 15:17:21 -0700 Subject: [PATCH 787/925] fix debian amd64 warnings Signed-off-by: Nikolaj Bjorner --- src/math/simplex/sparse_matrix.h | 2 +- src/muz/rel/udoc_relation.cpp | 1 - src/opt/mus.cpp | 3 ++- src/sat/sat_sls.cpp | 2 +- src/sat/tactic/goal2sat.cpp | 2 +- src/shell/opt_frontend.cpp | 6 +++--- src/smt/theory_arith_core.h | 2 +- src/smt/theory_wmaxsat.cpp | 5 +++-- src/tactic/sls/bvsls_opt_engine.cpp | 5 +++-- 9 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/math/simplex/sparse_matrix.h b/src/math/simplex/sparse_matrix.h index ee28e1475..c02375e7e 100644 --- a/src/math/simplex/sparse_matrix.h +++ b/src/math/simplex/sparse_matrix.h @@ -48,7 +48,7 @@ namespace simplex { } }; - static const int dead_id = -1; + static const unsigned dead_id = UINT_MAX; /** \brief A row_entry is: m_var*m_coeff diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index b6fa339ff..6d69550ef 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -559,7 +559,6 @@ namespace datalog { filter_identical_fn(const relation_base & _r, unsigned col_cnt, const unsigned *identical_cols) : m_cols(col_cnt), m_equalities(union_ctx) { udoc_relation const& r = get(_r); - doc_manager& dm = r.get_dm(); m_size = r.column_num_bits(identical_cols[0]); m_empty_bv.resize(r.get_num_bits(), false); for (unsigned i = 0; i < col_cnt; ++i) { diff --git a/src/opt/mus.cpp b/src/opt/mus.cpp index 7f265ab0f..566f4ec0b 100644 --- a/src/opt/mus.cpp +++ b/src/opt/mus.cpp @@ -54,7 +54,8 @@ struct mus::imp { unsigned add_soft(expr* cls) { - SASSERT(is_uninterp_const(cls) || m.is_not(cls) && is_uninterp_const(to_app(cls)->get_arg(0))); + SASSERT(is_uninterp_const(cls) || + (m.is_not(cls) && is_uninterp_const(to_app(cls)->get_arg(0)))); unsigned idx = m_cls2expr.size(); m_expr2cls.insert(cls, idx); m_cls2expr.push_back(cls); diff --git a/src/sat/sat_sls.cpp b/src/sat/sat_sls.cpp index 0744ef37a..ad26554af 100644 --- a/src/sat/sat_sls.cpp +++ b/src/sat/sat_sls.cpp @@ -273,7 +273,7 @@ namespace sat { clause const& c = *m_clauses[i]; bool is_sat = c.satisfied_by(m_model); SASSERT(is_sat != m_false.contains(i)); - SASSERT(is_sat == m_num_true[i] > 0); + SASSERT(is_sat == (m_num_true[i] > 0)); } } diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 7224de971..ff201042b 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -36,7 +36,7 @@ Notes: #include"model_v2_pp.h" #include"tactic.h" #include"ast_pp.h" -#include +#include struct goal2sat::imp { struct frame { diff --git a/src/shell/opt_frontend.cpp b/src/shell/opt_frontend.cpp index a7b4f807e..6e39313fd 100644 --- a/src/shell/opt_frontend.cpp +++ b/src/shell/opt_frontend.cpp @@ -89,11 +89,11 @@ class wcnf { ast_manager& m; stream_buffer& in; - app_ref read_clause(unsigned& weight) { + app_ref read_clause(int& weight) { int parsed_lit; int var; parsed_lit = in.parse_int(); - weight = static_cast(parsed_lit); + weight = parsed_lit; app_ref result(m), p(m); expr_ref_vector ors(m); while (true) { @@ -137,7 +137,7 @@ public: parse_spec(num_vars, num_clauses, max_weight); } else { - unsigned weight = 0; + int weight = 0; app_ref cls = read_clause(weight); if (weight == max_weight) { opt.add_hard_constraint(cls); diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 34657de63..f481e35d0 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -72,7 +72,7 @@ namespace smt { m_value .push_back(inf_numeral()); } m_old_value .push_back(inf_numeral()); - SASSERT(m_var_occs.size() == r); + SASSERT(m_var_occs.size() == static_cast(r)); m_var_occs .push_back(atoms()); SASSERT(m_var_occs.back().empty()); m_unassigned_atoms .push_back(0); diff --git a/src/smt/theory_wmaxsat.cpp b/src/smt/theory_wmaxsat.cpp index 539a3e909..0c9e64e93 100644 --- a/src/smt/theory_wmaxsat.cpp +++ b/src/smt/theory_wmaxsat.cpp @@ -55,7 +55,8 @@ void theory_wmaxsat::get_assignment(svector& result) { } else { std::sort(m_cost_save.begin(), m_cost_save.end()); - for (unsigned i = 0, j = 0; i < m_vars.size(); ++i) { + unsigned j = 0; + for (theory_var i = 0; i < m_vars.size(); ++i) { if (j < m_cost_save.size() && m_cost_save[j] == i) { result.push_back(false); ++j; @@ -120,7 +121,7 @@ bool_var theory_wmaxsat::register_var(app* var, bool attach) { theory_var v = mk_var(x); ctx.attach_th_var(x, this, v); m_bool2var.insert(bv, v); - SASSERT(v == m_var2bool.size()); + SASSERT(v == static_cast(m_var2bool.size())); m_var2bool.push_back(bv); SASSERT(ctx.bool_var2enode(bv)); } diff --git a/src/tactic/sls/bvsls_opt_engine.cpp b/src/tactic/sls/bvsls_opt_engine.cpp index a674e8a25..96fad9a5a 100644 --- a/src/tactic/sls/bvsls_opt_engine.cpp +++ b/src/tactic/sls/bvsls_opt_engine.cpp @@ -318,7 +318,8 @@ mpz bvsls_opt_engine::find_best_move( } // reset to what it was before - double check = incremental_score(fd, old_value); + //double check = + incremental_score(fd, old_value); m_obj_evaluator.update(fd, old_value); } @@ -363,4 +364,4 @@ bool bvsls_opt_engine::randomize_wrt_hard() { } return false; -} \ No newline at end of file +} From 25f37c8a0ca804a7edaa7b492342751d01c42e6f Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 19 May 2015 11:00:34 +0100 Subject: [PATCH 788/925] Resolved mpf merge conflicts. --- src/util/mpf.cpp | 59 +++++++++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 994083834..683140129 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -210,7 +210,7 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode std::string f, e; - f = (e_pos != std::string::npos) ? v.substr(0, e_pos) : v; + f = (e_pos != std::string::npos) ? v.substr(0, e_pos) : v; e = (e_pos != std::string::npos) ? v.substr(e_pos+1) : "0"; TRACE("mpf_dbg", tout << " f = " << f << " e = " << e << std::endl;); @@ -232,18 +232,18 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode o.ebits = ebits; o.sbits = sbits; - o.sign = m_mpq_manager.is_neg(significand); + o.sign = m_mpq_manager.is_neg(significand); if (m_mpq_manager.is_zero(significand)) mk_zero(ebits, sbits, o.sign, o); - else { + else { scoped_mpq sig(m_mpq_manager); scoped_mpz exp(m_mpq_manager); m_mpq_manager.set(sig, significand); m_mpq_manager.abs(sig); - m_mpz_manager.set(exp, exponent); - + m_mpz_manager.set(exp, exponent); + // Normalize while (m_mpq_manager.ge(sig, 2)) { m_mpq_manager.div(sig, mpq(2), sig); @@ -277,7 +277,7 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode TRACE("mpf_dbg", tout << "sig = " << m_mpz_manager.to_string(o.significand) << " exp = " << o.exponent << std::endl;); - + if (m_mpz_manager.is_small(exp)) { o.exponent = m_mpz_manager.get_int64(exp); round(rm, o); @@ -1012,6 +1012,7 @@ void mpf_manager::round_to_integral(mpf_rounding_mode rm, mpf const & x, mpf & o else if (rm == MPF_ROUND_NEAREST_TEVEN || rm == MPF_ROUND_NEAREST_TAWAY) { bool tie = m_mpz_manager.is_zero(x.significand) && x.exponent == -1; + TRACE("mpf_dbg", tout << "tie = " << tie << std::endl;); if (tie && rm == MPF_ROUND_NEAREST_TEVEN) mk_zero(x.ebits, x.sbits, x.sign, o); else if (tie && rm == MPF_ROUND_NEAREST_TAWAY) @@ -1042,42 +1043,54 @@ void mpf_manager::round_to_integral(mpf_rounding_mode rm, mpf const & x, mpf & o set(a, x); unpack(a, true); // A includes hidden bit - TRACE("mpf_dbg", tout << "A = " << to_string(a) << std::endl;); + TRACE("mpf_dbg", tout << "A = " << to_string_raw(a) << std::endl;); SASSERT(m_mpz_manager.lt(a.significand(), m_powers2(x.sbits))); SASSERT(m_mpz_manager.ge(a.significand(), m_powers2(x.sbits - 1))); o.exponent = a.exponent(); m_mpz_manager.set(o.significand, a.significand()); - - unsigned shift = o.sbits - ((unsigned)o.exponent) - 1; + + unsigned shift = (o.sbits - 1) - ((unsigned)o.exponent); const mpz & shift_p = m_powers2(shift); TRACE("mpf_dbg", tout << "shift=" << shift << std::endl;); - scoped_mpz div(m_mpz_manager), rem(m_mpz_manager); + scoped_mpz div(m_mpz_manager), rem(m_mpz_manager); m_mpz_manager.machine_div_rem(o.significand, shift_p, div, rem); - TRACE("mpf_dbg", tout << "div=" << m_mpz_manager.to_string(div) << " rem=" << m_mpz_manager.to_string(rem) << std::endl;); + TRACE("mpf_dbg", tout << "div=" << m_mpz_manager.to_string(div) << " rem=" << m_mpz_manager.to_string(rem) << std::endl;); + + const mpz & shift_p1 = m_powers2(shift-1); + TRACE("mpf_dbg", tout << "shift_p1=" << m_mpz_manager.to_string(shift_p1) << std::endl;); switch (rm) { case MPF_ROUND_NEAREST_TEVEN: - case MPF_ROUND_NEAREST_TAWAY: { - scoped_mpz t(m_mpz_manager); - m_mpz_manager.mul2k(rem, 1, t); - bool tie = m_mpz_manager.eq(t, shift_p); - if (tie && - ((rm == MPF_ROUND_NEAREST_TEVEN && m_mpz_manager.is_odd(div)) || - (rm == MPF_ROUND_NEAREST_TAWAY && m_mpz_manager.is_even(div)))) - m_mpz_manager.inc(div); - else if (x.sign ^ m_mpz_manager.gt(t, shift_p)) - m_mpz_manager.inc(div); + case MPF_ROUND_NEAREST_TAWAY: { + bool tie = m_mpz_manager.eq(rem, shift_p1); + bool less_than_tie = m_mpz_manager.lt(rem, shift_p1); + bool more_than_tie = m_mpz_manager.gt(rem, shift_p1); + TRACE("mpf_dbg", tout << "tie= " << tie << "; tie = " << more_than_tie << std::endl;); + if (tie) { + if ((rm == MPF_ROUND_NEAREST_TEVEN && m_mpz_manager.is_odd(div)) || + (rm == MPF_ROUND_NEAREST_TAWAY && m_mpz_manager.is_even(div))) { + TRACE("mpf_dbg", tout << "div++ (1)" << std::endl;); + m_mpz_manager.inc(div); + } + } + else { + SASSERT(less_than_tie || more_than_tie); + if (more_than_tie) { + m_mpz_manager.inc(div); + TRACE("mpf_dbg", tout << "div++ (2)" << std::endl;); + } + } break; } case MPF_ROUND_TOWARD_POSITIVE: - if (!m_mpz_manager.is_zero(rem) && o.sign) + if (!m_mpz_manager.is_zero(rem) && !o.sign) m_mpz_manager.inc(div); break; case MPF_ROUND_TOWARD_NEGATIVE: - if (!m_mpz_manager.is_zero(rem) && !o.sign) + if (!m_mpz_manager.is_zero(rem) && o.sign) m_mpz_manager.inc(div); break; case MPF_ROUND_TOWARD_ZERO: From 32fb679066e25071969419905f11477a78c7826e Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 19 May 2015 11:01:15 +0100 Subject: [PATCH 789/925] tabs --- src/api/api_context.cpp | 2 +- src/ast/simplifier/inj_axiom.cpp | 2 +- src/cmd_context/interpolant_cmds.cpp | 10 +++--- src/duality/duality_rpfp.cpp | 16 +++++----- src/duality/duality_solver.cpp | 37 +++++++++++---------- src/duality/duality_wrapper.cpp | 2 +- src/interp/iz3base.cpp | 30 ++++++++--------- src/interp/iz3checker.cpp | 36 ++++++++++----------- src/interp/iz3interp.cpp | 48 ++++++++++++++-------------- src/interp/iz3pp.cpp | 6 ++-- src/interp/iz3proof_itp.cpp | 8 ++--- src/interp/iz3scopes.cpp | 4 +-- src/interp/iz3translate.cpp | 18 +++++------ src/interp/iz3translate_direct.cpp | 8 ++--- src/muz/base/dl_context.cpp | 12 +++---- src/shell/main.cpp | 2 +- src/util/mpz.cpp | 42 ++++++++++++------------ 17 files changed, 141 insertions(+), 142 deletions(-) diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index 846bab097..6e0c3cd82 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -89,7 +89,7 @@ namespace api { m_bv_util(m()), m_datalog_util(m()), m_fpa_util(m()), - m_dtutil(m()), + m_dtutil(m()), m_last_result(m()), m_ast_trail(m()), m_replay_stack() { diff --git a/src/ast/simplifier/inj_axiom.cpp b/src/ast/simplifier/inj_axiom.cpp index 50d051d2e..5925e23ac 100644 --- a/src/ast/simplifier/inj_axiom.cpp +++ b/src/ast/simplifier/inj_axiom.cpp @@ -114,7 +114,7 @@ bool simplify_inj_axiom(ast_manager & m, quantifier * q, expr_ref & result) { ptr_vector domain; inv_vars.push_back(f); - for (unsigned i = 0; i < inv_vars.size(); ++i) { + for (unsigned i = 0; i < inv_vars.size(); ++i) { domain.push_back(m.get_sort(inv_vars[i])); } sort * d = decl->get_domain(idx); diff --git a/src/cmd_context/interpolant_cmds.cpp b/src/cmd_context/interpolant_cmds.cpp index f41f175ea..3add76030 100644 --- a/src/cmd_context/interpolant_cmds.cpp +++ b/src/cmd_context/interpolant_cmds.cpp @@ -36,11 +36,11 @@ #include"scoped_proof.h" static void show_interpolant_and_maybe_check(cmd_context & ctx, - ptr_vector &cnsts, - expr *t, - ptr_vector &interps, - params_ref &m_params, - bool check) + ptr_vector &cnsts, + expr *t, + ptr_vector &interps, + params_ref &m_params, + bool check) { if (m_params.get_bool("som", false)) diff --git a/src/duality/duality_rpfp.cpp b/src/duality/duality_rpfp.cpp index 0a3692295..897bc521f 100755 --- a/src/duality/duality_rpfp.cpp +++ b/src/duality/duality_rpfp.cpp @@ -1171,7 +1171,7 @@ namespace Duality { new_alits.push_back(conj); #endif slvr().add(ctx.make(Implies, res, conj)); - // std::cout << res << ": " << conj << "\n"; + // std::cout << res << ": " << conj << "\n"; } if (opt_map) (*opt_map)[res] = conj; @@ -2734,7 +2734,7 @@ namespace Duality { if(res != unsat) throw "should be unsat"; s.pop(1); - + for(unsigned i = 0; i < conjuncts.size(); ){ std::swap(conjuncts[i],conjuncts.back()); expr save = conjuncts.back(); @@ -3056,7 +3056,7 @@ namespace Duality { Push(); expr the_impl = is.get_implicant(); if(eq(the_impl,prev_impl)){ - // std::cout << "got old implicant\n"; + // std::cout << "got old implicant\n"; repeated_case_count++; } prev_impl = the_impl; @@ -3126,8 +3126,8 @@ namespace Duality { axioms_added = true; } else { - //#define KILL_ON_BAD_INTERPOLANT -#ifdef KILL_ON_BAD_INTERPOLANT + //#define KILL_ON_BAD_INTERPOLANT +#ifdef KILL_ON_BAD_INTERPOLANT std::cout << "bad in InterpolateByCase -- core:\n"; #if 0 std::vector assumps; @@ -3137,7 +3137,7 @@ namespace Duality { #endif std::cout << "checking for inconsistency\n"; std::cout << "model:\n"; - is.get_model().show(); + is.get_model().show(); expr impl = is.get_implicant(); std::vector conjuncts; CollectConjuncts(impl,conjuncts,true); @@ -3379,7 +3379,7 @@ namespace Duality { int arity = f.arity(); std::vector domain; for(int i = 0; i < arity; i++) - domain.push_back(f.domain(i)); + domain.push_back(f.domain(i)); return ctx.function(name.c_str(), arity, &domain[0], f.range()); } @@ -3390,7 +3390,7 @@ namespace Duality { int arity = f.arity(); std::vector domain; for(int i = 0; i < arity; i++) - domain.push_back(f.domain(i)); + domain.push_back(f.domain(i)); return ctx.function(name.c_str(), arity, &domain[0], f.range()); } diff --git a/src/duality/duality_solver.cpp b/src/duality/duality_solver.cpp index 1c441e5d2..4568ea913 100644 --- a/src/duality/duality_solver.cpp +++ b/src/duality/duality_solver.cpp @@ -55,7 +55,7 @@ // #define KEEP_EXPANSIONS // #define USE_CACHING_RPFP // #define PROPAGATE_BEFORE_CHECK -#define NEW_STRATIFIED_INLINING +#define NEW_STRATIFIED_INLINING #define USE_RPFP_CLONE #define USE_NEW_GEN_CANDS @@ -389,7 +389,7 @@ namespace Duality { else InstantiateAllEdges(); } else { -#ifdef NEW_STRATIFIED_INLINING +#ifdef NEW_STRATIFIED_INLINING #else CreateLeaves(); @@ -929,7 +929,7 @@ namespace Duality { int StratifiedLeafCount; -#ifdef NEW_STRATIFIED_INLINING +#ifdef NEW_STRATIFIED_INLINING /** Stratified inlining builds an initial layered unwinding before switching to the LAWI strategy. Currently the number of layers @@ -1135,7 +1135,6 @@ namespace Duality { conj = rpfp->conjoin(conjs); } } - Node *CreateUnderapproxNode(Node *node){ // cex.get_tree()->ComputeUnderapprox(cex.get_root(),0); @@ -1872,7 +1871,7 @@ namespace Duality { underapproximations as upper bounds. This mode is used to complete the partial derivation constructed in underapprox mode. - */ + */ bool Derive(RPFP *rpfp, RPFP::Node *root, bool _underapprox, bool _constrained = false, RPFP *_tree = 0){ underapprox = _underapprox; @@ -2066,7 +2065,7 @@ namespace Duality { if(!top->Outgoing || tree->Check(top,unused_set) == unsat){ unused_set.resize(orig_unused); if(to - from == 1){ -#if 1 +#if 1 std::cout << "Not using underapprox of " << used_set[from] ->number << std::endl; #endif choices.insert(used_set[from]); @@ -2250,14 +2249,14 @@ namespace Duality { throw "stacks out of sync!"; reporter->Depth(stack.size()); - // res = tree->Solve(top, 1); // incremental solve, keep interpolants for one pop + // res = tree->Solve(top, 1); // incremental solve, keep interpolants for one pop check_result foo = Check(); res = foo == unsat ? l_false : l_true; if (res == l_false) { if (stack.empty()) // should never happen return false; - + { std::vector &expansions = stack.back().expansions; int update_count = 0; @@ -2384,7 +2383,7 @@ namespace Duality { tree->Pop(1); node_order.clear(); while(stack.size() > 1){ - tree->Pop(1); + tree->Pop(1); std::vector &expansions = stack.back().expansions; for(unsigned i = 0; i < expansions.size(); i++) node_order.push_back(expansions[i]); @@ -2420,12 +2419,12 @@ namespace Duality { void PopLevel(){ std::vector &expansions = stack.back().expansions; - tree->Pop(1); + tree->Pop(1); hash_set leaves_to_remove; for(unsigned i = 0; i < expansions.size(); i++){ Node *node = expansions[i]; - // if(node != top) - // tree->ConstrainParent(node->Incoming[0],node); + // if(node != top) + //tree->ConstrainParent(node->Incoming[0],node); std::vector &cs = node->Outgoing->Children; for(unsigned i = 0; i < cs.size(); i++){ leaves_to_remove.insert(cs[i]); @@ -2441,7 +2440,7 @@ namespace Duality { } stack.pop_back(); } - + bool NodeTooComplicated(Node *node){ int ops = tree->CountOperators(node->Annotation.Formula); if(ops > 10) return true; @@ -2670,7 +2669,7 @@ namespace Duality { } } } -#endif +#endif } @@ -2732,7 +2731,7 @@ namespace Duality { return false; if(parent->underapprox_map.find(covering) != parent->underapprox_map.end()) return covering->number < covered->number || parent->underapprox_map[covering] == covered; -#endif +#endif return covering->number < covered->number; } @@ -2778,7 +2777,7 @@ namespace Duality { else return false; } -#endif +#endif bool Close(Node *node){ if(covered_by(node)) @@ -2842,7 +2841,7 @@ namespace Duality { #ifdef UNDERAPPROX_NODES // if(parent->underapprox_map.find(covering) != parent->underapprox_map.end()) // return parent->underapprox_map[covering] == covered; -#endif +#endif if(CoverOrder(covering,covered) && !IsCovered(covering)){ RPFP::Transformer f(covering->Annotation); f.SetEmpty(); @@ -3175,7 +3174,7 @@ namespace Duality { // else // std::cout << "constant not matched\n"; } - + RPFP *old_unwinding = old_solver->unwinding; hash_map > pred_match; @@ -3467,7 +3466,7 @@ namespace Duality { dnode->Bound.Formula = bound_fmla; } db_saved_bounds.push_back(bound_fmla); - // dnode->Annotation.Formula = ctx.make(And,node->Annotation.Formula,ctx.make(Geq,dvar,ctx.int_val(0))); + // dnode->Annotation.Formula = ctx.make(And,node->Annotation.Formula,ctx.make(Geq,dvar,ctx.int_val(0))); } for(unsigned i = 0; i < rpfp->edges.size(); i++){ Edge *edge = rpfp->edges[i]; diff --git a/src/duality/duality_wrapper.cpp b/src/duality/duality_wrapper.cpp index 0cb5df056..dc509d809 100755 --- a/src/duality/duality_wrapper.cpp +++ b/src/duality/duality_wrapper.cpp @@ -727,7 +727,7 @@ namespace Duality { if(!started){ sw.start(); started = true; - } + } return sw.get_current_seconds(); } diff --git a/src/interp/iz3base.cpp b/src/interp/iz3base.cpp index bb4f760f5..57188e5ca 100755 --- a/src/interp/iz3base.cpp +++ b/src/interp/iz3base.cpp @@ -292,14 +292,14 @@ bool iz3base::is_sat(const std::vector &q, ast &_proof, std::vector &v void iz3base::find_children(const stl_ext::hash_set &cnsts_set, - const ast &tree, - std::vector &cnsts, - std::vector &parents, - std::vector &conjuncts, - std::vector &children, - std::vector &pos_map, - bool merge - ){ + const ast &tree, + std::vector &cnsts, + std::vector &parents, + std::vector &conjuncts, + std::vector &children, + std::vector &pos_map, + bool merge + ){ std::vector my_children; std::vector my_conjuncts; if(op(tree) == Interp){ // if we've hit an interpolation position... @@ -336,13 +336,13 @@ void iz3base::find_children(const stl_ext::hash_set &cnsts_set, } void iz3base::to_parents_vec_representation(const std::vector &_cnsts, - const ast &tree, - std::vector &cnsts, - std::vector &parents, - std::vector &theory, - std::vector &pos_map, - bool merge - ){ + const ast &tree, + std::vector &cnsts, + std::vector &parents, + std::vector &theory, + std::vector &pos_map, + bool merge + ){ std::vector my_children; std::vector my_conjuncts; hash_set cnsts_set; diff --git a/src/interp/iz3checker.cpp b/src/interp/iz3checker.cpp index 480e85274..69cfea8b8 100755 --- a/src/interp/iz3checker.cpp +++ b/src/interp/iz3checker.cpp @@ -144,7 +144,7 @@ struct iz3checker : iz3base { hash_set tmemo; for(unsigned j = 0; j < theory.size(); j++) support(theory[j],common,tmemo); // all theory symbols allowed in interps - } + } hash_set memo; support(itp[i],Isup,memo); std::set_difference(Isup.begin(),Isup.end(),common.begin(),common.end(),std::inserter(bad,bad.begin())); @@ -192,35 +192,35 @@ std::vector to_std_vector(const ::vector &v){ bool iz3check(ast_manager &_m_manager, - solver *s, - std::ostream &err, - const ptr_vector &cnsts, - const ::vector &parents, - const ptr_vector &interps, - const ptr_vector &theory) + solver *s, + std::ostream &err, + const ptr_vector &cnsts, + const ::vector &parents, + const ptr_vector &interps, + const ptr_vector &theory) { iz3checker chk(_m_manager); return chk.check(s,err,chk.cook(cnsts),to_std_vector(parents),chk.cook(interps),chk.cook(theory)); } bool iz3check(iz3mgr &mgr, - solver *s, - std::ostream &err, - const std::vector &cnsts, - const std::vector &parents, - const std::vector &interps, - const std::vector &theory) + solver *s, + std::ostream &err, + const std::vector &cnsts, + const std::vector &parents, + const std::vector &interps, + const std::vector &theory) { iz3checker chk(mgr); return chk.check(s,err,cnsts,parents,interps,theory); } bool iz3check(ast_manager &_m_manager, - solver *s, - std::ostream &err, - const ptr_vector &_cnsts, - ast *tree, - const ptr_vector &interps) + solver *s, + std::ostream &err, + const ptr_vector &_cnsts, + ast *tree, + const ptr_vector &interps) { iz3checker chk(_m_manager); return chk.check(s,err,chk.cook(_cnsts),chk.cook(tree),chk.cook(interps)); diff --git a/src/interp/iz3interp.cpp b/src/interp/iz3interp.cpp index c9b5e7920..810afb103 100755 --- a/src/interp/iz3interp.cpp +++ b/src/interp/iz3interp.cpp @@ -252,7 +252,7 @@ public: // create a secondary prover iz3secondary *sp = iz3foci::create(this,num,parents_vec.empty()?0:&parents_vec[0]); sp_killer.set(sp); // kill this on exit - + #define BINARY_INTERPOLATION #ifndef BINARY_INTERPOLATION // create a translator @@ -420,12 +420,12 @@ public: void iz3interpolate(ast_manager &_m_manager, - ast *proof, - const ptr_vector &cnsts, - const ::vector &parents, - ptr_vector &interps, - const ptr_vector &theory, - interpolation_options_struct * options) + ast *proof, + const ptr_vector &cnsts, + const ::vector &parents, + ptr_vector &interps, + const ptr_vector &theory, + interpolation_options_struct * options) { iz3interp itp(_m_manager); if(options) @@ -448,12 +448,12 @@ void iz3interpolate(ast_manager &_m_manager, } void iz3interpolate(ast_manager &_m_manager, - ast *proof, - const ::vector > &cnsts, - const ::vector &parents, - ptr_vector &interps, - const ptr_vector &theory, - interpolation_options_struct * options) + ast *proof, + const ::vector > &cnsts, + const ::vector &parents, + ptr_vector &interps, + const ptr_vector &theory, + interpolation_options_struct * options) { iz3interp itp(_m_manager); if(options) @@ -477,11 +477,11 @@ void iz3interpolate(ast_manager &_m_manager, } void iz3interpolate(ast_manager &_m_manager, - ast *proof, - const ptr_vector &cnsts, - ast *tree, - ptr_vector &interps, - interpolation_options_struct * options) + ast *proof, + const ptr_vector &cnsts, + ast *tree, + ptr_vector &interps, + interpolation_options_struct * options) { iz3interp itp(_m_manager); if(options) @@ -506,12 +506,12 @@ void iz3interpolate(ast_manager &_m_manager, } lbool iz3interpolate(ast_manager &_m_manager, - solver &s, - ast *tree, - ptr_vector &cnsts, - ptr_vector &interps, - model_ref &m, - interpolation_options_struct * options) + solver &s, + ast *tree, + ptr_vector &cnsts, + ptr_vector &interps, + model_ref &m, + interpolation_options_struct * options) { iz3interp itp(_m_manager); if(options) diff --git a/src/interp/iz3pp.cpp b/src/interp/iz3pp.cpp index 26cefedb3..066e04e83 100644 --- a/src/interp/iz3pp.cpp +++ b/src/interp/iz3pp.cpp @@ -107,9 +107,9 @@ public: }; void iz3pp(ast_manager &m, - const ptr_vector &cnsts_vec, - expr *tree, - std::ostream& out) { + const ptr_vector &cnsts_vec, + expr *tree, + std::ostream& out) { unsigned sz = cnsts_vec.size(); expr* const* cnsts = &cnsts_vec[0]; diff --git a/src/interp/iz3proof_itp.cpp b/src/interp/iz3proof_itp.cpp index 0bdd51ed8..f76de14cf 100755 --- a/src/interp/iz3proof_itp.cpp +++ b/src/interp/iz3proof_itp.cpp @@ -778,7 +778,7 @@ class iz3proof_itp_impl : public iz3proof_itp { sum_cond_ineq(ineq2,make_int("1"),yleqx,Aproves2,Bproves2); ast Bcond = my_implies(Bproves1,my_and(Aproves1,z3_simplify(ineq2))); // if(!is_true(Aproves1) || !is_true(Bproves1)) - // std::cout << "foo!\n";; + // std::cout << "foo!\n";; if(y == make_int(rational(0)) && op(x) == Plus && num_args(x) == 2){ if(get_term_type(arg(x,0)) == LitA){ ast iter = z3_simplify(make(Plus,arg(x,0),get_ineq_rhs(xleqy))); @@ -915,7 +915,7 @@ class iz3proof_itp_impl : public iz3proof_itp { int ipos = pos.get_unsigned(); ast cond = mk_true(); ast equa = sep_cond(arg(pf,0),cond); -#if 0 +#if 0 if(op(equa) == Equal){ ast pe = mk_not(neg_equality); ast lhs = subst_in_arg_pos(ipos,arg(equa,0),arg(pe,0)); @@ -2784,7 +2784,7 @@ class iz3proof_itp_impl : public iz3proof_itp { } else if(o == Plus || o == Times){ // don't want bound variables inside arith ops // std::cout << "WARNING: non-local arithmetic\n"; - // frng = erng; // this term will be localized + // frng = erng; // this term will be localized } else if(o == Select){ // treat the array term like a function symbol prover::range srng = pv->ast_scope(arg(e,0)); @@ -2805,7 +2805,7 @@ class iz3proof_itp_impl : public iz3proof_itp { pfs.push_back(argpf); } } - + e = clone(e,largs); if(pfs.size()) pf = make_congruence(eqs,make_equiv(e,orig_e),pfs); diff --git a/src/interp/iz3scopes.cpp b/src/interp/iz3scopes.cpp index c365619b2..b70f37a06 100755 --- a/src/interp/iz3scopes.cpp +++ b/src/interp/iz3scopes.cpp @@ -97,7 +97,7 @@ namespace std { template <> inline size_t stdext::hash_value(const scopes::range_lo& p) -{ +{ std::hash h; return h(p); } @@ -133,7 +133,7 @@ namespace std { template <> inline size_t stdext::hash_value(const range_op& p) -{ +{ std::hash h; return h(p); } diff --git a/src/interp/iz3translate.cpp b/src/interp/iz3translate.cpp index 5b420673c..e4bccace1 100755 --- a/src/interp/iz3translate.cpp +++ b/src/interp/iz3translate.cpp @@ -274,7 +274,7 @@ public: ast neglit = mk_not(arg(con,i)); res.erase(neglit); } - } + } } } #if 0 @@ -612,7 +612,7 @@ public: rng = range_glb(rng,ast_scope(lit)); } if(range_is_empty(rng)) return -1; - int hi = range_max(rng); + int hi = range_max(rng); if(hi >= frames) return frames - 1; return hi; } @@ -2003,10 +2003,10 @@ public: } iz3translation_full(iz3mgr &mgr, - iz3secondary *_secondary, + iz3secondary *_secondary, const std::vector > &cnsts, - const std::vector &parents, - const std::vector &theory) + const std::vector &parents, + const std::vector &theory) : iz3translation(mgr, cnsts, parents, theory) { frames = cnsts.size(); @@ -2027,10 +2027,10 @@ public: #ifdef IZ3_TRANSLATE_FULL iz3translation *iz3translation::create(iz3mgr &mgr, - iz3secondary *secondary, - const std::vector > &cnsts, - const std::vector &parents, - const std::vector &theory){ + iz3secondary *secondary, + const std::vector > &cnsts, + const std::vector &parents, + const std::vector &theory){ return new iz3translation_full(mgr,secondary,cnsts,parents,theory); } diff --git a/src/interp/iz3translate_direct.cpp b/src/interp/iz3translate_direct.cpp index c1b751c6f..ec3af1ca3 100755 --- a/src/interp/iz3translate_direct.cpp +++ b/src/interp/iz3translate_direct.cpp @@ -293,7 +293,7 @@ public: ast neglit = mk_not(arg(con,i)); res.erase(neglit); } - } + } } } #if 0 @@ -589,7 +589,7 @@ public: rng = range_glb(rng,ast_scope(lit)); } if(range_is_empty(rng)) return -1; - int hi = range_max(rng); + int hi = range_max(rng); if(hi >= frames) return frames - 1; return hi; } @@ -881,7 +881,7 @@ public: || dk == PR_QUANT_INST //|| dk == PR_UNIT_RESOLUTION //|| dk == PR_LEMMA - ) + ) return false; if(dk == PR_HYPOTHESIS && hyps.find(con) != hyps.end()) ; //std::cout << "blif!\n"; @@ -1481,7 +1481,7 @@ public: AstSet dummy; collect_resolvent_lits(nll->proofs[i],dummy,reslits); litset.insert(reslits.begin(),reslits.end()); - } + } } if(to_keep.size() == nll->proofs.size()) return nll; ResolventAppSet new_proofs; diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index a2ab3610a..b7cb5680f 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -584,7 +584,7 @@ namespace datalog { m_rule_properties.check_existential_tail(); m_rule_properties.check_for_negated_predicates(); break; - case DUALITY_ENGINE: + case DUALITY_ENGINE: m_rule_properties.collect(r); m_rule_properties.check_existential_tail(); m_rule_properties.check_for_negated_predicates(); @@ -986,12 +986,12 @@ namespace datalog { } } - void context::get_raw_rule_formulas(expr_ref_vector& rules, svector& names, vector &bounds){ + void context::get_raw_rule_formulas(expr_ref_vector& rules, svector& names, vector &bounds) { for (unsigned i = 0; i < m_rule_fmls.size(); ++i) { - expr_ref r = bind_vars(m_rule_fmls[i].get(), true); - rules.push_back(r.get()); - names.push_back(m_rule_names[i]); - bounds.push_back(m_rule_bounds[i]); + expr_ref r = bind_vars(m_rule_fmls[i].get(), true); + rules.push_back(r.get()); + names.push_back(m_rule_names[i]); + bounds.push_back(m_rule_bounds[i]); } } diff --git a/src/shell/main.cpp b/src/shell/main.cpp index 2dbd459fa..5a47d0d16 100644 --- a/src/shell/main.cpp +++ b/src/shell/main.cpp @@ -329,7 +329,7 @@ int main(int argc, char ** argv) { g_input_kind = IN_SMTLIB; } } - } + } switch (g_input_kind) { case IN_SMTLIB: return_value = read_smtlib_file(g_input_file); diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index 163f7fb86..855927919 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -336,17 +336,17 @@ void mpz_manager::set(mpz & target, unsigned sz, digit_t const * digits) } } #else - mk_big(target); - // reset - mpz_set_ui(*target.m_ptr, digits[sz - 1]); - SASSERT(sz > 0); - unsigned i = sz - 1; - while (i > 0) { - --i; - mpz_mul_2exp(*target.m_ptr, *target.m_ptr, 32); - mpz_set_ui(m_tmp, digits[i]); - mpz_add(*target.m_ptr, *target.m_ptr, m_tmp); - } + mk_big(target); + // reset + mpz_set_ui(*target.m_ptr, digits[sz - 1]); + SASSERT(sz > 0); + unsigned i = sz - 1; + while (i > 0) { + --i; + mpz_mul_2exp(*target.m_ptr, *target.m_ptr, 32); + mpz_set_ui(m_tmp, digits[i]); + mpz_add(*target.m_ptr, *target.m_ptr, m_tmp); + } #endif } } @@ -2037,16 +2037,16 @@ bool mpz_manager::decompose(mpz const & a, svector & digits) { } return a.m_val < 0; #else - bool r = is_neg(a); - mpz_set(m_tmp, *a.m_ptr); - mpz_abs(m_tmp, m_tmp); - while (mpz_sgn(m_tmp) != 0) { - mpz_tdiv_r_2exp(m_tmp2, m_tmp, 32); - unsigned v = mpz_get_ui(m_tmp2); - digits.push_back(v); - mpz_tdiv_q_2exp(m_tmp, m_tmp, 32); - } - return r; + bool r = is_neg(a); + mpz_set(m_tmp, *a.m_ptr); + mpz_abs(m_tmp, m_tmp); + while (mpz_sgn(m_tmp) != 0) { + mpz_tdiv_r_2exp(m_tmp2, m_tmp, 32); + unsigned v = mpz_get_ui(m_tmp2); + digits.push_back(v); + mpz_tdiv_q_2exp(m_tmp, m_tmp, 32); + } + return r; #endif } } From 7232877d92e0734f42047e51af5c21b2be6edbc1 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 19 May 2015 11:01:27 +0100 Subject: [PATCH 790/925] tabs, indentation --- src/api/python/z3.py | 102 +++++++++++++++++++++---------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index 54ffd0a69..16d2eb6ba 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -554,7 +554,7 @@ def _to_sort_ref(s, ctx): elif k == Z3_DATATYPE_SORT: return DatatypeSortRef(s, ctx) elif k == Z3_FINITE_DOMAIN_SORT: - return FiniteDomainSortRef(s, ctx) + return FiniteDomainSortRef(s, ctx) elif k == Z3_FLOATING_POINT_SORT: return FPSortRef(s, ctx) elif k == Z3_ROUNDING_MODE_SORT: @@ -6356,12 +6356,12 @@ class FiniteDomainSortRef(SortRef): """Finite domain sort.""" def size(self): - """Return the size of the finite domain sort""" - r = (ctype.c_ulonglong * 1)() - if Z3_get_finite_domain_sort_size(self.ctx_ref(), self.ast(), r): - return r[0] - else: - raise Z3Exception("Failed to retrieve finite domain sort size") + """Return the size of the finite domain sort""" + r = (ctype.c_ulonglong * 1)() + if Z3_get_finite_domain_sort_size(self.ctx_ref(), self.ast(), r): + return r[0] + else: + raise Z3Exception("Failed to retrieve finite domain sort size") def FiniteDomainSort(name, sz, ctx=None): """Create a named finite domain sort of a given size sz""" @@ -6376,30 +6376,30 @@ def FiniteDomainSort(name, sz, ctx=None): class OptimizeObjective: def __init__(self, opt, value, is_max): - self._opt = opt - self._value = value - self._is_max = is_max + self._opt = opt + self._value = value + self._is_max = is_max def lower(self): - opt = self._opt - return _to_expr_ref(Z3_optimize_get_lower(opt.ctx.ref(), opt.optimize, self._value), opt.ctx) + opt = self._opt + return _to_expr_ref(Z3_optimize_get_lower(opt.ctx.ref(), opt.optimize, self._value), opt.ctx) def upper(self): - opt = self._opt - return _to_expr_ref(Z3_optimize_get_upper(opt.ctx.ref(), opt.optimize, self._value), opt.ctx) + opt = self._opt + return _to_expr_ref(Z3_optimize_get_upper(opt.ctx.ref(), opt.optimize, self._value), opt.ctx) def value(self): - if self._is_max: - return self.upper() - else: - return self.lower() + if self._is_max: + return self.upper() + else: + return self.lower() class Optimize(Z3PPObject): """Optimize API provides methods for solving using objective functions and weighted soft constraints""" def __init__(self, ctx=None): self.ctx = _get_ctx(ctx) - self.optimize = Z3_mk_optimize(self.ctx.ref()) + self.optimize = Z3_mk_optimize(self.ctx.ref()) Z3_optimize_inc_ref(self.ctx.ref(), self.optimize) def __del__(self): @@ -6435,29 +6435,29 @@ class Optimize(Z3PPObject): self.assert_exprs(*args) def add_soft(self, arg, weight = "1", id = None): - """Add soft constraint with optional weight and optional identifier. - If no weight is supplied, then the penalty for violating the soft constraint - is 1. - Soft constraints are grouped by identifiers. Soft constraints that are - added without identifiers are grouped by default. - """ - if _is_int(weight): - weight = "%d" % weight - if not isinstance(weight, str): - raise Z3Exception("weight should be a string or an integer") - if id == None: - id = "" - id = to_symbol(id, self.ctx) - v = Z3_optimize_assert_soft(self.ctx.ref(), self.optimize, arg.as_ast(), weight, id) - return OptimizeObjective(self, v, False) + """Add soft constraint with optional weight and optional identifier. + If no weight is supplied, then the penalty for violating the soft constraint + is 1. + Soft constraints are grouped by identifiers. Soft constraints that are + added without identifiers are grouped by default. + """ + if _is_int(weight): + weight = "%d" % weight + if not isinstance(weight, str): + raise Z3Exception("weight should be a string or an integer") + if id == None: + id = "" + id = to_symbol(id, self.ctx) + v = Z3_optimize_assert_soft(self.ctx.ref(), self.optimize, arg.as_ast(), weight, id) + return OptimizeObjective(self, v, False) def maximize(self, arg): - """Add objective function to maximize.""" - return OptimizeObjective(self, Z3_optimize_maximize(self.ctx.ref(), self.optimize, arg.as_ast()), True) + """Add objective function to maximize.""" + return OptimizeObjective(self, Z3_optimize_maximize(self.ctx.ref(), self.optimize, arg.as_ast()), True) def minimize(self, arg): - """Add objective function to minimize.""" - return OptimizeObjective(self, Z3_optimize_minimize(self.ctx.ref(), self.optimize, arg.as_ast()), False) + """Add objective function to minimize.""" + return OptimizeObjective(self, Z3_optimize_minimize(self.ctx.ref(), self.optimize, arg.as_ast()), False) def push(self): """create a backtracking point for added rules, facts and assertions""" @@ -6468,25 +6468,25 @@ class Optimize(Z3PPObject): Z3_optimize_pop(self.ctx.ref(), self.optimize) def check(self): - """Check satisfiability while optimizing objective functions.""" - return CheckSatResult(Z3_optimize_check(self.ctx.ref(), self.optimize)) + """Check satisfiability while optimizing objective functions.""" + return CheckSatResult(Z3_optimize_check(self.ctx.ref(), self.optimize)) def model(self): - """Return a model for the last check().""" - try: - return ModelRef(Z3_optimize_get_model(self.ctx.ref(), self.optimize), self.ctx) - except Z3Exception: - raise Z3Exception("model is not available") + """Return a model for the last check().""" + try: + return ModelRef(Z3_optimize_get_model(self.ctx.ref(), self.optimize), self.ctx) + except Z3Exception: + raise Z3Exception("model is not available") def lower(self, obj): - if not isinstance(obj, OptimizeObjective): - raise Z3Exception("Expecting objective handle returned by maximize/minimize") - return obj.lower() + if not isinstance(obj, OptimizeObjective): + raise Z3Exception("Expecting objective handle returned by maximize/minimize") + return obj.lower() def upper(self, obj): - if not isinstance(obj, OptimizeObjective): - raise Z3Exception("Expecting objective handle returned by maximize/minimize") - return obj.upper() + if not isinstance(obj, OptimizeObjective): + raise Z3Exception("Expecting objective handle returned by maximize/minimize") + return obj.upper() def __repr__(self): """Return a formatted string with all added rules and constraints.""" From e9f7d558e3e1ac45b53f33ad177073ad8b75bae9 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 19 May 2015 12:40:41 +0100 Subject: [PATCH 791/925] tabs, indentation --- examples/python/complex/complex.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/python/complex/complex.py b/examples/python/complex/complex.py index 5d6283745..467d76c55 100644 --- a/examples/python/complex/complex.py +++ b/examples/python/complex/complex.py @@ -47,13 +47,13 @@ class ComplexExpr: return ComplexExpr(other.r*self.r - other.i*self.i, other.i*self.r + other.r*self.i) def __pow__(self, k): - if k == 0: - return ComplexExpr(1, 0) - if k == 1: - return self - if k < 0: - return (self ** (-k)).inv() - return reduce(lambda x, y: x * y, [self for _ in xrange(k)], ComplexExpr(1, 0)) + if k == 0: + return ComplexExpr(1, 0) + if k == 1: + return self + if k < 0: + return (self ** (-k)).inv() + return reduce(lambda x, y: x * y, [self for _ in xrange(k)], ComplexExpr(1, 0)) def inv(self): den = self.r*self.r + self.i*self.i From f0b699f03a153531a3a24c8d8c3b848df9491dfc Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 19 May 2015 12:41:51 +0100 Subject: [PATCH 792/925] Added Optimize.cs to to Microsoft.Z3.csproj --- src/api/dotnet/Microsoft.Z3.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/api/dotnet/Microsoft.Z3.csproj b/src/api/dotnet/Microsoft.Z3.csproj index 2b5e08173..937edb69d 100644 --- a/src/api/dotnet/Microsoft.Z3.csproj +++ b/src/api/dotnet/Microsoft.Z3.csproj @@ -365,6 +365,7 @@ + From a41a9c94dd92a018fe5af04106d6afe67c796ca8 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 19 May 2015 12:43:25 +0100 Subject: [PATCH 793/925] Formatting --- src/api/dotnet/Optimize.cs | 98 +++++++++++++++++++------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/src/api/dotnet/Optimize.cs b/src/api/dotnet/Optimize.cs index edd259100..dc94db78a 100644 --- a/src/api/dotnet/Optimize.cs +++ b/src/api/dotnet/Optimize.cs @@ -85,43 +85,43 @@ namespace Microsoft.Z3 Assert(constraints); } - /// - /// Handle to objectives returned by objective functions. - /// - public class Handle + /// + /// Handle to objectives returned by objective functions. + /// + public class Handle { - Optimize opt; - uint handle; - internal Handle(Optimize opt, uint h) - { - this.opt = opt; - this.handle = h; - } + Optimize opt; + uint handle; + internal Handle(Optimize opt, uint h) + { + this.opt = opt; + this.handle = h; + } /// /// Retrieve a lower bound for the objective handle. /// - public ArithExpr Lower - { - get { return opt.GetLower(handle); } - } + public ArithExpr Lower + { + get { return opt.GetLower(handle); } + } /// /// Retrieve an upper bound for the objective handle. /// - public ArithExpr Upper - { - get { return opt.GetUpper(handle); } - } + public ArithExpr Upper + { + get { return opt.GetUpper(handle); } + } /// /// Retrieve the value of an objective. /// - public ArithExpr Value - { - get { return Lower; } - } - } + public ArithExpr Value + { + get { return Lower; } + } + } /// /// Assert soft constraint @@ -132,29 +132,29 @@ namespace Microsoft.Z3 public Handle AssertSoft(BoolExpr constraint, uint weight, string group) { Context.CheckContextMatch(constraint); - Symbol s = Context.MkSymbol(group); - return new Handle(this, Native.Z3_optimize_assert_soft(Context.nCtx, NativeObject, constraint.NativeObject, weight.ToString(), s.NativeObject)); + Symbol s = Context.MkSymbol(group); + return new Handle(this, Native.Z3_optimize_assert_soft(Context.nCtx, NativeObject, constraint.NativeObject, weight.ToString(), s.NativeObject)); } - - /// - /// - /// Check satisfiability of asserted constraints. - /// Produce a model that (when the objectives are bounded and - /// don't use strict inequalities) meets the objectives. - /// - /// - public Status Check() { - Z3_lbool r = (Z3_lbool)Native.Z3_optimize_check(Context.nCtx, NativeObject); + + /// + /// Check satisfiability of asserted constraints. + /// Produce a model that (when the objectives are bounded and + /// don't use strict inequalities) meets the objectives. + /// + /// + public Status Check() + { + Z3_lbool r = (Z3_lbool)Native.Z3_optimize_check(Context.nCtx, NativeObject); switch (r) { - case Z3_lbool.Z3_L_TRUE: + case Z3_lbool.Z3_L_TRUE: return Status.SATISFIABLE; - case Z3_lbool.Z3_L_FALSE: + case Z3_lbool.Z3_L_FALSE: return Status.UNSATISFIABLE; - default: + default: return Status.UNKNOWN; - } + } } /// @@ -198,27 +198,27 @@ namespace Microsoft.Z3 /// /// Declare an arithmetical maximization objective. - /// Return a handle to the objective. The handle is used as - /// to retrieve the values of objectives after calling Check. + /// Return a handle to the objective. The handle is used as + /// to retrieve the values of objectives after calling Check. /// - public Handle MkMaximize(ArithExpr e) + public Handle MkMaximize(ArithExpr e) { - return new Handle(this, Native.Z3_optimize_maximize(Context.nCtx, NativeObject, e.NativeObject)); - } + return new Handle(this, Native.Z3_optimize_maximize(Context.nCtx, NativeObject, e.NativeObject)); + } /// /// Declare an arithmetical minimization objective. - /// Similar to MkMaximize. + /// Similar to MkMaximize. /// public Handle MkMinimize(ArithExpr e) { - return new Handle(this, Native.Z3_optimize_minimize(Context.nCtx, NativeObject, e.NativeObject)); + return new Handle(this, Native.Z3_optimize_minimize(Context.nCtx, NativeObject, e.NativeObject)); } /// /// Retrieve a lower bound for the objective handle. /// - private ArithExpr GetLower(uint index) + private ArithExpr GetLower(uint index) { return (ArithExpr)Expr.Create(Context, Native.Z3_optimize_get_lower(Context.nCtx, NativeObject, index)); } @@ -236,7 +236,7 @@ namespace Microsoft.Z3 /// /// Print the context to a string (SMT-LIB parseable benchmark). /// - public override string ToString() + public override string ToString() { return Native.Z3_optimize_to_string(Context.nCtx, NativeObject); } From db411eef25fae56f70d0ffd2ab8781824d3416b1 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 19 May 2015 13:35:19 +0100 Subject: [PATCH 794/925] Improved supported logics checks for FPA logics. --- src/cmd_context/cmd_context.cpp | 18 ++++++++---------- src/cmd_context/cmd_context.h | 1 + 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 788a8affd..651a84110 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -550,9 +550,7 @@ bool cmd_context::logic_has_bv_core(symbol const & s) const { } bool cmd_context::logic_has_horn(symbol const& s) const { - return - s == "HORN"; - + return s == "HORN"; } bool cmd_context::logic_has_bv() const { @@ -560,19 +558,20 @@ bool cmd_context::logic_has_bv() const { } bool cmd_context::logic_has_seq_core(symbol const& s) const { - return - s == "QF_BVRE"; - + return s == "QF_BVRE"; } bool cmd_context::logic_has_seq() const { return !has_logic() || logic_has_seq_core(m_logic); } -bool cmd_context::logic_has_fpa() const { - return !has_logic() || m_logic == "QF_FP" || m_logic == "QF_FPBV"; +bool cmd_context::logic_has_fpa_core(symbol const& s) const { + return s == "QF_FP" || s == "QF_FPBV" || s == "QF_BVFP"; } +bool cmd_context::logic_has_fpa() const { + return !has_logic() || logic_has_fpa_core(m_logic); +} bool cmd_context::logic_has_array_core(symbol const & s) const { return @@ -682,8 +681,7 @@ bool cmd_context::supported_logic(symbol const & s) const { return s == "QF_UF" || s == "UF" || logic_has_arith_core(s) || logic_has_bv_core(s) || logic_has_array_core(s) || logic_has_seq_core(s) || - logic_has_horn(s) || - s == "QF_FP" || s == "QF_FPBV"; + logic_has_horn(s) || logic_has_fpa_core(s); } bool cmd_context::set_logic(symbol const & s) { diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index 7758424e0..148bb61d9 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -250,6 +250,7 @@ protected: bool logic_has_bv_core(symbol const & s) const; bool logic_has_array_core(symbol const & s) const; bool logic_has_seq_core(symbol const & s) const; + bool logic_has_fpa_core(symbol const & s) const; bool logic_has_horn(symbol const& s) const; bool logic_has_arith() const; bool logic_has_bv() const; From 8f86542f2656f508b2666611cf050909a500c333 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 19 May 2015 13:38:26 +0100 Subject: [PATCH 795/925] Added QF_ALIA to supported logics. Fixes #90 --- src/cmd_context/cmd_context.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 651a84110..80aa10cde 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -500,6 +500,7 @@ bool cmd_context::logic_has_arith_core(symbol const & s) const { s == "QF_RDL" || s == "QF_IDL" || s == "QF_AUFLIA" || + s == "QF_ALIA" || s == "QF_AUFLIRA" || s == "QF_AUFNIA" || s == "QF_AUFNIRA" || @@ -577,6 +578,7 @@ bool cmd_context::logic_has_array_core(symbol const & s) const { return s == "QF_AX" || s == "QF_AUFLIA" || + s == "QF_ALIA" || s == "QF_AUFLIRA" || s == "QF_AUFNIA" || s == "QF_AUFNIRA" || From 8ff7735a20ced308680ad6e12eeca0da1638e331 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 19 May 2015 13:47:43 +0100 Subject: [PATCH 796/925] python 3 fixes Signed-off-by: Nuno Lopes --- scripts/mk_util.py | 10 +++++----- src/api/python/z3util.py | 16 ++++++++-------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 5b7c10605..820396c0d 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -553,7 +553,7 @@ def display_help(exit_code): if IS_WINDOWS: print(" -n, --nodotnet do not generate Microsoft.Z3.dll make rules.") if IS_WINDOWS: - print(" --optimize generate optimized code during linking.") + print(" --optimize generate optimized code during linking.") print(" -j, --java generate Java bindings.") print(" --ml generate OCaml bindings.") print(" --staticlib build Z3 static library.") @@ -621,8 +621,8 @@ def parse_options(): DOTNET_ENABLED = False elif opt in ('--staticlib'): STATIC_LIB = True - elif opt in ('--optimize'): - OPTIMIZE = True + elif opt in ('--optimize'): + OPTIMIZE = True elif not IS_WINDOWS and opt in ('-p', '--prefix'): PREFIX = arg PYTHON_PACKAGE_DIR = os.path.join(PREFIX, 'lib', 'python%s' % distutils.sysconfig.get_python_version(), 'dist-packages') @@ -1786,8 +1786,8 @@ def mk_config(): 'SLINK_EXTRA_FLAGS=/link /DEBUG /MACHINE:X64 /SUBSYSTEM:WINDOWS /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE:NO\n') else: # Windows Release mode - if OPTIMIZE: - config.write('AR_FLAGS=/nologo /LTCG\n') + if OPTIMIZE: + config.write('AR_FLAGS=/nologo /LTCG\n') config.write( 'LINK_FLAGS=/nologo /MD\n' 'SLINK_FLAGS=/nologo /LD\n') diff --git a/src/api/python/z3util.py b/src/api/python/z3util.py index 6cdd4de32..e0e9aba32 100644 --- a/src/api/python/z3util.py +++ b/src/api/python/z3util.py @@ -210,18 +210,18 @@ def prove(claim,assume=None,verbose=0): if verbose >= 2: - print 'assume: ' - print assume - print 'claim: ' - print claim - print 'to_prove: ' - print to_prove + print('assume: ') + print(assume) + print('claim: ') + print(claim) + print('to_prove: ') + print(to_prove) f = Not(to_prove) models = get_models(f,k=1) if models is None: #unknown - print 'E: cannot solve !' + print('E: cannot solve !') return None, None elif models == False: #unsat return True,None @@ -458,7 +458,7 @@ def model_str(m,as_str=True): if m : vs = [(v,m[v]) for v in m] - vs = sorted(vs,key=lambda (a,_): str(a)) + vs = sorted(vs,key=lambda a,_: str(a)) if as_str: return '\n'.join(['{} = {}'.format(k,v) for (k,v) in vs]) else: From 4c7fea7e55b64258214b4e71cf8af18423e881be Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 19 May 2015 13:48:14 +0100 Subject: [PATCH 797/925] fix 'make test' for newer gcc versions Signed-off-by: Nuno Lopes --- src/test/pdr.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/test/pdr.cpp b/src/test/pdr.cpp index 82448e6f5..a9194ec60 100644 --- a/src/test/pdr.cpp +++ b/src/test/pdr.cpp @@ -47,10 +47,15 @@ struct test_model_search { void add_tree(model_node* parent, bool force_goal) { unsigned level = parent->level(); search.add_leaf(*parent); + expr_ref state(m); if (level > 0 && (force_goal || parent->is_goal())) { search.remove_goal(*parent); - add_tree(alloc(model_node, parent, mk_state(states, rand), pt, level-1), false); - add_tree(alloc(model_node, parent, mk_state(states, rand), pt, level-1), false); + + state = mk_state(states, rand); + add_tree(alloc(model_node, parent, state, pt, level-1), false); + + state = mk_state(states, rand); + add_tree(alloc(model_node, parent, state, pt, level-1), false); parent->check_pre_closed(); } } @@ -91,7 +96,8 @@ struct test_model_search { state = states[0].get(); unsigned level = 4; for(unsigned n = 0; n < 100; ++n) { - model_node* root = alloc(model_node, 0, mk_state(states, rand), pt, level); + state = mk_state(states, rand); + model_node* root = alloc(model_node, 0, state, pt, level); search.set_root(root); add_tree(root, false); search.display(std::cout); From 92cfc242d25727ffeb1bef5e60731793b85a8731 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 May 2015 08:15:59 -0700 Subject: [PATCH 798/925] cast variables to avoid compiler warning on signed/unsigned comparison Signed-off-by: Nikolaj Bjorner --- src/smt/theory_wmaxsat.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/smt/theory_wmaxsat.cpp b/src/smt/theory_wmaxsat.cpp index 0c9e64e93..9ed944d2c 100644 --- a/src/smt/theory_wmaxsat.cpp +++ b/src/smt/theory_wmaxsat.cpp @@ -55,9 +55,8 @@ void theory_wmaxsat::get_assignment(svector& result) { } else { std::sort(m_cost_save.begin(), m_cost_save.end()); - unsigned j = 0; - for (theory_var i = 0; i < m_vars.size(); ++i) { - if (j < m_cost_save.size() && m_cost_save[j] == i) { + for (unsigned i = 0,j = 0; i < m_vars.size(); ++i) { + if (j < m_cost_save.size() && m_cost_save[j] == static_cast(i)) { result.push_back(false); ++j; } From 15e1c8459221cf7b9348c6772c2ee9e8726f5076 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 May 2015 08:38:07 -0700 Subject: [PATCH 799/925] update docuemntation for codeplex question 29927489/z3-proofs-are-hypothesis-and-lemma-rules-always-cleanly-nested Signed-off-by: Nikolaj Bjorner --- src/api/z3_api.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 6fc74ac88..da24f4caf 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -594,7 +594,10 @@ typedef enum } This proof object has one antecedent: a hypothetical proof for false. It converts the proof in a proof for (or (not l_1) ... (not l_n)), - when T1 contains the hypotheses: l_1, ..., l_n. + when T1 contains the open hypotheses: l_1, ..., l_n. + The hypotheses are closed after an application of a lemma. + Furthermore, there are no other open hypotheses in the subtree covered by + the lemma. - Z3_OP_PR_UNIT_RESOLUTION: \nicebox{ From 0197f6e010ace575ee267682dcae0eb63fd89594 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 19 May 2015 16:51:56 +0100 Subject: [PATCH 800/925] Bugfix for fp.rem when the result is zero. Fixes #91 --- src/ast/fpa/fpa2bv_converter.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index cc189f462..ed3a66515 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -1018,9 +1018,11 @@ void fpa2bv_converter::mk_rem(func_decl * f, unsigned num, expr * const * args, m_bv_util.mk_numeral(0, 3)); res_exp = m_bv_util.mk_sign_extend(2, b_exp); + // CMW: Actual rounding is not necessary here, this is + // just convenience to get rid of the extra bits. expr_ref rm(m); - rm = m_bv_util.mk_numeral(BV_RM_TIES_TO_EVEN, 3); - round(f->get_range(), rm, res_sgn, res_sig, res_exp, v7); + rm = m_bv_util.mk_numeral(BV_RM_TIES_TO_EVEN, 3); + round(f->get_range(), rm, res_sgn, res_sig, res_exp, v7); // And finally, we tie them together. mk_ite(c6, v6, v7, result); @@ -1030,6 +1032,11 @@ void fpa2bv_converter::mk_rem(func_decl * f, unsigned num, expr * const * args, mk_ite(c2, v2, result, result); mk_ite(c1, v1, result, result); + expr_ref result_is_zero(m), zeros(m); + mk_is_zero(result, result_is_zero); + mk_ite(x_is_pos, pzero, nzero, zeros); + mk_ite(result_is_zero, zeros, result, result); + SASSERT(is_well_sorted(m, result)); TRACE("fpa2bv_rem", tout << "REM = " << mk_ismt2_pp(result, m) << std::endl; ); From 66e6e673955ca7f67d0187328d77412e66c88847 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 19 May 2015 16:52:47 +0100 Subject: [PATCH 801/925] fix build on CentOS Signed-off-by: Nuno Lopes --- src/util/trace.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/trace.cpp b/src/util/trace.cpp index 3410febd5..72984d808 100644 --- a/src/util/trace.cpp +++ b/src/util/trace.cpp @@ -23,8 +23,8 @@ Revision History: std::ofstream tout(".z3-trace"); #endif -bool g_enable_all_trace_tags = false; -str_hashtable* g_enabled_trace_tags = 0; +static bool g_enable_all_trace_tags = false; +static str_hashtable* g_enabled_trace_tags = 0; static str_hashtable& get_enabled_trace_tags() { if (!g_enabled_trace_tags) { From ccc1f0221663c1a67b0d7aa62155b61d6df58020 Mon Sep 17 00:00:00 2001 From: Ken McMillan Date: Tue, 19 May 2015 18:47:13 -0700 Subject: [PATCH 802/925] fix for github issue 54 --- src/interp/iz3mgr.h | 6 ++++++ src/interp/iz3proof_itp.cpp | 8 ++++++-- src/interp/iz3translate.cpp | 14 +++++++++++++- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/interp/iz3mgr.h b/src/interp/iz3mgr.h index 3f4138354..54fb35a0f 100755 --- a/src/interp/iz3mgr.h +++ b/src/interp/iz3mgr.h @@ -279,6 +279,12 @@ class iz3mgr { res[i] = arg(t,i); } + std::vector args(const ast &t){ + std::vector res; + get_args(t,res); + return res; + } + symb sym(ast t){ raw_ast *_ast = t.raw(); return is_app(_ast) ? to_app(_ast)->get_decl() : 0; diff --git a/src/interp/iz3proof_itp.cpp b/src/interp/iz3proof_itp.cpp index f76de14cf..2b4100e5e 100755 --- a/src/interp/iz3proof_itp.cpp +++ b/src/interp/iz3proof_itp.cpp @@ -2215,8 +2215,12 @@ class iz3proof_itp_impl : public iz3proof_itp { } else { if(get_term_type(p) == LitA){ - if(get_term_type(q) == LitA) - itp = mk_false(); + if(get_term_type(q) == LitA){ + if(op(q) == Or) + itp = make_assumption(rng.hi,args(q)); + else + itp = mk_false(); + } else { if(get_term_type(p_eq_q) == LitA) itp = q; diff --git a/src/interp/iz3translate.cpp b/src/interp/iz3translate.cpp index e4bccace1..d1479e4cc 100755 --- a/src/interp/iz3translate.cpp +++ b/src/interp/iz3translate.cpp @@ -1702,14 +1702,16 @@ public: return res; } } - if(dk == PR_MODUS_PONENS && expect_clause && op(con) == Or){ + if(dk == PR_MODUS_PONENS && expect_clause && op(con) == Or && op(conc(prem(proof,0))) == Or){ Iproof::node clause = translate_main(prem(proof,0),true); res = RewriteClause(clause,prem(proof,1)); return res; } +#if 0 if(dk == PR_MODUS_PONENS && expect_clause && op(con) == Or) std::cout << "foo!\n"; +#endif // no idea why this shows up if(dk == PR_MODUS_PONENS_OEQ){ @@ -1965,6 +1967,16 @@ public: res = make(commute,pf,comm_equiv); break; } + case PR_AND_ELIM: { + std::vector rule_ax, res_conc; + ast piv = conc(prem(proof,0)); + rule_ax.push_back(make(Not,piv)); + rule_ax.push_back(con); + ast pf = iproof->make_axiom(rule_ax); + res_conc.push_back(con); + res = iproof->make_resolution(piv,res_conc,pf,args[0]); + break; + } default: pfgoto(proof); assert(0 && "translate_main: unsupported proof rule"); From 33ddf0bcdfcf630c0bdb4cad3414e9dea6eb79bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henning=20G=C3=BCnther?= Date: Wed, 20 May 2015 14:33:46 +0100 Subject: [PATCH 803/925] Expose insert_if_not_there_core method in map class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Henning Günther --- src/util/map.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/util/map.h b/src/util/map.h index d659b89c0..4640eb111 100644 --- a/src/util/map.h +++ b/src/util/map.h @@ -108,6 +108,10 @@ public: m_table.insert(key_data(k, v)); } + bool insert_if_not_there_core(key const & k, value const & v, entry *& et) { + return m_table.insert_if_not_there_core(key_data(k,v), et); + } + key_data const & insert_if_not_there(key const & k, value const & v) { return m_table.insert_if_not_there(key_data(k, v)); } From 28f6adf79e1ecfeee45c6e4eab9851f74645ba8d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 20 May 2015 09:21:55 -0700 Subject: [PATCH 804/925] disable hybrid relations pending overhaul/deletion of product relations Signed-off-by: Nikolaj Bjorner --- src/muz/base/dl_context.cpp | 1 + src/muz/base/rule_properties.cpp | 27 +++++++++-- src/muz/base/rule_properties.h | 4 ++ src/muz/rel/dl_mk_explanations.cpp | 2 +- src/muz/rel/dl_product_relation.cpp | 69 +++++++++++++++++++---------- src/muz/rel/dl_product_relation.h | 8 ++-- src/muz/rel/dl_relation_manager.cpp | 3 +- src/muz/rel/rel_context.cpp | 2 +- src/qe/qe_sat_tactic.cpp | 2 +- 9 files changed, 84 insertions(+), 34 deletions(-) diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index b7cb5680f..bd70c06ef 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -558,6 +558,7 @@ namespace datalog { m_rule_properties.check_quantifier_free(); m_rule_properties.check_uninterpreted_free(); m_rule_properties.check_nested_free(); + m_rule_properties.check_infinite_sorts(); break; case PDR_ENGINE: m_rule_properties.collect(r); diff --git a/src/muz/base/rule_properties.cpp b/src/muz/base/rule_properties.cpp index 7cb1c6241..5d1aff44e 100644 --- a/src/muz/base/rule_properties.cpp +++ b/src/muz/base/rule_properties.cpp @@ -26,7 +26,7 @@ Notes: using namespace datalog; rule_properties::rule_properties(ast_manager & m, rule_manager& rm, context& ctx, i_expr_pred& p): - m(m), rm(rm), m_ctx(ctx), m_is_predicate(p), m_dt(m), m_dl(m), m_generate_proof(false) {} + m(m), rm(rm), m_ctx(ctx), m_is_predicate(p), m_dt(m), m_dl(m), m_bv(m), m_generate_proof(false) {} rule_properties::~rule_properties() {} @@ -48,6 +48,12 @@ void rule_properties::collect(rule_set const& rules) { if (m_generate_proof && !r->get_proof()) { rm.mk_rule_asserted_proof(*r); } + for (unsigned i = 0; m_inf_sort.empty() && i < r->get_decl()->get_arity(); ++i) { + sort* d = r->get_decl()->get_domain(i); + if (!m.is_bool(d) && !m_dl.is_finite_sort(d) && !m_bv.is_bv_sort(d)) { + m_inf_sort.push_back(m_rule); + } + } } } @@ -85,6 +91,16 @@ void rule_properties::check_uninterpreted_free() { } } +void rule_properties::check_infinite_sorts() { + if (!m_inf_sort.empty()) { + std::stringstream stm; + rule* r = m_inf_sort.back(); + stm << "Rule contains infinite sorts in rule "; + r->display(m_ctx, stm); + throw default_exception(stm.str()); + } +} + void rule_properties::check_nested_free() { if (!m_interp_pred.empty()) { std::stringstream stm; @@ -92,7 +108,6 @@ void rule_properties::check_nested_free() { stm << "Rule contains nested predicates "; r->display(m_ctx, stm); throw default_exception(stm.str()); - } } @@ -158,7 +173,8 @@ void rule_properties::insert(ptr_vector& rules, rule* r) { } } -void rule_properties::operator()(var* n) { } +void rule_properties::operator()(var* n) { +} void rule_properties::operator()(quantifier* n) { m_quantifiers.insert(n, m_rule); @@ -177,6 +193,10 @@ void rule_properties::operator()(app* n) { m_uninterp_funs.insert(n->get_decl(), m_rule); } } + else { + std::cout << mk_pp(n, m) << "\n"; + } + } void rule_properties::reset() { @@ -184,5 +204,6 @@ void rule_properties::reset() { m_uninterp_funs.reset(); m_interp_pred.reset(); m_negative_rules.reset(); + m_inf_sort.reset(); } diff --git a/src/muz/base/rule_properties.h b/src/muz/base/rule_properties.h index a16f63507..18ecd2ee8 100644 --- a/src/muz/base/rule_properties.h +++ b/src/muz/base/rule_properties.h @@ -23,6 +23,7 @@ Notes: #include"ast.h" #include"datatype_decl_plugin.h" +#include"bv_decl_plugin.h" #include"dl_rule.h" namespace datalog { @@ -33,12 +34,14 @@ namespace datalog { i_expr_pred& m_is_predicate; datatype_util m_dt; dl_decl_util m_dl; + bv_util m_bv; bool m_generate_proof; rule* m_rule; obj_map m_quantifiers; obj_map m_uninterp_funs; ptr_vector m_interp_pred; ptr_vector m_negative_rules; + ptr_vector m_inf_sort; void insert(ptr_vector& rules, rule* r); public: @@ -51,6 +54,7 @@ namespace datalog { void check_existential_tail(); void check_for_negated_predicates(); void check_nested_free(); + void check_infinite_sorts(); void operator()(var* n); void operator()(quantifier* n); void operator()(app* n); diff --git a/src/muz/rel/dl_mk_explanations.cpp b/src/muz/rel/dl_mk_explanations.cpp index 1338a6de6..7fcbdaaff 100644 --- a/src/muz/rel/dl_mk_explanations.cpp +++ b/src/muz/rel/dl_mk_explanations.cpp @@ -654,7 +654,7 @@ namespace datalog { family_id expl_kind = m_er_plugin->get_kind(); family_id expl_sieve_kind = sieve_plugin.get_relation_kind(sig, expl_sieve, expl_kind); - product_relation_plugin::rel_spec product_spec; + rel_spec product_spec; product_spec.push_back(inner_sieve_kind); product_spec.push_back(expl_sieve_kind); diff --git a/src/muz/rel/dl_product_relation.cpp b/src/muz/rel/dl_product_relation.cpp index f1dbc589c..1bc5e3545 100644 --- a/src/muz/rel/dl_product_relation.cpp +++ b/src/muz/rel/dl_product_relation.cpp @@ -77,6 +77,7 @@ namespace datalog { } family_id product_relation_plugin::get_relation_kind(const relation_signature & sig, const rel_spec & spec) { + SASSERT(spec.well_formed()); return m_spec_store.get_relation_kind(sig, spec); } @@ -132,14 +133,11 @@ namespace datalog { ptr_vector::const_iterator rend = rels.end(); for(; rit!=rend; ++rit) { specs.push_back((*rit)->m_spec); + SASSERT(specs.back().well_formed()); + std::sort(specs.back().begin(), specs.back().end()); } - vector::iterator sit = specs.begin(); - vector::iterator send = specs.end(); - for(; sit!=send; ++sit) { - rel_spec & s = *sit; - std::sort(s.begin(), s.end()); - } + vector::iterator sit = specs.begin(), send = specs.end(); res.reset(); for(;;) { @@ -160,7 +158,7 @@ namespace datalog { sit = specs.begin(); for(; sit!=send; ++sit) { rel_spec & s = *sit; - if(!s.empty() && s.back()==next) { + while (!s.empty() && s.back()==next) { s.pop_back(); } } @@ -191,6 +189,7 @@ namespace datalog { } rel_spec spec; m_spec_store.get_relation_spec(s, kind, spec); + SASSERT(spec.well_formed()); relation_vector inner_rels; unsigned rel_cnt = spec.size(); for(unsigned i=0; i intersect_fun = m_rmgr.mk_filter_by_intersection_fn(tgt, src); - if(!intersect_fun) { + if (!intersect_fun) { + TRACE("dl", tgt.display(tout << "tgt\n"); src.display(tout << "src\n");); warning_msg("intersection does not exist"); return; } @@ -613,9 +615,13 @@ namespace datalog { (*union_fun)(tgt, src); } public: - aligned_union_fn(product_relation const& tgt, product_relation const& src, product_relation const* delta, - bool is_widen) : + aligned_union_fn( + product_relation const& tgt, + product_relation const& src, + product_relation const* delta, + bool is_widen) : m_rmgr(tgt.get_manager()), + m_plugin(tgt.get_plugin()), m_is_widen(is_widen) { SASSERT(vectors_equal(tgt.m_spec, src.m_spec)); SASSERT(!delta || vectors_equal(tgt.m_spec, delta->m_spec)); @@ -631,6 +637,9 @@ namespace datalog { virtual void operator()(relation_base& _tgt, const relation_base& _src, relation_base* _delta) { TRACE("dl", _tgt.display(tout << "dst:\n"); _src.display(tout << "src:\n");); + SASSERT(m_plugin.check_kind(_tgt)); + SASSERT(m_plugin.check_kind(_src)); + SASSERT(!_delta || m_plugin.check_kind(*_delta)); product_relation& tgt = get(_tgt); product_relation const& src = get(_src); product_relation* delta = get(_delta); @@ -652,7 +661,7 @@ namespace datalog { if (i == j) { continue; //this is the basic union which we will perform later } - if (can_do_inner_union(i, j)) { + if (can_do_inner_union(i, j) && can_do_inner_union(j, i)) { TRACE("dl", itgt.display(tout << "tgt:\n"); src[j].display(tout << "src:\n");); // union[i][j] scoped_rel one_side_union = itgt.clone(); @@ -740,7 +749,7 @@ namespace datalog { virtual void operator()(relation_base& _tgt, const relation_base& _src, relation_base* _delta) { - TRACE("dl", _tgt.display(tout << "dst:\n"); _src.display(tout << "src:\n");); + TRACE("dl_verbose", _tgt.display(tout << "dst:\n"); _src.display(tout << "src:\n");); product_relation& tgt = get(_tgt); product_relation const& src0 = get(_src); product_relation* delta = _delta ? get(_delta) : 0; @@ -775,6 +784,7 @@ namespace datalog { m_inner_union_fun(inner_union_fun) {} virtual void operator()(relation_base& tgt, const relation_base& _src, relation_base* delta) { + TRACE("dl", tgt.display(tout); _src.display(tout); ); product_relation const& src = get(_src); (*m_inner_union_fun)(tgt, src[m_single_rel_idx], delta); } @@ -788,7 +798,8 @@ namespace datalog { } return alloc(unaligned_union_fn, get(tgt), get(src), get(delta), is_widen); } - if(check_kind(src)) { + if (check_kind(src)) { + TRACE("dl", tgt.display(tout << "different kinds"); src.display(tout);); const product_relation & p_src = get(src); unsigned single_idx; if(p_src.try_get_single_non_transparent(single_idx)) { @@ -799,7 +810,7 @@ namespace datalog { else { inner = get_manager().mk_union_fn(tgt, p_src[single_idx], delta); } - if(inner) { + if (inner) { return alloc(single_non_transparent_src_union_fn, single_idx, inner); } } @@ -975,10 +986,20 @@ namespace datalog { func_decl* p = 0; const relation_signature & sig = get_signature(); family_id new_kind = get_plugin().get_relation_kind(sig, spec); - if(new_kind == get_kind()) { + if (new_kind == get_kind()) { return; } + TRACE("dl", { + ast_manager& m = get_ast_manager_from_rel_manager(get_manager()); + sig.output(m, tout); tout << "\n"; + for (unsigned i = 0; i < spec.size(); ++i) { + tout << spec[i] << " "; + } + tout << "\n"; + } + ); + unsigned old_sz = size(); unsigned new_sz = spec.size(); unsigned old_remain = old_sz; @@ -1001,10 +1022,10 @@ namespace datalog { if(old_sz == 0 && m_default_empty) { //The relation didn't contain any inner relations but it was empty, //so we make the newly added relations empty as well. - irel = get_manager().mk_empty_relation(sig, new_kind); + irel = get_manager().mk_empty_relation(sig, ikind); } else { - irel = get_manager().mk_full_relation(sig, p, new_kind); + irel = get_manager().mk_full_relation(sig, p, ikind); } } new_rels.push_back(irel); @@ -1013,10 +1034,8 @@ namespace datalog { m_relations = new_rels; set_kind(new_kind); - DEBUG_CODE( - ensure_correct_kind(); - SASSERT(get_kind() == new_kind); - ); + m_spec = spec; + SASSERT(get_kind() == new_kind); } bool product_relation::try_get_single_non_transparent(unsigned & idx) const { @@ -1104,7 +1123,11 @@ namespace datalog { } void product_relation::display(std::ostream & out) const { - out<<"Product of the following relations:\n"; + if (m_relations.empty()) { + out << "{}\n"; + return; + } + out << "Product of the following relations:\n"; for (unsigned i = 0; i < m_relations.size(); ++i) { m_relations[i]->display(out); } diff --git a/src/muz/rel/dl_product_relation.h b/src/muz/rel/dl_product_relation.h index 0633ddbf1..f2efd9678 100644 --- a/src/muz/rel/dl_product_relation.h +++ b/src/muz/rel/dl_product_relation.h @@ -27,10 +27,12 @@ namespace datalog { class product_relation; + struct rel_spec : public svector { + bool well_formed() const { return true; } + }; + class product_relation_plugin : public relation_plugin { friend class product_relation; - public: - typedef svector rel_spec; private: class join_fn; class transform_fn; @@ -120,8 +122,6 @@ namespace datalog { - typedef product_relation_plugin::rel_spec rel_spec; - /** If m_relations is empty, value of this determines whether the relation is empty or full. */ diff --git a/src/muz/rel/dl_relation_manager.cpp b/src/muz/rel/dl_relation_manager.cpp index 9a2d0575d..b92c9f796 100644 --- a/src/muz/rel/dl_relation_manager.cpp +++ b/src/muz/rel/dl_relation_manager.cpp @@ -350,6 +350,7 @@ namespace datalog { //If there is no plugin to handle the signature, we just create an empty product relation and //stuff will be added to it by later operations. + TRACE("dl", s.output(get_context().get_manager(), tout << "empty product relation"); tout << "\n";); return product_relation_plugin::get_plugin(*this).mk_empty(s); } @@ -756,7 +757,6 @@ namespace datalog { relation_union_fn * relation_manager::mk_union_fn(const relation_base & tgt, const relation_base & src, const relation_base * delta) { - TRACE("dl", tout << src.get_plugin().get_name() << " " << tgt.get_plugin().get_name() << "\n";); relation_union_fn * res = tgt.get_plugin().mk_union_fn(tgt, src, delta); if(!res && &tgt.get_plugin()!=&src.get_plugin()) { res = src.get_plugin().mk_union_fn(tgt, src, delta); @@ -764,6 +764,7 @@ namespace datalog { if(!res && delta && &tgt.get_plugin()!=&delta->get_plugin() && &src.get_plugin()!=&delta->get_plugin()) { res = delta->get_plugin().mk_union_fn(tgt, src, delta); } + // TRACE("dl", tout << src.get_plugin().get_name() << " " << tgt.get_plugin().get_name() << " " << (res?"created":"not created") << "\n";); return res; } diff --git a/src/muz/rel/rel_context.cpp b/src/muz/rel/rel_context.cpp index f3ac4bf84..c3ffdceae 100644 --- a/src/muz/rel/rel_context.cpp +++ b/src/muz/rel/rel_context.cpp @@ -486,7 +486,7 @@ namespace datalog { target_kind = get_ordinary_relation_plugin(relation_names[0]).get_kind(); break; default: { - svector rel_kinds; // kinds of plugins that are not table plugins + rel_spec rel_kinds; // kinds of plugins that are not table plugins family_id rel_kind; // the aggregate kind of non-table plugins for (unsigned i = 0; i < relation_name_cnt; i++) { relation_plugin & p = get_ordinary_relation_plugin(relation_names[i]); diff --git a/src/qe/qe_sat_tactic.cpp b/src/qe/qe_sat_tactic.cpp index 2be32c02d..d2360762a 100644 --- a/src/qe/qe_sat_tactic.cpp +++ b/src/qe/qe_sat_tactic.cpp @@ -399,7 +399,7 @@ namespace qe { expr_ref qt(unsigned i, expr* ctx, model_ref& model) { model_ref model1; while (true) { - IF_VERBOSE(1, verbose_stream() << "qt " << i << "\n";); + IF_VERBOSE(1, verbose_stream() << "(qt " << i << ")\n";); TRACE("qe", tout << i << " " << mk_pp(ctx, m) << "\n"; display(tout);); From c377fec7a4153b6b5fffc2267cb55aef83451506 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 20 May 2015 17:57:27 +0100 Subject: [PATCH 805/925] Made fp.* comparison chainable. --- src/ast/fpa_decl_plugin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ast/fpa_decl_plugin.cpp b/src/ast/fpa_decl_plugin.cpp index e559ee179..0b28c4277 100644 --- a/src/ast/fpa_decl_plugin.cpp +++ b/src/ast/fpa_decl_plugin.cpp @@ -289,7 +289,7 @@ func_decl * fpa_decl_plugin::mk_float_const_decl(decl_kind k, unsigned num_param func_decl * fpa_decl_plugin::mk_bin_rel_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { - if (arity != 2) + if (arity < 2) m_manager->raise_exception("invalid number of arguments to floating point relation"); if (domain[0] != domain[1] || !is_float_sort(domain[0])) m_manager->raise_exception("sort mismatch, expected equal FloatingPoint sorts as arguments"); @@ -306,7 +306,7 @@ func_decl * fpa_decl_plugin::mk_bin_rel_decl(decl_kind k, unsigned num_parameter } func_decl_info finfo(m_family_id, k); finfo.set_chainable(true); - return m_manager->mk_func_decl(name, arity, domain, m_manager->mk_bool_sort(), finfo); + return m_manager->mk_func_decl(name, domain[0], domain[1], m_manager->mk_bool_sort(), finfo); } func_decl * fpa_decl_plugin::mk_unary_rel_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, From 1e3952406c4b217dad6f40c17bc54a82ebb66f93 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 20 May 2015 18:14:38 +0100 Subject: [PATCH 806/925] disabled debug output --- src/ast/fpa/fpa2bv_converter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index ed3a66515..6d07092ea 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -3351,7 +3351,7 @@ void fpa2bv_converter::mk_rounding_mode(func_decl * f, expr_ref & result) void fpa2bv_converter::dbg_decouple(const char * prefix, expr_ref & e) { #ifdef Z3DEBUG - // return; + return; // CMW: This works only for quantifier-free formulas. expr_ref new_e(m); new_e = m.mk_fresh_const(prefix, m.get_sort(e)); From 51040d3e19dae7046225405c27a6ef977167d4f5 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 20 May 2015 18:32:40 +0100 Subject: [PATCH 807/925] Bugfix for fp.isNormal --- src/ast/fpa/fpa2bv_converter.cpp | 4 +++- src/util/mpf.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 6d07092ea..83ba843ac 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -3132,14 +3132,16 @@ void fpa2bv_converter::mk_is_normal(expr * e, expr_ref & result) { expr * sgn, * sig, * exp; split_fp(e, sgn, exp, sig); - expr_ref is_special(m), is_denormal(m), p(m); + expr_ref is_special(m), is_denormal(m), p(m), is_zero(m); mk_is_denormal(e, is_denormal); + mk_is_zero(e, is_zero); unsigned ebits = m_bv_util.get_bv_size(exp); p = m_bv_util.mk_numeral(fu().fm().m_powers2.m1(ebits), ebits); m_simp.mk_eq(exp, p, is_special); expr_ref or_ex(m); m_simp.mk_or(is_special, is_denormal, or_ex); + m_simp.mk_or(is_zero, or_ex, or_ex); m_simp.mk_not(or_ex, result); } diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 683140129..1dab7b995 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -1428,7 +1428,7 @@ bool mpf_manager::is_ninf(mpf const & x) { } bool mpf_manager::is_normal(mpf const & x) { - return !(has_top_exp(x) || is_denormal(x)); + return !(has_top_exp(x) || is_denormal(x) || is_zero(x)); } bool mpf_manager::is_denormal(mpf const & x) { From 9d0e3abd2411bbedd47b1e8a80a3df829287a1ad Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 20 May 2015 10:41:41 -0700 Subject: [PATCH 808/925] use static features to set hidden configuration parameters on small integers and int vs. real Signed-off-by: Nikolaj Bjorner --- src/ast/static_features.h | 2 ++ src/smt/smt_setup.cpp | 22 ++++++++++++++-------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/ast/static_features.h b/src/ast/static_features.h index 4bdcd6f05..c07667325 100644 --- a/src/ast/static_features.h +++ b/src/ast/static_features.h @@ -142,6 +142,8 @@ struct static_features { } } + bool arith_k_sum_is_small() const { return m_arith_k_sum < rational(INT_MAX / 8); } + void inc_num_apps(func_decl const * d) { unsigned id = d->get_decl_id(); m_num_apps.reserve(id+1, 0); m_num_apps[id]++; } void inc_theory_terms(family_id fid) { m_num_theory_terms.reserve(fid+1, 0); m_num_theory_terms[fid]++; } void inc_theory_atoms(family_id fid) { m_num_theory_atoms.reserve(fid+1, 0); m_num_theory_atoms[fid]++; } diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 800bcaaed..d4c0e1efb 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -276,7 +276,7 @@ namespace smt { m_context.register_plugin(alloc(smt::theory_mi_arith, m_manager, m_params)); } else if (!m_params.m_arith_auto_config_simplex && is_dense(st)) { - if (!st.m_has_rational && !m_params.m_model && st.m_arith_k_sum < rational(INT_MAX / 8)) + if (!st.m_has_rational && !m_params.m_model && st.arith_k_sum_is_small()) m_context.register_plugin(alloc(smt::theory_dense_smi, m_manager, m_params)); else m_context.register_plugin(alloc(smt::theory_dense_mi, m_manager, m_params)); @@ -284,7 +284,7 @@ namespace smt { else { if (m_params.m_arith_auto_config_simplex || st.m_num_uninterpreted_constants > 4 * st.m_num_bool_constants || st.m_num_ite_terms > 0 /* theory_rdl and theory_frdl do not support ite-terms */) { - // if (!st.m_has_rational && !m_params.m_model && st.m_arith_k_sum < rational(INT_MAX / 8)) { + // if (!st.m_has_rational && !m_params.m_model && st.arith_k_sum_is_small()) { // TRACE("rdl_bug", tout << "using theory_smi_arith\n";); // m_context.register_plugin(alloc(smt::theory_smi_arith, m_manager, m_params)); // } @@ -297,7 +297,7 @@ namespace smt { m_params.m_arith_bound_prop = BP_NONE; m_params.m_arith_propagation_strategy = ARITH_PROP_AGILITY; m_params.m_arith_add_binary_bounds = true; - if (!st.m_has_rational && !m_params.m_model && st.m_arith_k_sum < rational(INT_MAX / 8)) + if (!st.m_has_rational && !m_params.m_model && st.arith_k_sum_is_small()) m_context.register_plugin(alloc(smt::theory_frdl, m_manager, m_params)); else m_context.register_plugin(alloc(smt::theory_rdl, m_manager, m_params)); @@ -356,14 +356,14 @@ namespace smt { else if (!m_params.m_arith_auto_config_simplex && is_dense(st)) { TRACE("setup", tout << "using dense diff logic...\n";); m_params.m_phase_selection = PS_CACHING_CONSERVATIVE; - if (st.m_arith_k_sum < rational(INT_MAX / 8)) + if (st.arith_k_sum_is_small()) m_context.register_plugin(alloc(smt::theory_dense_si, m_manager, m_params)); else m_context.register_plugin(alloc(smt::theory_dense_i, m_manager, m_params)); } else { - // if (st.m_arith_k_sum < rational(INT_MAX / 8)) { + // if (st.arith_k_sum_is_small()) { // TRACE("setup", tout << "using small integer simplex...\n";); // m_context.register_plugin(alloc(smt::theory_si_arith, m_manager, m_params)); // } @@ -406,7 +406,7 @@ namespace smt { if (m_manager.proofs_enabled()) { m_context.register_plugin(alloc(smt::theory_mi_arith, m_manager, m_params)); } - else if (st.m_arith_k_sum < rational(INT_MAX / 8)) + else if (st.arith_k_sum_is_small()) m_context.register_plugin(alloc(smt::theory_dense_si, m_manager, m_params)); else m_context.register_plugin(alloc(smt::theory_dense_i, m_manager, m_params)); @@ -421,7 +421,7 @@ namespace smt { if (m_manager.proofs_enabled()) { m_context.register_plugin(alloc(smt::theory_mi_arith, m_manager, m_params)); } - // else if (st.m_arith_k_sum < rational(INT_MAX / 8)) + // else if (st.arith_k_sum_is_small()) // m_context.register_plugin(alloc(smt::theory_dense_si, m_manager, m_params)); else m_context.register_plugin(alloc(smt::theory_i_arith, m_manager, m_params)); @@ -602,7 +602,7 @@ namespace smt { m_params.m_phase_selection = PS_CACHING_CONSERVATIVE2; m_params.m_random_initial_activity = IA_ZERO; } - // if (st.m_num_arith_ineqs == st.m_num_diff_ineqs && st.m_num_arith_eqs == st.m_num_diff_eqs && st.m_arith_k_sum < rational(INT_MAX / 8)) + // if (st.m_num_arith_ineqs == st.m_num_diff_ineqs && st.m_num_arith_eqs == st.m_num_diff_eqs && st.arith_k_sum_is_small()) // m_context.register_plugin(new smt::theory_si_arith(m_manager, m_params)); // else setup_i_arith(); @@ -715,6 +715,12 @@ namespace smt { } void setup::setup_arith() { + static_features st(m_manager); + IF_VERBOSE(100, verbose_stream() << "(smt.collecting-features)\n";); + st.collect(m_context.get_num_asserted_formulas(), m_context.get_asserted_formulas()); + IF_VERBOSE(1000, st.display_primitive(verbose_stream());); + m_params.m_arith_fixnum = st.arith_k_sum_is_small(); + m_params.m_arith_int_only = !st.m_has_rational && !st.m_has_real; switch(m_params.m_arith_mode) { case AS_NO_ARITH: m_context.register_plugin(alloc(smt::theory_dummy, m_manager.mk_family_id("arith"), "no arithmetic")); From caa616f11b93a3175abef079f1f35e684e4446e9 Mon Sep 17 00:00:00 2001 From: Ken McMillan Date: Wed, 20 May 2015 15:37:51 -0700 Subject: [PATCH 809/925] fix for github issue 83 --- src/interp/iz3mgr.cpp | 14 ++++++++++++++ src/interp/iz3mgr.h | 2 ++ src/interp/iz3translate.cpp | 8 +++++++- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/interp/iz3mgr.cpp b/src/interp/iz3mgr.cpp index 5a7f71987..78dd6f174 100755 --- a/src/interp/iz3mgr.cpp +++ b/src/interp/iz3mgr.cpp @@ -556,6 +556,20 @@ void iz3mgr::get_farkas_coeffs(const ast &proof, std::vector& rats){ extract_lcd(rats); } +void iz3mgr::get_broken_gcd_test_coeffs(const ast &proof, std::vector& rats){ + symb s = sym(proof); + int numps = s->get_num_parameters(); + rats.resize(numps-2); + for(int i = 2; i < numps; i++){ + rational r; + bool ok = s->get_parameter(i).is_rational(r); + if(!ok) + throw "Bad Farkas coefficient"; + rats[i-2] = r; + } + extract_lcd(rats); +} + void iz3mgr::get_assign_bounds_coeffs(const ast &proof, std::vector& coeffs){ std::vector rats; get_assign_bounds_coeffs(proof,rats); diff --git a/src/interp/iz3mgr.h b/src/interp/iz3mgr.h index 54fb35a0f..8d4479f8f 100755 --- a/src/interp/iz3mgr.h +++ b/src/interp/iz3mgr.h @@ -424,6 +424,8 @@ class iz3mgr { void get_farkas_coeffs(const ast &proof, std::vector& rats); + void get_broken_gcd_test_coeffs(const ast &proof, std::vector& rats); + void get_assign_bounds_coeffs(const ast &proof, std::vector& rats); void get_assign_bounds_coeffs(const ast &proof, std::vector& rats); diff --git a/src/interp/iz3translate.cpp b/src/interp/iz3translate.cpp index d1479e4cc..f510f4070 100755 --- a/src/interp/iz3translate.cpp +++ b/src/interp/iz3translate.cpp @@ -1021,6 +1021,12 @@ public: my_coeffs.push_back(make_int(c)); my_prem_cons.push_back(conc(prem(proof,i))); } + else if(c.is_neg()){ + int j = (i % 2 == 0) ? i + 1 : i - 1; + my_prems.push_back(prems[j]); + my_coeffs.push_back(make_int(-coeffs[j])); + my_prem_cons.push_back(conc(prem(proof,j))); + } } ast my_con = sum_inequalities(my_coeffs,my_prem_cons); @@ -1884,7 +1890,7 @@ public: } case GCDTestKind: { std::vector farkas_coeffs; - get_farkas_coeffs(proof,farkas_coeffs); + get_broken_gcd_test_coeffs(proof,farkas_coeffs); if(farkas_coeffs.size() != nprems){ pfgoto(proof); throw unsupported(); From c422b48bf43f9a1e2b29c4803c646de0617e32b4 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 21 May 2015 15:06:47 +0100 Subject: [PATCH 810/925] Bugfix for hwf_manager::round_to_integral --- src/util/hwf.cpp | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/util/hwf.cpp b/src/util/hwf.cpp index 40d20b644..b159cbdb6 100644 --- a/src/util/hwf.cpp +++ b/src/util/hwf.cpp @@ -338,8 +338,39 @@ void hwf_manager::sqrt(mpf_rounding_mode rm, hwf const & x, hwf & o) { void hwf_manager::round_to_integral(mpf_rounding_mode rm, hwf const & x, hwf & o) { set_rounding_mode(rm); - modf(x.value, &o.value); - // Note: on x64, this sometimes produces an SNAN instead of a QNAN? + // CMW: modf is not the right function here. + // modf(x.value, &o.value); + + // According to the Intel Architecture manual, the x87-instrunction FRNDINT is the + // same in 32-bit and 64-bit mode. The _mm_round_* intrinsics are SSE4 extensions. + +#ifdef USE_INTRINSICS + switch (rm) { + case 0: _mm_store_sd(&o.value, _mm_round_pd(_mm_set_sd(x.value), _MM_FROUND_TO_NEAREST_INT)); break; + case 2: _mm_store_sd(&o.value, _mm_round_pd(_mm_set_sd(x.value), _MM_FROUND_TO_POS_INF)); break; + case 3: _mm_store_sd(&o.value, _mm_round_pd(_mm_set_sd(x.value), _MM_FROUND_TO_NEG_INF)); break; + case 4: _mm_store_sd(&o.value, _mm_round_pd(_mm_set_sd(x.value), _MM_FROUND_TO_ZERO)); break; + case 1: + UNREACHABLE(); // Note: MPF_ROUND_NEAREST_TAWAY is not supported by the hardware! + break; + default: + UNREACHABLE(); // Unknown rounding mode. + } +#else + NOT_IMPLEMENTED_YET(); +#endif + +#if 0 + double xv = x.value; + double & ov = o.value; + + __asm { + fld xv + frndint + fstp ov // Store result away. + } + +#endif } void hwf_manager::rem(hwf const & x, hwf const & y, hwf & o) { From 8c18bdcca9e72ce71ac4de47816c351c3dbfb84f Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 21 May 2015 18:12:14 +0100 Subject: [PATCH 811/925] Bugfix for fp.roundToIntegral. Fixes #69 --- src/ast/fpa/fpa2bv_converter.cpp | 13 +++++++++---- src/util/mpf.cpp | 28 ++++++++++++++++------------ 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 83ba843ac..f69f27214 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -1586,9 +1586,10 @@ void fpa2bv_converter::mk_round_to_integral(func_decl * f, unsigned num, expr * mk_nzero(f, nzero); mk_pzero(f, pzero); - expr_ref x_is_zero(m), x_is_pos(m); + expr_ref x_is_zero(m), x_is_pos(m), x_is_neg(m); mk_is_zero(x, x_is_zero); mk_is_pos(x, x_is_pos); + mk_is_neg(x, x_is_neg); dbg_decouple("fpa2bv_r2i_x_is_zero", x_is_zero); dbg_decouple("fpa2bv_r2i_x_is_pos", x_is_pos); @@ -1655,9 +1656,13 @@ void fpa2bv_converter::mk_round_to_integral(func_decl * f, unsigned num, expr * mk_ite(c422, xone, v42, v42); mk_ite(c421, xzero, v42, v42); - mk_ite(m.mk_eq(a_sgn, one_1), nzero, pone, v4); - mk_ite(m.mk_or(rm_is_rte, rm_is_rta), v42, v4, v4); - mk_ite(m.mk_or(rm_is_rtz, rm_is_rtn), xzero, v4, v4); + expr_ref v4_rtn(m), v4_rtp(m); + mk_ite(x_is_neg, nzero, pone, v4_rtp); + mk_ite(x_is_neg, none, pzero, v4_rtn); + + mk_ite(rm_is_rtp, v4_rtp, v42, v4); + mk_ite(rm_is_rtn, v4_rtn, v4, v4); + mk_ite(rm_is_rtz, xzero, v4, v4); SASSERT(is_well_sorted(m, v4)); diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 1dab7b995..e66f6d270 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -1006,11 +1006,22 @@ void mpf_manager::round_to_integral(mpf_rounding_mode rm, mpf const & x, mpf & o else if (is_zero(x)) mk_zero(x.ebits, x.sbits, x.sign, o); // -0.0 -> -0.0, says IEEE754, Sec 5.9. else if (x.exponent < 0) { - if (rm == MPF_ROUND_TOWARD_ZERO || - rm == MPF_ROUND_TOWARD_NEGATIVE) + if (rm == MPF_ROUND_TOWARD_ZERO) mk_zero(x.ebits, x.sbits, x.sign, o); - else if (rm == MPF_ROUND_NEAREST_TEVEN || - rm == MPF_ROUND_NEAREST_TAWAY) { + else if (rm == MPF_ROUND_TOWARD_NEGATIVE) { + if (x.sign) + mk_one(x.ebits, x.sbits, true, o); + else + mk_zero(x.ebits, x.sbits, false, o); + } + else if (rm == MPF_ROUND_TOWARD_POSITIVE) { + if (x.sign) + mk_zero(x.ebits, x.sbits, true, o); + else + mk_one(x.ebits, x.sbits, false, o); + } + else { + SASSERT(rm == MPF_ROUND_NEAREST_TEVEN || rm == MPF_ROUND_NEAREST_TAWAY); bool tie = m_mpz_manager.is_zero(x.significand) && x.exponent == -1; TRACE("mpf_dbg", tout << "tie = " << tie << std::endl;); if (tie && rm == MPF_ROUND_NEAREST_TEVEN) @@ -1019,15 +1030,8 @@ void mpf_manager::round_to_integral(mpf_rounding_mode rm, mpf const & x, mpf & o mk_one(x.ebits, x.sbits, x.sign, o); else if (x.exponent < -1) mk_zero(x.ebits, x.sbits, x.sign, o); - else - mk_one(x.ebits, x.sbits, x.sign, o); - } - else { - SASSERT(rm == MPF_ROUND_TOWARD_POSITIVE); - if (x.sign) - mk_nzero(x.ebits, x.sbits, o); else - mk_one(x.ebits, x.sbits, false, o); + mk_one(x.ebits, x.sbits, x.sign, o); } } else if (x.exponent >= x.sbits - 1) From eee076b9f8b5d2f3347dfa4f83b64851cb2372a0 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 21 May 2015 18:16:02 +0100 Subject: [PATCH 812/925] Bugfixes for fp.min, fp.max. Fixes the fix for #68 --- src/ast/fpa/fpa2bv_converter.cpp | 4 ++-- src/ast/rewriter/fpa_rewriter.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index f69f27214..1d794c898 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -1072,7 +1072,7 @@ void fpa2bv_converter::mk_min(func_decl * f, unsigned num, expr * const * args, result = y; mk_ite(lt, x, result, result); - mk_ite(both_zero, pzero, result, result); + mk_ite(both_zero, y, result, result); mk_ite(y_is_nan, x, result, result); mk_ite(x_is_nan, y, result, result); @@ -1102,7 +1102,7 @@ void fpa2bv_converter::mk_max(func_decl * f, unsigned num, expr * const * args, result = y; mk_ite(gt, x, result, result); - mk_ite(both_zero, pzero, result, result); + mk_ite(both_zero, y, result, result); mk_ite(y_is_nan, x, result, result); mk_ite(x_is_nan, y, result, result); diff --git a/src/ast/rewriter/fpa_rewriter.cpp b/src/ast/rewriter/fpa_rewriter.cpp index 40021e330..37c42b494 100644 --- a/src/ast/rewriter/fpa_rewriter.cpp +++ b/src/ast/rewriter/fpa_rewriter.cpp @@ -412,7 +412,7 @@ br_status fpa_rewriter::mk_min(expr * arg1, expr * arg2, expr_ref & result) { return BR_DONE; } if (m_util.is_zero(arg1) && m_util.is_zero(arg2)) { - result = m_util.mk_pzero(m().get_sort(arg1)); + result = arg2; return BR_DONE; } @@ -421,7 +421,7 @@ br_status fpa_rewriter::mk_min(expr * arg1, expr * arg2, expr_ref & result) { m().mk_ite(mk_eq_nan(arg2), arg1, m().mk_ite(m().mk_and(m_util.mk_is_zero(arg1), m_util.mk_is_zero(arg2)), - m_util.mk_pzero(m().get_sort(arg1)), + arg2, m().mk_ite(m_util.mk_lt(arg1, arg2), arg1, arg2)))); @@ -438,7 +438,7 @@ br_status fpa_rewriter::mk_max(expr * arg1, expr * arg2, expr_ref & result) { return BR_DONE; } if (m_util.is_zero(arg1) && m_util.is_zero(arg2)) { - result = m_util.mk_pzero(m().get_sort(arg1)); + result = arg2; return BR_DONE; } @@ -447,7 +447,7 @@ br_status fpa_rewriter::mk_max(expr * arg1, expr * arg2, expr_ref & result) { m().mk_ite(mk_eq_nan(arg2), arg1, m().mk_ite(m().mk_and(m_util.mk_is_zero(arg1), m_util.mk_is_zero(arg2)), - m_util.mk_pzero(m().get_sort(arg1)), + arg2, m().mk_ite(m_util.mk_gt(arg1, arg2), arg1, arg2)))); From 6f575689b190740a78f8073816046f5efd4c4eab Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 21 May 2015 19:02:09 +0100 Subject: [PATCH 813/925] Added injection of auxiliary lemmas for fp.isNaN, so that the value propagation can pick up these values and propagate them. Fixes #96. --- src/ast/fpa/fpa2bv_converter.cpp | 7 +++++++ src/tactic/fpa/qffp_tactic.cpp | 1 + 2 files changed, 8 insertions(+) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 1d794c898..cc0fef3c3 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -3044,6 +3044,13 @@ void fpa2bv_converter::mk_is_nan(expr * e, expr_ref & result) { m_simp.mk_not(sig_is_zero, sig_is_not_zero); m_simp.mk_eq(exp, top_exp, exp_is_top); m_simp.mk_and(exp_is_top, sig_is_not_zero, result); + + // Inject auxiliary lemmas that fix e to the one and only NaN value, + // that is (= e (fp #b0 #b1...1 #b0...01)), so that the value propagation + // has a value to propagate. + m_extra_assertions.push_back(m.mk_eq(sgn, m_bv_util.mk_numeral(0, 1))); + m_extra_assertions.push_back(m.mk_eq(exp, top_exp)); + m_extra_assertions.push_back(m.mk_eq(sig, m_bv_util.mk_numeral(1, m_bv_util.get_bv_size(sig)))); } void fpa2bv_converter::mk_is_inf(expr * e, expr_ref & result) { diff --git a/src/tactic/fpa/qffp_tactic.cpp b/src/tactic/fpa/qffp_tactic.cpp index c45898cc7..4854b3c07 100644 --- a/src/tactic/fpa/qffp_tactic.cpp +++ b/src/tactic/fpa/qffp_tactic.cpp @@ -37,6 +37,7 @@ tactic * mk_qffp_tactic(ast_manager & m, params_ref const & p) { mk_smt_tactic(), and_then( mk_fpa2bv_tactic(m, p), + mk_propagate_values_tactic(m, p), using_params(mk_simplify_tactic(m, p), simp_p), mk_bit_blaster_tactic(m, p), using_params(mk_simplify_tactic(m, p), simp_p), From f100d4feda71e78af653c76fae52b7427e26f2ce Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 21 May 2015 11:10:42 -0700 Subject: [PATCH 814/925] hoist out basic union find Signed-off-by: Nikolaj Bjorner --- .../dl_mk_quantifier_instantiation.h | 70 ++----------------- src/util/union_find.h | 66 +++++++++++++++++ 2 files changed, 70 insertions(+), 66 deletions(-) diff --git a/src/muz/transforms/dl_mk_quantifier_instantiation.h b/src/muz/transforms/dl_mk_quantifier_instantiation.h index 138d5abee..37a5b8a6c 100644 --- a/src/muz/transforms/dl_mk_quantifier_instantiation.h +++ b/src/muz/transforms/dl_mk_quantifier_instantiation.h @@ -26,8 +26,9 @@ Revision History: #define _DL_MK_QUANTIFIER_INSTANTIATION_H_ -#include"dl_rule_transformer.h" -#include"expr_safe_replace.h" +#include "dl_rule_transformer.h" +#include "expr_safe_replace.h" +#include "union_find.h" namespace datalog { @@ -37,75 +38,12 @@ namespace datalog { class mk_quantifier_instantiation : public rule_transformer::plugin { typedef svector > term_pairs; - class union_find { - unsigned_vector m_find; - unsigned_vector m_size; - unsigned_vector m_next; - - void ensure_size(unsigned v) { - while (v >= get_num_vars()) { - mk_var(); - } - } - public: - unsigned mk_var() { - unsigned r = m_find.size(); - m_find.push_back(r); - m_size.push_back(1); - m_next.push_back(r); - return r; - } - unsigned get_num_vars() const { return m_find.size(); } - - unsigned find(unsigned v) const { - if (v >= get_num_vars()) { - return v; - } - while (true) { - unsigned new_v = m_find[v]; - if (new_v == v) - return v; - v = new_v; - } - } - - unsigned next(unsigned v) const { - if (v >= get_num_vars()) { - return v; - } - return m_next[v]; - } - - bool is_root(unsigned v) const { - return v >= get_num_vars() || m_find[v] == v; - } - - void merge(unsigned v1, unsigned v2) { - unsigned r1 = find(v1); - unsigned r2 = find(v2); - if (r1 == r2) - return; - ensure_size(v1); - ensure_size(v2); - if (m_size[r1] > m_size[r2]) - std::swap(r1, r2); - m_find[r1] = r2; - m_size[r2] += m_size[r1]; - std::swap(m_next[r1], m_next[r2]); - } - - void reset() { - m_find.reset(); - m_next.reset(); - m_size.reset(); - } - }; ast_manager& m; context& m_ctx; expr_safe_replace m_var2cnst; expr_safe_replace m_cnst2var; - union_find m_uf; + basic_union_find m_uf; ptr_vector m_todo; ptr_vector m_terms; ptr_vector m_binding; diff --git a/src/util/union_find.h b/src/util/union_find.h index 32de6846a..23d33a442 100644 --- a/src/util/union_find.h +++ b/src/util/union_find.h @@ -173,5 +173,71 @@ public: #endif }; + +class basic_union_find { + unsigned_vector m_find; + unsigned_vector m_size; + unsigned_vector m_next; + + void ensure_size(unsigned v) { + while (v >= get_num_vars()) { + mk_var(); + } + } + public: + unsigned mk_var() { + unsigned r = m_find.size(); + m_find.push_back(r); + m_size.push_back(1); + m_next.push_back(r); + return r; + } + unsigned get_num_vars() const { return m_find.size(); } + + unsigned find(unsigned v) const { + if (v >= get_num_vars()) { + return v; + } + while (true) { + unsigned new_v = m_find[v]; + if (new_v == v) + return v; + v = new_v; + } + } + + unsigned next(unsigned v) const { + if (v >= get_num_vars()) { + return v; + } + return m_next[v]; + } + + bool is_root(unsigned v) const { + return v >= get_num_vars() || m_find[v] == v; + } + + void merge(unsigned v1, unsigned v2) { + unsigned r1 = find(v1); + unsigned r2 = find(v2); + if (r1 == r2) + return; + ensure_size(v1); + ensure_size(v2); + if (m_size[r1] > m_size[r2]) + std::swap(r1, r2); + m_find[r1] = r2; + m_size[r2] += m_size[r1]; + std::swap(m_next[r1], m_next[r2]); + } + + void reset() { + m_find.reset(); + m_next.reset(); + m_size.reset(); + } +}; + + #endif /* _UNION_FIND_H_ */ From c969d7804235292fc919fbfd5061a0b3b918da15 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 21 May 2015 15:07:01 -0700 Subject: [PATCH 815/925] throw exception instead of debug mode assertion in ast_manager on malformed input Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 10 +++++++++- src/math/euclid/euclidean_solver.cpp | 2 +- src/smt/theory_arith_int.h | 4 ++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 86c23a799..4ae6b6106 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -2043,7 +2043,15 @@ inline app * ast_manager::mk_app_core(func_decl * decl, expr * arg1, expr * arg2 } app * ast_manager::mk_app(func_decl * decl, unsigned num_args, expr * const * args) { - SASSERT(decl->get_arity() == num_args || decl->is_right_associative() || decl->is_left_associative() || decl->is_chainable()); + if (decl->get_arity() != num_args && + !decl->is_right_associative() && + !decl->is_left_associative() && + !decl->is_chainable()) { + std::ostringstream buffer; + buffer << "Wrong number of arguments (" << num_args + << ") passed to function " << mk_pp(decl, *this); + throw ast_exception(buffer.str().c_str()); + } app * r = 0; if (num_args > 2 && !decl->is_flat_associative()) { if (decl->is_right_associative()) { diff --git a/src/math/euclid/euclidean_solver.cpp b/src/math/euclid/euclidean_solver.cpp index 718dbb052..02ff1591e 100644 --- a/src/math/euclid/euclidean_solver.cpp +++ b/src/math/euclid/euclidean_solver.cpp @@ -717,7 +717,7 @@ struct euclidean_solver::imp { elim_unit(); else decompose_and_elim(); - TRACE("euclidean_solver_step", display(tout);); + TRACE("euclidean_solver", display(tout);); if (inconsistent()) return false; } return true; diff --git a/src/smt/theory_arith_int.h b/src/smt/theory_arith_int.h index b600dd3c0..45c615e0c 100644 --- a/src/smt/theory_arith_int.h +++ b/src/smt/theory_arith_int.h @@ -1041,8 +1041,8 @@ namespace smt { num_args = 1; args = &n; } - for (unsigned j = 0; j < num_args; j++) { - expr * arg = args[j]; + for (unsigned i = 0; i < num_args; i++) { + expr * arg = args[i]; expr * pp; rational a_val; get_monomial(arg, a_val, pp); From 8a34bd2bf1c8d2b686f65f059c236884cab10d3f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 21 May 2015 15:08:39 -0700 Subject: [PATCH 816/925] fixes issue #88 Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 4ae6b6106..d56bb73ff 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -2043,10 +2043,8 @@ inline app * ast_manager::mk_app_core(func_decl * decl, expr * arg1, expr * arg2 } app * ast_manager::mk_app(func_decl * decl, unsigned num_args, expr * const * args) { - if (decl->get_arity() != num_args && - !decl->is_right_associative() && - !decl->is_left_associative() && - !decl->is_chainable()) { + if (decl->get_arity() != num_args && !decl->is_right_associative() && + !decl->is_left_associative() && !decl->is_chainable()) { std::ostringstream buffer; buffer << "Wrong number of arguments (" << num_args << ") passed to function " << mk_pp(decl, *this); From 705ace6f0a6722dff15dd7edfc77e162dd295b58 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 22 May 2015 11:39:08 +0100 Subject: [PATCH 817/925] Naming consistency --- src/util/hwf.cpp | 2 +- src/util/hwf.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/hwf.cpp b/src/util/hwf.cpp index b159cbdb6..ff92d57d0 100644 --- a/src/util/hwf.cpp +++ b/src/util/hwf.cpp @@ -306,7 +306,7 @@ void hwf_manager::div(mpf_rounding_mode rm, hwf const & x, hwf const & y, hwf & #pragma fp_contract(on) #endif -void hwf_manager::fused_mul_add(mpf_rounding_mode rm, hwf const & x, hwf const & y, hwf const &z, hwf & o) { +void hwf_manager::fma(mpf_rounding_mode rm, hwf const & x, hwf const & y, hwf const &z, hwf & o) { // CMW: fused_mul_add is not available on most CPUs. As of 2012, only Itanium, // Intel Sandybridge and AMD Bulldozers support that (via AVX). diff --git a/src/util/hwf.h b/src/util/hwf.h index 9059869a0..97b4133f7 100644 --- a/src/util/hwf.h +++ b/src/util/hwf.h @@ -105,7 +105,7 @@ public: void mul(mpf_rounding_mode rm, hwf const & x, hwf const & y, hwf & o); void div(mpf_rounding_mode rm, hwf const & x, hwf const & y, hwf & o); - void fused_mul_add(mpf_rounding_mode rm, hwf const & x, hwf const & y, hwf const &z, hwf & o); + void fma(mpf_rounding_mode rm, hwf const & x, hwf const & y, hwf const &z, hwf & o); void sqrt(mpf_rounding_mode rm, hwf const & x, hwf & o); From 759d9f2ddadfe2ce51bf356589fa372afa8485de Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 22 May 2015 11:39:28 +0100 Subject: [PATCH 818/925] bugfix for hwf::fma --- src/util/hwf.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/util/hwf.cpp b/src/util/hwf.cpp index ff92d57d0..3cbda74cd 100644 --- a/src/util/hwf.cpp +++ b/src/util/hwf.cpp @@ -315,11 +315,8 @@ void hwf_manager::fma(mpf_rounding_mode rm, hwf const & x, hwf const & y, hwf co set_rounding_mode(rm); o.value = x.value * y.value + z.value; #else - // NOT_IMPLEMENTED_YET(); - // Just a dummy for now: - hwf t; - mul(rm, x, y, t); - add(rm, t, z, o); + set_rounding_mode(rm); + o.value = ::fma(x.value, y.value, z.value); #endif } From 54cde7cabb1e66e706de440dffa6ee34d7e833dd Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 22 May 2015 11:39:58 +0100 Subject: [PATCH 819/925] Bugfix for hwf::round_to_integral --- src/util/hwf.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/util/hwf.cpp b/src/util/hwf.cpp index 3cbda74cd..5a41ac86c 100644 --- a/src/util/hwf.cpp +++ b/src/util/hwf.cpp @@ -340,7 +340,7 @@ void hwf_manager::round_to_integral(mpf_rounding_mode rm, hwf const & x, hwf & o // According to the Intel Architecture manual, the x87-instrunction FRNDINT is the // same in 32-bit and 64-bit mode. The _mm_round_* intrinsics are SSE4 extensions. - +#ifdef _WINDOWS #ifdef USE_INTRINSICS switch (rm) { case 0: _mm_store_sd(&o.value, _mm_round_pd(_mm_set_sd(x.value), _MM_FROUND_TO_NEAREST_INT)); break; @@ -354,10 +354,6 @@ void hwf_manager::round_to_integral(mpf_rounding_mode rm, hwf const & x, hwf & o UNREACHABLE(); // Unknown rounding mode. } #else - NOT_IMPLEMENTED_YET(); -#endif - -#if 0 double xv = x.value; double & ov = o.value; @@ -366,7 +362,10 @@ void hwf_manager::round_to_integral(mpf_rounding_mode rm, hwf const & x, hwf & o frndint fstp ov // Store result away. } - +#endif +#else + // Linux, OSX. + o.value = nearbyint(x.value); #endif } From ffbbf08d201cd7b6412328af901deaba05521aae Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 22 May 2015 11:59:31 +0100 Subject: [PATCH 820/925] Fixed warning message about unused lock when OpenMP is not available. --- src/util/mpn.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/util/mpn.h b/src/util/mpn.h index 495ae135c..f8cec0301 100644 --- a/src/util/mpn.h +++ b/src/util/mpn.h @@ -27,7 +27,9 @@ Revision History: typedef unsigned int mpn_digit; class mpn_manager { +#ifndef _NO_OMP omp_nest_lock_t m_lock; +#endif #define MPN_BEGIN_CRITICAL() omp_set_nest_lock(&m_lock); #define MPN_END_CRITICAL() omp_unset_nest_lock(&m_lock); From 891073d3fe8ce0066102b9822b3b3ee12752f39a Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 22 May 2015 12:01:10 +0100 Subject: [PATCH 821/925] typo --- src/util/mpn.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/mpn.h b/src/util/mpn.h index f8cec0301..c5566bf7e 100644 --- a/src/util/mpn.h +++ b/src/util/mpn.h @@ -27,7 +27,7 @@ Revision History: typedef unsigned int mpn_digit; class mpn_manager { -#ifndef _NO_OMP +#ifndef _NO_OMP_ omp_nest_lock_t m_lock; #endif #define MPN_BEGIN_CRITICAL() omp_set_nest_lock(&m_lock); From 8fc0ba0ab544a92e93033626c9744ce9e6c101a4 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 22 May 2015 12:33:53 +0100 Subject: [PATCH 822/925] Moved auxiliary fp.isNaN lemma injection to the right place. Fixes #102 --- src/ast/fpa/fpa2bv_converter.cpp | 7 ------- src/tactic/fpa/fpa2bv_tactic.cpp | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index cc0fef3c3..1d794c898 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -3044,13 +3044,6 @@ void fpa2bv_converter::mk_is_nan(expr * e, expr_ref & result) { m_simp.mk_not(sig_is_zero, sig_is_not_zero); m_simp.mk_eq(exp, top_exp, exp_is_top); m_simp.mk_and(exp_is_top, sig_is_not_zero, result); - - // Inject auxiliary lemmas that fix e to the one and only NaN value, - // that is (= e (fp #b0 #b1...1 #b0...01)), so that the value propagation - // has a value to propagate. - m_extra_assertions.push_back(m.mk_eq(sgn, m_bv_util.mk_numeral(0, 1))); - m_extra_assertions.push_back(m.mk_eq(exp, top_exp)); - m_extra_assertions.push_back(m.mk_eq(sig, m_bv_util.mk_numeral(1, m_bv_util.get_bv_size(sig)))); } void fpa2bv_converter::mk_is_inf(expr * e, expr_ref & result) { diff --git a/src/tactic/fpa/fpa2bv_tactic.cpp b/src/tactic/fpa/fpa2bv_tactic.cpp index 5fb35d972..9149f1b9a 100644 --- a/src/tactic/fpa/fpa2bv_tactic.cpp +++ b/src/tactic/fpa/fpa2bv_tactic.cpp @@ -88,6 +88,22 @@ class fpa2bv_tactic : public tactic { new_pr = m.mk_modus_ponens(pr, new_pr); } g->update(idx, new_curr, new_pr, g->dep(idx)); + + if (is_app(new_curr)) { + const app * a = to_app(new_curr.get()); + if (a->get_family_id() == m_conv.fu().get_family_id() && + a->get_decl_kind() == OP_FPA_IS_NAN) { + // Inject auxiliary lemmas that fix e to the one and only NaN value, + // that is (= e (fp #b0 #b1...1 #b0...01)), so that the value propagation + // has a value to propagate. + expr * sgn, *sig, *exp; + expr_ref top_exp(m); + m_conv.split_fp(new_curr, sgn, exp, sig); + m.mk_eq(sgn, m_conv.bu().mk_numeral(0, 1)); + m.mk_eq(exp, m_conv.bu().mk_numeral(-1, m_conv.bu().get_bv_size(exp))); + m.mk_eq(sig, m_conv.bu().mk_numeral(1, m_conv.bu().get_bv_size(sig))); + } + } } if (g->models_enabled()) From a229416a2bd12ec4beb9b638d8da65aecc9af645 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcus=20V=C3=B6lker?= Date: Fri, 22 May 2015 15:55:09 +0200 Subject: [PATCH 823/925] Change ASTVector to Expr[] in interpolation result --- src/api/java/InterpolationContext.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/api/java/InterpolationContext.java b/src/api/java/InterpolationContext.java index 667c91a53..25f132fa7 100644 --- a/src/api/java/InterpolationContext.java +++ b/src/api/java/InterpolationContext.java @@ -90,7 +90,7 @@ public class InterpolationContext extends Context public class ComputeInterpolantResult { public Z3_lbool status = Z3_lbool.Z3_L_UNDEF; - public ASTVector interp = null; + public Expr[] interp = null; public Model model = null; }; @@ -110,7 +110,14 @@ public class InterpolationContext extends Context Native.LongPtr n_i = new Native.LongPtr(); Native.LongPtr n_m = new Native.LongPtr(); res.status =Z3_lbool.fromInt(Native.computeInterpolant(nCtx(), pat.getNativeObject(), p.getNativeObject(), n_i, n_m)); - if (res.status == Z3_lbool.Z3_L_FALSE) res.interp = new ASTVector(this, n_i.value); + if (res.status == Z3_lbool.Z3_L_FALSE) + { + ASTVector seq = new ASTVector(this, n_i.value); + int n = seq.size(); + res.interp = new Expr[n]; + for (int i = 0; i < n; i++) + res.interp[i] = Expr.create(this, seq.get(i).getNativeObject()); + } if (res.status == Z3_lbool.Z3_L_TRUE) res.model = new Model(this, n_m.value); return res; } From b4f72c81457712929405f397b89c02bd8ca264c3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 22 May 2015 08:24:45 -0700 Subject: [PATCH 824/925] Revert "Change ASTVector to Expr[] in interpolation result" --- src/api/java/InterpolationContext.java | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/api/java/InterpolationContext.java b/src/api/java/InterpolationContext.java index 25f132fa7..667c91a53 100644 --- a/src/api/java/InterpolationContext.java +++ b/src/api/java/InterpolationContext.java @@ -90,7 +90,7 @@ public class InterpolationContext extends Context public class ComputeInterpolantResult { public Z3_lbool status = Z3_lbool.Z3_L_UNDEF; - public Expr[] interp = null; + public ASTVector interp = null; public Model model = null; }; @@ -110,14 +110,7 @@ public class InterpolationContext extends Context Native.LongPtr n_i = new Native.LongPtr(); Native.LongPtr n_m = new Native.LongPtr(); res.status =Z3_lbool.fromInt(Native.computeInterpolant(nCtx(), pat.getNativeObject(), p.getNativeObject(), n_i, n_m)); - if (res.status == Z3_lbool.Z3_L_FALSE) - { - ASTVector seq = new ASTVector(this, n_i.value); - int n = seq.size(); - res.interp = new Expr[n]; - for (int i = 0; i < n; i++) - res.interp[i] = Expr.create(this, seq.get(i).getNativeObject()); - } + if (res.status == Z3_lbool.Z3_L_FALSE) res.interp = new ASTVector(this, n_i.value); if (res.status == Z3_lbool.Z3_L_TRUE) res.model = new Model(this, n_m.value); return res; } From 279ef05713462237e427dc96192d911a9cb18dbc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 22 May 2015 08:57:05 -0700 Subject: [PATCH 825/925] expose BoolExpr[] for ASTVector and merge common functionality Signed-off-by: Nikolaj Bjorner --- src/api/java/ASTVector.java | 8 ++++++++ src/api/java/Fixedpoint.java | 12 ++---------- src/api/java/InterpolationContext.java | 8 +++++--- src/api/java/Solver.java | 6 +----- 4 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/api/java/ASTVector.java b/src/api/java/ASTVector.java index 9c6504493..e08a75e7f 100644 --- a/src/api/java/ASTVector.java +++ b/src/api/java/ASTVector.java @@ -119,4 +119,12 @@ public class ASTVector extends Z3Object getContext().getASTVectorDRQ().add(o); super.decRef(o); } + + BoolExpr[] ToBoolArray() { + int n = size(); + BoolExpr[] res = new BoolExpr[n]; + for (int i = 0; i < n; i++) + res[i] = new BoolExpr(getContext(), get(i).getNativeObject()); + return res; + } } diff --git a/src/api/java/Fixedpoint.java b/src/api/java/Fixedpoint.java index c9d14288b..daa0f4e3f 100644 --- a/src/api/java/Fixedpoint.java +++ b/src/api/java/Fixedpoint.java @@ -298,11 +298,7 @@ public class Fixedpoint extends Z3Object ASTVector v = new ASTVector(getContext(), Native.fixedpointGetRules( getContext().nCtx(), getNativeObject())); - int n = v.size(); - BoolExpr[] res = new BoolExpr[n]; - for (int i = 0; i < n; i++) - res[i] = new BoolExpr(getContext(), v.get(i).getNativeObject()); - return res; + return v.ToBoolArray(); } /** @@ -315,11 +311,7 @@ public class Fixedpoint extends Z3Object ASTVector v = new ASTVector(getContext(), Native.fixedpointGetAssertions( getContext().nCtx(), getNativeObject())); - int n = v.size(); - BoolExpr[] res = new BoolExpr[n]; - for (int i = 0; i < n; i++) - res[i] = new BoolExpr(getContext(), v.get(i).getNativeObject()); - return res; + return v.ToBoolArray(); } /** diff --git a/src/api/java/InterpolationContext.java b/src/api/java/InterpolationContext.java index 667c91a53..50c6a223a 100644 --- a/src/api/java/InterpolationContext.java +++ b/src/api/java/InterpolationContext.java @@ -90,7 +90,7 @@ public class InterpolationContext extends Context public class ComputeInterpolantResult { public Z3_lbool status = Z3_lbool.Z3_L_UNDEF; - public ASTVector interp = null; + public BoolExpr[] interp = null; public Model model = null; }; @@ -109,8 +109,10 @@ public class InterpolationContext extends Context ComputeInterpolantResult res = new ComputeInterpolantResult(); Native.LongPtr n_i = new Native.LongPtr(); Native.LongPtr n_m = new Native.LongPtr(); - res.status =Z3_lbool.fromInt(Native.computeInterpolant(nCtx(), pat.getNativeObject(), p.getNativeObject(), n_i, n_m)); - if (res.status == Z3_lbool.Z3_L_FALSE) res.interp = new ASTVector(this, n_i.value); + res.status = Z3_lbool.fromInt(Native.computeInterpolant(nCtx(), pat.getNativeObject(), p.getNativeObject(), n_i, n_m)); + if (res.status == Z3_lbool.Z3_L_FALSE) { + res.interp = (new ASTVector(this, n_i.value)).ToBoolArray(); + } if (res.status == Z3_lbool.Z3_L_TRUE) res.model = new Model(this, n_m.value); return res; } diff --git a/src/api/java/Solver.java b/src/api/java/Solver.java index e4ba9de42..7c4c1f4b9 100644 --- a/src/api/java/Solver.java +++ b/src/api/java/Solver.java @@ -190,11 +190,7 @@ public class Solver extends Z3Object { ASTVector assrts = new ASTVector(getContext(), Native.solverGetAssertions( getContext().nCtx(), getNativeObject())); - int n = assrts.size(); - BoolExpr[] res = new BoolExpr[n]; - for (int i = 0; i < n; i++) - res[i] = new BoolExpr(getContext(), assrts.get(i).getNativeObject()); - return res; + return assrts.ToBoolArray(); } /** From 13a3bdd7a3589c0a7e8b622acfba20e542c2f2b8 Mon Sep 17 00:00:00 2001 From: Ken McMillan Date: Fri, 22 May 2015 10:28:19 -0700 Subject: [PATCH 826/925] fix proof for extended GCD rule --- src/smt/theory_arith_int.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_arith_int.h b/src/smt/theory_arith_int.h index b600dd3c0..7c9e67da6 100644 --- a/src/smt/theory_arith_int.h +++ b/src/smt/theory_arith_int.h @@ -777,8 +777,8 @@ namespace smt { // u += ncoeff * lower_bound(v).get_rational(); u.addmul(ncoeff, lower_bound(v).get_rational()); } - lower(v)->push_justification(ante, numeral::zero(), coeffs_enabled()); - upper(v)->push_justification(ante, numeral::zero(), coeffs_enabled()); + lower(v)->push_justification(ante, it->m_coeff, coeffs_enabled()); + upper(v)->push_justification(ante, it->m_coeff, coeffs_enabled()); } else if (gcds.is_zero()) { gcds = abs_ncoeff; From e438143abce11f3217b275c916307a9cb14ca51e Mon Sep 17 00:00:00 2001 From: Ken McMillan Date: Fri, 22 May 2015 11:02:26 -0700 Subject: [PATCH 827/925] fix for github issue #105 --- src/interp/iz3translate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/interp/iz3translate.cpp b/src/interp/iz3translate.cpp index f510f4070..2debdaf42 100755 --- a/src/interp/iz3translate.cpp +++ b/src/interp/iz3translate.cpp @@ -966,7 +966,7 @@ public: get_linear_coefficients(t,coeffs); if(coeffs.size() == 0) return make_int("1"); // arbitrary - rational d = coeffs[0]; + rational d = abs(coeffs[0]); for(unsigned i = 1; i < coeffs.size(); i++){ d = gcd(d,coeffs[i]); } From 6f6cd61817a1f5767be5f84a625c12ff14332a79 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 22 May 2015 20:30:12 +0100 Subject: [PATCH 828/925] Bugfix for float-to-float conversion. Fixes #77 --- src/ast/fpa/fpa2bv_converter.cpp | 116 ++++++++++++++++++++----------- src/util/mpf.cpp | 2 +- 2 files changed, 78 insertions(+), 40 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 1d794c898..2c32e7f1a 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -48,19 +48,31 @@ void fpa2bv_converter::mk_eq(expr * a, expr * b, expr_ref & result) { SASSERT(is_app_of(a, m_plugin->get_family_id(), OP_FPA_FP)); SASSERT(is_app_of(b, m_plugin->get_family_id(), OP_FPA_FP)); - expr_ref sgn(m), s(m), e(m); - m_simp.mk_eq(to_app(a)->get_arg(0), to_app(b)->get_arg(0), sgn); - m_simp.mk_eq(to_app(a)->get_arg(1), to_app(b)->get_arg(1), e); - m_simp.mk_eq(to_app(a)->get_arg(2), to_app(b)->get_arg(2), s); + TRACE("fpa2bv", tout << "mk_eq a=" << mk_ismt2_pp(a, m) << std::endl; + tout << "mk_eq b=" << mk_ismt2_pp(b, m) << std::endl;); + + expr_ref eq_sgn(m), eq_exp(m), eq_sig(m); + m_simp.mk_eq(to_app(a)->get_arg(0), to_app(b)->get_arg(0), eq_sgn); + m_simp.mk_eq(to_app(a)->get_arg(1), to_app(b)->get_arg(1), eq_exp); + m_simp.mk_eq(to_app(a)->get_arg(2), to_app(b)->get_arg(2), eq_sig); + + dbg_decouple("fpa2bv_eq_sgn", eq_sgn); + dbg_decouple("fpa2bv_eq_exp", eq_exp); + dbg_decouple("fpa2bv_eq_sig", eq_sig); + + expr_ref both_the_same(m); + m_simp.mk_and(eq_sgn, eq_exp, eq_sig, both_the_same); + dbg_decouple("fpa2bv_eq_both_the_same", both_the_same); // The SMT FPA theory asks for _one_ NaN value, but the bit-blasting // has many, like IEEE754. This encoding of equality makes it look like // a single NaN again. - expr_ref both_the_same(m), a_is_nan(m), b_is_nan(m), both_are_nan(m); - m_simp.mk_and(sgn, s, e, both_the_same); + expr_ref a_is_nan(m), b_is_nan(m), both_are_nan(m); mk_is_nan(a, a_is_nan); mk_is_nan(b, b_is_nan); m_simp.mk_and(a_is_nan, b_is_nan, both_are_nan); + dbg_decouple("fpa2bv_eq_both_are_nan", both_are_nan); + m_simp.mk_or(both_are_nan, both_the_same, result); } @@ -2051,6 +2063,7 @@ void fpa2bv_converter::mk_to_fp_float(func_decl * f, sort * s, expr * rm, expr * expr_ref sgn(m), sig(m), exp(m), lz(m); unpack(x, sgn, sig, exp, lz, true); + dbg_decouple("fpa2bv_to_float_x_sgn", sgn); dbg_decouple("fpa2bv_to_float_x_sig", sig); dbg_decouple("fpa2bv_to_float_x_exp", exp); dbg_decouple("fpa2bv_to_float_lz", lz); @@ -2068,13 +2081,17 @@ void fpa2bv_converter::mk_to_fp_float(func_decl * f, sort * s, expr * rm, expr * // make sure that sig has at least to_sbits + 3 res_sig = m_bv_util.mk_concat(sig, m_bv_util.mk_numeral(0, to_sbits + 3 - from_sbits)); } - else if (from_sbits >(to_sbits + 3)) { + else if (from_sbits > (to_sbits + 3)) { // collapse the extra bits into a sticky bit. expr_ref sticky(m), low(m), high(m); - low = m_bv_util.mk_extract(from_sbits - to_sbits - 3, 0, sig); high = m_bv_util.mk_extract(from_sbits - 1, from_sbits - to_sbits - 2, sig); + SASSERT(m_bv_util.get_bv_size(high) == to_sbits + 2); + low = m_bv_util.mk_extract(from_sbits - to_sbits - 3, 0, sig); sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, low.get()); - res_sig = m_bv_util.mk_concat(high, sticky); + SASSERT(m_bv_util.get_bv_size(sticky) == 1); + dbg_decouple("fpa2bv_to_float_sticky", sticky); + res_sig = m_bv_util.mk_concat(high, sticky); + SASSERT(m_bv_util.get_bv_size(res_sig) == to_sbits + 3); } else res_sig = sig; @@ -2083,8 +2100,9 @@ void fpa2bv_converter::mk_to_fp_float(func_decl * f, sort * s, expr * rm, expr * unsigned sig_sz = m_bv_util.get_bv_size(res_sig); SASSERT(sig_sz == to_sbits + 4); - expr_ref exponent_overflow(m); + expr_ref exponent_overflow(m), exponent_underflow(m); exponent_overflow = m.mk_false(); + exponent_underflow = m.mk_false(); if (from_ebits < (to_ebits + 2)) { res_exp = m_bv_util.mk_sign_extend(to_ebits - from_ebits + 2, exp); @@ -2094,37 +2112,58 @@ void fpa2bv_converter::mk_to_fp_float(func_decl * f, sort * s, expr * rm, expr * lz_ext = m_bv_util.mk_zero_extend(to_ebits - from_ebits + 2, lz); res_exp = m_bv_util.mk_bv_sub(res_exp, lz_ext); } - else if (from_ebits >(to_ebits + 2)) { - expr_ref high(m), low(m), lows(m), high_red_or(m), high_red_and(m), h_or_eq(m), h_and_eq(m); - expr_ref no_ovf(m), zero1(m), s_is_one(m), s_is_zero(m); - high = m_bv_util.mk_extract(from_ebits - 1, to_ebits + 2, exp); - low = m_bv_util.mk_extract(to_ebits + 1, 0, exp); - lows = m_bv_util.mk_extract(to_ebits + 1, to_ebits + 1, low); - - high_red_or = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, high.get()); - high_red_and = m.mk_app(m_bv_util.get_fid(), OP_BREDAND, high.get()); - - zero1 = m_bv_util.mk_numeral(0, 1); - m_simp.mk_eq(high_red_and, one1, h_and_eq); - m_simp.mk_eq(high_red_or, zero1, h_or_eq); - m_simp.mk_eq(lows, zero1, s_is_zero); - m_simp.mk_eq(lows, one1, s_is_one); - - expr_ref c2(m); - m_simp.mk_ite(h_or_eq, s_is_one, m.mk_false(), c2); - m_simp.mk_ite(h_and_eq, s_is_zero, c2, exponent_overflow); - - // Note: Upon overflow, we _could_ try to shift the significand around... - - // subtract lz for subnormal numbers. - expr_ref lz_ext(m), lz_rest(m), lz_redor(m), lz_redor_bool(m); - lz_ext = m_bv_util.mk_extract(to_ebits + 1, 0, lz); + else if (from_ebits > (to_ebits + 2)) { + expr_ref lz_rest(m), lz_redor(m), lz_redor_bool(m); lz_rest = m_bv_util.mk_extract(from_ebits - 1, to_ebits + 2, lz); lz_redor = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, lz_rest.get()); m_simp.mk_eq(lz_redor, one1, lz_redor_bool); - m_simp.mk_or(exponent_overflow, lz_redor_bool, exponent_overflow); + dbg_decouple("fpa2bv_to_float_exp_lz_redor", lz_redor); - res_exp = m_bv_util.mk_bv_sub(low, lz_ext); + // subtract lz for subnormal numbers. + expr_ref exp_sub_lz(m); + exp_sub_lz = m_bv_util.mk_bv_sub(exp, lz); + dbg_decouple("fpa2bv_to_float_exp_sub_lz", exp_sub_lz); + + expr_ref high(m), low(m), low_msb(m); + expr_ref no_ovf(m), zero1(m); + high = m_bv_util.mk_extract(from_ebits - 1, to_ebits + 2, exp_sub_lz); + low = m_bv_util.mk_extract(to_ebits + 1, 0, exp_sub_lz); + low_msb = m_bv_util.mk_extract(to_ebits + 1, to_ebits + 1, low); + dbg_decouple("fpa2bv_to_float_exp_high", high); + dbg_decouple("fpa2bv_to_float_exp_low", low); + dbg_decouple("fpa2bv_to_float_exp_low_msb", low_msb); + + res_exp = low; + + expr_ref high_red_or(m), high_red_and(m); + high_red_or = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, high.get()); + high_red_and = m.mk_app(m_bv_util.get_fid(), OP_BREDAND, high.get()); + + expr_ref h_or_eq_0(m), h_and_eq_1(m), low_msb_is_one(m), low_msb_is_zero(m); + zero1 = m_bv_util.mk_numeral(0, 1); + m_simp.mk_eq(high_red_and, one1, h_and_eq_1); + m_simp.mk_eq(high_red_or, zero1, h_or_eq_0); + m_simp.mk_eq(low_msb, zero1, low_msb_is_zero); + m_simp.mk_eq(low_msb, one1, low_msb_is_one); + dbg_decouple("fpa2bv_to_float_exp_h_and_eq_1", h_and_eq_1); + dbg_decouple("fpa2bv_to_float_exp_h_or_eq_0", h_or_eq_0); + dbg_decouple("fpa2bv_to_float_exp_s_is_zero", low_msb_is_zero); + dbg_decouple("fpa2bv_to_float_exp_s_is_one", low_msb_is_one); + + m_simp.mk_and(h_or_eq_0, low_msb_is_one, exponent_underflow); + m_simp.mk_and(h_and_eq_1, low_msb_is_zero, exponent_overflow); + m_simp.mk_or(exponent_overflow, lz_redor_bool, exponent_overflow); + dbg_decouple("fpa2bv_to_float_exp_ovf", exponent_overflow); + dbg_decouple("fpa2bv_to_float_exp_udf", exponent_underflow); + + // exponent underflow means that the result is the smallest + // representable float, rounded according to rm. + m_simp.mk_ite(exponent_underflow, + m_bv_util.mk_concat(m_bv_util.mk_numeral(1, 1), + m_bv_util.mk_numeral(1, to_ebits+1)), + res_exp, + res_exp); + m_simp.mk_ite(exponent_underflow, m_bv_util.mk_numeral(1, to_sbits+4), res_sig, res_sig); } else // from_ebits == (to_ebits + 2) res_exp = m_bv_util.mk_bv_sub(exp, lz); @@ -2143,8 +2182,7 @@ void fpa2bv_converter::mk_to_fp_float(func_decl * f, sort * s, expr * rm, expr * m_simp.mk_eq(sgn, one1, is_neg); mk_ite(is_neg, ninf, pinf, sig_inf); - dbg_decouple("fpa2bv_to_float_exp_ovf", exponent_overflow); - mk_ite(exponent_overflow, sig_inf, rounded, v6); + mk_ite(exponent_overflow, sig_inf, rounded, v6); // And finally, we tie them together. mk_ite(c5, v5, v6, result); diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index e66f6d270..1521a8f87 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -348,7 +348,7 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode bool sticky = false; while (ds < 0) { - if (!m_mpz_manager.is_even(o.significand)) sticky = true; + sticky |= m_mpz_manager.is_odd(o.significand); m_mpz_manager.machine_div2k(o.significand, 1); ds++; } From c577ab361b0b668434726316b86afe961013b82b Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Sat, 23 May 2015 11:45:12 +0100 Subject: [PATCH 829/925] fix assorted undefined behaviors caught by clang Signed-off-by: Nuno Lopes --- src/ast/ast.cpp | 9 ++++++--- src/math/polynomial/polynomial.cpp | 1 + src/smt/smt_justification.cpp | 3 ++- src/util/hash.cpp | 2 +- src/util/inf_int_rational.cpp | 25 ++++++++++++++++++++++--- src/util/inf_int_rational.h | 6 ++++-- src/util/inf_rational.cpp | 30 +++++++++++++++++++++++++----- src/util/inf_rational.h | 10 ++++++---- src/util/rational.cpp | 16 ++++++++++++++-- 9 files changed, 81 insertions(+), 21 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index d56bb73ff..59efb2a89 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -316,7 +316,8 @@ func_decl::func_decl(symbol const & name, unsigned arity, sort * const * domain, decl(AST_FUNC_DECL, name, info), m_arity(arity), m_range(range) { - memcpy(const_cast(get_domain()), domain, sizeof(sort *) * arity); + if (arity != 0) + memcpy(const_cast(get_domain()), domain, sizeof(sort *) * arity); } // ----------------------------------- @@ -378,8 +379,10 @@ quantifier::quantifier(bool forall, unsigned num_decls, sort * const * decl_sort memcpy(const_cast(get_decl_sorts()), decl_sorts, sizeof(sort *) * num_decls); memcpy(const_cast(get_decl_names()), decl_names, sizeof(symbol) * num_decls); - memcpy(const_cast(get_patterns()), patterns, sizeof(expr *) * num_patterns); - memcpy(const_cast(get_no_patterns()), no_patterns, sizeof(expr *) * num_no_patterns); + if (num_patterns != 0) + memcpy(const_cast(get_patterns()), patterns, sizeof(expr *) * num_patterns); + if (num_no_patterns != 0) + memcpy(const_cast(get_no_patterns()), no_patterns, sizeof(expr *) * num_no_patterns); } // ----------------------------------- diff --git a/src/math/polynomial/polynomial.cpp b/src/math/polynomial/polynomial.cpp index 8f4c55392..638c83642 100644 --- a/src/math/polynomial/polynomial.cpp +++ b/src/math/polynomial/polynomial.cpp @@ -542,6 +542,7 @@ namespace polynomial { increase_capacity(sz * 2); SASSERT(sz < m_capacity); m_ptr->m_size = sz; + if (sz == 0) return; memcpy(m_ptr->m_powers, pws, sizeof(power) * sz); } diff --git a/src/smt/smt_justification.cpp b/src/smt/smt_justification.cpp index 81f496187..de3594fcc 100644 --- a/src/smt/smt_justification.cpp +++ b/src/smt/smt_justification.cpp @@ -308,7 +308,8 @@ namespace smt { simple_justification(r, num_lits, lits), m_num_eqs(num_eqs) { m_eqs = new (r) enode_pair[num_eqs]; - memcpy(m_eqs, eqs, sizeof(enode_pair) * num_eqs); + if (num_eqs != 0) + memcpy(m_eqs, eqs, sizeof(enode_pair) * num_eqs); DEBUG_CODE({ for (unsigned i = 0; i < num_eqs; i++) { SASSERT(eqs[i].first->get_root() == eqs[i].second->get_root()); diff --git a/src/util/hash.cpp b/src/util/hash.cpp index 8b7530376..41c4db584 100644 --- a/src/util/hash.cpp +++ b/src/util/hash.cpp @@ -23,7 +23,7 @@ Revision History: // I'm using Bob Jenkin's hash function. // http://burtleburtle.net/bob/hash/doobs.html unsigned string_hash(const char * str, unsigned length, unsigned init_value) { - register unsigned a, b, c, len; + unsigned a, b, c, len; /* Set up the internal state */ len = length; diff --git a/src/util/inf_int_rational.cpp b/src/util/inf_int_rational.cpp index 54a838a75..7bc68e641 100644 --- a/src/util/inf_int_rational.cpp +++ b/src/util/inf_int_rational.cpp @@ -19,9 +19,9 @@ Revision History: #include #include"inf_int_rational.h" -inf_int_rational inf_int_rational::m_zero(0); -inf_int_rational inf_int_rational::m_one(1); -inf_int_rational inf_int_rational::m_minus_one(-1); +inf_int_rational inf_int_rational::m_zero; +inf_int_rational inf_int_rational::m_one; +inf_int_rational inf_int_rational::m_minus_one; std::string inf_int_rational::to_string() const { if (m_second == 0) { @@ -39,3 +39,22 @@ std::string inf_int_rational::to_string() const { return s.str(); } +void initialize_inf_int_rational() { + inf_int_rational::init(); +} + +void inf_int_rational::init() { + m_zero.m_first = rational::zero(); + m_one.m_first = rational::one(); + m_minus_one.m_first = rational::minus_one(); +} + +void finalize_inf_int_rational() { + inf_int_rational::finalize(); +} + +void inf_int_rational::finalize() { + m_zero.~inf_int_rational(); + m_one.~inf_int_rational(); + m_minus_one.~inf_int_rational(); +} diff --git a/src/util/inf_int_rational.h b/src/util/inf_int_rational.h index b1b1fb89f..06cbc1267 100644 --- a/src/util/inf_int_rational.h +++ b/src/util/inf_int_rational.h @@ -33,6 +33,8 @@ class inf_int_rational { rational m_first; int m_second; public: + static void init(); // called from rational::initialize() only + static void finalize(); // called from rational::finalize() only unsigned hash() const { return m_first.hash() ^ (static_cast(m_second) + 1); @@ -272,7 +274,7 @@ class inf_int_rational { if (r.m_second >= 0) { return r.m_first; } - return r.m_first - rational(1); + return r.m_first - rational::one(); } return floor(r.m_first); @@ -283,7 +285,7 @@ class inf_int_rational { if (r.m_second <= 0) { return r.m_first; } - return r.m_first + rational(1); + return r.m_first + rational::one(); } return ceil(r.m_first); diff --git a/src/util/inf_rational.cpp b/src/util/inf_rational.cpp index 3837d2c15..0b043e94d 100644 --- a/src/util/inf_rational.cpp +++ b/src/util/inf_rational.cpp @@ -18,9 +18,9 @@ Revision History: --*/ #include"inf_rational.h" -inf_rational inf_rational::m_zero(0); -inf_rational inf_rational::m_one(1); -inf_rational inf_rational::m_minus_one(-1); +inf_rational inf_rational::m_zero; +inf_rational inf_rational::m_one; +inf_rational inf_rational::m_minus_one; inf_rational inf_mult(inf_rational const& r1, inf_rational const& r2) { @@ -128,7 +128,7 @@ inf_rational inf_power(inf_rational const& r, unsigned n) // 0 will work. } else if (r.m_first.is_zero()) { - result.m_first = rational(-1); + result.m_first = rational::minus_one(); } else if (r.m_first.is_pos()) { result.m_first = rational(r.m_first - r.m_first/rational(2)).expt(n); @@ -152,7 +152,7 @@ inf_rational sup_power(inf_rational const& r, unsigned n) result.m_first = r.m_first.expt(n); } else if (r.m_first.is_zero() || (n == 0)) { - result.m_first = rational(1); + result.m_first = rational::one(); } else if (r.m_first.is_pos() || is_even) { result.m_first = rational(r.m_first + r.m_first/rational(2)).expt(n); @@ -177,3 +177,23 @@ inf_rational sup_root(inf_rational const& r, unsigned n) // use r. return r; } + +void initialize_inf_rational() { + inf_rational::init(); +} + +void inf_rational::init() { + m_zero.m_first = rational::zero(); + m_one.m_first = rational::one(); + m_minus_one.m_first = rational::minus_one(); +} + +void finalize_inf_rational() { + inf_rational::finalize(); +} + +void inf_rational::finalize() { + m_zero.~inf_rational(); + m_one.~inf_rational(); + m_minus_one.~inf_rational(); +} diff --git a/src/util/inf_rational.h b/src/util/inf_rational.h index e1060a7b0..b832b8793 100644 --- a/src/util/inf_rational.h +++ b/src/util/inf_rational.h @@ -33,6 +33,8 @@ class inf_rational { rational m_first; rational m_second; public: + static void init(); // called from rational::initialize() only + static void finalize(); // called from rational::finalize() only unsigned hash() const { return m_first.hash() ^ (m_second.hash()+1); @@ -40,7 +42,7 @@ class inf_rational { struct hash_proc { unsigned operator()(inf_rational const& r) const { return r.hash(); } }; - struct eq_proc { bool operator()(inf_rational const& r1, inf_rational const& r2) const { return r1 == r2; } }; + struct eq_proc { bool operator()(inf_rational const& r1, inf_rational const& r2) const { return r1 == r2; } }; void swap(inf_rational & n) { m_first.swap(n.m_first); @@ -82,7 +84,7 @@ class inf_rational { explicit inf_rational(rational const& r, bool pos_inf): m_first(r), - m_second(pos_inf?rational(1):rational(-1)) + m_second(pos_inf ? rational::one() : rational::minus_one()) {} inf_rational(rational const& r): @@ -313,7 +315,7 @@ class inf_rational { if (r.m_second.is_nonneg()) { return r.m_first; } - return r.m_first - rational(1); + return r.m_first - rational::one(); } return floor(r.m_first); @@ -324,7 +326,7 @@ class inf_rational { if (r.m_second.is_nonpos()) { return r.m_first; } - return r.m_first + rational(1); + return r.m_first + rational::one(); } return ceil(r.m_first); diff --git a/src/util/rational.cpp b/src/util/rational.cpp index 743038972..43dc9110a 100644 --- a/src/util/rational.cpp +++ b/src/util/rational.cpp @@ -29,9 +29,9 @@ rational rational::m_one; rational rational::m_minus_one; vector rational::m_powers_of_two; -void mk_power_up_to(vector & pws, unsigned n) { +static void mk_power_up_to(vector & pws, unsigned n) { if (pws.empty()) { - pws.push_back(rational(1)); + pws.push_back(rational::one()); } unsigned sz = pws.size(); rational curr = pws[sz - 1]; @@ -53,16 +53,28 @@ rational rational::power_of_two(unsigned k) { return result; } +// in inf_rational.cpp +void initialize_inf_rational(); +void finalize_inf_rational(); + +// in inf_int_rational.cpp +void initialize_inf_int_rational(); +void finalize_inf_int_rational(); + void rational::initialize() { if (!g_mpq_manager) { g_mpq_manager = alloc(synch_mpq_manager); m().set(m_zero.m_val, 0); m().set(m_one.m_val, 1); m().set(m_minus_one.m_val, -1); + initialize_inf_rational(); + initialize_inf_int_rational(); } } void rational::finalize() { + finalize_inf_rational(); + finalize_inf_int_rational(); m_powers_of_two.finalize(); m_zero.~rational(); m_one.~rational(); From d5c39798ea455262bf31b86d87d00ca08af61895 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 23 May 2015 12:02:53 +0100 Subject: [PATCH 830/925] Bugfix for hwf --- src/util/hwf.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/util/hwf.cpp b/src/util/hwf.cpp index 5a41ac86c..94255bb84 100644 --- a/src/util/hwf.cpp +++ b/src/util/hwf.cpp @@ -17,16 +17,15 @@ Revision History: --*/ #include +#include #ifdef _WINDOWS #pragma float_control( except, on ) // exception semantics; this does _not_ mean that exceptions are enabled (we want them off!) #pragma float_control( precise, on ) // precise semantics (no guessing!) #pragma fp_contract(off) // contractions off (`contraction' means x*y+z is turned into a fused-mul-add). #pragma fenv_access(on) // fpu environment sensitivity (needed to be allowed to make FPU mode changes). +#include #else -#ifdef _WINDOWS -#pragma STDC FENV_ACCESS ON -#endif #include #include #endif @@ -35,8 +34,6 @@ Revision History: #define USE_INTRINSICS #endif -#include - #include"hwf.h" // Note: From 08b563532788bef18c70ec5980eabf45c8eaa6b2 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Sat, 23 May 2015 12:13:39 +0100 Subject: [PATCH 831/925] fix unaligned load in hash_string() Signed-off-by: Nuno Lopes --- src/test/polynomial_factorization.cpp | 3 ++- src/util/hash.cpp | 14 +++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/test/polynomial_factorization.cpp b/src/test/polynomial_factorization.cpp index 06c67b9c2..7af0742ef 100644 --- a/src/test/polynomial_factorization.cpp +++ b/src/test/polynomial_factorization.cpp @@ -24,7 +24,8 @@ Notes: #include"polynomial_factorization.h" #endif -using namespace std; +using std::cout; +using std::endl; // some prime numbers unsigned primes[] = { diff --git a/src/util/hash.cpp b/src/util/hash.cpp index 41c4db584..bb5ca0a41 100644 --- a/src/util/hash.cpp +++ b/src/util/hash.cpp @@ -19,6 +19,13 @@ Revision History: #include"debug.h" #include"hash.h" +#include + +static unsigned read_unsigned(const char *s) { + unsigned n; + memcpy(&n, s, sizeof(unsigned)); + return n; +} // I'm using Bob Jenkin's hash function. // http://burtleburtle.net/bob/hash/doobs.html @@ -31,10 +38,11 @@ unsigned string_hash(const char * str, unsigned length, unsigned init_value) { c = init_value; /* the previous hash value */ /*---------------------------------------- handle most of the key */ + SASSERT(sizeof(unsigned) == 4); while (len >= 12) { - a += reinterpret_cast(str)[0]; - b += reinterpret_cast(str)[1]; - c += reinterpret_cast(str)[2]; + a += read_unsigned(str); + b += read_unsigned(str+4); + c += read_unsigned(str+8); mix(a,b,c); str += 12; len -= 12; } From 98f33c3f8b8c5fc64679656dad99798afa21c38c Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 23 May 2015 13:10:07 +0100 Subject: [PATCH 832/925] Bug/build fix for hwf::fma --- src/util/hwf.cpp | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/util/hwf.cpp b/src/util/hwf.cpp index 94255bb84..21f1c281f 100644 --- a/src/util/hwf.cpp +++ b/src/util/hwf.cpp @@ -16,6 +16,7 @@ Author: Revision History: --*/ +#include #include #include @@ -24,10 +25,8 @@ Revision History: #pragma float_control( precise, on ) // precise semantics (no guessing!) #pragma fp_contract(off) // contractions off (`contraction' means x*y+z is turned into a fused-mul-add). #pragma fenv_access(on) // fpu environment sensitivity (needed to be allowed to make FPU mode changes). -#include #else -#include -#include +#include #endif #ifndef _M_IA64 @@ -54,7 +53,7 @@ Revision History: hwf_manager::hwf_manager() : m_mpz_manager(m_mpq_manager) -{ +{ #ifdef _WINDOWS #if defined(_AMD64_) || defined(_M_IA64) // Precision control is not supported on x64. @@ -307,14 +306,28 @@ void hwf_manager::fma(mpf_rounding_mode rm, hwf const & x, hwf const & y, hwf co // CMW: fused_mul_add is not available on most CPUs. As of 2012, only Itanium, // Intel Sandybridge and AMD Bulldozers support that (via AVX). -#ifdef _M_IA64 - // IA64 (Itanium) will do it, if contractions are on. set_rounding_mode(rm); + +#ifdef _M_IA64 + // IA64 (Itanium) will do it, if contractions are on. o.value = x.value * y.value + z.value; #else - set_rounding_mode(rm); +#if defined(_WINDOWS) +#if _MSC_VER >= 1800 + o.value = ::fma(x.value, y.value, z.value); +#else // Windows, older than VS 2013 + #ifdef USE_INTRINSICS + _mm_store_sd(&o.value, _mm_fmadd_sd(_mm_set_sd(x.value), _mm_set_sd(y.value), _mm_set_sd(z.value))); + #else + // If all else fails, we are imprecise. + o.value = (x.value * y.value) + z; + #endif +#endif +#else + // Linux, OSX o.value = ::fma(x.value, y.value, z.value); #endif +#endif } #ifdef _M_IA64 From a361e4dcefc9e63f5164c4bc09fea4419c7f3b54 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 23 May 2015 16:40:43 +0100 Subject: [PATCH 833/925] typo --- src/api/z3_api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index da24f4caf..ec321b66d 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -6022,7 +6022,7 @@ END_MLAPI_EXCLUDE /** \brief Parse an SMT-LIB2 string with fixedpoint rules. Add the rules to the current fixedpoint context. - Return the set of queries in the file. + Return the set of queries in the string. \param c - context. \param f - fixedpoint context. From e33ff427664f161f9960bddce964f0e760f3f146 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 23 May 2015 16:49:41 +0100 Subject: [PATCH 834/925] Updates for the .NET, Java, and ML APIs for recently changed fixedpoint and interpolation functionality. Fixes #103 --- src/api/dotnet/ASTMap.cs | 5 +++-- src/api/dotnet/ASTVector.cs | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/api/dotnet/ASTMap.cs b/src/api/dotnet/ASTMap.cs index 6f296147e..596b2943f 100644 --- a/src/api/dotnet/ASTMap.cs +++ b/src/api/dotnet/ASTMap.cs @@ -98,11 +98,12 @@ namespace Microsoft.Z3 /// /// The keys stored in the map. /// - public ASTVector Keys + public AST[] Keys { get { - return new ASTVector(Context, Native.Z3_ast_map_keys(Context.nCtx, NativeObject)); + ASTVector res = new ASTVector(Context, Native.Z3_ast_map_keys(Context.nCtx, NativeObject)); + return res.ToArray(); } } diff --git a/src/api/dotnet/ASTVector.cs b/src/api/dotnet/ASTVector.cs index b70ff13b6..f858c7862 100644 --- a/src/api/dotnet/ASTVector.cs +++ b/src/api/dotnet/ASTVector.cs @@ -99,6 +99,30 @@ namespace Microsoft.Z3 return Native.Z3_ast_vector_to_string(Context.nCtx, NativeObject); } + /// + /// Translates an AST vector into an AST[] + /// + public AST[] ToArray() + { + uint n = Size; + AST[] res = new AST[n]; + for (uint i = 0; i < n; i++) + res[i] = AST.Create(this.Context, this[i].NativeObject); + return res; + } + + /// + /// Translates an AST vector into an Expr[] + /// + public Expr[] ToExprArray() + { + uint n = Size; + Expr[] res = new Expr[n]; + for (uint i = 0; i < n; i++) + res[i] = Expr.Create(this.Context, this[i].NativeObject); + return res; + } + #region Internal internal ASTVector(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); } internal ASTVector(Context ctx) : base(ctx, Native.Z3_mk_ast_vector(ctx.nCtx)) { Contract.Requires(ctx != null); } From d8f6d84217a6999fd70eccae9c7656bc86bd7654 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 23 May 2015 16:53:47 +0100 Subject: [PATCH 835/925] Updates for the .NET, Java, and ML APIs for recently changed fixedpoint and interpolation functionality. Fixes #103 --- src/api/dotnet/Fixedpoint.cs | 31 +- src/api/dotnet/InterpolationContext.cs | 10 +- src/api/dotnet/Model.cs | 8 +- src/api/dotnet/Solver.cs | 22 +- src/api/java/ASTMap.java | 6 +- src/api/java/ASTVector.java | 23 +- src/api/java/Fixedpoint.java | 36 +- src/api/java/InterpolationContext.java | 11 +- src/api/java/Model.java | 6 +- src/api/java/Solver.java | 19 +- src/api/ml/z3.ml | 661 ++++++++++++++----------- src/api/ml/z3.mli | 134 ++--- 12 files changed, 529 insertions(+), 438 deletions(-) diff --git a/src/api/dotnet/Fixedpoint.cs b/src/api/dotnet/Fixedpoint.cs index 925e741c7..54dbcd3c1 100644 --- a/src/api/dotnet/Fixedpoint.cs +++ b/src/api/dotnet/Fixedpoint.cs @@ -269,14 +269,6 @@ namespace Microsoft.Z3 AST.ArrayLength(queries), AST.ArrayToNative(queries)); } - BoolExpr[] ToBoolExprs(ASTVector v) { - uint n = v.Size; - BoolExpr[] res = new BoolExpr[n]; - for (uint i = 0; i < n; i++) - res[i] = new BoolExpr(Context, v[i].NativeObject); - return res; - } - /// /// Retrieve set of rules added to fixedpoint context. /// @@ -286,7 +278,8 @@ namespace Microsoft.Z3 { Contract.Ensures(Contract.Result() != null); - return ToBoolExprs(new ASTVector(Context, Native.Z3_fixedpoint_get_rules(Context.nCtx, NativeObject))); + ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_get_rules(Context.nCtx, NativeObject)); + return (BoolExpr[])av.ToExprArray(); } } @@ -299,7 +292,8 @@ namespace Microsoft.Z3 { Contract.Ensures(Contract.Result() != null); - return ToBoolExprs(new ASTVector(Context, Native.Z3_fixedpoint_get_assertions(Context.nCtx, NativeObject))); + ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_get_assertions(Context.nCtx, NativeObject)); + return (BoolExpr[])av.ToExprArray(); } } @@ -316,21 +310,24 @@ namespace Microsoft.Z3 } } - /// + /// /// Parse an SMT-LIB2 file with fixedpoint rules. /// Add the rules to the current fixedpoint context. /// Return the set of queries in the file. /// - public BoolExpr[] ParseFile(string file) { - return ToBoolExprs(new ASTVector(Context, Native.Z3_fixedpoint_from_file(Context.nCtx, NativeObject, file))); + public BoolExpr[] ParseFile(string file) + { + ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_from_file(Context.nCtx, NativeObject, file)); + return (BoolExpr[])av.ToExprArray(); } /// /// Similar to ParseFile. Instead it takes as argument a string. - /// - - public BoolExpr[] ParseString(string s) { - return ToBoolExprs(new ASTVector(Context, Native.Z3_fixedpoint_from_string(Context.nCtx, NativeObject, s))); + /// + public BoolExpr[] ParseString(string s) + { + ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_from_string(Context.nCtx, NativeObject, s)); + return (BoolExpr[])av.ToExprArray(); } diff --git a/src/api/dotnet/InterpolationContext.cs b/src/api/dotnet/InterpolationContext.cs index d54c8f634..9fbdf456e 100644 --- a/src/api/dotnet/InterpolationContext.cs +++ b/src/api/dotnet/InterpolationContext.cs @@ -59,11 +59,7 @@ namespace Microsoft.Z3 CheckContextMatch(p); ASTVector seq = new ASTVector(this, Native.Z3_get_interpolant(nCtx, pf.NativeObject, pat.NativeObject, p.NativeObject)); - uint n = seq.Size; - Expr[] res = new Expr[n]; - for (uint i = 0; i < n; i++) - res[i] = Expr.Create(this, seq[i].NativeObject); - return res; + return seq.ToExprArray(); } /// @@ -72,7 +68,7 @@ namespace Microsoft.Z3 /// For more information on interpolation please refer /// too the function Z3_compute_interpolant in the C/C++ API, which is /// well documented. - public Z3_lbool ComputeInterpolant(Expr pat, Params p, out ASTVector interp, out Model model) + public Z3_lbool ComputeInterpolant(Expr pat, Params p, out Expr[] interp, out Model model) { Contract.Requires(pat != null); Contract.Requires(p != null); @@ -84,7 +80,7 @@ namespace Microsoft.Z3 IntPtr i = IntPtr.Zero, m = IntPtr.Zero; int r = Native.Z3_compute_interpolant(nCtx, pat.NativeObject, p.NativeObject, ref i, ref m); - interp = new ASTVector(this, i); + interp = new ASTVector(this, i).ToExprArray(); model = new Model(this, m); return (Z3_lbool)r; } diff --git a/src/api/dotnet/Model.cs b/src/api/dotnet/Model.cs index adf233a98..a7f62e6e8 100644 --- a/src/api/dotnet/Model.cs +++ b/src/api/dotnet/Model.cs @@ -265,12 +265,8 @@ namespace Microsoft.Z3 Contract.Requires(s != null); Contract.Ensures(Contract.Result() != null); - ASTVector nUniv = new ASTVector(Context, Native.Z3_model_get_sort_universe(Context.nCtx, NativeObject, s.NativeObject)); - uint n = nUniv.Size; - Expr[] res = new Expr[n]; - for (uint i = 0; i < n; i++) - res[i] = Expr.Create(Context, nUniv[i].NativeObject); - return res; + ASTVector av = new ASTVector(Context, Native.Z3_model_get_sort_universe(Context.nCtx, NativeObject, s.NativeObject)); + return av.ToExprArray(); } /// diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index 012a283f5..c5227d18f 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -178,8 +178,8 @@ namespace Microsoft.Z3 { get { - ASTVector ass = new ASTVector(Context, Native.Z3_solver_get_assertions(Context.nCtx, NativeObject)); - return ass.Size; + ASTVector assertions = new ASTVector(Context, Native.Z3_solver_get_assertions(Context.nCtx, NativeObject)); + return assertions.Size; } } @@ -192,12 +192,8 @@ namespace Microsoft.Z3 { Contract.Ensures(Contract.Result() != null); - ASTVector ass = new ASTVector(Context, Native.Z3_solver_get_assertions(Context.nCtx, NativeObject)); - uint n = ass.Size; - BoolExpr[] res = new BoolExpr[n]; - for (uint i = 0; i < n; i++) - res[i] = new BoolExpr(Context, ass[i].NativeObject); - return res; + ASTVector assertions = new ASTVector(Context, Native.Z3_solver_get_assertions(Context.nCtx, NativeObject)); + return (BoolExpr[])assertions.ToExprArray(); } } @@ -270,18 +266,14 @@ namespace Microsoft.Z3 /// The result is empty if Check was not invoked before, /// if its results was not UNSATISFIABLE, or if core production is disabled. /// - public Expr[] UnsatCore + public BoolExpr[] UnsatCore { get { Contract.Ensures(Contract.Result() != null); - ASTVector core = new ASTVector(Context, Native.Z3_solver_get_unsat_core(Context.nCtx, NativeObject)); - uint n = core.Size; - Expr[] res = new Expr[n]; - for (uint i = 0; i < n; i++) - res[i] = Expr.Create(Context, core[i].NativeObject); - return res; + ASTVector core = new ASTVector(Context, Native.Z3_solver_get_unsat_core(Context.nCtx, NativeObject)); + return (BoolExpr[])core.ToExprArray(); } } diff --git a/src/api/java/ASTMap.java b/src/api/java/ASTMap.java index 398aac77f..afeb868ca 100644 --- a/src/api/java/ASTMap.java +++ b/src/api/java/ASTMap.java @@ -92,10 +92,10 @@ class ASTMap extends Z3Object * * @throws Z3Exception **/ - public ASTVector getKeys() + public AST[] getKeys() { - return new ASTVector(getContext(), Native.astMapKeys(getContext().nCtx(), - getNativeObject())); + ASTVector av = new ASTVector(getContext(), Native.astMapKeys(getContext().nCtx(), getNativeObject())); + return av.ToArray(); } /** diff --git a/src/api/java/ASTVector.java b/src/api/java/ASTVector.java index e08a75e7f..7011eeb50 100644 --- a/src/api/java/ASTVector.java +++ b/src/api/java/ASTVector.java @@ -119,12 +119,27 @@ public class ASTVector extends Z3Object getContext().getASTVectorDRQ().add(o); super.decRef(o); } - - BoolExpr[] ToBoolArray() { + + /** + * Translates the AST vector into an AST[] + * */ + public AST[] ToArray() + { int n = size(); - BoolExpr[] res = new BoolExpr[n]; + AST[] res = new AST[n]; for (int i = 0; i < n; i++) - res[i] = new BoolExpr(getContext(), get(i).getNativeObject()); + res[i] = AST.create(getContext(), get(i).getNativeObject()); + return res; + } + + /** + * Translates the AST vector into an Expr[] + * */ + public Expr[] ToExprArray() { + int n = size(); + Expr[] res = new Expr[n]; + for (int i = 0; i < n; i++) + res[i] = Expr.create(getContext(), get(i).getNativeObject()); return res; } } diff --git a/src/api/java/Fixedpoint.java b/src/api/java/Fixedpoint.java index daa0f4e3f..b59a9700a 100644 --- a/src/api/java/Fixedpoint.java +++ b/src/api/java/Fixedpoint.java @@ -295,10 +295,8 @@ public class Fixedpoint extends Z3Object **/ public BoolExpr[] getRules() { - - ASTVector v = new ASTVector(getContext(), Native.fixedpointGetRules( - getContext().nCtx(), getNativeObject())); - return v.ToBoolArray(); + ASTVector v = new ASTVector(getContext(), Native.fixedpointGetRules(getContext().nCtx(), getNativeObject())); + return (BoolExpr[]) v.ToExprArray(); } /** @@ -308,10 +306,8 @@ public class Fixedpoint extends Z3Object **/ public BoolExpr[] getAssertions() { - - ASTVector v = new ASTVector(getContext(), Native.fixedpointGetAssertions( - getContext().nCtx(), getNativeObject())); - return v.ToBoolArray(); + ASTVector v = new ASTVector(getContext(), Native.fixedpointGetAssertions(getContext().nCtx(), getNativeObject())); + return (BoolExpr[]) v.ToExprArray(); } /** @@ -319,12 +315,34 @@ public class Fixedpoint extends Z3Object * * @throws Z3Exception **/ - public Statistics getStatistics() throws Z3Exception + public Statistics getStatistics() { return new Statistics(getContext(), Native.fixedpointGetStatistics( getContext().nCtx(), getNativeObject())); } + /** + * Parse an SMT-LIB2 file with fixedpoint rules. + * Add the rules to the current fixedpoint context. + * Return the set of queries in the file. + **/ + public BoolExpr[] ParseFile(String file) + { + ASTVector av = new ASTVector(getContext(), Native.fixedpointFromFile(getContext().nCtx(), getNativeObject(), file)); + return (BoolExpr[])av.ToExprArray(); + } + + /** + * Parse an SMT-LIB2 string with fixedpoint rules. + * Add the rules to the current fixedpoint context. + * Return the set of queries in the file. + **/ + public BoolExpr[] ParseString(String s) + { + ASTVector av = new ASTVector(getContext(), Native.fixedpointFromString(getContext().nCtx(), getNativeObject(), s)); + return (BoolExpr[])av.ToExprArray(); + } + Fixedpoint(Context ctx, long obj) throws Z3Exception { diff --git a/src/api/java/InterpolationContext.java b/src/api/java/InterpolationContext.java index 50c6a223a..5af2a6af8 100644 --- a/src/api/java/InterpolationContext.java +++ b/src/api/java/InterpolationContext.java @@ -80,11 +80,7 @@ public class InterpolationContext extends Context checkContextMatch(p); ASTVector seq = new ASTVector(this, Native.getInterpolant(nCtx(), pf.getNativeObject(), pat.getNativeObject(), p.getNativeObject())); - int n = seq.size(); - Expr[] res = new Expr[n]; - for (int i = 0; i < n; i++) - res[i] = Expr.create(this, seq.get(i).getNativeObject()); - return res; + return seq.ToExprArray(); } public class ComputeInterpolantResult @@ -110,9 +106,8 @@ public class InterpolationContext extends Context Native.LongPtr n_i = new Native.LongPtr(); Native.LongPtr n_m = new Native.LongPtr(); res.status = Z3_lbool.fromInt(Native.computeInterpolant(nCtx(), pat.getNativeObject(), p.getNativeObject(), n_i, n_m)); - if (res.status == Z3_lbool.Z3_L_FALSE) { - res.interp = (new ASTVector(this, n_i.value)).ToBoolArray(); - } + if (res.status == Z3_lbool.Z3_L_FALSE) + res.interp = (BoolExpr[]) (new ASTVector(this, n_i.value)).ToExprArray(); if (res.status == Z3_lbool.Z3_L_TRUE) res.model = new Model(this, n_m.value); return res; } diff --git a/src/api/java/Model.java b/src/api/java/Model.java index 22d232006..e9922ac58 100644 --- a/src/api/java/Model.java +++ b/src/api/java/Model.java @@ -273,11 +273,7 @@ public class Model extends Z3Object ASTVector nUniv = new ASTVector(getContext(), Native.modelGetSortUniverse( getContext().nCtx(), getNativeObject(), s.getNativeObject())); - int n = nUniv.size(); - Expr[] res = new Expr[n]; - for (int i = 0; i < n; i++) - res[i] = Expr.create(getContext(), nUniv.get(i).getNativeObject()); - return res; + return nUniv.ToExprArray(); } /** diff --git a/src/api/java/Solver.java b/src/api/java/Solver.java index 7c4c1f4b9..eb8e81aa5 100644 --- a/src/api/java/Solver.java +++ b/src/api/java/Solver.java @@ -176,8 +176,7 @@ public class Solver extends Z3Object **/ public int getNumAssertions() { - ASTVector assrts = new ASTVector(getContext(), Native.solverGetAssertions( - getContext().nCtx(), getNativeObject())); + ASTVector assrts = new ASTVector(getContext(), Native.solverGetAssertions(getContext().nCtx(), getNativeObject())); return assrts.size(); } @@ -188,9 +187,8 @@ public class Solver extends Z3Object **/ public BoolExpr[] getAssertions() { - ASTVector assrts = new ASTVector(getContext(), Native.solverGetAssertions( - getContext().nCtx(), getNativeObject())); - return assrts.ToBoolArray(); + ASTVector assrts = new ASTVector(getContext(), Native.solverGetAssertions(getContext().nCtx(), getNativeObject())); + return (BoolExpr[]) assrts.ToExprArray(); } /** @@ -278,16 +276,11 @@ public class Solver extends Z3Object * * @throws Z3Exception **/ - public Expr[] getUnsatCore() + public BoolExpr[] getUnsatCore() { - ASTVector core = new ASTVector(getContext(), Native.solverGetUnsatCore( - getContext().nCtx(), getNativeObject())); - int n = core.size(); - Expr[] res = new Expr[n]; - for (int i = 0; i < n; i++) - res[i] = Expr.create(getContext(), core.get(i).getNativeObject()); - return res; + ASTVector core = new ASTVector(getContext(), Native.solverGetUnsatCore(getContext().nCtx(), getNativeObject())); + return (BoolExpr[])core.ToExprArray(); } /** diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index d03c5bba9..fa6ce6c81 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -192,8 +192,59 @@ struct end -module AST = -struct +module rec AST : +sig + type ast = z3_native_object + val context_of_ast : ast -> context + val nc_of_ast : ast -> Z3native.z3_context + val ptr_of_ast : ast -> Z3native.ptr + val ast_of_ptr : context -> Z3native.ptr -> ast + module ASTVector : + sig + type ast_vector = z3_native_object + val create : context -> Z3native.ptr -> ast_vector + val mk_ast_vector : context -> ast_vector + val get_size : ast_vector -> int + val get : ast_vector -> int -> ast + val set : ast_vector -> int -> ast -> unit + val resize : ast_vector -> int -> unit + val push : ast_vector -> ast -> unit + val translate : ast_vector -> context -> ast_vector + val to_list : ast_vector -> ast list + val to_expr_list : ast_vector -> Expr.expr list + val to_string : ast_vector -> string + end + module ASTMap : + sig + type ast_map = z3_native_object + val create : context -> Z3native.ptr -> ast_map + val mk_ast_map : context -> ast_map + val contains : ast_map -> ast -> bool + val find : ast_map -> ast -> ast + val insert : ast_map -> ast -> ast -> unit + val erase : ast_map -> ast -> unit + val reset : ast_map -> unit + val get_size : ast_map -> int + val get_keys : ast_map -> Expr.expr list + val to_string : ast_map -> string + end + val hash : ast -> int + val get_id : ast -> int + val get_ast_kind : ast -> Z3enums.ast_kind + val is_expr : ast -> bool + val is_app : ast -> bool + val is_var : ast -> bool + val is_quantifier : ast -> bool + val is_sort : ast -> bool + val is_func_decl : ast -> bool + val to_string : ast -> string + val to_sexpr : ast -> string + val equal : ast -> ast -> bool + val compare : ast -> ast -> int + val translate : ast -> context -> ast + val unwrap_ast : ast -> Z3native.ptr + val wrap_ast : context -> Z3native.z3_ast -> ast +end = struct type ast = z3_native_object let context_of_ast ( x : ast ) = (z3obj_gc x) @@ -216,13 +267,13 @@ struct let create ( ctx : context ) ( no : Z3native.ptr ) = let res : ast_vector = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.ast_vector_inc_ref ; - dec_ref = Z3native.ast_vector_dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.ast_vector_inc_ref ; + dec_ref = Z3native.ast_vector_dec_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; res - + let mk_ast_vector ( ctx : context ) = (create ctx (Z3native.mk_ast_vector (context_gno ctx))) let get_size ( x : ast_vector ) = @@ -242,6 +293,16 @@ struct let translate ( x : ast_vector ) ( to_ctx : context ) = create to_ctx (Z3native.ast_vector_translate (z3obj_gnc x) (z3obj_gno x) (context_gno to_ctx)) + + let to_list ( x : ast_vector ) = + let xs = (get_size x) in + let f i = (get x i) in + mk_list f xs + + let to_expr_list ( x : ast_vector ) = + let xs = (get_size x) in + let f i = (Expr.expr_of_ptr (z3obj_gc x) (z3obj_gno (get x i))) in + mk_list f xs let to_string ( x : ast_vector ) = Z3native.ast_vector_to_string (z3obj_gnc x) (z3obj_gno x) @@ -253,9 +314,9 @@ struct let create ( ctx : context ) ( no : Z3native.ptr ) = let res : ast_map = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.ast_map_inc_ref ; - dec_ref = Z3native.ast_map_dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.ast_map_inc_ref ; + dec_ref = Z3native.ast_map_dec_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; res @@ -291,8 +352,7 @@ struct let get_keys ( x : ast_map ) = let av = ASTVector.create (z3obj_gc x) (Z3native.ast_map_keys (z3obj_gnc x) (z3obj_gno x)) in - let f i = (ASTVector.get av i) in - mk_list f (ASTVector.get_size av) + (ASTVector.to_expr_list av) let to_string ( x : ast_map ) = Z3native.ast_map_to_string (z3obj_gnc x) (z3obj_gno x) @@ -341,31 +401,43 @@ struct let wrap_ast ( ctx : context ) ( ptr : Z3native.ptr ) = ast_of_ptr ctx ptr end -open AST - - -module Sort = -struct +and Sort : +sig + type sort = Sort of AST.ast + val ast_of_sort : Sort.sort -> AST.ast + val sort_of_ptr : context -> Z3native.ptr -> sort + val gc : sort -> context + val gnc : sort -> Z3native.ptr + val gno : sort -> Z3native.ptr + val sort_lton : sort list -> Z3native.ptr array + val sort_option_lton : sort option list -> Z3native.ptr array + val equal : sort -> sort -> bool + val get_id : sort -> int + val get_sort_kind : sort -> Z3enums.sort_kind + val get_name : sort -> Symbol.symbol + val to_string : sort -> string + val mk_uninterpreted : context -> Symbol.symbol -> sort + val mk_uninterpreted_s : context -> string -> sort +end = struct type sort = Sort of AST.ast let sort_of_ptr : context -> Z3native.ptr -> sort = fun ctx no -> - let q = (z3_native_object_of_ast_ptr ctx no) in if ((Z3enums.ast_kind_of_int (Z3native.get_ast_kind (context_gno ctx) no)) != Z3enums.SORT_AST) then raise (Z3native.Exception "Invalid coercion") else match (sort_kind_of_int (Z3native.get_sort_kind (context_gno ctx) no)) with - | ARRAY_SORT - | BOOL_SORT - | BV_SORT - | DATATYPE_SORT - | INT_SORT - | REAL_SORT - | UNINTERPRETED_SORT - | FINITE_DOMAIN_SORT - | RELATION_SORT - | FLOATING_POINT_SORT - | ROUNDING_MODE_SORT -> Sort(q) - | UNKNOWN_SORT -> raise (Z3native.Exception "Unknown sort kind encountered") + | ARRAY_SORT + | BOOL_SORT + | BV_SORT + | DATATYPE_SORT + | INT_SORT + | REAL_SORT + | UNINTERPRETED_SORT + | FINITE_DOMAIN_SORT + | RELATION_SORT + | FLOATING_POINT_SORT + | ROUNDING_MODE_SORT -> Sort(z3_native_object_of_ast_ptr ctx no) + | UNKNOWN_SORT -> raise (Z3native.Exception "Unknown sort kind encountered") let ast_of_sort s = match s with Sort(x) -> x @@ -387,7 +459,7 @@ struct false else (Z3native.is_eq_sort (gnc a) (gno a) (gno b)) - + let get_id ( x : sort ) = Z3native.get_sort_id (gnc x) (gno x) let get_sort_kind ( x : sort ) = (sort_kind_of_int (Z3native.get_sort_kind (gnc x) (gno x))) @@ -407,10 +479,7 @@ struct mk_uninterpreted ctx (Symbol.mk_string ( ctx : context ) s) end -open Sort - - -module rec FuncDecl : +and FuncDecl : sig type func_decl = FuncDecl of AST.ast val ast_of_func_decl : FuncDecl.func_decl -> AST.ast @@ -467,21 +536,21 @@ end = struct let ast_of_func_decl f = match f with FuncDecl(x) -> x - let create_ndr ( ctx : context ) ( name : Symbol.symbol ) ( domain : sort list ) ( range : sort ) = + let create_ndr ( ctx : context ) ( name : Symbol.symbol ) ( domain : Sort.sort list ) ( range : Sort.sort ) = let res = { m_ctx = ctx ; m_n_obj = null ; inc_ref = Z3native.inc_ref ; dec_ref = Z3native.dec_ref } in - (z3obj_sno res ctx (Z3native.mk_func_decl (context_gno ctx) (Symbol.gno name) (List.length domain) (sort_lton domain) (Sort.gno range))) ; + (z3obj_sno res ctx (Z3native.mk_func_decl (context_gno ctx) (Symbol.gno name) (List.length domain) (Sort.sort_lton domain) (Sort.gno range))) ; (z3obj_create res) ; FuncDecl(res) - let create_pdr ( ctx : context) ( prefix : string ) ( domain : sort list ) ( range : sort ) = + let create_pdr ( ctx : context) ( prefix : string ) ( domain : Sort.sort list ) ( range : Sort.sort ) = let res = { m_ctx = ctx ; m_n_obj = null ; inc_ref = Z3native.inc_ref ; dec_ref = Z3native.dec_ref } in - (z3obj_sno res ctx (Z3native.mk_fresh_func_decl (context_gno ctx) prefix (List.length domain) (sort_lton domain) (Sort.gno range))) ; + (z3obj_sno res ctx (Z3native.mk_fresh_func_decl (context_gno ctx) prefix (List.length domain) (Sort.sort_lton domain) (Sort.gno range))) ; (z3obj_create res) ; FuncDecl(res) @@ -546,22 +615,22 @@ end = struct | _ -> raise (Z3native.Exception "parameter is not a rational string") end - let mk_func_decl ( ctx : context ) ( name : Symbol.symbol ) ( domain : sort list ) ( range : sort ) = + let mk_func_decl ( ctx : context ) ( name : Symbol.symbol ) ( domain : Sort.sort list ) ( range : Sort.sort ) = create_ndr ctx name domain range - let mk_func_decl_s ( ctx : context ) ( name : string ) ( domain : sort list ) ( range : sort ) = + let mk_func_decl_s ( ctx : context ) ( name : string ) ( domain : Sort.sort list ) ( range : Sort.sort ) = mk_func_decl ctx (Symbol.mk_string ctx name) domain range - let mk_fresh_func_decl ( ctx : context ) ( prefix : string ) ( domain : sort list ) ( range : sort ) = + let mk_fresh_func_decl ( ctx : context ) ( prefix : string ) ( domain : Sort.sort list ) ( range : Sort.sort ) = create_pdr ctx prefix domain range - let mk_const_decl ( ctx : context ) ( name : Symbol.symbol ) ( range : sort ) = + let mk_const_decl ( ctx : context ) ( name : Symbol.symbol ) ( range : Sort.sort ) = create_ndr ctx name [] range - let mk_const_decl_s ( ctx : context ) ( name : string ) ( range : sort ) = + let mk_const_decl_s ( ctx : context ) ( name : string ) ( range : Sort.sort ) = create_ndr ctx (Symbol.mk_string ctx name) [] range - let mk_fresh_const_decl ( ctx : context ) ( prefix : string ) ( range : sort ) = + let mk_fresh_const_decl ( ctx : context ) ( prefix : string ) ( range : Sort.sort ) = create_pdr ctx prefix [] range @@ -581,11 +650,11 @@ end = struct let get_domain ( x : func_decl ) = let n = (get_domain_size x) in - let f i = sort_of_ptr (gc x) (Z3native.get_domain (gnc x) (gno x) i) in + let f i = Sort.sort_of_ptr (gc x) (Z3native.get_domain (gnc x) (gno x) i) in mk_list f n let get_range ( x : func_decl ) = - sort_of_ptr (gc x) (Z3native.get_range (gnc x) (gno x)) + Sort.sort_of_ptr (gc x) (Z3native.get_range (gnc x) (gno x)) let get_decl_kind ( x : func_decl ) = (decl_kind_of_int (Z3native.get_decl_kind (gnc x) (gno x))) @@ -599,7 +668,7 @@ end = struct | PARAMETER_INT -> Parameter.P_Int (Z3native.get_decl_int_parameter (gnc x) (gno x) i) | PARAMETER_DOUBLE -> Parameter.P_Dbl (Z3native.get_decl_double_parameter (gnc x) (gno x) i) | PARAMETER_SYMBOL-> Parameter.P_Sym (Symbol.create (gc x) (Z3native.get_decl_symbol_parameter (gnc x) (gno x) i)) - | PARAMETER_SORT -> Parameter.P_Srt (sort_of_ptr (gc x) (Z3native.get_decl_sort_parameter (gnc x) (gno x) i)) + | PARAMETER_SORT -> Parameter.P_Srt (Sort.sort_of_ptr (gc x) (Z3native.get_decl_sort_parameter (gnc x) (gno x) i)) | PARAMETER_AST -> Parameter.P_Ast (AST.ast_of_ptr (gc x) (Z3native.get_decl_ast_parameter (gnc x) (gno x) i)) | PARAMETER_FUNC_DECL -> Parameter.P_Fdl (func_decl_of_ptr (gc x) (Z3native.get_decl_func_decl_parameter (gnc x) (gno x) i)) | PARAMETER_RATIONAL -> Parameter.P_Rat (Z3native.get_decl_rational_parameter (gnc x) (gno x) i) @@ -820,29 +889,29 @@ end = struct let is_well_sorted ( x : expr ) = Z3native.is_well_sorted (gnc x) (gno x) - let get_sort ( x : expr ) = sort_of_ptr (Expr.gc x) (Z3native.get_sort (gnc x) (gno x)) + let get_sort ( x : expr ) = Sort.sort_of_ptr (Expr.gc x) (Z3native.get_sort (gnc x) (gno x)) let is_const ( x : expr ) = (match x with Expr(a) -> (AST.is_app a)) && (get_num_args x) == 0 && (FuncDecl.get_domain_size (get_func_decl x)) == 0 - let mk_const ( ctx : context ) ( name : Symbol.symbol ) ( range : sort ) = + let mk_const ( ctx : context ) ( name : Symbol.symbol ) ( range : Sort.sort ) = expr_of_ptr ctx (Z3native.mk_const (context_gno ctx) (Symbol.gno name) (Sort.gno range)) - let mk_const_s ( ctx : context ) ( name : string ) ( range : sort ) = + let mk_const_s ( ctx : context ) ( name : string ) ( range : Sort.sort ) = mk_const ctx (Symbol.mk_string ctx name) range let mk_const_f ( ctx : context ) ( f : FuncDecl.func_decl ) = Expr.expr_of_func_app ctx f [] - let mk_fresh_const ( ctx : context ) ( prefix : string ) ( range : sort ) = + let mk_fresh_const ( ctx : context ) ( prefix : string ) ( range : Sort.sort ) = expr_of_ptr ctx (Z3native.mk_fresh_const (context_gno ctx) prefix (Sort.gno range)) let mk_app ( ctx : context ) ( f : FuncDecl.func_decl ) ( args : expr list ) = expr_of_func_app ctx f args - let mk_numeral_string ( ctx : context ) ( v : string ) ( ty : sort ) = + let mk_numeral_string ( ctx : context ) ( v : string ) ( ty : Sort.sort ) = expr_of_ptr ctx (Z3native.mk_numeral (context_gno ctx) v (Sort.gno ty)) - let mk_numeral_int ( ctx : context ) ( v : int ) ( ty : sort ) = + let mk_numeral_int ( ctx : context ) ( v : int ) ( ty : Sort.sort ) = expr_of_ptr ctx (Z3native.mk_int (context_gno ctx) v (Sort.gno ty)) let equal ( a : expr ) ( b : expr ) = AST.equal (ast_of_expr a) (ast_of_expr b) @@ -856,7 +925,7 @@ open Expr module Boolean = struct let mk_sort ( ctx : context ) = - (sort_of_ptr ctx (Z3native.mk_bool_sort (context_gno ctx))) + (Sort.sort_of_ptr ctx (Z3native.mk_bool_sort (context_gno ctx))) let mk_const ( ctx : context ) ( name : Symbol.symbol ) = (Expr.mk_const ctx name (mk_sort ctx)) @@ -943,7 +1012,7 @@ struct module Pattern = struct - type pattern = Pattern of ast + type pattern = Pattern of AST.ast let ast_of_pattern e = match e with Pattern(x) -> x @@ -1002,13 +1071,13 @@ struct let get_bound_variable_sorts ( x : quantifier ) = let n = (get_num_bound x) in - let f i = (sort_of_ptr (gc x) (Z3native.get_quantifier_bound_sort (gnc x) (gno x) i)) in + let f i = (Sort.sort_of_ptr (gc x) (Z3native.get_quantifier_bound_sort (gnc x) (gno x) i)) in mk_list f n let get_body ( x : quantifier ) = expr_of_ptr (gc x) (Z3native.get_quantifier_body (gnc x) (gno x)) - let mk_bound ( ctx : context ) ( index : int ) ( ty : sort ) = + let mk_bound ( ctx : context ) ( index : int ) ( ty : Sort.sort ) = expr_of_ptr ctx (Z3native.mk_bound (context_gno ctx) index (Sort.gno ty)) let mk_pattern ( ctx : context ) ( terms : expr list ) = @@ -1017,14 +1086,14 @@ struct else Pattern.Pattern(z3_native_object_of_ast_ptr ctx (Z3native.mk_pattern (context_gno ctx) (List.length terms) (expr_lton terms))) - let mk_forall ( ctx : context ) ( sorts : sort list ) ( names : Symbol.symbol list ) ( body : expr ) ( weight : int option ) ( patterns : Pattern.pattern list ) ( nopatterns : expr list ) ( quantifier_id : Symbol.symbol option ) ( skolem_id : Symbol.symbol option ) = + let mk_forall ( ctx : context ) ( sorts : Sort.sort list ) ( names : Symbol.symbol list ) ( body : expr ) ( weight : int option ) ( patterns : Pattern.pattern list ) ( nopatterns : expr list ) ( quantifier_id : Symbol.symbol option ) ( skolem_id : Symbol.symbol option ) = if (List.length sorts) != (List.length names) then raise (Z3native.Exception "Number of sorts does not match number of names") else if ((List.length nopatterns) == 0 && quantifier_id == None && skolem_id == None) then Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier (context_gno ctx) true (match weight with | None -> 1 | Some(x) -> x) (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) - (List.length sorts) (sort_lton sorts) + (List.length sorts) (Sort.sort_lton sorts) (Symbol.symbol_lton names) (Expr.gno body))) else @@ -1034,7 +1103,7 @@ struct (match skolem_id with | None -> null | Some(x) -> (Symbol.gno x)) (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) (List.length nopatterns) (expr_lton nopatterns) - (List.length sorts) (sort_lton sorts) + (List.length sorts) (Sort.sort_lton sorts) (Symbol.symbol_lton names) (Expr.gno body))) @@ -1055,14 +1124,14 @@ struct (List.length nopatterns) (expr_lton nopatterns) (Expr.gno body))) - let mk_exists ( ctx : context ) ( sorts : sort list ) ( names : Symbol.symbol list ) ( body : expr ) ( weight : int option ) ( patterns : Pattern.pattern list ) ( nopatterns : expr list ) ( quantifier_id : Symbol.symbol option ) ( skolem_id : Symbol.symbol option ) = + let mk_exists ( ctx : context ) ( sorts : Sort.sort list ) ( names : Symbol.symbol list ) ( body : expr ) ( weight : int option ) ( patterns : Pattern.pattern list ) ( nopatterns : expr list ) ( quantifier_id : Symbol.symbol option ) ( skolem_id : Symbol.symbol option ) = if (List.length sorts) != (List.length names) then raise (Z3native.Exception "Number of sorts does not match number of names") else if ((List.length nopatterns) == 0 && quantifier_id == None && skolem_id == None) then Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier (context_gno ctx) false (match weight with | None -> 1 | Some(x) -> x) (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) - (List.length sorts) (sort_lton sorts) + (List.length sorts) (Sort.sort_lton sorts) (Symbol.symbol_lton names) (Expr.gno body))) else @@ -1072,7 +1141,7 @@ struct (match skolem_id with | None -> null | Some(x) -> (Symbol.gno x)) (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) (List.length nopatterns) (expr_lton nopatterns) - (List.length sorts) (sort_lton sorts) + (List.length sorts) (Sort.sort_lton sorts) (Symbol.symbol_lton names) (Expr.gno body))) @@ -1093,7 +1162,7 @@ struct (List.length nopatterns) (expr_lton nopatterns) (Expr.gno body))) - let mk_quantifier ( ctx : context ) ( universal : bool ) ( sorts : sort list ) ( names : Symbol.symbol list ) ( body : expr ) ( weight : int option ) ( patterns : Pattern.pattern list ) ( nopatterns : expr list ) ( quantifier_id : Symbol.symbol option ) ( skolem_id : Symbol.symbol option ) = + let mk_quantifier ( ctx : context ) ( universal : bool ) ( sorts : Sort.sort list ) ( names : Symbol.symbol list ) ( body : expr ) ( weight : int option ) ( patterns : Pattern.pattern list ) ( nopatterns : expr list ) ( quantifier_id : Symbol.symbol option ) ( skolem_id : Symbol.symbol option ) = if (universal) then (mk_forall ctx sorts names body weight patterns nopatterns quantifier_id skolem_id) else @@ -1111,8 +1180,8 @@ end module Z3Array = struct - let mk_sort ( ctx : context ) ( domain : sort ) ( range : sort ) = - sort_of_ptr ctx (Z3native.mk_array_sort (context_gno ctx) (Sort.gno domain) (Sort.gno range)) + let mk_sort ( ctx : context ) ( domain : Sort.sort ) ( range : Sort.sort ) = + Sort.sort_of_ptr ctx (Z3native.mk_array_sort (context_gno ctx) (Sort.gno domain) (Sort.gno range)) let is_store ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_STORE) let is_select ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_SELECT) @@ -1124,13 +1193,13 @@ struct (Z3native.is_app (Expr.gnc x) (Expr.gno x)) && ((sort_kind_of_int (Z3native.get_sort_kind (Expr.gnc x) (Z3native.get_sort (Expr.gnc x) (Expr.gno x)))) == ARRAY_SORT) - let get_domain ( x : sort ) = Sort.sort_of_ptr (Sort.gc x) (Z3native.get_array_sort_domain (Sort.gnc x) (Sort.gno x)) - let get_range ( x : sort ) = Sort.sort_of_ptr (Sort.gc x) (Z3native.get_array_sort_range (Sort.gnc x) (Sort.gno x)) + let get_domain ( x : Sort.sort ) = Sort.sort_of_ptr (Sort.gc x) (Z3native.get_array_sort_domain (Sort.gnc x) (Sort.gno x)) + let get_range ( x : Sort.sort ) = Sort.sort_of_ptr (Sort.gc x) (Z3native.get_array_sort_range (Sort.gnc x) (Sort.gno x)) - let mk_const ( ctx : context ) ( name : Symbol.symbol ) ( domain : sort ) ( range : sort ) = + let mk_const ( ctx : context ) ( name : Symbol.symbol ) ( domain : Sort.sort ) ( range : Sort.sort ) = (Expr.mk_const ctx name (mk_sort ctx domain range)) - let mk_const_s ( ctx : context ) ( name : string ) ( domain : sort ) ( range : sort ) = + let mk_const_s ( ctx : context ) ( name : string ) ( domain : Sort.sort ) ( range : Sort.sort ) = mk_const ctx (Symbol.mk_string ctx name) domain range let mk_select ( ctx : context ) ( a : expr ) ( i : expr ) = @@ -1139,7 +1208,7 @@ struct let mk_store ( ctx : context ) ( a : expr ) ( i : expr ) ( v : expr ) = expr_of_ptr ctx (Z3native.mk_store (context_gno ctx) (Expr.gno a) (Expr.gno i) (Expr.gno v)) - let mk_const_array ( ctx : context ) ( domain : sort ) ( v : expr ) = + let mk_const_array ( ctx : context ) ( domain : Sort.sort ) ( v : expr ) = expr_of_ptr ctx (Z3native.mk_const_array (context_gno ctx) (Sort.gno domain) (Expr.gno v)) let mk_map ( ctx : context ) ( f : func_decl ) ( args : expr list ) = @@ -1153,8 +1222,8 @@ end module Set = struct - let mk_sort ( ctx : context ) ( ty : sort ) = - sort_of_ptr ctx (Z3native.mk_set_sort (context_gno ctx) (Sort.gno ty)) + let mk_sort ( ctx : context ) ( ty : Sort.sort ) = + Sort.sort_of_ptr ctx (Z3native.mk_set_sort (context_gno ctx) (Sort.gno ty)) let is_union ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_SET_UNION) let is_intersect ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_SET_INTERSECT) @@ -1163,10 +1232,10 @@ struct let is_subset ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_SET_SUBSET) - let mk_empty ( ctx : context ) ( domain : sort ) = + let mk_empty ( ctx : context ) ( domain : Sort.sort ) = (expr_of_ptr ctx (Z3native.mk_empty_set (context_gno ctx) (Sort.gno domain))) - let mk_full ( ctx : context ) ( domain : sort ) = + let mk_full ( ctx : context ) ( domain : Sort.sort ) = expr_of_ptr ctx (Z3native.mk_full_set (context_gno ctx) (Sort.gno domain)) let mk_set_add ( ctx : context ) ( set : expr ) ( element : expr ) = @@ -1199,7 +1268,7 @@ end module FiniteDomain = struct let mk_sort ( ctx : context ) ( name : Symbol.symbol ) ( size : int ) = - (sort_of_ptr ctx (Z3native.mk_finite_domain_sort (context_gno ctx) (Symbol.gno name) size)) + Sort.sort_of_ptr ctx (Z3native.mk_finite_domain_sort (context_gno ctx) (Symbol.gno name) size) let mk_sort_s ( ctx : context ) ( name : string ) ( size : int ) = mk_sort ctx (Symbol.mk_string ctx name) size @@ -1211,7 +1280,7 @@ struct let is_lt ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FD_LT) - let get_size ( x : sort ) = + let get_size ( x : Sort.sort ) = let (r, v) = (Z3native.get_finite_domain_sort_size (Sort.gnc x) (Sort.gno x)) in if r then v else raise (Z3native.Exception "Conversion failed.") @@ -1239,11 +1308,11 @@ struct let is_select ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_RA_SELECT) let is_clone ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_RA_CLONE) - let get_arity ( x : sort ) = Z3native.get_relation_arity (Sort.gnc x) (Sort.gno x) + let get_arity ( x : Sort.sort ) = Z3native.get_relation_arity (Sort.gnc x) (Sort.gno x) - let get_column_sorts ( x : sort ) = + let get_column_sorts ( x : Sort.sort ) = let n = get_arity x in - let f i = (sort_of_ptr (Sort.gc x) (Z3native.get_relation_column (Sort.gnc x) (Sort.gno x) i)) in + let f i = (Sort.sort_of_ptr (Sort.gc x) (Z3native.get_relation_column (Sort.gnc x) (Sort.gno x) i)) in mk_list f n end @@ -1262,7 +1331,7 @@ struct let _field_nums = FieldNumTable.create 0 - let create ( ctx : context ) ( name : Symbol.symbol ) ( recognizer : Symbol.symbol ) ( field_names : Symbol.symbol list ) ( sorts : sort option list ) ( sort_refs : int list ) = + let create ( ctx : context ) ( name : Symbol.symbol ) ( recognizer : Symbol.symbol ) ( field_names : Symbol.symbol list ) ( sorts : Sort.sort option list ) ( sort_refs : int list ) = let n = (List.length field_names) in if n != (List.length sorts) then raise (Z3native.Exception "Number of field names does not match number of sorts") @@ -1274,7 +1343,7 @@ struct (Symbol.gno recognizer) n (Symbol.symbol_lton field_names) - (sort_option_lton sorts) + (Sort.sort_option_lton sorts) (Array.of_list sort_refs)) in let no : constructor = { m_ctx = ctx ; m_n_obj = null ; @@ -1321,17 +1390,17 @@ struct res end - let mk_constructor ( ctx : context ) ( name : Symbol.symbol ) ( recognizer : Symbol.symbol ) ( field_names : Symbol.symbol list ) ( sorts : sort option list ) ( sort_refs : int list ) = + let mk_constructor ( ctx : context ) ( name : Symbol.symbol ) ( recognizer : Symbol.symbol ) ( field_names : Symbol.symbol list ) ( sorts : Sort.sort option list ) ( sort_refs : int list ) = Constructor.create ctx name recognizer field_names sorts sort_refs - let mk_constructor_s ( ctx : context ) ( name : string ) ( recognizer : Symbol.symbol ) ( field_names : Symbol.symbol list ) ( sorts : sort option list ) ( sort_refs : int list ) = + let mk_constructor_s ( ctx : context ) ( name : string ) ( recognizer : Symbol.symbol ) ( field_names : Symbol.symbol list ) ( sorts : Sort.sort option list ) ( sort_refs : int list ) = mk_constructor ctx (Symbol.mk_string ctx name) recognizer field_names sorts sort_refs let mk_sort ( ctx : context ) ( name : Symbol.symbol ) ( constructors : Constructor.constructor list ) = let f x = (z3obj_gno x) in let (x,_) = (Z3native.mk_datatype (context_gno ctx) (Symbol.gno name) (List.length constructors) (Array.of_list (List.map f constructors))) in - sort_of_ptr ctx x + Sort.sort_of_ptr ctx x let mk_sort_s ( ctx : context ) ( name : string ) ( constructors : Constructor.constructor list ) = mk_sort ctx (Symbol.mk_string ctx name) constructors @@ -1341,7 +1410,7 @@ struct let f e = (AST.ptr_of_ast (ConstructorList.create ctx e)) in let cla = (Array.of_list (List.map f c)) in let (r, a) = (Z3native.mk_datatypes (context_gno ctx) n (Symbol.symbol_lton names) cla) in - let g i = (sort_of_ptr ctx (Array.get r i)) in + let g i = (Sort.sort_of_ptr ctx (Array.get r i)) in mk_list g (Array.length r) let mk_sorts_s ( ctx : context ) ( names : string list ) ( c : Constructor.constructor list list ) = @@ -1352,19 +1421,19 @@ struct ) c - let get_num_constructors ( x : sort ) = Z3native.get_datatype_sort_num_constructors (Sort.gnc x) (Sort.gno x) + let get_num_constructors ( x : Sort.sort ) = Z3native.get_datatype_sort_num_constructors (Sort.gnc x) (Sort.gno x) - let get_constructors ( x : sort ) = + let get_constructors ( x : Sort.sort ) = let n = (get_num_constructors x) in let f i = func_decl_of_ptr (Sort.gc x) (Z3native.get_datatype_sort_constructor (Sort.gnc x) (Sort.gno x) i) in mk_list f n - let get_recognizers ( x : sort ) = + let get_recognizers ( x : Sort.sort ) = let n = (get_num_constructors x) in let f i = func_decl_of_ptr (Sort.gc x) (Z3native.get_datatype_sort_recognizer (Sort.gnc x) (Sort.gno x) i) in mk_list f n - let get_accessors ( x : sort ) = + let get_accessors ( x : Sort.sort ) = let n = (get_num_constructors x) in let f i = ( let fd = func_decl_of_ptr (Sort.gc x) (Z3native.get_datatype_sort_constructor (Sort.gnc x) (Sort.gno x) i) in @@ -1380,80 +1449,80 @@ module Enumeration = struct let mk_sort ( ctx : context ) ( name : Symbol.symbol ) ( enum_names : Symbol.symbol list ) = let (a, _, _) = (Z3native.mk_enumeration_sort (context_gno ctx) (Symbol.gno name) (List.length enum_names) (Symbol.symbol_lton enum_names)) in - sort_of_ptr ctx a + Sort.sort_of_ptr ctx a let mk_sort_s ( ctx : context ) ( name : string ) ( enum_names : string list ) = mk_sort ctx (Symbol.mk_string ctx name) (Symbol.mk_strings ctx enum_names) - let get_const_decls ( x : sort ) = + let get_const_decls ( x : Sort.sort ) = let n = Z3native.get_datatype_sort_num_constructors (Sort.gnc x) (Sort.gno x) in let f i = (func_decl_of_ptr (Sort.gc x) (Z3native.get_datatype_sort_constructor (Sort.gnc x) (Sort.gno x) i)) in mk_list f n - let get_const_decl ( x : sort ) ( inx : int ) = + let get_const_decl ( x : Sort.sort ) ( inx : int ) = func_decl_of_ptr (Sort.gc x) (Z3native.get_datatype_sort_constructor (Sort.gnc x) (Sort.gno x) inx) - let get_consts ( x : sort ) = + let get_consts ( x : Sort.sort ) = let n = Z3native.get_datatype_sort_num_constructors (Sort.gnc x) (Sort.gno x) in let f i = (Expr.mk_const_f (Sort.gc x) (get_const_decl x i)) in mk_list f n - let get_const ( x : sort ) ( inx : int ) = + let get_const ( x : Sort.sort ) ( inx : int ) = Expr.mk_const_f (Sort.gc x) (get_const_decl x inx) - let get_tester_decls ( x : sort ) = + let get_tester_decls ( x : Sort.sort ) = let n = Z3native.get_datatype_sort_num_constructors (Sort.gnc x) (Sort.gno x) in let f i = (func_decl_of_ptr (Sort.gc x) (Z3native.get_datatype_sort_recognizer (Sort.gnc x) (Sort.gno x) i)) in mk_list f n - let get_tester_decl ( x : sort ) ( inx : int ) = + let get_tester_decl ( x : Sort.sort ) ( inx : int ) = func_decl_of_ptr (Sort.gc x) (Z3native.get_datatype_sort_recognizer (Sort.gnc x) (Sort.gno x) inx) end module Z3List = struct - let mk_sort ( ctx : context ) ( name : Symbol.symbol ) ( elem_sort : sort ) = + let mk_sort ( ctx : context ) ( name : Symbol.symbol ) ( elem_sort : Sort.sort ) = let (r, _, _, _, _, _, _) = (Z3native.mk_list_sort (context_gno ctx) (Symbol.gno name) (Sort.gno elem_sort)) in - sort_of_ptr ctx r + Sort.sort_of_ptr ctx r - let mk_list_s ( ctx : context ) (name : string) elem_sort = + let mk_list_s ( ctx : context ) ( name : string ) elem_sort = mk_sort ctx (Symbol.mk_string ctx name) elem_sort - let get_nil_decl ( x : sort ) = + let get_nil_decl ( x : Sort.sort ) = func_decl_of_ptr (Sort.gc x) (Z3native.get_datatype_sort_constructor (Sort.gnc x) (Sort.gno x) 0) - let get_is_nil_decl ( x : sort ) = + let get_is_nil_decl ( x : Sort.sort ) = func_decl_of_ptr (Sort.gc x) (Z3native.get_datatype_sort_recognizer (Sort.gnc x) (Sort.gno x) 0) - let get_cons_decl ( x : sort ) = + let get_cons_decl ( x : Sort.sort ) = func_decl_of_ptr (Sort.gc x) (Z3native.get_datatype_sort_constructor (Sort.gnc x) (Sort.gno x) 1) - let get_is_cons_decl ( x : sort ) = + let get_is_cons_decl ( x : Sort.sort ) = func_decl_of_ptr (Sort.gc x) (Z3native.get_datatype_sort_recognizer (Sort.gnc x) (Sort.gno x) 1) - let get_head_decl ( x : sort ) = + let get_head_decl ( x : Sort.sort ) = func_decl_of_ptr (Sort.gc x) (Z3native.get_datatype_sort_constructor_accessor (Sort.gnc x) (Sort.gno x) 1 0) - let get_tail_decl ( x : sort ) = + let get_tail_decl ( x : Sort.sort ) = func_decl_of_ptr (Sort.gc x) (Z3native.get_datatype_sort_constructor_accessor (Sort.gnc x) (Sort.gno x) 1 1) - let nil ( x : sort ) = expr_of_func_app (Sort.gc x) (get_nil_decl x) [] + let nil ( x : Sort.sort ) = expr_of_func_app (Sort.gc x) (get_nil_decl x) [] end module Tuple = struct - let mk_sort ( ctx : context ) ( name : Symbol.symbol ) ( field_names : Symbol.symbol list ) ( field_sorts : sort list ) = - let (r, _, _) = (Z3native.mk_tuple_sort (context_gno ctx) (Symbol.gno name) (List.length field_names) (Symbol.symbol_lton field_names) (sort_lton field_sorts)) in - sort_of_ptr ctx r + let mk_sort ( ctx : context ) ( name : Symbol.symbol ) ( field_names : Symbol.symbol list ) ( field_sorts : Sort.sort list ) = + let (r, _, _) = (Z3native.mk_tuple_sort (context_gno ctx) (Symbol.gno name) (List.length field_names) (Symbol.symbol_lton field_names) (Sort.sort_lton field_sorts)) in + Sort.sort_of_ptr ctx r - let get_mk_decl ( x : sort ) = + let get_mk_decl ( x : Sort.sort ) = func_decl_of_ptr (Sort.gc x) (Z3native.get_tuple_sort_mk_decl (Sort.gnc x) (Sort.gno x)) - let get_num_fields ( x : sort ) = Z3native.get_tuple_sort_num_fields (Sort.gnc x) (Sort.gno x) + let get_num_fields ( x : Sort.sort ) = Z3native.get_tuple_sort_num_fields (Sort.gnc x) (Sort.gno x) - let get_field_decls ( x : sort ) = + let get_field_decls ( x : Sort.sort ) = let n = get_num_fields x in let f i = func_decl_of_ptr (Sort.gc x) (Z3native.get_tuple_sort_field_decl (Sort.gnc x) (Sort.gno x) i) in mk_list f n @@ -1510,7 +1579,7 @@ struct module Integer = struct let mk_sort ( ctx : context ) = - sort_of_ptr ctx (Z3native.mk_int_sort (context_gno ctx)) + Sort.sort_of_ptr ctx (Z3native.mk_int_sort (context_gno ctx)) let get_int ( x : expr ) = let (r, v) = Z3native.get_numeral_int (Expr.gnc x) (Expr.gno x) in @@ -1553,7 +1622,7 @@ struct module Real = struct let mk_sort ( ctx : context ) = - sort_of_ptr ctx (Z3native.mk_real_sort (context_gno ctx)) + Sort.sort_of_ptr ctx (Z3native.mk_real_sort (context_gno ctx)) let get_numerator ( x : expr ) = expr_of_ptr (Expr.gc x) (Z3native.get_numerator (Expr.gnc x) (Expr.gno x)) @@ -1599,14 +1668,14 @@ struct module AlgebraicNumber = struct let to_upper ( x : expr ) ( precision : int ) = - expr_of_ptr (Expr.gc x) (Z3native.get_algebraic_number_upper (Expr.gnc x) (Expr.gno x) precision) - + expr_of_ptr (Expr.gc x) (Z3native.get_algebraic_number_upper (Expr.gnc x) (Expr.gno x) precision) + let to_lower ( x : expr ) precision = - expr_of_ptr (Expr.gc x) (Z3native.get_algebraic_number_lower (Expr.gnc x) (Expr.gno x) precision) - + expr_of_ptr (Expr.gc x) (Z3native.get_algebraic_number_lower (Expr.gnc x) (Expr.gno x) precision) + let to_decimal_string ( x : expr ) ( precision : int ) = - Z3native.get_numeral_decimal_string (Expr.gnc x) (Expr.gno x) precision - + Z3native.get_numeral_decimal_string (Expr.gnc x) (Expr.gno x) precision + let numeral_to_string ( x : expr ) = Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x) end end @@ -1649,7 +1718,7 @@ end module BitVector = struct let mk_sort ( ctx : context ) size = - sort_of_ptr ctx (Z3native.mk_bv_sort (context_gno ctx) size) + Sort.sort_of_ptr ctx (Z3native.mk_bv_sort (context_gno ctx) size) let is_bv ( x : expr ) = ((sort_kind_of_int (Z3native.get_sort_kind (Expr.gnc x) (Z3native.get_sort (Expr.gnc x) (Expr.gno x)))) == BV_SORT) let is_bv_numeral ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BNUM) @@ -1703,7 +1772,7 @@ struct let is_bv2int ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_BV2INT) let is_bv_carry ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_CARRY) let is_bv_xor3 ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_XOR3) - let get_size (x : sort ) = Z3native.get_bv_sort_size (Sort.gnc x) (Sort.gno x) + let get_size (x : Sort.sort ) = Z3native.get_bv_sort_size (Sort.gnc x) (Sort.gno x) let get_int ( x : expr ) = let (r, v) = Z3native.get_numeral_int (Expr.gnc x) (Expr.gno x) in if r then v @@ -1817,7 +1886,7 @@ struct module RoundingMode = struct let mk_sort ( ctx : context ) = - (sort_of_ptr ctx (Z3native.mk_fpa_rounding_mode_sort (context_gno ctx))) + (Sort.sort_of_ptr ctx (Z3native.mk_fpa_rounding_mode_sort (context_gno ctx))) let is_fprm ( x : expr ) = (Sort.get_sort_kind (Expr.get_sort(x))) == ROUNDING_MODE_SORT let mk_round_nearest_ties_to_even ( ctx : context ) = @@ -1843,40 +1912,40 @@ struct end let mk_sort ( ctx : context ) ( ebits : int ) ( sbits : int ) = - (sort_of_ptr ctx (Z3native.mk_fpa_sort (context_gno ctx) ebits sbits)) + (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort (context_gno ctx) ebits sbits)) let mk_sort_half ( ctx : context ) = - (sort_of_ptr ctx (Z3native.mk_fpa_sort_half (context_gno ctx))) + (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_half (context_gno ctx))) let mk_sort_16 ( ctx : context ) = - (sort_of_ptr ctx (Z3native.mk_fpa_sort_16 (context_gno ctx))) + (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_16 (context_gno ctx))) let mk_sort_single ( ctx : context ) = - (sort_of_ptr ctx (Z3native.mk_fpa_sort_single (context_gno ctx))) + (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_single (context_gno ctx))) let mk_sort_32 ( ctx : context ) = - (sort_of_ptr ctx (Z3native.mk_fpa_sort_32 (context_gno ctx))) + (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_32 (context_gno ctx))) let mk_sort_double ( ctx : context ) = - (sort_of_ptr ctx (Z3native.mk_fpa_sort_double (context_gno ctx))) + (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_double (context_gno ctx))) let mk_sort_64 ( ctx : context ) = - (sort_of_ptr ctx (Z3native.mk_fpa_sort_64 (context_gno ctx))) + (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_64 (context_gno ctx))) let mk_sort_quadruple ( ctx : context ) = - (sort_of_ptr ctx (Z3native.mk_fpa_sort_quadruple (context_gno ctx))) + (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_quadruple (context_gno ctx))) let mk_sort_128 ( ctx : context ) = - (sort_of_ptr ctx (Z3native.mk_fpa_sort_128 (context_gno ctx))) + (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_128 (context_gno ctx))) - let mk_nan ( ctx : context ) ( s : sort ) = + let mk_nan ( ctx : context ) ( s : Sort.sort ) = (expr_of_ptr ctx (Z3native.mk_fpa_nan (context_gno ctx) (Sort.gno s))) - let mk_inf ( ctx : context ) ( s : sort ) ( negative : bool ) = + let mk_inf ( ctx : context ) ( s : Sort.sort ) ( negative : bool ) = (expr_of_ptr ctx (Z3native.mk_fpa_inf (context_gno ctx) (Sort.gno s) negative)) - let mk_zero ( ctx : context ) ( s : sort ) ( negative : bool ) = + let mk_zero ( ctx : context ) ( s : Sort.sort ) ( negative : bool ) = (expr_of_ptr ctx (Z3native.mk_fpa_zero (context_gno ctx) (Sort.gno s) negative)) let mk_fp ( ctx : context ) ( sign : expr ) ( exponent : expr ) ( significand : expr ) = (expr_of_ptr ctx (Z3native.mk_fpa_fp (context_gno ctx) (Expr.gno sign) (Expr.gno exponent) (Expr.gno significand))) - let mk_numeral_f ( ctx : context ) ( value : float ) ( s : sort ) = + let mk_numeral_f ( ctx : context ) ( value : float ) ( s : Sort.sort ) = (expr_of_ptr ctx (Z3native.mk_fpa_numeral_double (context_gno ctx) value (Sort.gno s))) - let mk_numeral_i ( ctx : context ) ( value : int ) ( s : sort ) = + let mk_numeral_i ( ctx : context ) ( value : int ) ( s : Sort.sort ) = (expr_of_ptr ctx (Z3native.mk_fpa_numeral_int (context_gno ctx) value (Sort.gno s))) - let mk_numeral_i_u ( ctx : context ) ( sign : bool ) ( exponent : int ) ( significand : int ) ( s : sort ) = + let mk_numeral_i_u ( ctx : context ) ( sign : bool ) ( exponent : int ) ( significand : int ) ( s : Sort.sort ) = (expr_of_ptr ctx (Z3native.mk_fpa_numeral_int64_uint64 (context_gno ctx) sign exponent significand (Sort.gno s))) - let mk_numeral_s ( ctx : context ) ( v : string ) ( s : sort ) = + let mk_numeral_s ( ctx : context ) ( v : string ) ( s : Sort.sort ) = (expr_of_ptr ctx (Z3native.mk_numeral (context_gno ctx) v (Sort.gno s))) let is_fp ( x : expr ) = (Sort.get_sort_kind (Expr.get_sort x)) == FLOATING_POINT_SORT @@ -1912,9 +1981,9 @@ struct let is_to_ieee_bv ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_TO_IEEE_BV) let numeral_to_string ( x : expr ) = Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x) - let mk_const ( ctx : context ) ( name : Symbol.symbol ) ( s : sort ) = + let mk_const ( ctx : context ) ( name : Symbol.symbol ) ( s : Sort.sort ) = Expr.mk_const ctx name s - let mk_const_s ( ctx : context ) ( name : string ) ( s : sort ) = + let mk_const_s ( ctx : context ) ( name : string ) ( s : Sort.sort ) = mk_const ctx (Symbol.mk_string ctx name) s let mk_abs ( ctx : context ) ( t : expr ) = @@ -1965,15 +2034,15 @@ struct expr_of_ptr ctx (Z3native.mk_fpa_is_negative (context_gno ctx) (Expr.gno t)) let mk_is_positive ( ctx : context ) ( t : expr ) = expr_of_ptr ctx (Z3native.mk_fpa_is_positive (context_gno ctx) (Expr.gno t)) - let mk_to_fp_bv ( ctx : context ) ( t : expr ) ( s : sort ) = + let mk_to_fp_bv ( ctx : context ) ( t : expr ) ( s : Sort.sort ) = expr_of_ptr ctx (Z3native.mk_fpa_to_fp_bv (context_gno ctx) (Expr.gno t) (Sort.gno s)) - let mk_to_fp_float ( ctx : context ) ( rm : expr) ( t : expr ) ( s : sort ) = + let mk_to_fp_float ( ctx : context ) ( rm : expr) ( t : expr ) ( s : Sort.sort ) = expr_of_ptr ctx (Z3native.mk_fpa_to_fp_float (context_gno ctx) (Expr.gno rm) (Expr.gno t) (Sort.gno s)) - let mk_to_fp_real ( ctx : context ) ( rm : expr ) ( t : expr ) ( s : sort ) = + let mk_to_fp_real ( ctx : context ) ( rm : expr ) ( t : expr ) ( s : Sort.sort ) = expr_of_ptr ctx (Z3native.mk_fpa_to_fp_real (context_gno ctx) (Expr.gno rm) (Expr.gno t) (Sort.gno s)) - let mk_to_fp_signed ( ctx : context ) ( rm : expr) ( t : expr ) ( s : sort ) = + let mk_to_fp_signed ( ctx : context ) ( rm : expr) ( t : expr ) ( s : Sort.sort ) = expr_of_ptr ctx (Z3native.mk_fpa_to_fp_signed (context_gno ctx) (Expr.gno rm) (Expr.gno t) (Sort.gno s)) - let mk_to_fp_unsigned ( ctx : context ) ( rm : expr) ( t : expr ) ( s : sort ) = + let mk_to_fp_unsigned ( ctx : context ) ( rm : expr) ( t : expr ) ( s : Sort.sort ) = expr_of_ptr ctx (Z3native.mk_fpa_to_fp_unsigned (context_gno ctx) (Expr.gno rm) (Expr.gno t) (Sort.gno s)) let mk_to_ubv ( ctx : context ) ( rm : expr) ( t : expr ) ( size : int ) = expr_of_ptr ctx (Z3native.mk_fpa_to_ubv (context_gno ctx) (Expr.gno rm) (Expr.gno t) size) @@ -1982,9 +2051,9 @@ struct let mk_to_real ( ctx : context ) ( t : expr ) = expr_of_ptr ctx (Z3native.mk_fpa_to_real (context_gno ctx) (Expr.gno t)) - let get_ebits ( ctx : context ) ( s : sort ) = + let get_ebits ( ctx : context ) ( s : Sort.sort ) = (Z3native.fpa_get_ebits (context_gno ctx) (Sort.gno s)) - let get_sbits ( ctx : context ) ( s : sort ) = + let get_sbits ( ctx : context ) ( s : Sort.sort ) = (Z3native.fpa_get_sbits (context_gno ctx) (Sort.gno s)) let get_numeral_sign ( ctx : context ) ( t : expr ) = (Z3native.fpa_get_numeral_sign (context_gno ctx) (Expr.gno t)) @@ -1997,7 +2066,7 @@ struct let mk_to_ieee_bv ( ctx : context ) ( t : expr ) = (expr_of_ptr ctx (Z3native.mk_fpa_to_ieee_bv (context_gno ctx) (Expr.gno t))) - let mk_to_fp_int_real ( ctx : context ) ( rm : expr ) ( exponent : expr ) ( significand : expr ) ( s : sort ) = + let mk_to_fp_int_real ( ctx : context ) ( rm : expr ) ( exponent : expr ) ( significand : expr ) ( s : Sort.sort ) = (expr_of_ptr ctx (Z3native.mk_fpa_to_fp_int_real (context_gno ctx) (Expr.gno rm) (Expr.gno exponent) (Expr.gno significand) (Sort.gno s))) let numeral_to_string ( x : expr ) = Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x) @@ -2280,14 +2349,12 @@ struct let get_sorts ( x : model ) = let n = (get_num_sorts x) in - let f i = (sort_of_ptr (z3obj_gc x) (Z3native.model_get_sort (z3obj_gnc x) (z3obj_gno x) i)) in + let f i = (Sort.sort_of_ptr (z3obj_gc x) (Z3native.model_get_sort (z3obj_gnc x) (z3obj_gno x) i)) in mk_list f n - let sort_universe ( x : model ) ( s : sort ) = - let n_univ = AST.ASTVector.create (z3obj_gc x) (Z3native.model_get_sort_universe (z3obj_gnc x) (z3obj_gno x) (Sort.gno s)) in - let n = (AST.ASTVector.get_size n_univ) in - let f i = (AST.ASTVector.get n_univ i) in - mk_list f n + let sort_universe ( x : model ) ( s : Sort.sort ) = + let av = AST.ASTVector.create (z3obj_gc x) (Z3native.model_get_sort_universe (z3obj_gnc x) (z3obj_gno x) (Sort.gno s)) in + (AST.ASTVector.to_expr_list av) let to_string ( x : model ) = Z3native.model_to_string (z3obj_gnc x) (z3obj_gno x) end @@ -2475,6 +2542,91 @@ struct end +module Statistics = +struct + type statistics = z3_native_object + + let create ( ctx : context ) ( no : Z3native.ptr ) = + let res : statistics = { m_ctx = ctx ; + m_n_obj = null ; + inc_ref = Z3native.stats_inc_ref ; + dec_ref = Z3native.stats_dec_ref } in + (z3obj_sno res ctx no) ; + (z3obj_create res) ; + res + + + module Entry = + struct + type statistics_entry = { + mutable m_key : string; + mutable m_is_int : bool ; + mutable m_is_float : bool ; + mutable m_int : int ; + mutable m_float : float } + + let create_si k v = + let res : statistics_entry = { + m_key = k ; + m_is_int = true ; + m_is_float = false ; + m_int = v ; + m_float = 0.0 + } in + res + + let create_sd k v = + let res : statistics_entry = { + m_key = k ; + m_is_int = false ; + m_is_float = true ; + m_int = 0 ; + m_float = v + } in + res + + + let get_key (x : statistics_entry) = x.m_key + let get_int (x : statistics_entry) = x.m_int + let get_float (x : statistics_entry) = x.m_float + let is_int (x : statistics_entry) = x.m_is_int + let is_float (x : statistics_entry) = x.m_is_float + let to_string_value (x : statistics_entry) = + if (is_int x) then + string_of_int (get_int x) + else if (is_float x) then + string_of_float (get_float x) + else + raise (Z3native.Exception "Unknown statistical entry type") + let to_string ( x : statistics_entry ) = (get_key x) ^ ": " ^ (to_string_value x) + end + + let to_string ( x : statistics ) = Z3native.stats_to_string (z3obj_gnc x) (z3obj_gno x) + + let get_size ( x : statistics ) = Z3native.stats_size (z3obj_gnc x) (z3obj_gno x) + + let get_entries ( x : statistics ) = + let n = (get_size x ) in + let f i = ( + let k = Z3native.stats_get_key (z3obj_gnc x) (z3obj_gno x) i in + if (Z3native.stats_is_uint (z3obj_gnc x) (z3obj_gno x) i) then + (Entry.create_si k (Z3native.stats_get_uint_value (z3obj_gnc x) (z3obj_gno x) i)) + else + (Entry.create_sd k (Z3native.stats_get_double_value (z3obj_gnc x) (z3obj_gno x) i)) + ) in + mk_list f n + + let get_keys ( x : statistics ) = + let n = (get_size x) in + let f i = (Z3native.stats_get_key (z3obj_gnc x) (z3obj_gno x) i) in + mk_list f n + + let get ( x : statistics ) ( key : string ) = + let f p c = (if ((Entry.get_key c) == key) then (Some c) else p) in + List.fold_left f None (get_entries x) +end + + module Solver = struct type solver = z3_native_object @@ -2494,90 +2646,6 @@ struct | SATISFIABLE -> "satisfiable" | _ -> "unknown" - module Statistics = - struct - type statistics = z3_native_object - - let create ( ctx : context ) ( no : Z3native.ptr ) = - let res : statistics = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.stats_inc_ref ; - dec_ref = Z3native.stats_dec_ref } in - (z3obj_sno res ctx no) ; - (z3obj_create res) ; - res - - - module Entry = - struct - type statistics_entry = { - mutable m_key : string; - mutable m_is_int : bool ; - mutable m_is_float : bool ; - mutable m_int : int ; - mutable m_float : float } - - let create_si k v = - let res : statistics_entry = { - m_key = k ; - m_is_int = true ; - m_is_float = false ; - m_int = v ; - m_float = 0.0 - } in - res - - let create_sd k v = - let res : statistics_entry = { - m_key = k ; - m_is_int = false ; - m_is_float = true ; - m_int = 0 ; - m_float = v - } in - res - - - let get_key (x : statistics_entry) = x.m_key - let get_int (x : statistics_entry) = x.m_int - let get_float (x : statistics_entry) = x.m_float - let is_int (x : statistics_entry) = x.m_is_int - let is_float (x : statistics_entry) = x.m_is_float - let to_string_value (x : statistics_entry) = - if (is_int x) then - string_of_int (get_int x) - else if (is_float x) then - string_of_float (get_float x) - else - raise (Z3native.Exception "Unknown statistical entry type") - let to_string ( x : statistics_entry ) = (get_key x) ^ ": " ^ (to_string_value x) - end - - let to_string ( x : statistics ) = Z3native.stats_to_string (z3obj_gnc x) (z3obj_gno x) - - let get_size ( x : statistics ) = Z3native.stats_size (z3obj_gnc x) (z3obj_gno x) - - let get_entries ( x : statistics ) = - let n = (get_size x ) in - let f i = ( - let k = Z3native.stats_get_key (z3obj_gnc x) (z3obj_gno x) i in - if (Z3native.stats_is_uint (z3obj_gnc x) (z3obj_gno x) i) then - (Entry.create_si k (Z3native.stats_get_uint_value (z3obj_gnc x) (z3obj_gno x) i)) - else - (Entry.create_sd k (Z3native.stats_get_double_value (z3obj_gnc x) (z3obj_gno x) i)) - ) in - mk_list f n - - let get_keys ( x : statistics ) = - let n = (get_size x) in - let f i = (Z3native.stats_get_key (z3obj_gnc x) (z3obj_gno x) i) in - mk_list f n - - let get ( x : statistics ) ( key : string ) = - let f p c = (if ((Entry.get_key c) == key) then (Some c) else p) in - List.fold_left f None (get_entries x) - end - let get_help ( x : solver ) = Z3native.solver_get_help (z3obj_gnc x) (z3obj_gno x) let set_parameters ( x : solver ) ( p : Params.params )= @@ -2613,10 +2681,8 @@ struct (AST.ASTVector.get_size a) let get_assertions ( x : solver ) = - let a = AST.ASTVector.create (z3obj_gc x) (Z3native.solver_get_assertions (z3obj_gnc x) (z3obj_gno x)) in - let n = (AST.ASTVector.get_size a) in - let f i = (expr_of_ptr (z3obj_gc x) (z3obj_gno (AST.ASTVector.get a i))) in - mk_list f n + let av = AST.ASTVector.create (z3obj_gc x) (Z3native.solver_get_assertions (z3obj_gnc x) (z3obj_gno x)) in + (AST.ASTVector.to_expr_list av) let check ( x : solver ) ( assumptions : expr list ) = let r = @@ -2646,10 +2712,8 @@ struct Some (expr_of_ptr (z3obj_gc x) q) let get_unsat_core ( x : solver ) = - let cn = AST.ASTVector.create (z3obj_gc x) (Z3native.solver_get_unsat_core (z3obj_gnc x) (z3obj_gno x)) in - let n = (AST.ASTVector.get_size cn) in - let f i = (AST.ASTVector.get cn i) in - mk_list f n + let av = AST.ASTVector.create (z3obj_gc x) (Z3native.solver_get_unsat_core (z3obj_gnc x) (z3obj_gno x)) in + (AST.ASTVector.to_expr_list av) let get_reason_unknown ( x : solver ) = Z3native.solver_get_reason_unknown (z3obj_gnc x) (z3obj_gno x) @@ -2720,7 +2784,7 @@ struct | _ -> Solver.UNKNOWN let query_r ( x : fixedpoint ) ( relations : func_decl list ) = - let f x = ptr_of_ast (ast_of_func_decl x) in + let f x = AST.ptr_of_ast (ast_of_func_decl x) in match (lbool_of_int (Z3native.fixedpoint_query_relations (z3obj_gnc x) (z3obj_gno x) (List.length relations) (Array.of_list (List.map f relations)))) with | L_TRUE -> Solver.SATISFIABLE | L_FALSE -> Solver.UNSATISFIABLE @@ -2768,18 +2832,26 @@ struct Z3native.fixedpoint_to_string (z3obj_gnc x) (z3obj_gno x) (List.length queries) (Array.of_list (List.map f queries)) let get_rules ( x : fixedpoint ) = - let v = (AST.ASTVector.create (z3obj_gc x) (Z3native.fixedpoint_get_rules (z3obj_gnc x) (z3obj_gno x))) in - let n = (AST.ASTVector.get_size v) in - let f i =(expr_of_ptr (z3obj_gc x) (z3obj_gno (AST.ASTVector.get v i))) in - mk_list f n + let av = (AST.ASTVector.create (z3obj_gc x) (Z3native.fixedpoint_get_rules (z3obj_gnc x) (z3obj_gno x))) in + (AST.ASTVector.to_expr_list av) let get_assertions ( x : fixedpoint ) = - let v = (AST.ASTVector.create (z3obj_gc x) (Z3native.fixedpoint_get_assertions (z3obj_gnc x) (z3obj_gno x))) in - let n = (AST.ASTVector.get_size v) in - let f i =(expr_of_ptr (z3obj_gc x) (z3obj_gno (AST.ASTVector.get v i))) in - mk_list f n + let av = (AST.ASTVector.create (z3obj_gc x) (Z3native.fixedpoint_get_assertions (z3obj_gnc x) (z3obj_gno x))) in + (AST.ASTVector.to_expr_list av) let mk_fixedpoint ( ctx : context ) = create ctx + + let get_statistics ( x : fixedpoint ) = + let s = Z3native.fixedpoint_get_statistics (z3obj_gnc x) (z3obj_gno x) in + (Statistics.create (z3obj_gc x) s) + + let parse_string ( x : fixedpoint ) ( s : string ) = + let av = (AST.ASTVector.create (z3obj_gc x) (Z3native.fixedpoint_from_string (z3obj_gnc x) (z3obj_gno x) s)) in + (AST.ASTVector.to_expr_list av) + + let parse_file ( x : fixedpoint ) ( filename : string ) = + let av = (AST.ASTVector.create (z3obj_gc x) (Z3native.fixedpoint_from_file (z3obj_gnc x) (z3obj_gno x) filename)) in + (AST.ASTVector.to_expr_list av) end @@ -2790,7 +2862,7 @@ struct (List.length assumptions) (let f x = Expr.gno (x) in (Array.of_list (List.map f assumptions))) (Expr.gno formula) - let parse_smtlib_string ( ctx : context ) ( str : string ) ( sort_names : Symbol.symbol list ) ( sorts : sort list ) ( decl_names : Symbol.symbol list ) ( decls : func_decl list ) = + let parse_smtlib_string ( ctx : context ) ( str : string ) ( sort_names : Symbol.symbol list ) ( sorts : Sort.sort list ) ( decl_names : Symbol.symbol list ) ( decls : func_decl list ) = let csn = (List.length sort_names) in let cs = (List.length sorts) in let cdn = (List.length decl_names) in @@ -2799,14 +2871,14 @@ struct raise (Z3native.Exception "Argument size mismatch") else Z3native.parse_smtlib_string (context_gno ctx) str - cs - (Symbol.symbol_lton sort_names) - (sort_lton sorts) - cd - (Symbol.symbol_lton decl_names) - (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls))) + cs + (Symbol.symbol_lton sort_names) + (Sort.sort_lton sorts) + cd + (Symbol.symbol_lton decl_names) + (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls))) - let parse_smtlib_file ( ctx : context ) ( file_name : string ) ( sort_names : Symbol.symbol list ) ( sorts : sort list ) ( decl_names : Symbol.symbol list ) ( decls : func_decl list ) = + let parse_smtlib_file ( ctx : context ) ( file_name : string ) ( sort_names : Symbol.symbol list ) ( sorts : Sort.sort list ) ( decl_names : Symbol.symbol list ) ( decls : func_decl list ) = let csn = (List.length sort_names) in let cs = (List.length sorts) in let cdn = (List.length decl_names) in @@ -2815,13 +2887,13 @@ struct raise (Z3native.Exception "Argument size mismatch") else Z3native.parse_smtlib_file (context_gno ctx) file_name - cs - (Symbol.symbol_lton sort_names) - (sort_lton sorts) - cd - (Symbol.symbol_lton decl_names) - (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls))) - + cs + (Symbol.symbol_lton sort_names) + (Sort.sort_lton sorts) + cd + (Symbol.symbol_lton decl_names) + (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls))) + let get_num_smtlib_formulas ( ctx : context ) = Z3native.get_smtlib_num_formulas (context_gno ctx) let get_smtlib_formulas ( ctx : context ) = @@ -2847,10 +2919,10 @@ struct let get_smtlib_sorts ( ctx : context ) = let n = (get_num_smtlib_sorts ctx) in - let f i = (sort_of_ptr ctx (Z3native.get_smtlib_sort (context_gno ctx) i)) in + let f i = (Sort.sort_of_ptr ctx (Z3native.get_smtlib_sort (context_gno ctx) i)) in mk_list f n - let parse_smtlib2_string ( ctx : context ) ( str : string ) ( sort_names : Symbol.symbol list ) ( sorts : sort list ) ( decl_names : Symbol.symbol list ) ( decls : func_decl list ) = + let parse_smtlib2_string ( ctx : context ) ( str : string ) ( sort_names : Symbol.symbol list ) ( sorts : Sort.sort list ) ( decl_names : Symbol.symbol list ) ( decls : func_decl list ) = let csn = (List.length sort_names) in let cs = (List.length sorts) in let cdn = (List.length decl_names) in @@ -2859,14 +2931,14 @@ struct raise (Z3native.Exception "Argument size mismatch") else (expr_of_ptr ctx (Z3native.parse_smtlib2_string (context_gno ctx) str - cs - (Symbol.symbol_lton sort_names) - (sort_lton sorts) - cd - (Symbol.symbol_lton decl_names) - (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls))))) - - let parse_smtlib2_file ( ctx : context ) ( file_name : string ) ( sort_names : Symbol.symbol list ) ( sorts : sort list ) ( decl_names : Symbol.symbol list ) ( decls : func_decl list ) = + cs + (Symbol.symbol_lton sort_names) + (Sort.sort_lton sorts) + cd + (Symbol.symbol_lton decl_names) + (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls))))) + + let parse_smtlib2_file ( ctx : context ) ( file_name : string ) ( sort_names : Symbol.symbol list ) ( sorts : Sort.sort list ) ( decl_names : Symbol.symbol list ) ( decls : func_decl list ) = let csn = (List.length sort_names) in let cs = (List.length sorts) in let cdn = (List.length decl_names) in @@ -2875,12 +2947,12 @@ struct raise (Z3native.Exception "Argument size mismatch") else (expr_of_ptr ctx (Z3native.parse_smtlib2_string (context_gno ctx) file_name - cs - (Symbol.symbol_lton sort_names) - (sort_lton sorts) - cd - (Symbol.symbol_lton decl_names) - (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls))))) + cs + (Symbol.symbol_lton sort_names) + (Sort.sort_lton sorts) + cd + (Symbol.symbol_lton decl_names) + (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls))))) end module Interpolation = @@ -2902,14 +2974,17 @@ struct res let get_interpolant ( ctx : context ) ( pf : expr ) ( pat: expr ) ( p : Params.params ) = - (ASTVector.create ctx (Z3native.get_interpolant (context_gno ctx) (Expr.gno pf) (Expr.gno pat) (z3obj_gno p))) + let av = (AST.ASTVector.create ctx (Z3native.get_interpolant (context_gno ctx) (Expr.gno pf) (Expr.gno pat) (z3obj_gno p))) in + AST.ASTVector.to_expr_list av let compute_interpolant ( ctx : context ) ( pat : expr ) ( p : Params.params ) = let (r, interp, model) = (Z3native.compute_interpolant (context_gno ctx) (Expr.gno pat) (z3obj_gno p)) in - match (lbool_of_int r) with - | L_TRUE -> ((ASTVector.create ctx interp), (Model.create ctx model)) - | _ -> raise (Z3native.Exception "Error computing interpolant.") - + let res = (lbool_of_int r) in + match res with + | L_TRUE -> (res, None, Some(Model.create ctx model)) + | L_FALSE -> (res, Some((AST.ASTVector.to_expr_list (AST.ASTVector.create ctx interp))), None) + | _ -> (res, None, None) + let get_interpolation_profile ( ctx : context ) = (Z3native.interpolation_profile (context_gno ctx)) diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli index 3c3b65f56..2099359fa 100644 --- a/src/api/ml/z3.mli +++ b/src/api/ml/z3.mli @@ -123,7 +123,7 @@ sig end (** The abstract syntax tree (AST) module *) -module AST : +module rec AST : sig type ast @@ -156,6 +156,12 @@ sig @return A new ASTVector *) val translate : ast_vector -> context -> ast_vector + (** Translates the ASTVector into an (Ast.ast list) *) + val to_list : ast_vector -> ast list + + (** Translates the ASTVector into an (Expr.expr list) *) + val to_expr_list : ast_vector -> Expr.expr list + (** Retrieves a string representation of the vector. *) val to_string : ast_vector -> string end @@ -189,7 +195,7 @@ sig val get_size : ast_map -> int (** The keys stored in the map. *) - val get_keys : ast_map -> ast list + val get_keys : ast_map -> Expr.expr list (** Retrieves a string representation of the map.*) val to_string : ast_map -> string @@ -260,7 +266,7 @@ sig end (** The Sort module implements type information for ASTs *) -module Sort : +and Sort : sig type sort = Sort of AST.ast @@ -291,7 +297,7 @@ sig end (** Function declarations *) -module rec FuncDecl : +and FuncDecl : sig type func_decl = FuncDecl of AST.ast @@ -2751,7 +2757,7 @@ sig (** The finite set of distinct values that represent the interpretation of a sort. {!get_sorts} @return A list of expressions, where each is an element of the universe of the sort *) - val sort_universe : model -> Sort.sort -> AST.ast list + val sort_universe : model -> Sort.sort -> Expr.expr list (** Conversion of models to strings. @return A string representation of the model. *) @@ -2938,6 +2944,55 @@ sig val interrupt : context -> unit end +(** Objects that track statistical information. *) +module Statistics : +sig + type statistics + + (** Statistical data is organized into pairs of \[Key, Entry\], where every + Entry is either a floating point or integer value. *) + module Entry : + sig + type statistics_entry + + (** The key of the entry. *) + val get_key : statistics_entry -> string + + (** The int-value of the entry. *) + val get_int : statistics_entry -> int + + (** The float-value of the entry. *) + val get_float : statistics_entry -> float + + (** True if the entry is uint-valued. *) + val is_int : statistics_entry -> bool + + (** True if the entry is float-valued. *) + val is_float : statistics_entry -> bool + + (** The string representation of the the entry's value. *) + val to_string_value : statistics_entry -> string + + (** The string representation of the entry (key and value) *) + val to_string : statistics_entry -> string + end + + (** A string representation of the statistical data. *) + val to_string : statistics -> string + + (** The number of statistical data. *) + val get_size : statistics -> int + + (** The data entries. *) + val get_entries : statistics -> Entry.statistics_entry list + + (** The statistical counters. *) + val get_keys : statistics -> string list + + (** The value of a particular statistical counter. *) + val get : statistics -> string -> Entry.statistics_entry option +end + (** Solvers *) module Solver : sig @@ -2946,56 +3001,6 @@ sig val string_of_status : status -> string - (** Objects that track statistical information about solvers. *) - module Statistics : - sig - type statistics - - (** Statistical data is organized into pairs of \[Key, Entry\], where every - Entry is either a floating point or integer value. - *) - module Entry : - sig - type statistics_entry - - (** The key of the entry. *) - val get_key : statistics_entry -> string - - (** The int-value of the entry. *) - val get_int : statistics_entry -> int - - (** The float-value of the entry. *) - val get_float : statistics_entry -> float - - (** True if the entry is uint-valued. *) - val is_int : statistics_entry -> bool - - (** True if the entry is float-valued. *) - val is_float : statistics_entry -> bool - - (** The string representation of the the entry's value. *) - val to_string_value : statistics_entry -> string - - (** The string representation of the entry (key and value) *) - val to_string : statistics_entry -> string - end - - (** A string representation of the statistical data. *) - val to_string : statistics -> string - - (** The number of statistical data. *) - val get_size : statistics -> int - - (** The data entries. *) - val get_entries : statistics -> Entry.statistics_entry list - - (** The statistical counters. *) - val get_keys : statistics -> string list - - (** The value of a particular statistical counter. *) - val get : statistics -> string -> Entry.statistics_entry option - end - (** A string that describes all available solver parameters. *) val get_help : solver -> string @@ -3081,7 +3086,7 @@ sig The unsat core is a subset of [Assertions] The result is empty if [Check] was not invoked before, if its results was not [UNSATISFIABLE], or if core production is disabled. *) - val get_unsat_core : solver -> AST.ast list + val get_unsat_core : solver -> Expr.expr list (** A brief justification of why the last call to [Check] returned [UNKNOWN]. *) val get_reason_unknown : solver -> string @@ -3198,6 +3203,19 @@ sig (** Create a Fixedpoint context. *) val mk_fixedpoint : context -> fixedpoint + + (** Retrieve statistics information from the last call to #Z3_fixedpoint_query. *) + val get_statistics : fixedpoint -> Statistics.statistics + + (** Parse an SMT-LIB2 string with fixedpoint rules. + Add the rules to the current fixedpoint context. + Return the set of queries in the string. *) + val parse_string : fixedpoint -> string -> Expr.expr list + + (** Parse an SMT-LIB2 file with fixedpoint rules. + Add the rules to the current fixedpoint context. + Return the set of queries in the file. *) + val parse_file : fixedpoint -> string -> Expr.expr list end (** Functions for handling SMT and SMT2 expressions and files *) @@ -3272,12 +3290,12 @@ sig (** Gets an interpolant. For more information on interpolation please refer too the C/C++ API, which is well documented. *) - val get_interpolant : context -> Expr.expr -> Expr.expr -> Params.params -> AST.ASTVector.ast_vector + val get_interpolant : context -> Expr.expr -> Expr.expr -> Params.params -> Expr.expr list (** Computes an interpolant. For more information on interpolation please refer too the C/C++ API, which is well documented. *) - val compute_interpolant : context -> Expr.expr -> Params.params -> (AST.ASTVector.ast_vector * Model.model) + val compute_interpolant : context -> Expr.expr -> Params.params -> (Z3enums.lbool * Expr.expr list option * Model.model option) (** Retrieves an interpolation profile. For more information on interpolation please refer From 4da7286a7b09b6c94fca5be167b72c31cbd9a1cd Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 23 May 2015 17:30:19 +0100 Subject: [PATCH 836/925] Fixed various signed/unsigned conversion warnings. --- src/math/simplex/sparse_matrix.h | 2 +- src/math/simplex/sparse_matrix_def.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/math/simplex/sparse_matrix.h b/src/math/simplex/sparse_matrix.h index c02375e7e..8c0357691 100644 --- a/src/math/simplex/sparse_matrix.h +++ b/src/math/simplex/sparse_matrix.h @@ -79,7 +79,7 @@ namespace simplex { }; col_entry(int r, int i): m_row_id(r), m_row_idx(i) {} col_entry(): m_row_id(0), m_row_idx(0) {} - bool is_dead() const { return m_row_id == dead_id; } + bool is_dead() const { return (unsigned) m_row_id == dead_id; } }; struct column; diff --git a/src/math/simplex/sparse_matrix_def.h b/src/math/simplex/sparse_matrix_def.h index 9fa3ceda7..64dcd8d84 100644 --- a/src/math/simplex/sparse_matrix_def.h +++ b/src/math/simplex/sparse_matrix_def.h @@ -79,7 +79,7 @@ namespace simplex { void sparse_matrix::_row::del_row_entry(unsigned idx) { _row_entry & t = m_entries[idx]; SASSERT(!t.is_dead()); - t.m_next_free_row_entry_idx = m_first_free_idx; + t.m_next_free_row_entry_idx = (unsigned)m_first_free_idx; t.m_var = dead_id; m_size--; m_first_free_idx = idx; @@ -513,8 +513,8 @@ namespace simplex { SASSERT(!m.is_zero(e.m_coeff)); SASSERT(e.m_var != dead_id); col_entry const& c = m_columns[e.m_var].m_entries[e.m_col_idx]; - SASSERT(c.m_row_id == row_id); - SASSERT(c.m_row_idx == i); + SASSERT((unsigned)c.m_row_id == row_id); + SASSERT((unsigned)c.m_row_idx == i); vars.insert(e.m_var); } int idx = r.m_first_free_idx; @@ -544,7 +544,7 @@ namespace simplex { _row const& row = m_rows[c.m_row_id]; _row_entry const& r = row.m_entries[c.m_row_idx]; SASSERT(r.m_var == v); - SASSERT(r.m_col_idx == i); + SASSERT((unsigned)r.m_col_idx == i); rows.insert(c.m_row_id); } int idx = col.m_first_free_idx; From 9912b2cd67def9fab10a81dcd9e5bc6490b69d1a Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 23 May 2015 18:01:00 +0100 Subject: [PATCH 837/925] Re-enabled the smt.arith.greatest_error_pivot parameter. --- src/smt/params/smt_params_helper.pyg | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 240d45f15..8be6110d5 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -44,7 +44,8 @@ def_module_params(module_name='smt', ('arith.branch_cut_ratio', UINT, 2, 'branch/cut ratio for linear integer arithmetic'), ('arith.int_eq_branch', BOOL, False, 'branching using derived integer equations'), ('arith.ignore_int', BOOL, False, 'treat integer variables as real'), - ('arith.dump_lemmas', BOOL, False, 'dump arithmetic theory lemmas to files'), + ('arith.dump_lemmas', BOOL, False, 'dump arithmetic theory lemmas to files'), + ('arith.greatest_error_pivot', BOOL, False, 'Pivoting strategy'), ('pb.conflict_frequency', UINT, 1000, 'conflict frequency for Pseudo-Boolean theory'), ('pb.learn_complements', BOOL, True, 'learn complement literals for Pseudo-Boolean theory'), ('pb.enable_compilation', BOOL, True, 'enable compilation into sorting circuits for Pseudo-Boolean'), From 91352369a979d90abb7143c327329cc3c8d433cc Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 26 May 2015 11:20:19 +0100 Subject: [PATCH 838/925] Added conversion functions to ASTVectors in .NET and Java. Fixes #108 --- src/api/dotnet/ASTVector.cs | 110 ++++++++++++++++++++++++- src/api/dotnet/Fixedpoint.cs | 8 +- src/api/dotnet/InterpolationContext.cs | 10 +-- src/api/dotnet/Solver.cs | 4 +- src/api/java/ASTVector.java | 110 ++++++++++++++++++++++++- src/api/java/Fixedpoint.java | 8 +- src/api/java/InterpolationContext.java | 8 +- src/api/java/Solver.java | 4 +- 8 files changed, 239 insertions(+), 23 deletions(-) diff --git a/src/api/dotnet/ASTVector.cs b/src/api/dotnet/ASTVector.cs index f858c7862..8b599ca48 100644 --- a/src/api/dotnet/ASTVector.cs +++ b/src/api/dotnet/ASTVector.cs @@ -112,7 +112,7 @@ namespace Microsoft.Z3 } /// - /// Translates an AST vector into an Expr[] + /// Translates an ASTVector into an Expr[] /// public Expr[] ToExprArray() { @@ -123,6 +123,114 @@ namespace Microsoft.Z3 return res; } + /// + /// Translates an ASTVector into a BoolExpr[] + /// + public BoolExpr[] ToBoolExprArray() + { + uint n = Size; + BoolExpr[] res = new BoolExpr[n]; + for (uint i = 0; i < n; i++) + res[i] = (BoolExpr) Expr.Create(this.Context, this[i].NativeObject); + return res; + } + + /// + /// Translates an ASTVector into a BitVecExpr[] + /// + public BitVecExpr[] ToBitVecExprArray() + { + uint n = Size; + BitVecExpr[] res = new BitVecExpr[n]; + for (uint i = 0; i < n; i++) + res[i] = (BitVecExpr)Expr.Create(this.Context, this[i].NativeObject); + return res; + } + + /// + /// Translates an ASTVector into a ArithExpr[] + /// + public ArithExpr[] ToArithExprArray() + { + uint n = Size; + ArithExpr[] res = new ArithExpr[n]; + for (uint i = 0; i < n; i++) + res[i] = (ArithExpr)Expr.Create(this.Context, this[i].NativeObject); + return res; + } + + /// + /// Translates an ASTVector into a ArrayExpr[] + /// + public ArrayExpr[] ToArrayExprArray() + { + uint n = Size; + ArrayExpr[] res = new ArrayExpr[n]; + for (uint i = 0; i < n; i++) + res[i] = (ArrayExpr)Expr.Create(this.Context, this[i].NativeObject); + return res; + } + + /// + /// Translates an ASTVector into a DatatypeExpr[] + /// + public DatatypeExpr[] ToDatatypeExprArray() + { + uint n = Size; + DatatypeExpr[] res = new DatatypeExpr[n]; + for (uint i = 0; i < n; i++) + res[i] = (DatatypeExpr)Expr.Create(this.Context, this[i].NativeObject); + return res; + } + + /// + /// Translates an ASTVector into a FPExpr[] + /// + public FPExpr[] ToFPExprArray() + { + uint n = Size; + FPExpr[] res = new FPExpr[n]; + for (uint i = 0; i < n; i++) + res[i] = (FPExpr)Expr.Create(this.Context, this[i].NativeObject); + return res; + } + + /// + /// Translates an ASTVector into a FPRMExpr[] + /// + public FPRMExpr[] ToFPRMExprArray() + { + uint n = Size; + FPRMExpr[] res = new FPRMExpr[n]; + for (uint i = 0; i < n; i++) + res[i] = (FPRMExpr)Expr.Create(this.Context, this[i].NativeObject); + return res; + } + + /// + /// Translates an ASTVector into a IntExpr[] + /// + public IntExpr[] ToIntExprArray() + { + uint n = Size; + IntExpr[] res = new IntExpr[n]; + for (uint i = 0; i < n; i++) + res[i] = (IntExpr)Expr.Create(this.Context, this[i].NativeObject); + return res; + } + + /// + /// Translates an ASTVector into a RealExpr[] + /// + public RealExpr[] ToRealExprArray() + { + uint n = Size; + RealExpr[] res = new RealExpr[n]; + for (uint i = 0; i < n; i++) + res[i] = (RealExpr)Expr.Create(this.Context, this[i].NativeObject); + return res; + } + #region Internal internal ASTVector(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); } internal ASTVector(Context ctx) : base(ctx, Native.Z3_mk_ast_vector(ctx.nCtx)) { Contract.Requires(ctx != null); } diff --git a/src/api/dotnet/Fixedpoint.cs b/src/api/dotnet/Fixedpoint.cs index 54dbcd3c1..66449ddbb 100644 --- a/src/api/dotnet/Fixedpoint.cs +++ b/src/api/dotnet/Fixedpoint.cs @@ -279,7 +279,7 @@ namespace Microsoft.Z3 Contract.Ensures(Contract.Result() != null); ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_get_rules(Context.nCtx, NativeObject)); - return (BoolExpr[])av.ToExprArray(); + return av.ToBoolExprArray(); } } @@ -293,7 +293,7 @@ namespace Microsoft.Z3 Contract.Ensures(Contract.Result() != null); ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_get_assertions(Context.nCtx, NativeObject)); - return (BoolExpr[])av.ToExprArray(); + return av.ToBoolExprArray(); } } @@ -318,7 +318,7 @@ namespace Microsoft.Z3 public BoolExpr[] ParseFile(string file) { ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_from_file(Context.nCtx, NativeObject, file)); - return (BoolExpr[])av.ToExprArray(); + return av.ToBoolExprArray(); } /// @@ -327,7 +327,7 @@ namespace Microsoft.Z3 public BoolExpr[] ParseString(string s) { ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_from_string(Context.nCtx, NativeObject, s)); - return (BoolExpr[])av.ToExprArray(); + return av.ToBoolExprArray(); } diff --git a/src/api/dotnet/InterpolationContext.cs b/src/api/dotnet/InterpolationContext.cs index 9fbdf456e..e6e258b9a 100644 --- a/src/api/dotnet/InterpolationContext.cs +++ b/src/api/dotnet/InterpolationContext.cs @@ -47,7 +47,7 @@ namespace Microsoft.Z3 /// For more information on interpolation please refer /// too the function Z3_get_interpolant in the C/C++ API, which is /// well documented. - public Expr[] GetInterpolant(Expr pf, Expr pat, Params p) + public BoolExpr[] GetInterpolant(Expr pf, Expr pat, Params p) { Contract.Requires(pf != null); Contract.Requires(pat != null); @@ -59,7 +59,7 @@ namespace Microsoft.Z3 CheckContextMatch(p); ASTVector seq = new ASTVector(this, Native.Z3_get_interpolant(nCtx, pf.NativeObject, pat.NativeObject, p.NativeObject)); - return seq.ToExprArray(); + return seq.ToBoolExprArray(); } /// @@ -68,7 +68,7 @@ namespace Microsoft.Z3 /// For more information on interpolation please refer /// too the function Z3_compute_interpolant in the C/C++ API, which is /// well documented. - public Z3_lbool ComputeInterpolant(Expr pat, Params p, out Expr[] interp, out Model model) + public Z3_lbool ComputeInterpolant(Expr pat, Params p, out BoolExpr[] interp, out Model model) { Contract.Requires(pat != null); Contract.Requires(p != null); @@ -80,7 +80,7 @@ namespace Microsoft.Z3 IntPtr i = IntPtr.Zero, m = IntPtr.Zero; int r = Native.Z3_compute_interpolant(nCtx, pat.NativeObject, p.NativeObject, ref i, ref m); - interp = new ASTVector(this, i).ToExprArray(); + interp = new ASTVector(this, i).ToBoolExprArray(); model = new Model(this, m); return (Z3_lbool)r; } @@ -102,7 +102,7 @@ namespace Microsoft.Z3 /// For more information on interpolation please refer /// too the function Z3_check_interpolant in the C/C++ API, which is /// well documented. - public int CheckInterpolant(Expr[] cnsts, uint[] parents, Expr[] interps, out string error, Expr[] theory) + public int CheckInterpolant(Expr[] cnsts, uint[] parents, BoolExpr[] interps, out string error, Expr[] theory) { Contract.Requires(cnsts.Length == parents.Length); Contract.Requires(cnsts.Length == interps.Length + 1); diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index c5227d18f..80ca7a0cd 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -193,7 +193,7 @@ namespace Microsoft.Z3 Contract.Ensures(Contract.Result() != null); ASTVector assertions = new ASTVector(Context, Native.Z3_solver_get_assertions(Context.nCtx, NativeObject)); - return (BoolExpr[])assertions.ToExprArray(); + return assertions.ToBoolExprArray(); } } @@ -273,7 +273,7 @@ namespace Microsoft.Z3 Contract.Ensures(Contract.Result() != null); ASTVector core = new ASTVector(Context, Native.Z3_solver_get_unsat_core(Context.nCtx, NativeObject)); - return (BoolExpr[])core.ToExprArray(); + return core.ToBoolExprArray(); } } diff --git a/src/api/java/ASTVector.java b/src/api/java/ASTVector.java index 7011eeb50..5b57db9d9 100644 --- a/src/api/java/ASTVector.java +++ b/src/api/java/ASTVector.java @@ -142,4 +142,112 @@ public class ASTVector extends Z3Object res[i] = Expr.create(getContext(), get(i).getNativeObject()); return res; } -} + + /** + * Translates the AST vector into an BoolExpr[] + * */ + public BoolExpr[] ToBoolExprArray() + { + int n = size(); + BoolExpr[] res = new BoolExpr[n]; + for (int i = 0; i < n; i++) + res[i] = (BoolExpr) Expr.create(getContext(), get(i).getNativeObject()); + return res; + } + + /** + * Translates the AST vector into an BitVecExpr[] + * */ + public BitVecExpr[] ToBitVecExprArray() + { + int n = size(); + BitVecExpr[] res = new BitVecExpr[n]; + for (int i = 0; i < n; i++) + res[i] = (BitVecExpr)Expr.create(getContext(), get(i).getNativeObject()); + return res; + } + + /** + * Translates the AST vector into an ArithExpr[] + * */ + public ArithExpr[] ToArithExprExprArray() + { + int n = size(); + ArithExpr[] res = new ArithExpr[n]; + for (int i = 0; i < n; i++) + res[i] = (ArithExpr)Expr.create(getContext(), get(i).getNativeObject()); + return res; + } + + /** + * Translates the AST vector into an ArrayExpr[] + * */ + public ArrayExpr[] ToArrayExprArray() + { + int n = size(); + ArrayExpr[] res = new ArrayExpr[n]; + for (int i = 0; i < n; i++) + res[i] = (ArrayExpr)Expr.create(getContext(), get(i).getNativeObject()); + return res; + } + + /** + * Translates the AST vector into an DatatypeExpr[] + * */ + public DatatypeExpr[] ToDatatypeExprArray() + { + int n = size(); + DatatypeExpr[] res = new DatatypeExpr[n]; + for (int i = 0; i < n; i++) + res[i] = (DatatypeExpr)Expr.create(getContext(), get(i).getNativeObject()); + return res; + } + + /** + * Translates the AST vector into an FPExpr[] + * */ + public FPExpr[] ToFPExprArray() + { + int n = size(); + FPExpr[] res = new FPExpr[n]; + for (int i = 0; i < n; i++) + res[i] = (FPExpr)Expr.create(getContext(), get(i).getNativeObject()); + return res; + } + + /** + * Translates the AST vector into an FPRMExpr[] + * */ + public FPRMExpr[] ToFPRMExprArray() + { + int n = size(); + FPRMExpr[] res = new FPRMExpr[n]; + for (int i = 0; i < n; i++) + res[i] = (FPRMExpr)Expr.create(getContext(), get(i).getNativeObject()); + return res; + } + + /** + * Translates the AST vector into an IntExpr[] + * */ + public IntExpr[] ToIntExprArray() + { + int n = size(); + IntExpr[] res = new IntExpr[n]; + for (int i = 0; i < n; i++) + res[i] = (IntExpr)Expr.create(getContext(), get(i).getNativeObject()); + return res; + } + + /** + * Translates the AST vector into an RealExpr[] + * */ + public RealExpr[] ToRealExprArray() + { + int n = size(); + RealExpr[] res = new RealExpr[n]; + for (int i = 0; i < n; i++) + res[i] = (RealExpr)Expr.create(getContext(), get(i).getNativeObject()); + return res; + } +} \ No newline at end of file diff --git a/src/api/java/Fixedpoint.java b/src/api/java/Fixedpoint.java index b59a9700a..e1fccdf4f 100644 --- a/src/api/java/Fixedpoint.java +++ b/src/api/java/Fixedpoint.java @@ -296,7 +296,7 @@ public class Fixedpoint extends Z3Object public BoolExpr[] getRules() { ASTVector v = new ASTVector(getContext(), Native.fixedpointGetRules(getContext().nCtx(), getNativeObject())); - return (BoolExpr[]) v.ToExprArray(); + return v.ToBoolExprArray(); } /** @@ -307,7 +307,7 @@ public class Fixedpoint extends Z3Object public BoolExpr[] getAssertions() { ASTVector v = new ASTVector(getContext(), Native.fixedpointGetAssertions(getContext().nCtx(), getNativeObject())); - return (BoolExpr[]) v.ToExprArray(); + return v.ToBoolExprArray(); } /** @@ -329,7 +329,7 @@ public class Fixedpoint extends Z3Object public BoolExpr[] ParseFile(String file) { ASTVector av = new ASTVector(getContext(), Native.fixedpointFromFile(getContext().nCtx(), getNativeObject(), file)); - return (BoolExpr[])av.ToExprArray(); + return av.ToBoolExprArray(); } /** @@ -340,7 +340,7 @@ public class Fixedpoint extends Z3Object public BoolExpr[] ParseString(String s) { ASTVector av = new ASTVector(getContext(), Native.fixedpointFromString(getContext().nCtx(), getNativeObject(), s)); - return (BoolExpr[])av.ToExprArray(); + return av.ToBoolExprArray(); } diff --git a/src/api/java/InterpolationContext.java b/src/api/java/InterpolationContext.java index 5af2a6af8..ddce9ee33 100644 --- a/src/api/java/InterpolationContext.java +++ b/src/api/java/InterpolationContext.java @@ -73,14 +73,14 @@ public class InterpolationContext extends Context * well documented. * @throws Z3Exception **/ - public Expr[] GetInterpolant(Expr pf, Expr pat, Params p) + public BoolExpr[] GetInterpolant(Expr pf, Expr pat, Params p) { checkContextMatch(pf); checkContextMatch(pat); checkContextMatch(p); ASTVector seq = new ASTVector(this, Native.getInterpolant(nCtx(), pf.getNativeObject(), pat.getNativeObject(), p.getNativeObject())); - return seq.ToExprArray(); + return seq.ToBoolExprArray(); } public class ComputeInterpolantResult @@ -107,7 +107,7 @@ public class InterpolationContext extends Context Native.LongPtr n_m = new Native.LongPtr(); res.status = Z3_lbool.fromInt(Native.computeInterpolant(nCtx(), pat.getNativeObject(), p.getNativeObject(), n_i, n_m)); if (res.status == Z3_lbool.Z3_L_FALSE) - res.interp = (BoolExpr[]) (new ASTVector(this, n_i.value)).ToExprArray(); + res.interp = (new ASTVector(this, n_i.value)).ToBoolExprArray(); if (res.status == Z3_lbool.Z3_L_TRUE) res.model = new Model(this, n_m.value); return res; } @@ -135,7 +135,7 @@ public class InterpolationContext extends Context /// Remarks: For more information on interpolation please refer /// too the function Z3_check_interpolant in the C/C++ API, which is /// well documented. - public CheckInterpolantResult CheckInterpolant(Expr[] cnsts, int[] parents, Expr[] interps, String error, Expr[] theory) + public CheckInterpolantResult CheckInterpolant(Expr[] cnsts, int[] parents, BoolExpr[] interps, String error, Expr[] theory) { CheckInterpolantResult res = new CheckInterpolantResult(); Native.StringPtr n_err_str = new Native.StringPtr(); diff --git a/src/api/java/Solver.java b/src/api/java/Solver.java index eb8e81aa5..4d2d9b641 100644 --- a/src/api/java/Solver.java +++ b/src/api/java/Solver.java @@ -188,7 +188,7 @@ public class Solver extends Z3Object public BoolExpr[] getAssertions() { ASTVector assrts = new ASTVector(getContext(), Native.solverGetAssertions(getContext().nCtx(), getNativeObject())); - return (BoolExpr[]) assrts.ToExprArray(); + return assrts.ToBoolExprArray(); } /** @@ -280,7 +280,7 @@ public class Solver extends Z3Object { ASTVector core = new ASTVector(getContext(), Native.solverGetUnsatCore(getContext().nCtx(), getNativeObject())); - return (BoolExpr[])core.ToExprArray(); + return core.ToBoolExprArray(); } /** From 98975e518715b60722df294487df6e105935ef9f Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 27 May 2015 14:47:24 +0100 Subject: [PATCH 839/925] Reordered the default qflia probe to be checked before the more permissive qfauflia. --- src/tactic/portfolio/default_tactic.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tactic/portfolio/default_tactic.cpp b/src/tactic/portfolio/default_tactic.cpp index ad811cc70..72c486c24 100644 --- a/src/tactic/portfolio/default_tactic.cpp +++ b/src/tactic/portfolio/default_tactic.cpp @@ -35,9 +35,9 @@ Notes: tactic * mk_default_tactic(ast_manager & m, params_ref const & p) { tactic * st = using_params(and_then(mk_simplify_tactic(m), cond(mk_is_qfbv_probe(), mk_qfbv_tactic(m), - cond(mk_is_qfaufbv_probe(), mk_qfaufbv_tactic(m), - cond(mk_is_qfauflia_probe(), mk_qfauflia_tactic(m), + cond(mk_is_qfaufbv_probe(), mk_qfaufbv_tactic(m), cond(mk_is_qflia_probe(), mk_qflia_tactic(m), + cond(mk_is_qfauflia_probe(), mk_qfauflia_tactic(m), cond(mk_is_qflra_probe(), mk_qflra_tactic(m), cond(mk_is_qfnra_probe(), mk_qfnra_tactic(m), cond(mk_is_qfnia_probe(), mk_qfnia_tactic(m), From b10f79a941c0114e37d8daa9a30b1b84d1cf5e08 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 27 May 2015 17:07:18 +0100 Subject: [PATCH 840/925] dl_compiler: minor simplifications Signed-off-by: Nuno Lopes --- src/muz/rel/dl_compiler.cpp | 14 ++++++++------ src/muz/rel/dl_compiler.h | 8 ++++---- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/muz/rel/dl_compiler.cpp b/src/muz/rel/dl_compiler.cpp index 9e8ead241..59ba260a4 100644 --- a/src/muz/rel/dl_compiler.cpp +++ b/src/muz/rel/dl_compiler.cpp @@ -85,7 +85,7 @@ namespace datalog { removed_cols.size(), removed_cols.c_ptr(), result)); } - void compiler::make_select_equal_and_project(reg_idx src, const relation_element & val, unsigned col, + void compiler::make_select_equal_and_project(reg_idx src, const relation_element val, unsigned col, reg_idx & result, bool reuse, instruction_block & acc) { relation_signature res_sig; relation_signature::from_project(m_reg_signatures[src], 1, &col, res_sig); @@ -139,7 +139,7 @@ namespace datalog { return r; } - compiler::reg_idx compiler::get_single_column_register(const relation_sort & s) { + compiler::reg_idx compiler::get_single_column_register(const relation_sort s) { relation_signature singl_sig; singl_sig.push_back(s); return get_fresh_register(singl_sig); @@ -165,7 +165,7 @@ namespace datalog { } } - void compiler::make_add_constant_column(func_decl* head_pred, reg_idx src, const relation_sort & s, const relation_element & val, + void compiler::make_add_constant_column(func_decl* head_pred, reg_idx src, const relation_sort s, const relation_element val, reg_idx & result, bool & dealloc, instruction_block & acc) { reg_idx singleton_table; if(!m_constant_registers.find(s, val, singleton_table)) { @@ -185,7 +185,7 @@ namespace datalog { } } - void compiler::make_add_unbound_column(rule* compiled_rule, unsigned col_idx, func_decl* pred, reg_idx src, const relation_sort & s, reg_idx & result, + void compiler::make_add_unbound_column(rule* compiled_rule, unsigned col_idx, func_decl* pred, reg_idx src, const relation_sort s, reg_idx & result, bool & dealloc, instruction_block & acc) { TRACE("dl", tout << "Adding unbound column " << mk_pp(pred, m_context.get_manager()) << "\n";); @@ -862,9 +862,11 @@ namespace datalog { ast_manager& m = m_context.get_manager(); unsigned pt_len = r->get_positive_tail_size(); unsigned ut_len = r->get_uninterpreted_tail_size(); - if (pt_len == ut_len) { + + // no negated predicates + if (pt_len == ut_len) return; - } + // populate negative variables: for (unsigned i = pt_len; i < ut_len; ++i) { app * neg_tail = r->get_tail(i); diff --git a/src/muz/rel/dl_compiler.h b/src/muz/rel/dl_compiler.h index 8c33f987c..4902b9387 100644 --- a/src/muz/rel/dl_compiler.h +++ b/src/muz/rel/dl_compiler.h @@ -135,7 +135,7 @@ namespace datalog { reg_idx get_fresh_register(const relation_signature & sig); reg_idx get_register(const relation_signature & sig, bool reuse, reg_idx r); - reg_idx get_single_column_register(const relation_sort & s); + reg_idx get_single_column_register(const relation_sort s); /** \brief Allocate registers for predicates in \c pred and add them into the \c regs map. @@ -150,7 +150,7 @@ namespace datalog { const unsigned_vector & removed_cols, reg_idx & result, bool reuse_t1, instruction_block & acc); void make_filter_interpreted_and_project(reg_idx src, app_ref & cond, const unsigned_vector & removed_cols, reg_idx & result, bool reuse, instruction_block & acc); - void make_select_equal_and_project(reg_idx src, const relation_element & val, unsigned col, + void make_select_equal_and_project(reg_idx src, const relation_element val, unsigned col, reg_idx & result, bool reuse, instruction_block & acc); /** \brief Create add an union or widen operation and put it into \c acc. @@ -174,10 +174,10 @@ namespace datalog { void make_dealloc_non_void(reg_idx r, instruction_block & acc); - void make_add_constant_column(func_decl* pred, reg_idx src, const relation_sort & s, const relation_element & val, + void make_add_constant_column(func_decl* pred, reg_idx src, const relation_sort s, const relation_element val, reg_idx & result, bool & dealloc, instruction_block & acc); - void make_add_unbound_column(rule* compiled_rule, unsigned col_idx, func_decl* pred, reg_idx src, const relation_sort & s, reg_idx & result, + void make_add_unbound_column(rule* compiled_rule, unsigned col_idx, func_decl* pred, reg_idx src, const relation_sort s, reg_idx & result, bool & dealloc, instruction_block & acc); void make_full_relation(func_decl* pred, const relation_signature & sig, reg_idx & result, instruction_block & acc); From cb0055563582b80d96907cad9863d63b22c115e9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 27 May 2015 09:18:52 -0700 Subject: [PATCH 841/925] local changes Signed-off-by: Nikolaj Bjorner --- src/api/java/InterpolationContext.java | 11 ++++++++--- src/math/euclid/euclidean_solver.cpp | 1 + src/smt/smt_internalizer.cpp | 6 ++++-- src/smt/theory_arith_core.h | 2 ++ src/smt/theory_arith_int.h | 4 +++- 5 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/api/java/InterpolationContext.java b/src/api/java/InterpolationContext.java index 667c91a53..5ce5a584a 100644 --- a/src/api/java/InterpolationContext.java +++ b/src/api/java/InterpolationContext.java @@ -90,7 +90,7 @@ public class InterpolationContext extends Context public class ComputeInterpolantResult { public Z3_lbool status = Z3_lbool.Z3_L_UNDEF; - public ASTVector interp = null; + public BoolExpr[] interp = null; public Model model = null; }; @@ -109,8 +109,13 @@ public class InterpolationContext extends Context ComputeInterpolantResult res = new ComputeInterpolantResult(); Native.LongPtr n_i = new Native.LongPtr(); Native.LongPtr n_m = new Native.LongPtr(); - res.status =Z3_lbool.fromInt(Native.computeInterpolant(nCtx(), pat.getNativeObject(), p.getNativeObject(), n_i, n_m)); - if (res.status == Z3_lbool.Z3_L_FALSE) res.interp = new ASTVector(this, n_i.value); + res.status = Z3_lbool.fromInt(Native.computeInterpolant(nCtx(), pat.getNativeObject(), p.getNativeObject(), n_i, n_m)); + if (res.status == Z3_lbool.Z3_L_FALSE) {xx + res.interp = new BoolExpr[Native.astVectorSize(nCtx(), n_i.value)]; + for (int i = 0; i < res.interp.Length; ++i) { + res.interp[i] = new BoolExpr(this, Native.astVectorGet(nCtx(), i)); + } + } if (res.status == Z3_lbool.Z3_L_TRUE) res.model = new Model(this, n_m.value); return res; } diff --git a/src/math/euclid/euclidean_solver.cpp b/src/math/euclid/euclidean_solver.cpp index 02ff1591e..9225a87ee 100644 --- a/src/math/euclid/euclidean_solver.cpp +++ b/src/math/euclid/euclidean_solver.cpp @@ -609,6 +609,7 @@ struct euclidean_solver::imp { // neg coeffs... to make sure that m_next_x is -1 neg_coeffs(eq.m_as); neg_coeffs(eq.m_bs); + m().neg(eq.m_c); } unsigned sz = eq.size(); for (unsigned i = 0; i < sz; i++) { diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index 74f2e09fa..4f810727a 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -1411,6 +1411,10 @@ namespace smt { void context::mk_th_axiom(theory_id tid, unsigned num_lits, literal * lits, unsigned num_params, parameter * params) { justification * js = 0; + TRACE("mk_th_axiom", + display_literals_verbose(tout, num_lits, lits); + tout << "\n";); + if (m_manager.proofs_enabled()) { js = mk_justification(theory_axiom_justification(tid, m_region, num_lits, lits, num_params, params)); } @@ -1425,13 +1429,11 @@ namespace smt { void context::mk_th_axiom(theory_id tid, literal l1, literal l2, unsigned num_params, parameter * params) { literal ls[2] = { l1, l2 }; - TRACE("mk_th_axiom", display_literal(tout, l1); tout << " "; display_literal(tout, l2); tout << "\n";); mk_th_axiom(tid, 2, ls, num_params, params); } void context::mk_th_axiom(theory_id tid, literal l1, literal l2, literal l3, unsigned num_params, parameter * params) { literal ls[3] = { l1, l2, l3 }; - TRACE("mk_th_axiom", display_literal(tout, l1); tout << " "; display_literal(tout, l2); tout << " "; display_literal(tout, l3); tout << "\n";); mk_th_axiom(tid, 3, ls, num_params, params); } diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index f481e35d0..d0c9953c2 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -439,6 +439,7 @@ namespace smt { j += rational(1); } ctx.mk_th_axiom(get_id(), lits.size(), lits.begin()); + #else // performs slightly worse. literal_buffer lits; @@ -2788,6 +2789,7 @@ namespace smt { tout << " --> "; ctx.display_detailed_literal(tout, l); tout << "\n";); + SASSERT(false); if (ante.lits().size() < small_lemma_size() && ante.eqs().empty()) { literal_vector & lits = m_tmp_literal_vector2; lits.reset(); diff --git a/src/smt/theory_arith_int.h b/src/smt/theory_arith_int.h index 45c615e0c..d34b02a27 100644 --- a/src/smt/theory_arith_int.h +++ b/src/smt/theory_arith_int.h @@ -1061,6 +1061,7 @@ namespace smt { } if (!failed) { m_solver.assert_eq(as.size(), as.c_ptr(), xs.c_ptr(), c, j); + TRACE("euclidean_solver", tout << "add definition: v" << v << " := " << mk_ismt2_pp(n, t.get_manager()) << "\n";); } else { TRACE("euclidean_solver", tout << "failed for:\n" << mk_ismt2_pp(n, t.get_manager()) << "\n";); @@ -1191,7 +1192,8 @@ namespace smt { if (l != 0) { rational l_old = l->get_value().get_rational().to_rational(); rational l_new = g*ceil((l_old - c2)/g) + c2; - TRACE("euclidean_solver_new", tout << "new lower: " << l_new << " old: " << l_old << "\n";); + TRACE("euclidean_solver_new", tout << "new lower: " << l_new << " old: " << l_old << "\n"; + tout << "c: " << c2 << " ceil((l_old - c2)/g): " << (ceil((l_old - c2)/g)) << "\n";); if (l_new > l_old) { propagated = true; mk_lower(v, l_new, l, m_js); From 562ed61a2415273e88f149113b8a1cc348e6d7da Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 27 May 2015 09:30:37 -0700 Subject: [PATCH 842/925] add shorthands for creating uninterpreted sorts to context API Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 0c5b34fb1..3c2053a5c 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -203,7 +203,12 @@ namespace z3 { and in \c ts the predicates for testing if terms of the enumeration sort correspond to an enumeration. */ sort enumeration_sort(char const * name, unsigned n, char const * const * enum_names, func_decl_vector & cs, func_decl_vector & ts); - + /** + \brief create an uninterpreted sort with the name given by the string or symbol. + */ + sort uninterpreted_sort(char const* name); + sort uninterpreted_sort(symbol const& name); + func_decl function(symbol const & name, unsigned arity, sort const * domain, sort const & range); func_decl function(char const * name, unsigned arity, sort const * domain, sort const & range); func_decl function(symbol const& name, sort_vector const& domain, sort const& range); @@ -1637,6 +1642,13 @@ namespace z3 { for (unsigned i = 0; i < n; i++) { cs.push_back(func_decl(*this, _cs[i])); ts.push_back(func_decl(*this, _ts[i])); } return s; } + inline sort context::uninterpreted_sort(char const* name) { + Z3_symbol _name = Z3_mk_string_symbol(*this, name); + return to_sort(*this, Z3_mk_uninterpreted_sort(*this, _name)); + } + inline sort context::uninterpreted_sort(symbol const& name) { + return to_sort(*this, Z3_mk_uninterpreted_sort(*this, name)); + } inline func_decl context::function(symbol const & name, unsigned arity, sort const * domain, sort const & range) { array args(arity); From 4f02d380aa9d0fc95fd24975357fbff5825176b8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 27 May 2015 09:34:47 -0700 Subject: [PATCH 843/925] make use of uninterpreted_sort shorthand Signed-off-by: Nikolaj Bjorner --- examples/tptp/tptp5.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/tptp/tptp5.cpp b/examples/tptp/tptp5.cpp index d40aa93e9..63971a7d9 100644 --- a/examples/tptp/tptp5.cpp +++ b/examples/tptp/tptp5.cpp @@ -1089,12 +1089,11 @@ class env { } z3::sort mk_sort(char const* s) { - z3::symbol sym = symbol(s); - return mk_sort(sym); + return m_context.uninterpreted_sort(s); } z3::sort mk_sort(z3::symbol& s) { - return z3::sort(m_context, Z3_mk_uninterpreted_sort(m_context, s)); + return m_context.uninterpreted_sort(s); } public: From e3b1ce1fdc24baf10be47ef760393c384c518c23 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 27 May 2015 10:07:09 -0700 Subject: [PATCH 844/925] also allw n-ary distrinct Signed-off-by: Nikolaj Bjorner --- examples/tptp/tptp5.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/tptp/tptp5.cpp b/examples/tptp/tptp5.cpp index 63971a7d9..3b8d2364d 100644 --- a/examples/tptp/tptp5.cpp +++ b/examples/tptp/tptp5.cpp @@ -809,8 +809,12 @@ class env { r = terms[0] / terms[1]; } else if (!strcmp(ch,"$distinct")) { - check_arity(terms.size(), 2); - r = terms[0] != terms[1]; + if (terms.size() == 2) { + r = terms[0] != terms[1]; + } + else { + r = distinct(terms); + } } else if (!strcmp(ch,"$floor") || !strcmp(ch,"$to_int")) { check_arity(terms.size(), 1); From 534271db08fbf0217dc44e99f3b5e837f9d29ccf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 27 May 2015 14:48:51 -0700 Subject: [PATCH 845/925] adding parameters to gomory cut axioms Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith.h | 2 ++ src/smt/theory_arith_int.h | 21 ++++++++++++--------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 660a11faa..db4b01395 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -245,6 +245,8 @@ namespace smt { parameter* params(char const* name); }; + class gomory_cut_justification; + class bound { protected: theory_var m_var; diff --git a/src/smt/theory_arith_int.h b/src/smt/theory_arith_int.h index 8993d6c84..cc69bb533 100644 --- a/src/smt/theory_arith_int.h +++ b/src/smt/theory_arith_int.h @@ -460,13 +460,16 @@ namespace smt { SASSERT(is_well_sorted(get_manager(), result)); } - class gomory_cut_justification : public ext_theory_propagation_justification { + template + class theory_arith::gomory_cut_justification : public ext_theory_propagation_justification { public: - gomory_cut_justification(family_id fid, region & r, + gomory_cut_justification(family_id fid, region & r, unsigned num_lits, literal const * lits, unsigned num_eqs, enode_pair const * eqs, + antecedents& bounds, literal consequent): - ext_theory_propagation_justification(fid, r, num_lits, lits, num_eqs, eqs, consequent) { + ext_theory_propagation_justification(fid, r, num_lits, lits, num_eqs, eqs, consequent, + bounds.num_params(), bounds.params("gomory-cut")) { } // Remark: the assignment must be propagated back to arith virtual theory_id get_from_theory() const { return null_theory_id; } @@ -530,7 +533,7 @@ namespace smt { } // k += new_a_ij * lower_bound(x_j).get_rational(); k.addmul(new_a_ij, lower_bound(x_j).get_rational()); - lower(x_j)->push_justification(ante, numeral::zero(), coeffs_enabled()); + lower(x_j)->push_justification(ante, new_a_ij, coeffs_enabled()); } else { SASSERT(at_upper(x_j)); @@ -546,7 +549,7 @@ namespace smt { } // k += new_a_ij * upper_bound(x_j).get_rational(); k.addmul(new_a_ij, upper_bound(x_j).get_rational()); - upper(x_j)->push_justification(ante, numeral::zero(), coeffs_enabled()); + upper(x_j)->push_justification(ante, new_a_ij, coeffs_enabled()); } pol.push_back(row_entry(new_a_ij, x_j)); } @@ -571,7 +574,7 @@ namespace smt { } // k += new_a_ij * lower_bound(x_j).get_rational(); k.addmul(new_a_ij, lower_bound(x_j).get_rational()); - lower(x_j)->push_justification(ante, numeral::zero(), coeffs_enabled()); + lower(x_j)->push_justification(ante, new_a_ij, coeffs_enabled()); } else { SASSERT(at_upper(x_j)); @@ -584,7 +587,7 @@ namespace smt { new_a_ij.neg(); // the upper terms are inverted // k += new_a_ij * upper_bound(x_j).get_rational(); k.addmul(new_a_ij, upper_bound(x_j).get_rational()); - upper(x_j)->push_justification(ante, numeral::zero(), coeffs_enabled()); + upper(x_j)->push_justification(ante, new_a_ij, coeffs_enabled()); } TRACE("gomory_cut_detail", tout << "new_a_ij: " << new_a_ij << "\n";); pol.push_back(row_entry(new_a_ij, x_j)); @@ -600,7 +603,7 @@ namespace smt { if (pol.empty()) { SASSERT(k.is_pos()); // conflict 0 >= k where k is positive - set_conflict(ante.lits().size(), ante.lits().c_ptr(), ante.eqs().size(), ante.eqs().c_ptr(), ante, true, "gomory_cut"); + set_conflict(ante.lits().size(), ante.lits().c_ptr(), ante.eqs().size(), ante.eqs().c_ptr(), ante, true, "gomory-cut"); return true; } else if (pol.size() == 1) { @@ -652,7 +655,7 @@ namespace smt { gomory_cut_justification( get_id(), ctx.get_region(), ante.lits().size(), ante.lits().c_ptr(), - ante.eqs().size(), ante.eqs().c_ptr(), l))); + ante.eqs().size(), ante.eqs().c_ptr(), ante, l))); return true; } From 3d2ef8bb4a3698c7617a2ddcb3175e1c7223c459 Mon Sep 17 00:00:00 2001 From: Ken McMillan Date: Wed, 27 May 2015 16:05:40 -0700 Subject: [PATCH 846/925] fix for issue #109 --- src/interp/iz3mgr.cpp | 24 ++++++++++++++++++++++++ src/interp/iz3mgr.h | 8 +++++++- src/interp/iz3translate.cpp | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/src/interp/iz3mgr.cpp b/src/interp/iz3mgr.cpp index 78dd6f174..268085090 100755 --- a/src/interp/iz3mgr.cpp +++ b/src/interp/iz3mgr.cpp @@ -616,6 +616,30 @@ void iz3mgr::get_assign_bounds_coeffs(const ast &proof, std::vector& r extract_lcd(rats); } +void iz3mgr::get_gomory_cut_coeffs(const ast &proof, std::vector& coeffs){ + std::vector rats; + get_gomory_cut_coeffs(proof,rats); + coeffs.resize(rats.size()); + for(unsigned i = 0; i < rats.size(); i++){ + coeffs[i] = make_int(rats[i]); + } +} + +void iz3mgr::get_gomory_cut_coeffs(const ast &proof, std::vector& rats){ + symb s = sym(proof); + int numps = s->get_num_parameters(); + rats.resize(numps-2); + for(int i = 2; i < numps; i++){ + rational r; + bool ok = s->get_parameter(i).is_rational(r); + if(!ok) + throw "Bad Farkas coefficient"; + rats[i-2] = r; + } + abs_rat(rats); + extract_lcd(rats); +} + void iz3mgr::get_assign_bounds_rule_coeffs(const ast &proof, std::vector& coeffs){ std::vector rats; get_assign_bounds_rule_coeffs(proof,rats); diff --git a/src/interp/iz3mgr.h b/src/interp/iz3mgr.h index 8d4479f8f..dcbe08817 100755 --- a/src/interp/iz3mgr.h +++ b/src/interp/iz3mgr.h @@ -396,7 +396,7 @@ class iz3mgr { return UnknownTheory; } - enum lemma_kind {FarkasKind,Leq2EqKind,Eq2LeqKind,GCDTestKind,AssignBoundsKind,EqPropagateKind,ArithMysteryKind,UnknownKind}; + enum lemma_kind {FarkasKind,Leq2EqKind,Eq2LeqKind,GCDTestKind,AssignBoundsKind,EqPropagateKind,GomoryCutKind,ArithMysteryKind,UnknownKind}; lemma_kind get_theory_lemma_kind(const ast &proof){ symb s = sym(proof); @@ -417,6 +417,8 @@ class iz3mgr { return AssignBoundsKind; if(foo == "eq-propagate") return EqPropagateKind; + if(foo == "gomory-cut") + return GomoryCutKind; return UnknownKind; } @@ -434,6 +436,10 @@ class iz3mgr { void get_assign_bounds_rule_coeffs(const ast &proof, std::vector& rats); + void get_gomory_cut_coeffs(const ast &proof, std::vector& rats); + + void get_gomory_cut_coeffs(const ast &proof, std::vector& rats); + bool is_farkas_coefficient_negative(const ast &proof, int n); bool is_true(ast t){ diff --git a/src/interp/iz3translate.cpp b/src/interp/iz3translate.cpp index 2debdaf42..3620f0ad1 100755 --- a/src/interp/iz3translate.cpp +++ b/src/interp/iz3translate.cpp @@ -1182,6 +1182,31 @@ public: return res; } + ast GomoryCutRule2Farkas(const ast &proof, const ast &con, std::vector prems){ + std::vector my_prems = prems; + std::vector my_coeffs; + std::vector my_prem_cons; + get_gomory_cut_coeffs(proof,my_coeffs); + int nargs = num_prems(proof); + if(nargs != (int)(my_coeffs.size())) + throw "bad gomory-cut theory lemma"; + for(int i = 0; i < nargs; i++) + my_prem_cons.push_back(conc(prem(proof,i))); + ast my_con = normalize_inequality(sum_inequalities(my_coeffs,my_prem_cons)); + Iproof::node hyp = iproof->make_hypothesis(mk_not(my_con)); + my_prems.push_back(hyp); + my_coeffs.push_back(make_int("1")); + my_prem_cons.push_back(mk_not(my_con)); + Iproof::node res = iproof->make_farkas(mk_false(),my_prems,my_prem_cons,my_coeffs); + ast t = arg(my_con,0); + ast c = arg(my_con,1); + ast d = gcd_of_coefficients(t); + t = z3_simplify(mk_idiv(t,d)); + c = z3_simplify(mk_idiv(c,d)); + ast cut_con = make(op(my_con),t,c); + return iproof->make_cut_rule(my_con,d,cut_con,res); + } + Iproof::node RewriteClause(Iproof::node clause, const ast &rew){ if(pr(rew) == PR_MONOTONICITY){ int nequivs = num_prems(rew); @@ -1912,6 +1937,13 @@ public: res = AssignBounds2Farkas(proof,conc(proof)); break; } + case GomoryCutKind: { + if(args.size() > 0) + res = GomoryCutRule2Farkas(proof, conc(proof), args); + else + throw unsupported(); + break; + } case EqPropagateKind: { std::vector prems(nprems); for(unsigned i = 0; i < nprems; i++) From 713126225b6e729d41ad6a246af58f79342b10dd Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 28 May 2015 12:19:55 +0100 Subject: [PATCH 847/925] FPA min/max -+0.0 special cases changed to +0.0 instead of second argument. --- src/ast/fpa/fpa2bv_converter.cpp | 12 ++++++++++-- src/ast/rewriter/fpa_rewriter.cpp | 19 +++++++++++++++---- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 2c32e7f1a..d2d2c6a3f 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -1071,7 +1071,7 @@ void fpa2bv_converter::mk_min(func_decl * f, unsigned num, expr * const * args, split_fp(x, x_sgn, x_exp, x_sig); split_fp(y, y_sgn, y_exp, y_sig); - expr_ref x_is_nan(m), y_is_nan(m), x_is_zero(m), y_is_zero(m), both_zero(m), pzero(m); + expr_ref x_is_nan(m), y_is_nan(m), x_is_zero(m), y_is_zero(m), both_zero(m), pzero(m); mk_is_zero(x, x_is_zero); mk_is_zero(y, y_is_zero); m_simp.mk_and(x_is_zero, y_is_zero, both_zero); @@ -1079,12 +1079,16 @@ void fpa2bv_converter::mk_min(func_decl * f, unsigned num, expr * const * args, mk_is_nan(y, y_is_nan); mk_pzero(f, pzero); + expr_ref sgn_diff(m); + sgn_diff = m.mk_not(m.mk_eq(x_sgn, y_sgn)); + expr_ref lt(m); mk_float_lt(f, num, args, lt); result = y; mk_ite(lt, x, result, result); mk_ite(both_zero, y, result, result); + mk_ite(m.mk_and(both_zero, sgn_diff), pzero, result, result); // min(-0.0, +0.0) = min(+0.0, -0.0) = +0.0 mk_ite(y_is_nan, x, result, result); mk_ite(x_is_nan, y, result, result); @@ -1109,12 +1113,16 @@ void fpa2bv_converter::mk_max(func_decl * f, unsigned num, expr * const * args, mk_is_nan(y, y_is_nan); mk_pzero(f, pzero); + expr_ref sgn_diff(m); + sgn_diff = m.mk_not(m.mk_eq(x_sgn, y_sgn)); + expr_ref gt(m); mk_float_gt(f, num, args, gt); result = y; mk_ite(gt, x, result, result); - mk_ite(both_zero, y, result, result); + mk_ite(both_zero, y, result, result); + mk_ite(m.mk_and(both_zero, sgn_diff), pzero, result, result); // max(-0.0, +0.0) = max(+0.0, -0.0) = +0.0 mk_ite(y_is_nan, x, result, result); mk_ite(x_is_nan, y, result, result); diff --git a/src/ast/rewriter/fpa_rewriter.cpp b/src/ast/rewriter/fpa_rewriter.cpp index 37c42b494..738e8ec29 100644 --- a/src/ast/rewriter/fpa_rewriter.cpp +++ b/src/ast/rewriter/fpa_rewriter.cpp @@ -243,7 +243,7 @@ br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const !m_util.au().is_numeral(args[2], r2)) return BR_FAILED; - TRACE("fp_rewriter", tout << "r1: " << r1 << ", r2: " << r2 << "\n";); + TRACE("fp_rewriter", tout << "r1: " << r1 << ", r2: " << r2 << "\n";); m_fm.set(v, ebits, sbits, rmv, r1.to_mpq(), r2.to_mpq().numerator()); result = m_util.mk_value(v); return BR_DONE; @@ -420,11 +420,15 @@ br_status fpa_rewriter::mk_min(expr * arg1, expr * arg2, expr_ref & result) { arg2, m().mk_ite(mk_eq_nan(arg2), arg1, + // min(-0.0, +0.0) = min(+0.0, -0.0) = +0.0 + m().mk_ite(m().mk_and(m_util.mk_is_zero(arg1), m_util.mk_is_zero(arg2), + m().mk_not(m().mk_eq(m_util.mk_is_positive(arg1), m_util.mk_is_positive(arg2)))), + m_util.mk_pzero(m().get_sort(arg1)), m().mk_ite(m().mk_and(m_util.mk_is_zero(arg1), m_util.mk_is_zero(arg2)), arg2, m().mk_ite(m_util.mk_lt(arg1, arg2), arg1, - arg2)))); + arg2))))); return BR_REWRITE_FULL; } @@ -445,12 +449,16 @@ br_status fpa_rewriter::mk_max(expr * arg1, expr * arg2, expr_ref & result) { result = m().mk_ite(mk_eq_nan(arg1), arg2, m().mk_ite(mk_eq_nan(arg2), - arg1, + arg1, + // max(-0.0, +0.0) = max(+0.0, -0.0) = +0.0 + m().mk_ite(m().mk_and(m_util.mk_is_zero(arg1), m_util.mk_is_zero(arg2), + m().mk_not(m().mk_eq(m_util.mk_is_positive(arg1), m_util.mk_is_positive(arg2)))), + m_util.mk_pzero(m().get_sort(arg1)), m().mk_ite(m().mk_and(m_util.mk_is_zero(arg1), m_util.mk_is_zero(arg2)), arg2, m().mk_ite(m_util.mk_gt(arg1, arg2), arg1, - arg2)))); + arg2))))); return BR_REWRITE_FULL; } @@ -583,6 +591,7 @@ br_status fpa_rewriter::mk_ge(expr * arg1, expr * arg2, expr_ref & result) { br_status fpa_rewriter::mk_is_zero(expr * arg1, expr_ref & result) { scoped_mpf v(m_fm); + if (m_util.is_numeral(arg1, v)) { result = (m_fm.is_zero(v)) ? m().mk_true() : m().mk_false(); return BR_DONE; @@ -593,6 +602,7 @@ br_status fpa_rewriter::mk_is_zero(expr * arg1, expr_ref & result) { br_status fpa_rewriter::mk_is_nzero(expr * arg1, expr_ref & result) { scoped_mpf v(m_fm); + if (m_util.is_numeral(arg1, v)) { result = (m_fm.is_nzero(v)) ? m().mk_true() : m().mk_false(); return BR_DONE; @@ -603,6 +613,7 @@ br_status fpa_rewriter::mk_is_nzero(expr * arg1, expr_ref & result) { br_status fpa_rewriter::mk_is_pzero(expr * arg1, expr_ref & result) { scoped_mpf v(m_fm); + if (m_util.is_numeral(arg1, v)) { result = (m_fm.is_pzero(v)) ? m().mk_true() : m().mk_false(); return BR_DONE; From 7619d609f925539ae985b525bfb70c726060d1b8 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 28 May 2015 12:19:55 +0100 Subject: [PATCH 848/925] FPA min/max -+0.0 special cases changed to +0.0 instead of second argument. Fixes #68 --- src/ast/fpa/fpa2bv_converter.cpp | 12 ++++++++++-- src/ast/rewriter/fpa_rewriter.cpp | 19 +++++++++++++++---- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 2c32e7f1a..d2d2c6a3f 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -1071,7 +1071,7 @@ void fpa2bv_converter::mk_min(func_decl * f, unsigned num, expr * const * args, split_fp(x, x_sgn, x_exp, x_sig); split_fp(y, y_sgn, y_exp, y_sig); - expr_ref x_is_nan(m), y_is_nan(m), x_is_zero(m), y_is_zero(m), both_zero(m), pzero(m); + expr_ref x_is_nan(m), y_is_nan(m), x_is_zero(m), y_is_zero(m), both_zero(m), pzero(m); mk_is_zero(x, x_is_zero); mk_is_zero(y, y_is_zero); m_simp.mk_and(x_is_zero, y_is_zero, both_zero); @@ -1079,12 +1079,16 @@ void fpa2bv_converter::mk_min(func_decl * f, unsigned num, expr * const * args, mk_is_nan(y, y_is_nan); mk_pzero(f, pzero); + expr_ref sgn_diff(m); + sgn_diff = m.mk_not(m.mk_eq(x_sgn, y_sgn)); + expr_ref lt(m); mk_float_lt(f, num, args, lt); result = y; mk_ite(lt, x, result, result); mk_ite(both_zero, y, result, result); + mk_ite(m.mk_and(both_zero, sgn_diff), pzero, result, result); // min(-0.0, +0.0) = min(+0.0, -0.0) = +0.0 mk_ite(y_is_nan, x, result, result); mk_ite(x_is_nan, y, result, result); @@ -1109,12 +1113,16 @@ void fpa2bv_converter::mk_max(func_decl * f, unsigned num, expr * const * args, mk_is_nan(y, y_is_nan); mk_pzero(f, pzero); + expr_ref sgn_diff(m); + sgn_diff = m.mk_not(m.mk_eq(x_sgn, y_sgn)); + expr_ref gt(m); mk_float_gt(f, num, args, gt); result = y; mk_ite(gt, x, result, result); - mk_ite(both_zero, y, result, result); + mk_ite(both_zero, y, result, result); + mk_ite(m.mk_and(both_zero, sgn_diff), pzero, result, result); // max(-0.0, +0.0) = max(+0.0, -0.0) = +0.0 mk_ite(y_is_nan, x, result, result); mk_ite(x_is_nan, y, result, result); diff --git a/src/ast/rewriter/fpa_rewriter.cpp b/src/ast/rewriter/fpa_rewriter.cpp index 37c42b494..738e8ec29 100644 --- a/src/ast/rewriter/fpa_rewriter.cpp +++ b/src/ast/rewriter/fpa_rewriter.cpp @@ -243,7 +243,7 @@ br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const !m_util.au().is_numeral(args[2], r2)) return BR_FAILED; - TRACE("fp_rewriter", tout << "r1: " << r1 << ", r2: " << r2 << "\n";); + TRACE("fp_rewriter", tout << "r1: " << r1 << ", r2: " << r2 << "\n";); m_fm.set(v, ebits, sbits, rmv, r1.to_mpq(), r2.to_mpq().numerator()); result = m_util.mk_value(v); return BR_DONE; @@ -420,11 +420,15 @@ br_status fpa_rewriter::mk_min(expr * arg1, expr * arg2, expr_ref & result) { arg2, m().mk_ite(mk_eq_nan(arg2), arg1, + // min(-0.0, +0.0) = min(+0.0, -0.0) = +0.0 + m().mk_ite(m().mk_and(m_util.mk_is_zero(arg1), m_util.mk_is_zero(arg2), + m().mk_not(m().mk_eq(m_util.mk_is_positive(arg1), m_util.mk_is_positive(arg2)))), + m_util.mk_pzero(m().get_sort(arg1)), m().mk_ite(m().mk_and(m_util.mk_is_zero(arg1), m_util.mk_is_zero(arg2)), arg2, m().mk_ite(m_util.mk_lt(arg1, arg2), arg1, - arg2)))); + arg2))))); return BR_REWRITE_FULL; } @@ -445,12 +449,16 @@ br_status fpa_rewriter::mk_max(expr * arg1, expr * arg2, expr_ref & result) { result = m().mk_ite(mk_eq_nan(arg1), arg2, m().mk_ite(mk_eq_nan(arg2), - arg1, + arg1, + // max(-0.0, +0.0) = max(+0.0, -0.0) = +0.0 + m().mk_ite(m().mk_and(m_util.mk_is_zero(arg1), m_util.mk_is_zero(arg2), + m().mk_not(m().mk_eq(m_util.mk_is_positive(arg1), m_util.mk_is_positive(arg2)))), + m_util.mk_pzero(m().get_sort(arg1)), m().mk_ite(m().mk_and(m_util.mk_is_zero(arg1), m_util.mk_is_zero(arg2)), arg2, m().mk_ite(m_util.mk_gt(arg1, arg2), arg1, - arg2)))); + arg2))))); return BR_REWRITE_FULL; } @@ -583,6 +591,7 @@ br_status fpa_rewriter::mk_ge(expr * arg1, expr * arg2, expr_ref & result) { br_status fpa_rewriter::mk_is_zero(expr * arg1, expr_ref & result) { scoped_mpf v(m_fm); + if (m_util.is_numeral(arg1, v)) { result = (m_fm.is_zero(v)) ? m().mk_true() : m().mk_false(); return BR_DONE; @@ -593,6 +602,7 @@ br_status fpa_rewriter::mk_is_zero(expr * arg1, expr_ref & result) { br_status fpa_rewriter::mk_is_nzero(expr * arg1, expr_ref & result) { scoped_mpf v(m_fm); + if (m_util.is_numeral(arg1, v)) { result = (m_fm.is_nzero(v)) ? m().mk_true() : m().mk_false(); return BR_DONE; @@ -603,6 +613,7 @@ br_status fpa_rewriter::mk_is_nzero(expr * arg1, expr_ref & result) { br_status fpa_rewriter::mk_is_pzero(expr * arg1, expr_ref & result) { scoped_mpf v(m_fm); + if (m_util.is_numeral(arg1, v)) { result = (m_fm.is_pzero(v)) ? m().mk_true() : m().mk_false(); return BR_DONE; From 49a4df0de144fb87b23d8af01be4816a428da25b Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 28 May 2015 12:54:57 +0100 Subject: [PATCH 849/925] MPF min/max -+0.0 special cases changed to +0.0 instead of second argument. Another piece of fix #68 --- src/util/mpf.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 1521a8f87..57e5b56b5 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -1229,7 +1229,11 @@ void mpf_manager::rem(mpf const & x, mpf const & y, mpf & o) { } void mpf_manager::maximum(mpf const & x, mpf const & y, mpf & o) { - if (is_nan(x) || (is_zero(x) && is_zero(y))) + if (is_nan(x)) + set(o, y); + else if (is_zero(x) && is_zero(y) && sgn(x) != sgn(y)) + mk_pzero(x.ebits, x.sbits, o); + else if (is_zero(x) && is_zero(y)) set(o, y); else if (is_nan(y)) set(o, x); @@ -1240,7 +1244,11 @@ void mpf_manager::maximum(mpf const & x, mpf const & y, mpf & o) { } void mpf_manager::minimum(mpf const & x, mpf const & y, mpf & o) { - if (is_nan(x) || (is_zero(x) && is_zero(y))) + if (is_nan(x)) + set(o, y); + else if (is_zero(x) && is_zero(y) && sgn(x) != sgn(y)) + mk_pzero(x.ebits, x.sbits, o); + else if (is_zero(x) && is_zero(y)) set(o, y); else if (is_nan(y)) set(o, x); From f6f16c1e9269a65994e728601821a78f22ca318a Mon Sep 17 00:00:00 2001 From: Aleksandar Zeljic Date: Thu, 28 May 2015 14:31:34 +0200 Subject: [PATCH 850/925] Added smallFloats files. --- src/sat/sat_solver.h | 2 +- src/tactic/fpa/const_intro_rewriter.h | 150 ++ src/tactic/fpa/fpa2bv_approx_tactic.cpp | 1257 +++++++++++++++ src/tactic/fpa/fpa2bv_approx_tactic.h | 33 + src/tactic/fpa/fpa2bv_converter_prec.cpp | 1783 ++++++++++++++++++++++ src/tactic/fpa/fpa2bv_converter_prec.h | 162 ++ src/tactic/fpa/fpa2bv_rewriter_prec.h | 229 +++ 7 files changed, 3615 insertions(+), 1 deletion(-) create mode 100644 src/tactic/fpa/const_intro_rewriter.h create mode 100644 src/tactic/fpa/fpa2bv_approx_tactic.cpp create mode 100644 src/tactic/fpa/fpa2bv_approx_tactic.h create mode 100644 src/tactic/fpa/fpa2bv_converter_prec.cpp create mode 100644 src/tactic/fpa/fpa2bv_converter_prec.h create mode 100644 src/tactic/fpa/fpa2bv_rewriter_prec.h diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 357b79f49..e3628823f 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -210,6 +210,7 @@ namespace sat { public: bool inconsistent() const { return m_inconsistent; } unsigned num_vars() const { return m_level.size(); } + unsigned num_clauses() const; bool is_external(bool_var v) const { return m_external[v] != 0; } bool was_eliminated(bool_var v) const { return m_eliminated[v] != 0; } unsigned scope_lvl() const { return m_scope_lvl; } @@ -447,7 +448,6 @@ namespace sat { protected: void display_binary(std::ostream & out) const; void display_units(std::ostream & out) const; - unsigned num_clauses() const; bool is_unit(clause const & c) const; bool is_empty(clause const & c) const; bool check_missed_propagation(clause_vector const & cs) const; diff --git a/src/tactic/fpa/const_intro_rewriter.h b/src/tactic/fpa/const_intro_rewriter.h new file mode 100644 index 000000000..5c4675fbb --- /dev/null +++ b/src/tactic/fpa/const_intro_rewriter.h @@ -0,0 +1,150 @@ +/*++ +Copyright (c) 2012 Microsoft Corporation + +Module Name: + + const_intro_rewriter.h + +Abstract: + + Rewriter for converting FPA to BV + +Author: + + Christoph (cwinter) 2012-02-09 + +Notes: + +--*/ + +#ifndef _CONST_INTRO_REWRITER_H_ +#define _CONST_INTRO_REWRITER_H_ + +#include"cooperate.h" +#include"bv_decl_plugin.h" +#include"tactic_exception.h" +#include"fpa2bv_converter_prec.h" + +struct const_intro_rewriter_cfg : public default_rewriter_cfg { + ast_manager & m_manager; + + expr * m_exp; + func_decl_ref_vector m_introduced_consts; + obj_map m_const2term_map; + + unsigned long long m_max_memory; + unsigned m_max_steps; + + fpa_util m_float_util; + + ast_manager & m() const { return m_manager; } + + const_intro_rewriter_cfg(ast_manager & m, params_ref const & p): + m_manager(m), + m_introduced_consts(m), + m_float_util(m) { + updt_params(p); + // We need to make sure that the mananger has the BV plugin loaded. + symbol s_bv("bv"); + if (!m_manager.has_plugin(s_bv)) + m_manager.register_plugin(s_bv, alloc(bv_decl_plugin)); + } + + ~const_intro_rewriter_cfg() { + for (obj_map::iterator it = m_const2term_map.begin(); + it != m_const2term_map.end(); + it++) + { + m().dec_ref(it->m_key); + m().dec_ref(it->m_value); + } + } + + void cleanup_buffers() { + } + + void updt_params(params_ref const & p) { + m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX)); + m_max_steps = p.get_uint("max_steps", UINT_MAX); + } + + bool max_steps_exceeded(unsigned num_steps) const { + cooperate("fpa2bv"); + if (memory::get_allocation_size() > m_max_memory) + throw tactic_exception(TACTIC_MAX_MEMORY_MSG); + return num_steps > m_max_steps; + } + + br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { + TRACE("fpa2bv_rw", tout << "APP: " << f->get_name() << std::endl; ); + + if (num == 0 && f->get_family_id() == null_family_id && m_float_util.is_float(f->get_range())) { + app * f_cnst = m_manager.mk_const(f); + if (!m_introduced_consts.contains(f)) + m_introduced_consts.push_back(f); + result = f_cnst; + return BR_DONE; + } + + if (f->get_family_id() == m_float_util.get_family_id()) { + switch (f->get_decl_kind()) { + case OP_FPA_ADD: + case OP_FPA_SUB: + case OP_FPA_NEG: + case OP_FPA_MUL: + case OP_FPA_DIV: + case OP_FPA_REM: + case OP_FPA_ABS: + case OP_FPA_MIN: + case OP_FPA_MAX: + case OP_FPA_FMA: + case OP_FPA_SQRT: + case OP_FPA_TO_FP: + case OP_FPA_ROUND_TO_INTEGRAL: + { + app * f_app = m_manager.mk_app(f, num, args); + result = m_manager.mk_fresh_const(NULL, f->get_range()); + func_decl * fd = to_app(result)->get_decl(); + m_introduced_consts.push_back(fd); + m_const2term_map.insert_if_not_there(fd, f_app); + m().inc_ref(fd); + m().inc_ref(f_app); + return BR_DONE; + } + default: + return BR_FAILED; + } + } + + return BR_FAILED; + } + + bool reduce_quantifier(quantifier * old_q, + expr * new_body, + expr * const * new_patterns, + expr * const * new_no_patterns, + expr_ref & result, + proof_ref & result_pr) { + return false; + } + + bool reduce_var(var * t, expr_ref & result, proof_ref & result_pr) { + return false; + } + + bool pre_visit(expr * t){ + return true; + } +}; + +template class rewriter_tpl; + +struct const_intro_rewriter : public rewriter_tpl { + const_intro_rewriter_cfg m_cfg; + const_intro_rewriter(ast_manager & m, params_ref const & p): + rewriter_tpl(m, m.proofs_enabled(), m_cfg), + m_cfg(m, p) { + } +}; + +#endif diff --git a/src/tactic/fpa/fpa2bv_approx_tactic.cpp b/src/tactic/fpa/fpa2bv_approx_tactic.cpp new file mode 100644 index 000000000..8a86ec0e8 --- /dev/null +++ b/src/tactic/fpa/fpa2bv_approx_tactic.cpp @@ -0,0 +1,1257 @@ +/*++ + Copyright (c) 2012 Microsoft Corporation + + Module Name: + + fpa2bv_approx_tactic.cpp + + Abstract: + + Tactic that converts floating points to bit-vectors lazily + + Author: + + Aleksander Zeljic 2012-11-15 + + Notes: + + --*/ +#include"tactical.h" +#include"cooperate.h" +#include"ref_util.h" + +#include"th_rewriter.h" +#include"bit_blaster_rewriter.h" +#include"bit_blaster_model_converter.h" +#include"model_v2_pp.h" +#include"goal2sat.h" +#include"sat_solver.h" +#include"fpa_decl_plugin.h" +#include"fpa2bv_converter_prec.h" +#include"fpa2bv_rewriter_prec.h" +#include"fpa2bv_approx_tactic.h" +#include"const_intro_rewriter.h" +#include"ctx_simplify_tactic.h" +#include"filter_model_converter.h" +#include +#include +#include + +#include + +#define K_MIN 10 +#define K_PERCENTAGE 0.3 +#define PREC_INCREMENT 20 +#define ERR_OP 0 // + +struct pair +{ + expr * exp; + double quotient;// mpf * +}; + +bool isinfinite(double x) { +#ifdef _WIN32 + int c = _fpclass(x); + return c == _FPCLASS_PINF || c == _FPCLASS_NINF; +#else + return fpclassify(x) == FP_INFINITE; +#endif +} + +class fpa2bv_approx_tactic: public tactic { + struct imp { + ast_manager & m; + goal2sat m_goal2sat; + sat2goal m_sat2goal; + params_ref m_params; + unsigned m_num_steps; + bool m_proofs_enabled; + bool m_produce_models; + bool m_produce_unsat_cores; + bool m_cancel; + + fpa_approximation_mode m_mode; + ast_manager * m_temp_manager; + model_ref m_fpa_model; + fpa_util m_float_util; + + imp(ast_manager & _m, params_ref const & p, fpa_approximation_mode mode) : + m(_m), + m_params(p), + m_proofs_enabled(false), + m_produce_models(false), + m_produce_unsat_cores(false), + m_cancel(false), + m_mode(mode), + m_temp_manager(0), + m_float_util(_m) { + } + + void updt_params(params_ref const & p) { + m_params = p; + } + + void set_cancel(bool f) { + //If f is true stop everything + m_cancel = f; + } + + void init_precision_mapping(func_decl_ref_vector const & cnsts, + obj_map & map, + obj_map & const2term_map) { + for (unsigned i = 0; i < cnsts.size(); i++) + { + if (const2term_map.contains(cnsts[i]) || m_mode == FPAA_SMALL_FLOATS) + map.insert_if_not_there(cnsts.get(i), 0); + else + map.insert_if_not_there(cnsts.get(i), MAX_PRECISION); + } + } + + bool proof_guided_refinement( + goal_ref const & g, + func_decl_ref_vector const & cnsts, + obj_map & cnst2prec_map, + obj_map & new_map) + { + // We have no model. Let's just increase precision of everything. + bool res = false; + for (unsigned i = 0; i < cnsts.size(); i++) + { + unsigned old = cnst2prec_map.find(cnsts.get(i)); + unsigned n = old + PREC_INCREMENT; + if (old >= MAX_PRECISION) n = MAX_PRECISION; + else { if (n > MAX_PRECISION) n = MAX_PRECISION; res = true; } + new_map.insert(cnsts.get(i), n); + } + return res; + } + + void boolean_comparison_of_models(goal_ref g, model_ref const & mdl, model_ref const & full_mdl, obj_map & cnst2term_map, obj_map& count) + { + std::queue to_traverse; + app * cur; + int cur_cnt; + + expr_ref mdl_eval(m), full_eval(m); + + for (unsigned i=0; i < g->size(); i++){ + mdl->eval(g->form(i),mdl_eval,true); + full_mdl->eval(g->form(i),full_eval,true); + + //Push only if the full model evaluates to false, or if the models differ? + if (!m.is_true(full_eval)) // m.is_true(full_eval) != m.is_true(mdl_eval) + to_traverse.push(g->form(i)); + } + + while (to_traverse.size() > 0) { + cur = to_app(to_traverse.front()); + mpf_rounding_mode rm; +#ifdef Z3DEBUG + std::cout<<"Analyze - traversing: "<get_decl())) + count.insert(cur,1); + + if(cnst2term_map.contains(cur->get_decl())) + to_traverse.push(cnst2term_map.find(cur->get_decl())); + + for(unsigned i=0;iget_num_args();i++) { + if(m_float_util.is_rm(cur->get_arg(i)) || m_float_util.is_numeral(cur->get_arg(i))) + continue; + to_traverse.push(cur->get_arg(i)); + } + } + else { //Comparing boolean values from the model and the expanded model + mdl->eval(cur,mdl_eval,true); + full_mdl->eval(cur,full_eval,true); + + + if (m.is_true(full_eval) != m.is_true(mdl_eval)) { + //queue arguments + for(unsigned i=0; i < cur->get_num_args(); i++) + to_traverse.push(cur->get_arg(i)); + } + } + to_traverse.pop(); + } +#ifdef Z3DEBUG + std::cout<<"Expression count"<::iterator it = count.begin(); + it!= count.end(); + it++) { + std::cout<m_key,m)<<":"<m_value<size();i++) { + eq = to_app(g->form(i)); + + if (eq->get_family_id() == m.get_basic_family_id() && + eq->get_decl_kind() == OP_EQ){ + //eq is in fact an equality + app * lhs = to_app(eq->get_arg(0)); + app * rhs = to_app(eq->get_arg(1)); + expr * lhs_e,*rhs_e,*exp, *exp_e; + app *other = NULL; + + + if(lhs->get_num_args()==0 && + rhs ->get_num_args()==0){ + //over constants + lhs_e = full_mdl->get_const_interp(lhs->get_decl()); + rhs_e = full_mdl->get_const_interp(rhs->get_decl()); + + // != would work as well, to make sure they are not both NULL, + //and could simplify later checks + if(lhs_e != rhs_e) { //SASSERT(lhs_e || rhs_e); + //and one is registered in the full model while the other is not + if(!lhs_e){// && rhs_e){ + other = lhs; + exp_e = rhs_e; + exp = rhs; + } + else { // if(!rhs_e && lhs_e){ + other = rhs; + exp_e = lhs_e; + exp = lhs; + } + full_mdl->register_decl(other->get_decl(),exp_e); + +#ifdef Z3DEBUG + std::cout< & cnst2term_map, + obj_map & precise_op, + obj_map & actual_value, + obj_map & err_est, + mpf_rounding_mode & rm, + bool & precise_children, + bool & seen_all_children, + bool & children_have_finite_err, + mpf * arg_val, + mpf * est_arg_val + //expr_ref * arg_e + ){ + + expr_ref arg_e[] = { expr_ref(m), expr_ref(m), expr_ref(m), expr_ref(m) }; + unsigned i=0; + //Set rounding mode + if (rhs->get_num_args() > 0 && m_float_util.is_rm(rhs->get_arg(0))) + i = 1; + //Collect argument values + for (; i < rhs->get_num_args(); i++) { + expr * arg = rhs->get_arg(i); + + if (is_app(arg) && to_app(arg)->get_num_args() == 0) { + if (precise_op.contains(arg)) { + precise_children &= precise_op.find(arg); + } + else if (!cnst2term_map.contains(to_app(arg)->get_decl())) { + /* that's okay */ + } + else { +#ifdef Z3DEBUG + std::cout << "Not seen all children of " << mk_ismt2_pp(rhs, m) << + " (spec. " << mk_ismt2_pp(arg, m) << ")" << std::endl; +#endif + precise_children = false; + seen_all_children = false; + break; + } + } + + // Value from small model + mdl->eval(arg, arg_e[i],true); + m_float_util.is_numeral(arg_e[i], arg_val[i]); + + if( children_have_finite_err && + err_est.contains(arg) && + isinfinite(err_est.find(arg))) + children_have_finite_err=false; + + if (actual_value.contains(arg)) + mpf_mngr.set(est_arg_val[i], *actual_value.find(arg)); + else if (seen_all_children && is_app(arg) && to_app(arg)->get_num_args()==0) { + //We have seen all children so if it is a constant and not in actual_value then + //it is an input variable and its est_val is the same as actual value + mpf * tmp = alloc(mpf); + mpf_mngr.set(*tmp, arg_val[i]); + actual_value.insert(arg, tmp); + mpf_mngr.set(est_arg_val[i], *tmp); + } + else + std::cout << "Estimated value missing: " << mk_ismt2_pp(arg,m) << std::endl; + } + + } + + + void full_semantics_eval( + app * rhs, + mpf_manager & mpf_mngr, + mpf_rounding_mode & rm, + mpf * arg_val, + mpf * est_arg_val, + mpf & rhs_value, + mpf & est_rhs_value){ + + switch (rhs->get_decl()->get_decl_kind()) { + case OP_FPA_ADD: + mpf_mngr.add(rm, arg_val[1], arg_val[2], rhs_value); + mpf_mngr.add(rm, est_arg_val[1], est_arg_val[2], est_rhs_value); + break; + case OP_FPA_SUB: + mpf_mngr.sub(rm, arg_val[1], arg_val[2], rhs_value); + mpf_mngr.sub(rm, est_arg_val[1], est_arg_val[2], est_rhs_value); + break; + case OP_FPA_NEG: + mpf_mngr.neg(arg_val[0], rhs_value); + mpf_mngr.neg(est_arg_val[0], est_rhs_value);//Does it even make sense to look at this? + break; + case OP_FPA_MUL: + mpf_mngr.mul(rm, arg_val[1], arg_val[2], rhs_value); + mpf_mngr.mul(rm, est_arg_val[1], est_arg_val[2], est_rhs_value); + break; + case OP_FPA_DIV: + mpf_mngr.div(rm, arg_val[1], arg_val[2], rhs_value); + mpf_mngr.div(rm, est_arg_val[1], est_arg_val[2], est_rhs_value); + break; + case OP_FPA_REM: + mpf_mngr.rem(arg_val[0], arg_val[1], rhs_value); + mpf_mngr.rem(est_arg_val[0], est_arg_val[1], est_rhs_value); + break; + case OP_FPA_FMA: + mpf_mngr.fused_mul_add(rm, arg_val[1], arg_val[2], arg_val[3], rhs_value); + mpf_mngr.fused_mul_add(rm, est_arg_val[1], est_arg_val[2], est_arg_val[3], est_rhs_value); + break; + case OP_FPA_SQRT: + mpf_mngr.sqrt(rm, arg_val[1], rhs_value); + mpf_mngr.sqrt(rm, est_arg_val[1], est_rhs_value); + break; + case OP_FPA_TO_FP: + { + unsigned ebits = rhs->get_decl()->get_parameter(0).get_int(); + unsigned sbits = rhs->get_decl()->get_parameter(1).get_int(); + mpf_mngr.set(rhs_value, ebits, sbits, rm, arg_val[1]); + mpf_mngr.set(est_rhs_value, ebits, sbits, rm, est_arg_val[1]); + break; + } + default: + NOT_IMPLEMENTED_YET(); + break; + } + + } + + void evaluate_constant( + app * rhs, + model_ref const & mdl, + mpf_manager & mpf_mngr, + obj_map & actual_value, + mpf & rhs_value, + mpf & est_rhs_value){ + + expr_ref exp(m); + mdl->eval(rhs, exp, true); + m_float_util.is_numeral(exp, rhs_value); //OLD:is_value + + if (actual_value.contains(rhs)) + mpf_mngr.set(est_rhs_value, *actual_value.find(rhs)); + else { + mpf * tmp = alloc(mpf); + mpf_mngr.set(*tmp, rhs_value); + actual_value.insert(rhs, tmp); + mpf_mngr.set(est_rhs_value, rhs_value); + } + } + + void calculate_error( + expr_ref & lhs, + mpf_manager & mpf_mngr, + obj_map & precise_op, + obj_map & err_est, + mpf & lhs_value, + mpf & est_rhs_value, + bool children_have_finite_err){ + mpf err, rel_err; + if (!mpf_mngr.eq(lhs_value, est_rhs_value) && + !(mpf_mngr.is_nan(lhs_value) && mpf_mngr.is_nan(est_rhs_value))) { +#ifdef Z3DEBUG + std::cout << "Increasing precision of " << mk_ismt2_pp(lhs, m) << + " because " << mk_ismt2_pp(lhs, m) << " != " << + mpf_mngr.to_string(est_rhs_value) << std::endl; +#endif + //TODO: smarter adjustment to be implemented + precise_op.insert(lhs, false); + if (mpf_mngr.is_regular(lhs_value) && mpf_mngr.is_regular(est_rhs_value)) { + mpf_mngr.sub(MPF_ROUND_TOWARD_ZERO, est_rhs_value, lhs_value, err); + mpf_mngr.div(MPF_ROUND_TOWARD_ZERO, err, lhs_value, rel_err); + mpf_mngr.abs(rel_err); + } + else// One of the two is a special value; in this case the relative error is +INF + mpf_mngr.mk_pinf(11, 53, rel_err); + + if(children_have_finite_err) + err_est.insert(lhs, mpf_mngr.to_double(rel_err)); + +#ifdef Z3DEBUG + std::cout << "Error estimate: "<size(); j++) { + mdl->eval(g->form(j), res, true); + if (!m.is_true(res)) { + std::cout << "Failed: " << mk_ismt2_pp(g->form(j), m) << std::endl; + std::cout << "Evaluates to: " << mk_ismt2_pp(res, m) << std::endl; + is_model=false; + } + } + return is_model; + } + void evaluate_and_patch( + func_decl_ref_vector const & cnsts, + model_ref const & mdl, + model_ref & full_mdl, + goal_ref const & g, + obj_map & cnst2term_map, + obj_map & err_est) { + + mpf_manager & mpf_mngr = m_float_util.fm(); + expr_ref lhs(m), lhs_eval(m); + app * rhs; + mpf arg_val[4]; //First argument can be rounding mode + mpf est_arg_val[4]; + mpf lhs_value, rhs_value, est_rhs_value; + mpf_rounding_mode rm; + + mpf err, rel_err; + + + + obj_map precise_op; + obj_map actual_value; + while (precise_op.size() != cnst2term_map.size()) + for(unsigned i=0;ieval(lhs, lhs_eval, true); + + if (m_float_util.is_numeral(lhs_eval, lhs_value)) {//OLD:is_value + bool precise_children = true; + bool seen_all_children = true; + bool children_have_finite_err = true; + + obtain_values(rhs, mdl, full_mdl,mpf_mngr,cnst2term_map,precise_op,actual_value, + err_est, rm, precise_children, seen_all_children, children_have_finite_err, arg_val, est_arg_val ); + + + if (seen_all_children) {//If some arguments are not evaluated yet, skip + if (rhs->get_num_args() == 0) + evaluate_constant(rhs,mdl,mpf_mngr,actual_value, rhs_value, est_rhs_value); + else + full_semantics_eval(rhs,mpf_mngr,rm,arg_val,est_arg_val, rhs_value, est_rhs_value); + + full_mdl->register_decl((to_app(lhs))->get_decl(), m_float_util.mk_value(est_rhs_value)); +#ifdef Z3DEBUG + std::cout << "Assigning " << mk_ismt2_pp(lhs, m) << + " value " << mpf_mngr.to_string(est_rhs_value) << std::endl + << "Values of " << mk_ismt2_pp(lhs, m) << std::endl + << "Precise children: " << ((precise_children) ? "True" : "False") << std::endl + << "Lhs: " << mk_ismt2_pp(lhs_eval, m) << std::endl + << "Model: " << mpf_mngr.to_string(rhs_value) << std::endl + << "Estimate: " << mpf_mngr.to_string(est_rhs_value) << std::endl; +#endif + + calculate_error(lhs,mpf_mngr,precise_op,err_est,lhs_value,est_rhs_value,children_have_finite_err); + + if (!actual_value.contains(lhs)) { + mpf * tmp = alloc(mpf); + mpf_mngr.set(*tmp, est_rhs_value); + actual_value.insert(lhs, tmp); + } + + if (!precise_children && !precise_op.contains(lhs)) { + std::cout << mk_ismt2_pp(lhs, m) << " is imprecise because some children are imprecise." << std::endl; + precise_op.insert(lhs, false); + } + } + } + } + + for (obj_map::iterator it = actual_value.begin(); + it != actual_value.end(); + it++) + mpf_mngr.del(*it->m_value); + + mpf_mngr.del(err); + mpf_mngr.del(rel_err); + mpf_mngr.del(lhs_value); + mpf_mngr.del(rhs_value); + mpf_mngr.del(est_rhs_value); + + for (unsigned i = 0; i < 4; i++) { + mpf_mngr.del(arg_val[i]); + mpf_mngr.del(est_arg_val[i]); + } + } + + bool precise_model_reconstruction( + model_ref const & mdl, + model_ref & full_mdl, + goal_ref const & g, + obj_map & err_est,//mpf* + func_decl_ref_vector const & cnsts, + obj_map & cnst2term_map) { +#ifdef Z3DEBUG + std::cout << "Attempting to patch small-float model" << std::endl; +#endif + expr_ref res(m); + bool is_model=true; + + //Evaluation of the model using full fpa semantics and construction of the full model + evaluate_and_patch(cnsts, mdl, full_mdl, g, cnst2term_map, err_est); + +#ifdef Z3DEBUG + std::cout<::iterator it = err_est.begin(); + it!= err_est.end(); it++) { + std::cout<m_key,m)<<":"<m_value<get_num_constants(); j++) { + if (!cnst2term_map.contains(mdl->get_constant(j)) + && !full_mdl->get_const_interp(mdl->get_constant(j))) { + mdl->eval(mdl->get_constant(j), res); + full_mdl->register_decl(mdl->get_constant(j), res); + } + } + + //Evaluate the full model + is_model = evaluate_model(g,full_mdl); + + return is_model; + } + + void calculate_relative_error( + obj_map & err_est, + obj_map & expr_count, + obj_map & err_ratio_map) { + unsigned num_args=0; + expr_ref exp(m); + double out_err,cur,err_ratio, avg_err; + + //AZ: Currently ignoring the expr_count, since it was blocking consideration of some expressions + for (obj_map::iterator it = err_est.begin(); + it != err_est.end(); + it++) { + // if any ancestor node has an error current node will be in expr_count. + /*if (!expr_count.contains(it->m_key)) + continue;*/ + + exp = it->m_key; + out_err = it->m_value; + num_args = to_app(exp)->get_num_args(); + + // Calculate average error of input params + avg_err = 0.0; + if (num_args > 0) { + for (unsigned i=0; iget_arg(i); + if (err_est.contains(arg)) { + cur = err_est.find(arg); + avg_err = avg_err + cur; + } + } + avg_err = avg_err/num_args; + } + // Relative error when input error exists, otherwise just output error + err_ratio = fabs((avg_err != (double) 0)? out_err / avg_err : out_err); + + if(expr_count.contains(exp)) { + if(ERR_OP) + err_ratio *= 1 + expr_count.find(exp); + else + err_ratio += expr_count.find(exp); + } + err_ratio_map.insert(exp, err_ratio); + } + + TRACE("fpa2bv_approx", + tout << "ERROR RATIO MAP: " << std::endl; + for (obj_map::iterator it = err_ratio_map.begin();// mpf* + it != err_ratio_map.end(); + it++) + tout << mk_ismt2_pp(it->m_key, m) << ": " <m_value<< std::endl; ); + + +#ifdef Z3DEBUG + std::cout<<"Error ratio:"<::iterator it = err_ratio_map.begin();//mpf* + it != err_ratio_map.end(); + it++) + std::cout<< mk_ismt2_pp(it->m_key, m) << ": " << it->m_value<< std::endl; + std::cout.flush(); +#endif + + } + + + void rank_terms(obj_map & err_ratio_map, std::list & ranked_terms) + { + unsigned kth = (unsigned)(err_ratio_map.size()*K_PERCENTAGE); + if (kth<10) kth=K_MIN; + SASSERT(!err_ratio_map.empty()); + + //Insertion sort the error ratios, keeping only the k highest elements + obj_map::iterator it = err_ratio_map.begin(); + struct pair * p = new struct pair(); + p->exp=it->m_key; + p->quotient=it->m_value; + ranked_terms.push_front(p); + + for (it++; it != err_ratio_map.end(); it++) { + if (ranked_terms.size()m_value >= ranked_terms.back()->quotient) { + std::list::iterator pos = ranked_terms.begin(); + while (pos!=ranked_terms.end() && it->m_value <= ranked_terms.back()->quotient) + pos++; + struct pair * p = new struct pair(); + p->exp=it->m_key; + p->quotient=it->m_value; + ranked_terms.insert(pos, p); + if (ranked_terms.size() > kth) { + delete ranked_terms.back(); + ranked_terms.pop_back(); + } + } + } + } + + void increase_precision( + std::list & ranked_terms, + func_decl_ref_vector const & cnsts, + obj_map & cnst2prec_map, + obj_map & cnst2term_map, + obj_map & new_map){ + + //Refine chosen terms and find the any input 'variables' which are + //its immediate arguments and refine them as well +#ifdef Z3DEBUG + std::cout<<"Increasing precision:"<::iterator itp = ranked_terms.begin(); + itp != ranked_terms.end(); + itp++) { + app * cur = to_app((*itp)->exp); + func_decl * f = cur->get_decl(); + unsigned new_prec = PREC_INCREMENT, old_prec; + bool in_new_map; + + if (cnst2prec_map.contains(f)) + new_prec += cnst2prec_map.find(f); + + new_prec= (new_prec > MAX_PRECISION) ? MAX_PRECISION : new_prec; + new_map.insert(f, new_prec); + +#ifdef Z3DEBUG + std::cout << f->get_name() << ":" << new_prec << std::endl; + std::cout << mk_ismt2_pp(cur, m) << ":" << new_prec << std::endl; +#endif + + if(cnst2term_map.contains(f)) + cur = cnst2term_map.find(f); + // Refine constants that are direct arguments of this term + for(unsigned i=0; iget_num_args();i++){ + func_decl * arg_decl = to_app(cur->get_arg(i))->get_decl(); + if (!cnst2term_map.contains(arg_decl) && //Not a constant introduced by flattening + !m_float_util.is_rm(cur->get_arg(i)) && //OLD:is_rm(...,rm) + !m_float_util.is_numeral(cur->get_arg(i))) { //OLD:is_value + //It is an input 'variable' + if ( (in_new_map = new_map.contains(arg_decl))) + old_prec=new_map.find(arg_decl); + else if (cnst2prec_map.contains(arg_decl)) + old_prec = cnst2prec_map.find(arg_decl); + else + old_prec=0; + + if (old_prec < new_prec) { + if (in_new_map) + new_map.remove(arg_decl); + SASSERT(new_prec <= MAX_PRECISION); + new_map.insert(arg_decl, new_prec); + std::cout << " " << arg_decl->get_name() << ":" << new_prec << std::endl; +#ifdef Z3DEBUG + std::cout<<" "<get_arg(i),m)<<":"< & cnst2prec_map, + obj_map & cnst2term_map, + obj_map & err_est, + obj_map & new_map) { + + obj_map err_ratio_map; + obj_map expr_count; + std::list ranked_terms; + + boolean_comparison_of_models(g, mdl, full_mdl, cnst2term_map, expr_count); + calculate_relative_error(err_est, expr_count, err_ratio_map); + rank_terms (err_ratio_map,ranked_terms); + increase_precision(ranked_terms,cnsts,cnst2prec_map,cnst2term_map,new_map); + } + + void simplify(goal_ref mg) { + ast_manager &m = mg->m(); // CMW: <--- We use the manager of the goal, so this works for any manager. + expr_ref new_curr(m); + proof_ref new_pr(m); + + th_rewriter simplifier(m, m_params); + + // CMW: we need to eliminate AND expressions. + params_ref elim_and(m_params); + elim_and.set_bool("elim_and", true); + // elim_and.set_uint("max_depth", 1); // CMW: This number can have a big impact on performance, either way. + simplifier.updt_params(elim_and); + + SASSERT(mg->is_well_sorted()); + TRACE("before_simplifier", mg->display(tout);); + m_num_steps = 0; + if (mg->inconsistent()) + return; + for (unsigned idx = 0; idx < mg->size(); idx++) { + if (mg->inconsistent()) + break; + expr * curr = mg->form(idx); + simplifier(curr, new_curr, new_pr); + m_num_steps += simplifier.get_num_steps(); + if (mg->proofs_enabled()) { + proof * pr = mg->pr(idx); + new_pr = m.mk_modus_ponens(pr, new_pr); + } + mg->update(idx, new_curr, new_pr, mg->dep(idx)); + } + TRACE("after_simplifier_bug", mg->display(tout);); + mg->elim_redundancies(); + TRACE("after_simplifier", mg->display(tout);); + TRACE("after_simplifier_detail", mg->display_with_dependencies(tout);); + SASSERT(mg->is_well_sorted()); + } + + bool fully_encoded(obj_map const & precision_map) + { + for (obj_map::iterator it = precision_map.begin(); + it != precision_map.end(); + it++) + if (it->m_value < MAX_PRECISION) return false; + return true; + } + + void bitblast(goal_ref const & g, + fpa2bv_converter_prec & fpa2bv, + bit_blaster_rewriter & bv2bool, + obj_map & const2prec_map, + sat::solver & solver, + atom2bool_var & map) + { + // CMW: This is all done using the temporary manager! + expr_ref new_curr(*m_temp_manager); + proof_ref new_pr(*m_temp_manager); + std::cout.flush(); + + SASSERT(g->is_well_sorted()); + + //fpa2bv + fpa2bv_rewriter_prec fpa2bv_rw(*m_temp_manager, fpa2bv, m_params); + fpa2bv_rw.m_cfg.set_mappings(&const2prec_map); + m_num_steps = 0; + unsigned size = g->size(); + for (unsigned idx = 0; idx < size; idx++) { + if (g->inconsistent()) + break; + expr * curr = g->form(idx); +#ifdef Z3DEBUG + std::cout<pr(idx); + new_pr = m_temp_manager->mk_modus_ponens(pr, new_pr); + } + g->update(idx, new_curr, new_pr, g->dep(idx)); + + SASSERT(g->is_well_sorted()); + } + + //Adding the equalities that fix bits + for(unsigned i=0;iassert_expr(fpa2bv.m_extra_assertions.get(i)); + + SASSERT(g->is_well_sorted()); + + simplify(g); + + //Bitblasting + TRACE("before_bit_blaster", g->display(tout);); + m_num_steps = 0; + size = g->size(); + for (unsigned idx = 0; idx < size; idx++) { + if (g->inconsistent()) + break; + expr * curr = g->form(idx); + bv2bool(curr, new_curr, new_pr); + m_num_steps += bv2bool.get_num_steps(); + if (m_proofs_enabled) { + proof * pr = g->pr(idx); + new_pr = m_temp_manager->mk_modus_ponens(pr, new_pr); + } + g->update(idx, new_curr, new_pr, g->dep(idx)); + } + + g->inc_depth(); + + simplify(g); + + TRACE("before_sat_solver", g->display(tout);); + g->elim_redundancies(); + + m_goal2sat(*g, m_params, solver, map); + + TRACE("sat_solver_unknown", tout << "interpreted_atoms: " << map.interpreted_atoms() << "\n"; + atom2bool_var::iterator it = map.begin(); + atom2bool_var::iterator end = map.end(); + for (; it != end; ++it) { + if (!is_uninterp_const(it->m_key)) + tout << mk_ismt2_pp(it->m_key, *m_temp_manager) << "\n"; + }); + + CASSERT("sat_solver", solver.check_invariant()); + IF_VERBOSE(TACTIC_VERBOSITY_LVL, solver.display_status(verbose_stream());); + TRACE("sat_dimacs", solver.display_dimacs(tout);); + } + + model_ref get_fpa_model(goal_ref const & g, + fpa2bv_converter_prec & fpa2bv, + bit_blaster_rewriter & bv2bool, + sat::solver & solver, + atom2bool_var & map) { + // CMW: This is all done using the temporary manager, until at the very end we translate the model back to this->m. + model_ref md = alloc(model, *m_temp_manager); + sat::model const & ll_m = solver.get_model(); + TRACE("sat_tactic", for (unsigned i = 0; i < ll_m.size(); i++) + tout << i << ":" << ll_m[i] << " "; tout << "\n";); + atom2bool_var::iterator it = map.begin(); + atom2bool_var::iterator end = map.end(); + for (; it != end; ++it) { + expr * n = it->m_key; + sat::bool_var v = it->m_value; + if (is_app(n) && to_app(n)->get_decl()->get_arity() != 0) + continue; + TRACE("sat_tactic", tout << "extracting value of " << mk_ismt2_pp(n, *m_temp_manager) << "\nvar: " << v << "\n";); + switch (sat::value_at(v, ll_m)) { + case l_true: md->register_decl(to_app(n)->get_decl(), m_temp_manager->mk_true()); break; + case l_false: md->register_decl(to_app(n)->get_decl(), m_temp_manager->mk_false()); break; + default: + break; + } + } + + TRACE("sat_tactic", model_v2_pp(tout, *md);); + model_converter_ref bb_mc = mk_bit_blaster_model_converter(*m_temp_manager, bv2bool.const2bits()); + model_converter_ref bv_mc = mk_fpa2bv_prec_model_converter(*m_temp_manager, fpa2bv.const2bv(), fpa2bv.rm_const2bv()); + bb_mc->operator()(md, 0); + bv_mc->operator()(md, 0); + +#ifdef Z3DEBUG + std::cout << "Model: " << std::endl; + for (unsigned i = 0 ; i < md->get_num_constants(); i++) { + func_decl * d = md->get_constant(i); + std::cout << d->get_name() << " = " << mk_ismt2_pp(md->get_const_interp(d), *m_temp_manager) << std::endl; + } +#endif + // md is in terms of the temporary manager. + ast_translation translator(*m_temp_manager, this->m); + return md->translate(translator); + } + + void encode_fpa_terms( goal_ref const & g, + obj_map & const2term_map) + { + for (obj_map::iterator it = const2term_map.begin(); + it!=const2term_map.end(); + it++) { + expr_ref q(m); +#ifdef Z3DEBUG + std::cout << "Adding " << it->m_key->get_name() << " = " << mk_ismt2_pp(it->m_value, m) << std::endl; +#endif + q = m.mk_eq(m.mk_const(it->m_key), it->m_value); + g->assert_expr(q); + } + } + + lbool approximate_model_construction(goal_ref & g, obj_map & const2prec_map) { + lbool r = l_undef; + // CMW: The following will introduce lots of stuff that we don't need (e.g., symbols) + // To save memory, we use a separate, new manager that we can throw away afterwards. + m_temp_manager = alloc(ast_manager, PGM_DISABLED); + { + ast_translation translator(m, *m_temp_manager); + goal_ref ng = g->translate(translator); + obj_map const2prec_map_tm; + + for (obj_map::iterator it = const2prec_map.begin(); + it!=const2prec_map.end(); + it++) + const2prec_map_tm.insert(translator(it->m_key), it->m_value); + + sat::solver sat_solver(m_params, 0); + atom2bool_var atom_map(*m_temp_manager); + { tactic_report report_i("fpa2bv_approx_before_bitblaster", *ng); } + fpa2bv_converter_prec fpa2bv(*m_temp_manager, m_mode); + bit_blaster_rewriter bv2bool(*m_temp_manager, m_params); + bitblast(ng, fpa2bv, bv2bool, const2prec_map_tm, sat_solver, atom_map); + { tactic_report report_i("fpa2bv_approx_after_bitblaster", *ng); } + + std::cout << "Iteration variables: " << sat_solver.num_vars() << std::endl; + std::cout << "Iteration clauses: " << sat_solver.num_clauses() << std::endl; + r = sat_solver.check(); + + if (r == l_true) + { + // we need to get the model and translate it back to m. + m_fpa_model = get_fpa_model(ng, fpa2bv, bv2bool, sat_solver, atom_map).get(); + } + else + m_fpa_model = 0; + + // CMW: translator, etc, gets destroyed here, so all references + // to temporary expressions are gone. + } + + dealloc(m_temp_manager); + m_temp_manager = 0; + + return r; + } + + void lift( goal_ref const & g, func_decl_ref_vector & constants, obj_map * const2term_map ) + { + expr_ref new_new_curr(m); + expr_ref new_curr(m); + proof_ref new_pr(m); + + simplify(g); + + //Renaming subexpressions using new constants + const_intro_rewriter const_rewriter(m, m_params); + for (unsigned idx = 0; idx < g->size(); idx++) { + if (g->inconsistent()) + break; + expr * curr = g->form(idx); + const_rewriter(curr, new_curr, new_pr); //Introduces constants that replace subexpressions + m_num_steps += const_rewriter.get_num_steps(); + if (m_proofs_enabled) { + proof * pr = g->pr(idx); + new_pr = m.mk_modus_ponens(pr, new_pr); + } + g->update(idx, new_curr, new_pr, g->dep(idx)); + } + + + constants.set(const_rewriter.m_cfg.m_introduced_consts); + const2term_map->swap(const_rewriter.m_cfg.m_const2term_map); + + // Note: Ideally, we would directly encode them. For now we're lazy and just add equalities + // and we rely on fpa2bv_converter_prec to `magically' recognize the equalities we added. + { tactic_report report_i("fpa2bv_approx_before_fpa_terms", *(g.get())); } + encode_fpa_terms(g, *const2term_map); + SASSERT(g.get()->is_well_sorted()); + + + } + + void verify_precise_model( goal_ref const & g, + model_ref & full_mdl, + func_decl_ref_vector & constants, + obj_map & const2term_map, + model_converter_ref & mc, + goal_ref_buffer & result ){ + expr_ref res(m); + + for (unsigned j = 0; j < g->size(); j++) { + full_mdl->eval(g->form(j), res, true); + if (!m.is_true(res)) { + std::cout << "Failed: " << mk_ismt2_pp(g->form(j), m) << std::endl; + std::cout << "Evaluates to: " << mk_ismt2_pp(res, m) << std::endl; + } + SASSERT(m.is_true(res)); + } + + std::cout << "Full model: " << std::endl; + for (unsigned i = 0 ; i < full_mdl->get_num_decls(); i++) + { + func_decl * d = full_mdl->get_decl(i); + if(constants.contains(d)) + std::cout << d->get_name() << " = " << mk_ismt2_pp(full_mdl->get_const_interp(d), m) << std::endl; + } + std::cout.flush(); + + result.back()->reset(); + + // Filter all the constants we introduced earlier from the model. + filter_model_converter * fmc = alloc(filter_model_converter, m); + for (obj_map::iterator it = const2term_map.begin(); + it != const2term_map.end(); + it++) + fmc->insert(it->m_key); + mc = concat(fmc, model2model_converter(m_fpa_model.get())); + } + + void setup_options(goal_ref const & g){ + SASSERT(g->is_well_sorted()); + fail_if_proof_generation("fpa2bv_approx", g); + fail_if_unsat_core_generation("fpa2bv_approx", g); + m_proofs_enabled = g->proofs_enabled(); + m_produce_models = g->models_enabled(); + m_produce_unsat_cores = g->unsat_core_enabled(); + m_num_steps = 0; + } + + void print_constants(func_decl_ref_vector & constants, obj_map & const2prec_map){ +#ifdef Z3DEBUG + for(unsigned i=0;iget_name()<<":"< const2prec_map; + obj_map next_const2prec_map; + func_decl_ref_vector constants(m); + obj_map const2term_map; + lbool r = l_true; + unsigned iteration_cnt = 0; + stopwatch sw; + + tactic_report report("fpa2bv_approx", *g); + TRACE("fpa2bv_approx", tout << "BEFORE: " << std::endl; g->display(tout);); + result.reset(); + result.push_back(g.get()); + + SASSERT(g->is_well_sorted()); + if (g->inconsistent()) + return; + + lift(g, constants, &const2term_map); + + init_precision_mapping(constants, const2prec_map, const2term_map); + + std::cout << "Simplified goal:" << std::endl; + g->display(std::cout); + + while (!solved && !m_cancel) + { + std::cout << "=============== Starting iteration " << ++iteration_cnt << std::endl; + + sw.reset(); + sw.start(); + + // Copy the goal + goal_ref mg(alloc(goal, g->m(),g->proofs_enabled(),g->models_enabled(),g->unsat_core_enabled())); + mg->copy_from(*g.get()); + tactic_report report_i("fpa2bv_approx_i", *mg); + + print_constants(constants, const2prec_map); + + TRACE("fpa2bv_approx_goal_i", mg->display(tout); ); + + r = approximate_model_construction(mg, const2prec_map); + + std::cout << "Approximation is " << (r==l_true?"SAT":r==l_false?"UNSAT":"UNKNOWN") << std::endl; + + if (r == l_true) { + model_ref full_mdl = alloc(model, m); + obj_map err_est; + + solved = precise_model_reconstruction(m_fpa_model, full_mdl, mg, err_est, constants, const2term_map); + + std::cout<<"Patching of the model "<<((solved)?"succeeded":"failed")< This is unsat. + solved = true; + result.back()->reset(); + result.back()->assert_expr(m.mk_false()); + } + } else { + // CMW: When the sat solver comes back with `unknown', what shall we do? + // AZ: Blindly refine? + m_cancel = true; + } + + const2prec_map.swap(next_const2prec_map); + next_const2prec_map.reset(); + std::cout << "Iteration time: " << sw.get_current_seconds() << std::endl; + } + + std::cout << "=============== Terminating " << std::endl; + dec_ref_map_key_values(m, const2term_map); + std::cout << "Iteration count: " << iteration_cnt << std::endl; + } + }; + + imp * m_imp; + params_ref m_params; + +public: + fpa2bv_approx_tactic(ast_manager & m, params_ref const & p) : + m_params(p){ + m_imp = alloc(imp, m, p, FPAA_DEFAULT_MODE); + } + + virtual tactic * translate(ast_manager & m) { + return alloc(fpa2bv_approx_tactic, m, m_params); + } + + virtual ~fpa2bv_approx_tactic() { + dealloc(m_imp); + } + + virtual void updt_params(params_ref const & p) { + m_params = p; + m_imp->updt_params(p); + } + + virtual void collect_param_descrs(param_descrs & r) { + } + + virtual void operator()(goal_ref const & in, goal_ref_buffer & result, + model_converter_ref & mc, proof_converter_ref & pc, + expr_dependency_ref & core) { + (*m_imp)(in, result, mc, pc, core); + } + + virtual void cleanup() { + ast_manager & m = m_imp->m; + imp * d = m_imp; +#pragma omp critical (tactic_cancel) + { + d = m_imp; + } + dealloc(d); + d = alloc(imp, m, m_params, FPAA_DEFAULT_MODE); +#pragma omp critical (tactic_cancel) + { + m_imp = d; + } + } + +protected: + virtual void set_cancel(bool f) { + if (m_imp) + m_imp->set_cancel(f); +} +}; + +tactic * mk_fpa2bv_approx_tactic(ast_manager & m, params_ref const & p) { + return and_then(clean(alloc(fpa2bv_approx_tactic, m, p)), mk_fail_if_undecided_tactic()); +} + + diff --git a/src/tactic/fpa/fpa2bv_approx_tactic.h b/src/tactic/fpa/fpa2bv_approx_tactic.h new file mode 100644 index 000000000..8838ca99d --- /dev/null +++ b/src/tactic/fpa/fpa2bv_approx_tactic.h @@ -0,0 +1,33 @@ +/*++ +Copyright (c) 2012 Microsoft Corporation + +Module Name: + + fpa2bv_lazy_tactic.h + +Abstract: + + Tactic that converts floating points to bit-vectors lazily + +Author: + + Aleksander Zeljic 2012-11-15 + +Notes: + +--*/ +#ifndef _FPA2BV_APPROX_TACTIC_ +#define _FPA2BV_APPROX_TACTIC_ + +#include"params.h" +class ast_manager; +class tactic; + + + +tactic * mk_fpa2bv_approx_tactic(ast_manager & m, params_ref const & p = params_ref()); +/* + ADD_TACTIC("fpa2bv_approx", "An iterative approximation based bit-blasting decision procedure for FPA.", "mk_fpa2bv_approx_tactic(m, p)") +*/ + +#endif diff --git a/src/tactic/fpa/fpa2bv_converter_prec.cpp b/src/tactic/fpa/fpa2bv_converter_prec.cpp new file mode 100644 index 000000000..ff627f7e4 --- /dev/null +++ b/src/tactic/fpa/fpa2bv_converter_prec.cpp @@ -0,0 +1,1783 @@ +/*++ +Copyright (c) 2012 Microsoft Corporation + +Module Name: + + fpa2bv_converter_prec.cpp + +Abstract: + + Conversion routines for Floating Point -> Bit-Vector + +Author: + + Christoph (cwinter) 2012-02-09 + +Notes: + +--*/ +#include"ast_smt2_pp.h" +#include"well_sorted.h" +#include + +#include"fpa2bv_converter_prec.h" + +#define BVULT(X,Y,R) { expr_ref bvult_eq(m), bvult_not(m); m_simp.mk_eq(X, Y, bvult_eq); m_simp.mk_not(bvult_eq, bvult_not); expr_ref t(m); t = m_bv_util.mk_ule(X,Y); m_simp.mk_and(t, bvult_not, R); } +#define BVSLT(X,Y,R) { expr_ref bvslt_eq(m), bvslt_not(m); m_simp.mk_eq(X, Y, bvslt_eq); m_simp.mk_not(bvslt_eq, bvslt_not); expr_ref t(m); t = m_bv_util.mk_sle(X,Y); m_simp.mk_and(t, bvslt_not, R); } + +#define MIN_EBITS 3 +#define MIN_SBITS 3 + +fpa2bv_converter_prec::fpa2bv_converter_prec(ast_manager & m, fpa_approximation_mode mode) : + fpa2bv_converter(m), + m_mode(mode) { +} + +void fpa2bv_converter_prec::fix_bits(unsigned prec, expr_ref rounded, unsigned sbits, unsigned ebits)//expr_ref& fixed, +{ //AZ: TODO: revise! minimal number of legal bits is 3!!!! Remove magic numbers + unsigned szeroes=((sbits-2)*(MAX_PRECISION - prec +0.0)/MAX_PRECISION);//3 bits are minimum for the significand + unsigned ezeroes=((ebits-2)*(MAX_PRECISION - prec+0.0)/MAX_PRECISION);//2 bits are minimum for the exponent + + expr_ref fix_sig(m), fix_exp(m); + expr * sgn, *sig, *expn; + split_fp( rounded.get(), sgn,sig,expn); + if(ezeroes>0) { + fix_exp=m.mk_eq(m_bv_util.mk_extract(ebits-2, ebits - ezeroes -1, sig), m_bv_util.mk_numeral(0,ezeroes)); + m_extra_assertions.push_back(fix_exp); + SASSERT(is_well_sorted(m, fix_exp)); + } + + if(szeroes>0) { + fix_sig=m.mk_eq(m_bv_util.mk_extract(sbits-2, sbits - szeroes -1, sig), m_bv_util.mk_numeral(0,szeroes)); + m_extra_assertions.push_back(fix_sig); + SASSERT(is_well_sorted(m, fix_sig)); + } +} + +void fpa2bv_converter_prec::mk_const(func_decl * f, unsigned prec, expr_ref & result) { + switch (m_mode) { + case FPAA_SMALL_FLOATS: + { + if (m_const2bv.contains(f)) + result = m_const2bv.find(f); + else { + if (prec == MAX_PRECISION) + fpa2bv_converter::mk_const(f, result); + else { + unsigned ebits = fu().get_ebits(f->get_range()); + unsigned sbits = fu().get_sbits(f->get_range()); + double rel = prec/(double)MAX_PRECISION; + unsigned new_ebits = (unsigned) (rel * (double)ebits); + unsigned new_sbits = (unsigned) (rel * (double)sbits); + if (new_ebits < MIN_EBITS) new_ebits = MIN_EBITS; + if (new_sbits < MIN_SBITS) new_sbits = MIN_SBITS; + sort_ref ns(m), fp_srt(m); + ns = fu().mk_float_sort(new_ebits, new_sbits); + app_ref small_const(m); + small_const = m.mk_fresh_const("small_const", ns); + + fp_srt = fu().mk_float_sort(ebits, sbits); + symbol name("asFloat"); + sort_ref rm_sort(m); + rm_sort = fu().mk_rm_sort(); + //sort * domain[2] = { rm_sort, ns }; + //parameter parameters[2] = { parameter(ebits), parameter(sbits) }; + + fpa2bv_converter::mk_const(small_const->get_decl(), result); + m_const2bv.insert(f, result.get()); + m.inc_ref(f); + m.inc_ref(result.get()); +#ifdef Z3DEBUG + std::cout << f->get_name() << " := " << small_const->get_decl()->get_name() << + " [" << new_sbits<<","<get_name() << " := " << mk_ismt2_pp(result, m) << std::endl;); + } + } + break; + } + case FPAA_PRECISE: + case FPAA_FIXBITS: + fpa2bv_converter::mk_const(f, result); break; + default: + UNREACHABLE(); + break; + } +} +void fpa2bv_converter_prec::mk_small_op(func_decl * f, unsigned new_ebits, unsigned new_sbits, unsigned num, expr * const * args, func_decl_ref & small_op, expr_ref_vector & cast_args) +{ + if (new_ebits < MIN_EBITS) new_ebits = MIN_EBITS; + if (new_sbits < MIN_SBITS) new_sbits = MIN_SBITS; + sort_ref new_srt(m), rm_srt(m); + new_srt = fu().mk_float_sort(new_ebits, new_sbits); + rm_srt = fu().mk_rm_sort(); + + sort_ref_vector new_domain(m); + cast_args.reset(); + + for (unsigned i=0; i < num; i++) // Recreate the domain by replacing the full fpa sort with the smaller one. + { + sort * d_i = f->get_domain(i); + expr * a_i = args[i]; + + if (fu().is_rm(d_i)) + { + new_domain.push_back(rm_srt); + cast_args.push_back(a_i); + } + else if (fu().is_float(f->get_domain(i))) + { + sort * a_i_srt = to_app(a_i)->get_decl()->get_range(); + new_domain.push_back(new_srt); + + // Cast the corresponding argument to the right fpa size + if (is_app(a_i)) + { + if (a_i_srt == new_srt) + cast_args.push_back(a_i); + else { + app_ref rtz(m); + rtz = fu().mk_round_toward_zero(); + expr_ref rm(m); + fpa2bv_converter::mk_rounding_mode(rtz->get_decl(), rm); + + sort * d[2] = { rm_srt, a_i_srt }; + symbol name("asFloat"); + func_decl_ref fd(m); + fd = m.mk_func_decl(name, 2, d, new_srt, func_decl_info(fu().get_family_id(), OP_FPA_TO_FP, new_srt->get_num_parameters(), new_srt->get_parameters())); + + expr_ref t(m); + expr * args[2] = { rm, a_i }; + fpa2bv_converter::mk_to_fp(fd, 2, args, t); + cast_args.push_back(t); + SASSERT(is_well_sorted(m, t)); + } + } + else + NOT_IMPLEMENTED_YET(); + } + else + // just keep everything else + cast_args.push_back(a_i); + } + + parameter parameters[2] = { parameter(new_ebits), parameter(new_sbits) }; + + // May I reuse parts of the existing declaration? CMW: Sure. + + small_op = m.mk_func_decl(f->get_name(), num, new_domain.c_ptr(), new_srt, + func_decl_info(fu().get_family_id(), f->get_decl_kind(), 2, parameters)); + + //std::cout<get_name()<<"["<get_range()); + unsigned sbits = fu().get_sbits(f->get_range()); + double rel = prec/(double)MAX_PRECISION; + unsigned new_ebits = (unsigned) (rel * (double)ebits);// (unsigned) (MIN_EBITS + rel * (double)(ebits-MIN_EBITS)) + unsigned new_sbits = (unsigned) (rel * (double)sbits);// (unsigned) (MIN_SBITS + rel * (double)(sbits-MIN_SBITS)) + mk_small_op(f,new_ebits,new_sbits,num,args, small_op, cast_args); +} + +void fpa2bv_converter_prec::mk_cast_small_to_big(func_decl * f, expr * arg, expr_ref & result) { + unsigned ebits = fu().get_ebits(f->get_range()); + unsigned sbits = fu().get_sbits(f->get_range()); + + app_ref rtz(m); + rtz = fu().mk_round_toward_zero(); + expr_ref rm(m); + fpa2bv_converter::mk_rounding_mode(rtz->get_decl(), rm); + sort_ref rm_srt(m); + rm_srt = fu().mk_rm_sort(); + sort * d[2] = { rm_srt, to_app(arg)->get_decl()->get_range() }; + parameter parameters[2] = { parameter(ebits), parameter(sbits) }; + symbol name("asFloat"); + func_decl_ref cast_up(m); + cast_up = m.mk_func_decl(name, 2, d, f->get_range(), func_decl_info(fu().get_family_id(), OP_FPA_TO_FP, f->get_range()->get_num_parameters(), parameters)); + expr * args[2] = { rm, arg }; + fpa2bv_converter::mk_to_fp(cast_up, 2, args, result); +} + +void fpa2bv_converter_prec::mk_cast_small_to_big(unsigned sbits, unsigned ebits, expr * arg, expr_ref & result) { + app_ref rtz(m); + rtz = fu().mk_round_toward_zero(); + expr_ref rm(m); + fpa2bv_converter::mk_rounding_mode(rtz->get_decl(), rm); + sort_ref rm_srt(m); + rm_srt = fu().mk_rm_sort(); + sort * d[2] = { rm_srt, to_app(arg)->get_decl()->get_range() }; + parameter parameters[2] = { parameter(ebits), parameter(sbits) }; + symbol name("asFloat"); + func_decl_ref cast_up(m); + sort_ref ns(m); + ns = fu().mk_float_sort(ebits, sbits); + cast_up = m.mk_func_decl(name, 2, d, ns, func_decl_info(fu().get_family_id(), OP_FPA_TO_FP, 2, parameters)); + expr * args[2] = { rm, arg }; + fpa2bv_converter::mk_to_fp(cast_up, 2, args, result); +} + + +void fpa2bv_converter_prec::match_sorts(expr * a, expr * b, expr_ref & n_a, expr_ref & n_b) +{ + //Check if the sorts of lhs and rhs match, otherwise cast them to appropriate size? + SASSERT(is_app_of(a, m_plugin->get_family_id(), OP_FPA_TO_FP)); + SASSERT(is_app_of(b, m_plugin->get_family_id(), OP_FPA_TO_FP)); + func_decl * a_decl = to_app(a)->get_decl(); + func_decl * b_decl = to_app(b)->get_decl(); + + unsigned a_ebits = fu().get_ebits(a_decl->get_range()); + unsigned a_sbits = fu().get_sbits(a_decl->get_range()); + unsigned b_ebits = fu().get_ebits(b_decl->get_range()); + unsigned b_sbits = fu().get_sbits(b_decl->get_range()); + unsigned n_ebits, n_sbits; + + //if( (a_ebits == b_ebits) && (a_sbits == b_sbits)) + //{//No need for adjustment + n_a = a; + n_b = b; + //} + //else + //{ + if ((a_ebits <= b_ebits) && (a_sbits<= b_sbits)) + {//sort of b is wider than sort of a, we cast a to the sort of b. + mk_cast_small_to_big(b_sbits,b_ebits,a,n_a); + n_b = b; + } + else if ((a_ebits >= b_ebits) && (a_sbits >= b_sbits)) + { + n_a = a; + mk_cast_small_to_big(a_sbits,a_ebits,b,n_b); + } + else + { + n_ebits = (a_ebits < b_ebits)? b_ebits:a_ebits; + n_sbits = (a_sbits < b_sbits)? b_sbits:a_sbits; + mk_cast_small_to_big(n_sbits,n_ebits,a,n_a); + mk_cast_small_to_big(n_sbits,n_ebits,b,n_b); + } + //} +} +void fpa2bv_converter_prec::mk_eq(expr * a, expr * b, expr_ref & result) { + // This is structural equality, not floating point equality. + expr_ref na(m),nb(m); + match_sorts(a,b,na,nb); + fpa2bv_converter::mk_eq(na,nb,result); +} + +void fpa2bv_converter_prec::mk_ite(expr * c, expr * t, expr * f, expr_ref & result) { + expr_ref nt(m),nf(m); + match_sorts(t,f,nt,nf); + fpa2bv_converter::mk_ite(c,nt,nf,result); +} + + + +void fpa2bv_converter_prec::mk_add(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result) { + // AZ: Switch can be moved just before the call to the fix_bits method, everything else should be the same + switch (m_mode) { + case FPAA_PRECISE: + fpa2bv_converter::mk_add(f,num,args,result); + break; + case FPAA_SMALL_FLOATS: + { + func_decl_ref small_fd(m); + expr_ref_vector small_args(m); + mk_small_op(f, prec, num, args, small_fd, small_args); + //expr_ref small_op(m); + fpa2bv_converter::mk_add(small_fd, num, small_args.c_ptr(), result); + //mk_cast_small_to_big(f, small_op, result); + SASSERT(is_well_sorted(m, result)); + TRACE("fpa2bv_small_float_add", tout << "small_fd: " << mk_ismt2_pp(small_fd, m) << std::endl << + "result = " << mk_ismt2_pp(result, m) << std::endl; ); + break; + } + + case FPAA_FIXBITS: { + if (MAX_PRECISION == prec) + fpa2bv_converter::mk_add(f,num,args,result); + else{ + //Alternative encoding + /*func_decl * nf = & func_decl(f->get_name(), + f->get_arity(), + f->get_domain(), + f->get_range(), + f->get_info());*/ + + + SASSERT(num == 3); + + expr_ref rm(m), x(m), y(m); + rm = args[0]; + x = args[1]; + y = args[2]; + + expr_ref nan(m), nzero(m), pzero(m); + mk_nan(f, nan); + mk_nzero(f, nzero); + mk_pzero(f, pzero); + + expr_ref x_is_nan(m), x_is_zero(m), x_is_pos(m), x_is_neg(m), x_is_inf(m); + expr_ref y_is_nan(m), y_is_zero(m), y_is_pos(m), y_is_neg(m), y_is_inf(m); + mk_is_nan(x, x_is_nan); + mk_is_zero(x, x_is_zero); + mk_is_pos(x, x_is_pos); + mk_is_neg(x, x_is_neg); + mk_is_inf(x, x_is_inf); + mk_is_nan(y, y_is_nan); + mk_is_zero(y, y_is_zero); + mk_is_pos(y, y_is_pos); + mk_is_neg(y, y_is_neg); + mk_is_inf(y, y_is_inf); + + dbg_decouple("fpa2bv_add_x_is_nan", x_is_nan); + dbg_decouple("fpa2bv_add_x_is_zero", x_is_zero); + dbg_decouple("fpa2bv_add_x_is_pos", x_is_pos); + dbg_decouple("fpa2bv_add_x_is_neg", x_is_neg); + dbg_decouple("fpa2bv_add_x_is_inf", x_is_inf); + dbg_decouple("fpa2bv_add_y_is_nan", y_is_nan); + dbg_decouple("fpa2bv_add_y_is_zero", y_is_zero); + dbg_decouple("fpa2bv_add_y_is_pos", y_is_pos); + dbg_decouple("fpa2bv_add_y_is_neg", y_is_neg); + dbg_decouple("fpa2bv_add_y_is_inf", y_is_inf); + + expr_ref c1(m), c2(m), c3(m), c4(m), c5(m), c6(m); + expr_ref v1(m), v2(m), v3(m), v4(m), v5(m), v6(m), v7(m); + + m_simp.mk_or(x_is_nan, y_is_nan, c1); + v1 = nan; + + mk_is_inf(x, c2); + expr_ref nx(m), ny(m), nx_xor_ny(m), inf_xor(m); + mk_is_neg(x, nx); + mk_is_neg(y, ny); + m_simp.mk_xor(nx, ny, nx_xor_ny); + m_simp.mk_and(y_is_inf, nx_xor_ny, inf_xor); + mk_ite(inf_xor, nan, x, v2); + + mk_is_inf(y, c3); + expr_ref xy_is_neg(m), v3_and(m); + m_simp.mk_xor(x_is_neg, y_is_neg, xy_is_neg); + m_simp.mk_and(x_is_inf, xy_is_neg, v3_and); + mk_ite(v3_and, nan, y, v3); + + expr_ref rm_is_to_neg(m), signs_and(m), signs_xor(m), v4_and(m), rm_and_xor(m), neg_cond(m); + m_simp.mk_and(x_is_zero, y_is_zero, c4); + m_simp.mk_and(x_is_neg, y_is_neg, signs_and); + m_simp.mk_xor(x_is_neg, y_is_neg, signs_xor); + mk_is_rm(rm, BV_RM_TO_NEGATIVE, rm_is_to_neg); + m_simp.mk_and(rm_is_to_neg, signs_xor, rm_and_xor); + m_simp.mk_or(signs_and, rm_and_xor, neg_cond); + mk_ite(neg_cond, nzero, pzero, v4); + m_simp.mk_and(x_is_neg, y_is_neg, v4_and); + mk_ite(v4_and, x, v4, v4); + + c5 = x_is_zero; + v5 = y; + + c6 = y_is_zero; + v6 = x; + + // Actual addition. + unsigned ebits = m_util.get_ebits(f->get_range()); + unsigned sbits = m_util.get_sbits(f->get_range()); + + expr_ref a_sgn(m), a_sig(m), a_exp(m), a_lz(m), b_sgn(m), b_sig(m), b_exp(m), b_lz(m); + unpack(x, a_sgn, a_sig, a_exp, a_lz, false); + unpack(y, b_sgn, b_sig, b_exp, b_lz, false); + + dbg_decouple("fpa2bv_add_unpack_a_sgn", a_sgn); + dbg_decouple("fpa2bv_add_unpack_a_sig", a_sig); + dbg_decouple("fpa2bv_add_unpack_a_exp", a_exp); + dbg_decouple("fpa2bv_add_unpack_b_sgn", b_sgn); + dbg_decouple("fpa2bv_add_unpack_b_sig", b_sig); + dbg_decouple("fpa2bv_add_unpack_b_exp", b_exp); + + expr_ref swap_cond(m); + swap_cond = m_bv_util.mk_sle(a_exp, b_exp); + + expr_ref c_sgn(m), c_sig(m), c_exp(m), d_sgn(m), d_sig(m), d_exp(m); + m_simp.mk_ite(swap_cond, b_sgn, a_sgn, c_sgn); + m_simp.mk_ite(swap_cond, b_sig, a_sig, c_sig); // has sbits + m_simp.mk_ite(swap_cond, b_exp, a_exp, c_exp); // has ebits + m_simp.mk_ite(swap_cond, a_sgn, b_sgn, d_sgn); + m_simp.mk_ite(swap_cond, a_sig, b_sig, d_sig); // has sbits + m_simp.mk_ite(swap_cond, a_exp, b_exp, d_exp); // has ebits + + expr_ref res_sgn(m), res_sig(m), res_exp(m); + add_core(sbits, ebits, rm, + c_sgn, c_sig, c_exp, d_sgn, d_sig, d_exp, + res_sgn, res_sig, res_exp); + + //Add the fixed zeroes here...? + expr_ref sbits_zero(m), ebits_zero(m); + // std::cout<<"res_sgn: "<1) + // //Exponent = 1 bit for bias, fixed bits, actual exponent bits + // res_exp=m_bv_util.mk_concat(m_bv_util.mk_extract(ebits+1, ebits-1, res_exp), + // m_bv_util.mk_concat(m_bv_util.mk_numeral(0,ezeroes), + // m_bv_util.mk_extract(ebits - 2 - ezeroes, 0 ,res_exp))); + // if(sones>1) + // res_sig=m_bv_util.mk_concat(m_bv_util.mk_extract(sbits+3,sones+4,res_sig), + // m_bv_util.mk_concat(m_bv_util.mk_numeral(0,sones), + // m_bv_util.mk_extract(3,0,res_sig))); + // + // std::cout<<"res_sgn': "<get_range(), rm, res_sgn, res_sig, res_exp, rounded); + + + mk_ite(is_zero_sig, zero_case, rounded, v7);*/ + + + + expr_ref rounded(m);//, fixed(m); + round(f->get_range(), rm, res_sgn, res_sig, res_exp, rounded); + + fix_bits(prec, rounded, sbits,ebits); + mk_ite(is_zero_sig, zero_case, rounded, v7); + + // signed sones=((sbits-3)*(MAX_PRECISION - prec +0.0)/MAX_PRECISION);//3 bits are minimum for the significand + // unsigned ezeroes=((ebits-2)*(MAX_PRECISION - prec+0.0)/MAX_PRECISION);//2 bits are minimum for the exponent + // expr_ref fix_sig(m), fix_exp(m), fix_sgn(m), rnd_sig(m), rnd_exp(m), rnd_sgn(m), rnd_lz(m); + // expr * sgn, *sig, *expn; + // split( rounded.get(), sgn,sig,expn); + // + // + // if(ezeroes>1) + // //Exponent = 1 bit for bias, fixed bits, actual exponent bits + // fix_exp=m_bv_util.mk_concat(m_bv_util.mk_extract(ebits-1, ebits-1, expn), + // m_bv_util.mk_concat(m_bv_util.mk_numeral(0,ezeroes), + // m_bv_util.mk_extract(ebits - 2 - ezeroes, 0 , expn))); + // if(sones>1) + // fix_sig=m_bv_util.mk_concat(m_bv_util.mk_extract(sbits-2,sones,sig), + // m_bv_util.mk_numeral(0,sones)); + // + // mk_triple(sgn, fix_sig, fix_exp, fixed); + // SASSERT(is_well_sorted(m, fixed)); + //mk_ite(is_zero_sig, zero_case, rounded, v7); + + + + + mk_ite(c6, v6, v7, result); + mk_ite(c5, v5, result, result); + mk_ite(c4, v4, result, result); + mk_ite(c3, v3, result, result); + mk_ite(c2, v2, result, result); + mk_ite(c1, v1, result, result); + + SASSERT(is_well_sorted(m, result)); + + TRACE("fpa2bv_add", tout << "ADD = " << mk_ismt2_pp(result, m) << std::endl; ); + } + break; + } + default: UNREACHABLE(); break; + } +} + +void fpa2bv_converter_prec::mk_sub(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result) { + SASSERT(num == 3); + expr_ref t(m); + fpa2bv_converter::mk_neg(f, 1, &args[2], t); + expr * nargs[3] = { args[0], args[1], t }; + + switch (m_mode) { + case FPAA_PRECISE: + fpa2bv_converter::mk_add(f, 3, nargs, result); + break; + case FPAA_FIXBITS: // Call the add with prec + case FPAA_SMALL_FLOATS: + fpa2bv_converter_prec::mk_add(f, prec, 3, nargs, result); + break; + default: UNREACHABLE(); break; + } +} + +void fpa2bv_converter_prec::mk_uminus(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result) { + switch (m_mode) { + case FPAA_PRECISE: + case FPAA_SMALL_FLOATS: + case FPAA_FIXBITS: // for now, encode fully. + fpa2bv_converter::mk_neg(f,num,args,result); + break; + default: UNREACHABLE(); break; + } +} + +void fpa2bv_converter_prec::mk_mul(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result) { + switch (m_mode) { + case FPAA_PRECISE: + fpa2bv_converter::mk_mul(f,num,args,result); + break; + case FPAA_SMALL_FLOATS: + { + func_decl_ref small_fd(m); + expr_ref_vector small_args(m); + mk_small_op(f, prec, num, args, small_fd, small_args); + expr_ref small_op(m); + fpa2bv_converter::mk_mul(small_fd, num, small_args.c_ptr(), small_op); + mk_cast_small_to_big(f, small_op, result); + SASSERT(is_well_sorted(m, result)); + TRACE("fpa2bv_small_float_mul", tout << mk_ismt2_pp(result, m) << std::endl; ); + break; + } + case FPAA_FIXBITS: // for now, encode fully. + { SASSERT(num == 3); + + expr_ref rm(m), x(m), y(m); + rm = args[0]; + x = args[1]; + y = args[2]; + + expr_ref nan(m), nzero(m), pzero(m), ninf(m), pinf(m); + mk_nan(f, nan); + mk_nzero(f, nzero); + mk_pzero(f, pzero); + mk_ninf(f, ninf); + mk_pinf(f, pinf); + + expr_ref x_is_nan(m), x_is_zero(m), x_is_pos(m), x_is_inf(m); + expr_ref y_is_nan(m), y_is_zero(m), y_is_pos(m), y_is_inf(m); + mk_is_nan(x, x_is_nan); + mk_is_zero(x, x_is_zero); + mk_is_pos(x, x_is_pos); + mk_is_inf(x, x_is_inf); + mk_is_nan(y, y_is_nan); + mk_is_zero(y, y_is_zero); + mk_is_pos(y, y_is_pos); + mk_is_inf(y, y_is_inf); + + dbg_decouple("fpa2bv_mul_x_is_nan", x_is_nan); + dbg_decouple("fpa2bv_mul_x_is_zero", x_is_zero); + dbg_decouple("fpa2bv_mul_x_is_pos", x_is_pos); + dbg_decouple("fpa2bv_mul_x_is_inf", x_is_inf); + dbg_decouple("fpa2bv_mul_y_is_nan", y_is_nan); + dbg_decouple("fpa2bv_mul_y_is_zero", y_is_zero); + dbg_decouple("fpa2bv_mul_y_is_pos", y_is_pos); + dbg_decouple("fpa2bv_mul_y_is_inf", y_is_inf); + + expr_ref c1(m), c2(m), c3(m), c4(m), c5(m), c6(m); + expr_ref v1(m), v2(m), v3(m), v4(m), v5(m), v6(m), v7(m); + + // (x is NaN) || (y is NaN) -> NaN + m_simp.mk_or(x_is_nan, y_is_nan, c1); + v1 = nan; + + // (x is +oo) -> if (y is 0) then NaN else inf with y's sign. + mk_is_pinf(x, c2); + expr_ref y_sgn_inf(m); + mk_ite(y_is_pos, pinf, ninf, y_sgn_inf); + mk_ite(y_is_zero, nan, y_sgn_inf, v2); + + // (y is +oo) -> if (x is 0) then NaN else inf with x's sign. + mk_is_pinf(y, c3); + expr_ref x_sgn_inf(m); + mk_ite(x_is_pos, pinf, ninf, x_sgn_inf); + mk_ite(x_is_zero, nan, x_sgn_inf, v3); + + // (x is -oo) -> if (y is 0) then NaN else inf with -y's sign. + mk_is_ninf(x, c4); + expr_ref neg_y_sgn_inf(m); + mk_ite(y_is_pos, ninf, pinf, neg_y_sgn_inf); + mk_ite(y_is_zero, nan, neg_y_sgn_inf, v4); + + // (y is -oo) -> if (x is 0) then NaN else inf with -x's sign. + mk_is_ninf(y, c5); + expr_ref neg_x_sgn_inf(m); + mk_ite(x_is_pos, ninf, pinf, neg_x_sgn_inf); + mk_ite(x_is_zero, nan, neg_x_sgn_inf, v5); + + // (x is 0) || (y is 0) -> x but with sign = x.sign ^ y.sign + m_simp.mk_or(x_is_zero, y_is_zero, c6); + expr_ref sign_xor(m); + m_simp.mk_xor(x_is_pos, y_is_pos, sign_xor); + mk_ite(sign_xor, nzero, pzero, v6); + + // else comes the actual multiplication. + unsigned ebits = m_util.get_ebits(f->get_range()); + unsigned sbits = m_util.get_sbits(f->get_range()); + SASSERT(ebits <= sbits); + + expr_ref a_sgn(m), a_sig(m), a_exp(m), a_lz(m), b_sgn(m), b_sig(m), b_exp(m), b_lz(m); + unpack(x, a_sgn, a_sig, a_exp, a_lz, true); + unpack(y, b_sgn, b_sig, b_exp, b_lz, true); + + dbg_decouple("fpa2bv_mul_a_sig", a_sig); + dbg_decouple("fpa2bv_mul_a_exp", a_exp); + dbg_decouple("fpa2bv_mul_b_sig", b_sig); + dbg_decouple("fpa2bv_mul_b_exp", b_exp); + + expr_ref a_lz_ext(m), b_lz_ext(m); + a_lz_ext = m_bv_util.mk_zero_extend(2, a_lz); + b_lz_ext = m_bv_util.mk_zero_extend(2, b_lz); + + dbg_decouple("fpa2bv_mul_lz_a", a_lz); + dbg_decouple("fpa2bv_mul_lz_b", b_lz); + + expr_ref a_sig_ext(m), b_sig_ext(m); + a_sig_ext = m_bv_util.mk_zero_extend(sbits, a_sig); + b_sig_ext = m_bv_util.mk_zero_extend(sbits, b_sig); + + expr_ref a_exp_ext(m), b_exp_ext(m); + a_exp_ext = m_bv_util.mk_sign_extend(2, a_exp); + b_exp_ext = m_bv_util.mk_sign_extend(2, b_exp); + + expr_ref res_sgn(m), res_sig(m), res_exp(m); + expr * signs[2] = { a_sgn, b_sgn }; + res_sgn = m_bv_util.mk_bv_xor(2, signs); + + dbg_decouple("fpa2bv_mul_res_sgn", res_sgn); + + res_exp = m_bv_util.mk_bv_add( + m_bv_util.mk_bv_sub(a_exp_ext, a_lz_ext), + m_bv_util.mk_bv_sub(b_exp_ext, b_lz_ext)); + + expr_ref product(m); + product = m_bv_util.mk_bv_mul(a_sig_ext, b_sig_ext); + + dbg_decouple("fpa2bv_mul_product", product); + + SASSERT(m_bv_util.get_bv_size(product) == 2*sbits); + + expr_ref h_p(m), l_p(m), rbits(m); + h_p = m_bv_util.mk_extract(2*sbits-1, sbits, product); + l_p = m_bv_util.mk_extract(sbits-1, 0, product); + + if (sbits >= 4) { + expr_ref sticky(m); + sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, m_bv_util.mk_extract(sbits-4, 0, product)); + rbits = m_bv_util.mk_concat(m_bv_util.mk_extract(sbits-1, sbits-3, product), sticky); + } + else + rbits = m_bv_util.mk_concat(l_p, m_bv_util.mk_numeral(0, 4 - sbits)); + + SASSERT(m_bv_util.get_bv_size(rbits) == 4); + res_sig = m_bv_util.mk_concat(h_p, rbits); + + //expr_ref rounded(m); + round(f->get_range(), rm, res_sgn, res_sig, res_exp, v7); + + //AZ:the only difference to the original + fix_bits(prec, v7, sbits, ebits); + + // And finally, we tie them together. + mk_ite(c6, v6, v7, result); + mk_ite(c5, v5, result, result); + mk_ite(c4, v4, result, result); + mk_ite(c3, v3, result, result); + mk_ite(c2, v2, result, result); + mk_ite(c1, v1, result, result); + + SASSERT(is_well_sorted(m, result)); + + TRACE("fpa2bv_mul", tout << "MUL = " << mk_ismt2_pp(result, m) << std::endl; ); + } + break; + default: UNREACHABLE(); break; + } +} + +void fpa2bv_converter_prec::mk_div(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result) { + switch (m_mode) { + case FPAA_SMALL_FLOATS: + { + func_decl_ref small_fd(m); + expr_ref_vector small_args(m); + mk_small_op(f, prec, num, args, small_fd, small_args); + expr_ref small_op(m); + fpa2bv_converter::mk_div(small_fd, num, small_args.c_ptr(), small_op); + mk_cast_small_to_big(f, small_op, result); + SASSERT(is_well_sorted(m, result)); + TRACE("fpa2bv_small_float_div", tout << mk_ismt2_pp(result, m) << std::endl; ); + break; + } + case FPAA_PRECISE: + case FPAA_FIXBITS: // for now, encode fully. + fpa2bv_converter::mk_div(f,num,args,result); + break; + + { + SASSERT(num == 3); + + expr_ref rm(m), x(m), y(m); + rm = args[0]; + x = args[1]; + y = args[2]; + + expr_ref nan(m), nzero(m), pzero(m), ninf(m), pinf(m); + mk_nan(f, nan); + mk_nzero(f, nzero); + mk_pzero(f, pzero); + mk_ninf(f, ninf); + mk_pinf(f, pinf); + + expr_ref x_is_nan(m), x_is_zero(m), x_is_pos(m), x_is_inf(m); + expr_ref y_is_nan(m), y_is_zero(m), y_is_pos(m), y_is_inf(m); + mk_is_nan(x, x_is_nan); + mk_is_zero(x, x_is_zero); + mk_is_pos(x, x_is_pos); + mk_is_inf(x, x_is_inf); + mk_is_nan(y, y_is_nan); + mk_is_zero(y, y_is_zero); + mk_is_pos(y, y_is_pos); + mk_is_inf(y, y_is_inf); + + dbg_decouple("fpa2bv_div_x_is_nan", x_is_nan); + dbg_decouple("fpa2bv_div_x_is_zero", x_is_zero); + dbg_decouple("fpa2bv_div_x_is_pos", x_is_pos); + dbg_decouple("fpa2bv_div_x_is_inf", x_is_inf); + dbg_decouple("fpa2bv_div_y_is_nan", y_is_nan); + dbg_decouple("fpa2bv_div_y_is_zero", y_is_zero); + dbg_decouple("fpa2bv_div_y_is_pos", y_is_pos); + dbg_decouple("fpa2bv_div_y_is_inf", y_is_inf); + + expr_ref c1(m), c2(m), c3(m), c4(m), c5(m), c6(m), c7(m); + expr_ref v1(m), v2(m), v3(m), v4(m), v5(m), v6(m), v7(m), v8(m); + + // (x is NaN) || (y is NaN) -> NaN + m_simp.mk_or(x_is_nan, y_is_nan, c1); + v1 = nan; + + // (x is +oo) -> if (y is oo) then NaN else inf with y's sign. + mk_is_pinf(x, c2); + expr_ref y_sgn_inf(m); + mk_ite(y_is_pos, pinf, ninf, y_sgn_inf); + mk_ite(y_is_inf, nan, y_sgn_inf, v2); + + // (y is +oo) -> if (x is oo) then NaN else 0 with sign x.sgn ^ y.sgn + mk_is_pinf(y, c3); + expr_ref xy_zero(m), signs_xor(m); + m_simp.mk_xor(x_is_pos, y_is_pos, signs_xor); + mk_ite(signs_xor, nzero, pzero, xy_zero); + mk_ite(x_is_inf, nan, xy_zero, v3); + + // (x is -oo) -> if (y is oo) then NaN else inf with -y's sign. + mk_is_ninf(x, c4); + expr_ref neg_y_sgn_inf(m); + mk_ite(y_is_pos, ninf, pinf, neg_y_sgn_inf); + mk_ite(y_is_inf, nan, neg_y_sgn_inf, v4); + + // (y is -oo) -> if (x is oo) then NaN else 0 with sign x.sgn ^ y.sgn + mk_is_ninf(y, c5); + mk_ite(x_is_inf, nan, xy_zero, v5); + + // (y is 0) -> if (x is 0) then NaN else inf with xor sign. + c6 = y_is_zero; + expr_ref sgn_inf(m); + mk_ite(signs_xor, ninf, pinf, sgn_inf); + mk_ite(x_is_zero, nan, sgn_inf, v6); + + // (x is 0) -> result is zero with sgn = x.sgn^y.sgn + // This is a special case to avoid problems with the unpacking of zero. + c7 = x_is_zero; + mk_ite(signs_xor, nzero, pzero, v7); + + // else comes the actual division. + unsigned ebits = m_util.get_ebits(f->get_range()); + unsigned sbits = m_util.get_sbits(f->get_range()); + SASSERT(ebits <= sbits); + + expr_ref a_sgn(m), a_sig(m), a_exp(m), a_lz(m), b_sgn(m), b_sig(m), b_exp(m), b_lz(m); + unpack(x, a_sgn, a_sig, a_exp, a_lz, true); + unpack(y, b_sgn, b_sig, b_exp, b_lz, true); + + unsigned extra_bits = sbits+2; + expr_ref a_sig_ext(m), b_sig_ext(m); + a_sig_ext = m_bv_util.mk_concat(a_sig, m_bv_util.mk_numeral(0, sbits + extra_bits)); + b_sig_ext = m_bv_util.mk_zero_extend(sbits + extra_bits, b_sig); + + expr_ref a_exp_ext(m), b_exp_ext(m); + a_exp_ext = m_bv_util.mk_sign_extend(2, a_exp); + b_exp_ext = m_bv_util.mk_sign_extend(2, b_exp); + + expr_ref res_sgn(m), res_sig(m), res_exp(m); + expr * signs[2] = { a_sgn, b_sgn }; + res_sgn = m_bv_util.mk_bv_xor(2, signs); + + expr_ref a_lz_ext(m), b_lz_ext(m); + a_lz_ext = m_bv_util.mk_zero_extend(2, a_lz); + b_lz_ext = m_bv_util.mk_zero_extend(2, b_lz); + + res_exp = m_bv_util.mk_bv_sub( + m_bv_util.mk_bv_sub(a_exp_ext, a_lz_ext), + m_bv_util.mk_bv_sub(b_exp_ext, b_lz_ext)); + + expr_ref quotient(m); + quotient = m.mk_app(m_bv_util.get_fid(), OP_BUDIV, a_sig_ext, b_sig_ext); + + dbg_decouple("fpa2bv_div_quotient", quotient); + + SASSERT(m_bv_util.get_bv_size(quotient) == (sbits + sbits + extra_bits)); + + expr_ref sticky(m); + sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, m_bv_util.mk_extract(extra_bits-2, 0, quotient)); + res_sig = m_bv_util.mk_concat(m_bv_util.mk_extract(extra_bits+sbits+1, extra_bits-1, quotient), sticky); + + SASSERT(m_bv_util.get_bv_size(res_sig) == (sbits + 4)); + + //expr_ref rounded(m);//AZ + round(f->get_range(), rm, res_sgn, res_sig, res_exp, v8); + + fix_bits(prec, v8,sbits,ebits);//AZ + + // And finally, we tie them together. + mk_ite(c7, v7, v8, result); + mk_ite(c6, v6, result, result); + mk_ite(c5, v5, result, result); + mk_ite(c4, v4, result, result); + mk_ite(c3, v3, result, result); + mk_ite(c2, v2, result, result); + mk_ite(c1, v1, result, result); + + SASSERT(is_well_sorted(m, result)); + + TRACE("fpa2bv_div", tout << "DIV = " << mk_ismt2_pp(result, m) << std::endl; ); + } + break; + default: UNREACHABLE(); break; + } +} + +void fpa2bv_converter_prec::mk_remainder(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result) { + switch (m_mode) { + case FPAA_SMALL_FLOATS: + { + func_decl_ref small_fd(m); + expr_ref_vector small_args(m); + mk_small_op(f, prec, num, args, small_fd, small_args); + expr_ref small_op(m); + fpa2bv_converter::mk_rem(small_fd, num, small_args.c_ptr(), small_op); + mk_cast_small_to_big(f, small_op, result); + SASSERT(is_well_sorted(m, result)); + TRACE("fpa2bv_small_float_remainder", tout << mk_ismt2_pp(result, m) << std::endl; ); + break; + } + case FPAA_PRECISE: + fpa2bv_converter::mk_rem(f,num,args,result); + break; + case FPAA_FIXBITS: // for now, encode fully. + { + SASSERT(num == 2); + + // Remainder is always exact, so there is no rounding mode. + expr_ref x(m), y(m); + x = args[0]; + y = args[1]; + + expr_ref nan(m), nzero(m), pzero(m), ninf(m), pinf(m); + mk_nan(f, nan); + mk_nzero(f, nzero); + mk_pzero(f, pzero); + mk_ninf(f, ninf); + mk_pinf(f, pinf); + + expr_ref x_is_nan(m), x_is_zero(m), x_is_pos(m), x_is_inf(m); + expr_ref y_is_nan(m), y_is_zero(m), y_is_pos(m), y_is_inf(m); + mk_is_nan(x, x_is_nan); + mk_is_zero(x, x_is_zero); + mk_is_pos(x, x_is_pos); + mk_is_inf(x, x_is_inf); + mk_is_nan(y, y_is_nan); + mk_is_zero(y, y_is_zero); + mk_is_pos(y, y_is_pos); + mk_is_inf(y, y_is_inf); + + dbg_decouple("fpa2bv_rem_x_is_nan", x_is_nan); + dbg_decouple("fpa2bv_rem_x_is_zero", x_is_zero); + dbg_decouple("fpa2bv_rem_x_is_pos", x_is_pos); + dbg_decouple("fpa2bv_rem_x_is_inf", x_is_inf); + dbg_decouple("fpa2bv_rem_y_is_nan", y_is_nan); + dbg_decouple("fpa2bv_rem_y_is_zero", y_is_zero); + dbg_decouple("fpa2bv_rem_y_is_pos", y_is_pos); + dbg_decouple("fpa2bv_rem_y_is_inf", y_is_inf); + + expr_ref c1(m), c2(m), c3(m), c4(m), c5(m), c6(m); + expr_ref v1(m), v2(m), v3(m), v4(m), v5(m), v6(m), v7(m); + + // (x is NaN) || (y is NaN) -> NaN + m_simp.mk_or(x_is_nan, y_is_nan, c1); + v1 = nan; + + // (x is +-oo) -> NaN + c2 = x_is_inf; + v2 = nan; + + // (y is +-oo) -> x + c3 = y_is_inf; + v3 = x; + + // (x is 0) -> x + c4 = x_is_zero; + v4 = pzero; + + // (y is 0) -> NaN. + c5 = y_is_zero; + v5 = nan; + + // else the actual remainder. + unsigned ebits = m_util.get_ebits(f->get_range()); + unsigned sbits = m_util.get_sbits(f->get_range()); + + expr_ref a_sgn(m), a_sig(m), a_exp(m), a_lz(m); + expr_ref b_sgn(m), b_sig(m), b_exp(m), b_lz(m); + unpack(x, a_sgn, a_sig, a_exp, a_lz, true); + unpack(y, b_sgn, b_sig, b_exp, b_lz, true); + + BVSLT(a_exp, b_exp, c6); + v6 = x; + + // max. exponent difference is (2^ebits) - 3 + const mpz & two_to_ebits = fu().fm().m_powers2(ebits); + mpz max_exp_diff; + m_mpz_manager.sub(two_to_ebits, 3, max_exp_diff); + SASSERT(m_mpz_manager.is_int64(max_exp_diff)); + SASSERT(m_mpz_manager.get_uint64(max_exp_diff) <= UINT_MAX); + + unsigned int max_exp_diff_ui = (unsigned int)m_mpz_manager.get_uint64(max_exp_diff); + m_mpz_manager.del(max_exp_diff); + + expr_ref exp_diff(m); + exp_diff = m_bv_util.mk_bv_sub(a_exp, b_exp); + dbg_decouple("fpa2bv_rem_exp_diff", exp_diff); + + // CMW: This creates _huge_ bit-vectors, which is potentially sub-optimal, + // but calculating this via rem = x - y * nearest(x/y) creates huge circuits. + expr_ref huge_sig(m), shifted_sig(m), huge_rem(m); + huge_sig = m_bv_util.mk_zero_extend(max_exp_diff_ui, a_sig); + shifted_sig = m_bv_util.mk_bv_shl(huge_sig, m_bv_util.mk_zero_extend(max_exp_diff_ui + sbits - ebits, exp_diff)); + huge_rem = m_bv_util.mk_bv_urem(shifted_sig, m_bv_util.mk_zero_extend(max_exp_diff_ui, b_sig)); + dbg_decouple("fpa2bv_rem_huge_rem", huge_rem); + + expr_ref res_sgn(m), res_sig(m), res_exp(m); + res_sgn = a_sgn; + res_sig = m_bv_util.mk_concat(m_bv_util.mk_extract(sbits, 0, huge_rem), + m_bv_util.mk_numeral(0, 3)); + res_exp = m_bv_util.mk_sign_extend(2, b_exp); + + expr_ref rm(m); + rm = m_bv_util.mk_numeral(BV_RM_TIES_TO_EVEN, 3); + + //expr_ref rounded(m); + round(f->get_range(), rm, res_sgn, res_sig, res_exp, v7); + + fix_bits(prec, v7,sbits, ebits); + + // And finally, we tie them together. + mk_ite(c6, v6, v7, result); + mk_ite(c5, v5, result, result); + mk_ite(c4, v4, result, result); + mk_ite(c3, v3, result, result); + mk_ite(c2, v2, result, result); + mk_ite(c1, v1, result, result); + + SASSERT(is_well_sorted(m, result)); + + TRACE("fpa2bv_rem", tout << "REM = " << mk_ismt2_pp(result, m) << std::endl; ); + } + break; + default: UNREACHABLE(); break; + } +} + +void fpa2bv_converter_prec::mk_abs(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result) { + //This doesn't need approximation in it's current form + switch (m_mode) { + case FPAA_PRECISE: + case FPAA_SMALL_FLOATS: + case FPAA_FIXBITS: // for now, encode fully. + fpa2bv_converter::mk_abs(f,num,args,result); + break; + default: UNREACHABLE(); break; + } +} + +void fpa2bv_converter_prec::mk_min(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result) { + switch (m_mode) { + case FPAA_PRECISE: + case FPAA_SMALL_FLOATS: + case FPAA_FIXBITS: // for now, encode fully. + fpa2bv_converter::mk_min(f,num,args,result); + break; + default: UNREACHABLE(); break; + } +} + +void fpa2bv_converter_prec::mk_max(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result) { + switch (m_mode) { + case FPAA_PRECISE: + case FPAA_SMALL_FLOATS: + case FPAA_FIXBITS: // for now, encode fully. + fpa2bv_converter::mk_max(f,num,args,result); + break; + default: UNREACHABLE(); break; + } +} + +void fpa2bv_converter_prec::mk_fusedma(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result) { + switch (m_mode) { + case FPAA_SMALL_FLOATS: + { + func_decl_ref small_fd(m); + expr_ref_vector small_args(m); + mk_small_op(f, prec, num, args, small_fd, small_args); + expr_ref small_op(m); + fpa2bv_converter::mk_fma(small_fd, num, small_args.c_ptr(), small_op); + mk_cast_small_to_big(f, small_op, result); + SASSERT(is_well_sorted(m, result)); + TRACE("fpa2bv_small_float_fma", tout << mk_ismt2_pp(result, m) << std::endl; ); + break; + } + case FPAA_PRECISE: + fpa2bv_converter::mk_fma(f,num,args,result); + break; + case FPAA_FIXBITS: + { + SASSERT(num == 4); + + // fusedma means (x * y) + z + expr_ref rm(m), x(m), y(m), z(m); + rm = args[0]; + x = args[1]; + y = args[2]; + z = args[3]; + + expr_ref nan(m), nzero(m), pzero(m), ninf(m), pinf(m); + mk_nan(f, nan); + mk_nzero(f, nzero); + mk_pzero(f, pzero); + mk_ninf(f, ninf); + mk_pinf(f, pinf); + + expr_ref x_is_nan(m), x_is_zero(m), x_is_pos(m), x_is_neg(m), x_is_inf(m); + expr_ref y_is_nan(m), y_is_zero(m), y_is_pos(m), y_is_neg(m), y_is_inf(m); + expr_ref z_is_nan(m), z_is_zero(m), z_is_pos(m), z_is_neg(m), z_is_inf(m); + mk_is_nan(x, x_is_nan); + mk_is_zero(x, x_is_zero); + mk_is_pos(x, x_is_pos); + mk_is_neg(x, x_is_neg); + mk_is_inf(x, x_is_inf); + mk_is_nan(y, y_is_nan); + mk_is_zero(y, y_is_zero); + mk_is_pos(y, y_is_pos); + mk_is_neg(y, y_is_neg); + mk_is_inf(y, y_is_inf); + mk_is_nan(z, z_is_nan); + mk_is_zero(z, z_is_zero); + mk_is_pos(z, z_is_pos); + mk_is_neg(z, z_is_neg); + mk_is_inf(z, z_is_inf); + + expr_ref rm_is_to_neg(m); + mk_is_rm(rm, BV_RM_TO_NEGATIVE, rm_is_to_neg); + + dbg_decouple("fpa2bv_fma_x_is_nan", x_is_nan); + dbg_decouple("fpa2bv_fma_x_is_zero", x_is_zero); + dbg_decouple("fpa2bv_fma_x_is_pos", x_is_pos); + dbg_decouple("fpa2bv_fma_x_is_inf", x_is_inf); + dbg_decouple("fpa2bv_fma_y_is_nan", y_is_nan); + dbg_decouple("fpa2bv_fma_y_is_zero", y_is_zero); + dbg_decouple("fpa2bv_fma_y_is_pos", y_is_pos); + dbg_decouple("fpa2bv_fma_y_is_inf", y_is_inf); + dbg_decouple("fpa2bv_fma_z_is_nan", z_is_nan); + dbg_decouple("fpa2bv_fma_z_is_zero", z_is_zero); + dbg_decouple("fpa2bv_fma_z_is_pos", z_is_pos); + dbg_decouple("fpa2bv_fma_z_is_inf", z_is_inf); + + expr_ref c1(m), c2(m), c3(m), c4(m), c5(m), c6(m), c7(m); + expr_ref v1(m), v2(m), v3(m), v4(m), v5(m), v6(m), v7(m), v8(m); + + expr_ref inf_xor(m), inf_cond(m); + m_simp.mk_xor(x_is_neg, y_is_neg, inf_xor); + m_simp.mk_xor(inf_xor, z_is_neg, inf_xor); + m_simp.mk_and(z_is_inf, inf_xor, inf_cond); + + // (x is NaN) || (y is NaN) || (z is Nan) -> NaN + m_simp.mk_or(x_is_nan, y_is_nan, z_is_nan, c1); + v1 = nan; + + // (x is +oo) -> if (y is 0) then NaN else inf with y's sign. + mk_is_pinf(x, c2); + expr_ref y_sgn_inf(m), inf_or(m); + mk_ite(y_is_pos, pinf, ninf, y_sgn_inf); + m_simp.mk_or(y_is_zero, inf_cond, inf_or); + mk_ite(inf_or, nan, y_sgn_inf, v2); + + // (y is +oo) -> if (x is 0) then NaN else inf with x's sign. + mk_is_pinf(y, c3); + expr_ref x_sgn_inf(m); + mk_ite(x_is_pos, pinf, ninf, x_sgn_inf); + m_simp.mk_or(x_is_zero, inf_cond, inf_or); + mk_ite(inf_or, nan, x_sgn_inf, v3); + + // (x is -oo) -> if (y is 0) then NaN else inf with -y's sign. + mk_is_ninf(x, c4); + expr_ref neg_y_sgn_inf(m); + mk_ite(y_is_pos, ninf, pinf, neg_y_sgn_inf); + m_simp.mk_or(y_is_zero, inf_cond, inf_or); + mk_ite(inf_or, nan, neg_y_sgn_inf, v4); + + // (y is -oo) -> if (x is 0) then NaN else inf with -x's sign. + mk_is_ninf(y, c5); + expr_ref neg_x_sgn_inf(m); + mk_ite(x_is_pos, ninf, pinf, neg_x_sgn_inf); + m_simp.mk_or(x_is_zero, inf_cond, inf_or); + mk_ite(inf_or, nan, neg_x_sgn_inf, v5); + + // z is +-INF -> z. + mk_is_inf(z, c6); + v6 = z; + + // (x is 0) || (y is 0) -> z + m_simp.mk_or(x_is_zero, y_is_zero, c7); + expr_ref ite_c(m); + m_simp.mk_and(z_is_zero, m.mk_not(rm_is_to_neg), ite_c); + mk_ite(ite_c, pzero, z, v7); + + + // else comes the fused multiplication. + unsigned ebits = m_util.get_ebits(f->get_range()); + unsigned sbits = m_util.get_sbits(f->get_range()); + SASSERT(ebits <= sbits); + + expr_ref a_sgn(m), a_sig(m), a_exp(m), a_lz(m); + expr_ref b_sgn(m), b_sig(m), b_exp(m), b_lz(m); + expr_ref c_sgn(m), c_sig(m), c_exp(m), c_lz(m); + unpack(x, a_sgn, a_sig, a_exp, a_lz, true); + unpack(y, b_sgn, b_sig, b_exp, b_lz, true); + unpack(z, c_sgn, c_sig, c_exp, c_lz, true); + + expr_ref a_lz_ext(m), b_lz_ext(m), c_lz_ext(m); + a_lz_ext = m_bv_util.mk_zero_extend(2, a_lz); + b_lz_ext = m_bv_util.mk_zero_extend(2, b_lz); + c_lz_ext = m_bv_util.mk_zero_extend(2, c_lz); + + expr_ref a_sig_ext(m), b_sig_ext(m); + a_sig_ext = m_bv_util.mk_zero_extend(sbits, a_sig); + b_sig_ext = m_bv_util.mk_zero_extend(sbits, b_sig); + + expr_ref a_exp_ext(m), b_exp_ext(m), c_exp_ext(m); + a_exp_ext = m_bv_util.mk_sign_extend(2, a_exp); + b_exp_ext = m_bv_util.mk_sign_extend(2, b_exp); + c_exp_ext = m_bv_util.mk_sign_extend(2, c_exp); + + dbg_decouple("fpa2bv_fma_a_sig", a_sig_ext); + dbg_decouple("fpa2bv_fma_b_sig", b_sig_ext); + dbg_decouple("fpa2bv_fma_c_sig", c_sig); + dbg_decouple("fpa2bv_fma_a_exp", a_exp_ext); + dbg_decouple("fpa2bv_fma_b_exp", b_exp_ext); + dbg_decouple("fpa2bv_fma_c_exp", c_exp_ext); + dbg_decouple("fpa2bv_fma_a_lz", a_lz_ext); + dbg_decouple("fpa2bv_fma_b_lz", b_lz_ext); + dbg_decouple("fpa2bv_fma_c_lz", c_lz_ext); + + expr_ref mul_sgn(m), mul_sig(m), mul_exp(m); + expr * signs[2] = { a_sgn, b_sgn }; + + mul_sgn = m_bv_util.mk_bv_xor(2, signs); + dbg_decouple("fpa2bv_fma_mul_sgn", mul_sgn); + + mul_exp = m_bv_util.mk_bv_add(m_bv_util.mk_bv_sub(a_exp_ext, a_lz_ext), + m_bv_util.mk_bv_sub(b_exp_ext, b_lz_ext)); + dbg_decouple("fpa2bv_fma_mul_exp", mul_exp); + + mul_sig = m_bv_util.mk_bv_mul(a_sig_ext, b_sig_ext); + dbg_decouple("fpa2bv_fma_mul_sig", mul_sig); + + SASSERT(m_bv_util.get_bv_size(mul_sig) == 2*sbits); + SASSERT(m_bv_util.get_bv_size(mul_exp) == ebits + 2); + + // The product has the form [-1][0].[2*sbits - 2]. + + // Extend c + c_sig = m_bv_util.mk_zero_extend(1, m_bv_util.mk_concat(c_sig, m_bv_util.mk_numeral(0, sbits-1))); + c_exp_ext = m_bv_util.mk_bv_sub(c_exp_ext, c_lz_ext); + + SASSERT(m_bv_util.get_bv_size(mul_sig) == 2 * sbits); + SASSERT(m_bv_util.get_bv_size(c_sig) == 2 * sbits); + + expr_ref swap_cond(m); + swap_cond = m_bv_util.mk_sle(mul_exp, c_exp_ext); + SASSERT(is_well_sorted(m, swap_cond)); + dbg_decouple("fpa2bv_fma_swap_cond", swap_cond); + + expr_ref e_sgn(m), e_sig(m), e_exp(m), f_sgn(m), f_sig(m), f_exp(m); + m_simp.mk_ite(swap_cond, c_sgn, mul_sgn, e_sgn); + m_simp.mk_ite(swap_cond, c_sig, mul_sig, e_sig); // has 2 * sbits + m_simp.mk_ite(swap_cond, c_exp_ext, mul_exp, e_exp); // has ebits + 2 + m_simp.mk_ite(swap_cond, mul_sgn, c_sgn, f_sgn); + m_simp.mk_ite(swap_cond, mul_sig, c_sig, f_sig); // has 2 * sbits + m_simp.mk_ite(swap_cond, mul_exp, c_exp_ext, f_exp); // has ebits + 2 + + SASSERT(is_well_sorted(m, e_sgn)); + SASSERT(is_well_sorted(m, e_sig)); + SASSERT(is_well_sorted(m, e_exp)); + SASSERT(is_well_sorted(m, f_sgn)); + SASSERT(is_well_sorted(m, f_sig)); + SASSERT(is_well_sorted(m, f_exp)); + + SASSERT(m_bv_util.get_bv_size(e_sig) == 2 * sbits); + SASSERT(m_bv_util.get_bv_size(f_sig) == 2 * sbits); + SASSERT(m_bv_util.get_bv_size(e_exp) == ebits + 2); + SASSERT(m_bv_util.get_bv_size(f_exp) == ebits + 2); + + expr_ref res_sgn(m), res_sig(m), res_exp(m); + + expr_ref exp_delta(m); + exp_delta = m_bv_util.mk_bv_sub(e_exp, f_exp); + dbg_decouple("fpa2bv_fma_add_exp_delta", exp_delta); + + // cap the delta + expr_ref cap(m), cap_le_delta(m); + cap = m_bv_util.mk_numeral(2*sbits, ebits+2); + cap_le_delta = m_bv_util.mk_ule(cap, exp_delta); + m_simp.mk_ite(cap_le_delta, cap, exp_delta, exp_delta); + SASSERT(m_bv_util.get_bv_size(exp_delta) == ebits+2); + SASSERT(is_well_sorted(m, exp_delta)); + dbg_decouple("fpa2bv_fma_add_exp_delta_capped", exp_delta); + + // Alignment shift with sticky bit computation. + expr_ref shifted_big(m), shifted_f_sig(m), sticky_raw(m); + shifted_big = m_bv_util.mk_bv_lshr( + m_bv_util.mk_concat(f_sig, m_bv_util.mk_numeral(0, sbits)), + m_bv_util.mk_zero_extend((3*sbits)-(ebits+2), exp_delta)); + shifted_f_sig = m_bv_util.mk_extract(3*sbits-1, sbits, shifted_big); + sticky_raw = m_bv_util.mk_extract(sbits-1, 0, shifted_big); + SASSERT(m_bv_util.get_bv_size(shifted_f_sig) == 2 * sbits); + SASSERT(is_well_sorted(m, shifted_f_sig)); + + expr_ref sticky(m); + sticky = m_bv_util.mk_zero_extend(2*sbits-1, m.mk_app(m_bv_util.get_fid(), OP_BREDOR, sticky_raw.get())); + SASSERT(is_well_sorted(m, sticky)); + dbg_decouple("fpa2bv_fma_f_sig_sticky_raw", sticky_raw); + dbg_decouple("fpa2bv_fma_f_sig_sticky", sticky); + + expr * or_args[2] = { shifted_f_sig, sticky }; + shifted_f_sig = m_bv_util.mk_bv_or(2, or_args); + SASSERT(is_well_sorted(m, shifted_f_sig)); + + // Significant addition. + // Two extra bits for catching the overflow. + e_sig = m_bv_util.mk_zero_extend(2, e_sig); + shifted_f_sig = m_bv_util.mk_zero_extend(2, shifted_f_sig); + + expr_ref eq_sgn(m); + m_simp.mk_eq(e_sgn, f_sgn, eq_sgn); + + SASSERT(m_bv_util.get_bv_size(e_sig) == 2*sbits + 2); + SASSERT(m_bv_util.get_bv_size(shifted_f_sig) == 2*sbits + 2); + + dbg_decouple("fpa2bv_fma_add_e_sig", e_sig); + dbg_decouple("fpa2bv_fma_add_shifted_f_sig", shifted_f_sig); + + expr_ref sum(m); + m_simp.mk_ite(eq_sgn, + m_bv_util.mk_bv_add(e_sig, shifted_f_sig), + m_bv_util.mk_bv_sub(e_sig, shifted_f_sig), + sum); + + SASSERT(is_well_sorted(m, sum)); + + dbg_decouple("fpa2bv_fma_add_sum", sum); + + expr_ref sign_bv(m), n_sum(m); + sign_bv = m_bv_util.mk_extract(2*sbits+1, 2*sbits+1, sum); + n_sum = m_bv_util.mk_bv_neg(sum); + + expr_ref res_sig_eq(m), sig_abs(m), one_1(m); + one_1 = m_bv_util.mk_numeral(1, 1); + m_simp.mk_eq(sign_bv, one_1, res_sig_eq); + m_simp.mk_ite(res_sig_eq, n_sum, sum, sig_abs); + dbg_decouple("fpa2bv_fma_add_sign_bv", sign_bv); + dbg_decouple("fpa2bv_fma_add_n_sum", n_sum); + dbg_decouple("fpa2bv_fma_add_sig_abs", sig_abs); + + res_exp = e_exp; + + // Result could overflow into 4.xxx ... + + family_id bvfid = m_bv_util.get_fid(); + expr_ref res_sgn_c1(m), res_sgn_c2(m), res_sgn_c3(m); + expr_ref not_e_sgn(m), not_f_sgn(m), not_sign_bv(m); + not_e_sgn = m_bv_util.mk_bv_not(e_sgn); + not_f_sgn = m_bv_util.mk_bv_not(f_sgn); + not_sign_bv = m_bv_util.mk_bv_not(sign_bv); + res_sgn_c1 = m.mk_app(bvfid, OP_BAND, not_e_sgn, e_sgn, sign_bv); + res_sgn_c2 = m.mk_app(bvfid, OP_BAND, e_sgn, not_f_sgn, not_sign_bv); + res_sgn_c3 = m.mk_app(bvfid, OP_BAND, e_sgn, f_sgn); + expr * res_sgn_or_args[3] = { res_sgn_c1, res_sgn_c2, res_sgn_c3 }; + res_sgn = m_bv_util.mk_bv_or(3, res_sgn_or_args); + + sticky_raw = m_bv_util.mk_extract(sbits-5, 0, sig_abs); + sticky = m_bv_util.mk_zero_extend(sbits+3, m.mk_app(bvfid, OP_BREDOR, sticky_raw.get())); + dbg_decouple("fpa2bv_fma_add_sum_sticky", sticky); + + expr * res_or_args[2] = { m_bv_util.mk_extract(2*sbits-1, sbits-4, sig_abs), sticky }; + res_sig = m_bv_util.mk_bv_or(2, res_or_args); + SASSERT(m_bv_util.get_bv_size(res_sig) == sbits+4); + + expr_ref is_zero_sig(m), nil_sbits4(m); + nil_sbits4 = m_bv_util.mk_numeral(0, sbits+4); + m_simp.mk_eq(res_sig, nil_sbits4, is_zero_sig); + SASSERT(is_well_sorted(m, is_zero_sig)); + + dbg_decouple("fpa2bv_fma_is_zero_sig", is_zero_sig); + + expr_ref zero_case(m); + mk_ite(rm_is_to_neg, nzero, pzero, zero_case); + + + //AZ: Should the zero case be constrained in some manner? + expr_ref rounded(m);//, fixed(m); + round(f->get_range(), rm, res_sgn, res_sig, res_exp, rounded); + + fix_bits(prec,rounded,sbits, ebits); + + mk_ite(is_zero_sig, zero_case, rounded, v8); + + // And finally, we tie them together. + mk_ite(c7, v7, v8, result); + mk_ite(c6, v6, result, result); + mk_ite(c5, v5, result, result); + mk_ite(c4, v4, result, result); + mk_ite(c3, v3, result, result); + mk_ite(c2, v2, result, result); + mk_ite(c1, v1, result, result); + + SASSERT(is_well_sorted(m, result)); + + TRACE("fpa2bv_fma_", tout << "FMA = " << mk_ismt2_pp(result, m) << std::endl; ); + } + break; + default: UNREACHABLE(); break; + } +} + +void fpa2bv_converter_prec::mk_sqrt(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result) { + switch (m_mode) { + case FPAA_SMALL_FLOATS: + { + func_decl_ref small_fd(m); + expr_ref_vector small_args(m); + mk_small_op(f, prec, num, args, small_fd, small_args); + expr_ref small_op(m); + fpa2bv_converter::mk_sqrt(small_fd, num, small_args.c_ptr(), small_op); + mk_cast_small_to_big(f, small_op, result); + SASSERT(is_well_sorted(m, result)); + TRACE("fpa2bv_small_float_sqrt", tout << mk_ismt2_pp(result, m) << std::endl; ); + break; + } + case FPAA_PRECISE: + case FPAA_FIXBITS: // for now, encode fully. + fpa2bv_converter::mk_sqrt(f,num,args,result); + break; + default: UNREACHABLE(); break; + } +} + +void fpa2bv_converter_prec::mk_round_to_integral(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result) { + switch (m_mode) { + case FPAA_SMALL_FLOATS: + { + func_decl_ref small_fd(m); + expr_ref_vector small_args(m); + mk_small_op(f, prec, num, args, small_fd, small_args); + expr_ref small_op(m); + fpa2bv_converter::mk_round_to_integral(small_fd, num, small_args.c_ptr(), small_op); + mk_cast_small_to_big(f, small_op, result); + SASSERT(is_well_sorted(m, result)); + TRACE("fpa2bv_small_float_r2i", tout << mk_ismt2_pp(result, m) << std::endl; ); + break; + } + case FPAA_PRECISE: + case FPAA_FIXBITS: // for now, encode fully. + fpa2bv_converter::mk_sqrt(f,num,args,result); + break; + default: UNREACHABLE(); break; + } +} + +void fpa2bv_converter_prec::establish_sort(unsigned num, expr * const * args, unsigned & ebits, unsigned & sbits) +{ + unsigned ne,ns; + //hardcoding for now + ebits = 3; + sbits = 3; + for(unsigned i=0;iget_decl()->get_range())) + { + ne = fu().get_ebits(s); + ns = fu().get_sbits(s); + ebits = (ne < ebits)?ebits:ne; + sbits = (ns < sbits)?sbits:ns; + } + } +} + +void fpa2bv_converter_prec::mk_float_eq(func_decl * f, unsigned num, expr * const * args, expr_ref & result) +{ + switch (m_mode) { + case FPAA_PRECISE: + case FPAA_FIXBITS: + fpa2bv_converter::mk_float_eq(f,num,args,result); + break; + case FPAA_SMALL_FLOATS: + { + unsigned sbits, ebits; + + func_decl_ref small_fd(m); + expr_ref_vector small_args(m); + establish_sort(num, args, ebits, sbits); + mk_small_op(f, ebits, sbits, num, args, small_fd, small_args); + fpa2bv_converter::mk_float_eq(small_fd, num, small_args.c_ptr(), result); + SASSERT(is_well_sorted(m, result)); + TRACE("fpa2bv_small_float_add", tout << mk_ismt2_pp(result, m) << std::endl; ); + break; + } + } + +} + +void fpa2bv_converter_prec::mk_float_lt(func_decl * f, unsigned num, expr * const * args, expr_ref & result) +{ + switch (m_mode){ + case FPAA_PRECISE: + case FPAA_FIXBITS: + fpa2bv_converter::mk_float_lt(f,num,args,result); + break; + case FPAA_SMALL_FLOATS: { + unsigned sbits, ebits; + + func_decl_ref small_fd(m); + expr_ref_vector small_args(m); + establish_sort(num, args, ebits, sbits); + mk_small_op(f, ebits, sbits, num, args, small_fd, small_args); + fpa2bv_converter::mk_float_lt(small_fd, num, small_args.c_ptr(), result); + SASSERT(is_well_sorted(m, result)); + TRACE("fpa2bv_small_float_add", tout << mk_ismt2_pp(result, m) << std::endl; ); + break; + } + } +} +void fpa2bv_converter_prec::mk_float_gt(func_decl * f, unsigned num, expr * const * args, expr_ref & result) +{ + switch (m_mode){ + case FPAA_PRECISE: + case FPAA_FIXBITS: + fpa2bv_converter::mk_float_gt(f,num,args,result); + break; + case FPAA_SMALL_FLOATS: { + unsigned sbits, ebits; + + func_decl_ref small_fd(m); + expr_ref_vector small_args(m); + establish_sort(num, args, ebits, sbits); + mk_small_op(f, ebits, sbits, num, args, small_fd, small_args); + fpa2bv_converter::mk_float_gt(small_fd, num, small_args.c_ptr(), result); + SASSERT(is_well_sorted(m, result)); + TRACE("fpa2bv_small_float_add", tout << mk_ismt2_pp(result, m) << std::endl; ); + break; + } + } +} +void fpa2bv_converter_prec::mk_float_le(func_decl * f, unsigned num, expr * const * args, expr_ref & result) +{ + switch (m_mode){ + case FPAA_PRECISE: + case FPAA_FIXBITS: + fpa2bv_converter::mk_float_le(f,num,args,result); + break; + case FPAA_SMALL_FLOATS: { + unsigned sbits, ebits; + + func_decl_ref small_fd(m); + expr_ref_vector small_args(m); + establish_sort(num, args, ebits, sbits); + mk_small_op(f, ebits, sbits, num, args, small_fd, small_args); + fpa2bv_converter::mk_float_le(small_fd, num, small_args.c_ptr(), result); + SASSERT(is_well_sorted(m, result)); + TRACE("fpa2bv_small_float_add", tout << mk_ismt2_pp(result, m) << std::endl; ); + break; + } + } +} +void fpa2bv_converter_prec::mk_float_ge(func_decl * f, unsigned num, expr * const * args, expr_ref & result) +{ + switch (m_mode){ + case FPAA_PRECISE: + case FPAA_FIXBITS: + fpa2bv_converter::mk_float_ge(f,num,args,result); + break; + case FPAA_SMALL_FLOATS: { + unsigned sbits, ebits; + + func_decl_ref small_fd(m); + expr_ref_vector small_args(m); + establish_sort(num, args, ebits, sbits); + mk_small_op(f, ebits, sbits, num, args, small_fd, small_args); + fpa2bv_converter::mk_float_ge(small_fd, num, small_args.c_ptr(), result); + SASSERT(is_well_sorted(m, result)); + TRACE("fpa2bv_small_float_add", tout << mk_ismt2_pp(result, m) << std::endl; ); + break; + } + } +} +/* + +void fpa2bv_converter_prec::mk_is_zero(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result) +{ + switch (m_mode){ + case FPAA_PRECISE: + case FPAA_FIXBITS: + fpa2bv_converter::mk_float_eq(f,num,args,result); + break; + case FPAA_SMALL_FLOATS: { + unsigned sbits, ebits; + + func_decl_ref small_fd(m); + expr_ref_vector small_args(m); + establish_sort(num, args, ebits, sbits); + mk_small_op(f, ebits, sbits, num, args, small_fd, small_args); + fpa2bv_converter::mk_is_zero(small_fd, num, small_args.c_ptr(), result); + SASSERT(is_well_sorted(m, result)); + TRACE("fpa2bv_small_float_add", tout << mk_ismt2_pp(result, m) << std::endl; ); + break; + } + } +} +void fpa2bv_converter_prec::mk_is_nzero(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result); +void fpa2bv_converter_prec::mk_is_pzero(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result); +void fpa2bv_converter_prec::mk_is_sign_minus(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result); +void fpa2bv_converter_prec::mk_is_nan(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result); +void fpa2bv_converter_prec::mk_is_inf(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result); +void fpa2bv_converter_prec::mk_is_normal(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result); +void fpa2bv_converter_prec::mk_is_subnormal(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result); +*/ + + + + +void fpa2bv_prec_model_converter::display(std::ostream & out) { + out << "(fpa2bv-model-converter"; + for (obj_map::iterator it = m_const2bv.begin(); + it != m_const2bv.end(); + it++) { + const symbol & n = it->m_key->get_name(); + out << "\n (" << n << " "; + unsigned indent = n.size() + 4; + out << mk_ismt2_pp(it->m_value, m, indent) << ")"; + } + for (obj_map::iterator it = m_rm_const2bv.begin(); + it != m_rm_const2bv.end(); + it++) { + const symbol & n = it->m_key->get_name(); + out << "\n (" << n << " "; + unsigned indent = n.size() + 4; + out << mk_ismt2_pp(it->m_value, m, indent) << ")"; + } + out << ")" << std::endl; +} + +model_converter * fpa2bv_prec_model_converter::translate(ast_translation & translator) { + fpa2bv_prec_model_converter * res = alloc(fpa2bv_prec_model_converter, translator.to()); + for (obj_map::iterator it = m_const2bv.begin(); + it != m_const2bv.end(); + it++) + { + func_decl * k = translator(it->m_key); + expr * v = translator(it->m_value); + res->m_const2bv.insert(k, v); + translator.to().inc_ref(k); + translator.to().inc_ref(v); + } + for (obj_map::iterator it = m_rm_const2bv.begin(); + it != m_rm_const2bv.end(); + it++) + { + func_decl * k = translator(it->m_key); + expr * v = translator(it->m_value); + res->m_rm_const2bv.insert(k, v); + translator.to().inc_ref(k); + translator.to().inc_ref(v); + } + return res; +} + + + +void fpa2bv_prec_model_converter::convert(model * bv_mdl, model * float_mdl) { + fpa_util fu(m); + bv_util bu(m); + mpf fp_val,sfp_val; + unsynch_mpz_manager & mpzm = fu.fm().mpz_manager(); + unsynch_mpq_manager & mpqm = fu.fm().mpq_manager(); + + TRACE("fpa2bv_mc", tout << "BV Model: " << std::endl; + for (unsigned i = 0 ; i < bv_mdl->get_num_constants(); i++) + tout << bv_mdl->get_constant(i)->get_name() << " --> " << + mk_ismt2_pp(bv_mdl->get_const_interp(bv_mdl->get_constant(i)), m) << std::endl; + ); + + obj_hashtable seen; + + for (obj_map::iterator it = m_const2bv.begin(); + it != m_const2bv.end(); + it++) + { + func_decl * var = it->m_key; + app * a = to_app(it->m_value); + SASSERT(fu.is_float(var->get_range())); + SASSERT(var->get_range()->get_num_parameters() == 2); + + unsigned ebits = fu.get_ebits(var->get_range()); + unsigned sbits = fu.get_sbits(var->get_range()); + unsigned sfpa_ebits = fu.get_ebits(a->get_decl()->get_range()); + unsigned sfpa_sbits = fu.get_sbits(a->get_decl()->get_range()); + + expr_ref sgn(m), sig(m), exp(m); + if (a->get_decl_kind() == OP_FPA_TO_FP) + { + bv_mdl->eval(a->get_arg(0), sgn, true); + bv_mdl->eval(a->get_arg(1), sig, true); + bv_mdl->eval(a->get_arg(2), exp, true); + } + else + { + sgn = bv_mdl->get_const_interp(to_app(a->get_arg(0))->get_decl()); + sig = bv_mdl->get_const_interp(to_app(a->get_arg(1))->get_decl()); + exp = bv_mdl->get_const_interp(to_app(a->get_arg(2))->get_decl()); + } + + seen.insert(to_app(a->get_arg(0))->get_decl()); + seen.insert(to_app(a->get_arg(1))->get_decl()); + seen.insert(to_app(a->get_arg(2))->get_decl()); + + if (!sgn && !sig && !exp) + continue; + + unsigned sgn_sz = bu.get_bv_size(m.get_sort(a->get_arg(0))); + unsigned sig_sz = bu.get_bv_size(m.get_sort(a->get_arg(1))) - 1; + unsigned exp_sz = bu.get_bv_size(m.get_sort(a->get_arg(2))); + + rational sgn_q(0), sig_q(0), exp_q(0); + + if (sgn) bu.is_numeral(sgn, sgn_q, sgn_sz); + if (sig) bu.is_numeral(sig, sig_q, sig_sz); + if (exp) bu.is_numeral(exp, exp_q, exp_sz); + + // un-bias exponent + rational exp_unbiased_q; + mpz sig_z; mpf_exp_t exp_z; + + exp_unbiased_q = exp_q - fu.fm().m_powers2.m1(sfpa_ebits-1); + + mpzm.set(sig_z, sig_q.to_mpq().numerator()); + exp_z = mpzm.get_int64(exp_unbiased_q.to_mpq().numerator()); + + TRACE("fpa2bv_mc", tout << var->get_name() << " == [" << sgn_q.to_string() << " " << + mpzm.to_string(sig_z) << " " << exp_z << "(" << exp_q.to_string() << ")]" << std::endl; ); + + + fu.fm().set(sfp_val, sfpa_ebits, sfpa_sbits, !mpqm.is_zero(sgn_q.to_mpq()), sig_z, exp_z); + fu.fm().set(fp_val, ebits, sbits,MPF_ROUND_TOWARD_ZERO,sfp_val); + //fu.fm().set(fp_val, ebits, sbits, !mpqm.is_zero(sgn_q.to_mpq()), sig_z, exp_z); + /*std::cout<< mk_ismt2_pp(a,m) <<":" << fu.mk_value(fp_val)<register_decl(var, fu.mk_value(fp_val)); + + mpzm.del(sig_z); + fu.fm().del(fp_val); + fu.fm().del(sfp_val); + } + + for (obj_map::iterator it = m_rm_const2bv.begin(); + it != m_rm_const2bv.end(); + it++) + { + func_decl * var = it->m_key; + app * a = to_app(it->m_value); + SASSERT(fu.is_rm(var->get_range())); + rational val(0); + unsigned sz = 0; + if (a && bu.is_numeral(a, val, sz)) { + TRACE("fpa2bv_mc", tout << var->get_name() << " == " << val.to_string() << std::endl; ); + SASSERT(val.is_uint64()); + switch (val.get_uint64()) + { + case BV_RM_TIES_TO_AWAY: float_mdl->register_decl(var, fu.mk_round_nearest_ties_to_away()); break; + case BV_RM_TIES_TO_EVEN: float_mdl->register_decl(var, fu.mk_round_nearest_ties_to_even()); break; + case BV_RM_TO_NEGATIVE: float_mdl->register_decl(var, fu.mk_round_toward_negative()); break; + case BV_RM_TO_POSITIVE: float_mdl->register_decl(var, fu.mk_round_toward_positive()); break; + case BV_RM_TO_ZERO: + default: float_mdl->register_decl(var, fu.mk_round_toward_zero()); + } + seen.insert(var); + } + } + + fu.fm().del(fp_val); + + // Keep all the non-float constants. + unsigned sz = bv_mdl->get_num_constants(); + for (unsigned i = 0; i < sz; i++) + { + func_decl * c = bv_mdl->get_constant(i); + if (!seen.contains(c)) + float_mdl->register_decl(c, bv_mdl->get_const_interp(c)); + } + + // And keep everything else + sz = bv_mdl->get_num_functions(); + for (unsigned i = 0; i < sz; i++) + { + func_decl * c = bv_mdl->get_function(i); + float_mdl->register_decl(c, bv_mdl->get_const_interp(c)); + } + + sz = bv_mdl->get_num_uninterpreted_sorts(); + for (unsigned i = 0; i < sz; i++) + { + sort * s = bv_mdl->get_uninterpreted_sort(i); + ptr_vector u = bv_mdl->get_universe(s); + float_mdl->register_usort(s, u.size(), u.c_ptr()); + } +} + +model_converter * mk_fpa2bv_prec_model_converter(ast_manager & m, + obj_map const & const2bv, + obj_map const & rm_const2bv) { + return alloc(fpa2bv_prec_model_converter, m, const2bv, rm_const2bv); +} + diff --git a/src/tactic/fpa/fpa2bv_converter_prec.h b/src/tactic/fpa/fpa2bv_converter_prec.h new file mode 100644 index 000000000..330cd271f --- /dev/null +++ b/src/tactic/fpa/fpa2bv_converter_prec.h @@ -0,0 +1,162 @@ +/*++ +Copyright (c) 2012 Microsoft Corporation + +Module Name: + + fpa2bv_converter_prec.h + +Abstract: + + Conversion routines for Floating Point -> Bit-Vector + +Author: + + Christoph (cwinter) 2012-02-09 + +Notes: + +--*/ +#ifndef _FPA2BV_CONVERTER_PREC +#define _FPA2BV_CONVERTER_PREC + +#include"ast.h" +#include"obj_hashtable.h" +#include"ref_util.h" +#include"fpa_decl_plugin.h" +#include"bv_decl_plugin.h" +#include"model_converter.h" +#include"basic_simplifier_plugin.h" +#include"fpa2bv_converter.h" + +#define MAX_PRECISION 100 +#define MIN_PRECISION 0 + +class fpa2bv_prec_model_converter; + +enum fpa_approximation_mode { + FPAA_PRECISE, // Always use precise encoding + FPAA_FIXBITS, // Approximate by fixing some bits of the encoding + FPAA_SMALL_FLOATS // Approximate by using smaller floats +}; + +#define FPAA_DEFAULT_MODE FPAA_SMALL_FLOATS + +class fpa2bv_converter_prec : public fpa2bv_converter { + fpa_approximation_mode m_mode; + + void fix_bits(unsigned prec, expr_ref rounded, unsigned sbits, unsigned ebits);//expr_ref& fixed, + + void mk_small_op(func_decl * f, unsigned prec, unsigned num, expr * const * args, func_decl_ref & small_op, expr_ref_vector & cast_args); + void mk_small_op(func_decl * f, unsigned new_ebits, unsigned new_sbits, unsigned num, expr * const * args, func_decl_ref & small_op, expr_ref_vector & cast_args); + void mk_cast_small_to_big(func_decl * big_fd, expr * arg, expr_ref & result); + void mk_cast_small_to_big(unsigned sbits, unsigned ebits, expr * arg, expr_ref & result); + void match_sorts(expr * a, expr * b, expr_ref & n_a, expr_ref & n_b); + void establish_sort(unsigned num, expr * const * args, unsigned & ebits, unsigned & sbits); +public: + fpa2bv_converter_prec(ast_manager & m, fpa_approximation_mode mode); + + void mk_const(func_decl * f, unsigned prec, expr_ref & result); + + void mk_eq(expr * a, expr * b, expr_ref & result); + void mk_ite(expr * c, expr * t, expr * f, expr_ref & result); + + void mk_add(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result); + void mk_sub(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result); + void mk_uminus(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result); + void mk_mul(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result); + void mk_div(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result); + void mk_remainder(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result); + void mk_abs(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result); + void mk_min(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result); + void mk_max(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result); + void mk_fusedma(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result); + void mk_sqrt(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result); + void mk_round_to_integral(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result); + + void mk_float_eq(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + void mk_float_lt(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + void mk_float_gt(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + void mk_float_le(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + void mk_float_ge(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + + /* + void mk_is_zero(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result); + void mk_is_nzero(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result); + void mk_is_pzero(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result); + void mk_is_sign_minus(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result); + void mk_is_nan(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result); + void mk_is_inf(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result); + void mk_is_normal(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result); + void mk_is_subnormal(func_decl * f, unsigned prec, unsigned num, expr * const * args, expr_ref & result); + */ + + + + void reset() { + dec_ref_map_key_values(m, m_const2bv); + dec_ref_map_key_values(m, m_rm_const2bv); + } +}; + + +class fpa2bv_prec_model_converter : public model_converter { + ast_manager & m; + obj_map m_const2bv; + obj_map m_rm_const2bv; + +public: + fpa2bv_prec_model_converter(ast_manager & m, obj_map const & const2bv, + obj_map const & rm_const2bv) : + m(m) { + // Just create a copy? + for (obj_map::iterator it = const2bv.begin(); + it != const2bv.end(); + it++) + { + m_const2bv.insert(it->m_key, it->m_value); + m.inc_ref(it->m_key); + m.inc_ref(it->m_value); + } + for (obj_map::iterator it = rm_const2bv.begin(); + it != rm_const2bv.end(); + it++) + { + m_rm_const2bv.insert(it->m_key, it->m_value); + m.inc_ref(it->m_key); + m.inc_ref(it->m_value); + } + } + + virtual ~fpa2bv_prec_model_converter() { + dec_ref_map_key_values(m, m_const2bv); + dec_ref_map_key_values(m, m_rm_const2bv); + } + + virtual void operator()(model_ref & md, unsigned goal_idx) { + SASSERT(goal_idx == 0); + model * new_model = alloc(model, m); + obj_hashtable bits; + convert(md.get(), new_model); + md = new_model; + } + + virtual void operator()(model_ref & md) { + operator()(md, 0); + } + + void display(std::ostream & out); + + virtual model_converter * translate(ast_translation & translator); + +protected: + fpa2bv_prec_model_converter(ast_manager & m) : m(m) { } + + void convert(model * bv_mdl, model * float_mdl); +}; + + +model_converter * mk_fpa2bv_prec_model_converter(ast_manager & m, + obj_map const & const2bv, + obj_map const & rm_const2bv); + +#endif diff --git a/src/tactic/fpa/fpa2bv_rewriter_prec.h b/src/tactic/fpa/fpa2bv_rewriter_prec.h new file mode 100644 index 000000000..d82255d39 --- /dev/null +++ b/src/tactic/fpa/fpa2bv_rewriter_prec.h @@ -0,0 +1,229 @@ +/*++ +Copyright (c) 2012 Microsoft Corporation + +Module Name: + + fpa2bv_rewriter.h + +Abstract: + + Rewriter for converting FPA to BV + +Author: + + Christoph (cwinter) 2012-02-09 + +Notes: + +--*/ + +#ifndef _FPA2BV_REWRITER_H_ +#define _FPA2BV_REWRITER_H_ + +#include"cooperate.h" +#include"rewriter_def.h" +#include"bv_decl_plugin.h" +#include"fpa2bv_converter_prec.h" +#include"tactic_exception.h" +#include + +struct fpa2bv_rewriter_prec_cfg : public default_rewriter_cfg { + ast_manager & m_manager; + expr_ref_vector m_out; + fpa2bv_converter_prec & m_conv; + obj_map * cnst2prec_map; + + unsigned precision; + unsigned long long m_max_memory; + unsigned m_max_steps; + + ast_manager & m() const { return m_manager; } + + fpa2bv_rewriter_prec_cfg(ast_manager & m, fpa2bv_converter_prec & c, params_ref const & p): + m_manager(m), + m_out(m), + m_conv(c) { + updt_params(p); + // We need to make sure that the mananger has the BV plugin loaded. + symbol s_bv("bv"); + if (!m_manager.has_plugin(s_bv)) + m_manager.register_plugin(s_bv, alloc(bv_decl_plugin)); + } + + ~fpa2bv_rewriter_prec_cfg() { + } + + void cleanup_buffers() { + m_out.finalize(); + } + + unsigned get_precision(func_decl * f){ + if(cnst2prec_map->contains(f)) + return cnst2prec_map->find(f); + else return precision; + } + void set_precision(unsigned p) { precision=p; } + void set_mappings(obj_map * o2p) + { + this->cnst2prec_map=o2p; + } + + void updt_params(params_ref const & p) { + m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX)); + m_max_steps = p.get_uint("max_steps", UINT_MAX); + } + + bool max_steps_exceeded(unsigned num_steps) const { + cooperate("fpa2bv"); + if (memory::get_allocation_size() > m_max_memory) + throw tactic_exception(TACTIC_MAX_MEMORY_MSG); + return num_steps > m_max_steps; + } + + br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { + TRACE("fpa2bv_rw", tout << "APP: " << f->get_name() << std::endl; ); + + if (num == 0 && f->get_family_id() == null_family_id && m_conv.is_float(f->get_range())) { + m_conv.mk_const(f, get_precision(f), result); + return BR_DONE; + } + + if (num == 0 && f->get_family_id() == null_family_id && m_conv.is_rm(f->get_range())) { + m_conv.mk_rm_const(f, result); + return BR_DONE; + } + + if (m().is_eq(f)) { + SASSERT(num == 2); + if (m_conv.is_float(args[0])) { + m_conv.mk_eq(args[0], args[1], result); + return BR_DONE; + } + return BR_FAILED; + } + + if (m().is_ite(f)) { + SASSERT(num == 3); + if (m_conv.is_float(args[1])) { + m_conv.mk_ite(args[0], args[1], args[2], result); + return BR_DONE; + } + return BR_FAILED; + } + + expr_ref newAssertion(m_manager); + + if (m_conv.is_float_family(f)) + { + switch (f->get_decl_kind()) + { + case OP_FPA_RM_NEAREST_TIES_TO_AWAY: + case OP_FPA_RM_NEAREST_TIES_TO_EVEN: + case OP_FPA_RM_TOWARD_NEGATIVE: + case OP_FPA_RM_TOWARD_POSITIVE: + case OP_FPA_RM_TOWARD_ZERO: m_conv.mk_rounding_mode(f, result); return BR_DONE; + case OP_FPA_NUM: m_conv.mk_numeral(f, num, args, result); return BR_DONE; + case OP_FPA_PLUS_INF: m_conv.mk_pinf(f, result); return BR_DONE; + case OP_FPA_MINUS_INF: m_conv.mk_ninf(f, result); return BR_DONE; + case OP_FPA_NAN: m_conv.mk_nan(f, result); return BR_DONE; + //AZ: Added precision, if precision is MAX_PRECISION uses the regular implementation of the methods + case OP_FPA_ADD: + m_conv.mk_add(f,get_precision(f), num, args, result);return BR_DONE; + case OP_FPA_SUB: + m_conv.mk_sub(f, get_precision(f), num, args, result); return BR_DONE; + case OP_FPA_NEG: + m_conv.mk_uminus(f, get_precision(f), num, args, result); return BR_DONE; + case OP_FPA_MUL: + m_conv.mk_mul(f, get_precision(f), num, args, result); return BR_DONE; + case OP_FPA_DIV: + m_conv.mk_div(f, get_precision(f), num, args, result); return BR_DONE; + case OP_FPA_REM: + m_conv.mk_remainder(f, get_precision(f), num, args, result); return BR_DONE; + case OP_FPA_FMA: + m_conv.mk_fusedma(f, get_precision(f), num, args, result); return BR_DONE; + case OP_FPA_SQRT: + m_conv.mk_sqrt(f, get_precision(f), num, args, result); return BR_DONE; + case OP_FPA_ABS: m_conv.mk_abs(f, get_precision(f), num, args, result); return BR_DONE; + case OP_FPA_MIN: m_conv.mk_min(f, get_precision(f), num, args, result); return BR_DONE; + case OP_FPA_MAX: m_conv.mk_max(f, get_precision(f), num, args, result); return BR_DONE; + case OP_FPA_ROUND_TO_INTEGRAL: m_conv.mk_round_to_integral(f, get_precision(f), num, args, result); return BR_DONE; + case OP_FPA_EQ: m_conv.mk_float_eq(f, num, args, result); return BR_DONE; + case OP_FPA_LT: m_conv.mk_float_lt(f, num, args, result); return BR_DONE; + case OP_FPA_GT: m_conv.mk_float_gt(f, num, args, result); return BR_DONE; + case OP_FPA_LE: m_conv.mk_float_le(f, num, args, result); return BR_DONE; + case OP_FPA_GE: m_conv.mk_float_ge(f, num, args, result); return BR_DONE; + case OP_FPA_IS_ZERO: m_conv.mk_is_zero(f, num, args, result); return BR_DONE; +//case OP_FPA_IS_NZERO: m_conv.mk_is_nzero(f, num, args, result); return BR_DONE; +//case OP_FPA_IS_PZERO: m_conv.mk_is_pzero(f, num, args, result); return BR_DONE; + case OP_FPA_IS_NAN: m_conv.mk_is_nan(f, num, args, result); return BR_DONE; + case OP_FPA_IS_INF: m_conv.mk_is_inf(f, num, args, result); return BR_DONE; + case OP_FPA_IS_NORMAL: m_conv.mk_is_normal(f, num, args, result); return BR_DONE; + case OP_FPA_IS_SUBNORMAL: m_conv.mk_is_subnormal(f, num, args, result); return BR_DONE; + case OP_FPA_IS_NEGATIVE: m_conv.mk_is_negative(f, num, args, result); return BR_DONE; + case OP_FPA_TO_FP: m_conv.mk_to_fp(f, num, args, result); return BR_DONE; + case OP_FPA_TO_IEEE_BV: m_conv.mk_to_ieee_bv(f, num, args, result); return BR_DONE; + default: + TRACE("fpa2bv", tout << "unsupported operator: " << f->get_name() << "\n"; + for (unsigned i = 0; i < num; i++) tout << mk_ismt2_pp(args[i], m()) << std::endl;); + throw tactic_exception("NYI"); + } + } + return BR_FAILED; + } + + bool pre_visit(expr * t) + { + TRACE("pre_visit_prec", tout << mk_ismt2_pp(t, m()) << std::endl;); + + if(t->get_kind() == AST_APP && is_app_of(t, to_app(t)->get_family_id(), OP_EQ)) { + //Equation over non-boolean expressions, it should be of form constantI = subexprI + app * a = to_app(t); + + if (a->get_num_args() == 2) { + expr * a0 = a->get_arg(0); + expr * a1 = a->get_arg(1); + func_decl * cnst = 0; + + if (a0->get_kind() == AST_APP && cnst2prec_map->contains(to_app(a0)->get_decl())) + cnst = to_app(a0)->get_decl(); + else if (a1->get_kind() == AST_APP && cnst2prec_map->contains(to_app(a1)->get_decl())) + cnst = to_app(a1)->get_decl(); + + if (cnst == 0) { + // For all equalities that were in the original problem, we don't + // have any precision tracking, so those simply get 100% precision. + set_precision(100); + } + else + set_precision(cnst2prec_map->find(cnst)); + TRACE("pre_visit_prec", tout << "Precision = " << get_precision(NULL) << std::endl;); + } + } + return true; + } + + bool reduce_quantifier(quantifier * old_q, + expr * new_body, + expr * const * new_patterns, + expr * const * new_no_patterns, + expr_ref & result, + proof_ref & result_pr) { + return false; + } + + bool reduce_var(var * t, expr_ref & result, proof_ref & result_pr) { + return false; + } +}; + +template class rewriter_tpl; + +struct fpa2bv_rewriter_prec : public rewriter_tpl { + fpa2bv_rewriter_prec_cfg m_cfg; + fpa2bv_rewriter_prec(ast_manager & m, fpa2bv_converter_prec & c, params_ref const & p): + rewriter_tpl(m, m.proofs_enabled(), m_cfg), + m_cfg(m, c, p) { + } +}; + +#endif From 13eac21b2c3b07d0c723de45488454a13ccf7c44 Mon Sep 17 00:00:00 2001 From: Aleksandar Zeljic Date: Thu, 28 May 2015 18:09:18 +0200 Subject: [PATCH 851/925] Introduced an empty dep2asm_map. --- src/tactic/fpa/fpa2bv_approx_tactic.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tactic/fpa/fpa2bv_approx_tactic.cpp b/src/tactic/fpa/fpa2bv_approx_tactic.cpp index 8a86ec0e8..4670883e1 100644 --- a/src/tactic/fpa/fpa2bv_approx_tactic.cpp +++ b/src/tactic/fpa/fpa2bv_approx_tactic.cpp @@ -896,7 +896,9 @@ class fpa2bv_approx_tactic: public tactic { TRACE("before_sat_solver", g->display(tout);); g->elim_redundancies(); - m_goal2sat(*g, m_params, solver, map); + goal2sat::dep2asm_map d2am ; + m_goal2sat(*g, m_params, solver, map, d2am , false); + TRACE("sat_solver_unknown", tout << "interpreted_atoms: " << map.interpreted_atoms() << "\n"; atom2bool_var::iterator it = map.begin(); From 23a6138d81799947b25e614c8bb115090e9e3321 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 May 2015 14:55:37 -0700 Subject: [PATCH 852/925] initialize potentially unused variables. Fixes issue #112 Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 3c2053a5c..cd47d6900 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -683,7 +683,7 @@ namespace z3 { friend expr operator+(expr const & a, expr const & b) { check_context(a, b); - Z3_ast r; + Z3_ast r = 0; if (a.is_arith() && b.is_arith()) { Z3_ast args[2] = { a, b }; r = Z3_mk_add(a.ctx(), 2, args); @@ -703,7 +703,7 @@ namespace z3 { friend expr operator*(expr const & a, expr const & b) { check_context(a, b); - Z3_ast r; + Z3_ast r = 0; if (a.is_arith() && b.is_arith()) { Z3_ast args[2] = { a, b }; r = Z3_mk_mul(a.ctx(), 2, args); @@ -730,7 +730,7 @@ namespace z3 { friend expr operator/(expr const & a, expr const & b) { check_context(a, b); - Z3_ast r; + Z3_ast r = 0; if (a.is_arith() && b.is_arith()) { r = Z3_mk_div(a.ctx(), a, b); } @@ -748,7 +748,7 @@ namespace z3 { friend expr operator/(int a, expr const & b) { return b.ctx().num_val(a, b.get_sort()) / b; } friend expr operator-(expr const & a) { - Z3_ast r; + Z3_ast r = 0; if (a.is_arith()) { r = Z3_mk_unary_minus(a.ctx(), a); } @@ -765,7 +765,7 @@ namespace z3 { friend expr operator-(expr const & a, expr const & b) { check_context(a, b); - Z3_ast r; + Z3_ast r = 0; if (a.is_arith() && b.is_arith()) { Z3_ast args[2] = { a, b }; r = Z3_mk_sub(a.ctx(), 2, args); @@ -785,7 +785,7 @@ namespace z3 { friend expr operator<=(expr const & a, expr const & b) { check_context(a, b); - Z3_ast r; + Z3_ast r = 0; if (a.is_arith() && b.is_arith()) { r = Z3_mk_le(a.ctx(), a, b); } @@ -804,7 +804,7 @@ namespace z3 { friend expr operator>=(expr const & a, expr const & b) { check_context(a, b); - Z3_ast r; + Z3_ast r = 0; if (a.is_arith() && b.is_arith()) { r = Z3_mk_ge(a.ctx(), a, b); } @@ -823,7 +823,7 @@ namespace z3 { friend expr operator<(expr const & a, expr const & b) { check_context(a, b); - Z3_ast r; + Z3_ast r = 0; if (a.is_arith() && b.is_arith()) { r = Z3_mk_lt(a.ctx(), a, b); } @@ -842,7 +842,7 @@ namespace z3 { friend expr operator>(expr const & a, expr const & b) { check_context(a, b); - Z3_ast r; + Z3_ast r = 0; if (a.is_arith() && b.is_arith()) { r = Z3_mk_gt(a.ctx(), a, b); } @@ -1189,7 +1189,7 @@ namespace z3 { expr eval(expr const & n, bool model_completion=false) const { check_context(*this, n); - Z3_ast r; + Z3_ast r = 0; Z3_bool status = Z3_model_eval(ctx(), m_model, n, model_completion, &r); check_error(); if (status == Z3_FALSE) From ac732a500cb90d255f7bf4cee992a04fb5a97ef3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 May 2015 15:20:25 -0700 Subject: [PATCH 853/925] add first file Signed-off-by: Nikolaj Bjorner --- src/qe/qe_mbp.h | 51 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 src/qe/qe_mbp.h diff --git a/src/qe/qe_mbp.h b/src/qe/qe_mbp.h new file mode 100644 index 000000000..b8a73a890 --- /dev/null +++ b/src/qe/qe_mbp.h @@ -0,0 +1,51 @@ +/*++ +Copyright (c) 2015 Microsoft Corporation + +Module Name: + + qe_mbp.h + +Abstract: + + Model-based projection utilities + +Author: + + Nikolaj Bjorner (nbjorner) 2015-5-28 + +Revision History: + + +--*/ + +#ifndef __QE_MBP_H__ +#define __QE_MBP_H__ + +#include "ast.h" +#include "params.h" + +class qe_mbp { + class impl; + impl * m_impl; +public: + qe_mbp(ast_manager& m); + + ~qe_mbp(); + + /** + \brief + Apply model-based qe on constants provided as vector of variables. + Return the updated formula and updated set of variables that were not eliminated. + + */ + void operator()(app_ref_vector& vars, model_ref& mdl, expr_ref& fml); + + /** + \brief full rewriting based light-weight quantifier elimination round. + */ + void operator()(expr_ref& fml, proof_ref& pr); + + void set_cancel(bool f); +}; + +#endif From e47eea2c610e19e1afde2ac3df5565aca755a4d4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 May 2015 17:22:34 -0700 Subject: [PATCH 854/925] n/a Signed-off-by: Nikolaj Bjorner --- src/qe/qe_mbp.h | 43 +++++------ src/qe/qsat.cpp | 200 ++++++++++++++++++++++++++++++++++++++++++++++++ src/qe/qsat.h | 52 +++++++++++++ 3 files changed, 272 insertions(+), 23 deletions(-) create mode 100644 src/qe/qsat.cpp create mode 100644 src/qe/qsat.h diff --git a/src/qe/qe_mbp.h b/src/qe/qe_mbp.h index b8a73a890..11bceef0b 100644 --- a/src/qe/qe_mbp.h +++ b/src/qe/qe_mbp.h @@ -24,28 +24,25 @@ Revision History: #include "ast.h" #include "params.h" -class qe_mbp { - class impl; - impl * m_impl; -public: - qe_mbp(ast_manager& m); - - ~qe_mbp(); - - /** - \brief - Apply model-based qe on constants provided as vector of variables. - Return the updated formula and updated set of variables that were not eliminated. - - */ - void operator()(app_ref_vector& vars, model_ref& mdl, expr_ref& fml); - - /** - \brief full rewriting based light-weight quantifier elimination round. - */ - void operator()(expr_ref& fml, proof_ref& pr); - - void set_cancel(bool f); -}; +namespace qe { + class mbp { + class impl; + impl * m_impl; + public: + mbp(ast_manager& m); + + ~mbp(); + + /** + \brief + Apply model-based qe on constants provided as vector of variables. + Return the updated formula and updated set of variables that were not eliminated. + + */ + void operator()(app_ref_vector& vars, model_ref& mdl, expr_ref& fml); + + void set_cancel(bool f); + }; +} #endif diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp new file mode 100644 index 000000000..6a59b40cd --- /dev/null +++ b/src/qe/qsat.cpp @@ -0,0 +1,200 @@ +/*++ +Copyright (c) 2015 Microsoft Corporation + +Module Name: + + qsat.cpp + +Abstract: + + Quantifier Satisfiability Solver. + +Author: + + Nikolaj Bjorner (nbjorner) 2015-5-28 + +Revision History: + + +--*/ + +#include "qsat.h" +#include "smt_kernel.h" +#include "qe_mbp.h" + +namespace qe; + +sturct qdef_t { + expr_ref m_pred; + expr_ref m_expr; + expr_ref_vector m_vars; + bool m_is_forall; + qdef_t(expr_ref& p, expr_ref& e, expr_ref_vector const& vars, bool is_forall): + m_pred(p), + m_expr(e), + m_vars(vars), + m_is_forall(is_forall) {} +}; + +typedef vector qdefs_t; + +struct pdef_t { + expr_ref m_pred; + expr_ref m_atom; + pdef_t(expr_ref& p, expr_ref& a): + m_pred(p), + m_atom(a) + {} +}; + +class qsat::impl { + ast_manager& m; + mbp mbp; + + /** + \brief replace quantified sub-formulas by a predicate, introduce definitions for the predicate. + */ + void remove_quantifiers(expr_ref_vector& fmls, qdefs_t& defs) { + + } + + /** + \brief create propositional abstration of formula by replacing atomic sub-formulas by fresh + propositional variables, and adding definitions for each propositional formula on the side. + Assumption is that the formula is quantifier-free. + */ + void mk_abstract(expr_ref_vector& fmls, vector& pdefs) { + expr_ref_vector todo(fmls), trail(m); + obj_map cache; + ptr_vector args; + expr_ref r(m); + while (!todo.empty()) { + expr* e = todo.back(); + if (cache.contains(e)) { + todo.pop_back(); + continue; + } + SASSERT(is_app(e)); + app* a = to_app(e); + if (a->get_family_id() == m.get_basic_family_id()) { + unsigned sz = a->get_num_args(); + args.reset(); + for (unsigned i = 0; i < sz; ++i) { + expr* f = a->get_arg(i); + if (cache.find(f, f)) { + args.push_back(f); + } + else { + todo.push_back(f); + } + } + if (args.size() == sz) { + r = m.mk_app(a->get_decl(), sz, args.c_ptr()); + cache.insert(e, r); + trail.push_back(r); + todo.pop_back(e); + } + } + else if (is_uninterpreted_const(a)) { + cache.insert(e, e); + } + else { + // TBD: nested Booleans. + r = m.mk_fresh_const("p",m.mk_bool_sort()); + trail.push_back(r); + cache.insert(e, r); + pdefs.push_back(pdef_t(e, r)); + } + } + + for (unsigned i = 0; i < fmls.size(); ++i) { + fmls[i] = cache.find(fmls[i].get()); + } + } + + /** + \brief use dual propagation to minimize model. + */ + void minimize_assignment(app_ref_vector& assignment) { + + } + +public: + impl(ast_manager& m): + m(m), + mbp(m) {} + + void updt_params(params_ref const & p) { + } + void collect_param_descrs(param_descrs & r) { + } + void operator()(/* in */ goal_ref const & in, + /* out */ goal_ref_buffer & result, + /* out */ model_converter_ref & mc, + /* out */ proof_converter_ref & pc, + /* out */ expr_dependency_ref & core) { + + } + + void collect_statistics(statistics & st) const { + + } + void reset_statistics() { + } + void cleanup() { + } + void set_logic(symbol const & l) { + } + void set_progress_callback(progress_callback * callback) { + } + tactic * translate(ast_manager & m) { + return 0; + } + +}; + +qsat::qsat(ast_manager& m) { + m_impl = alloc(impl, m); +} + +qsat::~qsat() { + dealloc(m_impl); +} + +void qsat::updt_params(params_ref const & p) { + m_impl->updt_params(p); +} +void qsat::collect_param_descrs(param_descrs & r) { + m_impl->collect_param_descrs(r); +} +void qsat::operator()(/* in */ goal_ref const & in, + /* out */ goal_ref_buffer & result, + /* out */ model_converter_ref & mc, + /* out */ proof_converter_ref & pc, + /* out */ expr_dependency_ref & core) { + (*m_impl)(in, result, mc, pc, core); +} + +void qsat::collect_statistics(statistics & st) const { + m_impl->collect_statistics(st); +} +void qsat::reset_statistics() { + m_impl->reset_statistics(); +} +void qsat::cleanup() { + m_impl->cleanup(); +} +void qsat::set_logic(symbol const & l) { + m_impl->set_logic(l); +} +void qsat::set_progress_callback(progress_callback * callback) { + m_impl->set_progress_callback(callback); +} +tactic * qsat::translate(ast_manager & m) { + return m_impl->translate(m); +} + + +}; + +#endif diff --git a/src/qe/qsat.h b/src/qe/qsat.h new file mode 100644 index 000000000..23d506294 --- /dev/null +++ b/src/qe/qsat.h @@ -0,0 +1,52 @@ +/*++ +Copyright (c) 2015 Microsoft Corporation + +Module Name: + + qsat.h + +Abstract: + + Quantifier Satisfiability Solver. + +Author: + + Nikolaj Bjorner (nbjorner) 2015-5-28 + +Revision History: + + +--*/ + +#ifndef __QE_MBP_H__ +#define __QE_MBP_H__ + +#include "tactic.h" + +namespace qe { + class qsat : public tactic { + class impl; + impl * m_impl; + public: + qsat(ast_manager& m); + ~qsat(); + + virtual void updt_params(params_ref const & p); + virtual void collect_param_descrs(param_descrs & r); + virtual void operator()(/* in */ goal_ref const & in, + /* out */ goal_ref_buffer & result, + /* out */ model_converter_ref & mc, + /* out */ proof_converter_ref & pc, + /* out */ expr_dependency_ref & core); + + virtual void collect_statistics(statistics & st) const; + virtual void reset_statistics(); + virtual void cleanup() = 0; + virtual void set_logic(symbol const & l); + virtual void set_progress_callback(progress_callback * callback); + virtual tactic * translate(ast_manager & m); + + }; +}; + +#endif From ed7e0e11a80a2d6cad4c8a11eaa0e2fbdc5ee3e8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 May 2015 20:55:13 -0700 Subject: [PATCH 855/925] n/a Signed-off-by: Nikolaj Bjorner --- src/api/api_solver.cpp | 4 ++ src/muz/base/dl_context.cpp | 4 ++ src/opt/opt_cmds.cpp | 6 +- src/opt/opt_context.cpp | 4 ++ src/qe/qsat.cpp | 131 +++++++++++++++++++++++++++------- src/qe/qsat.h | 4 +- src/smt/theory_array_full.cpp | 37 +++++----- src/smt/theory_array_full.h | 7 +- 8 files changed, 142 insertions(+), 55 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index e57050e82..ca15762f5 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -355,6 +355,10 @@ extern "C" { init_solver(c, s); Z3_stats_ref * st = alloc(Z3_stats_ref); to_solver_ref(s)->collect_statistics(st->m_stats); + unsigned long long max_mem = memory::get_max_used_memory(); + unsigned long long mem = memory::get_allocation_size(); + st->m_stats.update("max memory", static_cast(max_mem)/(1024.0*1024.0)); + st->m_stats.update("memory", static_cast(mem)/(1024.0*1024.0)); mk_c(c)->save_object(st); Z3_stats r = of_stats(st); RETURN_Z3(r); diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index bd70c06ef..3555e5bdc 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -945,6 +945,10 @@ namespace datalog { if (m_engine) { m_engine->collect_statistics(st); } + unsigned long long max_mem = memory::get_max_used_memory(); + unsigned long long mem = memory::get_allocation_size(); + st.update("max memory", static_cast(max_mem)/(1024.0*1024.0)); + st.update("memory", static_cast(mem)/(1024.0*1024.0)); } diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index 537f4bf22..01324fc67 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -323,12 +323,8 @@ private: void display_statistics(cmd_context& ctx) { statistics stats; - unsigned long long max_mem = memory::get_max_used_memory(); - unsigned long long mem = memory::get_allocation_size(); - stats.update("time", ctx.get_seconds()); - stats.update("memory", static_cast(mem)/static_cast(1024*1024)); - stats.update("max memory", static_cast(max_mem)/static_cast(1024*1024)); get_opt(ctx).collect_statistics(stats); + stats.update("time", ctx.get_seconds()); stats.display_smt2(ctx.regular_stream()); } }; diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 857b57296..5353d9b53 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -1179,6 +1179,10 @@ namespace opt { for (; it != end; ++it) { it->m_value->collect_statistics(stats); } + unsigned long long max_mem = memory::get_max_used_memory(); + unsigned long long mem = memory::get_allocation_size(); + stats.update("memory", static_cast(mem)/static_cast(1024*1024)); + stats.update("max memory", static_cast(max_mem)/static_cast(1024*1024)); } void context::collect_param_descrs(param_descrs & r) { diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp index 6a59b40cd..4c736bc31 100644 --- a/src/qe/qsat.cpp +++ b/src/qe/qsat.cpp @@ -21,10 +21,12 @@ Revision History: #include "qsat.h" #include "smt_kernel.h" #include "qe_mbp.h" +#include "smt_params.h" +#include "ast_util.h" -namespace qe; +using namespace qe; -sturct qdef_t { +struct qdef_t { expr_ref m_pred; expr_ref m_expr; expr_ref_vector m_vars; @@ -41,15 +43,25 @@ typedef vector qdefs_t; struct pdef_t { expr_ref m_pred; expr_ref m_atom; - pdef_t(expr_ref& p, expr_ref& a): - m_pred(p), - m_atom(a) + pdef_t(expr_ref& p, expr* a): + m_pred(p), + m_atom(a, p.get_manager()) {} }; class qsat::impl { - ast_manager& m; - mbp mbp; + ast_manager& m; + qe::mbp mbp; + smt_params m_smtp; + smt::kernel m_kernel; + expr_ref m_fml_pred; // predicate that encodes top-level formula + expr_ref_vector m_atoms; // predicates that encode atomic subformulas + + + lbool check_sat() { + // TBD main procedure goes here. + return l_undef; + } /** \brief replace quantified sub-formulas by a predicate, introduce definitions for the predicate. @@ -63,11 +75,12 @@ class qsat::impl { propositional variables, and adding definitions for each propositional formula on the side. Assumption is that the formula is quantifier-free. */ - void mk_abstract(expr_ref_vector& fmls, vector& pdefs) { - expr_ref_vector todo(fmls), trail(m); + void mk_abstract(expr_ref& fml, vector& pdefs) { + expr_ref_vector todo(m), trail(m); obj_map cache; ptr_vector args; expr_ref r(m); + todo.push_back(fml); while (!todo.empty()) { expr* e = todo.back(); if (cache.contains(e)) { @@ -87,47 +100,114 @@ class qsat::impl { else { todo.push_back(f); } - } + } if (args.size() == sz) { r = m.mk_app(a->get_decl(), sz, args.c_ptr()); cache.insert(e, r); trail.push_back(r); - todo.pop_back(e); + todo.pop_back(); } } - else if (is_uninterpreted_const(a)) { + else if (is_uninterp_const(a)) { cache.insert(e, e); } else { - // TBD: nested Booleans. + // TBD: nested Booleans. + r = m.mk_fresh_const("p",m.mk_bool_sort()); trail.push_back(r); cache.insert(e, r); - pdefs.push_back(pdef_t(e, r)); + pdefs.push_back(pdef_t(r, e)); } } - - for (unsigned i = 0; i < fmls.size(); ++i) { - fmls[i] = cache.find(fmls[i].get()); - } + fml = cache.find(fml); } /** \brief use dual propagation to minimize model. */ - void minimize_assignment(app_ref_vector& assignment) { - + bool minimize_assignment(expr_ref_vector& assignment, expr* not_fml) { + bool result = false; + assignment.push_back(not_fml); + lbool res = m_kernel.check(assignment.size(), assignment.c_ptr()); + switch (res) { + case l_true: + UNREACHABLE(); + break; + case l_undef: + break; + case l_false: + result = true; + get_core(assignment, not_fml); + break; + } + return result; + } + + lbool check_sat(expr_ref_vector& assignment, expr* fml) { + assignment.push_back(fml); + lbool res = m_kernel.check(assignment.size(), assignment.c_ptr()); + switch (res) { + case l_true: { + model_ref mdl; + expr_ref tmp(m); + assignment.reset(); + m_kernel.get_model(mdl); + for (unsigned i = 0; i < m_atoms.size(); ++i) { + expr* p = m_atoms[i].get(); + if (mdl->eval(p, tmp)) { + if (m.is_true(tmp)) { + assignment.push_back(p); + } + else if (m.is_false(tmp)) { + assignment.push_back(m.mk_not(p)); + } + } + } + expr_ref not_fml = mk_not(fml); + if (!minimize_assignment(assignment, not_fml)) { + res = l_undef; + } + break; + } + case l_undef: + break; + case l_false: + get_core(assignment, fml); + break; + } + return res; + } + + void get_core(expr_ref_vector& core, expr* exclude) { + unsigned sz = m_kernel.get_unsat_core_size(); + core.reset(); + for (unsigned i = 0; i < sz; ++i) { + expr* e = m_kernel.get_unsat_core_expr(i); + if (e != exclude) { + core.push_back(e); + } + } + } + + expr_ref mk_not(expr* e) { + return expr_ref(::mk_not(m, e), m); } public: impl(ast_manager& m): m(m), - mbp(m) {} - + mbp(m), + m_kernel(m, m_smtp), + m_fml_pred(m), + m_atoms(m) {} + void updt_params(params_ref const & p) { } + void collect_param_descrs(param_descrs & r) { } + void operator()(/* in */ goal_ref const & in, /* out */ goal_ref_buffer & result, /* out */ model_converter_ref & mc, @@ -141,12 +221,16 @@ public: } void reset_statistics() { } + void cleanup() { } + void set_logic(symbol const & l) { } + void set_progress_callback(progress_callback * callback) { } + tactic * translate(ast_manager & m) { return 0; } @@ -195,6 +279,3 @@ tactic * qsat::translate(ast_manager & m) { } -}; - -#endif diff --git a/src/qe/qsat.h b/src/qe/qsat.h index 23d506294..2fc071c76 100644 --- a/src/qe/qsat.h +++ b/src/qe/qsat.h @@ -18,8 +18,8 @@ Revision History: --*/ -#ifndef __QE_MBP_H__ -#define __QE_MBP_H__ +#ifndef __QE_QSAT_H__ +#define __QE_QSAT_H__ #include "tactic.h" diff --git a/src/smt/theory_array_full.cpp b/src/smt/theory_array_full.cpp index 28314c421..dd74f2871 100644 --- a/src/smt/theory_array_full.cpp +++ b/src/smt/theory_array_full.cpp @@ -208,6 +208,8 @@ namespace smt { theory_array::reset_eh(); std::for_each(m_var_data_full.begin(), m_var_data_full.end(), delete_proc()); m_var_data_full.reset(); + m_eqs.reset(); + m_eqsv.reset(); } void theory_array_full::display_var(std::ostream & out, theory_var v) const { @@ -223,7 +225,6 @@ namespace smt { } theory_var theory_array_full::mk_var(enode * n) { - theory_var r = theory_array::mk_var(n); SASSERT(r == static_cast(m_var_data_full.size())); m_var_data_full.push_back(alloc(var_data_full)); @@ -512,7 +513,7 @@ namespace smt { TRACE("array_map_bug", tout << "select-map axiom\n" << mk_ismt2_pp(sel1, m) << "\n=\n" << mk_ismt2_pp(sel2,m) << "\n";); - + return try_assign_eq(sel1, sel2); } @@ -760,36 +761,30 @@ namespace smt { r = FC_CONTINUE; } } + while (!m_eqsv.empty()) { + literal eq = m_eqsv.back(); + m_eqsv.pop_back(); + get_context().mark_as_relevant(eq); + assert_axiom(eq); + r = FC_CONTINUE; + } if (r == FC_DONE && m_found_unsupported_op) r = FC_GIVEUP; return r; } + bool theory_array_full::try_assign_eq(expr* v1, expr* v2) { context& ctx = get_context(); - enode* n1 = ctx.get_enode(v1); - enode* n2 = ctx.get_enode(v2); - if (n1->get_root() == n2->get_root()) { + if (m_eqs.contains(v1, v2)) { return false; } + m_eqs.insert(v1, v2, true); TRACE("array", tout << mk_bounded_pp(v1, get_manager()) << "\n==\n" << mk_bounded_pp(v2, get_manager()) << "\n";); - -#if 0 - if (m.proofs_enabled()) { -#endif - literal eq(mk_eq(v1,v2,true)); - ctx.mark_as_relevant(eq); - assert_axiom(eq); -#if 0 - } - else { - ctx.mark_as_relevant(n1); - ctx.mark_as_relevant(n2); - ctx.assign_eq(n1, n2, eq_justification::mk_axiom()); - } -#endif + literal eq(mk_eq(v1, v2, true)); + m_eqsv.push_back(eq); return true; } @@ -798,6 +793,8 @@ namespace smt { theory_array::pop_scope_eh(num_scopes); std::for_each(m_var_data_full.begin() + num_old_vars, m_var_data_full.end(), delete_proc()); m_var_data_full.shrink(num_old_vars); + m_eqs.reset(); + m_eqsv.reset(); } void theory_array_full::collect_statistics(::statistics & st) const { diff --git a/src/smt/theory_array_full.h b/src/smt/theory_array_full.h index 7c066f765..bbbf35408 100644 --- a/src/smt/theory_array_full.h +++ b/src/smt/theory_array_full.h @@ -38,12 +38,12 @@ namespace smt { ast2ast_trailmap m_sort2epsilon; simplifier* m_simp; + obj_pair_map m_eqs; + svector m_eqsv; protected: -#if 0 - virtual final_check_status final_check_eh(); -#endif + //virtual final_check_status final_check_eh(); virtual void reset_eh(); virtual void set_prop_upward(theory_var v); @@ -84,6 +84,7 @@ namespace smt { bool try_assign_eq(expr* n1, expr* n2); + void assign_eqs(); public: From 3f22201ba3e1518d9b6cb9cc18752bcd997e8fe8 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 29 May 2015 12:25:44 +0100 Subject: [PATCH 856/925] Bugfix for dll/so name resolution in Java. --- scripts/update_api.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index 051e8fced..0d57a29ac 100644 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -568,10 +568,12 @@ def mk_java(): java_native.write(' public static class ObjArrayPtr { public long[] value; }\n') java_native.write(' public static class UIntArrayPtr { public int[] value; }\n') java_native.write(' public static native void setInternalErrorHandler(long ctx);\n\n') - if IS_WINDOWS or os.uname()[0]=="CYGWIN": - java_native.write(' static { System.loadLibrary("%s"); }\n' % get_component('java').dll_name) - else: - java_native.write(' static { System.loadLibrary("%s"); }\n' % get_component('java').dll_name[3:]) # We need 3: to extract the prexi 'lib' form the dll_name + + java_native.write(' static {\n') + java_native.write(' try { System.loadLibrary("z3java"); }\n') + java_native.write(' catch (UnsatisfiedLinkError ex) { System.loadLibrary("libz3java"); }\n') + java_native.write(' }\n') + java_native.write('\n') for name, result, params in _dotnet_decls: java_native.write(' protected static native %s INTERNAL%s(' % (type2java(result), java_method_name(name))) From d8d0b21e4212e24c2acbea64d43bc1f018efbebe Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 29 May 2015 12:25:44 +0100 Subject: [PATCH 857/925] Bugfix for dll/so name resolution in Java. Fixes #111 --- scripts/update_api.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index 051e8fced..0d57a29ac 100644 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -568,10 +568,12 @@ def mk_java(): java_native.write(' public static class ObjArrayPtr { public long[] value; }\n') java_native.write(' public static class UIntArrayPtr { public int[] value; }\n') java_native.write(' public static native void setInternalErrorHandler(long ctx);\n\n') - if IS_WINDOWS or os.uname()[0]=="CYGWIN": - java_native.write(' static { System.loadLibrary("%s"); }\n' % get_component('java').dll_name) - else: - java_native.write(' static { System.loadLibrary("%s"); }\n' % get_component('java').dll_name[3:]) # We need 3: to extract the prexi 'lib' form the dll_name + + java_native.write(' static {\n') + java_native.write(' try { System.loadLibrary("z3java"); }\n') + java_native.write(' catch (UnsatisfiedLinkError ex) { System.loadLibrary("libz3java"); }\n') + java_native.write(' }\n') + java_native.write('\n') for name, result, params in _dotnet_decls: java_native.write(' protected static native %s INTERNAL%s(' % (type2java(result), java_method_name(name))) From f2f6fc1994fcbfaa1c4191f51e75babf7f67544e Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 29 May 2015 13:58:23 +0100 Subject: [PATCH 858/925] Added QF_BVFP logic alias for QF_FPBV --- src/cmd_context/cmd_context.cpp | 2 ++ src/smt/smt_setup.cpp | 2 +- src/tactic/portfolio/smt_strategic_solver.cpp | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 80aa10cde..9aa089096 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -528,6 +528,7 @@ bool cmd_context::logic_has_arith_core(symbol const & s) const { s == "LRA" || s == "QF_FP" || s == "QF_FPBV" || + s == "QF_BVFP" || s == "HORN"; } @@ -547,6 +548,7 @@ bool cmd_context::logic_has_bv_core(symbol const & s) const { s == "QF_AUFBV" || s == "QF_BVRE" || s == "QF_FPBV" || + s == "QF_BVFP" || s == "HORN"; } diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index d4c0e1efb..98ad5e51a 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -116,7 +116,7 @@ namespace smt { setup_LRA(); else if (m_logic == "QF_FP") setup_QF_FP(); - else if (m_logic == "QF_FPBV") + else if (m_logic == "QF_FPBV" || m_logic == "QF_BVFP") setup_QF_FPBV(); else setup_unknown(); diff --git a/src/tactic/portfolio/smt_strategic_solver.cpp b/src/tactic/portfolio/smt_strategic_solver.cpp index b28c8cf3d..687771a30 100644 --- a/src/tactic/portfolio/smt_strategic_solver.cpp +++ b/src/tactic/portfolio/smt_strategic_solver.cpp @@ -81,7 +81,7 @@ tactic * mk_tactic_for_logic(ast_manager & m, params_ref const & p, symbol const return mk_ufbv_tactic(m, p); else if (logic=="QF_FP") return mk_qffp_tactic(m, p); - else if (logic == "QF_FPBV") + else if (logic == "QF_FPBV" || logic == "QF_BVFP") return mk_qffpbv_tactic(m, p); else if (logic=="HORN") return mk_horn_tactic(m, p); From 9428acd578459edcec0936259d00b3c002378ef2 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 29 May 2015 13:58:33 +0100 Subject: [PATCH 859/925] Bugfix for FPA rewriter. --- src/ast/rewriter/fpa_rewriter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ast/rewriter/fpa_rewriter.cpp b/src/ast/rewriter/fpa_rewriter.cpp index 738e8ec29..07a39bcae 100644 --- a/src/ast/rewriter/fpa_rewriter.cpp +++ b/src/ast/rewriter/fpa_rewriter.cpp @@ -143,9 +143,9 @@ br_status fpa_rewriter::mk_to_sbv_unspecified(func_decl * f, expr_ref & result) br_status fpa_rewriter::mk_to_real_unspecified(expr_ref & result) { if (m_hi_fp_unspecified) - result = m_util.au().mk_numeral(0, false); - else // The "hardware interpretation" is 0. + result = m_util.au().mk_numeral(rational(0), false); + else result = m_util.mk_internal_to_real_unspecified(); return BR_DONE; From 85419ca503496b0cd873234320ef195199ac3093 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 29 May 2015 14:21:27 +0100 Subject: [PATCH 860/925] Added branch into QF_NRA from QF_FP problems containing to_real terms. --- scripts/mk_project.py | 2 +- src/tactic/fpa/qffp_tactic.cpp | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 4bccdf6bb..b9641c869 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -55,7 +55,6 @@ def init_project_def(): add_lib('bv_tactics', ['tactic', 'bit_blaster'], 'tactic/bv') add_lib('fuzzing', ['ast'], 'test/fuzzing') add_lib('smt_tactic', ['smt'], 'smt/tactic') - add_lib('fpa_tactics', ['fpa', 'core_tactics', 'bv_tactics', 'sat_tactic', 'smt_tactic'], 'tactic/fpa') add_lib('sls_tactic', ['tactic', 'normal_forms', 'core_tactics', 'bv_tactics'], 'tactic/sls') add_lib('qe', ['smt','sat'], 'qe') add_lib('duality', ['smt', 'interp', 'qe']) @@ -71,6 +70,7 @@ def init_project_def(): add_lib('fp', ['muz', 'pdr', 'clp', 'tab', 'rel', 'bmc', 'duality_intf', 'ddnf'], 'muz/fp') add_lib('nlsat_smt_tactic', ['nlsat_tactic', 'smt_tactic'], 'tactic/nlsat_smt') add_lib('smtlogic_tactics', ['arith_tactics', 'bv_tactics', 'nlsat_tactic', 'smt_tactic', 'aig_tactic', 'fp', 'muz','qe','nlsat_smt_tactic'], 'tactic/smtlogics') + add_lib('fpa_tactics', ['fpa', 'core_tactics', 'bv_tactics', 'sat_tactic', 'smt_tactic', 'arith_tactics', 'smtlogic_tactics'], 'tactic/fpa') add_lib('ufbv_tactic', ['normal_forms', 'core_tactics', 'macros', 'smt_tactic', 'rewriter'], 'tactic/ufbv') add_lib('portfolio', ['smtlogic_tactics', 'ufbv_tactic', 'fpa_tactics', 'aig_tactic', 'fp', 'qe','sls_tactic', 'subpaving_tactic'], 'tactic/portfolio') add_lib('smtparser', ['portfolio'], 'parsers/smt') diff --git a/src/tactic/fpa/qffp_tactic.cpp b/src/tactic/fpa/qffp_tactic.cpp index 4854b3c07..12c127a37 100644 --- a/src/tactic/fpa/qffp_tactic.cpp +++ b/src/tactic/fpa/qffp_tactic.cpp @@ -23,6 +23,8 @@ Notes: #include"fpa2bv_tactic.h" #include"smt_tactic.h" #include"propagate_values_tactic.h" +#include"probe_arith.h" +#include"qfnra_tactic.h" #include"qffp_tactic.h" @@ -40,10 +42,13 @@ tactic * mk_qffp_tactic(ast_manager & m, params_ref const & p) { mk_propagate_values_tactic(m, p), using_params(mk_simplify_tactic(m, p), simp_p), mk_bit_blaster_tactic(m, p), - using_params(mk_simplify_tactic(m, p), simp_p), + using_params(mk_simplify_tactic(m, p), simp_p), cond(mk_is_propositional_probe(), mk_sat_tactic(m, p), - mk_smt_tactic(p)), + cond(mk_is_qfnra_probe(), + mk_qfnra_tactic(m, p), + mk_smt_tactic(p)) + ), mk_fail_if_undecided_tactic()))); st->updt_params(p); From d35ebd6e57564815a8c89ca52fb57c15ecd1d4d5 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 29 May 2015 14:49:26 +0100 Subject: [PATCH 861/925] Bugfix for FP to_fp from non-numeral reals. --- src/ast/fpa/fpa2bv_converter.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index d2d2c6a3f..16b7cc1da 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -2312,7 +2312,8 @@ void fpa2bv_converter::mk_to_fp_real(func_decl * f, sort * s, expr * rm, expr * mk_ite(rm_nta, v1, result, result); } } - else { + else { + SASSERT(!m_arith_util.is_numeral(x)); bv_util & bu = m_bv_util; arith_util & au = m_arith_util; @@ -2330,12 +2331,8 @@ void fpa2bv_converter::mk_to_fp_real(func_decl * f, sort * s, expr * rm, expr * expr_ref rme(rm, m); round(s, rme, sgn, sig, exp, result); - expr_ref c0(m); - mk_is_zero(x, c0); - mk_ite(c0, x, result, result); - expr * e = m.mk_eq(m_util.mk_to_real(result), x); - m_extra_assertions.push_back(e); + m_extra_assertions.push_back(e); } SASSERT(is_well_sorted(m, result)); From ba8864846816603742a06d60ab9191604fd1b6bd Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 29 May 2015 14:49:53 +0100 Subject: [PATCH 862/925] Added has_fp_to_real probe to detect when QF_FP need QF_NRA. --- src/tactic/fpa/qffp_tactic.cpp | 38 +++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/tactic/fpa/qffp_tactic.cpp b/src/tactic/fpa/qffp_tactic.cpp index 12c127a37..3bee224b3 100644 --- a/src/tactic/fpa/qffp_tactic.cpp +++ b/src/tactic/fpa/qffp_tactic.cpp @@ -28,6 +28,42 @@ Notes: #include"qffp_tactic.h" + +struct has_fp_to_real_predicate { + struct found {}; + ast_manager & m; + bv_util bu; + fpa_util fu; + arith_util au; + + has_fp_to_real_predicate(ast_manager & _m) : m(_m), bu(m), fu(m), au(m) {} + + void operator()(var *) { throw found(); } + + void operator()(quantifier *) { throw found(); } + + void operator()(app * n) { + sort * s = get_sort(n); + if (au.is_real(s) && n->get_family_id() == fu.get_family_id() && + is_app(n) && to_app(n)->get_kind() == OP_FPA_TO_REAL) + throw found(); + } +}; + +class has_fp_to_real_probe : public probe { +public: + virtual result operator()(goal const & g) { + return !test(g); + } + + virtual ~has_fp_to_real_probe() {} +}; + +probe * mk_has_fp_to_real_probe() { + return alloc(has_fp_to_real_probe); +} + + tactic * mk_qffp_tactic(ast_manager & m, params_ref const & p) { params_ref simp_p = p; simp_p.set_bool("arith_lhs", true); @@ -45,7 +81,7 @@ tactic * mk_qffp_tactic(ast_manager & m, params_ref const & p) { using_params(mk_simplify_tactic(m, p), simp_p), cond(mk_is_propositional_probe(), mk_sat_tactic(m, p), - cond(mk_is_qfnra_probe(), + cond(mk_has_fp_to_real_probe(), mk_qfnra_tactic(m, p), mk_smt_tactic(p)) ), From a2448be0cde41a774f8321d94521373563285608 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 29 May 2015 08:55:44 -0700 Subject: [PATCH 863/925] print pareto model in check-sat too Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.cpp | 10 ++++++++++ src/cmd_context/cmd_context.h | 1 + src/opt/opt_context.cpp | 6 ++++++ src/opt/opt_context.h | 1 + 4 files changed, 18 insertions(+) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 80aa10cde..187c7ba63 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -40,6 +40,7 @@ Notes: #include"for_each_expr.h" #include"scoped_timer.h" #include"interpolant_cmds.h" +#include"model_smt2_pp.h" func_decls::func_decls(ast_manager & m, func_decl * f): m_decls(TAG(func_decl*, f, 0)) { @@ -1402,6 +1403,15 @@ void cmd_context::check_sat(unsigned num_assumptions, expr * const * assumptions was_pareto = true; get_opt()->display_assignment(regular_stream()); regular_stream() << "\n"; + if (get_opt()->print_model()) { + model_ref mdl; + get_opt()->get_model(mdl); + if (mdl) { + regular_stream() << "(model " << std::endl; + model_smt2_pp(regular_stream(), *this, *(mdl.get()), 2); + regular_stream() << ")" << std::endl; + } + } r = get_opt()->optimize(); } } diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index 148bb61d9..795b3a65a 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -124,6 +124,7 @@ public: virtual void display_assignment(std::ostream& out) = 0; virtual bool is_pareto() = 0; virtual void set_logic(symbol const& s) = 0; + virtual bool print_model() const = 0; }; class cmd_context : public progress_callback, public tactic_manager, public ast_printer_context { diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 857b57296..f5a3b5c67 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -254,6 +254,12 @@ namespace opt { } } + + bool context::print_model() const { + opt_params optp(m_params); + return optp.print_model(); + } + void context::get_base_model(model_ref& mdl) { mdl = m_model; } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 59868dd1e..eabc2550f 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -180,6 +180,7 @@ namespace opt { virtual void cancel() { set_cancel(true); } virtual void set_hard_constraints(ptr_vector & hard); virtual lbool optimize(); + virtual bool print_model() const; virtual void get_model(model_ref& _m); virtual void set_model(model_ref& _m); virtual void fix_model(model_ref& _m); From fec815b41ef66c5dc28a04aeabd933fca59e4d37 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 29 May 2015 18:13:39 +0100 Subject: [PATCH 864/925] Various variable renamings to avoid conflicts with previously defined local variables, function parameters, or members (Visual Studio 2015 warnings). --- src/ast/ast_smt2_pp.cpp | 8 +-- src/ast/ast_util.cpp | 6 +- src/ast/datatype_decl_plugin.cpp | 14 ++--- src/ast/expr2polynomial.cpp | 10 ++-- src/ast/fpa/fpa2bv_converter.cpp | 58 +++++++++---------- src/ast/func_decl_dependencies.cpp | 16 ++--- .../bit_blaster/bit_blaster_tpl_def.h | 12 ++-- src/ast/rewriter/rewriter_def.h | 2 +- src/ast/shared_occs.h | 2 +- src/tactic/arith/arith_bounds_tactic.cpp | 4 +- src/tactic/tactical.cpp | 2 - 11 files changed, 65 insertions(+), 69 deletions(-) diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index 0d319af39..c74b4f185 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -341,22 +341,22 @@ format * smt2_pp_environment::pp_arith_literal(app * t, bool decimal, unsigned d } else { SASSERT(u.is_irrational_algebraic_numeral(t)); - anum const & val = u.to_irrational_algebraic_numeral(t); + anum const & val2 = u.to_irrational_algebraic_numeral(t); algebraic_numbers::manager & am = u.am(); format * vf; std::ostringstream buffer; bool is_neg = false; if (decimal) { scoped_anum abs_val(am); - am.set(abs_val, val); - if (am.is_neg(val)) { + am.set(abs_val, val2); + if (am.is_neg(val2)) { is_neg = true; am.neg(abs_val); } am.display_decimal(buffer, abs_val, decimal_prec); } else { - am.display_root_smt2(buffer, val); + am.display_root_smt2(buffer, val2); } vf = mk_string(get_manager(), buffer.str().c_str()); return is_neg ? mk_neg(vf) : vf; diff --git a/src/ast/ast_util.cpp b/src/ast/ast_util.cpp index d77deca01..79f8f740e 100644 --- a/src/ast/ast_util.cpp +++ b/src/ast/ast_util.cpp @@ -44,12 +44,12 @@ app * mk_list_assoc_app(ast_manager & m, family_id fid, decl_kind k, unsigned nu return mk_list_assoc_app(m, decl, num_args, args); } -bool is_well_formed_vars(ptr_vector& bound, expr* e) { +bool is_well_formed_vars(ptr_vector& bound, expr * top) { ptr_vector todo; ast_mark mark; - todo.push_back(e); + todo.push_back(top); while (!todo.empty()) { - expr* e = todo.back(); + expr * e = todo.back(); todo.pop_back(); if (mark.is_marked(e)) { continue; diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index d707f0178..c185540b7 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -149,10 +149,10 @@ enum status { */ static bool is_recursive_datatype(parameter const * parameters) { unsigned num_types = parameters[0].get_int(); - unsigned tid = parameters[1].get_int(); + unsigned top_tid = parameters[1].get_int(); buffer already_found(num_types, WHITE); buffer todo; - todo.push_back(tid); + todo.push_back(top_tid); while (!todo.empty()) { unsigned tid = todo.back(); if (already_found[tid] == BLACK) { @@ -198,11 +198,11 @@ static bool is_recursive_datatype(parameter const * parameters) { */ static sort_size get_datatype_size(parameter const * parameters) { unsigned num_types = parameters[0].get_int(); - unsigned tid = parameters[1].get_int(); + unsigned top_tid = parameters[1].get_int(); buffer szs(num_types, sort_size()); buffer already_found(num_types, WHITE); buffer todo; - todo.push_back(tid); + todo.push_back(top_tid); while (!todo.empty()) { unsigned tid = todo.back(); if (already_found[tid] == BLACK) { @@ -280,7 +280,7 @@ static sort_size get_datatype_size(parameter const * parameters) { } } } - return szs[tid]; + return szs[top_tid]; } /** @@ -657,8 +657,8 @@ bool datatype_decl_plugin::is_fully_interp(sort const * s) const { for (unsigned tid = 0; tid < num_types; tid++) { unsigned o = parameters[2 + 2*tid + 1].get_int(); // constructor offset unsigned num_constructors = parameters[o].get_int(); - for (unsigned s = 1; s <= num_constructors; s++) { - unsigned k_i = parameters[o + s].get_int(); + for (unsigned si = 1; si <= num_constructors; si++) { + unsigned k_i = parameters[o + si].get_int(); unsigned num_accessors = parameters[k_i + 2].get_int(); unsigned r = 0; for (; r < num_accessors; r++) { diff --git a/src/ast/expr2polynomial.cpp b/src/ast/expr2polynomial.cpp index fbabcb150..097d77cbc 100644 --- a/src/ast/expr2polynomial.cpp +++ b/src/ast/expr2polynomial.cpp @@ -367,16 +367,16 @@ struct expr2polynomial::imp { begin_loop: checkpoint(); frame & fr = m_frame_stack.back(); - app * t = fr.m_curr; - TRACE("expr2polynomial", tout << "processing: " << fr.m_idx << "\n" << mk_ismt2_pp(t, m()) << "\n";); - unsigned num_args = t->get_num_args(); + app * a = fr.m_curr; + TRACE("expr2polynomial", tout << "processing: " << fr.m_idx << "\n" << mk_ismt2_pp(a, m()) << "\n";); + unsigned num_args = a->get_num_args(); while (fr.m_idx < num_args) { - expr * arg = t->get_arg(fr.m_idx); + expr * arg = a->get_arg(fr.m_idx); fr.m_idx++; if (!visit(arg)) goto begin_loop; } - process_app(t); + process_app(a); m_frame_stack.pop_back(); } } diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 16b7cc1da..75e8dfd99 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -2219,13 +2219,13 @@ void fpa2bv_converter::mk_to_fp_real(func_decl * f, sort * s, expr * rm, expr * SASSERT(sz == 3); BV_RM_VAL bv_rm = (BV_RM_VAL)tmp_rat.get_unsigned(); - mpf_rounding_mode rm; + mpf_rounding_mode mrm; switch (bv_rm) { - case BV_RM_TIES_TO_AWAY: rm = MPF_ROUND_NEAREST_TAWAY; break; - case BV_RM_TIES_TO_EVEN: rm = MPF_ROUND_NEAREST_TEVEN; break; - case BV_RM_TO_NEGATIVE: rm = MPF_ROUND_TOWARD_NEGATIVE; break; - case BV_RM_TO_POSITIVE: rm = MPF_ROUND_TOWARD_POSITIVE; break; - case BV_RM_TO_ZERO: rm = MPF_ROUND_TOWARD_ZERO; break; + case BV_RM_TIES_TO_AWAY: mrm = MPF_ROUND_NEAREST_TAWAY; break; + case BV_RM_TIES_TO_EVEN: mrm = MPF_ROUND_NEAREST_TEVEN; break; + case BV_RM_TO_NEGATIVE: mrm = MPF_ROUND_TOWARD_NEGATIVE; break; + case BV_RM_TO_POSITIVE: mrm = MPF_ROUND_TOWARD_POSITIVE; break; + case BV_RM_TO_ZERO: mrm = MPF_ROUND_TOWARD_ZERO; break; default: UNREACHABLE(); } @@ -2237,17 +2237,15 @@ void fpa2bv_converter::mk_to_fp_real(func_decl * f, sort * s, expr * rm, expr * return mk_pzero(f, result); else { scoped_mpf v(m_mpf_manager); - m_util.fm().set(v, ebits, sbits, rm, q.to_mpq()); + m_util.fm().set(v, ebits, sbits, mrm, q.to_mpq()); - - - expr_ref sgn(m), s(m), e(m), unbiased_exp(m); + expr_ref sgn(m), sig(m), exp(m), unbiased_exp(m); sgn = m_bv_util.mk_numeral((m_util.fm().sgn(v)) ? 1 : 0, 1); - s = m_bv_util.mk_numeral(m_util.fm().sig(v), sbits - 1); + sig = m_bv_util.mk_numeral(m_util.fm().sig(v), sbits - 1); unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v), ebits); - mk_bias(unbiased_exp, e); + mk_bias(unbiased_exp, exp); - mk_fp(sgn, e, s, result); + mk_fp(sgn, exp, sig, result); } } else if (m_util.au().is_numeral(x)) { @@ -2275,37 +2273,37 @@ void fpa2bv_converter::mk_to_fp_real(func_decl * f, sort * s, expr * rm, expr * expr_ref v1(m), v2(m), v3(m), v4(m); - expr_ref sgn(m), s(m), e(m), unbiased_exp(m); + expr_ref sgn(m), sig(m), exp(m), unbiased_exp(m); sgn = m_bv_util.mk_numeral((m_util.fm().sgn(v_nta)) ? 1 : 0, 1); - s = m_bv_util.mk_numeral(m_util.fm().sig(v_nta), sbits - 1); + sig = m_bv_util.mk_numeral(m_util.fm().sig(v_nta), sbits - 1); unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v_nta), ebits); - mk_bias(unbiased_exp, e); - mk_fp(sgn, e, s, v1); + mk_bias(unbiased_exp, exp); + mk_fp(sgn, exp, sig, v1); sgn = m_bv_util.mk_numeral((m_util.fm().sgn(v_nte)) ? 1 : 0, 1); - s = m_bv_util.mk_numeral(m_util.fm().sig(v_nte), sbits - 1); + sig = m_bv_util.mk_numeral(m_util.fm().sig(v_nte), sbits - 1); unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v_nte), ebits); - mk_bias(unbiased_exp, e); - mk_fp(sgn, e, s, v2); + mk_bias(unbiased_exp, exp); + mk_fp(sgn, exp, sig, v2); sgn = m_bv_util.mk_numeral((m_util.fm().sgn(v_tp)) ? 1 : 0, 1); - s = m_bv_util.mk_numeral(m_util.fm().sig(v_tp), sbits - 1); + sig = m_bv_util.mk_numeral(m_util.fm().sig(v_tp), sbits - 1); unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v_tp), ebits); - mk_bias(unbiased_exp, e); - mk_fp(sgn, e, s, v3); + mk_bias(unbiased_exp, exp); + mk_fp(sgn, exp, sig, v3); sgn = m_bv_util.mk_numeral((m_util.fm().sgn(v_tn)) ? 1 : 0, 1); - s = m_bv_util.mk_numeral(m_util.fm().sig(v_tn), sbits - 1); + sig = m_bv_util.mk_numeral(m_util.fm().sig(v_tn), sbits - 1); unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v_tn), ebits); - mk_bias(unbiased_exp, e); - mk_fp(sgn, e, s, v4); + mk_bias(unbiased_exp, exp); + mk_fp(sgn, exp, sig, v4); sgn = m_bv_util.mk_numeral((m_util.fm().sgn(v_tp)) ? 1 : 0, 1); - s = m_bv_util.mk_numeral(m_util.fm().sig(v_tp), sbits - 1); + sig = m_bv_util.mk_numeral(m_util.fm().sig(v_tp), sbits - 1); unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v_tp), ebits); - mk_bias(unbiased_exp, e); + mk_bias(unbiased_exp, exp); - mk_fp(sgn, e, s, result); + mk_fp(sgn, exp, sig, result); mk_ite(rm_tn, v4, result, result); mk_ite(rm_tp, v3, result, result); mk_ite(rm_nte, v2, result, result); @@ -3350,7 +3348,7 @@ void fpa2bv_converter::unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref // the maximum shift is `sbits', because after that the mantissa // would be zero anyways. So we can safely cut the shift variable down, // as long as we check the higher bits. - expr_ref sh(m), is_sh_zero(m), sl(m), zero_s(m), sbits_s(m), short_shift(m); + expr_ref sh(m), is_sh_zero(m), sl(m), sbits_s(m), short_shift(m); zero_s = m_bv_util.mk_numeral(0, sbits-1); sbits_s = m_bv_util.mk_numeral(sbits, sbits); sh = m_bv_util.mk_extract(ebits-1, sbits, shift); diff --git a/src/ast/func_decl_dependencies.cpp b/src/ast/func_decl_dependencies.cpp index 162efb0dd..76f1e3889 100644 --- a/src/ast/func_decl_dependencies.cpp +++ b/src/ast/func_decl_dependencies.cpp @@ -145,24 +145,24 @@ class func_decl_dependencies::top_sort { return false; m_todo.push_back(f); while (!m_todo.empty()) { - func_decl * f = m_todo.back(); + func_decl * cf = m_todo.back(); - switch (get_color(f)) { + switch (get_color(cf)) { case CLOSED: m_todo.pop_back(); break; case OPEN: - set_color(f, IN_PROGRESS); - if (visit_children(f)) { + set_color(cf, IN_PROGRESS); + if (visit_children(cf)) { SASSERT(m_todo.back() == f); m_todo.pop_back(); - set_color(f, CLOSED); + set_color(cf, CLOSED); } break; case IN_PROGRESS: - if (all_children_closed(f)) { - SASSERT(m_todo.back() == f); - set_color(f, CLOSED); + if (all_children_closed(cf)) { + SASSERT(m_todo.back() == cf); + set_color(cf, CLOSED); } else { m_todo.reset(); return true; diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h index e97933921..9284ff420 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h +++ b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h @@ -464,18 +464,18 @@ void bit_blaster_tpl::mk_udiv_urem(unsigned sz, expr * const * a_bits, expr // update p if (i < sz - 1) { for (unsigned j = sz - 1; j > 0; j--) { - expr_ref i(m()); - mk_ite(q, t.get(j-1), p.get(j-1), i); - p.set(j, i); + expr_ref ie(m()); + mk_ite(q, t.get(j-1), p.get(j-1), ie); + p.set(j, ie); } p.set(0, a_bits[sz - i - 2]); } else { // last step: p contains the remainder for (unsigned j = 0; j < sz; j++) { - expr_ref i(m()); - mk_ite(q, t.get(j), p.get(j), i); - p.set(j, i); + expr_ref ie(m()); + mk_ite(q, t.get(j), p.get(j), ie); + p.set(j, ie); } } } diff --git a/src/ast/rewriter/rewriter_def.h b/src/ast/rewriter/rewriter_def.h index 92f06679d..be3bfbd0a 100644 --- a/src/ast/rewriter/rewriter_def.h +++ b/src/ast/rewriter/rewriter_def.h @@ -324,7 +324,7 @@ void rewriter_tpl::process_app(app * t, frame & fr) { } result_stack().push_back(def); TRACE("get_macro", tout << "bindings:\n"; - for (unsigned i = 0; i < m_bindings.size(); i++) tout << i << ": " << mk_ismt2_pp(m_bindings[i], m()) << "\n";); + for (unsigned j = 0; j < m_bindings.size(); j++) tout << j << ": " << mk_ismt2_pp(m_bindings[j], m()) << "\n";); begin_scope(); m_num_qvars = 0; m_root = def; diff --git a/src/ast/shared_occs.h b/src/ast/shared_occs.h index e135fea84..b522f4a4d 100644 --- a/src/ast/shared_occs.h +++ b/src/ast/shared_occs.h @@ -75,7 +75,7 @@ public: iterator end_shared() const { return m_shared.end(); } void reset(); void cleanup(); - void display(std::ostream & out, ast_manager & m) const; + void display(std::ostream & out, ast_manager & mgr) const; }; #endif diff --git a/src/tactic/arith/arith_bounds_tactic.cpp b/src/tactic/arith/arith_bounds_tactic.cpp index 0de507183..dc24a625b 100644 --- a/src/tactic/arith/arith_bounds_tactic.cpp +++ b/src/tactic/arith/arith_bounds_tactic.cpp @@ -34,8 +34,8 @@ struct arith_bounds_tactic : public tactic { bounds_arith_subsumption(in, result); } - virtual tactic* translate(ast_manager& m) { - return alloc(arith_bounds_tactic, m); + virtual tactic* translate(ast_manager & mgr) { + return alloc(arith_bounds_tactic, mgr); } void checkpoint() { diff --git a/src/tactic/tactical.cpp b/src/tactic/tactical.cpp index 9765bced5..149cbc272 100644 --- a/src/tactic/tactical.cpp +++ b/src/tactic/tactical.cpp @@ -709,8 +709,6 @@ public: tactic_ref_vector ts2; goal_ref_vector g_copies; - ast_manager & m = in->m(); - for (unsigned i = 0; i < r1_size; i++) { ast_manager * new_m = alloc(ast_manager, m, !m.proof_mode()); managers.push_back(new_m); From f8e2fa03379d752fc400376f312a5d8115e173fa Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 29 May 2015 11:11:13 -0700 Subject: [PATCH 865/925] fixes issue #93 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_array_full.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/smt/theory_array_full.cpp b/src/smt/theory_array_full.cpp index dd74f2871..f2d1527c0 100644 --- a/src/smt/theory_array_full.cpp +++ b/src/smt/theory_array_full.cpp @@ -775,17 +775,19 @@ namespace smt { bool theory_array_full::try_assign_eq(expr* v1, expr* v2) { + TRACE("array", + tout << mk_bounded_pp(v1, get_manager()) << "\n==\n" + << mk_bounded_pp(v2, get_manager()) << "\n";); context& ctx = get_context(); if (m_eqs.contains(v1, v2)) { return false; } - m_eqs.insert(v1, v2, true); - TRACE("array", - tout << mk_bounded_pp(v1, get_manager()) << "\n==\n" - << mk_bounded_pp(v2, get_manager()) << "\n";); - literal eq(mk_eq(v1, v2, true)); - m_eqsv.push_back(eq); - return true; + else { + m_eqs.insert(v1, v2, true); + literal eq(mk_eq(v1, v2, true)); + m_eqsv.push_back(eq); + return true; + } } void theory_array_full::pop_scope_eh(unsigned num_scopes) { From 894d6cb11b4be3750d32ca42218f8f379f7b9e25 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 29 May 2015 13:38:54 -0700 Subject: [PATCH 866/925] fix build break to support new statistics items Signed-off-by: Nikolaj Bjorner --- src/api/python/z3.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index 16d2eb6ba..6d0c5bad0 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -5617,7 +5617,7 @@ class Statistics: sat >>> st = s.statistics() >>> len(st) - 2 + 4 """ return int(Z3_stats_size(self.ctx.ref(), self.stats)) @@ -5631,7 +5631,7 @@ class Statistics: sat >>> st = s.statistics() >>> len(st) - 2 + 4 >>> st[0] ('nlsat propagations', 2) >>> st[1] @@ -5655,7 +5655,7 @@ class Statistics: sat >>> st = s.statistics() >>> st.keys() - ['nlsat propagations', 'nlsat stages'] + ['nlsat propagations', 'nlsat stages', 'max memory', 'memory'] """ return [Z3_stats_get_key(self.ctx.ref(), self.stats, idx) for idx in range(len(self))] @@ -5692,7 +5692,7 @@ class Statistics: sat >>> st = s.statistics() >>> st.keys() - ['nlsat propagations', 'nlsat stages'] + ['nlsat propagations', 'nlsat stages', 'max memory', 'memory'] >>> st.nlsat_propagations 2 >>> st.nlsat_stages From 2d409c6042318e74d6d1b8adfc5c36225b53a691 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 29 May 2015 14:32:24 -0700 Subject: [PATCH 867/925] revert bug introduced to avoid stack overflow in arrays Signed-off-by: Nikolaj Bjorner --- src/smt/theory_array_full.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_array_full.cpp b/src/smt/theory_array_full.cpp index f2d1527c0..4e169a8be 100644 --- a/src/smt/theory_array_full.cpp +++ b/src/smt/theory_array_full.cpp @@ -785,7 +785,10 @@ namespace smt { else { m_eqs.insert(v1, v2, true); literal eq(mk_eq(v1, v2, true)); - m_eqsv.push_back(eq); + get_context().mark_as_relevant(eq); + assert_axiom(eq); + + // m_eqsv.push_back(eq); return true; } } From e240e6c4300aad2b6cd64bef92cf9d8e165b5bfb Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 30 May 2015 12:12:23 +0100 Subject: [PATCH 868/925] Bugfix for variable renamings (fec815b41ef66c5dc28a04aeabd933fca59e4d37) --- src/ast/func_decl_dependencies.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/func_decl_dependencies.cpp b/src/ast/func_decl_dependencies.cpp index 76f1e3889..d53c2d9b1 100644 --- a/src/ast/func_decl_dependencies.cpp +++ b/src/ast/func_decl_dependencies.cpp @@ -154,7 +154,7 @@ class func_decl_dependencies::top_sort { case OPEN: set_color(cf, IN_PROGRESS); if (visit_children(cf)) { - SASSERT(m_todo.back() == f); + SASSERT(m_todo.back() == cf); m_todo.pop_back(); set_color(cf, CLOSED); } From fde873ac09c0e183b28d9b27809ec05a416467e4 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 30 May 2015 14:50:15 +0100 Subject: [PATCH 869/925] Bugfix for rounding in FP to_sbv. Fixes #113 --- src/ast/fpa/fpa2bv_converter.cpp | 50 ++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 75e8dfd99..ef11a4f1e 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -2953,9 +2953,8 @@ void fpa2bv_converter::mk_to_sbv(func_decl * f, unsigned num, expr * const * arg shift_abs = m.mk_ite(m_bv_util.mk_sle(shift, bv0_e2), shift_neg, shift); SASSERT(m_bv_util.get_bv_size(shift) == ebits + 2); SASSERT(m_bv_util.get_bv_size(shift_neg) == ebits + 2); - SASSERT(m_bv_util.get_bv_size(shift_abs) == ebits + 2); - dbg_decouple("fpa2bv_to_sbv_shift", shift); - dbg_decouple("fpa2bv_to_sbv_shift_abs", shift_abs); + SASSERT(m_bv_util.get_bv_size(shift_abs) == ebits + 2); + dbg_decouple("fpa2bv_to_sbv_shift", shift); // sig is of the form +- [1].[sig][r][g][s] ... and at least bv_sz + 3 long // [1][ ... sig ... ][r][g][ ... s ...] @@ -2964,34 +2963,48 @@ void fpa2bv_converter::mk_to_sbv(func_decl * f, unsigned num, expr * const * arg max_shift = m_bv_util.mk_numeral(sig_sz, sig_sz); shift_abs = m_bv_util.mk_zero_extend(sig_sz - ebits - 2, shift_abs); SASSERT(m_bv_util.get_bv_size(shift_abs) == sig_sz); + dbg_decouple("fpa2bv_to_sbv_shift_abs", shift_abs); expr_ref c_in_limits(m); c_in_limits = m_bv_util.mk_sle(shift, m_bv_util.mk_numeral(0, ebits + 2)); dbg_decouple("fpa2bv_to_sbv_in_limits", c_in_limits); - expr_ref shifted_sig(m); - shifted_sig = m_bv_util.mk_bv_lshr(sig, shift_abs); - dbg_decouple("fpa2bv_to_sbv_shifted_sig", shifted_sig); + expr_ref huge_sig(m), huge_shift(m), huge_shifted_sig(m); + huge_sig = m_bv_util.mk_concat(sig, m_bv_util.mk_numeral(0, sig_sz)); + huge_shift = m_bv_util.mk_concat(m_bv_util.mk_numeral(0, sig_sz), shift_abs); + huge_shifted_sig = m_bv_util.mk_bv_lshr(huge_sig, huge_shift); + dbg_decouple("fpa2bv_to_sbv_huge_shifted_sig", huge_shifted_sig); + SASSERT(m_bv_util.get_bv_size(huge_shifted_sig) == 2 * sig_sz); + + expr_ref upper_hss(m), lower_hss(m); + upper_hss = m_bv_util.mk_extract(2 * sig_sz - 1, sig_sz + 1, huge_shifted_sig); + lower_hss = m_bv_util.mk_extract(sig_sz, 0, huge_shifted_sig); + SASSERT(m_bv_util.get_bv_size(upper_hss) == sig_sz - 1); + SASSERT(m_bv_util.get_bv_size(lower_hss) == sig_sz + 1); + dbg_decouple("fpa2bv_to_sbv_upper_hss", upper_hss); + dbg_decouple("fpa2bv_to_sbv_lower_hss", lower_hss); expr_ref last(m), round(m), sticky(m); - last = m_bv_util.mk_extract(sig_sz - bv_sz - 0, sig_sz - bv_sz - 0, shifted_sig); - round = m_bv_util.mk_extract(sig_sz - bv_sz - 1, sig_sz - bv_sz - 1, shifted_sig); - sticky = m.mk_ite(m.mk_eq(m_bv_util.mk_extract(sig_sz - bv_sz - 2, 0, shifted_sig), - m_bv_util.mk_numeral(0, sig_sz - (bv_sz + 3) + 2)), - bv0, - bv1); + last = m_bv_util.mk_extract(1, 1, upper_hss); + round = m_bv_util.mk_extract(0, 0, upper_hss); + sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, lower_hss); dbg_decouple("fpa2bv_to_sbv_last", last); dbg_decouple("fpa2bv_to_sbv_round", round); dbg_decouple("fpa2bv_to_sbv_sticky", sticky); + expr_ref upper_hss_w_sticky(m); + upper_hss_w_sticky = m_bv_util.mk_concat(upper_hss, sticky); + dbg_decouple("fpa2bv_to_sbv_upper_hss_w_sticky", upper_hss_w_sticky); + SASSERT(m_bv_util.get_bv_size(upper_hss_w_sticky) == sig_sz); + expr_ref rounding_decision(m); rounding_decision = mk_rounding_decision(rm, sgn, last, round, sticky); SASSERT(m_bv_util.get_bv_size(rounding_decision) == 1); dbg_decouple("fpa2bv_to_sbv_rounding_decision", rounding_decision); expr_ref unrounded_sig(m), pre_rounded(m), inc(m); - unrounded_sig = m_bv_util.mk_zero_extend(1, m_bv_util.mk_extract(sig_sz - 1, sig_sz - bv_sz, shifted_sig)); - inc = m_bv_util.mk_zero_extend(1, m_bv_util.mk_zero_extend(bv_sz - 1, rounding_decision)); + unrounded_sig = m_bv_util.mk_extract(sig_sz - 1, sig_sz - bv_sz - 1, upper_hss_w_sticky); + inc = m_bv_util.mk_zero_extend(bv_sz, rounding_decision); pre_rounded = m_bv_util.mk_bv_add(unrounded_sig, inc); dbg_decouple("fpa2bv_to_sbv_inc", inc); dbg_decouple("fpa2bv_to_sbv_unrounded_sig", unrounded_sig); @@ -3399,7 +3412,7 @@ void fpa2bv_converter::mk_rounding_mode(func_decl * f, expr_ref & result) void fpa2bv_converter::dbg_decouple(const char * prefix, expr_ref & e) { #ifdef Z3DEBUG - return; + // return; // CMW: This works only for quantifier-free formulas. expr_ref new_e(m); new_e = m.mk_fresh_const(prefix, m.get_sort(e)); @@ -3409,6 +3422,12 @@ void fpa2bv_converter::dbg_decouple(const char * prefix, expr_ref & e) { } expr_ref fpa2bv_converter::mk_rounding_decision(expr * rm, expr * sgn, expr * last, expr * round, expr * sticky) { + dbg_decouple("fpa2bv_rnd_dec_rm", expr_ref(rm, m)); + dbg_decouple("fpa2bv_rnd_dec_sgn", expr_ref(sgn, m)); + dbg_decouple("fpa2bv_rnd_dec_last", expr_ref(last, m)); + dbg_decouple("fpa2bv_rnd_dec_round", expr_ref(round, m)); + dbg_decouple("fpa2bv_rnd_dec_sticky", expr_ref(sticky, m)); + expr_ref last_or_sticky(m), round_or_sticky(m), not_last(m), not_round(m), not_sticky(m), not_lors(m), not_rors(m), not_sgn(m); expr * last_sticky[2] = { last, sticky }; expr * round_sticky[2] = { round, sticky }; @@ -3446,6 +3465,7 @@ expr_ref fpa2bv_converter::mk_rounding_decision(expr * rm, expr * sgn, expr * la m_simp.mk_ite(rm_is_away, inc_taway, inc_c3, inc_c2); m_simp.mk_ite(rm_is_even, inc_teven, inc_c2, res); + dbg_decouple("fpa2bv_rnd_dec_res", res); return res; } From 5ae2dd9c747946535f1f05771161b19d0e03ccf6 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 30 May 2015 15:20:07 +0100 Subject: [PATCH 870/925] Bugfix for QF_FP default tactic. --- src/tactic/fpa/qffp_tactic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tactic/fpa/qffp_tactic.cpp b/src/tactic/fpa/qffp_tactic.cpp index 3bee224b3..fbce1668e 100644 --- a/src/tactic/fpa/qffp_tactic.cpp +++ b/src/tactic/fpa/qffp_tactic.cpp @@ -45,7 +45,7 @@ struct has_fp_to_real_predicate { void operator()(app * n) { sort * s = get_sort(n); if (au.is_real(s) && n->get_family_id() == fu.get_family_id() && - is_app(n) && to_app(n)->get_kind() == OP_FPA_TO_REAL) + is_app(n) && to_app(n)->get_decl_kind() == OP_FPA_TO_REAL) throw found(); } }; From 8d55159dc85a6d353c0f5d5b8ec45de04c73cded Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 30 May 2015 15:23:30 +0100 Subject: [PATCH 871/925] Proper declaration of locals to make clang happy. --- src/ast/fpa/fpa2bv_converter.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index ef11a4f1e..11c6f8bf6 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -2987,7 +2987,7 @@ void fpa2bv_converter::mk_to_sbv(func_decl * f, unsigned num, expr * const * arg expr_ref last(m), round(m), sticky(m); last = m_bv_util.mk_extract(1, 1, upper_hss); round = m_bv_util.mk_extract(0, 0, upper_hss); - sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, lower_hss); + sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, lower_hss.get()); dbg_decouple("fpa2bv_to_sbv_last", last); dbg_decouple("fpa2bv_to_sbv_round", round); dbg_decouple("fpa2bv_to_sbv_sticky", sticky); @@ -3412,7 +3412,7 @@ void fpa2bv_converter::mk_rounding_mode(func_decl * f, expr_ref & result) void fpa2bv_converter::dbg_decouple(const char * prefix, expr_ref & e) { #ifdef Z3DEBUG - // return; + return; // CMW: This works only for quantifier-free formulas. expr_ref new_e(m); new_e = m.mk_fresh_const(prefix, m.get_sort(e)); @@ -3422,11 +3422,16 @@ void fpa2bv_converter::dbg_decouple(const char * prefix, expr_ref & e) { } expr_ref fpa2bv_converter::mk_rounding_decision(expr * rm, expr * sgn, expr * last, expr * round, expr * sticky) { - dbg_decouple("fpa2bv_rnd_dec_rm", expr_ref(rm, m)); - dbg_decouple("fpa2bv_rnd_dec_sgn", expr_ref(sgn, m)); - dbg_decouple("fpa2bv_rnd_dec_last", expr_ref(last, m)); - dbg_decouple("fpa2bv_rnd_dec_round", expr_ref(round, m)); - dbg_decouple("fpa2bv_rnd_dec_sticky", expr_ref(sticky, m)); + expr_ref rmr(rm, m); + expr_ref sgnr(sgn, m); + expr_ref lastr(last, m); + expr_ref roundr(round, m); + expr_ref stickyr(sticky, m); + dbg_decouple("fpa2bv_rnd_dec_rm", rmr); + dbg_decouple("fpa2bv_rnd_dec_sgn", sgnr); + dbg_decouple("fpa2bv_rnd_dec_last", lastr); + dbg_decouple("fpa2bv_rnd_dec_round", roundr); + dbg_decouple("fpa2bv_rnd_dec_sticky", stickyr); expr_ref last_or_sticky(m), round_or_sticky(m), not_last(m), not_round(m), not_sticky(m), not_lors(m), not_rors(m), not_sgn(m); expr * last_sticky[2] = { last, sticky }; From 6f42cbd325f6d9474d58720e3d7e7d5e84c3fc4b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 1 Jun 2015 09:22:19 -0700 Subject: [PATCH 872/925] remove std-out Signed-off-by: Nikolaj Bjorner --- src/muz/base/rule_properties.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/muz/base/rule_properties.cpp b/src/muz/base/rule_properties.cpp index 5d1aff44e..455e02e45 100644 --- a/src/muz/base/rule_properties.cpp +++ b/src/muz/base/rule_properties.cpp @@ -194,7 +194,6 @@ void rule_properties::operator()(app* n) { } } else { - std::cout << mk_pp(n, m) << "\n"; } } From 46a5aeaef1c0ed393c4595b72fb7805ff3056585 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 1 Jun 2015 14:10:22 -0700 Subject: [PATCH 873/925] improve type checking and reporting, fixes issue #116 Signed-off-by: Nikolaj Bjorner --- src/ast/bv_decl_plugin.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/ast/bv_decl_plugin.cpp b/src/ast/bv_decl_plugin.cpp index b056ded36..37b339ddb 100644 --- a/src/ast/bv_decl_plugin.cpp +++ b/src/ast/bv_decl_plugin.cpp @@ -594,6 +594,18 @@ func_decl * bv_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p } func_decl * r = mk_func_decl(k, bv_size); if (r != 0) { + if (num_args != r->get_arity()) { + m.raise_exception("declared arity mismatches supplied arity"); + return 0; + } + for (unsigned i = 0; i < num_args; ++i) { + if (m.get_sort(args[i]) != r->get_domain(i)) { + std::ostringstream buffer; + buffer << "Argument " << mk_pp(args[i], m) << " at position " << i << " does not match declaration " << mk_pp(r, m); + m.raise_exception(buffer.str().c_str()); + return 0; + } + } return r; } return decl_plugin::mk_func_decl(k, num_parameters, parameters, num_args, args, range); From d4dd608badd15221cd95da57ddc044f19e239fab Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 1 Jun 2015 14:11:31 -0700 Subject: [PATCH 874/925] improve type checking and reporting, fixes issue #116 Signed-off-by: Nikolaj Bjorner --- src/ast/bv_decl_plugin.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ast/bv_decl_plugin.cpp b/src/ast/bv_decl_plugin.cpp index 37b339ddb..d01b8371b 100644 --- a/src/ast/bv_decl_plugin.cpp +++ b/src/ast/bv_decl_plugin.cpp @@ -566,6 +566,7 @@ func_decl * bv_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p func_decl * bv_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned num_args, expr * const * args, sort * range) { + ast_manager& m = *m_manager; int bv_size; if (k == OP_INT2BV && get_int2bv_size(num_parameters, parameters, bv_size)) { // bv_size is filled in. @@ -589,7 +590,7 @@ func_decl * bv_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p return decl_plugin::mk_func_decl(k, num_parameters, parameters, num_args, args, range); } else if (num_args == 0 || !get_bv_size(args[0], bv_size)) { - m_manager->raise_exception("operator is applied to arguments of the wrong sort"); + m.raise_exception("operator is applied to arguments of the wrong sort"); return 0; } func_decl * r = mk_func_decl(k, bv_size); From aee18130568812d06f3a02e8aa075eb540fc803a Mon Sep 17 00:00:00 2001 From: Matthias Schlaipfer Date: Tue, 2 Jun 2015 09:49:08 +0100 Subject: [PATCH 875/925] Added missing input format option "-dl" Signed-off-by: Matthias Schlaipfer --- src/shell/main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/shell/main.cpp b/src/shell/main.cpp index 5a47d0d16..609f5d47b 100644 --- a/src/shell/main.cpp +++ b/src/shell/main.cpp @@ -163,6 +163,9 @@ void parse_cmd_line_args(int argc, char ** argv) { else if (strcmp(opt_name, "smt2") == 0) { g_input_kind = IN_SMTLIB_2; } + else if (strcmp(opt_name, "dl") == 0) { + g_input_kind = IN_DATALOG; + } else if (strcmp(opt_name, "in") == 0) { g_standard_input = true; } From d6398c4fdc7eb625c3d20f709fc3691d14214b1a Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 2 Jun 2015 11:59:55 +0100 Subject: [PATCH 876/925] Fixed FPA Python doctest --- src/api/python/z3.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index 6d0c5bad0..9ac9da3e8 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -8194,21 +8194,21 @@ def FP(name, fpsort, ctx=None): >>> eq(x, x2) True """ - ctx = fpsort.ctx + if isinstance(fpsort, FPSortRef): + ctx = fpsort.ctx + else: + ctx = _get_ctx(ctx) return FPRef(Z3_mk_const(ctx.ref(), to_symbol(name, ctx), fpsort.ast), ctx) def FPs(names, fpsort, ctx=None): """Return an array of floating-point constants. - >>> x, y, z = BitVecs('x y z', 16) - >>> x.size() - 16 + >>> x, y, z = FPs('x y z', FPSort(8, 24)) >>> x.sort() - BitVec(16) - >>> Sum(x, y, z) - 0 + x + y + z - >>> Product(x, y, z) - 1*x*y*z + >>> x.sbits() + 24 + >>> x.ebits() + 8 >>> simplify(Product(x, y, z)) x*y*z """ From c7fd74e8adc6be5eca0f153ddb781927f98210e0 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 2 Jun 2015 12:45:55 +0100 Subject: [PATCH 877/925] Fixed FPA Python doctest --- src/api/python/z3.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index 9ac9da3e8..f6a617317 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -8205,12 +8205,13 @@ def FPs(names, fpsort, ctx=None): >>> x, y, z = FPs('x y z', FPSort(8, 24)) >>> x.sort() + FPSort(8, 24) >>> x.sbits() 24 >>> x.ebits() 8 - >>> simplify(Product(x, y, z)) - x*y*z + >>> fpMul(RNE(), fpAdd(RNE(), x, y), z) + fpMul(RNE(), fpAdd(RNE(), x, y), z) """ ctx = z3._get_ctx(ctx) if isinstance(names, str): From 17c06199a89ae28ec605d7d47e6274a4c43da0da Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 2 Jun 2015 12:46:30 +0100 Subject: [PATCH 878/925] Relaxed BV type checking, follow up to issue #116 --- src/ast/bv_decl_plugin.cpp | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/ast/bv_decl_plugin.cpp b/src/ast/bv_decl_plugin.cpp index d01b8371b..f65462d1b 100644 --- a/src/ast/bv_decl_plugin.cpp +++ b/src/ast/bv_decl_plugin.cpp @@ -501,13 +501,17 @@ func_decl * bv_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p func_decl * r = mk_func_decl(k, bv_size); if (r != 0) { if (arity != r->get_arity()) { - m_manager->raise_exception("declared arity mismatches supplied arity"); - return 0; + if (r->get_info()->is_associative()) + arity = r->get_arity(); + else { + m_manager->raise_exception("declared arity mismatches supplied arity"); + return 0; + } } for (unsigned i = 0; i < arity; ++i) { if (domain[i] != r->get_domain(i)) { m_manager->raise_exception("declared sorts do not match supplied sorts"); - return 0; + return 0; } } return r; @@ -596,15 +600,27 @@ func_decl * bv_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p func_decl * r = mk_func_decl(k, bv_size); if (r != 0) { if (num_args != r->get_arity()) { - m.raise_exception("declared arity mismatches supplied arity"); - return 0; + if (r->get_info()->is_associative()) { + sort * fs = r->get_domain(0); + for (unsigned i = 0; i < num_args; ++i) { + if (m.get_sort(args[i]) != fs) { + m_manager->raise_exception("declared sorts do not match supplied sorts"); + return 0; + } + } + return r; + } + else { + m.raise_exception("declared arity mismatches supplied arity"); + return 0; + } } for (unsigned i = 0; i < num_args; ++i) { if (m.get_sort(args[i]) != r->get_domain(i)) { std::ostringstream buffer; buffer << "Argument " << mk_pp(args[i], m) << " at position " << i << " does not match declaration " << mk_pp(r, m); m.raise_exception(buffer.str().c_str()); - return 0; + return 0; } } return r; From bc94007207e62a5e56c8660263d50552c880ab92 Mon Sep 17 00:00:00 2001 From: Matthias Schlaipfer Date: Tue, 2 Jun 2015 14:58:31 +0100 Subject: [PATCH 879/925] Fixed non-deterministic behaviour in relation_map Use of ptr_hash and subsequent iteration led to non-deterministic behaviour in Datalog engine. Signed-off-by: Matthias Schlaipfer --- src/muz/rel/dl_relation_manager.cpp | 2 +- src/muz/rel/dl_relation_manager.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/muz/rel/dl_relation_manager.cpp b/src/muz/rel/dl_relation_manager.cpp index b92c9f796..6a9bb7f2a 100644 --- a/src/muz/rel/dl_relation_manager.cpp +++ b/src/muz/rel/dl_relation_manager.cpp @@ -108,7 +108,7 @@ namespace datalog { void relation_manager::store_relation(func_decl * pred, relation_base * rel) { SASSERT(rel); - relation_map::entry * e = m_relations.insert_if_not_there2(pred, 0); + relation_map::obj_map_entry * e = m_relations.insert_if_not_there2(pred, 0); if (e->get_data().m_value) { e->get_data().m_value->deallocate(); } diff --git a/src/muz/rel/dl_relation_manager.h b/src/muz/rel/dl_relation_manager.h index 530538df5..53d7f21e2 100644 --- a/src/muz/rel/dl_relation_manager.h +++ b/src/muz/rel/dl_relation_manager.h @@ -73,7 +73,7 @@ namespace datalog { typedef map, ptr_eq > rp2fprp_map; - typedef map, ptr_eq > relation_map; + typedef obj_map relation_map; typedef ptr_vector table_plugin_vector; typedef ptr_vector relation_plugin_vector; From 7161d6c1503eea13e7bde7ae17333b0f5ddf1aaa Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 2 Jun 2015 08:48:37 -0700 Subject: [PATCH 880/925] fixes crash from issue #119 Signed-off-by: Nikolaj Bjorner --- src/tactic/arith/card2bv_tactic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tactic/arith/card2bv_tactic.cpp b/src/tactic/arith/card2bv_tactic.cpp index 933b687b4..7c715e6e7 100644 --- a/src/tactic/arith/card2bv_tactic.cpp +++ b/src/tactic/arith/card2bv_tactic.cpp @@ -488,7 +488,7 @@ public: unsigned size = g->size(); expr_ref new_f1(m), new_f2(m); proof_ref new_pr1(m), new_pr2(m); - for (unsigned idx = 0; idx < size; idx++) { + for (unsigned idx = 0; !g->inconsistent() && idx < g->size(); idx++) { m_rw1(g->form(idx), new_f1, new_pr1); TRACE("card2bv", tout << "Rewriting " << mk_ismt2_pp(new_f1.get(), m) << std::endl;); m_rw2.rewrite(new_f1, new_f2); From a07cba72bccf568486f0aaf701912222827a39d3 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 2 Jun 2015 17:15:07 +0100 Subject: [PATCH 881/925] eliminated unused variables --- src/tactic/fpa/fpa2bv_approx_tactic.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_approx_tactic.cpp b/src/tactic/fpa/fpa2bv_approx_tactic.cpp index 4670883e1..9d5873f12 100644 --- a/src/tactic/fpa/fpa2bv_approx_tactic.cpp +++ b/src/tactic/fpa/fpa2bv_approx_tactic.cpp @@ -147,7 +147,6 @@ class fpa2bv_approx_tactic: public tactic { while (to_traverse.size() > 0) { cur = to_app(to_traverse.front()); - mpf_rounding_mode rm; #ifdef Z3DEBUG std::cout<<"Analyze - traversing: "<::iterator itp = ranked_terms.begin(); itp != ranked_terms.end(); itp++) { From ffff006945611126334728fd0640f38a808da729 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 2 Jun 2015 09:15:08 -0700 Subject: [PATCH 882/925] remove old files Signed-off-by: Nikolaj Bjorner --- src/opt/opt_solver.cpp | 16 ++- src/opt/opt_solver.h | 2 +- src/qe/qe_mbp.h | 48 ------- src/qe/qsat.cpp | 281 ----------------------------------------- src/qe/qsat.h | 52 -------- 5 files changed, 10 insertions(+), 389 deletions(-) delete mode 100644 src/qe/qe_mbp.h delete mode 100644 src/qe/qsat.cpp delete mode 100644 src/qe/qsat.h diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index d505a9ffb..dcbbc3fae 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -42,7 +42,7 @@ namespace opt { m_context(mgr, m_params), m(mgr), m_fm(fm), - m_objective_sorts(m), + m_objective_terms(m), m_dump_benchmarks(false), m_first(true) { m_params.updt_params(p); @@ -213,11 +213,13 @@ namespace opt { } else { SASSERT(has_shared); - decrement_value(i, val); + decrement_value(i, val); } m_objective_values[i] = val; - TRACE("opt", { tout << val << "\n"; - tout << blocker << "\n"; + TRACE("opt", { + tout << "objective: " << mk_pp(m_objective_terms[i].get(), m) << "\n"; + tout << "maximal value: " << val << "\n"; + tout << "new condition: " << blocker << "\n"; model_smt2_pp(tout << "update model:\n", m, *m_models[i], 0); }); } @@ -240,7 +242,7 @@ namespace opt { TRACE("opt", tout << is_sat << "\n";); if (is_sat != l_true) { // cop-out approximation - if (arith_util(m).is_real(m_objective_sorts[i].get())) { + if (arith_util(m).is_real(m_objective_terms[i].get())) { val -= inf_eps(inf_rational(rational(0), true)); } else { @@ -304,7 +306,7 @@ namespace opt { smt::theory_var v = get_optimizer().add_objective(term); m_objective_vars.push_back(v); m_objective_values.push_back(inf_eps(rational(-1), inf_rational())); - m_objective_sorts.push_back(m.get_sort(term)); + m_objective_terms.push_back(term); m_valid_objectives.push_back(true); m_models.push_back(0); return v; @@ -363,7 +365,7 @@ namespace opt { void opt_solver::reset_objectives() { m_objective_vars.reset(); m_objective_values.reset(); - m_objective_sorts.reset(); + m_objective_terms.reset(); m_valid_objectives.reset(); } diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 19205ddd9..a18ad9540 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -76,7 +76,7 @@ namespace opt { svector m_objective_vars; vector m_objective_values; sref_vector m_models; - sort_ref_vector m_objective_sorts; + expr_ref_vector m_objective_terms; svector m_valid_objectives; bool m_dump_benchmarks; static unsigned m_dump_count; diff --git a/src/qe/qe_mbp.h b/src/qe/qe_mbp.h deleted file mode 100644 index 11bceef0b..000000000 --- a/src/qe/qe_mbp.h +++ /dev/null @@ -1,48 +0,0 @@ -/*++ -Copyright (c) 2015 Microsoft Corporation - -Module Name: - - qe_mbp.h - -Abstract: - - Model-based projection utilities - -Author: - - Nikolaj Bjorner (nbjorner) 2015-5-28 - -Revision History: - - ---*/ - -#ifndef __QE_MBP_H__ -#define __QE_MBP_H__ - -#include "ast.h" -#include "params.h" - -namespace qe { - class mbp { - class impl; - impl * m_impl; - public: - mbp(ast_manager& m); - - ~mbp(); - - /** - \brief - Apply model-based qe on constants provided as vector of variables. - Return the updated formula and updated set of variables that were not eliminated. - - */ - void operator()(app_ref_vector& vars, model_ref& mdl, expr_ref& fml); - - void set_cancel(bool f); - }; -} - -#endif diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp deleted file mode 100644 index 4c736bc31..000000000 --- a/src/qe/qsat.cpp +++ /dev/null @@ -1,281 +0,0 @@ -/*++ -Copyright (c) 2015 Microsoft Corporation - -Module Name: - - qsat.cpp - -Abstract: - - Quantifier Satisfiability Solver. - -Author: - - Nikolaj Bjorner (nbjorner) 2015-5-28 - -Revision History: - - ---*/ - -#include "qsat.h" -#include "smt_kernel.h" -#include "qe_mbp.h" -#include "smt_params.h" -#include "ast_util.h" - -using namespace qe; - -struct qdef_t { - expr_ref m_pred; - expr_ref m_expr; - expr_ref_vector m_vars; - bool m_is_forall; - qdef_t(expr_ref& p, expr_ref& e, expr_ref_vector const& vars, bool is_forall): - m_pred(p), - m_expr(e), - m_vars(vars), - m_is_forall(is_forall) {} -}; - -typedef vector qdefs_t; - -struct pdef_t { - expr_ref m_pred; - expr_ref m_atom; - pdef_t(expr_ref& p, expr* a): - m_pred(p), - m_atom(a, p.get_manager()) - {} -}; - -class qsat::impl { - ast_manager& m; - qe::mbp mbp; - smt_params m_smtp; - smt::kernel m_kernel; - expr_ref m_fml_pred; // predicate that encodes top-level formula - expr_ref_vector m_atoms; // predicates that encode atomic subformulas - - - lbool check_sat() { - // TBD main procedure goes here. - return l_undef; - } - - /** - \brief replace quantified sub-formulas by a predicate, introduce definitions for the predicate. - */ - void remove_quantifiers(expr_ref_vector& fmls, qdefs_t& defs) { - - } - - /** - \brief create propositional abstration of formula by replacing atomic sub-formulas by fresh - propositional variables, and adding definitions for each propositional formula on the side. - Assumption is that the formula is quantifier-free. - */ - void mk_abstract(expr_ref& fml, vector& pdefs) { - expr_ref_vector todo(m), trail(m); - obj_map cache; - ptr_vector args; - expr_ref r(m); - todo.push_back(fml); - while (!todo.empty()) { - expr* e = todo.back(); - if (cache.contains(e)) { - todo.pop_back(); - continue; - } - SASSERT(is_app(e)); - app* a = to_app(e); - if (a->get_family_id() == m.get_basic_family_id()) { - unsigned sz = a->get_num_args(); - args.reset(); - for (unsigned i = 0; i < sz; ++i) { - expr* f = a->get_arg(i); - if (cache.find(f, f)) { - args.push_back(f); - } - else { - todo.push_back(f); - } - } - if (args.size() == sz) { - r = m.mk_app(a->get_decl(), sz, args.c_ptr()); - cache.insert(e, r); - trail.push_back(r); - todo.pop_back(); - } - } - else if (is_uninterp_const(a)) { - cache.insert(e, e); - } - else { - // TBD: nested Booleans. - - r = m.mk_fresh_const("p",m.mk_bool_sort()); - trail.push_back(r); - cache.insert(e, r); - pdefs.push_back(pdef_t(r, e)); - } - } - fml = cache.find(fml); - } - - /** - \brief use dual propagation to minimize model. - */ - bool minimize_assignment(expr_ref_vector& assignment, expr* not_fml) { - bool result = false; - assignment.push_back(not_fml); - lbool res = m_kernel.check(assignment.size(), assignment.c_ptr()); - switch (res) { - case l_true: - UNREACHABLE(); - break; - case l_undef: - break; - case l_false: - result = true; - get_core(assignment, not_fml); - break; - } - return result; - } - - lbool check_sat(expr_ref_vector& assignment, expr* fml) { - assignment.push_back(fml); - lbool res = m_kernel.check(assignment.size(), assignment.c_ptr()); - switch (res) { - case l_true: { - model_ref mdl; - expr_ref tmp(m); - assignment.reset(); - m_kernel.get_model(mdl); - for (unsigned i = 0; i < m_atoms.size(); ++i) { - expr* p = m_atoms[i].get(); - if (mdl->eval(p, tmp)) { - if (m.is_true(tmp)) { - assignment.push_back(p); - } - else if (m.is_false(tmp)) { - assignment.push_back(m.mk_not(p)); - } - } - } - expr_ref not_fml = mk_not(fml); - if (!minimize_assignment(assignment, not_fml)) { - res = l_undef; - } - break; - } - case l_undef: - break; - case l_false: - get_core(assignment, fml); - break; - } - return res; - } - - void get_core(expr_ref_vector& core, expr* exclude) { - unsigned sz = m_kernel.get_unsat_core_size(); - core.reset(); - for (unsigned i = 0; i < sz; ++i) { - expr* e = m_kernel.get_unsat_core_expr(i); - if (e != exclude) { - core.push_back(e); - } - } - } - - expr_ref mk_not(expr* e) { - return expr_ref(::mk_not(m, e), m); - } - -public: - impl(ast_manager& m): - m(m), - mbp(m), - m_kernel(m, m_smtp), - m_fml_pred(m), - m_atoms(m) {} - - void updt_params(params_ref const & p) { - } - - void collect_param_descrs(param_descrs & r) { - } - - void operator()(/* in */ goal_ref const & in, - /* out */ goal_ref_buffer & result, - /* out */ model_converter_ref & mc, - /* out */ proof_converter_ref & pc, - /* out */ expr_dependency_ref & core) { - - } - - void collect_statistics(statistics & st) const { - - } - void reset_statistics() { - } - - void cleanup() { - } - - void set_logic(symbol const & l) { - } - - void set_progress_callback(progress_callback * callback) { - } - - tactic * translate(ast_manager & m) { - return 0; - } - -}; - -qsat::qsat(ast_manager& m) { - m_impl = alloc(impl, m); -} - -qsat::~qsat() { - dealloc(m_impl); -} - -void qsat::updt_params(params_ref const & p) { - m_impl->updt_params(p); -} -void qsat::collect_param_descrs(param_descrs & r) { - m_impl->collect_param_descrs(r); -} -void qsat::operator()(/* in */ goal_ref const & in, - /* out */ goal_ref_buffer & result, - /* out */ model_converter_ref & mc, - /* out */ proof_converter_ref & pc, - /* out */ expr_dependency_ref & core) { - (*m_impl)(in, result, mc, pc, core); -} - -void qsat::collect_statistics(statistics & st) const { - m_impl->collect_statistics(st); -} -void qsat::reset_statistics() { - m_impl->reset_statistics(); -} -void qsat::cleanup() { - m_impl->cleanup(); -} -void qsat::set_logic(symbol const & l) { - m_impl->set_logic(l); -} -void qsat::set_progress_callback(progress_callback * callback) { - m_impl->set_progress_callback(callback); -} -tactic * qsat::translate(ast_manager & m) { - return m_impl->translate(m); -} - - diff --git a/src/qe/qsat.h b/src/qe/qsat.h deleted file mode 100644 index 2fc071c76..000000000 --- a/src/qe/qsat.h +++ /dev/null @@ -1,52 +0,0 @@ -/*++ -Copyright (c) 2015 Microsoft Corporation - -Module Name: - - qsat.h - -Abstract: - - Quantifier Satisfiability Solver. - -Author: - - Nikolaj Bjorner (nbjorner) 2015-5-28 - -Revision History: - - ---*/ - -#ifndef __QE_QSAT_H__ -#define __QE_QSAT_H__ - -#include "tactic.h" - -namespace qe { - class qsat : public tactic { - class impl; - impl * m_impl; - public: - qsat(ast_manager& m); - ~qsat(); - - virtual void updt_params(params_ref const & p); - virtual void collect_param_descrs(param_descrs & r); - virtual void operator()(/* in */ goal_ref const & in, - /* out */ goal_ref_buffer & result, - /* out */ model_converter_ref & mc, - /* out */ proof_converter_ref & pc, - /* out */ expr_dependency_ref & core); - - virtual void collect_statistics(statistics & st) const; - virtual void reset_statistics(); - virtual void cleanup() = 0; - virtual void set_logic(symbol const & l); - virtual void set_progress_callback(progress_callback * callback); - virtual tactic * translate(ast_manager & m); - - }; -}; - -#endif From 65a6845945670c01b420e3eb2bece65ce9a03a66 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 2 Jun 2015 17:19:31 +0100 Subject: [PATCH 883/925] Bugfix for fpa2bv_converter_prec --- src/tactic/fpa/fpa2bv_converter_prec.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_converter_prec.cpp b/src/tactic/fpa/fpa2bv_converter_prec.cpp index ff627f7e4..b60a58968 100644 --- a/src/tactic/fpa/fpa2bv_converter_prec.cpp +++ b/src/tactic/fpa/fpa2bv_converter_prec.cpp @@ -35,8 +35,8 @@ fpa2bv_converter_prec::fpa2bv_converter_prec(ast_manager & m, fpa_approximation_ void fpa2bv_converter_prec::fix_bits(unsigned prec, expr_ref rounded, unsigned sbits, unsigned ebits)//expr_ref& fixed, { //AZ: TODO: revise! minimal number of legal bits is 3!!!! Remove magic numbers - unsigned szeroes=((sbits-2)*(MAX_PRECISION - prec +0.0)/MAX_PRECISION);//3 bits are minimum for the significand - unsigned ezeroes=((ebits-2)*(MAX_PRECISION - prec+0.0)/MAX_PRECISION);//2 bits are minimum for the exponent + unsigned szeroes = (unsigned) ((sbits-2)*(MAX_PRECISION - prec +0.0) / MAX_PRECISION);//3 bits are minimum for the significand + unsigned ezeroes = (unsigned) ((ebits - 2)*(MAX_PRECISION - prec + 0.0) / MAX_PRECISION);//2 bits are minimum for the exponent expr_ref fix_sig(m), fix_exp(m); expr * sgn, *sig, *expn; @@ -226,8 +226,8 @@ void fpa2bv_converter_prec::mk_cast_small_to_big(unsigned sbits, unsigned ebits, void fpa2bv_converter_prec::match_sorts(expr * a, expr * b, expr_ref & n_a, expr_ref & n_b) { //Check if the sorts of lhs and rhs match, otherwise cast them to appropriate size? - SASSERT(is_app_of(a, m_plugin->get_family_id(), OP_FPA_TO_FP)); - SASSERT(is_app_of(b, m_plugin->get_family_id(), OP_FPA_TO_FP)); + SASSERT(is_app_of(a, m_plugin->get_family_id(), OP_FPA_FP)); + SASSERT(is_app_of(b, m_plugin->get_family_id(), OP_FPA_FP)); func_decl * a_decl = to_app(a)->get_decl(); func_decl * b_decl = to_app(b)->get_decl(); From 610c549104770d4c9cecb1bc5b23d6c3ea424865 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 2 Jun 2015 18:17:49 +0100 Subject: [PATCH 884/925] fpa2bv_approx: added fp.abs, fixed rounding mode model extraction --- src/tactic/fpa/fpa2bv_approx_tactic.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/tactic/fpa/fpa2bv_approx_tactic.cpp b/src/tactic/fpa/fpa2bv_approx_tactic.cpp index 9d5873f12..bc0b5d39a 100644 --- a/src/tactic/fpa/fpa2bv_approx_tactic.cpp +++ b/src/tactic/fpa/fpa2bv_approx_tactic.cpp @@ -272,8 +272,12 @@ class fpa2bv_approx_tactic: public tactic { expr_ref arg_e[] = { expr_ref(m), expr_ref(m), expr_ref(m), expr_ref(m) }; unsigned i=0; //Set rounding mode - if (rhs->get_num_args() > 0 && m_float_util.is_rm(rhs->get_arg(0))) + if (rhs->get_num_args() > 0 && m_float_util.is_rm(rhs->get_arg(0))) { + expr_ref rm_val(m); + mdl->eval(rhs->get_arg(0), rm_val, true); + m_float_util.is_rm_numeral(rm_val, rm); i = 1; + } //Collect argument values for (; i < rhs->get_num_args(); i++) { expr * arg = rhs->get_arg(i); @@ -372,6 +376,11 @@ class fpa2bv_approx_tactic: public tactic { mpf_mngr.set(est_rhs_value, ebits, sbits, rm, est_arg_val[1]); break; } + case OP_FPA_ABS: + { + mpf_mngr.abs(arg_val[0], rhs_value); + break; + } default: NOT_IMPLEMENTED_YET(); break; From a7b12e6321d7f511e0940a31ae1e08995980884d Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 2 Jun 2015 18:31:09 +0100 Subject: [PATCH 885/925] Bugfix for fp.fma with sbits <= 3 --- src/ast/fpa/fpa2bv_converter.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 11c6f8bf6..ca6aa4858 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -1403,9 +1403,19 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args, expr * res_sgn_or_args[3] = { res_sgn_c1, res_sgn_c2, res_sgn_c3 }; res_sgn = m_bv_util.mk_bv_or(3, res_sgn_or_args); - sticky_raw = m_bv_util.mk_extract(sbits-5, 0, sig_abs); - sticky = m_bv_util.mk_zero_extend(sbits+3, m.mk_app(bvfid, OP_BREDOR, sticky_raw.get())); + if (sbits > 5) { + sticky_raw = m_bv_util.mk_extract(sbits - 5, 0, sig_abs); + sticky = m_bv_util.mk_zero_extend(sbits + 3, m.mk_app(bvfid, OP_BREDOR, sticky_raw.get())); + expr * res_or_args[2] = { m_bv_util.mk_extract(2 * sbits - 1, sbits - 4, sig_abs), sticky }; + res_sig = m_bv_util.mk_bv_or(2, res_or_args); + } + else { + unsigned too_short = 6 - sbits; + sig_abs = m_bv_util.mk_concat(sig_abs, m_bv_util.mk_numeral(0, too_short)); + res_sig = m_bv_util.mk_extract(sbits + 3, 0, sig_abs); + } dbg_decouple("fpa2bv_fma_add_sum_sticky", sticky); + SASSERT(m_bv_util.get_bv_size(res_sig) == sbits + 4); expr * res_or_args[2] = { m_bv_util.mk_extract(2*sbits-1, sbits-4, sig_abs), sticky }; res_sig = m_bv_util.mk_bv_or(2, res_or_args); From 81218c098343a13a561a6c1ad54c4213cdea6253 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 2 Jun 2015 18:36:19 +0100 Subject: [PATCH 886/925] Bugfix for fp.fma --- src/ast/fpa/fpa2bv_converter.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index ca6aa4858..13f406aeb 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -1417,10 +1417,6 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args, dbg_decouple("fpa2bv_fma_add_sum_sticky", sticky); SASSERT(m_bv_util.get_bv_size(res_sig) == sbits + 4); - expr * res_or_args[2] = { m_bv_util.mk_extract(2*sbits-1, sbits-4, sig_abs), sticky }; - res_sig = m_bv_util.mk_bv_or(2, res_or_args); - SASSERT(m_bv_util.get_bv_size(res_sig) == sbits+4); - expr_ref is_zero_sig(m), nil_sbits4(m); nil_sbits4 = m_bv_util.mk_numeral(0, sbits+4); m_simp.mk_eq(res_sig, nil_sbits4, is_zero_sig); From d06207f072c4989cde037b40cdd420249451507a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 2 Jun 2015 10:38:22 -0700 Subject: [PATCH 887/925] remove ite terms from objectives to synchronize values in tableau with objective value. Fixes part of (three repros) from issue #120 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 7 +++++-- src/opt/optsmt.cpp | 3 +++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index bf8a9dd7f..6fb4ef542 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -31,6 +31,7 @@ Notes: #include "propagate_values_tactic.h" #include "solve_eqs_tactic.h" #include "elim_uncnstr_tactic.h" +#include "elim_term_ite_tactic.h" #include "tactical.h" #include "model_smt2_pp.h" #include "card2bv_tactic.h" @@ -650,17 +651,19 @@ namespace opt { and_then(mk_simplify_tactic(m), mk_propagate_values_tactic(m), mk_solve_eqs_tactic(m), + mk_elim_term_ite_tactic(m), // NB: mk_elim_uncstr_tactic(m) is not sound with soft constraints mk_simplify_tactic(m)); opt_params optp(m_params); - tactic_ref tac2, tac3; + tactic_ref tac2, tac3, tac4; if (optp.elim_01()) { tac2 = mk_elim01_tactic(m); tac3 = mk_lia2card_tactic(m); + tac4 = mk_elim_term_ite_tactic(m); params_ref lia_p; lia_p.set_bool("compile_equality", optp.pb_compile_equality()); tac3->updt_params(lia_p); - set_simplify(and_then(tac0.get(), tac2.get(), tac3.get())); + set_simplify(and_then(tac0.get(), tac2.get(), tac3.get(), tac4.get())); } else { set_simplify(tac0.get()); diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 6b061f9cd..02effa337 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -141,6 +141,7 @@ namespace opt { ors.push_back(m_s->mk_ge(i, m_upper[i])); } + fml = m.mk_or(ors.size(), ors.c_ptr()); tmp = m.mk_fresh_const("b", m.mk_bool_sort()); fml = m.mk_implies(tmp, fml); @@ -150,6 +151,7 @@ namespace opt { solver::scoped_push _push(*m_s); while (!m_cancel) { m_s->assert_expr(fml); + TRACE("opt", tout << fml << "\n";); is_sat = m_s->check_sat(1,vars); if (is_sat == l_true) { disj.reset(); @@ -343,6 +345,7 @@ namespace opt { m_lower[i] = m_s->saved_objective_value(i); } } + TRACE("opt", tout << "strengthen bound: " << block << "\n";); m_s->assert_expr(block); // TBD: only works for simplex From c910ed2eae2588bd10092f4e878fb2a187d4121e Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 2 Jun 2015 18:40:11 +0100 Subject: [PATCH 888/925] fpa2bv_approx: bugfix for fp.abs --- src/tactic/fpa/fpa2bv_approx_tactic.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tactic/fpa/fpa2bv_approx_tactic.cpp b/src/tactic/fpa/fpa2bv_approx_tactic.cpp index bc0b5d39a..02c5ab8bd 100644 --- a/src/tactic/fpa/fpa2bv_approx_tactic.cpp +++ b/src/tactic/fpa/fpa2bv_approx_tactic.cpp @@ -379,6 +379,7 @@ class fpa2bv_approx_tactic: public tactic { case OP_FPA_ABS: { mpf_mngr.abs(arg_val[0], rhs_value); + mpf_mngr.abs(est_arg_val[0], est_rhs_value); break; } default: From c09ac5422ba5132b8739dfa44328db1527cd35cd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 2 Jun 2015 10:42:03 -0700 Subject: [PATCH 889/925] fix by anomaly detection, issue #118 Signed-off-by: Nikolaj Bjorner --- src/math/realclosure/realclosure.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/math/realclosure/realclosure.cpp b/src/math/realclosure/realclosure.cpp index 84ba606fd..1ca8823a1 100644 --- a/src/math/realclosure/realclosure.cpp +++ b/src/math/realclosure/realclosure.cpp @@ -4075,7 +4075,7 @@ namespace realclosure { void refine_rational_interval(rational_value * v, unsigned prec) { mpbqi & i = interval(v); - if (!i.lower_is_open() && !i.lower_is_open()) { + if (!i.lower_is_open() && !i.upper_is_open()) { SASSERT(bqm().eq(i.lower(), i.upper())); return; } From 9734407cde074c5bc65029548919f4a94f2d905f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 2 Jun 2015 11:14:59 -0700 Subject: [PATCH 890/925] disable throttle on unbounded objectives in shared theories. It may violate an interface equality, to fix issue #120 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith.h | 1 + src/smt/theory_arith_aux.h | 31 ++++++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index db4b01395..6531c33f2 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -885,6 +885,7 @@ namespace smt { void add_tmp_row_entry(row & r, numeral const & coeff, theory_var v); enum max_min_t { UNBOUNDED, AT_BOUND, OPTIMIZED, BEST_EFFORT}; max_min_t max_min(theory_var v, bool max, bool maintain_integrality, bool& has_shared); + bool has_interface_equality(theory_var v); bool max_min(svector const & vars); max_min_t max_min(row& r, bool max, bool maintain_integrality, bool& has_shared); diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 91ee6def5..8bf366682 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -1545,6 +1545,25 @@ namespace smt { return is_tighter; } + /** + \brief Check if bound change affects interface equality. + */ + template + bool theory_arith::has_interface_equality(theory_var x) { + theory_var num = get_num_vars(); + context& ctx = get_context(); + enode* r = get_enode(x)->get_root(); + for (theory_var v = 0; v < num; v++) { + if (v == x) continue; + enode* n = get_enode(v); + if (ctx.is_shared(n) && n->get_root() == r) { + return true; + } + } + return false; + } + + /** \brief Maximize (Minimize) the given temporary row. Return true if succeeded. @@ -1660,13 +1679,23 @@ namespace smt { SASSERT(!maintain_integrality || valid_assignment()); continue; } - if (ctx.is_shared(get_enode(x_j))) { +#if 0 + if (ctx.is_shared(get_enode(x_j)) && has_interface_equality(x_j)) { ++best_efforts; } else { SASSERT(unbounded_gain(max_gain)); + has_shared = false; best_efforts = 0; } +#endif + // + // NB. As it stands this is a possibly unsound conclusion for shared theories. + // the tradeoff is non-termination for unbounded objectives in the + // presence of sharing. + // + has_shared = false; + best_efforts = 0; result = UNBOUNDED; break; } From b65d5797f805d1cd46fefc85fec029f7ea255b79 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 3 Jun 2015 17:21:01 +0100 Subject: [PATCH 891/925] optimize expr_safe_replace for when a subexpression has no substitutions Signed-off-by: Nuno Lopes --- src/ast/rewriter/expr_safe_replace.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/ast/rewriter/expr_safe_replace.cpp b/src/ast/rewriter/expr_safe_replace.cpp index 37fcdfe6a..b43577960 100644 --- a/src/ast/rewriter/expr_safe_replace.cpp +++ b/src/ast/rewriter/expr_safe_replace.cpp @@ -49,17 +49,23 @@ void expr_safe_replace::operator()(expr* e, expr_ref& res) { app* c = to_app(a); unsigned n = c->get_num_args(); m_args.reset(); + bool arg_differs = false; for (unsigned i = 0; i < n; ++i) { if (m_cache.find(c->get_arg(i), d)) { m_args.push_back(d); + arg_differs |= c->get_arg(i) != d; } else { m_todo.push_back(c->get_arg(i)); } } if (m_args.size() == n) { - b = m.mk_app(c->get_decl(), m_args.size(), m_args.c_ptr()); - m_refs.push_back(b); + if (arg_differs) { + b = m.mk_app(c->get_decl(), m_args.size(), m_args.c_ptr()); + m_refs.push_back(b); + } else { + b = a; + } m_cache.insert(a, b); m_todo.pop_back(); } From 2733899c01d38b5b43a1b1b1957ad58ae88b8d6e Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 5 Jun 2015 09:30:44 +0100 Subject: [PATCH 892/925] remove unused var Signed-off-by: Nuno Lopes --- src/tactic/arith/card2bv_tactic.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tactic/arith/card2bv_tactic.cpp b/src/tactic/arith/card2bv_tactic.cpp index 7c715e6e7..465173196 100644 --- a/src/tactic/arith/card2bv_tactic.cpp +++ b/src/tactic/arith/card2bv_tactic.cpp @@ -485,7 +485,6 @@ public: return; } - unsigned size = g->size(); expr_ref new_f1(m), new_f2(m); proof_ref new_pr1(m), new_pr2(m); for (unsigned idx = 0; !g->inconsistent() && idx < g->size(); idx++) { From 6217804ed59a21ae232a09837e44661bbc1fb15c Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Sun, 7 Jun 2015 12:07:24 +0100 Subject: [PATCH 893/925] fix another UB in bit_vector Signed-off-by: Nuno Lopes --- src/util/bit_vector.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/util/bit_vector.h b/src/util/bit_vector.h index e874d8a3d..f3fd7c27b 100644 --- a/src/util/bit_vector.h +++ b/src/util/bit_vector.h @@ -94,7 +94,8 @@ public: } void reset() { - memset(m_data, 0, m_capacity * sizeof(unsigned)); + if (m_data) + memset(m_data, 0, m_capacity * sizeof(unsigned)); m_num_bits = 0; } From 444dc0ed0ad8ddd619599b86078c9dd6554b09e0 Mon Sep 17 00:00:00 2001 From: aleze648 Date: Sun, 7 Jun 2015 05:31:10 -0700 Subject: [PATCH 894/925] Added missing cases for positive zero, negative zero and is positive. --- src/tactic/fpa/fpa2bv_rewriter_prec.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_rewriter_prec.h b/src/tactic/fpa/fpa2bv_rewriter_prec.h index d82255d39..1e3cf71ac 100644 --- a/src/tactic/fpa/fpa2bv_rewriter_prec.h +++ b/src/tactic/fpa/fpa2bv_rewriter_prec.h @@ -126,6 +126,8 @@ struct fpa2bv_rewriter_prec_cfg : public default_rewriter_cfg { case OP_FPA_PLUS_INF: m_conv.mk_pinf(f, result); return BR_DONE; case OP_FPA_MINUS_INF: m_conv.mk_ninf(f, result); return BR_DONE; case OP_FPA_NAN: m_conv.mk_nan(f, result); return BR_DONE; + case OP_FPA_PLUS_ZERO: m_conv.mk_pzero(f, result); return BR_DONE; + case OP_FPA_MINUS_ZERO: m_conv.mk_nzero(f, result); return BR_DONE; //AZ: Added precision, if precision is MAX_PRECISION uses the regular implementation of the methods case OP_FPA_ADD: m_conv.mk_add(f,get_precision(f), num, args, result);return BR_DONE; @@ -153,13 +155,12 @@ struct fpa2bv_rewriter_prec_cfg : public default_rewriter_cfg { case OP_FPA_LE: m_conv.mk_float_le(f, num, args, result); return BR_DONE; case OP_FPA_GE: m_conv.mk_float_ge(f, num, args, result); return BR_DONE; case OP_FPA_IS_ZERO: m_conv.mk_is_zero(f, num, args, result); return BR_DONE; -//case OP_FPA_IS_NZERO: m_conv.mk_is_nzero(f, num, args, result); return BR_DONE; -//case OP_FPA_IS_PZERO: m_conv.mk_is_pzero(f, num, args, result); return BR_DONE; case OP_FPA_IS_NAN: m_conv.mk_is_nan(f, num, args, result); return BR_DONE; case OP_FPA_IS_INF: m_conv.mk_is_inf(f, num, args, result); return BR_DONE; case OP_FPA_IS_NORMAL: m_conv.mk_is_normal(f, num, args, result); return BR_DONE; case OP_FPA_IS_SUBNORMAL: m_conv.mk_is_subnormal(f, num, args, result); return BR_DONE; case OP_FPA_IS_NEGATIVE: m_conv.mk_is_negative(f, num, args, result); return BR_DONE; + case OP_FPA_IS_POSITIVE: m_conv.mk_is_positive(f, num, args, result); return BR_DONE; case OP_FPA_TO_FP: m_conv.mk_to_fp(f, num, args, result); return BR_DONE; case OP_FPA_TO_IEEE_BV: m_conv.mk_to_ieee_bv(f, num, args, result); return BR_DONE; default: From 0997d0d2b5aade097769be2a5868f9a54be76481 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Sun, 7 Jun 2015 14:55:15 +0100 Subject: [PATCH 895/925] add new C API function: Z3_finalize_memory() Useful to debug memory leaks in Z3 and in client applications Signed-off-by: Nuno Lopes --- src/api/api_context.cpp | 5 +++++ src/api/z3_api.h | 14 +++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index 6e0c3cd82..c857be48d 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -516,6 +516,11 @@ extern "C" { memory::initialize(0); } + void Z3_API Z3_finalize_memory(void) { + LOG_Z3_finalize_memory(); + memory::finalize(); + } + Z3_error_code Z3_API Z3_get_error_code(Z3_context c) { LOG_Z3_get_error_code(c); return mk_c(c)->get_error_code(); diff --git a/src/api/z3_api.h b/src/api/z3_api.h index ec321b66d..4746d4a33 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -5365,7 +5365,19 @@ END_MLAPI_EXCLUDE */ void Z3_API Z3_reset_memory(void); #endif - + +#ifdef CorML3 + /** + \brief Destroy all allocated resources. + + Any pointers previously returned by the API become invalid. + Can be used for memory leak detection. + + def_API('Z3_finalize_memory', VOID, ()) + */ + void Z3_API Z3_finalize_memory(void); +#endif + /*@}*/ #ifdef CorML3 From 3e1042c6806baf5f782cc8be791caabd2b76f01b Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 8 Jun 2015 15:35:29 +0100 Subject: [PATCH 896/925] Exported the quasi-pb probe as per user request. --- src/tactic/smtlogics/qflia_tactic.cpp | 4 ++-- src/tactic/smtlogics/qflia_tactic.h | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/tactic/smtlogics/qflia_tactic.cpp b/src/tactic/smtlogics/qflia_tactic.cpp index 6fbf34255..c7659dddb 100644 --- a/src/tactic/smtlogics/qflia_tactic.cpp +++ b/src/tactic/smtlogics/qflia_tactic.cpp @@ -56,7 +56,7 @@ struct quasi_pb_probe : public probe { } }; -probe * mk_quasi_pb_probe() { +probe * mk_is_quasi_pb_probe() { return mk_and(mk_not(mk_is_unbounded_probe()), alloc(quasi_pb_probe)); } @@ -208,7 +208,7 @@ tactic * mk_qflia_tactic(ast_manager & m, params_ref const & p) { tactic * st = using_params(and_then(preamble_st, or_else(mk_ilp_model_finder_tactic(m), mk_pb_tactic(m), - and_then(fail_if_not(mk_quasi_pb_probe()), + and_then(fail_if_not(mk_is_quasi_pb_probe()), using_params(mk_lia2sat_tactic(m), quasi_pb_p), mk_fail_if_undecided_tactic()), mk_bounded_tactic(m), diff --git a/src/tactic/smtlogics/qflia_tactic.h b/src/tactic/smtlogics/qflia_tactic.h index 9ddaf1f88..47a2108ae 100644 --- a/src/tactic/smtlogics/qflia_tactic.h +++ b/src/tactic/smtlogics/qflia_tactic.h @@ -28,4 +28,11 @@ tactic * mk_qflia_tactic(ast_manager & m, params_ref const & p = params_ref()); ADD_TACTIC("qflia", "builtin strategy for solving QF_LIA problems.", "mk_qflia_tactic(m, p)") */ + +probe * mk_is_quasi_pb_probe(); + +/* + ADD_PROBE("is-quasi-pb", "true if the goal is quasi-pb.", "mk_is_quasi_pb_probe()") +*/ + #endif From 24a5ff825a8d841c17d911e5758ca8c9ccf118d1 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 8 Jun 2015 15:36:00 +0100 Subject: [PATCH 897/925] Fixed collect_param_descrs in pb2bv tactic. --- src/tactic/arith/pb2bv_tactic.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/tactic/arith/pb2bv_tactic.cpp b/src/tactic/arith/pb2bv_tactic.cpp index 643195b05..1ef0efc47 100644 --- a/src/tactic/arith/pb2bv_tactic.cpp +++ b/src/tactic/arith/pb2bv_tactic.cpp @@ -854,7 +854,7 @@ private: m_temporary_ints(m), m_used_dependencies(m), m_rw(*this) { - updt_params(p); + updt_params(p); m_b_rw.set_flat(false); // no flattening otherwise will blowup the memory m_b_rw.set_elim_and(true); } @@ -871,12 +871,17 @@ private: m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX)); m_all_clauses_limit = p.get_uint("pb2bv_all_clauses_limit", 8); m_cardinality_limit = p.get_uint("pb2bv_cardinality_limit", UINT_MAX); + m_b_rw.updt_params(p); } void collect_param_descrs(param_descrs & r) { - insert_max_memory(r); + insert_max_memory(r); r.insert("pb2bv_all_clauses_limit", CPK_UINT, "(default: 8) maximum number of literals for using equivalent CNF encoding of PB constraint."); r.insert("pb2bv_cardinality_limit", CPK_UINT, "(default: inf) limit for using arc-consistent cardinality constraint encoding."); + + m_b_rw.get_param_descrs(r); + r.erase("flat"); + r.erase("elim_and"); } void set_cancel(bool f) { From f92064489233e58c8551e360458477530b1d5eb9 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 8 Jun 2015 15:37:17 +0100 Subject: [PATCH 898/925] Parameter fix for the qflia default tactic --- src/tactic/smtlogics/qflia_tactic.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/tactic/smtlogics/qflia_tactic.cpp b/src/tactic/smtlogics/qflia_tactic.cpp index c7659dddb..00f6480d8 100644 --- a/src/tactic/smtlogics/qflia_tactic.cpp +++ b/src/tactic/smtlogics/qflia_tactic.cpp @@ -100,9 +100,11 @@ static tactic * mk_bv2sat_tactic(ast_manager & m) { #define SMALL_SIZE 80000 static tactic * mk_pb_tactic(ast_manager & m) { - params_ref pb2bv_p; - pb2bv_p.set_bool("ite_extra", true); + params_ref pb2bv_p; pb2bv_p.set_uint("pb2bv_all_clauses_limit", 8); + + params_ref bv2sat_p; + bv2sat_p.set_bool("ite_extra", true); return and_then(fail_if_not(mk_is_pb_probe()), fail_if(mk_produce_proofs_probe()), @@ -113,14 +115,16 @@ static tactic * mk_pb_tactic(ast_manager & m) { mk_fail_if_undecided_tactic()), and_then(using_params(mk_pb2bv_tactic(m), pb2bv_p), fail_if_not(mk_is_qfbv_probe()), - mk_bv2sat_tactic(m)))); + using_params(mk_bv2sat_tactic(m), bv2sat_p)))); } static tactic * mk_lia2sat_tactic(ast_manager & m) { params_ref pb2bv_p; - pb2bv_p.set_bool("ite_extra", true); pb2bv_p.set_uint("pb2bv_all_clauses_limit", 8); + + params_ref bv2sat_p; + bv2sat_p.set_bool("ite_extra", true); return and_then(fail_if(mk_is_unbounded_probe()), fail_if(mk_produce_proofs_probe()), @@ -130,7 +134,7 @@ static tactic * mk_lia2sat_tactic(ast_manager & m) { mk_lia2pb_tactic(m), using_params(mk_pb2bv_tactic(m), pb2bv_p), fail_if_not(mk_is_qfbv_probe()), - mk_bv2sat_tactic(m)); + using_params(mk_bv2sat_tactic(m), bv2sat_p)); } // Try to find a model for an unbounded ILP problem. From fd0c86ec7d7e4d27ba7e9cff13d7152a747df77d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 8 Jun 2015 08:44:30 -0700 Subject: [PATCH 899/925] remove tests Signed-off-by: Nikolaj Bjorner --- tests/chat1.smt2 | 3380 ------------------------- tests/chat_pb.smt2 | 3382 ------------------------- tests/chat_sls.smt2 | 3380 ------------------------- tests/ravi_sls.smt2 | 443 ---- tests/sls1.smt2 | 5844 ------------------------------------------- tests/wmax1.smt2 | 5842 ------------------------------------------ 6 files changed, 22271 deletions(-) delete mode 100644 tests/chat1.smt2 delete mode 100644 tests/chat_pb.smt2 delete mode 100644 tests/chat_sls.smt2 delete mode 100644 tests/ravi_sls.smt2 delete mode 100644 tests/sls1.smt2 delete mode 100644 tests/wmax1.smt2 diff --git a/tests/chat1.smt2 b/tests/chat1.smt2 deleted file mode 100644 index e6e11076b..000000000 --- a/tests/chat1.smt2 +++ /dev/null @@ -1,3380 +0,0 @@ -(declare-const |dn([7,Main.main],41)| Bool) -(declare-const |dn([3,7],24)| Bool) -(declare-const |dn([7,Main.main],47)| Bool) -(declare-const |dn([9,Main.main],86)| Bool) -(declare-const |dn([7,Main.main],51)| Bool) -(declare-const |dn([3,7],20)| Bool) -(declare-const |dn([6,9],91)| Bool) -(declare-const |scc(3)| Bool) -(declare-const |dn([6,9],92)| Bool) -(declare-const |scc(4)| Bool) -(declare-const |dn([7,Main.main],54)| Bool) -(declare-const |scc(0)| Bool) -(declare-const |dn([Main.main],109)| Bool) -(declare-const |dn([7,Main.main],58)| Bool) -(declare-const |dn([Main.main],104)| Bool) -(declare-const |dn([Main.main],102)| Bool) -(declare-const |dn([8,Main.main],101)| Bool) -(declare-const |dn([6,9],95)| Bool) -(declare-const |dn([8,Main.main],96)| Bool) -(declare-const |dn([3,7],28)| Bool) -(declare-const |dn([Main.main],106)| Bool) -(declare-const |dn([2,3],36)| Bool) -(declare-const |dn([4,1],78)| Bool) -(declare-const |dn([Main.main],114)| Bool) -(declare-const |dn([2,3],35)| Bool) -(declare-const |dn([2,3],38)| Bool) -(declare-const |dn([5,1],63)| Bool) -(declare-const |dn([7,Main.main],39)| Bool) -(declare-const |dn([3,7],33)| Bool) -(declare-const |dn([9,Main.main],88)| Bool) -(declare-const |dn([4,1],80)| Bool) -(declare-const |dn([Main.main],116)| Bool) -(declare-const |dn([Main.main],111)| Bool) -(declare-const |dn([7,Main.main],42)| Bool) -(declare-const |dn([9,Main.main],85)| Bool) -(declare-const |dn([3,7],27)| Bool) -(declare-const |dn([1,3],64)| Bool) -(declare-const |dn([9,Main.main],83)| Bool) -(declare-const |dn([1,3],67)| Bool) -(declare-const |dn([7,Main.main],40)| Bool) -(declare-const |dn([3,7],25)| Bool) -(declare-const |dn([6,9],90)| Bool) -(declare-const |dn([7,Main.main],60)| Bool) -(declare-const |dn([7,Main.main],50)| Bool) -(declare-const |dn([5,1],62)| Bool) -(declare-const |dn([3,7],22)| Bool) -(declare-const |dn([7,Main.main],53)| Bool) -(declare-const |dn([6,9],93)| Bool) -(declare-const |dn([7,Main.main],57)| Bool) -(declare-const |dn([Main.main],108)| Bool) -(declare-const |dn([7,Main.main],55)| Bool) -(declare-const |scc(1)| Bool) -(declare-const |dn([Main.main],105)| Bool) -(declare-const |scc(2)| Bool) -(declare-const |dn([8,Main.main],97)| Bool) -(declare-const |dn([Main.main],103)| Bool) -(declare-const |scc(5)| Bool) -(declare-const |dn([4,1],70)| Bool) -(declare-const |dn([6,9],94)| Bool) -(declare-const |dn([8,Main.main],100)| Bool) -(declare-const |dn([7,Main.main],59)| Bool) -(declare-const |dn([5,1],61)| Bool) -(declare-const |dn([4,1],69)| Bool) -(declare-const |dn([3,7],29)| Bool) -(declare-const |dn([3,7],31)| Bool) -(declare-const |dn([Main.main],113)| Bool) -(declare-const |dn([4,1],79)| Bool) -(declare-const |dn([2,3],34)| Bool) -(declare-const |dn([Main.main],115)| Bool) -(declare-const |dn([2,3],37)| Bool) -(declare-const |dn([1,3],68)| Bool) -(declare-const |dn([4,1],81)| Bool) -(declare-const |scc(7)| Bool) -(declare-const |dn([9,Main.main],89)| Bool) -(declare-const |dn([1,3],66)| Bool) -(declare-const |dn([9,Main.main],84)| Bool) -(declare-const |dn([1,3],65)| Bool) -(declare-const |dn([7,Main.main],43)| Bool) -(declare-const |dn([9,Main.main],82)| Bool) -(declare-const |dn([7,Main.main],45)| Bool) -(declare-const |dn([3,7],30)| Bool) -(declare-const |scc(8)| Bool) -(declare-const |dn([9,Main.main],87)| Bool) -(declare-const |dn([3,7],21)| Bool) -(declare-const |dn([7,Main.main],49)| Bool) -(declare-const |scc(6)| Bool) -(declare-const |dn([7,Main.main],41)_dn([3,7],20)| Bool) -(declare-const |dn([7,Main.main],41)_dn([7,Main.main],42)| Bool) -(declare-const |dn([3,7],24)_dn([3,7],25)| Bool) -(declare-const |dn([3,7],24)_dn([4,1],80)| Bool) -(declare-const |dn([7,Main.main],47)_dn([7,Main.main],41)| Bool) -(declare-const |dn([7,Main.main],47)_dn([7,Main.main],45)| Bool) -(declare-const |dn([9,Main.main],86)_dn([9,Main.main],87)| Bool) -(declare-const |dn([9,Main.main],86)_dn([6,9],91)| Bool) -(declare-const |dn([7,Main.main],51)_dn([9,Main.main],84)| Bool) -(declare-const |dn([3,7],20)_dn([3,7],21)| Bool) -(declare-const |dn([3,7],20)_dn([1,3],64)| Bool) -(declare-const |dn([6,9],91)_dn([7,Main.main],54)| Bool) -(declare-const |dn([6,9],91)_dn([6,9],92)| Bool) -(declare-const |scc(3)_dn([3,7],20)| Bool) -(declare-const |scc(3)_dn([3,7],22)| Bool) -(declare-const |scc(3)_dn([3,7],27)| Bool) -(declare-const |scc(3)_dn([3,7],29)| Bool) -(declare-const |scc(3)_dn([3,7],31)| Bool) -(declare-const |scc(3)_dn([3,7],33)| Bool) -(declare-const |dn([6,9],92)_dn([6,9],90)| Bool) -(declare-const |dn([6,9],92)_dn([6,9],91)| Bool) -(declare-const |dn([6,9],92)_dn([6,9],93)| Bool) -(declare-const |dn([6,9],92)_dn([6,9],95)| Bool) -(declare-const |scc(4)_dn([2,3],35)| Bool) -(declare-const |scc(4)_dn([4,1],70)| Bool) -(declare-const |dn([7,Main.main],54)_dn([7,Main.main],39)| Bool) -(declare-const |dn([7,Main.main],54)_dn([7,Main.main],47)| Bool) -(declare-const |dn([7,Main.main],54)_dn([7,Main.main],49)| Bool) -(declare-const |dn([7,Main.main],54)_dn([7,Main.main],50)| Bool) -(declare-const |dn([7,Main.main],54)_dn([7,Main.main],51)| Bool) -(declare-const |dn([7,Main.main],54)_dn([7,Main.main],55)| Bool) -(declare-const |dn([7,Main.main],54)_dn([7,Main.main],58)| Bool) -(declare-const |dn([7,Main.main],54)_dn([7,Main.main],59)| Bool) -(declare-const |dn([7,Main.main],54)_scc(1)| Bool) -(declare-const |dn([7,Main.main],54)_scc(7)| Bool) -(declare-const |scc(0)_dn([3,7],24)| Bool) -(declare-const |scc(0)_dn([2,3],34)| Bool) -(declare-const |dn([Main.main],109)_dn([Main.main],111)| Bool) -(declare-const |dn([7,Main.main],58)_dn([7,Main.main],39)| Bool) -(declare-const |dn([7,Main.main],58)_dn([7,Main.main],47)| Bool) -(declare-const |dn([7,Main.main],58)_dn([7,Main.main],49)| Bool) -(declare-const |dn([7,Main.main],58)_dn([7,Main.main],50)| Bool) -(declare-const |dn([7,Main.main],58)_dn([7,Main.main],51)| Bool) -(declare-const |dn([7,Main.main],58)_dn([7,Main.main],54)| Bool) -(declare-const |dn([7,Main.main],58)_dn([7,Main.main],55)| Bool) -(declare-const |dn([7,Main.main],58)_dn([7,Main.main],59)| Bool) -(declare-const |dn([7,Main.main],58)_scc(1)| Bool) -(declare-const |dn([7,Main.main],58)_scc(7)| Bool) -(declare-const |dn([Main.main],104)_dn([7,Main.main],49)| Bool) -(declare-const |dn([Main.main],104)_dn([Main.main],105)| Bool) -(declare-const |dn([8,Main.main],101)_dn([8,Main.main],96)| Bool) -(declare-const |dn([8,Main.main],101)_dn([8,Main.main],97)| Bool) -(declare-const |dn([6,9],95)_dn([6,9],90)| Bool) -(declare-const |dn([6,9],95)_dn([6,9],91)| Bool) -(declare-const |dn([6,9],95)_dn([6,9],93)| Bool) -(declare-const |dn([6,9],95)_scc(1)| Bool) -(declare-const |dn([8,Main.main],96)_dn([8,Main.main],97)| Bool) -(declare-const |dn([3,7],28)_dn([3,7],20)| Bool) -(declare-const |dn([3,7],28)_dn([3,7],22)| Bool) -(declare-const |dn([3,7],28)_dn([3,7],27)| Bool) -(declare-const |dn([3,7],28)_dn([3,7],29)| Bool) -(declare-const |dn([3,7],28)_dn([3,7],31)| Bool) -(declare-const |dn([3,7],28)_dn([3,7],33)| Bool) -(declare-const |dn([3,7],28)_scc(6)| Bool) -(declare-const |dn([Main.main],106)_dn([7,Main.main],47)| Bool) -(declare-const |dn([2,3],36)_dn([3,7],31)| Bool) -(declare-const |dn([2,3],36)_dn([2,3],37)| Bool) -(declare-const |dn([4,1],78)_dn([4,1],79)| Bool) -(declare-const |dn([4,1],78)_scc(4)| Bool) -(declare-const |dn([Main.main],114)_dn([9,Main.main],83)| Bool) -(declare-const |dn([Main.main],114)_dn([Main.main],115)| Bool) -(declare-const |dn([2,3],35)_dn([3,7],33)| Bool) -(declare-const |dn([2,3],35)_dn([2,3],36)| Bool) -(declare-const |dn([2,3],38)_dn([2,3],34)| Bool) -(declare-const |dn([2,3],38)_dn([2,3],35)| Bool) -(declare-const |dn([5,1],63)_dn([5,1],61)| Bool) -(declare-const |dn([5,1],63)_dn([5,1],62)| Bool) -(declare-const |dn([7,Main.main],39)_dn([7,Main.main],47)| Bool) -(declare-const |dn([7,Main.main],39)_dn([7,Main.main],49)| Bool) -(declare-const |dn([7,Main.main],39)_dn([7,Main.main],50)| Bool) -(declare-const |dn([7,Main.main],39)_dn([7,Main.main],54)| Bool) -(declare-const |dn([7,Main.main],39)_dn([7,Main.main],58)| Bool) -(declare-const |dn([3,7],33)_dn([3,7],20)| Bool) -(declare-const |dn([3,7],33)_dn([3,7],22)| Bool) -(declare-const |dn([3,7],33)_dn([3,7],27)| Bool) -(declare-const |dn([3,7],33)_dn([3,7],29)| Bool) -(declare-const |dn([3,7],33)_dn([3,7],31)| Bool) -(declare-const |dn([9,Main.main],88)_dn([9,Main.main],89)| Bool) -(declare-const |dn([4,1],80)_dn([4,1],81)| Bool) -(declare-const |dn([Main.main],116)_dn([Main.main],113)| Bool) -(declare-const |dn([Main.main],111)_dn([Main.main],102)| Bool) -(declare-const |dn([Main.main],111)_dn([Main.main],103)| Bool) -(declare-const |dn([7,Main.main],42)_dn([3,7],22)| Bool) -(declare-const |dn([7,Main.main],42)_dn([7,Main.main],43)| Bool) -(declare-const |dn([9,Main.main],85)_dn([9,Main.main],86)| Bool) -(declare-const |dn([9,Main.main],85)_dn([6,9],90)| Bool) -(declare-const |dn([3,7],27)_dn([3,7],20)| Bool) -(declare-const |dn([3,7],27)_dn([3,7],22)| Bool) -(declare-const |dn([3,7],27)_dn([3,7],28)| Bool) -(declare-const |dn([3,7],27)_dn([3,7],29)| Bool) -(declare-const |dn([3,7],27)_dn([3,7],30)| Bool) -(declare-const |dn([3,7],27)_dn([3,7],31)| Bool) -(declare-const |dn([3,7],27)_dn([3,7],33)| Bool) -(declare-const |dn([1,3],64)_dn([1,3],65)| Bool) -(declare-const |dn([1,3],64)_dn([1,3],67)| Bool) -(declare-const |dn([9,Main.main],83)_dn([9,Main.main],82)| Bool) -(declare-const |dn([9,Main.main],83)_dn([9,Main.main],84)| Bool) -(declare-const |dn([9,Main.main],83)_dn([9,Main.main],88)| Bool) -(declare-const |dn([1,3],67)_dn([5,1],61)| Bool) -(declare-const |dn([1,3],67)_dn([1,3],68)| Bool) -(declare-const |dn([7,Main.main],40)_dn([7,Main.main],39)| Bool) -(declare-const |dn([7,Main.main],40)_dn([7,Main.main],47)| Bool) -(declare-const |dn([7,Main.main],40)_dn([7,Main.main],49)| Bool) -(declare-const |dn([7,Main.main],40)_dn([7,Main.main],50)| Bool) -(declare-const |dn([7,Main.main],40)_dn([7,Main.main],54)| Bool) -(declare-const |dn([7,Main.main],40)_dn([7,Main.main],58)| Bool) -(declare-const |dn([3,7],25)_dn([1,3],67)| Bool) -(declare-const |dn([6,9],90)_dn([6,9],91)| Bool) -(declare-const |dn([6,9],90)_dn([6,9],93)| Bool) -(declare-const |dn([6,9],90)_dn([6,9],95)| Bool) -(declare-const |dn([7,Main.main],60)_dn([7,Main.main],39)| Bool) -(declare-const |dn([7,Main.main],60)_dn([7,Main.main],47)| Bool) -(declare-const |dn([7,Main.main],60)_dn([7,Main.main],49)| Bool) -(declare-const |dn([7,Main.main],60)_dn([7,Main.main],50)| Bool) -(declare-const |dn([7,Main.main],60)_dn([7,Main.main],54)| Bool) -(declare-const |dn([7,Main.main],60)_dn([7,Main.main],58)| Bool) -(declare-const |dn([7,Main.main],50)_dn([7,Main.main],39)| Bool) -(declare-const |dn([7,Main.main],50)_dn([7,Main.main],47)| Bool) -(declare-const |dn([7,Main.main],50)_dn([7,Main.main],49)| Bool) -(declare-const |dn([7,Main.main],50)_dn([7,Main.main],51)| Bool) -(declare-const |dn([7,Main.main],50)_dn([7,Main.main],54)| Bool) -(declare-const |dn([7,Main.main],50)_dn([7,Main.main],55)| Bool) -(declare-const |dn([7,Main.main],50)_dn([7,Main.main],58)| Bool) -(declare-const |dn([7,Main.main],50)_dn([7,Main.main],59)| Bool) -(declare-const |dn([7,Main.main],50)_scc(1)| Bool) -(declare-const |dn([7,Main.main],50)_scc(7)| Bool) -(declare-const |dn([5,1],62)_dn([5,1],61)| Bool) -(declare-const |dn([5,1],62)_dn([5,1],63)| Bool) -(declare-const |dn([5,1],62)_scc(2)| Bool) -(declare-const |dn([3,7],22)_dn([1,3],65)| Bool) -(declare-const |dn([7,Main.main],53)_dn([7,Main.main],39)| Bool) -(declare-const |dn([7,Main.main],53)_dn([7,Main.main],47)| Bool) -(declare-const |dn([7,Main.main],53)_dn([7,Main.main],49)| Bool) -(declare-const |dn([7,Main.main],53)_dn([7,Main.main],50)| Bool) -(declare-const |dn([7,Main.main],53)_dn([7,Main.main],54)| Bool) -(declare-const |dn([7,Main.main],53)_dn([7,Main.main],58)| Bool) -(declare-const |dn([6,9],93)_dn([9,Main.main],88)| Bool) -(declare-const |dn([6,9],93)_dn([6,9],94)| Bool) -(declare-const |dn([7,Main.main],57)_dn([7,Main.main],39)| Bool) -(declare-const |dn([7,Main.main],57)_dn([7,Main.main],47)| Bool) -(declare-const |dn([7,Main.main],57)_dn([7,Main.main],49)| Bool) -(declare-const |dn([7,Main.main],57)_dn([7,Main.main],50)| Bool) -(declare-const |dn([7,Main.main],57)_dn([7,Main.main],54)| Bool) -(declare-const |dn([7,Main.main],57)_dn([7,Main.main],58)| Bool) -(declare-const |dn([Main.main],108)_dn([8,Main.main],97)| Bool) -(declare-const |dn([Main.main],108)_dn([Main.main],109)| Bool) -(declare-const |dn([7,Main.main],55)_dn([6,9],95)| Bool) -(declare-const |scc(1)_dn([7,Main.main],39)| Bool) -(declare-const |scc(1)_dn([7,Main.main],47)| Bool) -(declare-const |scc(1)_dn([7,Main.main],49)| Bool) -(declare-const |scc(1)_dn([7,Main.main],50)| Bool) -(declare-const |scc(1)_dn([7,Main.main],51)| Bool) -(declare-const |scc(1)_dn([7,Main.main],54)| Bool) -(declare-const |scc(1)_dn([7,Main.main],55)| Bool) -(declare-const |scc(1)_dn([7,Main.main],57)| Bool) -(declare-const |scc(1)_dn([7,Main.main],58)| Bool) -(declare-const |scc(1)_dn([7,Main.main],59)| Bool) -(declare-const |scc(1)_dn([6,9],93)| Bool) -(declare-const |scc(1)_scc(7)| Bool) -(declare-const |dn([Main.main],105)_dn([7,Main.main],50)| Bool) -(declare-const |dn([Main.main],105)_dn([Main.main],106)| Bool) -(declare-const |scc(2)_dn([3,7],20)| Bool) -(declare-const |scc(2)_dn([3,7],22)| Bool) -(declare-const |scc(2)_dn([3,7],27)| Bool) -(declare-const |scc(2)_dn([3,7],29)| Bool) -(declare-const |scc(2)_dn([3,7],31)| Bool) -(declare-const |scc(2)_dn([3,7],33)| Bool) -(declare-const |dn([8,Main.main],97)_dn([3,7],27)| Bool) -(declare-const |dn([Main.main],103)_dn([7,Main.main],39)| Bool) -(declare-const |dn([Main.main],103)_dn([Main.main],104)| Bool) -(declare-const |scc(5)_dn([5,1],63)| Bool) -(declare-const |scc(5)_dn([8,Main.main],100)| Bool) -(declare-const |dn([6,9],94)_dn([6,9],90)| Bool) -(declare-const |dn([6,9],94)_dn([6,9],91)| Bool) -(declare-const |dn([6,9],94)_dn([6,9],93)| Bool) -(declare-const |dn([6,9],94)_dn([6,9],95)| Bool) -(declare-const |dn([8,Main.main],100)_dn([4,1],78)| Bool) -(declare-const |dn([8,Main.main],100)_dn([8,Main.main],101)| Bool) -(declare-const |dn([7,Main.main],59)_dn([7,Main.main],60)| Bool) -(declare-const |dn([7,Main.main],59)_dn([6,9],95)| Bool) -(declare-const |dn([5,1],61)_dn([5,1],62)| Bool) -(declare-const |dn([5,1],61)_dn([5,1],63)| Bool) -(declare-const |dn([4,1],69)_dn([4,1],78)| Bool) -(declare-const |dn([4,1],69)_dn([4,1],80)| Bool) -(declare-const |dn([3,7],29)_dn([3,7],20)| Bool) -(declare-const |dn([3,7],29)_dn([3,7],22)| Bool) -(declare-const |dn([3,7],29)_dn([3,7],27)| Bool) -(declare-const |dn([3,7],29)_dn([3,7],28)| Bool) -(declare-const |dn([3,7],29)_dn([3,7],30)| Bool) -(declare-const |dn([3,7],29)_dn([3,7],31)| Bool) -(declare-const |dn([3,7],29)_dn([3,7],33)| Bool) -(declare-const |dn([3,7],31)_dn([5,1],62)| Bool) -(declare-const |dn([Main.main],113)_dn([9,Main.main],82)| Bool) -(declare-const |dn([Main.main],113)_dn([Main.main],114)| Bool) -(declare-const |dn([4,1],79)_dn([4,1],69)| Bool) -(declare-const |dn([4,1],79)_dn([4,1],78)| Bool) -(declare-const |dn([4,1],79)_dn([4,1],80)| Bool) -(declare-const |dn([2,3],34)_dn([2,3],35)| Bool) -(declare-const |dn([Main.main],115)_dn([Main.main],111)| Bool) -(declare-const |dn([Main.main],115)_dn([Main.main],116)| Bool) -(declare-const |dn([2,3],37)_dn([2,3],38)| Bool) -(declare-const |dn([2,3],37)_dn([7,Main.main],58)| Bool) -(declare-const |dn([1,3],68)_dn([1,3],64)| Bool) -(declare-const |dn([1,3],68)_dn([1,3],65)| Bool) -(declare-const |dn([1,3],68)_dn([1,3],67)| Bool) -(declare-const |dn([4,1],81)_dn([4,1],69)| Bool) -(declare-const |dn([4,1],81)_dn([4,1],78)| Bool) -(declare-const |dn([4,1],81)_dn([4,1],80)| Bool) -(declare-const |scc(7)_dn([7,Main.main],39)| Bool) -(declare-const |scc(7)_dn([7,Main.main],47)| Bool) -(declare-const |scc(7)_dn([7,Main.main],49)| Bool) -(declare-const |scc(7)_dn([7,Main.main],50)| Bool) -(declare-const |scc(7)_dn([7,Main.main],51)| Bool) -(declare-const |scc(7)_dn([7,Main.main],53)| Bool) -(declare-const |scc(7)_dn([7,Main.main],54)| Bool) -(declare-const |scc(7)_dn([7,Main.main],55)| Bool) -(declare-const |scc(7)_dn([7,Main.main],58)| Bool) -(declare-const |scc(7)_dn([7,Main.main],59)| Bool) -(declare-const |scc(7)_scc(1)| Bool) -(declare-const |dn([9,Main.main],89)_dn([9,Main.main],82)| Bool) -(declare-const |dn([9,Main.main],89)_dn([9,Main.main],83)| Bool) -(declare-const |dn([9,Main.main],89)_dn([9,Main.main],84)| Bool) -(declare-const |dn([9,Main.main],89)_dn([9,Main.main],88)| Bool) -(declare-const |dn([1,3],66)_dn([1,3],64)| Bool) -(declare-const |dn([1,3],66)_dn([1,3],65)| Bool) -(declare-const |dn([1,3],66)_dn([1,3],67)| Bool) -(declare-const |dn([1,3],66)_scc(0)| Bool) -(declare-const |dn([9,Main.main],84)_dn([9,Main.main],82)| Bool) -(declare-const |dn([9,Main.main],84)_dn([9,Main.main],83)| Bool) -(declare-const |dn([9,Main.main],84)_dn([9,Main.main],85)| Bool) -(declare-const |dn([9,Main.main],84)_dn([9,Main.main],88)| Bool) -(declare-const |dn([1,3],65)_dn([1,3],66)| Bool) -(declare-const |dn([1,3],65)_dn([4,1],69)| Bool) -(declare-const |dn([7,Main.main],43)_dn([7,Main.main],40)| Bool) -(declare-const |dn([9,Main.main],82)_dn([9,Main.main],83)| Bool) -(declare-const |dn([9,Main.main],82)_dn([9,Main.main],84)| Bool) -(declare-const |dn([9,Main.main],82)_dn([9,Main.main],88)| Bool) -(declare-const |dn([7,Main.main],45)_dn([7,Main.main],40)| Bool) -(declare-const |dn([3,7],30)_dn([3,7],20)| Bool) -(declare-const |dn([3,7],30)_dn([3,7],22)| Bool) -(declare-const |dn([3,7],30)_dn([3,7],27)| Bool) -(declare-const |dn([3,7],30)_dn([3,7],29)| Bool) -(declare-const |dn([3,7],30)_dn([3,7],31)| Bool) -(declare-const |dn([3,7],30)_dn([3,7],33)| Bool) -(declare-const |dn([3,7],30)_scc(5)| Bool) -(declare-const |scc(8)_dn([8,Main.main],96)| Bool) -(declare-const |scc(8)_dn([Main.main],108)| Bool) -(declare-const |dn([9,Main.main],87)_dn([7,Main.main],53)| Bool) -(declare-const |dn([9,Main.main],87)_dn([9,Main.main],82)| Bool) -(declare-const |dn([9,Main.main],87)_dn([9,Main.main],83)| Bool) -(declare-const |dn([9,Main.main],87)_dn([9,Main.main],84)| Bool) -(declare-const |dn([9,Main.main],87)_dn([9,Main.main],88)| Bool) -(declare-const |dn([9,Main.main],87)_scc(7)| Bool) -(declare-const |dn([3,7],21)_dn([3,7],20)| Bool) -(declare-const |dn([3,7],21)_dn([3,7],22)| Bool) -(declare-const |dn([3,7],21)_dn([3,7],27)| Bool) -(declare-const |dn([3,7],21)_dn([3,7],29)| Bool) -(declare-const |dn([3,7],21)_dn([3,7],31)| Bool) -(declare-const |dn([3,7],21)_dn([3,7],33)| Bool) -(declare-const |dn([7,Main.main],49)_dn([7,Main.main],39)| Bool) -(declare-const |dn([7,Main.main],49)_dn([7,Main.main],47)| Bool) -(declare-const |dn([7,Main.main],49)_dn([7,Main.main],50)| Bool) -(declare-const |dn([7,Main.main],49)_dn([7,Main.main],54)| Bool) -(declare-const |dn([7,Main.main],49)_dn([7,Main.main],58)| Bool) -(declare-const |scc(6)_dn([3,7],29)| Bool) -(assert |dn([Main.main],113)|) -(assert (= |dn([7,Main.main],41)| (or |dn([7,Main.main],41)_dn([3,7],20)| |dn([7,Main.main],41)_dn([7,Main.main],42)|))) -(assert (not (and |dn([7,Main.main],41)_dn([3,7],20)| |dn([7,Main.main],41)_dn([7,Main.main],42)|))) -(assert (not (and |dn([7,Main.main],41)_dn([7,Main.main],42)| |dn([7,Main.main],41)_dn([3,7],20)|))) -(assert (= |dn([3,7],24)| (or |dn([3,7],24)_dn([3,7],25)| |dn([3,7],24)_dn([4,1],80)|))) -(assert (not (and |dn([3,7],24)_dn([3,7],25)| |dn([3,7],24)_dn([4,1],80)|))) -(assert (not (and |dn([3,7],24)_dn([4,1],80)| |dn([3,7],24)_dn([3,7],25)|))) -(assert (= |dn([7,Main.main],47)| (or |dn([7,Main.main],47)_dn([7,Main.main],41)| |dn([7,Main.main],47)_dn([7,Main.main],45)|))) -(assert (not (and |dn([7,Main.main],47)_dn([7,Main.main],41)| |dn([7,Main.main],47)_dn([7,Main.main],45)|))) -(assert (not (and |dn([7,Main.main],47)_dn([7,Main.main],45)| |dn([7,Main.main],47)_dn([7,Main.main],41)|))) -(assert (= |dn([9,Main.main],86)| (or |dn([9,Main.main],86)_dn([9,Main.main],87)| |dn([9,Main.main],86)_dn([6,9],91)|))) -(assert (not (and |dn([9,Main.main],86)_dn([9,Main.main],87)| |dn([9,Main.main],86)_dn([6,9],91)|))) -(assert (not (and |dn([9,Main.main],86)_dn([6,9],91)| |dn([9,Main.main],86)_dn([9,Main.main],87)|))) -(assert (= |dn([7,Main.main],51)| (or |dn([7,Main.main],51)_dn([9,Main.main],84)|))) -(assert (= |dn([3,7],20)| (or |dn([3,7],20)_dn([3,7],21)| |dn([3,7],20)_dn([1,3],64)|))) -(assert (not (and |dn([3,7],20)_dn([3,7],21)| |dn([3,7],20)_dn([1,3],64)|))) -(assert (not (and |dn([3,7],20)_dn([1,3],64)| |dn([3,7],20)_dn([3,7],21)|))) -(assert (= |dn([6,9],91)| (or |dn([6,9],91)_dn([7,Main.main],54)| |dn([6,9],91)_dn([6,9],92)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |dn([6,9],91)_dn([6,9],92)|))) -(assert (not (and |dn([6,9],91)_dn([6,9],92)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (= |scc(3)| (or |scc(3)_dn([3,7],20)| |scc(3)_dn([3,7],22)| |scc(3)_dn([3,7],27)| |scc(3)_dn([3,7],29)| |scc(3)_dn([3,7],31)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |scc(3)_dn([3,7],31)|))) -(assert (= |dn([6,9],92)| (or |dn([6,9],92)_dn([6,9],90)| |dn([6,9],92)_dn([6,9],91)| |dn([6,9],92)_dn([6,9],93)| |dn([6,9],92)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],90)| |dn([6,9],92)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],90)| |dn([6,9],92)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],90)| |dn([6,9],92)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],91)| |dn([6,9],92)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],91)| |dn([6,9],92)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],91)| |dn([6,9],92)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],93)| |dn([6,9],92)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],93)| |dn([6,9],92)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],93)| |dn([6,9],92)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],95)| |dn([6,9],92)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],95)| |dn([6,9],92)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],95)| |dn([6,9],92)_dn([6,9],93)|))) -(assert (= |scc(4)| (or |scc(4)_dn([2,3],35)| |scc(4)_dn([4,1],70)|))) -(assert (not (and |scc(4)_dn([2,3],35)| |scc(4)_dn([4,1],70)|))) -(assert (not (and |scc(4)_dn([4,1],70)| |scc(4)_dn([2,3],35)|))) -(assert (= |dn([7,Main.main],54)| (or |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],54)_scc(1)|))) -(assert (= |scc(0)| (or |scc(0)_dn([3,7],24)| |scc(0)_dn([2,3],34)|))) -(assert (not (and |scc(0)_dn([3,7],24)| |scc(0)_dn([2,3],34)|))) -(assert (not (and |scc(0)_dn([2,3],34)| |scc(0)_dn([3,7],24)|))) -(assert (= |dn([Main.main],109)| (or |dn([Main.main],109)_dn([Main.main],111)|))) -(assert (= |dn([7,Main.main],58)| (or |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],58)_scc(1)|))) -(assert (= |dn([Main.main],104)| (or |dn([Main.main],104)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([Main.main],105)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([Main.main],105)|))) -(assert (not (and |dn([Main.main],104)_dn([Main.main],105)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not |dn([Main.main],102)|)) -(assert (= |dn([8,Main.main],101)| (or |dn([8,Main.main],101)_dn([8,Main.main],96)| |dn([8,Main.main],101)_dn([8,Main.main],97)|))) -(assert (not (and |dn([8,Main.main],101)_dn([8,Main.main],96)| |dn([8,Main.main],101)_dn([8,Main.main],97)|))) -(assert (not (and |dn([8,Main.main],101)_dn([8,Main.main],97)| |dn([8,Main.main],101)_dn([8,Main.main],96)|))) -(assert (= |dn([6,9],95)| (or |dn([6,9],95)_dn([6,9],90)| |dn([6,9],95)_dn([6,9],91)| |dn([6,9],95)_dn([6,9],93)| |dn([6,9],95)_scc(1)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],90)| |dn([6,9],95)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],90)| |dn([6,9],95)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],90)| |dn([6,9],95)_scc(1)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],91)| |dn([6,9],95)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],91)| |dn([6,9],95)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],91)| |dn([6,9],95)_scc(1)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],93)| |dn([6,9],95)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],93)| |dn([6,9],95)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],93)| |dn([6,9],95)_scc(1)|))) -(assert (not (and |dn([6,9],95)_scc(1)| |dn([6,9],95)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],95)_scc(1)| |dn([6,9],95)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],95)_scc(1)| |dn([6,9],95)_dn([6,9],93)|))) -(assert (= |dn([8,Main.main],96)| (or |dn([8,Main.main],96)_dn([8,Main.main],97)|))) -(assert (= |dn([3,7],28)| (or |dn([3,7],28)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],33)| |dn([3,7],28)_scc(6)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],28)_scc(6)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],28)_scc(6)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([3,7],28)_scc(6)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |dn([3,7],28)_scc(6)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],28)_scc(6)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([3,7],28)_scc(6)|))) -(assert (not (and |dn([3,7],28)_scc(6)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_scc(6)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_scc(6)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_scc(6)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_scc(6)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_scc(6)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (= |dn([Main.main],106)| (or |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (= |dn([2,3],36)| (or |dn([2,3],36)_dn([3,7],31)| |dn([2,3],36)_dn([2,3],37)|))) -(assert (not (and |dn([2,3],36)_dn([3,7],31)| |dn([2,3],36)_dn([2,3],37)|))) -(assert (not (and |dn([2,3],36)_dn([2,3],37)| |dn([2,3],36)_dn([3,7],31)|))) -(assert (= |dn([4,1],78)| (or |dn([4,1],78)_dn([4,1],79)| |dn([4,1],78)_scc(4)|))) -(assert (not (and |dn([4,1],78)_dn([4,1],79)| |dn([4,1],78)_scc(4)|))) -(assert (not (and |dn([4,1],78)_scc(4)| |dn([4,1],78)_dn([4,1],79)|))) -(assert (= |dn([Main.main],114)| (or |dn([Main.main],114)_dn([9,Main.main],83)| |dn([Main.main],114)_dn([Main.main],115)|))) -(assert (not (and |dn([Main.main],114)_dn([9,Main.main],83)| |dn([Main.main],114)_dn([Main.main],115)|))) -(assert (not (and |dn([Main.main],114)_dn([Main.main],115)| |dn([Main.main],114)_dn([9,Main.main],83)|))) -(assert (= |dn([2,3],35)| (or |dn([2,3],35)_dn([3,7],33)| |dn([2,3],35)_dn([2,3],36)|))) -(assert (not (and |dn([2,3],35)_dn([3,7],33)| |dn([2,3],35)_dn([2,3],36)|))) -(assert (not (and |dn([2,3],35)_dn([2,3],36)| |dn([2,3],35)_dn([3,7],33)|))) -(assert (= |dn([2,3],38)| (or |dn([2,3],38)_dn([2,3],34)| |dn([2,3],38)_dn([2,3],35)|))) -(assert (not (and |dn([2,3],38)_dn([2,3],34)| |dn([2,3],38)_dn([2,3],35)|))) -(assert (not (and |dn([2,3],38)_dn([2,3],35)| |dn([2,3],38)_dn([2,3],34)|))) -(assert (= |dn([5,1],63)| (or |dn([5,1],63)_dn([5,1],61)| |dn([5,1],63)_dn([5,1],62)|))) -(assert (not (and |dn([5,1],63)_dn([5,1],61)| |dn([5,1],63)_dn([5,1],62)|))) -(assert (not (and |dn([5,1],63)_dn([5,1],62)| |dn([5,1],63)_dn([5,1],61)|))) -(assert (= |dn([7,Main.main],39)| (or |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (= |dn([3,7],33)| (or |dn([3,7],33)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (= |dn([9,Main.main],88)| (or |dn([9,Main.main],88)_dn([9,Main.main],89)|))) -(assert (= |dn([4,1],80)| (or |dn([4,1],80)_dn([4,1],81)|))) -(assert (= |dn([Main.main],116)| (or |dn([Main.main],116)_dn([Main.main],113)|))) -(assert (= |dn([Main.main],111)| (or |dn([Main.main],111)_dn([Main.main],102)| |dn([Main.main],111)_dn([Main.main],103)|))) -(assert (not (and |dn([Main.main],111)_dn([Main.main],102)| |dn([Main.main],111)_dn([Main.main],103)|))) -(assert (not (and |dn([Main.main],111)_dn([Main.main],103)| |dn([Main.main],111)_dn([Main.main],102)|))) -(assert (= |dn([7,Main.main],42)| (or |dn([7,Main.main],42)_dn([3,7],22)| |dn([7,Main.main],42)_dn([7,Main.main],43)|))) -(assert (not (and |dn([7,Main.main],42)_dn([3,7],22)| |dn([7,Main.main],42)_dn([7,Main.main],43)|))) -(assert (not (and |dn([7,Main.main],42)_dn([7,Main.main],43)| |dn([7,Main.main],42)_dn([3,7],22)|))) -(assert (= |dn([9,Main.main],85)| (or |dn([9,Main.main],85)_dn([9,Main.main],86)| |dn([9,Main.main],85)_dn([6,9],90)|))) -(assert (not (and |dn([9,Main.main],85)_dn([9,Main.main],86)| |dn([9,Main.main],85)_dn([6,9],90)|))) -(assert (not (and |dn([9,Main.main],85)_dn([6,9],90)| |dn([9,Main.main],85)_dn([9,Main.main],86)|))) -(assert (= |dn([3,7],27)| (or |dn([3,7],27)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],28)| |dn([3,7],27)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],30)| |dn([3,7],27)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],28)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],28)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],28)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],28)| |dn([3,7],27)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],28)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],28)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],30)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],30)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],30)| |dn([3,7],27)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],30)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],30)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],30)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (= |dn([1,3],64)| (or |dn([1,3],64)_dn([1,3],65)| |dn([1,3],64)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],64)_dn([1,3],65)| |dn([1,3],64)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],64)_dn([1,3],67)| |dn([1,3],64)_dn([1,3],65)|))) -(assert (= |dn([9,Main.main],83)| (or |dn([9,Main.main],83)_dn([9,Main.main],82)| |dn([9,Main.main],83)_dn([9,Main.main],84)| |dn([9,Main.main],83)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],82)| |dn([9,Main.main],83)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],82)| |dn([9,Main.main],83)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],84)| |dn([9,Main.main],83)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],84)| |dn([9,Main.main],83)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],88)| |dn([9,Main.main],83)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],88)| |dn([9,Main.main],83)_dn([9,Main.main],84)|))) -(assert (= |dn([1,3],67)| (or |dn([1,3],67)_dn([5,1],61)| |dn([1,3],67)_dn([1,3],68)|))) -(assert (not (and |dn([1,3],67)_dn([5,1],61)| |dn([1,3],67)_dn([1,3],68)|))) -(assert (not (and |dn([1,3],67)_dn([1,3],68)| |dn([1,3],67)_dn([5,1],61)|))) -(assert (= |dn([7,Main.main],40)| (or |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (= |dn([3,7],25)| (or |dn([3,7],25)_dn([1,3],67)|))) -(assert (= |dn([6,9],90)| (or |dn([6,9],90)_dn([6,9],91)| |dn([6,9],90)_dn([6,9],93)| |dn([6,9],90)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],91)| |dn([6,9],90)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],91)| |dn([6,9],90)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],93)| |dn([6,9],90)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],93)| |dn([6,9],90)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],95)| |dn([6,9],90)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],95)| |dn([6,9],90)_dn([6,9],93)|))) -(assert (= |dn([7,Main.main],60)| (or |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (= |dn([7,Main.main],50)| (or |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],50)_scc(1)|))) -(assert (= |dn([5,1],62)| (or |dn([5,1],62)_dn([5,1],61)| |dn([5,1],62)_dn([5,1],63)| |dn([5,1],62)_scc(2)|))) -(assert (not (and |dn([5,1],62)_dn([5,1],61)| |dn([5,1],62)_dn([5,1],63)|))) -(assert (not (and |dn([5,1],62)_dn([5,1],61)| |dn([5,1],62)_scc(2)|))) -(assert (not (and |dn([5,1],62)_dn([5,1],63)| |dn([5,1],62)_dn([5,1],61)|))) -(assert (not (and |dn([5,1],62)_dn([5,1],63)| |dn([5,1],62)_scc(2)|))) -(assert (not (and |dn([5,1],62)_scc(2)| |dn([5,1],62)_dn([5,1],61)|))) -(assert (not (and |dn([5,1],62)_scc(2)| |dn([5,1],62)_dn([5,1],63)|))) -(assert (= |dn([3,7],22)| (or |dn([3,7],22)_dn([1,3],65)|))) -(assert (= |dn([7,Main.main],53)| (or |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (= |dn([6,9],93)| (or |dn([6,9],93)_dn([9,Main.main],88)| |dn([6,9],93)_dn([6,9],94)|))) -(assert (not (and |dn([6,9],93)_dn([9,Main.main],88)| |dn([6,9],93)_dn([6,9],94)|))) -(assert (not (and |dn([6,9],93)_dn([6,9],94)| |dn([6,9],93)_dn([9,Main.main],88)|))) -(assert (= |dn([7,Main.main],57)| (or |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (= |dn([Main.main],108)| (or |dn([Main.main],108)_dn([8,Main.main],97)| |dn([Main.main],108)_dn([Main.main],109)|))) -(assert (not (and |dn([Main.main],108)_dn([8,Main.main],97)| |dn([Main.main],108)_dn([Main.main],109)|))) -(assert (not (and |dn([Main.main],108)_dn([Main.main],109)| |dn([Main.main],108)_dn([8,Main.main],97)|))) -(assert (= |dn([7,Main.main],55)| (or |dn([7,Main.main],55)_dn([6,9],95)|))) -(assert (= |scc(1)| (or |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([6,9],93)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([6,9],93)|))) -(assert (= |dn([Main.main],105)| (or |dn([Main.main],105)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([Main.main],106)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([Main.main],106)|))) -(assert (not (and |dn([Main.main],105)_dn([Main.main],106)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (= |scc(2)| (or |scc(2)_dn([3,7],20)| |scc(2)_dn([3,7],22)| |scc(2)_dn([3,7],27)| |scc(2)_dn([3,7],29)| |scc(2)_dn([3,7],31)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |scc(2)_dn([3,7],31)|))) -(assert (= |dn([8,Main.main],97)| (or |dn([8,Main.main],97)_dn([3,7],27)|))) -(assert (= |dn([Main.main],103)| (or |dn([Main.main],103)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([Main.main],104)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([Main.main],104)|))) -(assert (not (and |dn([Main.main],103)_dn([Main.main],104)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (= |scc(5)| (or |scc(5)_dn([5,1],63)| |scc(5)_dn([8,Main.main],100)|))) -(assert (not (and |scc(5)_dn([5,1],63)| |scc(5)_dn([8,Main.main],100)|))) -(assert (not (and |scc(5)_dn([8,Main.main],100)| |scc(5)_dn([5,1],63)|))) -(assert (not |dn([4,1],70)|)) -(assert (= |dn([6,9],94)| (or |dn([6,9],94)_dn([6,9],90)| |dn([6,9],94)_dn([6,9],91)| |dn([6,9],94)_dn([6,9],93)| |dn([6,9],94)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],90)| |dn([6,9],94)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],90)| |dn([6,9],94)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],90)| |dn([6,9],94)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],91)| |dn([6,9],94)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],91)| |dn([6,9],94)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],91)| |dn([6,9],94)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],93)| |dn([6,9],94)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],93)| |dn([6,9],94)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],93)| |dn([6,9],94)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],95)| |dn([6,9],94)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],95)| |dn([6,9],94)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],95)| |dn([6,9],94)_dn([6,9],93)|))) -(assert (= |dn([8,Main.main],100)| (or |dn([8,Main.main],100)_dn([4,1],78)| |dn([8,Main.main],100)_dn([8,Main.main],101)|))) -(assert (not (and |dn([8,Main.main],100)_dn([4,1],78)| |dn([8,Main.main],100)_dn([8,Main.main],101)|))) -(assert (not (and |dn([8,Main.main],100)_dn([8,Main.main],101)| |dn([8,Main.main],100)_dn([4,1],78)|))) -(assert (= |dn([7,Main.main],59)| (or |dn([7,Main.main],59)_dn([7,Main.main],60)| |dn([7,Main.main],59)_dn([6,9],95)|))) -(assert (not (and |dn([7,Main.main],59)_dn([7,Main.main],60)| |dn([7,Main.main],59)_dn([6,9],95)|))) -(assert (not (and |dn([7,Main.main],59)_dn([6,9],95)| |dn([7,Main.main],59)_dn([7,Main.main],60)|))) -(assert (= |dn([5,1],61)| (or |dn([5,1],61)_dn([5,1],62)| |dn([5,1],61)_dn([5,1],63)|))) -(assert (not (and |dn([5,1],61)_dn([5,1],62)| |dn([5,1],61)_dn([5,1],63)|))) -(assert (not (and |dn([5,1],61)_dn([5,1],63)| |dn([5,1],61)_dn([5,1],62)|))) -(assert (= |dn([4,1],69)| (or |dn([4,1],69)_dn([4,1],78)| |dn([4,1],69)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],69)_dn([4,1],78)| |dn([4,1],69)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],69)_dn([4,1],80)| |dn([4,1],69)_dn([4,1],78)|))) -(assert (= |dn([3,7],29)| (or |dn([3,7],29)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],28)| |dn([3,7],29)_dn([3,7],30)| |dn([3,7],29)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],28)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],28)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],28)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],28)| |dn([3,7],29)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],28)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],28)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],30)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],30)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],30)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],30)| |dn([3,7],29)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],30)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],30)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (= |dn([3,7],31)| (or |dn([3,7],31)_dn([5,1],62)|))) -(assert (= |dn([Main.main],113)| (or |dn([Main.main],113)_dn([9,Main.main],82)| |dn([Main.main],113)_dn([Main.main],114)|))) -(assert (not (and |dn([Main.main],113)_dn([9,Main.main],82)| |dn([Main.main],113)_dn([Main.main],114)|))) -(assert (not (and |dn([Main.main],113)_dn([Main.main],114)| |dn([Main.main],113)_dn([9,Main.main],82)|))) -(assert (= |dn([4,1],79)| (or |dn([4,1],79)_dn([4,1],69)| |dn([4,1],79)_dn([4,1],78)| |dn([4,1],79)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],69)| |dn([4,1],79)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],69)| |dn([4,1],79)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],78)| |dn([4,1],79)_dn([4,1],69)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],78)| |dn([4,1],79)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],80)| |dn([4,1],79)_dn([4,1],69)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],80)| |dn([4,1],79)_dn([4,1],78)|))) -(assert (= |dn([2,3],34)| (or |dn([2,3],34)_dn([2,3],35)|))) -(assert (= |dn([Main.main],115)| (or |dn([Main.main],115)_dn([Main.main],111)| |dn([Main.main],115)_dn([Main.main],116)|))) -(assert (not (and |dn([Main.main],115)_dn([Main.main],111)| |dn([Main.main],115)_dn([Main.main],116)|))) -(assert (not (and |dn([Main.main],115)_dn([Main.main],116)| |dn([Main.main],115)_dn([Main.main],111)|))) -(assert (= |dn([2,3],37)| (or |dn([2,3],37)_dn([2,3],38)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([2,3],38)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |dn([2,3],37)_dn([2,3],38)|))) -(assert (= |dn([1,3],68)| (or |dn([1,3],68)_dn([1,3],64)| |dn([1,3],68)_dn([1,3],65)| |dn([1,3],68)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],64)| |dn([1,3],68)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],64)| |dn([1,3],68)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],65)| |dn([1,3],68)_dn([1,3],64)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],65)| |dn([1,3],68)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],67)| |dn([1,3],68)_dn([1,3],64)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],67)| |dn([1,3],68)_dn([1,3],65)|))) -(assert (= |dn([4,1],81)| (or |dn([4,1],81)_dn([4,1],69)| |dn([4,1],81)_dn([4,1],78)| |dn([4,1],81)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],69)| |dn([4,1],81)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],69)| |dn([4,1],81)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],78)| |dn([4,1],81)_dn([4,1],69)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],78)| |dn([4,1],81)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],80)| |dn([4,1],81)_dn([4,1],69)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],80)| |dn([4,1],81)_dn([4,1],78)|))) -(assert (= |scc(7)| (or |scc(7)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],59)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_scc(1)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_scc(1)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_scc(1)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_scc(1)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_scc(1)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_scc(1)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_scc(1)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_scc(1)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_scc(1)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_scc(1)| |scc(7)_dn([7,Main.main],59)|))) -(assert (= |dn([9,Main.main],89)| (or |dn([9,Main.main],89)_dn([9,Main.main],82)| |dn([9,Main.main],89)_dn([9,Main.main],83)| |dn([9,Main.main],89)_dn([9,Main.main],84)| |dn([9,Main.main],89)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],82)| |dn([9,Main.main],89)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],82)| |dn([9,Main.main],89)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],82)| |dn([9,Main.main],89)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],83)| |dn([9,Main.main],89)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],83)| |dn([9,Main.main],89)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],83)| |dn([9,Main.main],89)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],84)| |dn([9,Main.main],89)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],84)| |dn([9,Main.main],89)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],84)| |dn([9,Main.main],89)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],88)| |dn([9,Main.main],89)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],88)| |dn([9,Main.main],89)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],88)| |dn([9,Main.main],89)_dn([9,Main.main],84)|))) -(assert (= |dn([1,3],66)| (or |dn([1,3],66)_dn([1,3],64)| |dn([1,3],66)_dn([1,3],65)| |dn([1,3],66)_dn([1,3],67)| |dn([1,3],66)_scc(0)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],64)| |dn([1,3],66)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],64)| |dn([1,3],66)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],64)| |dn([1,3],66)_scc(0)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],65)| |dn([1,3],66)_dn([1,3],64)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],65)| |dn([1,3],66)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],65)| |dn([1,3],66)_scc(0)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],67)| |dn([1,3],66)_dn([1,3],64)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],67)| |dn([1,3],66)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],67)| |dn([1,3],66)_scc(0)|))) -(assert (not (and |dn([1,3],66)_scc(0)| |dn([1,3],66)_dn([1,3],64)|))) -(assert (not (and |dn([1,3],66)_scc(0)| |dn([1,3],66)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],66)_scc(0)| |dn([1,3],66)_dn([1,3],67)|))) -(assert (= |dn([9,Main.main],84)| (or |dn([9,Main.main],84)_dn([9,Main.main],82)| |dn([9,Main.main],84)_dn([9,Main.main],83)| |dn([9,Main.main],84)_dn([9,Main.main],85)| |dn([9,Main.main],84)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],82)| |dn([9,Main.main],84)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],82)| |dn([9,Main.main],84)_dn([9,Main.main],85)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],82)| |dn([9,Main.main],84)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],83)| |dn([9,Main.main],84)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],83)| |dn([9,Main.main],84)_dn([9,Main.main],85)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],83)| |dn([9,Main.main],84)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],85)| |dn([9,Main.main],84)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],85)| |dn([9,Main.main],84)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],85)| |dn([9,Main.main],84)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],88)| |dn([9,Main.main],84)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],88)| |dn([9,Main.main],84)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],88)| |dn([9,Main.main],84)_dn([9,Main.main],85)|))) -(assert (= |dn([1,3],65)| (or |dn([1,3],65)_dn([1,3],66)| |dn([1,3],65)_dn([4,1],69)|))) -(assert (not (and |dn([1,3],65)_dn([1,3],66)| |dn([1,3],65)_dn([4,1],69)|))) -(assert (not (and |dn([1,3],65)_dn([4,1],69)| |dn([1,3],65)_dn([1,3],66)|))) -(assert (= |dn([7,Main.main],43)| (or |dn([7,Main.main],43)_dn([7,Main.main],40)|))) -(assert (= |dn([9,Main.main],82)| (or |dn([9,Main.main],82)_dn([9,Main.main],83)| |dn([9,Main.main],82)_dn([9,Main.main],84)| |dn([9,Main.main],82)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],83)| |dn([9,Main.main],82)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],83)| |dn([9,Main.main],82)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],84)| |dn([9,Main.main],82)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],84)| |dn([9,Main.main],82)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],88)| |dn([9,Main.main],82)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],88)| |dn([9,Main.main],82)_dn([9,Main.main],84)|))) -(assert (= |dn([7,Main.main],45)| (or |dn([7,Main.main],45)_dn([7,Main.main],40)|))) -(assert (= |dn([3,7],30)| (or |dn([3,7],30)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],33)| |dn([3,7],30)_scc(5)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],30)_scc(5)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],30)_scc(5)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([3,7],30)_scc(5)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |dn([3,7],30)_scc(5)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],30)_scc(5)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([3,7],30)_scc(5)|))) -(assert (not (and |dn([3,7],30)_scc(5)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_scc(5)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_scc(5)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_scc(5)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_scc(5)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_scc(5)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (= |scc(8)| (or |scc(8)_dn([8,Main.main],96)| |scc(8)_dn([Main.main],108)|))) -(assert (not (and |scc(8)_dn([8,Main.main],96)| |scc(8)_dn([Main.main],108)|))) -(assert (not (and |scc(8)_dn([Main.main],108)| |scc(8)_dn([8,Main.main],96)|))) -(assert (= |dn([9,Main.main],87)| (or |dn([9,Main.main],87)_dn([7,Main.main],53)| |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],87)_scc(7)|))) -(assert (not (and |dn([9,Main.main],87)_dn([7,Main.main],53)| |dn([9,Main.main],87)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],87)_dn([7,Main.main],53)| |dn([9,Main.main],87)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],87)_dn([7,Main.main],53)| |dn([9,Main.main],87)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],87)_dn([7,Main.main],53)| |dn([9,Main.main],87)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],87)_dn([7,Main.main],53)| |dn([9,Main.main],87)_scc(7)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([9,Main.main],87)_dn([7,Main.main],53)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([9,Main.main],87)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([9,Main.main],87)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([9,Main.main],87)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([9,Main.main],87)_scc(7)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([9,Main.main],87)_dn([7,Main.main],53)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([9,Main.main],87)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([9,Main.main],87)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([9,Main.main],87)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([9,Main.main],87)_scc(7)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([9,Main.main],87)_dn([7,Main.main],53)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([9,Main.main],87)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([9,Main.main],87)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([9,Main.main],87)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([9,Main.main],87)_scc(7)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],87)_dn([7,Main.main],53)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],87)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],87)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],87)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],87)_scc(7)|))) -(assert (not (and |dn([9,Main.main],87)_scc(7)| |dn([9,Main.main],87)_dn([7,Main.main],53)|))) -(assert (not (and |dn([9,Main.main],87)_scc(7)| |dn([9,Main.main],87)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],87)_scc(7)| |dn([9,Main.main],87)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],87)_scc(7)| |dn([9,Main.main],87)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],87)_scc(7)| |dn([9,Main.main],87)_dn([9,Main.main],88)|))) -(assert (= |dn([7,Main.main],49)| (or |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (= |scc(6)| (or |scc(6)_dn([3,7],29)|))) -(assert (= |dn([7,Main.main],41)| (or |dn([7,Main.main],47)_dn([7,Main.main],41)|))) -(assert (= |dn([3,7],24)| (or |scc(0)_dn([3,7],24)|))) -(assert (= |dn([7,Main.main],47)| (or |dn([Main.main],106)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (= |dn([9,Main.main],86)| (or |dn([9,Main.main],85)_dn([9,Main.main],86)|))) -(assert (= |dn([7,Main.main],51)| (or |dn([7,Main.main],50)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (= |dn([3,7],20)| (or |dn([7,Main.main],41)_dn([3,7],20)| |scc(2)_dn([3,7],20)| |scc(3)_dn([3,7],20)| |dn([3,7],21)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([7,Main.main],41)_dn([3,7],20)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |dn([7,Main.main],41)_dn([3,7],20)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |dn([7,Main.main],41)_dn([3,7],20)| |dn([3,7],21)_dn([3,7],20)|))) -(assert (not (and |dn([7,Main.main],41)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([7,Main.main],41)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([7,Main.main],41)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |dn([7,Main.main],41)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([7,Main.main],41)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |dn([7,Main.main],41)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |dn([3,7],21)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |dn([7,Main.main],41)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |dn([3,7],21)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],20)| |dn([7,Main.main],41)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],20)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],20)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([7,Main.main],41)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],21)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([7,Main.main],41)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],21)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |dn([7,Main.main],41)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |dn([3,7],21)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([7,Main.main],41)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],21)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([7,Main.main],41)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],21)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (= |dn([6,9],91)| (or |dn([9,Main.main],86)_dn([6,9],91)| |dn([6,9],90)_dn([6,9],91)| |dn([6,9],92)_dn([6,9],91)| |dn([6,9],94)_dn([6,9],91)| |dn([6,9],95)_dn([6,9],91)|))) -(assert (not (and |dn([9,Main.main],86)_dn([6,9],91)| |dn([6,9],90)_dn([6,9],91)|))) -(assert (not (and |dn([9,Main.main],86)_dn([6,9],91)| |dn([6,9],92)_dn([6,9],91)|))) -(assert (not (and |dn([9,Main.main],86)_dn([6,9],91)| |dn([6,9],94)_dn([6,9],91)|))) -(assert (not (and |dn([9,Main.main],86)_dn([6,9],91)| |dn([6,9],95)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],91)| |dn([9,Main.main],86)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],91)| |dn([6,9],92)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],91)| |dn([6,9],94)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],91)| |dn([6,9],95)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],91)| |dn([9,Main.main],86)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],91)| |dn([6,9],90)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],91)| |dn([6,9],94)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],91)| |dn([6,9],95)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],91)| |dn([9,Main.main],86)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],91)| |dn([6,9],90)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],91)| |dn([6,9],92)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],91)| |dn([6,9],95)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],91)| |dn([9,Main.main],86)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],91)| |dn([6,9],90)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],91)| |dn([6,9],92)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],91)| |dn([6,9],94)_dn([6,9],91)|))) -(assert (not |scc(3)|)) -(assert (= |dn([6,9],92)| (or |dn([6,9],91)_dn([6,9],92)|))) -(assert (= |scc(4)| (or |dn([4,1],78)_scc(4)|))) -(assert (= |dn([7,Main.main],54)| (or |dn([6,9],91)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (= |scc(0)| (or |dn([1,3],66)_scc(0)|))) -(assert (= |dn([Main.main],109)| (or |dn([Main.main],108)_dn([Main.main],109)|))) -(assert (= |dn([7,Main.main],58)| (or |dn([2,3],37)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (= |dn([Main.main],104)| (or |dn([Main.main],103)_dn([Main.main],104)|))) -(assert (= |dn([Main.main],102)| (or |dn([Main.main],111)_dn([Main.main],102)|))) -(assert (= |dn([8,Main.main],101)| (or |dn([8,Main.main],100)_dn([8,Main.main],101)|))) -(assert (= |dn([6,9],95)| (or |dn([7,Main.main],55)_dn([6,9],95)| |dn([7,Main.main],59)_dn([6,9],95)| |dn([6,9],90)_dn([6,9],95)| |dn([6,9],92)_dn([6,9],95)| |dn([6,9],94)_dn([6,9],95)|))) -(assert (not (and |dn([7,Main.main],55)_dn([6,9],95)| |dn([7,Main.main],59)_dn([6,9],95)|))) -(assert (not (and |dn([7,Main.main],55)_dn([6,9],95)| |dn([6,9],90)_dn([6,9],95)|))) -(assert (not (and |dn([7,Main.main],55)_dn([6,9],95)| |dn([6,9],92)_dn([6,9],95)|))) -(assert (not (and |dn([7,Main.main],55)_dn([6,9],95)| |dn([6,9],94)_dn([6,9],95)|))) -(assert (not (and |dn([7,Main.main],59)_dn([6,9],95)| |dn([7,Main.main],55)_dn([6,9],95)|))) -(assert (not (and |dn([7,Main.main],59)_dn([6,9],95)| |dn([6,9],90)_dn([6,9],95)|))) -(assert (not (and |dn([7,Main.main],59)_dn([6,9],95)| |dn([6,9],92)_dn([6,9],95)|))) -(assert (not (and |dn([7,Main.main],59)_dn([6,9],95)| |dn([6,9],94)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],95)| |dn([7,Main.main],55)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],95)| |dn([7,Main.main],59)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],95)| |dn([6,9],92)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],95)| |dn([6,9],94)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],95)| |dn([7,Main.main],55)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],95)| |dn([7,Main.main],59)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],95)| |dn([6,9],90)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],95)| |dn([6,9],94)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],95)| |dn([7,Main.main],55)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],95)| |dn([7,Main.main],59)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],95)| |dn([6,9],90)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],95)| |dn([6,9],92)_dn([6,9],95)|))) -(assert (= |dn([8,Main.main],96)| (or |scc(8)_dn([8,Main.main],96)| |dn([8,Main.main],101)_dn([8,Main.main],96)|))) -(assert (not (and |scc(8)_dn([8,Main.main],96)| |dn([8,Main.main],101)_dn([8,Main.main],96)|))) -(assert (not (and |dn([8,Main.main],101)_dn([8,Main.main],96)| |scc(8)_dn([8,Main.main],96)|))) -(assert (= |dn([3,7],28)| (or |dn([3,7],27)_dn([3,7],28)| |dn([3,7],29)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],28)| |dn([3,7],29)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],28)| |dn([3,7],27)_dn([3,7],28)|))) -(assert (= |dn([Main.main],106)| (or |dn([Main.main],105)_dn([Main.main],106)|))) -(assert (= |dn([2,3],36)| (or |dn([2,3],35)_dn([2,3],36)|))) -(assert (= |dn([4,1],78)| (or |dn([8,Main.main],100)_dn([4,1],78)| |dn([4,1],69)_dn([4,1],78)| |dn([4,1],79)_dn([4,1],78)| |dn([4,1],81)_dn([4,1],78)|))) -(assert (not (and |dn([8,Main.main],100)_dn([4,1],78)| |dn([4,1],69)_dn([4,1],78)|))) -(assert (not (and |dn([8,Main.main],100)_dn([4,1],78)| |dn([4,1],79)_dn([4,1],78)|))) -(assert (not (and |dn([8,Main.main],100)_dn([4,1],78)| |dn([4,1],81)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],69)_dn([4,1],78)| |dn([8,Main.main],100)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],69)_dn([4,1],78)| |dn([4,1],79)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],69)_dn([4,1],78)| |dn([4,1],81)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],78)| |dn([8,Main.main],100)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],78)| |dn([4,1],69)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],78)| |dn([4,1],81)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],78)| |dn([8,Main.main],100)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],78)| |dn([4,1],69)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],78)| |dn([4,1],79)_dn([4,1],78)|))) -(assert (= |dn([Main.main],114)| (or |dn([Main.main],113)_dn([Main.main],114)|))) -(assert (= |dn([2,3],35)| (or |scc(4)_dn([2,3],35)| |dn([2,3],34)_dn([2,3],35)| |dn([2,3],38)_dn([2,3],35)|))) -(assert (not (and |scc(4)_dn([2,3],35)| |dn([2,3],34)_dn([2,3],35)|))) -(assert (not (and |scc(4)_dn([2,3],35)| |dn([2,3],38)_dn([2,3],35)|))) -(assert (not (and |dn([2,3],34)_dn([2,3],35)| |scc(4)_dn([2,3],35)|))) -(assert (not (and |dn([2,3],34)_dn([2,3],35)| |dn([2,3],38)_dn([2,3],35)|))) -(assert (not (and |dn([2,3],38)_dn([2,3],35)| |scc(4)_dn([2,3],35)|))) -(assert (not (and |dn([2,3],38)_dn([2,3],35)| |dn([2,3],34)_dn([2,3],35)|))) -(assert (= |dn([2,3],38)| (or |dn([2,3],37)_dn([2,3],38)|))) -(assert (= |dn([5,1],63)| (or |scc(5)_dn([5,1],63)| |dn([5,1],61)_dn([5,1],63)| |dn([5,1],62)_dn([5,1],63)|))) -(assert (not (and |scc(5)_dn([5,1],63)| |dn([5,1],61)_dn([5,1],63)|))) -(assert (not (and |scc(5)_dn([5,1],63)| |dn([5,1],62)_dn([5,1],63)|))) -(assert (not (and |dn([5,1],61)_dn([5,1],63)| |scc(5)_dn([5,1],63)|))) -(assert (not (and |dn([5,1],61)_dn([5,1],63)| |dn([5,1],62)_dn([5,1],63)|))) -(assert (not (and |dn([5,1],62)_dn([5,1],63)| |scc(5)_dn([5,1],63)|))) -(assert (not (and |dn([5,1],62)_dn([5,1],63)| |dn([5,1],61)_dn([5,1],63)|))) -(assert (= |dn([7,Main.main],39)| (or |dn([Main.main],103)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (= |dn([3,7],33)| (or |dn([2,3],35)_dn([3,7],33)| |scc(2)_dn([3,7],33)| |scc(3)_dn([3,7],33)| |dn([3,7],21)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([2,3],35)_dn([3,7],33)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |dn([2,3],35)_dn([3,7],33)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |dn([2,3],35)_dn([3,7],33)| |dn([3,7],21)_dn([3,7],33)|))) -(assert (not (and |dn([2,3],35)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |dn([2,3],35)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |dn([2,3],35)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([2,3],35)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |dn([2,3],35)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |dn([3,7],21)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |dn([2,3],35)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |dn([3,7],21)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],33)| |dn([2,3],35)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],33)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],33)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([2,3],35)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([3,7],21)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([2,3],35)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([3,7],21)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([2,3],35)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([3,7],21)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([2,3],35)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([3,7],21)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (= |dn([9,Main.main],88)| (or |dn([6,9],93)_dn([9,Main.main],88)| |dn([9,Main.main],82)_dn([9,Main.main],88)| |dn([9,Main.main],83)_dn([9,Main.main],88)| |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],89)_dn([9,Main.main],88)| |dn([9,Main.main],84)_dn([9,Main.main],88)|))) -(assert (not (and |dn([6,9],93)_dn([9,Main.main],88)| |dn([9,Main.main],82)_dn([9,Main.main],88)|))) -(assert (not (and |dn([6,9],93)_dn([9,Main.main],88)| |dn([9,Main.main],83)_dn([9,Main.main],88)|))) -(assert (not (and |dn([6,9],93)_dn([9,Main.main],88)| |dn([9,Main.main],87)_dn([9,Main.main],88)|))) -(assert (not (and |dn([6,9],93)_dn([9,Main.main],88)| |dn([9,Main.main],89)_dn([9,Main.main],88)|))) -(assert (not (and |dn([6,9],93)_dn([9,Main.main],88)| |dn([9,Main.main],84)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],88)| |dn([6,9],93)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],88)| |dn([9,Main.main],83)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],88)| |dn([9,Main.main],87)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],88)| |dn([9,Main.main],89)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],88)| |dn([9,Main.main],84)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],88)| |dn([6,9],93)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],88)| |dn([9,Main.main],82)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],88)| |dn([9,Main.main],87)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],88)| |dn([9,Main.main],89)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],88)| |dn([9,Main.main],84)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([6,9],93)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],82)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],83)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],89)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],84)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],88)| |dn([6,9],93)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],88)| |dn([9,Main.main],82)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],88)| |dn([9,Main.main],83)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],88)| |dn([9,Main.main],87)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],88)| |dn([9,Main.main],84)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],88)| |dn([6,9],93)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],88)| |dn([9,Main.main],82)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],88)| |dn([9,Main.main],83)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],88)| |dn([9,Main.main],87)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],88)| |dn([9,Main.main],89)_dn([9,Main.main],88)|))) -(assert (= |dn([4,1],80)| (or |dn([3,7],24)_dn([4,1],80)| |dn([4,1],69)_dn([4,1],80)| |dn([4,1],79)_dn([4,1],80)| |dn([4,1],81)_dn([4,1],80)|))) -(assert (not (and |dn([3,7],24)_dn([4,1],80)| |dn([4,1],69)_dn([4,1],80)|))) -(assert (not (and |dn([3,7],24)_dn([4,1],80)| |dn([4,1],79)_dn([4,1],80)|))) -(assert (not (and |dn([3,7],24)_dn([4,1],80)| |dn([4,1],81)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],69)_dn([4,1],80)| |dn([3,7],24)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],69)_dn([4,1],80)| |dn([4,1],79)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],69)_dn([4,1],80)| |dn([4,1],81)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],80)| |dn([3,7],24)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],80)| |dn([4,1],69)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],80)| |dn([4,1],81)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],80)| |dn([3,7],24)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],80)| |dn([4,1],69)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],80)| |dn([4,1],79)_dn([4,1],80)|))) -(assert (= |dn([Main.main],116)| (or |dn([Main.main],115)_dn([Main.main],116)|))) -(assert (= |dn([Main.main],111)| (or |dn([Main.main],109)_dn([Main.main],111)| |dn([Main.main],115)_dn([Main.main],111)|))) -(assert (not (and |dn([Main.main],109)_dn([Main.main],111)| |dn([Main.main],115)_dn([Main.main],111)|))) -(assert (not (and |dn([Main.main],115)_dn([Main.main],111)| |dn([Main.main],109)_dn([Main.main],111)|))) -(assert (= |dn([7,Main.main],42)| (or |dn([7,Main.main],41)_dn([7,Main.main],42)|))) -(assert (= |dn([9,Main.main],85)| (or |dn([9,Main.main],84)_dn([9,Main.main],85)|))) -(assert (= |dn([3,7],27)| (or |dn([8,Main.main],97)_dn([3,7],27)| |scc(2)_dn([3,7],27)| |scc(3)_dn([3,7],27)| |dn([3,7],21)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([8,Main.main],97)_dn([3,7],27)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |dn([8,Main.main],97)_dn([3,7],27)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |dn([8,Main.main],97)_dn([3,7],27)| |dn([3,7],21)_dn([3,7],27)|))) -(assert (not (and |dn([8,Main.main],97)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([8,Main.main],97)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([8,Main.main],97)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (not (and |dn([8,Main.main],97)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |dn([8,Main.main],97)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |dn([3,7],21)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |dn([8,Main.main],97)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |dn([3,7],21)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],27)| |dn([8,Main.main],97)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],27)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],27)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([8,Main.main],97)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([3,7],21)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([8,Main.main],97)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([3,7],21)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |dn([8,Main.main],97)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |dn([3,7],21)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([8,Main.main],97)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([3,7],21)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (= |dn([1,3],64)| (or |dn([3,7],20)_dn([1,3],64)| |dn([1,3],66)_dn([1,3],64)| |dn([1,3],68)_dn([1,3],64)|))) -(assert (not (and |dn([3,7],20)_dn([1,3],64)| |dn([1,3],66)_dn([1,3],64)|))) -(assert (not (and |dn([3,7],20)_dn([1,3],64)| |dn([1,3],68)_dn([1,3],64)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],64)| |dn([3,7],20)_dn([1,3],64)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],64)| |dn([1,3],68)_dn([1,3],64)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],64)| |dn([3,7],20)_dn([1,3],64)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],64)| |dn([1,3],66)_dn([1,3],64)|))) -(assert (= |dn([9,Main.main],83)| (or |dn([Main.main],114)_dn([9,Main.main],83)| |dn([9,Main.main],82)_dn([9,Main.main],83)| |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([9,Main.main],89)_dn([9,Main.main],83)| |dn([9,Main.main],84)_dn([9,Main.main],83)|))) -(assert (not (and |dn([Main.main],114)_dn([9,Main.main],83)| |dn([9,Main.main],82)_dn([9,Main.main],83)|))) -(assert (not (and |dn([Main.main],114)_dn([9,Main.main],83)| |dn([9,Main.main],87)_dn([9,Main.main],83)|))) -(assert (not (and |dn([Main.main],114)_dn([9,Main.main],83)| |dn([9,Main.main],89)_dn([9,Main.main],83)|))) -(assert (not (and |dn([Main.main],114)_dn([9,Main.main],83)| |dn([9,Main.main],84)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],83)| |dn([Main.main],114)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],83)| |dn([9,Main.main],87)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],83)| |dn([9,Main.main],89)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],83)| |dn([9,Main.main],84)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([Main.main],114)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([9,Main.main],82)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([9,Main.main],89)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([9,Main.main],84)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],83)| |dn([Main.main],114)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],83)| |dn([9,Main.main],82)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],83)| |dn([9,Main.main],87)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],83)| |dn([9,Main.main],84)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],83)| |dn([Main.main],114)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],83)| |dn([9,Main.main],82)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],83)| |dn([9,Main.main],87)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],83)| |dn([9,Main.main],89)_dn([9,Main.main],83)|))) -(assert (= |dn([1,3],67)| (or |dn([3,7],25)_dn([1,3],67)| |dn([1,3],64)_dn([1,3],67)| |dn([1,3],66)_dn([1,3],67)| |dn([1,3],68)_dn([1,3],67)|))) -(assert (not (and |dn([3,7],25)_dn([1,3],67)| |dn([1,3],64)_dn([1,3],67)|))) -(assert (not (and |dn([3,7],25)_dn([1,3],67)| |dn([1,3],66)_dn([1,3],67)|))) -(assert (not (and |dn([3,7],25)_dn([1,3],67)| |dn([1,3],68)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],64)_dn([1,3],67)| |dn([3,7],25)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],64)_dn([1,3],67)| |dn([1,3],66)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],64)_dn([1,3],67)| |dn([1,3],68)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],67)| |dn([3,7],25)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],67)| |dn([1,3],64)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],67)| |dn([1,3],68)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],67)| |dn([3,7],25)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],67)| |dn([1,3],64)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],67)| |dn([1,3],66)_dn([1,3],67)|))) -(assert (= |dn([7,Main.main],40)| (or |dn([7,Main.main],43)_dn([7,Main.main],40)| |dn([7,Main.main],45)_dn([7,Main.main],40)|))) -(assert (not (and |dn([7,Main.main],43)_dn([7,Main.main],40)| |dn([7,Main.main],45)_dn([7,Main.main],40)|))) -(assert (not (and |dn([7,Main.main],45)_dn([7,Main.main],40)| |dn([7,Main.main],43)_dn([7,Main.main],40)|))) -(assert (= |dn([3,7],25)| (or |dn([3,7],24)_dn([3,7],25)|))) -(assert (= |dn([6,9],90)| (or |dn([9,Main.main],85)_dn([6,9],90)| |dn([6,9],92)_dn([6,9],90)| |dn([6,9],94)_dn([6,9],90)| |dn([6,9],95)_dn([6,9],90)|))) -(assert (not (and |dn([9,Main.main],85)_dn([6,9],90)| |dn([6,9],92)_dn([6,9],90)|))) -(assert (not (and |dn([9,Main.main],85)_dn([6,9],90)| |dn([6,9],94)_dn([6,9],90)|))) -(assert (not (and |dn([9,Main.main],85)_dn([6,9],90)| |dn([6,9],95)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],90)| |dn([9,Main.main],85)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],90)| |dn([6,9],94)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],90)| |dn([6,9],95)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],90)| |dn([9,Main.main],85)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],90)| |dn([6,9],92)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],90)| |dn([6,9],95)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],90)| |dn([9,Main.main],85)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],90)| |dn([6,9],92)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],90)| |dn([6,9],94)_dn([6,9],90)|))) -(assert (= |dn([7,Main.main],60)| (or |dn([7,Main.main],59)_dn([7,Main.main],60)|))) -(assert (= |dn([7,Main.main],50)| (or |dn([Main.main],105)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (= |dn([5,1],62)| (or |dn([3,7],31)_dn([5,1],62)| |dn([5,1],61)_dn([5,1],62)| |dn([5,1],63)_dn([5,1],62)|))) -(assert (not (and |dn([3,7],31)_dn([5,1],62)| |dn([5,1],61)_dn([5,1],62)|))) -(assert (not (and |dn([3,7],31)_dn([5,1],62)| |dn([5,1],63)_dn([5,1],62)|))) -(assert (not (and |dn([5,1],61)_dn([5,1],62)| |dn([3,7],31)_dn([5,1],62)|))) -(assert (not (and |dn([5,1],61)_dn([5,1],62)| |dn([5,1],63)_dn([5,1],62)|))) -(assert (not (and |dn([5,1],63)_dn([5,1],62)| |dn([3,7],31)_dn([5,1],62)|))) -(assert (not (and |dn([5,1],63)_dn([5,1],62)| |dn([5,1],61)_dn([5,1],62)|))) -(assert (= |dn([3,7],22)| (or |dn([7,Main.main],42)_dn([3,7],22)| |scc(2)_dn([3,7],22)| |scc(3)_dn([3,7],22)| |dn([3,7],21)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([7,Main.main],42)_dn([3,7],22)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |dn([7,Main.main],42)_dn([3,7],22)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |dn([7,Main.main],42)_dn([3,7],22)| |dn([3,7],21)_dn([3,7],22)|))) -(assert (not (and |dn([7,Main.main],42)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([7,Main.main],42)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([7,Main.main],42)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |dn([7,Main.main],42)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([7,Main.main],42)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |dn([7,Main.main],42)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |dn([3,7],21)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |dn([7,Main.main],42)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |dn([3,7],21)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],22)| |dn([7,Main.main],42)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],22)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],22)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([7,Main.main],42)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],21)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([7,Main.main],42)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],21)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |dn([7,Main.main],42)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |dn([3,7],21)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([7,Main.main],42)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],21)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([7,Main.main],42)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],21)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (= |dn([7,Main.main],53)| (or |dn([9,Main.main],87)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |dn([9,Main.main],87)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |dn([9,Main.main],87)_dn([7,Main.main],53)|))) -(assert (= |dn([6,9],93)| (or |scc(1)_dn([6,9],93)| |dn([6,9],90)_dn([6,9],93)| |dn([6,9],92)_dn([6,9],93)| |dn([6,9],94)_dn([6,9],93)| |dn([6,9],95)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |dn([6,9],90)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |dn([6,9],92)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |dn([6,9],94)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |dn([6,9],95)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],93)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],93)| |dn([6,9],92)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],93)| |dn([6,9],94)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],93)| |dn([6,9],95)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],93)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],93)| |dn([6,9],90)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],93)| |dn([6,9],94)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],93)| |dn([6,9],95)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],93)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],93)| |dn([6,9],90)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],93)| |dn([6,9],92)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],93)| |dn([6,9],95)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],93)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],93)| |dn([6,9],90)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],93)| |dn([6,9],92)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],93)| |dn([6,9],94)_dn([6,9],93)|))) -(assert (= |dn([7,Main.main],57)| (or |scc(1)_dn([7,Main.main],57)|))) -(assert (= |dn([Main.main],108)| (or |scc(8)_dn([Main.main],108)|))) -(assert (= |dn([7,Main.main],55)| (or |dn([7,Main.main],54)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (= |scc(1)| (or |dn([6,9],95)_scc(1)| |scc(7)_scc(1)| |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([6,9],95)_scc(1)| |scc(7)_scc(1)|))) -(assert (not (and |dn([6,9],95)_scc(1)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([6,9],95)_scc(1)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |dn([6,9],95)_scc(1)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |scc(7)_scc(1)| |dn([6,9],95)_scc(1)|))) -(assert (not (and |scc(7)_scc(1)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |scc(7)_scc(1)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |scc(7)_scc(1)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([6,9],95)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |scc(7)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([6,9],95)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |scc(7)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([6,9],95)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |scc(7)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],54)_scc(1)|))) -(assert (= |dn([Main.main],105)| (or |dn([Main.main],104)_dn([Main.main],105)|))) -(assert (= |scc(2)| (or |dn([5,1],62)_scc(2)|))) -(assert (= |dn([8,Main.main],97)| (or |dn([Main.main],108)_dn([8,Main.main],97)| |dn([8,Main.main],96)_dn([8,Main.main],97)| |dn([8,Main.main],101)_dn([8,Main.main],97)|))) -(assert (not (and |dn([Main.main],108)_dn([8,Main.main],97)| |dn([8,Main.main],96)_dn([8,Main.main],97)|))) -(assert (not (and |dn([Main.main],108)_dn([8,Main.main],97)| |dn([8,Main.main],101)_dn([8,Main.main],97)|))) -(assert (not (and |dn([8,Main.main],96)_dn([8,Main.main],97)| |dn([Main.main],108)_dn([8,Main.main],97)|))) -(assert (not (and |dn([8,Main.main],96)_dn([8,Main.main],97)| |dn([8,Main.main],101)_dn([8,Main.main],97)|))) -(assert (not (and |dn([8,Main.main],101)_dn([8,Main.main],97)| |dn([Main.main],108)_dn([8,Main.main],97)|))) -(assert (not (and |dn([8,Main.main],101)_dn([8,Main.main],97)| |dn([8,Main.main],96)_dn([8,Main.main],97)|))) -(assert (= |dn([Main.main],103)| (or |dn([Main.main],111)_dn([Main.main],103)|))) -(assert (= |scc(5)| (or |dn([3,7],30)_scc(5)|))) -(assert (= |dn([4,1],70)| (or |scc(4)_dn([4,1],70)|))) -(assert (= |dn([6,9],94)| (or |dn([6,9],93)_dn([6,9],94)|))) -(assert (= |dn([8,Main.main],100)| (or |scc(5)_dn([8,Main.main],100)|))) -(assert (= |dn([7,Main.main],59)| (or |dn([7,Main.main],58)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (= |dn([5,1],61)| (or |dn([1,3],67)_dn([5,1],61)| |dn([5,1],62)_dn([5,1],61)| |dn([5,1],63)_dn([5,1],61)|))) -(assert (not (and |dn([1,3],67)_dn([5,1],61)| |dn([5,1],62)_dn([5,1],61)|))) -(assert (not (and |dn([1,3],67)_dn([5,1],61)| |dn([5,1],63)_dn([5,1],61)|))) -(assert (not (and |dn([5,1],62)_dn([5,1],61)| |dn([1,3],67)_dn([5,1],61)|))) -(assert (not (and |dn([5,1],62)_dn([5,1],61)| |dn([5,1],63)_dn([5,1],61)|))) -(assert (not (and |dn([5,1],63)_dn([5,1],61)| |dn([1,3],67)_dn([5,1],61)|))) -(assert (not (and |dn([5,1],63)_dn([5,1],61)| |dn([5,1],62)_dn([5,1],61)|))) -(assert (= |dn([4,1],69)| (or |dn([1,3],65)_dn([4,1],69)| |dn([4,1],79)_dn([4,1],69)| |dn([4,1],81)_dn([4,1],69)|))) -(assert (not (and |dn([1,3],65)_dn([4,1],69)| |dn([4,1],79)_dn([4,1],69)|))) -(assert (not (and |dn([1,3],65)_dn([4,1],69)| |dn([4,1],81)_dn([4,1],69)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],69)| |dn([1,3],65)_dn([4,1],69)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],69)| |dn([4,1],81)_dn([4,1],69)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],69)| |dn([1,3],65)_dn([4,1],69)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],69)| |dn([4,1],79)_dn([4,1],69)|))) -(assert (= |dn([3,7],29)| (or |scc(6)_dn([3,7],29)| |scc(2)_dn([3,7],29)| |scc(3)_dn([3,7],29)| |dn([3,7],21)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |scc(6)_dn([3,7],29)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |scc(6)_dn([3,7],29)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |scc(6)_dn([3,7],29)| |dn([3,7],21)_dn([3,7],29)|))) -(assert (not (and |scc(6)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |scc(6)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |scc(6)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (not (and |scc(6)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |scc(6)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |dn([3,7],21)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |scc(6)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |dn([3,7],21)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],29)| |scc(6)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],29)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],29)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |scc(6)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |dn([3,7],21)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |scc(6)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |dn([3,7],21)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |scc(6)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |dn([3,7],21)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |scc(6)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |dn([3,7],21)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (= |dn([3,7],31)| (or |dn([2,3],36)_dn([3,7],31)| |scc(2)_dn([3,7],31)| |scc(3)_dn([3,7],31)| |dn([3,7],21)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([2,3],36)_dn([3,7],31)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |dn([2,3],36)_dn([3,7],31)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |dn([2,3],36)_dn([3,7],31)| |dn([3,7],21)_dn([3,7],31)|))) -(assert (not (and |dn([2,3],36)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([2,3],36)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([2,3],36)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([2,3],36)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |dn([2,3],36)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |dn([2,3],36)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |dn([3,7],21)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |dn([2,3],36)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |dn([3,7],21)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],31)| |dn([2,3],36)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],31)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],31)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([2,3],36)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],21)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([2,3],36)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],21)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |dn([2,3],36)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |dn([3,7],21)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([2,3],36)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],21)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([2,3],36)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],21)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (= |dn([4,1],79)| (or |dn([4,1],78)_dn([4,1],79)|))) -(assert (= |dn([2,3],34)| (or |scc(0)_dn([2,3],34)| |dn([2,3],38)_dn([2,3],34)|))) -(assert (not (and |scc(0)_dn([2,3],34)| |dn([2,3],38)_dn([2,3],34)|))) -(assert (not (and |dn([2,3],38)_dn([2,3],34)| |scc(0)_dn([2,3],34)|))) -(assert (= |dn([Main.main],115)| (or |dn([Main.main],114)_dn([Main.main],115)|))) -(assert (= |dn([2,3],37)| (or |dn([2,3],36)_dn([2,3],37)|))) -(assert (= |dn([1,3],68)| (or |dn([1,3],67)_dn([1,3],68)|))) -(assert (= |dn([4,1],81)| (or |dn([4,1],80)_dn([4,1],81)|))) -(assert (= |scc(7)| (or |dn([9,Main.main],87)_scc(7)| |scc(1)_scc(7)| |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([9,Main.main],87)_scc(7)| |scc(1)_scc(7)|))) -(assert (not (and |dn([9,Main.main],87)_scc(7)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([9,Main.main],87)_scc(7)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([9,Main.main],87)_scc(7)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |scc(1)_scc(7)| |dn([9,Main.main],87)_scc(7)|))) -(assert (not (and |scc(1)_scc(7)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |scc(1)_scc(7)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |scc(1)_scc(7)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([9,Main.main],87)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |scc(1)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([9,Main.main],87)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |scc(1)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([9,Main.main],87)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |scc(1)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],54)_scc(7)|))) -(assert (= |dn([9,Main.main],89)| (or |dn([9,Main.main],88)_dn([9,Main.main],89)|))) -(assert (= |dn([1,3],66)| (or |dn([1,3],65)_dn([1,3],66)|))) -(assert (= |dn([9,Main.main],84)| (or |dn([7,Main.main],51)_dn([9,Main.main],84)| |dn([9,Main.main],82)_dn([9,Main.main],84)| |dn([9,Main.main],83)_dn([9,Main.main],84)| |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([9,Main.main],89)_dn([9,Main.main],84)|))) -(assert (not (and |dn([7,Main.main],51)_dn([9,Main.main],84)| |dn([9,Main.main],82)_dn([9,Main.main],84)|))) -(assert (not (and |dn([7,Main.main],51)_dn([9,Main.main],84)| |dn([9,Main.main],83)_dn([9,Main.main],84)|))) -(assert (not (and |dn([7,Main.main],51)_dn([9,Main.main],84)| |dn([9,Main.main],87)_dn([9,Main.main],84)|))) -(assert (not (and |dn([7,Main.main],51)_dn([9,Main.main],84)| |dn([9,Main.main],89)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],84)| |dn([7,Main.main],51)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],84)| |dn([9,Main.main],83)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],84)| |dn([9,Main.main],87)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],84)| |dn([9,Main.main],89)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],84)| |dn([7,Main.main],51)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],84)| |dn([9,Main.main],82)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],84)| |dn([9,Main.main],87)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],84)| |dn([9,Main.main],89)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([7,Main.main],51)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([9,Main.main],82)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([9,Main.main],83)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([9,Main.main],89)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],84)| |dn([7,Main.main],51)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],84)| |dn([9,Main.main],82)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],84)| |dn([9,Main.main],83)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],84)| |dn([9,Main.main],87)_dn([9,Main.main],84)|))) -(assert (= |dn([1,3],65)| (or |dn([3,7],22)_dn([1,3],65)| |dn([1,3],64)_dn([1,3],65)| |dn([1,3],66)_dn([1,3],65)| |dn([1,3],68)_dn([1,3],65)|))) -(assert (not (and |dn([3,7],22)_dn([1,3],65)| |dn([1,3],64)_dn([1,3],65)|))) -(assert (not (and |dn([3,7],22)_dn([1,3],65)| |dn([1,3],66)_dn([1,3],65)|))) -(assert (not (and |dn([3,7],22)_dn([1,3],65)| |dn([1,3],68)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],64)_dn([1,3],65)| |dn([3,7],22)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],64)_dn([1,3],65)| |dn([1,3],66)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],64)_dn([1,3],65)| |dn([1,3],68)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],65)| |dn([3,7],22)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],65)| |dn([1,3],64)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],65)| |dn([1,3],68)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],65)| |dn([3,7],22)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],65)| |dn([1,3],64)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],65)| |dn([1,3],66)_dn([1,3],65)|))) -(assert (= |dn([7,Main.main],43)| (or |dn([7,Main.main],42)_dn([7,Main.main],43)|))) -(assert (= |dn([9,Main.main],82)| (or |dn([Main.main],113)_dn([9,Main.main],82)| |dn([9,Main.main],83)_dn([9,Main.main],82)| |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([9,Main.main],89)_dn([9,Main.main],82)| |dn([9,Main.main],84)_dn([9,Main.main],82)|))) -(assert (not (and |dn([Main.main],113)_dn([9,Main.main],82)| |dn([9,Main.main],83)_dn([9,Main.main],82)|))) -(assert (not (and |dn([Main.main],113)_dn([9,Main.main],82)| |dn([9,Main.main],87)_dn([9,Main.main],82)|))) -(assert (not (and |dn([Main.main],113)_dn([9,Main.main],82)| |dn([9,Main.main],89)_dn([9,Main.main],82)|))) -(assert (not (and |dn([Main.main],113)_dn([9,Main.main],82)| |dn([9,Main.main],84)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],82)| |dn([Main.main],113)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],82)| |dn([9,Main.main],87)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],82)| |dn([9,Main.main],89)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],82)| |dn([9,Main.main],84)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([Main.main],113)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([9,Main.main],83)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([9,Main.main],89)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([9,Main.main],84)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],82)| |dn([Main.main],113)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],82)| |dn([9,Main.main],83)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],82)| |dn([9,Main.main],87)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],82)| |dn([9,Main.main],84)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],82)| |dn([Main.main],113)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],82)| |dn([9,Main.main],83)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],82)| |dn([9,Main.main],87)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],82)| |dn([9,Main.main],89)_dn([9,Main.main],82)|))) -(assert (= |dn([7,Main.main],45)| (or |dn([7,Main.main],47)_dn([7,Main.main],45)|))) -(assert (= |dn([3,7],30)| (or |dn([3,7],29)_dn([3,7],30)| |dn([3,7],27)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],30)| |dn([3,7],27)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],30)| |dn([3,7],29)_dn([3,7],30)|))) -(assert (not |scc(8)|)) -(assert (= |dn([9,Main.main],87)| (or |dn([9,Main.main],86)_dn([9,Main.main],87)|))) -(assert (= |dn([3,7],21)| (or |dn([3,7],20)_dn([3,7],21)|))) -(assert (= |dn([7,Main.main],49)| (or |dn([Main.main],104)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (= |scc(6)| (or |dn([3,7],28)_scc(6)|))) -(assert-soft |dn([7,Main.main],41)_dn([3,7],20)| :weight 1) -(assert-soft |scc(2)_dn([3,7],20)| :weight 1) -(assert-soft |scc(3)_dn([3,7],20)| :weight 1) -(assert-soft |dn([3,7],21)_dn([3,7],20)| :weight 1) -(assert-soft |dn([3,7],28)_dn([3,7],20)| :weight 1) -(assert-soft |dn([3,7],30)_dn([3,7],20)| :weight 1) -(assert-soft |dn([3,7],33)_dn([3,7],20)| :weight 1) -(assert-soft |dn([3,7],27)_dn([3,7],20)| :weight 1) -(assert-soft |dn([3,7],29)_dn([3,7],20)| :weight 1) -(assert-soft |dn([3,7],20)_dn([3,7],21)| :weight 1) -(assert-soft |dn([7,Main.main],42)_dn([3,7],22)| :weight 1) -(assert-soft |scc(2)_dn([3,7],22)| :weight 1) -(assert-soft |scc(3)_dn([3,7],22)| :weight 1) -(assert-soft |dn([3,7],21)_dn([3,7],22)| :weight 1) -(assert-soft |dn([3,7],28)_dn([3,7],22)| :weight 1) -(assert-soft |dn([3,7],30)_dn([3,7],22)| :weight 1) -(assert-soft |dn([3,7],33)_dn([3,7],22)| :weight 1) -(assert-soft |dn([3,7],27)_dn([3,7],22)| :weight 1) -(assert-soft |dn([3,7],29)_dn([3,7],22)| :weight 1) -(assert-soft |scc(0)_dn([3,7],24)| :weight 1) -(assert-soft |dn([3,7],24)_dn([3,7],25)| :weight 1) -(assert-soft |dn([8,Main.main],97)_dn([3,7],27)| :weight 2) -(assert-soft |scc(2)_dn([3,7],27)| :weight 2) -(assert-soft |scc(3)_dn([3,7],27)| :weight 2) -(assert-soft |dn([3,7],21)_dn([3,7],27)| :weight 2) -(assert-soft |dn([3,7],28)_dn([3,7],27)| :weight 2) -(assert-soft |dn([3,7],30)_dn([3,7],27)| :weight 2) -(assert-soft |dn([3,7],33)_dn([3,7],27)| :weight 2) -(assert-soft |dn([3,7],29)_dn([3,7],27)| :weight 2) -(assert-soft |dn([3,7],27)_dn([3,7],28)| :weight 6) -(assert-soft |dn([3,7],29)_dn([3,7],28)| :weight 6) -(assert-soft |scc(6)_dn([3,7],29)| :weight 2) -(assert-soft |scc(2)_dn([3,7],29)| :weight 2) -(assert-soft |scc(3)_dn([3,7],29)| :weight 2) -(assert-soft |dn([3,7],21)_dn([3,7],29)| :weight 2) -(assert-soft |dn([3,7],28)_dn([3,7],29)| :weight 2) -(assert-soft |dn([3,7],30)_dn([3,7],29)| :weight 2) -(assert-soft |dn([3,7],33)_dn([3,7],29)| :weight 2) -(assert-soft |dn([3,7],27)_dn([3,7],29)| :weight 2) -(assert-soft |dn([3,7],29)_dn([3,7],30)| :weight 6) -(assert-soft |dn([3,7],27)_dn([3,7],30)| :weight 6) -(assert-soft |dn([2,3],36)_dn([3,7],31)| :weight 1) -(assert-soft |scc(2)_dn([3,7],31)| :weight 1) -(assert-soft |scc(3)_dn([3,7],31)| :weight 1) -(assert-soft |dn([3,7],21)_dn([3,7],31)| :weight 1) -(assert-soft |dn([3,7],28)_dn([3,7],31)| :weight 1) -(assert-soft |dn([3,7],30)_dn([3,7],31)| :weight 1) -(assert-soft |dn([3,7],33)_dn([3,7],31)| :weight 1) -(assert-soft |dn([3,7],27)_dn([3,7],31)| :weight 1) -(assert-soft |dn([3,7],29)_dn([3,7],31)| :weight 1) -(assert-soft |dn([2,3],35)_dn([3,7],33)| :weight 1) -(assert-soft |scc(2)_dn([3,7],33)| :weight 1) -(assert-soft |scc(3)_dn([3,7],33)| :weight 1) -(assert-soft |dn([3,7],21)_dn([3,7],33)| :weight 1) -(assert-soft |dn([3,7],28)_dn([3,7],33)| :weight 1) -(assert-soft |dn([3,7],30)_dn([3,7],33)| :weight 1) -(assert-soft |dn([3,7],27)_dn([3,7],33)| :weight 1) -(assert-soft |dn([3,7],29)_dn([3,7],33)| :weight 1) -(assert-soft |scc(0)_dn([2,3],34)| :weight 1) -(assert-soft |dn([2,3],38)_dn([2,3],34)| :weight 1) -(assert-soft |scc(4)_dn([2,3],35)| :weight 1) -(assert-soft |dn([2,3],34)_dn([2,3],35)| :weight 1) -(assert-soft |dn([2,3],38)_dn([2,3],35)| :weight 1) -(assert-soft |dn([2,3],35)_dn([2,3],36)| :weight 1) -(assert-soft |dn([2,3],36)_dn([2,3],37)| :weight 1) -(assert-soft |dn([2,3],37)_dn([2,3],38)| :weight 1) -(assert-soft |dn([Main.main],103)_dn([7,Main.main],39)| :weight 6) -(assert-soft |dn([7,Main.main],40)_dn([7,Main.main],39)| :weight 6) -(assert-soft |dn([7,Main.main],49)_dn([7,Main.main],39)| :weight 6) -(assert-soft |dn([7,Main.main],53)_dn([7,Main.main],39)| :weight 6) -(assert-soft |dn([7,Main.main],57)_dn([7,Main.main],39)| :weight 6) -(assert-soft |dn([7,Main.main],60)_dn([7,Main.main],39)| :weight 6) -(assert-soft |scc(1)_dn([7,Main.main],39)| :weight 6) -(assert-soft |scc(7)_dn([7,Main.main],39)| :weight 6) -(assert-soft |dn([7,Main.main],50)_dn([7,Main.main],39)| :weight 6) -(assert-soft |dn([7,Main.main],54)_dn([7,Main.main],39)| :weight 6) -(assert-soft |dn([7,Main.main],58)_dn([7,Main.main],39)| :weight 6) -(assert-soft |dn([7,Main.main],43)_dn([7,Main.main],40)| :weight 4) -(assert-soft |dn([7,Main.main],45)_dn([7,Main.main],40)| :weight 4) -(assert-soft |dn([7,Main.main],47)_dn([7,Main.main],41)| :weight 1) -(assert-soft |dn([7,Main.main],41)_dn([7,Main.main],42)| :weight 1) -(assert-soft |dn([7,Main.main],42)_dn([7,Main.main],43)| :weight 1) -(assert-soft |dn([7,Main.main],47)_dn([7,Main.main],45)| :weight 4) -(assert-soft |dn([Main.main],106)_dn([7,Main.main],47)| :weight 8) -(assert-soft |dn([7,Main.main],39)_dn([7,Main.main],47)| :weight 8) -(assert-soft |dn([7,Main.main],40)_dn([7,Main.main],47)| :weight 8) -(assert-soft |dn([7,Main.main],49)_dn([7,Main.main],47)| :weight 8) -(assert-soft |dn([7,Main.main],53)_dn([7,Main.main],47)| :weight 8) -(assert-soft |dn([7,Main.main],57)_dn([7,Main.main],47)| :weight 8) -(assert-soft |dn([7,Main.main],60)_dn([7,Main.main],47)| :weight 8) -(assert-soft |scc(1)_dn([7,Main.main],47)| :weight 8) -(assert-soft |scc(7)_dn([7,Main.main],47)| :weight 8) -(assert-soft |dn([7,Main.main],50)_dn([7,Main.main],47)| :weight 8) -(assert-soft |dn([7,Main.main],54)_dn([7,Main.main],47)| :weight 8) -(assert-soft |dn([7,Main.main],58)_dn([7,Main.main],47)| :weight 8) -(assert-soft |dn([Main.main],104)_dn([7,Main.main],49)| :weight 8) -(assert-soft |dn([7,Main.main],39)_dn([7,Main.main],49)| :weight 8) -(assert-soft |dn([7,Main.main],40)_dn([7,Main.main],49)| :weight 8) -(assert-soft |dn([7,Main.main],53)_dn([7,Main.main],49)| :weight 8) -(assert-soft |dn([7,Main.main],57)_dn([7,Main.main],49)| :weight 8) -(assert-soft |dn([7,Main.main],60)_dn([7,Main.main],49)| :weight 8) -(assert-soft |scc(1)_dn([7,Main.main],49)| :weight 8) -(assert-soft |scc(7)_dn([7,Main.main],49)| :weight 8) -(assert-soft |dn([7,Main.main],50)_dn([7,Main.main],49)| :weight 8) -(assert-soft |dn([7,Main.main],54)_dn([7,Main.main],49)| :weight 8) -(assert-soft |dn([7,Main.main],58)_dn([7,Main.main],49)| :weight 8) -(assert-soft |dn([Main.main],105)_dn([7,Main.main],50)| :weight 2) -(assert-soft |dn([7,Main.main],39)_dn([7,Main.main],50)| :weight 2) -(assert-soft |dn([7,Main.main],40)_dn([7,Main.main],50)| :weight 2) -(assert-soft |dn([7,Main.main],49)_dn([7,Main.main],50)| :weight 2) -(assert-soft |dn([7,Main.main],53)_dn([7,Main.main],50)| :weight 2) -(assert-soft |dn([7,Main.main],57)_dn([7,Main.main],50)| :weight 2) -(assert-soft |dn([7,Main.main],60)_dn([7,Main.main],50)| :weight 2) -(assert-soft |scc(1)_dn([7,Main.main],50)| :weight 2) -(assert-soft |scc(7)_dn([7,Main.main],50)| :weight 2) -(assert-soft |dn([7,Main.main],54)_dn([7,Main.main],50)| :weight 2) -(assert-soft |dn([7,Main.main],58)_dn([7,Main.main],50)| :weight 2) -(assert-soft |dn([7,Main.main],50)_dn([7,Main.main],51)| :weight 6) -(assert-soft |scc(1)_dn([7,Main.main],51)| :weight 6) -(assert-soft |scc(7)_dn([7,Main.main],51)| :weight 6) -(assert-soft |dn([7,Main.main],54)_dn([7,Main.main],51)| :weight 6) -(assert-soft |dn([7,Main.main],58)_dn([7,Main.main],51)| :weight 6) -(assert-soft |dn([9,Main.main],87)_dn([7,Main.main],53)| :weight 6) -(assert-soft |scc(7)_dn([7,Main.main],53)| :weight 6) -(assert-soft |dn([6,9],91)_dn([7,Main.main],54)| :weight 2) -(assert-soft |dn([7,Main.main],39)_dn([7,Main.main],54)| :weight 2) -(assert-soft |dn([7,Main.main],40)_dn([7,Main.main],54)| :weight 2) -(assert-soft |dn([7,Main.main],49)_dn([7,Main.main],54)| :weight 2) -(assert-soft |dn([7,Main.main],53)_dn([7,Main.main],54)| :weight 2) -(assert-soft |dn([7,Main.main],57)_dn([7,Main.main],54)| :weight 2) -(assert-soft |dn([7,Main.main],60)_dn([7,Main.main],54)| :weight 2) -(assert-soft |scc(1)_dn([7,Main.main],54)| :weight 2) -(assert-soft |scc(7)_dn([7,Main.main],54)| :weight 2) -(assert-soft |dn([7,Main.main],50)_dn([7,Main.main],54)| :weight 2) -(assert-soft |dn([7,Main.main],58)_dn([7,Main.main],54)| :weight 2) -(assert-soft |dn([7,Main.main],54)_dn([7,Main.main],55)| :weight 18) -(assert-soft |scc(1)_dn([7,Main.main],55)| :weight 18) -(assert-soft |scc(7)_dn([7,Main.main],55)| :weight 18) -(assert-soft |dn([7,Main.main],50)_dn([7,Main.main],55)| :weight 18) -(assert-soft |dn([7,Main.main],58)_dn([7,Main.main],55)| :weight 18) -(assert-soft |scc(1)_dn([7,Main.main],57)| :weight 4) -(assert-soft |dn([2,3],37)_dn([7,Main.main],58)| :weight 1) -(assert-soft |dn([7,Main.main],39)_dn([7,Main.main],58)| :weight 1) -(assert-soft |dn([7,Main.main],40)_dn([7,Main.main],58)| :weight 1) -(assert-soft |dn([7,Main.main],49)_dn([7,Main.main],58)| :weight 1) -(assert-soft |dn([7,Main.main],53)_dn([7,Main.main],58)| :weight 1) -(assert-soft |dn([7,Main.main],57)_dn([7,Main.main],58)| :weight 1) -(assert-soft |dn([7,Main.main],60)_dn([7,Main.main],58)| :weight 1) -(assert-soft |scc(1)_dn([7,Main.main],58)| :weight 1) -(assert-soft |scc(7)_dn([7,Main.main],58)| :weight 1) -(assert-soft |dn([7,Main.main],50)_dn([7,Main.main],58)| :weight 1) -(assert-soft |dn([7,Main.main],54)_dn([7,Main.main],58)| :weight 1) -(assert-soft |dn([7,Main.main],58)_dn([7,Main.main],59)| :weight 1) -(assert-soft |scc(1)_dn([7,Main.main],59)| :weight 1) -(assert-soft |scc(7)_dn([7,Main.main],59)| :weight 1) -(assert-soft |dn([7,Main.main],50)_dn([7,Main.main],59)| :weight 1) -(assert-soft |dn([7,Main.main],54)_dn([7,Main.main],59)| :weight 1) -(assert-soft |dn([7,Main.main],59)_dn([7,Main.main],60)| :weight 1) -(assert-soft |dn([1,3],67)_dn([5,1],61)| :weight 1) -(assert-soft |dn([5,1],62)_dn([5,1],61)| :weight 1) -(assert-soft |dn([5,1],63)_dn([5,1],61)| :weight 1) -(assert-soft |dn([3,7],31)_dn([5,1],62)| :weight 1) -(assert-soft |dn([5,1],61)_dn([5,1],62)| :weight 1) -(assert-soft |dn([5,1],63)_dn([5,1],62)| :weight 1) -(assert-soft |scc(5)_dn([5,1],63)| :weight 8) -(assert-soft |dn([5,1],61)_dn([5,1],63)| :weight 8) -(assert-soft |dn([5,1],62)_dn([5,1],63)| :weight 8) -(assert-soft |dn([3,7],20)_dn([1,3],64)| :weight 1) -(assert-soft |dn([1,3],66)_dn([1,3],64)| :weight 1) -(assert-soft |dn([1,3],68)_dn([1,3],64)| :weight 1) -(assert-soft |dn([3,7],22)_dn([1,3],65)| :weight 1) -(assert-soft |dn([1,3],64)_dn([1,3],65)| :weight 1) -(assert-soft |dn([1,3],66)_dn([1,3],65)| :weight 1) -(assert-soft |dn([1,3],68)_dn([1,3],65)| :weight 1) -(assert-soft |dn([1,3],65)_dn([1,3],66)| :weight 1) -(assert-soft |dn([3,7],25)_dn([1,3],67)| :weight 1) -(assert-soft |dn([1,3],64)_dn([1,3],67)| :weight 1) -(assert-soft |dn([1,3],66)_dn([1,3],67)| :weight 1) -(assert-soft |dn([1,3],68)_dn([1,3],67)| :weight 1) -(assert-soft |dn([1,3],67)_dn([1,3],68)| :weight 1) -(assert-soft |dn([1,3],65)_dn([4,1],69)| :weight 1) -(assert-soft |dn([4,1],79)_dn([4,1],69)| :weight 1) -(assert-soft |dn([4,1],81)_dn([4,1],69)| :weight 1) -(assert-soft |scc(4)_dn([4,1],70)| :weight 2) -(assert-soft |dn([8,Main.main],100)_dn([4,1],78)| :weight 6) -(assert-soft |dn([4,1],69)_dn([4,1],78)| :weight 6) -(assert-soft |dn([4,1],79)_dn([4,1],78)| :weight 6) -(assert-soft |dn([4,1],81)_dn([4,1],78)| :weight 6) -(assert-soft |dn([4,1],78)_dn([4,1],79)| :weight 4) -(assert-soft |dn([3,7],24)_dn([4,1],80)| :weight 1) -(assert-soft |dn([4,1],69)_dn([4,1],80)| :weight 1) -(assert-soft |dn([4,1],79)_dn([4,1],80)| :weight 1) -(assert-soft |dn([4,1],81)_dn([4,1],80)| :weight 1) -(assert-soft |dn([4,1],80)_dn([4,1],81)| :weight 1) -(assert-soft |dn([Main.main],113)_dn([9,Main.main],82)| :weight 4) -(assert-soft |dn([9,Main.main],83)_dn([9,Main.main],82)| :weight 4) -(assert-soft |dn([9,Main.main],87)_dn([9,Main.main],82)| :weight 4) -(assert-soft |dn([9,Main.main],89)_dn([9,Main.main],82)| :weight 4) -(assert-soft |dn([9,Main.main],84)_dn([9,Main.main],82)| :weight 4) -(assert-soft |dn([Main.main],114)_dn([9,Main.main],83)| :weight 4) -(assert-soft |dn([9,Main.main],82)_dn([9,Main.main],83)| :weight 4) -(assert-soft |dn([9,Main.main],87)_dn([9,Main.main],83)| :weight 4) -(assert-soft |dn([9,Main.main],89)_dn([9,Main.main],83)| :weight 4) -(assert-soft |dn([9,Main.main],84)_dn([9,Main.main],83)| :weight 4) -(assert-soft |dn([7,Main.main],51)_dn([9,Main.main],84)| :weight 2) -(assert-soft |dn([9,Main.main],82)_dn([9,Main.main],84)| :weight 2) -(assert-soft |dn([9,Main.main],83)_dn([9,Main.main],84)| :weight 2) -(assert-soft |dn([9,Main.main],87)_dn([9,Main.main],84)| :weight 2) -(assert-soft |dn([9,Main.main],89)_dn([9,Main.main],84)| :weight 2) -(assert-soft |dn([9,Main.main],84)_dn([9,Main.main],85)| :weight 6) -(assert-soft |dn([9,Main.main],85)_dn([9,Main.main],86)| :weight 6) -(assert-soft |dn([9,Main.main],86)_dn([9,Main.main],87)| :weight 2) -(assert-soft |dn([6,9],93)_dn([9,Main.main],88)| :weight 6) -(assert-soft |dn([9,Main.main],82)_dn([9,Main.main],88)| :weight 6) -(assert-soft |dn([9,Main.main],83)_dn([9,Main.main],88)| :weight 6) -(assert-soft |dn([9,Main.main],87)_dn([9,Main.main],88)| :weight 6) -(assert-soft |dn([9,Main.main],89)_dn([9,Main.main],88)| :weight 6) -(assert-soft |dn([9,Main.main],84)_dn([9,Main.main],88)| :weight 6) -(assert-soft |dn([9,Main.main],88)_dn([9,Main.main],89)| :weight 6) -(assert-soft |dn([9,Main.main],85)_dn([6,9],90)| :weight 8) -(assert-soft |dn([6,9],92)_dn([6,9],90)| :weight 8) -(assert-soft |dn([6,9],94)_dn([6,9],90)| :weight 8) -(assert-soft |dn([6,9],95)_dn([6,9],90)| :weight 8) -(assert-soft |dn([9,Main.main],86)_dn([6,9],91)| :weight 8) -(assert-soft |dn([6,9],90)_dn([6,9],91)| :weight 8) -(assert-soft |dn([6,9],92)_dn([6,9],91)| :weight 8) -(assert-soft |dn([6,9],94)_dn([6,9],91)| :weight 8) -(assert-soft |dn([6,9],95)_dn([6,9],91)| :weight 8) -(assert-soft |dn([6,9],91)_dn([6,9],92)| :weight 4) -(assert-soft |scc(1)_dn([6,9],93)| :weight 6) -(assert-soft |dn([6,9],90)_dn([6,9],93)| :weight 6) -(assert-soft |dn([6,9],92)_dn([6,9],93)| :weight 6) -(assert-soft |dn([6,9],94)_dn([6,9],93)| :weight 6) -(assert-soft |dn([6,9],95)_dn([6,9],93)| :weight 6) -(assert-soft |dn([6,9],93)_dn([6,9],94)| :weight 4) -(assert-soft |dn([7,Main.main],55)_dn([6,9],95)| :weight 6) -(assert-soft |dn([7,Main.main],59)_dn([6,9],95)| :weight 6) -(assert-soft |dn([6,9],90)_dn([6,9],95)| :weight 6) -(assert-soft |dn([6,9],92)_dn([6,9],95)| :weight 6) -(assert-soft |dn([6,9],94)_dn([6,9],95)| :weight 6) -(assert-soft |scc(8)_dn([8,Main.main],96)| :weight 4) -(assert-soft |dn([8,Main.main],101)_dn([8,Main.main],96)| :weight 4) -(assert-soft |dn([Main.main],108)_dn([8,Main.main],97)| :weight 8) -(assert-soft |dn([8,Main.main],96)_dn([8,Main.main],97)| :weight 8) -(assert-soft |dn([8,Main.main],101)_dn([8,Main.main],97)| :weight 8) -(assert-soft |scc(5)_dn([8,Main.main],100)| :weight 4) -(assert-soft |dn([8,Main.main],100)_dn([8,Main.main],101)| :weight 4) -(assert-soft |dn([Main.main],111)_dn([Main.main],102)| :weight 1) -(assert-soft |dn([Main.main],111)_dn([Main.main],103)| :weight 6) -(assert-soft |dn([Main.main],103)_dn([Main.main],104)| :weight 2) -(assert-soft |dn([Main.main],104)_dn([Main.main],105)| :weight 2) -(assert-soft |dn([Main.main],105)_dn([Main.main],106)| :weight 2) -(assert-soft |scc(8)_dn([Main.main],108)| :weight 2) -(assert-soft |dn([Main.main],108)_dn([Main.main],109)| :weight 6) -(assert-soft |dn([Main.main],109)_dn([Main.main],111)| :weight 6) -(assert-soft |dn([Main.main],115)_dn([Main.main],111)| :weight 6) -(assert-soft |dn([Main.main],116)_dn([Main.main],113)| :weight 3) -(assert-soft |dn([Main.main],113)_dn([Main.main],114)| :weight 1) -(assert-soft |dn([Main.main],114)_dn([Main.main],115)| :weight 1) -(assert-soft |dn([Main.main],115)_dn([Main.main],116)| :weight 2) -(assert-soft |dn([1,3],66)_scc(0)| :weight 1) -(assert-soft |dn([6,9],95)_scc(1)| :weight 6) -(assert-soft |scc(7)_scc(1)| :weight 6) -(assert-soft |dn([7,Main.main],50)_scc(1)| :weight 6) -(assert-soft |dn([7,Main.main],54)_scc(1)| :weight 6) -(assert-soft |dn([7,Main.main],58)_scc(1)| :weight 6) -(assert-soft |dn([5,1],62)_scc(2)| :weight 1) -(assert-soft |dn([4,1],78)_scc(4)| :weight 4) -(assert-soft |dn([3,7],30)_scc(5)| :weight 8) -(assert-soft |dn([3,7],28)_scc(6)| :weight 6) -(assert-soft |dn([9,Main.main],87)_scc(7)| :weight 2) -(assert-soft |scc(1)_scc(7)| :weight 2) -(assert-soft |dn([7,Main.main],50)_scc(7)| :weight 2) -(assert-soft |dn([7,Main.main],54)_scc(7)| :weight 2) -(assert-soft |dn([7,Main.main],58)_scc(7)| :weight 2) -(optimize -; :wmaxsat_engine wpm2 -; :wmaxsat_engine pwmax -; :wmaxsat_engine bvmax - :print_statistics true - :timeout 1200000 -) diff --git a/tests/chat_pb.smt2 b/tests/chat_pb.smt2 deleted file mode 100644 index 8f32a6328..000000000 --- a/tests/chat_pb.smt2 +++ /dev/null @@ -1,3382 +0,0 @@ -(declare-const |dn([7,Main.main],41)| Bool) -(declare-const |dn([3,7],24)| Bool) -(declare-const |dn([7,Main.main],47)| Bool) -(declare-const |dn([9,Main.main],86)| Bool) -(declare-const |dn([7,Main.main],51)| Bool) -(declare-const |dn([3,7],20)| Bool) -(declare-const |dn([6,9],91)| Bool) -(declare-const |scc(3)| Bool) -(declare-const |dn([6,9],92)| Bool) -(declare-const |scc(4)| Bool) -(declare-const |dn([7,Main.main],54)| Bool) -(declare-const |scc(0)| Bool) -(declare-const |dn([Main.main],109)| Bool) -(declare-const |dn([7,Main.main],58)| Bool) -(declare-const |dn([Main.main],104)| Bool) -(declare-const |dn([Main.main],102)| Bool) -(declare-const |dn([8,Main.main],101)| Bool) -(declare-const |dn([6,9],95)| Bool) -(declare-const |dn([8,Main.main],96)| Bool) -(declare-const |dn([3,7],28)| Bool) -(declare-const |dn([Main.main],106)| Bool) -(declare-const |dn([2,3],36)| Bool) -(declare-const |dn([4,1],78)| Bool) -(declare-const |dn([Main.main],114)| Bool) -(declare-const |dn([2,3],35)| Bool) -(declare-const |dn([2,3],38)| Bool) -(declare-const |dn([5,1],63)| Bool) -(declare-const |dn([7,Main.main],39)| Bool) -(declare-const |dn([3,7],33)| Bool) -(declare-const |dn([9,Main.main],88)| Bool) -(declare-const |dn([4,1],80)| Bool) -(declare-const |dn([Main.main],116)| Bool) -(declare-const |dn([Main.main],111)| Bool) -(declare-const |dn([7,Main.main],42)| Bool) -(declare-const |dn([9,Main.main],85)| Bool) -(declare-const |dn([3,7],27)| Bool) -(declare-const |dn([1,3],64)| Bool) -(declare-const |dn([9,Main.main],83)| Bool) -(declare-const |dn([1,3],67)| Bool) -(declare-const |dn([7,Main.main],40)| Bool) -(declare-const |dn([3,7],25)| Bool) -(declare-const |dn([6,9],90)| Bool) -(declare-const |dn([7,Main.main],60)| Bool) -(declare-const |dn([7,Main.main],50)| Bool) -(declare-const |dn([5,1],62)| Bool) -(declare-const |dn([3,7],22)| Bool) -(declare-const |dn([7,Main.main],53)| Bool) -(declare-const |dn([6,9],93)| Bool) -(declare-const |dn([7,Main.main],57)| Bool) -(declare-const |dn([Main.main],108)| Bool) -(declare-const |dn([7,Main.main],55)| Bool) -(declare-const |scc(1)| Bool) -(declare-const |dn([Main.main],105)| Bool) -(declare-const |scc(2)| Bool) -(declare-const |dn([8,Main.main],97)| Bool) -(declare-const |dn([Main.main],103)| Bool) -(declare-const |scc(5)| Bool) -(declare-const |dn([4,1],70)| Bool) -(declare-const |dn([6,9],94)| Bool) -(declare-const |dn([8,Main.main],100)| Bool) -(declare-const |dn([7,Main.main],59)| Bool) -(declare-const |dn([5,1],61)| Bool) -(declare-const |dn([4,1],69)| Bool) -(declare-const |dn([3,7],29)| Bool) -(declare-const |dn([3,7],31)| Bool) -(declare-const |dn([Main.main],113)| Bool) -(declare-const |dn([4,1],79)| Bool) -(declare-const |dn([2,3],34)| Bool) -(declare-const |dn([Main.main],115)| Bool) -(declare-const |dn([2,3],37)| Bool) -(declare-const |dn([1,3],68)| Bool) -(declare-const |dn([4,1],81)| Bool) -(declare-const |scc(7)| Bool) -(declare-const |dn([9,Main.main],89)| Bool) -(declare-const |dn([1,3],66)| Bool) -(declare-const |dn([9,Main.main],84)| Bool) -(declare-const |dn([1,3],65)| Bool) -(declare-const |dn([7,Main.main],43)| Bool) -(declare-const |dn([9,Main.main],82)| Bool) -(declare-const |dn([7,Main.main],45)| Bool) -(declare-const |dn([3,7],30)| Bool) -(declare-const |scc(8)| Bool) -(declare-const |dn([9,Main.main],87)| Bool) -(declare-const |dn([3,7],21)| Bool) -(declare-const |dn([7,Main.main],49)| Bool) -(declare-const |scc(6)| Bool) -(declare-const |dn([7,Main.main],41)_dn([3,7],20)| Bool) -(declare-const |dn([7,Main.main],41)_dn([7,Main.main],42)| Bool) -(declare-const |dn([3,7],24)_dn([3,7],25)| Bool) -(declare-const |dn([3,7],24)_dn([4,1],80)| Bool) -(declare-const |dn([7,Main.main],47)_dn([7,Main.main],41)| Bool) -(declare-const |dn([7,Main.main],47)_dn([7,Main.main],45)| Bool) -(declare-const |dn([9,Main.main],86)_dn([9,Main.main],87)| Bool) -(declare-const |dn([9,Main.main],86)_dn([6,9],91)| Bool) -(declare-const |dn([7,Main.main],51)_dn([9,Main.main],84)| Bool) -(declare-const |dn([3,7],20)_dn([3,7],21)| Bool) -(declare-const |dn([3,7],20)_dn([1,3],64)| Bool) -(declare-const |dn([6,9],91)_dn([7,Main.main],54)| Bool) -(declare-const |dn([6,9],91)_dn([6,9],92)| Bool) -(declare-const |scc(3)_dn([3,7],20)| Bool) -(declare-const |scc(3)_dn([3,7],22)| Bool) -(declare-const |scc(3)_dn([3,7],27)| Bool) -(declare-const |scc(3)_dn([3,7],29)| Bool) -(declare-const |scc(3)_dn([3,7],31)| Bool) -(declare-const |scc(3)_dn([3,7],33)| Bool) -(declare-const |dn([6,9],92)_dn([6,9],90)| Bool) -(declare-const |dn([6,9],92)_dn([6,9],91)| Bool) -(declare-const |dn([6,9],92)_dn([6,9],93)| Bool) -(declare-const |dn([6,9],92)_dn([6,9],95)| Bool) -(declare-const |scc(4)_dn([2,3],35)| Bool) -(declare-const |scc(4)_dn([4,1],70)| Bool) -(declare-const |dn([7,Main.main],54)_dn([7,Main.main],39)| Bool) -(declare-const |dn([7,Main.main],54)_dn([7,Main.main],47)| Bool) -(declare-const |dn([7,Main.main],54)_dn([7,Main.main],49)| Bool) -(declare-const |dn([7,Main.main],54)_dn([7,Main.main],50)| Bool) -(declare-const |dn([7,Main.main],54)_dn([7,Main.main],51)| Bool) -(declare-const |dn([7,Main.main],54)_dn([7,Main.main],55)| Bool) -(declare-const |dn([7,Main.main],54)_dn([7,Main.main],58)| Bool) -(declare-const |dn([7,Main.main],54)_dn([7,Main.main],59)| Bool) -(declare-const |dn([7,Main.main],54)_scc(1)| Bool) -(declare-const |dn([7,Main.main],54)_scc(7)| Bool) -(declare-const |scc(0)_dn([3,7],24)| Bool) -(declare-const |scc(0)_dn([2,3],34)| Bool) -(declare-const |dn([Main.main],109)_dn([Main.main],111)| Bool) -(declare-const |dn([7,Main.main],58)_dn([7,Main.main],39)| Bool) -(declare-const |dn([7,Main.main],58)_dn([7,Main.main],47)| Bool) -(declare-const |dn([7,Main.main],58)_dn([7,Main.main],49)| Bool) -(declare-const |dn([7,Main.main],58)_dn([7,Main.main],50)| Bool) -(declare-const |dn([7,Main.main],58)_dn([7,Main.main],51)| Bool) -(declare-const |dn([7,Main.main],58)_dn([7,Main.main],54)| Bool) -(declare-const |dn([7,Main.main],58)_dn([7,Main.main],55)| Bool) -(declare-const |dn([7,Main.main],58)_dn([7,Main.main],59)| Bool) -(declare-const |dn([7,Main.main],58)_scc(1)| Bool) -(declare-const |dn([7,Main.main],58)_scc(7)| Bool) -(declare-const |dn([Main.main],104)_dn([7,Main.main],49)| Bool) -(declare-const |dn([Main.main],104)_dn([Main.main],105)| Bool) -(declare-const |dn([8,Main.main],101)_dn([8,Main.main],96)| Bool) -(declare-const |dn([8,Main.main],101)_dn([8,Main.main],97)| Bool) -(declare-const |dn([6,9],95)_dn([6,9],90)| Bool) -(declare-const |dn([6,9],95)_dn([6,9],91)| Bool) -(declare-const |dn([6,9],95)_dn([6,9],93)| Bool) -(declare-const |dn([6,9],95)_scc(1)| Bool) -(declare-const |dn([8,Main.main],96)_dn([8,Main.main],97)| Bool) -(declare-const |dn([3,7],28)_dn([3,7],20)| Bool) -(declare-const |dn([3,7],28)_dn([3,7],22)| Bool) -(declare-const |dn([3,7],28)_dn([3,7],27)| Bool) -(declare-const |dn([3,7],28)_dn([3,7],29)| Bool) -(declare-const |dn([3,7],28)_dn([3,7],31)| Bool) -(declare-const |dn([3,7],28)_dn([3,7],33)| Bool) -(declare-const |dn([3,7],28)_scc(6)| Bool) -(declare-const |dn([Main.main],106)_dn([7,Main.main],47)| Bool) -(declare-const |dn([2,3],36)_dn([3,7],31)| Bool) -(declare-const |dn([2,3],36)_dn([2,3],37)| Bool) -(declare-const |dn([4,1],78)_dn([4,1],79)| Bool) -(declare-const |dn([4,1],78)_scc(4)| Bool) -(declare-const |dn([Main.main],114)_dn([9,Main.main],83)| Bool) -(declare-const |dn([Main.main],114)_dn([Main.main],115)| Bool) -(declare-const |dn([2,3],35)_dn([3,7],33)| Bool) -(declare-const |dn([2,3],35)_dn([2,3],36)| Bool) -(declare-const |dn([2,3],38)_dn([2,3],34)| Bool) -(declare-const |dn([2,3],38)_dn([2,3],35)| Bool) -(declare-const |dn([5,1],63)_dn([5,1],61)| Bool) -(declare-const |dn([5,1],63)_dn([5,1],62)| Bool) -(declare-const |dn([7,Main.main],39)_dn([7,Main.main],47)| Bool) -(declare-const |dn([7,Main.main],39)_dn([7,Main.main],49)| Bool) -(declare-const |dn([7,Main.main],39)_dn([7,Main.main],50)| Bool) -(declare-const |dn([7,Main.main],39)_dn([7,Main.main],54)| Bool) -(declare-const |dn([7,Main.main],39)_dn([7,Main.main],58)| Bool) -(declare-const |dn([3,7],33)_dn([3,7],20)| Bool) -(declare-const |dn([3,7],33)_dn([3,7],22)| Bool) -(declare-const |dn([3,7],33)_dn([3,7],27)| Bool) -(declare-const |dn([3,7],33)_dn([3,7],29)| Bool) -(declare-const |dn([3,7],33)_dn([3,7],31)| Bool) -(declare-const |dn([9,Main.main],88)_dn([9,Main.main],89)| Bool) -(declare-const |dn([4,1],80)_dn([4,1],81)| Bool) -(declare-const |dn([Main.main],116)_dn([Main.main],113)| Bool) -(declare-const |dn([Main.main],111)_dn([Main.main],102)| Bool) -(declare-const |dn([Main.main],111)_dn([Main.main],103)| Bool) -(declare-const |dn([7,Main.main],42)_dn([3,7],22)| Bool) -(declare-const |dn([7,Main.main],42)_dn([7,Main.main],43)| Bool) -(declare-const |dn([9,Main.main],85)_dn([9,Main.main],86)| Bool) -(declare-const |dn([9,Main.main],85)_dn([6,9],90)| Bool) -(declare-const |dn([3,7],27)_dn([3,7],20)| Bool) -(declare-const |dn([3,7],27)_dn([3,7],22)| Bool) -(declare-const |dn([3,7],27)_dn([3,7],28)| Bool) -(declare-const |dn([3,7],27)_dn([3,7],29)| Bool) -(declare-const |dn([3,7],27)_dn([3,7],30)| Bool) -(declare-const |dn([3,7],27)_dn([3,7],31)| Bool) -(declare-const |dn([3,7],27)_dn([3,7],33)| Bool) -(declare-const |dn([1,3],64)_dn([1,3],65)| Bool) -(declare-const |dn([1,3],64)_dn([1,3],67)| Bool) -(declare-const |dn([9,Main.main],83)_dn([9,Main.main],82)| Bool) -(declare-const |dn([9,Main.main],83)_dn([9,Main.main],84)| Bool) -(declare-const |dn([9,Main.main],83)_dn([9,Main.main],88)| Bool) -(declare-const |dn([1,3],67)_dn([5,1],61)| Bool) -(declare-const |dn([1,3],67)_dn([1,3],68)| Bool) -(declare-const |dn([7,Main.main],40)_dn([7,Main.main],39)| Bool) -(declare-const |dn([7,Main.main],40)_dn([7,Main.main],47)| Bool) -(declare-const |dn([7,Main.main],40)_dn([7,Main.main],49)| Bool) -(declare-const |dn([7,Main.main],40)_dn([7,Main.main],50)| Bool) -(declare-const |dn([7,Main.main],40)_dn([7,Main.main],54)| Bool) -(declare-const |dn([7,Main.main],40)_dn([7,Main.main],58)| Bool) -(declare-const |dn([3,7],25)_dn([1,3],67)| Bool) -(declare-const |dn([6,9],90)_dn([6,9],91)| Bool) -(declare-const |dn([6,9],90)_dn([6,9],93)| Bool) -(declare-const |dn([6,9],90)_dn([6,9],95)| Bool) -(declare-const |dn([7,Main.main],60)_dn([7,Main.main],39)| Bool) -(declare-const |dn([7,Main.main],60)_dn([7,Main.main],47)| Bool) -(declare-const |dn([7,Main.main],60)_dn([7,Main.main],49)| Bool) -(declare-const |dn([7,Main.main],60)_dn([7,Main.main],50)| Bool) -(declare-const |dn([7,Main.main],60)_dn([7,Main.main],54)| Bool) -(declare-const |dn([7,Main.main],60)_dn([7,Main.main],58)| Bool) -(declare-const |dn([7,Main.main],50)_dn([7,Main.main],39)| Bool) -(declare-const |dn([7,Main.main],50)_dn([7,Main.main],47)| Bool) -(declare-const |dn([7,Main.main],50)_dn([7,Main.main],49)| Bool) -(declare-const |dn([7,Main.main],50)_dn([7,Main.main],51)| Bool) -(declare-const |dn([7,Main.main],50)_dn([7,Main.main],54)| Bool) -(declare-const |dn([7,Main.main],50)_dn([7,Main.main],55)| Bool) -(declare-const |dn([7,Main.main],50)_dn([7,Main.main],58)| Bool) -(declare-const |dn([7,Main.main],50)_dn([7,Main.main],59)| Bool) -(declare-const |dn([7,Main.main],50)_scc(1)| Bool) -(declare-const |dn([7,Main.main],50)_scc(7)| Bool) -(declare-const |dn([5,1],62)_dn([5,1],61)| Bool) -(declare-const |dn([5,1],62)_dn([5,1],63)| Bool) -(declare-const |dn([5,1],62)_scc(2)| Bool) -(declare-const |dn([3,7],22)_dn([1,3],65)| Bool) -(declare-const |dn([7,Main.main],53)_dn([7,Main.main],39)| Bool) -(declare-const |dn([7,Main.main],53)_dn([7,Main.main],47)| Bool) -(declare-const |dn([7,Main.main],53)_dn([7,Main.main],49)| Bool) -(declare-const |dn([7,Main.main],53)_dn([7,Main.main],50)| Bool) -(declare-const |dn([7,Main.main],53)_dn([7,Main.main],54)| Bool) -(declare-const |dn([7,Main.main],53)_dn([7,Main.main],58)| Bool) -(declare-const |dn([6,9],93)_dn([9,Main.main],88)| Bool) -(declare-const |dn([6,9],93)_dn([6,9],94)| Bool) -(declare-const |dn([7,Main.main],57)_dn([7,Main.main],39)| Bool) -(declare-const |dn([7,Main.main],57)_dn([7,Main.main],47)| Bool) -(declare-const |dn([7,Main.main],57)_dn([7,Main.main],49)| Bool) -(declare-const |dn([7,Main.main],57)_dn([7,Main.main],50)| Bool) -(declare-const |dn([7,Main.main],57)_dn([7,Main.main],54)| Bool) -(declare-const |dn([7,Main.main],57)_dn([7,Main.main],58)| Bool) -(declare-const |dn([Main.main],108)_dn([8,Main.main],97)| Bool) -(declare-const |dn([Main.main],108)_dn([Main.main],109)| Bool) -(declare-const |dn([7,Main.main],55)_dn([6,9],95)| Bool) -(declare-const |scc(1)_dn([7,Main.main],39)| Bool) -(declare-const |scc(1)_dn([7,Main.main],47)| Bool) -(declare-const |scc(1)_dn([7,Main.main],49)| Bool) -(declare-const |scc(1)_dn([7,Main.main],50)| Bool) -(declare-const |scc(1)_dn([7,Main.main],51)| Bool) -(declare-const |scc(1)_dn([7,Main.main],54)| Bool) -(declare-const |scc(1)_dn([7,Main.main],55)| Bool) -(declare-const |scc(1)_dn([7,Main.main],57)| Bool) -(declare-const |scc(1)_dn([7,Main.main],58)| Bool) -(declare-const |scc(1)_dn([7,Main.main],59)| Bool) -(declare-const |scc(1)_dn([6,9],93)| Bool) -(declare-const |scc(1)_scc(7)| Bool) -(declare-const |dn([Main.main],105)_dn([7,Main.main],50)| Bool) -(declare-const |dn([Main.main],105)_dn([Main.main],106)| Bool) -(declare-const |scc(2)_dn([3,7],20)| Bool) -(declare-const |scc(2)_dn([3,7],22)| Bool) -(declare-const |scc(2)_dn([3,7],27)| Bool) -(declare-const |scc(2)_dn([3,7],29)| Bool) -(declare-const |scc(2)_dn([3,7],31)| Bool) -(declare-const |scc(2)_dn([3,7],33)| Bool) -(declare-const |dn([8,Main.main],97)_dn([3,7],27)| Bool) -(declare-const |dn([Main.main],103)_dn([7,Main.main],39)| Bool) -(declare-const |dn([Main.main],103)_dn([Main.main],104)| Bool) -(declare-const |scc(5)_dn([5,1],63)| Bool) -(declare-const |scc(5)_dn([8,Main.main],100)| Bool) -(declare-const |dn([6,9],94)_dn([6,9],90)| Bool) -(declare-const |dn([6,9],94)_dn([6,9],91)| Bool) -(declare-const |dn([6,9],94)_dn([6,9],93)| Bool) -(declare-const |dn([6,9],94)_dn([6,9],95)| Bool) -(declare-const |dn([8,Main.main],100)_dn([4,1],78)| Bool) -(declare-const |dn([8,Main.main],100)_dn([8,Main.main],101)| Bool) -(declare-const |dn([7,Main.main],59)_dn([7,Main.main],60)| Bool) -(declare-const |dn([7,Main.main],59)_dn([6,9],95)| Bool) -(declare-const |dn([5,1],61)_dn([5,1],62)| Bool) -(declare-const |dn([5,1],61)_dn([5,1],63)| Bool) -(declare-const |dn([4,1],69)_dn([4,1],78)| Bool) -(declare-const |dn([4,1],69)_dn([4,1],80)| Bool) -(declare-const |dn([3,7],29)_dn([3,7],20)| Bool) -(declare-const |dn([3,7],29)_dn([3,7],22)| Bool) -(declare-const |dn([3,7],29)_dn([3,7],27)| Bool) -(declare-const |dn([3,7],29)_dn([3,7],28)| Bool) -(declare-const |dn([3,7],29)_dn([3,7],30)| Bool) -(declare-const |dn([3,7],29)_dn([3,7],31)| Bool) -(declare-const |dn([3,7],29)_dn([3,7],33)| Bool) -(declare-const |dn([3,7],31)_dn([5,1],62)| Bool) -(declare-const |dn([Main.main],113)_dn([9,Main.main],82)| Bool) -(declare-const |dn([Main.main],113)_dn([Main.main],114)| Bool) -(declare-const |dn([4,1],79)_dn([4,1],69)| Bool) -(declare-const |dn([4,1],79)_dn([4,1],78)| Bool) -(declare-const |dn([4,1],79)_dn([4,1],80)| Bool) -(declare-const |dn([2,3],34)_dn([2,3],35)| Bool) -(declare-const |dn([Main.main],115)_dn([Main.main],111)| Bool) -(declare-const |dn([Main.main],115)_dn([Main.main],116)| Bool) -(declare-const |dn([2,3],37)_dn([2,3],38)| Bool) -(declare-const |dn([2,3],37)_dn([7,Main.main],58)| Bool) -(declare-const |dn([1,3],68)_dn([1,3],64)| Bool) -(declare-const |dn([1,3],68)_dn([1,3],65)| Bool) -(declare-const |dn([1,3],68)_dn([1,3],67)| Bool) -(declare-const |dn([4,1],81)_dn([4,1],69)| Bool) -(declare-const |dn([4,1],81)_dn([4,1],78)| Bool) -(declare-const |dn([4,1],81)_dn([4,1],80)| Bool) -(declare-const |scc(7)_dn([7,Main.main],39)| Bool) -(declare-const |scc(7)_dn([7,Main.main],47)| Bool) -(declare-const |scc(7)_dn([7,Main.main],49)| Bool) -(declare-const |scc(7)_dn([7,Main.main],50)| Bool) -(declare-const |scc(7)_dn([7,Main.main],51)| Bool) -(declare-const |scc(7)_dn([7,Main.main],53)| Bool) -(declare-const |scc(7)_dn([7,Main.main],54)| Bool) -(declare-const |scc(7)_dn([7,Main.main],55)| Bool) -(declare-const |scc(7)_dn([7,Main.main],58)| Bool) -(declare-const |scc(7)_dn([7,Main.main],59)| Bool) -(declare-const |scc(7)_scc(1)| Bool) -(declare-const |dn([9,Main.main],89)_dn([9,Main.main],82)| Bool) -(declare-const |dn([9,Main.main],89)_dn([9,Main.main],83)| Bool) -(declare-const |dn([9,Main.main],89)_dn([9,Main.main],84)| Bool) -(declare-const |dn([9,Main.main],89)_dn([9,Main.main],88)| Bool) -(declare-const |dn([1,3],66)_dn([1,3],64)| Bool) -(declare-const |dn([1,3],66)_dn([1,3],65)| Bool) -(declare-const |dn([1,3],66)_dn([1,3],67)| Bool) -(declare-const |dn([1,3],66)_scc(0)| Bool) -(declare-const |dn([9,Main.main],84)_dn([9,Main.main],82)| Bool) -(declare-const |dn([9,Main.main],84)_dn([9,Main.main],83)| Bool) -(declare-const |dn([9,Main.main],84)_dn([9,Main.main],85)| Bool) -(declare-const |dn([9,Main.main],84)_dn([9,Main.main],88)| Bool) -(declare-const |dn([1,3],65)_dn([1,3],66)| Bool) -(declare-const |dn([1,3],65)_dn([4,1],69)| Bool) -(declare-const |dn([7,Main.main],43)_dn([7,Main.main],40)| Bool) -(declare-const |dn([9,Main.main],82)_dn([9,Main.main],83)| Bool) -(declare-const |dn([9,Main.main],82)_dn([9,Main.main],84)| Bool) -(declare-const |dn([9,Main.main],82)_dn([9,Main.main],88)| Bool) -(declare-const |dn([7,Main.main],45)_dn([7,Main.main],40)| Bool) -(declare-const |dn([3,7],30)_dn([3,7],20)| Bool) -(declare-const |dn([3,7],30)_dn([3,7],22)| Bool) -(declare-const |dn([3,7],30)_dn([3,7],27)| Bool) -(declare-const |dn([3,7],30)_dn([3,7],29)| Bool) -(declare-const |dn([3,7],30)_dn([3,7],31)| Bool) -(declare-const |dn([3,7],30)_dn([3,7],33)| Bool) -(declare-const |dn([3,7],30)_scc(5)| Bool) -(declare-const |scc(8)_dn([8,Main.main],96)| Bool) -(declare-const |scc(8)_dn([Main.main],108)| Bool) -(declare-const |dn([9,Main.main],87)_dn([7,Main.main],53)| Bool) -(declare-const |dn([9,Main.main],87)_dn([9,Main.main],82)| Bool) -(declare-const |dn([9,Main.main],87)_dn([9,Main.main],83)| Bool) -(declare-const |dn([9,Main.main],87)_dn([9,Main.main],84)| Bool) -(declare-const |dn([9,Main.main],87)_dn([9,Main.main],88)| Bool) -(declare-const |dn([9,Main.main],87)_scc(7)| Bool) -(declare-const |dn([3,7],21)_dn([3,7],20)| Bool) -(declare-const |dn([3,7],21)_dn([3,7],22)| Bool) -(declare-const |dn([3,7],21)_dn([3,7],27)| Bool) -(declare-const |dn([3,7],21)_dn([3,7],29)| Bool) -(declare-const |dn([3,7],21)_dn([3,7],31)| Bool) -(declare-const |dn([3,7],21)_dn([3,7],33)| Bool) -(declare-const |dn([7,Main.main],49)_dn([7,Main.main],39)| Bool) -(declare-const |dn([7,Main.main],49)_dn([7,Main.main],47)| Bool) -(declare-const |dn([7,Main.main],49)_dn([7,Main.main],50)| Bool) -(declare-const |dn([7,Main.main],49)_dn([7,Main.main],54)| Bool) -(declare-const |dn([7,Main.main],49)_dn([7,Main.main],58)| Bool) -(declare-const |scc(6)_dn([3,7],29)| Bool) -(assert |dn([Main.main],113)|) -(assert (= |dn([7,Main.main],41)| (or |dn([7,Main.main],41)_dn([3,7],20)| |dn([7,Main.main],41)_dn([7,Main.main],42)|))) -(assert (not (and |dn([7,Main.main],41)_dn([3,7],20)| |dn([7,Main.main],41)_dn([7,Main.main],42)|))) -(assert (not (and |dn([7,Main.main],41)_dn([7,Main.main],42)| |dn([7,Main.main],41)_dn([3,7],20)|))) -(assert (= |dn([3,7],24)| (or |dn([3,7],24)_dn([3,7],25)| |dn([3,7],24)_dn([4,1],80)|))) -(assert (not (and |dn([3,7],24)_dn([3,7],25)| |dn([3,7],24)_dn([4,1],80)|))) -(assert (not (and |dn([3,7],24)_dn([4,1],80)| |dn([3,7],24)_dn([3,7],25)|))) -(assert (= |dn([7,Main.main],47)| (or |dn([7,Main.main],47)_dn([7,Main.main],41)| |dn([7,Main.main],47)_dn([7,Main.main],45)|))) -(assert (not (and |dn([7,Main.main],47)_dn([7,Main.main],41)| |dn([7,Main.main],47)_dn([7,Main.main],45)|))) -(assert (not (and |dn([7,Main.main],47)_dn([7,Main.main],45)| |dn([7,Main.main],47)_dn([7,Main.main],41)|))) -(assert (= |dn([9,Main.main],86)| (or |dn([9,Main.main],86)_dn([9,Main.main],87)| |dn([9,Main.main],86)_dn([6,9],91)|))) -(assert (not (and |dn([9,Main.main],86)_dn([9,Main.main],87)| |dn([9,Main.main],86)_dn([6,9],91)|))) -(assert (not (and |dn([9,Main.main],86)_dn([6,9],91)| |dn([9,Main.main],86)_dn([9,Main.main],87)|))) -(assert (= |dn([7,Main.main],51)| (or |dn([7,Main.main],51)_dn([9,Main.main],84)|))) -(assert (= |dn([3,7],20)| (or |dn([3,7],20)_dn([3,7],21)| |dn([3,7],20)_dn([1,3],64)|))) -(assert (not (and |dn([3,7],20)_dn([3,7],21)| |dn([3,7],20)_dn([1,3],64)|))) -(assert (not (and |dn([3,7],20)_dn([1,3],64)| |dn([3,7],20)_dn([3,7],21)|))) -(assert (= |dn([6,9],91)| (or |dn([6,9],91)_dn([7,Main.main],54)| |dn([6,9],91)_dn([6,9],92)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |dn([6,9],91)_dn([6,9],92)|))) -(assert (not (and |dn([6,9],91)_dn([6,9],92)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (= |scc(3)| (or |scc(3)_dn([3,7],20)| |scc(3)_dn([3,7],22)| |scc(3)_dn([3,7],27)| |scc(3)_dn([3,7],29)| |scc(3)_dn([3,7],31)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |scc(3)_dn([3,7],31)|))) -(assert (= |dn([6,9],92)| (or |dn([6,9],92)_dn([6,9],90)| |dn([6,9],92)_dn([6,9],91)| |dn([6,9],92)_dn([6,9],93)| |dn([6,9],92)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],90)| |dn([6,9],92)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],90)| |dn([6,9],92)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],90)| |dn([6,9],92)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],91)| |dn([6,9],92)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],91)| |dn([6,9],92)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],91)| |dn([6,9],92)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],93)| |dn([6,9],92)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],93)| |dn([6,9],92)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],93)| |dn([6,9],92)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],95)| |dn([6,9],92)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],95)| |dn([6,9],92)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],95)| |dn([6,9],92)_dn([6,9],93)|))) -(assert (= |scc(4)| (or |scc(4)_dn([2,3],35)| |scc(4)_dn([4,1],70)|))) -(assert (not (and |scc(4)_dn([2,3],35)| |scc(4)_dn([4,1],70)|))) -(assert (not (and |scc(4)_dn([4,1],70)| |scc(4)_dn([2,3],35)|))) -(assert (= |dn([7,Main.main],54)| (or |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],54)_scc(1)|))) -(assert (= |scc(0)| (or |scc(0)_dn([3,7],24)| |scc(0)_dn([2,3],34)|))) -(assert (not (and |scc(0)_dn([3,7],24)| |scc(0)_dn([2,3],34)|))) -(assert (not (and |scc(0)_dn([2,3],34)| |scc(0)_dn([3,7],24)|))) -(assert (= |dn([Main.main],109)| (or |dn([Main.main],109)_dn([Main.main],111)|))) -(assert (= |dn([7,Main.main],58)| (or |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],58)_scc(1)|))) -(assert (= |dn([Main.main],104)| (or |dn([Main.main],104)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([Main.main],105)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([Main.main],105)|))) -(assert (not (and |dn([Main.main],104)_dn([Main.main],105)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not |dn([Main.main],102)|)) -(assert (= |dn([8,Main.main],101)| (or |dn([8,Main.main],101)_dn([8,Main.main],96)| |dn([8,Main.main],101)_dn([8,Main.main],97)|))) -(assert (not (and |dn([8,Main.main],101)_dn([8,Main.main],96)| |dn([8,Main.main],101)_dn([8,Main.main],97)|))) -(assert (not (and |dn([8,Main.main],101)_dn([8,Main.main],97)| |dn([8,Main.main],101)_dn([8,Main.main],96)|))) -(assert (= |dn([6,9],95)| (or |dn([6,9],95)_dn([6,9],90)| |dn([6,9],95)_dn([6,9],91)| |dn([6,9],95)_dn([6,9],93)| |dn([6,9],95)_scc(1)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],90)| |dn([6,9],95)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],90)| |dn([6,9],95)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],90)| |dn([6,9],95)_scc(1)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],91)| |dn([6,9],95)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],91)| |dn([6,9],95)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],91)| |dn([6,9],95)_scc(1)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],93)| |dn([6,9],95)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],93)| |dn([6,9],95)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],93)| |dn([6,9],95)_scc(1)|))) -(assert (not (and |dn([6,9],95)_scc(1)| |dn([6,9],95)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],95)_scc(1)| |dn([6,9],95)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],95)_scc(1)| |dn([6,9],95)_dn([6,9],93)|))) -(assert (= |dn([8,Main.main],96)| (or |dn([8,Main.main],96)_dn([8,Main.main],97)|))) -(assert (= |dn([3,7],28)| (or |dn([3,7],28)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],33)| |dn([3,7],28)_scc(6)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],28)_scc(6)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],28)_scc(6)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([3,7],28)_scc(6)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |dn([3,7],28)_scc(6)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],28)_scc(6)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([3,7],28)_scc(6)|))) -(assert (not (and |dn([3,7],28)_scc(6)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_scc(6)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_scc(6)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_scc(6)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_scc(6)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_scc(6)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (= |dn([Main.main],106)| (or |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (= |dn([2,3],36)| (or |dn([2,3],36)_dn([3,7],31)| |dn([2,3],36)_dn([2,3],37)|))) -(assert (not (and |dn([2,3],36)_dn([3,7],31)| |dn([2,3],36)_dn([2,3],37)|))) -(assert (not (and |dn([2,3],36)_dn([2,3],37)| |dn([2,3],36)_dn([3,7],31)|))) -(assert (= |dn([4,1],78)| (or |dn([4,1],78)_dn([4,1],79)| |dn([4,1],78)_scc(4)|))) -(assert (not (and |dn([4,1],78)_dn([4,1],79)| |dn([4,1],78)_scc(4)|))) -(assert (not (and |dn([4,1],78)_scc(4)| |dn([4,1],78)_dn([4,1],79)|))) -(assert (= |dn([Main.main],114)| (or |dn([Main.main],114)_dn([9,Main.main],83)| |dn([Main.main],114)_dn([Main.main],115)|))) -(assert (not (and |dn([Main.main],114)_dn([9,Main.main],83)| |dn([Main.main],114)_dn([Main.main],115)|))) -(assert (not (and |dn([Main.main],114)_dn([Main.main],115)| |dn([Main.main],114)_dn([9,Main.main],83)|))) -(assert (= |dn([2,3],35)| (or |dn([2,3],35)_dn([3,7],33)| |dn([2,3],35)_dn([2,3],36)|))) -(assert (not (and |dn([2,3],35)_dn([3,7],33)| |dn([2,3],35)_dn([2,3],36)|))) -(assert (not (and |dn([2,3],35)_dn([2,3],36)| |dn([2,3],35)_dn([3,7],33)|))) -(assert (= |dn([2,3],38)| (or |dn([2,3],38)_dn([2,3],34)| |dn([2,3],38)_dn([2,3],35)|))) -(assert (not (and |dn([2,3],38)_dn([2,3],34)| |dn([2,3],38)_dn([2,3],35)|))) -(assert (not (and |dn([2,3],38)_dn([2,3],35)| |dn([2,3],38)_dn([2,3],34)|))) -(assert (= |dn([5,1],63)| (or |dn([5,1],63)_dn([5,1],61)| |dn([5,1],63)_dn([5,1],62)|))) -(assert (not (and |dn([5,1],63)_dn([5,1],61)| |dn([5,1],63)_dn([5,1],62)|))) -(assert (not (and |dn([5,1],63)_dn([5,1],62)| |dn([5,1],63)_dn([5,1],61)|))) -(assert (= |dn([7,Main.main],39)| (or |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (= |dn([3,7],33)| (or |dn([3,7],33)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (= |dn([9,Main.main],88)| (or |dn([9,Main.main],88)_dn([9,Main.main],89)|))) -(assert (= |dn([4,1],80)| (or |dn([4,1],80)_dn([4,1],81)|))) -(assert (= |dn([Main.main],116)| (or |dn([Main.main],116)_dn([Main.main],113)|))) -(assert (= |dn([Main.main],111)| (or |dn([Main.main],111)_dn([Main.main],102)| |dn([Main.main],111)_dn([Main.main],103)|))) -(assert (not (and |dn([Main.main],111)_dn([Main.main],102)| |dn([Main.main],111)_dn([Main.main],103)|))) -(assert (not (and |dn([Main.main],111)_dn([Main.main],103)| |dn([Main.main],111)_dn([Main.main],102)|))) -(assert (= |dn([7,Main.main],42)| (or |dn([7,Main.main],42)_dn([3,7],22)| |dn([7,Main.main],42)_dn([7,Main.main],43)|))) -(assert (not (and |dn([7,Main.main],42)_dn([3,7],22)| |dn([7,Main.main],42)_dn([7,Main.main],43)|))) -(assert (not (and |dn([7,Main.main],42)_dn([7,Main.main],43)| |dn([7,Main.main],42)_dn([3,7],22)|))) -(assert (= |dn([9,Main.main],85)| (or |dn([9,Main.main],85)_dn([9,Main.main],86)| |dn([9,Main.main],85)_dn([6,9],90)|))) -(assert (not (and |dn([9,Main.main],85)_dn([9,Main.main],86)| |dn([9,Main.main],85)_dn([6,9],90)|))) -(assert (not (and |dn([9,Main.main],85)_dn([6,9],90)| |dn([9,Main.main],85)_dn([9,Main.main],86)|))) -(assert (= |dn([3,7],27)| (or |dn([3,7],27)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],28)| |dn([3,7],27)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],30)| |dn([3,7],27)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],28)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],28)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],28)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],28)| |dn([3,7],27)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],28)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],28)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],30)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],30)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],30)| |dn([3,7],27)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],30)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],30)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],30)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (= |dn([1,3],64)| (or |dn([1,3],64)_dn([1,3],65)| |dn([1,3],64)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],64)_dn([1,3],65)| |dn([1,3],64)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],64)_dn([1,3],67)| |dn([1,3],64)_dn([1,3],65)|))) -(assert (= |dn([9,Main.main],83)| (or |dn([9,Main.main],83)_dn([9,Main.main],82)| |dn([9,Main.main],83)_dn([9,Main.main],84)| |dn([9,Main.main],83)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],82)| |dn([9,Main.main],83)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],82)| |dn([9,Main.main],83)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],84)| |dn([9,Main.main],83)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],84)| |dn([9,Main.main],83)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],88)| |dn([9,Main.main],83)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],88)| |dn([9,Main.main],83)_dn([9,Main.main],84)|))) -(assert (= |dn([1,3],67)| (or |dn([1,3],67)_dn([5,1],61)| |dn([1,3],67)_dn([1,3],68)|))) -(assert (not (and |dn([1,3],67)_dn([5,1],61)| |dn([1,3],67)_dn([1,3],68)|))) -(assert (not (and |dn([1,3],67)_dn([1,3],68)| |dn([1,3],67)_dn([5,1],61)|))) -(assert (= |dn([7,Main.main],40)| (or |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (= |dn([3,7],25)| (or |dn([3,7],25)_dn([1,3],67)|))) -(assert (= |dn([6,9],90)| (or |dn([6,9],90)_dn([6,9],91)| |dn([6,9],90)_dn([6,9],93)| |dn([6,9],90)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],91)| |dn([6,9],90)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],91)| |dn([6,9],90)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],93)| |dn([6,9],90)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],93)| |dn([6,9],90)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],95)| |dn([6,9],90)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],95)| |dn([6,9],90)_dn([6,9],93)|))) -(assert (= |dn([7,Main.main],60)| (or |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (= |dn([7,Main.main],50)| (or |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],50)_scc(1)|))) -(assert (= |dn([5,1],62)| (or |dn([5,1],62)_dn([5,1],61)| |dn([5,1],62)_dn([5,1],63)| |dn([5,1],62)_scc(2)|))) -(assert (not (and |dn([5,1],62)_dn([5,1],61)| |dn([5,1],62)_dn([5,1],63)|))) -(assert (not (and |dn([5,1],62)_dn([5,1],61)| |dn([5,1],62)_scc(2)|))) -(assert (not (and |dn([5,1],62)_dn([5,1],63)| |dn([5,1],62)_dn([5,1],61)|))) -(assert (not (and |dn([5,1],62)_dn([5,1],63)| |dn([5,1],62)_scc(2)|))) -(assert (not (and |dn([5,1],62)_scc(2)| |dn([5,1],62)_dn([5,1],61)|))) -(assert (not (and |dn([5,1],62)_scc(2)| |dn([5,1],62)_dn([5,1],63)|))) -(assert (= |dn([3,7],22)| (or |dn([3,7],22)_dn([1,3],65)|))) -(assert (= |dn([7,Main.main],53)| (or |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (= |dn([6,9],93)| (or |dn([6,9],93)_dn([9,Main.main],88)| |dn([6,9],93)_dn([6,9],94)|))) -(assert (not (and |dn([6,9],93)_dn([9,Main.main],88)| |dn([6,9],93)_dn([6,9],94)|))) -(assert (not (and |dn([6,9],93)_dn([6,9],94)| |dn([6,9],93)_dn([9,Main.main],88)|))) -(assert (= |dn([7,Main.main],57)| (or |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (= |dn([Main.main],108)| (or |dn([Main.main],108)_dn([8,Main.main],97)| |dn([Main.main],108)_dn([Main.main],109)|))) -(assert (not (and |dn([Main.main],108)_dn([8,Main.main],97)| |dn([Main.main],108)_dn([Main.main],109)|))) -(assert (not (and |dn([Main.main],108)_dn([Main.main],109)| |dn([Main.main],108)_dn([8,Main.main],97)|))) -(assert (= |dn([7,Main.main],55)| (or |dn([7,Main.main],55)_dn([6,9],95)|))) -(assert (= |scc(1)| (or |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([6,9],93)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([6,9],93)|))) -(assert (= |dn([Main.main],105)| (or |dn([Main.main],105)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([Main.main],106)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([Main.main],106)|))) -(assert (not (and |dn([Main.main],105)_dn([Main.main],106)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (= |scc(2)| (or |scc(2)_dn([3,7],20)| |scc(2)_dn([3,7],22)| |scc(2)_dn([3,7],27)| |scc(2)_dn([3,7],29)| |scc(2)_dn([3,7],31)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |scc(2)_dn([3,7],31)|))) -(assert (= |dn([8,Main.main],97)| (or |dn([8,Main.main],97)_dn([3,7],27)|))) -(assert (= |dn([Main.main],103)| (or |dn([Main.main],103)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([Main.main],104)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([Main.main],104)|))) -(assert (not (and |dn([Main.main],103)_dn([Main.main],104)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (= |scc(5)| (or |scc(5)_dn([5,1],63)| |scc(5)_dn([8,Main.main],100)|))) -(assert (not (and |scc(5)_dn([5,1],63)| |scc(5)_dn([8,Main.main],100)|))) -(assert (not (and |scc(5)_dn([8,Main.main],100)| |scc(5)_dn([5,1],63)|))) -(assert (not |dn([4,1],70)|)) -(assert (= |dn([6,9],94)| (or |dn([6,9],94)_dn([6,9],90)| |dn([6,9],94)_dn([6,9],91)| |dn([6,9],94)_dn([6,9],93)| |dn([6,9],94)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],90)| |dn([6,9],94)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],90)| |dn([6,9],94)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],90)| |dn([6,9],94)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],91)| |dn([6,9],94)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],91)| |dn([6,9],94)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],91)| |dn([6,9],94)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],93)| |dn([6,9],94)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],93)| |dn([6,9],94)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],93)| |dn([6,9],94)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],95)| |dn([6,9],94)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],95)| |dn([6,9],94)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],95)| |dn([6,9],94)_dn([6,9],93)|))) -(assert (= |dn([8,Main.main],100)| (or |dn([8,Main.main],100)_dn([4,1],78)| |dn([8,Main.main],100)_dn([8,Main.main],101)|))) -(assert (not (and |dn([8,Main.main],100)_dn([4,1],78)| |dn([8,Main.main],100)_dn([8,Main.main],101)|))) -(assert (not (and |dn([8,Main.main],100)_dn([8,Main.main],101)| |dn([8,Main.main],100)_dn([4,1],78)|))) -(assert (= |dn([7,Main.main],59)| (or |dn([7,Main.main],59)_dn([7,Main.main],60)| |dn([7,Main.main],59)_dn([6,9],95)|))) -(assert (not (and |dn([7,Main.main],59)_dn([7,Main.main],60)| |dn([7,Main.main],59)_dn([6,9],95)|))) -(assert (not (and |dn([7,Main.main],59)_dn([6,9],95)| |dn([7,Main.main],59)_dn([7,Main.main],60)|))) -(assert (= |dn([5,1],61)| (or |dn([5,1],61)_dn([5,1],62)| |dn([5,1],61)_dn([5,1],63)|))) -(assert (not (and |dn([5,1],61)_dn([5,1],62)| |dn([5,1],61)_dn([5,1],63)|))) -(assert (not (and |dn([5,1],61)_dn([5,1],63)| |dn([5,1],61)_dn([5,1],62)|))) -(assert (= |dn([4,1],69)| (or |dn([4,1],69)_dn([4,1],78)| |dn([4,1],69)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],69)_dn([4,1],78)| |dn([4,1],69)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],69)_dn([4,1],80)| |dn([4,1],69)_dn([4,1],78)|))) -(assert (= |dn([3,7],29)| (or |dn([3,7],29)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],28)| |dn([3,7],29)_dn([3,7],30)| |dn([3,7],29)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],28)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],28)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],28)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],28)| |dn([3,7],29)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],28)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],28)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],30)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],30)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],30)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],30)| |dn([3,7],29)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],30)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],30)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (= |dn([3,7],31)| (or |dn([3,7],31)_dn([5,1],62)|))) -(assert (= |dn([Main.main],113)| (or |dn([Main.main],113)_dn([9,Main.main],82)| |dn([Main.main],113)_dn([Main.main],114)|))) -(assert (not (and |dn([Main.main],113)_dn([9,Main.main],82)| |dn([Main.main],113)_dn([Main.main],114)|))) -(assert (not (and |dn([Main.main],113)_dn([Main.main],114)| |dn([Main.main],113)_dn([9,Main.main],82)|))) -(assert (= |dn([4,1],79)| (or |dn([4,1],79)_dn([4,1],69)| |dn([4,1],79)_dn([4,1],78)| |dn([4,1],79)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],69)| |dn([4,1],79)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],69)| |dn([4,1],79)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],78)| |dn([4,1],79)_dn([4,1],69)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],78)| |dn([4,1],79)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],80)| |dn([4,1],79)_dn([4,1],69)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],80)| |dn([4,1],79)_dn([4,1],78)|))) -(assert (= |dn([2,3],34)| (or |dn([2,3],34)_dn([2,3],35)|))) -(assert (= |dn([Main.main],115)| (or |dn([Main.main],115)_dn([Main.main],111)| |dn([Main.main],115)_dn([Main.main],116)|))) -(assert (not (and |dn([Main.main],115)_dn([Main.main],111)| |dn([Main.main],115)_dn([Main.main],116)|))) -(assert (not (and |dn([Main.main],115)_dn([Main.main],116)| |dn([Main.main],115)_dn([Main.main],111)|))) -(assert (= |dn([2,3],37)| (or |dn([2,3],37)_dn([2,3],38)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([2,3],38)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |dn([2,3],37)_dn([2,3],38)|))) -(assert (= |dn([1,3],68)| (or |dn([1,3],68)_dn([1,3],64)| |dn([1,3],68)_dn([1,3],65)| |dn([1,3],68)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],64)| |dn([1,3],68)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],64)| |dn([1,3],68)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],65)| |dn([1,3],68)_dn([1,3],64)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],65)| |dn([1,3],68)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],67)| |dn([1,3],68)_dn([1,3],64)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],67)| |dn([1,3],68)_dn([1,3],65)|))) -(assert (= |dn([4,1],81)| (or |dn([4,1],81)_dn([4,1],69)| |dn([4,1],81)_dn([4,1],78)| |dn([4,1],81)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],69)| |dn([4,1],81)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],69)| |dn([4,1],81)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],78)| |dn([4,1],81)_dn([4,1],69)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],78)| |dn([4,1],81)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],80)| |dn([4,1],81)_dn([4,1],69)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],80)| |dn([4,1],81)_dn([4,1],78)|))) -(assert (= |scc(7)| (or |scc(7)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],59)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_scc(1)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_scc(1)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_scc(1)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_scc(1)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_scc(1)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_scc(1)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_scc(1)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_scc(1)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_scc(1)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_scc(1)| |scc(7)_dn([7,Main.main],59)|))) -(assert (= |dn([9,Main.main],89)| (or |dn([9,Main.main],89)_dn([9,Main.main],82)| |dn([9,Main.main],89)_dn([9,Main.main],83)| |dn([9,Main.main],89)_dn([9,Main.main],84)| |dn([9,Main.main],89)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],82)| |dn([9,Main.main],89)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],82)| |dn([9,Main.main],89)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],82)| |dn([9,Main.main],89)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],83)| |dn([9,Main.main],89)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],83)| |dn([9,Main.main],89)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],83)| |dn([9,Main.main],89)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],84)| |dn([9,Main.main],89)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],84)| |dn([9,Main.main],89)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],84)| |dn([9,Main.main],89)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],88)| |dn([9,Main.main],89)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],88)| |dn([9,Main.main],89)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],88)| |dn([9,Main.main],89)_dn([9,Main.main],84)|))) -(assert (= |dn([1,3],66)| (or |dn([1,3],66)_dn([1,3],64)| |dn([1,3],66)_dn([1,3],65)| |dn([1,3],66)_dn([1,3],67)| |dn([1,3],66)_scc(0)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],64)| |dn([1,3],66)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],64)| |dn([1,3],66)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],64)| |dn([1,3],66)_scc(0)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],65)| |dn([1,3],66)_dn([1,3],64)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],65)| |dn([1,3],66)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],65)| |dn([1,3],66)_scc(0)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],67)| |dn([1,3],66)_dn([1,3],64)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],67)| |dn([1,3],66)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],67)| |dn([1,3],66)_scc(0)|))) -(assert (not (and |dn([1,3],66)_scc(0)| |dn([1,3],66)_dn([1,3],64)|))) -(assert (not (and |dn([1,3],66)_scc(0)| |dn([1,3],66)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],66)_scc(0)| |dn([1,3],66)_dn([1,3],67)|))) -(assert (= |dn([9,Main.main],84)| (or |dn([9,Main.main],84)_dn([9,Main.main],82)| |dn([9,Main.main],84)_dn([9,Main.main],83)| |dn([9,Main.main],84)_dn([9,Main.main],85)| |dn([9,Main.main],84)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],82)| |dn([9,Main.main],84)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],82)| |dn([9,Main.main],84)_dn([9,Main.main],85)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],82)| |dn([9,Main.main],84)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],83)| |dn([9,Main.main],84)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],83)| |dn([9,Main.main],84)_dn([9,Main.main],85)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],83)| |dn([9,Main.main],84)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],85)| |dn([9,Main.main],84)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],85)| |dn([9,Main.main],84)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],85)| |dn([9,Main.main],84)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],88)| |dn([9,Main.main],84)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],88)| |dn([9,Main.main],84)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],88)| |dn([9,Main.main],84)_dn([9,Main.main],85)|))) -(assert (= |dn([1,3],65)| (or |dn([1,3],65)_dn([1,3],66)| |dn([1,3],65)_dn([4,1],69)|))) -(assert (not (and |dn([1,3],65)_dn([1,3],66)| |dn([1,3],65)_dn([4,1],69)|))) -(assert (not (and |dn([1,3],65)_dn([4,1],69)| |dn([1,3],65)_dn([1,3],66)|))) -(assert (= |dn([7,Main.main],43)| (or |dn([7,Main.main],43)_dn([7,Main.main],40)|))) -(assert (= |dn([9,Main.main],82)| (or |dn([9,Main.main],82)_dn([9,Main.main],83)| |dn([9,Main.main],82)_dn([9,Main.main],84)| |dn([9,Main.main],82)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],83)| |dn([9,Main.main],82)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],83)| |dn([9,Main.main],82)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],84)| |dn([9,Main.main],82)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],84)| |dn([9,Main.main],82)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],88)| |dn([9,Main.main],82)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],88)| |dn([9,Main.main],82)_dn([9,Main.main],84)|))) -(assert (= |dn([7,Main.main],45)| (or |dn([7,Main.main],45)_dn([7,Main.main],40)|))) -(assert (= |dn([3,7],30)| (or |dn([3,7],30)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],33)| |dn([3,7],30)_scc(5)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],30)_scc(5)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],30)_scc(5)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([3,7],30)_scc(5)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |dn([3,7],30)_scc(5)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],30)_scc(5)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([3,7],30)_scc(5)|))) -(assert (not (and |dn([3,7],30)_scc(5)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_scc(5)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_scc(5)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_scc(5)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_scc(5)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_scc(5)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (= |scc(8)| (or |scc(8)_dn([8,Main.main],96)| |scc(8)_dn([Main.main],108)|))) -(assert (not (and |scc(8)_dn([8,Main.main],96)| |scc(8)_dn([Main.main],108)|))) -(assert (not (and |scc(8)_dn([Main.main],108)| |scc(8)_dn([8,Main.main],96)|))) -(assert (= |dn([9,Main.main],87)| (or |dn([9,Main.main],87)_dn([7,Main.main],53)| |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],87)_scc(7)|))) -(assert (not (and |dn([9,Main.main],87)_dn([7,Main.main],53)| |dn([9,Main.main],87)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],87)_dn([7,Main.main],53)| |dn([9,Main.main],87)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],87)_dn([7,Main.main],53)| |dn([9,Main.main],87)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],87)_dn([7,Main.main],53)| |dn([9,Main.main],87)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],87)_dn([7,Main.main],53)| |dn([9,Main.main],87)_scc(7)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([9,Main.main],87)_dn([7,Main.main],53)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([9,Main.main],87)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([9,Main.main],87)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([9,Main.main],87)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([9,Main.main],87)_scc(7)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([9,Main.main],87)_dn([7,Main.main],53)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([9,Main.main],87)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([9,Main.main],87)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([9,Main.main],87)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([9,Main.main],87)_scc(7)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([9,Main.main],87)_dn([7,Main.main],53)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([9,Main.main],87)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([9,Main.main],87)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([9,Main.main],87)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([9,Main.main],87)_scc(7)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],87)_dn([7,Main.main],53)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],87)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],87)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],87)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],87)_scc(7)|))) -(assert (not (and |dn([9,Main.main],87)_scc(7)| |dn([9,Main.main],87)_dn([7,Main.main],53)|))) -(assert (not (and |dn([9,Main.main],87)_scc(7)| |dn([9,Main.main],87)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],87)_scc(7)| |dn([9,Main.main],87)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],87)_scc(7)| |dn([9,Main.main],87)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],87)_scc(7)| |dn([9,Main.main],87)_dn([9,Main.main],88)|))) -(assert (= |dn([7,Main.main],49)| (or |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (= |scc(6)| (or |scc(6)_dn([3,7],29)|))) -(assert (= |dn([7,Main.main],41)| (or |dn([7,Main.main],47)_dn([7,Main.main],41)|))) -(assert (= |dn([3,7],24)| (or |scc(0)_dn([3,7],24)|))) -(assert (= |dn([7,Main.main],47)| (or |dn([Main.main],106)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (= |dn([9,Main.main],86)| (or |dn([9,Main.main],85)_dn([9,Main.main],86)|))) -(assert (= |dn([7,Main.main],51)| (or |dn([7,Main.main],50)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (= |dn([3,7],20)| (or |dn([7,Main.main],41)_dn([3,7],20)| |scc(2)_dn([3,7],20)| |scc(3)_dn([3,7],20)| |dn([3,7],21)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([7,Main.main],41)_dn([3,7],20)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |dn([7,Main.main],41)_dn([3,7],20)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |dn([7,Main.main],41)_dn([3,7],20)| |dn([3,7],21)_dn([3,7],20)|))) -(assert (not (and |dn([7,Main.main],41)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([7,Main.main],41)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([7,Main.main],41)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |dn([7,Main.main],41)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([7,Main.main],41)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |dn([7,Main.main],41)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |dn([3,7],21)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |dn([7,Main.main],41)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |dn([3,7],21)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],20)| |dn([7,Main.main],41)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],20)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],20)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([7,Main.main],41)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],21)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([7,Main.main],41)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],21)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |dn([7,Main.main],41)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |dn([3,7],21)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([7,Main.main],41)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],21)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([7,Main.main],41)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],21)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (= |dn([6,9],91)| (or |dn([9,Main.main],86)_dn([6,9],91)| |dn([6,9],90)_dn([6,9],91)| |dn([6,9],92)_dn([6,9],91)| |dn([6,9],94)_dn([6,9],91)| |dn([6,9],95)_dn([6,9],91)|))) -(assert (not (and |dn([9,Main.main],86)_dn([6,9],91)| |dn([6,9],90)_dn([6,9],91)|))) -(assert (not (and |dn([9,Main.main],86)_dn([6,9],91)| |dn([6,9],92)_dn([6,9],91)|))) -(assert (not (and |dn([9,Main.main],86)_dn([6,9],91)| |dn([6,9],94)_dn([6,9],91)|))) -(assert (not (and |dn([9,Main.main],86)_dn([6,9],91)| |dn([6,9],95)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],91)| |dn([9,Main.main],86)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],91)| |dn([6,9],92)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],91)| |dn([6,9],94)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],91)| |dn([6,9],95)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],91)| |dn([9,Main.main],86)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],91)| |dn([6,9],90)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],91)| |dn([6,9],94)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],91)| |dn([6,9],95)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],91)| |dn([9,Main.main],86)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],91)| |dn([6,9],90)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],91)| |dn([6,9],92)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],91)| |dn([6,9],95)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],91)| |dn([9,Main.main],86)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],91)| |dn([6,9],90)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],91)| |dn([6,9],92)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],91)| |dn([6,9],94)_dn([6,9],91)|))) -(assert (not |scc(3)|)) -(assert (= |dn([6,9],92)| (or |dn([6,9],91)_dn([6,9],92)|))) -(assert (= |scc(4)| (or |dn([4,1],78)_scc(4)|))) -(assert (= |dn([7,Main.main],54)| (or |dn([6,9],91)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (= |scc(0)| (or |dn([1,3],66)_scc(0)|))) -(assert (= |dn([Main.main],109)| (or |dn([Main.main],108)_dn([Main.main],109)|))) -(assert (= |dn([7,Main.main],58)| (or |dn([2,3],37)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (= |dn([Main.main],104)| (or |dn([Main.main],103)_dn([Main.main],104)|))) -(assert (= |dn([Main.main],102)| (or |dn([Main.main],111)_dn([Main.main],102)|))) -(assert (= |dn([8,Main.main],101)| (or |dn([8,Main.main],100)_dn([8,Main.main],101)|))) -(assert (= |dn([6,9],95)| (or |dn([7,Main.main],55)_dn([6,9],95)| |dn([7,Main.main],59)_dn([6,9],95)| |dn([6,9],90)_dn([6,9],95)| |dn([6,9],92)_dn([6,9],95)| |dn([6,9],94)_dn([6,9],95)|))) -(assert (not (and |dn([7,Main.main],55)_dn([6,9],95)| |dn([7,Main.main],59)_dn([6,9],95)|))) -(assert (not (and |dn([7,Main.main],55)_dn([6,9],95)| |dn([6,9],90)_dn([6,9],95)|))) -(assert (not (and |dn([7,Main.main],55)_dn([6,9],95)| |dn([6,9],92)_dn([6,9],95)|))) -(assert (not (and |dn([7,Main.main],55)_dn([6,9],95)| |dn([6,9],94)_dn([6,9],95)|))) -(assert (not (and |dn([7,Main.main],59)_dn([6,9],95)| |dn([7,Main.main],55)_dn([6,9],95)|))) -(assert (not (and |dn([7,Main.main],59)_dn([6,9],95)| |dn([6,9],90)_dn([6,9],95)|))) -(assert (not (and |dn([7,Main.main],59)_dn([6,9],95)| |dn([6,9],92)_dn([6,9],95)|))) -(assert (not (and |dn([7,Main.main],59)_dn([6,9],95)| |dn([6,9],94)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],95)| |dn([7,Main.main],55)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],95)| |dn([7,Main.main],59)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],95)| |dn([6,9],92)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],95)| |dn([6,9],94)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],95)| |dn([7,Main.main],55)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],95)| |dn([7,Main.main],59)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],95)| |dn([6,9],90)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],95)| |dn([6,9],94)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],95)| |dn([7,Main.main],55)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],95)| |dn([7,Main.main],59)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],95)| |dn([6,9],90)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],95)| |dn([6,9],92)_dn([6,9],95)|))) -(assert (= |dn([8,Main.main],96)| (or |scc(8)_dn([8,Main.main],96)| |dn([8,Main.main],101)_dn([8,Main.main],96)|))) -(assert (not (and |scc(8)_dn([8,Main.main],96)| |dn([8,Main.main],101)_dn([8,Main.main],96)|))) -(assert (not (and |dn([8,Main.main],101)_dn([8,Main.main],96)| |scc(8)_dn([8,Main.main],96)|))) -(assert (= |dn([3,7],28)| (or |dn([3,7],27)_dn([3,7],28)| |dn([3,7],29)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],28)| |dn([3,7],29)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],28)| |dn([3,7],27)_dn([3,7],28)|))) -(assert (= |dn([Main.main],106)| (or |dn([Main.main],105)_dn([Main.main],106)|))) -(assert (= |dn([2,3],36)| (or |dn([2,3],35)_dn([2,3],36)|))) -(assert (= |dn([4,1],78)| (or |dn([8,Main.main],100)_dn([4,1],78)| |dn([4,1],69)_dn([4,1],78)| |dn([4,1],79)_dn([4,1],78)| |dn([4,1],81)_dn([4,1],78)|))) -(assert (not (and |dn([8,Main.main],100)_dn([4,1],78)| |dn([4,1],69)_dn([4,1],78)|))) -(assert (not (and |dn([8,Main.main],100)_dn([4,1],78)| |dn([4,1],79)_dn([4,1],78)|))) -(assert (not (and |dn([8,Main.main],100)_dn([4,1],78)| |dn([4,1],81)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],69)_dn([4,1],78)| |dn([8,Main.main],100)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],69)_dn([4,1],78)| |dn([4,1],79)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],69)_dn([4,1],78)| |dn([4,1],81)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],78)| |dn([8,Main.main],100)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],78)| |dn([4,1],69)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],78)| |dn([4,1],81)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],78)| |dn([8,Main.main],100)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],78)| |dn([4,1],69)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],78)| |dn([4,1],79)_dn([4,1],78)|))) -(assert (= |dn([Main.main],114)| (or |dn([Main.main],113)_dn([Main.main],114)|))) -(assert (= |dn([2,3],35)| (or |scc(4)_dn([2,3],35)| |dn([2,3],34)_dn([2,3],35)| |dn([2,3],38)_dn([2,3],35)|))) -(assert (not (and |scc(4)_dn([2,3],35)| |dn([2,3],34)_dn([2,3],35)|))) -(assert (not (and |scc(4)_dn([2,3],35)| |dn([2,3],38)_dn([2,3],35)|))) -(assert (not (and |dn([2,3],34)_dn([2,3],35)| |scc(4)_dn([2,3],35)|))) -(assert (not (and |dn([2,3],34)_dn([2,3],35)| |dn([2,3],38)_dn([2,3],35)|))) -(assert (not (and |dn([2,3],38)_dn([2,3],35)| |scc(4)_dn([2,3],35)|))) -(assert (not (and |dn([2,3],38)_dn([2,3],35)| |dn([2,3],34)_dn([2,3],35)|))) -(assert (= |dn([2,3],38)| (or |dn([2,3],37)_dn([2,3],38)|))) -(assert (= |dn([5,1],63)| (or |scc(5)_dn([5,1],63)| |dn([5,1],61)_dn([5,1],63)| |dn([5,1],62)_dn([5,1],63)|))) -(assert (not (and |scc(5)_dn([5,1],63)| |dn([5,1],61)_dn([5,1],63)|))) -(assert (not (and |scc(5)_dn([5,1],63)| |dn([5,1],62)_dn([5,1],63)|))) -(assert (not (and |dn([5,1],61)_dn([5,1],63)| |scc(5)_dn([5,1],63)|))) -(assert (not (and |dn([5,1],61)_dn([5,1],63)| |dn([5,1],62)_dn([5,1],63)|))) -(assert (not (and |dn([5,1],62)_dn([5,1],63)| |scc(5)_dn([5,1],63)|))) -(assert (not (and |dn([5,1],62)_dn([5,1],63)| |dn([5,1],61)_dn([5,1],63)|))) -(assert (= |dn([7,Main.main],39)| (or |dn([Main.main],103)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (= |dn([3,7],33)| (or |dn([2,3],35)_dn([3,7],33)| |scc(2)_dn([3,7],33)| |scc(3)_dn([3,7],33)| |dn([3,7],21)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([2,3],35)_dn([3,7],33)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |dn([2,3],35)_dn([3,7],33)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |dn([2,3],35)_dn([3,7],33)| |dn([3,7],21)_dn([3,7],33)|))) -(assert (not (and |dn([2,3],35)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |dn([2,3],35)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |dn([2,3],35)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([2,3],35)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |dn([2,3],35)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |dn([3,7],21)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |dn([2,3],35)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |dn([3,7],21)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],33)| |dn([2,3],35)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],33)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],33)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([2,3],35)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([3,7],21)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([2,3],35)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([3,7],21)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([2,3],35)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([3,7],21)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([2,3],35)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([3,7],21)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (= |dn([9,Main.main],88)| (or |dn([6,9],93)_dn([9,Main.main],88)| |dn([9,Main.main],82)_dn([9,Main.main],88)| |dn([9,Main.main],83)_dn([9,Main.main],88)| |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],89)_dn([9,Main.main],88)| |dn([9,Main.main],84)_dn([9,Main.main],88)|))) -(assert (not (and |dn([6,9],93)_dn([9,Main.main],88)| |dn([9,Main.main],82)_dn([9,Main.main],88)|))) -(assert (not (and |dn([6,9],93)_dn([9,Main.main],88)| |dn([9,Main.main],83)_dn([9,Main.main],88)|))) -(assert (not (and |dn([6,9],93)_dn([9,Main.main],88)| |dn([9,Main.main],87)_dn([9,Main.main],88)|))) -(assert (not (and |dn([6,9],93)_dn([9,Main.main],88)| |dn([9,Main.main],89)_dn([9,Main.main],88)|))) -(assert (not (and |dn([6,9],93)_dn([9,Main.main],88)| |dn([9,Main.main],84)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],88)| |dn([6,9],93)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],88)| |dn([9,Main.main],83)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],88)| |dn([9,Main.main],87)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],88)| |dn([9,Main.main],89)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],88)| |dn([9,Main.main],84)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],88)| |dn([6,9],93)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],88)| |dn([9,Main.main],82)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],88)| |dn([9,Main.main],87)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],88)| |dn([9,Main.main],89)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],88)| |dn([9,Main.main],84)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([6,9],93)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],82)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],83)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],89)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],84)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],88)| |dn([6,9],93)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],88)| |dn([9,Main.main],82)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],88)| |dn([9,Main.main],83)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],88)| |dn([9,Main.main],87)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],88)| |dn([9,Main.main],84)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],88)| |dn([6,9],93)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],88)| |dn([9,Main.main],82)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],88)| |dn([9,Main.main],83)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],88)| |dn([9,Main.main],87)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],88)| |dn([9,Main.main],89)_dn([9,Main.main],88)|))) -(assert (= |dn([4,1],80)| (or |dn([3,7],24)_dn([4,1],80)| |dn([4,1],69)_dn([4,1],80)| |dn([4,1],79)_dn([4,1],80)| |dn([4,1],81)_dn([4,1],80)|))) -(assert (not (and |dn([3,7],24)_dn([4,1],80)| |dn([4,1],69)_dn([4,1],80)|))) -(assert (not (and |dn([3,7],24)_dn([4,1],80)| |dn([4,1],79)_dn([4,1],80)|))) -(assert (not (and |dn([3,7],24)_dn([4,1],80)| |dn([4,1],81)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],69)_dn([4,1],80)| |dn([3,7],24)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],69)_dn([4,1],80)| |dn([4,1],79)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],69)_dn([4,1],80)| |dn([4,1],81)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],80)| |dn([3,7],24)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],80)| |dn([4,1],69)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],80)| |dn([4,1],81)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],80)| |dn([3,7],24)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],80)| |dn([4,1],69)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],80)| |dn([4,1],79)_dn([4,1],80)|))) -(assert (= |dn([Main.main],116)| (or |dn([Main.main],115)_dn([Main.main],116)|))) -(assert (= |dn([Main.main],111)| (or |dn([Main.main],109)_dn([Main.main],111)| |dn([Main.main],115)_dn([Main.main],111)|))) -(assert (not (and |dn([Main.main],109)_dn([Main.main],111)| |dn([Main.main],115)_dn([Main.main],111)|))) -(assert (not (and |dn([Main.main],115)_dn([Main.main],111)| |dn([Main.main],109)_dn([Main.main],111)|))) -(assert (= |dn([7,Main.main],42)| (or |dn([7,Main.main],41)_dn([7,Main.main],42)|))) -(assert (= |dn([9,Main.main],85)| (or |dn([9,Main.main],84)_dn([9,Main.main],85)|))) -(assert (= |dn([3,7],27)| (or |dn([8,Main.main],97)_dn([3,7],27)| |scc(2)_dn([3,7],27)| |scc(3)_dn([3,7],27)| |dn([3,7],21)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([8,Main.main],97)_dn([3,7],27)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |dn([8,Main.main],97)_dn([3,7],27)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |dn([8,Main.main],97)_dn([3,7],27)| |dn([3,7],21)_dn([3,7],27)|))) -(assert (not (and |dn([8,Main.main],97)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([8,Main.main],97)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([8,Main.main],97)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (not (and |dn([8,Main.main],97)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |dn([8,Main.main],97)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |dn([3,7],21)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |dn([8,Main.main],97)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |dn([3,7],21)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],27)| |dn([8,Main.main],97)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],27)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],27)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([8,Main.main],97)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([3,7],21)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([8,Main.main],97)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([3,7],21)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |dn([8,Main.main],97)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |dn([3,7],21)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([8,Main.main],97)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([3,7],21)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (= |dn([1,3],64)| (or |dn([3,7],20)_dn([1,3],64)| |dn([1,3],66)_dn([1,3],64)| |dn([1,3],68)_dn([1,3],64)|))) -(assert (not (and |dn([3,7],20)_dn([1,3],64)| |dn([1,3],66)_dn([1,3],64)|))) -(assert (not (and |dn([3,7],20)_dn([1,3],64)| |dn([1,3],68)_dn([1,3],64)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],64)| |dn([3,7],20)_dn([1,3],64)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],64)| |dn([1,3],68)_dn([1,3],64)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],64)| |dn([3,7],20)_dn([1,3],64)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],64)| |dn([1,3],66)_dn([1,3],64)|))) -(assert (= |dn([9,Main.main],83)| (or |dn([Main.main],114)_dn([9,Main.main],83)| |dn([9,Main.main],82)_dn([9,Main.main],83)| |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([9,Main.main],89)_dn([9,Main.main],83)| |dn([9,Main.main],84)_dn([9,Main.main],83)|))) -(assert (not (and |dn([Main.main],114)_dn([9,Main.main],83)| |dn([9,Main.main],82)_dn([9,Main.main],83)|))) -(assert (not (and |dn([Main.main],114)_dn([9,Main.main],83)| |dn([9,Main.main],87)_dn([9,Main.main],83)|))) -(assert (not (and |dn([Main.main],114)_dn([9,Main.main],83)| |dn([9,Main.main],89)_dn([9,Main.main],83)|))) -(assert (not (and |dn([Main.main],114)_dn([9,Main.main],83)| |dn([9,Main.main],84)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],83)| |dn([Main.main],114)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],83)| |dn([9,Main.main],87)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],83)| |dn([9,Main.main],89)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],83)| |dn([9,Main.main],84)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([Main.main],114)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([9,Main.main],82)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([9,Main.main],89)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([9,Main.main],84)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],83)| |dn([Main.main],114)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],83)| |dn([9,Main.main],82)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],83)| |dn([9,Main.main],87)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],83)| |dn([9,Main.main],84)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],83)| |dn([Main.main],114)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],83)| |dn([9,Main.main],82)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],83)| |dn([9,Main.main],87)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],83)| |dn([9,Main.main],89)_dn([9,Main.main],83)|))) -(assert (= |dn([1,3],67)| (or |dn([3,7],25)_dn([1,3],67)| |dn([1,3],64)_dn([1,3],67)| |dn([1,3],66)_dn([1,3],67)| |dn([1,3],68)_dn([1,3],67)|))) -(assert (not (and |dn([3,7],25)_dn([1,3],67)| |dn([1,3],64)_dn([1,3],67)|))) -(assert (not (and |dn([3,7],25)_dn([1,3],67)| |dn([1,3],66)_dn([1,3],67)|))) -(assert (not (and |dn([3,7],25)_dn([1,3],67)| |dn([1,3],68)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],64)_dn([1,3],67)| |dn([3,7],25)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],64)_dn([1,3],67)| |dn([1,3],66)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],64)_dn([1,3],67)| |dn([1,3],68)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],67)| |dn([3,7],25)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],67)| |dn([1,3],64)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],67)| |dn([1,3],68)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],67)| |dn([3,7],25)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],67)| |dn([1,3],64)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],67)| |dn([1,3],66)_dn([1,3],67)|))) -(assert (= |dn([7,Main.main],40)| (or |dn([7,Main.main],43)_dn([7,Main.main],40)| |dn([7,Main.main],45)_dn([7,Main.main],40)|))) -(assert (not (and |dn([7,Main.main],43)_dn([7,Main.main],40)| |dn([7,Main.main],45)_dn([7,Main.main],40)|))) -(assert (not (and |dn([7,Main.main],45)_dn([7,Main.main],40)| |dn([7,Main.main],43)_dn([7,Main.main],40)|))) -(assert (= |dn([3,7],25)| (or |dn([3,7],24)_dn([3,7],25)|))) -(assert (= |dn([6,9],90)| (or |dn([9,Main.main],85)_dn([6,9],90)| |dn([6,9],92)_dn([6,9],90)| |dn([6,9],94)_dn([6,9],90)| |dn([6,9],95)_dn([6,9],90)|))) -(assert (not (and |dn([9,Main.main],85)_dn([6,9],90)| |dn([6,9],92)_dn([6,9],90)|))) -(assert (not (and |dn([9,Main.main],85)_dn([6,9],90)| |dn([6,9],94)_dn([6,9],90)|))) -(assert (not (and |dn([9,Main.main],85)_dn([6,9],90)| |dn([6,9],95)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],90)| |dn([9,Main.main],85)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],90)| |dn([6,9],94)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],90)| |dn([6,9],95)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],90)| |dn([9,Main.main],85)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],90)| |dn([6,9],92)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],90)| |dn([6,9],95)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],90)| |dn([9,Main.main],85)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],90)| |dn([6,9],92)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],90)| |dn([6,9],94)_dn([6,9],90)|))) -(assert (= |dn([7,Main.main],60)| (or |dn([7,Main.main],59)_dn([7,Main.main],60)|))) -(assert (= |dn([7,Main.main],50)| (or |dn([Main.main],105)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (= |dn([5,1],62)| (or |dn([3,7],31)_dn([5,1],62)| |dn([5,1],61)_dn([5,1],62)| |dn([5,1],63)_dn([5,1],62)|))) -(assert (not (and |dn([3,7],31)_dn([5,1],62)| |dn([5,1],61)_dn([5,1],62)|))) -(assert (not (and |dn([3,7],31)_dn([5,1],62)| |dn([5,1],63)_dn([5,1],62)|))) -(assert (not (and |dn([5,1],61)_dn([5,1],62)| |dn([3,7],31)_dn([5,1],62)|))) -(assert (not (and |dn([5,1],61)_dn([5,1],62)| |dn([5,1],63)_dn([5,1],62)|))) -(assert (not (and |dn([5,1],63)_dn([5,1],62)| |dn([3,7],31)_dn([5,1],62)|))) -(assert (not (and |dn([5,1],63)_dn([5,1],62)| |dn([5,1],61)_dn([5,1],62)|))) -(assert (= |dn([3,7],22)| (or |dn([7,Main.main],42)_dn([3,7],22)| |scc(2)_dn([3,7],22)| |scc(3)_dn([3,7],22)| |dn([3,7],21)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([7,Main.main],42)_dn([3,7],22)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |dn([7,Main.main],42)_dn([3,7],22)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |dn([7,Main.main],42)_dn([3,7],22)| |dn([3,7],21)_dn([3,7],22)|))) -(assert (not (and |dn([7,Main.main],42)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([7,Main.main],42)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([7,Main.main],42)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |dn([7,Main.main],42)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([7,Main.main],42)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |dn([7,Main.main],42)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |dn([3,7],21)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |dn([7,Main.main],42)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |dn([3,7],21)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],22)| |dn([7,Main.main],42)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],22)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],22)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([7,Main.main],42)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],21)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([7,Main.main],42)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],21)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |dn([7,Main.main],42)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |dn([3,7],21)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([7,Main.main],42)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],21)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([7,Main.main],42)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],21)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (= |dn([7,Main.main],53)| (or |dn([9,Main.main],87)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |dn([9,Main.main],87)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |dn([9,Main.main],87)_dn([7,Main.main],53)|))) -(assert (= |dn([6,9],93)| (or |scc(1)_dn([6,9],93)| |dn([6,9],90)_dn([6,9],93)| |dn([6,9],92)_dn([6,9],93)| |dn([6,9],94)_dn([6,9],93)| |dn([6,9],95)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |dn([6,9],90)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |dn([6,9],92)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |dn([6,9],94)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |dn([6,9],95)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],93)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],93)| |dn([6,9],92)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],93)| |dn([6,9],94)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],93)| |dn([6,9],95)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],93)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],93)| |dn([6,9],90)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],93)| |dn([6,9],94)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],93)| |dn([6,9],95)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],93)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],93)| |dn([6,9],90)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],93)| |dn([6,9],92)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],93)| |dn([6,9],95)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],93)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],93)| |dn([6,9],90)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],93)| |dn([6,9],92)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],93)| |dn([6,9],94)_dn([6,9],93)|))) -(assert (= |dn([7,Main.main],57)| (or |scc(1)_dn([7,Main.main],57)|))) -(assert (= |dn([Main.main],108)| (or |scc(8)_dn([Main.main],108)|))) -(assert (= |dn([7,Main.main],55)| (or |dn([7,Main.main],54)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (= |scc(1)| (or |dn([6,9],95)_scc(1)| |scc(7)_scc(1)| |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([6,9],95)_scc(1)| |scc(7)_scc(1)|))) -(assert (not (and |dn([6,9],95)_scc(1)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([6,9],95)_scc(1)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |dn([6,9],95)_scc(1)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |scc(7)_scc(1)| |dn([6,9],95)_scc(1)|))) -(assert (not (and |scc(7)_scc(1)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |scc(7)_scc(1)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |scc(7)_scc(1)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([6,9],95)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |scc(7)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([6,9],95)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |scc(7)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([6,9],95)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |scc(7)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],54)_scc(1)|))) -(assert (= |dn([Main.main],105)| (or |dn([Main.main],104)_dn([Main.main],105)|))) -(assert (= |scc(2)| (or |dn([5,1],62)_scc(2)|))) -(assert (= |dn([8,Main.main],97)| (or |dn([Main.main],108)_dn([8,Main.main],97)| |dn([8,Main.main],96)_dn([8,Main.main],97)| |dn([8,Main.main],101)_dn([8,Main.main],97)|))) -(assert (not (and |dn([Main.main],108)_dn([8,Main.main],97)| |dn([8,Main.main],96)_dn([8,Main.main],97)|))) -(assert (not (and |dn([Main.main],108)_dn([8,Main.main],97)| |dn([8,Main.main],101)_dn([8,Main.main],97)|))) -(assert (not (and |dn([8,Main.main],96)_dn([8,Main.main],97)| |dn([Main.main],108)_dn([8,Main.main],97)|))) -(assert (not (and |dn([8,Main.main],96)_dn([8,Main.main],97)| |dn([8,Main.main],101)_dn([8,Main.main],97)|))) -(assert (not (and |dn([8,Main.main],101)_dn([8,Main.main],97)| |dn([Main.main],108)_dn([8,Main.main],97)|))) -(assert (not (and |dn([8,Main.main],101)_dn([8,Main.main],97)| |dn([8,Main.main],96)_dn([8,Main.main],97)|))) -(assert (= |dn([Main.main],103)| (or |dn([Main.main],111)_dn([Main.main],103)|))) -(assert (= |scc(5)| (or |dn([3,7],30)_scc(5)|))) -(assert (= |dn([4,1],70)| (or |scc(4)_dn([4,1],70)|))) -(assert (= |dn([6,9],94)| (or |dn([6,9],93)_dn([6,9],94)|))) -(assert (= |dn([8,Main.main],100)| (or |scc(5)_dn([8,Main.main],100)|))) -(assert (= |dn([7,Main.main],59)| (or |dn([7,Main.main],58)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (= |dn([5,1],61)| (or |dn([1,3],67)_dn([5,1],61)| |dn([5,1],62)_dn([5,1],61)| |dn([5,1],63)_dn([5,1],61)|))) -(assert (not (and |dn([1,3],67)_dn([5,1],61)| |dn([5,1],62)_dn([5,1],61)|))) -(assert (not (and |dn([1,3],67)_dn([5,1],61)| |dn([5,1],63)_dn([5,1],61)|))) -(assert (not (and |dn([5,1],62)_dn([5,1],61)| |dn([1,3],67)_dn([5,1],61)|))) -(assert (not (and |dn([5,1],62)_dn([5,1],61)| |dn([5,1],63)_dn([5,1],61)|))) -(assert (not (and |dn([5,1],63)_dn([5,1],61)| |dn([1,3],67)_dn([5,1],61)|))) -(assert (not (and |dn([5,1],63)_dn([5,1],61)| |dn([5,1],62)_dn([5,1],61)|))) -(assert (= |dn([4,1],69)| (or |dn([1,3],65)_dn([4,1],69)| |dn([4,1],79)_dn([4,1],69)| |dn([4,1],81)_dn([4,1],69)|))) -(assert (not (and |dn([1,3],65)_dn([4,1],69)| |dn([4,1],79)_dn([4,1],69)|))) -(assert (not (and |dn([1,3],65)_dn([4,1],69)| |dn([4,1],81)_dn([4,1],69)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],69)| |dn([1,3],65)_dn([4,1],69)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],69)| |dn([4,1],81)_dn([4,1],69)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],69)| |dn([1,3],65)_dn([4,1],69)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],69)| |dn([4,1],79)_dn([4,1],69)|))) -(assert (= |dn([3,7],29)| (or |scc(6)_dn([3,7],29)| |scc(2)_dn([3,7],29)| |scc(3)_dn([3,7],29)| |dn([3,7],21)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |scc(6)_dn([3,7],29)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |scc(6)_dn([3,7],29)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |scc(6)_dn([3,7],29)| |dn([3,7],21)_dn([3,7],29)|))) -(assert (not (and |scc(6)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |scc(6)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |scc(6)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (not (and |scc(6)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |scc(6)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |dn([3,7],21)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |scc(6)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |dn([3,7],21)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],29)| |scc(6)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],29)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],29)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |scc(6)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |dn([3,7],21)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |scc(6)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |dn([3,7],21)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |scc(6)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |dn([3,7],21)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |scc(6)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |dn([3,7],21)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (= |dn([3,7],31)| (or |dn([2,3],36)_dn([3,7],31)| |scc(2)_dn([3,7],31)| |scc(3)_dn([3,7],31)| |dn([3,7],21)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([2,3],36)_dn([3,7],31)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |dn([2,3],36)_dn([3,7],31)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |dn([2,3],36)_dn([3,7],31)| |dn([3,7],21)_dn([3,7],31)|))) -(assert (not (and |dn([2,3],36)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([2,3],36)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([2,3],36)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([2,3],36)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |dn([2,3],36)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |dn([2,3],36)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |dn([3,7],21)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |dn([2,3],36)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |dn([3,7],21)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],31)| |dn([2,3],36)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],31)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],31)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([2,3],36)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],21)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([2,3],36)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],21)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |dn([2,3],36)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |dn([3,7],21)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([2,3],36)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],21)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([2,3],36)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],21)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (= |dn([4,1],79)| (or |dn([4,1],78)_dn([4,1],79)|))) -(assert (= |dn([2,3],34)| (or |scc(0)_dn([2,3],34)| |dn([2,3],38)_dn([2,3],34)|))) -(assert (not (and |scc(0)_dn([2,3],34)| |dn([2,3],38)_dn([2,3],34)|))) -(assert (not (and |dn([2,3],38)_dn([2,3],34)| |scc(0)_dn([2,3],34)|))) -(assert (= |dn([Main.main],115)| (or |dn([Main.main],114)_dn([Main.main],115)|))) -(assert (= |dn([2,3],37)| (or |dn([2,3],36)_dn([2,3],37)|))) -(assert (= |dn([1,3],68)| (or |dn([1,3],67)_dn([1,3],68)|))) -(assert (= |dn([4,1],81)| (or |dn([4,1],80)_dn([4,1],81)|))) -(assert (= |scc(7)| (or |dn([9,Main.main],87)_scc(7)| |scc(1)_scc(7)| |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([9,Main.main],87)_scc(7)| |scc(1)_scc(7)|))) -(assert (not (and |dn([9,Main.main],87)_scc(7)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([9,Main.main],87)_scc(7)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([9,Main.main],87)_scc(7)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |scc(1)_scc(7)| |dn([9,Main.main],87)_scc(7)|))) -(assert (not (and |scc(1)_scc(7)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |scc(1)_scc(7)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |scc(1)_scc(7)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([9,Main.main],87)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |scc(1)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([9,Main.main],87)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |scc(1)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([9,Main.main],87)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |scc(1)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],54)_scc(7)|))) -(assert (= |dn([9,Main.main],89)| (or |dn([9,Main.main],88)_dn([9,Main.main],89)|))) -(assert (= |dn([1,3],66)| (or |dn([1,3],65)_dn([1,3],66)|))) -(assert (= |dn([9,Main.main],84)| (or |dn([7,Main.main],51)_dn([9,Main.main],84)| |dn([9,Main.main],82)_dn([9,Main.main],84)| |dn([9,Main.main],83)_dn([9,Main.main],84)| |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([9,Main.main],89)_dn([9,Main.main],84)|))) -(assert (not (and |dn([7,Main.main],51)_dn([9,Main.main],84)| |dn([9,Main.main],82)_dn([9,Main.main],84)|))) -(assert (not (and |dn([7,Main.main],51)_dn([9,Main.main],84)| |dn([9,Main.main],83)_dn([9,Main.main],84)|))) -(assert (not (and |dn([7,Main.main],51)_dn([9,Main.main],84)| |dn([9,Main.main],87)_dn([9,Main.main],84)|))) -(assert (not (and |dn([7,Main.main],51)_dn([9,Main.main],84)| |dn([9,Main.main],89)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],84)| |dn([7,Main.main],51)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],84)| |dn([9,Main.main],83)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],84)| |dn([9,Main.main],87)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],84)| |dn([9,Main.main],89)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],84)| |dn([7,Main.main],51)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],84)| |dn([9,Main.main],82)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],84)| |dn([9,Main.main],87)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],84)| |dn([9,Main.main],89)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([7,Main.main],51)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([9,Main.main],82)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([9,Main.main],83)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([9,Main.main],89)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],84)| |dn([7,Main.main],51)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],84)| |dn([9,Main.main],82)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],84)| |dn([9,Main.main],83)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],84)| |dn([9,Main.main],87)_dn([9,Main.main],84)|))) -(assert (= |dn([1,3],65)| (or |dn([3,7],22)_dn([1,3],65)| |dn([1,3],64)_dn([1,3],65)| |dn([1,3],66)_dn([1,3],65)| |dn([1,3],68)_dn([1,3],65)|))) -(assert (not (and |dn([3,7],22)_dn([1,3],65)| |dn([1,3],64)_dn([1,3],65)|))) -(assert (not (and |dn([3,7],22)_dn([1,3],65)| |dn([1,3],66)_dn([1,3],65)|))) -(assert (not (and |dn([3,7],22)_dn([1,3],65)| |dn([1,3],68)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],64)_dn([1,3],65)| |dn([3,7],22)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],64)_dn([1,3],65)| |dn([1,3],66)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],64)_dn([1,3],65)| |dn([1,3],68)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],65)| |dn([3,7],22)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],65)| |dn([1,3],64)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],65)| |dn([1,3],68)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],65)| |dn([3,7],22)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],65)| |dn([1,3],64)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],65)| |dn([1,3],66)_dn([1,3],65)|))) -(assert (= |dn([7,Main.main],43)| (or |dn([7,Main.main],42)_dn([7,Main.main],43)|))) -(assert (= |dn([9,Main.main],82)| (or |dn([Main.main],113)_dn([9,Main.main],82)| |dn([9,Main.main],83)_dn([9,Main.main],82)| |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([9,Main.main],89)_dn([9,Main.main],82)| |dn([9,Main.main],84)_dn([9,Main.main],82)|))) -(assert (not (and |dn([Main.main],113)_dn([9,Main.main],82)| |dn([9,Main.main],83)_dn([9,Main.main],82)|))) -(assert (not (and |dn([Main.main],113)_dn([9,Main.main],82)| |dn([9,Main.main],87)_dn([9,Main.main],82)|))) -(assert (not (and |dn([Main.main],113)_dn([9,Main.main],82)| |dn([9,Main.main],89)_dn([9,Main.main],82)|))) -(assert (not (and |dn([Main.main],113)_dn([9,Main.main],82)| |dn([9,Main.main],84)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],82)| |dn([Main.main],113)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],82)| |dn([9,Main.main],87)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],82)| |dn([9,Main.main],89)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],82)| |dn([9,Main.main],84)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([Main.main],113)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([9,Main.main],83)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([9,Main.main],89)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([9,Main.main],84)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],82)| |dn([Main.main],113)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],82)| |dn([9,Main.main],83)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],82)| |dn([9,Main.main],87)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],82)| |dn([9,Main.main],84)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],82)| |dn([Main.main],113)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],82)| |dn([9,Main.main],83)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],82)| |dn([9,Main.main],87)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],82)| |dn([9,Main.main],89)_dn([9,Main.main],82)|))) -(assert (= |dn([7,Main.main],45)| (or |dn([7,Main.main],47)_dn([7,Main.main],45)|))) -(assert (= |dn([3,7],30)| (or |dn([3,7],29)_dn([3,7],30)| |dn([3,7],27)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],30)| |dn([3,7],27)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],30)| |dn([3,7],29)_dn([3,7],30)|))) -(assert (not |scc(8)|)) -(assert (= |dn([9,Main.main],87)| (or |dn([9,Main.main],86)_dn([9,Main.main],87)|))) -(assert (= |dn([3,7],21)| (or |dn([3,7],20)_dn([3,7],21)|))) -(assert (= |dn([7,Main.main],49)| (or |dn([Main.main],104)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (= |scc(6)| (or |dn([3,7],28)_scc(6)|))) -(assert-soft |dn([7,Main.main],41)_dn([3,7],20)| :weight 1) -(assert-soft |scc(2)_dn([3,7],20)| :weight 1) -(assert-soft |scc(3)_dn([3,7],20)| :weight 1) -(assert-soft |dn([3,7],21)_dn([3,7],20)| :weight 1) -(assert-soft |dn([3,7],28)_dn([3,7],20)| :weight 1) -(assert-soft |dn([3,7],30)_dn([3,7],20)| :weight 1) -(assert-soft |dn([3,7],33)_dn([3,7],20)| :weight 1) -(assert-soft |dn([3,7],27)_dn([3,7],20)| :weight 1) -(assert-soft |dn([3,7],29)_dn([3,7],20)| :weight 1) -(assert-soft |dn([3,7],20)_dn([3,7],21)| :weight 1) -(assert-soft |dn([7,Main.main],42)_dn([3,7],22)| :weight 1) -(assert-soft |scc(2)_dn([3,7],22)| :weight 1) -(assert-soft |scc(3)_dn([3,7],22)| :weight 1) -(assert-soft |dn([3,7],21)_dn([3,7],22)| :weight 1) -(assert-soft |dn([3,7],28)_dn([3,7],22)| :weight 1) -(assert-soft |dn([3,7],30)_dn([3,7],22)| :weight 1) -(assert-soft |dn([3,7],33)_dn([3,7],22)| :weight 1) -(assert-soft |dn([3,7],27)_dn([3,7],22)| :weight 1) -(assert-soft |dn([3,7],29)_dn([3,7],22)| :weight 1) -(assert-soft |scc(0)_dn([3,7],24)| :weight 1) -(assert-soft |dn([3,7],24)_dn([3,7],25)| :weight 1) -(assert-soft |dn([8,Main.main],97)_dn([3,7],27)| :weight 2) -(assert-soft |scc(2)_dn([3,7],27)| :weight 2) -(assert-soft |scc(3)_dn([3,7],27)| :weight 2) -(assert-soft |dn([3,7],21)_dn([3,7],27)| :weight 2) -(assert-soft |dn([3,7],28)_dn([3,7],27)| :weight 2) -(assert-soft |dn([3,7],30)_dn([3,7],27)| :weight 2) -(assert-soft |dn([3,7],33)_dn([3,7],27)| :weight 2) -(assert-soft |dn([3,7],29)_dn([3,7],27)| :weight 2) -(assert-soft |dn([3,7],27)_dn([3,7],28)| :weight 6) -(assert-soft |dn([3,7],29)_dn([3,7],28)| :weight 6) -(assert-soft |scc(6)_dn([3,7],29)| :weight 2) -(assert-soft |scc(2)_dn([3,7],29)| :weight 2) -(assert-soft |scc(3)_dn([3,7],29)| :weight 2) -(assert-soft |dn([3,7],21)_dn([3,7],29)| :weight 2) -(assert-soft |dn([3,7],28)_dn([3,7],29)| :weight 2) -(assert-soft |dn([3,7],30)_dn([3,7],29)| :weight 2) -(assert-soft |dn([3,7],33)_dn([3,7],29)| :weight 2) -(assert-soft |dn([3,7],27)_dn([3,7],29)| :weight 2) -(assert-soft |dn([3,7],29)_dn([3,7],30)| :weight 6) -(assert-soft |dn([3,7],27)_dn([3,7],30)| :weight 6) -(assert-soft |dn([2,3],36)_dn([3,7],31)| :weight 1) -(assert-soft |scc(2)_dn([3,7],31)| :weight 1) -(assert-soft |scc(3)_dn([3,7],31)| :weight 1) -(assert-soft |dn([3,7],21)_dn([3,7],31)| :weight 1) -(assert-soft |dn([3,7],28)_dn([3,7],31)| :weight 1) -(assert-soft |dn([3,7],30)_dn([3,7],31)| :weight 1) -(assert-soft |dn([3,7],33)_dn([3,7],31)| :weight 1) -(assert-soft |dn([3,7],27)_dn([3,7],31)| :weight 1) -(assert-soft |dn([3,7],29)_dn([3,7],31)| :weight 1) -(assert-soft |dn([2,3],35)_dn([3,7],33)| :weight 1) -(assert-soft |scc(2)_dn([3,7],33)| :weight 1) -(assert-soft |scc(3)_dn([3,7],33)| :weight 1) -(assert-soft |dn([3,7],21)_dn([3,7],33)| :weight 1) -(assert-soft |dn([3,7],28)_dn([3,7],33)| :weight 1) -(assert-soft |dn([3,7],30)_dn([3,7],33)| :weight 1) -(assert-soft |dn([3,7],27)_dn([3,7],33)| :weight 1) -(assert-soft |dn([3,7],29)_dn([3,7],33)| :weight 1) -(assert-soft |scc(0)_dn([2,3],34)| :weight 1) -(assert-soft |dn([2,3],38)_dn([2,3],34)| :weight 1) -(assert-soft |scc(4)_dn([2,3],35)| :weight 1) -(assert-soft |dn([2,3],34)_dn([2,3],35)| :weight 1) -(assert-soft |dn([2,3],38)_dn([2,3],35)| :weight 1) -(assert-soft |dn([2,3],35)_dn([2,3],36)| :weight 1) -(assert-soft |dn([2,3],36)_dn([2,3],37)| :weight 1) -(assert-soft |dn([2,3],37)_dn([2,3],38)| :weight 1) -(assert-soft |dn([Main.main],103)_dn([7,Main.main],39)| :weight 6) -(assert-soft |dn([7,Main.main],40)_dn([7,Main.main],39)| :weight 6) -(assert-soft |dn([7,Main.main],49)_dn([7,Main.main],39)| :weight 6) -(assert-soft |dn([7,Main.main],53)_dn([7,Main.main],39)| :weight 6) -(assert-soft |dn([7,Main.main],57)_dn([7,Main.main],39)| :weight 6) -(assert-soft |dn([7,Main.main],60)_dn([7,Main.main],39)| :weight 6) -(assert-soft |scc(1)_dn([7,Main.main],39)| :weight 6) -(assert-soft |scc(7)_dn([7,Main.main],39)| :weight 6) -(assert-soft |dn([7,Main.main],50)_dn([7,Main.main],39)| :weight 6) -(assert-soft |dn([7,Main.main],54)_dn([7,Main.main],39)| :weight 6) -(assert-soft |dn([7,Main.main],58)_dn([7,Main.main],39)| :weight 6) -(assert-soft |dn([7,Main.main],43)_dn([7,Main.main],40)| :weight 4) -(assert-soft |dn([7,Main.main],45)_dn([7,Main.main],40)| :weight 4) -(assert-soft |dn([7,Main.main],47)_dn([7,Main.main],41)| :weight 1) -(assert-soft |dn([7,Main.main],41)_dn([7,Main.main],42)| :weight 1) -(assert-soft |dn([7,Main.main],42)_dn([7,Main.main],43)| :weight 1) -(assert-soft |dn([7,Main.main],47)_dn([7,Main.main],45)| :weight 4) -(assert-soft |dn([Main.main],106)_dn([7,Main.main],47)| :weight 8) -(assert-soft |dn([7,Main.main],39)_dn([7,Main.main],47)| :weight 8) -(assert-soft |dn([7,Main.main],40)_dn([7,Main.main],47)| :weight 8) -(assert-soft |dn([7,Main.main],49)_dn([7,Main.main],47)| :weight 8) -(assert-soft |dn([7,Main.main],53)_dn([7,Main.main],47)| :weight 8) -(assert-soft |dn([7,Main.main],57)_dn([7,Main.main],47)| :weight 8) -(assert-soft |dn([7,Main.main],60)_dn([7,Main.main],47)| :weight 8) -(assert-soft |scc(1)_dn([7,Main.main],47)| :weight 8) -(assert-soft |scc(7)_dn([7,Main.main],47)| :weight 8) -(assert-soft |dn([7,Main.main],50)_dn([7,Main.main],47)| :weight 8) -(assert-soft |dn([7,Main.main],54)_dn([7,Main.main],47)| :weight 8) -(assert-soft |dn([7,Main.main],58)_dn([7,Main.main],47)| :weight 8) -(assert-soft |dn([Main.main],104)_dn([7,Main.main],49)| :weight 8) -(assert-soft |dn([7,Main.main],39)_dn([7,Main.main],49)| :weight 8) -(assert-soft |dn([7,Main.main],40)_dn([7,Main.main],49)| :weight 8) -(assert-soft |dn([7,Main.main],53)_dn([7,Main.main],49)| :weight 8) -(assert-soft |dn([7,Main.main],57)_dn([7,Main.main],49)| :weight 8) -(assert-soft |dn([7,Main.main],60)_dn([7,Main.main],49)| :weight 8) -(assert-soft |scc(1)_dn([7,Main.main],49)| :weight 8) -(assert-soft |scc(7)_dn([7,Main.main],49)| :weight 8) -(assert-soft |dn([7,Main.main],50)_dn([7,Main.main],49)| :weight 8) -(assert-soft |dn([7,Main.main],54)_dn([7,Main.main],49)| :weight 8) -(assert-soft |dn([7,Main.main],58)_dn([7,Main.main],49)| :weight 8) -(assert-soft |dn([Main.main],105)_dn([7,Main.main],50)| :weight 2) -(assert-soft |dn([7,Main.main],39)_dn([7,Main.main],50)| :weight 2) -(assert-soft |dn([7,Main.main],40)_dn([7,Main.main],50)| :weight 2) -(assert-soft |dn([7,Main.main],49)_dn([7,Main.main],50)| :weight 2) -(assert-soft |dn([7,Main.main],53)_dn([7,Main.main],50)| :weight 2) -(assert-soft |dn([7,Main.main],57)_dn([7,Main.main],50)| :weight 2) -(assert-soft |dn([7,Main.main],60)_dn([7,Main.main],50)| :weight 2) -(assert-soft |scc(1)_dn([7,Main.main],50)| :weight 2) -(assert-soft |scc(7)_dn([7,Main.main],50)| :weight 2) -(assert-soft |dn([7,Main.main],54)_dn([7,Main.main],50)| :weight 2) -(assert-soft |dn([7,Main.main],58)_dn([7,Main.main],50)| :weight 2) -(assert-soft |dn([7,Main.main],50)_dn([7,Main.main],51)| :weight 6) -(assert-soft |scc(1)_dn([7,Main.main],51)| :weight 6) -(assert-soft |scc(7)_dn([7,Main.main],51)| :weight 6) -(assert-soft |dn([7,Main.main],54)_dn([7,Main.main],51)| :weight 6) -(assert-soft |dn([7,Main.main],58)_dn([7,Main.main],51)| :weight 6) -(assert-soft |dn([9,Main.main],87)_dn([7,Main.main],53)| :weight 6) -(assert-soft |scc(7)_dn([7,Main.main],53)| :weight 6) -(assert-soft |dn([6,9],91)_dn([7,Main.main],54)| :weight 2) -(assert-soft |dn([7,Main.main],39)_dn([7,Main.main],54)| :weight 2) -(assert-soft |dn([7,Main.main],40)_dn([7,Main.main],54)| :weight 2) -(assert-soft |dn([7,Main.main],49)_dn([7,Main.main],54)| :weight 2) -(assert-soft |dn([7,Main.main],53)_dn([7,Main.main],54)| :weight 2) -(assert-soft |dn([7,Main.main],57)_dn([7,Main.main],54)| :weight 2) -(assert-soft |dn([7,Main.main],60)_dn([7,Main.main],54)| :weight 2) -(assert-soft |scc(1)_dn([7,Main.main],54)| :weight 2) -(assert-soft |scc(7)_dn([7,Main.main],54)| :weight 2) -(assert-soft |dn([7,Main.main],50)_dn([7,Main.main],54)| :weight 2) -(assert-soft |dn([7,Main.main],58)_dn([7,Main.main],54)| :weight 2) -(assert-soft |dn([7,Main.main],54)_dn([7,Main.main],55)| :weight 18) -(assert-soft |scc(1)_dn([7,Main.main],55)| :weight 18) -(assert-soft |scc(7)_dn([7,Main.main],55)| :weight 18) -(assert-soft |dn([7,Main.main],50)_dn([7,Main.main],55)| :weight 18) -(assert-soft |dn([7,Main.main],58)_dn([7,Main.main],55)| :weight 18) -(assert-soft |scc(1)_dn([7,Main.main],57)| :weight 4) -(assert-soft |dn([2,3],37)_dn([7,Main.main],58)| :weight 1) -(assert-soft |dn([7,Main.main],39)_dn([7,Main.main],58)| :weight 1) -(assert-soft |dn([7,Main.main],40)_dn([7,Main.main],58)| :weight 1) -(assert-soft |dn([7,Main.main],49)_dn([7,Main.main],58)| :weight 1) -(assert-soft |dn([7,Main.main],53)_dn([7,Main.main],58)| :weight 1) -(assert-soft |dn([7,Main.main],57)_dn([7,Main.main],58)| :weight 1) -(assert-soft |dn([7,Main.main],60)_dn([7,Main.main],58)| :weight 1) -(assert-soft |scc(1)_dn([7,Main.main],58)| :weight 1) -(assert-soft |scc(7)_dn([7,Main.main],58)| :weight 1) -(assert-soft |dn([7,Main.main],50)_dn([7,Main.main],58)| :weight 1) -(assert-soft |dn([7,Main.main],54)_dn([7,Main.main],58)| :weight 1) -(assert-soft |dn([7,Main.main],58)_dn([7,Main.main],59)| :weight 1) -(assert-soft |scc(1)_dn([7,Main.main],59)| :weight 1) -(assert-soft |scc(7)_dn([7,Main.main],59)| :weight 1) -(assert-soft |dn([7,Main.main],50)_dn([7,Main.main],59)| :weight 1) -(assert-soft |dn([7,Main.main],54)_dn([7,Main.main],59)| :weight 1) -(assert-soft |dn([7,Main.main],59)_dn([7,Main.main],60)| :weight 1) -(assert-soft |dn([1,3],67)_dn([5,1],61)| :weight 1) -(assert-soft |dn([5,1],62)_dn([5,1],61)| :weight 1) -(assert-soft |dn([5,1],63)_dn([5,1],61)| :weight 1) -(assert-soft |dn([3,7],31)_dn([5,1],62)| :weight 1) -(assert-soft |dn([5,1],61)_dn([5,1],62)| :weight 1) -(assert-soft |dn([5,1],63)_dn([5,1],62)| :weight 1) -(assert-soft |scc(5)_dn([5,1],63)| :weight 8) -(assert-soft |dn([5,1],61)_dn([5,1],63)| :weight 8) -(assert-soft |dn([5,1],62)_dn([5,1],63)| :weight 8) -(assert-soft |dn([3,7],20)_dn([1,3],64)| :weight 1) -(assert-soft |dn([1,3],66)_dn([1,3],64)| :weight 1) -(assert-soft |dn([1,3],68)_dn([1,3],64)| :weight 1) -(assert-soft |dn([3,7],22)_dn([1,3],65)| :weight 1) -(assert-soft |dn([1,3],64)_dn([1,3],65)| :weight 1) -(assert-soft |dn([1,3],66)_dn([1,3],65)| :weight 1) -(assert-soft |dn([1,3],68)_dn([1,3],65)| :weight 1) -(assert-soft |dn([1,3],65)_dn([1,3],66)| :weight 1) -(assert-soft |dn([3,7],25)_dn([1,3],67)| :weight 1) -(assert-soft |dn([1,3],64)_dn([1,3],67)| :weight 1) -(assert-soft |dn([1,3],66)_dn([1,3],67)| :weight 1) -(assert-soft |dn([1,3],68)_dn([1,3],67)| :weight 1) -(assert-soft |dn([1,3],67)_dn([1,3],68)| :weight 1) -(assert-soft |dn([1,3],65)_dn([4,1],69)| :weight 1) -(assert-soft |dn([4,1],79)_dn([4,1],69)| :weight 1) -(assert-soft |dn([4,1],81)_dn([4,1],69)| :weight 1) -(assert-soft |scc(4)_dn([4,1],70)| :weight 2) -(assert-soft |dn([8,Main.main],100)_dn([4,1],78)| :weight 6) -(assert-soft |dn([4,1],69)_dn([4,1],78)| :weight 6) -(assert-soft |dn([4,1],79)_dn([4,1],78)| :weight 6) -(assert-soft |dn([4,1],81)_dn([4,1],78)| :weight 6) -(assert-soft |dn([4,1],78)_dn([4,1],79)| :weight 4) -(assert-soft |dn([3,7],24)_dn([4,1],80)| :weight 1) -(assert-soft |dn([4,1],69)_dn([4,1],80)| :weight 1) -(assert-soft |dn([4,1],79)_dn([4,1],80)| :weight 1) -(assert-soft |dn([4,1],81)_dn([4,1],80)| :weight 1) -(assert-soft |dn([4,1],80)_dn([4,1],81)| :weight 1) -(assert-soft |dn([Main.main],113)_dn([9,Main.main],82)| :weight 4) -(assert-soft |dn([9,Main.main],83)_dn([9,Main.main],82)| :weight 4) -(assert-soft |dn([9,Main.main],87)_dn([9,Main.main],82)| :weight 4) -(assert-soft |dn([9,Main.main],89)_dn([9,Main.main],82)| :weight 4) -(assert-soft |dn([9,Main.main],84)_dn([9,Main.main],82)| :weight 4) -(assert-soft |dn([Main.main],114)_dn([9,Main.main],83)| :weight 4) -(assert-soft |dn([9,Main.main],82)_dn([9,Main.main],83)| :weight 4) -(assert-soft |dn([9,Main.main],87)_dn([9,Main.main],83)| :weight 4) -(assert-soft |dn([9,Main.main],89)_dn([9,Main.main],83)| :weight 4) -(assert-soft |dn([9,Main.main],84)_dn([9,Main.main],83)| :weight 4) -(assert-soft |dn([7,Main.main],51)_dn([9,Main.main],84)| :weight 2) -(assert-soft |dn([9,Main.main],82)_dn([9,Main.main],84)| :weight 2) -(assert-soft |dn([9,Main.main],83)_dn([9,Main.main],84)| :weight 2) -(assert-soft |dn([9,Main.main],87)_dn([9,Main.main],84)| :weight 2) -(assert-soft |dn([9,Main.main],89)_dn([9,Main.main],84)| :weight 2) -(assert-soft |dn([9,Main.main],84)_dn([9,Main.main],85)| :weight 6) -(assert-soft |dn([9,Main.main],85)_dn([9,Main.main],86)| :weight 6) -(assert-soft |dn([9,Main.main],86)_dn([9,Main.main],87)| :weight 2) -(assert-soft |dn([6,9],93)_dn([9,Main.main],88)| :weight 6) -(assert-soft |dn([9,Main.main],82)_dn([9,Main.main],88)| :weight 6) -(assert-soft |dn([9,Main.main],83)_dn([9,Main.main],88)| :weight 6) -(assert-soft |dn([9,Main.main],87)_dn([9,Main.main],88)| :weight 6) -(assert-soft |dn([9,Main.main],89)_dn([9,Main.main],88)| :weight 6) -(assert-soft |dn([9,Main.main],84)_dn([9,Main.main],88)| :weight 6) -(assert-soft |dn([9,Main.main],88)_dn([9,Main.main],89)| :weight 6) -(assert-soft |dn([9,Main.main],85)_dn([6,9],90)| :weight 8) -(assert-soft |dn([6,9],92)_dn([6,9],90)| :weight 8) -(assert-soft |dn([6,9],94)_dn([6,9],90)| :weight 8) -(assert-soft |dn([6,9],95)_dn([6,9],90)| :weight 8) -(assert-soft |dn([9,Main.main],86)_dn([6,9],91)| :weight 8) -(assert-soft |dn([6,9],90)_dn([6,9],91)| :weight 8) -(assert-soft |dn([6,9],92)_dn([6,9],91)| :weight 8) -(assert-soft |dn([6,9],94)_dn([6,9],91)| :weight 8) -(assert-soft |dn([6,9],95)_dn([6,9],91)| :weight 8) -(assert-soft |dn([6,9],91)_dn([6,9],92)| :weight 4) -(assert-soft |scc(1)_dn([6,9],93)| :weight 6) -(assert-soft |dn([6,9],90)_dn([6,9],93)| :weight 6) -(assert-soft |dn([6,9],92)_dn([6,9],93)| :weight 6) -(assert-soft |dn([6,9],94)_dn([6,9],93)| :weight 6) -(assert-soft |dn([6,9],95)_dn([6,9],93)| :weight 6) -(assert-soft |dn([6,9],93)_dn([6,9],94)| :weight 4) -(assert-soft |dn([7,Main.main],55)_dn([6,9],95)| :weight 6) -(assert-soft |dn([7,Main.main],59)_dn([6,9],95)| :weight 6) -(assert-soft |dn([6,9],90)_dn([6,9],95)| :weight 6) -(assert-soft |dn([6,9],92)_dn([6,9],95)| :weight 6) -(assert-soft |dn([6,9],94)_dn([6,9],95)| :weight 6) -(assert-soft |scc(8)_dn([8,Main.main],96)| :weight 4) -(assert-soft |dn([8,Main.main],101)_dn([8,Main.main],96)| :weight 4) -(assert-soft |dn([Main.main],108)_dn([8,Main.main],97)| :weight 8) -(assert-soft |dn([8,Main.main],96)_dn([8,Main.main],97)| :weight 8) -(assert-soft |dn([8,Main.main],101)_dn([8,Main.main],97)| :weight 8) -(assert-soft |scc(5)_dn([8,Main.main],100)| :weight 4) -(assert-soft |dn([8,Main.main],100)_dn([8,Main.main],101)| :weight 4) -(assert-soft |dn([Main.main],111)_dn([Main.main],102)| :weight 1) -(assert-soft |dn([Main.main],111)_dn([Main.main],103)| :weight 6) -(assert-soft |dn([Main.main],103)_dn([Main.main],104)| :weight 2) -(assert-soft |dn([Main.main],104)_dn([Main.main],105)| :weight 2) -(assert-soft |dn([Main.main],105)_dn([Main.main],106)| :weight 2) -(assert-soft |scc(8)_dn([Main.main],108)| :weight 2) -(assert-soft |dn([Main.main],108)_dn([Main.main],109)| :weight 6) -(assert-soft |dn([Main.main],109)_dn([Main.main],111)| :weight 6) -(assert-soft |dn([Main.main],115)_dn([Main.main],111)| :weight 6) -(assert-soft |dn([Main.main],116)_dn([Main.main],113)| :weight 3) -(assert-soft |dn([Main.main],113)_dn([Main.main],114)| :weight 1) -(assert-soft |dn([Main.main],114)_dn([Main.main],115)| :weight 1) -(assert-soft |dn([Main.main],115)_dn([Main.main],116)| :weight 2) -(assert-soft |dn([1,3],66)_scc(0)| :weight 1) -(assert-soft |dn([6,9],95)_scc(1)| :weight 6) -(assert-soft |scc(7)_scc(1)| :weight 6) -(assert-soft |dn([7,Main.main],50)_scc(1)| :weight 6) -(assert-soft |dn([7,Main.main],54)_scc(1)| :weight 6) -(assert-soft |dn([7,Main.main],58)_scc(1)| :weight 6) -(assert-soft |dn([5,1],62)_scc(2)| :weight 1) -(assert-soft |dn([4,1],78)_scc(4)| :weight 4) -(assert-soft |dn([3,7],30)_scc(5)| :weight 8) -(assert-soft |dn([3,7],28)_scc(6)| :weight 6) -(assert-soft |dn([9,Main.main],87)_scc(7)| :weight 2) -(assert-soft |scc(1)_scc(7)| :weight 2) -(assert-soft |dn([7,Main.main],50)_scc(7)| :weight 2) -(assert-soft |dn([7,Main.main],54)_scc(7)| :weight 2) -(assert-soft |dn([7,Main.main],58)_scc(7)| :weight 2) -(set-option :smt.pb.conflict_frequency 100) - -(optimize -; :wmaxsat_engine wpm2 - :wmaxsat_engine pwmax -; :wmaxsat_engine bvmax - :print_statistics true - :timeout 1200000 -) diff --git a/tests/chat_sls.smt2 b/tests/chat_sls.smt2 deleted file mode 100644 index 33a6d9b5e..000000000 --- a/tests/chat_sls.smt2 +++ /dev/null @@ -1,3380 +0,0 @@ -(declare-const |dn([7,Main.main],41)| Bool) -(declare-const |dn([3,7],24)| Bool) -(declare-const |dn([7,Main.main],47)| Bool) -(declare-const |dn([9,Main.main],86)| Bool) -(declare-const |dn([7,Main.main],51)| Bool) -(declare-const |dn([3,7],20)| Bool) -(declare-const |dn([6,9],91)| Bool) -(declare-const |scc(3)| Bool) -(declare-const |dn([6,9],92)| Bool) -(declare-const |scc(4)| Bool) -(declare-const |dn([7,Main.main],54)| Bool) -(declare-const |scc(0)| Bool) -(declare-const |dn([Main.main],109)| Bool) -(declare-const |dn([7,Main.main],58)| Bool) -(declare-const |dn([Main.main],104)| Bool) -(declare-const |dn([Main.main],102)| Bool) -(declare-const |dn([8,Main.main],101)| Bool) -(declare-const |dn([6,9],95)| Bool) -(declare-const |dn([8,Main.main],96)| Bool) -(declare-const |dn([3,7],28)| Bool) -(declare-const |dn([Main.main],106)| Bool) -(declare-const |dn([2,3],36)| Bool) -(declare-const |dn([4,1],78)| Bool) -(declare-const |dn([Main.main],114)| Bool) -(declare-const |dn([2,3],35)| Bool) -(declare-const |dn([2,3],38)| Bool) -(declare-const |dn([5,1],63)| Bool) -(declare-const |dn([7,Main.main],39)| Bool) -(declare-const |dn([3,7],33)| Bool) -(declare-const |dn([9,Main.main],88)| Bool) -(declare-const |dn([4,1],80)| Bool) -(declare-const |dn([Main.main],116)| Bool) -(declare-const |dn([Main.main],111)| Bool) -(declare-const |dn([7,Main.main],42)| Bool) -(declare-const |dn([9,Main.main],85)| Bool) -(declare-const |dn([3,7],27)| Bool) -(declare-const |dn([1,3],64)| Bool) -(declare-const |dn([9,Main.main],83)| Bool) -(declare-const |dn([1,3],67)| Bool) -(declare-const |dn([7,Main.main],40)| Bool) -(declare-const |dn([3,7],25)| Bool) -(declare-const |dn([6,9],90)| Bool) -(declare-const |dn([7,Main.main],60)| Bool) -(declare-const |dn([7,Main.main],50)| Bool) -(declare-const |dn([5,1],62)| Bool) -(declare-const |dn([3,7],22)| Bool) -(declare-const |dn([7,Main.main],53)| Bool) -(declare-const |dn([6,9],93)| Bool) -(declare-const |dn([7,Main.main],57)| Bool) -(declare-const |dn([Main.main],108)| Bool) -(declare-const |dn([7,Main.main],55)| Bool) -(declare-const |scc(1)| Bool) -(declare-const |dn([Main.main],105)| Bool) -(declare-const |scc(2)| Bool) -(declare-const |dn([8,Main.main],97)| Bool) -(declare-const |dn([Main.main],103)| Bool) -(declare-const |scc(5)| Bool) -(declare-const |dn([4,1],70)| Bool) -(declare-const |dn([6,9],94)| Bool) -(declare-const |dn([8,Main.main],100)| Bool) -(declare-const |dn([7,Main.main],59)| Bool) -(declare-const |dn([5,1],61)| Bool) -(declare-const |dn([4,1],69)| Bool) -(declare-const |dn([3,7],29)| Bool) -(declare-const |dn([3,7],31)| Bool) -(declare-const |dn([Main.main],113)| Bool) -(declare-const |dn([4,1],79)| Bool) -(declare-const |dn([2,3],34)| Bool) -(declare-const |dn([Main.main],115)| Bool) -(declare-const |dn([2,3],37)| Bool) -(declare-const |dn([1,3],68)| Bool) -(declare-const |dn([4,1],81)| Bool) -(declare-const |scc(7)| Bool) -(declare-const |dn([9,Main.main],89)| Bool) -(declare-const |dn([1,3],66)| Bool) -(declare-const |dn([9,Main.main],84)| Bool) -(declare-const |dn([1,3],65)| Bool) -(declare-const |dn([7,Main.main],43)| Bool) -(declare-const |dn([9,Main.main],82)| Bool) -(declare-const |dn([7,Main.main],45)| Bool) -(declare-const |dn([3,7],30)| Bool) -(declare-const |scc(8)| Bool) -(declare-const |dn([9,Main.main],87)| Bool) -(declare-const |dn([3,7],21)| Bool) -(declare-const |dn([7,Main.main],49)| Bool) -(declare-const |scc(6)| Bool) -(declare-const |dn([7,Main.main],41)_dn([3,7],20)| Bool) -(declare-const |dn([7,Main.main],41)_dn([7,Main.main],42)| Bool) -(declare-const |dn([3,7],24)_dn([3,7],25)| Bool) -(declare-const |dn([3,7],24)_dn([4,1],80)| Bool) -(declare-const |dn([7,Main.main],47)_dn([7,Main.main],41)| Bool) -(declare-const |dn([7,Main.main],47)_dn([7,Main.main],45)| Bool) -(declare-const |dn([9,Main.main],86)_dn([9,Main.main],87)| Bool) -(declare-const |dn([9,Main.main],86)_dn([6,9],91)| Bool) -(declare-const |dn([7,Main.main],51)_dn([9,Main.main],84)| Bool) -(declare-const |dn([3,7],20)_dn([3,7],21)| Bool) -(declare-const |dn([3,7],20)_dn([1,3],64)| Bool) -(declare-const |dn([6,9],91)_dn([7,Main.main],54)| Bool) -(declare-const |dn([6,9],91)_dn([6,9],92)| Bool) -(declare-const |scc(3)_dn([3,7],20)| Bool) -(declare-const |scc(3)_dn([3,7],22)| Bool) -(declare-const |scc(3)_dn([3,7],27)| Bool) -(declare-const |scc(3)_dn([3,7],29)| Bool) -(declare-const |scc(3)_dn([3,7],31)| Bool) -(declare-const |scc(3)_dn([3,7],33)| Bool) -(declare-const |dn([6,9],92)_dn([6,9],90)| Bool) -(declare-const |dn([6,9],92)_dn([6,9],91)| Bool) -(declare-const |dn([6,9],92)_dn([6,9],93)| Bool) -(declare-const |dn([6,9],92)_dn([6,9],95)| Bool) -(declare-const |scc(4)_dn([2,3],35)| Bool) -(declare-const |scc(4)_dn([4,1],70)| Bool) -(declare-const |dn([7,Main.main],54)_dn([7,Main.main],39)| Bool) -(declare-const |dn([7,Main.main],54)_dn([7,Main.main],47)| Bool) -(declare-const |dn([7,Main.main],54)_dn([7,Main.main],49)| Bool) -(declare-const |dn([7,Main.main],54)_dn([7,Main.main],50)| Bool) -(declare-const |dn([7,Main.main],54)_dn([7,Main.main],51)| Bool) -(declare-const |dn([7,Main.main],54)_dn([7,Main.main],55)| Bool) -(declare-const |dn([7,Main.main],54)_dn([7,Main.main],58)| Bool) -(declare-const |dn([7,Main.main],54)_dn([7,Main.main],59)| Bool) -(declare-const |dn([7,Main.main],54)_scc(1)| Bool) -(declare-const |dn([7,Main.main],54)_scc(7)| Bool) -(declare-const |scc(0)_dn([3,7],24)| Bool) -(declare-const |scc(0)_dn([2,3],34)| Bool) -(declare-const |dn([Main.main],109)_dn([Main.main],111)| Bool) -(declare-const |dn([7,Main.main],58)_dn([7,Main.main],39)| Bool) -(declare-const |dn([7,Main.main],58)_dn([7,Main.main],47)| Bool) -(declare-const |dn([7,Main.main],58)_dn([7,Main.main],49)| Bool) -(declare-const |dn([7,Main.main],58)_dn([7,Main.main],50)| Bool) -(declare-const |dn([7,Main.main],58)_dn([7,Main.main],51)| Bool) -(declare-const |dn([7,Main.main],58)_dn([7,Main.main],54)| Bool) -(declare-const |dn([7,Main.main],58)_dn([7,Main.main],55)| Bool) -(declare-const |dn([7,Main.main],58)_dn([7,Main.main],59)| Bool) -(declare-const |dn([7,Main.main],58)_scc(1)| Bool) -(declare-const |dn([7,Main.main],58)_scc(7)| Bool) -(declare-const |dn([Main.main],104)_dn([7,Main.main],49)| Bool) -(declare-const |dn([Main.main],104)_dn([Main.main],105)| Bool) -(declare-const |dn([8,Main.main],101)_dn([8,Main.main],96)| Bool) -(declare-const |dn([8,Main.main],101)_dn([8,Main.main],97)| Bool) -(declare-const |dn([6,9],95)_dn([6,9],90)| Bool) -(declare-const |dn([6,9],95)_dn([6,9],91)| Bool) -(declare-const |dn([6,9],95)_dn([6,9],93)| Bool) -(declare-const |dn([6,9],95)_scc(1)| Bool) -(declare-const |dn([8,Main.main],96)_dn([8,Main.main],97)| Bool) -(declare-const |dn([3,7],28)_dn([3,7],20)| Bool) -(declare-const |dn([3,7],28)_dn([3,7],22)| Bool) -(declare-const |dn([3,7],28)_dn([3,7],27)| Bool) -(declare-const |dn([3,7],28)_dn([3,7],29)| Bool) -(declare-const |dn([3,7],28)_dn([3,7],31)| Bool) -(declare-const |dn([3,7],28)_dn([3,7],33)| Bool) -(declare-const |dn([3,7],28)_scc(6)| Bool) -(declare-const |dn([Main.main],106)_dn([7,Main.main],47)| Bool) -(declare-const |dn([2,3],36)_dn([3,7],31)| Bool) -(declare-const |dn([2,3],36)_dn([2,3],37)| Bool) -(declare-const |dn([4,1],78)_dn([4,1],79)| Bool) -(declare-const |dn([4,1],78)_scc(4)| Bool) -(declare-const |dn([Main.main],114)_dn([9,Main.main],83)| Bool) -(declare-const |dn([Main.main],114)_dn([Main.main],115)| Bool) -(declare-const |dn([2,3],35)_dn([3,7],33)| Bool) -(declare-const |dn([2,3],35)_dn([2,3],36)| Bool) -(declare-const |dn([2,3],38)_dn([2,3],34)| Bool) -(declare-const |dn([2,3],38)_dn([2,3],35)| Bool) -(declare-const |dn([5,1],63)_dn([5,1],61)| Bool) -(declare-const |dn([5,1],63)_dn([5,1],62)| Bool) -(declare-const |dn([7,Main.main],39)_dn([7,Main.main],47)| Bool) -(declare-const |dn([7,Main.main],39)_dn([7,Main.main],49)| Bool) -(declare-const |dn([7,Main.main],39)_dn([7,Main.main],50)| Bool) -(declare-const |dn([7,Main.main],39)_dn([7,Main.main],54)| Bool) -(declare-const |dn([7,Main.main],39)_dn([7,Main.main],58)| Bool) -(declare-const |dn([3,7],33)_dn([3,7],20)| Bool) -(declare-const |dn([3,7],33)_dn([3,7],22)| Bool) -(declare-const |dn([3,7],33)_dn([3,7],27)| Bool) -(declare-const |dn([3,7],33)_dn([3,7],29)| Bool) -(declare-const |dn([3,7],33)_dn([3,7],31)| Bool) -(declare-const |dn([9,Main.main],88)_dn([9,Main.main],89)| Bool) -(declare-const |dn([4,1],80)_dn([4,1],81)| Bool) -(declare-const |dn([Main.main],116)_dn([Main.main],113)| Bool) -(declare-const |dn([Main.main],111)_dn([Main.main],102)| Bool) -(declare-const |dn([Main.main],111)_dn([Main.main],103)| Bool) -(declare-const |dn([7,Main.main],42)_dn([3,7],22)| Bool) -(declare-const |dn([7,Main.main],42)_dn([7,Main.main],43)| Bool) -(declare-const |dn([9,Main.main],85)_dn([9,Main.main],86)| Bool) -(declare-const |dn([9,Main.main],85)_dn([6,9],90)| Bool) -(declare-const |dn([3,7],27)_dn([3,7],20)| Bool) -(declare-const |dn([3,7],27)_dn([3,7],22)| Bool) -(declare-const |dn([3,7],27)_dn([3,7],28)| Bool) -(declare-const |dn([3,7],27)_dn([3,7],29)| Bool) -(declare-const |dn([3,7],27)_dn([3,7],30)| Bool) -(declare-const |dn([3,7],27)_dn([3,7],31)| Bool) -(declare-const |dn([3,7],27)_dn([3,7],33)| Bool) -(declare-const |dn([1,3],64)_dn([1,3],65)| Bool) -(declare-const |dn([1,3],64)_dn([1,3],67)| Bool) -(declare-const |dn([9,Main.main],83)_dn([9,Main.main],82)| Bool) -(declare-const |dn([9,Main.main],83)_dn([9,Main.main],84)| Bool) -(declare-const |dn([9,Main.main],83)_dn([9,Main.main],88)| Bool) -(declare-const |dn([1,3],67)_dn([5,1],61)| Bool) -(declare-const |dn([1,3],67)_dn([1,3],68)| Bool) -(declare-const |dn([7,Main.main],40)_dn([7,Main.main],39)| Bool) -(declare-const |dn([7,Main.main],40)_dn([7,Main.main],47)| Bool) -(declare-const |dn([7,Main.main],40)_dn([7,Main.main],49)| Bool) -(declare-const |dn([7,Main.main],40)_dn([7,Main.main],50)| Bool) -(declare-const |dn([7,Main.main],40)_dn([7,Main.main],54)| Bool) -(declare-const |dn([7,Main.main],40)_dn([7,Main.main],58)| Bool) -(declare-const |dn([3,7],25)_dn([1,3],67)| Bool) -(declare-const |dn([6,9],90)_dn([6,9],91)| Bool) -(declare-const |dn([6,9],90)_dn([6,9],93)| Bool) -(declare-const |dn([6,9],90)_dn([6,9],95)| Bool) -(declare-const |dn([7,Main.main],60)_dn([7,Main.main],39)| Bool) -(declare-const |dn([7,Main.main],60)_dn([7,Main.main],47)| Bool) -(declare-const |dn([7,Main.main],60)_dn([7,Main.main],49)| Bool) -(declare-const |dn([7,Main.main],60)_dn([7,Main.main],50)| Bool) -(declare-const |dn([7,Main.main],60)_dn([7,Main.main],54)| Bool) -(declare-const |dn([7,Main.main],60)_dn([7,Main.main],58)| Bool) -(declare-const |dn([7,Main.main],50)_dn([7,Main.main],39)| Bool) -(declare-const |dn([7,Main.main],50)_dn([7,Main.main],47)| Bool) -(declare-const |dn([7,Main.main],50)_dn([7,Main.main],49)| Bool) -(declare-const |dn([7,Main.main],50)_dn([7,Main.main],51)| Bool) -(declare-const |dn([7,Main.main],50)_dn([7,Main.main],54)| Bool) -(declare-const |dn([7,Main.main],50)_dn([7,Main.main],55)| Bool) -(declare-const |dn([7,Main.main],50)_dn([7,Main.main],58)| Bool) -(declare-const |dn([7,Main.main],50)_dn([7,Main.main],59)| Bool) -(declare-const |dn([7,Main.main],50)_scc(1)| Bool) -(declare-const |dn([7,Main.main],50)_scc(7)| Bool) -(declare-const |dn([5,1],62)_dn([5,1],61)| Bool) -(declare-const |dn([5,1],62)_dn([5,1],63)| Bool) -(declare-const |dn([5,1],62)_scc(2)| Bool) -(declare-const |dn([3,7],22)_dn([1,3],65)| Bool) -(declare-const |dn([7,Main.main],53)_dn([7,Main.main],39)| Bool) -(declare-const |dn([7,Main.main],53)_dn([7,Main.main],47)| Bool) -(declare-const |dn([7,Main.main],53)_dn([7,Main.main],49)| Bool) -(declare-const |dn([7,Main.main],53)_dn([7,Main.main],50)| Bool) -(declare-const |dn([7,Main.main],53)_dn([7,Main.main],54)| Bool) -(declare-const |dn([7,Main.main],53)_dn([7,Main.main],58)| Bool) -(declare-const |dn([6,9],93)_dn([9,Main.main],88)| Bool) -(declare-const |dn([6,9],93)_dn([6,9],94)| Bool) -(declare-const |dn([7,Main.main],57)_dn([7,Main.main],39)| Bool) -(declare-const |dn([7,Main.main],57)_dn([7,Main.main],47)| Bool) -(declare-const |dn([7,Main.main],57)_dn([7,Main.main],49)| Bool) -(declare-const |dn([7,Main.main],57)_dn([7,Main.main],50)| Bool) -(declare-const |dn([7,Main.main],57)_dn([7,Main.main],54)| Bool) -(declare-const |dn([7,Main.main],57)_dn([7,Main.main],58)| Bool) -(declare-const |dn([Main.main],108)_dn([8,Main.main],97)| Bool) -(declare-const |dn([Main.main],108)_dn([Main.main],109)| Bool) -(declare-const |dn([7,Main.main],55)_dn([6,9],95)| Bool) -(declare-const |scc(1)_dn([7,Main.main],39)| Bool) -(declare-const |scc(1)_dn([7,Main.main],47)| Bool) -(declare-const |scc(1)_dn([7,Main.main],49)| Bool) -(declare-const |scc(1)_dn([7,Main.main],50)| Bool) -(declare-const |scc(1)_dn([7,Main.main],51)| Bool) -(declare-const |scc(1)_dn([7,Main.main],54)| Bool) -(declare-const |scc(1)_dn([7,Main.main],55)| Bool) -(declare-const |scc(1)_dn([7,Main.main],57)| Bool) -(declare-const |scc(1)_dn([7,Main.main],58)| Bool) -(declare-const |scc(1)_dn([7,Main.main],59)| Bool) -(declare-const |scc(1)_dn([6,9],93)| Bool) -(declare-const |scc(1)_scc(7)| Bool) -(declare-const |dn([Main.main],105)_dn([7,Main.main],50)| Bool) -(declare-const |dn([Main.main],105)_dn([Main.main],106)| Bool) -(declare-const |scc(2)_dn([3,7],20)| Bool) -(declare-const |scc(2)_dn([3,7],22)| Bool) -(declare-const |scc(2)_dn([3,7],27)| Bool) -(declare-const |scc(2)_dn([3,7],29)| Bool) -(declare-const |scc(2)_dn([3,7],31)| Bool) -(declare-const |scc(2)_dn([3,7],33)| Bool) -(declare-const |dn([8,Main.main],97)_dn([3,7],27)| Bool) -(declare-const |dn([Main.main],103)_dn([7,Main.main],39)| Bool) -(declare-const |dn([Main.main],103)_dn([Main.main],104)| Bool) -(declare-const |scc(5)_dn([5,1],63)| Bool) -(declare-const |scc(5)_dn([8,Main.main],100)| Bool) -(declare-const |dn([6,9],94)_dn([6,9],90)| Bool) -(declare-const |dn([6,9],94)_dn([6,9],91)| Bool) -(declare-const |dn([6,9],94)_dn([6,9],93)| Bool) -(declare-const |dn([6,9],94)_dn([6,9],95)| Bool) -(declare-const |dn([8,Main.main],100)_dn([4,1],78)| Bool) -(declare-const |dn([8,Main.main],100)_dn([8,Main.main],101)| Bool) -(declare-const |dn([7,Main.main],59)_dn([7,Main.main],60)| Bool) -(declare-const |dn([7,Main.main],59)_dn([6,9],95)| Bool) -(declare-const |dn([5,1],61)_dn([5,1],62)| Bool) -(declare-const |dn([5,1],61)_dn([5,1],63)| Bool) -(declare-const |dn([4,1],69)_dn([4,1],78)| Bool) -(declare-const |dn([4,1],69)_dn([4,1],80)| Bool) -(declare-const |dn([3,7],29)_dn([3,7],20)| Bool) -(declare-const |dn([3,7],29)_dn([3,7],22)| Bool) -(declare-const |dn([3,7],29)_dn([3,7],27)| Bool) -(declare-const |dn([3,7],29)_dn([3,7],28)| Bool) -(declare-const |dn([3,7],29)_dn([3,7],30)| Bool) -(declare-const |dn([3,7],29)_dn([3,7],31)| Bool) -(declare-const |dn([3,7],29)_dn([3,7],33)| Bool) -(declare-const |dn([3,7],31)_dn([5,1],62)| Bool) -(declare-const |dn([Main.main],113)_dn([9,Main.main],82)| Bool) -(declare-const |dn([Main.main],113)_dn([Main.main],114)| Bool) -(declare-const |dn([4,1],79)_dn([4,1],69)| Bool) -(declare-const |dn([4,1],79)_dn([4,1],78)| Bool) -(declare-const |dn([4,1],79)_dn([4,1],80)| Bool) -(declare-const |dn([2,3],34)_dn([2,3],35)| Bool) -(declare-const |dn([Main.main],115)_dn([Main.main],111)| Bool) -(declare-const |dn([Main.main],115)_dn([Main.main],116)| Bool) -(declare-const |dn([2,3],37)_dn([2,3],38)| Bool) -(declare-const |dn([2,3],37)_dn([7,Main.main],58)| Bool) -(declare-const |dn([1,3],68)_dn([1,3],64)| Bool) -(declare-const |dn([1,3],68)_dn([1,3],65)| Bool) -(declare-const |dn([1,3],68)_dn([1,3],67)| Bool) -(declare-const |dn([4,1],81)_dn([4,1],69)| Bool) -(declare-const |dn([4,1],81)_dn([4,1],78)| Bool) -(declare-const |dn([4,1],81)_dn([4,1],80)| Bool) -(declare-const |scc(7)_dn([7,Main.main],39)| Bool) -(declare-const |scc(7)_dn([7,Main.main],47)| Bool) -(declare-const |scc(7)_dn([7,Main.main],49)| Bool) -(declare-const |scc(7)_dn([7,Main.main],50)| Bool) -(declare-const |scc(7)_dn([7,Main.main],51)| Bool) -(declare-const |scc(7)_dn([7,Main.main],53)| Bool) -(declare-const |scc(7)_dn([7,Main.main],54)| Bool) -(declare-const |scc(7)_dn([7,Main.main],55)| Bool) -(declare-const |scc(7)_dn([7,Main.main],58)| Bool) -(declare-const |scc(7)_dn([7,Main.main],59)| Bool) -(declare-const |scc(7)_scc(1)| Bool) -(declare-const |dn([9,Main.main],89)_dn([9,Main.main],82)| Bool) -(declare-const |dn([9,Main.main],89)_dn([9,Main.main],83)| Bool) -(declare-const |dn([9,Main.main],89)_dn([9,Main.main],84)| Bool) -(declare-const |dn([9,Main.main],89)_dn([9,Main.main],88)| Bool) -(declare-const |dn([1,3],66)_dn([1,3],64)| Bool) -(declare-const |dn([1,3],66)_dn([1,3],65)| Bool) -(declare-const |dn([1,3],66)_dn([1,3],67)| Bool) -(declare-const |dn([1,3],66)_scc(0)| Bool) -(declare-const |dn([9,Main.main],84)_dn([9,Main.main],82)| Bool) -(declare-const |dn([9,Main.main],84)_dn([9,Main.main],83)| Bool) -(declare-const |dn([9,Main.main],84)_dn([9,Main.main],85)| Bool) -(declare-const |dn([9,Main.main],84)_dn([9,Main.main],88)| Bool) -(declare-const |dn([1,3],65)_dn([1,3],66)| Bool) -(declare-const |dn([1,3],65)_dn([4,1],69)| Bool) -(declare-const |dn([7,Main.main],43)_dn([7,Main.main],40)| Bool) -(declare-const |dn([9,Main.main],82)_dn([9,Main.main],83)| Bool) -(declare-const |dn([9,Main.main],82)_dn([9,Main.main],84)| Bool) -(declare-const |dn([9,Main.main],82)_dn([9,Main.main],88)| Bool) -(declare-const |dn([7,Main.main],45)_dn([7,Main.main],40)| Bool) -(declare-const |dn([3,7],30)_dn([3,7],20)| Bool) -(declare-const |dn([3,7],30)_dn([3,7],22)| Bool) -(declare-const |dn([3,7],30)_dn([3,7],27)| Bool) -(declare-const |dn([3,7],30)_dn([3,7],29)| Bool) -(declare-const |dn([3,7],30)_dn([3,7],31)| Bool) -(declare-const |dn([3,7],30)_dn([3,7],33)| Bool) -(declare-const |dn([3,7],30)_scc(5)| Bool) -(declare-const |scc(8)_dn([8,Main.main],96)| Bool) -(declare-const |scc(8)_dn([Main.main],108)| Bool) -(declare-const |dn([9,Main.main],87)_dn([7,Main.main],53)| Bool) -(declare-const |dn([9,Main.main],87)_dn([9,Main.main],82)| Bool) -(declare-const |dn([9,Main.main],87)_dn([9,Main.main],83)| Bool) -(declare-const |dn([9,Main.main],87)_dn([9,Main.main],84)| Bool) -(declare-const |dn([9,Main.main],87)_dn([9,Main.main],88)| Bool) -(declare-const |dn([9,Main.main],87)_scc(7)| Bool) -(declare-const |dn([3,7],21)_dn([3,7],20)| Bool) -(declare-const |dn([3,7],21)_dn([3,7],22)| Bool) -(declare-const |dn([3,7],21)_dn([3,7],27)| Bool) -(declare-const |dn([3,7],21)_dn([3,7],29)| Bool) -(declare-const |dn([3,7],21)_dn([3,7],31)| Bool) -(declare-const |dn([3,7],21)_dn([3,7],33)| Bool) -(declare-const |dn([7,Main.main],49)_dn([7,Main.main],39)| Bool) -(declare-const |dn([7,Main.main],49)_dn([7,Main.main],47)| Bool) -(declare-const |dn([7,Main.main],49)_dn([7,Main.main],50)| Bool) -(declare-const |dn([7,Main.main],49)_dn([7,Main.main],54)| Bool) -(declare-const |dn([7,Main.main],49)_dn([7,Main.main],58)| Bool) -(declare-const |scc(6)_dn([3,7],29)| Bool) -(assert |dn([Main.main],113)|) -(assert (= |dn([7,Main.main],41)| (or |dn([7,Main.main],41)_dn([3,7],20)| |dn([7,Main.main],41)_dn([7,Main.main],42)|))) -(assert (not (and |dn([7,Main.main],41)_dn([3,7],20)| |dn([7,Main.main],41)_dn([7,Main.main],42)|))) -(assert (not (and |dn([7,Main.main],41)_dn([7,Main.main],42)| |dn([7,Main.main],41)_dn([3,7],20)|))) -(assert (= |dn([3,7],24)| (or |dn([3,7],24)_dn([3,7],25)| |dn([3,7],24)_dn([4,1],80)|))) -(assert (not (and |dn([3,7],24)_dn([3,7],25)| |dn([3,7],24)_dn([4,1],80)|))) -(assert (not (and |dn([3,7],24)_dn([4,1],80)| |dn([3,7],24)_dn([3,7],25)|))) -(assert (= |dn([7,Main.main],47)| (or |dn([7,Main.main],47)_dn([7,Main.main],41)| |dn([7,Main.main],47)_dn([7,Main.main],45)|))) -(assert (not (and |dn([7,Main.main],47)_dn([7,Main.main],41)| |dn([7,Main.main],47)_dn([7,Main.main],45)|))) -(assert (not (and |dn([7,Main.main],47)_dn([7,Main.main],45)| |dn([7,Main.main],47)_dn([7,Main.main],41)|))) -(assert (= |dn([9,Main.main],86)| (or |dn([9,Main.main],86)_dn([9,Main.main],87)| |dn([9,Main.main],86)_dn([6,9],91)|))) -(assert (not (and |dn([9,Main.main],86)_dn([9,Main.main],87)| |dn([9,Main.main],86)_dn([6,9],91)|))) -(assert (not (and |dn([9,Main.main],86)_dn([6,9],91)| |dn([9,Main.main],86)_dn([9,Main.main],87)|))) -(assert (= |dn([7,Main.main],51)| (or |dn([7,Main.main],51)_dn([9,Main.main],84)|))) -(assert (= |dn([3,7],20)| (or |dn([3,7],20)_dn([3,7],21)| |dn([3,7],20)_dn([1,3],64)|))) -(assert (not (and |dn([3,7],20)_dn([3,7],21)| |dn([3,7],20)_dn([1,3],64)|))) -(assert (not (and |dn([3,7],20)_dn([1,3],64)| |dn([3,7],20)_dn([3,7],21)|))) -(assert (= |dn([6,9],91)| (or |dn([6,9],91)_dn([7,Main.main],54)| |dn([6,9],91)_dn([6,9],92)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |dn([6,9],91)_dn([6,9],92)|))) -(assert (not (and |dn([6,9],91)_dn([6,9],92)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (= |scc(3)| (or |scc(3)_dn([3,7],20)| |scc(3)_dn([3,7],22)| |scc(3)_dn([3,7],27)| |scc(3)_dn([3,7],29)| |scc(3)_dn([3,7],31)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |scc(3)_dn([3,7],31)|))) -(assert (= |dn([6,9],92)| (or |dn([6,9],92)_dn([6,9],90)| |dn([6,9],92)_dn([6,9],91)| |dn([6,9],92)_dn([6,9],93)| |dn([6,9],92)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],90)| |dn([6,9],92)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],90)| |dn([6,9],92)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],90)| |dn([6,9],92)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],91)| |dn([6,9],92)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],91)| |dn([6,9],92)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],91)| |dn([6,9],92)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],93)| |dn([6,9],92)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],93)| |dn([6,9],92)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],93)| |dn([6,9],92)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],95)| |dn([6,9],92)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],95)| |dn([6,9],92)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],95)| |dn([6,9],92)_dn([6,9],93)|))) -(assert (= |scc(4)| (or |scc(4)_dn([2,3],35)| |scc(4)_dn([4,1],70)|))) -(assert (not (and |scc(4)_dn([2,3],35)| |scc(4)_dn([4,1],70)|))) -(assert (not (and |scc(4)_dn([4,1],70)| |scc(4)_dn([2,3],35)|))) -(assert (= |dn([7,Main.main],54)| (or |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],54)_scc(1)|))) -(assert (= |scc(0)| (or |scc(0)_dn([3,7],24)| |scc(0)_dn([2,3],34)|))) -(assert (not (and |scc(0)_dn([3,7],24)| |scc(0)_dn([2,3],34)|))) -(assert (not (and |scc(0)_dn([2,3],34)| |scc(0)_dn([3,7],24)|))) -(assert (= |dn([Main.main],109)| (or |dn([Main.main],109)_dn([Main.main],111)|))) -(assert (= |dn([7,Main.main],58)| (or |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],58)_scc(1)|))) -(assert (= |dn([Main.main],104)| (or |dn([Main.main],104)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([Main.main],105)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([Main.main],105)|))) -(assert (not (and |dn([Main.main],104)_dn([Main.main],105)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not |dn([Main.main],102)|)) -(assert (= |dn([8,Main.main],101)| (or |dn([8,Main.main],101)_dn([8,Main.main],96)| |dn([8,Main.main],101)_dn([8,Main.main],97)|))) -(assert (not (and |dn([8,Main.main],101)_dn([8,Main.main],96)| |dn([8,Main.main],101)_dn([8,Main.main],97)|))) -(assert (not (and |dn([8,Main.main],101)_dn([8,Main.main],97)| |dn([8,Main.main],101)_dn([8,Main.main],96)|))) -(assert (= |dn([6,9],95)| (or |dn([6,9],95)_dn([6,9],90)| |dn([6,9],95)_dn([6,9],91)| |dn([6,9],95)_dn([6,9],93)| |dn([6,9],95)_scc(1)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],90)| |dn([6,9],95)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],90)| |dn([6,9],95)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],90)| |dn([6,9],95)_scc(1)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],91)| |dn([6,9],95)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],91)| |dn([6,9],95)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],91)| |dn([6,9],95)_scc(1)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],93)| |dn([6,9],95)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],93)| |dn([6,9],95)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],93)| |dn([6,9],95)_scc(1)|))) -(assert (not (and |dn([6,9],95)_scc(1)| |dn([6,9],95)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],95)_scc(1)| |dn([6,9],95)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],95)_scc(1)| |dn([6,9],95)_dn([6,9],93)|))) -(assert (= |dn([8,Main.main],96)| (or |dn([8,Main.main],96)_dn([8,Main.main],97)|))) -(assert (= |dn([3,7],28)| (or |dn([3,7],28)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],33)| |dn([3,7],28)_scc(6)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],28)_scc(6)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],28)_scc(6)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([3,7],28)_scc(6)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |dn([3,7],28)_scc(6)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],28)_scc(6)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([3,7],28)_scc(6)|))) -(assert (not (and |dn([3,7],28)_scc(6)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_scc(6)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_scc(6)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_scc(6)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_scc(6)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_scc(6)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (= |dn([Main.main],106)| (or |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (= |dn([2,3],36)| (or |dn([2,3],36)_dn([3,7],31)| |dn([2,3],36)_dn([2,3],37)|))) -(assert (not (and |dn([2,3],36)_dn([3,7],31)| |dn([2,3],36)_dn([2,3],37)|))) -(assert (not (and |dn([2,3],36)_dn([2,3],37)| |dn([2,3],36)_dn([3,7],31)|))) -(assert (= |dn([4,1],78)| (or |dn([4,1],78)_dn([4,1],79)| |dn([4,1],78)_scc(4)|))) -(assert (not (and |dn([4,1],78)_dn([4,1],79)| |dn([4,1],78)_scc(4)|))) -(assert (not (and |dn([4,1],78)_scc(4)| |dn([4,1],78)_dn([4,1],79)|))) -(assert (= |dn([Main.main],114)| (or |dn([Main.main],114)_dn([9,Main.main],83)| |dn([Main.main],114)_dn([Main.main],115)|))) -(assert (not (and |dn([Main.main],114)_dn([9,Main.main],83)| |dn([Main.main],114)_dn([Main.main],115)|))) -(assert (not (and |dn([Main.main],114)_dn([Main.main],115)| |dn([Main.main],114)_dn([9,Main.main],83)|))) -(assert (= |dn([2,3],35)| (or |dn([2,3],35)_dn([3,7],33)| |dn([2,3],35)_dn([2,3],36)|))) -(assert (not (and |dn([2,3],35)_dn([3,7],33)| |dn([2,3],35)_dn([2,3],36)|))) -(assert (not (and |dn([2,3],35)_dn([2,3],36)| |dn([2,3],35)_dn([3,7],33)|))) -(assert (= |dn([2,3],38)| (or |dn([2,3],38)_dn([2,3],34)| |dn([2,3],38)_dn([2,3],35)|))) -(assert (not (and |dn([2,3],38)_dn([2,3],34)| |dn([2,3],38)_dn([2,3],35)|))) -(assert (not (and |dn([2,3],38)_dn([2,3],35)| |dn([2,3],38)_dn([2,3],34)|))) -(assert (= |dn([5,1],63)| (or |dn([5,1],63)_dn([5,1],61)| |dn([5,1],63)_dn([5,1],62)|))) -(assert (not (and |dn([5,1],63)_dn([5,1],61)| |dn([5,1],63)_dn([5,1],62)|))) -(assert (not (and |dn([5,1],63)_dn([5,1],62)| |dn([5,1],63)_dn([5,1],61)|))) -(assert (= |dn([7,Main.main],39)| (or |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (= |dn([3,7],33)| (or |dn([3,7],33)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (= |dn([9,Main.main],88)| (or |dn([9,Main.main],88)_dn([9,Main.main],89)|))) -(assert (= |dn([4,1],80)| (or |dn([4,1],80)_dn([4,1],81)|))) -(assert (= |dn([Main.main],116)| (or |dn([Main.main],116)_dn([Main.main],113)|))) -(assert (= |dn([Main.main],111)| (or |dn([Main.main],111)_dn([Main.main],102)| |dn([Main.main],111)_dn([Main.main],103)|))) -(assert (not (and |dn([Main.main],111)_dn([Main.main],102)| |dn([Main.main],111)_dn([Main.main],103)|))) -(assert (not (and |dn([Main.main],111)_dn([Main.main],103)| |dn([Main.main],111)_dn([Main.main],102)|))) -(assert (= |dn([7,Main.main],42)| (or |dn([7,Main.main],42)_dn([3,7],22)| |dn([7,Main.main],42)_dn([7,Main.main],43)|))) -(assert (not (and |dn([7,Main.main],42)_dn([3,7],22)| |dn([7,Main.main],42)_dn([7,Main.main],43)|))) -(assert (not (and |dn([7,Main.main],42)_dn([7,Main.main],43)| |dn([7,Main.main],42)_dn([3,7],22)|))) -(assert (= |dn([9,Main.main],85)| (or |dn([9,Main.main],85)_dn([9,Main.main],86)| |dn([9,Main.main],85)_dn([6,9],90)|))) -(assert (not (and |dn([9,Main.main],85)_dn([9,Main.main],86)| |dn([9,Main.main],85)_dn([6,9],90)|))) -(assert (not (and |dn([9,Main.main],85)_dn([6,9],90)| |dn([9,Main.main],85)_dn([9,Main.main],86)|))) -(assert (= |dn([3,7],27)| (or |dn([3,7],27)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],28)| |dn([3,7],27)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],30)| |dn([3,7],27)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],28)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],28)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],28)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],28)| |dn([3,7],27)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],28)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],28)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],30)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],30)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],30)| |dn([3,7],27)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],30)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],30)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],30)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (= |dn([1,3],64)| (or |dn([1,3],64)_dn([1,3],65)| |dn([1,3],64)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],64)_dn([1,3],65)| |dn([1,3],64)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],64)_dn([1,3],67)| |dn([1,3],64)_dn([1,3],65)|))) -(assert (= |dn([9,Main.main],83)| (or |dn([9,Main.main],83)_dn([9,Main.main],82)| |dn([9,Main.main],83)_dn([9,Main.main],84)| |dn([9,Main.main],83)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],82)| |dn([9,Main.main],83)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],82)| |dn([9,Main.main],83)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],84)| |dn([9,Main.main],83)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],84)| |dn([9,Main.main],83)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],88)| |dn([9,Main.main],83)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],88)| |dn([9,Main.main],83)_dn([9,Main.main],84)|))) -(assert (= |dn([1,3],67)| (or |dn([1,3],67)_dn([5,1],61)| |dn([1,3],67)_dn([1,3],68)|))) -(assert (not (and |dn([1,3],67)_dn([5,1],61)| |dn([1,3],67)_dn([1,3],68)|))) -(assert (not (and |dn([1,3],67)_dn([1,3],68)| |dn([1,3],67)_dn([5,1],61)|))) -(assert (= |dn([7,Main.main],40)| (or |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (= |dn([3,7],25)| (or |dn([3,7],25)_dn([1,3],67)|))) -(assert (= |dn([6,9],90)| (or |dn([6,9],90)_dn([6,9],91)| |dn([6,9],90)_dn([6,9],93)| |dn([6,9],90)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],91)| |dn([6,9],90)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],91)| |dn([6,9],90)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],93)| |dn([6,9],90)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],93)| |dn([6,9],90)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],95)| |dn([6,9],90)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],95)| |dn([6,9],90)_dn([6,9],93)|))) -(assert (= |dn([7,Main.main],60)| (or |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (= |dn([7,Main.main],50)| (or |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],50)_scc(1)|))) -(assert (= |dn([5,1],62)| (or |dn([5,1],62)_dn([5,1],61)| |dn([5,1],62)_dn([5,1],63)| |dn([5,1],62)_scc(2)|))) -(assert (not (and |dn([5,1],62)_dn([5,1],61)| |dn([5,1],62)_dn([5,1],63)|))) -(assert (not (and |dn([5,1],62)_dn([5,1],61)| |dn([5,1],62)_scc(2)|))) -(assert (not (and |dn([5,1],62)_dn([5,1],63)| |dn([5,1],62)_dn([5,1],61)|))) -(assert (not (and |dn([5,1],62)_dn([5,1],63)| |dn([5,1],62)_scc(2)|))) -(assert (not (and |dn([5,1],62)_scc(2)| |dn([5,1],62)_dn([5,1],61)|))) -(assert (not (and |dn([5,1],62)_scc(2)| |dn([5,1],62)_dn([5,1],63)|))) -(assert (= |dn([3,7],22)| (or |dn([3,7],22)_dn([1,3],65)|))) -(assert (= |dn([7,Main.main],53)| (or |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (= |dn([6,9],93)| (or |dn([6,9],93)_dn([9,Main.main],88)| |dn([6,9],93)_dn([6,9],94)|))) -(assert (not (and |dn([6,9],93)_dn([9,Main.main],88)| |dn([6,9],93)_dn([6,9],94)|))) -(assert (not (and |dn([6,9],93)_dn([6,9],94)| |dn([6,9],93)_dn([9,Main.main],88)|))) -(assert (= |dn([7,Main.main],57)| (or |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (= |dn([Main.main],108)| (or |dn([Main.main],108)_dn([8,Main.main],97)| |dn([Main.main],108)_dn([Main.main],109)|))) -(assert (not (and |dn([Main.main],108)_dn([8,Main.main],97)| |dn([Main.main],108)_dn([Main.main],109)|))) -(assert (not (and |dn([Main.main],108)_dn([Main.main],109)| |dn([Main.main],108)_dn([8,Main.main],97)|))) -(assert (= |dn([7,Main.main],55)| (or |dn([7,Main.main],55)_dn([6,9],95)|))) -(assert (= |scc(1)| (or |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([6,9],93)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([7,Main.main],57)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |scc(1)_scc(7)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([7,Main.main],57)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_scc(7)| |scc(1)_dn([6,9],93)|))) -(assert (= |dn([Main.main],105)| (or |dn([Main.main],105)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([Main.main],106)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([Main.main],106)|))) -(assert (not (and |dn([Main.main],105)_dn([Main.main],106)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (= |scc(2)| (or |scc(2)_dn([3,7],20)| |scc(2)_dn([3,7],22)| |scc(2)_dn([3,7],27)| |scc(2)_dn([3,7],29)| |scc(2)_dn([3,7],31)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |scc(2)_dn([3,7],31)|))) -(assert (= |dn([8,Main.main],97)| (or |dn([8,Main.main],97)_dn([3,7],27)|))) -(assert (= |dn([Main.main],103)| (or |dn([Main.main],103)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([Main.main],104)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([Main.main],104)|))) -(assert (not (and |dn([Main.main],103)_dn([Main.main],104)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (= |scc(5)| (or |scc(5)_dn([5,1],63)| |scc(5)_dn([8,Main.main],100)|))) -(assert (not (and |scc(5)_dn([5,1],63)| |scc(5)_dn([8,Main.main],100)|))) -(assert (not (and |scc(5)_dn([8,Main.main],100)| |scc(5)_dn([5,1],63)|))) -(assert (not |dn([4,1],70)|)) -(assert (= |dn([6,9],94)| (or |dn([6,9],94)_dn([6,9],90)| |dn([6,9],94)_dn([6,9],91)| |dn([6,9],94)_dn([6,9],93)| |dn([6,9],94)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],90)| |dn([6,9],94)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],90)| |dn([6,9],94)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],90)| |dn([6,9],94)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],91)| |dn([6,9],94)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],91)| |dn([6,9],94)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],91)| |dn([6,9],94)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],93)| |dn([6,9],94)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],93)| |dn([6,9],94)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],93)| |dn([6,9],94)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],95)| |dn([6,9],94)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],95)| |dn([6,9],94)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],95)| |dn([6,9],94)_dn([6,9],93)|))) -(assert (= |dn([8,Main.main],100)| (or |dn([8,Main.main],100)_dn([4,1],78)| |dn([8,Main.main],100)_dn([8,Main.main],101)|))) -(assert (not (and |dn([8,Main.main],100)_dn([4,1],78)| |dn([8,Main.main],100)_dn([8,Main.main],101)|))) -(assert (not (and |dn([8,Main.main],100)_dn([8,Main.main],101)| |dn([8,Main.main],100)_dn([4,1],78)|))) -(assert (= |dn([7,Main.main],59)| (or |dn([7,Main.main],59)_dn([7,Main.main],60)| |dn([7,Main.main],59)_dn([6,9],95)|))) -(assert (not (and |dn([7,Main.main],59)_dn([7,Main.main],60)| |dn([7,Main.main],59)_dn([6,9],95)|))) -(assert (not (and |dn([7,Main.main],59)_dn([6,9],95)| |dn([7,Main.main],59)_dn([7,Main.main],60)|))) -(assert (= |dn([5,1],61)| (or |dn([5,1],61)_dn([5,1],62)| |dn([5,1],61)_dn([5,1],63)|))) -(assert (not (and |dn([5,1],61)_dn([5,1],62)| |dn([5,1],61)_dn([5,1],63)|))) -(assert (not (and |dn([5,1],61)_dn([5,1],63)| |dn([5,1],61)_dn([5,1],62)|))) -(assert (= |dn([4,1],69)| (or |dn([4,1],69)_dn([4,1],78)| |dn([4,1],69)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],69)_dn([4,1],78)| |dn([4,1],69)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],69)_dn([4,1],80)| |dn([4,1],69)_dn([4,1],78)|))) -(assert (= |dn([3,7],29)| (or |dn([3,7],29)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],28)| |dn([3,7],29)_dn([3,7],30)| |dn([3,7],29)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],28)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],28)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],28)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],28)| |dn([3,7],29)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],28)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],28)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],30)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],30)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],30)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],30)| |dn([3,7],29)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],30)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],30)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (= |dn([3,7],31)| (or |dn([3,7],31)_dn([5,1],62)|))) -(assert (= |dn([Main.main],113)| (or |dn([Main.main],113)_dn([9,Main.main],82)| |dn([Main.main],113)_dn([Main.main],114)|))) -(assert (not (and |dn([Main.main],113)_dn([9,Main.main],82)| |dn([Main.main],113)_dn([Main.main],114)|))) -(assert (not (and |dn([Main.main],113)_dn([Main.main],114)| |dn([Main.main],113)_dn([9,Main.main],82)|))) -(assert (= |dn([4,1],79)| (or |dn([4,1],79)_dn([4,1],69)| |dn([4,1],79)_dn([4,1],78)| |dn([4,1],79)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],69)| |dn([4,1],79)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],69)| |dn([4,1],79)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],78)| |dn([4,1],79)_dn([4,1],69)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],78)| |dn([4,1],79)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],80)| |dn([4,1],79)_dn([4,1],69)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],80)| |dn([4,1],79)_dn([4,1],78)|))) -(assert (= |dn([2,3],34)| (or |dn([2,3],34)_dn([2,3],35)|))) -(assert (= |dn([Main.main],115)| (or |dn([Main.main],115)_dn([Main.main],111)| |dn([Main.main],115)_dn([Main.main],116)|))) -(assert (not (and |dn([Main.main],115)_dn([Main.main],111)| |dn([Main.main],115)_dn([Main.main],116)|))) -(assert (not (and |dn([Main.main],115)_dn([Main.main],116)| |dn([Main.main],115)_dn([Main.main],111)|))) -(assert (= |dn([2,3],37)| (or |dn([2,3],37)_dn([2,3],38)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([2,3],38)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |dn([2,3],37)_dn([2,3],38)|))) -(assert (= |dn([1,3],68)| (or |dn([1,3],68)_dn([1,3],64)| |dn([1,3],68)_dn([1,3],65)| |dn([1,3],68)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],64)| |dn([1,3],68)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],64)| |dn([1,3],68)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],65)| |dn([1,3],68)_dn([1,3],64)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],65)| |dn([1,3],68)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],67)| |dn([1,3],68)_dn([1,3],64)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],67)| |dn([1,3],68)_dn([1,3],65)|))) -(assert (= |dn([4,1],81)| (or |dn([4,1],81)_dn([4,1],69)| |dn([4,1],81)_dn([4,1],78)| |dn([4,1],81)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],69)| |dn([4,1],81)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],69)| |dn([4,1],81)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],78)| |dn([4,1],81)_dn([4,1],69)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],78)| |dn([4,1],81)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],80)| |dn([4,1],81)_dn([4,1],69)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],80)| |dn([4,1],81)_dn([4,1],78)|))) -(assert (= |scc(7)| (or |scc(7)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],59)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(7)_scc(1)|))) -(assert (not (and |scc(7)_scc(1)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_scc(1)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_scc(1)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_scc(1)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_scc(1)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_scc(1)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_scc(1)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_scc(1)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_scc(1)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_scc(1)| |scc(7)_dn([7,Main.main],59)|))) -(assert (= |dn([9,Main.main],89)| (or |dn([9,Main.main],89)_dn([9,Main.main],82)| |dn([9,Main.main],89)_dn([9,Main.main],83)| |dn([9,Main.main],89)_dn([9,Main.main],84)| |dn([9,Main.main],89)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],82)| |dn([9,Main.main],89)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],82)| |dn([9,Main.main],89)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],82)| |dn([9,Main.main],89)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],83)| |dn([9,Main.main],89)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],83)| |dn([9,Main.main],89)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],83)| |dn([9,Main.main],89)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],84)| |dn([9,Main.main],89)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],84)| |dn([9,Main.main],89)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],84)| |dn([9,Main.main],89)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],88)| |dn([9,Main.main],89)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],88)| |dn([9,Main.main],89)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],88)| |dn([9,Main.main],89)_dn([9,Main.main],84)|))) -(assert (= |dn([1,3],66)| (or |dn([1,3],66)_dn([1,3],64)| |dn([1,3],66)_dn([1,3],65)| |dn([1,3],66)_dn([1,3],67)| |dn([1,3],66)_scc(0)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],64)| |dn([1,3],66)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],64)| |dn([1,3],66)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],64)| |dn([1,3],66)_scc(0)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],65)| |dn([1,3],66)_dn([1,3],64)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],65)| |dn([1,3],66)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],65)| |dn([1,3],66)_scc(0)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],67)| |dn([1,3],66)_dn([1,3],64)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],67)| |dn([1,3],66)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],67)| |dn([1,3],66)_scc(0)|))) -(assert (not (and |dn([1,3],66)_scc(0)| |dn([1,3],66)_dn([1,3],64)|))) -(assert (not (and |dn([1,3],66)_scc(0)| |dn([1,3],66)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],66)_scc(0)| |dn([1,3],66)_dn([1,3],67)|))) -(assert (= |dn([9,Main.main],84)| (or |dn([9,Main.main],84)_dn([9,Main.main],82)| |dn([9,Main.main],84)_dn([9,Main.main],83)| |dn([9,Main.main],84)_dn([9,Main.main],85)| |dn([9,Main.main],84)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],82)| |dn([9,Main.main],84)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],82)| |dn([9,Main.main],84)_dn([9,Main.main],85)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],82)| |dn([9,Main.main],84)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],83)| |dn([9,Main.main],84)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],83)| |dn([9,Main.main],84)_dn([9,Main.main],85)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],83)| |dn([9,Main.main],84)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],85)| |dn([9,Main.main],84)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],85)| |dn([9,Main.main],84)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],85)| |dn([9,Main.main],84)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],88)| |dn([9,Main.main],84)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],88)| |dn([9,Main.main],84)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],88)| |dn([9,Main.main],84)_dn([9,Main.main],85)|))) -(assert (= |dn([1,3],65)| (or |dn([1,3],65)_dn([1,3],66)| |dn([1,3],65)_dn([4,1],69)|))) -(assert (not (and |dn([1,3],65)_dn([1,3],66)| |dn([1,3],65)_dn([4,1],69)|))) -(assert (not (and |dn([1,3],65)_dn([4,1],69)| |dn([1,3],65)_dn([1,3],66)|))) -(assert (= |dn([7,Main.main],43)| (or |dn([7,Main.main],43)_dn([7,Main.main],40)|))) -(assert (= |dn([9,Main.main],82)| (or |dn([9,Main.main],82)_dn([9,Main.main],83)| |dn([9,Main.main],82)_dn([9,Main.main],84)| |dn([9,Main.main],82)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],83)| |dn([9,Main.main],82)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],83)| |dn([9,Main.main],82)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],84)| |dn([9,Main.main],82)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],84)| |dn([9,Main.main],82)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],88)| |dn([9,Main.main],82)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],88)| |dn([9,Main.main],82)_dn([9,Main.main],84)|))) -(assert (= |dn([7,Main.main],45)| (or |dn([7,Main.main],45)_dn([7,Main.main],40)|))) -(assert (= |dn([3,7],30)| (or |dn([3,7],30)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],33)| |dn([3,7],30)_scc(5)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],30)_scc(5)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],30)_scc(5)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([3,7],30)_scc(5)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |dn([3,7],30)_scc(5)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],30)_scc(5)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([3,7],30)_scc(5)|))) -(assert (not (and |dn([3,7],30)_scc(5)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_scc(5)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_scc(5)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_scc(5)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_scc(5)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_scc(5)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (= |scc(8)| (or |scc(8)_dn([8,Main.main],96)| |scc(8)_dn([Main.main],108)|))) -(assert (not (and |scc(8)_dn([8,Main.main],96)| |scc(8)_dn([Main.main],108)|))) -(assert (not (and |scc(8)_dn([Main.main],108)| |scc(8)_dn([8,Main.main],96)|))) -(assert (= |dn([9,Main.main],87)| (or |dn([9,Main.main],87)_dn([7,Main.main],53)| |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],87)_scc(7)|))) -(assert (not (and |dn([9,Main.main],87)_dn([7,Main.main],53)| |dn([9,Main.main],87)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],87)_dn([7,Main.main],53)| |dn([9,Main.main],87)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],87)_dn([7,Main.main],53)| |dn([9,Main.main],87)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],87)_dn([7,Main.main],53)| |dn([9,Main.main],87)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],87)_dn([7,Main.main],53)| |dn([9,Main.main],87)_scc(7)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([9,Main.main],87)_dn([7,Main.main],53)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([9,Main.main],87)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([9,Main.main],87)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([9,Main.main],87)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([9,Main.main],87)_scc(7)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([9,Main.main],87)_dn([7,Main.main],53)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([9,Main.main],87)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([9,Main.main],87)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([9,Main.main],87)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([9,Main.main],87)_scc(7)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([9,Main.main],87)_dn([7,Main.main],53)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([9,Main.main],87)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([9,Main.main],87)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([9,Main.main],87)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([9,Main.main],87)_scc(7)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],87)_dn([7,Main.main],53)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],87)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],87)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],87)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],87)_scc(7)|))) -(assert (not (and |dn([9,Main.main],87)_scc(7)| |dn([9,Main.main],87)_dn([7,Main.main],53)|))) -(assert (not (and |dn([9,Main.main],87)_scc(7)| |dn([9,Main.main],87)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],87)_scc(7)| |dn([9,Main.main],87)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],87)_scc(7)| |dn([9,Main.main],87)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],87)_scc(7)| |dn([9,Main.main],87)_dn([9,Main.main],88)|))) -(assert (= |dn([7,Main.main],49)| (or |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (= |scc(6)| (or |scc(6)_dn([3,7],29)|))) -(assert (= |dn([7,Main.main],41)| (or |dn([7,Main.main],47)_dn([7,Main.main],41)|))) -(assert (= |dn([3,7],24)| (or |scc(0)_dn([3,7],24)|))) -(assert (= |dn([7,Main.main],47)| (or |dn([Main.main],106)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([Main.main],106)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |scc(1)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |scc(7)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],47)| |dn([7,Main.main],58)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([Main.main],106)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],39)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],40)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],49)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],53)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],57)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],60)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |scc(1)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |scc(7)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],50)_dn([7,Main.main],47)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],47)| |dn([7,Main.main],54)_dn([7,Main.main],47)|))) -(assert (= |dn([9,Main.main],86)| (or |dn([9,Main.main],85)_dn([9,Main.main],86)|))) -(assert (= |dn([7,Main.main],51)| (or |dn([7,Main.main],50)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |scc(1)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (not (and |scc(7)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],51)| |dn([7,Main.main],58)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],50)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |scc(1)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |scc(7)_dn([7,Main.main],51)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],51)| |dn([7,Main.main],54)_dn([7,Main.main],51)|))) -(assert (= |dn([3,7],20)| (or |dn([7,Main.main],41)_dn([3,7],20)| |scc(2)_dn([3,7],20)| |scc(3)_dn([3,7],20)| |dn([3,7],21)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([7,Main.main],41)_dn([3,7],20)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |dn([7,Main.main],41)_dn([3,7],20)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |dn([7,Main.main],41)_dn([3,7],20)| |dn([3,7],21)_dn([3,7],20)|))) -(assert (not (and |dn([7,Main.main],41)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([7,Main.main],41)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([7,Main.main],41)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |dn([7,Main.main],41)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([7,Main.main],41)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |dn([7,Main.main],41)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |dn([3,7],21)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |scc(2)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |dn([7,Main.main],41)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |dn([3,7],21)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |scc(3)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],20)| |dn([7,Main.main],41)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],20)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],20)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([7,Main.main],41)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],21)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([7,Main.main],41)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],21)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |dn([7,Main.main],41)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |dn([3,7],21)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([7,Main.main],41)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],21)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],20)| |dn([3,7],29)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([7,Main.main],41)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |scc(2)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |scc(3)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],21)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],28)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],30)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],33)_dn([3,7],20)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],20)| |dn([3,7],27)_dn([3,7],20)|))) -(assert (= |dn([6,9],91)| (or |dn([9,Main.main],86)_dn([6,9],91)| |dn([6,9],90)_dn([6,9],91)| |dn([6,9],92)_dn([6,9],91)| |dn([6,9],94)_dn([6,9],91)| |dn([6,9],95)_dn([6,9],91)|))) -(assert (not (and |dn([9,Main.main],86)_dn([6,9],91)| |dn([6,9],90)_dn([6,9],91)|))) -(assert (not (and |dn([9,Main.main],86)_dn([6,9],91)| |dn([6,9],92)_dn([6,9],91)|))) -(assert (not (and |dn([9,Main.main],86)_dn([6,9],91)| |dn([6,9],94)_dn([6,9],91)|))) -(assert (not (and |dn([9,Main.main],86)_dn([6,9],91)| |dn([6,9],95)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],91)| |dn([9,Main.main],86)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],91)| |dn([6,9],92)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],91)| |dn([6,9],94)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],91)| |dn([6,9],95)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],91)| |dn([9,Main.main],86)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],91)| |dn([6,9],90)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],91)| |dn([6,9],94)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],91)| |dn([6,9],95)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],91)| |dn([9,Main.main],86)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],91)| |dn([6,9],90)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],91)| |dn([6,9],92)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],91)| |dn([6,9],95)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],91)| |dn([9,Main.main],86)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],91)| |dn([6,9],90)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],91)| |dn([6,9],92)_dn([6,9],91)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],91)| |dn([6,9],94)_dn([6,9],91)|))) -(assert (not |scc(3)|)) -(assert (= |dn([6,9],92)| (or |dn([6,9],91)_dn([6,9],92)|))) -(assert (= |scc(4)| (or |dn([4,1],78)_scc(4)|))) -(assert (= |dn([7,Main.main],54)| (or |dn([6,9],91)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([6,9],91)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |scc(1)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (not (and |scc(7)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],54)| |dn([7,Main.main],58)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([6,9],91)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],39)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],40)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],49)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],53)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],57)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],60)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |scc(1)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |scc(7)_dn([7,Main.main],54)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],54)| |dn([7,Main.main],50)_dn([7,Main.main],54)|))) -(assert (= |scc(0)| (or |dn([1,3],66)_scc(0)|))) -(assert (= |dn([Main.main],109)| (or |dn([Main.main],108)_dn([Main.main],109)|))) -(assert (= |dn([7,Main.main],58)| (or |dn([2,3],37)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([2,3],37)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |scc(1)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (not (and |scc(7)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],58)| |dn([7,Main.main],54)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([2,3],37)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],39)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],40)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],49)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],53)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],57)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],60)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |scc(1)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |scc(7)_dn([7,Main.main],58)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],58)| |dn([7,Main.main],50)_dn([7,Main.main],58)|))) -(assert (= |dn([Main.main],104)| (or |dn([Main.main],103)_dn([Main.main],104)|))) -(assert (= |dn([Main.main],102)| (or |dn([Main.main],111)_dn([Main.main],102)|))) -(assert (= |dn([8,Main.main],101)| (or |dn([8,Main.main],100)_dn([8,Main.main],101)|))) -(assert (= |dn([6,9],95)| (or |dn([7,Main.main],55)_dn([6,9],95)| |dn([7,Main.main],59)_dn([6,9],95)| |dn([6,9],90)_dn([6,9],95)| |dn([6,9],92)_dn([6,9],95)| |dn([6,9],94)_dn([6,9],95)|))) -(assert (not (and |dn([7,Main.main],55)_dn([6,9],95)| |dn([7,Main.main],59)_dn([6,9],95)|))) -(assert (not (and |dn([7,Main.main],55)_dn([6,9],95)| |dn([6,9],90)_dn([6,9],95)|))) -(assert (not (and |dn([7,Main.main],55)_dn([6,9],95)| |dn([6,9],92)_dn([6,9],95)|))) -(assert (not (and |dn([7,Main.main],55)_dn([6,9],95)| |dn([6,9],94)_dn([6,9],95)|))) -(assert (not (and |dn([7,Main.main],59)_dn([6,9],95)| |dn([7,Main.main],55)_dn([6,9],95)|))) -(assert (not (and |dn([7,Main.main],59)_dn([6,9],95)| |dn([6,9],90)_dn([6,9],95)|))) -(assert (not (and |dn([7,Main.main],59)_dn([6,9],95)| |dn([6,9],92)_dn([6,9],95)|))) -(assert (not (and |dn([7,Main.main],59)_dn([6,9],95)| |dn([6,9],94)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],95)| |dn([7,Main.main],55)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],95)| |dn([7,Main.main],59)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],95)| |dn([6,9],92)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],95)| |dn([6,9],94)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],95)| |dn([7,Main.main],55)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],95)| |dn([7,Main.main],59)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],95)| |dn([6,9],90)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],95)| |dn([6,9],94)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],95)| |dn([7,Main.main],55)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],95)| |dn([7,Main.main],59)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],95)| |dn([6,9],90)_dn([6,9],95)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],95)| |dn([6,9],92)_dn([6,9],95)|))) -(assert (= |dn([8,Main.main],96)| (or |scc(8)_dn([8,Main.main],96)| |dn([8,Main.main],101)_dn([8,Main.main],96)|))) -(assert (not (and |scc(8)_dn([8,Main.main],96)| |dn([8,Main.main],101)_dn([8,Main.main],96)|))) -(assert (not (and |dn([8,Main.main],101)_dn([8,Main.main],96)| |scc(8)_dn([8,Main.main],96)|))) -(assert (= |dn([3,7],28)| (or |dn([3,7],27)_dn([3,7],28)| |dn([3,7],29)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],28)| |dn([3,7],29)_dn([3,7],28)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],28)| |dn([3,7],27)_dn([3,7],28)|))) -(assert (= |dn([Main.main],106)| (or |dn([Main.main],105)_dn([Main.main],106)|))) -(assert (= |dn([2,3],36)| (or |dn([2,3],35)_dn([2,3],36)|))) -(assert (= |dn([4,1],78)| (or |dn([8,Main.main],100)_dn([4,1],78)| |dn([4,1],69)_dn([4,1],78)| |dn([4,1],79)_dn([4,1],78)| |dn([4,1],81)_dn([4,1],78)|))) -(assert (not (and |dn([8,Main.main],100)_dn([4,1],78)| |dn([4,1],69)_dn([4,1],78)|))) -(assert (not (and |dn([8,Main.main],100)_dn([4,1],78)| |dn([4,1],79)_dn([4,1],78)|))) -(assert (not (and |dn([8,Main.main],100)_dn([4,1],78)| |dn([4,1],81)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],69)_dn([4,1],78)| |dn([8,Main.main],100)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],69)_dn([4,1],78)| |dn([4,1],79)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],69)_dn([4,1],78)| |dn([4,1],81)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],78)| |dn([8,Main.main],100)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],78)| |dn([4,1],69)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],78)| |dn([4,1],81)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],78)| |dn([8,Main.main],100)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],78)| |dn([4,1],69)_dn([4,1],78)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],78)| |dn([4,1],79)_dn([4,1],78)|))) -(assert (= |dn([Main.main],114)| (or |dn([Main.main],113)_dn([Main.main],114)|))) -(assert (= |dn([2,3],35)| (or |scc(4)_dn([2,3],35)| |dn([2,3],34)_dn([2,3],35)| |dn([2,3],38)_dn([2,3],35)|))) -(assert (not (and |scc(4)_dn([2,3],35)| |dn([2,3],34)_dn([2,3],35)|))) -(assert (not (and |scc(4)_dn([2,3],35)| |dn([2,3],38)_dn([2,3],35)|))) -(assert (not (and |dn([2,3],34)_dn([2,3],35)| |scc(4)_dn([2,3],35)|))) -(assert (not (and |dn([2,3],34)_dn([2,3],35)| |dn([2,3],38)_dn([2,3],35)|))) -(assert (not (and |dn([2,3],38)_dn([2,3],35)| |scc(4)_dn([2,3],35)|))) -(assert (not (and |dn([2,3],38)_dn([2,3],35)| |dn([2,3],34)_dn([2,3],35)|))) -(assert (= |dn([2,3],38)| (or |dn([2,3],37)_dn([2,3],38)|))) -(assert (= |dn([5,1],63)| (or |scc(5)_dn([5,1],63)| |dn([5,1],61)_dn([5,1],63)| |dn([5,1],62)_dn([5,1],63)|))) -(assert (not (and |scc(5)_dn([5,1],63)| |dn([5,1],61)_dn([5,1],63)|))) -(assert (not (and |scc(5)_dn([5,1],63)| |dn([5,1],62)_dn([5,1],63)|))) -(assert (not (and |dn([5,1],61)_dn([5,1],63)| |scc(5)_dn([5,1],63)|))) -(assert (not (and |dn([5,1],61)_dn([5,1],63)| |dn([5,1],62)_dn([5,1],63)|))) -(assert (not (and |dn([5,1],62)_dn([5,1],63)| |scc(5)_dn([5,1],63)|))) -(assert (not (and |dn([5,1],62)_dn([5,1],63)| |dn([5,1],61)_dn([5,1],63)|))) -(assert (= |dn([7,Main.main],39)| (or |dn([Main.main],103)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([Main.main],103)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |scc(1)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |scc(7)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],39)| |dn([7,Main.main],58)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([Main.main],103)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],40)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],49)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],53)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],57)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],60)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |scc(1)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |scc(7)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],50)_dn([7,Main.main],39)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],39)| |dn([7,Main.main],54)_dn([7,Main.main],39)|))) -(assert (= |dn([3,7],33)| (or |dn([2,3],35)_dn([3,7],33)| |scc(2)_dn([3,7],33)| |scc(3)_dn([3,7],33)| |dn([3,7],21)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([2,3],35)_dn([3,7],33)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |dn([2,3],35)_dn([3,7],33)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |dn([2,3],35)_dn([3,7],33)| |dn([3,7],21)_dn([3,7],33)|))) -(assert (not (and |dn([2,3],35)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |dn([2,3],35)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |dn([2,3],35)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([2,3],35)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |dn([2,3],35)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |dn([3,7],21)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |scc(2)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |dn([2,3],35)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |dn([3,7],21)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |scc(3)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],33)| |dn([2,3],35)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],33)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],33)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([2,3],35)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([3,7],21)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([2,3],35)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([3,7],21)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([2,3],35)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([3,7],21)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],33)| |dn([3,7],29)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([2,3],35)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |scc(2)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |scc(3)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([3,7],21)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([3,7],28)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([3,7],30)_dn([3,7],33)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],33)| |dn([3,7],27)_dn([3,7],33)|))) -(assert (= |dn([9,Main.main],88)| (or |dn([6,9],93)_dn([9,Main.main],88)| |dn([9,Main.main],82)_dn([9,Main.main],88)| |dn([9,Main.main],83)_dn([9,Main.main],88)| |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],89)_dn([9,Main.main],88)| |dn([9,Main.main],84)_dn([9,Main.main],88)|))) -(assert (not (and |dn([6,9],93)_dn([9,Main.main],88)| |dn([9,Main.main],82)_dn([9,Main.main],88)|))) -(assert (not (and |dn([6,9],93)_dn([9,Main.main],88)| |dn([9,Main.main],83)_dn([9,Main.main],88)|))) -(assert (not (and |dn([6,9],93)_dn([9,Main.main],88)| |dn([9,Main.main],87)_dn([9,Main.main],88)|))) -(assert (not (and |dn([6,9],93)_dn([9,Main.main],88)| |dn([9,Main.main],89)_dn([9,Main.main],88)|))) -(assert (not (and |dn([6,9],93)_dn([9,Main.main],88)| |dn([9,Main.main],84)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],88)| |dn([6,9],93)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],88)| |dn([9,Main.main],83)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],88)| |dn([9,Main.main],87)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],88)| |dn([9,Main.main],89)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],88)| |dn([9,Main.main],84)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],88)| |dn([6,9],93)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],88)| |dn([9,Main.main],82)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],88)| |dn([9,Main.main],87)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],88)| |dn([9,Main.main],89)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],88)| |dn([9,Main.main],84)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([6,9],93)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],82)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],83)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],89)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],88)| |dn([9,Main.main],84)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],88)| |dn([6,9],93)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],88)| |dn([9,Main.main],82)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],88)| |dn([9,Main.main],83)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],88)| |dn([9,Main.main],87)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],88)| |dn([9,Main.main],84)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],88)| |dn([6,9],93)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],88)| |dn([9,Main.main],82)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],88)| |dn([9,Main.main],83)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],88)| |dn([9,Main.main],87)_dn([9,Main.main],88)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],88)| |dn([9,Main.main],89)_dn([9,Main.main],88)|))) -(assert (= |dn([4,1],80)| (or |dn([3,7],24)_dn([4,1],80)| |dn([4,1],69)_dn([4,1],80)| |dn([4,1],79)_dn([4,1],80)| |dn([4,1],81)_dn([4,1],80)|))) -(assert (not (and |dn([3,7],24)_dn([4,1],80)| |dn([4,1],69)_dn([4,1],80)|))) -(assert (not (and |dn([3,7],24)_dn([4,1],80)| |dn([4,1],79)_dn([4,1],80)|))) -(assert (not (and |dn([3,7],24)_dn([4,1],80)| |dn([4,1],81)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],69)_dn([4,1],80)| |dn([3,7],24)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],69)_dn([4,1],80)| |dn([4,1],79)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],69)_dn([4,1],80)| |dn([4,1],81)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],80)| |dn([3,7],24)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],80)| |dn([4,1],69)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],80)| |dn([4,1],81)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],80)| |dn([3,7],24)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],80)| |dn([4,1],69)_dn([4,1],80)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],80)| |dn([4,1],79)_dn([4,1],80)|))) -(assert (= |dn([Main.main],116)| (or |dn([Main.main],115)_dn([Main.main],116)|))) -(assert (= |dn([Main.main],111)| (or |dn([Main.main],109)_dn([Main.main],111)| |dn([Main.main],115)_dn([Main.main],111)|))) -(assert (not (and |dn([Main.main],109)_dn([Main.main],111)| |dn([Main.main],115)_dn([Main.main],111)|))) -(assert (not (and |dn([Main.main],115)_dn([Main.main],111)| |dn([Main.main],109)_dn([Main.main],111)|))) -(assert (= |dn([7,Main.main],42)| (or |dn([7,Main.main],41)_dn([7,Main.main],42)|))) -(assert (= |dn([9,Main.main],85)| (or |dn([9,Main.main],84)_dn([9,Main.main],85)|))) -(assert (= |dn([3,7],27)| (or |dn([8,Main.main],97)_dn([3,7],27)| |scc(2)_dn([3,7],27)| |scc(3)_dn([3,7],27)| |dn([3,7],21)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([8,Main.main],97)_dn([3,7],27)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |dn([8,Main.main],97)_dn([3,7],27)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |dn([8,Main.main],97)_dn([3,7],27)| |dn([3,7],21)_dn([3,7],27)|))) -(assert (not (and |dn([8,Main.main],97)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([8,Main.main],97)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([8,Main.main],97)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (not (and |dn([8,Main.main],97)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |dn([8,Main.main],97)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |dn([3,7],21)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (not (and |scc(2)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |dn([8,Main.main],97)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |dn([3,7],21)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (not (and |scc(3)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],27)| |dn([8,Main.main],97)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],27)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],27)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([8,Main.main],97)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([3,7],21)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([8,Main.main],97)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([3,7],21)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |dn([8,Main.main],97)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |dn([3,7],21)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],27)| |dn([3,7],29)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([8,Main.main],97)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |scc(2)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |scc(3)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([3,7],21)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([3,7],28)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([3,7],30)_dn([3,7],27)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],27)| |dn([3,7],33)_dn([3,7],27)|))) -(assert (= |dn([1,3],64)| (or |dn([3,7],20)_dn([1,3],64)| |dn([1,3],66)_dn([1,3],64)| |dn([1,3],68)_dn([1,3],64)|))) -(assert (not (and |dn([3,7],20)_dn([1,3],64)| |dn([1,3],66)_dn([1,3],64)|))) -(assert (not (and |dn([3,7],20)_dn([1,3],64)| |dn([1,3],68)_dn([1,3],64)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],64)| |dn([3,7],20)_dn([1,3],64)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],64)| |dn([1,3],68)_dn([1,3],64)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],64)| |dn([3,7],20)_dn([1,3],64)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],64)| |dn([1,3],66)_dn([1,3],64)|))) -(assert (= |dn([9,Main.main],83)| (or |dn([Main.main],114)_dn([9,Main.main],83)| |dn([9,Main.main],82)_dn([9,Main.main],83)| |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([9,Main.main],89)_dn([9,Main.main],83)| |dn([9,Main.main],84)_dn([9,Main.main],83)|))) -(assert (not (and |dn([Main.main],114)_dn([9,Main.main],83)| |dn([9,Main.main],82)_dn([9,Main.main],83)|))) -(assert (not (and |dn([Main.main],114)_dn([9,Main.main],83)| |dn([9,Main.main],87)_dn([9,Main.main],83)|))) -(assert (not (and |dn([Main.main],114)_dn([9,Main.main],83)| |dn([9,Main.main],89)_dn([9,Main.main],83)|))) -(assert (not (and |dn([Main.main],114)_dn([9,Main.main],83)| |dn([9,Main.main],84)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],83)| |dn([Main.main],114)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],83)| |dn([9,Main.main],87)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],83)| |dn([9,Main.main],89)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],83)| |dn([9,Main.main],84)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([Main.main],114)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([9,Main.main],82)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([9,Main.main],89)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],83)| |dn([9,Main.main],84)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],83)| |dn([Main.main],114)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],83)| |dn([9,Main.main],82)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],83)| |dn([9,Main.main],87)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],83)| |dn([9,Main.main],84)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],83)| |dn([Main.main],114)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],83)| |dn([9,Main.main],82)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],83)| |dn([9,Main.main],87)_dn([9,Main.main],83)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],83)| |dn([9,Main.main],89)_dn([9,Main.main],83)|))) -(assert (= |dn([1,3],67)| (or |dn([3,7],25)_dn([1,3],67)| |dn([1,3],64)_dn([1,3],67)| |dn([1,3],66)_dn([1,3],67)| |dn([1,3],68)_dn([1,3],67)|))) -(assert (not (and |dn([3,7],25)_dn([1,3],67)| |dn([1,3],64)_dn([1,3],67)|))) -(assert (not (and |dn([3,7],25)_dn([1,3],67)| |dn([1,3],66)_dn([1,3],67)|))) -(assert (not (and |dn([3,7],25)_dn([1,3],67)| |dn([1,3],68)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],64)_dn([1,3],67)| |dn([3,7],25)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],64)_dn([1,3],67)| |dn([1,3],66)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],64)_dn([1,3],67)| |dn([1,3],68)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],67)| |dn([3,7],25)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],67)| |dn([1,3],64)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],67)| |dn([1,3],68)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],67)| |dn([3,7],25)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],67)| |dn([1,3],64)_dn([1,3],67)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],67)| |dn([1,3],66)_dn([1,3],67)|))) -(assert (= |dn([7,Main.main],40)| (or |dn([7,Main.main],43)_dn([7,Main.main],40)| |dn([7,Main.main],45)_dn([7,Main.main],40)|))) -(assert (not (and |dn([7,Main.main],43)_dn([7,Main.main],40)| |dn([7,Main.main],45)_dn([7,Main.main],40)|))) -(assert (not (and |dn([7,Main.main],45)_dn([7,Main.main],40)| |dn([7,Main.main],43)_dn([7,Main.main],40)|))) -(assert (= |dn([3,7],25)| (or |dn([3,7],24)_dn([3,7],25)|))) -(assert (= |dn([6,9],90)| (or |dn([9,Main.main],85)_dn([6,9],90)| |dn([6,9],92)_dn([6,9],90)| |dn([6,9],94)_dn([6,9],90)| |dn([6,9],95)_dn([6,9],90)|))) -(assert (not (and |dn([9,Main.main],85)_dn([6,9],90)| |dn([6,9],92)_dn([6,9],90)|))) -(assert (not (and |dn([9,Main.main],85)_dn([6,9],90)| |dn([6,9],94)_dn([6,9],90)|))) -(assert (not (and |dn([9,Main.main],85)_dn([6,9],90)| |dn([6,9],95)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],90)| |dn([9,Main.main],85)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],90)| |dn([6,9],94)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],90)| |dn([6,9],95)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],90)| |dn([9,Main.main],85)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],90)| |dn([6,9],92)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],90)| |dn([6,9],95)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],90)| |dn([9,Main.main],85)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],90)| |dn([6,9],92)_dn([6,9],90)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],90)| |dn([6,9],94)_dn([6,9],90)|))) -(assert (= |dn([7,Main.main],60)| (or |dn([7,Main.main],59)_dn([7,Main.main],60)|))) -(assert (= |dn([7,Main.main],50)| (or |dn([Main.main],105)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([Main.main],105)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],49)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |scc(1)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (not (and |scc(7)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],50)| |dn([7,Main.main],58)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([Main.main],105)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],39)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],40)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],49)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],53)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],57)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],60)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |scc(1)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |scc(7)_dn([7,Main.main],50)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],50)| |dn([7,Main.main],54)_dn([7,Main.main],50)|))) -(assert (= |dn([5,1],62)| (or |dn([3,7],31)_dn([5,1],62)| |dn([5,1],61)_dn([5,1],62)| |dn([5,1],63)_dn([5,1],62)|))) -(assert (not (and |dn([3,7],31)_dn([5,1],62)| |dn([5,1],61)_dn([5,1],62)|))) -(assert (not (and |dn([3,7],31)_dn([5,1],62)| |dn([5,1],63)_dn([5,1],62)|))) -(assert (not (and |dn([5,1],61)_dn([5,1],62)| |dn([3,7],31)_dn([5,1],62)|))) -(assert (not (and |dn([5,1],61)_dn([5,1],62)| |dn([5,1],63)_dn([5,1],62)|))) -(assert (not (and |dn([5,1],63)_dn([5,1],62)| |dn([3,7],31)_dn([5,1],62)|))) -(assert (not (and |dn([5,1],63)_dn([5,1],62)| |dn([5,1],61)_dn([5,1],62)|))) -(assert (= |dn([3,7],22)| (or |dn([7,Main.main],42)_dn([3,7],22)| |scc(2)_dn([3,7],22)| |scc(3)_dn([3,7],22)| |dn([3,7],21)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([7,Main.main],42)_dn([3,7],22)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |dn([7,Main.main],42)_dn([3,7],22)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |dn([7,Main.main],42)_dn([3,7],22)| |dn([3,7],21)_dn([3,7],22)|))) -(assert (not (and |dn([7,Main.main],42)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([7,Main.main],42)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([7,Main.main],42)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |dn([7,Main.main],42)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([7,Main.main],42)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |dn([7,Main.main],42)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |dn([3,7],21)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |scc(2)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |dn([7,Main.main],42)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |dn([3,7],21)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |scc(3)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],22)| |dn([7,Main.main],42)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],22)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],22)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([7,Main.main],42)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],21)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([7,Main.main],42)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],21)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |dn([7,Main.main],42)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |dn([3,7],21)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([7,Main.main],42)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],21)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],22)| |dn([3,7],29)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([7,Main.main],42)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |scc(2)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |scc(3)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],21)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],28)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],30)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],33)_dn([3,7],22)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],22)| |dn([3,7],27)_dn([3,7],22)|))) -(assert (= |dn([7,Main.main],53)| (or |dn([9,Main.main],87)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |dn([9,Main.main],87)_dn([7,Main.main],53)| |scc(7)_dn([7,Main.main],53)|))) -(assert (not (and |scc(7)_dn([7,Main.main],53)| |dn([9,Main.main],87)_dn([7,Main.main],53)|))) -(assert (= |dn([6,9],93)| (or |scc(1)_dn([6,9],93)| |dn([6,9],90)_dn([6,9],93)| |dn([6,9],92)_dn([6,9],93)| |dn([6,9],94)_dn([6,9],93)| |dn([6,9],95)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |dn([6,9],90)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |dn([6,9],92)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |dn([6,9],94)_dn([6,9],93)|))) -(assert (not (and |scc(1)_dn([6,9],93)| |dn([6,9],95)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],93)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],93)| |dn([6,9],92)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],93)| |dn([6,9],94)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],90)_dn([6,9],93)| |dn([6,9],95)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],93)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],93)| |dn([6,9],90)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],93)| |dn([6,9],94)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],92)_dn([6,9],93)| |dn([6,9],95)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],93)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],93)| |dn([6,9],90)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],93)| |dn([6,9],92)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],94)_dn([6,9],93)| |dn([6,9],95)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],93)| |scc(1)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],93)| |dn([6,9],90)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],93)| |dn([6,9],92)_dn([6,9],93)|))) -(assert (not (and |dn([6,9],95)_dn([6,9],93)| |dn([6,9],94)_dn([6,9],93)|))) -(assert (= |dn([7,Main.main],57)| (or |scc(1)_dn([7,Main.main],57)|))) -(assert (= |dn([Main.main],108)| (or |scc(8)_dn([Main.main],108)|))) -(assert (= |dn([7,Main.main],55)| (or |dn([7,Main.main],54)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |scc(1)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (not (and |scc(7)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],55)| |dn([7,Main.main],58)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],54)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |scc(1)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |scc(7)_dn([7,Main.main],55)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],55)| |dn([7,Main.main],50)_dn([7,Main.main],55)|))) -(assert (= |scc(1)| (or |dn([6,9],95)_scc(1)| |scc(7)_scc(1)| |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([6,9],95)_scc(1)| |scc(7)_scc(1)|))) -(assert (not (and |dn([6,9],95)_scc(1)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([6,9],95)_scc(1)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |dn([6,9],95)_scc(1)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |scc(7)_scc(1)| |dn([6,9],95)_scc(1)|))) -(assert (not (and |scc(7)_scc(1)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |scc(7)_scc(1)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |scc(7)_scc(1)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([6,9],95)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |scc(7)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],54)_scc(1)|))) -(assert (not (and |dn([7,Main.main],50)_scc(1)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([6,9],95)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |scc(7)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([7,Main.main],54)_scc(1)| |dn([7,Main.main],58)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([6,9],95)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |scc(7)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],50)_scc(1)|))) -(assert (not (and |dn([7,Main.main],58)_scc(1)| |dn([7,Main.main],54)_scc(1)|))) -(assert (= |dn([Main.main],105)| (or |dn([Main.main],104)_dn([Main.main],105)|))) -(assert (= |scc(2)| (or |dn([5,1],62)_scc(2)|))) -(assert (= |dn([8,Main.main],97)| (or |dn([Main.main],108)_dn([8,Main.main],97)| |dn([8,Main.main],96)_dn([8,Main.main],97)| |dn([8,Main.main],101)_dn([8,Main.main],97)|))) -(assert (not (and |dn([Main.main],108)_dn([8,Main.main],97)| |dn([8,Main.main],96)_dn([8,Main.main],97)|))) -(assert (not (and |dn([Main.main],108)_dn([8,Main.main],97)| |dn([8,Main.main],101)_dn([8,Main.main],97)|))) -(assert (not (and |dn([8,Main.main],96)_dn([8,Main.main],97)| |dn([Main.main],108)_dn([8,Main.main],97)|))) -(assert (not (and |dn([8,Main.main],96)_dn([8,Main.main],97)| |dn([8,Main.main],101)_dn([8,Main.main],97)|))) -(assert (not (and |dn([8,Main.main],101)_dn([8,Main.main],97)| |dn([Main.main],108)_dn([8,Main.main],97)|))) -(assert (not (and |dn([8,Main.main],101)_dn([8,Main.main],97)| |dn([8,Main.main],96)_dn([8,Main.main],97)|))) -(assert (= |dn([Main.main],103)| (or |dn([Main.main],111)_dn([Main.main],103)|))) -(assert (= |scc(5)| (or |dn([3,7],30)_scc(5)|))) -(assert (= |dn([4,1],70)| (or |scc(4)_dn([4,1],70)|))) -(assert (= |dn([6,9],94)| (or |dn([6,9],93)_dn([6,9],94)|))) -(assert (= |dn([8,Main.main],100)| (or |scc(5)_dn([8,Main.main],100)|))) -(assert (= |dn([7,Main.main],59)| (or |dn([7,Main.main],58)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |scc(1)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (not (and |scc(7)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],59)| |dn([7,Main.main],54)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],58)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |scc(1)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |scc(7)_dn([7,Main.main],59)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],59)| |dn([7,Main.main],50)_dn([7,Main.main],59)|))) -(assert (= |dn([5,1],61)| (or |dn([1,3],67)_dn([5,1],61)| |dn([5,1],62)_dn([5,1],61)| |dn([5,1],63)_dn([5,1],61)|))) -(assert (not (and |dn([1,3],67)_dn([5,1],61)| |dn([5,1],62)_dn([5,1],61)|))) -(assert (not (and |dn([1,3],67)_dn([5,1],61)| |dn([5,1],63)_dn([5,1],61)|))) -(assert (not (and |dn([5,1],62)_dn([5,1],61)| |dn([1,3],67)_dn([5,1],61)|))) -(assert (not (and |dn([5,1],62)_dn([5,1],61)| |dn([5,1],63)_dn([5,1],61)|))) -(assert (not (and |dn([5,1],63)_dn([5,1],61)| |dn([1,3],67)_dn([5,1],61)|))) -(assert (not (and |dn([5,1],63)_dn([5,1],61)| |dn([5,1],62)_dn([5,1],61)|))) -(assert (= |dn([4,1],69)| (or |dn([1,3],65)_dn([4,1],69)| |dn([4,1],79)_dn([4,1],69)| |dn([4,1],81)_dn([4,1],69)|))) -(assert (not (and |dn([1,3],65)_dn([4,1],69)| |dn([4,1],79)_dn([4,1],69)|))) -(assert (not (and |dn([1,3],65)_dn([4,1],69)| |dn([4,1],81)_dn([4,1],69)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],69)| |dn([1,3],65)_dn([4,1],69)|))) -(assert (not (and |dn([4,1],79)_dn([4,1],69)| |dn([4,1],81)_dn([4,1],69)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],69)| |dn([1,3],65)_dn([4,1],69)|))) -(assert (not (and |dn([4,1],81)_dn([4,1],69)| |dn([4,1],79)_dn([4,1],69)|))) -(assert (= |dn([3,7],29)| (or |scc(6)_dn([3,7],29)| |scc(2)_dn([3,7],29)| |scc(3)_dn([3,7],29)| |dn([3,7],21)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |scc(6)_dn([3,7],29)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |scc(6)_dn([3,7],29)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |scc(6)_dn([3,7],29)| |dn([3,7],21)_dn([3,7],29)|))) -(assert (not (and |scc(6)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |scc(6)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |scc(6)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (not (and |scc(6)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |scc(6)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |dn([3,7],21)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (not (and |scc(2)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |scc(6)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |dn([3,7],21)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (not (and |scc(3)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],29)| |scc(6)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],29)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],29)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |scc(6)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |dn([3,7],21)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |scc(6)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |dn([3,7],21)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |scc(6)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |dn([3,7],21)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],29)| |dn([3,7],27)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |scc(6)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |scc(2)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |scc(3)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |dn([3,7],21)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |dn([3,7],28)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |dn([3,7],30)_dn([3,7],29)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],29)| |dn([3,7],33)_dn([3,7],29)|))) -(assert (= |dn([3,7],31)| (or |dn([2,3],36)_dn([3,7],31)| |scc(2)_dn([3,7],31)| |scc(3)_dn([3,7],31)| |dn([3,7],21)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([2,3],36)_dn([3,7],31)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |dn([2,3],36)_dn([3,7],31)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |dn([2,3],36)_dn([3,7],31)| |dn([3,7],21)_dn([3,7],31)|))) -(assert (not (and |dn([2,3],36)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([2,3],36)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([2,3],36)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([2,3],36)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |dn([2,3],36)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |dn([2,3],36)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |dn([3,7],21)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |scc(2)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |dn([2,3],36)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |dn([3,7],21)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |scc(3)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],31)| |dn([2,3],36)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],31)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],31)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],21)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([2,3],36)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],21)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],28)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([2,3],36)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],21)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],30)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |dn([2,3],36)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |dn([3,7],21)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],33)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([2,3],36)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],21)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],31)| |dn([3,7],29)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([2,3],36)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |scc(2)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |scc(3)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],21)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],28)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],30)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],33)_dn([3,7],31)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],31)| |dn([3,7],27)_dn([3,7],31)|))) -(assert (= |dn([4,1],79)| (or |dn([4,1],78)_dn([4,1],79)|))) -(assert (= |dn([2,3],34)| (or |scc(0)_dn([2,3],34)| |dn([2,3],38)_dn([2,3],34)|))) -(assert (not (and |scc(0)_dn([2,3],34)| |dn([2,3],38)_dn([2,3],34)|))) -(assert (not (and |dn([2,3],38)_dn([2,3],34)| |scc(0)_dn([2,3],34)|))) -(assert (= |dn([Main.main],115)| (or |dn([Main.main],114)_dn([Main.main],115)|))) -(assert (= |dn([2,3],37)| (or |dn([2,3],36)_dn([2,3],37)|))) -(assert (= |dn([1,3],68)| (or |dn([1,3],67)_dn([1,3],68)|))) -(assert (= |dn([4,1],81)| (or |dn([4,1],80)_dn([4,1],81)|))) -(assert (= |scc(7)| (or |dn([9,Main.main],87)_scc(7)| |scc(1)_scc(7)| |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([9,Main.main],87)_scc(7)| |scc(1)_scc(7)|))) -(assert (not (and |dn([9,Main.main],87)_scc(7)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([9,Main.main],87)_scc(7)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([9,Main.main],87)_scc(7)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |scc(1)_scc(7)| |dn([9,Main.main],87)_scc(7)|))) -(assert (not (and |scc(1)_scc(7)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |scc(1)_scc(7)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |scc(1)_scc(7)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([9,Main.main],87)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |scc(1)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],54)_scc(7)|))) -(assert (not (and |dn([7,Main.main],50)_scc(7)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([9,Main.main],87)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |scc(1)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],54)_scc(7)| |dn([7,Main.main],58)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([9,Main.main],87)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |scc(1)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],50)_scc(7)|))) -(assert (not (and |dn([7,Main.main],58)_scc(7)| |dn([7,Main.main],54)_scc(7)|))) -(assert (= |dn([9,Main.main],89)| (or |dn([9,Main.main],88)_dn([9,Main.main],89)|))) -(assert (= |dn([1,3],66)| (or |dn([1,3],65)_dn([1,3],66)|))) -(assert (= |dn([9,Main.main],84)| (or |dn([7,Main.main],51)_dn([9,Main.main],84)| |dn([9,Main.main],82)_dn([9,Main.main],84)| |dn([9,Main.main],83)_dn([9,Main.main],84)| |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([9,Main.main],89)_dn([9,Main.main],84)|))) -(assert (not (and |dn([7,Main.main],51)_dn([9,Main.main],84)| |dn([9,Main.main],82)_dn([9,Main.main],84)|))) -(assert (not (and |dn([7,Main.main],51)_dn([9,Main.main],84)| |dn([9,Main.main],83)_dn([9,Main.main],84)|))) -(assert (not (and |dn([7,Main.main],51)_dn([9,Main.main],84)| |dn([9,Main.main],87)_dn([9,Main.main],84)|))) -(assert (not (and |dn([7,Main.main],51)_dn([9,Main.main],84)| |dn([9,Main.main],89)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],84)| |dn([7,Main.main],51)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],84)| |dn([9,Main.main],83)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],84)| |dn([9,Main.main],87)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],82)_dn([9,Main.main],84)| |dn([9,Main.main],89)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],84)| |dn([7,Main.main],51)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],84)| |dn([9,Main.main],82)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],84)| |dn([9,Main.main],87)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],84)| |dn([9,Main.main],89)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([7,Main.main],51)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([9,Main.main],82)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([9,Main.main],83)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],84)| |dn([9,Main.main],89)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],84)| |dn([7,Main.main],51)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],84)| |dn([9,Main.main],82)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],84)| |dn([9,Main.main],83)_dn([9,Main.main],84)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],84)| |dn([9,Main.main],87)_dn([9,Main.main],84)|))) -(assert (= |dn([1,3],65)| (or |dn([3,7],22)_dn([1,3],65)| |dn([1,3],64)_dn([1,3],65)| |dn([1,3],66)_dn([1,3],65)| |dn([1,3],68)_dn([1,3],65)|))) -(assert (not (and |dn([3,7],22)_dn([1,3],65)| |dn([1,3],64)_dn([1,3],65)|))) -(assert (not (and |dn([3,7],22)_dn([1,3],65)| |dn([1,3],66)_dn([1,3],65)|))) -(assert (not (and |dn([3,7],22)_dn([1,3],65)| |dn([1,3],68)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],64)_dn([1,3],65)| |dn([3,7],22)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],64)_dn([1,3],65)| |dn([1,3],66)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],64)_dn([1,3],65)| |dn([1,3],68)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],65)| |dn([3,7],22)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],65)| |dn([1,3],64)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],66)_dn([1,3],65)| |dn([1,3],68)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],65)| |dn([3,7],22)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],65)| |dn([1,3],64)_dn([1,3],65)|))) -(assert (not (and |dn([1,3],68)_dn([1,3],65)| |dn([1,3],66)_dn([1,3],65)|))) -(assert (= |dn([7,Main.main],43)| (or |dn([7,Main.main],42)_dn([7,Main.main],43)|))) -(assert (= |dn([9,Main.main],82)| (or |dn([Main.main],113)_dn([9,Main.main],82)| |dn([9,Main.main],83)_dn([9,Main.main],82)| |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([9,Main.main],89)_dn([9,Main.main],82)| |dn([9,Main.main],84)_dn([9,Main.main],82)|))) -(assert (not (and |dn([Main.main],113)_dn([9,Main.main],82)| |dn([9,Main.main],83)_dn([9,Main.main],82)|))) -(assert (not (and |dn([Main.main],113)_dn([9,Main.main],82)| |dn([9,Main.main],87)_dn([9,Main.main],82)|))) -(assert (not (and |dn([Main.main],113)_dn([9,Main.main],82)| |dn([9,Main.main],89)_dn([9,Main.main],82)|))) -(assert (not (and |dn([Main.main],113)_dn([9,Main.main],82)| |dn([9,Main.main],84)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],82)| |dn([Main.main],113)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],82)| |dn([9,Main.main],87)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],82)| |dn([9,Main.main],89)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],83)_dn([9,Main.main],82)| |dn([9,Main.main],84)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([Main.main],113)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([9,Main.main],83)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([9,Main.main],89)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],87)_dn([9,Main.main],82)| |dn([9,Main.main],84)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],82)| |dn([Main.main],113)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],82)| |dn([9,Main.main],83)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],82)| |dn([9,Main.main],87)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],89)_dn([9,Main.main],82)| |dn([9,Main.main],84)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],82)| |dn([Main.main],113)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],82)| |dn([9,Main.main],83)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],82)| |dn([9,Main.main],87)_dn([9,Main.main],82)|))) -(assert (not (and |dn([9,Main.main],84)_dn([9,Main.main],82)| |dn([9,Main.main],89)_dn([9,Main.main],82)|))) -(assert (= |dn([7,Main.main],45)| (or |dn([7,Main.main],47)_dn([7,Main.main],45)|))) -(assert (= |dn([3,7],30)| (or |dn([3,7],29)_dn([3,7],30)| |dn([3,7],27)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],29)_dn([3,7],30)| |dn([3,7],27)_dn([3,7],30)|))) -(assert (not (and |dn([3,7],27)_dn([3,7],30)| |dn([3,7],29)_dn([3,7],30)|))) -(assert (not |scc(8)|)) -(assert (= |dn([9,Main.main],87)| (or |dn([9,Main.main],86)_dn([9,Main.main],87)|))) -(assert (= |dn([3,7],21)| (or |dn([3,7],20)_dn([3,7],21)|))) -(assert (= |dn([7,Main.main],49)| (or |dn([Main.main],104)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([Main.main],104)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],39)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],40)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],53)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],57)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],60)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |scc(1)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |scc(7)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],50)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],54)_dn([7,Main.main],49)| |dn([7,Main.main],58)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([Main.main],104)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],39)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],40)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],53)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],57)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],60)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |scc(1)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |scc(7)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],50)_dn([7,Main.main],49)|))) -(assert (not (and |dn([7,Main.main],58)_dn([7,Main.main],49)| |dn([7,Main.main],54)_dn([7,Main.main],49)|))) -(assert (= |scc(6)| (or |dn([3,7],28)_scc(6)|))) -(assert-soft |dn([7,Main.main],41)_dn([3,7],20)| :weight 1) -(assert-soft |scc(2)_dn([3,7],20)| :weight 1) -(assert-soft |scc(3)_dn([3,7],20)| :weight 1) -(assert-soft |dn([3,7],21)_dn([3,7],20)| :weight 1) -(assert-soft |dn([3,7],28)_dn([3,7],20)| :weight 1) -(assert-soft |dn([3,7],30)_dn([3,7],20)| :weight 1) -(assert-soft |dn([3,7],33)_dn([3,7],20)| :weight 1) -(assert-soft |dn([3,7],27)_dn([3,7],20)| :weight 1) -(assert-soft |dn([3,7],29)_dn([3,7],20)| :weight 1) -(assert-soft |dn([3,7],20)_dn([3,7],21)| :weight 1) -(assert-soft |dn([7,Main.main],42)_dn([3,7],22)| :weight 1) -(assert-soft |scc(2)_dn([3,7],22)| :weight 1) -(assert-soft |scc(3)_dn([3,7],22)| :weight 1) -(assert-soft |dn([3,7],21)_dn([3,7],22)| :weight 1) -(assert-soft |dn([3,7],28)_dn([3,7],22)| :weight 1) -(assert-soft |dn([3,7],30)_dn([3,7],22)| :weight 1) -(assert-soft |dn([3,7],33)_dn([3,7],22)| :weight 1) -(assert-soft |dn([3,7],27)_dn([3,7],22)| :weight 1) -(assert-soft |dn([3,7],29)_dn([3,7],22)| :weight 1) -(assert-soft |scc(0)_dn([3,7],24)| :weight 1) -(assert-soft |dn([3,7],24)_dn([3,7],25)| :weight 1) -(assert-soft |dn([8,Main.main],97)_dn([3,7],27)| :weight 2) -(assert-soft |scc(2)_dn([3,7],27)| :weight 2) -(assert-soft |scc(3)_dn([3,7],27)| :weight 2) -(assert-soft |dn([3,7],21)_dn([3,7],27)| :weight 2) -(assert-soft |dn([3,7],28)_dn([3,7],27)| :weight 2) -(assert-soft |dn([3,7],30)_dn([3,7],27)| :weight 2) -(assert-soft |dn([3,7],33)_dn([3,7],27)| :weight 2) -(assert-soft |dn([3,7],29)_dn([3,7],27)| :weight 2) -(assert-soft |dn([3,7],27)_dn([3,7],28)| :weight 6) -(assert-soft |dn([3,7],29)_dn([3,7],28)| :weight 6) -(assert-soft |scc(6)_dn([3,7],29)| :weight 2) -(assert-soft |scc(2)_dn([3,7],29)| :weight 2) -(assert-soft |scc(3)_dn([3,7],29)| :weight 2) -(assert-soft |dn([3,7],21)_dn([3,7],29)| :weight 2) -(assert-soft |dn([3,7],28)_dn([3,7],29)| :weight 2) -(assert-soft |dn([3,7],30)_dn([3,7],29)| :weight 2) -(assert-soft |dn([3,7],33)_dn([3,7],29)| :weight 2) -(assert-soft |dn([3,7],27)_dn([3,7],29)| :weight 2) -(assert-soft |dn([3,7],29)_dn([3,7],30)| :weight 6) -(assert-soft |dn([3,7],27)_dn([3,7],30)| :weight 6) -(assert-soft |dn([2,3],36)_dn([3,7],31)| :weight 1) -(assert-soft |scc(2)_dn([3,7],31)| :weight 1) -(assert-soft |scc(3)_dn([3,7],31)| :weight 1) -(assert-soft |dn([3,7],21)_dn([3,7],31)| :weight 1) -(assert-soft |dn([3,7],28)_dn([3,7],31)| :weight 1) -(assert-soft |dn([3,7],30)_dn([3,7],31)| :weight 1) -(assert-soft |dn([3,7],33)_dn([3,7],31)| :weight 1) -(assert-soft |dn([3,7],27)_dn([3,7],31)| :weight 1) -(assert-soft |dn([3,7],29)_dn([3,7],31)| :weight 1) -(assert-soft |dn([2,3],35)_dn([3,7],33)| :weight 1) -(assert-soft |scc(2)_dn([3,7],33)| :weight 1) -(assert-soft |scc(3)_dn([3,7],33)| :weight 1) -(assert-soft |dn([3,7],21)_dn([3,7],33)| :weight 1) -(assert-soft |dn([3,7],28)_dn([3,7],33)| :weight 1) -(assert-soft |dn([3,7],30)_dn([3,7],33)| :weight 1) -(assert-soft |dn([3,7],27)_dn([3,7],33)| :weight 1) -(assert-soft |dn([3,7],29)_dn([3,7],33)| :weight 1) -(assert-soft |scc(0)_dn([2,3],34)| :weight 1) -(assert-soft |dn([2,3],38)_dn([2,3],34)| :weight 1) -(assert-soft |scc(4)_dn([2,3],35)| :weight 1) -(assert-soft |dn([2,3],34)_dn([2,3],35)| :weight 1) -(assert-soft |dn([2,3],38)_dn([2,3],35)| :weight 1) -(assert-soft |dn([2,3],35)_dn([2,3],36)| :weight 1) -(assert-soft |dn([2,3],36)_dn([2,3],37)| :weight 1) -(assert-soft |dn([2,3],37)_dn([2,3],38)| :weight 1) -(assert-soft |dn([Main.main],103)_dn([7,Main.main],39)| :weight 6) -(assert-soft |dn([7,Main.main],40)_dn([7,Main.main],39)| :weight 6) -(assert-soft |dn([7,Main.main],49)_dn([7,Main.main],39)| :weight 6) -(assert-soft |dn([7,Main.main],53)_dn([7,Main.main],39)| :weight 6) -(assert-soft |dn([7,Main.main],57)_dn([7,Main.main],39)| :weight 6) -(assert-soft |dn([7,Main.main],60)_dn([7,Main.main],39)| :weight 6) -(assert-soft |scc(1)_dn([7,Main.main],39)| :weight 6) -(assert-soft |scc(7)_dn([7,Main.main],39)| :weight 6) -(assert-soft |dn([7,Main.main],50)_dn([7,Main.main],39)| :weight 6) -(assert-soft |dn([7,Main.main],54)_dn([7,Main.main],39)| :weight 6) -(assert-soft |dn([7,Main.main],58)_dn([7,Main.main],39)| :weight 6) -(assert-soft |dn([7,Main.main],43)_dn([7,Main.main],40)| :weight 4) -(assert-soft |dn([7,Main.main],45)_dn([7,Main.main],40)| :weight 4) -(assert-soft |dn([7,Main.main],47)_dn([7,Main.main],41)| :weight 1) -(assert-soft |dn([7,Main.main],41)_dn([7,Main.main],42)| :weight 1) -(assert-soft |dn([7,Main.main],42)_dn([7,Main.main],43)| :weight 1) -(assert-soft |dn([7,Main.main],47)_dn([7,Main.main],45)| :weight 4) -(assert-soft |dn([Main.main],106)_dn([7,Main.main],47)| :weight 8) -(assert-soft |dn([7,Main.main],39)_dn([7,Main.main],47)| :weight 8) -(assert-soft |dn([7,Main.main],40)_dn([7,Main.main],47)| :weight 8) -(assert-soft |dn([7,Main.main],49)_dn([7,Main.main],47)| :weight 8) -(assert-soft |dn([7,Main.main],53)_dn([7,Main.main],47)| :weight 8) -(assert-soft |dn([7,Main.main],57)_dn([7,Main.main],47)| :weight 8) -(assert-soft |dn([7,Main.main],60)_dn([7,Main.main],47)| :weight 8) -(assert-soft |scc(1)_dn([7,Main.main],47)| :weight 8) -(assert-soft |scc(7)_dn([7,Main.main],47)| :weight 8) -(assert-soft |dn([7,Main.main],50)_dn([7,Main.main],47)| :weight 8) -(assert-soft |dn([7,Main.main],54)_dn([7,Main.main],47)| :weight 8) -(assert-soft |dn([7,Main.main],58)_dn([7,Main.main],47)| :weight 8) -(assert-soft |dn([Main.main],104)_dn([7,Main.main],49)| :weight 8) -(assert-soft |dn([7,Main.main],39)_dn([7,Main.main],49)| :weight 8) -(assert-soft |dn([7,Main.main],40)_dn([7,Main.main],49)| :weight 8) -(assert-soft |dn([7,Main.main],53)_dn([7,Main.main],49)| :weight 8) -(assert-soft |dn([7,Main.main],57)_dn([7,Main.main],49)| :weight 8) -(assert-soft |dn([7,Main.main],60)_dn([7,Main.main],49)| :weight 8) -(assert-soft |scc(1)_dn([7,Main.main],49)| :weight 8) -(assert-soft |scc(7)_dn([7,Main.main],49)| :weight 8) -(assert-soft |dn([7,Main.main],50)_dn([7,Main.main],49)| :weight 8) -(assert-soft |dn([7,Main.main],54)_dn([7,Main.main],49)| :weight 8) -(assert-soft |dn([7,Main.main],58)_dn([7,Main.main],49)| :weight 8) -(assert-soft |dn([Main.main],105)_dn([7,Main.main],50)| :weight 2) -(assert-soft |dn([7,Main.main],39)_dn([7,Main.main],50)| :weight 2) -(assert-soft |dn([7,Main.main],40)_dn([7,Main.main],50)| :weight 2) -(assert-soft |dn([7,Main.main],49)_dn([7,Main.main],50)| :weight 2) -(assert-soft |dn([7,Main.main],53)_dn([7,Main.main],50)| :weight 2) -(assert-soft |dn([7,Main.main],57)_dn([7,Main.main],50)| :weight 2) -(assert-soft |dn([7,Main.main],60)_dn([7,Main.main],50)| :weight 2) -(assert-soft |scc(1)_dn([7,Main.main],50)| :weight 2) -(assert-soft |scc(7)_dn([7,Main.main],50)| :weight 2) -(assert-soft |dn([7,Main.main],54)_dn([7,Main.main],50)| :weight 2) -(assert-soft |dn([7,Main.main],58)_dn([7,Main.main],50)| :weight 2) -(assert-soft |dn([7,Main.main],50)_dn([7,Main.main],51)| :weight 6) -(assert-soft |scc(1)_dn([7,Main.main],51)| :weight 6) -(assert-soft |scc(7)_dn([7,Main.main],51)| :weight 6) -(assert-soft |dn([7,Main.main],54)_dn([7,Main.main],51)| :weight 6) -(assert-soft |dn([7,Main.main],58)_dn([7,Main.main],51)| :weight 6) -(assert-soft |dn([9,Main.main],87)_dn([7,Main.main],53)| :weight 6) -(assert-soft |scc(7)_dn([7,Main.main],53)| :weight 6) -(assert-soft |dn([6,9],91)_dn([7,Main.main],54)| :weight 2) -(assert-soft |dn([7,Main.main],39)_dn([7,Main.main],54)| :weight 2) -(assert-soft |dn([7,Main.main],40)_dn([7,Main.main],54)| :weight 2) -(assert-soft |dn([7,Main.main],49)_dn([7,Main.main],54)| :weight 2) -(assert-soft |dn([7,Main.main],53)_dn([7,Main.main],54)| :weight 2) -(assert-soft |dn([7,Main.main],57)_dn([7,Main.main],54)| :weight 2) -(assert-soft |dn([7,Main.main],60)_dn([7,Main.main],54)| :weight 2) -(assert-soft |scc(1)_dn([7,Main.main],54)| :weight 2) -(assert-soft |scc(7)_dn([7,Main.main],54)| :weight 2) -(assert-soft |dn([7,Main.main],50)_dn([7,Main.main],54)| :weight 2) -(assert-soft |dn([7,Main.main],58)_dn([7,Main.main],54)| :weight 2) -(assert-soft |dn([7,Main.main],54)_dn([7,Main.main],55)| :weight 18) -(assert-soft |scc(1)_dn([7,Main.main],55)| :weight 18) -(assert-soft |scc(7)_dn([7,Main.main],55)| :weight 18) -(assert-soft |dn([7,Main.main],50)_dn([7,Main.main],55)| :weight 18) -(assert-soft |dn([7,Main.main],58)_dn([7,Main.main],55)| :weight 18) -(assert-soft |scc(1)_dn([7,Main.main],57)| :weight 4) -(assert-soft |dn([2,3],37)_dn([7,Main.main],58)| :weight 1) -(assert-soft |dn([7,Main.main],39)_dn([7,Main.main],58)| :weight 1) -(assert-soft |dn([7,Main.main],40)_dn([7,Main.main],58)| :weight 1) -(assert-soft |dn([7,Main.main],49)_dn([7,Main.main],58)| :weight 1) -(assert-soft |dn([7,Main.main],53)_dn([7,Main.main],58)| :weight 1) -(assert-soft |dn([7,Main.main],57)_dn([7,Main.main],58)| :weight 1) -(assert-soft |dn([7,Main.main],60)_dn([7,Main.main],58)| :weight 1) -(assert-soft |scc(1)_dn([7,Main.main],58)| :weight 1) -(assert-soft |scc(7)_dn([7,Main.main],58)| :weight 1) -(assert-soft |dn([7,Main.main],50)_dn([7,Main.main],58)| :weight 1) -(assert-soft |dn([7,Main.main],54)_dn([7,Main.main],58)| :weight 1) -(assert-soft |dn([7,Main.main],58)_dn([7,Main.main],59)| :weight 1) -(assert-soft |scc(1)_dn([7,Main.main],59)| :weight 1) -(assert-soft |scc(7)_dn([7,Main.main],59)| :weight 1) -(assert-soft |dn([7,Main.main],50)_dn([7,Main.main],59)| :weight 1) -(assert-soft |dn([7,Main.main],54)_dn([7,Main.main],59)| :weight 1) -(assert-soft |dn([7,Main.main],59)_dn([7,Main.main],60)| :weight 1) -(assert-soft |dn([1,3],67)_dn([5,1],61)| :weight 1) -(assert-soft |dn([5,1],62)_dn([5,1],61)| :weight 1) -(assert-soft |dn([5,1],63)_dn([5,1],61)| :weight 1) -(assert-soft |dn([3,7],31)_dn([5,1],62)| :weight 1) -(assert-soft |dn([5,1],61)_dn([5,1],62)| :weight 1) -(assert-soft |dn([5,1],63)_dn([5,1],62)| :weight 1) -(assert-soft |scc(5)_dn([5,1],63)| :weight 8) -(assert-soft |dn([5,1],61)_dn([5,1],63)| :weight 8) -(assert-soft |dn([5,1],62)_dn([5,1],63)| :weight 8) -(assert-soft |dn([3,7],20)_dn([1,3],64)| :weight 1) -(assert-soft |dn([1,3],66)_dn([1,3],64)| :weight 1) -(assert-soft |dn([1,3],68)_dn([1,3],64)| :weight 1) -(assert-soft |dn([3,7],22)_dn([1,3],65)| :weight 1) -(assert-soft |dn([1,3],64)_dn([1,3],65)| :weight 1) -(assert-soft |dn([1,3],66)_dn([1,3],65)| :weight 1) -(assert-soft |dn([1,3],68)_dn([1,3],65)| :weight 1) -(assert-soft |dn([1,3],65)_dn([1,3],66)| :weight 1) -(assert-soft |dn([3,7],25)_dn([1,3],67)| :weight 1) -(assert-soft |dn([1,3],64)_dn([1,3],67)| :weight 1) -(assert-soft |dn([1,3],66)_dn([1,3],67)| :weight 1) -(assert-soft |dn([1,3],68)_dn([1,3],67)| :weight 1) -(assert-soft |dn([1,3],67)_dn([1,3],68)| :weight 1) -(assert-soft |dn([1,3],65)_dn([4,1],69)| :weight 1) -(assert-soft |dn([4,1],79)_dn([4,1],69)| :weight 1) -(assert-soft |dn([4,1],81)_dn([4,1],69)| :weight 1) -(assert-soft |scc(4)_dn([4,1],70)| :weight 2) -(assert-soft |dn([8,Main.main],100)_dn([4,1],78)| :weight 6) -(assert-soft |dn([4,1],69)_dn([4,1],78)| :weight 6) -(assert-soft |dn([4,1],79)_dn([4,1],78)| :weight 6) -(assert-soft |dn([4,1],81)_dn([4,1],78)| :weight 6) -(assert-soft |dn([4,1],78)_dn([4,1],79)| :weight 4) -(assert-soft |dn([3,7],24)_dn([4,1],80)| :weight 1) -(assert-soft |dn([4,1],69)_dn([4,1],80)| :weight 1) -(assert-soft |dn([4,1],79)_dn([4,1],80)| :weight 1) -(assert-soft |dn([4,1],81)_dn([4,1],80)| :weight 1) -(assert-soft |dn([4,1],80)_dn([4,1],81)| :weight 1) -(assert-soft |dn([Main.main],113)_dn([9,Main.main],82)| :weight 4) -(assert-soft |dn([9,Main.main],83)_dn([9,Main.main],82)| :weight 4) -(assert-soft |dn([9,Main.main],87)_dn([9,Main.main],82)| :weight 4) -(assert-soft |dn([9,Main.main],89)_dn([9,Main.main],82)| :weight 4) -(assert-soft |dn([9,Main.main],84)_dn([9,Main.main],82)| :weight 4) -(assert-soft |dn([Main.main],114)_dn([9,Main.main],83)| :weight 4) -(assert-soft |dn([9,Main.main],82)_dn([9,Main.main],83)| :weight 4) -(assert-soft |dn([9,Main.main],87)_dn([9,Main.main],83)| :weight 4) -(assert-soft |dn([9,Main.main],89)_dn([9,Main.main],83)| :weight 4) -(assert-soft |dn([9,Main.main],84)_dn([9,Main.main],83)| :weight 4) -(assert-soft |dn([7,Main.main],51)_dn([9,Main.main],84)| :weight 2) -(assert-soft |dn([9,Main.main],82)_dn([9,Main.main],84)| :weight 2) -(assert-soft |dn([9,Main.main],83)_dn([9,Main.main],84)| :weight 2) -(assert-soft |dn([9,Main.main],87)_dn([9,Main.main],84)| :weight 2) -(assert-soft |dn([9,Main.main],89)_dn([9,Main.main],84)| :weight 2) -(assert-soft |dn([9,Main.main],84)_dn([9,Main.main],85)| :weight 6) -(assert-soft |dn([9,Main.main],85)_dn([9,Main.main],86)| :weight 6) -(assert-soft |dn([9,Main.main],86)_dn([9,Main.main],87)| :weight 2) -(assert-soft |dn([6,9],93)_dn([9,Main.main],88)| :weight 6) -(assert-soft |dn([9,Main.main],82)_dn([9,Main.main],88)| :weight 6) -(assert-soft |dn([9,Main.main],83)_dn([9,Main.main],88)| :weight 6) -(assert-soft |dn([9,Main.main],87)_dn([9,Main.main],88)| :weight 6) -(assert-soft |dn([9,Main.main],89)_dn([9,Main.main],88)| :weight 6) -(assert-soft |dn([9,Main.main],84)_dn([9,Main.main],88)| :weight 6) -(assert-soft |dn([9,Main.main],88)_dn([9,Main.main],89)| :weight 6) -(assert-soft |dn([9,Main.main],85)_dn([6,9],90)| :weight 8) -(assert-soft |dn([6,9],92)_dn([6,9],90)| :weight 8) -(assert-soft |dn([6,9],94)_dn([6,9],90)| :weight 8) -(assert-soft |dn([6,9],95)_dn([6,9],90)| :weight 8) -(assert-soft |dn([9,Main.main],86)_dn([6,9],91)| :weight 8) -(assert-soft |dn([6,9],90)_dn([6,9],91)| :weight 8) -(assert-soft |dn([6,9],92)_dn([6,9],91)| :weight 8) -(assert-soft |dn([6,9],94)_dn([6,9],91)| :weight 8) -(assert-soft |dn([6,9],95)_dn([6,9],91)| :weight 8) -(assert-soft |dn([6,9],91)_dn([6,9],92)| :weight 4) -(assert-soft |scc(1)_dn([6,9],93)| :weight 6) -(assert-soft |dn([6,9],90)_dn([6,9],93)| :weight 6) -(assert-soft |dn([6,9],92)_dn([6,9],93)| :weight 6) -(assert-soft |dn([6,9],94)_dn([6,9],93)| :weight 6) -(assert-soft |dn([6,9],95)_dn([6,9],93)| :weight 6) -(assert-soft |dn([6,9],93)_dn([6,9],94)| :weight 4) -(assert-soft |dn([7,Main.main],55)_dn([6,9],95)| :weight 6) -(assert-soft |dn([7,Main.main],59)_dn([6,9],95)| :weight 6) -(assert-soft |dn([6,9],90)_dn([6,9],95)| :weight 6) -(assert-soft |dn([6,9],92)_dn([6,9],95)| :weight 6) -(assert-soft |dn([6,9],94)_dn([6,9],95)| :weight 6) -(assert-soft |scc(8)_dn([8,Main.main],96)| :weight 4) -(assert-soft |dn([8,Main.main],101)_dn([8,Main.main],96)| :weight 4) -(assert-soft |dn([Main.main],108)_dn([8,Main.main],97)| :weight 8) -(assert-soft |dn([8,Main.main],96)_dn([8,Main.main],97)| :weight 8) -(assert-soft |dn([8,Main.main],101)_dn([8,Main.main],97)| :weight 8) -(assert-soft |scc(5)_dn([8,Main.main],100)| :weight 4) -(assert-soft |dn([8,Main.main],100)_dn([8,Main.main],101)| :weight 4) -(assert-soft |dn([Main.main],111)_dn([Main.main],102)| :weight 1) -(assert-soft |dn([Main.main],111)_dn([Main.main],103)| :weight 6) -(assert-soft |dn([Main.main],103)_dn([Main.main],104)| :weight 2) -(assert-soft |dn([Main.main],104)_dn([Main.main],105)| :weight 2) -(assert-soft |dn([Main.main],105)_dn([Main.main],106)| :weight 2) -(assert-soft |scc(8)_dn([Main.main],108)| :weight 2) -(assert-soft |dn([Main.main],108)_dn([Main.main],109)| :weight 6) -(assert-soft |dn([Main.main],109)_dn([Main.main],111)| :weight 6) -(assert-soft |dn([Main.main],115)_dn([Main.main],111)| :weight 6) -(assert-soft |dn([Main.main],116)_dn([Main.main],113)| :weight 3) -(assert-soft |dn([Main.main],113)_dn([Main.main],114)| :weight 1) -(assert-soft |dn([Main.main],114)_dn([Main.main],115)| :weight 1) -(assert-soft |dn([Main.main],115)_dn([Main.main],116)| :weight 2) -(assert-soft |dn([1,3],66)_scc(0)| :weight 1) -(assert-soft |dn([6,9],95)_scc(1)| :weight 6) -(assert-soft |scc(7)_scc(1)| :weight 6) -(assert-soft |dn([7,Main.main],50)_scc(1)| :weight 6) -(assert-soft |dn([7,Main.main],54)_scc(1)| :weight 6) -(assert-soft |dn([7,Main.main],58)_scc(1)| :weight 6) -(assert-soft |dn([5,1],62)_scc(2)| :weight 1) -(assert-soft |dn([4,1],78)_scc(4)| :weight 4) -(assert-soft |dn([3,7],30)_scc(5)| :weight 8) -(assert-soft |dn([3,7],28)_scc(6)| :weight 6) -(assert-soft |dn([9,Main.main],87)_scc(7)| :weight 2) -(assert-soft |scc(1)_scc(7)| :weight 2) -(assert-soft |dn([7,Main.main],50)_scc(7)| :weight 2) -(assert-soft |dn([7,Main.main],54)_scc(7)| :weight 2) -(assert-soft |dn([7,Main.main],58)_scc(7)| :weight 2) -(set-option :smt.pb.conflict_frequency 100) - -(optimize - :wmaxsat_engine bvsls - :print_statistics true - :timeout 1200000 -) diff --git a/tests/ravi_sls.smt2 b/tests/ravi_sls.smt2 deleted file mode 100644 index 7db65dc40..000000000 --- a/tests/ravi_sls.smt2 +++ /dev/null @@ -1,443 +0,0 @@ -(set-option :smt.relevancy 0) -(set-option :smt.pb.conflict_frequency 10000) -(set-option :opt.pb.compile_equality true) -(set-option :smt.pb.enable_simplex true) -; declare an integer variable for each mini-pathlet's multiplicity -(declare-const A0_2_3_10 Int) -(declare-const A0_2_3_5_4_7_9 Int) -(declare-const A0_2_3_5_4_8_9 Int) -(declare-const A0_1_3_10 Int) -(declare-const A0_1_3_5_4_7_9 Int) -(declare-const A0_1_3_5_4_8_9 Int) -(declare-const A1_3_10 Int) -(declare-const A1_3_5_4_7_9 Int) -(declare-const A1_3_5_4_8_9 Int) -(declare-const A2_3_10 Int) -(declare-const A2_3_5_4_7_9 Int) -(declare-const A2_3_5_4_8_9 Int) -(declare-const A3_10 Int) -(declare-const A3_5_4_7_9_12_13 Int) -(declare-const A3_5_4_7_9_11_13 Int) -(declare-const A3_5_4_8_9_12_13 Int) -(declare-const A3_5_4_8_9_11_13 Int) -(declare-const A4_7_9_12_13 Int) -(declare-const A4_7_9_11_13 Int) -(declare-const A4_8_9_12_13 Int) -(declare-const A4_8_9_11_13 Int) -(declare-const A5_4_7_9_12_13 Int) -(declare-const A5_4_7_9_11_13 Int) -(declare-const A5_4_8_9_12_13 Int) -(declare-const A5_4_8_9_11_13 Int) -(declare-const A6_21_10 Int) -(declare-const A6_4_7_9_12_13 Int) -(declare-const A6_4_7_9_11_13 Int) -(declare-const A6_4_8_9_12_13 Int) -(declare-const A6_4_8_9_11_13 Int) -(declare-const A7_9_12_13 Int) -(declare-const A7_9_11_13 Int) -(declare-const A8_9_12_13 Int) -(declare-const A8_9_11_13 Int) -(declare-const A9_12_13_15_17_18 Int) -(declare-const A9_12_13_15_17_16_19 Int) -(declare-const A9_12_13_14_17_18 Int) -(declare-const A9_12_13_14_17_16_19 Int) -(declare-const A9_11_13_15_17_18 Int) -(declare-const A9_11_13_15_17_16_19 Int) -(declare-const A9_11_13_14_17_18 Int) -(declare-const A9_11_13_14_17_16_19 Int) -(declare-const A11_13_15_17_18_19 Int) -(declare-const A11_13_15_17_16_19 Int) -(declare-const A11_13_14_17_18_19 Int) -(declare-const A11_13_14_17_16_19 Int) -(declare-const A12_13_15_17_18_19 Int) -(declare-const A12_13_15_17_16_19 Int) -(declare-const A12_13_14_17_18_19 Int) -(declare-const A12_13_14_17_16_19 Int) -(declare-const A13_15_17_18_19 Int) -(declare-const A13_15_17_16_19 Int) -(declare-const A13_14_17_18_19 Int) -(declare-const A13_14_17_16_19 Int) -(declare-const A20_6_21_10 Int) -(declare-const A20_6_4_7_9_12 Int) -(declare-const A20_6_4_7_9_11 Int) -(declare-const A20_6_4_8_9_12 Int) -(declare-const A20_6_4_8_9_11 Int) -(declare-const A21_10 Int) -; positive mult for each minipathlet -(assert (<= 0 A0_2_3_10)) -(assert (<= A0_2_3_10 4)) -(assert (<= 0 A0_2_3_5_4_7_9)) -(assert (<= A0_2_3_5_4_7_9 4)) -(assert (<= 0 A0_2_3_5_4_8_9)) -(assert (<= A0_2_3_5_4_8_9 4)) -(assert (<= 0 A0_1_3_10)) -(assert (<= A0_1_3_10 4)) -(assert (<= 0 A0_1_3_5_4_7_9)) -(assert (<= A0_1_3_5_4_7_9 4)) -(assert (<= 0 A0_1_3_5_4_8_9)) -(assert (<= A0_1_3_5_4_8_9 4)) -(assert (<= 0 A1_3_10)) -(assert (<= A1_3_10 4)) -(assert (<= 0 A1_3_5_4_7_9)) -(assert (<= A1_3_5_4_7_9 4)) -(assert (<= 0 A1_3_5_4_8_9)) -(assert (<= A1_3_5_4_8_9 4)) -(assert (<= 0 A2_3_10)) -(assert (<= A2_3_10 4)) -(assert (<= 0 A2_3_5_4_7_9)) -(assert (<= A2_3_5_4_7_9 4)) -(assert (<= 0 A2_3_5_4_8_9)) -(assert (<= A2_3_5_4_8_9 4)) -(assert (<= 0 A3_10)) -(assert (<= A3_10 4)) -(assert (<= 0 A3_5_4_7_9_12_13)) -(assert (<= A3_5_4_7_9_12_13 4)) -(assert (<= 0 A3_5_4_7_9_11_13)) -(assert (<= A3_5_4_7_9_11_13 4)) -(assert (<= 0 A3_5_4_8_9_12_13)) -(assert (<= A3_5_4_8_9_12_13 4)) -(assert (<= 0 A3_5_4_8_9_11_13)) -(assert (<= A3_5_4_8_9_11_13 4)) -(assert (<= 0 A4_7_9_12_13)) -(assert (<= A4_7_9_12_13 4)) -(assert (<= 0 A4_7_9_11_13)) -(assert (<= A4_7_9_11_13 4)) -(assert (<= 0 A4_8_9_12_13)) -(assert (<= A4_8_9_12_13 4)) -(assert (<= 0 A4_8_9_11_13)) -(assert (<= A4_8_9_11_13 4)) -(assert (<= 0 A5_4_7_9_12_13)) -(assert (<= A5_4_7_9_12_13 4)) -(assert (<= 0 A5_4_7_9_11_13)) -(assert (<= A5_4_7_9_11_13 4)) -(assert (<= 0 A5_4_8_9_12_13)) -(assert (<= A5_4_8_9_12_13 4)) -(assert (<= 0 A5_4_8_9_11_13)) -(assert (<= A5_4_8_9_11_13 4)) -(assert (<= 0 A6_21_10)) -(assert (<= A6_21_10 4)) -(assert (<= 0 A6_4_7_9_12_13)) -(assert (<= A6_4_7_9_12_13 4)) -(assert (<= 0 A6_4_7_9_11_13)) -(assert (<= A6_4_7_9_11_13 4)) -(assert (<= 0 A6_4_8_9_12_13)) -(assert (<= A6_4_8_9_12_13 4)) -(assert (<= 0 A6_4_8_9_11_13)) -(assert (<= A6_4_8_9_11_13 4)) -(assert (<= 0 A7_9_12_13)) -(assert (<= A7_9_12_13 4)) -(assert (<= 0 A7_9_11_13)) -(assert (<= A7_9_11_13 4)) -(assert (<= 0 A8_9_12_13)) -(assert (<= A8_9_12_13 4)) -(assert (<= 0 A8_9_11_13)) -(assert (<= A8_9_11_13 4)) -(assert (<= 0 A9_12_13_15_17_18)) -(assert (<= A9_12_13_15_17_18 4)) -(assert (<= 0 A9_12_13_15_17_16_19)) -(assert (<= A9_12_13_15_17_16_19 4)) -(assert (<= 0 A9_12_13_14_17_18)) -(assert (<= A9_12_13_14_17_18 4)) -(assert (<= 0 A9_12_13_14_17_16_19)) -(assert (<= A9_12_13_14_17_16_19 4)) -(assert (<= 0 A9_11_13_15_17_18)) -(assert (<= A9_11_13_15_17_18 4)) -(assert (<= 0 A9_11_13_15_17_16_19)) -(assert (<= A9_11_13_15_17_16_19 4)) -(assert (<= 0 A9_11_13_14_17_18)) -(assert (<= A9_11_13_14_17_18 4)) -(assert (<= 0 A9_11_13_14_17_16_19)) -(assert (<= A9_11_13_14_17_16_19 4)) -(assert (<= 0 A11_13_15_17_18_19)) -(assert (<= A11_13_15_17_18_19 4)) -(assert (<= 0 A11_13_15_17_16_19)) -(assert (<= A11_13_15_17_16_19 4)) -(assert (<= 0 A11_13_14_17_18_19)) -(assert (<= A11_13_14_17_18_19 4)) -(assert (<= 0 A11_13_14_17_16_19)) -(assert (<= A11_13_14_17_16_19 4)) -(assert (<= 0 A12_13_15_17_18_19)) -(assert (<= A12_13_15_17_18_19 4)) -(assert (<= 0 A12_13_15_17_16_19)) -(assert (<= A12_13_15_17_16_19 4)) -(assert (<= 0 A12_13_14_17_18_19)) -(assert (<= A12_13_14_17_18_19 4)) -(assert (<= 0 A12_13_14_17_16_19)) -(assert (<= A12_13_14_17_16_19 4)) -(assert (<= 0 A13_15_17_18_19)) -(assert (<= A13_15_17_18_19 4)) -(assert (<= 0 A13_15_17_16_19)) -(assert (<= A13_15_17_16_19 4)) -(assert (<= 0 A13_14_17_18_19)) -(assert (<= A13_14_17_18_19 4)) -(assert (<= 0 A13_14_17_16_19)) -(assert (<= A13_14_17_16_19 4)) -(assert (<= 0 A20_6_21_10)) -(assert (<= A20_6_21_10 4)) -(assert (<= 0 A20_6_4_7_9_12)) -(assert (<= A20_6_4_7_9_12 4)) -(assert (<= 0 A20_6_4_7_9_11)) -(assert (<= A20_6_4_7_9_11 4)) -(assert (<= 0 A20_6_4_8_9_12)) -(assert (<= A20_6_4_8_9_12 4)) -(assert (<= 0 A20_6_4_8_9_11)) -(assert (<= A20_6_4_8_9_11 4)) -(assert (<= 0 A21_10)) -(assert (<= A21_10 4)) -; range of multiplicities for each contig-pair -; contigs 0 1, #pairs 7, dist 8.36 -(assert (and (<= 0 (+ A0_1_3_10 A0_1_3_5_4_7_9 A0_1_3_5_4_8_9)) (<= (+ A0_1_3_10 A0_1_3_5_4_7_9 A0_1_3_5_4_8_9) 4))) -(assert-soft (= 0 (+ A0_1_3_10 A0_1_3_5_4_7_9 A0_1_3_5_4_8_9)) :dweight 2.852312) ; p=0001405 -(assert-soft (= 1 (+ A0_1_3_10 A0_1_3_5_4_7_9 A0_1_3_5_4_8_9)) :dweight 0.852312) ; p=0140504 -(assert-soft (= 2 (+ A0_1_3_10 A0_1_3_5_4_7_9 A0_1_3_5_4_8_9)) :dweight 1.408176) ; p=0039068 -(assert-soft (= 3 (+ A0_1_3_10 A0_1_3_5_4_7_9 A0_1_3_5_4_8_9)) :dweight 2.838611) ; p=0001450 -(assert-soft (= 4 (+ A0_1_3_10 A0_1_3_5_4_7_9 A0_1_3_5_4_8_9)) :dweight 4.627113) ; p=0000024 -; contigs 1 3, #pairs 5, dist 1.07 -(assert (and (<= 0 (+ A1_3_10 A1_3_5_4_7_9 A1_3_5_4_8_9)) (<= (+ A1_3_10 A1_3_5_4_7_9 A1_3_5_4_8_9) 4))) -(assert-soft (= 0 (+ A1_3_10 A1_3_5_4_7_9 A1_3_5_4_8_9)) :dweight 4.168291) ; p=0000068 -(assert-soft (= 1 (+ A1_3_10 A1_3_5_4_7_9 A1_3_5_4_8_9)) :dweight 2.168291) ; p=0006787 -(assert-soft (= 2 (+ A1_3_10 A1_3_5_4_7_9 A1_3_5_4_8_9)) :dweight 1.195873) ; p=0063698 -(assert-soft (= 3 (+ A1_3_10 A1_3_5_4_7_9 A1_3_5_4_8_9)) :dweight 0.848149) ; p=0141857 -(assert-soft (= 4 (+ A1_3_10 A1_3_5_4_7_9 A1_3_5_4_8_9)) :dweight 0.756187) ; p=0175313 -; contigs 2 3, #pairs 4, dist 1.07 -(assert (and (<= 0 (+ A2_3_10 A2_3_5_4_7_9 A2_3_5_4_8_9)) (<= (+ A2_3_10 A2_3_5_4_7_9 A2_3_5_4_8_9) 4))) -(assert-soft (= 0 (+ A2_3_10 A2_3_5_4_7_9 A2_3_5_4_8_9)) :dweight 3.535379) ; p=0000291 -(assert-soft (= 1 (+ A2_3_10 A2_3_5_4_7_9 A2_3_5_4_8_9)) :dweight 1.535379) ; p=0029149 -(assert-soft (= 2 (+ A2_3_10 A2_3_5_4_7_9 A2_3_5_4_8_9)) :dweight 0.874154) ; p=0133612 -(assert-soft (= 3 (+ A2_3_10 A2_3_5_4_7_9 A2_3_5_4_8_9)) :dweight 0.712685) ; p=0193783 -(assert-soft (= 4 (+ A2_3_10 A2_3_5_4_7_9 A2_3_5_4_8_9)) :dweight 0.755826) ; p=0175458 -; contigs 3 4, #pairs 3, dist 2.77 -(assert (and (<= 0 (+ A3_5_4_7_9_12_13 A3_5_4_7_9_11_13 A3_5_4_8_9_12_13 A3_5_4_8_9_11_13)) (<= (+ A3_5_4_7_9_12_13 A3_5_4_7_9_11_13 A3_5_4_8_9_12_13 A3_5_4_8_9_11_13) 4))) -(assert-soft (= 0 (+ A3_5_4_7_9_12_13 A3_5_4_7_9_11_13 A3_5_4_8_9_12_13 A3_5_4_8_9_11_13)) :dweight 5.564238) ; p=0000003 -(assert-soft (= 1 (+ A3_5_4_7_9_12_13 A3_5_4_7_9_11_13 A3_5_4_8_9_12_13 A3_5_4_8_9_11_13)) :dweight 3.564238) ; p=0000273 -(assert-soft (= 2 (+ A3_5_4_7_9_12_13 A3_5_4_7_9_11_13 A3_5_4_8_9_12_13 A3_5_4_8_9_11_13)) :dweight 2.714464) ; p=0001930 -(assert-soft (= 3 (+ A3_5_4_7_9_12_13 A3_5_4_7_9_11_13 A3_5_4_8_9_12_13 A3_5_4_8_9_11_13)) :dweight 2.239507) ; p=0005761 -(assert-soft (= 4 (+ A3_5_4_7_9_12_13 A3_5_4_7_9_11_13 A3_5_4_8_9_12_13 A3_5_4_8_9_11_13)) :dweight 1.918007) ; p=0012078 -; contigs 4 9, #pairs 2, dist 1.24 -(assert (and (<= 0 (+ A4_7_9_12_13 A4_7_9_11_13 A4_8_9_12_13 A4_8_9_11_13)) (<= (+ A4_7_9_12_13 A4_7_9_11_13 A4_8_9_12_13 A4_8_9_11_13) 4))) -(assert-soft (= 0 (+ A4_7_9_12_13 A4_7_9_11_13 A4_8_9_12_13 A4_8_9_11_13)) :dweight 4.280499) ; p=0000052 -(assert-soft (= 1 (+ A4_7_9_12_13 A4_7_9_11_13 A4_8_9_12_13 A4_8_9_11_13)) :dweight 2.280499) ; p=0005242 -(assert-soft (= 2 (+ A4_7_9_12_13 A4_7_9_11_13 A4_8_9_12_13 A4_8_9_11_13)) :dweight 1.725376) ; p=0018820 -(assert-soft (= 3 (+ A4_7_9_12_13 A4_7_9_11_13 A4_8_9_12_13 A4_8_9_11_13)) :dweight 1.420131) ; p=0038007 -(assert-soft (= 4 (+ A4_7_9_12_13 A4_7_9_11_13 A4_8_9_12_13 A4_8_9_11_13)) :dweight 1.217191) ; p=0060647 -; contigs 5 9, #pairs 1, dist 1.46 -(assert (and (<= 0 (+ A5_4_7_9_12_13 A5_4_7_9_11_13 A5_4_8_9_12_13 A5_4_8_9_11_13)) (<= (+ A5_4_7_9_12_13 A5_4_7_9_11_13 A5_4_8_9_12_13 A5_4_8_9_11_13) 4))) -(assert-soft (= 0 (+ A5_4_7_9_12_13 A5_4_7_9_11_13 A5_4_8_9_12_13 A5_4_8_9_11_13)) :dweight 6.000000) ; p=0000001 -(assert-soft (= 1 (+ A5_4_7_9_12_13 A5_4_7_9_11_13 A5_4_8_9_12_13 A5_4_8_9_11_13)) :dweight 4.000000) ; p=0000100 -(assert-soft (= 2 (+ A5_4_7_9_12_13 A5_4_7_9_11_13 A5_4_8_9_12_13 A5_4_8_9_11_13)) :dweight 6.000000) ; p=0000001 -(assert-soft (= 3 (+ A5_4_7_9_12_13 A5_4_7_9_11_13 A5_4_8_9_12_13 A5_4_8_9_11_13)) :dweight 8.000000) ; p=0000000 -(assert-soft (= 4 (+ A5_4_7_9_12_13 A5_4_7_9_11_13 A5_4_8_9_12_13 A5_4_8_9_11_13)) :dweight 1.0000000) ; p=0000000 -; contigs 6 9, #pairs 0, dist 2.79 -(assert (and (<= 0 (+ A6_4_7_9_12_13 A6_4_7_9_11_13 A6_4_8_9_12_13 A6_4_8_9_11_13)) (<= (+ A6_4_7_9_12_13 A6_4_7_9_11_13 A6_4_8_9_12_13 A6_4_8_9_11_13) 4))) -(assert-soft (= 0 (+ A6_4_7_9_12_13 A6_4_7_9_11_13 A6_4_8_9_12_13 A6_4_8_9_11_13)) :dweight 1.100798) ; p=0079287 -(assert-soft (= 1 (+ A6_4_7_9_12_13 A6_4_7_9_11_13 A6_4_8_9_12_13 A6_4_8_9_11_13)) :dweight 1.100798) ; p=0079287 -(assert-soft (= 2 (+ A6_4_7_9_12_13 A6_4_7_9_11_13 A6_4_8_9_12_13 A6_4_8_9_11_13)) :dweight 1.100798) ; p=0079287 -(assert-soft (= 3 (+ A6_4_7_9_12_13 A6_4_7_9_11_13 A6_4_8_9_12_13 A6_4_8_9_11_13)) :dweight 1.100798) ; p=0079287 -(assert-soft (= 4 (+ A6_4_7_9_12_13 A6_4_7_9_11_13 A6_4_8_9_12_13 A6_4_8_9_11_13)) :dweight 1.100798) ; p=0079287 -; contigs 7 9, #pairs 4, dist 1.08 -(assert (and (<= 0 (+ A7_9_12_13 A7_9_11_13)) (<= (+ A7_9_12_13 A7_9_11_13) 4))) -(assert-soft (= 0 (+ A7_9_12_13 A7_9_11_13)) :dweight 4.830293) ; p=0000015 -(assert-soft (= 1 (+ A7_9_12_13 A7_9_11_13)) :dweight 2.830293) ; p=0001478 -(assert-soft (= 2 (+ A7_9_12_13 A7_9_11_13)) :dweight 1.839248) ; p=0014479 -(assert-soft (= 3 (+ A7_9_12_13 A7_9_11_13)) :dweight 1.347958) ; p=0044879 -(assert-soft (= 4 (+ A7_9_12_13 A7_9_11_13)) :dweight 1.061278) ; p=0086840 -; contigs 8 9, #pairs 2, dist 1.10 -(assert (and (<= 0 (+ A8_9_12_13 A8_9_11_13)) (<= (+ A8_9_12_13 A8_9_11_13) 4))) -(assert-soft (= 0 (+ A8_9_12_13 A8_9_11_13)) :dweight 3.085052) ; p=0000822 -(assert-soft (= 1 (+ A8_9_12_13 A8_9_11_13)) :dweight 1.085052) ; p=0082214 -(assert-soft (= 2 (+ A8_9_12_13 A8_9_11_13)) :dweight 0.712306) ; p=0193952 -(assert-soft (= 3 (+ A8_9_12_13 A8_9_11_13)) :dweight 0.589437) ; p=0257373 -(assert-soft (= 4 (+ A8_9_12_13 A8_9_11_13)) :dweight 0.568873) ; p=0269853 -; contigs 9 12, #pairs 1, dist 1.77 -(assert (and (<= 0 (+ A9_12_13_15_17_18 A9_12_13_15_17_16_19 A9_12_13_14_17_18 A9_12_13_14_17_16_19)) (<= (+ A9_12_13_15_17_18 A9_12_13_15_17_16_19 A9_12_13_14_17_18 A9_12_13_14_17_16_19) 4))) -(assert-soft (= 0 (+ A9_12_13_15_17_18 A9_12_13_15_17_16_19 A9_12_13_14_17_18 A9_12_13_14_17_16_19)) :dweight 2.518279) ; p=0003032 -(assert-soft (= 1 (+ A9_12_13_15_17_18 A9_12_13_15_17_16_19 A9_12_13_14_17_18 A9_12_13_14_17_16_19)) :dweight 0.518279) ; p=0303195 -(assert-soft (= 2 (+ A9_12_13_15_17_18 A9_12_13_15_17_16_19 A9_12_13_14_17_18 A9_12_13_14_17_16_19)) :dweight 0.434295) ; p=0367879 -(assert-soft (= 3 (+ A9_12_13_15_17_18 A9_12_13_15_17_16_19 A9_12_13_14_17_18 A9_12_13_14_17_16_19)) :dweight 0.475249) ; p=0334773 -(assert-soft (= 4 (+ A9_12_13_15_17_18 A9_12_13_15_17_16_19 A9_12_13_14_17_18 A9_12_13_14_17_16_19)) :dweight 0.567356) ; p=0270797 -; contigs 11 13, #pairs 2, dist 1.00 -(assert (and (<= 0 (+ A11_13_15_17_18_19 A11_13_15_17_16_19 A11_13_14_17_18_19 A11_13_14_17_16_19)) (<= (+ A11_13_15_17_18_19 A11_13_15_17_16_19 A11_13_14_17_18_19 A11_13_14_17_16_19) 4))) -(assert-soft (= 0 (+ A11_13_15_17_18_19 A11_13_15_17_16_19 A11_13_14_17_18_19 A11_13_14_17_16_19)) :dweight 2.755831) ; p=0001755 -(assert-soft (= 1 (+ A11_13_15_17_18_19 A11_13_15_17_16_19 A11_13_14_17_18_19 A11_13_14_17_16_19)) :dweight 0.755831) ; p=0175456 -(assert-soft (= 2 (+ A11_13_15_17_18_19 A11_13_15_17_16_19 A11_13_14_17_18_19 A11_13_14_17_16_19)) :dweight 0.568471) ; p=0270103 -(assert-soft (= 3 (+ A11_13_15_17_18_19 A11_13_15_17_16_19 A11_13_14_17_18_19 A11_13_14_17_16_19)) :dweight 0.630988) ; p=0233890 -(assert-soft (= 4 (+ A11_13_15_17_18_19 A11_13_15_17_16_19 A11_13_14_17_18_19 A11_13_14_17_16_19)) :dweight 0.795810) ; p=0160026 -; contigs 12 13, #pairs 2, dist 1.01 -(assert (and (<= 0 (+ A12_13_15_17_18_19 A12_13_15_17_16_19 A12_13_14_17_18_19 A12_13_14_17_16_19)) (<= (+ A12_13_15_17_18_19 A12_13_15_17_16_19 A12_13_14_17_18_19 A12_13_14_17_16_19) 4))) -(assert-soft (= 0 (+ A12_13_15_17_18_19 A12_13_15_17_16_19 A12_13_14_17_18_19 A12_13_14_17_16_19)) :dweight 2.662349) ; p=0002176 -(assert-soft (= 1 (+ A12_13_15_17_18_19 A12_13_15_17_16_19 A12_13_14_17_18_19 A12_13_14_17_16_19)) :dweight 0.662349) ; p=0217596 -(assert-soft (= 2 (+ A12_13_15_17_18_19 A12_13_15_17_16_19 A12_13_14_17_18_19 A12_13_14_17_16_19)) :dweight 0.583662) ; p=0260818 -(assert-soft (= 3 (+ A12_13_15_17_18_19 A12_13_15_17_16_19 A12_13_14_17_18_19 A12_13_14_17_16_19)) :dweight 0.754853) ; p=0175852 -(assert-soft (= 4 (+ A12_13_15_17_18_19 A12_13_15_17_16_19 A12_13_14_17_18_19 A12_13_14_17_16_19)) :dweight 1.028349) ; p=0093681 -; contigs 13 15, #pairs 1, dist 2.58 -(assert (and (<= 0 (+ A13_15_17_18_19 A13_15_17_16_19)) (<= (+ A13_15_17_18_19 A13_15_17_16_19) 4))) -(assert-soft (= 0 (+ A13_15_17_18_19 A13_15_17_16_19)) :dweight 2.434616) ; p=0003676 -(assert-soft (= 1 (+ A13_15_17_18_19 A13_15_17_16_19)) :dweight 0.434616) ; p=0367607 -(assert-soft (= 2 (+ A13_15_17_18_19 A13_15_17_16_19)) :dweight 0.584809) ; p=0260130 -(assert-soft (= 3 (+ A13_15_17_18_19 A13_15_17_16_19)) :dweight 0.859941) ; p=0138057 -(assert-soft (= 4 (+ A13_15_17_18_19 A13_15_17_16_19)) :dweight 1.186226) ; p=0065129 -; contigs 20 6, #pairs 7, dist 1.085 -(assert (and (<= 0 (+ A20_6_21_10 A20_6_4_7_9_12 A20_6_4_7_9_11 A20_6_4_8_9_12 A20_6_4_8_9_11)) (<= (+ A20_6_21_10 A20_6_4_7_9_12 A20_6_4_7_9_11 A20_6_4_8_9_12 A20_6_4_8_9_11) 4))) -(assert-soft (= 0 (+ A20_6_21_10 A20_6_4_7_9_12 A20_6_4_7_9_11 A20_6_4_8_9_12 A20_6_4_8_9_11)) :dweight 2.850723) ; p=0001410 -(assert-soft (= 1 (+ A20_6_21_10 A20_6_4_7_9_12 A20_6_4_7_9_11 A20_6_4_8_9_12 A20_6_4_8_9_11)) :dweight 0.850723) ; p=0141019 -(assert-soft (= 2 (+ A20_6_21_10 A20_6_4_7_9_12 A20_6_4_7_9_11 A20_6_4_8_9_12 A20_6_4_8_9_11)) :dweight 2.181023) ; p=0006591 -(assert-soft (= 3 (+ A20_6_21_10 A20_6_4_7_9_12 A20_6_4_7_9_11 A20_6_4_8_9_12 A20_6_4_8_9_11)) :dweight 4.385894) ; p=0000041 -(assert-soft (= 4 (+ A20_6_21_10 A20_6_4_7_9_12 A20_6_4_7_9_11 A20_6_4_8_9_12 A20_6_4_8_9_11)) :dweight 6.948833) ; p=0000000 -; contigs 21 10, #pairs 1, dist 1.2 -(assert (and (<= 0 (+ A21_10)) (<= (+ A21_10) 4))) -(assert-soft (= 0 (+ A21_10)) :dweight 2.629839) ; p=0002345 -(assert-soft (= 1 (+ A21_10)) :dweight 0.629839) ; p=0234510 -(assert-soft (= 2 (+ A21_10)) :dweight 0.469677) ; p=0339096 -(assert-soft (= 3 (+ A21_10)) :dweight 0.434455) ; p=0367744 -(assert-soft (= 4 (+ A21_10)) :dweight 0.450384) ; p=0354499 -; range of multiplicities for each contig -; contig 0, length 931, #reads 41, min 0, max 4 -(assert (and (<= 0 (+ A0_2_3_10 A0_2_3_5_4_7_9 A0_2_3_5_4_8_9 A0_1_3_10 A0_1_3_5_4_7_9 A0_1_3_5_4_8_9)) (<= (+ A0_2_3_10 A0_2_3_5_4_7_9 A0_2_3_5_4_8_9 A0_1_3_10 A0_1_3_5_4_7_9 A0_1_3_5_4_8_9) 4))) -(assert-soft (= 0 (+ A0_2_3_10 A0_2_3_5_4_7_9 A0_2_3_5_4_8_9 A0_1_3_10 A0_1_3_5_4_7_9 A0_1_3_5_4_8_9)) :dweight 4.060041) ; p=0000087 -(assert-soft (= 1 (+ A0_2_3_10 A0_2_3_5_4_7_9 A0_2_3_5_4_8_9 A0_1_3_10 A0_1_3_5_4_7_9 A0_1_3_5_4_8_9)) :dweight 2.060041) ; p=0008709 -(assert-soft (= 2 (+ A0_2_3_10 A0_2_3_5_4_7_9 A0_2_3_5_4_8_9 A0_1_3_10 A0_1_3_5_4_7_9 A0_1_3_5_4_8_9)) :dweight 1.3620829) ; p=0000000 -(assert-soft (= 3 (+ A0_2_3_10 A0_2_3_5_4_7_9 A0_2_3_5_4_8_9 A0_1_3_10 A0_1_3_5_4_7_9 A0_1_3_5_4_8_9)) :dweight 3.0304105) ; p=0000000 -(assert-soft (= 4 (+ A0_2_3_10 A0_2_3_5_4_7_9 A0_2_3_5_4_8_9 A0_1_3_10 A0_1_3_5_4_7_9 A0_1_3_5_4_8_9)) :dweight 4.9084634) ; p=0000000 -; contig 1, length 195, #reads 16, min 0, max 4 -(assert (and (<= 0 (+ A1_3_10 A1_3_5_4_7_9 A1_3_5_4_8_9)) (<= (+ A1_3_10 A1_3_5_4_7_9 A1_3_5_4_8_9) 4))) -(assert-soft (= 0 (+ A1_3_10 A1_3_5_4_7_9 A1_3_5_4_8_9)) :dweight 5.312217) ; p=0000005 -(assert-soft (= 1 (+ A1_3_10 A1_3_5_4_7_9 A1_3_5_4_8_9)) :dweight 3.312217) ; p=0000487 -(assert-soft (= 2 (+ A1_3_10 A1_3_5_4_7_9 A1_3_5_4_8_9)) :dweight 1.202826) ; p=0062686 -(assert-soft (= 3 (+ A1_3_10 A1_3_5_4_7_9 A1_3_5_4_8_9)) :dweight 1.092455) ; p=0080825 -(assert-soft (= 4 (+ A1_3_10 A1_3_5_4_7_9 A1_3_5_4_8_9)) :dweight 1.800524) ; p=0015830 -; contig 2, length 198, #reads 21, min 0, max 4 -(assert (and (<= 0 (+ A2_3_10 A2_3_5_4_7_9 A2_3_5_4_8_9)) (<= (+ A2_3_10 A2_3_5_4_7_9 A2_3_5_4_8_9) 4))) -(assert-soft (= 0 (+ A2_3_10 A2_3_5_4_7_9 A2_3_5_4_8_9)) :dweight 7.526226) ; p=0000000 -(assert-soft (= 1 (+ A2_3_10 A2_3_5_4_7_9 A2_3_5_4_8_9)) :dweight 5.526226) ; p=0000003 -(assert-soft (= 2 (+ A2_3_10 A2_3_5_4_7_9 A2_3_5_4_8_9)) :dweight 1.998081) ; p=0010044 -(assert-soft (= 3 (+ A2_3_10 A2_3_5_4_7_9 A2_3_5_4_8_9)) :dweight 1.093650) ; p=0080603 -(assert-soft (= 4 (+ A2_3_10 A2_3_5_4_7_9 A2_3_5_4_8_9)) :dweight 1.263422) ; p=0054523 -; contig 3, length 347, #reads 56, min 0, max 4 -(assert (and (<= 0 (+ A3_10 A3_5_4_7_9_12_13 A3_5_4_7_9_11_13 A3_5_4_8_9_12_13 A3_5_4_8_9_11_13)) (<= (+ A3_10 A3_5_4_7_9_12_13 A3_5_4_7_9_11_13 A3_5_4_8_9_12_13 A3_5_4_8_9_11_13) 4))) -(assert-soft (= 0 (+ A3_10 A3_5_4_7_9_12_13 A3_5_4_7_9_11_13 A3_5_4_8_9_12_13 A3_5_4_8_9_11_13)) :dweight 1.6034953) ; p=0000000 -(assert-soft (= 1 (+ A3_10 A3_5_4_7_9_12_13 A3_5_4_7_9_11_13 A3_5_4_8_9_12_13 A3_5_4_8_9_11_13)) :dweight 1.4034953) ; p=0000000 -(assert-soft (= 2 (+ A3_10 A3_5_4_7_9_12_13 A3_5_4_7_9_11_13 A3_5_4_8_9_12_13 A3_5_4_8_9_11_13)) :dweight 4.261782) ; p=0000055 -(assert-soft (= 3 (+ A3_10 A3_5_4_7_9_12_13 A3_5_4_7_9_11_13 A3_5_4_8_9_12_13 A3_5_4_8_9_11_13)) :dweight 1.485181) ; p=0032720 -(assert-soft (= 4 (+ A3_10 A3_5_4_7_9_12_13 A3_5_4_7_9_11_13 A3_5_4_8_9_12_13 A3_5_4_8_9_11_13)) :dweight 1.573120) ; p=0026723 -; contig 4, length 113, #reads 8, min 0, max 4 -(assert (and (<= 0 (+ A4_7_9_12_13 A4_7_9_11_13 A4_8_9_12_13 A4_8_9_11_13)) (<= (+ A4_7_9_12_13 A4_7_9_11_13 A4_8_9_12_13 A4_8_9_11_13) 4))) -(assert-soft (= 0 (+ A4_7_9_12_13 A4_7_9_11_13 A4_8_9_12_13 A4_8_9_11_13)) :dweight 7.744934) ; p=0000000 -(assert-soft (= 1 (+ A4_7_9_12_13 A4_7_9_11_13 A4_8_9_12_13 A4_8_9_11_13)) :dweight 5.744934) ; p=0000002 -(assert-soft (= 2 (+ A4_7_9_12_13 A4_7_9_11_13 A4_8_9_12_13 A4_8_9_11_13)) :dweight 3.682280) ; p=0000208 -(assert-soft (= 3 (+ A4_7_9_12_13 A4_7_9_11_13 A4_8_9_12_13 A4_8_9_11_13)) :dweight 2.619135) ; p=0002404 -(assert-soft (= 4 (+ A4_7_9_12_13 A4_7_9_11_13 A4_8_9_12_13 A4_8_9_11_13)) :dweight 1.965211) ; p=0010834 -; contig 5, length 101, #reads 2, min 0, max 4 -(assert (and (<= 0 (+ A5_4_7_9_12_13 A5_4_7_9_11_13 A5_4_8_9_12_13 A5_4_8_9_11_13)) (<= (+ A5_4_7_9_12_13 A5_4_7_9_11_13 A5_4_8_9_12_13 A5_4_8_9_11_13) 4))) -(assert-soft (= 0 (+ A5_4_7_9_12_13 A5_4_7_9_11_13 A5_4_8_9_12_13 A5_4_8_9_11_13)) :dweight 4.686648) ; p=0000021 -(assert-soft (= 1 (+ A5_4_7_9_12_13 A5_4_7_9_11_13 A5_4_8_9_12_13 A5_4_8_9_11_13)) :dweight 2.686648) ; p=0002058 -(assert-soft (= 2 (+ A5_4_7_9_12_13 A5_4_7_9_11_13 A5_4_8_9_12_13 A5_4_8_9_11_13)) :dweight 2.113387) ; p=0007702 -(assert-soft (= 3 (+ A5_4_7_9_12_13 A5_4_7_9_11_13 A5_4_8_9_12_13 A5_4_8_9_11_13)) :dweight 1.790003) ; p=0016218 -(assert-soft (= 4 (+ A5_4_7_9_12_13 A5_4_7_9_11_13 A5_4_8_9_12_13 A5_4_8_9_11_13)) :dweight 1.568925) ; p=0026982 -; contig 6, length 223, #reads 24, min 0, max 4 -(assert (and (<= 0 (+ A6_21_10 A6_4_7_9_12_13 A6_4_7_9_11_13 A6_4_8_9_12_13 A6_4_8_9_11_13)) (<= (+ A6_21_10 A6_4_7_9_12_13 A6_4_7_9_11_13 A6_4_8_9_12_13 A6_4_8_9_11_13) 4))) -(assert-soft (= 0 (+ A6_21_10 A6_4_7_9_12_13 A6_4_7_9_11_13 A6_4_8_9_12_13 A6_4_8_9_11_13)) :dweight 7.515357) ; p=0000000 -(assert-soft (= 1 (+ A6_21_10 A6_4_7_9_12_13 A6_4_7_9_11_13 A6_4_8_9_12_13 A6_4_8_9_11_13)) :dweight 5.515357) ; p=0000003 -(assert-soft (= 2 (+ A6_21_10 A6_4_7_9_12_13 A6_4_7_9_11_13 A6_4_8_9_12_13 A6_4_8_9_11_13)) :dweight 1.804093) ; p=0015700 -(assert-soft (= 3 (+ A6_21_10 A6_4_7_9_12_13 A6_4_7_9_11_13 A6_4_8_9_12_13 A6_4_8_9_11_13)) :dweight 1.091359) ; p=0081029 -(assert-soft (= 4 (+ A6_21_10 A6_4_7_9_12_13 A6_4_7_9_11_13 A6_4_8_9_12_13 A6_4_8_9_11_13)) :dweight 1.606284) ; p=0024758 -; contig 7, length 191, #reads 9, min 0, max 4 -(assert (and (<= 0 (+ A7_9_12_13 A7_9_11_13)) (<= (+ A7_9_12_13 A7_9_11_13) 4))) -(assert-soft (= 0 (+ A7_9_12_13 A7_9_11_13)) :dweight 3.169161) ; p=0000677 -(assert-soft (= 1 (+ A7_9_12_13 A7_9_11_13)) :dweight 1.169161) ; p=0067739 -(assert-soft (= 2 (+ A7_9_12_13 A7_9_11_13)) :dweight 1.051784) ; p=0088760 -(assert-soft (= 3 (+ A7_9_12_13 A7_9_11_13)) :dweight 2.058857) ; p=0008733 -(assert-soft (= 4 (+ A7_9_12_13 A7_9_11_13)) :dweight 3.526301) ; p=0000298 -; contig 8, length 200, #reads 12, min 0, max 4 -(assert (and (<= 0 (+ A8_9_12_13 A8_9_11_13)) (<= (+ A8_9_12_13 A8_9_11_13) 4))) -(assert-soft (= 0 (+ A8_9_12_13 A8_9_11_13)) :dweight 3.724714) ; p=0000188 -(assert-soft (= 1 (+ A8_9_12_13 A8_9_11_13)) :dweight 1.724714) ; p=0018849 -(assert-soft (= 2 (+ A8_9_12_13 A8_9_11_13)) :dweight 0.963436) ; p=0108784 -(assert-soft (= 3 (+ A8_9_12_13 A8_9_11_13)) :dweight 1.701424) ; p=0019887 -(assert-soft (= 4 (+ A8_9_12_13 A8_9_11_13)) :dweight 3.053242) ; p=0000885 -; contig 9, length 269, #reads 32, min 0, max 4 -(assert (and (<= 0 (+ A9_12_13_15_17_18 A9_12_13_15_17_16_19 A9_12_13_14_17_18 A9_12_13_14_17_16_19 A9_11_13_15_17_18 A9_11_13_15_17_16_19 A9_11_13_14_17_18 A9_11_13_14_17_16_19)) (<= (+ A9_12_13_15_17_18 A9_12_13_15_17_16_19 A9_12_13_14_17_18 A9_12_13_14_17_16_19 A9_11_13_15_17_18 A9_11_13_15_17_16_19 A9_11_13_14_17_18 A9_11_13_14_17_16_19) 4))) -(assert-soft (= 0 (+ A9_12_13_15_17_18 A9_12_13_15_17_16_19 A9_12_13_14_17_18 A9_12_13_14_17_16_19 A9_11_13_15_17_18 A9_11_13_15_17_16_19 A9_11_13_14_17_18 A9_11_13_14_17_16_19)) :dweight 8.757585) ; p=0000000 -(assert-soft (= 1 (+ A9_12_13_15_17_18 A9_12_13_15_17_16_19 A9_12_13_14_17_18 A9_12_13_14_17_16_19 A9_11_13_15_17_18 A9_11_13_15_17_16_19 A9_11_13_14_17_18 A9_11_13_14_17_16_19)) :dweight 6.757585) ; p=0000000 -(assert-soft (= 2 (+ A9_12_13_15_17_18 A9_12_13_15_17_16_19 A9_12_13_14_17_18 A9_12_13_14_17_16_19 A9_11_13_15_17_18 A9_11_13_15_17_16_19 A9_11_13_14_17_18 A9_11_13_14_17_16_19)) :dweight 1.962827) ; p=0010894 -(assert-soft (= 3 (+ A9_12_13_15_17_18 A9_12_13_15_17_16_19 A9_12_13_14_17_18 A9_12_13_14_17_16_19 A9_11_13_15_17_18 A9_11_13_15_17_16_19 A9_11_13_14_17_18 A9_11_13_14_17_16_19)) :dweight 1.166108) ; p=0068217 -(assert-soft (= 4 (+ A9_12_13_15_17_18 A9_12_13_15_17_16_19 A9_12_13_14_17_18 A9_12_13_14_17_16_19 A9_11_13_15_17_18 A9_11_13_15_17_16_19 A9_11_13_14_17_18 A9_11_13_14_17_16_19)) :dweight 2.006269) ; p=0009857 -; contig 11, length 170, #reads 7, min 0, max 4 -(assert (and (<= 0 (+ A11_13_15_17_18_19 A11_13_15_17_16_19 A11_13_14_17_18_19 A11_13_14_17_16_19)) (<= (+ A11_13_15_17_18_19 A11_13_15_17_16_19 A11_13_14_17_18_19 A11_13_14_17_16_19) 4))) -(assert-soft (= 0 (+ A11_13_15_17_18_19 A11_13_15_17_16_19 A11_13_14_17_18_19 A11_13_14_17_16_19)) :dweight 3.066473) ; p=0000858 -(assert-soft (= 1 (+ A11_13_15_17_18_19 A11_13_15_17_16_19 A11_13_14_17_18_19 A11_13_14_17_16_19)) :dweight 1.066473) ; p=0085808 -(assert-soft (= 2 (+ A11_13_15_17_18_19 A11_13_15_17_16_19 A11_13_14_17_18_19 A11_13_14_17_16_19)) :dweight 0.946381) ; p=0113141 -(assert-soft (= 3 (+ A11_13_15_17_18_19 A11_13_15_17_16_19 A11_13_14_17_18_19 A11_13_14_17_16_19)) :dweight 1.700861) ; p=0019913 -(assert-soft (= 4 (+ A11_13_15_17_18_19 A11_13_15_17_16_19 A11_13_14_17_18_19 A11_13_14_17_16_19)) :dweight 2.813408) ; p=0001537 -; contig 12, length 198, #reads 15, min 0, max 4 -(assert (and (<= 0 (+ A12_13_15_17_18_19 A12_13_15_17_16_19 A12_13_14_17_18_19 A12_13_14_17_16_19)) (<= (+ A12_13_15_17_18_19 A12_13_15_17_16_19 A12_13_14_17_18_19 A12_13_14_17_16_19) 4))) -(assert-soft (= 0 (+ A12_13_15_17_18_19 A12_13_15_17_16_19 A12_13_14_17_18_19 A12_13_14_17_16_19)) :dweight 4.784554) ; p=0000016 -(assert-soft (= 1 (+ A12_13_15_17_18_19 A12_13_15_17_16_19 A12_13_14_17_18_19 A12_13_14_17_16_19)) :dweight 2.784554) ; p=0001642 -(assert-soft (= 2 (+ A12_13_15_17_18_19 A12_13_15_17_16_19 A12_13_14_17_18_19 A12_13_14_17_16_19)) :dweight 1.062589) ; p=0086579 -(assert-soft (= 3 (+ A12_13_15_17_18_19 A12_13_15_17_16_19 A12_13_14_17_18_19 A12_13_14_17_16_19)) :dweight 1.214705) ; p=0060995 -(assert-soft (= 4 (+ A12_13_15_17_18_19 A12_13_15_17_16_19 A12_13_14_17_18_19 A12_13_14_17_16_19)) :dweight 2.134110) ; p=0007343 -; contig 13, length 349, #reads 28, min 0, max 4 -(assert (and (<= 0 (+ A13_15_17_18_19 A13_15_17_16_19 A13_14_17_18_19 A13_14_17_16_19)) (<= (+ A13_15_17_18_19 A13_15_17_16_19 A13_14_17_18_19 A13_14_17_16_19) 4))) -(assert-soft (= 0 (+ A13_15_17_18_19 A13_15_17_16_19 A13_14_17_18_19 A13_14_17_16_19)) :dweight 4.577071) ; p=0000026 -(assert-soft (= 1 (+ A13_15_17_18_19 A13_15_17_16_19 A13_14_17_18_19 A13_14_17_16_19)) :dweight 2.577071) ; p=0002648 -(assert-soft (= 2 (+ A13_15_17_18_19 A13_15_17_16_19 A13_14_17_18_19 A13_14_17_16_19)) :dweight 1.290338) ; p=0051246 -(assert-soft (= 3 (+ A13_15_17_18_19 A13_15_17_16_19 A13_14_17_18_19 A13_14_17_16_19)) :dweight 3.501889) ; p=0000315 -(assert-soft (= 4 (+ A13_15_17_18_19 A13_15_17_16_19 A13_14_17_18_19 A13_14_17_16_19)) :dweight 7.145711) ; p=0000000 -; contig 20, length 1151, #reads 32, min 0, max 4 -(assert (and (<= 0 (+ A20_6_21_10 A20_6_4_7_9_12 A20_6_4_7_9_11 A20_6_4_8_9_12 A20_6_4_8_9_11)) (<= (+ A20_6_21_10 A20_6_4_7_9_12 A20_6_4_7_9_11 A20_6_4_8_9_12 A20_6_4_8_9_11) 4))) -(assert-soft (= 0 (+ A20_6_21_10 A20_6_4_7_9_12 A20_6_4_7_9_11 A20_6_4_8_9_12 A20_6_4_8_9_11)) :dweight 8.689981) ; p=0000000 -(assert-soft (= 1 (+ A20_6_21_10 A20_6_4_7_9_12 A20_6_4_7_9_11 A20_6_4_8_9_12 A20_6_4_8_9_11)) :dweight 6.689981) ; p=0000000 -(assert-soft (= 2 (+ A20_6_21_10 A20_6_4_7_9_12 A20_6_4_7_9_11 A20_6_4_8_9_12 A20_6_4_8_9_11)) :dweight 2.7295778) ; p=0000000 -(assert-soft (= 3 (+ A20_6_21_10 A20_6_4_7_9_12 A20_6_4_7_9_11 A20_6_4_8_9_12 A20_6_4_8_9_11)) :dweight 5.1899615) ; p=0000000 -(assert-soft (= 4 (+ A20_6_21_10 A20_6_4_7_9_12 A20_6_4_7_9_11 A20_6_4_8_9_12 A20_6_4_8_9_11)) :dweight 7.8140332) ; p=0000000 -; contig 21, length 107, #reads 4, min 0, max 4 -(assert (and (<= 0 (+ A21_10)) (<= (+ A21_10) 4))) -(assert-soft (= 0 (+ A21_10)) :dweight 5.154038) ; p=0000007 -(assert-soft (= 1 (+ A21_10)) :dweight 3.154038) ; p=0000701 -(assert-soft (= 2 (+ A21_10)) :dweight 2.122711) ; p=0007539 -(assert-soft (= 3 (+ A21_10)) :dweight 1.591139) ; p=0025637 -(assert-soft (= 4 (+ A21_10)) :dweight 1.264177) ; p=0054428 -; consistency of minipathlet multiplicities -(assert (= (+ A9_12_13_15_17_18) (+ A12_13_15_17_18_19))) -(assert (= (+ A5_4_7_9_11_13 A6_4_7_9_11_13) (+ A4_7_9_11_13))) -(assert (= (+ A0_2_3_5_4_8_9) (+ A2_3_5_4_8_9))) -(assert (= (+ A1_3_5_4_8_9 A2_3_5_4_8_9) (+ A3_5_4_8_9_12_13 A3_5_4_8_9_11_13))) -(assert (= (+ A9_11_13_14_17_16_19) (+ A11_13_14_17_16_19))) -(assert (= (+ A11_13_14_17_16_19 A12_13_14_17_16_19) (+ A13_14_17_16_19))) -(assert (= (+ A20_6_21_10) (+ A6_21_10))) -(assert (= (+ A11_13_14_17_18_19 A12_13_14_17_18_19) (+ A13_14_17_18_19))) -(assert (= (+ A0_1_3_5_4_7_9) (+ A1_3_5_4_7_9))) -(assert (= (+ A9_12_13_14_17_18) (+ A12_13_14_17_18_19))) -(assert (= (+ A1_3_10 A2_3_10) (+ A3_10))) -(assert (= (+ A11_13_15_17_18_19 A12_13_15_17_18_19) (+ A13_15_17_18_19))) -(assert (= (+ A11_13_15_17_16_19 A12_13_15_17_16_19) (+ A13_15_17_16_19))) -(assert (= (+ A9_12_13_14_17_16_19) (+ A12_13_14_17_16_19))) -(assert (= (+ A7_9_11_13 A8_9_11_13) (+ A9_11_13_15_17_18 A9_11_13_15_17_16_19 A9_11_13_14_17_18 A9_11_13_14_17_16_19))) -(assert (= (+ A0_2_3_5_4_7_9) (+ A2_3_5_4_7_9))) -(assert (= (+ A4_8_9_11_13) (+ A8_9_11_13))) -(assert (= (+ A0_1_3_10) (+ A1_3_10))) -(assert (= (+ A20_6_4_8_9_12) (+ A6_4_8_9_12_13))) -(assert (= (+ A3_5_4_8_9_11_13) (+ A5_4_8_9_11_13))) -(assert (= (+ A0_1_3_5_4_8_9) (+ A1_3_5_4_8_9))) -(assert (= (+ A5_4_8_9_11_13 A6_4_8_9_11_13) (+ A4_8_9_11_13))) -(assert (= (+ A20_6_4_7_9_12) (+ A6_4_7_9_12_13))) -(assert (= (+ A20_6_4_7_9_11) (+ A6_4_7_9_11_13))) -(assert (= (+ A3_5_4_8_9_12_13) (+ A5_4_8_9_12_13))) -(assert (= (+ A4_7_9_12_13) (+ A7_9_12_13))) -(assert (= (+ A9_12_13_15_17_16_19) (+ A12_13_15_17_16_19))) -(assert (= (+ A9_11_13_15_17_16_19) (+ A11_13_15_17_16_19))) -(assert (= (+ A1_3_5_4_7_9 A2_3_5_4_7_9) (+ A3_5_4_7_9_12_13 A3_5_4_7_9_11_13))) -(assert (= (+ A3_5_4_7_9_12_13) (+ A5_4_7_9_12_13))) -(assert (= (+ A7_9_12_13 A8_9_12_13) (+ A9_12_13_15_17_18 A9_12_13_15_17_16_19 A9_12_13_14_17_18 A9_12_13_14_17_16_19))) -(assert (= (+ A0_2_3_10) (+ A2_3_10))) -(assert (= (+ A9_11_13_14_17_18) (+ A11_13_14_17_18_19))) -(assert (= (+ A4_8_9_12_13) (+ A8_9_12_13))) -(assert (= (+ A5_4_7_9_12_13 A6_4_7_9_12_13) (+ A4_7_9_12_13))) -(assert (= (+ A9_11_13_15_17_18) (+ A11_13_15_17_18_19))) -(assert (= (+ A6_21_10) (+ A21_10))) -(assert (= (+ A20_6_4_8_9_11) (+ A6_4_8_9_11_13))) -(assert (= (+ A3_5_4_7_9_11_13) (+ A5_4_7_9_11_13))) -(assert (= (+ A5_4_8_9_12_13 A6_4_8_9_12_13) (+ A4_8_9_12_13))) -(assert (= (+ A4_7_9_11_13) (+ A7_9_11_13))) -(optimize :print_statistics true - :wmaxsat_engine sls - :maxsat_engine weighted_maxsat) diff --git a/tests/sls1.smt2 b/tests/sls1.smt2 deleted file mode 100644 index 5f38a9418..000000000 --- a/tests/sls1.smt2 +++ /dev/null @@ -1,5844 +0,0 @@ -(set-option :smt.relevancy 0) -(set-option :smt.pb.conflict_frequency 10000) -(declare-fun x_354 () Int) -(declare-fun x_522 () Int) -(declare-fun x_464 () Int) -(declare-fun x_644 () Int) -(declare-fun x_174 () Int) -(declare-fun x_397 () Int) -(declare-fun x_432 () Int) -(declare-fun x_557 () Int) -(declare-fun x_926 () Int) -(declare-fun x_582 () Int) -(declare-fun x_779 () Int) -(declare-fun x_759 () Int) -(declare-fun x_912 () Int) -(declare-fun x_868 () Int) -(declare-fun x_384 () Int) -(declare-fun x_963 () Int) -(declare-fun x_658 () Int) -(declare-fun x_362 () Int) -(declare-fun x_984 () Int) -(declare-fun x_308 () Int) -(declare-fun x_456 () Int) -(declare-fun x_17 () Int) -(declare-fun x_816 () Int) -(declare-fun x_833 () Int) -(declare-fun x_463 () Int) -(declare-fun x_211 () Int) -(declare-fun x_607 () Int) -(declare-fun x_139 () Int) -(declare-fun x_124 () Int) -(declare-fun x_291 () Int) -(declare-fun x_859 () Int) -(declare-fun x_888 () Int) -(declare-fun x_31 () Int) -(declare-fun x_472 () Int) -(declare-fun x_434 () Int) -(declare-fun x_154 () Int) -(declare-fun x_347 () Int) -(declare-fun x_88 () Int) -(declare-fun x_769 () Int) -(declare-fun x_986 () Int) -(declare-fun x_8 () Int) -(declare-fun x_196 () Int) -(declare-fun x_882 () Int) -(declare-fun x_711 () Int) -(declare-fun x_167 () Int) -(declare-fun x_119 () Int) -(declare-fun x_4 () Int) -(declare-fun x_33 () Int) -(declare-fun x_178 () Int) -(declare-fun x_893 () Int) -(declare-fun x_429 () Int) -(declare-fun x_527 () Int) -(declare-fun x_194 () Int) -(declare-fun x_498 () Int) -(declare-fun x_346 () Int) -(declare-fun x_712 () Int) -(declare-fun x_691 () Int) -(declare-fun x_294 () Int) -(declare-fun x_402 () Int) -(declare-fun x_213 () Int) -(declare-fun x_239 () Int) -(declare-fun x_297 () Int) -(declare-fun x_427 () Int) -(declare-fun x_489 () Int) -(declare-fun x_841 () Int) -(declare-fun x_186 () Int) -(declare-fun x_149 () Int) -(declare-fun x_586 () Int) -(declare-fun x_932 () Int) -(declare-fun x_367 () Int) -(declare-fun x_77 () Int) -(declare-fun x_123 () Int) -(declare-fun x_884 () Int) -(declare-fun x_989 () Int) -(declare-fun x_242 () Int) -(declare-fun x_614 () Int) -(declare-fun x_381 () Int) -(declare-fun x_388 () Int) -(declare-fun x_306 () Int) -(declare-fun x_737 () Int) -(declare-fun x_277 () Int) -(declare-fun x_966 () Int) -(declare-fun x_67 () Int) -(declare-fun x_678 () Int) -(declare-fun x_87 () Int) -(declare-fun x_496 () Int) -(declare-fun x_919 () Int) -(declare-fun x_439 () Int) -(declare-fun x_854 () Int) -(declare-fun x_961 () Int) -(declare-fun x_697 () Int) -(declare-fun x_19 () Int) -(declare-fun x_818 () Int) -(declare-fun x_158 () Int) -(declare-fun x_26 () Int) -(declare-fun x_436 () Int) -(declare-fun x_798 () Int) -(declare-fun x_457 () Int) -(declare-fun x_838 () Int) -(declare-fun x_953 () Int) -(declare-fun x_524 () Int) -(declare-fun x_574 () Int) -(declare-fun x_212 () Int) -(declare-fun x_486 () Int) -(declare-fun x_3 () Int) -(declare-fun x_256 () Int) -(declare-fun x_22 () Int) -(declare-fun x_676 () Int) -(declare-fun x_789 () Int) -(declare-fun x_892 () Int) -(declare-fun x_682 () Int) -(declare-fun x_84 () Int) -(declare-fun x_819 () Int) -(declare-fun x_454 () Int) -(declare-fun x_59 () Int) -(declare-fun x_227 () Int) -(declare-fun x_572 () Int) -(declare-fun x_914 () Int) -(declare-fun x_39 () Int) -(declare-fun x_679 () Int) -(declare-fun x_824 () Int) -(declare-fun x_684 () Int) -(declare-fun x_221 () Int) -(declare-fun x_274 () Int) -(declare-fun x_32 () Int) -(declare-fun x_348 () Int) -(declare-fun x_877 () Int) -(declare-fun x_701 () Int) -(declare-fun x_231 () Int) -(declare-fun x_549 () Int) -(declare-fun x_889 () Int) -(declare-fun x_879 () Int) -(declare-fun x_662 () Int) -(declare-fun x_302 () Int) -(declare-fun x_979 () Int) -(declare-fun x_861 () Int) -(declare-fun x_973 () Int) -(declare-fun x_401 () Int) -(declare-fun x_537 () Int) -(declare-fun x_972 () Int) -(declare-fun x_269 () Int) -(declare-fun x_957 () Int) -(declare-fun x_271 () Int) -(declare-fun x_363 () Int) -(declare-fun x_181 () Int) -(declare-fun x_357 () Int) -(declare-fun x_591 () Int) -(declare-fun x_559 () Int) -(declare-fun x_51 () Int) -(declare-fun x_916 () Int) -(declare-fun x_389 () Int) -(declare-fun x_512 () Int) -(declare-fun x_988 () Int) -(declare-fun x_667 () Int) -(declare-fun x_511 () Int) -(declare-fun x_733 () Int) -(declare-fun x_821 () Int) -(declare-fun x_671 () Int) -(declare-fun x_707 () Int) -(declare-fun x_826 () Int) -(declare-fun x_319 () Int) -(declare-fun x_399 () Int) -(declare-fun x_852 () Int) -(declare-fun x_442 () Int) -(declare-fun x_108 () Int) -(declare-fun x_392 () Int) -(declare-fun x_776 () Int) -(declare-fun x_993 () Int) -(declare-fun x_459 () Int) -(declare-fun x_913 () Int) -(declare-fun x_107 () Int) -(declare-fun x_994 () Int) -(declare-fun x_61 () Int) -(declare-fun x_802 () Int) -(declare-fun x_677 () Int) -(declare-fun x_857 () Int) -(declare-fun x_706 () Int) -(declare-fun x_278 () Int) -(declare-fun x_443 () Int) -(declare-fun x_813 () Int) -(declare-fun x_971 () Int) -(declare-fun x_173 () Int) -(declare-fun x_91 () Int) -(declare-fun x_396 () Int) -(declare-fun x_551 () Int) -(declare-fun x_846 () Int) -(declare-fun x_417 () Int) -(declare-fun x_54 () Int) -(declare-fun x_721 () Int) -(declare-fun x_331 () Int) -(declare-fun x_467 () Int) -(declare-fun x_553 () Int) -(declare-fun x_959 () Int) -(declare-fun x_871 () Int) -(declare-fun x_692 () Int) -(declare-fun x_792 () Int) -(declare-fun x_593 () Int) -(declare-fun x_412 () Int) -(declare-fun x_531 () Int) -(declare-fun x_352 () Int) -(declare-fun x_333 () Int) -(declare-fun x_596 () Int) -(declare-fun x_229 () Int) -(declare-fun x_447 () Int) -(declare-fun x_53 () Int) -(declare-fun x_548 () Int) -(declare-fun x_43 () Int) -(declare-fun x_13 () Int) -(declare-fun x_198 () Int) -(declare-fun x_47 () Int) -(declare-fun x_626 () Int) -(declare-fun x_648 () Int) -(declare-fun x_902 () Int) -(declare-fun x_594 () Int) -(declare-fun x_113 () Int) -(declare-fun x_286 () Int) -(declare-fun x_163 () Int) -(declare-fun x_157 () Int) -(declare-fun x_659 () Int) -(declare-fun x_24 () Int) -(declare-fun x_631 () Int) -(declare-fun x_699 () Int) -(declare-fun x_366 () Int) -(declare-fun x_6 () Int) -(declare-fun x_156 () Int) -(declare-fun x_876 () Int) -(declare-fun x_598 () Int) -(declare-fun x_974 () Int) -(declare-fun x_372 () Int) -(declare-fun x_538 () Int) -(declare-fun x_287 () Int) -(declare-fun x_71 () Int) -(declare-fun x_371 () Int) -(declare-fun x_646 () Int) -(declare-fun x_519 () Int) -(declare-fun x_121 () Int) -(declare-fun x_268 () Int) -(declare-fun x_746 () Int) -(declare-fun x_562 () Int) -(declare-fun x_799 () Int) -(declare-fun x_423 () Int) -(declare-fun x_808 () Int) -(declare-fun x_303 () Int) -(declare-fun x_536 () Int) -(declare-fun x_344 () Int) -(declare-fun x_322 () Int) -(declare-fun x_299 () Int) -(declare-fun x_976 () Int) -(declare-fun x_279 () Int) -(declare-fun x_482 () Int) -(declare-fun x_246 () Int) -(declare-fun x_763 () Int) -(declare-fun x_111 () Int) -(declare-fun x_226 () Int) -(declare-fun x_741 () Int) -(declare-fun x_188 () Int) -(declare-fun x_873 () Int) -(declare-fun x_767 () Int) -(declare-fun x_766 () Int) -(declare-fun x_7 () Int) -(declare-fun x_377 () Int) -(declare-fun x_719 () Int) -(declare-fun x_704 () Int) -(declare-fun x_72 () Int) -(declare-fun x_27 () Int) -(declare-fun x_284 () Int) -(declare-fun x_943 () Int) -(declare-fun x_42 () Int) -(declare-fun x_881 () Int) -(declare-fun x_693 () Int) -(declare-fun x_422 () Int) -(declare-fun x_218 () Int) -(declare-fun x_736 () Int) -(declare-fun x_817 () Int) -(declare-fun x_168 () Int) -(declare-fun x_359 () Int) -(declare-fun x_16 () Int) -(declare-fun x_469 () Int) -(declare-fun x_814 () Int) -(declare-fun x_62 () Int) -(declare-fun x_461 () Int) -(declare-fun x_483 () Int) -(declare-fun x_68 () Int) -(declare-fun x_786 () Int) -(declare-fun x_938 () Int) -(declare-fun x_204 () Int) -(declare-fun x_718 () Int) -(declare-fun x_197 () Int) -(declare-fun x_603 () Int) -(declare-fun x_616 () Int) -(declare-fun x_117 () Int) -(declare-fun x_567 () Int) -(declare-fun x_729 () Int) -(declare-fun x_942 () Int) -(declare-fun x_748 () Int) -(declare-fun x_992 () Int) -(declare-fun x_713 () Int) -(declare-fun x_326 () Int) -(declare-fun x_689 () Int) -(declare-fun x_948 () Int) -(declare-fun x_717 () Int) -(declare-fun x_403 () Int) -(declare-fun x_872 () Int) -(declare-fun x_73 () Int) -(declare-fun x_639 () Int) -(declare-fun x_137 () Int) -(declare-fun x_373 () Int) -(declare-fun x_364 () Int) -(declare-fun x_576 () Int) -(declare-fun x_358 () Int) -(declare-fun x_466 () Int) -(declare-fun x_122 () Int) -(declare-fun x_637 () Int) -(declare-fun x_202 () Int) -(declare-fun x_476 () Int) -(declare-fun x_44 () Int) -(declare-fun x_151 () Int) -(declare-fun x_253 () Int) -(declare-fun x_696 () Int) -(declare-fun x_822 () Int) -(declare-fun x_641 () Int) -(declare-fun x_924 () Int) -(declare-fun x_233 () Int) -(declare-fun x_136 () Int) -(declare-fun x_222 () Int) -(declare-fun x_318 () Int) -(declare-fun x_694 () Int) -(declare-fun x_543 () Int) -(declare-fun x_141 () Int) -(declare-fun x_418 () Int) -(declare-fun x_409 () Int) -(declare-fun x_601 () Int) -(declare-fun x_339 () Int) -(declare-fun x_958 () Int) -(declare-fun x_773 () Int) -(declare-fun x_448 () Int) -(declare-fun x_508 () Int) -(declare-fun x_104 () Int) -(declare-fun x_674 () Int) -(declare-fun x_991 () Int) -(declare-fun x_406 () Int) -(declare-fun x_283 () Int) -(declare-fun x_552 () Int) -(declare-fun x_907 () Int) -(declare-fun x_408 () Int) -(declare-fun x_451 () Int) -(declare-fun x_897 () Int) -(declare-fun x_503 () Int) -(declare-fun x_672 () Int) -(declare-fun x_264 () Int) -(declare-fun x_382 () Int) -(declare-fun x_554 () Int) -(declare-fun x_561 () Int) -(declare-fun x_11 () Int) -(declare-fun x_329 () Int) -(declare-fun x_727 () Int) -(declare-fun x_97 () Int) -(declare-fun x_343 () Int) -(declare-fun x_918 () Int) -(declare-fun x_289 () Int) -(declare-fun x_803 () Int) -(declare-fun x_812 () Int) -(declare-fun x_547 () Int) -(declare-fun x_806 () Int) -(declare-fun x_252 () Int) -(declare-fun x_273 () Int) -(declare-fun x_618 () Int) -(declare-fun x_301 () Int) -(declare-fun x_688 () Int) -(declare-fun x_224 () Int) -(declare-fun x_449 () Int) -(declare-fun x_327 () Int) -(declare-fun x_387 () Int) -(declare-fun x_86 () Int) -(declare-fun x_89 () Int) -(declare-fun x_404 () Int) -(declare-fun x_507 () Int) -(declare-fun x_312 () Int) -(declare-fun x_578 () Int) -(declare-fun x_722 () Int) -(declare-fun x_762 () Int) -(declare-fun x_169 () Int) -(declare-fun x_206 () Int) -(declare-fun x_383 () Int) -(declare-fun x_867 () Int) -(declare-fun x_627 () Int) -(declare-fun x_638 () Int) -(declare-fun x_184 () Int) -(declare-fun x_479 () Int) -(declare-fun x_292 () Int) -(declare-fun x_844 () Int) -(declare-fun x_421 () Int) -(declare-fun x_911 () Int) -(declare-fun x_419 () Int) -(declare-fun x_612 () Int) -(declare-fun x_192 () Int) -(declare-fun x_656 () Int) -(declare-fun x_702 () Int) -(declare-fun x_778 () Int) -(declare-fun x_281 () Int) -(declare-fun x_834 () Int) -(declare-fun x_63 () Int) -(declare-fun x_836 () Int) -(declare-fun x_793 () Int) -(declare-fun x_622 () Int) -(declare-fun x_899 () Int) -(declare-fun x_944 () Int) -(declare-fun x_369 () Int) -(declare-fun x_336 () Int) -(declare-fun x_869 () Int) -(declare-fun x_257 () Int) -(declare-fun x_1001 () Int) -(declare-fun x_904 () Int) -(declare-fun x_528 () Int) -(declare-fun x_997 () Int) -(declare-fun x_414 () Int) -(declare-fun x_223 () Int) -(declare-fun x_642 () Int) -(declare-fun x_76 () Int) -(declare-fun x_29 () Int) -(declare-fun x_533 () Int) -(declare-fun x_41 () Int) -(declare-fun x_581 () Int) -(declare-fun x_791 () Int) -(declare-fun x_809 () Int) -(declare-fun x_321 () Int) -(declare-fun x_939 () Int) -(declare-fun x_541 () Int) -(declare-fun x_652 () Int) -(declare-fun x_569 () Int) -(declare-fun x_934 () Int) -(declare-fun x_207 () Int) -(declare-fun x_376 () Int) -(declare-fun x_109 () Int) -(declare-fun x_761 () Int) -(declare-fun x_446 () Int) -(declare-fun x_657 () Int) -(declare-fun x_171 () Int) -(declare-fun x_558 () Int) -(declare-fun x_276 () Int) -(declare-fun x_46 () Int) -(declare-fun x_668 () Int) -(declare-fun x_57 () Int) -(declare-fun x_374 () Int) -(declare-fun x_209 () Int) -(declare-fun x_739 () Int) -(declare-fun x_909 () Int) -(declare-fun x_468 () Int) -(declare-fun x_14 () Int) -(declare-fun x_832 () Int) -(declare-fun x_391 () Int) -(declare-fun x_517 () Int) -(declare-fun x_12 () Int) -(declare-fun x_244 () Int) -(declare-fun x_628 () Int) -(declare-fun x_334 () Int) -(declare-fun x_502 () Int) -(declare-fun x_883 () Int) -(declare-fun x_379 () Int) -(declare-fun x_307 () Int) -(declare-fun x_182 () Int) -(declare-fun x_293 () Int) -(declare-fun x_288 () Int) -(declare-fun x_633 () Int) -(declare-fun x_866 () Int) -(declare-fun x_571 () Int) -(declare-fun x_842 () Int) -(declare-fun x_921 () Int) -(declare-fun x_797 () Int) -(declare-fun x_153 () Int) -(declare-fun x_398 () Int) -(declare-fun x_583 () Int) -(declare-fun x_683 () Int) -(declare-fun x_189 () Int) -(declare-fun x_964 () Int) -(declare-fun x_164 () Int) -(declare-fun x_474 () Int) -(declare-fun x_521 () Int) -(declare-fun x_21 () Int) -(declare-fun x_518 () Int) -(declare-fun x_473 () Int) -(declare-fun x_896 () Int) -(declare-fun x_796 () Int) -(declare-fun x_477 () Int) -(declare-fun x_74 () Int) -(declare-fun x_116 () Int) -(declare-fun x_837 () Int) -(declare-fun x_673 () Int) -(declare-fun x_309 () Int) -(declare-fun x_58 () Int) -(declare-fun x_428 () Int) -(declare-fun x_589 () Int) -(declare-fun x_747 () Int) -(declare-fun x_929 () Int) -(declare-fun x_529 () Int) -(declare-fun x_413 () Int) -(declare-fun x_847 () Int) -(declare-fun x_262 () Int) -(declare-fun x_801 () Int) -(declare-fun x_952 () Int) -(declare-fun x_632 () Int) -(declare-fun x_142 () Int) -(declare-fun x_491 () Int) -(declare-fun x_546 () Int) -(declare-fun x_839 () Int) -(declare-fun x_588 () Int) -(declare-fun x_393 () Int) -(declare-fun x_118 () Int) -(declare-fun x_901 () Int) -(declare-fun x_962 () Int) -(declare-fun x_968 () Int) -(declare-fun x_886 () Int) -(declare-fun x_774 () Int) -(declare-fun x_487 () Int) -(declare-fun x_127 () Int) -(declare-fun x_237 () Int) -(declare-fun x_723 () Int) -(declare-fun x_542 () Int) -(declare-fun x_753 () Int) -(declare-fun x_129 () Int) -(declare-fun x_864 () Int) -(declare-fun x_611 () Int) -(declare-fun x_416 () Int) -(declare-fun x_947 () Int) -(declare-fun x_1202 () Int) -(declare-fun x_563 () Int) -(declare-fun x_337 () Int) -(declare-fun x_544 () Int) -(declare-fun x_654 () Int) -(declare-fun x_756 () Int) -(declare-fun x_744 () Int) -(declare-fun x_891 () Int) -(declare-fun x_378 () Int) -(declare-fun x_134 () Int) -(declare-fun x_208 () Int) -(declare-fun x_758 () Int) -(declare-fun x_848 () Int) -(declare-fun x_927 () Int) -(declare-fun x_937 () Int) -(declare-fun x_602 () Int) -(declare-fun x_349 () Int) -(declare-fun x_96 () Int) -(declare-fun x_162 () Int) -(declare-fun x_37 () Int) -(declare-fun x_941 () Int) -(declare-fun x_906 () Int) -(declare-fun x_811 () Int) -(declare-fun x_138 () Int) -(declare-fun x_621 () Int) -(declare-fun x_492 () Int) -(declare-fun x_764 () Int) -(declare-fun x_452 () Int) -(declare-fun x_851 () Int) -(declare-fun x_98 () Int) -(declare-fun x_236 () Int) -(declare-fun x_453 () Int) -(declare-fun x_978 () Int) -(declare-fun x_499 () Int) -(declare-fun x_494 () Int) -(declare-fun x_316 () Int) -(declare-fun x_587 () Int) -(declare-fun x_103 () Int) -(declare-fun x_734 () Int) -(declare-fun x_923 () Int) -(declare-fun x_228 () Int) -(declare-fun x_504 () Int) -(declare-fun x_564 () Int) -(declare-fun x_592 () Int) -(declare-fun x_2 () Int) -(declare-fun x_539 () Int) -(declare-fun x_247 () Int) -(declare-fun x_931 () Int) -(declare-fun x_903 () Int) -(declare-fun x_64 () Int) -(declare-fun x_232 () Int) -(declare-fun x_298 () Int) -(declare-fun x_126 () Int) -(declare-fun x_787 () Int) -(declare-fun x_243 () Int) -(declare-fun x_356 () Int) -(declare-fun x_709 () Int) -(declare-fun x_823 () Int) -(declare-fun x_338 () Int) -(declare-fun x_201 () Int) -(declare-fun x_304 () Int) -(declare-fun x_101 () Int) -(declare-fun x_568 () Int) -(declare-fun x_573 () Int) -(declare-fun x_28 () Int) -(declare-fun x_516 () Int) -(declare-fun x_619 () Int) -(declare-fun x_102 () Int) -(declare-fun x_92 () Int) -(declare-fun x_604 () Int) -(declare-fun x_597 () Int) -(declare-fun x_663 () Int) -(declare-fun x_731 () Int) -(declare-fun x_328 () Int) -(declare-fun x_143 () Int) -(declare-fun x_849 () Int) -(declare-fun x_128 () Int) -(declare-fun x_266 () Int) -(declare-fun x_203 () Int) -(declare-fun x_661 () Int) -(declare-fun x_996 () Int) -(declare-fun x_462 () Int) -(declare-fun x_977 () Int) -(declare-fun x_458 () Int) -(declare-fun x_933 () Int) -(declare-fun x_94 () Int) -(declare-fun x_332 () Int) -(declare-fun x_514 () Int) -(declare-fun x_969 () Int) -(declare-fun x_987 () Int) -(declare-fun x_497 () Int) -(declare-fun x_666 () Int) -(declare-fun x_858 () Int) -(declare-fun x_643 () Int) -(declare-fun x_523 () Int) -(declare-fun x_609 () Int) -(declare-fun x_263 () Int) -(declare-fun x_878 () Int) -(declare-fun x_981 () Int) -(declare-fun x_863 () Int) -(declare-fun x_324 () Int) -(declare-fun x_783 () Int) -(declare-fun x_241 () Int) -(declare-fun x_407 () Int) -(declare-fun x_708 () Int) -(declare-fun x_862 () Int) -(declare-fun x_757 () Int) -(declare-fun x_251 () Int) -(declare-fun x_771 () Int) -(declare-fun x_478 () Int) -(declare-fun x_437 () Int) -(declare-fun x_267 () Int) -(declare-fun x_599 () Int) -(declare-fun x_234 () Int) -(declare-fun x_177 () Int) -(declare-fun x_726 () Int) -(declare-fun x_261 () Int) -(declare-fun x_353 () Int) -(declare-fun x_732 () Int) -(declare-fun x_908 () Int) -(declare-fun x_361 () Int) -(declare-fun x_887 () Int) -(declare-fun x_488 () Int) -(declare-fun x_917 () Int) -(declare-fun x_716 () Int) -(declare-fun x_166 () Int) -(declare-fun x_112 () Int) -(declare-fun x_629 () Int) -(declare-fun x_52 () Int) -(declare-fun x_34 () Int) -(declare-fun x_183 () Int) -(declare-fun x_999 () Int) -(declare-fun x_99 () Int) -(declare-fun x_444 () Int) -(declare-fun x_424 () Int) -(declare-fun x_317 () Int) -(declare-fun x_784 () Int) -(declare-fun x_584 () Int) -(declare-fun x_282 () Int) -(declare-fun x_743 () Int) -(declare-fun x_56 () Int) -(declare-fun x_749 () Int) -(declare-fun x_411 () Int) -(declare-fun x_647 () Int) -(declare-fun x_219 () Int) -(declare-fun x_946 () Int) -(declare-fun x_433 () Int) -(declare-fun x_106 () Int) -(declare-fun x_38 () Int) -(declare-fun x_314 () Int) -(declare-fun x_481 () Int) -(declare-fun x_768 () Int) -(declare-fun x_579 () Int) -(declare-fun x_114 () Int) -(declare-fun x_894 () Int) -(declare-fun x_146 () Int) -(declare-fun x_577 () Int) -(declare-fun x_394 () Int) -(declare-fun x_566 () Int) -(declare-fun x_738 () Int) -(declare-fun x_506 () Int) -(declare-fun x_351 () Int) -(declare-fun x_493 () Int) -(declare-fun x_624 () Int) -(declare-fun x_653 () Int) -(declare-fun x_386 () Int) -(declare-fun x_526 () Int) -(declare-fun x_148 () Int) -(declare-fun x_131 () Int) -(declare-fun x_669 () Int) -(declare-fun x_982 () Int) -(declare-fun x_664 () Int) -(declare-fun x_501 () Int) -(declare-fun x_856 () Int) -(declare-fun x_828 () Int) -(declare-fun x_161 () Int) -(declare-fun x_772 () Int) -(declare-fun x_147 () Int) -(declare-fun x_967 () Int) -(declare-fun x_313 () Int) -(declare-fun x_681 () Int) -(declare-fun x_724 () Int) -(declare-fun x_636 () Int) -(declare-fun x_83 () Int) -(declare-fun x_754 () Int) -(declare-fun x_484 () Int) -(declare-fun x_49 () Int) -(declare-fun x_703 () Int) -(declare-fun x_36 () Int) -(declare-fun x_152 () Int) -(declare-fun x_187 () Int) -(declare-fun x_752 () Int) -(declare-fun x_191 () Int) -(declare-fun x_634 () Int) -(declare-fun x_788 () Int) -(declare-fun x_259 () Int) -(declare-fun x_431 () Int) -(declare-fun x_509 () Int) -(declare-fun x_93 () Int) -(declare-fun x_9 () Int) -(declare-fun x_513 () Int) -(declare-fun x_248 () Int) -(declare-fun x_272 () Int) -(declare-fun x_751 () Int) -(declare-fun x_686 () Int) -(declare-fun x_714 () Int) -(declare-fun x_807 () Int) -(declare-fun x_922 () Int) -(declare-fun x_81 () Int) -(declare-fun x_613 () Int) -(declare-fun x_928 () Int) -(declare-fun x_1604 () Int) -(declare-fun x_78 () Int) -(declare-fun x_249 () Int) -(declare-fun x_79 () Int) -(declare-fun x_649 () Int) -(declare-fun x_781 () Int) -(declare-fun x_687 () Int) -(declare-fun x_82 () Int) -(declare-fun x_804 () Int) -(declare-fun x_441 () Int) -(declare-fun x_651 () Int) -(declare-fun x_936 () Int) -(declare-fun x_1 () Int) -(declare-fun x_179 () Int) -(declare-fun x_199 () Int) -(declare-fun x_623 () Int) -(declare-fun x_794 () Int) -(declare-fun x_777 () Int) -(declare-fun x_214 () Int) -(declare-fun x_296 () Int) -(declare-fun x_949 () Int) -(declare-fun x_133 () Int) -(declare-fun x_829 () Int) -(declare-fun x_556 () Int) -(declare-fun x_617 () Int) -(declare-fun x_18 () Int) -(declare-fun x_728 () Int) -(declare-fun x_426 () Int) -(declare-fun x_898 () Int) -(declare-fun x_23 () Int) -(declare-fun x_843 () Int) -(declare-fun x_827 () Int) -(declare-fun x_831 () Int) -(declare-fun x_954 () Int) -(declare-fun x_341 () Int) -(declare-fun x_956 () Int) -(declare-fun x_983 () Int) -(declare-fun x_606 () Int) -(declare-fun x_874 () Int) -(declare-fun x_698 () Int) -(declare-fun x_782 () Int) -(declare-fun x_48 () Int) -(declare-fun x_172 () Int) -(declare-fun x_342 () Int) -(declare-fun x_238 () Int) -(declare-fun x_323 () Int) -(declare-fun x_608 () Int) -(declare-fun x_471 () Int) -(declare-fun x_216 () Int) -(declare-fun x_69 () Int) -(declare-fun x_438 () Int) -(declare-fun x_534 () Int) -(declare-fun x_368 () Int) -(declare-fun x_193 () Int) -(declare-fun x_532 () Int) -(declare-fun x_951 () Int) -(declare-fun x_258 () Int) -(declare-fun x_853 () Int) -(declare-fun x_132 () Int) -(declare-fun x_159 () Int) -(declare-fun x_217 () Int) -(declare-fun x_742 () Int) -(declare-fun x_311 () Int) -(declare-fun x_1403 () Int) -(declare-fun x_176 () Int) -(declare-fun x_254 () Int) -(declare-fun x_66 () Int) -(declare-fun x_144 () Int) -(declare-fun x_998 () Int) -(assert (<= 0 x_1)) -(assert (>= 1 x_1)) -(assert (<= 0 x_2)) -(assert (>= 1 x_2)) -(assert (<= 0 x_3)) -(assert (>= 1 x_3)) -(assert (<= 0 x_4)) -(assert (>= 1 x_4)) -(assert (<= 0 x_6)) -(assert (>= 1 x_6)) -(assert (<= 0 x_7)) -(assert (>= 1 x_7)) -(assert (<= 0 x_8)) -(assert (>= 1 x_8)) -(assert (<= 0 x_9)) -(assert (>= 1 x_9)) -(assert (<= 0 x_11)) -(assert (>= 1 x_11)) -(assert (<= 0 x_12)) -(assert (>= 1 x_12)) -(assert (<= 0 x_13)) -(assert (>= 1 x_13)) -(assert (<= 0 x_14)) -(assert (>= 1 x_14)) -(assert (<= 0 x_16)) -(assert (>= 1 x_16)) -(assert (<= 0 x_17)) -(assert (>= 1 x_17)) -(assert (<= 0 x_18)) -(assert (>= 1 x_18)) -(assert (<= 0 x_19)) -(assert (>= 1 x_19)) -(assert (<= 0 x_21)) -(assert (>= 1 x_21)) -(assert (<= 0 x_22)) -(assert (>= 1 x_22)) -(assert (<= 0 x_23)) -(assert (>= 1 x_23)) -(assert (<= 0 x_24)) -(assert (>= 1 x_24)) -(assert (<= 0 x_26)) -(assert (>= 1 x_26)) -(assert (<= 0 x_27)) -(assert (>= 1 x_27)) -(assert (<= 0 x_28)) -(assert (>= 1 x_28)) -(assert (<= 0 x_29)) -(assert (>= 1 x_29)) -(assert (<= 0 x_31)) -(assert (>= 1 x_31)) -(assert (<= 0 x_32)) -(assert (>= 1 x_32)) -(assert (<= 0 x_33)) -(assert (>= 1 x_33)) -(assert (<= 0 x_34)) -(assert (>= 1 x_34)) -(assert (<= 0 x_36)) -(assert (>= 1 x_36)) -(assert (<= 0 x_37)) -(assert (>= 1 x_37)) -(assert (<= 0 x_38)) -(assert (>= 1 x_38)) -(assert (<= 0 x_39)) -(assert (>= 1 x_39)) -(assert (<= 0 x_41)) -(assert (>= 1 x_41)) -(assert (<= 0 x_42)) -(assert (>= 1 x_42)) -(assert (<= 0 x_43)) -(assert (>= 1 x_43)) -(assert (<= 0 x_44)) -(assert (>= 1 x_44)) -(assert (<= 0 x_46)) -(assert (>= 1 x_46)) -(assert (<= 0 x_47)) -(assert (>= 1 x_47)) -(assert (<= 0 x_48)) -(assert (>= 1 x_48)) -(assert (<= 0 x_49)) -(assert (>= 1 x_49)) -(assert (<= 0 x_51)) -(assert (>= 1 x_51)) -(assert (<= 0 x_52)) -(assert (>= 1 x_52)) -(assert (<= 0 x_53)) -(assert (>= 1 x_53)) -(assert (<= 0 x_54)) -(assert (>= 1 x_54)) -(assert (<= 0 x_56)) -(assert (>= 1 x_56)) -(assert (<= 0 x_57)) -(assert (>= 1 x_57)) -(assert (<= 0 x_58)) -(assert (>= 1 x_58)) -(assert (<= 0 x_59)) -(assert (>= 1 x_59)) -(assert (<= 0 x_61)) -(assert (>= 1 x_61)) -(assert (<= 0 x_62)) -(assert (>= 1 x_62)) -(assert (<= 0 x_63)) -(assert (>= 1 x_63)) -(assert (<= 0 x_64)) -(assert (>= 1 x_64)) -(assert (<= 0 x_66)) -(assert (>= 1 x_66)) -(assert (<= 0 x_67)) -(assert (>= 1 x_67)) -(assert (<= 0 x_68)) -(assert (>= 1 x_68)) -(assert (<= 0 x_69)) -(assert (>= 1 x_69)) -(assert (<= 0 x_71)) -(assert (>= 1 x_71)) -(assert (<= 0 x_72)) -(assert (>= 1 x_72)) -(assert (<= 0 x_73)) -(assert (>= 1 x_73)) -(assert (<= 0 x_74)) -(assert (>= 1 x_74)) -(assert (<= 0 x_76)) -(assert (>= 1 x_76)) -(assert (<= 0 x_77)) -(assert (>= 1 x_77)) -(assert (<= 0 x_78)) -(assert (>= 1 x_78)) -(assert (<= 0 x_79)) -(assert (>= 1 x_79)) -(assert (<= 0 x_81)) -(assert (>= 1 x_81)) -(assert (<= 0 x_82)) -(assert (>= 1 x_82)) -(assert (<= 0 x_83)) -(assert (>= 1 x_83)) -(assert (<= 0 x_84)) -(assert (>= 1 x_84)) -(assert (<= 0 x_86)) -(assert (>= 1 x_86)) -(assert (<= 0 x_87)) -(assert (>= 1 x_87)) -(assert (<= 0 x_88)) -(assert (>= 1 x_88)) -(assert (<= 0 x_89)) -(assert (>= 1 x_89)) -(assert (<= 0 x_91)) -(assert (>= 1 x_91)) -(assert (<= 0 x_92)) -(assert (>= 1 x_92)) -(assert (<= 0 x_93)) -(assert (>= 1 x_93)) -(assert (<= 0 x_94)) -(assert (>= 1 x_94)) -(assert (<= 0 x_96)) -(assert (>= 1 x_96)) -(assert (<= 0 x_97)) -(assert (>= 1 x_97)) -(assert (<= 0 x_98)) -(assert (>= 1 x_98)) -(assert (<= 0 x_99)) -(assert (>= 1 x_99)) -(assert (<= 0 x_101)) -(assert (>= 1 x_101)) -(assert (<= 0 x_102)) -(assert (>= 1 x_102)) -(assert (<= 0 x_103)) -(assert (>= 1 x_103)) -(assert (<= 0 x_104)) -(assert (>= 1 x_104)) -(assert (<= 0 x_106)) -(assert (>= 1 x_106)) -(assert (<= 0 x_107)) -(assert (>= 1 x_107)) -(assert (<= 0 x_108)) -(assert (>= 1 x_108)) -(assert (<= 0 x_109)) -(assert (>= 1 x_109)) -(assert (<= 0 x_111)) -(assert (>= 1 x_111)) -(assert (<= 0 x_112)) -(assert (>= 1 x_112)) -(assert (<= 0 x_113)) -(assert (>= 1 x_113)) -(assert (<= 0 x_114)) -(assert (>= 1 x_114)) -(assert (<= 0 x_116)) -(assert (>= 1 x_116)) -(assert (<= 0 x_117)) -(assert (>= 1 x_117)) -(assert (<= 0 x_118)) -(assert (>= 1 x_118)) -(assert (<= 0 x_119)) -(assert (>= 1 x_119)) -(assert (<= 0 x_121)) -(assert (>= 1 x_121)) -(assert (<= 0 x_122)) -(assert (>= 1 x_122)) -(assert (<= 0 x_123)) -(assert (>= 1 x_123)) -(assert (<= 0 x_124)) -(assert (>= 1 x_124)) -(assert (<= 0 x_126)) -(assert (>= 1 x_126)) -(assert (<= 0 x_127)) -(assert (>= 1 x_127)) -(assert (<= 0 x_128)) -(assert (>= 1 x_128)) -(assert (<= 0 x_129)) -(assert (>= 1 x_129)) -(assert (<= 0 x_131)) -(assert (>= 1 x_131)) -(assert (<= 0 x_132)) -(assert (>= 1 x_132)) -(assert (<= 0 x_133)) -(assert (>= 1 x_133)) -(assert (<= 0 x_134)) -(assert (>= 1 x_134)) -(assert (<= 0 x_136)) -(assert (>= 1 x_136)) -(assert (<= 0 x_137)) -(assert (>= 1 x_137)) -(assert (<= 0 x_138)) -(assert (>= 1 x_138)) -(assert (<= 0 x_139)) -(assert (>= 1 x_139)) -(assert (<= 0 x_141)) -(assert (>= 1 x_141)) -(assert (<= 0 x_142)) -(assert (>= 1 x_142)) -(assert (<= 0 x_143)) -(assert (>= 1 x_143)) -(assert (<= 0 x_144)) -(assert (>= 1 x_144)) -(assert (<= 0 x_146)) -(assert (>= 1 x_146)) -(assert (<= 0 x_147)) -(assert (>= 1 x_147)) -(assert (<= 0 x_148)) -(assert (>= 1 x_148)) -(assert (<= 0 x_149)) -(assert (>= 1 x_149)) -(assert (<= 0 x_151)) -(assert (>= 1 x_151)) -(assert (<= 0 x_152)) -(assert (>= 1 x_152)) -(assert (<= 0 x_153)) -(assert (>= 1 x_153)) -(assert (<= 0 x_154)) -(assert (>= 1 x_154)) -(assert (<= 0 x_156)) -(assert (>= 1 x_156)) -(assert (<= 0 x_157)) -(assert (>= 1 x_157)) -(assert (<= 0 x_158)) -(assert (>= 1 x_158)) -(assert (<= 0 x_159)) -(assert (>= 1 x_159)) -(assert (<= 0 x_161)) -(assert (>= 1 x_161)) -(assert (<= 0 x_162)) -(assert (>= 1 x_162)) -(assert (<= 0 x_163)) -(assert (>= 1 x_163)) -(assert (<= 0 x_164)) -(assert (>= 1 x_164)) -(assert (<= 0 x_166)) -(assert (>= 1 x_166)) -(assert (<= 0 x_167)) -(assert (>= 1 x_167)) -(assert (<= 0 x_168)) -(assert (>= 1 x_168)) -(assert (<= 0 x_169)) -(assert (>= 1 x_169)) -(assert (<= 0 x_171)) -(assert (>= 1 x_171)) -(assert (<= 0 x_172)) -(assert (>= 1 x_172)) -(assert (<= 0 x_173)) -(assert (>= 1 x_173)) -(assert (<= 0 x_174)) -(assert (>= 1 x_174)) -(assert (<= 0 x_176)) -(assert (>= 1 x_176)) -(assert (<= 0 x_177)) -(assert (>= 1 x_177)) -(assert (<= 0 x_178)) -(assert (>= 1 x_178)) -(assert (<= 0 x_179)) -(assert (>= 1 x_179)) -(assert (<= 0 x_181)) -(assert (>= 1 x_181)) -(assert (<= 0 x_182)) -(assert (>= 1 x_182)) -(assert (<= 0 x_183)) -(assert (>= 1 x_183)) -(assert (<= 0 x_184)) -(assert (>= 1 x_184)) -(assert (<= 0 x_186)) -(assert (>= 1 x_186)) -(assert (<= 0 x_187)) -(assert (>= 1 x_187)) -(assert (<= 0 x_188)) -(assert (>= 1 x_188)) -(assert (<= 0 x_189)) -(assert (>= 1 x_189)) -(assert (<= 0 x_191)) -(assert (>= 1 x_191)) -(assert (<= 0 x_192)) -(assert (>= 1 x_192)) -(assert (<= 0 x_193)) -(assert (>= 1 x_193)) -(assert (<= 0 x_194)) -(assert (>= 1 x_194)) -(assert (<= 0 x_196)) -(assert (>= 1 x_196)) -(assert (<= 0 x_197)) -(assert (>= 1 x_197)) -(assert (<= 0 x_198)) -(assert (>= 1 x_198)) -(assert (<= 0 x_199)) -(assert (>= 1 x_199)) -(assert (<= 0 x_201)) -(assert (>= 1 x_201)) -(assert (<= 0 x_202)) -(assert (>= 1 x_202)) -(assert (<= 0 x_203)) -(assert (>= 1 x_203)) -(assert (<= 0 x_204)) -(assert (>= 1 x_204)) -(assert (<= 0 x_206)) -(assert (>= 1 x_206)) -(assert (<= 0 x_207)) -(assert (>= 1 x_207)) -(assert (<= 0 x_208)) -(assert (>= 1 x_208)) -(assert (<= 0 x_209)) -(assert (>= 1 x_209)) -(assert (<= 0 x_211)) -(assert (>= 1 x_211)) -(assert (<= 0 x_212)) -(assert (>= 1 x_212)) -(assert (<= 0 x_213)) -(assert (>= 1 x_213)) -(assert (<= 0 x_214)) -(assert (>= 1 x_214)) -(assert (<= 0 x_216)) -(assert (>= 1 x_216)) -(assert (<= 0 x_217)) -(assert (>= 1 x_217)) -(assert (<= 0 x_218)) -(assert (>= 1 x_218)) -(assert (<= 0 x_219)) -(assert (>= 1 x_219)) -(assert (<= 0 x_221)) -(assert (>= 1 x_221)) -(assert (<= 0 x_222)) -(assert (>= 1 x_222)) -(assert (<= 0 x_223)) -(assert (>= 1 x_223)) -(assert (<= 0 x_224)) -(assert (>= 1 x_224)) -(assert (<= 0 x_226)) -(assert (>= 1 x_226)) -(assert (<= 0 x_227)) -(assert (>= 1 x_227)) -(assert (<= 0 x_228)) -(assert (>= 1 x_228)) -(assert (<= 0 x_229)) -(assert (>= 1 x_229)) -(assert (<= 0 x_231)) -(assert (>= 1 x_231)) -(assert (<= 0 x_232)) -(assert (>= 1 x_232)) -(assert (<= 0 x_233)) -(assert (>= 1 x_233)) -(assert (<= 0 x_234)) -(assert (>= 1 x_234)) -(assert (<= 0 x_236)) -(assert (>= 1 x_236)) -(assert (<= 0 x_237)) -(assert (>= 1 x_237)) -(assert (<= 0 x_238)) -(assert (>= 1 x_238)) -(assert (<= 0 x_239)) -(assert (>= 1 x_239)) -(assert (<= 0 x_241)) -(assert (>= 1 x_241)) -(assert (<= 0 x_242)) -(assert (>= 1 x_242)) -(assert (<= 0 x_243)) -(assert (>= 1 x_243)) -(assert (<= 0 x_244)) -(assert (>= 1 x_244)) -(assert (<= 0 x_246)) -(assert (>= 1 x_246)) -(assert (<= 0 x_247)) -(assert (>= 1 x_247)) -(assert (<= 0 x_248)) -(assert (>= 1 x_248)) -(assert (<= 0 x_249)) -(assert (>= 1 x_249)) -(assert (<= 0 x_251)) -(assert (>= 1 x_251)) -(assert (<= 0 x_252)) -(assert (>= 1 x_252)) -(assert (<= 0 x_253)) -(assert (>= 1 x_253)) -(assert (<= 0 x_254)) -(assert (>= 1 x_254)) -(assert (<= 0 x_256)) -(assert (>= 1 x_256)) -(assert (<= 0 x_257)) -(assert (>= 1 x_257)) -(assert (<= 0 x_258)) -(assert (>= 1 x_258)) -(assert (<= 0 x_259)) -(assert (>= 1 x_259)) -(assert (<= 0 x_261)) -(assert (>= 1 x_261)) -(assert (<= 0 x_262)) -(assert (>= 1 x_262)) -(assert (<= 0 x_263)) -(assert (>= 1 x_263)) -(assert (<= 0 x_264)) -(assert (>= 1 x_264)) -(assert (<= 0 x_266)) -(assert (>= 1 x_266)) -(assert (<= 0 x_267)) -(assert (>= 1 x_267)) -(assert (<= 0 x_268)) -(assert (>= 1 x_268)) -(assert (<= 0 x_269)) -(assert (>= 1 x_269)) -(assert (<= 0 x_271)) -(assert (>= 1 x_271)) -(assert (<= 0 x_272)) -(assert (>= 1 x_272)) -(assert (<= 0 x_273)) -(assert (>= 1 x_273)) -(assert (<= 0 x_274)) -(assert (>= 1 x_274)) -(assert (<= 0 x_276)) -(assert (>= 1 x_276)) -(assert (<= 0 x_277)) -(assert (>= 1 x_277)) -(assert (<= 0 x_278)) -(assert (>= 1 x_278)) -(assert (<= 0 x_279)) -(assert (>= 1 x_279)) -(assert (<= 0 x_281)) -(assert (>= 1 x_281)) -(assert (<= 0 x_282)) -(assert (>= 1 x_282)) -(assert (<= 0 x_283)) -(assert (>= 1 x_283)) -(assert (<= 0 x_284)) -(assert (>= 1 x_284)) -(assert (<= 0 x_286)) -(assert (>= 1 x_286)) -(assert (<= 0 x_287)) -(assert (>= 1 x_287)) -(assert (<= 0 x_288)) -(assert (>= 1 x_288)) -(assert (<= 0 x_289)) -(assert (>= 1 x_289)) -(assert (<= 0 x_291)) -(assert (>= 1 x_291)) -(assert (<= 0 x_292)) -(assert (>= 1 x_292)) -(assert (<= 0 x_293)) -(assert (>= 1 x_293)) -(assert (<= 0 x_294)) -(assert (>= 1 x_294)) -(assert (<= 0 x_296)) -(assert (>= 1 x_296)) -(assert (<= 0 x_297)) -(assert (>= 1 x_297)) -(assert (<= 0 x_298)) -(assert (>= 1 x_298)) -(assert (<= 0 x_299)) -(assert (>= 1 x_299)) -(assert (<= 0 x_301)) -(assert (>= 1 x_301)) -(assert (<= 0 x_302)) -(assert (>= 1 x_302)) -(assert (<= 0 x_303)) -(assert (>= 1 x_303)) -(assert (<= 0 x_304)) -(assert (>= 1 x_304)) -(assert (<= 0 x_306)) -(assert (>= 1 x_306)) -(assert (<= 0 x_307)) -(assert (>= 1 x_307)) -(assert (<= 0 x_308)) -(assert (>= 1 x_308)) -(assert (<= 0 x_309)) -(assert (>= 1 x_309)) -(assert (<= 0 x_311)) -(assert (>= 1 x_311)) -(assert (<= 0 x_312)) -(assert (>= 1 x_312)) -(assert (<= 0 x_313)) -(assert (>= 1 x_313)) -(assert (<= 0 x_314)) -(assert (>= 1 x_314)) -(assert (<= 0 x_316)) -(assert (>= 1 x_316)) -(assert (<= 0 x_317)) -(assert (>= 1 x_317)) -(assert (<= 0 x_318)) -(assert (>= 1 x_318)) -(assert (<= 0 x_319)) -(assert (>= 1 x_319)) -(assert (<= 0 x_321)) -(assert (>= 1 x_321)) -(assert (<= 0 x_322)) -(assert (>= 1 x_322)) -(assert (<= 0 x_323)) -(assert (>= 1 x_323)) -(assert (<= 0 x_324)) -(assert (>= 1 x_324)) -(assert (<= 0 x_326)) -(assert (>= 1 x_326)) -(assert (<= 0 x_327)) -(assert (>= 1 x_327)) -(assert (<= 0 x_328)) -(assert (>= 1 x_328)) -(assert (<= 0 x_329)) -(assert (>= 1 x_329)) -(assert (<= 0 x_331)) -(assert (>= 1 x_331)) -(assert (<= 0 x_332)) -(assert (>= 1 x_332)) -(assert (<= 0 x_333)) -(assert (>= 1 x_333)) -(assert (<= 0 x_334)) -(assert (>= 1 x_334)) -(assert (<= 0 x_336)) -(assert (>= 1 x_336)) -(assert (<= 0 x_337)) -(assert (>= 1 x_337)) -(assert (<= 0 x_338)) -(assert (>= 1 x_338)) -(assert (<= 0 x_339)) -(assert (>= 1 x_339)) -(assert (<= 0 x_341)) -(assert (>= 1 x_341)) -(assert (<= 0 x_342)) -(assert (>= 1 x_342)) -(assert (<= 0 x_343)) -(assert (>= 1 x_343)) -(assert (<= 0 x_344)) -(assert (>= 1 x_344)) -(assert (<= 0 x_346)) -(assert (>= 1 x_346)) -(assert (<= 0 x_347)) -(assert (>= 1 x_347)) -(assert (<= 0 x_348)) -(assert (>= 1 x_348)) -(assert (<= 0 x_349)) -(assert (>= 1 x_349)) -(assert (<= 0 x_351)) -(assert (>= 1 x_351)) -(assert (<= 0 x_352)) -(assert (>= 1 x_352)) -(assert (<= 0 x_353)) -(assert (>= 1 x_353)) -(assert (<= 0 x_354)) -(assert (>= 1 x_354)) -(assert (<= 0 x_356)) -(assert (>= 1 x_356)) -(assert (<= 0 x_357)) -(assert (>= 1 x_357)) -(assert (<= 0 x_358)) -(assert (>= 1 x_358)) -(assert (<= 0 x_359)) -(assert (>= 1 x_359)) -(assert (<= 0 x_361)) -(assert (>= 1 x_361)) -(assert (<= 0 x_362)) -(assert (>= 1 x_362)) -(assert (<= 0 x_363)) -(assert (>= 1 x_363)) -(assert (<= 0 x_364)) -(assert (>= 1 x_364)) -(assert (<= 0 x_366)) -(assert (>= 1 x_366)) -(assert (<= 0 x_367)) -(assert (>= 1 x_367)) -(assert (<= 0 x_368)) -(assert (>= 1 x_368)) -(assert (<= 0 x_369)) -(assert (>= 1 x_369)) -(assert (<= 0 x_371)) -(assert (>= 1 x_371)) -(assert (<= 0 x_372)) -(assert (>= 1 x_372)) -(assert (<= 0 x_373)) -(assert (>= 1 x_373)) -(assert (<= 0 x_374)) -(assert (>= 1 x_374)) -(assert (<= 0 x_376)) -(assert (>= 1 x_376)) -(assert (<= 0 x_377)) -(assert (>= 1 x_377)) -(assert (<= 0 x_378)) -(assert (>= 1 x_378)) -(assert (<= 0 x_379)) -(assert (>= 1 x_379)) -(assert (<= 0 x_381)) -(assert (>= 1 x_381)) -(assert (<= 0 x_382)) -(assert (>= 1 x_382)) -(assert (<= 0 x_383)) -(assert (>= 1 x_383)) -(assert (<= 0 x_384)) -(assert (>= 1 x_384)) -(assert (<= 0 x_386)) -(assert (>= 1 x_386)) -(assert (<= 0 x_387)) -(assert (>= 1 x_387)) -(assert (<= 0 x_388)) -(assert (>= 1 x_388)) -(assert (<= 0 x_389)) -(assert (>= 1 x_389)) -(assert (<= 0 x_391)) -(assert (>= 1 x_391)) -(assert (<= 0 x_392)) -(assert (>= 1 x_392)) -(assert (<= 0 x_393)) -(assert (>= 1 x_393)) -(assert (<= 0 x_394)) -(assert (>= 1 x_394)) -(assert (<= 0 x_396)) -(assert (>= 1 x_396)) -(assert (<= 0 x_397)) -(assert (>= 1 x_397)) -(assert (<= 0 x_398)) -(assert (>= 1 x_398)) -(assert (<= 0 x_399)) -(assert (>= 1 x_399)) -(assert (<= 0 x_401)) -(assert (>= 1 x_401)) -(assert (<= 0 x_402)) -(assert (>= 1 x_402)) -(assert (<= 0 x_403)) -(assert (>= 1 x_403)) -(assert (<= 0 x_404)) -(assert (>= 1 x_404)) -(assert (<= 0 x_406)) -(assert (>= 1 x_406)) -(assert (<= 0 x_407)) -(assert (>= 1 x_407)) -(assert (<= 0 x_408)) -(assert (>= 1 x_408)) -(assert (<= 0 x_409)) -(assert (>= 1 x_409)) -(assert (<= 0 x_411)) -(assert (>= 1 x_411)) -(assert (<= 0 x_412)) -(assert (>= 1 x_412)) -(assert (<= 0 x_413)) -(assert (>= 1 x_413)) -(assert (<= 0 x_414)) -(assert (>= 1 x_414)) -(assert (<= 0 x_416)) -(assert (>= 1 x_416)) -(assert (<= 0 x_417)) -(assert (>= 1 x_417)) -(assert (<= 0 x_418)) -(assert (>= 1 x_418)) -(assert (<= 0 x_419)) -(assert (>= 1 x_419)) -(assert (<= 0 x_421)) -(assert (>= 1 x_421)) -(assert (<= 0 x_422)) -(assert (>= 1 x_422)) -(assert (<= 0 x_423)) -(assert (>= 1 x_423)) -(assert (<= 0 x_424)) -(assert (>= 1 x_424)) -(assert (<= 0 x_426)) -(assert (>= 1 x_426)) -(assert (<= 0 x_427)) -(assert (>= 1 x_427)) -(assert (<= 0 x_428)) -(assert (>= 1 x_428)) -(assert (<= 0 x_429)) -(assert (>= 1 x_429)) -(assert (<= 0 x_431)) -(assert (>= 1 x_431)) -(assert (<= 0 x_432)) -(assert (>= 1 x_432)) -(assert (<= 0 x_433)) -(assert (>= 1 x_433)) -(assert (<= 0 x_434)) -(assert (>= 1 x_434)) -(assert (<= 0 x_436)) -(assert (>= 1 x_436)) -(assert (<= 0 x_437)) -(assert (>= 1 x_437)) -(assert (<= 0 x_438)) -(assert (>= 1 x_438)) -(assert (<= 0 x_439)) -(assert (>= 1 x_439)) -(assert (<= 0 x_441)) -(assert (>= 1 x_441)) -(assert (<= 0 x_442)) -(assert (>= 1 x_442)) -(assert (<= 0 x_443)) -(assert (>= 1 x_443)) -(assert (<= 0 x_444)) -(assert (>= 1 x_444)) -(assert (<= 0 x_446)) -(assert (>= 1 x_446)) -(assert (<= 0 x_447)) -(assert (>= 1 x_447)) -(assert (<= 0 x_448)) -(assert (>= 1 x_448)) -(assert (<= 0 x_449)) -(assert (>= 1 x_449)) -(assert (<= 0 x_451)) -(assert (>= 1 x_451)) -(assert (<= 0 x_452)) -(assert (>= 1 x_452)) -(assert (<= 0 x_453)) -(assert (>= 1 x_453)) -(assert (<= 0 x_454)) -(assert (>= 1 x_454)) -(assert (<= 0 x_456)) -(assert (>= 1 x_456)) -(assert (<= 0 x_457)) -(assert (>= 1 x_457)) -(assert (<= 0 x_458)) -(assert (>= 1 x_458)) -(assert (<= 0 x_459)) -(assert (>= 1 x_459)) -(assert (<= 0 x_461)) -(assert (>= 1 x_461)) -(assert (<= 0 x_462)) -(assert (>= 1 x_462)) -(assert (<= 0 x_463)) -(assert (>= 1 x_463)) -(assert (<= 0 x_464)) -(assert (>= 1 x_464)) -(assert (<= 0 x_466)) -(assert (>= 1 x_466)) -(assert (<= 0 x_467)) -(assert (>= 1 x_467)) -(assert (<= 0 x_468)) -(assert (>= 1 x_468)) -(assert (<= 0 x_469)) -(assert (>= 1 x_469)) -(assert (<= 0 x_471)) -(assert (>= 1 x_471)) -(assert (<= 0 x_472)) -(assert (>= 1 x_472)) -(assert (<= 0 x_473)) -(assert (>= 1 x_473)) -(assert (<= 0 x_474)) -(assert (>= 1 x_474)) -(assert (<= 0 x_476)) -(assert (>= 1 x_476)) -(assert (<= 0 x_477)) -(assert (>= 1 x_477)) -(assert (<= 0 x_478)) -(assert (>= 1 x_478)) -(assert (<= 0 x_479)) -(assert (>= 1 x_479)) -(assert (<= 0 x_481)) -(assert (>= 1 x_481)) -(assert (<= 0 x_482)) -(assert (>= 1 x_482)) -(assert (<= 0 x_483)) -(assert (>= 1 x_483)) -(assert (<= 0 x_484)) -(assert (>= 1 x_484)) -(assert (<= 0 x_486)) -(assert (>= 1 x_486)) -(assert (<= 0 x_487)) -(assert (>= 1 x_487)) -(assert (<= 0 x_488)) -(assert (>= 1 x_488)) -(assert (<= 0 x_489)) -(assert (>= 1 x_489)) -(assert (<= 0 x_491)) -(assert (>= 1 x_491)) -(assert (<= 0 x_492)) -(assert (>= 1 x_492)) -(assert (<= 0 x_493)) -(assert (>= 1 x_493)) -(assert (<= 0 x_494)) -(assert (>= 1 x_494)) -(assert (<= 0 x_496)) -(assert (>= 1 x_496)) -(assert (<= 0 x_497)) -(assert (>= 1 x_497)) -(assert (<= 0 x_498)) -(assert (>= 1 x_498)) -(assert (<= 0 x_499)) -(assert (>= 1 x_499)) -(assert (<= 0 x_501)) -(assert (>= 1 x_501)) -(assert (<= 0 x_502)) -(assert (>= 1 x_502)) -(assert (<= 0 x_503)) -(assert (>= 1 x_503)) -(assert (<= 0 x_504)) -(assert (>= 1 x_504)) -(assert (<= 0 x_506)) -(assert (>= 1 x_506)) -(assert (<= 0 x_507)) -(assert (>= 1 x_507)) -(assert (<= 0 x_508)) -(assert (>= 1 x_508)) -(assert (<= 0 x_509)) -(assert (>= 1 x_509)) -(assert (<= 0 x_511)) -(assert (>= 1 x_511)) -(assert (<= 0 x_512)) -(assert (>= 1 x_512)) -(assert (<= 0 x_513)) -(assert (>= 1 x_513)) -(assert (<= 0 x_514)) -(assert (>= 1 x_514)) -(assert (<= 0 x_516)) -(assert (>= 1 x_516)) -(assert (<= 0 x_517)) -(assert (>= 1 x_517)) -(assert (<= 0 x_518)) -(assert (>= 1 x_518)) -(assert (<= 0 x_519)) -(assert (>= 1 x_519)) -(assert (<= 0 x_521)) -(assert (>= 1 x_521)) -(assert (<= 0 x_522)) -(assert (>= 1 x_522)) -(assert (<= 0 x_523)) -(assert (>= 1 x_523)) -(assert (<= 0 x_524)) -(assert (>= 1 x_524)) -(assert (<= 0 x_526)) -(assert (>= 1 x_526)) -(assert (<= 0 x_527)) -(assert (>= 1 x_527)) -(assert (<= 0 x_528)) -(assert (>= 1 x_528)) -(assert (<= 0 x_529)) -(assert (>= 1 x_529)) -(assert (<= 0 x_531)) -(assert (>= 1 x_531)) -(assert (<= 0 x_532)) -(assert (>= 1 x_532)) -(assert (<= 0 x_533)) -(assert (>= 1 x_533)) -(assert (<= 0 x_534)) -(assert (>= 1 x_534)) -(assert (<= 0 x_536)) -(assert (>= 1 x_536)) -(assert (<= 0 x_537)) -(assert (>= 1 x_537)) -(assert (<= 0 x_538)) -(assert (>= 1 x_538)) -(assert (<= 0 x_539)) -(assert (>= 1 x_539)) -(assert (<= 0 x_541)) -(assert (>= 1 x_541)) -(assert (<= 0 x_542)) -(assert (>= 1 x_542)) -(assert (<= 0 x_543)) -(assert (>= 1 x_543)) -(assert (<= 0 x_544)) -(assert (>= 1 x_544)) -(assert (<= 0 x_546)) -(assert (>= 1 x_546)) -(assert (<= 0 x_547)) -(assert (>= 1 x_547)) -(assert (<= 0 x_548)) -(assert (>= 1 x_548)) -(assert (<= 0 x_549)) -(assert (>= 1 x_549)) -(assert (<= 0 x_551)) -(assert (>= 1 x_551)) -(assert (<= 0 x_552)) -(assert (>= 1 x_552)) -(assert (<= 0 x_553)) -(assert (>= 1 x_553)) -(assert (<= 0 x_554)) -(assert (>= 1 x_554)) -(assert (<= 0 x_556)) -(assert (>= 1 x_556)) -(assert (<= 0 x_557)) -(assert (>= 1 x_557)) -(assert (<= 0 x_558)) -(assert (>= 1 x_558)) -(assert (<= 0 x_559)) -(assert (>= 1 x_559)) -(assert (<= 0 x_561)) -(assert (>= 1 x_561)) -(assert (<= 0 x_562)) -(assert (>= 1 x_562)) -(assert (<= 0 x_563)) -(assert (>= 1 x_563)) -(assert (<= 0 x_564)) -(assert (>= 1 x_564)) -(assert (<= 0 x_566)) -(assert (>= 1 x_566)) -(assert (<= 0 x_567)) -(assert (>= 1 x_567)) -(assert (<= 0 x_568)) -(assert (>= 1 x_568)) -(assert (<= 0 x_569)) -(assert (>= 1 x_569)) -(assert (<= 0 x_571)) -(assert (>= 1 x_571)) -(assert (<= 0 x_572)) -(assert (>= 1 x_572)) -(assert (<= 0 x_573)) -(assert (>= 1 x_573)) -(assert (<= 0 x_574)) -(assert (>= 1 x_574)) -(assert (<= 0 x_576)) -(assert (>= 1 x_576)) -(assert (<= 0 x_577)) -(assert (>= 1 x_577)) -(assert (<= 0 x_578)) -(assert (>= 1 x_578)) -(assert (<= 0 x_579)) -(assert (>= 1 x_579)) -(assert (<= 0 x_581)) -(assert (>= 1 x_581)) -(assert (<= 0 x_582)) -(assert (>= 1 x_582)) -(assert (<= 0 x_583)) -(assert (>= 1 x_583)) -(assert (<= 0 x_584)) -(assert (>= 1 x_584)) -(assert (<= 0 x_586)) -(assert (>= 1 x_586)) -(assert (<= 0 x_587)) -(assert (>= 1 x_587)) -(assert (<= 0 x_588)) -(assert (>= 1 x_588)) -(assert (<= 0 x_589)) -(assert (>= 1 x_589)) -(assert (<= 0 x_591)) -(assert (>= 1 x_591)) -(assert (<= 0 x_592)) -(assert (>= 1 x_592)) -(assert (<= 0 x_593)) -(assert (>= 1 x_593)) -(assert (<= 0 x_594)) -(assert (>= 1 x_594)) -(assert (<= 0 x_596)) -(assert (>= 1 x_596)) -(assert (<= 0 x_597)) -(assert (>= 1 x_597)) -(assert (<= 0 x_598)) -(assert (>= 1 x_598)) -(assert (<= 0 x_599)) -(assert (>= 1 x_599)) -(assert (<= 0 x_601)) -(assert (>= 1 x_601)) -(assert (<= 0 x_602)) -(assert (>= 1 x_602)) -(assert (<= 0 x_603)) -(assert (>= 1 x_603)) -(assert (<= 0 x_604)) -(assert (>= 1 x_604)) -(assert (<= 0 x_606)) -(assert (>= 1 x_606)) -(assert (<= 0 x_607)) -(assert (>= 1 x_607)) -(assert (<= 0 x_608)) -(assert (>= 1 x_608)) -(assert (<= 0 x_609)) -(assert (>= 1 x_609)) -(assert (<= 0 x_611)) -(assert (>= 1 x_611)) -(assert (<= 0 x_612)) -(assert (>= 1 x_612)) -(assert (<= 0 x_613)) -(assert (>= 1 x_613)) -(assert (<= 0 x_614)) -(assert (>= 1 x_614)) -(assert (<= 0 x_616)) -(assert (>= 1 x_616)) -(assert (<= 0 x_617)) -(assert (>= 1 x_617)) -(assert (<= 0 x_618)) -(assert (>= 1 x_618)) -(assert (<= 0 x_619)) -(assert (>= 1 x_619)) -(assert (<= 0 x_621)) -(assert (>= 1 x_621)) -(assert (<= 0 x_622)) -(assert (>= 1 x_622)) -(assert (<= 0 x_623)) -(assert (>= 1 x_623)) -(assert (<= 0 x_624)) -(assert (>= 1 x_624)) -(assert (<= 0 x_626)) -(assert (>= 1 x_626)) -(assert (<= 0 x_627)) -(assert (>= 1 x_627)) -(assert (<= 0 x_628)) -(assert (>= 1 x_628)) -(assert (<= 0 x_629)) -(assert (>= 1 x_629)) -(assert (<= 0 x_631)) -(assert (>= 1 x_631)) -(assert (<= 0 x_632)) -(assert (>= 1 x_632)) -(assert (<= 0 x_633)) -(assert (>= 1 x_633)) -(assert (<= 0 x_634)) -(assert (>= 1 x_634)) -(assert (<= 0 x_636)) -(assert (>= 1 x_636)) -(assert (<= 0 x_637)) -(assert (>= 1 x_637)) -(assert (<= 0 x_638)) -(assert (>= 1 x_638)) -(assert (<= 0 x_639)) -(assert (>= 1 x_639)) -(assert (<= 0 x_641)) -(assert (>= 1 x_641)) -(assert (<= 0 x_642)) -(assert (>= 1 x_642)) -(assert (<= 0 x_643)) -(assert (>= 1 x_643)) -(assert (<= 0 x_644)) -(assert (>= 1 x_644)) -(assert (<= 0 x_646)) -(assert (>= 1 x_646)) -(assert (<= 0 x_647)) -(assert (>= 1 x_647)) -(assert (<= 0 x_648)) -(assert (>= 1 x_648)) -(assert (<= 0 x_649)) -(assert (>= 1 x_649)) -(assert (<= 0 x_651)) -(assert (>= 1 x_651)) -(assert (<= 0 x_652)) -(assert (>= 1 x_652)) -(assert (<= 0 x_653)) -(assert (>= 1 x_653)) -(assert (<= 0 x_654)) -(assert (>= 1 x_654)) -(assert (<= 0 x_656)) -(assert (>= 1 x_656)) -(assert (<= 0 x_657)) -(assert (>= 1 x_657)) -(assert (<= 0 x_658)) -(assert (>= 1 x_658)) -(assert (<= 0 x_659)) -(assert (>= 1 x_659)) -(assert (<= 0 x_661)) -(assert (>= 1 x_661)) -(assert (<= 0 x_662)) -(assert (>= 1 x_662)) -(assert (<= 0 x_663)) -(assert (>= 1 x_663)) -(assert (<= 0 x_664)) -(assert (>= 1 x_664)) -(assert (<= 0 x_666)) -(assert (>= 1 x_666)) -(assert (<= 0 x_667)) -(assert (>= 1 x_667)) -(assert (<= 0 x_668)) -(assert (>= 1 x_668)) -(assert (<= 0 x_669)) -(assert (>= 1 x_669)) -(assert (<= 0 x_671)) -(assert (>= 1 x_671)) -(assert (<= 0 x_672)) -(assert (>= 1 x_672)) -(assert (<= 0 x_673)) -(assert (>= 1 x_673)) -(assert (<= 0 x_674)) -(assert (>= 1 x_674)) -(assert (<= 0 x_676)) -(assert (>= 1 x_676)) -(assert (<= 0 x_677)) -(assert (>= 1 x_677)) -(assert (<= 0 x_678)) -(assert (>= 1 x_678)) -(assert (<= 0 x_679)) -(assert (>= 1 x_679)) -(assert (<= 0 x_681)) -(assert (>= 1 x_681)) -(assert (<= 0 x_682)) -(assert (>= 1 x_682)) -(assert (<= 0 x_683)) -(assert (>= 1 x_683)) -(assert (<= 0 x_684)) -(assert (>= 1 x_684)) -(assert (<= 0 x_686)) -(assert (>= 1 x_686)) -(assert (<= 0 x_687)) -(assert (>= 1 x_687)) -(assert (<= 0 x_688)) -(assert (>= 1 x_688)) -(assert (<= 0 x_689)) -(assert (>= 1 x_689)) -(assert (<= 0 x_691)) -(assert (>= 1 x_691)) -(assert (<= 0 x_692)) -(assert (>= 1 x_692)) -(assert (<= 0 x_693)) -(assert (>= 1 x_693)) -(assert (<= 0 x_694)) -(assert (>= 1 x_694)) -(assert (<= 0 x_696)) -(assert (>= 1 x_696)) -(assert (<= 0 x_697)) -(assert (>= 1 x_697)) -(assert (<= 0 x_698)) -(assert (>= 1 x_698)) -(assert (<= 0 x_699)) -(assert (>= 1 x_699)) -(assert (<= 0 x_701)) -(assert (>= 1 x_701)) -(assert (<= 0 x_702)) -(assert (>= 1 x_702)) -(assert (<= 0 x_703)) -(assert (>= 1 x_703)) -(assert (<= 0 x_704)) -(assert (>= 1 x_704)) -(assert (<= 0 x_706)) -(assert (>= 1 x_706)) -(assert (<= 0 x_707)) -(assert (>= 1 x_707)) -(assert (<= 0 x_708)) -(assert (>= 1 x_708)) -(assert (<= 0 x_709)) -(assert (>= 1 x_709)) -(assert (<= 0 x_711)) -(assert (>= 1 x_711)) -(assert (<= 0 x_712)) -(assert (>= 1 x_712)) -(assert (<= 0 x_713)) -(assert (>= 1 x_713)) -(assert (<= 0 x_714)) -(assert (>= 1 x_714)) -(assert (<= 0 x_716)) -(assert (>= 1 x_716)) -(assert (<= 0 x_717)) -(assert (>= 1 x_717)) -(assert (<= 0 x_718)) -(assert (>= 1 x_718)) -(assert (<= 0 x_719)) -(assert (>= 1 x_719)) -(assert (<= 0 x_721)) -(assert (>= 1 x_721)) -(assert (<= 0 x_722)) -(assert (>= 1 x_722)) -(assert (<= 0 x_723)) -(assert (>= 1 x_723)) -(assert (<= 0 x_724)) -(assert (>= 1 x_724)) -(assert (<= 0 x_726)) -(assert (>= 1 x_726)) -(assert (<= 0 x_727)) -(assert (>= 1 x_727)) -(assert (<= 0 x_728)) -(assert (>= 1 x_728)) -(assert (<= 0 x_729)) -(assert (>= 1 x_729)) -(assert (<= 0 x_731)) -(assert (>= 1 x_731)) -(assert (<= 0 x_732)) -(assert (>= 1 x_732)) -(assert (<= 0 x_733)) -(assert (>= 1 x_733)) -(assert (<= 0 x_734)) -(assert (>= 1 x_734)) -(assert (<= 0 x_736)) -(assert (>= 1 x_736)) -(assert (<= 0 x_737)) -(assert (>= 1 x_737)) -(assert (<= 0 x_738)) -(assert (>= 1 x_738)) -(assert (<= 0 x_739)) -(assert (>= 1 x_739)) -(assert (<= 0 x_741)) -(assert (>= 1 x_741)) -(assert (<= 0 x_742)) -(assert (>= 1 x_742)) -(assert (<= 0 x_743)) -(assert (>= 1 x_743)) -(assert (<= 0 x_744)) -(assert (>= 1 x_744)) -(assert (<= 0 x_746)) -(assert (>= 1 x_746)) -(assert (<= 0 x_747)) -(assert (>= 1 x_747)) -(assert (<= 0 x_748)) -(assert (>= 1 x_748)) -(assert (<= 0 x_749)) -(assert (>= 1 x_749)) -(assert (<= 0 x_751)) -(assert (>= 1 x_751)) -(assert (<= 0 x_752)) -(assert (>= 1 x_752)) -(assert (<= 0 x_753)) -(assert (>= 1 x_753)) -(assert (<= 0 x_754)) -(assert (>= 1 x_754)) -(assert (<= 0 x_756)) -(assert (>= 1 x_756)) -(assert (<= 0 x_757)) -(assert (>= 1 x_757)) -(assert (<= 0 x_758)) -(assert (>= 1 x_758)) -(assert (<= 0 x_759)) -(assert (>= 1 x_759)) -(assert (<= 0 x_761)) -(assert (>= 1 x_761)) -(assert (<= 0 x_762)) -(assert (>= 1 x_762)) -(assert (<= 0 x_763)) -(assert (>= 1 x_763)) -(assert (<= 0 x_764)) -(assert (>= 1 x_764)) -(assert (<= 0 x_766)) -(assert (>= 1 x_766)) -(assert (<= 0 x_767)) -(assert (>= 1 x_767)) -(assert (<= 0 x_768)) -(assert (>= 1 x_768)) -(assert (<= 0 x_769)) -(assert (>= 1 x_769)) -(assert (<= 0 x_771)) -(assert (>= 1 x_771)) -(assert (<= 0 x_772)) -(assert (>= 1 x_772)) -(assert (<= 0 x_773)) -(assert (>= 1 x_773)) -(assert (<= 0 x_774)) -(assert (>= 1 x_774)) -(assert (<= 0 x_776)) -(assert (>= 1 x_776)) -(assert (<= 0 x_777)) -(assert (>= 1 x_777)) -(assert (<= 0 x_778)) -(assert (>= 1 x_778)) -(assert (<= 0 x_779)) -(assert (>= 1 x_779)) -(assert (<= 0 x_781)) -(assert (>= 1 x_781)) -(assert (<= 0 x_782)) -(assert (>= 1 x_782)) -(assert (<= 0 x_783)) -(assert (>= 1 x_783)) -(assert (<= 0 x_784)) -(assert (>= 1 x_784)) -(assert (<= 0 x_786)) -(assert (>= 1 x_786)) -(assert (<= 0 x_787)) -(assert (>= 1 x_787)) -(assert (<= 0 x_788)) -(assert (>= 1 x_788)) -(assert (<= 0 x_789)) -(assert (>= 1 x_789)) -(assert (<= 0 x_791)) -(assert (>= 1 x_791)) -(assert (<= 0 x_792)) -(assert (>= 1 x_792)) -(assert (<= 0 x_793)) -(assert (>= 1 x_793)) -(assert (<= 0 x_794)) -(assert (>= 1 x_794)) -(assert (<= 0 x_796)) -(assert (>= 1 x_796)) -(assert (<= 0 x_797)) -(assert (>= 1 x_797)) -(assert (<= 0 x_798)) -(assert (>= 1 x_798)) -(assert (<= 0 x_799)) -(assert (>= 1 x_799)) -(assert (<= 0 x_801)) -(assert (>= 1 x_801)) -(assert (<= 0 x_802)) -(assert (>= 1 x_802)) -(assert (<= 0 x_803)) -(assert (>= 1 x_803)) -(assert (<= 0 x_804)) -(assert (>= 1 x_804)) -(assert (<= 0 x_806)) -(assert (>= 1 x_806)) -(assert (<= 0 x_807)) -(assert (>= 1 x_807)) -(assert (<= 0 x_808)) -(assert (>= 1 x_808)) -(assert (<= 0 x_809)) -(assert (>= 1 x_809)) -(assert (<= 0 x_811)) -(assert (>= 1 x_811)) -(assert (<= 0 x_812)) -(assert (>= 1 x_812)) -(assert (<= 0 x_813)) -(assert (>= 1 x_813)) -(assert (<= 0 x_814)) -(assert (>= 1 x_814)) -(assert (<= 0 x_816)) -(assert (>= 1 x_816)) -(assert (<= 0 x_817)) -(assert (>= 1 x_817)) -(assert (<= 0 x_818)) -(assert (>= 1 x_818)) -(assert (<= 0 x_819)) -(assert (>= 1 x_819)) -(assert (<= 0 x_821)) -(assert (>= 1 x_821)) -(assert (<= 0 x_822)) -(assert (>= 1 x_822)) -(assert (<= 0 x_823)) -(assert (>= 1 x_823)) -(assert (<= 0 x_824)) -(assert (>= 1 x_824)) -(assert (<= 0 x_826)) -(assert (>= 1 x_826)) -(assert (<= 0 x_827)) -(assert (>= 1 x_827)) -(assert (<= 0 x_828)) -(assert (>= 1 x_828)) -(assert (<= 0 x_829)) -(assert (>= 1 x_829)) -(assert (<= 0 x_831)) -(assert (>= 1 x_831)) -(assert (<= 0 x_832)) -(assert (>= 1 x_832)) -(assert (<= 0 x_833)) -(assert (>= 1 x_833)) -(assert (<= 0 x_834)) -(assert (>= 1 x_834)) -(assert (<= 0 x_836)) -(assert (>= 1 x_836)) -(assert (<= 0 x_837)) -(assert (>= 1 x_837)) -(assert (<= 0 x_838)) -(assert (>= 1 x_838)) -(assert (<= 0 x_839)) -(assert (>= 1 x_839)) -(assert (<= 0 x_841)) -(assert (>= 1 x_841)) -(assert (<= 0 x_842)) -(assert (>= 1 x_842)) -(assert (<= 0 x_843)) -(assert (>= 1 x_843)) -(assert (<= 0 x_844)) -(assert (>= 1 x_844)) -(assert (<= 0 x_846)) -(assert (>= 1 x_846)) -(assert (<= 0 x_847)) -(assert (>= 1 x_847)) -(assert (<= 0 x_848)) -(assert (>= 1 x_848)) -(assert (<= 0 x_849)) -(assert (>= 1 x_849)) -(assert (<= 0 x_851)) -(assert (>= 1 x_851)) -(assert (<= 0 x_852)) -(assert (>= 1 x_852)) -(assert (<= 0 x_853)) -(assert (>= 1 x_853)) -(assert (<= 0 x_854)) -(assert (>= 1 x_854)) -(assert (<= 0 x_856)) -(assert (>= 1 x_856)) -(assert (<= 0 x_857)) -(assert (>= 1 x_857)) -(assert (<= 0 x_858)) -(assert (>= 1 x_858)) -(assert (<= 0 x_859)) -(assert (>= 1 x_859)) -(assert (<= 0 x_861)) -(assert (>= 1 x_861)) -(assert (<= 0 x_862)) -(assert (>= 1 x_862)) -(assert (<= 0 x_863)) -(assert (>= 1 x_863)) -(assert (<= 0 x_864)) -(assert (>= 1 x_864)) -(assert (<= 0 x_866)) -(assert (>= 1 x_866)) -(assert (<= 0 x_867)) -(assert (>= 1 x_867)) -(assert (<= 0 x_868)) -(assert (>= 1 x_868)) -(assert (<= 0 x_869)) -(assert (>= 1 x_869)) -(assert (<= 0 x_871)) -(assert (>= 1 x_871)) -(assert (<= 0 x_872)) -(assert (>= 1 x_872)) -(assert (<= 0 x_873)) -(assert (>= 1 x_873)) -(assert (<= 0 x_874)) -(assert (>= 1 x_874)) -(assert (<= 0 x_876)) -(assert (>= 1 x_876)) -(assert (<= 0 x_877)) -(assert (>= 1 x_877)) -(assert (<= 0 x_878)) -(assert (>= 1 x_878)) -(assert (<= 0 x_879)) -(assert (>= 1 x_879)) -(assert (<= 0 x_881)) -(assert (>= 1 x_881)) -(assert (<= 0 x_882)) -(assert (>= 1 x_882)) -(assert (<= 0 x_883)) -(assert (>= 1 x_883)) -(assert (<= 0 x_884)) -(assert (>= 1 x_884)) -(assert (<= 0 x_886)) -(assert (>= 1 x_886)) -(assert (<= 0 x_887)) -(assert (>= 1 x_887)) -(assert (<= 0 x_888)) -(assert (>= 1 x_888)) -(assert (<= 0 x_889)) -(assert (>= 1 x_889)) -(assert (<= 0 x_891)) -(assert (>= 1 x_891)) -(assert (<= 0 x_892)) -(assert (>= 1 x_892)) -(assert (<= 0 x_893)) -(assert (>= 1 x_893)) -(assert (<= 0 x_894)) -(assert (>= 1 x_894)) -(assert (<= 0 x_896)) -(assert (>= 1 x_896)) -(assert (<= 0 x_897)) -(assert (>= 1 x_897)) -(assert (<= 0 x_898)) -(assert (>= 1 x_898)) -(assert (<= 0 x_899)) -(assert (>= 1 x_899)) -(assert (<= 0 x_901)) -(assert (>= 1 x_901)) -(assert (<= 0 x_902)) -(assert (>= 1 x_902)) -(assert (<= 0 x_903)) -(assert (>= 1 x_903)) -(assert (<= 0 x_904)) -(assert (>= 1 x_904)) -(assert (<= 0 x_906)) -(assert (>= 1 x_906)) -(assert (<= 0 x_907)) -(assert (>= 1 x_907)) -(assert (<= 0 x_908)) -(assert (>= 1 x_908)) -(assert (<= 0 x_909)) -(assert (>= 1 x_909)) -(assert (<= 0 x_911)) -(assert (>= 1 x_911)) -(assert (<= 0 x_912)) -(assert (>= 1 x_912)) -(assert (<= 0 x_913)) -(assert (>= 1 x_913)) -(assert (<= 0 x_914)) -(assert (>= 1 x_914)) -(assert (<= 0 x_916)) -(assert (>= 1 x_916)) -(assert (<= 0 x_917)) -(assert (>= 1 x_917)) -(assert (<= 0 x_918)) -(assert (>= 1 x_918)) -(assert (<= 0 x_919)) -(assert (>= 1 x_919)) -(assert (<= 0 x_921)) -(assert (>= 1 x_921)) -(assert (<= 0 x_922)) -(assert (>= 1 x_922)) -(assert (<= 0 x_923)) -(assert (>= 1 x_923)) -(assert (<= 0 x_924)) -(assert (>= 1 x_924)) -(assert (<= 0 x_926)) -(assert (>= 1 x_926)) -(assert (<= 0 x_927)) -(assert (>= 1 x_927)) -(assert (<= 0 x_928)) -(assert (>= 1 x_928)) -(assert (<= 0 x_929)) -(assert (>= 1 x_929)) -(assert (<= 0 x_931)) -(assert (>= 1 x_931)) -(assert (<= 0 x_932)) -(assert (>= 1 x_932)) -(assert (<= 0 x_933)) -(assert (>= 1 x_933)) -(assert (<= 0 x_934)) -(assert (>= 1 x_934)) -(assert (<= 0 x_936)) -(assert (>= 1 x_936)) -(assert (<= 0 x_937)) -(assert (>= 1 x_937)) -(assert (<= 0 x_938)) -(assert (>= 1 x_938)) -(assert (<= 0 x_939)) -(assert (>= 1 x_939)) -(assert (<= 0 x_941)) -(assert (>= 1 x_941)) -(assert (<= 0 x_942)) -(assert (>= 1 x_942)) -(assert (<= 0 x_943)) -(assert (>= 1 x_943)) -(assert (<= 0 x_944)) -(assert (>= 1 x_944)) -(assert (<= 0 x_946)) -(assert (>= 1 x_946)) -(assert (<= 0 x_947)) -(assert (>= 1 x_947)) -(assert (<= 0 x_948)) -(assert (>= 1 x_948)) -(assert (<= 0 x_949)) -(assert (>= 1 x_949)) -(assert (<= 0 x_951)) -(assert (>= 1 x_951)) -(assert (<= 0 x_952)) -(assert (>= 1 x_952)) -(assert (<= 0 x_953)) -(assert (>= 1 x_953)) -(assert (<= 0 x_954)) -(assert (>= 1 x_954)) -(assert (<= 0 x_956)) -(assert (>= 1 x_956)) -(assert (<= 0 x_957)) -(assert (>= 1 x_957)) -(assert (<= 0 x_958)) -(assert (>= 1 x_958)) -(assert (<= 0 x_959)) -(assert (>= 1 x_959)) -(assert (<= 0 x_961)) -(assert (>= 1 x_961)) -(assert (<= 0 x_962)) -(assert (>= 1 x_962)) -(assert (<= 0 x_963)) -(assert (>= 1 x_963)) -(assert (<= 0 x_964)) -(assert (>= 1 x_964)) -(assert (<= 0 x_966)) -(assert (>= 1 x_966)) -(assert (<= 0 x_967)) -(assert (>= 1 x_967)) -(assert (<= 0 x_968)) -(assert (>= 1 x_968)) -(assert (<= 0 x_969)) -(assert (>= 1 x_969)) -(assert (<= 0 x_971)) -(assert (>= 1 x_971)) -(assert (<= 0 x_972)) -(assert (>= 1 x_972)) -(assert (<= 0 x_973)) -(assert (>= 1 x_973)) -(assert (<= 0 x_974)) -(assert (>= 1 x_974)) -(assert (<= 0 x_976)) -(assert (>= 1 x_976)) -(assert (<= 0 x_977)) -(assert (>= 1 x_977)) -(assert (<= 0 x_978)) -(assert (>= 1 x_978)) -(assert (<= 0 x_979)) -(assert (>= 1 x_979)) -(assert (<= 0 x_981)) -(assert (>= 1 x_981)) -(assert (<= 0 x_982)) -(assert (>= 1 x_982)) -(assert (<= 0 x_983)) -(assert (>= 1 x_983)) -(assert (<= 0 x_984)) -(assert (>= 1 x_984)) -(assert (<= 0 x_986)) -(assert (>= 1 x_986)) -(assert (<= 0 x_987)) -(assert (>= 1 x_987)) -(assert (<= 0 x_988)) -(assert (>= 1 x_988)) -(assert (<= 0 x_989)) -(assert (>= 1 x_989)) -(assert (<= 0 x_991)) -(assert (>= 1 x_991)) -(assert (<= 0 x_992)) -(assert (>= 1 x_992)) -(assert (<= 0 x_993)) -(assert (>= 1 x_993)) -(assert (<= 0 x_994)) -(assert (>= 1 x_994)) -(assert (<= 0 x_996)) -(assert (>= 1 x_996)) -(assert (<= 0 x_997)) -(assert (>= 1 x_997)) -(assert (<= 0 x_998)) -(assert (>= 1 x_998)) -(assert (<= 0 x_999)) -(assert (>= 1 x_999)) -(assert (<= 0 x_1001)) -(assert (>= 1 x_1001)) -(assert (<= 0 x_1202)) -(assert (>= 1 x_1202)) -(assert (<= 0 x_1403)) -(assert (>= 1 x_1403)) -(assert (<= 0 x_1604)) -(assert (>= 1 x_1604)) -(assert (= 1 (+ x_1 x_2 x_3 x_4))) -(assert (= 1 (+ x_6 x_7 x_8 x_9))) -(assert (= 1 (+ x_11 x_12 x_13 x_14))) -(assert (= 1 (+ x_16 x_17 x_18 x_19))) -(assert (= 1 (+ x_21 x_22 x_23 x_24))) -(assert (= 1 (+ x_26 x_27 x_28 x_29))) -(assert (= 1 (+ x_31 x_32 x_33 x_34))) -(assert (= 1 (+ x_36 x_37 x_38 x_39))) -(assert (= 1 (+ x_41 x_42 x_43 x_44))) -(assert (= 1 (+ x_46 x_47 x_48 x_49))) -(assert (= 1 (+ x_51 x_52 x_53 x_54))) -(assert (= 1 (+ x_56 x_57 x_58 x_59))) -(assert (= 1 (+ x_61 x_62 x_63 x_64))) -(assert (= 1 (+ x_66 x_67 x_68 x_69))) -(assert (= 1 (+ x_71 x_72 x_73 x_74))) -(assert (= 1 (+ x_76 x_77 x_78 x_79))) -(assert (= 1 (+ x_81 x_82 x_83 x_84))) -(assert (= 1 (+ x_86 x_87 x_88 x_89))) -(assert (= 1 (+ x_91 x_92 x_93 x_94))) -(assert (= 1 (+ x_96 x_97 x_98 x_99))) -(assert (= 1 (+ x_101 x_102 x_103 x_104))) -(assert (= 1 (+ x_106 x_107 x_108 x_109))) -(assert (= 1 (+ x_111 x_112 x_113 x_114))) -(assert (= 1 (+ x_116 x_117 x_118 x_119))) -(assert (= 1 (+ x_121 x_122 x_123 x_124))) -(assert (= 1 (+ x_126 x_127 x_128 x_129))) -(assert (= 1 (+ x_131 x_132 x_133 x_134))) -(assert (= 1 (+ x_136 x_137 x_138 x_139))) -(assert (= 1 (+ x_141 x_142 x_143 x_144))) -(assert (= 1 (+ x_146 x_147 x_148 x_149))) -(assert (= 1 (+ x_151 x_152 x_153 x_154))) -(assert (= 1 (+ x_156 x_157 x_158 x_159))) -(assert (= 1 (+ x_161 x_162 x_163 x_164))) -(assert (= 1 (+ x_166 x_167 x_168 x_169))) -(assert (= 1 (+ x_171 x_172 x_173 x_174))) -(assert (= 1 (+ x_176 x_177 x_178 x_179))) -(assert (= 1 (+ x_181 x_182 x_183 x_184))) -(assert (= 1 (+ x_186 x_187 x_188 x_189))) -(assert (= 1 (+ x_191 x_192 x_193 x_194))) -(assert (= 1 (+ x_196 x_197 x_198 x_199))) -(assert (= 1 (+ x_201 x_202 x_203 x_204))) -(assert (= 1 (+ x_206 x_207 x_208 x_209))) -(assert (= 1 (+ x_211 x_212 x_213 x_214))) -(assert (= 1 (+ x_216 x_217 x_218 x_219))) -(assert (= 1 (+ x_221 x_222 x_223 x_224))) -(assert (= 1 (+ x_226 x_227 x_228 x_229))) -(assert (= 1 (+ x_231 x_232 x_233 x_234))) -(assert (= 1 (+ x_236 x_237 x_238 x_239))) -(assert (= 1 (+ x_241 x_242 x_243 x_244))) -(assert (= 1 (+ x_246 x_247 x_248 x_249))) -(assert (= 1 (+ x_251 x_252 x_253 x_254))) -(assert (= 1 (+ x_256 x_257 x_258 x_259))) -(assert (= 1 (+ x_261 x_262 x_263 x_264))) -(assert (= 1 (+ x_266 x_267 x_268 x_269))) -(assert (= 1 (+ x_271 x_272 x_273 x_274))) -(assert (= 1 (+ x_276 x_277 x_278 x_279))) -(assert (= 1 (+ x_281 x_282 x_283 x_284))) -(assert (= 1 (+ x_286 x_287 x_288 x_289))) -(assert (= 1 (+ x_291 x_292 x_293 x_294))) -(assert (= 1 (+ x_296 x_297 x_298 x_299))) -(assert (= 1 (+ x_301 x_302 x_303 x_304))) -(assert (= 1 (+ x_306 x_307 x_308 x_309))) -(assert (= 1 (+ x_311 x_312 x_313 x_314))) -(assert (= 1 (+ x_316 x_317 x_318 x_319))) -(assert (= 1 (+ x_321 x_322 x_323 x_324))) -(assert (= 1 (+ x_326 x_327 x_328 x_329))) -(assert (= 1 (+ x_331 x_332 x_333 x_334))) -(assert (= 1 (+ x_336 x_337 x_338 x_339))) -(assert (= 1 (+ x_341 x_342 x_343 x_344))) -(assert (= 1 (+ x_346 x_347 x_348 x_349))) -(assert (= 1 (+ x_351 x_352 x_353 x_354))) -(assert (= 1 (+ x_356 x_357 x_358 x_359))) -(assert (= 1 (+ x_361 x_362 x_363 x_364))) -(assert (= 1 (+ x_366 x_367 x_368 x_369))) -(assert (= 1 (+ x_371 x_372 x_373 x_374))) -(assert (= 1 (+ x_376 x_377 x_378 x_379))) -(assert (= 1 (+ x_381 x_382 x_383 x_384))) -(assert (= 1 (+ x_386 x_387 x_388 x_389))) -(assert (= 1 (+ x_391 x_392 x_393 x_394))) -(assert (= 1 (+ x_396 x_397 x_398 x_399))) -(assert (= 1 (+ x_401 x_402 x_403 x_404))) -(assert (= 1 (+ x_406 x_407 x_408 x_409))) -(assert (= 1 (+ x_411 x_412 x_413 x_414))) -(assert (= 1 (+ x_416 x_417 x_418 x_419))) -(assert (= 1 (+ x_421 x_422 x_423 x_424))) -(assert (= 1 (+ x_426 x_427 x_428 x_429))) -(assert (= 1 (+ x_431 x_432 x_433 x_434))) -(assert (= 1 (+ x_436 x_437 x_438 x_439))) -(assert (= 1 (+ x_441 x_442 x_443 x_444))) -(assert (= 1 (+ x_446 x_447 x_448 x_449))) -(assert (= 1 (+ x_451 x_452 x_453 x_454))) -(assert (= 1 (+ x_456 x_457 x_458 x_459))) -(assert (= 1 (+ x_461 x_462 x_463 x_464))) -(assert (= 1 (+ x_466 x_467 x_468 x_469))) -(assert (= 1 (+ x_471 x_472 x_473 x_474))) -(assert (= 1 (+ x_476 x_477 x_478 x_479))) -(assert (= 1 (+ x_481 x_482 x_483 x_484))) -(assert (= 1 (+ x_486 x_487 x_488 x_489))) -(assert (= 1 (+ x_491 x_492 x_493 x_494))) -(assert (= 1 (+ x_496 x_497 x_498 x_499))) -(assert (= 1 (+ x_501 x_502 x_503 x_504))) -(assert (= 1 (+ x_506 x_507 x_508 x_509))) -(assert (= 1 (+ x_511 x_512 x_513 x_514))) -(assert (= 1 (+ x_516 x_517 x_518 x_519))) -(assert (= 1 (+ x_521 x_522 x_523 x_524))) -(assert (= 1 (+ x_526 x_527 x_528 x_529))) -(assert (= 1 (+ x_531 x_532 x_533 x_534))) -(assert (= 1 (+ x_536 x_537 x_538 x_539))) -(assert (= 1 (+ x_541 x_542 x_543 x_544))) -(assert (= 1 (+ x_546 x_547 x_548 x_549))) -(assert (= 1 (+ x_551 x_552 x_553 x_554))) -(assert (= 1 (+ x_556 x_557 x_558 x_559))) -(assert (= 1 (+ x_561 x_562 x_563 x_564))) -(assert (= 1 (+ x_566 x_567 x_568 x_569))) -(assert (= 1 (+ x_571 x_572 x_573 x_574))) -(assert (= 1 (+ x_576 x_577 x_578 x_579))) -(assert (= 1 (+ x_581 x_582 x_583 x_584))) -(assert (= 1 (+ x_586 x_587 x_588 x_589))) -(assert (= 1 (+ x_591 x_592 x_593 x_594))) -(assert (= 1 (+ x_596 x_597 x_598 x_599))) -(assert (= 1 (+ x_601 x_602 x_603 x_604))) -(assert (= 1 (+ x_606 x_607 x_608 x_609))) -(assert (= 1 (+ x_611 x_612 x_613 x_614))) -(assert (= 1 (+ x_616 x_617 x_618 x_619))) -(assert (= 1 (+ x_621 x_622 x_623 x_624))) -(assert (= 1 (+ x_626 x_627 x_628 x_629))) -(assert (= 1 (+ x_631 x_632 x_633 x_634))) -(assert (= 1 (+ x_636 x_637 x_638 x_639))) -(assert (= 1 (+ x_641 x_642 x_643 x_644))) -(assert (= 1 (+ x_646 x_647 x_648 x_649))) -(assert (= 1 (+ x_651 x_652 x_653 x_654))) -(assert (= 1 (+ x_656 x_657 x_658 x_659))) -(assert (= 1 (+ x_661 x_662 x_663 x_664))) -(assert (= 1 (+ x_666 x_667 x_668 x_669))) -(assert (= 1 (+ x_671 x_672 x_673 x_674))) -(assert (= 1 (+ x_676 x_677 x_678 x_679))) -(assert (= 1 (+ x_681 x_682 x_683 x_684))) -(assert (= 1 (+ x_686 x_687 x_688 x_689))) -(assert (= 1 (+ x_691 x_692 x_693 x_694))) -(assert (= 1 (+ x_696 x_697 x_698 x_699))) -(assert (= 1 (+ x_701 x_702 x_703 x_704))) -(assert (= 1 (+ x_706 x_707 x_708 x_709))) -(assert (= 1 (+ x_711 x_712 x_713 x_714))) -(assert (= 1 (+ x_716 x_717 x_718 x_719))) -(assert (= 1 (+ x_721 x_722 x_723 x_724))) -(assert (= 1 (+ x_726 x_727 x_728 x_729))) -(assert (= 1 (+ x_731 x_732 x_733 x_734))) -(assert (= 1 (+ x_736 x_737 x_738 x_739))) -(assert (= 1 (+ x_741 x_742 x_743 x_744))) -(assert (= 1 (+ x_746 x_747 x_748 x_749))) -(assert (= 1 (+ x_751 x_752 x_753 x_754))) -(assert (= 1 (+ x_756 x_757 x_758 x_759))) -(assert (= 1 (+ x_761 x_762 x_763 x_764))) -(assert (= 1 (+ x_766 x_767 x_768 x_769))) -(assert (= 1 (+ x_771 x_772 x_773 x_774))) -(assert (= 1 (+ x_776 x_777 x_778 x_779))) -(assert (= 1 (+ x_781 x_782 x_783 x_784))) -(assert (= 1 (+ x_786 x_787 x_788 x_789))) -(assert (= 1 (+ x_791 x_792 x_793 x_794))) -(assert (= 1 (+ x_796 x_797 x_798 x_799))) -(assert (= 1 (+ x_801 x_802 x_803 x_804))) -(assert (= 1 (+ x_806 x_807 x_808 x_809))) -(assert (= 1 (+ x_811 x_812 x_813 x_814))) -(assert (= 1 (+ x_816 x_817 x_818 x_819))) -(assert (= 1 (+ x_821 x_822 x_823 x_824))) -(assert (= 1 (+ x_826 x_827 x_828 x_829))) -(assert (= 1 (+ x_831 x_832 x_833 x_834))) -(assert (= 1 (+ x_836 x_837 x_838 x_839))) -(assert (= 1 (+ x_841 x_842 x_843 x_844))) -(assert (= 1 (+ x_846 x_847 x_848 x_849))) -(assert (= 1 (+ x_851 x_852 x_853 x_854))) -(assert (= 1 (+ x_856 x_857 x_858 x_859))) -(assert (= 1 (+ x_861 x_862 x_863 x_864))) -(assert (= 1 (+ x_866 x_867 x_868 x_869))) -(assert (= 1 (+ x_871 x_872 x_873 x_874))) -(assert (= 1 (+ x_876 x_877 x_878 x_879))) -(assert (= 1 (+ x_881 x_882 x_883 x_884))) -(assert (= 1 (+ x_886 x_887 x_888 x_889))) -(assert (= 1 (+ x_891 x_892 x_893 x_894))) -(assert (= 1 (+ x_896 x_897 x_898 x_899))) -(assert (= 1 (+ x_901 x_902 x_903 x_904))) -(assert (= 1 (+ x_906 x_907 x_908 x_909))) -(assert (= 1 (+ x_911 x_912 x_913 x_914))) -(assert (= 1 (+ x_916 x_917 x_918 x_919))) -(assert (= 1 (+ x_921 x_922 x_923 x_924))) -(assert (= 1 (+ x_926 x_927 x_928 x_929))) -(assert (= 1 (+ x_931 x_932 x_933 x_934))) -(assert (= 1 (+ x_936 x_937 x_938 x_939))) -(assert (= 1 (+ x_941 x_942 x_943 x_944))) -(assert (= 1 (+ x_946 x_947 x_948 x_949))) -(assert (= 1 (+ x_951 x_952 x_953 x_954))) -(assert (= 1 (+ x_956 x_957 x_958 x_959))) -(assert (= 1 (+ x_961 x_962 x_963 x_964))) -(assert (= 1 (+ x_966 x_967 x_968 x_969))) -(assert (= 1 (+ x_971 x_972 x_973 x_974))) -(assert (= 1 (+ x_976 x_977 x_978 x_979))) -(assert (= 1 (+ x_981 x_982 x_983 x_984))) -(assert (= 1 (+ x_986 x_987 x_988 x_989))) -(assert (= 1 (+ x_991 x_992 x_993 x_994))) -(assert (= 1 (+ x_996 x_997 x_998 x_999))) -(assert (<= 0 (+ x_1001 (* (- 1) x_4)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_9)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_14)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_19)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_24)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_29)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_34)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_39)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_44)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_49)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_54)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_59)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_64)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_69)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_74)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_79)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_84)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_89)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_94)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_99)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_104)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_109)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_114)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_119)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_124)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_129)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_134)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_139)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_144)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_149)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_154)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_159)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_164)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_169)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_174)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_179)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_184)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_189)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_194)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_199)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_204)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_209)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_214)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_219)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_224)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_229)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_234)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_239)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_244)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_249)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_254)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_259)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_264)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_269)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_274)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_279)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_284)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_289)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_294)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_299)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_304)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_309)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_314)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_319)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_324)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_329)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_334)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_339)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_344)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_349)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_354)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_359)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_364)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_369)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_374)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_379)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_384)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_389)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_394)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_399)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_404)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_409)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_414)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_419)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_424)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_429)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_434)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_439)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_444)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_449)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_454)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_459)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_464)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_469)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_474)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_479)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_484)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_489)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_494)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_499)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_504)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_509)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_514)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_519)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_524)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_529)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_534)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_539)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_544)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_549)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_554)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_559)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_564)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_569)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_574)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_579)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_584)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_589)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_594)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_599)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_604)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_609)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_614)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_619)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_624)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_629)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_634)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_639)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_644)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_649)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_654)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_659)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_664)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_669)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_674)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_679)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_684)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_689)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_694)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_699)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_704)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_709)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_714)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_719)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_724)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_729)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_734)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_739)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_744)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_749)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_754)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_759)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_764)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_769)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_774)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_779)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_784)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_789)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_794)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_799)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_804)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_809)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_814)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_819)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_824)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_829)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_834)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_839)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_844)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_849)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_854)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_859)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_864)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_869)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_874)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_879)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_884)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_889)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_894)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_899)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_904)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_909)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_914)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_919)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_924)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_929)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_934)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_939)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_944)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_949)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_954)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_959)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_964)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_969)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_974)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_979)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_984)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_989)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_994)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_999)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_1)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_6)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_11)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_16)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_21)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_26)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_31)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_36)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_41)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_46)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_51)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_56)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_61)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_66)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_71)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_76)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_81)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_86)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_91)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_96)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_101)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_106)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_111)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_116)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_121)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_126)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_131)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_136)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_141)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_146)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_151)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_156)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_161)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_166)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_171)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_176)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_181)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_186)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_191)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_196)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_201)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_206)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_211)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_216)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_221)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_226)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_231)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_236)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_241)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_246)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_251)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_256)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_261)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_266)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_271)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_276)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_281)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_286)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_291)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_296)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_301)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_306)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_311)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_316)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_321)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_326)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_331)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_336)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_341)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_346)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_351)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_356)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_361)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_366)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_371)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_376)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_381)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_386)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_391)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_396)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_401)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_406)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_411)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_416)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_421)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_426)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_431)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_436)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_441)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_446)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_451)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_456)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_461)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_466)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_471)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_476)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_481)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_486)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_491)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_496)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_501)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_506)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_511)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_516)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_521)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_526)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_531)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_536)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_541)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_546)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_551)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_556)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_561)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_566)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_571)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_576)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_581)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_586)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_591)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_596)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_601)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_606)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_611)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_616)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_621)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_626)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_631)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_636)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_641)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_646)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_651)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_656)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_661)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_666)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_671)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_676)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_681)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_686)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_691)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_696)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_701)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_706)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_711)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_716)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_721)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_726)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_731)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_736)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_741)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_746)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_751)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_756)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_761)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_766)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_771)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_776)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_781)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_786)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_791)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_796)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_801)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_806)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_811)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_816)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_821)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_826)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_831)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_836)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_841)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_846)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_851)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_856)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_861)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_866)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_871)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_876)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_881)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_886)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_891)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_896)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_901)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_906)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_911)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_916)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_921)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_926)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_931)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_936)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_941)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_946)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_951)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_956)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_961)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_966)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_971)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_976)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_981)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_986)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_991)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_996)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_2)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_7)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_12)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_17)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_22)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_27)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_32)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_37)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_42)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_47)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_52)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_57)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_62)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_67)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_72)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_77)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_82)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_87)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_92)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_97)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_102)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_107)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_112)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_117)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_122)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_127)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_132)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_137)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_142)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_147)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_152)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_157)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_162)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_167)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_172)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_177)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_182)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_187)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_192)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_197)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_202)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_207)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_212)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_217)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_222)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_227)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_232)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_237)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_242)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_247)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_252)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_257)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_262)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_267)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_272)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_277)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_282)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_287)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_292)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_297)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_302)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_307)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_312)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_317)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_322)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_327)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_332)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_337)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_342)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_347)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_352)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_357)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_362)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_367)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_372)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_377)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_382)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_387)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_392)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_397)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_402)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_407)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_412)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_417)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_422)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_427)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_432)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_437)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_442)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_447)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_452)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_457)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_462)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_467)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_472)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_477)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_482)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_487)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_492)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_497)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_502)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_507)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_512)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_517)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_522)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_527)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_532)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_537)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_542)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_547)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_552)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_557)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_562)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_567)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_572)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_577)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_582)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_587)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_592)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_597)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_602)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_607)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_612)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_617)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_622)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_627)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_632)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_637)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_642)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_647)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_652)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_657)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_662)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_667)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_672)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_677)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_682)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_687)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_692)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_697)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_702)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_707)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_712)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_717)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_722)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_727)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_732)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_737)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_742)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_747)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_752)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_757)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_762)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_767)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_772)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_777)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_782)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_787)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_792)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_797)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_802)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_807)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_812)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_817)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_822)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_827)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_832)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_837)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_842)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_847)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_852)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_857)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_862)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_867)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_872)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_877)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_882)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_887)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_892)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_897)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_902)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_907)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_912)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_917)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_922)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_927)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_932)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_937)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_942)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_947)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_952)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_957)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_962)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_967)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_972)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_977)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_982)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_987)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_992)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_997)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_3)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_8)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_13)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_18)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_23)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_28)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_33)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_38)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_43)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_48)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_53)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_58)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_63)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_68)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_73)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_78)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_83)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_88)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_93)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_98)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_103)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_108)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_113)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_118)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_123)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_128)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_133)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_138)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_143)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_148)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_153)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_158)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_163)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_168)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_173)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_178)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_183)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_188)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_193)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_198)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_203)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_208)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_213)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_218)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_223)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_228)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_233)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_238)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_243)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_248)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_253)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_258)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_263)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_268)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_273)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_278)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_283)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_288)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_293)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_298)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_303)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_308)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_313)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_318)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_323)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_328)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_333)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_338)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_343)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_348)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_353)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_358)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_363)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_368)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_373)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_378)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_383)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_388)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_393)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_398)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_403)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_408)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_413)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_418)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_423)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_428)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_433)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_438)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_443)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_448)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_453)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_458)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_463)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_468)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_473)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_478)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_483)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_488)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_493)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_498)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_503)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_508)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_513)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_518)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_523)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_528)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_533)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_538)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_543)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_548)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_553)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_558)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_563)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_568)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_573)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_578)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_583)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_588)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_593)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_598)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_603)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_608)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_613)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_618)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_623)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_628)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_633)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_638)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_643)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_648)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_653)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_658)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_663)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_668)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_673)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_678)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_683)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_688)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_693)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_698)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_703)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_708)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_713)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_718)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_723)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_728)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_733)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_738)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_743)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_748)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_753)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_758)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_763)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_768)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_773)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_778)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_783)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_788)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_793)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_798)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_803)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_808)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_813)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_818)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_823)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_828)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_833)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_838)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_843)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_848)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_853)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_858)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_863)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_868)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_873)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_878)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_883)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_888)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_893)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_898)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_903)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_908)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_913)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_918)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_923)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_928)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_933)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_938)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_943)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_948)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_953)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_958)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_963)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_968)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_973)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_978)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_983)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_988)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_993)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_998)))) -(assert (<= 0 - (+ (* 21600 x_1001) - (* (- 50) x_9) - (* (- 40) x_14) - (* (- 50) x_19) - (* (- 60) x_24) - (* (- 40) x_29) - (* (- 40) x_34) - (* (- 50) x_39) - (* (- 40) x_44) - (* (- 40) x_49) - (* (- 40) x_54) - (* (- 50) x_59) - (* (- 40) x_64) - (* (- 40) x_69) - (* (- 50) x_74) - (* (- 60) x_79) - (* (- 70) x_84) - (* (- 80) x_89) - (* (- 90) x_94) - (* (- 100) x_99) - (* (- 40) x_104) - (* (- 50) x_109) - (* (- 60) x_114) - (* (- 70) x_119) - (* (- 40) x_124) - (* (- 50) x_129) - (* (- 60) x_134) - (* (- 70) x_139) - (* (- 80) x_144) - (* (- 90) x_149) - (* (- 100) x_154) - (* (- 110) x_159) - (* (- 120) x_164) - (* (- 40) x_169) - (* (- 50) x_174) - (* (- 60) x_179) - (* (- 70) x_184) - (* (- 40) x_189) - (* (- 50) x_194) - (* (- 60) x_199) - (* (- 40) x_204) - (* (- 50) x_209) - (* (- 40) x_214) - (* (- 50) x_219) - (* (- 60) x_224) - (* (- 70) x_229) - (* (- 80) x_234) - (* (- 90) x_239) - (* (- 100) x_244) - (* (- 110) x_249) - (* (- 40) x_254) - (* (- 50) x_259) - (* (- 60) x_264) - (* (- 70) x_269) - (* (- 80) x_274) - (* (- 90) x_279) - (* (- 100) x_284) - (* (- 40) x_289) - (* (- 50) x_294) - (* (- 60) x_299) - (* (- 70) x_304) - (* (- 80) x_309) - (* (- 90) x_314) - (* (- 100) x_319) - (* (- 110) x_324) - (* (- 40) x_329) - (* (- 50) x_334) - (* (- 60) x_339) - (* (- 70) x_344) - (* (- 80) x_349) - (* (- 90) x_354) - (* (- 100) x_359) - (* (- 40) x_364) - (* (- 50) x_369) - (* (- 60) x_374) - (* (- 70) x_379) - (* (- 80) x_384) - (* (- 90) x_389) - (* (- 100) x_394) - (* (- 40) x_399) - (* (- 50) x_404) - (* (- 60) x_409) - (* (- 40) x_414) - (* (- 50) x_419) - (* (- 60) x_424) - (* (- 70) x_429) - (* (- 80) x_434) - (* (- 90) x_439) - (* (- 100) x_444) - (* (- 110) x_449) - (* (- 120) x_454) - (* (- 130) x_459) - (* (- 40) x_464) - (* (- 50) x_469) - (* (- 60) x_474) - (* (- 70) x_479) - (* (- 80) x_484) - (* (- 90) x_489) - (* (- 40) x_494) - (* (- 40) x_499) - (* (- 50) x_504) - (* (- 60) x_509) - (* (- 70) x_514) - (* (- 80) x_519) - (* (- 90) x_524) - (* (- 40) x_529) - (* (- 50) x_534) - (* (- 60) x_539) - (* (- 40) x_544) - (* (- 50) x_549) - (* (- 60) x_554) - (* (- 70) x_559) - (* (- 40) x_564) - (* (- 50) x_569) - (* (- 60) x_574) - (* (- 70) x_579) - (* (- 80) x_584) - (* (- 90) x_589) - (* (- 40) x_594) - (* (- 40) x_599) - (* (- 50) x_604) - (* (- 60) x_609) - (* (- 70) x_614) - (* (- 80) x_619) - (* (- 40) x_624) - (* (- 50) x_629) - (* (- 60) x_634) - (* (- 70) x_639) - (* (- 80) x_644) - (* (- 90) x_649) - (* (- 100) x_654) - (* (- 110) x_659) - (* (- 40) x_664) - (* (- 50) x_669) - (* (- 60) x_674) - (* (- 70) x_679) - (* (- 40) x_684) - (* (- 50) x_689) - (* (- 60) x_694) - (* (- 70) x_699) - (* (- 80) x_704) - (* (- 90) x_709) - (* (- 100) x_714) - (* (- 110) x_719) - (* (- 120) x_724) - (* (- 40) x_729) - (* (- 50) x_734) - (* (- 60) x_739) - (* (- 70) x_744) - (* (- 80) x_749) - (* (- 90) x_754) - (* (- 100) x_759) - (* (- 110) x_764) - (* (- 40) x_769) - (* (- 50) x_774) - (* (- 40) x_779) - (* (- 50) x_784) - (* (- 40) x_789) - (* (- 50) x_794) - (* (- 60) x_799) - (* (- 70) x_804) - (* (- 80) x_809) - (* (- 90) x_814) - (* (- 100) x_819) - (* (- 40) x_824) - (* (- 50) x_829) - (* (- 60) x_834) - (* (- 70) x_839) - (* (- 80) x_844) - (* (- 90) x_849) - (* (- 100) x_854) - (* (- 110) x_859) - (* (- 40) x_864) - (* (- 50) x_869) - (* (- 60) x_874) - (* (- 70) x_879) - (* (- 80) x_884) - (* (- 90) x_889) - (* (- 40) x_894) - (* (- 50) x_899) - (* (- 60) x_904) - (* (- 70) x_909) - (* (- 80) x_914) - (* (- 90) x_919) - (* (- 100) x_924) - (* (- 52) x_929) - (* (- 52) x_934) - (* (- 65) x_939) - (* (- 52) x_944) - (* (- 52) x_949) - (* (- 65) x_954) - (* (- 52) x_959) - (* (- 65) x_964) - (* (- 52) x_969) - (* (- 65) x_974) - (* (- 78) x_979) - (* (- 91) x_984) - (* (- 104) x_989) - (* (- 117) x_994) - (* (- 130) x_999) - (* (- 40) x_4)))) -(assert (<= 0 - (+ (* 7400 x_1202) - (* (- 50) x_6) - (* (- 40) x_11) - (* (- 50) x_16) - (* (- 60) x_21) - (* (- 40) x_26) - (* (- 40) x_31) - (* (- 50) x_36) - (* (- 40) x_41) - (* (- 40) x_46) - (* (- 40) x_51) - (* (- 50) x_56) - (* (- 40) x_61) - (* (- 40) x_66) - (* (- 50) x_71) - (* (- 60) x_76) - (* (- 70) x_81) - (* (- 80) x_86) - (* (- 90) x_91) - (* (- 100) x_96) - (* (- 40) x_101) - (* (- 50) x_106) - (* (- 60) x_111) - (* (- 70) x_116) - (* (- 40) x_121) - (* (- 50) x_126) - (* (- 60) x_131) - (* (- 70) x_136) - (* (- 80) x_141) - (* (- 90) x_146) - (* (- 100) x_151) - (* (- 110) x_156) - (* (- 120) x_161) - (* (- 40) x_166) - (* (- 50) x_171) - (* (- 60) x_176) - (* (- 70) x_181) - (* (- 40) x_186) - (* (- 50) x_191) - (* (- 60) x_196) - (* (- 40) x_201) - (* (- 50) x_206) - (* (- 40) x_211) - (* (- 50) x_216) - (* (- 60) x_221) - (* (- 70) x_226) - (* (- 80) x_231) - (* (- 90) x_236) - (* (- 100) x_241) - (* (- 110) x_246) - (* (- 40) x_251) - (* (- 50) x_256) - (* (- 60) x_261) - (* (- 70) x_266) - (* (- 80) x_271) - (* (- 90) x_276) - (* (- 100) x_281) - (* (- 40) x_286) - (* (- 50) x_291) - (* (- 60) x_296) - (* (- 70) x_301) - (* (- 80) x_306) - (* (- 90) x_311) - (* (- 100) x_316) - (* (- 110) x_321) - (* (- 40) x_326) - (* (- 50) x_331) - (* (- 60) x_336) - (* (- 70) x_341) - (* (- 80) x_346) - (* (- 90) x_351) - (* (- 100) x_356) - (* (- 40) x_361) - (* (- 50) x_366) - (* (- 60) x_371) - (* (- 70) x_376) - (* (- 80) x_381) - (* (- 90) x_386) - (* (- 100) x_391) - (* (- 40) x_396) - (* (- 50) x_401) - (* (- 60) x_406) - (* (- 40) x_411) - (* (- 50) x_416) - (* (- 60) x_421) - (* (- 70) x_426) - (* (- 80) x_431) - (* (- 90) x_436) - (* (- 100) x_441) - (* (- 110) x_446) - (* (- 120) x_451) - (* (- 130) x_456) - (* (- 40) x_461) - (* (- 50) x_466) - (* (- 60) x_471) - (* (- 70) x_476) - (* (- 80) x_481) - (* (- 90) x_486) - (* (- 40) x_491) - (* (- 40) x_496) - (* (- 50) x_501) - (* (- 60) x_506) - (* (- 70) x_511) - (* (- 80) x_516) - (* (- 90) x_521) - (* (- 40) x_526) - (* (- 50) x_531) - (* (- 60) x_536) - (* (- 40) x_541) - (* (- 50) x_546) - (* (- 60) x_551) - (* (- 70) x_556) - (* (- 40) x_561) - (* (- 50) x_566) - (* (- 60) x_571) - (* (- 70) x_576) - (* (- 80) x_581) - (* (- 90) x_586) - (* (- 40) x_591) - (* (- 40) x_596) - (* (- 50) x_601) - (* (- 60) x_606) - (* (- 70) x_611) - (* (- 80) x_616) - (* (- 40) x_621) - (* (- 50) x_626) - (* (- 60) x_631) - (* (- 70) x_636) - (* (- 80) x_641) - (* (- 90) x_646) - (* (- 100) x_651) - (* (- 110) x_656) - (* (- 40) x_661) - (* (- 50) x_666) - (* (- 60) x_671) - (* (- 70) x_676) - (* (- 40) x_681) - (* (- 50) x_686) - (* (- 60) x_691) - (* (- 70) x_696) - (* (- 80) x_701) - (* (- 90) x_706) - (* (- 100) x_711) - (* (- 110) x_716) - (* (- 120) x_721) - (* (- 40) x_726) - (* (- 50) x_731) - (* (- 60) x_736) - (* (- 70) x_741) - (* (- 80) x_746) - (* (- 90) x_751) - (* (- 100) x_756) - (* (- 110) x_761) - (* (- 40) x_766) - (* (- 50) x_771) - (* (- 40) x_776) - (* (- 50) x_781) - (* (- 40) x_786) - (* (- 50) x_791) - (* (- 60) x_796) - (* (- 70) x_801) - (* (- 80) x_806) - (* (- 90) x_811) - (* (- 100) x_816) - (* (- 40) x_821) - (* (- 50) x_826) - (* (- 60) x_831) - (* (- 70) x_836) - (* (- 80) x_841) - (* (- 90) x_846) - (* (- 100) x_851) - (* (- 110) x_856) - (* (- 40) x_861) - (* (- 50) x_866) - (* (- 60) x_871) - (* (- 70) x_876) - (* (- 80) x_881) - (* (- 90) x_886) - (* (- 40) x_891) - (* (- 50) x_896) - (* (- 60) x_901) - (* (- 70) x_906) - (* (- 80) x_911) - (* (- 90) x_916) - (* (- 100) x_921) - (* (- 52) x_926) - (* (- 52) x_931) - (* (- 65) x_936) - (* (- 52) x_941) - (* (- 52) x_946) - (* (- 65) x_951) - (* (- 52) x_956) - (* (- 65) x_961) - (* (- 52) x_966) - (* (- 65) x_971) - (* (- 78) x_976) - (* (- 91) x_981) - (* (- 104) x_986) - (* (- 117) x_991) - (* (- 130) x_996) - (* (- 40) x_1)))) -(assert (<= 0 - (+ (* 26500 x_1403) - (* (- 50) x_7) - (* (- 40) x_12) - (* (- 50) x_17) - (* (- 60) x_22) - (* (- 40) x_27) - (* (- 40) x_32) - (* (- 50) x_37) - (* (- 40) x_42) - (* (- 40) x_47) - (* (- 40) x_52) - (* (- 50) x_57) - (* (- 40) x_62) - (* (- 40) x_67) - (* (- 50) x_72) - (* (- 60) x_77) - (* (- 70) x_82) - (* (- 80) x_87) - (* (- 90) x_92) - (* (- 100) x_97) - (* (- 40) x_102) - (* (- 50) x_107) - (* (- 60) x_112) - (* (- 70) x_117) - (* (- 40) x_122) - (* (- 50) x_127) - (* (- 60) x_132) - (* (- 70) x_137) - (* (- 80) x_142) - (* (- 90) x_147) - (* (- 100) x_152) - (* (- 110) x_157) - (* (- 120) x_162) - (* (- 40) x_167) - (* (- 50) x_172) - (* (- 60) x_177) - (* (- 70) x_182) - (* (- 40) x_187) - (* (- 50) x_192) - (* (- 60) x_197) - (* (- 40) x_202) - (* (- 50) x_207) - (* (- 40) x_212) - (* (- 50) x_217) - (* (- 60) x_222) - (* (- 70) x_227) - (* (- 80) x_232) - (* (- 90) x_237) - (* (- 100) x_242) - (* (- 110) x_247) - (* (- 40) x_252) - (* (- 50) x_257) - (* (- 60) x_262) - (* (- 70) x_267) - (* (- 80) x_272) - (* (- 90) x_277) - (* (- 100) x_282) - (* (- 40) x_287) - (* (- 50) x_292) - (* (- 60) x_297) - (* (- 70) x_302) - (* (- 80) x_307) - (* (- 90) x_312) - (* (- 100) x_317) - (* (- 110) x_322) - (* (- 40) x_327) - (* (- 50) x_332) - (* (- 60) x_337) - (* (- 70) x_342) - (* (- 80) x_347) - (* (- 90) x_352) - (* (- 100) x_357) - (* (- 40) x_362) - (* (- 50) x_367) - (* (- 60) x_372) - (* (- 70) x_377) - (* (- 80) x_382) - (* (- 90) x_387) - (* (- 100) x_392) - (* (- 40) x_397) - (* (- 50) x_402) - (* (- 60) x_407) - (* (- 40) x_412) - (* (- 50) x_417) - (* (- 60) x_422) - (* (- 70) x_427) - (* (- 80) x_432) - (* (- 90) x_437) - (* (- 100) x_442) - (* (- 110) x_447) - (* (- 120) x_452) - (* (- 130) x_457) - (* (- 40) x_462) - (* (- 50) x_467) - (* (- 60) x_472) - (* (- 70) x_477) - (* (- 80) x_482) - (* (- 90) x_487) - (* (- 40) x_492) - (* (- 40) x_497) - (* (- 50) x_502) - (* (- 60) x_507) - (* (- 70) x_512) - (* (- 80) x_517) - (* (- 90) x_522) - (* (- 40) x_527) - (* (- 50) x_532) - (* (- 60) x_537) - (* (- 40) x_542) - (* (- 50) x_547) - (* (- 60) x_552) - (* (- 70) x_557) - (* (- 40) x_562) - (* (- 50) x_567) - (* (- 60) x_572) - (* (- 70) x_577) - (* (- 80) x_582) - (* (- 90) x_587) - (* (- 40) x_592) - (* (- 40) x_597) - (* (- 50) x_602) - (* (- 60) x_607) - (* (- 70) x_612) - (* (- 80) x_617) - (* (- 40) x_622) - (* (- 50) x_627) - (* (- 60) x_632) - (* (- 70) x_637) - (* (- 80) x_642) - (* (- 90) x_647) - (* (- 100) x_652) - (* (- 110) x_657) - (* (- 40) x_662) - (* (- 50) x_667) - (* (- 60) x_672) - (* (- 70) x_677) - (* (- 40) x_682) - (* (- 50) x_687) - (* (- 60) x_692) - (* (- 70) x_697) - (* (- 80) x_702) - (* (- 90) x_707) - (* (- 100) x_712) - (* (- 110) x_717) - (* (- 120) x_722) - (* (- 40) x_727) - (* (- 50) x_732) - (* (- 60) x_737) - (* (- 70) x_742) - (* (- 80) x_747) - (* (- 90) x_752) - (* (- 100) x_757) - (* (- 110) x_762) - (* (- 40) x_767) - (* (- 50) x_772) - (* (- 40) x_777) - (* (- 50) x_782) - (* (- 40) x_787) - (* (- 50) x_792) - (* (- 60) x_797) - (* (- 70) x_802) - (* (- 80) x_807) - (* (- 90) x_812) - (* (- 100) x_817) - (* (- 40) x_822) - (* (- 50) x_827) - (* (- 60) x_832) - (* (- 70) x_837) - (* (- 80) x_842) - (* (- 90) x_847) - (* (- 100) x_852) - (* (- 110) x_857) - (* (- 40) x_862) - (* (- 50) x_867) - (* (- 60) x_872) - (* (- 70) x_877) - (* (- 80) x_882) - (* (- 90) x_887) - (* (- 40) x_892) - (* (- 50) x_897) - (* (- 60) x_902) - (* (- 70) x_907) - (* (- 80) x_912) - (* (- 90) x_917) - (* (- 100) x_922) - (* (- 52) x_927) - (* (- 52) x_932) - (* (- 65) x_937) - (* (- 52) x_942) - (* (- 52) x_947) - (* (- 65) x_952) - (* (- 52) x_957) - (* (- 65) x_962) - (* (- 52) x_967) - (* (- 65) x_972) - (* (- 78) x_977) - (* (- 91) x_982) - (* (- 104) x_987) - (* (- 117) x_992) - (* (- 130) x_997) - (* (- 40) x_2)))) -(assert (<= 0 - (+ (* 4500 x_1604) - (* (- 50) x_8) - (* (- 40) x_13) - (* (- 50) x_18) - (* (- 60) x_23) - (* (- 40) x_28) - (* (- 40) x_33) - (* (- 50) x_38) - (* (- 40) x_43) - (* (- 40) x_48) - (* (- 40) x_53) - (* (- 50) x_58) - (* (- 40) x_63) - (* (- 40) x_68) - (* (- 50) x_73) - (* (- 60) x_78) - (* (- 70) x_83) - (* (- 80) x_88) - (* (- 90) x_93) - (* (- 100) x_98) - (* (- 40) x_103) - (* (- 50) x_108) - (* (- 60) x_113) - (* (- 70) x_118) - (* (- 40) x_123) - (* (- 50) x_128) - (* (- 60) x_133) - (* (- 70) x_138) - (* (- 80) x_143) - (* (- 90) x_148) - (* (- 100) x_153) - (* (- 110) x_158) - (* (- 120) x_163) - (* (- 40) x_168) - (* (- 50) x_173) - (* (- 60) x_178) - (* (- 70) x_183) - (* (- 40) x_188) - (* (- 50) x_193) - (* (- 60) x_198) - (* (- 40) x_203) - (* (- 50) x_208) - (* (- 40) x_213) - (* (- 50) x_218) - (* (- 60) x_223) - (* (- 70) x_228) - (* (- 80) x_233) - (* (- 90) x_238) - (* (- 100) x_243) - (* (- 110) x_248) - (* (- 40) x_253) - (* (- 50) x_258) - (* (- 60) x_263) - (* (- 70) x_268) - (* (- 80) x_273) - (* (- 90) x_278) - (* (- 100) x_283) - (* (- 40) x_288) - (* (- 50) x_293) - (* (- 60) x_298) - (* (- 70) x_303) - (* (- 80) x_308) - (* (- 90) x_313) - (* (- 100) x_318) - (* (- 110) x_323) - (* (- 40) x_328) - (* (- 50) x_333) - (* (- 60) x_338) - (* (- 70) x_343) - (* (- 80) x_348) - (* (- 90) x_353) - (* (- 100) x_358) - (* (- 40) x_363) - (* (- 50) x_368) - (* (- 60) x_373) - (* (- 70) x_378) - (* (- 80) x_383) - (* (- 90) x_388) - (* (- 100) x_393) - (* (- 40) x_398) - (* (- 50) x_403) - (* (- 60) x_408) - (* (- 40) x_413) - (* (- 50) x_418) - (* (- 60) x_423) - (* (- 70) x_428) - (* (- 80) x_433) - (* (- 90) x_438) - (* (- 100) x_443) - (* (- 110) x_448) - (* (- 120) x_453) - (* (- 130) x_458) - (* (- 40) x_463) - (* (- 50) x_468) - (* (- 60) x_473) - (* (- 70) x_478) - (* (- 80) x_483) - (* (- 90) x_488) - (* (- 40) x_493) - (* (- 40) x_498) - (* (- 50) x_503) - (* (- 60) x_508) - (* (- 70) x_513) - (* (- 80) x_518) - (* (- 90) x_523) - (* (- 40) x_528) - (* (- 50) x_533) - (* (- 60) x_538) - (* (- 40) x_543) - (* (- 50) x_548) - (* (- 60) x_553) - (* (- 70) x_558) - (* (- 40) x_563) - (* (- 50) x_568) - (* (- 60) x_573) - (* (- 70) x_578) - (* (- 80) x_583) - (* (- 90) x_588) - (* (- 40) x_593) - (* (- 40) x_598) - (* (- 50) x_603) - (* (- 60) x_608) - (* (- 70) x_613) - (* (- 80) x_618) - (* (- 40) x_623) - (* (- 50) x_628) - (* (- 60) x_633) - (* (- 70) x_638) - (* (- 80) x_643) - (* (- 90) x_648) - (* (- 100) x_653) - (* (- 110) x_658) - (* (- 40) x_663) - (* (- 50) x_668) - (* (- 60) x_673) - (* (- 70) x_678) - (* (- 40) x_683) - (* (- 50) x_688) - (* (- 60) x_693) - (* (- 70) x_698) - (* (- 80) x_703) - (* (- 90) x_708) - (* (- 100) x_713) - (* (- 110) x_718) - (* (- 120) x_723) - (* (- 40) x_728) - (* (- 50) x_733) - (* (- 60) x_738) - (* (- 70) x_743) - (* (- 80) x_748) - (* (- 90) x_753) - (* (- 100) x_758) - (* (- 110) x_763) - (* (- 40) x_768) - (* (- 50) x_773) - (* (- 40) x_778) - (* (- 50) x_783) - (* (- 40) x_788) - (* (- 50) x_793) - (* (- 60) x_798) - (* (- 70) x_803) - (* (- 80) x_808) - (* (- 90) x_813) - (* (- 100) x_818) - (* (- 40) x_823) - (* (- 50) x_828) - (* (- 60) x_833) - (* (- 70) x_838) - (* (- 80) x_843) - (* (- 90) x_848) - (* (- 100) x_853) - (* (- 110) x_858) - (* (- 40) x_863) - (* (- 50) x_868) - (* (- 60) x_873) - (* (- 70) x_878) - (* (- 80) x_883) - (* (- 90) x_888) - (* (- 40) x_893) - (* (- 50) x_898) - (* (- 60) x_903) - (* (- 70) x_908) - (* (- 80) x_913) - (* (- 90) x_918) - (* (- 100) x_923) - (* (- 52) x_928) - (* (- 52) x_933) - (* (- 65) x_938) - (* (- 52) x_943) - (* (- 52) x_948) - (* (- 65) x_953) - (* (- 52) x_958) - (* (- 65) x_963) - (* (- 52) x_968) - (* (- 65) x_973) - (* (- 78) x_978) - (* (- 91) x_983) - (* (- 104) x_988) - (* (- 117) x_993) - (* (- 130) x_998) - (* (- 40) x_3)))) -(assert (<= 0 - (+ (* 3850 x_1001) - (* (- 30) x_9) - (* (- 24) x_14) - (* (- 30) x_19) - (* (- 36) x_24) - (* (- 24) x_29) - (* (- 24) x_34) - (* (- 30) x_39) - (* (- 24) x_44) - (* (- 24) x_49) - (* (- 24) x_54) - (* (- 30) x_59) - (* (- 24) x_64) - (* (- 24) x_69) - (* (- 30) x_74) - (* (- 36) x_79) - (* (- 42) x_84) - (* (- 48) x_89) - (* (- 54) x_94) - (* (- 60) x_99) - (* (- 24) x_104) - (* (- 30) x_109) - (* (- 36) x_114) - (* (- 42) x_119) - (* (- 24) x_124) - (* (- 30) x_129) - (* (- 36) x_134) - (* (- 42) x_139) - (* (- 48) x_144) - (* (- 54) x_149) - (* (- 60) x_154) - (* (- 66) x_159) - (* (- 72) x_164) - (* (- 24) x_169) - (* (- 30) x_174) - (* (- 36) x_179) - (* (- 42) x_184) - (* (- 24) x_189) - (* (- 30) x_194) - (* (- 36) x_199) - (* (- 24) x_204) - (* (- 30) x_209) - (* (- 24) x_214) - (* (- 30) x_219) - (* (- 36) x_224) - (* (- 42) x_229) - (* (- 48) x_234) - (* (- 54) x_239) - (* (- 60) x_244) - (* (- 66) x_249) - (* (- 24) x_254) - (* (- 30) x_259) - (* (- 36) x_264) - (* (- 42) x_269) - (* (- 48) x_274) - (* (- 54) x_279) - (* (- 60) x_284) - (* (- 24) x_289) - (* (- 30) x_294) - (* (- 36) x_299) - (* (- 42) x_304) - (* (- 48) x_309) - (* (- 54) x_314) - (* (- 60) x_319) - (* (- 66) x_324) - (* (- 24) x_329) - (* (- 30) x_334) - (* (- 36) x_339) - (* (- 42) x_344) - (* (- 48) x_349) - (* (- 54) x_354) - (* (- 60) x_359) - (* (- 24) x_364) - (* (- 30) x_369) - (* (- 36) x_374) - (* (- 42) x_379) - (* (- 48) x_384) - (* (- 54) x_389) - (* (- 60) x_394) - (* (- 24) x_399) - (* (- 30) x_404) - (* (- 36) x_409) - (* (- 24) x_414) - (* (- 30) x_419) - (* (- 36) x_424) - (* (- 42) x_429) - (* (- 48) x_434) - (* (- 54) x_439) - (* (- 60) x_444) - (* (- 66) x_449) - (* (- 72) x_454) - (* (- 78) x_459) - (* (- 24) x_464) - (* (- 30) x_469) - (* (- 36) x_474) - (* (- 42) x_479) - (* (- 48) x_484) - (* (- 54) x_489) - (* (- 24) x_494) - (* (- 24) x_499) - (* (- 30) x_504) - (* (- 36) x_509) - (* (- 42) x_514) - (* (- 48) x_519) - (* (- 54) x_524) - (* (- 24) x_529) - (* (- 30) x_534) - (* (- 36) x_539) - (* (- 24) x_544) - (* (- 30) x_549) - (* (- 36) x_554) - (* (- 42) x_559) - (* (- 24) x_564) - (* (- 30) x_569) - (* (- 36) x_574) - (* (- 42) x_579) - (* (- 48) x_584) - (* (- 54) x_589) - (* (- 24) x_594) - (* (- 24) x_599) - (* (- 30) x_604) - (* (- 36) x_609) - (* (- 42) x_614) - (* (- 48) x_619) - (* (- 24) x_624) - (* (- 30) x_629) - (* (- 36) x_634) - (* (- 42) x_639) - (* (- 48) x_644) - (* (- 54) x_649) - (* (- 60) x_654) - (* (- 66) x_659) - (* (- 24) x_664) - (* (- 30) x_669) - (* (- 36) x_674) - (* (- 42) x_679) - (* (- 24) x_684) - (* (- 30) x_689) - (* (- 36) x_694) - (* (- 42) x_699) - (* (- 48) x_704) - (* (- 54) x_709) - (* (- 60) x_714) - (* (- 66) x_719) - (* (- 72) x_724) - (* (- 24) x_729) - (* (- 30) x_734) - (* (- 36) x_739) - (* (- 42) x_744) - (* (- 48) x_749) - (* (- 54) x_754) - (* (- 60) x_759) - (* (- 66) x_764) - (* (- 24) x_769) - (* (- 30) x_774) - (* (- 24) x_779) - (* (- 30) x_784) - (* (- 24) x_789) - (* (- 30) x_794) - (* (- 36) x_799) - (* (- 42) x_804) - (* (- 48) x_809) - (* (- 54) x_814) - (* (- 60) x_819) - (* (- 24) x_824) - (* (- 30) x_829) - (* (- 36) x_834) - (* (- 42) x_839) - (* (- 48) x_844) - (* (- 54) x_849) - (* (- 60) x_854) - (* (- 66) x_859) - (* (- 24) x_864) - (* (- 30) x_869) - (* (- 36) x_874) - (* (- 42) x_879) - (* (- 48) x_884) - (* (- 54) x_889) - (* (- 24) x_894) - (* (- 30) x_899) - (* (- 36) x_904) - (* (- 42) x_909) - (* (- 48) x_914) - (* (- 54) x_919) - (* (- 60) x_924) - (* (- 36) x_929) - (* (- 36) x_934) - (* (- 45) x_939) - (* (- 36) x_944) - (* (- 36) x_949) - (* (- 45) x_954) - (* (- 36) x_959) - (* (- 45) x_964) - (* (- 36) x_969) - (* (- 45) x_974) - (* (- 54) x_979) - (* (- 63) x_984) - (* (- 72) x_989) - (* (- 81) x_994) - (* (- 90) x_999) - (* (- 24) x_4)))) -(assert (<= 0 - (+ (* 3000 x_1202) - (* (- 30) x_6) - (* (- 24) x_11) - (* (- 30) x_16) - (* (- 36) x_21) - (* (- 24) x_26) - (* (- 24) x_31) - (* (- 30) x_36) - (* (- 24) x_41) - (* (- 24) x_46) - (* (- 24) x_51) - (* (- 30) x_56) - (* (- 24) x_61) - (* (- 24) x_66) - (* (- 30) x_71) - (* (- 36) x_76) - (* (- 42) x_81) - (* (- 48) x_86) - (* (- 54) x_91) - (* (- 60) x_96) - (* (- 24) x_101) - (* (- 30) x_106) - (* (- 36) x_111) - (* (- 42) x_116) - (* (- 24) x_121) - (* (- 30) x_126) - (* (- 36) x_131) - (* (- 42) x_136) - (* (- 48) x_141) - (* (- 54) x_146) - (* (- 60) x_151) - (* (- 66) x_156) - (* (- 72) x_161) - (* (- 24) x_166) - (* (- 30) x_171) - (* (- 36) x_176) - (* (- 42) x_181) - (* (- 24) x_186) - (* (- 30) x_191) - (* (- 36) x_196) - (* (- 24) x_201) - (* (- 30) x_206) - (* (- 24) x_211) - (* (- 30) x_216) - (* (- 36) x_221) - (* (- 42) x_226) - (* (- 48) x_231) - (* (- 54) x_236) - (* (- 60) x_241) - (* (- 66) x_246) - (* (- 24) x_251) - (* (- 30) x_256) - (* (- 36) x_261) - (* (- 42) x_266) - (* (- 48) x_271) - (* (- 54) x_276) - (* (- 60) x_281) - (* (- 24) x_286) - (* (- 30) x_291) - (* (- 36) x_296) - (* (- 42) x_301) - (* (- 48) x_306) - (* (- 54) x_311) - (* (- 60) x_316) - (* (- 66) x_321) - (* (- 24) x_326) - (* (- 30) x_331) - (* (- 36) x_336) - (* (- 42) x_341) - (* (- 48) x_346) - (* (- 54) x_351) - (* (- 60) x_356) - (* (- 24) x_361) - (* (- 30) x_366) - (* (- 36) x_371) - (* (- 42) x_376) - (* (- 48) x_381) - (* (- 54) x_386) - (* (- 60) x_391) - (* (- 24) x_396) - (* (- 30) x_401) - (* (- 36) x_406) - (* (- 24) x_411) - (* (- 30) x_416) - (* (- 36) x_421) - (* (- 42) x_426) - (* (- 48) x_431) - (* (- 54) x_436) - (* (- 60) x_441) - (* (- 66) x_446) - (* (- 72) x_451) - (* (- 78) x_456) - (* (- 24) x_461) - (* (- 30) x_466) - (* (- 36) x_471) - (* (- 42) x_476) - (* (- 48) x_481) - (* (- 54) x_486) - (* (- 24) x_491) - (* (- 24) x_496) - (* (- 30) x_501) - (* (- 36) x_506) - (* (- 42) x_511) - (* (- 48) x_516) - (* (- 54) x_521) - (* (- 24) x_526) - (* (- 30) x_531) - (* (- 36) x_536) - (* (- 24) x_541) - (* (- 30) x_546) - (* (- 36) x_551) - (* (- 42) x_556) - (* (- 24) x_561) - (* (- 30) x_566) - (* (- 36) x_571) - (* (- 42) x_576) - (* (- 48) x_581) - (* (- 54) x_586) - (* (- 24) x_591) - (* (- 24) x_596) - (* (- 30) x_601) - (* (- 36) x_606) - (* (- 42) x_611) - (* (- 48) x_616) - (* (- 24) x_621) - (* (- 30) x_626) - (* (- 36) x_631) - (* (- 42) x_636) - (* (- 48) x_641) - (* (- 54) x_646) - (* (- 60) x_651) - (* (- 66) x_656) - (* (- 24) x_661) - (* (- 30) x_666) - (* (- 36) x_671) - (* (- 42) x_676) - (* (- 24) x_681) - (* (- 30) x_686) - (* (- 36) x_691) - (* (- 42) x_696) - (* (- 48) x_701) - (* (- 54) x_706) - (* (- 60) x_711) - (* (- 66) x_716) - (* (- 72) x_721) - (* (- 24) x_726) - (* (- 30) x_731) - (* (- 36) x_736) - (* (- 42) x_741) - (* (- 48) x_746) - (* (- 54) x_751) - (* (- 60) x_756) - (* (- 66) x_761) - (* (- 24) x_766) - (* (- 30) x_771) - (* (- 24) x_776) - (* (- 30) x_781) - (* (- 24) x_786) - (* (- 30) x_791) - (* (- 36) x_796) - (* (- 42) x_801) - (* (- 48) x_806) - (* (- 54) x_811) - (* (- 60) x_816) - (* (- 24) x_821) - (* (- 30) x_826) - (* (- 36) x_831) - (* (- 42) x_836) - (* (- 48) x_841) - (* (- 54) x_846) - (* (- 60) x_851) - (* (- 66) x_856) - (* (- 24) x_861) - (* (- 30) x_866) - (* (- 36) x_871) - (* (- 42) x_876) - (* (- 48) x_881) - (* (- 54) x_886) - (* (- 24) x_891) - (* (- 30) x_896) - (* (- 36) x_901) - (* (- 42) x_906) - (* (- 48) x_911) - (* (- 54) x_916) - (* (- 60) x_921) - (* (- 36) x_926) - (* (- 36) x_931) - (* (- 45) x_936) - (* (- 36) x_941) - (* (- 36) x_946) - (* (- 45) x_951) - (* (- 36) x_956) - (* (- 45) x_961) - (* (- 36) x_966) - (* (- 45) x_971) - (* (- 54) x_976) - (* (- 63) x_981) - (* (- 72) x_986) - (* (- 81) x_991) - (* (- 90) x_996) - (* (- 24) x_1)))) -(assert (<= 0 - (+ (* 7700 x_1403) - (* (- 30) x_7) - (* (- 24) x_12) - (* (- 30) x_17) - (* (- 36) x_22) - (* (- 24) x_27) - (* (- 24) x_32) - (* (- 30) x_37) - (* (- 24) x_42) - (* (- 24) x_47) - (* (- 24) x_52) - (* (- 30) x_57) - (* (- 24) x_62) - (* (- 24) x_67) - (* (- 30) x_72) - (* (- 36) x_77) - (* (- 42) x_82) - (* (- 48) x_87) - (* (- 54) x_92) - (* (- 60) x_97) - (* (- 24) x_102) - (* (- 30) x_107) - (* (- 36) x_112) - (* (- 42) x_117) - (* (- 24) x_122) - (* (- 30) x_127) - (* (- 36) x_132) - (* (- 42) x_137) - (* (- 48) x_142) - (* (- 54) x_147) - (* (- 60) x_152) - (* (- 66) x_157) - (* (- 72) x_162) - (* (- 24) x_167) - (* (- 30) x_172) - (* (- 36) x_177) - (* (- 42) x_182) - (* (- 24) x_187) - (* (- 30) x_192) - (* (- 36) x_197) - (* (- 24) x_202) - (* (- 30) x_207) - (* (- 24) x_212) - (* (- 30) x_217) - (* (- 36) x_222) - (* (- 42) x_227) - (* (- 48) x_232) - (* (- 54) x_237) - (* (- 60) x_242) - (* (- 66) x_247) - (* (- 24) x_252) - (* (- 30) x_257) - (* (- 36) x_262) - (* (- 42) x_267) - (* (- 48) x_272) - (* (- 54) x_277) - (* (- 60) x_282) - (* (- 24) x_287) - (* (- 30) x_292) - (* (- 36) x_297) - (* (- 42) x_302) - (* (- 48) x_307) - (* (- 54) x_312) - (* (- 60) x_317) - (* (- 66) x_322) - (* (- 24) x_327) - (* (- 30) x_332) - (* (- 36) x_337) - (* (- 42) x_342) - (* (- 48) x_347) - (* (- 54) x_352) - (* (- 60) x_357) - (* (- 24) x_362) - (* (- 30) x_367) - (* (- 36) x_372) - (* (- 42) x_377) - (* (- 48) x_382) - (* (- 54) x_387) - (* (- 60) x_392) - (* (- 24) x_397) - (* (- 30) x_402) - (* (- 36) x_407) - (* (- 24) x_412) - (* (- 30) x_417) - (* (- 36) x_422) - (* (- 42) x_427) - (* (- 48) x_432) - (* (- 54) x_437) - (* (- 60) x_442) - (* (- 66) x_447) - (* (- 72) x_452) - (* (- 78) x_457) - (* (- 24) x_462) - (* (- 30) x_467) - (* (- 36) x_472) - (* (- 42) x_477) - (* (- 48) x_482) - (* (- 54) x_487) - (* (- 24) x_492) - (* (- 24) x_497) - (* (- 30) x_502) - (* (- 36) x_507) - (* (- 42) x_512) - (* (- 48) x_517) - (* (- 54) x_522) - (* (- 24) x_527) - (* (- 30) x_532) - (* (- 36) x_537) - (* (- 24) x_542) - (* (- 30) x_547) - (* (- 36) x_552) - (* (- 42) x_557) - (* (- 24) x_562) - (* (- 30) x_567) - (* (- 36) x_572) - (* (- 42) x_577) - (* (- 48) x_582) - (* (- 54) x_587) - (* (- 24) x_592) - (* (- 24) x_597) - (* (- 30) x_602) - (* (- 36) x_607) - (* (- 42) x_612) - (* (- 48) x_617) - (* (- 24) x_622) - (* (- 30) x_627) - (* (- 36) x_632) - (* (- 42) x_637) - (* (- 48) x_642) - (* (- 54) x_647) - (* (- 60) x_652) - (* (- 66) x_657) - (* (- 24) x_662) - (* (- 30) x_667) - (* (- 36) x_672) - (* (- 42) x_677) - (* (- 24) x_682) - (* (- 30) x_687) - (* (- 36) x_692) - (* (- 42) x_697) - (* (- 48) x_702) - (* (- 54) x_707) - (* (- 60) x_712) - (* (- 66) x_717) - (* (- 72) x_722) - (* (- 24) x_727) - (* (- 30) x_732) - (* (- 36) x_737) - (* (- 42) x_742) - (* (- 48) x_747) - (* (- 54) x_752) - (* (- 60) x_757) - (* (- 66) x_762) - (* (- 24) x_767) - (* (- 30) x_772) - (* (- 24) x_777) - (* (- 30) x_782) - (* (- 24) x_787) - (* (- 30) x_792) - (* (- 36) x_797) - (* (- 42) x_802) - (* (- 48) x_807) - (* (- 54) x_812) - (* (- 60) x_817) - (* (- 24) x_822) - (* (- 30) x_827) - (* (- 36) x_832) - (* (- 42) x_837) - (* (- 48) x_842) - (* (- 54) x_847) - (* (- 60) x_852) - (* (- 66) x_857) - (* (- 24) x_862) - (* (- 30) x_867) - (* (- 36) x_872) - (* (- 42) x_877) - (* (- 48) x_882) - (* (- 54) x_887) - (* (- 24) x_892) - (* (- 30) x_897) - (* (- 36) x_902) - (* (- 42) x_907) - (* (- 48) x_912) - (* (- 54) x_917) - (* (- 60) x_922) - (* (- 36) x_927) - (* (- 36) x_932) - (* (- 45) x_937) - (* (- 36) x_942) - (* (- 36) x_947) - (* (- 45) x_952) - (* (- 36) x_957) - (* (- 45) x_962) - (* (- 36) x_967) - (* (- 45) x_972) - (* (- 54) x_977) - (* (- 63) x_982) - (* (- 72) x_987) - (* (- 81) x_992) - (* (- 90) x_997) - (* (- 24) x_2)))) -(assert (<= 0 - (+ (* 3960 x_1604) - (* (- 30) x_8) - (* (- 24) x_13) - (* (- 30) x_18) - (* (- 36) x_23) - (* (- 24) x_28) - (* (- 24) x_33) - (* (- 30) x_38) - (* (- 24) x_43) - (* (- 24) x_48) - (* (- 24) x_53) - (* (- 30) x_58) - (* (- 24) x_63) - (* (- 24) x_68) - (* (- 30) x_73) - (* (- 36) x_78) - (* (- 42) x_83) - (* (- 48) x_88) - (* (- 54) x_93) - (* (- 60) x_98) - (* (- 24) x_103) - (* (- 30) x_108) - (* (- 36) x_113) - (* (- 42) x_118) - (* (- 24) x_123) - (* (- 30) x_128) - (* (- 36) x_133) - (* (- 42) x_138) - (* (- 48) x_143) - (* (- 54) x_148) - (* (- 60) x_153) - (* (- 66) x_158) - (* (- 72) x_163) - (* (- 24) x_168) - (* (- 30) x_173) - (* (- 36) x_178) - (* (- 42) x_183) - (* (- 24) x_188) - (* (- 30) x_193) - (* (- 36) x_198) - (* (- 24) x_203) - (* (- 30) x_208) - (* (- 24) x_213) - (* (- 30) x_218) - (* (- 36) x_223) - (* (- 42) x_228) - (* (- 48) x_233) - (* (- 54) x_238) - (* (- 60) x_243) - (* (- 66) x_248) - (* (- 24) x_253) - (* (- 30) x_258) - (* (- 36) x_263) - (* (- 42) x_268) - (* (- 48) x_273) - (* (- 54) x_278) - (* (- 60) x_283) - (* (- 24) x_288) - (* (- 30) x_293) - (* (- 36) x_298) - (* (- 42) x_303) - (* (- 48) x_308) - (* (- 54) x_313) - (* (- 60) x_318) - (* (- 66) x_323) - (* (- 24) x_328) - (* (- 30) x_333) - (* (- 36) x_338) - (* (- 42) x_343) - (* (- 48) x_348) - (* (- 54) x_353) - (* (- 60) x_358) - (* (- 24) x_363) - (* (- 30) x_368) - (* (- 36) x_373) - (* (- 42) x_378) - (* (- 48) x_383) - (* (- 54) x_388) - (* (- 60) x_393) - (* (- 24) x_398) - (* (- 30) x_403) - (* (- 36) x_408) - (* (- 24) x_413) - (* (- 30) x_418) - (* (- 36) x_423) - (* (- 42) x_428) - (* (- 48) x_433) - (* (- 54) x_438) - (* (- 60) x_443) - (* (- 66) x_448) - (* (- 72) x_453) - (* (- 78) x_458) - (* (- 24) x_463) - (* (- 30) x_468) - (* (- 36) x_473) - (* (- 42) x_478) - (* (- 48) x_483) - (* (- 54) x_488) - (* (- 24) x_493) - (* (- 24) x_498) - (* (- 30) x_503) - (* (- 36) x_508) - (* (- 42) x_513) - (* (- 48) x_518) - (* (- 54) x_523) - (* (- 24) x_528) - (* (- 30) x_533) - (* (- 36) x_538) - (* (- 24) x_543) - (* (- 30) x_548) - (* (- 36) x_553) - (* (- 42) x_558) - (* (- 24) x_563) - (* (- 30) x_568) - (* (- 36) x_573) - (* (- 42) x_578) - (* (- 48) x_583) - (* (- 54) x_588) - (* (- 24) x_593) - (* (- 24) x_598) - (* (- 30) x_603) - (* (- 36) x_608) - (* (- 42) x_613) - (* (- 48) x_618) - (* (- 24) x_623) - (* (- 30) x_628) - (* (- 36) x_633) - (* (- 42) x_638) - (* (- 48) x_643) - (* (- 54) x_648) - (* (- 60) x_653) - (* (- 66) x_658) - (* (- 24) x_663) - (* (- 30) x_668) - (* (- 36) x_673) - (* (- 42) x_678) - (* (- 24) x_683) - (* (- 30) x_688) - (* (- 36) x_693) - (* (- 42) x_698) - (* (- 48) x_703) - (* (- 54) x_708) - (* (- 60) x_713) - (* (- 66) x_718) - (* (- 72) x_723) - (* (- 24) x_728) - (* (- 30) x_733) - (* (- 36) x_738) - (* (- 42) x_743) - (* (- 48) x_748) - (* (- 54) x_753) - (* (- 60) x_758) - (* (- 66) x_763) - (* (- 24) x_768) - (* (- 30) x_773) - (* (- 24) x_778) - (* (- 30) x_783) - (* (- 24) x_788) - (* (- 30) x_793) - (* (- 36) x_798) - (* (- 42) x_803) - (* (- 48) x_808) - (* (- 54) x_813) - (* (- 60) x_818) - (* (- 24) x_823) - (* (- 30) x_828) - (* (- 36) x_833) - (* (- 42) x_838) - (* (- 48) x_843) - (* (- 54) x_848) - (* (- 60) x_853) - (* (- 66) x_858) - (* (- 24) x_863) - (* (- 30) x_868) - (* (- 36) x_873) - (* (- 42) x_878) - (* (- 48) x_883) - (* (- 54) x_888) - (* (- 24) x_893) - (* (- 30) x_898) - (* (- 36) x_903) - (* (- 42) x_908) - (* (- 48) x_913) - (* (- 54) x_918) - (* (- 60) x_923) - (* (- 36) x_928) - (* (- 36) x_933) - (* (- 45) x_938) - (* (- 36) x_943) - (* (- 36) x_948) - (* (- 45) x_953) - (* (- 36) x_958) - (* (- 45) x_963) - (* (- 36) x_968) - (* (- 45) x_973) - (* (- 54) x_978) - (* (- 63) x_983) - (* (- 72) x_988) - (* (- 81) x_993) - (* (- 90) x_998) - (* (- 24) x_3)))) - -(assert (= x_1202 1)) -(assert (= x_1403 1)) -(assert (= x_1604 0)) -(assert (= x_1001 0)) - -;(minimize (+ x_1202 x_1403 x_1604 x_1001)) -(minimize (+ (* 2 x_1) - (* 3 x_2) - (* 4 x_3) - x_9 - (* 2 x_6) - (* 3 x_7) - (* 4 x_8) - x_14 - (* 2 x_11) - (* 3 x_12) - (* 4 x_13) - x_19 - (* 2 x_16) - (* 3 x_17) - (* 4 x_18) - x_24 - (* 2 x_21) - (* 3 x_22) - (* 4 x_23) - x_29 - (* 2 x_26) - (* 3 x_27) - (* 4 x_28) - x_34 - (* 2 x_31) - (* 3 x_32) - (* 4 x_33) - x_39 - (* 2 x_36) - (* 3 x_37) - (* 4 x_38) - x_44 - (* 2 x_41) - (* 3 x_42) - (* 4 x_43) - x_49 - (* 2 x_46) - (* 3 x_47) - (* 4 x_48) - x_54 - (* 2 x_51) - (* 3 x_52) - (* 4 x_53) - x_59 - (* 2 x_56) - (* 3 x_57) - (* 4 x_58) - x_64 - (* 2 x_61) - (* 3 x_62) - (* 4 x_63) - x_69 - (* 2 x_66) - (* 3 x_67) - (* 4 x_68) - x_74 - (* 2 x_71) - (* 3 x_72) - (* 4 x_73) - x_79 - (* 2 x_76) - (* 3 x_77) - (* 4 x_78) - x_84 - (* 2 x_81) - (* 3 x_82) - (* 4 x_83) - x_89 - (* 2 x_86) - (* 3 x_87) - (* 4 x_88) - x_94 - (* 2 x_91) - (* 3 x_92) - (* 4 x_93) - x_99 - (* 2 x_96) - (* 3 x_97) - (* 4 x_98) - x_104 - (* 2 x_101) - (* 3 x_102) - (* 4 x_103) - x_109 - (* 2 x_106) - (* 3 x_107) - (* 4 x_108) - x_114 - (* 2 x_111) - (* 3 x_112) - (* 4 x_113) - x_119 - (* 2 x_116) - (* 3 x_117) - (* 4 x_118) - x_124 - (* 2 x_121) - (* 3 x_122) - (* 4 x_123) - x_129 - (* 2 x_126) - (* 3 x_127) - (* 4 x_128) - x_134 - (* 2 x_131) - (* 3 x_132) - (* 4 x_133) - x_139 - (* 2 x_136) - (* 3 x_137) - (* 4 x_138) - x_144 - (* 2 x_141) - (* 3 x_142) - (* 4 x_143) - x_149 - (* 2 x_146) - (* 3 x_147) - (* 4 x_148) - x_154 - (* 2 x_151) - (* 3 x_152) - (* 4 x_153) - x_159 - (* 2 x_156) - (* 3 x_157) - (* 4 x_158) - x_164 - (* 2 x_161) - (* 3 x_162) - (* 4 x_163) - x_169 - (* 2 x_166) - (* 3 x_167) - (* 4 x_168) - x_174 - (* 2 x_171) - (* 3 x_172) - (* 4 x_173) - x_179 - (* 2 x_176) - (* 3 x_177) - (* 4 x_178) - x_184 - (* 2 x_181) - (* 3 x_182) - (* 4 x_183) - x_189 - (* 2 x_186) - (* 3 x_187) - (* 4 x_188) - x_194 - (* 2 x_191) - (* 3 x_192) - (* 4 x_193) - x_199 - (* 2 x_196) - (* 3 x_197) - (* 4 x_198) - x_204 - (* 2 x_201) - (* 3 x_202) - (* 4 x_203) - x_209 - (* 2 x_206) - (* 3 x_207) - (* 4 x_208) - x_214 - (* 2 x_211) - (* 3 x_212) - (* 4 x_213) - x_219 - (* 2 x_216) - (* 3 x_217) - (* 4 x_218) - x_224 - (* 2 x_221) - (* 3 x_222) - (* 4 x_223) - x_229 - (* 2 x_226) - (* 3 x_227) - (* 4 x_228) - x_234 - (* 2 x_231) - (* 3 x_232) - (* 4 x_233) - x_239 - (* 2 x_236) - (* 3 x_237) - (* 4 x_238) - x_244 - (* 2 x_241) - (* 3 x_242) - (* 4 x_243) - x_249 - (* 2 x_246) - (* 3 x_247) - (* 4 x_248) - x_254 - (* 2 x_251) - (* 3 x_252) - (* 4 x_253) - x_259 - (* 2 x_256) - (* 3 x_257) - (* 4 x_258) - x_264 - (* 2 x_261) - (* 3 x_262) - (* 4 x_263) - x_269 - (* 2 x_266) - (* 3 x_267) - (* 4 x_268) - x_274 - (* 2 x_271) - (* 3 x_272) - (* 4 x_273) - x_279 - (* 2 x_276) - (* 3 x_277) - (* 4 x_278) - x_284 - (* 2 x_281) - (* 3 x_282) - (* 4 x_283) - x_289 - (* 2 x_286) - (* 3 x_287) - (* 4 x_288) - x_294 - (* 2 x_291) - (* 3 x_292) - (* 4 x_293) - x_299 - (* 2 x_296) - (* 3 x_297) - (* 4 x_298) - x_304 - (* 2 x_301) - (* 3 x_302) - (* 4 x_303) - x_309 - (* 2 x_306) - (* 3 x_307) - (* 4 x_308) - x_314 - (* 2 x_311) - (* 3 x_312) - (* 4 x_313) - x_319 - (* 2 x_316) - (* 3 x_317) - (* 4 x_318) - x_324 - (* 2 x_321) - (* 3 x_322) - (* 4 x_323) - x_329 - (* 2 x_326) - (* 3 x_327) - (* 4 x_328) - x_334 - (* 2 x_331) - (* 3 x_332) - (* 4 x_333) - x_339 - (* 2 x_336) - (* 3 x_337) - (* 4 x_338) - x_344 - (* 2 x_341) - (* 3 x_342) - (* 4 x_343) - x_349 - (* 2 x_346) - (* 3 x_347) - (* 4 x_348) - x_354 - (* 2 x_351) - (* 3 x_352) - (* 4 x_353) - x_359 - (* 2 x_356) - (* 3 x_357) - (* 4 x_358) - x_364 - (* 2 x_361) - (* 3 x_362) - (* 4 x_363) - x_369 - (* 2 x_366) - (* 3 x_367) - (* 4 x_368) - x_374 - (* 2 x_371) - (* 3 x_372) - (* 4 x_373) - x_379 - (* 2 x_376) - (* 3 x_377) - (* 4 x_378) - x_384 - (* 2 x_381) - (* 3 x_382) - (* 4 x_383) - x_389 - (* 2 x_386) - (* 3 x_387) - (* 4 x_388) - x_394 - (* 2 x_391) - (* 3 x_392) - (* 4 x_393) - x_399 - (* 2 x_396) - (* 3 x_397) - (* 4 x_398) - x_404 - (* 2 x_401) - (* 3 x_402) - (* 4 x_403) - x_409 - (* 2 x_406) - (* 3 x_407) - (* 4 x_408) - x_414 - (* 2 x_411) - (* 3 x_412) - (* 4 x_413) - x_419 - (* 2 x_416) - (* 3 x_417) - (* 4 x_418) - x_424 - (* 2 x_421) - (* 3 x_422) - (* 4 x_423) - x_429 - (* 2 x_426) - (* 3 x_427) - (* 4 x_428) - x_434 - (* 2 x_431) - (* 3 x_432) - (* 4 x_433) - x_439 - (* 2 x_436) - (* 3 x_437) - (* 4 x_438) - x_444 - (* 2 x_441) - (* 3 x_442) - (* 4 x_443) - x_449 - (* 2 x_446) - (* 3 x_447) - (* 4 x_448) - x_454 - (* 2 x_451) - (* 3 x_452) - (* 4 x_453) - x_459 - (* 2 x_456) - (* 3 x_457) - (* 4 x_458) - x_464 - (* 2 x_461) - (* 3 x_462) - (* 4 x_463) - x_469 - (* 2 x_466) - (* 3 x_467) - (* 4 x_468) - x_474 - (* 2 x_471) - (* 3 x_472) - (* 4 x_473) - x_479 - (* 2 x_476) - (* 3 x_477) - (* 4 x_478) - x_484 - (* 2 x_481) - (* 3 x_482) - (* 4 x_483) - x_489 - (* 2 x_486) - (* 3 x_487) - (* 4 x_488) - x_494 - (* 2 x_491) - (* 3 x_492) - (* 4 x_493) - x_499 - (* 2 x_496) - (* 3 x_497) - (* 4 x_498) - x_504 - (* 2 x_501) - (* 3 x_502) - (* 4 x_503) - x_509 - (* 2 x_506) - (* 3 x_507) - (* 4 x_508) - x_514 - (* 2 x_511) - (* 3 x_512) - (* 4 x_513) - x_519 - (* 2 x_516) - (* 3 x_517) - (* 4 x_518) - x_524 - (* 2 x_521) - (* 3 x_522) - (* 4 x_523) - x_529 - (* 2 x_526) - (* 3 x_527) - (* 4 x_528) - x_534 - (* 2 x_531) - (* 3 x_532) - (* 4 x_533) - x_539 - (* 2 x_536) - (* 3 x_537) - (* 4 x_538) - x_544 - (* 2 x_541) - (* 3 x_542) - (* 4 x_543) - x_549 - (* 2 x_546) - (* 3 x_547) - (* 4 x_548) - x_554 - (* 2 x_551) - (* 3 x_552) - (* 4 x_553) - x_559 - (* 2 x_556) - (* 3 x_557) - (* 4 x_558) - x_564 - (* 2 x_561) - (* 3 x_562) - (* 4 x_563) - x_569 - (* 2 x_566) - (* 3 x_567) - (* 4 x_568) - x_574 - (* 2 x_571) - (* 3 x_572) - (* 4 x_573) - x_579 - (* 2 x_576) - (* 3 x_577) - (* 4 x_578) - x_584 - (* 2 x_581) - (* 3 x_582) - (* 4 x_583) - x_589 - (* 2 x_586) - (* 3 x_587) - (* 4 x_588) - x_594 - (* 2 x_591) - (* 3 x_592) - (* 4 x_593) - x_599 - (* 2 x_596) - (* 3 x_597) - (* 4 x_598) - x_604 - (* 2 x_601) - (* 3 x_602) - (* 4 x_603) - x_609 - (* 2 x_606) - (* 3 x_607) - (* 4 x_608) - x_614 - (* 2 x_611) - (* 3 x_612) - (* 4 x_613) - x_619 - (* 2 x_616) - (* 3 x_617) - (* 4 x_618) - x_624 - (* 2 x_621) - (* 3 x_622) - (* 4 x_623) - x_629 - (* 2 x_626) - (* 3 x_627) - (* 4 x_628) - x_634 - (* 2 x_631) - (* 3 x_632) - (* 4 x_633) - x_639 - (* 2 x_636) - (* 3 x_637) - (* 4 x_638) - x_644 - (* 2 x_641) - (* 3 x_642) - (* 4 x_643) - x_649 - (* 2 x_646) - (* 3 x_647) - (* 4 x_648) - x_654 - (* 2 x_651) - (* 3 x_652) - (* 4 x_653) - x_659 - (* 2 x_656) - (* 3 x_657) - (* 4 x_658) - x_664 - (* 2 x_661) - (* 3 x_662) - (* 4 x_663) - x_669 - (* 2 x_666) - (* 3 x_667) - (* 4 x_668) - x_674 - (* 2 x_671) - (* 3 x_672) - (* 4 x_673) - x_679 - (* 2 x_676) - (* 3 x_677) - (* 4 x_678) - x_684 - (* 2 x_681) - (* 3 x_682) - (* 4 x_683) - x_689 - (* 2 x_686) - (* 3 x_687) - (* 4 x_688) - x_694 - (* 2 x_691) - (* 3 x_692) - (* 4 x_693) - x_699 - (* 2 x_696) - (* 3 x_697) - (* 4 x_698) - x_704 - (* 2 x_701) - (* 3 x_702) - (* 4 x_703) - x_709 - (* 2 x_706) - (* 3 x_707) - (* 4 x_708) - x_714 - (* 2 x_711) - (* 3 x_712) - (* 4 x_713) - x_719 - (* 2 x_716) - (* 3 x_717) - (* 4 x_718) - x_724 - (* 2 x_721) - (* 3 x_722) - (* 4 x_723) - x_729 - (* 2 x_726) - (* 3 x_727) - (* 4 x_728) - x_734 - (* 2 x_731) - (* 3 x_732) - (* 4 x_733) - x_739 - (* 2 x_736) - (* 3 x_737) - (* 4 x_738) - x_744 - (* 2 x_741) - (* 3 x_742) - (* 4 x_743) - x_749 - (* 2 x_746) - (* 3 x_747) - (* 4 x_748) - x_754 - (* 2 x_751) - (* 3 x_752) - (* 4 x_753) - x_759 - (* 2 x_756) - (* 3 x_757) - (* 4 x_758) - x_764 - (* 2 x_761) - (* 3 x_762) - (* 4 x_763) - x_769 - (* 2 x_766) - (* 3 x_767) - (* 4 x_768) - x_774 - (* 2 x_771) - (* 3 x_772) - (* 4 x_773) - x_779 - (* 2 x_776) - (* 3 x_777) - (* 4 x_778) - x_784 - (* 2 x_781) - (* 3 x_782) - (* 4 x_783) - x_789 - (* 2 x_786) - (* 3 x_787) - (* 4 x_788) - x_794 - (* 2 x_791) - (* 3 x_792) - (* 4 x_793) - x_799 - (* 2 x_796) - (* 3 x_797) - (* 4 x_798) - x_804 - (* 2 x_801) - (* 3 x_802) - (* 4 x_803) - x_809 - (* 2 x_806) - (* 3 x_807) - (* 4 x_808) - x_814 - (* 2 x_811) - (* 3 x_812) - (* 4 x_813) - x_819 - (* 2 x_816) - (* 3 x_817) - (* 4 x_818) - x_824 - (* 2 x_821) - (* 3 x_822) - (* 4 x_823) - x_829 - (* 2 x_826) - (* 3 x_827) - (* 4 x_828) - x_834 - (* 2 x_831) - (* 3 x_832) - (* 4 x_833) - x_839 - (* 2 x_836) - (* 3 x_837) - (* 4 x_838) - x_844 - (* 2 x_841) - (* 3 x_842) - (* 4 x_843) - x_849 - (* 2 x_846) - (* 3 x_847) - (* 4 x_848) - x_854 - (* 2 x_851) - (* 3 x_852) - (* 4 x_853) - x_859 - (* 2 x_856) - (* 3 x_857) - (* 4 x_858) - x_864 - (* 2 x_861) - (* 3 x_862) - (* 4 x_863) - x_869 - (* 2 x_866) - (* 3 x_867) - (* 4 x_868) - x_874 - (* 2 x_871) - (* 3 x_872) - (* 4 x_873) - x_879 - (* 2 x_876) - (* 3 x_877) - (* 4 x_878) - x_884 - (* 2 x_881) - (* 3 x_882) - (* 4 x_883) - x_889 - (* 2 x_886) - (* 3 x_887) - (* 4 x_888) - x_894 - (* 2 x_891) - (* 3 x_892) - (* 4 x_893) - x_899 - (* 2 x_896) - (* 3 x_897) - (* 4 x_898) - x_904 - (* 2 x_901) - (* 3 x_902) - (* 4 x_903) - x_909 - (* 2 x_906) - (* 3 x_907) - (* 4 x_908) - x_914 - (* 2 x_911) - (* 3 x_912) - (* 4 x_913) - x_919 - (* 2 x_916) - (* 3 x_917) - (* 4 x_918) - x_924 - (* 2 x_921) - (* 3 x_922) - (* 4 x_923) - x_929 - (* 2 x_926) - (* 3 x_927) - (* 4 x_928) - x_934 - (* 2 x_931) - (* 3 x_932) - (* 4 x_933) - x_939 - (* 2 x_936) - (* 3 x_937) - (* 4 x_938) - x_944 - (* 2 x_941) - (* 3 x_942) - (* 4 x_943) - x_949 - (* 2 x_946) - (* 3 x_947) - (* 4 x_948) - x_954 - (* 2 x_951) - (* 3 x_952) - (* 4 x_953) - x_959 - (* 2 x_956) - (* 3 x_957) - (* 4 x_958) - x_964 - (* 2 x_961) - (* 3 x_962) - (* 4 x_963) - x_969 - (* 2 x_966) - (* 3 x_967) - (* 4 x_968) - x_974 - (* 2 x_971) - (* 3 x_972) - (* 4 x_973) - x_979 - (* 2 x_976) - (* 3 x_977) - (* 4 x_978) - x_984 - (* 2 x_981) - (* 3 x_982) - (* 4 x_983) - x_989 - (* 2 x_986) - (* 3 x_987) - (* 4 x_988) - x_994 - (* 2 x_991) - (* 3 x_992) - (* 4 x_993) - x_999 - (* 2 x_996) - (* 3 x_997) - (* 4 x_998) - x_4 - (* 100 x_1202) - (* 100 x_1403) - (* 100 x_1604) - (* 100 x_1001))) -(optimize :print_statistics true - :wmaxsat_engine bvsls - :maxsat_engine weighted_maxsat) diff --git a/tests/wmax1.smt2 b/tests/wmax1.smt2 deleted file mode 100644 index 602309e95..000000000 --- a/tests/wmax1.smt2 +++ /dev/null @@ -1,5842 +0,0 @@ -(declare-fun x_354 () Int) -(declare-fun x_522 () Int) -(declare-fun x_464 () Int) -(declare-fun x_644 () Int) -(declare-fun x_174 () Int) -(declare-fun x_397 () Int) -(declare-fun x_432 () Int) -(declare-fun x_557 () Int) -(declare-fun x_926 () Int) -(declare-fun x_582 () Int) -(declare-fun x_779 () Int) -(declare-fun x_759 () Int) -(declare-fun x_912 () Int) -(declare-fun x_868 () Int) -(declare-fun x_384 () Int) -(declare-fun x_963 () Int) -(declare-fun x_658 () Int) -(declare-fun x_362 () Int) -(declare-fun x_984 () Int) -(declare-fun x_308 () Int) -(declare-fun x_456 () Int) -(declare-fun x_17 () Int) -(declare-fun x_816 () Int) -(declare-fun x_833 () Int) -(declare-fun x_463 () Int) -(declare-fun x_211 () Int) -(declare-fun x_607 () Int) -(declare-fun x_139 () Int) -(declare-fun x_124 () Int) -(declare-fun x_291 () Int) -(declare-fun x_859 () Int) -(declare-fun x_888 () Int) -(declare-fun x_31 () Int) -(declare-fun x_472 () Int) -(declare-fun x_434 () Int) -(declare-fun x_154 () Int) -(declare-fun x_347 () Int) -(declare-fun x_88 () Int) -(declare-fun x_769 () Int) -(declare-fun x_986 () Int) -(declare-fun x_8 () Int) -(declare-fun x_196 () Int) -(declare-fun x_882 () Int) -(declare-fun x_711 () Int) -(declare-fun x_167 () Int) -(declare-fun x_119 () Int) -(declare-fun x_4 () Int) -(declare-fun x_33 () Int) -(declare-fun x_178 () Int) -(declare-fun x_893 () Int) -(declare-fun x_429 () Int) -(declare-fun x_527 () Int) -(declare-fun x_194 () Int) -(declare-fun x_498 () Int) -(declare-fun x_346 () Int) -(declare-fun x_712 () Int) -(declare-fun x_691 () Int) -(declare-fun x_294 () Int) -(declare-fun x_402 () Int) -(declare-fun x_213 () Int) -(declare-fun x_239 () Int) -(declare-fun x_297 () Int) -(declare-fun x_427 () Int) -(declare-fun x_489 () Int) -(declare-fun x_841 () Int) -(declare-fun x_186 () Int) -(declare-fun x_149 () Int) -(declare-fun x_586 () Int) -(declare-fun x_932 () Int) -(declare-fun x_367 () Int) -(declare-fun x_77 () Int) -(declare-fun x_123 () Int) -(declare-fun x_884 () Int) -(declare-fun x_989 () Int) -(declare-fun x_242 () Int) -(declare-fun x_614 () Int) -(declare-fun x_381 () Int) -(declare-fun x_388 () Int) -(declare-fun x_306 () Int) -(declare-fun x_737 () Int) -(declare-fun x_277 () Int) -(declare-fun x_966 () Int) -(declare-fun x_67 () Int) -(declare-fun x_678 () Int) -(declare-fun x_87 () Int) -(declare-fun x_496 () Int) -(declare-fun x_919 () Int) -(declare-fun x_439 () Int) -(declare-fun x_854 () Int) -(declare-fun x_961 () Int) -(declare-fun x_697 () Int) -(declare-fun x_19 () Int) -(declare-fun x_818 () Int) -(declare-fun x_158 () Int) -(declare-fun x_26 () Int) -(declare-fun x_436 () Int) -(declare-fun x_798 () Int) -(declare-fun x_457 () Int) -(declare-fun x_838 () Int) -(declare-fun x_953 () Int) -(declare-fun x_524 () Int) -(declare-fun x_574 () Int) -(declare-fun x_212 () Int) -(declare-fun x_486 () Int) -(declare-fun x_3 () Int) -(declare-fun x_256 () Int) -(declare-fun x_22 () Int) -(declare-fun x_676 () Int) -(declare-fun x_789 () Int) -(declare-fun x_892 () Int) -(declare-fun x_682 () Int) -(declare-fun x_84 () Int) -(declare-fun x_819 () Int) -(declare-fun x_454 () Int) -(declare-fun x_59 () Int) -(declare-fun x_227 () Int) -(declare-fun x_572 () Int) -(declare-fun x_914 () Int) -(declare-fun x_39 () Int) -(declare-fun x_679 () Int) -(declare-fun x_824 () Int) -(declare-fun x_684 () Int) -(declare-fun x_221 () Int) -(declare-fun x_274 () Int) -(declare-fun x_32 () Int) -(declare-fun x_348 () Int) -(declare-fun x_877 () Int) -(declare-fun x_701 () Int) -(declare-fun x_231 () Int) -(declare-fun x_549 () Int) -(declare-fun x_889 () Int) -(declare-fun x_879 () Int) -(declare-fun x_662 () Int) -(declare-fun x_302 () Int) -(declare-fun x_979 () Int) -(declare-fun x_861 () Int) -(declare-fun x_973 () Int) -(declare-fun x_401 () Int) -(declare-fun x_537 () Int) -(declare-fun x_972 () Int) -(declare-fun x_269 () Int) -(declare-fun x_957 () Int) -(declare-fun x_271 () Int) -(declare-fun x_363 () Int) -(declare-fun x_181 () Int) -(declare-fun x_357 () Int) -(declare-fun x_591 () Int) -(declare-fun x_559 () Int) -(declare-fun x_51 () Int) -(declare-fun x_916 () Int) -(declare-fun x_389 () Int) -(declare-fun x_512 () Int) -(declare-fun x_988 () Int) -(declare-fun x_667 () Int) -(declare-fun x_511 () Int) -(declare-fun x_733 () Int) -(declare-fun x_821 () Int) -(declare-fun x_671 () Int) -(declare-fun x_707 () Int) -(declare-fun x_826 () Int) -(declare-fun x_319 () Int) -(declare-fun x_399 () Int) -(declare-fun x_852 () Int) -(declare-fun x_442 () Int) -(declare-fun x_108 () Int) -(declare-fun x_392 () Int) -(declare-fun x_776 () Int) -(declare-fun x_993 () Int) -(declare-fun x_459 () Int) -(declare-fun x_913 () Int) -(declare-fun x_107 () Int) -(declare-fun x_994 () Int) -(declare-fun x_61 () Int) -(declare-fun x_802 () Int) -(declare-fun x_677 () Int) -(declare-fun x_857 () Int) -(declare-fun x_706 () Int) -(declare-fun x_278 () Int) -(declare-fun x_443 () Int) -(declare-fun x_813 () Int) -(declare-fun x_971 () Int) -(declare-fun x_173 () Int) -(declare-fun x_91 () Int) -(declare-fun x_396 () Int) -(declare-fun x_551 () Int) -(declare-fun x_846 () Int) -(declare-fun x_417 () Int) -(declare-fun x_54 () Int) -(declare-fun x_721 () Int) -(declare-fun x_331 () Int) -(declare-fun x_467 () Int) -(declare-fun x_553 () Int) -(declare-fun x_959 () Int) -(declare-fun x_871 () Int) -(declare-fun x_692 () Int) -(declare-fun x_792 () Int) -(declare-fun x_593 () Int) -(declare-fun x_412 () Int) -(declare-fun x_531 () Int) -(declare-fun x_352 () Int) -(declare-fun x_333 () Int) -(declare-fun x_596 () Int) -(declare-fun x_229 () Int) -(declare-fun x_447 () Int) -(declare-fun x_53 () Int) -(declare-fun x_548 () Int) -(declare-fun x_43 () Int) -(declare-fun x_13 () Int) -(declare-fun x_198 () Int) -(declare-fun x_47 () Int) -(declare-fun x_626 () Int) -(declare-fun x_648 () Int) -(declare-fun x_902 () Int) -(declare-fun x_594 () Int) -(declare-fun x_113 () Int) -(declare-fun x_286 () Int) -(declare-fun x_163 () Int) -(declare-fun x_157 () Int) -(declare-fun x_659 () Int) -(declare-fun x_24 () Int) -(declare-fun x_631 () Int) -(declare-fun x_699 () Int) -(declare-fun x_366 () Int) -(declare-fun x_6 () Int) -(declare-fun x_156 () Int) -(declare-fun x_876 () Int) -(declare-fun x_598 () Int) -(declare-fun x_974 () Int) -(declare-fun x_372 () Int) -(declare-fun x_538 () Int) -(declare-fun x_287 () Int) -(declare-fun x_71 () Int) -(declare-fun x_371 () Int) -(declare-fun x_646 () Int) -(declare-fun x_519 () Int) -(declare-fun x_121 () Int) -(declare-fun x_268 () Int) -(declare-fun x_746 () Int) -(declare-fun x_562 () Int) -(declare-fun x_799 () Int) -(declare-fun x_423 () Int) -(declare-fun x_808 () Int) -(declare-fun x_303 () Int) -(declare-fun x_536 () Int) -(declare-fun x_344 () Int) -(declare-fun x_322 () Int) -(declare-fun x_299 () Int) -(declare-fun x_976 () Int) -(declare-fun x_279 () Int) -(declare-fun x_482 () Int) -(declare-fun x_246 () Int) -(declare-fun x_763 () Int) -(declare-fun x_111 () Int) -(declare-fun x_226 () Int) -(declare-fun x_741 () Int) -(declare-fun x_188 () Int) -(declare-fun x_873 () Int) -(declare-fun x_767 () Int) -(declare-fun x_766 () Int) -(declare-fun x_7 () Int) -(declare-fun x_377 () Int) -(declare-fun x_719 () Int) -(declare-fun x_704 () Int) -(declare-fun x_72 () Int) -(declare-fun x_27 () Int) -(declare-fun x_284 () Int) -(declare-fun x_943 () Int) -(declare-fun x_42 () Int) -(declare-fun x_881 () Int) -(declare-fun x_693 () Int) -(declare-fun x_422 () Int) -(declare-fun x_218 () Int) -(declare-fun x_736 () Int) -(declare-fun x_817 () Int) -(declare-fun x_168 () Int) -(declare-fun x_359 () Int) -(declare-fun x_16 () Int) -(declare-fun x_469 () Int) -(declare-fun x_814 () Int) -(declare-fun x_62 () Int) -(declare-fun x_461 () Int) -(declare-fun x_483 () Int) -(declare-fun x_68 () Int) -(declare-fun x_786 () Int) -(declare-fun x_938 () Int) -(declare-fun x_204 () Int) -(declare-fun x_718 () Int) -(declare-fun x_197 () Int) -(declare-fun x_603 () Int) -(declare-fun x_616 () Int) -(declare-fun x_117 () Int) -(declare-fun x_567 () Int) -(declare-fun x_729 () Int) -(declare-fun x_942 () Int) -(declare-fun x_748 () Int) -(declare-fun x_992 () Int) -(declare-fun x_713 () Int) -(declare-fun x_326 () Int) -(declare-fun x_689 () Int) -(declare-fun x_948 () Int) -(declare-fun x_717 () Int) -(declare-fun x_403 () Int) -(declare-fun x_872 () Int) -(declare-fun x_73 () Int) -(declare-fun x_639 () Int) -(declare-fun x_137 () Int) -(declare-fun x_373 () Int) -(declare-fun x_364 () Int) -(declare-fun x_576 () Int) -(declare-fun x_358 () Int) -(declare-fun x_466 () Int) -(declare-fun x_122 () Int) -(declare-fun x_637 () Int) -(declare-fun x_202 () Int) -(declare-fun x_476 () Int) -(declare-fun x_44 () Int) -(declare-fun x_151 () Int) -(declare-fun x_253 () Int) -(declare-fun x_696 () Int) -(declare-fun x_822 () Int) -(declare-fun x_641 () Int) -(declare-fun x_924 () Int) -(declare-fun x_233 () Int) -(declare-fun x_136 () Int) -(declare-fun x_222 () Int) -(declare-fun x_318 () Int) -(declare-fun x_694 () Int) -(declare-fun x_543 () Int) -(declare-fun x_141 () Int) -(declare-fun x_418 () Int) -(declare-fun x_409 () Int) -(declare-fun x_601 () Int) -(declare-fun x_339 () Int) -(declare-fun x_958 () Int) -(declare-fun x_773 () Int) -(declare-fun x_448 () Int) -(declare-fun x_508 () Int) -(declare-fun x_104 () Int) -(declare-fun x_674 () Int) -(declare-fun x_991 () Int) -(declare-fun x_406 () Int) -(declare-fun x_283 () Int) -(declare-fun x_552 () Int) -(declare-fun x_907 () Int) -(declare-fun x_408 () Int) -(declare-fun x_451 () Int) -(declare-fun x_897 () Int) -(declare-fun x_503 () Int) -(declare-fun x_672 () Int) -(declare-fun x_264 () Int) -(declare-fun x_382 () Int) -(declare-fun x_554 () Int) -(declare-fun x_561 () Int) -(declare-fun x_11 () Int) -(declare-fun x_329 () Int) -(declare-fun x_727 () Int) -(declare-fun x_97 () Int) -(declare-fun x_343 () Int) -(declare-fun x_918 () Int) -(declare-fun x_289 () Int) -(declare-fun x_803 () Int) -(declare-fun x_812 () Int) -(declare-fun x_547 () Int) -(declare-fun x_806 () Int) -(declare-fun x_252 () Int) -(declare-fun x_273 () Int) -(declare-fun x_618 () Int) -(declare-fun x_301 () Int) -(declare-fun x_688 () Int) -(declare-fun x_224 () Int) -(declare-fun x_449 () Int) -(declare-fun x_327 () Int) -(declare-fun x_387 () Int) -(declare-fun x_86 () Int) -(declare-fun x_89 () Int) -(declare-fun x_404 () Int) -(declare-fun x_507 () Int) -(declare-fun x_312 () Int) -(declare-fun x_578 () Int) -(declare-fun x_722 () Int) -(declare-fun x_762 () Int) -(declare-fun x_169 () Int) -(declare-fun x_206 () Int) -(declare-fun x_383 () Int) -(declare-fun x_867 () Int) -(declare-fun x_627 () Int) -(declare-fun x_638 () Int) -(declare-fun x_184 () Int) -(declare-fun x_479 () Int) -(declare-fun x_292 () Int) -(declare-fun x_844 () Int) -(declare-fun x_421 () Int) -(declare-fun x_911 () Int) -(declare-fun x_419 () Int) -(declare-fun x_612 () Int) -(declare-fun x_192 () Int) -(declare-fun x_656 () Int) -(declare-fun x_702 () Int) -(declare-fun x_778 () Int) -(declare-fun x_281 () Int) -(declare-fun x_834 () Int) -(declare-fun x_63 () Int) -(declare-fun x_836 () Int) -(declare-fun x_793 () Int) -(declare-fun x_622 () Int) -(declare-fun x_899 () Int) -(declare-fun x_944 () Int) -(declare-fun x_369 () Int) -(declare-fun x_336 () Int) -(declare-fun x_869 () Int) -(declare-fun x_257 () Int) -(declare-fun x_1001 () Int) -(declare-fun x_904 () Int) -(declare-fun x_528 () Int) -(declare-fun x_997 () Int) -(declare-fun x_414 () Int) -(declare-fun x_223 () Int) -(declare-fun x_642 () Int) -(declare-fun x_76 () Int) -(declare-fun x_29 () Int) -(declare-fun x_533 () Int) -(declare-fun x_41 () Int) -(declare-fun x_581 () Int) -(declare-fun x_791 () Int) -(declare-fun x_809 () Int) -(declare-fun x_321 () Int) -(declare-fun x_939 () Int) -(declare-fun x_541 () Int) -(declare-fun x_652 () Int) -(declare-fun x_569 () Int) -(declare-fun x_934 () Int) -(declare-fun x_207 () Int) -(declare-fun x_376 () Int) -(declare-fun x_109 () Int) -(declare-fun x_761 () Int) -(declare-fun x_446 () Int) -(declare-fun x_657 () Int) -(declare-fun x_171 () Int) -(declare-fun x_558 () Int) -(declare-fun x_276 () Int) -(declare-fun x_46 () Int) -(declare-fun x_668 () Int) -(declare-fun x_57 () Int) -(declare-fun x_374 () Int) -(declare-fun x_209 () Int) -(declare-fun x_739 () Int) -(declare-fun x_909 () Int) -(declare-fun x_468 () Int) -(declare-fun x_14 () Int) -(declare-fun x_832 () Int) -(declare-fun x_391 () Int) -(declare-fun x_517 () Int) -(declare-fun x_12 () Int) -(declare-fun x_244 () Int) -(declare-fun x_628 () Int) -(declare-fun x_334 () Int) -(declare-fun x_502 () Int) -(declare-fun x_883 () Int) -(declare-fun x_379 () Int) -(declare-fun x_307 () Int) -(declare-fun x_182 () Int) -(declare-fun x_293 () Int) -(declare-fun x_288 () Int) -(declare-fun x_633 () Int) -(declare-fun x_866 () Int) -(declare-fun x_571 () Int) -(declare-fun x_842 () Int) -(declare-fun x_921 () Int) -(declare-fun x_797 () Int) -(declare-fun x_153 () Int) -(declare-fun x_398 () Int) -(declare-fun x_583 () Int) -(declare-fun x_683 () Int) -(declare-fun x_189 () Int) -(declare-fun x_964 () Int) -(declare-fun x_164 () Int) -(declare-fun x_474 () Int) -(declare-fun x_521 () Int) -(declare-fun x_21 () Int) -(declare-fun x_518 () Int) -(declare-fun x_473 () Int) -(declare-fun x_896 () Int) -(declare-fun x_796 () Int) -(declare-fun x_477 () Int) -(declare-fun x_74 () Int) -(declare-fun x_116 () Int) -(declare-fun x_837 () Int) -(declare-fun x_673 () Int) -(declare-fun x_309 () Int) -(declare-fun x_58 () Int) -(declare-fun x_428 () Int) -(declare-fun x_589 () Int) -(declare-fun x_747 () Int) -(declare-fun x_929 () Int) -(declare-fun x_529 () Int) -(declare-fun x_413 () Int) -(declare-fun x_847 () Int) -(declare-fun x_262 () Int) -(declare-fun x_801 () Int) -(declare-fun x_952 () Int) -(declare-fun x_632 () Int) -(declare-fun x_142 () Int) -(declare-fun x_491 () Int) -(declare-fun x_546 () Int) -(declare-fun x_839 () Int) -(declare-fun x_588 () Int) -(declare-fun x_393 () Int) -(declare-fun x_118 () Int) -(declare-fun x_901 () Int) -(declare-fun x_962 () Int) -(declare-fun x_968 () Int) -(declare-fun x_886 () Int) -(declare-fun x_774 () Int) -(declare-fun x_487 () Int) -(declare-fun x_127 () Int) -(declare-fun x_237 () Int) -(declare-fun x_723 () Int) -(declare-fun x_542 () Int) -(declare-fun x_753 () Int) -(declare-fun x_129 () Int) -(declare-fun x_864 () Int) -(declare-fun x_611 () Int) -(declare-fun x_416 () Int) -(declare-fun x_947 () Int) -(declare-fun x_1202 () Int) -(declare-fun x_563 () Int) -(declare-fun x_337 () Int) -(declare-fun x_544 () Int) -(declare-fun x_654 () Int) -(declare-fun x_756 () Int) -(declare-fun x_744 () Int) -(declare-fun x_891 () Int) -(declare-fun x_378 () Int) -(declare-fun x_134 () Int) -(declare-fun x_208 () Int) -(declare-fun x_758 () Int) -(declare-fun x_848 () Int) -(declare-fun x_927 () Int) -(declare-fun x_937 () Int) -(declare-fun x_602 () Int) -(declare-fun x_349 () Int) -(declare-fun x_96 () Int) -(declare-fun x_162 () Int) -(declare-fun x_37 () Int) -(declare-fun x_941 () Int) -(declare-fun x_906 () Int) -(declare-fun x_811 () Int) -(declare-fun x_138 () Int) -(declare-fun x_621 () Int) -(declare-fun x_492 () Int) -(declare-fun x_764 () Int) -(declare-fun x_452 () Int) -(declare-fun x_851 () Int) -(declare-fun x_98 () Int) -(declare-fun x_236 () Int) -(declare-fun x_453 () Int) -(declare-fun x_978 () Int) -(declare-fun x_499 () Int) -(declare-fun x_494 () Int) -(declare-fun x_316 () Int) -(declare-fun x_587 () Int) -(declare-fun x_103 () Int) -(declare-fun x_734 () Int) -(declare-fun x_923 () Int) -(declare-fun x_228 () Int) -(declare-fun x_504 () Int) -(declare-fun x_564 () Int) -(declare-fun x_592 () Int) -(declare-fun x_2 () Int) -(declare-fun x_539 () Int) -(declare-fun x_247 () Int) -(declare-fun x_931 () Int) -(declare-fun x_903 () Int) -(declare-fun x_64 () Int) -(declare-fun x_232 () Int) -(declare-fun x_298 () Int) -(declare-fun x_126 () Int) -(declare-fun x_787 () Int) -(declare-fun x_243 () Int) -(declare-fun x_356 () Int) -(declare-fun x_709 () Int) -(declare-fun x_823 () Int) -(declare-fun x_338 () Int) -(declare-fun x_201 () Int) -(declare-fun x_304 () Int) -(declare-fun x_101 () Int) -(declare-fun x_568 () Int) -(declare-fun x_573 () Int) -(declare-fun x_28 () Int) -(declare-fun x_516 () Int) -(declare-fun x_619 () Int) -(declare-fun x_102 () Int) -(declare-fun x_92 () Int) -(declare-fun x_604 () Int) -(declare-fun x_597 () Int) -(declare-fun x_663 () Int) -(declare-fun x_731 () Int) -(declare-fun x_328 () Int) -(declare-fun x_143 () Int) -(declare-fun x_849 () Int) -(declare-fun x_128 () Int) -(declare-fun x_266 () Int) -(declare-fun x_203 () Int) -(declare-fun x_661 () Int) -(declare-fun x_996 () Int) -(declare-fun x_462 () Int) -(declare-fun x_977 () Int) -(declare-fun x_458 () Int) -(declare-fun x_933 () Int) -(declare-fun x_94 () Int) -(declare-fun x_332 () Int) -(declare-fun x_514 () Int) -(declare-fun x_969 () Int) -(declare-fun x_987 () Int) -(declare-fun x_497 () Int) -(declare-fun x_666 () Int) -(declare-fun x_858 () Int) -(declare-fun x_643 () Int) -(declare-fun x_523 () Int) -(declare-fun x_609 () Int) -(declare-fun x_263 () Int) -(declare-fun x_878 () Int) -(declare-fun x_981 () Int) -(declare-fun x_863 () Int) -(declare-fun x_324 () Int) -(declare-fun x_783 () Int) -(declare-fun x_241 () Int) -(declare-fun x_407 () Int) -(declare-fun x_708 () Int) -(declare-fun x_862 () Int) -(declare-fun x_757 () Int) -(declare-fun x_251 () Int) -(declare-fun x_771 () Int) -(declare-fun x_478 () Int) -(declare-fun x_437 () Int) -(declare-fun x_267 () Int) -(declare-fun x_599 () Int) -(declare-fun x_234 () Int) -(declare-fun x_177 () Int) -(declare-fun x_726 () Int) -(declare-fun x_261 () Int) -(declare-fun x_353 () Int) -(declare-fun x_732 () Int) -(declare-fun x_908 () Int) -(declare-fun x_361 () Int) -(declare-fun x_887 () Int) -(declare-fun x_488 () Int) -(declare-fun x_917 () Int) -(declare-fun x_716 () Int) -(declare-fun x_166 () Int) -(declare-fun x_112 () Int) -(declare-fun x_629 () Int) -(declare-fun x_52 () Int) -(declare-fun x_34 () Int) -(declare-fun x_183 () Int) -(declare-fun x_999 () Int) -(declare-fun x_99 () Int) -(declare-fun x_444 () Int) -(declare-fun x_424 () Int) -(declare-fun x_317 () Int) -(declare-fun x_784 () Int) -(declare-fun x_584 () Int) -(declare-fun x_282 () Int) -(declare-fun x_743 () Int) -(declare-fun x_56 () Int) -(declare-fun x_749 () Int) -(declare-fun x_411 () Int) -(declare-fun x_647 () Int) -(declare-fun x_219 () Int) -(declare-fun x_946 () Int) -(declare-fun x_433 () Int) -(declare-fun x_106 () Int) -(declare-fun x_38 () Int) -(declare-fun x_314 () Int) -(declare-fun x_481 () Int) -(declare-fun x_768 () Int) -(declare-fun x_579 () Int) -(declare-fun x_114 () Int) -(declare-fun x_894 () Int) -(declare-fun x_146 () Int) -(declare-fun x_577 () Int) -(declare-fun x_394 () Int) -(declare-fun x_566 () Int) -(declare-fun x_738 () Int) -(declare-fun x_506 () Int) -(declare-fun x_351 () Int) -(declare-fun x_493 () Int) -(declare-fun x_624 () Int) -(declare-fun x_653 () Int) -(declare-fun x_386 () Int) -(declare-fun x_526 () Int) -(declare-fun x_148 () Int) -(declare-fun x_131 () Int) -(declare-fun x_669 () Int) -(declare-fun x_982 () Int) -(declare-fun x_664 () Int) -(declare-fun x_501 () Int) -(declare-fun x_856 () Int) -(declare-fun x_828 () Int) -(declare-fun x_161 () Int) -(declare-fun x_772 () Int) -(declare-fun x_147 () Int) -(declare-fun x_967 () Int) -(declare-fun x_313 () Int) -(declare-fun x_681 () Int) -(declare-fun x_724 () Int) -(declare-fun x_636 () Int) -(declare-fun x_83 () Int) -(declare-fun x_754 () Int) -(declare-fun x_484 () Int) -(declare-fun x_49 () Int) -(declare-fun x_703 () Int) -(declare-fun x_36 () Int) -(declare-fun x_152 () Int) -(declare-fun x_187 () Int) -(declare-fun x_752 () Int) -(declare-fun x_191 () Int) -(declare-fun x_634 () Int) -(declare-fun x_788 () Int) -(declare-fun x_259 () Int) -(declare-fun x_431 () Int) -(declare-fun x_509 () Int) -(declare-fun x_93 () Int) -(declare-fun x_9 () Int) -(declare-fun x_513 () Int) -(declare-fun x_248 () Int) -(declare-fun x_272 () Int) -(declare-fun x_751 () Int) -(declare-fun x_686 () Int) -(declare-fun x_714 () Int) -(declare-fun x_807 () Int) -(declare-fun x_922 () Int) -(declare-fun x_81 () Int) -(declare-fun x_613 () Int) -(declare-fun x_928 () Int) -(declare-fun x_1604 () Int) -(declare-fun x_78 () Int) -(declare-fun x_249 () Int) -(declare-fun x_79 () Int) -(declare-fun x_649 () Int) -(declare-fun x_781 () Int) -(declare-fun x_687 () Int) -(declare-fun x_82 () Int) -(declare-fun x_804 () Int) -(declare-fun x_441 () Int) -(declare-fun x_651 () Int) -(declare-fun x_936 () Int) -(declare-fun x_1 () Int) -(declare-fun x_179 () Int) -(declare-fun x_199 () Int) -(declare-fun x_623 () Int) -(declare-fun x_794 () Int) -(declare-fun x_777 () Int) -(declare-fun x_214 () Int) -(declare-fun x_296 () Int) -(declare-fun x_949 () Int) -(declare-fun x_133 () Int) -(declare-fun x_829 () Int) -(declare-fun x_556 () Int) -(declare-fun x_617 () Int) -(declare-fun x_18 () Int) -(declare-fun x_728 () Int) -(declare-fun x_426 () Int) -(declare-fun x_898 () Int) -(declare-fun x_23 () Int) -(declare-fun x_843 () Int) -(declare-fun x_827 () Int) -(declare-fun x_831 () Int) -(declare-fun x_954 () Int) -(declare-fun x_341 () Int) -(declare-fun x_956 () Int) -(declare-fun x_983 () Int) -(declare-fun x_606 () Int) -(declare-fun x_874 () Int) -(declare-fun x_698 () Int) -(declare-fun x_782 () Int) -(declare-fun x_48 () Int) -(declare-fun x_172 () Int) -(declare-fun x_342 () Int) -(declare-fun x_238 () Int) -(declare-fun x_323 () Int) -(declare-fun x_608 () Int) -(declare-fun x_471 () Int) -(declare-fun x_216 () Int) -(declare-fun x_69 () Int) -(declare-fun x_438 () Int) -(declare-fun x_534 () Int) -(declare-fun x_368 () Int) -(declare-fun x_193 () Int) -(declare-fun x_532 () Int) -(declare-fun x_951 () Int) -(declare-fun x_258 () Int) -(declare-fun x_853 () Int) -(declare-fun x_132 () Int) -(declare-fun x_159 () Int) -(declare-fun x_217 () Int) -(declare-fun x_742 () Int) -(declare-fun x_311 () Int) -(declare-fun x_1403 () Int) -(declare-fun x_176 () Int) -(declare-fun x_254 () Int) -(declare-fun x_66 () Int) -(declare-fun x_144 () Int) -(declare-fun x_998 () Int) -(assert (<= 0 x_1)) -(assert (>= 1 x_1)) -(assert (<= 0 x_2)) -(assert (>= 1 x_2)) -(assert (<= 0 x_3)) -(assert (>= 1 x_3)) -(assert (<= 0 x_4)) -(assert (>= 1 x_4)) -(assert (<= 0 x_6)) -(assert (>= 1 x_6)) -(assert (<= 0 x_7)) -(assert (>= 1 x_7)) -(assert (<= 0 x_8)) -(assert (>= 1 x_8)) -(assert (<= 0 x_9)) -(assert (>= 1 x_9)) -(assert (<= 0 x_11)) -(assert (>= 1 x_11)) -(assert (<= 0 x_12)) -(assert (>= 1 x_12)) -(assert (<= 0 x_13)) -(assert (>= 1 x_13)) -(assert (<= 0 x_14)) -(assert (>= 1 x_14)) -(assert (<= 0 x_16)) -(assert (>= 1 x_16)) -(assert (<= 0 x_17)) -(assert (>= 1 x_17)) -(assert (<= 0 x_18)) -(assert (>= 1 x_18)) -(assert (<= 0 x_19)) -(assert (>= 1 x_19)) -(assert (<= 0 x_21)) -(assert (>= 1 x_21)) -(assert (<= 0 x_22)) -(assert (>= 1 x_22)) -(assert (<= 0 x_23)) -(assert (>= 1 x_23)) -(assert (<= 0 x_24)) -(assert (>= 1 x_24)) -(assert (<= 0 x_26)) -(assert (>= 1 x_26)) -(assert (<= 0 x_27)) -(assert (>= 1 x_27)) -(assert (<= 0 x_28)) -(assert (>= 1 x_28)) -(assert (<= 0 x_29)) -(assert (>= 1 x_29)) -(assert (<= 0 x_31)) -(assert (>= 1 x_31)) -(assert (<= 0 x_32)) -(assert (>= 1 x_32)) -(assert (<= 0 x_33)) -(assert (>= 1 x_33)) -(assert (<= 0 x_34)) -(assert (>= 1 x_34)) -(assert (<= 0 x_36)) -(assert (>= 1 x_36)) -(assert (<= 0 x_37)) -(assert (>= 1 x_37)) -(assert (<= 0 x_38)) -(assert (>= 1 x_38)) -(assert (<= 0 x_39)) -(assert (>= 1 x_39)) -(assert (<= 0 x_41)) -(assert (>= 1 x_41)) -(assert (<= 0 x_42)) -(assert (>= 1 x_42)) -(assert (<= 0 x_43)) -(assert (>= 1 x_43)) -(assert (<= 0 x_44)) -(assert (>= 1 x_44)) -(assert (<= 0 x_46)) -(assert (>= 1 x_46)) -(assert (<= 0 x_47)) -(assert (>= 1 x_47)) -(assert (<= 0 x_48)) -(assert (>= 1 x_48)) -(assert (<= 0 x_49)) -(assert (>= 1 x_49)) -(assert (<= 0 x_51)) -(assert (>= 1 x_51)) -(assert (<= 0 x_52)) -(assert (>= 1 x_52)) -(assert (<= 0 x_53)) -(assert (>= 1 x_53)) -(assert (<= 0 x_54)) -(assert (>= 1 x_54)) -(assert (<= 0 x_56)) -(assert (>= 1 x_56)) -(assert (<= 0 x_57)) -(assert (>= 1 x_57)) -(assert (<= 0 x_58)) -(assert (>= 1 x_58)) -(assert (<= 0 x_59)) -(assert (>= 1 x_59)) -(assert (<= 0 x_61)) -(assert (>= 1 x_61)) -(assert (<= 0 x_62)) -(assert (>= 1 x_62)) -(assert (<= 0 x_63)) -(assert (>= 1 x_63)) -(assert (<= 0 x_64)) -(assert (>= 1 x_64)) -(assert (<= 0 x_66)) -(assert (>= 1 x_66)) -(assert (<= 0 x_67)) -(assert (>= 1 x_67)) -(assert (<= 0 x_68)) -(assert (>= 1 x_68)) -(assert (<= 0 x_69)) -(assert (>= 1 x_69)) -(assert (<= 0 x_71)) -(assert (>= 1 x_71)) -(assert (<= 0 x_72)) -(assert (>= 1 x_72)) -(assert (<= 0 x_73)) -(assert (>= 1 x_73)) -(assert (<= 0 x_74)) -(assert (>= 1 x_74)) -(assert (<= 0 x_76)) -(assert (>= 1 x_76)) -(assert (<= 0 x_77)) -(assert (>= 1 x_77)) -(assert (<= 0 x_78)) -(assert (>= 1 x_78)) -(assert (<= 0 x_79)) -(assert (>= 1 x_79)) -(assert (<= 0 x_81)) -(assert (>= 1 x_81)) -(assert (<= 0 x_82)) -(assert (>= 1 x_82)) -(assert (<= 0 x_83)) -(assert (>= 1 x_83)) -(assert (<= 0 x_84)) -(assert (>= 1 x_84)) -(assert (<= 0 x_86)) -(assert (>= 1 x_86)) -(assert (<= 0 x_87)) -(assert (>= 1 x_87)) -(assert (<= 0 x_88)) -(assert (>= 1 x_88)) -(assert (<= 0 x_89)) -(assert (>= 1 x_89)) -(assert (<= 0 x_91)) -(assert (>= 1 x_91)) -(assert (<= 0 x_92)) -(assert (>= 1 x_92)) -(assert (<= 0 x_93)) -(assert (>= 1 x_93)) -(assert (<= 0 x_94)) -(assert (>= 1 x_94)) -(assert (<= 0 x_96)) -(assert (>= 1 x_96)) -(assert (<= 0 x_97)) -(assert (>= 1 x_97)) -(assert (<= 0 x_98)) -(assert (>= 1 x_98)) -(assert (<= 0 x_99)) -(assert (>= 1 x_99)) -(assert (<= 0 x_101)) -(assert (>= 1 x_101)) -(assert (<= 0 x_102)) -(assert (>= 1 x_102)) -(assert (<= 0 x_103)) -(assert (>= 1 x_103)) -(assert (<= 0 x_104)) -(assert (>= 1 x_104)) -(assert (<= 0 x_106)) -(assert (>= 1 x_106)) -(assert (<= 0 x_107)) -(assert (>= 1 x_107)) -(assert (<= 0 x_108)) -(assert (>= 1 x_108)) -(assert (<= 0 x_109)) -(assert (>= 1 x_109)) -(assert (<= 0 x_111)) -(assert (>= 1 x_111)) -(assert (<= 0 x_112)) -(assert (>= 1 x_112)) -(assert (<= 0 x_113)) -(assert (>= 1 x_113)) -(assert (<= 0 x_114)) -(assert (>= 1 x_114)) -(assert (<= 0 x_116)) -(assert (>= 1 x_116)) -(assert (<= 0 x_117)) -(assert (>= 1 x_117)) -(assert (<= 0 x_118)) -(assert (>= 1 x_118)) -(assert (<= 0 x_119)) -(assert (>= 1 x_119)) -(assert (<= 0 x_121)) -(assert (>= 1 x_121)) -(assert (<= 0 x_122)) -(assert (>= 1 x_122)) -(assert (<= 0 x_123)) -(assert (>= 1 x_123)) -(assert (<= 0 x_124)) -(assert (>= 1 x_124)) -(assert (<= 0 x_126)) -(assert (>= 1 x_126)) -(assert (<= 0 x_127)) -(assert (>= 1 x_127)) -(assert (<= 0 x_128)) -(assert (>= 1 x_128)) -(assert (<= 0 x_129)) -(assert (>= 1 x_129)) -(assert (<= 0 x_131)) -(assert (>= 1 x_131)) -(assert (<= 0 x_132)) -(assert (>= 1 x_132)) -(assert (<= 0 x_133)) -(assert (>= 1 x_133)) -(assert (<= 0 x_134)) -(assert (>= 1 x_134)) -(assert (<= 0 x_136)) -(assert (>= 1 x_136)) -(assert (<= 0 x_137)) -(assert (>= 1 x_137)) -(assert (<= 0 x_138)) -(assert (>= 1 x_138)) -(assert (<= 0 x_139)) -(assert (>= 1 x_139)) -(assert (<= 0 x_141)) -(assert (>= 1 x_141)) -(assert (<= 0 x_142)) -(assert (>= 1 x_142)) -(assert (<= 0 x_143)) -(assert (>= 1 x_143)) -(assert (<= 0 x_144)) -(assert (>= 1 x_144)) -(assert (<= 0 x_146)) -(assert (>= 1 x_146)) -(assert (<= 0 x_147)) -(assert (>= 1 x_147)) -(assert (<= 0 x_148)) -(assert (>= 1 x_148)) -(assert (<= 0 x_149)) -(assert (>= 1 x_149)) -(assert (<= 0 x_151)) -(assert (>= 1 x_151)) -(assert (<= 0 x_152)) -(assert (>= 1 x_152)) -(assert (<= 0 x_153)) -(assert (>= 1 x_153)) -(assert (<= 0 x_154)) -(assert (>= 1 x_154)) -(assert (<= 0 x_156)) -(assert (>= 1 x_156)) -(assert (<= 0 x_157)) -(assert (>= 1 x_157)) -(assert (<= 0 x_158)) -(assert (>= 1 x_158)) -(assert (<= 0 x_159)) -(assert (>= 1 x_159)) -(assert (<= 0 x_161)) -(assert (>= 1 x_161)) -(assert (<= 0 x_162)) -(assert (>= 1 x_162)) -(assert (<= 0 x_163)) -(assert (>= 1 x_163)) -(assert (<= 0 x_164)) -(assert (>= 1 x_164)) -(assert (<= 0 x_166)) -(assert (>= 1 x_166)) -(assert (<= 0 x_167)) -(assert (>= 1 x_167)) -(assert (<= 0 x_168)) -(assert (>= 1 x_168)) -(assert (<= 0 x_169)) -(assert (>= 1 x_169)) -(assert (<= 0 x_171)) -(assert (>= 1 x_171)) -(assert (<= 0 x_172)) -(assert (>= 1 x_172)) -(assert (<= 0 x_173)) -(assert (>= 1 x_173)) -(assert (<= 0 x_174)) -(assert (>= 1 x_174)) -(assert (<= 0 x_176)) -(assert (>= 1 x_176)) -(assert (<= 0 x_177)) -(assert (>= 1 x_177)) -(assert (<= 0 x_178)) -(assert (>= 1 x_178)) -(assert (<= 0 x_179)) -(assert (>= 1 x_179)) -(assert (<= 0 x_181)) -(assert (>= 1 x_181)) -(assert (<= 0 x_182)) -(assert (>= 1 x_182)) -(assert (<= 0 x_183)) -(assert (>= 1 x_183)) -(assert (<= 0 x_184)) -(assert (>= 1 x_184)) -(assert (<= 0 x_186)) -(assert (>= 1 x_186)) -(assert (<= 0 x_187)) -(assert (>= 1 x_187)) -(assert (<= 0 x_188)) -(assert (>= 1 x_188)) -(assert (<= 0 x_189)) -(assert (>= 1 x_189)) -(assert (<= 0 x_191)) -(assert (>= 1 x_191)) -(assert (<= 0 x_192)) -(assert (>= 1 x_192)) -(assert (<= 0 x_193)) -(assert (>= 1 x_193)) -(assert (<= 0 x_194)) -(assert (>= 1 x_194)) -(assert (<= 0 x_196)) -(assert (>= 1 x_196)) -(assert (<= 0 x_197)) -(assert (>= 1 x_197)) -(assert (<= 0 x_198)) -(assert (>= 1 x_198)) -(assert (<= 0 x_199)) -(assert (>= 1 x_199)) -(assert (<= 0 x_201)) -(assert (>= 1 x_201)) -(assert (<= 0 x_202)) -(assert (>= 1 x_202)) -(assert (<= 0 x_203)) -(assert (>= 1 x_203)) -(assert (<= 0 x_204)) -(assert (>= 1 x_204)) -(assert (<= 0 x_206)) -(assert (>= 1 x_206)) -(assert (<= 0 x_207)) -(assert (>= 1 x_207)) -(assert (<= 0 x_208)) -(assert (>= 1 x_208)) -(assert (<= 0 x_209)) -(assert (>= 1 x_209)) -(assert (<= 0 x_211)) -(assert (>= 1 x_211)) -(assert (<= 0 x_212)) -(assert (>= 1 x_212)) -(assert (<= 0 x_213)) -(assert (>= 1 x_213)) -(assert (<= 0 x_214)) -(assert (>= 1 x_214)) -(assert (<= 0 x_216)) -(assert (>= 1 x_216)) -(assert (<= 0 x_217)) -(assert (>= 1 x_217)) -(assert (<= 0 x_218)) -(assert (>= 1 x_218)) -(assert (<= 0 x_219)) -(assert (>= 1 x_219)) -(assert (<= 0 x_221)) -(assert (>= 1 x_221)) -(assert (<= 0 x_222)) -(assert (>= 1 x_222)) -(assert (<= 0 x_223)) -(assert (>= 1 x_223)) -(assert (<= 0 x_224)) -(assert (>= 1 x_224)) -(assert (<= 0 x_226)) -(assert (>= 1 x_226)) -(assert (<= 0 x_227)) -(assert (>= 1 x_227)) -(assert (<= 0 x_228)) -(assert (>= 1 x_228)) -(assert (<= 0 x_229)) -(assert (>= 1 x_229)) -(assert (<= 0 x_231)) -(assert (>= 1 x_231)) -(assert (<= 0 x_232)) -(assert (>= 1 x_232)) -(assert (<= 0 x_233)) -(assert (>= 1 x_233)) -(assert (<= 0 x_234)) -(assert (>= 1 x_234)) -(assert (<= 0 x_236)) -(assert (>= 1 x_236)) -(assert (<= 0 x_237)) -(assert (>= 1 x_237)) -(assert (<= 0 x_238)) -(assert (>= 1 x_238)) -(assert (<= 0 x_239)) -(assert (>= 1 x_239)) -(assert (<= 0 x_241)) -(assert (>= 1 x_241)) -(assert (<= 0 x_242)) -(assert (>= 1 x_242)) -(assert (<= 0 x_243)) -(assert (>= 1 x_243)) -(assert (<= 0 x_244)) -(assert (>= 1 x_244)) -(assert (<= 0 x_246)) -(assert (>= 1 x_246)) -(assert (<= 0 x_247)) -(assert (>= 1 x_247)) -(assert (<= 0 x_248)) -(assert (>= 1 x_248)) -(assert (<= 0 x_249)) -(assert (>= 1 x_249)) -(assert (<= 0 x_251)) -(assert (>= 1 x_251)) -(assert (<= 0 x_252)) -(assert (>= 1 x_252)) -(assert (<= 0 x_253)) -(assert (>= 1 x_253)) -(assert (<= 0 x_254)) -(assert (>= 1 x_254)) -(assert (<= 0 x_256)) -(assert (>= 1 x_256)) -(assert (<= 0 x_257)) -(assert (>= 1 x_257)) -(assert (<= 0 x_258)) -(assert (>= 1 x_258)) -(assert (<= 0 x_259)) -(assert (>= 1 x_259)) -(assert (<= 0 x_261)) -(assert (>= 1 x_261)) -(assert (<= 0 x_262)) -(assert (>= 1 x_262)) -(assert (<= 0 x_263)) -(assert (>= 1 x_263)) -(assert (<= 0 x_264)) -(assert (>= 1 x_264)) -(assert (<= 0 x_266)) -(assert (>= 1 x_266)) -(assert (<= 0 x_267)) -(assert (>= 1 x_267)) -(assert (<= 0 x_268)) -(assert (>= 1 x_268)) -(assert (<= 0 x_269)) -(assert (>= 1 x_269)) -(assert (<= 0 x_271)) -(assert (>= 1 x_271)) -(assert (<= 0 x_272)) -(assert (>= 1 x_272)) -(assert (<= 0 x_273)) -(assert (>= 1 x_273)) -(assert (<= 0 x_274)) -(assert (>= 1 x_274)) -(assert (<= 0 x_276)) -(assert (>= 1 x_276)) -(assert (<= 0 x_277)) -(assert (>= 1 x_277)) -(assert (<= 0 x_278)) -(assert (>= 1 x_278)) -(assert (<= 0 x_279)) -(assert (>= 1 x_279)) -(assert (<= 0 x_281)) -(assert (>= 1 x_281)) -(assert (<= 0 x_282)) -(assert (>= 1 x_282)) -(assert (<= 0 x_283)) -(assert (>= 1 x_283)) -(assert (<= 0 x_284)) -(assert (>= 1 x_284)) -(assert (<= 0 x_286)) -(assert (>= 1 x_286)) -(assert (<= 0 x_287)) -(assert (>= 1 x_287)) -(assert (<= 0 x_288)) -(assert (>= 1 x_288)) -(assert (<= 0 x_289)) -(assert (>= 1 x_289)) -(assert (<= 0 x_291)) -(assert (>= 1 x_291)) -(assert (<= 0 x_292)) -(assert (>= 1 x_292)) -(assert (<= 0 x_293)) -(assert (>= 1 x_293)) -(assert (<= 0 x_294)) -(assert (>= 1 x_294)) -(assert (<= 0 x_296)) -(assert (>= 1 x_296)) -(assert (<= 0 x_297)) -(assert (>= 1 x_297)) -(assert (<= 0 x_298)) -(assert (>= 1 x_298)) -(assert (<= 0 x_299)) -(assert (>= 1 x_299)) -(assert (<= 0 x_301)) -(assert (>= 1 x_301)) -(assert (<= 0 x_302)) -(assert (>= 1 x_302)) -(assert (<= 0 x_303)) -(assert (>= 1 x_303)) -(assert (<= 0 x_304)) -(assert (>= 1 x_304)) -(assert (<= 0 x_306)) -(assert (>= 1 x_306)) -(assert (<= 0 x_307)) -(assert (>= 1 x_307)) -(assert (<= 0 x_308)) -(assert (>= 1 x_308)) -(assert (<= 0 x_309)) -(assert (>= 1 x_309)) -(assert (<= 0 x_311)) -(assert (>= 1 x_311)) -(assert (<= 0 x_312)) -(assert (>= 1 x_312)) -(assert (<= 0 x_313)) -(assert (>= 1 x_313)) -(assert (<= 0 x_314)) -(assert (>= 1 x_314)) -(assert (<= 0 x_316)) -(assert (>= 1 x_316)) -(assert (<= 0 x_317)) -(assert (>= 1 x_317)) -(assert (<= 0 x_318)) -(assert (>= 1 x_318)) -(assert (<= 0 x_319)) -(assert (>= 1 x_319)) -(assert (<= 0 x_321)) -(assert (>= 1 x_321)) -(assert (<= 0 x_322)) -(assert (>= 1 x_322)) -(assert (<= 0 x_323)) -(assert (>= 1 x_323)) -(assert (<= 0 x_324)) -(assert (>= 1 x_324)) -(assert (<= 0 x_326)) -(assert (>= 1 x_326)) -(assert (<= 0 x_327)) -(assert (>= 1 x_327)) -(assert (<= 0 x_328)) -(assert (>= 1 x_328)) -(assert (<= 0 x_329)) -(assert (>= 1 x_329)) -(assert (<= 0 x_331)) -(assert (>= 1 x_331)) -(assert (<= 0 x_332)) -(assert (>= 1 x_332)) -(assert (<= 0 x_333)) -(assert (>= 1 x_333)) -(assert (<= 0 x_334)) -(assert (>= 1 x_334)) -(assert (<= 0 x_336)) -(assert (>= 1 x_336)) -(assert (<= 0 x_337)) -(assert (>= 1 x_337)) -(assert (<= 0 x_338)) -(assert (>= 1 x_338)) -(assert (<= 0 x_339)) -(assert (>= 1 x_339)) -(assert (<= 0 x_341)) -(assert (>= 1 x_341)) -(assert (<= 0 x_342)) -(assert (>= 1 x_342)) -(assert (<= 0 x_343)) -(assert (>= 1 x_343)) -(assert (<= 0 x_344)) -(assert (>= 1 x_344)) -(assert (<= 0 x_346)) -(assert (>= 1 x_346)) -(assert (<= 0 x_347)) -(assert (>= 1 x_347)) -(assert (<= 0 x_348)) -(assert (>= 1 x_348)) -(assert (<= 0 x_349)) -(assert (>= 1 x_349)) -(assert (<= 0 x_351)) -(assert (>= 1 x_351)) -(assert (<= 0 x_352)) -(assert (>= 1 x_352)) -(assert (<= 0 x_353)) -(assert (>= 1 x_353)) -(assert (<= 0 x_354)) -(assert (>= 1 x_354)) -(assert (<= 0 x_356)) -(assert (>= 1 x_356)) -(assert (<= 0 x_357)) -(assert (>= 1 x_357)) -(assert (<= 0 x_358)) -(assert (>= 1 x_358)) -(assert (<= 0 x_359)) -(assert (>= 1 x_359)) -(assert (<= 0 x_361)) -(assert (>= 1 x_361)) -(assert (<= 0 x_362)) -(assert (>= 1 x_362)) -(assert (<= 0 x_363)) -(assert (>= 1 x_363)) -(assert (<= 0 x_364)) -(assert (>= 1 x_364)) -(assert (<= 0 x_366)) -(assert (>= 1 x_366)) -(assert (<= 0 x_367)) -(assert (>= 1 x_367)) -(assert (<= 0 x_368)) -(assert (>= 1 x_368)) -(assert (<= 0 x_369)) -(assert (>= 1 x_369)) -(assert (<= 0 x_371)) -(assert (>= 1 x_371)) -(assert (<= 0 x_372)) -(assert (>= 1 x_372)) -(assert (<= 0 x_373)) -(assert (>= 1 x_373)) -(assert (<= 0 x_374)) -(assert (>= 1 x_374)) -(assert (<= 0 x_376)) -(assert (>= 1 x_376)) -(assert (<= 0 x_377)) -(assert (>= 1 x_377)) -(assert (<= 0 x_378)) -(assert (>= 1 x_378)) -(assert (<= 0 x_379)) -(assert (>= 1 x_379)) -(assert (<= 0 x_381)) -(assert (>= 1 x_381)) -(assert (<= 0 x_382)) -(assert (>= 1 x_382)) -(assert (<= 0 x_383)) -(assert (>= 1 x_383)) -(assert (<= 0 x_384)) -(assert (>= 1 x_384)) -(assert (<= 0 x_386)) -(assert (>= 1 x_386)) -(assert (<= 0 x_387)) -(assert (>= 1 x_387)) -(assert (<= 0 x_388)) -(assert (>= 1 x_388)) -(assert (<= 0 x_389)) -(assert (>= 1 x_389)) -(assert (<= 0 x_391)) -(assert (>= 1 x_391)) -(assert (<= 0 x_392)) -(assert (>= 1 x_392)) -(assert (<= 0 x_393)) -(assert (>= 1 x_393)) -(assert (<= 0 x_394)) -(assert (>= 1 x_394)) -(assert (<= 0 x_396)) -(assert (>= 1 x_396)) -(assert (<= 0 x_397)) -(assert (>= 1 x_397)) -(assert (<= 0 x_398)) -(assert (>= 1 x_398)) -(assert (<= 0 x_399)) -(assert (>= 1 x_399)) -(assert (<= 0 x_401)) -(assert (>= 1 x_401)) -(assert (<= 0 x_402)) -(assert (>= 1 x_402)) -(assert (<= 0 x_403)) -(assert (>= 1 x_403)) -(assert (<= 0 x_404)) -(assert (>= 1 x_404)) -(assert (<= 0 x_406)) -(assert (>= 1 x_406)) -(assert (<= 0 x_407)) -(assert (>= 1 x_407)) -(assert (<= 0 x_408)) -(assert (>= 1 x_408)) -(assert (<= 0 x_409)) -(assert (>= 1 x_409)) -(assert (<= 0 x_411)) -(assert (>= 1 x_411)) -(assert (<= 0 x_412)) -(assert (>= 1 x_412)) -(assert (<= 0 x_413)) -(assert (>= 1 x_413)) -(assert (<= 0 x_414)) -(assert (>= 1 x_414)) -(assert (<= 0 x_416)) -(assert (>= 1 x_416)) -(assert (<= 0 x_417)) -(assert (>= 1 x_417)) -(assert (<= 0 x_418)) -(assert (>= 1 x_418)) -(assert (<= 0 x_419)) -(assert (>= 1 x_419)) -(assert (<= 0 x_421)) -(assert (>= 1 x_421)) -(assert (<= 0 x_422)) -(assert (>= 1 x_422)) -(assert (<= 0 x_423)) -(assert (>= 1 x_423)) -(assert (<= 0 x_424)) -(assert (>= 1 x_424)) -(assert (<= 0 x_426)) -(assert (>= 1 x_426)) -(assert (<= 0 x_427)) -(assert (>= 1 x_427)) -(assert (<= 0 x_428)) -(assert (>= 1 x_428)) -(assert (<= 0 x_429)) -(assert (>= 1 x_429)) -(assert (<= 0 x_431)) -(assert (>= 1 x_431)) -(assert (<= 0 x_432)) -(assert (>= 1 x_432)) -(assert (<= 0 x_433)) -(assert (>= 1 x_433)) -(assert (<= 0 x_434)) -(assert (>= 1 x_434)) -(assert (<= 0 x_436)) -(assert (>= 1 x_436)) -(assert (<= 0 x_437)) -(assert (>= 1 x_437)) -(assert (<= 0 x_438)) -(assert (>= 1 x_438)) -(assert (<= 0 x_439)) -(assert (>= 1 x_439)) -(assert (<= 0 x_441)) -(assert (>= 1 x_441)) -(assert (<= 0 x_442)) -(assert (>= 1 x_442)) -(assert (<= 0 x_443)) -(assert (>= 1 x_443)) -(assert (<= 0 x_444)) -(assert (>= 1 x_444)) -(assert (<= 0 x_446)) -(assert (>= 1 x_446)) -(assert (<= 0 x_447)) -(assert (>= 1 x_447)) -(assert (<= 0 x_448)) -(assert (>= 1 x_448)) -(assert (<= 0 x_449)) -(assert (>= 1 x_449)) -(assert (<= 0 x_451)) -(assert (>= 1 x_451)) -(assert (<= 0 x_452)) -(assert (>= 1 x_452)) -(assert (<= 0 x_453)) -(assert (>= 1 x_453)) -(assert (<= 0 x_454)) -(assert (>= 1 x_454)) -(assert (<= 0 x_456)) -(assert (>= 1 x_456)) -(assert (<= 0 x_457)) -(assert (>= 1 x_457)) -(assert (<= 0 x_458)) -(assert (>= 1 x_458)) -(assert (<= 0 x_459)) -(assert (>= 1 x_459)) -(assert (<= 0 x_461)) -(assert (>= 1 x_461)) -(assert (<= 0 x_462)) -(assert (>= 1 x_462)) -(assert (<= 0 x_463)) -(assert (>= 1 x_463)) -(assert (<= 0 x_464)) -(assert (>= 1 x_464)) -(assert (<= 0 x_466)) -(assert (>= 1 x_466)) -(assert (<= 0 x_467)) -(assert (>= 1 x_467)) -(assert (<= 0 x_468)) -(assert (>= 1 x_468)) -(assert (<= 0 x_469)) -(assert (>= 1 x_469)) -(assert (<= 0 x_471)) -(assert (>= 1 x_471)) -(assert (<= 0 x_472)) -(assert (>= 1 x_472)) -(assert (<= 0 x_473)) -(assert (>= 1 x_473)) -(assert (<= 0 x_474)) -(assert (>= 1 x_474)) -(assert (<= 0 x_476)) -(assert (>= 1 x_476)) -(assert (<= 0 x_477)) -(assert (>= 1 x_477)) -(assert (<= 0 x_478)) -(assert (>= 1 x_478)) -(assert (<= 0 x_479)) -(assert (>= 1 x_479)) -(assert (<= 0 x_481)) -(assert (>= 1 x_481)) -(assert (<= 0 x_482)) -(assert (>= 1 x_482)) -(assert (<= 0 x_483)) -(assert (>= 1 x_483)) -(assert (<= 0 x_484)) -(assert (>= 1 x_484)) -(assert (<= 0 x_486)) -(assert (>= 1 x_486)) -(assert (<= 0 x_487)) -(assert (>= 1 x_487)) -(assert (<= 0 x_488)) -(assert (>= 1 x_488)) -(assert (<= 0 x_489)) -(assert (>= 1 x_489)) -(assert (<= 0 x_491)) -(assert (>= 1 x_491)) -(assert (<= 0 x_492)) -(assert (>= 1 x_492)) -(assert (<= 0 x_493)) -(assert (>= 1 x_493)) -(assert (<= 0 x_494)) -(assert (>= 1 x_494)) -(assert (<= 0 x_496)) -(assert (>= 1 x_496)) -(assert (<= 0 x_497)) -(assert (>= 1 x_497)) -(assert (<= 0 x_498)) -(assert (>= 1 x_498)) -(assert (<= 0 x_499)) -(assert (>= 1 x_499)) -(assert (<= 0 x_501)) -(assert (>= 1 x_501)) -(assert (<= 0 x_502)) -(assert (>= 1 x_502)) -(assert (<= 0 x_503)) -(assert (>= 1 x_503)) -(assert (<= 0 x_504)) -(assert (>= 1 x_504)) -(assert (<= 0 x_506)) -(assert (>= 1 x_506)) -(assert (<= 0 x_507)) -(assert (>= 1 x_507)) -(assert (<= 0 x_508)) -(assert (>= 1 x_508)) -(assert (<= 0 x_509)) -(assert (>= 1 x_509)) -(assert (<= 0 x_511)) -(assert (>= 1 x_511)) -(assert (<= 0 x_512)) -(assert (>= 1 x_512)) -(assert (<= 0 x_513)) -(assert (>= 1 x_513)) -(assert (<= 0 x_514)) -(assert (>= 1 x_514)) -(assert (<= 0 x_516)) -(assert (>= 1 x_516)) -(assert (<= 0 x_517)) -(assert (>= 1 x_517)) -(assert (<= 0 x_518)) -(assert (>= 1 x_518)) -(assert (<= 0 x_519)) -(assert (>= 1 x_519)) -(assert (<= 0 x_521)) -(assert (>= 1 x_521)) -(assert (<= 0 x_522)) -(assert (>= 1 x_522)) -(assert (<= 0 x_523)) -(assert (>= 1 x_523)) -(assert (<= 0 x_524)) -(assert (>= 1 x_524)) -(assert (<= 0 x_526)) -(assert (>= 1 x_526)) -(assert (<= 0 x_527)) -(assert (>= 1 x_527)) -(assert (<= 0 x_528)) -(assert (>= 1 x_528)) -(assert (<= 0 x_529)) -(assert (>= 1 x_529)) -(assert (<= 0 x_531)) -(assert (>= 1 x_531)) -(assert (<= 0 x_532)) -(assert (>= 1 x_532)) -(assert (<= 0 x_533)) -(assert (>= 1 x_533)) -(assert (<= 0 x_534)) -(assert (>= 1 x_534)) -(assert (<= 0 x_536)) -(assert (>= 1 x_536)) -(assert (<= 0 x_537)) -(assert (>= 1 x_537)) -(assert (<= 0 x_538)) -(assert (>= 1 x_538)) -(assert (<= 0 x_539)) -(assert (>= 1 x_539)) -(assert (<= 0 x_541)) -(assert (>= 1 x_541)) -(assert (<= 0 x_542)) -(assert (>= 1 x_542)) -(assert (<= 0 x_543)) -(assert (>= 1 x_543)) -(assert (<= 0 x_544)) -(assert (>= 1 x_544)) -(assert (<= 0 x_546)) -(assert (>= 1 x_546)) -(assert (<= 0 x_547)) -(assert (>= 1 x_547)) -(assert (<= 0 x_548)) -(assert (>= 1 x_548)) -(assert (<= 0 x_549)) -(assert (>= 1 x_549)) -(assert (<= 0 x_551)) -(assert (>= 1 x_551)) -(assert (<= 0 x_552)) -(assert (>= 1 x_552)) -(assert (<= 0 x_553)) -(assert (>= 1 x_553)) -(assert (<= 0 x_554)) -(assert (>= 1 x_554)) -(assert (<= 0 x_556)) -(assert (>= 1 x_556)) -(assert (<= 0 x_557)) -(assert (>= 1 x_557)) -(assert (<= 0 x_558)) -(assert (>= 1 x_558)) -(assert (<= 0 x_559)) -(assert (>= 1 x_559)) -(assert (<= 0 x_561)) -(assert (>= 1 x_561)) -(assert (<= 0 x_562)) -(assert (>= 1 x_562)) -(assert (<= 0 x_563)) -(assert (>= 1 x_563)) -(assert (<= 0 x_564)) -(assert (>= 1 x_564)) -(assert (<= 0 x_566)) -(assert (>= 1 x_566)) -(assert (<= 0 x_567)) -(assert (>= 1 x_567)) -(assert (<= 0 x_568)) -(assert (>= 1 x_568)) -(assert (<= 0 x_569)) -(assert (>= 1 x_569)) -(assert (<= 0 x_571)) -(assert (>= 1 x_571)) -(assert (<= 0 x_572)) -(assert (>= 1 x_572)) -(assert (<= 0 x_573)) -(assert (>= 1 x_573)) -(assert (<= 0 x_574)) -(assert (>= 1 x_574)) -(assert (<= 0 x_576)) -(assert (>= 1 x_576)) -(assert (<= 0 x_577)) -(assert (>= 1 x_577)) -(assert (<= 0 x_578)) -(assert (>= 1 x_578)) -(assert (<= 0 x_579)) -(assert (>= 1 x_579)) -(assert (<= 0 x_581)) -(assert (>= 1 x_581)) -(assert (<= 0 x_582)) -(assert (>= 1 x_582)) -(assert (<= 0 x_583)) -(assert (>= 1 x_583)) -(assert (<= 0 x_584)) -(assert (>= 1 x_584)) -(assert (<= 0 x_586)) -(assert (>= 1 x_586)) -(assert (<= 0 x_587)) -(assert (>= 1 x_587)) -(assert (<= 0 x_588)) -(assert (>= 1 x_588)) -(assert (<= 0 x_589)) -(assert (>= 1 x_589)) -(assert (<= 0 x_591)) -(assert (>= 1 x_591)) -(assert (<= 0 x_592)) -(assert (>= 1 x_592)) -(assert (<= 0 x_593)) -(assert (>= 1 x_593)) -(assert (<= 0 x_594)) -(assert (>= 1 x_594)) -(assert (<= 0 x_596)) -(assert (>= 1 x_596)) -(assert (<= 0 x_597)) -(assert (>= 1 x_597)) -(assert (<= 0 x_598)) -(assert (>= 1 x_598)) -(assert (<= 0 x_599)) -(assert (>= 1 x_599)) -(assert (<= 0 x_601)) -(assert (>= 1 x_601)) -(assert (<= 0 x_602)) -(assert (>= 1 x_602)) -(assert (<= 0 x_603)) -(assert (>= 1 x_603)) -(assert (<= 0 x_604)) -(assert (>= 1 x_604)) -(assert (<= 0 x_606)) -(assert (>= 1 x_606)) -(assert (<= 0 x_607)) -(assert (>= 1 x_607)) -(assert (<= 0 x_608)) -(assert (>= 1 x_608)) -(assert (<= 0 x_609)) -(assert (>= 1 x_609)) -(assert (<= 0 x_611)) -(assert (>= 1 x_611)) -(assert (<= 0 x_612)) -(assert (>= 1 x_612)) -(assert (<= 0 x_613)) -(assert (>= 1 x_613)) -(assert (<= 0 x_614)) -(assert (>= 1 x_614)) -(assert (<= 0 x_616)) -(assert (>= 1 x_616)) -(assert (<= 0 x_617)) -(assert (>= 1 x_617)) -(assert (<= 0 x_618)) -(assert (>= 1 x_618)) -(assert (<= 0 x_619)) -(assert (>= 1 x_619)) -(assert (<= 0 x_621)) -(assert (>= 1 x_621)) -(assert (<= 0 x_622)) -(assert (>= 1 x_622)) -(assert (<= 0 x_623)) -(assert (>= 1 x_623)) -(assert (<= 0 x_624)) -(assert (>= 1 x_624)) -(assert (<= 0 x_626)) -(assert (>= 1 x_626)) -(assert (<= 0 x_627)) -(assert (>= 1 x_627)) -(assert (<= 0 x_628)) -(assert (>= 1 x_628)) -(assert (<= 0 x_629)) -(assert (>= 1 x_629)) -(assert (<= 0 x_631)) -(assert (>= 1 x_631)) -(assert (<= 0 x_632)) -(assert (>= 1 x_632)) -(assert (<= 0 x_633)) -(assert (>= 1 x_633)) -(assert (<= 0 x_634)) -(assert (>= 1 x_634)) -(assert (<= 0 x_636)) -(assert (>= 1 x_636)) -(assert (<= 0 x_637)) -(assert (>= 1 x_637)) -(assert (<= 0 x_638)) -(assert (>= 1 x_638)) -(assert (<= 0 x_639)) -(assert (>= 1 x_639)) -(assert (<= 0 x_641)) -(assert (>= 1 x_641)) -(assert (<= 0 x_642)) -(assert (>= 1 x_642)) -(assert (<= 0 x_643)) -(assert (>= 1 x_643)) -(assert (<= 0 x_644)) -(assert (>= 1 x_644)) -(assert (<= 0 x_646)) -(assert (>= 1 x_646)) -(assert (<= 0 x_647)) -(assert (>= 1 x_647)) -(assert (<= 0 x_648)) -(assert (>= 1 x_648)) -(assert (<= 0 x_649)) -(assert (>= 1 x_649)) -(assert (<= 0 x_651)) -(assert (>= 1 x_651)) -(assert (<= 0 x_652)) -(assert (>= 1 x_652)) -(assert (<= 0 x_653)) -(assert (>= 1 x_653)) -(assert (<= 0 x_654)) -(assert (>= 1 x_654)) -(assert (<= 0 x_656)) -(assert (>= 1 x_656)) -(assert (<= 0 x_657)) -(assert (>= 1 x_657)) -(assert (<= 0 x_658)) -(assert (>= 1 x_658)) -(assert (<= 0 x_659)) -(assert (>= 1 x_659)) -(assert (<= 0 x_661)) -(assert (>= 1 x_661)) -(assert (<= 0 x_662)) -(assert (>= 1 x_662)) -(assert (<= 0 x_663)) -(assert (>= 1 x_663)) -(assert (<= 0 x_664)) -(assert (>= 1 x_664)) -(assert (<= 0 x_666)) -(assert (>= 1 x_666)) -(assert (<= 0 x_667)) -(assert (>= 1 x_667)) -(assert (<= 0 x_668)) -(assert (>= 1 x_668)) -(assert (<= 0 x_669)) -(assert (>= 1 x_669)) -(assert (<= 0 x_671)) -(assert (>= 1 x_671)) -(assert (<= 0 x_672)) -(assert (>= 1 x_672)) -(assert (<= 0 x_673)) -(assert (>= 1 x_673)) -(assert (<= 0 x_674)) -(assert (>= 1 x_674)) -(assert (<= 0 x_676)) -(assert (>= 1 x_676)) -(assert (<= 0 x_677)) -(assert (>= 1 x_677)) -(assert (<= 0 x_678)) -(assert (>= 1 x_678)) -(assert (<= 0 x_679)) -(assert (>= 1 x_679)) -(assert (<= 0 x_681)) -(assert (>= 1 x_681)) -(assert (<= 0 x_682)) -(assert (>= 1 x_682)) -(assert (<= 0 x_683)) -(assert (>= 1 x_683)) -(assert (<= 0 x_684)) -(assert (>= 1 x_684)) -(assert (<= 0 x_686)) -(assert (>= 1 x_686)) -(assert (<= 0 x_687)) -(assert (>= 1 x_687)) -(assert (<= 0 x_688)) -(assert (>= 1 x_688)) -(assert (<= 0 x_689)) -(assert (>= 1 x_689)) -(assert (<= 0 x_691)) -(assert (>= 1 x_691)) -(assert (<= 0 x_692)) -(assert (>= 1 x_692)) -(assert (<= 0 x_693)) -(assert (>= 1 x_693)) -(assert (<= 0 x_694)) -(assert (>= 1 x_694)) -(assert (<= 0 x_696)) -(assert (>= 1 x_696)) -(assert (<= 0 x_697)) -(assert (>= 1 x_697)) -(assert (<= 0 x_698)) -(assert (>= 1 x_698)) -(assert (<= 0 x_699)) -(assert (>= 1 x_699)) -(assert (<= 0 x_701)) -(assert (>= 1 x_701)) -(assert (<= 0 x_702)) -(assert (>= 1 x_702)) -(assert (<= 0 x_703)) -(assert (>= 1 x_703)) -(assert (<= 0 x_704)) -(assert (>= 1 x_704)) -(assert (<= 0 x_706)) -(assert (>= 1 x_706)) -(assert (<= 0 x_707)) -(assert (>= 1 x_707)) -(assert (<= 0 x_708)) -(assert (>= 1 x_708)) -(assert (<= 0 x_709)) -(assert (>= 1 x_709)) -(assert (<= 0 x_711)) -(assert (>= 1 x_711)) -(assert (<= 0 x_712)) -(assert (>= 1 x_712)) -(assert (<= 0 x_713)) -(assert (>= 1 x_713)) -(assert (<= 0 x_714)) -(assert (>= 1 x_714)) -(assert (<= 0 x_716)) -(assert (>= 1 x_716)) -(assert (<= 0 x_717)) -(assert (>= 1 x_717)) -(assert (<= 0 x_718)) -(assert (>= 1 x_718)) -(assert (<= 0 x_719)) -(assert (>= 1 x_719)) -(assert (<= 0 x_721)) -(assert (>= 1 x_721)) -(assert (<= 0 x_722)) -(assert (>= 1 x_722)) -(assert (<= 0 x_723)) -(assert (>= 1 x_723)) -(assert (<= 0 x_724)) -(assert (>= 1 x_724)) -(assert (<= 0 x_726)) -(assert (>= 1 x_726)) -(assert (<= 0 x_727)) -(assert (>= 1 x_727)) -(assert (<= 0 x_728)) -(assert (>= 1 x_728)) -(assert (<= 0 x_729)) -(assert (>= 1 x_729)) -(assert (<= 0 x_731)) -(assert (>= 1 x_731)) -(assert (<= 0 x_732)) -(assert (>= 1 x_732)) -(assert (<= 0 x_733)) -(assert (>= 1 x_733)) -(assert (<= 0 x_734)) -(assert (>= 1 x_734)) -(assert (<= 0 x_736)) -(assert (>= 1 x_736)) -(assert (<= 0 x_737)) -(assert (>= 1 x_737)) -(assert (<= 0 x_738)) -(assert (>= 1 x_738)) -(assert (<= 0 x_739)) -(assert (>= 1 x_739)) -(assert (<= 0 x_741)) -(assert (>= 1 x_741)) -(assert (<= 0 x_742)) -(assert (>= 1 x_742)) -(assert (<= 0 x_743)) -(assert (>= 1 x_743)) -(assert (<= 0 x_744)) -(assert (>= 1 x_744)) -(assert (<= 0 x_746)) -(assert (>= 1 x_746)) -(assert (<= 0 x_747)) -(assert (>= 1 x_747)) -(assert (<= 0 x_748)) -(assert (>= 1 x_748)) -(assert (<= 0 x_749)) -(assert (>= 1 x_749)) -(assert (<= 0 x_751)) -(assert (>= 1 x_751)) -(assert (<= 0 x_752)) -(assert (>= 1 x_752)) -(assert (<= 0 x_753)) -(assert (>= 1 x_753)) -(assert (<= 0 x_754)) -(assert (>= 1 x_754)) -(assert (<= 0 x_756)) -(assert (>= 1 x_756)) -(assert (<= 0 x_757)) -(assert (>= 1 x_757)) -(assert (<= 0 x_758)) -(assert (>= 1 x_758)) -(assert (<= 0 x_759)) -(assert (>= 1 x_759)) -(assert (<= 0 x_761)) -(assert (>= 1 x_761)) -(assert (<= 0 x_762)) -(assert (>= 1 x_762)) -(assert (<= 0 x_763)) -(assert (>= 1 x_763)) -(assert (<= 0 x_764)) -(assert (>= 1 x_764)) -(assert (<= 0 x_766)) -(assert (>= 1 x_766)) -(assert (<= 0 x_767)) -(assert (>= 1 x_767)) -(assert (<= 0 x_768)) -(assert (>= 1 x_768)) -(assert (<= 0 x_769)) -(assert (>= 1 x_769)) -(assert (<= 0 x_771)) -(assert (>= 1 x_771)) -(assert (<= 0 x_772)) -(assert (>= 1 x_772)) -(assert (<= 0 x_773)) -(assert (>= 1 x_773)) -(assert (<= 0 x_774)) -(assert (>= 1 x_774)) -(assert (<= 0 x_776)) -(assert (>= 1 x_776)) -(assert (<= 0 x_777)) -(assert (>= 1 x_777)) -(assert (<= 0 x_778)) -(assert (>= 1 x_778)) -(assert (<= 0 x_779)) -(assert (>= 1 x_779)) -(assert (<= 0 x_781)) -(assert (>= 1 x_781)) -(assert (<= 0 x_782)) -(assert (>= 1 x_782)) -(assert (<= 0 x_783)) -(assert (>= 1 x_783)) -(assert (<= 0 x_784)) -(assert (>= 1 x_784)) -(assert (<= 0 x_786)) -(assert (>= 1 x_786)) -(assert (<= 0 x_787)) -(assert (>= 1 x_787)) -(assert (<= 0 x_788)) -(assert (>= 1 x_788)) -(assert (<= 0 x_789)) -(assert (>= 1 x_789)) -(assert (<= 0 x_791)) -(assert (>= 1 x_791)) -(assert (<= 0 x_792)) -(assert (>= 1 x_792)) -(assert (<= 0 x_793)) -(assert (>= 1 x_793)) -(assert (<= 0 x_794)) -(assert (>= 1 x_794)) -(assert (<= 0 x_796)) -(assert (>= 1 x_796)) -(assert (<= 0 x_797)) -(assert (>= 1 x_797)) -(assert (<= 0 x_798)) -(assert (>= 1 x_798)) -(assert (<= 0 x_799)) -(assert (>= 1 x_799)) -(assert (<= 0 x_801)) -(assert (>= 1 x_801)) -(assert (<= 0 x_802)) -(assert (>= 1 x_802)) -(assert (<= 0 x_803)) -(assert (>= 1 x_803)) -(assert (<= 0 x_804)) -(assert (>= 1 x_804)) -(assert (<= 0 x_806)) -(assert (>= 1 x_806)) -(assert (<= 0 x_807)) -(assert (>= 1 x_807)) -(assert (<= 0 x_808)) -(assert (>= 1 x_808)) -(assert (<= 0 x_809)) -(assert (>= 1 x_809)) -(assert (<= 0 x_811)) -(assert (>= 1 x_811)) -(assert (<= 0 x_812)) -(assert (>= 1 x_812)) -(assert (<= 0 x_813)) -(assert (>= 1 x_813)) -(assert (<= 0 x_814)) -(assert (>= 1 x_814)) -(assert (<= 0 x_816)) -(assert (>= 1 x_816)) -(assert (<= 0 x_817)) -(assert (>= 1 x_817)) -(assert (<= 0 x_818)) -(assert (>= 1 x_818)) -(assert (<= 0 x_819)) -(assert (>= 1 x_819)) -(assert (<= 0 x_821)) -(assert (>= 1 x_821)) -(assert (<= 0 x_822)) -(assert (>= 1 x_822)) -(assert (<= 0 x_823)) -(assert (>= 1 x_823)) -(assert (<= 0 x_824)) -(assert (>= 1 x_824)) -(assert (<= 0 x_826)) -(assert (>= 1 x_826)) -(assert (<= 0 x_827)) -(assert (>= 1 x_827)) -(assert (<= 0 x_828)) -(assert (>= 1 x_828)) -(assert (<= 0 x_829)) -(assert (>= 1 x_829)) -(assert (<= 0 x_831)) -(assert (>= 1 x_831)) -(assert (<= 0 x_832)) -(assert (>= 1 x_832)) -(assert (<= 0 x_833)) -(assert (>= 1 x_833)) -(assert (<= 0 x_834)) -(assert (>= 1 x_834)) -(assert (<= 0 x_836)) -(assert (>= 1 x_836)) -(assert (<= 0 x_837)) -(assert (>= 1 x_837)) -(assert (<= 0 x_838)) -(assert (>= 1 x_838)) -(assert (<= 0 x_839)) -(assert (>= 1 x_839)) -(assert (<= 0 x_841)) -(assert (>= 1 x_841)) -(assert (<= 0 x_842)) -(assert (>= 1 x_842)) -(assert (<= 0 x_843)) -(assert (>= 1 x_843)) -(assert (<= 0 x_844)) -(assert (>= 1 x_844)) -(assert (<= 0 x_846)) -(assert (>= 1 x_846)) -(assert (<= 0 x_847)) -(assert (>= 1 x_847)) -(assert (<= 0 x_848)) -(assert (>= 1 x_848)) -(assert (<= 0 x_849)) -(assert (>= 1 x_849)) -(assert (<= 0 x_851)) -(assert (>= 1 x_851)) -(assert (<= 0 x_852)) -(assert (>= 1 x_852)) -(assert (<= 0 x_853)) -(assert (>= 1 x_853)) -(assert (<= 0 x_854)) -(assert (>= 1 x_854)) -(assert (<= 0 x_856)) -(assert (>= 1 x_856)) -(assert (<= 0 x_857)) -(assert (>= 1 x_857)) -(assert (<= 0 x_858)) -(assert (>= 1 x_858)) -(assert (<= 0 x_859)) -(assert (>= 1 x_859)) -(assert (<= 0 x_861)) -(assert (>= 1 x_861)) -(assert (<= 0 x_862)) -(assert (>= 1 x_862)) -(assert (<= 0 x_863)) -(assert (>= 1 x_863)) -(assert (<= 0 x_864)) -(assert (>= 1 x_864)) -(assert (<= 0 x_866)) -(assert (>= 1 x_866)) -(assert (<= 0 x_867)) -(assert (>= 1 x_867)) -(assert (<= 0 x_868)) -(assert (>= 1 x_868)) -(assert (<= 0 x_869)) -(assert (>= 1 x_869)) -(assert (<= 0 x_871)) -(assert (>= 1 x_871)) -(assert (<= 0 x_872)) -(assert (>= 1 x_872)) -(assert (<= 0 x_873)) -(assert (>= 1 x_873)) -(assert (<= 0 x_874)) -(assert (>= 1 x_874)) -(assert (<= 0 x_876)) -(assert (>= 1 x_876)) -(assert (<= 0 x_877)) -(assert (>= 1 x_877)) -(assert (<= 0 x_878)) -(assert (>= 1 x_878)) -(assert (<= 0 x_879)) -(assert (>= 1 x_879)) -(assert (<= 0 x_881)) -(assert (>= 1 x_881)) -(assert (<= 0 x_882)) -(assert (>= 1 x_882)) -(assert (<= 0 x_883)) -(assert (>= 1 x_883)) -(assert (<= 0 x_884)) -(assert (>= 1 x_884)) -(assert (<= 0 x_886)) -(assert (>= 1 x_886)) -(assert (<= 0 x_887)) -(assert (>= 1 x_887)) -(assert (<= 0 x_888)) -(assert (>= 1 x_888)) -(assert (<= 0 x_889)) -(assert (>= 1 x_889)) -(assert (<= 0 x_891)) -(assert (>= 1 x_891)) -(assert (<= 0 x_892)) -(assert (>= 1 x_892)) -(assert (<= 0 x_893)) -(assert (>= 1 x_893)) -(assert (<= 0 x_894)) -(assert (>= 1 x_894)) -(assert (<= 0 x_896)) -(assert (>= 1 x_896)) -(assert (<= 0 x_897)) -(assert (>= 1 x_897)) -(assert (<= 0 x_898)) -(assert (>= 1 x_898)) -(assert (<= 0 x_899)) -(assert (>= 1 x_899)) -(assert (<= 0 x_901)) -(assert (>= 1 x_901)) -(assert (<= 0 x_902)) -(assert (>= 1 x_902)) -(assert (<= 0 x_903)) -(assert (>= 1 x_903)) -(assert (<= 0 x_904)) -(assert (>= 1 x_904)) -(assert (<= 0 x_906)) -(assert (>= 1 x_906)) -(assert (<= 0 x_907)) -(assert (>= 1 x_907)) -(assert (<= 0 x_908)) -(assert (>= 1 x_908)) -(assert (<= 0 x_909)) -(assert (>= 1 x_909)) -(assert (<= 0 x_911)) -(assert (>= 1 x_911)) -(assert (<= 0 x_912)) -(assert (>= 1 x_912)) -(assert (<= 0 x_913)) -(assert (>= 1 x_913)) -(assert (<= 0 x_914)) -(assert (>= 1 x_914)) -(assert (<= 0 x_916)) -(assert (>= 1 x_916)) -(assert (<= 0 x_917)) -(assert (>= 1 x_917)) -(assert (<= 0 x_918)) -(assert (>= 1 x_918)) -(assert (<= 0 x_919)) -(assert (>= 1 x_919)) -(assert (<= 0 x_921)) -(assert (>= 1 x_921)) -(assert (<= 0 x_922)) -(assert (>= 1 x_922)) -(assert (<= 0 x_923)) -(assert (>= 1 x_923)) -(assert (<= 0 x_924)) -(assert (>= 1 x_924)) -(assert (<= 0 x_926)) -(assert (>= 1 x_926)) -(assert (<= 0 x_927)) -(assert (>= 1 x_927)) -(assert (<= 0 x_928)) -(assert (>= 1 x_928)) -(assert (<= 0 x_929)) -(assert (>= 1 x_929)) -(assert (<= 0 x_931)) -(assert (>= 1 x_931)) -(assert (<= 0 x_932)) -(assert (>= 1 x_932)) -(assert (<= 0 x_933)) -(assert (>= 1 x_933)) -(assert (<= 0 x_934)) -(assert (>= 1 x_934)) -(assert (<= 0 x_936)) -(assert (>= 1 x_936)) -(assert (<= 0 x_937)) -(assert (>= 1 x_937)) -(assert (<= 0 x_938)) -(assert (>= 1 x_938)) -(assert (<= 0 x_939)) -(assert (>= 1 x_939)) -(assert (<= 0 x_941)) -(assert (>= 1 x_941)) -(assert (<= 0 x_942)) -(assert (>= 1 x_942)) -(assert (<= 0 x_943)) -(assert (>= 1 x_943)) -(assert (<= 0 x_944)) -(assert (>= 1 x_944)) -(assert (<= 0 x_946)) -(assert (>= 1 x_946)) -(assert (<= 0 x_947)) -(assert (>= 1 x_947)) -(assert (<= 0 x_948)) -(assert (>= 1 x_948)) -(assert (<= 0 x_949)) -(assert (>= 1 x_949)) -(assert (<= 0 x_951)) -(assert (>= 1 x_951)) -(assert (<= 0 x_952)) -(assert (>= 1 x_952)) -(assert (<= 0 x_953)) -(assert (>= 1 x_953)) -(assert (<= 0 x_954)) -(assert (>= 1 x_954)) -(assert (<= 0 x_956)) -(assert (>= 1 x_956)) -(assert (<= 0 x_957)) -(assert (>= 1 x_957)) -(assert (<= 0 x_958)) -(assert (>= 1 x_958)) -(assert (<= 0 x_959)) -(assert (>= 1 x_959)) -(assert (<= 0 x_961)) -(assert (>= 1 x_961)) -(assert (<= 0 x_962)) -(assert (>= 1 x_962)) -(assert (<= 0 x_963)) -(assert (>= 1 x_963)) -(assert (<= 0 x_964)) -(assert (>= 1 x_964)) -(assert (<= 0 x_966)) -(assert (>= 1 x_966)) -(assert (<= 0 x_967)) -(assert (>= 1 x_967)) -(assert (<= 0 x_968)) -(assert (>= 1 x_968)) -(assert (<= 0 x_969)) -(assert (>= 1 x_969)) -(assert (<= 0 x_971)) -(assert (>= 1 x_971)) -(assert (<= 0 x_972)) -(assert (>= 1 x_972)) -(assert (<= 0 x_973)) -(assert (>= 1 x_973)) -(assert (<= 0 x_974)) -(assert (>= 1 x_974)) -(assert (<= 0 x_976)) -(assert (>= 1 x_976)) -(assert (<= 0 x_977)) -(assert (>= 1 x_977)) -(assert (<= 0 x_978)) -(assert (>= 1 x_978)) -(assert (<= 0 x_979)) -(assert (>= 1 x_979)) -(assert (<= 0 x_981)) -(assert (>= 1 x_981)) -(assert (<= 0 x_982)) -(assert (>= 1 x_982)) -(assert (<= 0 x_983)) -(assert (>= 1 x_983)) -(assert (<= 0 x_984)) -(assert (>= 1 x_984)) -(assert (<= 0 x_986)) -(assert (>= 1 x_986)) -(assert (<= 0 x_987)) -(assert (>= 1 x_987)) -(assert (<= 0 x_988)) -(assert (>= 1 x_988)) -(assert (<= 0 x_989)) -(assert (>= 1 x_989)) -(assert (<= 0 x_991)) -(assert (>= 1 x_991)) -(assert (<= 0 x_992)) -(assert (>= 1 x_992)) -(assert (<= 0 x_993)) -(assert (>= 1 x_993)) -(assert (<= 0 x_994)) -(assert (>= 1 x_994)) -(assert (<= 0 x_996)) -(assert (>= 1 x_996)) -(assert (<= 0 x_997)) -(assert (>= 1 x_997)) -(assert (<= 0 x_998)) -(assert (>= 1 x_998)) -(assert (<= 0 x_999)) -(assert (>= 1 x_999)) -(assert (<= 0 x_1001)) -(assert (>= 1 x_1001)) -(assert (<= 0 x_1202)) -(assert (>= 1 x_1202)) -(assert (<= 0 x_1403)) -(assert (>= 1 x_1403)) -(assert (<= 0 x_1604)) -(assert (>= 1 x_1604)) -(assert (= 1 (+ x_1 x_2 x_3 x_4))) -(assert (= 1 (+ x_6 x_7 x_8 x_9))) -(assert (= 1 (+ x_11 x_12 x_13 x_14))) -(assert (= 1 (+ x_16 x_17 x_18 x_19))) -(assert (= 1 (+ x_21 x_22 x_23 x_24))) -(assert (= 1 (+ x_26 x_27 x_28 x_29))) -(assert (= 1 (+ x_31 x_32 x_33 x_34))) -(assert (= 1 (+ x_36 x_37 x_38 x_39))) -(assert (= 1 (+ x_41 x_42 x_43 x_44))) -(assert (= 1 (+ x_46 x_47 x_48 x_49))) -(assert (= 1 (+ x_51 x_52 x_53 x_54))) -(assert (= 1 (+ x_56 x_57 x_58 x_59))) -(assert (= 1 (+ x_61 x_62 x_63 x_64))) -(assert (= 1 (+ x_66 x_67 x_68 x_69))) -(assert (= 1 (+ x_71 x_72 x_73 x_74))) -(assert (= 1 (+ x_76 x_77 x_78 x_79))) -(assert (= 1 (+ x_81 x_82 x_83 x_84))) -(assert (= 1 (+ x_86 x_87 x_88 x_89))) -(assert (= 1 (+ x_91 x_92 x_93 x_94))) -(assert (= 1 (+ x_96 x_97 x_98 x_99))) -(assert (= 1 (+ x_101 x_102 x_103 x_104))) -(assert (= 1 (+ x_106 x_107 x_108 x_109))) -(assert (= 1 (+ x_111 x_112 x_113 x_114))) -(assert (= 1 (+ x_116 x_117 x_118 x_119))) -(assert (= 1 (+ x_121 x_122 x_123 x_124))) -(assert (= 1 (+ x_126 x_127 x_128 x_129))) -(assert (= 1 (+ x_131 x_132 x_133 x_134))) -(assert (= 1 (+ x_136 x_137 x_138 x_139))) -(assert (= 1 (+ x_141 x_142 x_143 x_144))) -(assert (= 1 (+ x_146 x_147 x_148 x_149))) -(assert (= 1 (+ x_151 x_152 x_153 x_154))) -(assert (= 1 (+ x_156 x_157 x_158 x_159))) -(assert (= 1 (+ x_161 x_162 x_163 x_164))) -(assert (= 1 (+ x_166 x_167 x_168 x_169))) -(assert (= 1 (+ x_171 x_172 x_173 x_174))) -(assert (= 1 (+ x_176 x_177 x_178 x_179))) -(assert (= 1 (+ x_181 x_182 x_183 x_184))) -(assert (= 1 (+ x_186 x_187 x_188 x_189))) -(assert (= 1 (+ x_191 x_192 x_193 x_194))) -(assert (= 1 (+ x_196 x_197 x_198 x_199))) -(assert (= 1 (+ x_201 x_202 x_203 x_204))) -(assert (= 1 (+ x_206 x_207 x_208 x_209))) -(assert (= 1 (+ x_211 x_212 x_213 x_214))) -(assert (= 1 (+ x_216 x_217 x_218 x_219))) -(assert (= 1 (+ x_221 x_222 x_223 x_224))) -(assert (= 1 (+ x_226 x_227 x_228 x_229))) -(assert (= 1 (+ x_231 x_232 x_233 x_234))) -(assert (= 1 (+ x_236 x_237 x_238 x_239))) -(assert (= 1 (+ x_241 x_242 x_243 x_244))) -(assert (= 1 (+ x_246 x_247 x_248 x_249))) -(assert (= 1 (+ x_251 x_252 x_253 x_254))) -(assert (= 1 (+ x_256 x_257 x_258 x_259))) -(assert (= 1 (+ x_261 x_262 x_263 x_264))) -(assert (= 1 (+ x_266 x_267 x_268 x_269))) -(assert (= 1 (+ x_271 x_272 x_273 x_274))) -(assert (= 1 (+ x_276 x_277 x_278 x_279))) -(assert (= 1 (+ x_281 x_282 x_283 x_284))) -(assert (= 1 (+ x_286 x_287 x_288 x_289))) -(assert (= 1 (+ x_291 x_292 x_293 x_294))) -(assert (= 1 (+ x_296 x_297 x_298 x_299))) -(assert (= 1 (+ x_301 x_302 x_303 x_304))) -(assert (= 1 (+ x_306 x_307 x_308 x_309))) -(assert (= 1 (+ x_311 x_312 x_313 x_314))) -(assert (= 1 (+ x_316 x_317 x_318 x_319))) -(assert (= 1 (+ x_321 x_322 x_323 x_324))) -(assert (= 1 (+ x_326 x_327 x_328 x_329))) -(assert (= 1 (+ x_331 x_332 x_333 x_334))) -(assert (= 1 (+ x_336 x_337 x_338 x_339))) -(assert (= 1 (+ x_341 x_342 x_343 x_344))) -(assert (= 1 (+ x_346 x_347 x_348 x_349))) -(assert (= 1 (+ x_351 x_352 x_353 x_354))) -(assert (= 1 (+ x_356 x_357 x_358 x_359))) -(assert (= 1 (+ x_361 x_362 x_363 x_364))) -(assert (= 1 (+ x_366 x_367 x_368 x_369))) -(assert (= 1 (+ x_371 x_372 x_373 x_374))) -(assert (= 1 (+ x_376 x_377 x_378 x_379))) -(assert (= 1 (+ x_381 x_382 x_383 x_384))) -(assert (= 1 (+ x_386 x_387 x_388 x_389))) -(assert (= 1 (+ x_391 x_392 x_393 x_394))) -(assert (= 1 (+ x_396 x_397 x_398 x_399))) -(assert (= 1 (+ x_401 x_402 x_403 x_404))) -(assert (= 1 (+ x_406 x_407 x_408 x_409))) -(assert (= 1 (+ x_411 x_412 x_413 x_414))) -(assert (= 1 (+ x_416 x_417 x_418 x_419))) -(assert (= 1 (+ x_421 x_422 x_423 x_424))) -(assert (= 1 (+ x_426 x_427 x_428 x_429))) -(assert (= 1 (+ x_431 x_432 x_433 x_434))) -(assert (= 1 (+ x_436 x_437 x_438 x_439))) -(assert (= 1 (+ x_441 x_442 x_443 x_444))) -(assert (= 1 (+ x_446 x_447 x_448 x_449))) -(assert (= 1 (+ x_451 x_452 x_453 x_454))) -(assert (= 1 (+ x_456 x_457 x_458 x_459))) -(assert (= 1 (+ x_461 x_462 x_463 x_464))) -(assert (= 1 (+ x_466 x_467 x_468 x_469))) -(assert (= 1 (+ x_471 x_472 x_473 x_474))) -(assert (= 1 (+ x_476 x_477 x_478 x_479))) -(assert (= 1 (+ x_481 x_482 x_483 x_484))) -(assert (= 1 (+ x_486 x_487 x_488 x_489))) -(assert (= 1 (+ x_491 x_492 x_493 x_494))) -(assert (= 1 (+ x_496 x_497 x_498 x_499))) -(assert (= 1 (+ x_501 x_502 x_503 x_504))) -(assert (= 1 (+ x_506 x_507 x_508 x_509))) -(assert (= 1 (+ x_511 x_512 x_513 x_514))) -(assert (= 1 (+ x_516 x_517 x_518 x_519))) -(assert (= 1 (+ x_521 x_522 x_523 x_524))) -(assert (= 1 (+ x_526 x_527 x_528 x_529))) -(assert (= 1 (+ x_531 x_532 x_533 x_534))) -(assert (= 1 (+ x_536 x_537 x_538 x_539))) -(assert (= 1 (+ x_541 x_542 x_543 x_544))) -(assert (= 1 (+ x_546 x_547 x_548 x_549))) -(assert (= 1 (+ x_551 x_552 x_553 x_554))) -(assert (= 1 (+ x_556 x_557 x_558 x_559))) -(assert (= 1 (+ x_561 x_562 x_563 x_564))) -(assert (= 1 (+ x_566 x_567 x_568 x_569))) -(assert (= 1 (+ x_571 x_572 x_573 x_574))) -(assert (= 1 (+ x_576 x_577 x_578 x_579))) -(assert (= 1 (+ x_581 x_582 x_583 x_584))) -(assert (= 1 (+ x_586 x_587 x_588 x_589))) -(assert (= 1 (+ x_591 x_592 x_593 x_594))) -(assert (= 1 (+ x_596 x_597 x_598 x_599))) -(assert (= 1 (+ x_601 x_602 x_603 x_604))) -(assert (= 1 (+ x_606 x_607 x_608 x_609))) -(assert (= 1 (+ x_611 x_612 x_613 x_614))) -(assert (= 1 (+ x_616 x_617 x_618 x_619))) -(assert (= 1 (+ x_621 x_622 x_623 x_624))) -(assert (= 1 (+ x_626 x_627 x_628 x_629))) -(assert (= 1 (+ x_631 x_632 x_633 x_634))) -(assert (= 1 (+ x_636 x_637 x_638 x_639))) -(assert (= 1 (+ x_641 x_642 x_643 x_644))) -(assert (= 1 (+ x_646 x_647 x_648 x_649))) -(assert (= 1 (+ x_651 x_652 x_653 x_654))) -(assert (= 1 (+ x_656 x_657 x_658 x_659))) -(assert (= 1 (+ x_661 x_662 x_663 x_664))) -(assert (= 1 (+ x_666 x_667 x_668 x_669))) -(assert (= 1 (+ x_671 x_672 x_673 x_674))) -(assert (= 1 (+ x_676 x_677 x_678 x_679))) -(assert (= 1 (+ x_681 x_682 x_683 x_684))) -(assert (= 1 (+ x_686 x_687 x_688 x_689))) -(assert (= 1 (+ x_691 x_692 x_693 x_694))) -(assert (= 1 (+ x_696 x_697 x_698 x_699))) -(assert (= 1 (+ x_701 x_702 x_703 x_704))) -(assert (= 1 (+ x_706 x_707 x_708 x_709))) -(assert (= 1 (+ x_711 x_712 x_713 x_714))) -(assert (= 1 (+ x_716 x_717 x_718 x_719))) -(assert (= 1 (+ x_721 x_722 x_723 x_724))) -(assert (= 1 (+ x_726 x_727 x_728 x_729))) -(assert (= 1 (+ x_731 x_732 x_733 x_734))) -(assert (= 1 (+ x_736 x_737 x_738 x_739))) -(assert (= 1 (+ x_741 x_742 x_743 x_744))) -(assert (= 1 (+ x_746 x_747 x_748 x_749))) -(assert (= 1 (+ x_751 x_752 x_753 x_754))) -(assert (= 1 (+ x_756 x_757 x_758 x_759))) -(assert (= 1 (+ x_761 x_762 x_763 x_764))) -(assert (= 1 (+ x_766 x_767 x_768 x_769))) -(assert (= 1 (+ x_771 x_772 x_773 x_774))) -(assert (= 1 (+ x_776 x_777 x_778 x_779))) -(assert (= 1 (+ x_781 x_782 x_783 x_784))) -(assert (= 1 (+ x_786 x_787 x_788 x_789))) -(assert (= 1 (+ x_791 x_792 x_793 x_794))) -(assert (= 1 (+ x_796 x_797 x_798 x_799))) -(assert (= 1 (+ x_801 x_802 x_803 x_804))) -(assert (= 1 (+ x_806 x_807 x_808 x_809))) -(assert (= 1 (+ x_811 x_812 x_813 x_814))) -(assert (= 1 (+ x_816 x_817 x_818 x_819))) -(assert (= 1 (+ x_821 x_822 x_823 x_824))) -(assert (= 1 (+ x_826 x_827 x_828 x_829))) -(assert (= 1 (+ x_831 x_832 x_833 x_834))) -(assert (= 1 (+ x_836 x_837 x_838 x_839))) -(assert (= 1 (+ x_841 x_842 x_843 x_844))) -(assert (= 1 (+ x_846 x_847 x_848 x_849))) -(assert (= 1 (+ x_851 x_852 x_853 x_854))) -(assert (= 1 (+ x_856 x_857 x_858 x_859))) -(assert (= 1 (+ x_861 x_862 x_863 x_864))) -(assert (= 1 (+ x_866 x_867 x_868 x_869))) -(assert (= 1 (+ x_871 x_872 x_873 x_874))) -(assert (= 1 (+ x_876 x_877 x_878 x_879))) -(assert (= 1 (+ x_881 x_882 x_883 x_884))) -(assert (= 1 (+ x_886 x_887 x_888 x_889))) -(assert (= 1 (+ x_891 x_892 x_893 x_894))) -(assert (= 1 (+ x_896 x_897 x_898 x_899))) -(assert (= 1 (+ x_901 x_902 x_903 x_904))) -(assert (= 1 (+ x_906 x_907 x_908 x_909))) -(assert (= 1 (+ x_911 x_912 x_913 x_914))) -(assert (= 1 (+ x_916 x_917 x_918 x_919))) -(assert (= 1 (+ x_921 x_922 x_923 x_924))) -(assert (= 1 (+ x_926 x_927 x_928 x_929))) -(assert (= 1 (+ x_931 x_932 x_933 x_934))) -(assert (= 1 (+ x_936 x_937 x_938 x_939))) -(assert (= 1 (+ x_941 x_942 x_943 x_944))) -(assert (= 1 (+ x_946 x_947 x_948 x_949))) -(assert (= 1 (+ x_951 x_952 x_953 x_954))) -(assert (= 1 (+ x_956 x_957 x_958 x_959))) -(assert (= 1 (+ x_961 x_962 x_963 x_964))) -(assert (= 1 (+ x_966 x_967 x_968 x_969))) -(assert (= 1 (+ x_971 x_972 x_973 x_974))) -(assert (= 1 (+ x_976 x_977 x_978 x_979))) -(assert (= 1 (+ x_981 x_982 x_983 x_984))) -(assert (= 1 (+ x_986 x_987 x_988 x_989))) -(assert (= 1 (+ x_991 x_992 x_993 x_994))) -(assert (= 1 (+ x_996 x_997 x_998 x_999))) -(assert (<= 0 (+ x_1001 (* (- 1) x_4)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_9)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_14)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_19)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_24)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_29)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_34)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_39)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_44)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_49)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_54)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_59)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_64)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_69)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_74)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_79)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_84)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_89)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_94)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_99)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_104)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_109)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_114)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_119)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_124)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_129)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_134)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_139)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_144)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_149)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_154)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_159)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_164)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_169)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_174)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_179)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_184)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_189)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_194)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_199)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_204)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_209)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_214)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_219)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_224)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_229)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_234)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_239)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_244)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_249)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_254)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_259)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_264)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_269)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_274)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_279)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_284)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_289)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_294)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_299)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_304)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_309)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_314)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_319)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_324)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_329)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_334)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_339)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_344)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_349)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_354)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_359)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_364)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_369)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_374)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_379)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_384)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_389)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_394)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_399)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_404)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_409)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_414)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_419)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_424)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_429)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_434)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_439)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_444)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_449)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_454)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_459)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_464)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_469)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_474)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_479)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_484)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_489)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_494)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_499)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_504)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_509)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_514)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_519)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_524)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_529)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_534)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_539)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_544)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_549)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_554)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_559)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_564)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_569)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_574)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_579)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_584)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_589)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_594)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_599)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_604)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_609)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_614)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_619)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_624)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_629)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_634)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_639)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_644)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_649)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_654)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_659)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_664)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_669)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_674)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_679)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_684)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_689)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_694)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_699)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_704)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_709)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_714)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_719)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_724)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_729)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_734)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_739)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_744)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_749)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_754)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_759)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_764)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_769)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_774)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_779)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_784)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_789)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_794)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_799)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_804)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_809)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_814)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_819)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_824)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_829)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_834)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_839)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_844)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_849)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_854)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_859)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_864)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_869)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_874)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_879)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_884)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_889)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_894)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_899)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_904)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_909)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_914)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_919)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_924)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_929)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_934)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_939)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_944)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_949)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_954)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_959)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_964)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_969)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_974)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_979)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_984)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_989)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_994)))) -(assert (<= 0 (+ x_1001 (* (- 1) x_999)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_1)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_6)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_11)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_16)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_21)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_26)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_31)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_36)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_41)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_46)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_51)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_56)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_61)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_66)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_71)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_76)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_81)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_86)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_91)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_96)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_101)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_106)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_111)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_116)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_121)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_126)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_131)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_136)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_141)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_146)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_151)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_156)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_161)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_166)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_171)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_176)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_181)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_186)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_191)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_196)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_201)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_206)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_211)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_216)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_221)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_226)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_231)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_236)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_241)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_246)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_251)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_256)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_261)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_266)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_271)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_276)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_281)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_286)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_291)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_296)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_301)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_306)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_311)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_316)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_321)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_326)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_331)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_336)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_341)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_346)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_351)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_356)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_361)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_366)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_371)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_376)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_381)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_386)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_391)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_396)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_401)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_406)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_411)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_416)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_421)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_426)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_431)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_436)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_441)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_446)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_451)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_456)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_461)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_466)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_471)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_476)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_481)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_486)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_491)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_496)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_501)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_506)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_511)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_516)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_521)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_526)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_531)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_536)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_541)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_546)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_551)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_556)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_561)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_566)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_571)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_576)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_581)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_586)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_591)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_596)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_601)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_606)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_611)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_616)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_621)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_626)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_631)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_636)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_641)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_646)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_651)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_656)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_661)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_666)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_671)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_676)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_681)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_686)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_691)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_696)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_701)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_706)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_711)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_716)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_721)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_726)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_731)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_736)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_741)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_746)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_751)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_756)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_761)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_766)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_771)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_776)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_781)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_786)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_791)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_796)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_801)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_806)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_811)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_816)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_821)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_826)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_831)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_836)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_841)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_846)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_851)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_856)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_861)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_866)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_871)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_876)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_881)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_886)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_891)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_896)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_901)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_906)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_911)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_916)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_921)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_926)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_931)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_936)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_941)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_946)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_951)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_956)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_961)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_966)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_971)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_976)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_981)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_986)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_991)))) -(assert (<= 0 (+ x_1202 (* (- 1) x_996)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_2)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_7)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_12)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_17)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_22)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_27)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_32)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_37)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_42)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_47)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_52)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_57)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_62)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_67)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_72)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_77)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_82)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_87)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_92)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_97)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_102)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_107)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_112)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_117)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_122)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_127)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_132)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_137)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_142)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_147)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_152)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_157)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_162)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_167)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_172)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_177)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_182)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_187)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_192)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_197)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_202)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_207)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_212)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_217)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_222)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_227)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_232)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_237)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_242)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_247)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_252)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_257)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_262)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_267)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_272)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_277)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_282)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_287)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_292)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_297)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_302)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_307)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_312)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_317)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_322)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_327)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_332)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_337)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_342)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_347)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_352)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_357)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_362)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_367)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_372)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_377)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_382)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_387)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_392)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_397)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_402)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_407)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_412)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_417)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_422)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_427)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_432)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_437)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_442)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_447)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_452)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_457)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_462)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_467)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_472)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_477)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_482)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_487)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_492)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_497)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_502)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_507)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_512)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_517)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_522)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_527)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_532)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_537)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_542)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_547)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_552)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_557)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_562)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_567)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_572)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_577)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_582)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_587)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_592)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_597)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_602)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_607)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_612)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_617)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_622)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_627)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_632)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_637)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_642)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_647)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_652)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_657)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_662)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_667)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_672)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_677)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_682)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_687)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_692)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_697)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_702)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_707)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_712)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_717)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_722)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_727)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_732)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_737)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_742)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_747)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_752)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_757)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_762)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_767)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_772)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_777)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_782)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_787)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_792)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_797)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_802)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_807)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_812)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_817)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_822)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_827)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_832)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_837)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_842)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_847)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_852)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_857)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_862)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_867)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_872)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_877)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_882)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_887)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_892)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_897)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_902)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_907)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_912)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_917)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_922)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_927)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_932)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_937)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_942)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_947)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_952)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_957)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_962)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_967)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_972)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_977)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_982)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_987)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_992)))) -(assert (<= 0 (+ x_1403 (* (- 1) x_997)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_3)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_8)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_13)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_18)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_23)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_28)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_33)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_38)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_43)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_48)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_53)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_58)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_63)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_68)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_73)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_78)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_83)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_88)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_93)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_98)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_103)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_108)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_113)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_118)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_123)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_128)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_133)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_138)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_143)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_148)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_153)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_158)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_163)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_168)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_173)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_178)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_183)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_188)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_193)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_198)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_203)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_208)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_213)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_218)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_223)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_228)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_233)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_238)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_243)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_248)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_253)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_258)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_263)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_268)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_273)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_278)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_283)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_288)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_293)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_298)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_303)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_308)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_313)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_318)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_323)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_328)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_333)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_338)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_343)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_348)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_353)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_358)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_363)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_368)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_373)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_378)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_383)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_388)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_393)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_398)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_403)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_408)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_413)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_418)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_423)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_428)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_433)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_438)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_443)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_448)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_453)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_458)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_463)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_468)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_473)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_478)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_483)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_488)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_493)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_498)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_503)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_508)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_513)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_518)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_523)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_528)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_533)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_538)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_543)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_548)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_553)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_558)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_563)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_568)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_573)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_578)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_583)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_588)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_593)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_598)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_603)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_608)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_613)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_618)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_623)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_628)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_633)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_638)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_643)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_648)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_653)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_658)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_663)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_668)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_673)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_678)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_683)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_688)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_693)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_698)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_703)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_708)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_713)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_718)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_723)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_728)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_733)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_738)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_743)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_748)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_753)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_758)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_763)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_768)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_773)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_778)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_783)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_788)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_793)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_798)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_803)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_808)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_813)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_818)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_823)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_828)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_833)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_838)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_843)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_848)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_853)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_858)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_863)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_868)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_873)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_878)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_883)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_888)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_893)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_898)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_903)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_908)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_913)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_918)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_923)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_928)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_933)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_938)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_943)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_948)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_953)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_958)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_963)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_968)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_973)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_978)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_983)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_988)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_993)))) -(assert (<= 0 (+ x_1604 (* (- 1) x_998)))) -(assert (<= 0 - (+ (* 21600 x_1001) - (* (- 50) x_9) - (* (- 40) x_14) - (* (- 50) x_19) - (* (- 60) x_24) - (* (- 40) x_29) - (* (- 40) x_34) - (* (- 50) x_39) - (* (- 40) x_44) - (* (- 40) x_49) - (* (- 40) x_54) - (* (- 50) x_59) - (* (- 40) x_64) - (* (- 40) x_69) - (* (- 50) x_74) - (* (- 60) x_79) - (* (- 70) x_84) - (* (- 80) x_89) - (* (- 90) x_94) - (* (- 100) x_99) - (* (- 40) x_104) - (* (- 50) x_109) - (* (- 60) x_114) - (* (- 70) x_119) - (* (- 40) x_124) - (* (- 50) x_129) - (* (- 60) x_134) - (* (- 70) x_139) - (* (- 80) x_144) - (* (- 90) x_149) - (* (- 100) x_154) - (* (- 110) x_159) - (* (- 120) x_164) - (* (- 40) x_169) - (* (- 50) x_174) - (* (- 60) x_179) - (* (- 70) x_184) - (* (- 40) x_189) - (* (- 50) x_194) - (* (- 60) x_199) - (* (- 40) x_204) - (* (- 50) x_209) - (* (- 40) x_214) - (* (- 50) x_219) - (* (- 60) x_224) - (* (- 70) x_229) - (* (- 80) x_234) - (* (- 90) x_239) - (* (- 100) x_244) - (* (- 110) x_249) - (* (- 40) x_254) - (* (- 50) x_259) - (* (- 60) x_264) - (* (- 70) x_269) - (* (- 80) x_274) - (* (- 90) x_279) - (* (- 100) x_284) - (* (- 40) x_289) - (* (- 50) x_294) - (* (- 60) x_299) - (* (- 70) x_304) - (* (- 80) x_309) - (* (- 90) x_314) - (* (- 100) x_319) - (* (- 110) x_324) - (* (- 40) x_329) - (* (- 50) x_334) - (* (- 60) x_339) - (* (- 70) x_344) - (* (- 80) x_349) - (* (- 90) x_354) - (* (- 100) x_359) - (* (- 40) x_364) - (* (- 50) x_369) - (* (- 60) x_374) - (* (- 70) x_379) - (* (- 80) x_384) - (* (- 90) x_389) - (* (- 100) x_394) - (* (- 40) x_399) - (* (- 50) x_404) - (* (- 60) x_409) - (* (- 40) x_414) - (* (- 50) x_419) - (* (- 60) x_424) - (* (- 70) x_429) - (* (- 80) x_434) - (* (- 90) x_439) - (* (- 100) x_444) - (* (- 110) x_449) - (* (- 120) x_454) - (* (- 130) x_459) - (* (- 40) x_464) - (* (- 50) x_469) - (* (- 60) x_474) - (* (- 70) x_479) - (* (- 80) x_484) - (* (- 90) x_489) - (* (- 40) x_494) - (* (- 40) x_499) - (* (- 50) x_504) - (* (- 60) x_509) - (* (- 70) x_514) - (* (- 80) x_519) - (* (- 90) x_524) - (* (- 40) x_529) - (* (- 50) x_534) - (* (- 60) x_539) - (* (- 40) x_544) - (* (- 50) x_549) - (* (- 60) x_554) - (* (- 70) x_559) - (* (- 40) x_564) - (* (- 50) x_569) - (* (- 60) x_574) - (* (- 70) x_579) - (* (- 80) x_584) - (* (- 90) x_589) - (* (- 40) x_594) - (* (- 40) x_599) - (* (- 50) x_604) - (* (- 60) x_609) - (* (- 70) x_614) - (* (- 80) x_619) - (* (- 40) x_624) - (* (- 50) x_629) - (* (- 60) x_634) - (* (- 70) x_639) - (* (- 80) x_644) - (* (- 90) x_649) - (* (- 100) x_654) - (* (- 110) x_659) - (* (- 40) x_664) - (* (- 50) x_669) - (* (- 60) x_674) - (* (- 70) x_679) - (* (- 40) x_684) - (* (- 50) x_689) - (* (- 60) x_694) - (* (- 70) x_699) - (* (- 80) x_704) - (* (- 90) x_709) - (* (- 100) x_714) - (* (- 110) x_719) - (* (- 120) x_724) - (* (- 40) x_729) - (* (- 50) x_734) - (* (- 60) x_739) - (* (- 70) x_744) - (* (- 80) x_749) - (* (- 90) x_754) - (* (- 100) x_759) - (* (- 110) x_764) - (* (- 40) x_769) - (* (- 50) x_774) - (* (- 40) x_779) - (* (- 50) x_784) - (* (- 40) x_789) - (* (- 50) x_794) - (* (- 60) x_799) - (* (- 70) x_804) - (* (- 80) x_809) - (* (- 90) x_814) - (* (- 100) x_819) - (* (- 40) x_824) - (* (- 50) x_829) - (* (- 60) x_834) - (* (- 70) x_839) - (* (- 80) x_844) - (* (- 90) x_849) - (* (- 100) x_854) - (* (- 110) x_859) - (* (- 40) x_864) - (* (- 50) x_869) - (* (- 60) x_874) - (* (- 70) x_879) - (* (- 80) x_884) - (* (- 90) x_889) - (* (- 40) x_894) - (* (- 50) x_899) - (* (- 60) x_904) - (* (- 70) x_909) - (* (- 80) x_914) - (* (- 90) x_919) - (* (- 100) x_924) - (* (- 52) x_929) - (* (- 52) x_934) - (* (- 65) x_939) - (* (- 52) x_944) - (* (- 52) x_949) - (* (- 65) x_954) - (* (- 52) x_959) - (* (- 65) x_964) - (* (- 52) x_969) - (* (- 65) x_974) - (* (- 78) x_979) - (* (- 91) x_984) - (* (- 104) x_989) - (* (- 117) x_994) - (* (- 130) x_999) - (* (- 40) x_4)))) -(assert (<= 0 - (+ (* 7400 x_1202) - (* (- 50) x_6) - (* (- 40) x_11) - (* (- 50) x_16) - (* (- 60) x_21) - (* (- 40) x_26) - (* (- 40) x_31) - (* (- 50) x_36) - (* (- 40) x_41) - (* (- 40) x_46) - (* (- 40) x_51) - (* (- 50) x_56) - (* (- 40) x_61) - (* (- 40) x_66) - (* (- 50) x_71) - (* (- 60) x_76) - (* (- 70) x_81) - (* (- 80) x_86) - (* (- 90) x_91) - (* (- 100) x_96) - (* (- 40) x_101) - (* (- 50) x_106) - (* (- 60) x_111) - (* (- 70) x_116) - (* (- 40) x_121) - (* (- 50) x_126) - (* (- 60) x_131) - (* (- 70) x_136) - (* (- 80) x_141) - (* (- 90) x_146) - (* (- 100) x_151) - (* (- 110) x_156) - (* (- 120) x_161) - (* (- 40) x_166) - (* (- 50) x_171) - (* (- 60) x_176) - (* (- 70) x_181) - (* (- 40) x_186) - (* (- 50) x_191) - (* (- 60) x_196) - (* (- 40) x_201) - (* (- 50) x_206) - (* (- 40) x_211) - (* (- 50) x_216) - (* (- 60) x_221) - (* (- 70) x_226) - (* (- 80) x_231) - (* (- 90) x_236) - (* (- 100) x_241) - (* (- 110) x_246) - (* (- 40) x_251) - (* (- 50) x_256) - (* (- 60) x_261) - (* (- 70) x_266) - (* (- 80) x_271) - (* (- 90) x_276) - (* (- 100) x_281) - (* (- 40) x_286) - (* (- 50) x_291) - (* (- 60) x_296) - (* (- 70) x_301) - (* (- 80) x_306) - (* (- 90) x_311) - (* (- 100) x_316) - (* (- 110) x_321) - (* (- 40) x_326) - (* (- 50) x_331) - (* (- 60) x_336) - (* (- 70) x_341) - (* (- 80) x_346) - (* (- 90) x_351) - (* (- 100) x_356) - (* (- 40) x_361) - (* (- 50) x_366) - (* (- 60) x_371) - (* (- 70) x_376) - (* (- 80) x_381) - (* (- 90) x_386) - (* (- 100) x_391) - (* (- 40) x_396) - (* (- 50) x_401) - (* (- 60) x_406) - (* (- 40) x_411) - (* (- 50) x_416) - (* (- 60) x_421) - (* (- 70) x_426) - (* (- 80) x_431) - (* (- 90) x_436) - (* (- 100) x_441) - (* (- 110) x_446) - (* (- 120) x_451) - (* (- 130) x_456) - (* (- 40) x_461) - (* (- 50) x_466) - (* (- 60) x_471) - (* (- 70) x_476) - (* (- 80) x_481) - (* (- 90) x_486) - (* (- 40) x_491) - (* (- 40) x_496) - (* (- 50) x_501) - (* (- 60) x_506) - (* (- 70) x_511) - (* (- 80) x_516) - (* (- 90) x_521) - (* (- 40) x_526) - (* (- 50) x_531) - (* (- 60) x_536) - (* (- 40) x_541) - (* (- 50) x_546) - (* (- 60) x_551) - (* (- 70) x_556) - (* (- 40) x_561) - (* (- 50) x_566) - (* (- 60) x_571) - (* (- 70) x_576) - (* (- 80) x_581) - (* (- 90) x_586) - (* (- 40) x_591) - (* (- 40) x_596) - (* (- 50) x_601) - (* (- 60) x_606) - (* (- 70) x_611) - (* (- 80) x_616) - (* (- 40) x_621) - (* (- 50) x_626) - (* (- 60) x_631) - (* (- 70) x_636) - (* (- 80) x_641) - (* (- 90) x_646) - (* (- 100) x_651) - (* (- 110) x_656) - (* (- 40) x_661) - (* (- 50) x_666) - (* (- 60) x_671) - (* (- 70) x_676) - (* (- 40) x_681) - (* (- 50) x_686) - (* (- 60) x_691) - (* (- 70) x_696) - (* (- 80) x_701) - (* (- 90) x_706) - (* (- 100) x_711) - (* (- 110) x_716) - (* (- 120) x_721) - (* (- 40) x_726) - (* (- 50) x_731) - (* (- 60) x_736) - (* (- 70) x_741) - (* (- 80) x_746) - (* (- 90) x_751) - (* (- 100) x_756) - (* (- 110) x_761) - (* (- 40) x_766) - (* (- 50) x_771) - (* (- 40) x_776) - (* (- 50) x_781) - (* (- 40) x_786) - (* (- 50) x_791) - (* (- 60) x_796) - (* (- 70) x_801) - (* (- 80) x_806) - (* (- 90) x_811) - (* (- 100) x_816) - (* (- 40) x_821) - (* (- 50) x_826) - (* (- 60) x_831) - (* (- 70) x_836) - (* (- 80) x_841) - (* (- 90) x_846) - (* (- 100) x_851) - (* (- 110) x_856) - (* (- 40) x_861) - (* (- 50) x_866) - (* (- 60) x_871) - (* (- 70) x_876) - (* (- 80) x_881) - (* (- 90) x_886) - (* (- 40) x_891) - (* (- 50) x_896) - (* (- 60) x_901) - (* (- 70) x_906) - (* (- 80) x_911) - (* (- 90) x_916) - (* (- 100) x_921) - (* (- 52) x_926) - (* (- 52) x_931) - (* (- 65) x_936) - (* (- 52) x_941) - (* (- 52) x_946) - (* (- 65) x_951) - (* (- 52) x_956) - (* (- 65) x_961) - (* (- 52) x_966) - (* (- 65) x_971) - (* (- 78) x_976) - (* (- 91) x_981) - (* (- 104) x_986) - (* (- 117) x_991) - (* (- 130) x_996) - (* (- 40) x_1)))) -(assert (<= 0 - (+ (* 26500 x_1403) - (* (- 50) x_7) - (* (- 40) x_12) - (* (- 50) x_17) - (* (- 60) x_22) - (* (- 40) x_27) - (* (- 40) x_32) - (* (- 50) x_37) - (* (- 40) x_42) - (* (- 40) x_47) - (* (- 40) x_52) - (* (- 50) x_57) - (* (- 40) x_62) - (* (- 40) x_67) - (* (- 50) x_72) - (* (- 60) x_77) - (* (- 70) x_82) - (* (- 80) x_87) - (* (- 90) x_92) - (* (- 100) x_97) - (* (- 40) x_102) - (* (- 50) x_107) - (* (- 60) x_112) - (* (- 70) x_117) - (* (- 40) x_122) - (* (- 50) x_127) - (* (- 60) x_132) - (* (- 70) x_137) - (* (- 80) x_142) - (* (- 90) x_147) - (* (- 100) x_152) - (* (- 110) x_157) - (* (- 120) x_162) - (* (- 40) x_167) - (* (- 50) x_172) - (* (- 60) x_177) - (* (- 70) x_182) - (* (- 40) x_187) - (* (- 50) x_192) - (* (- 60) x_197) - (* (- 40) x_202) - (* (- 50) x_207) - (* (- 40) x_212) - (* (- 50) x_217) - (* (- 60) x_222) - (* (- 70) x_227) - (* (- 80) x_232) - (* (- 90) x_237) - (* (- 100) x_242) - (* (- 110) x_247) - (* (- 40) x_252) - (* (- 50) x_257) - (* (- 60) x_262) - (* (- 70) x_267) - (* (- 80) x_272) - (* (- 90) x_277) - (* (- 100) x_282) - (* (- 40) x_287) - (* (- 50) x_292) - (* (- 60) x_297) - (* (- 70) x_302) - (* (- 80) x_307) - (* (- 90) x_312) - (* (- 100) x_317) - (* (- 110) x_322) - (* (- 40) x_327) - (* (- 50) x_332) - (* (- 60) x_337) - (* (- 70) x_342) - (* (- 80) x_347) - (* (- 90) x_352) - (* (- 100) x_357) - (* (- 40) x_362) - (* (- 50) x_367) - (* (- 60) x_372) - (* (- 70) x_377) - (* (- 80) x_382) - (* (- 90) x_387) - (* (- 100) x_392) - (* (- 40) x_397) - (* (- 50) x_402) - (* (- 60) x_407) - (* (- 40) x_412) - (* (- 50) x_417) - (* (- 60) x_422) - (* (- 70) x_427) - (* (- 80) x_432) - (* (- 90) x_437) - (* (- 100) x_442) - (* (- 110) x_447) - (* (- 120) x_452) - (* (- 130) x_457) - (* (- 40) x_462) - (* (- 50) x_467) - (* (- 60) x_472) - (* (- 70) x_477) - (* (- 80) x_482) - (* (- 90) x_487) - (* (- 40) x_492) - (* (- 40) x_497) - (* (- 50) x_502) - (* (- 60) x_507) - (* (- 70) x_512) - (* (- 80) x_517) - (* (- 90) x_522) - (* (- 40) x_527) - (* (- 50) x_532) - (* (- 60) x_537) - (* (- 40) x_542) - (* (- 50) x_547) - (* (- 60) x_552) - (* (- 70) x_557) - (* (- 40) x_562) - (* (- 50) x_567) - (* (- 60) x_572) - (* (- 70) x_577) - (* (- 80) x_582) - (* (- 90) x_587) - (* (- 40) x_592) - (* (- 40) x_597) - (* (- 50) x_602) - (* (- 60) x_607) - (* (- 70) x_612) - (* (- 80) x_617) - (* (- 40) x_622) - (* (- 50) x_627) - (* (- 60) x_632) - (* (- 70) x_637) - (* (- 80) x_642) - (* (- 90) x_647) - (* (- 100) x_652) - (* (- 110) x_657) - (* (- 40) x_662) - (* (- 50) x_667) - (* (- 60) x_672) - (* (- 70) x_677) - (* (- 40) x_682) - (* (- 50) x_687) - (* (- 60) x_692) - (* (- 70) x_697) - (* (- 80) x_702) - (* (- 90) x_707) - (* (- 100) x_712) - (* (- 110) x_717) - (* (- 120) x_722) - (* (- 40) x_727) - (* (- 50) x_732) - (* (- 60) x_737) - (* (- 70) x_742) - (* (- 80) x_747) - (* (- 90) x_752) - (* (- 100) x_757) - (* (- 110) x_762) - (* (- 40) x_767) - (* (- 50) x_772) - (* (- 40) x_777) - (* (- 50) x_782) - (* (- 40) x_787) - (* (- 50) x_792) - (* (- 60) x_797) - (* (- 70) x_802) - (* (- 80) x_807) - (* (- 90) x_812) - (* (- 100) x_817) - (* (- 40) x_822) - (* (- 50) x_827) - (* (- 60) x_832) - (* (- 70) x_837) - (* (- 80) x_842) - (* (- 90) x_847) - (* (- 100) x_852) - (* (- 110) x_857) - (* (- 40) x_862) - (* (- 50) x_867) - (* (- 60) x_872) - (* (- 70) x_877) - (* (- 80) x_882) - (* (- 90) x_887) - (* (- 40) x_892) - (* (- 50) x_897) - (* (- 60) x_902) - (* (- 70) x_907) - (* (- 80) x_912) - (* (- 90) x_917) - (* (- 100) x_922) - (* (- 52) x_927) - (* (- 52) x_932) - (* (- 65) x_937) - (* (- 52) x_942) - (* (- 52) x_947) - (* (- 65) x_952) - (* (- 52) x_957) - (* (- 65) x_962) - (* (- 52) x_967) - (* (- 65) x_972) - (* (- 78) x_977) - (* (- 91) x_982) - (* (- 104) x_987) - (* (- 117) x_992) - (* (- 130) x_997) - (* (- 40) x_2)))) -(assert (<= 0 - (+ (* 4500 x_1604) - (* (- 50) x_8) - (* (- 40) x_13) - (* (- 50) x_18) - (* (- 60) x_23) - (* (- 40) x_28) - (* (- 40) x_33) - (* (- 50) x_38) - (* (- 40) x_43) - (* (- 40) x_48) - (* (- 40) x_53) - (* (- 50) x_58) - (* (- 40) x_63) - (* (- 40) x_68) - (* (- 50) x_73) - (* (- 60) x_78) - (* (- 70) x_83) - (* (- 80) x_88) - (* (- 90) x_93) - (* (- 100) x_98) - (* (- 40) x_103) - (* (- 50) x_108) - (* (- 60) x_113) - (* (- 70) x_118) - (* (- 40) x_123) - (* (- 50) x_128) - (* (- 60) x_133) - (* (- 70) x_138) - (* (- 80) x_143) - (* (- 90) x_148) - (* (- 100) x_153) - (* (- 110) x_158) - (* (- 120) x_163) - (* (- 40) x_168) - (* (- 50) x_173) - (* (- 60) x_178) - (* (- 70) x_183) - (* (- 40) x_188) - (* (- 50) x_193) - (* (- 60) x_198) - (* (- 40) x_203) - (* (- 50) x_208) - (* (- 40) x_213) - (* (- 50) x_218) - (* (- 60) x_223) - (* (- 70) x_228) - (* (- 80) x_233) - (* (- 90) x_238) - (* (- 100) x_243) - (* (- 110) x_248) - (* (- 40) x_253) - (* (- 50) x_258) - (* (- 60) x_263) - (* (- 70) x_268) - (* (- 80) x_273) - (* (- 90) x_278) - (* (- 100) x_283) - (* (- 40) x_288) - (* (- 50) x_293) - (* (- 60) x_298) - (* (- 70) x_303) - (* (- 80) x_308) - (* (- 90) x_313) - (* (- 100) x_318) - (* (- 110) x_323) - (* (- 40) x_328) - (* (- 50) x_333) - (* (- 60) x_338) - (* (- 70) x_343) - (* (- 80) x_348) - (* (- 90) x_353) - (* (- 100) x_358) - (* (- 40) x_363) - (* (- 50) x_368) - (* (- 60) x_373) - (* (- 70) x_378) - (* (- 80) x_383) - (* (- 90) x_388) - (* (- 100) x_393) - (* (- 40) x_398) - (* (- 50) x_403) - (* (- 60) x_408) - (* (- 40) x_413) - (* (- 50) x_418) - (* (- 60) x_423) - (* (- 70) x_428) - (* (- 80) x_433) - (* (- 90) x_438) - (* (- 100) x_443) - (* (- 110) x_448) - (* (- 120) x_453) - (* (- 130) x_458) - (* (- 40) x_463) - (* (- 50) x_468) - (* (- 60) x_473) - (* (- 70) x_478) - (* (- 80) x_483) - (* (- 90) x_488) - (* (- 40) x_493) - (* (- 40) x_498) - (* (- 50) x_503) - (* (- 60) x_508) - (* (- 70) x_513) - (* (- 80) x_518) - (* (- 90) x_523) - (* (- 40) x_528) - (* (- 50) x_533) - (* (- 60) x_538) - (* (- 40) x_543) - (* (- 50) x_548) - (* (- 60) x_553) - (* (- 70) x_558) - (* (- 40) x_563) - (* (- 50) x_568) - (* (- 60) x_573) - (* (- 70) x_578) - (* (- 80) x_583) - (* (- 90) x_588) - (* (- 40) x_593) - (* (- 40) x_598) - (* (- 50) x_603) - (* (- 60) x_608) - (* (- 70) x_613) - (* (- 80) x_618) - (* (- 40) x_623) - (* (- 50) x_628) - (* (- 60) x_633) - (* (- 70) x_638) - (* (- 80) x_643) - (* (- 90) x_648) - (* (- 100) x_653) - (* (- 110) x_658) - (* (- 40) x_663) - (* (- 50) x_668) - (* (- 60) x_673) - (* (- 70) x_678) - (* (- 40) x_683) - (* (- 50) x_688) - (* (- 60) x_693) - (* (- 70) x_698) - (* (- 80) x_703) - (* (- 90) x_708) - (* (- 100) x_713) - (* (- 110) x_718) - (* (- 120) x_723) - (* (- 40) x_728) - (* (- 50) x_733) - (* (- 60) x_738) - (* (- 70) x_743) - (* (- 80) x_748) - (* (- 90) x_753) - (* (- 100) x_758) - (* (- 110) x_763) - (* (- 40) x_768) - (* (- 50) x_773) - (* (- 40) x_778) - (* (- 50) x_783) - (* (- 40) x_788) - (* (- 50) x_793) - (* (- 60) x_798) - (* (- 70) x_803) - (* (- 80) x_808) - (* (- 90) x_813) - (* (- 100) x_818) - (* (- 40) x_823) - (* (- 50) x_828) - (* (- 60) x_833) - (* (- 70) x_838) - (* (- 80) x_843) - (* (- 90) x_848) - (* (- 100) x_853) - (* (- 110) x_858) - (* (- 40) x_863) - (* (- 50) x_868) - (* (- 60) x_873) - (* (- 70) x_878) - (* (- 80) x_883) - (* (- 90) x_888) - (* (- 40) x_893) - (* (- 50) x_898) - (* (- 60) x_903) - (* (- 70) x_908) - (* (- 80) x_913) - (* (- 90) x_918) - (* (- 100) x_923) - (* (- 52) x_928) - (* (- 52) x_933) - (* (- 65) x_938) - (* (- 52) x_943) - (* (- 52) x_948) - (* (- 65) x_953) - (* (- 52) x_958) - (* (- 65) x_963) - (* (- 52) x_968) - (* (- 65) x_973) - (* (- 78) x_978) - (* (- 91) x_983) - (* (- 104) x_988) - (* (- 117) x_993) - (* (- 130) x_998) - (* (- 40) x_3)))) -(assert (<= 0 - (+ (* 3850 x_1001) - (* (- 30) x_9) - (* (- 24) x_14) - (* (- 30) x_19) - (* (- 36) x_24) - (* (- 24) x_29) - (* (- 24) x_34) - (* (- 30) x_39) - (* (- 24) x_44) - (* (- 24) x_49) - (* (- 24) x_54) - (* (- 30) x_59) - (* (- 24) x_64) - (* (- 24) x_69) - (* (- 30) x_74) - (* (- 36) x_79) - (* (- 42) x_84) - (* (- 48) x_89) - (* (- 54) x_94) - (* (- 60) x_99) - (* (- 24) x_104) - (* (- 30) x_109) - (* (- 36) x_114) - (* (- 42) x_119) - (* (- 24) x_124) - (* (- 30) x_129) - (* (- 36) x_134) - (* (- 42) x_139) - (* (- 48) x_144) - (* (- 54) x_149) - (* (- 60) x_154) - (* (- 66) x_159) - (* (- 72) x_164) - (* (- 24) x_169) - (* (- 30) x_174) - (* (- 36) x_179) - (* (- 42) x_184) - (* (- 24) x_189) - (* (- 30) x_194) - (* (- 36) x_199) - (* (- 24) x_204) - (* (- 30) x_209) - (* (- 24) x_214) - (* (- 30) x_219) - (* (- 36) x_224) - (* (- 42) x_229) - (* (- 48) x_234) - (* (- 54) x_239) - (* (- 60) x_244) - (* (- 66) x_249) - (* (- 24) x_254) - (* (- 30) x_259) - (* (- 36) x_264) - (* (- 42) x_269) - (* (- 48) x_274) - (* (- 54) x_279) - (* (- 60) x_284) - (* (- 24) x_289) - (* (- 30) x_294) - (* (- 36) x_299) - (* (- 42) x_304) - (* (- 48) x_309) - (* (- 54) x_314) - (* (- 60) x_319) - (* (- 66) x_324) - (* (- 24) x_329) - (* (- 30) x_334) - (* (- 36) x_339) - (* (- 42) x_344) - (* (- 48) x_349) - (* (- 54) x_354) - (* (- 60) x_359) - (* (- 24) x_364) - (* (- 30) x_369) - (* (- 36) x_374) - (* (- 42) x_379) - (* (- 48) x_384) - (* (- 54) x_389) - (* (- 60) x_394) - (* (- 24) x_399) - (* (- 30) x_404) - (* (- 36) x_409) - (* (- 24) x_414) - (* (- 30) x_419) - (* (- 36) x_424) - (* (- 42) x_429) - (* (- 48) x_434) - (* (- 54) x_439) - (* (- 60) x_444) - (* (- 66) x_449) - (* (- 72) x_454) - (* (- 78) x_459) - (* (- 24) x_464) - (* (- 30) x_469) - (* (- 36) x_474) - (* (- 42) x_479) - (* (- 48) x_484) - (* (- 54) x_489) - (* (- 24) x_494) - (* (- 24) x_499) - (* (- 30) x_504) - (* (- 36) x_509) - (* (- 42) x_514) - (* (- 48) x_519) - (* (- 54) x_524) - (* (- 24) x_529) - (* (- 30) x_534) - (* (- 36) x_539) - (* (- 24) x_544) - (* (- 30) x_549) - (* (- 36) x_554) - (* (- 42) x_559) - (* (- 24) x_564) - (* (- 30) x_569) - (* (- 36) x_574) - (* (- 42) x_579) - (* (- 48) x_584) - (* (- 54) x_589) - (* (- 24) x_594) - (* (- 24) x_599) - (* (- 30) x_604) - (* (- 36) x_609) - (* (- 42) x_614) - (* (- 48) x_619) - (* (- 24) x_624) - (* (- 30) x_629) - (* (- 36) x_634) - (* (- 42) x_639) - (* (- 48) x_644) - (* (- 54) x_649) - (* (- 60) x_654) - (* (- 66) x_659) - (* (- 24) x_664) - (* (- 30) x_669) - (* (- 36) x_674) - (* (- 42) x_679) - (* (- 24) x_684) - (* (- 30) x_689) - (* (- 36) x_694) - (* (- 42) x_699) - (* (- 48) x_704) - (* (- 54) x_709) - (* (- 60) x_714) - (* (- 66) x_719) - (* (- 72) x_724) - (* (- 24) x_729) - (* (- 30) x_734) - (* (- 36) x_739) - (* (- 42) x_744) - (* (- 48) x_749) - (* (- 54) x_754) - (* (- 60) x_759) - (* (- 66) x_764) - (* (- 24) x_769) - (* (- 30) x_774) - (* (- 24) x_779) - (* (- 30) x_784) - (* (- 24) x_789) - (* (- 30) x_794) - (* (- 36) x_799) - (* (- 42) x_804) - (* (- 48) x_809) - (* (- 54) x_814) - (* (- 60) x_819) - (* (- 24) x_824) - (* (- 30) x_829) - (* (- 36) x_834) - (* (- 42) x_839) - (* (- 48) x_844) - (* (- 54) x_849) - (* (- 60) x_854) - (* (- 66) x_859) - (* (- 24) x_864) - (* (- 30) x_869) - (* (- 36) x_874) - (* (- 42) x_879) - (* (- 48) x_884) - (* (- 54) x_889) - (* (- 24) x_894) - (* (- 30) x_899) - (* (- 36) x_904) - (* (- 42) x_909) - (* (- 48) x_914) - (* (- 54) x_919) - (* (- 60) x_924) - (* (- 36) x_929) - (* (- 36) x_934) - (* (- 45) x_939) - (* (- 36) x_944) - (* (- 36) x_949) - (* (- 45) x_954) - (* (- 36) x_959) - (* (- 45) x_964) - (* (- 36) x_969) - (* (- 45) x_974) - (* (- 54) x_979) - (* (- 63) x_984) - (* (- 72) x_989) - (* (- 81) x_994) - (* (- 90) x_999) - (* (- 24) x_4)))) -(assert (<= 0 - (+ (* 3000 x_1202) - (* (- 30) x_6) - (* (- 24) x_11) - (* (- 30) x_16) - (* (- 36) x_21) - (* (- 24) x_26) - (* (- 24) x_31) - (* (- 30) x_36) - (* (- 24) x_41) - (* (- 24) x_46) - (* (- 24) x_51) - (* (- 30) x_56) - (* (- 24) x_61) - (* (- 24) x_66) - (* (- 30) x_71) - (* (- 36) x_76) - (* (- 42) x_81) - (* (- 48) x_86) - (* (- 54) x_91) - (* (- 60) x_96) - (* (- 24) x_101) - (* (- 30) x_106) - (* (- 36) x_111) - (* (- 42) x_116) - (* (- 24) x_121) - (* (- 30) x_126) - (* (- 36) x_131) - (* (- 42) x_136) - (* (- 48) x_141) - (* (- 54) x_146) - (* (- 60) x_151) - (* (- 66) x_156) - (* (- 72) x_161) - (* (- 24) x_166) - (* (- 30) x_171) - (* (- 36) x_176) - (* (- 42) x_181) - (* (- 24) x_186) - (* (- 30) x_191) - (* (- 36) x_196) - (* (- 24) x_201) - (* (- 30) x_206) - (* (- 24) x_211) - (* (- 30) x_216) - (* (- 36) x_221) - (* (- 42) x_226) - (* (- 48) x_231) - (* (- 54) x_236) - (* (- 60) x_241) - (* (- 66) x_246) - (* (- 24) x_251) - (* (- 30) x_256) - (* (- 36) x_261) - (* (- 42) x_266) - (* (- 48) x_271) - (* (- 54) x_276) - (* (- 60) x_281) - (* (- 24) x_286) - (* (- 30) x_291) - (* (- 36) x_296) - (* (- 42) x_301) - (* (- 48) x_306) - (* (- 54) x_311) - (* (- 60) x_316) - (* (- 66) x_321) - (* (- 24) x_326) - (* (- 30) x_331) - (* (- 36) x_336) - (* (- 42) x_341) - (* (- 48) x_346) - (* (- 54) x_351) - (* (- 60) x_356) - (* (- 24) x_361) - (* (- 30) x_366) - (* (- 36) x_371) - (* (- 42) x_376) - (* (- 48) x_381) - (* (- 54) x_386) - (* (- 60) x_391) - (* (- 24) x_396) - (* (- 30) x_401) - (* (- 36) x_406) - (* (- 24) x_411) - (* (- 30) x_416) - (* (- 36) x_421) - (* (- 42) x_426) - (* (- 48) x_431) - (* (- 54) x_436) - (* (- 60) x_441) - (* (- 66) x_446) - (* (- 72) x_451) - (* (- 78) x_456) - (* (- 24) x_461) - (* (- 30) x_466) - (* (- 36) x_471) - (* (- 42) x_476) - (* (- 48) x_481) - (* (- 54) x_486) - (* (- 24) x_491) - (* (- 24) x_496) - (* (- 30) x_501) - (* (- 36) x_506) - (* (- 42) x_511) - (* (- 48) x_516) - (* (- 54) x_521) - (* (- 24) x_526) - (* (- 30) x_531) - (* (- 36) x_536) - (* (- 24) x_541) - (* (- 30) x_546) - (* (- 36) x_551) - (* (- 42) x_556) - (* (- 24) x_561) - (* (- 30) x_566) - (* (- 36) x_571) - (* (- 42) x_576) - (* (- 48) x_581) - (* (- 54) x_586) - (* (- 24) x_591) - (* (- 24) x_596) - (* (- 30) x_601) - (* (- 36) x_606) - (* (- 42) x_611) - (* (- 48) x_616) - (* (- 24) x_621) - (* (- 30) x_626) - (* (- 36) x_631) - (* (- 42) x_636) - (* (- 48) x_641) - (* (- 54) x_646) - (* (- 60) x_651) - (* (- 66) x_656) - (* (- 24) x_661) - (* (- 30) x_666) - (* (- 36) x_671) - (* (- 42) x_676) - (* (- 24) x_681) - (* (- 30) x_686) - (* (- 36) x_691) - (* (- 42) x_696) - (* (- 48) x_701) - (* (- 54) x_706) - (* (- 60) x_711) - (* (- 66) x_716) - (* (- 72) x_721) - (* (- 24) x_726) - (* (- 30) x_731) - (* (- 36) x_736) - (* (- 42) x_741) - (* (- 48) x_746) - (* (- 54) x_751) - (* (- 60) x_756) - (* (- 66) x_761) - (* (- 24) x_766) - (* (- 30) x_771) - (* (- 24) x_776) - (* (- 30) x_781) - (* (- 24) x_786) - (* (- 30) x_791) - (* (- 36) x_796) - (* (- 42) x_801) - (* (- 48) x_806) - (* (- 54) x_811) - (* (- 60) x_816) - (* (- 24) x_821) - (* (- 30) x_826) - (* (- 36) x_831) - (* (- 42) x_836) - (* (- 48) x_841) - (* (- 54) x_846) - (* (- 60) x_851) - (* (- 66) x_856) - (* (- 24) x_861) - (* (- 30) x_866) - (* (- 36) x_871) - (* (- 42) x_876) - (* (- 48) x_881) - (* (- 54) x_886) - (* (- 24) x_891) - (* (- 30) x_896) - (* (- 36) x_901) - (* (- 42) x_906) - (* (- 48) x_911) - (* (- 54) x_916) - (* (- 60) x_921) - (* (- 36) x_926) - (* (- 36) x_931) - (* (- 45) x_936) - (* (- 36) x_941) - (* (- 36) x_946) - (* (- 45) x_951) - (* (- 36) x_956) - (* (- 45) x_961) - (* (- 36) x_966) - (* (- 45) x_971) - (* (- 54) x_976) - (* (- 63) x_981) - (* (- 72) x_986) - (* (- 81) x_991) - (* (- 90) x_996) - (* (- 24) x_1)))) -(assert (<= 0 - (+ (* 7700 x_1403) - (* (- 30) x_7) - (* (- 24) x_12) - (* (- 30) x_17) - (* (- 36) x_22) - (* (- 24) x_27) - (* (- 24) x_32) - (* (- 30) x_37) - (* (- 24) x_42) - (* (- 24) x_47) - (* (- 24) x_52) - (* (- 30) x_57) - (* (- 24) x_62) - (* (- 24) x_67) - (* (- 30) x_72) - (* (- 36) x_77) - (* (- 42) x_82) - (* (- 48) x_87) - (* (- 54) x_92) - (* (- 60) x_97) - (* (- 24) x_102) - (* (- 30) x_107) - (* (- 36) x_112) - (* (- 42) x_117) - (* (- 24) x_122) - (* (- 30) x_127) - (* (- 36) x_132) - (* (- 42) x_137) - (* (- 48) x_142) - (* (- 54) x_147) - (* (- 60) x_152) - (* (- 66) x_157) - (* (- 72) x_162) - (* (- 24) x_167) - (* (- 30) x_172) - (* (- 36) x_177) - (* (- 42) x_182) - (* (- 24) x_187) - (* (- 30) x_192) - (* (- 36) x_197) - (* (- 24) x_202) - (* (- 30) x_207) - (* (- 24) x_212) - (* (- 30) x_217) - (* (- 36) x_222) - (* (- 42) x_227) - (* (- 48) x_232) - (* (- 54) x_237) - (* (- 60) x_242) - (* (- 66) x_247) - (* (- 24) x_252) - (* (- 30) x_257) - (* (- 36) x_262) - (* (- 42) x_267) - (* (- 48) x_272) - (* (- 54) x_277) - (* (- 60) x_282) - (* (- 24) x_287) - (* (- 30) x_292) - (* (- 36) x_297) - (* (- 42) x_302) - (* (- 48) x_307) - (* (- 54) x_312) - (* (- 60) x_317) - (* (- 66) x_322) - (* (- 24) x_327) - (* (- 30) x_332) - (* (- 36) x_337) - (* (- 42) x_342) - (* (- 48) x_347) - (* (- 54) x_352) - (* (- 60) x_357) - (* (- 24) x_362) - (* (- 30) x_367) - (* (- 36) x_372) - (* (- 42) x_377) - (* (- 48) x_382) - (* (- 54) x_387) - (* (- 60) x_392) - (* (- 24) x_397) - (* (- 30) x_402) - (* (- 36) x_407) - (* (- 24) x_412) - (* (- 30) x_417) - (* (- 36) x_422) - (* (- 42) x_427) - (* (- 48) x_432) - (* (- 54) x_437) - (* (- 60) x_442) - (* (- 66) x_447) - (* (- 72) x_452) - (* (- 78) x_457) - (* (- 24) x_462) - (* (- 30) x_467) - (* (- 36) x_472) - (* (- 42) x_477) - (* (- 48) x_482) - (* (- 54) x_487) - (* (- 24) x_492) - (* (- 24) x_497) - (* (- 30) x_502) - (* (- 36) x_507) - (* (- 42) x_512) - (* (- 48) x_517) - (* (- 54) x_522) - (* (- 24) x_527) - (* (- 30) x_532) - (* (- 36) x_537) - (* (- 24) x_542) - (* (- 30) x_547) - (* (- 36) x_552) - (* (- 42) x_557) - (* (- 24) x_562) - (* (- 30) x_567) - (* (- 36) x_572) - (* (- 42) x_577) - (* (- 48) x_582) - (* (- 54) x_587) - (* (- 24) x_592) - (* (- 24) x_597) - (* (- 30) x_602) - (* (- 36) x_607) - (* (- 42) x_612) - (* (- 48) x_617) - (* (- 24) x_622) - (* (- 30) x_627) - (* (- 36) x_632) - (* (- 42) x_637) - (* (- 48) x_642) - (* (- 54) x_647) - (* (- 60) x_652) - (* (- 66) x_657) - (* (- 24) x_662) - (* (- 30) x_667) - (* (- 36) x_672) - (* (- 42) x_677) - (* (- 24) x_682) - (* (- 30) x_687) - (* (- 36) x_692) - (* (- 42) x_697) - (* (- 48) x_702) - (* (- 54) x_707) - (* (- 60) x_712) - (* (- 66) x_717) - (* (- 72) x_722) - (* (- 24) x_727) - (* (- 30) x_732) - (* (- 36) x_737) - (* (- 42) x_742) - (* (- 48) x_747) - (* (- 54) x_752) - (* (- 60) x_757) - (* (- 66) x_762) - (* (- 24) x_767) - (* (- 30) x_772) - (* (- 24) x_777) - (* (- 30) x_782) - (* (- 24) x_787) - (* (- 30) x_792) - (* (- 36) x_797) - (* (- 42) x_802) - (* (- 48) x_807) - (* (- 54) x_812) - (* (- 60) x_817) - (* (- 24) x_822) - (* (- 30) x_827) - (* (- 36) x_832) - (* (- 42) x_837) - (* (- 48) x_842) - (* (- 54) x_847) - (* (- 60) x_852) - (* (- 66) x_857) - (* (- 24) x_862) - (* (- 30) x_867) - (* (- 36) x_872) - (* (- 42) x_877) - (* (- 48) x_882) - (* (- 54) x_887) - (* (- 24) x_892) - (* (- 30) x_897) - (* (- 36) x_902) - (* (- 42) x_907) - (* (- 48) x_912) - (* (- 54) x_917) - (* (- 60) x_922) - (* (- 36) x_927) - (* (- 36) x_932) - (* (- 45) x_937) - (* (- 36) x_942) - (* (- 36) x_947) - (* (- 45) x_952) - (* (- 36) x_957) - (* (- 45) x_962) - (* (- 36) x_967) - (* (- 45) x_972) - (* (- 54) x_977) - (* (- 63) x_982) - (* (- 72) x_987) - (* (- 81) x_992) - (* (- 90) x_997) - (* (- 24) x_2)))) -(assert (<= 0 - (+ (* 3960 x_1604) - (* (- 30) x_8) - (* (- 24) x_13) - (* (- 30) x_18) - (* (- 36) x_23) - (* (- 24) x_28) - (* (- 24) x_33) - (* (- 30) x_38) - (* (- 24) x_43) - (* (- 24) x_48) - (* (- 24) x_53) - (* (- 30) x_58) - (* (- 24) x_63) - (* (- 24) x_68) - (* (- 30) x_73) - (* (- 36) x_78) - (* (- 42) x_83) - (* (- 48) x_88) - (* (- 54) x_93) - (* (- 60) x_98) - (* (- 24) x_103) - (* (- 30) x_108) - (* (- 36) x_113) - (* (- 42) x_118) - (* (- 24) x_123) - (* (- 30) x_128) - (* (- 36) x_133) - (* (- 42) x_138) - (* (- 48) x_143) - (* (- 54) x_148) - (* (- 60) x_153) - (* (- 66) x_158) - (* (- 72) x_163) - (* (- 24) x_168) - (* (- 30) x_173) - (* (- 36) x_178) - (* (- 42) x_183) - (* (- 24) x_188) - (* (- 30) x_193) - (* (- 36) x_198) - (* (- 24) x_203) - (* (- 30) x_208) - (* (- 24) x_213) - (* (- 30) x_218) - (* (- 36) x_223) - (* (- 42) x_228) - (* (- 48) x_233) - (* (- 54) x_238) - (* (- 60) x_243) - (* (- 66) x_248) - (* (- 24) x_253) - (* (- 30) x_258) - (* (- 36) x_263) - (* (- 42) x_268) - (* (- 48) x_273) - (* (- 54) x_278) - (* (- 60) x_283) - (* (- 24) x_288) - (* (- 30) x_293) - (* (- 36) x_298) - (* (- 42) x_303) - (* (- 48) x_308) - (* (- 54) x_313) - (* (- 60) x_318) - (* (- 66) x_323) - (* (- 24) x_328) - (* (- 30) x_333) - (* (- 36) x_338) - (* (- 42) x_343) - (* (- 48) x_348) - (* (- 54) x_353) - (* (- 60) x_358) - (* (- 24) x_363) - (* (- 30) x_368) - (* (- 36) x_373) - (* (- 42) x_378) - (* (- 48) x_383) - (* (- 54) x_388) - (* (- 60) x_393) - (* (- 24) x_398) - (* (- 30) x_403) - (* (- 36) x_408) - (* (- 24) x_413) - (* (- 30) x_418) - (* (- 36) x_423) - (* (- 42) x_428) - (* (- 48) x_433) - (* (- 54) x_438) - (* (- 60) x_443) - (* (- 66) x_448) - (* (- 72) x_453) - (* (- 78) x_458) - (* (- 24) x_463) - (* (- 30) x_468) - (* (- 36) x_473) - (* (- 42) x_478) - (* (- 48) x_483) - (* (- 54) x_488) - (* (- 24) x_493) - (* (- 24) x_498) - (* (- 30) x_503) - (* (- 36) x_508) - (* (- 42) x_513) - (* (- 48) x_518) - (* (- 54) x_523) - (* (- 24) x_528) - (* (- 30) x_533) - (* (- 36) x_538) - (* (- 24) x_543) - (* (- 30) x_548) - (* (- 36) x_553) - (* (- 42) x_558) - (* (- 24) x_563) - (* (- 30) x_568) - (* (- 36) x_573) - (* (- 42) x_578) - (* (- 48) x_583) - (* (- 54) x_588) - (* (- 24) x_593) - (* (- 24) x_598) - (* (- 30) x_603) - (* (- 36) x_608) - (* (- 42) x_613) - (* (- 48) x_618) - (* (- 24) x_623) - (* (- 30) x_628) - (* (- 36) x_633) - (* (- 42) x_638) - (* (- 48) x_643) - (* (- 54) x_648) - (* (- 60) x_653) - (* (- 66) x_658) - (* (- 24) x_663) - (* (- 30) x_668) - (* (- 36) x_673) - (* (- 42) x_678) - (* (- 24) x_683) - (* (- 30) x_688) - (* (- 36) x_693) - (* (- 42) x_698) - (* (- 48) x_703) - (* (- 54) x_708) - (* (- 60) x_713) - (* (- 66) x_718) - (* (- 72) x_723) - (* (- 24) x_728) - (* (- 30) x_733) - (* (- 36) x_738) - (* (- 42) x_743) - (* (- 48) x_748) - (* (- 54) x_753) - (* (- 60) x_758) - (* (- 66) x_763) - (* (- 24) x_768) - (* (- 30) x_773) - (* (- 24) x_778) - (* (- 30) x_783) - (* (- 24) x_788) - (* (- 30) x_793) - (* (- 36) x_798) - (* (- 42) x_803) - (* (- 48) x_808) - (* (- 54) x_813) - (* (- 60) x_818) - (* (- 24) x_823) - (* (- 30) x_828) - (* (- 36) x_833) - (* (- 42) x_838) - (* (- 48) x_843) - (* (- 54) x_848) - (* (- 60) x_853) - (* (- 66) x_858) - (* (- 24) x_863) - (* (- 30) x_868) - (* (- 36) x_873) - (* (- 42) x_878) - (* (- 48) x_883) - (* (- 54) x_888) - (* (- 24) x_893) - (* (- 30) x_898) - (* (- 36) x_903) - (* (- 42) x_908) - (* (- 48) x_913) - (* (- 54) x_918) - (* (- 60) x_923) - (* (- 36) x_928) - (* (- 36) x_933) - (* (- 45) x_938) - (* (- 36) x_943) - (* (- 36) x_948) - (* (- 45) x_953) - (* (- 36) x_958) - (* (- 45) x_963) - (* (- 36) x_968) - (* (- 45) x_973) - (* (- 54) x_978) - (* (- 63) x_983) - (* (- 72) x_988) - (* (- 81) x_993) - (* (- 90) x_998) - (* (- 24) x_3)))) - -(assert (= x_1202 1)) -(assert (= x_1403 1)) -(assert (= x_1604 0)) -(assert (= x_1001 0)) - -;(minimize (+ x_1202 x_1403 x_1604 x_1001)) -(minimize (+ (* 2 x_1) - (* 3 x_2) - (* 4 x_3) - x_9 - (* 2 x_6) - (* 3 x_7) - (* 4 x_8) - x_14 - (* 2 x_11) - (* 3 x_12) - (* 4 x_13) - x_19 - (* 2 x_16) - (* 3 x_17) - (* 4 x_18) - x_24 - (* 2 x_21) - (* 3 x_22) - (* 4 x_23) - x_29 - (* 2 x_26) - (* 3 x_27) - (* 4 x_28) - x_34 - (* 2 x_31) - (* 3 x_32) - (* 4 x_33) - x_39 - (* 2 x_36) - (* 3 x_37) - (* 4 x_38) - x_44 - (* 2 x_41) - (* 3 x_42) - (* 4 x_43) - x_49 - (* 2 x_46) - (* 3 x_47) - (* 4 x_48) - x_54 - (* 2 x_51) - (* 3 x_52) - (* 4 x_53) - x_59 - (* 2 x_56) - (* 3 x_57) - (* 4 x_58) - x_64 - (* 2 x_61) - (* 3 x_62) - (* 4 x_63) - x_69 - (* 2 x_66) - (* 3 x_67) - (* 4 x_68) - x_74 - (* 2 x_71) - (* 3 x_72) - (* 4 x_73) - x_79 - (* 2 x_76) - (* 3 x_77) - (* 4 x_78) - x_84 - (* 2 x_81) - (* 3 x_82) - (* 4 x_83) - x_89 - (* 2 x_86) - (* 3 x_87) - (* 4 x_88) - x_94 - (* 2 x_91) - (* 3 x_92) - (* 4 x_93) - x_99 - (* 2 x_96) - (* 3 x_97) - (* 4 x_98) - x_104 - (* 2 x_101) - (* 3 x_102) - (* 4 x_103) - x_109 - (* 2 x_106) - (* 3 x_107) - (* 4 x_108) - x_114 - (* 2 x_111) - (* 3 x_112) - (* 4 x_113) - x_119 - (* 2 x_116) - (* 3 x_117) - (* 4 x_118) - x_124 - (* 2 x_121) - (* 3 x_122) - (* 4 x_123) - x_129 - (* 2 x_126) - (* 3 x_127) - (* 4 x_128) - x_134 - (* 2 x_131) - (* 3 x_132) - (* 4 x_133) - x_139 - (* 2 x_136) - (* 3 x_137) - (* 4 x_138) - x_144 - (* 2 x_141) - (* 3 x_142) - (* 4 x_143) - x_149 - (* 2 x_146) - (* 3 x_147) - (* 4 x_148) - x_154 - (* 2 x_151) - (* 3 x_152) - (* 4 x_153) - x_159 - (* 2 x_156) - (* 3 x_157) - (* 4 x_158) - x_164 - (* 2 x_161) - (* 3 x_162) - (* 4 x_163) - x_169 - (* 2 x_166) - (* 3 x_167) - (* 4 x_168) - x_174 - (* 2 x_171) - (* 3 x_172) - (* 4 x_173) - x_179 - (* 2 x_176) - (* 3 x_177) - (* 4 x_178) - x_184 - (* 2 x_181) - (* 3 x_182) - (* 4 x_183) - x_189 - (* 2 x_186) - (* 3 x_187) - (* 4 x_188) - x_194 - (* 2 x_191) - (* 3 x_192) - (* 4 x_193) - x_199 - (* 2 x_196) - (* 3 x_197) - (* 4 x_198) - x_204 - (* 2 x_201) - (* 3 x_202) - (* 4 x_203) - x_209 - (* 2 x_206) - (* 3 x_207) - (* 4 x_208) - x_214 - (* 2 x_211) - (* 3 x_212) - (* 4 x_213) - x_219 - (* 2 x_216) - (* 3 x_217) - (* 4 x_218) - x_224 - (* 2 x_221) - (* 3 x_222) - (* 4 x_223) - x_229 - (* 2 x_226) - (* 3 x_227) - (* 4 x_228) - x_234 - (* 2 x_231) - (* 3 x_232) - (* 4 x_233) - x_239 - (* 2 x_236) - (* 3 x_237) - (* 4 x_238) - x_244 - (* 2 x_241) - (* 3 x_242) - (* 4 x_243) - x_249 - (* 2 x_246) - (* 3 x_247) - (* 4 x_248) - x_254 - (* 2 x_251) - (* 3 x_252) - (* 4 x_253) - x_259 - (* 2 x_256) - (* 3 x_257) - (* 4 x_258) - x_264 - (* 2 x_261) - (* 3 x_262) - (* 4 x_263) - x_269 - (* 2 x_266) - (* 3 x_267) - (* 4 x_268) - x_274 - (* 2 x_271) - (* 3 x_272) - (* 4 x_273) - x_279 - (* 2 x_276) - (* 3 x_277) - (* 4 x_278) - x_284 - (* 2 x_281) - (* 3 x_282) - (* 4 x_283) - x_289 - (* 2 x_286) - (* 3 x_287) - (* 4 x_288) - x_294 - (* 2 x_291) - (* 3 x_292) - (* 4 x_293) - x_299 - (* 2 x_296) - (* 3 x_297) - (* 4 x_298) - x_304 - (* 2 x_301) - (* 3 x_302) - (* 4 x_303) - x_309 - (* 2 x_306) - (* 3 x_307) - (* 4 x_308) - x_314 - (* 2 x_311) - (* 3 x_312) - (* 4 x_313) - x_319 - (* 2 x_316) - (* 3 x_317) - (* 4 x_318) - x_324 - (* 2 x_321) - (* 3 x_322) - (* 4 x_323) - x_329 - (* 2 x_326) - (* 3 x_327) - (* 4 x_328) - x_334 - (* 2 x_331) - (* 3 x_332) - (* 4 x_333) - x_339 - (* 2 x_336) - (* 3 x_337) - (* 4 x_338) - x_344 - (* 2 x_341) - (* 3 x_342) - (* 4 x_343) - x_349 - (* 2 x_346) - (* 3 x_347) - (* 4 x_348) - x_354 - (* 2 x_351) - (* 3 x_352) - (* 4 x_353) - x_359 - (* 2 x_356) - (* 3 x_357) - (* 4 x_358) - x_364 - (* 2 x_361) - (* 3 x_362) - (* 4 x_363) - x_369 - (* 2 x_366) - (* 3 x_367) - (* 4 x_368) - x_374 - (* 2 x_371) - (* 3 x_372) - (* 4 x_373) - x_379 - (* 2 x_376) - (* 3 x_377) - (* 4 x_378) - x_384 - (* 2 x_381) - (* 3 x_382) - (* 4 x_383) - x_389 - (* 2 x_386) - (* 3 x_387) - (* 4 x_388) - x_394 - (* 2 x_391) - (* 3 x_392) - (* 4 x_393) - x_399 - (* 2 x_396) - (* 3 x_397) - (* 4 x_398) - x_404 - (* 2 x_401) - (* 3 x_402) - (* 4 x_403) - x_409 - (* 2 x_406) - (* 3 x_407) - (* 4 x_408) - x_414 - (* 2 x_411) - (* 3 x_412) - (* 4 x_413) - x_419 - (* 2 x_416) - (* 3 x_417) - (* 4 x_418) - x_424 - (* 2 x_421) - (* 3 x_422) - (* 4 x_423) - x_429 - (* 2 x_426) - (* 3 x_427) - (* 4 x_428) - x_434 - (* 2 x_431) - (* 3 x_432) - (* 4 x_433) - x_439 - (* 2 x_436) - (* 3 x_437) - (* 4 x_438) - x_444 - (* 2 x_441) - (* 3 x_442) - (* 4 x_443) - x_449 - (* 2 x_446) - (* 3 x_447) - (* 4 x_448) - x_454 - (* 2 x_451) - (* 3 x_452) - (* 4 x_453) - x_459 - (* 2 x_456) - (* 3 x_457) - (* 4 x_458) - x_464 - (* 2 x_461) - (* 3 x_462) - (* 4 x_463) - x_469 - (* 2 x_466) - (* 3 x_467) - (* 4 x_468) - x_474 - (* 2 x_471) - (* 3 x_472) - (* 4 x_473) - x_479 - (* 2 x_476) - (* 3 x_477) - (* 4 x_478) - x_484 - (* 2 x_481) - (* 3 x_482) - (* 4 x_483) - x_489 - (* 2 x_486) - (* 3 x_487) - (* 4 x_488) - x_494 - (* 2 x_491) - (* 3 x_492) - (* 4 x_493) - x_499 - (* 2 x_496) - (* 3 x_497) - (* 4 x_498) - x_504 - (* 2 x_501) - (* 3 x_502) - (* 4 x_503) - x_509 - (* 2 x_506) - (* 3 x_507) - (* 4 x_508) - x_514 - (* 2 x_511) - (* 3 x_512) - (* 4 x_513) - x_519 - (* 2 x_516) - (* 3 x_517) - (* 4 x_518) - x_524 - (* 2 x_521) - (* 3 x_522) - (* 4 x_523) - x_529 - (* 2 x_526) - (* 3 x_527) - (* 4 x_528) - x_534 - (* 2 x_531) - (* 3 x_532) - (* 4 x_533) - x_539 - (* 2 x_536) - (* 3 x_537) - (* 4 x_538) - x_544 - (* 2 x_541) - (* 3 x_542) - (* 4 x_543) - x_549 - (* 2 x_546) - (* 3 x_547) - (* 4 x_548) - x_554 - (* 2 x_551) - (* 3 x_552) - (* 4 x_553) - x_559 - (* 2 x_556) - (* 3 x_557) - (* 4 x_558) - x_564 - (* 2 x_561) - (* 3 x_562) - (* 4 x_563) - x_569 - (* 2 x_566) - (* 3 x_567) - (* 4 x_568) - x_574 - (* 2 x_571) - (* 3 x_572) - (* 4 x_573) - x_579 - (* 2 x_576) - (* 3 x_577) - (* 4 x_578) - x_584 - (* 2 x_581) - (* 3 x_582) - (* 4 x_583) - x_589 - (* 2 x_586) - (* 3 x_587) - (* 4 x_588) - x_594 - (* 2 x_591) - (* 3 x_592) - (* 4 x_593) - x_599 - (* 2 x_596) - (* 3 x_597) - (* 4 x_598) - x_604 - (* 2 x_601) - (* 3 x_602) - (* 4 x_603) - x_609 - (* 2 x_606) - (* 3 x_607) - (* 4 x_608) - x_614 - (* 2 x_611) - (* 3 x_612) - (* 4 x_613) - x_619 - (* 2 x_616) - (* 3 x_617) - (* 4 x_618) - x_624 - (* 2 x_621) - (* 3 x_622) - (* 4 x_623) - x_629 - (* 2 x_626) - (* 3 x_627) - (* 4 x_628) - x_634 - (* 2 x_631) - (* 3 x_632) - (* 4 x_633) - x_639 - (* 2 x_636) - (* 3 x_637) - (* 4 x_638) - x_644 - (* 2 x_641) - (* 3 x_642) - (* 4 x_643) - x_649 - (* 2 x_646) - (* 3 x_647) - (* 4 x_648) - x_654 - (* 2 x_651) - (* 3 x_652) - (* 4 x_653) - x_659 - (* 2 x_656) - (* 3 x_657) - (* 4 x_658) - x_664 - (* 2 x_661) - (* 3 x_662) - (* 4 x_663) - x_669 - (* 2 x_666) - (* 3 x_667) - (* 4 x_668) - x_674 - (* 2 x_671) - (* 3 x_672) - (* 4 x_673) - x_679 - (* 2 x_676) - (* 3 x_677) - (* 4 x_678) - x_684 - (* 2 x_681) - (* 3 x_682) - (* 4 x_683) - x_689 - (* 2 x_686) - (* 3 x_687) - (* 4 x_688) - x_694 - (* 2 x_691) - (* 3 x_692) - (* 4 x_693) - x_699 - (* 2 x_696) - (* 3 x_697) - (* 4 x_698) - x_704 - (* 2 x_701) - (* 3 x_702) - (* 4 x_703) - x_709 - (* 2 x_706) - (* 3 x_707) - (* 4 x_708) - x_714 - (* 2 x_711) - (* 3 x_712) - (* 4 x_713) - x_719 - (* 2 x_716) - (* 3 x_717) - (* 4 x_718) - x_724 - (* 2 x_721) - (* 3 x_722) - (* 4 x_723) - x_729 - (* 2 x_726) - (* 3 x_727) - (* 4 x_728) - x_734 - (* 2 x_731) - (* 3 x_732) - (* 4 x_733) - x_739 - (* 2 x_736) - (* 3 x_737) - (* 4 x_738) - x_744 - (* 2 x_741) - (* 3 x_742) - (* 4 x_743) - x_749 - (* 2 x_746) - (* 3 x_747) - (* 4 x_748) - x_754 - (* 2 x_751) - (* 3 x_752) - (* 4 x_753) - x_759 - (* 2 x_756) - (* 3 x_757) - (* 4 x_758) - x_764 - (* 2 x_761) - (* 3 x_762) - (* 4 x_763) - x_769 - (* 2 x_766) - (* 3 x_767) - (* 4 x_768) - x_774 - (* 2 x_771) - (* 3 x_772) - (* 4 x_773) - x_779 - (* 2 x_776) - (* 3 x_777) - (* 4 x_778) - x_784 - (* 2 x_781) - (* 3 x_782) - (* 4 x_783) - x_789 - (* 2 x_786) - (* 3 x_787) - (* 4 x_788) - x_794 - (* 2 x_791) - (* 3 x_792) - (* 4 x_793) - x_799 - (* 2 x_796) - (* 3 x_797) - (* 4 x_798) - x_804 - (* 2 x_801) - (* 3 x_802) - (* 4 x_803) - x_809 - (* 2 x_806) - (* 3 x_807) - (* 4 x_808) - x_814 - (* 2 x_811) - (* 3 x_812) - (* 4 x_813) - x_819 - (* 2 x_816) - (* 3 x_817) - (* 4 x_818) - x_824 - (* 2 x_821) - (* 3 x_822) - (* 4 x_823) - x_829 - (* 2 x_826) - (* 3 x_827) - (* 4 x_828) - x_834 - (* 2 x_831) - (* 3 x_832) - (* 4 x_833) - x_839 - (* 2 x_836) - (* 3 x_837) - (* 4 x_838) - x_844 - (* 2 x_841) - (* 3 x_842) - (* 4 x_843) - x_849 - (* 2 x_846) - (* 3 x_847) - (* 4 x_848) - x_854 - (* 2 x_851) - (* 3 x_852) - (* 4 x_853) - x_859 - (* 2 x_856) - (* 3 x_857) - (* 4 x_858) - x_864 - (* 2 x_861) - (* 3 x_862) - (* 4 x_863) - x_869 - (* 2 x_866) - (* 3 x_867) - (* 4 x_868) - x_874 - (* 2 x_871) - (* 3 x_872) - (* 4 x_873) - x_879 - (* 2 x_876) - (* 3 x_877) - (* 4 x_878) - x_884 - (* 2 x_881) - (* 3 x_882) - (* 4 x_883) - x_889 - (* 2 x_886) - (* 3 x_887) - (* 4 x_888) - x_894 - (* 2 x_891) - (* 3 x_892) - (* 4 x_893) - x_899 - (* 2 x_896) - (* 3 x_897) - (* 4 x_898) - x_904 - (* 2 x_901) - (* 3 x_902) - (* 4 x_903) - x_909 - (* 2 x_906) - (* 3 x_907) - (* 4 x_908) - x_914 - (* 2 x_911) - (* 3 x_912) - (* 4 x_913) - x_919 - (* 2 x_916) - (* 3 x_917) - (* 4 x_918) - x_924 - (* 2 x_921) - (* 3 x_922) - (* 4 x_923) - x_929 - (* 2 x_926) - (* 3 x_927) - (* 4 x_928) - x_934 - (* 2 x_931) - (* 3 x_932) - (* 4 x_933) - x_939 - (* 2 x_936) - (* 3 x_937) - (* 4 x_938) - x_944 - (* 2 x_941) - (* 3 x_942) - (* 4 x_943) - x_949 - (* 2 x_946) - (* 3 x_947) - (* 4 x_948) - x_954 - (* 2 x_951) - (* 3 x_952) - (* 4 x_953) - x_959 - (* 2 x_956) - (* 3 x_957) - (* 4 x_958) - x_964 - (* 2 x_961) - (* 3 x_962) - (* 4 x_963) - x_969 - (* 2 x_966) - (* 3 x_967) - (* 4 x_968) - x_974 - (* 2 x_971) - (* 3 x_972) - (* 4 x_973) - x_979 - (* 2 x_976) - (* 3 x_977) - (* 4 x_978) - x_984 - (* 2 x_981) - (* 3 x_982) - (* 4 x_983) - x_989 - (* 2 x_986) - (* 3 x_987) - (* 4 x_988) - x_994 - (* 2 x_991) - (* 3 x_992) - (* 4 x_993) - x_999 - (* 2 x_996) - (* 3 x_997) - (* 4 x_998) - x_4 - (* 100 x_1202) - (* 100 x_1403) - (* 100 x_1604) - (* 100 x_1001))) -(optimize :print_statistics true - :wmaxsat_engine wmax - :maxsat_engine weighted_maxsat) From 624cc8a8745c049fbe5ea3ded4cfbd5a81936723 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 9 Jun 2015 11:53:43 +0100 Subject: [PATCH 900/925] Bugfixes for FPA API. Thanks to Christian Dernehl for reporting these. --- src/api/api_fpa.cpp | 2 +- src/api/java/FPSort.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index e7ae685fc..6aba9f842 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -712,7 +712,7 @@ extern "C" { unsigned Z3_API Z3_fpa_get_sbits(Z3_context c, Z3_sort s) { Z3_TRY; - LOG_Z3_fpa_get_ebits(c, s); + LOG_Z3_fpa_get_sbits(c, s); RESET_ERROR_CODE(); CHECK_NON_NULL(s, 0); return mk_c(c)->fpautil().get_sbits(to_sort(s)); diff --git a/src/api/java/FPSort.java b/src/api/java/FPSort.java index 82e69afbe..59313fe27 100644 --- a/src/api/java/FPSort.java +++ b/src/api/java/FPSort.java @@ -43,7 +43,7 @@ public class FPSort extends Sort * The number of significand bits. */ public int getSBits() { - return Native.fpaGetEbits(getContext().nCtx(), getNativeObject()); + return Native.fpaGetSbits(getContext().nCtx(), getNativeObject()); } } From d39969f0a010cdb654b035afa746b508349e4db5 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 9 Jun 2015 12:28:23 +0100 Subject: [PATCH 901/925] Added extraction of uint64 significand bits from FP numerals. --- src/api/api_fpa.cpp | 23 +++++++++++++++++++++++ src/api/z3_fpa.h | 14 ++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 6aba9f842..c944200cf 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -765,7 +765,30 @@ extern "C" { mpqm.display_decimal(ss, q, sbits); return mk_c(c)->mk_external_string(ss.str()); Z3_CATCH_RETURN(""); + } + Z3_bool Z3_API Z3_fpa_get_numeral_significand_uint64(__in Z3_context c, __in Z3_ast t, __out __uint64 * n) { + Z3_TRY; + LOG_Z3_fpa_get_numeral_significand_uint64(c, t, n); + RESET_ERROR_CODE(); + ast_manager & m = mk_c(c)->m(); + mpf_manager & mpfm = mk_c(c)->fpautil().fm(); + unsynch_mpz_manager & mpzm = mpfm.mpz_manager(); + fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(mk_c(c)->get_fpa_fid()); + scoped_mpf val(mpfm); + bool r = plugin->is_numeral(to_expr(t), val); + if (!r) { + SET_ERROR_CODE(Z3_INVALID_ARG); + return 0; + } + const mpz & z = mpfm.sig(val); + if (!mpzm.is_uint64(z)) { + SET_ERROR_CODE(Z3_INVALID_ARG); + return 0; + } + *n = mpzm.get_uint64(z); + return 1; + Z3_CATCH_RETURN(0); } Z3_string Z3_API Z3_fpa_get_numeral_exponent_string(__in Z3_context c, __in Z3_ast t) { diff --git a/src/api/z3_fpa.h b/src/api/z3_fpa.h index e1bd67d66..01908e358 100644 --- a/src/api/z3_fpa.h +++ b/src/api/z3_fpa.h @@ -858,6 +858,20 @@ extern "C" { */ Z3_string Z3_API Z3_fpa_get_numeral_significand_string(__in Z3_context c, __in Z3_ast t); + /** + \brief Return the significand value of a floating-point numeral as a uint64. + + \param c logical context + \param t a floating-point numeral + + Remarks: This function extracts the significand bits in `t`, without the + hidden bit or normalization. Sets the Z3_INVALID_ARG error code if the + signicand does not fit into a uint64. + + def_API('Z3_fpa_get_numeral_significand_uint64', BOOL, (_in(CONTEXT), _in(AST))) + */ + Z3_bool Z3_API Z3_fpa_get_numeral_significand_uint64(__in Z3_context c, __in Z3_ast t, __out __uint64 * n); + /** \brief Return the exponent value of a floating-point numeral as a string From eb3d499888eaaeac8e6428a06223b8e549be830e Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 9 Jun 2015 12:28:52 +0100 Subject: [PATCH 902/925] documentation fix --- src/api/z3_fpa.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/api/z3_fpa.h b/src/api/z3_fpa.h index 01908e358..6bd752f0a 100644 --- a/src/api/z3_fpa.h +++ b/src/api/z3_fpa.h @@ -859,16 +859,16 @@ extern "C" { Z3_string Z3_API Z3_fpa_get_numeral_significand_string(__in Z3_context c, __in Z3_ast t); /** - \brief Return the significand value of a floating-point numeral as a uint64. + \brief Return the significand value of a floating-point numeral as a uint64. - \param c logical context - \param t a floating-point numeral + \param c logical context + \param t a floating-point numeral - Remarks: This function extracts the significand bits in `t`, without the - hidden bit or normalization. Sets the Z3_INVALID_ARG error code if the - signicand does not fit into a uint64. + Remarks: This function extracts the significand bits in `t`, without the + hidden bit or normalization. Sets the Z3_INVALID_ARG error code if the + signicand does not fit into a uint64. - def_API('Z3_fpa_get_numeral_significand_uint64', BOOL, (_in(CONTEXT), _in(AST))) + def_API('Z3_fpa_get_numeral_significand_uint64', BOOL, (_in(CONTEXT), _in(AST), _out(UINT64))) */ Z3_bool Z3_API Z3_fpa_get_numeral_significand_uint64(__in Z3_context c, __in Z3_ast t, __out __uint64 * n); From da3243fb079bc40288499cd250b32e8110cef7a4 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 9 Jun 2015 12:29:05 +0100 Subject: [PATCH 903/925] FPA API bugfix --- src/api/api_fpa.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index c944200cf..e79a04cad 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -817,7 +817,7 @@ extern "C" { Z3_bool Z3_API Z3_fpa_get_numeral_exponent_int64(__in Z3_context c, __in Z3_ast t, __out __int64 * n) { Z3_TRY; - LOG_Z3_fpa_get_numeral_exponent_string(c, t); + LOG_Z3_fpa_get_numeral_exponent_int64(c, t, n); RESET_ERROR_CODE(); ast_manager & m = mk_c(c)->m(); mpf_manager & mpfm = mk_c(c)->fpautil().fm(); From 98f2de32160f13e495d1269a63d84f2e05978658 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 9 Jun 2015 12:57:19 +0100 Subject: [PATCH 904/925] Added Z3_fpa_get_numeral_significand_uint64 to .NET, Java, and ML APIs. --- src/api/dotnet/FPNum.cs | 19 +++++++++++++++++++ src/api/java/FPNum.java | 15 +++++++++++++++ src/api/ml/z3.ml | 2 ++ src/api/ml/z3.mli | 6 ++++++ src/api/z3_fpa.h | 2 +- 5 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/api/dotnet/FPNum.cs b/src/api/dotnet/FPNum.cs index e85687ccf..ac1fae5f5 100644 --- a/src/api/dotnet/FPNum.cs +++ b/src/api/dotnet/FPNum.cs @@ -59,6 +59,25 @@ namespace Microsoft.Z3 } } + /// + /// The significand value of a floating-point numeral as a UInt64 + /// + /// + /// This function extracts the significand bits, without the + /// hidden bit or normalization. Throws an exception if the + /// significand does not fit into a UInt64. + /// + public UInt64 SignificandUInt64 + { + get + { + UInt64 result = 0; + if (Native.Z3_fpa_get_numeral_significand_uint64(Context.nCtx, NativeObject, ref result) == 0) + throw new Z3Exception("Significand is not a 64 bit unsigned integer"); + return result; + } + } + /// /// Return the exponent value of a floating-point numeral as a string /// diff --git a/src/api/java/FPNum.java b/src/api/java/FPNum.java index 9a147778a..69a44c559 100644 --- a/src/api/java/FPNum.java +++ b/src/api/java/FPNum.java @@ -43,6 +43,21 @@ public class FPNum extends FPExpr return Native.fpaGetNumeralSignificandString(getContext().nCtx(), getNativeObject()); } + /** + * The significand value of a floating-point numeral as a UInt64 + * Remarks: This function extracts the significand bits, without the + * hidden bit or normalization. Throws an exception if the + * significand does not fit into a UInt64. + * @throws Z3Exception + **/ + public long getSignificandUInt64() + { + Native.LongPtr res = new Native.LongPtr(); + if (Native.fpaGetNumeralSignificandUint64(getContext().nCtx(), getNativeObject(), res) ^ true) + throw new Z3Exception("Significand is not a 64 bit unsigned integer"); + return res.value; + } + /** * Return the exponent value of a floating-point numeral as a string * @throws Z3Exception diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index fa6ce6c81..a776eacd3 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -2059,6 +2059,8 @@ struct (Z3native.fpa_get_numeral_sign (context_gno ctx) (Expr.gno t)) let get_numeral_significand_string ( ctx : context ) ( t : expr ) = (Z3native.fpa_get_numeral_significand_string (context_gno ctx) (Expr.gno t)) + let get_numeral_significand_uint ( ctx : context ) ( t : expr ) = + (Z3native.fpa_get_numeral_significand_uint64 (context_gno ctx) (Expr.gno t)) let get_numeral_exponent_string ( ctx : context ) ( t : expr ) = (Z3native.fpa_get_numeral_exponent_string (context_gno ctx) (Expr.gno t)) let get_numeral_exponent_int ( ctx : context ) ( t : expr ) = diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli index 2099359fa..ce937d4e0 100644 --- a/src/api/ml/z3.mli +++ b/src/api/ml/z3.mli @@ -2161,6 +2161,12 @@ sig (** Return the significand value of a floating-point numeral as a string. *) val get_numeral_significand_string : context -> Expr.expr -> string + (** Return the significand value of a floating-point numeral as a uint64. + Remark: This function extracts the significand bits, without the + hidden bit or normalization. Throws an exception if the + significand does not fit into a uint64. *) + val get_numeral_significand_uint : context -> Expr.expr -> bool * int + (** Return the exponent value of a floating-point numeral as a string *) val get_numeral_exponent_string : context -> Expr.expr -> string diff --git a/src/api/z3_fpa.h b/src/api/z3_fpa.h index 6bd752f0a..7813142a3 100644 --- a/src/api/z3_fpa.h +++ b/src/api/z3_fpa.h @@ -866,7 +866,7 @@ extern "C" { Remarks: This function extracts the significand bits in `t`, without the hidden bit or normalization. Sets the Z3_INVALID_ARG error code if the - signicand does not fit into a uint64. + significand does not fit into a uint64. def_API('Z3_fpa_get_numeral_significand_uint64', BOOL, (_in(CONTEXT), _in(AST), _out(UINT64))) */ From a37ec413705010ab24791f4f9a7b197191b8cfc9 Mon Sep 17 00:00:00 2001 From: Aleksandar Zeljic Date: Tue, 9 Jun 2015 21:16:53 +0200 Subject: [PATCH 905/925] Buggy version, a full model is found but evaluation finds it to be invalid. --- src/tactic/fpa/fpa2bv_approx_tactic.cpp | 53 +++++++++++++++++-------- 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_approx_tactic.cpp b/src/tactic/fpa/fpa2bv_approx_tactic.cpp index 02c5ab8bd..a348c25e4 100644 --- a/src/tactic/fpa/fpa2bv_approx_tactic.cpp +++ b/src/tactic/fpa/fpa2bv_approx_tactic.cpp @@ -102,7 +102,7 @@ class fpa2bv_approx_tactic: public tactic { obj_map & const2term_map) { for (unsigned i = 0; i < cnsts.size(); i++) { - if (const2term_map.contains(cnsts[i]) || m_mode == FPAA_SMALL_FLOATS) + if (const2term_map.contains(cnsts.get(i)) || m_mode == FPAA_SMALL_FLOATS) map.insert_if_not_there(cnsts.get(i), 0); else map.insert_if_not_there(cnsts.get(i), MAX_PRECISION); @@ -516,19 +516,25 @@ class fpa2bv_approx_tactic: public tactic { else full_semantics_eval(rhs,mpf_mngr,rm,arg_val,est_arg_val, rhs_value, est_rhs_value); - full_mdl->register_decl((to_app(lhs))->get_decl(), m_float_util.mk_value(est_rhs_value)); + if (mpf_mngr.eq(rhs_value, est_rhs_value)) { + full_mdl->register_decl((to_app(lhs))->get_decl(), m_float_util.mk_value(est_rhs_value)); + precise_op.insert(lhs, true); + } + else { + full_mdl->register_decl((to_app(lhs))->get_decl(), m_float_util.mk_value(est_rhs_value)); #ifdef Z3DEBUG - std::cout << "Assigning " << mk_ismt2_pp(lhs, m) << - " value " << mpf_mngr.to_string(est_rhs_value) << std::endl - << "Values of " << mk_ismt2_pp(lhs, m) << std::endl - << "Precise children: " << ((precise_children) ? "True" : "False") << std::endl - << "Lhs: " << mk_ismt2_pp(lhs_eval, m) << std::endl - << "Model: " << mpf_mngr.to_string(rhs_value) << std::endl - << "Estimate: " << mpf_mngr.to_string(est_rhs_value) << std::endl; + std::cout << "Assigning " << mk_ismt2_pp(lhs, m) << + " value " << mpf_mngr.to_string(est_rhs_value) << std::endl + << "Values of " << mk_ismt2_pp(lhs, m) << std::endl + << "Precise children: " << ((precise_children) ? "True" : "False") << std::endl + << "Lhs: " << mk_ismt2_pp(lhs_eval, m) << std::endl + << "Model: " << mpf_mngr.to_string(rhs_value) << std::endl + << "Estimate: " << mpf_mngr.to_string(est_rhs_value) << std::endl; #endif - calculate_error(lhs,mpf_mngr,precise_op,err_est,lhs_value,est_rhs_value,children_have_finite_err); + calculate_error(lhs,mpf_mngr,precise_op,err_est,lhs_value,est_rhs_value,children_have_finite_err); + } if (!actual_value.contains(lhs)) { mpf * tmp = alloc(mpf); mpf_mngr.set(*tmp, est_rhs_value); @@ -695,6 +701,7 @@ class fpa2bv_approx_tactic: public tactic { } } } + } void increase_precision( @@ -784,8 +791,13 @@ class fpa2bv_approx_tactic: public tactic { boolean_comparison_of_models(g, mdl, full_mdl, cnst2term_map, expr_count); calculate_relative_error(err_est, expr_count, err_ratio_map); - rank_terms (err_ratio_map,ranked_terms); - increase_precision(ranked_terms,cnsts,cnst2prec_map,cnst2term_map,new_map); + if (err_ratio_map.empty()) { + proof_guided_refinement(g,cnsts,cnst2prec_map,new_map); + } + else { + rank_terms (err_ratio_map,ranked_terms); + increase_precision(ranked_terms,cnsts,cnst2prec_map,cnst2term_map,new_map); + } } void simplify(goal_ref mg) { @@ -1108,6 +1120,8 @@ class fpa2bv_approx_tactic: public tactic { m_num_steps = 0; } + + void print_constants(func_decl_ref_vector & constants, obj_map & const2prec_map){ #ifdef Z3DEBUG for(unsigned i=0;i err_est; - solved = precise_model_reconstruction(m_fpa_model, full_mdl, mg, err_est, constants, const2term_map); - - std::cout<<"Patching of the model "<<((solved)?"succeeded":"failed")< Date: Wed, 10 Jun 2015 13:17:34 +0100 Subject: [PATCH 906/925] Added conversion function for Goal to Expr conversion in .NET, Java, ML --- src/api/dotnet/Goal.cs | 15 +++++++++++++++ src/api/java/Goal.java | 16 ++++++++++++++++ src/api/ml/z3.ml | 9 +++++++++ src/api/ml/z3.mli | 3 +++ 4 files changed, 43 insertions(+) diff --git a/src/api/dotnet/Goal.cs b/src/api/dotnet/Goal.cs index 46d519d35..5ee44f34b 100644 --- a/src/api/dotnet/Goal.cs +++ b/src/api/dotnet/Goal.cs @@ -208,6 +208,21 @@ namespace Microsoft.Z3 return Native.Z3_goal_to_string(Context.nCtx, NativeObject); } + /// + /// Goal to BoolExpr conversion. + /// + /// A string representation of the Goal. + public BoolExpr AsBoolExpr() { + uint n = Size; + if (n == 0) + return Context.MkTrue(); + else if (n == 1) + return Formulas[0]; + else { + return Context.MkAnd(Formulas); + } + } + #region Internal internal Goal(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); } diff --git a/src/api/java/Goal.java b/src/api/java/Goal.java index 18aecb557..41d4e27ac 100644 --- a/src/api/java/Goal.java +++ b/src/api/java/Goal.java @@ -221,6 +221,22 @@ public class Goal extends Z3Object return "Z3Exception: " + e.getMessage(); } } + + /** + * Goal to BoolExpr conversion. + * + * Returns a string representation of the Goal. + **/ + public BoolExpr AsBoolExpr() { + int n = size(); + if (n == 0) + return getContext().mkTrue(); + else if (n == 1) + return getFormulas()[0]; + else { + return getContext().mkAnd(getFormulas()); + } + } Goal(Context ctx, long obj) { diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index a776eacd3..51eb35e29 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -2199,6 +2199,15 @@ struct create ctx (Z3native.mk_goal (context_gno ctx) models unsat_cores proofs) let to_string ( x : goal ) = Z3native.goal_to_string (z3obj_gnc x) (z3obj_gno x) + + let as_expr ( x : goal ) = + let n = get_size x in + if n = 0 then + (Boolean.mk_true (z3obj_gc x)) + else if n = 1 then + (List.hd (get_formulas x)) + else + (Boolean.mk_and (z3obj_gc x) (get_formulas x)) end diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli index ce937d4e0..e0f89565d 100644 --- a/src/api/ml/z3.mli +++ b/src/api/ml/z3.mli @@ -2653,6 +2653,9 @@ sig (** A string representation of the Goal. *) val to_string : goal -> string + + (** Goal to BoolExpr conversion. *) + val as_expr : goal -> Expr.expr end (** Models From 140fb7942dd051f4e8db608ef2d9b260353e7416 Mon Sep 17 00:00:00 2001 From: Alex Horn Date: Wed, 10 Jun 2015 18:09:56 +0100 Subject: [PATCH 907/925] Add datalog infrastructure for min aggregation function This patch adds an instruction to the datalog interpreter and constructs a new AST node for min aggregation functions. The compiler is currently still work in progress and depends on changes made to the handling of simple joins and the preprocessor. Signed-off-by: Alex Horn --- src/ast/dl_decl_plugin.cpp | 68 +++++++++++++++- src/ast/dl_decl_plugin.h | 59 ++++++++++++++ src/muz/base/dl_rule.h | 7 ++ src/muz/base/dl_rule_set.h | 1 + src/muz/rel/dl_base.cpp | 122 ++++++++++++++++++++++++++++ src/muz/rel/dl_base.h | 28 +++++++ src/muz/rel/dl_instruction.cpp | 54 ++++++++++++ src/muz/rel/dl_instruction.h | 3 + src/muz/rel/dl_relation_manager.cpp | 5 ++ src/muz/rel/dl_relation_manager.h | 3 + src/test/dl_table.cpp | 71 +++++++++++++++- 11 files changed, 418 insertions(+), 3 deletions(-) diff --git a/src/ast/dl_decl_plugin.cpp b/src/ast/dl_decl_plugin.cpp index badf8a59d..305ac1779 100644 --- a/src/ast/dl_decl_plugin.cpp +++ b/src/ast/dl_decl_plugin.cpp @@ -44,7 +44,8 @@ namespace datalog { m_num_sym("N"), m_lt_sym("<"), m_le_sym("<="), - m_rule_sym("R") + m_rule_sym("R"), + m_min_sym("min") { } @@ -490,6 +491,66 @@ namespace datalog { return m_manager->mk_func_decl(m_clone_sym, 1, &s, s, info); } + /** + In SMT2 syntax, we can write \c ((_ min R N) v_0 v_1 ... v_k)) where 0 <= N <= k, + R is a relation of sort V_0 x V_1 x ... x V_k and each v_i is a zero-arity function + (also known as a "constant" in SMT2 parlance) whose range is of sort V_i. + + Example: + + (define-sort number_t () (_ BitVec 2)) + (declare-rel numbers (number_t number_t)) + (declare-rel is_min (number_t number_t)) + + (declare-var x number_t) + (declare-var y number_t) + + (rule (numbers #b00 #b11)) + (rule (numbers #b00 #b01)) + + (rule (=> (and (numbers x y) ((_ min numbers 1) x y)) (is_min x y))) + + This says that we want to find the mininum y grouped by x. + */ + func_decl * dl_decl_plugin::mk_min(decl_kind k, unsigned num_parameters, parameter const * parameters) { + if (num_parameters < 2) { + m_manager->raise_exception("invalid min aggregate definition due to missing parameters"); + return 0; + } + + parameter const & relation_parameter = parameters[0]; + if (!relation_parameter.is_ast() || !is_func_decl(relation_parameter.get_ast())) { + m_manager->raise_exception("invalid min aggregate definition, first parameter is not a function declaration"); + return 0; + } + + func_decl* f = to_func_decl(relation_parameter.get_ast()); + if (!m_manager->is_bool(f->get_range())) { + m_manager->raise_exception("invalid min aggregate definition, first paramater must be a predicate"); + return 0; + } + + parameter const & min_col_parameter = parameters[1]; + if (!min_col_parameter.is_int()) { + m_manager->raise_exception("invalid min aggregate definition, second parameter must be an integer"); + return 0; + } + + if (min_col_parameter.get_int() < 0) { + m_manager->raise_exception("invalid min aggregate definition, second parameter must be non-negative"); + return 0; + } + + if ((unsigned)min_col_parameter.get_int() >= f->get_arity()) { + m_manager->raise_exception("invalid min aggregate definition, second parameter exceeds the arity of the relation"); + return 0; + } + + func_decl_info info(m_family_id, k, num_parameters, parameters); + SASSERT(f->get_info() == 0); + return m_manager->mk_func_decl(m_min_sym, f->get_arity(), f->get_domain(), f->get_range(), info); + } + func_decl * dl_decl_plugin::mk_func_decl( decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { @@ -617,6 +678,9 @@ namespace datalog { break; } + case OP_DL_MIN: + return mk_min(k, num_parameters, parameters); + default: m_manager->raise_exception("operator not recognized"); return 0; @@ -627,7 +691,7 @@ namespace datalog { } void dl_decl_plugin::get_op_names(svector & op_names, symbol const & logic) { - + op_names.push_back(builtin_name(m_min_sym.bare_str(), OP_DL_MIN)); } void dl_decl_plugin::get_sort_names(svector & sort_names, symbol const & logic) { diff --git a/src/ast/dl_decl_plugin.h b/src/ast/dl_decl_plugin.h index 65b00235c..e3bc4dd63 100644 --- a/src/ast/dl_decl_plugin.h +++ b/src/ast/dl_decl_plugin.h @@ -50,6 +50,7 @@ namespace datalog { OP_DL_LT, OP_DL_REP, OP_DL_ABS, + OP_DL_MIN, LAST_RA_OP }; @@ -71,6 +72,7 @@ namespace datalog { symbol m_lt_sym; symbol m_le_sym; symbol m_rule_sym; + symbol m_min_sym; bool check_bounds(char const* msg, unsigned low, unsigned up, unsigned val) const; bool check_domain(unsigned low, unsigned up, unsigned val) const; @@ -94,12 +96,69 @@ namespace datalog { func_decl * mk_compare(decl_kind k, symbol const& sym, sort*const* domain); func_decl * mk_clone(sort* r); func_decl * mk_rule(unsigned arity); + func_decl * mk_min(decl_kind k, unsigned num_parameters, parameter const * parameters); sort * mk_finite_sort(unsigned num_params, parameter const* params); sort * mk_relation_sort(unsigned num_params, parameter const* params); sort * mk_rule_sort(); public: + /** + Is \c decl a min aggregation function? + */ + static bool is_aggregate(const func_decl* const decl) + { + return decl->get_decl_kind() == OP_DL_MIN; + } + + /** + \pre: is_aggregate(aggregate) + + \returns function declaration of predicate which is subject to min aggregation function + */ + static func_decl * min_func_decl(const func_decl* const aggregate) + { + SASSERT(is_aggregate(aggregate)); + parameter const & relation_parameter = aggregate->get_parameter(0); + return to_func_decl(relation_parameter.get_ast()); + } + + /** + \pre: is_aggregate(aggregate) + + \returns column identifier (starting at zero) which is minimized by aggregation function + */ + static unsigned min_col(const func_decl* const aggregate) + { + SASSERT(is_aggregate(aggregate)); + return (unsigned)aggregate->get_parameter(1).get_int(); + } + + /** + \pre: is_aggregate(aggregate) + + \returns column identifiers for the "group by" in the given min aggregation function + */ + static unsigned_vector group_by_cols(const func_decl* const aggregate) + { + SASSERT(is_aggregate(aggregate)); + unsigned _min_col = min_col(aggregate); + if (aggregate->get_arity() == 0U) + return unsigned_vector(); + + unsigned col_num = 0; + unsigned_vector cols(aggregate->get_arity() - 1U); + for (unsigned i = 0; i < cols.size(); ++i, ++col_num) + { + if (col_num == _min_col) + ++col_num; + + cols[i] = col_num; + } + + return cols; + } + dl_decl_plugin(); virtual ~dl_decl_plugin() {} diff --git a/src/muz/base/dl_rule.h b/src/muz/base/dl_rule.h index bdca80d0b..468b9f88c 100644 --- a/src/muz/base/dl_rule.h +++ b/src/muz/base/dl_rule.h @@ -346,6 +346,13 @@ namespace datalog { bool is_neg_tail(unsigned i) const { SASSERT(i < m_tail_size); return GET_TAG(m_tail[i]) == 1; } + /** + A predicate P(Xj) can be annotated by adding an interpreted predicate of the form ((_ min P N) ...) + where N is the column number that should be used for the min aggregation function. + Such an interpreted predicate is an example for which this function returns true. + */ + bool is_min_tail(unsigned i) const { return dl_decl_plugin::is_aggregate(get_tail(i)->get_decl()); } + /** Check whether predicate p is in the interpreted tail. diff --git a/src/muz/base/dl_rule_set.h b/src/muz/base/dl_rule_set.h index e13d92105..5201d9257 100644 --- a/src/muz/base/dl_rule_set.h +++ b/src/muz/base/dl_rule_set.h @@ -179,6 +179,7 @@ namespace datalog { void compute_deps(); void compute_tc_deps(); bool stratified_negation(); + public: rule_set(context & ctx); rule_set(const rule_set & rs); diff --git a/src/muz/rel/dl_base.cpp b/src/muz/rel/dl_base.cpp index 95efccce8..a00c50d9e 100644 --- a/src/muz/rel/dl_base.cpp +++ b/src/muz/rel/dl_base.cpp @@ -485,4 +485,126 @@ namespace datalog { brw.mk_or(disjs.size(), disjs.c_ptr(), fml); } + class table_plugin::min_fn : public table_min_fn{ + table_signature m_sig; + const unsigned_vector m_group_by_cols; + const unsigned m_col; + public: + min_fn(const table_signature & t_sig, const unsigned_vector& group_by_cols, const unsigned col) + : m_sig(t_sig), + m_group_by_cols(group_by_cols), + m_col(col) {} + + virtual table_base* operator()(table_base const& t) { + //return reference_implementation(t); + return reference_implementation_with_hash(t); + } + + private: + + /** + Reference implementation with negation: + + T1 = join(T, T) by group_cols + T2 = { (t1,t2) in T1 | t1[col] > t2[col] } + T3 = { t1 | (t1,t2) in T2 } + T4 = T \ T3 + + The point of this reference implementation is to show + that the minimum requires negation (set difference). + This is relevant for fixed point computations. + */ + virtual table_base * reference_implementation(const table_base & t) { + relation_manager & manager = t.get_manager(); + table_join_fn * join_fn = manager.mk_join_fn(t, t, m_group_by_cols, m_group_by_cols); + table_base * join_table = (*join_fn)(t, t); + + table_base::iterator join_table_it = join_table->begin(); + table_base::iterator join_table_end = join_table->end(); + table_fact row; + + table_element i, j; + + for (; join_table_it != join_table_end; ++join_table_it) { + join_table_it->get_fact(row); + i = row[m_col]; + j = row[t.num_columns() + m_col]; + + if (i > j) { + continue; + } + + join_table->remove_fact(row); + } + + unsigned_vector cols(t.num_columns()); + for (unsigned k = 0; k < cols.size(); ++k) { + cols[k] = cols.size() + k; + SASSERT(cols[k] < join_table->num_columns()); + } + + table_transformer_fn * project_fn = manager.mk_project_fn(*join_table, cols); + table_base * gt_table = (*project_fn)(*join_table); + + for (unsigned k = 0; k < cols.size(); ++k) { + cols[k] = k; + SASSERT(cols[k] < t.num_columns()); + SASSERT(cols[k] < gt_table->num_columns()); + } + + table_base * result = t.clone(); + table_intersection_filter_fn * diff_fn = manager.mk_filter_by_negation_fn(*result, *gt_table, cols, cols); + (*diff_fn)(*result, *gt_table); + gt_table->deallocate(); + return result; + } + + typedef map < table_fact, table_element, svector_hash_proc, + vector_eq_proc > group_map; + + // Thanks to Nikolaj who kindly helped with the second reference implementation! + virtual table_base * reference_implementation_with_hash(const table_base & t) { + group_map group; + table_base::iterator it = t.begin(); + table_base::iterator end = t.end(); + table_fact row, row2; + table_element current_value, min_value; + for (; it != end; ++it) { + it->get_fact(row); + current_value = row[m_col]; + group_by(row, row2); + group_map::entry* entry = group.find_core(row2); + if (!entry) { + group.insert(row2, current_value); + } + else if (entry->get_data().m_value > current_value) { + entry->get_data().m_value = current_value; + } + } + table_base* result = t.get_plugin().mk_empty(m_sig); + table_base::iterator it2 = t.begin(); + for (; it2 != end; ++it2) { + it2->get_fact(row); + current_value = row[m_col]; + group_by(row, row2); + VERIFY(group.find(row2, min_value)); + if (min_value == current_value) { + result->add_fact(row); + } + } + return result; + } + + void group_by(table_fact const& in, table_fact& out) { + out.reset(); + for (unsigned i = 0; i < m_group_by_cols.size(); ++i) { + out.push_back(in[m_group_by_cols[i]]); + } + } + }; + + table_min_fn * table_plugin::mk_min_fn(const table_base & t, + unsigned_vector & group_by_cols, const unsigned col) { + return alloc(table_plugin::min_fn, t.get_signature(), group_by_cols, col); + } } diff --git a/src/muz/rel/dl_base.h b/src/muz/rel/dl_base.h index 268cc602e..6ab1b2a96 100644 --- a/src/muz/rel/dl_base.h +++ b/src/muz/rel/dl_base.h @@ -192,6 +192,29 @@ namespace datalog { virtual base_object * operator()(const base_object & t1, const base_object & t2) = 0; }; + /** + \brief Aggregate minimum value + + Informally, we want to group rows in a table \c t by \c group_by_cols and + return the minimum value in column \c col among each group. + + Let \c t be a table with N columns. + Let \c group_by_cols be a set of column identifers for table \c t such that |group_by_cols| < N. + Let \c col be a column identifier for table \c t such that \c col is not in \c group_by_cols. + + Let R_col be a set of rows in table \c t such that, for all rows r_i, r_j in R_col + and column identifiers k in \c group_by_cols, r_i[k] = r_j[k]. + + For each R_col, we want to restrict R_col to those rows whose value in column \c col is minimal. + + min_fn(R, group_by_cols, col) = + { row in R | forall row' in R . row'[group_by_cols] = row[group_by_cols] => row'[col] >= row[col] } + */ + class min_fn : public base_fn { + public: + virtual base_object * operator()(const base_object & t) = 0; + }; + class transformer_fn : public base_fn { public: virtual base_object * operator()(const base_object & t) = 0; @@ -856,6 +879,7 @@ namespace datalog { typedef table_infrastructure::base_fn base_table_fn; typedef table_infrastructure::join_fn table_join_fn; + typedef table_infrastructure::min_fn table_min_fn; typedef table_infrastructure::transformer_fn table_transformer_fn; typedef table_infrastructure::union_fn table_union_fn; typedef table_infrastructure::mutator_fn table_mutator_fn; @@ -1020,6 +1044,7 @@ namespace datalog { class table_plugin : public table_infrastructure::plugin_object { friend class relation_manager; + class min_fn; protected: table_plugin(symbol const& n, relation_manager & manager) : plugin_object(n, manager) {} public: @@ -1027,6 +1052,9 @@ namespace datalog { virtual bool can_handle_signature(const table_signature & s) { return s.functional_columns()==0; } protected: + virtual table_min_fn * mk_min_fn(const table_base & t, + unsigned_vector & group_by_cols, const unsigned col); + /** If the returned value is non-zero, the returned object must take ownership of \c mapper. Otherwise \c mapper must remain unmodified. diff --git a/src/muz/rel/dl_instruction.cpp b/src/muz/rel/dl_instruction.cpp index 7eb8d4375..c903519ce 100644 --- a/src/muz/rel/dl_instruction.cpp +++ b/src/muz/rel/dl_instruction.cpp @@ -25,6 +25,7 @@ Revision History: #include"rel_context.h" #include"debug.h" #include"warning.h" +#include"dl_table_relation.h" namespace datalog { @@ -883,6 +884,59 @@ namespace datalog { removed_cols, result); } + class instr_min : public instruction { + reg_idx m_source_reg; + reg_idx m_target_reg; + unsigned_vector m_group_by_cols; + unsigned m_min_col; + public: + instr_min(reg_idx source_reg, reg_idx target_reg, const unsigned_vector & group_by_cols, unsigned min_col) + : m_source_reg(source_reg), + m_target_reg(target_reg), + m_group_by_cols(group_by_cols), + m_min_col(min_col) { + } + virtual bool perform(execution_context & ctx) { + log_verbose(ctx); + if (!ctx.reg(m_source_reg)) { + ctx.make_empty(m_target_reg); + return true; + } + + const relation_base & s = *ctx.reg(m_source_reg); + if (!s.from_table()) { + throw default_exception("relation is not a table %s", + s.get_plugin().get_name().bare_str()); + } + ++ctx.m_stats.m_min; + const table_relation & tr = static_cast(s); + const table_base & source_t = tr.get_table(); + relation_manager & r_manager = s.get_manager(); + + const relation_signature & r_sig = s.get_signature(); + table_min_fn * fn = r_manager.mk_min_fn(source_t, m_group_by_cols, m_min_col); + table_base * target_t = (*fn)(source_t); + + TRACE("dl", + tout << "% "; + target_t->display(tout); + tout << "\n";); + + relation_base * target_r = r_manager.mk_table_relation(r_sig, target_t); + ctx.set_reg(m_target_reg, target_r); + return true; + } + virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { + out << " MIN AGGR "; + } + virtual void make_annotations(execution_context & ctx) { + } + }; + + instruction * instruction::mk_min(reg_idx source, reg_idx target, const unsigned_vector & group_by_cols, + const unsigned min_col) { + return alloc(instr_min, source, target, group_by_cols, min_col); + } class instr_select_equal_and_project : public instruction { reg_idx m_src; diff --git a/src/muz/rel/dl_instruction.h b/src/muz/rel/dl_instruction.h index 3910f6d0b..a02346b99 100644 --- a/src/muz/rel/dl_instruction.h +++ b/src/muz/rel/dl_instruction.h @@ -93,6 +93,7 @@ namespace datalog { unsigned m_filter_interp_project; unsigned m_filter_id; unsigned m_filter_eq; + unsigned m_min; stats() { reset(); } void reset() { memset(this, 0, sizeof(*this)); } }; @@ -284,6 +285,8 @@ namespace datalog { static instruction * mk_join_project(reg_idx rel1, reg_idx rel2, unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, const unsigned * removed_cols, reg_idx result); + static instruction * mk_min(reg_idx source, reg_idx target, const unsigned_vector & group_by_cols, + const unsigned min_col); static instruction * mk_rename(reg_idx src, unsigned cycle_len, const unsigned * permutation_cycle, reg_idx tgt); static instruction * mk_filter_by_negation(reg_idx tgt, reg_idx neg_rel, unsigned col_cnt, diff --git a/src/muz/rel/dl_relation_manager.cpp b/src/muz/rel/dl_relation_manager.cpp index 6a9bb7f2a..95b35899e 100644 --- a/src/muz/rel/dl_relation_manager.cpp +++ b/src/muz/rel/dl_relation_manager.cpp @@ -1021,6 +1021,11 @@ namespace datalog { return res; } + table_min_fn * relation_manager::mk_min_fn(const table_base & t, + unsigned_vector & group_by_cols, const unsigned col) + { + return t.get_plugin().mk_min_fn(t, group_by_cols, col); + } class relation_manager::auxiliary_table_transformer_fn { table_fact m_row; diff --git a/src/muz/rel/dl_relation_manager.h b/src/muz/rel/dl_relation_manager.h index 53d7f21e2..f91b7496a 100644 --- a/src/muz/rel/dl_relation_manager.h +++ b/src/muz/rel/dl_relation_manager.h @@ -251,6 +251,9 @@ namespace datalog { return mk_join_fn(t1, t2, cols1.size(), cols1.c_ptr(), cols2.c_ptr(), allow_product_relation); } + table_min_fn * mk_min_fn(const table_base & t, + unsigned_vector & group_by_cols, const unsigned col); + /** \brief Return functor that transforms a table into one that lacks columns listed in \c removed_cols array. diff --git a/src/test/dl_table.cpp b/src/test/dl_table.cpp index d24200f9b..06eb62fa1 100644 --- a/src/test/dl_table.cpp +++ b/src/test/dl_table.cpp @@ -1,4 +1,4 @@ -#ifdef _WINDOWS +#if defined(_WINDOWS) || defined(_CYGWIN) #include "dl_context.h" #include "dl_table.h" #include "dl_register_engine.h" @@ -91,9 +91,78 @@ void test_dl_bitvector_table() { test_table(mk_bv_table); } +void test_table_min() { + std::cout << "----- test_table_min -----\n"; + datalog::table_signature sig; + sig.push_back(2); + sig.push_back(4); + sig.push_back(8); + smt_params params; + ast_manager ast_m; + datalog::register_engine re; + datalog::context ctx(ast_m, re, params); + datalog::relation_manager & m = ctx.get_rel_context()->get_rmanager(); + + m.register_plugin(alloc(datalog::bitvector_table_plugin, m)); + + datalog::table_base* tbl = mk_bv_table(m, sig); + datalog::table_base& table = *tbl; + + datalog::table_fact row, row1, row2, row3; + row.push_back(1); + row.push_back(2); + row.push_back(5); + + // Group (1,2,*) + row1 = row; + row[2] = 6; + row2 = row; + row[2] = 5; + row3 = row; + + table.add_fact(row1); + table.add_fact(row2); + table.add_fact(row3); + + // Group (1,3,*) + row[1] = 3; + row1 = row; + row[2] = 7; + row2 = row; + row[2] = 4; + row3 = row; + + table.add_fact(row1); + table.add_fact(row2); + table.add_fact(row3); + + table.display(std::cout); + + unsigned_vector group_by(2); + group_by[0] = 0; + group_by[1] = 1; + + datalog::table_min_fn * min_fn = m.mk_min_fn(table, group_by, 2); + datalog::table_base * min_tbl = (*min_fn)(table); + + min_tbl->display(std::cout); + + row[1] = 2; + row[2] = 5; + SASSERT(min_tbl->contains_fact(row)); + + row[1] = 3; + row[2] = 4; + SASSERT(min_tbl->contains_fact(row)); + + dealloc(min_fn); + min_tbl->deallocate(); + tbl->deallocate(); +} void tst_dl_table() { test_dl_bitvector_table(); + test_table_min(); } #else void tst_dl_table() { From 08b3f9b46ee82366c9a93498ca5759ce4a245d83 Mon Sep 17 00:00:00 2001 From: Aleksandar Zeljic Date: Wed, 10 Jun 2015 19:57:32 +0200 Subject: [PATCH 908/925] Removed the fpa2bv_porec model converter which was outdated and causing evaluation bugs. --- src/tactic/fpa/fpa2bv_approx_tactic.cpp | 5 +- src/tactic/fpa/fpa2bv_converter_prec.cpp | 189 ----------------------- src/tactic/fpa/fpa2bv_converter_prec.h | 59 ------- 3 files changed, 4 insertions(+), 249 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_approx_tactic.cpp b/src/tactic/fpa/fpa2bv_approx_tactic.cpp index a348c25e4..77a87ae31 100644 --- a/src/tactic/fpa/fpa2bv_approx_tactic.cpp +++ b/src/tactic/fpa/fpa2bv_approx_tactic.cpp @@ -28,6 +28,8 @@ #include"sat_solver.h" #include"fpa_decl_plugin.h" #include"fpa2bv_converter_prec.h" +#include"fpa2bv_model_converter.h" +#include"fpa2bv_converter.h" #include"fpa2bv_rewriter_prec.h" #include"fpa2bv_approx_tactic.h" #include"const_intro_rewriter.h" @@ -961,7 +963,8 @@ class fpa2bv_approx_tactic: public tactic { TRACE("sat_tactic", model_v2_pp(tout, *md);); model_converter_ref bb_mc = mk_bit_blaster_model_converter(*m_temp_manager, bv2bool.const2bits()); - model_converter_ref bv_mc = mk_fpa2bv_prec_model_converter(*m_temp_manager, fpa2bv.const2bv(), fpa2bv.rm_const2bv()); + + model_converter_ref bv_mc = mk_fpa2bv_model_converter(*m_temp_manager, fpa2bv.const2bv(), fpa2bv.rm_const2bv(), fpa2bv.uf2bvuf(), fpa2bv.uf23bvuf()); bb_mc->operator()(md, 0); bv_mc->operator()(md, 0); diff --git a/src/tactic/fpa/fpa2bv_converter_prec.cpp b/src/tactic/fpa/fpa2bv_converter_prec.cpp index b60a58968..046511199 100644 --- a/src/tactic/fpa/fpa2bv_converter_prec.cpp +++ b/src/tactic/fpa/fpa2bv_converter_prec.cpp @@ -1590,194 +1590,5 @@ void fpa2bv_converter_prec::mk_is_subnormal(func_decl * f, unsigned prec, unsign -void fpa2bv_prec_model_converter::display(std::ostream & out) { - out << "(fpa2bv-model-converter"; - for (obj_map::iterator it = m_const2bv.begin(); - it != m_const2bv.end(); - it++) { - const symbol & n = it->m_key->get_name(); - out << "\n (" << n << " "; - unsigned indent = n.size() + 4; - out << mk_ismt2_pp(it->m_value, m, indent) << ")"; - } - for (obj_map::iterator it = m_rm_const2bv.begin(); - it != m_rm_const2bv.end(); - it++) { - const symbol & n = it->m_key->get_name(); - out << "\n (" << n << " "; - unsigned indent = n.size() + 4; - out << mk_ismt2_pp(it->m_value, m, indent) << ")"; - } - out << ")" << std::endl; -} - -model_converter * fpa2bv_prec_model_converter::translate(ast_translation & translator) { - fpa2bv_prec_model_converter * res = alloc(fpa2bv_prec_model_converter, translator.to()); - for (obj_map::iterator it = m_const2bv.begin(); - it != m_const2bv.end(); - it++) - { - func_decl * k = translator(it->m_key); - expr * v = translator(it->m_value); - res->m_const2bv.insert(k, v); - translator.to().inc_ref(k); - translator.to().inc_ref(v); - } - for (obj_map::iterator it = m_rm_const2bv.begin(); - it != m_rm_const2bv.end(); - it++) - { - func_decl * k = translator(it->m_key); - expr * v = translator(it->m_value); - res->m_rm_const2bv.insert(k, v); - translator.to().inc_ref(k); - translator.to().inc_ref(v); - } - return res; -} - -void fpa2bv_prec_model_converter::convert(model * bv_mdl, model * float_mdl) { - fpa_util fu(m); - bv_util bu(m); - mpf fp_val,sfp_val; - unsynch_mpz_manager & mpzm = fu.fm().mpz_manager(); - unsynch_mpq_manager & mpqm = fu.fm().mpq_manager(); - - TRACE("fpa2bv_mc", tout << "BV Model: " << std::endl; - for (unsigned i = 0 ; i < bv_mdl->get_num_constants(); i++) - tout << bv_mdl->get_constant(i)->get_name() << " --> " << - mk_ismt2_pp(bv_mdl->get_const_interp(bv_mdl->get_constant(i)), m) << std::endl; - ); - - obj_hashtable seen; - - for (obj_map::iterator it = m_const2bv.begin(); - it != m_const2bv.end(); - it++) - { - func_decl * var = it->m_key; - app * a = to_app(it->m_value); - SASSERT(fu.is_float(var->get_range())); - SASSERT(var->get_range()->get_num_parameters() == 2); - - unsigned ebits = fu.get_ebits(var->get_range()); - unsigned sbits = fu.get_sbits(var->get_range()); - unsigned sfpa_ebits = fu.get_ebits(a->get_decl()->get_range()); - unsigned sfpa_sbits = fu.get_sbits(a->get_decl()->get_range()); - - expr_ref sgn(m), sig(m), exp(m); - if (a->get_decl_kind() == OP_FPA_TO_FP) - { - bv_mdl->eval(a->get_arg(0), sgn, true); - bv_mdl->eval(a->get_arg(1), sig, true); - bv_mdl->eval(a->get_arg(2), exp, true); - } - else - { - sgn = bv_mdl->get_const_interp(to_app(a->get_arg(0))->get_decl()); - sig = bv_mdl->get_const_interp(to_app(a->get_arg(1))->get_decl()); - exp = bv_mdl->get_const_interp(to_app(a->get_arg(2))->get_decl()); - } - - seen.insert(to_app(a->get_arg(0))->get_decl()); - seen.insert(to_app(a->get_arg(1))->get_decl()); - seen.insert(to_app(a->get_arg(2))->get_decl()); - - if (!sgn && !sig && !exp) - continue; - - unsigned sgn_sz = bu.get_bv_size(m.get_sort(a->get_arg(0))); - unsigned sig_sz = bu.get_bv_size(m.get_sort(a->get_arg(1))) - 1; - unsigned exp_sz = bu.get_bv_size(m.get_sort(a->get_arg(2))); - - rational sgn_q(0), sig_q(0), exp_q(0); - - if (sgn) bu.is_numeral(sgn, sgn_q, sgn_sz); - if (sig) bu.is_numeral(sig, sig_q, sig_sz); - if (exp) bu.is_numeral(exp, exp_q, exp_sz); - - // un-bias exponent - rational exp_unbiased_q; - mpz sig_z; mpf_exp_t exp_z; - - exp_unbiased_q = exp_q - fu.fm().m_powers2.m1(sfpa_ebits-1); - - mpzm.set(sig_z, sig_q.to_mpq().numerator()); - exp_z = mpzm.get_int64(exp_unbiased_q.to_mpq().numerator()); - - TRACE("fpa2bv_mc", tout << var->get_name() << " == [" << sgn_q.to_string() << " " << - mpzm.to_string(sig_z) << " " << exp_z << "(" << exp_q.to_string() << ")]" << std::endl; ); - - - fu.fm().set(sfp_val, sfpa_ebits, sfpa_sbits, !mpqm.is_zero(sgn_q.to_mpq()), sig_z, exp_z); - fu.fm().set(fp_val, ebits, sbits,MPF_ROUND_TOWARD_ZERO,sfp_val); - //fu.fm().set(fp_val, ebits, sbits, !mpqm.is_zero(sgn_q.to_mpq()), sig_z, exp_z); - /*std::cout<< mk_ismt2_pp(a,m) <<":" << fu.mk_value(fp_val)<register_decl(var, fu.mk_value(fp_val)); - - mpzm.del(sig_z); - fu.fm().del(fp_val); - fu.fm().del(sfp_val); - } - - for (obj_map::iterator it = m_rm_const2bv.begin(); - it != m_rm_const2bv.end(); - it++) - { - func_decl * var = it->m_key; - app * a = to_app(it->m_value); - SASSERT(fu.is_rm(var->get_range())); - rational val(0); - unsigned sz = 0; - if (a && bu.is_numeral(a, val, sz)) { - TRACE("fpa2bv_mc", tout << var->get_name() << " == " << val.to_string() << std::endl; ); - SASSERT(val.is_uint64()); - switch (val.get_uint64()) - { - case BV_RM_TIES_TO_AWAY: float_mdl->register_decl(var, fu.mk_round_nearest_ties_to_away()); break; - case BV_RM_TIES_TO_EVEN: float_mdl->register_decl(var, fu.mk_round_nearest_ties_to_even()); break; - case BV_RM_TO_NEGATIVE: float_mdl->register_decl(var, fu.mk_round_toward_negative()); break; - case BV_RM_TO_POSITIVE: float_mdl->register_decl(var, fu.mk_round_toward_positive()); break; - case BV_RM_TO_ZERO: - default: float_mdl->register_decl(var, fu.mk_round_toward_zero()); - } - seen.insert(var); - } - } - - fu.fm().del(fp_val); - - // Keep all the non-float constants. - unsigned sz = bv_mdl->get_num_constants(); - for (unsigned i = 0; i < sz; i++) - { - func_decl * c = bv_mdl->get_constant(i); - if (!seen.contains(c)) - float_mdl->register_decl(c, bv_mdl->get_const_interp(c)); - } - - // And keep everything else - sz = bv_mdl->get_num_functions(); - for (unsigned i = 0; i < sz; i++) - { - func_decl * c = bv_mdl->get_function(i); - float_mdl->register_decl(c, bv_mdl->get_const_interp(c)); - } - - sz = bv_mdl->get_num_uninterpreted_sorts(); - for (unsigned i = 0; i < sz; i++) - { - sort * s = bv_mdl->get_uninterpreted_sort(i); - ptr_vector u = bv_mdl->get_universe(s); - float_mdl->register_usort(s, u.size(), u.c_ptr()); - } -} - -model_converter * mk_fpa2bv_prec_model_converter(ast_manager & m, - obj_map const & const2bv, - obj_map const & rm_const2bv) { - return alloc(fpa2bv_prec_model_converter, m, const2bv, rm_const2bv); -} - diff --git a/src/tactic/fpa/fpa2bv_converter_prec.h b/src/tactic/fpa/fpa2bv_converter_prec.h index 330cd271f..24631b1ff 100644 --- a/src/tactic/fpa/fpa2bv_converter_prec.h +++ b/src/tactic/fpa/fpa2bv_converter_prec.h @@ -99,64 +99,5 @@ public: }; -class fpa2bv_prec_model_converter : public model_converter { - ast_manager & m; - obj_map m_const2bv; - obj_map m_rm_const2bv; - -public: - fpa2bv_prec_model_converter(ast_manager & m, obj_map const & const2bv, - obj_map const & rm_const2bv) : - m(m) { - // Just create a copy? - for (obj_map::iterator it = const2bv.begin(); - it != const2bv.end(); - it++) - { - m_const2bv.insert(it->m_key, it->m_value); - m.inc_ref(it->m_key); - m.inc_ref(it->m_value); - } - for (obj_map::iterator it = rm_const2bv.begin(); - it != rm_const2bv.end(); - it++) - { - m_rm_const2bv.insert(it->m_key, it->m_value); - m.inc_ref(it->m_key); - m.inc_ref(it->m_value); - } - } - - virtual ~fpa2bv_prec_model_converter() { - dec_ref_map_key_values(m, m_const2bv); - dec_ref_map_key_values(m, m_rm_const2bv); - } - - virtual void operator()(model_ref & md, unsigned goal_idx) { - SASSERT(goal_idx == 0); - model * new_model = alloc(model, m); - obj_hashtable bits; - convert(md.get(), new_model); - md = new_model; - } - - virtual void operator()(model_ref & md) { - operator()(md, 0); - } - - void display(std::ostream & out); - - virtual model_converter * translate(ast_translation & translator); - -protected: - fpa2bv_prec_model_converter(ast_manager & m) : m(m) { } - - void convert(model * bv_mdl, model * float_mdl); -}; - - -model_converter * mk_fpa2bv_prec_model_converter(ast_manager & m, - obj_map const & const2bv, - obj_map const & rm_const2bv); #endif From b08ccc7816978ce17637ff446dbfa1e3dd9e365d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 10 Jun 2015 11:54:02 -0700 Subject: [PATCH 909/925] added missing Copyright forms Signed-off-by: Nikolaj Bjorner --- scripts/mk_copyright.py | 54 +++++++++++++++++++++++ src/api/dll/dll.cpp | 6 +++ src/api/z3_api.h | 6 +++ src/api/z3_macros.h | 6 +++ src/ast/proof_checker/proof_checker.cpp | 6 +++ src/ast/simplifier/bv_elim.cpp | 6 +++ src/muz/base/dl_boogie_proof.cpp | 6 +++ src/muz/base/dl_boogie_proof.h | 6 +++ src/muz/base/hnf.h | 6 +++ src/muz/base/proof_utils.cpp | 6 +++ src/muz/fp/datalog_parser.cpp | 6 +++ src/muz/rel/check_relation.cpp | 6 +++ src/muz/rel/karr_relation.cpp | 6 +++ src/parsers/smt/smtlib.cpp | 6 +++ src/qe/nlarith_util.cpp | 6 +++ src/qe/qe_arith.h | 6 +++ src/qe/qe_array_plugin.cpp | 6 +++ src/qe/qe_cmd.cpp | 6 +++ src/qe/qe_datatype_plugin.cpp | 6 +++ src/qe/qe_dl_plugin.cpp | 6 +++ src/qe/qe_util.cpp | 6 +++ src/shell/opt_frontend.cpp | 6 +++ src/shell/options.h | 6 +++ src/smt/database.h | 6 +++ src/tactic/arith/arith_bounds_tactic.cpp | 6 +++ src/test/api.cpp | 6 +++ src/test/api_bug.cpp | 6 +++ src/test/arith_rewriter.cpp | 6 +++ src/test/arith_simplifier_plugin.cpp | 6 +++ src/test/bits.cpp | 6 +++ src/test/bv_simplifier_plugin.cpp | 6 +++ src/test/check_assumptions.cpp | 6 +++ src/test/datalog_parser.cpp | 6 +++ src/test/ddnf.cpp | 6 +++ src/test/dl_context.cpp | 6 +++ src/test/dl_product_relation.cpp | 6 +++ src/test/dl_query.cpp | 6 +++ src/test/dl_relation.cpp | 6 +++ src/test/dl_table.cpp | 6 +++ src/test/dl_util.cpp | 6 +++ src/test/doc.cpp | 6 +++ src/test/expr_rand.cpp | 6 +++ src/test/expr_substitution.cpp | 6 +++ src/test/factor_rewriter.cpp | 6 +++ src/test/fuzzing/expr_delta.cpp | 6 +++ src/test/fuzzing/expr_rand.cpp | 6 +++ src/test/get_implied_equalities.cpp | 6 +++ src/test/heap_trie.cpp | 6 +++ src/test/hilbert_basis.cpp | 6 +++ src/test/horn_subsume_model_converter.cpp | 6 +++ src/test/karr.cpp | 6 +++ src/test/memory.cpp | 6 +++ src/test/model2expr.cpp | 6 +++ src/test/model_retrieval.cpp | 6 +++ src/test/nlarith_util.cpp | 6 +++ src/test/pdr.cpp | 6 +++ src/test/polynorm.cpp | 6 +++ src/test/proof_checker.cpp | 6 +++ src/test/qe_arith.cpp | 6 +++ src/test/quant_elim.cpp | 6 +++ src/test/quant_solve.cpp | 6 +++ src/test/sat_user_scope.cpp | 6 +++ src/test/simplex.cpp | 6 +++ src/test/simplifier.cpp | 6 +++ src/test/small_object_allocator.cpp | 6 +++ src/test/smt2print_parse.cpp | 6 +++ src/test/smt_context.cpp | 6 +++ src/test/sorting_network.cpp | 6 +++ src/test/substitution.cpp | 6 +++ src/test/tbv.cpp | 6 +++ src/test/test_util.h | 6 +++ src/test/theory_dl.cpp | 6 +++ src/test/theory_pb.cpp | 6 +++ src/test/timeout.cpp | 6 +++ src/test/udoc_relation.cpp | 6 +++ src/util/memory_manager.cpp | 6 +++ 76 files changed, 504 insertions(+) create mode 100644 scripts/mk_copyright.py diff --git a/scripts/mk_copyright.py b/scripts/mk_copyright.py new file mode 100644 index 000000000..f7a4cb8fd --- /dev/null +++ b/scripts/mk_copyright.py @@ -0,0 +1,54 @@ +import os +import re + +cr = re.compile("Copyright") +aut = re.compile("Automatically generated") + +cr_notice = """ +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + +""" + +def has_cr(file): + ins = open(file) + lines = 0 + line = ins.readline() + while line and lines < 20: + m = cr.search(line) + if m: + ins.close() + return True + m = aut.search(line) + if m: + ins.close() + return True + line = ins.readline() + ins.close() + return False + +def add_cr(file): + tmp = "%s.tmp" % file + ins = open(file) + ous = open(tmp,'w') + ous.write(cr_notice) + line = ins.readline() + while line: + ous.write(line) + line = ins.readline() + ins.close() + ous.close() + os.system("move %s %s" % (tmp, file)) + +def add_missing_cr(): + for root, dirs, files in os.walk('src'): + for f in files: + if f.endswith('.cpp') or f.endswith('.h'): + path = "%s\\%s" % (root, f) + if not has_cr(path): + print "Missing CR for %s" % path + add_cr(path) + +add_missing_cr() diff --git a/src/api/dll/dll.cpp b/src/api/dll/dll.cpp index 1730ede23..a0bd25d2e 100644 --- a/src/api/dll/dll.cpp +++ b/src/api/dll/dll.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #ifdef _WINDOWS #include diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 4746d4a33..dfad8b755 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #ifndef _Z3_API_H_ #define _Z3_API_H_ diff --git a/src/api/z3_macros.h b/src/api/z3_macros.h index 7a0b6857c..cdac41c97 100644 --- a/src/api/z3_macros.h +++ b/src/api/z3_macros.h @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #ifndef __in #define __in #endif diff --git a/src/ast/proof_checker/proof_checker.cpp b/src/ast/proof_checker/proof_checker.cpp index 41c43b26c..16546db1e 100644 --- a/src/ast/proof_checker/proof_checker.cpp +++ b/src/ast/proof_checker/proof_checker.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "proof_checker.h" #include "ast_ll_pp.h" #include "ast_pp.h" diff --git a/src/ast/simplifier/bv_elim.cpp b/src/ast/simplifier/bv_elim.cpp index fc4e7534b..8dc2671ca 100644 --- a/src/ast/simplifier/bv_elim.cpp +++ b/src/ast/simplifier/bv_elim.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "bv_elim.h" #include "bv_decl_plugin.h" #include "var_subst.h" diff --git a/src/muz/base/dl_boogie_proof.cpp b/src/muz/base/dl_boogie_proof.cpp index 42d21dfb9..cc0e28e2a 100644 --- a/src/muz/base/dl_boogie_proof.cpp +++ b/src/muz/base/dl_boogie_proof.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + /** Example from Boogie: diff --git a/src/muz/base/dl_boogie_proof.h b/src/muz/base/dl_boogie_proof.h index 6c8fbbae3..0f829dbdf 100644 --- a/src/muz/base/dl_boogie_proof.h +++ b/src/muz/base/dl_boogie_proof.h @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + /** output :: derivation model diff --git a/src/muz/base/hnf.h b/src/muz/base/hnf.h index 9dc7cccd9..4d3edcb68 100644 --- a/src/muz/base/hnf.h +++ b/src/muz/base/hnf.h @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + /*-- Module Name: diff --git a/src/muz/base/proof_utils.cpp b/src/muz/base/proof_utils.cpp index d4a8ab22b..4bfbf3365 100644 --- a/src/muz/base/proof_utils.cpp +++ b/src/muz/base/proof_utils.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "dl_util.h" #include "proof_utils.h" #include "ast_smt2_pp.h" diff --git a/src/muz/fp/datalog_parser.cpp b/src/muz/fp/datalog_parser.cpp index 58bc79e7a..c6f594d4e 100644 --- a/src/muz/fp/datalog_parser.cpp +++ b/src/muz/fp/datalog_parser.cpp @@ -1,4 +1,10 @@ +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + + #include"datalog_parser.h" #include"string_buffer.h" #include"str_hashtable.h" diff --git a/src/muz/rel/check_relation.cpp b/src/muz/rel/check_relation.cpp index 20364d5d5..60ca6c0be 100644 --- a/src/muz/rel/check_relation.cpp +++ b/src/muz/rel/check_relation.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "check_relation.h" #include "dl_relation_manager.h" #include "qe_util.h" diff --git a/src/muz/rel/karr_relation.cpp b/src/muz/rel/karr_relation.cpp index 436cd8598..6b9126161 100644 --- a/src/muz/rel/karr_relation.cpp +++ b/src/muz/rel/karr_relation.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "karr_relation.h" #include "bool_rewriter.h" diff --git a/src/parsers/smt/smtlib.cpp b/src/parsers/smt/smtlib.cpp index d53d3cafa..b743b5b0f 100644 --- a/src/parsers/smt/smtlib.cpp +++ b/src/parsers/smt/smtlib.cpp @@ -1,4 +1,10 @@ +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + + #include"smtlib.h" #include"ast_pp.h" #include"ast_smt2_pp.h" diff --git a/src/qe/nlarith_util.cpp b/src/qe/nlarith_util.cpp index c555b71f1..b7c1aef5d 100644 --- a/src/qe/nlarith_util.cpp +++ b/src/qe/nlarith_util.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "ast.h" #include "nlarith_util.h" #include "arith_decl_plugin.h" diff --git a/src/qe/qe_arith.h b/src/qe/qe_arith.h index c8f7e8b8d..725245fad 100644 --- a/src/qe/qe_arith.h +++ b/src/qe/qe_arith.h @@ -1,4 +1,10 @@ +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + + #ifndef __QE_ARITH_H_ #define __QE_ARITH_H_ diff --git a/src/qe/qe_array_plugin.cpp b/src/qe/qe_array_plugin.cpp index c9de1d745..e7cbe65b9 100644 --- a/src/qe/qe_array_plugin.cpp +++ b/src/qe/qe_array_plugin.cpp @@ -1,4 +1,10 @@ +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + + #include "qe.h" #include "array_decl_plugin.h" #include "expr_safe_replace.h" diff --git a/src/qe/qe_cmd.cpp b/src/qe/qe_cmd.cpp index 6f001c9da..9144c708c 100644 --- a/src/qe/qe_cmd.cpp +++ b/src/qe/qe_cmd.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "qe_cmd.h" #include "qe.h" #include "cmd_context.h" diff --git a/src/qe/qe_datatype_plugin.cpp b/src/qe/qe_datatype_plugin.cpp index 9b77de42a..088d2252d 100644 --- a/src/qe/qe_datatype_plugin.cpp +++ b/src/qe/qe_datatype_plugin.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + // --------------------- // datatypes // Quantifier elimination routine for recursive data-types. diff --git a/src/qe/qe_dl_plugin.cpp b/src/qe/qe_dl_plugin.cpp index a93301b4f..e04f4cbde 100644 --- a/src/qe/qe_dl_plugin.cpp +++ b/src/qe/qe_dl_plugin.cpp @@ -1,4 +1,10 @@ +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + + #include "qe.h" #include "expr_safe_replace.h" #include "dl_decl_plugin.h" diff --git a/src/qe/qe_util.cpp b/src/qe/qe_util.cpp index 77396ac49..2cf723c08 100644 --- a/src/qe/qe_util.cpp +++ b/src/qe/qe_util.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "qe_util.h" #include "bool_rewriter.h" diff --git a/src/shell/opt_frontend.cpp b/src/shell/opt_frontend.cpp index 6e39313fd..78d083e6e 100644 --- a/src/shell/opt_frontend.cpp +++ b/src/shell/opt_frontend.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include #include #include diff --git a/src/shell/options.h b/src/shell/options.h index 951062ff0..ee1de00fb 100644 --- a/src/shell/options.h +++ b/src/shell/options.h @@ -1,4 +1,10 @@ +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + + /** \page cmdline Command line options diff --git a/src/smt/database.h b/src/smt/database.h index 69843f434..3edb87f1f 100644 --- a/src/smt/database.h +++ b/src/smt/database.h @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + static char const g_pattern_database[] = "(benchmark patterns \n" " :status unknown \n" diff --git a/src/tactic/arith/arith_bounds_tactic.cpp b/src/tactic/arith/arith_bounds_tactic.cpp index dc24a625b..83b5c6daf 100644 --- a/src/tactic/arith/arith_bounds_tactic.cpp +++ b/src/tactic/arith/arith_bounds_tactic.cpp @@ -1,4 +1,10 @@ +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + + #include"arith_bounds_tactic.h" #include"arith_decl_plugin.h" diff --git a/src/test/api.cpp b/src/test/api.cpp index 234d1192c..a463bbe47 100644 --- a/src/test/api.cpp +++ b/src/test/api.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #ifdef _WINDOWS #include "z3.h" #include "z3_private.h" diff --git a/src/test/api_bug.cpp b/src/test/api_bug.cpp index 4519b2352..b88840eb6 100644 --- a/src/test/api_bug.cpp +++ b/src/test/api_bug.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include #include"z3.h" diff --git a/src/test/arith_rewriter.cpp b/src/test/arith_rewriter.cpp index 9eb9e559b..5ed7c3501 100644 --- a/src/test/arith_rewriter.cpp +++ b/src/test/arith_rewriter.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "arith_rewriter.h" #include "bv_decl_plugin.h" #include "ast_pp.h" diff --git a/src/test/arith_simplifier_plugin.cpp b/src/test/arith_simplifier_plugin.cpp index 59f4996ce..8464fd830 100644 --- a/src/test/arith_simplifier_plugin.cpp +++ b/src/test/arith_simplifier_plugin.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "arith_eq_solver.h" #include "smt_params.h" diff --git a/src/test/bits.cpp b/src/test/bits.cpp index 7254a177d..f32871a5a 100644 --- a/src/test/bits.cpp +++ b/src/test/bits.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + // Test some bit hacks #include"util.h" #include"debug.h" diff --git a/src/test/bv_simplifier_plugin.cpp b/src/test/bv_simplifier_plugin.cpp index 77e57f1f5..dc930bb82 100644 --- a/src/test/bv_simplifier_plugin.cpp +++ b/src/test/bv_simplifier_plugin.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "bv_simplifier_plugin.h" #include "arith_decl_plugin.h" #include "ast_pp.h" diff --git a/src/test/check_assumptions.cpp b/src/test/check_assumptions.cpp index 872af714c..fa8327cd4 100644 --- a/src/test/check_assumptions.cpp +++ b/src/test/check_assumptions.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "memory_manager.h" #include "smt_params.h" #include "ast.h" diff --git a/src/test/datalog_parser.cpp b/src/test/datalog_parser.cpp index e23650e3b..a927be29a 100644 --- a/src/test/datalog_parser.cpp +++ b/src/test/datalog_parser.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "datalog_parser.h" #include "ast_pp.h" #include "arith_decl_plugin.h" diff --git a/src/test/ddnf.cpp b/src/test/ddnf.cpp index 024f1bb0f..8620bd441 100644 --- a/src/test/ddnf.cpp +++ b/src/test/ddnf.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "ddnf.h" #include "tbv.h" #include diff --git a/src/test/dl_context.cpp b/src/test/dl_context.cpp index 5c70aa8b5..09db4bde2 100644 --- a/src/test/dl_context.cpp +++ b/src/test/dl_context.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "datalog_parser.h" #include "ast_pp.h" #include "arith_decl_plugin.h" diff --git a/src/test/dl_product_relation.cpp b/src/test/dl_product_relation.cpp index 357ccd604..c375587fb 100644 --- a/src/test/dl_product_relation.cpp +++ b/src/test/dl_product_relation.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #ifdef _WINDOWS #include "dl_context.h" #include "dl_register_engine.h" diff --git a/src/test/dl_query.cpp b/src/test/dl_query.cpp index 39ea06959..9e0f285c7 100644 --- a/src/test/dl_query.cpp +++ b/src/test/dl_query.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "datalog_parser.h" #include "ast_pp.h" #include "dl_table_relation.h" diff --git a/src/test/dl_relation.cpp b/src/test/dl_relation.cpp index bb1c8614c..c2ce807a9 100644 --- a/src/test/dl_relation.cpp +++ b/src/test/dl_relation.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #ifdef _WINDOWS #include "dl_context.h" #include "dl_register_engine.h" diff --git a/src/test/dl_table.cpp b/src/test/dl_table.cpp index d24200f9b..6dc688ede 100644 --- a/src/test/dl_table.cpp +++ b/src/test/dl_table.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #ifdef _WINDOWS #include "dl_context.h" #include "dl_table.h" diff --git a/src/test/dl_util.cpp b/src/test/dl_util.cpp index 601fd630a..02e40bbd9 100644 --- a/src/test/dl_util.cpp +++ b/src/test/dl_util.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "dl_util.h" using namespace datalog; diff --git a/src/test/doc.cpp b/src/test/doc.cpp index 593d09cfe..b2863a629 100644 --- a/src/test/doc.cpp +++ b/src/test/doc.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "doc.h" #include "trace.h" #include "vector.h" diff --git a/src/test/expr_rand.cpp b/src/test/expr_rand.cpp index 19a07e98a..972c6e242 100644 --- a/src/test/expr_rand.cpp +++ b/src/test/expr_rand.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "expr_rand.h" #include "ast_pp.h" #include "bv_decl_plugin.h" diff --git a/src/test/expr_substitution.cpp b/src/test/expr_substitution.cpp index f83bde97d..8af3f7197 100644 --- a/src/test/expr_substitution.cpp +++ b/src/test/expr_substitution.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "expr_substitution.h" #include "smt_params.h" #include "substitution.h" diff --git a/src/test/factor_rewriter.cpp b/src/test/factor_rewriter.cpp index 625710fe1..3bcdcd9e9 100644 --- a/src/test/factor_rewriter.cpp +++ b/src/test/factor_rewriter.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "factor_rewriter.h" #include "bv_decl_plugin.h" #include "ast_pp.h" diff --git a/src/test/fuzzing/expr_delta.cpp b/src/test/fuzzing/expr_delta.cpp index 344e555c9..fd5117a74 100644 --- a/src/test/fuzzing/expr_delta.cpp +++ b/src/test/fuzzing/expr_delta.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "expr_delta.h" #include "ast_pp.h" diff --git a/src/test/fuzzing/expr_rand.cpp b/src/test/fuzzing/expr_rand.cpp index a2aca7e6e..f56704e45 100644 --- a/src/test/fuzzing/expr_rand.cpp +++ b/src/test/fuzzing/expr_rand.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "expr_rand.h" #include "bv_decl_plugin.h" #include "array_decl_plugin.h" diff --git a/src/test/get_implied_equalities.cpp b/src/test/get_implied_equalities.cpp index 2576920cc..37fbe2004 100644 --- a/src/test/get_implied_equalities.cpp +++ b/src/test/get_implied_equalities.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "z3.h" #include "trace.h" #include "debug.h" diff --git a/src/test/heap_trie.cpp b/src/test/heap_trie.cpp index 92ef97f72..5b0047e82 100644 --- a/src/test/heap_trie.cpp +++ b/src/test/heap_trie.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "heap_trie.h" struct unsigned_le { diff --git a/src/test/hilbert_basis.cpp b/src/test/hilbert_basis.cpp index 6fdfb1560..57c8c5050 100644 --- a/src/test/hilbert_basis.cpp +++ b/src/test/hilbert_basis.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "hilbert_basis.h" #include "ast_pp.h" #include "reg_decl_plugins.h" diff --git a/src/test/horn_subsume_model_converter.cpp b/src/test/horn_subsume_model_converter.cpp index 28359b954..4b653e3a8 100644 --- a/src/test/horn_subsume_model_converter.cpp +++ b/src/test/horn_subsume_model_converter.cpp @@ -1,4 +1,10 @@ +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + + #include "horn_subsume_model_converter.h" #include "arith_decl_plugin.h" #include "model_smt2_pp.h" diff --git a/src/test/karr.cpp b/src/test/karr.cpp index 87debf662..4c0737230 100644 --- a/src/test/karr.cpp +++ b/src/test/karr.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "hilbert_basis.h" /* diff --git a/src/test/memory.cpp b/src/test/memory.cpp index 0f5a92e2c..340a1929c 100644 --- a/src/test/memory.cpp +++ b/src/test/memory.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #ifdef _WINDOWS #include "z3.h" #include "z3_private.h" diff --git a/src/test/model2expr.cpp b/src/test/model2expr.cpp index abca706c1..f96cee55f 100644 --- a/src/test/model2expr.cpp +++ b/src/test/model2expr.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "model2expr.h" #include "ast_pp.h" #include "arith_decl_plugin.h" diff --git a/src/test/model_retrieval.cpp b/src/test/model_retrieval.cpp index f40f89d22..e42e22539 100644 --- a/src/test/model_retrieval.cpp +++ b/src/test/model_retrieval.cpp @@ -1,4 +1,10 @@ +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + + #include "ast.h" #include "smt_params.h" #include "smt_context.h" diff --git a/src/test/nlarith_util.cpp b/src/test/nlarith_util.cpp index f08fa020e..2def66b38 100644 --- a/src/test/nlarith_util.cpp +++ b/src/test/nlarith_util.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "nlarith_util.h" #include "arith_decl_plugin.h" #include "ast_pp.h" diff --git a/src/test/pdr.cpp b/src/test/pdr.cpp index a9194ec60..a1410b482 100644 --- a/src/test/pdr.cpp +++ b/src/test/pdr.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "pdr_context.h" #include "reg_decl_plugins.h" diff --git a/src/test/polynorm.cpp b/src/test/polynorm.cpp index 3593e98ce..a8f4ab861 100644 --- a/src/test/polynorm.cpp +++ b/src/test/polynorm.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "th_rewriter.h" #include "smt2parser.h" #include "arith_decl_plugin.h" diff --git a/src/test/proof_checker.cpp b/src/test/proof_checker.cpp index 12a5245e6..7f9827187 100644 --- a/src/test/proof_checker.cpp +++ b/src/test/proof_checker.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "proof_checker.h" #include "ast_ll_pp.h" diff --git a/src/test/qe_arith.cpp b/src/test/qe_arith.cpp index 8b6577b3f..bd8266dc2 100644 --- a/src/test/qe_arith.cpp +++ b/src/test/qe_arith.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "qe_arith.h" #include "qe.h" #include "th_rewriter.h" diff --git a/src/test/quant_elim.cpp b/src/test/quant_elim.cpp index 15d23a574..0fe7f8eec 100644 --- a/src/test/quant_elim.cpp +++ b/src/test/quant_elim.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "ast.h" #include "smt_params.h" #include "simplifier.h" diff --git a/src/test/quant_solve.cpp b/src/test/quant_solve.cpp index ae2dadee9..aa1306128 100644 --- a/src/test/quant_solve.cpp +++ b/src/test/quant_solve.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "ast.h" #include "smt_params.h" #include "qe.h" diff --git a/src/test/sat_user_scope.cpp b/src/test/sat_user_scope.cpp index e39059563..5107361bd 100644 --- a/src/test/sat_user_scope.cpp +++ b/src/test/sat_user_scope.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "sat_solver.h" #include "util.h" diff --git a/src/test/simplex.cpp b/src/test/simplex.cpp index a70d0d8cf..61ab7180b 100644 --- a/src/test/simplex.cpp +++ b/src/test/simplex.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "sparse_matrix.h" #include "sparse_matrix_def.h" #include "simplex.h" diff --git a/src/test/simplifier.cpp b/src/test/simplifier.cpp index 733c9e23a..2e8f434e1 100644 --- a/src/test/simplifier.cpp +++ b/src/test/simplifier.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #ifdef _WINDOWS #include "z3.h" #include "z3_private.h" diff --git a/src/test/small_object_allocator.cpp b/src/test/small_object_allocator.cpp index 1e74a734b..1ecf865dd 100644 --- a/src/test/small_object_allocator.cpp +++ b/src/test/small_object_allocator.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include #include"util.h" #include"trace.h" diff --git a/src/test/smt2print_parse.cpp b/src/test/smt2print_parse.cpp index 39543d141..982e2e3f5 100644 --- a/src/test/smt2print_parse.cpp +++ b/src/test/smt2print_parse.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + // This is to test the print-parse facilities over the API // for SMT-LIB2. diff --git a/src/test/smt_context.cpp b/src/test/smt_context.cpp index 49ada8ebd..6c44b8b1d 100644 --- a/src/test/smt_context.cpp +++ b/src/test/smt_context.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "smt_context.h" #include "reg_decl_plugins.h" diff --git a/src/test/sorting_network.cpp b/src/test/sorting_network.cpp index dd46b61df..4802e2bec 100644 --- a/src/test/sorting_network.cpp +++ b/src/test/sorting_network.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "trace.h" #include "vector.h" #include "ast.h" diff --git a/src/test/substitution.cpp b/src/test/substitution.cpp index 0d7fb5856..cdc7f2080 100644 --- a/src/test/substitution.cpp +++ b/src/test/substitution.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "expr_substitution.h" #include "smt_params.h" #include "substitution.h" diff --git a/src/test/tbv.cpp b/src/test/tbv.cpp index c53eb3671..7637c7e83 100644 --- a/src/test/tbv.cpp +++ b/src/test/tbv.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "tbv.h" static void tst1(unsigned num_bits) { diff --git a/src/test/test_util.h b/src/test/test_util.h index c83a94dbf..c81524b0e 100644 --- a/src/test/test_util.h +++ b/src/test/test_util.h @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #pragma once #include "stopwatch.h" diff --git a/src/test/theory_dl.cpp b/src/test/theory_dl.cpp index 9521a8932..463625c88 100644 --- a/src/test/theory_dl.cpp +++ b/src/test/theory_dl.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "smt_context.h" #include "dl_decl_plugin.h" #include "ast_pp.h" diff --git a/src/test/theory_pb.cpp b/src/test/theory_pb.cpp index ee1ec126a..3a229d951 100644 --- a/src/test/theory_pb.cpp +++ b/src/test/theory_pb.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "smt_context.h" #include "ast_pp.h" #include "model_v2_pp.h" diff --git a/src/test/timeout.cpp b/src/test/timeout.cpp index 19daebb12..320006928 100644 --- a/src/test/timeout.cpp +++ b/src/test/timeout.cpp @@ -1,4 +1,10 @@ +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + + #include "timeout.h" #include "trace.h" diff --git a/src/test/udoc_relation.cpp b/src/test/udoc_relation.cpp index 7be048c73..0545ed62c 100644 --- a/src/test/udoc_relation.cpp +++ b/src/test/udoc_relation.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include "udoc_relation.h" #include "trace.h" #include "vector.h" diff --git a/src/util/memory_manager.cpp b/src/util/memory_manager.cpp index e911ff505..7539e7ba3 100644 --- a/src/util/memory_manager.cpp +++ b/src/util/memory_manager.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include #include #include From d469a16bb876edf4b1dc746fa5f89a930b8b6c15 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 10 Jun 2015 11:59:21 -0700 Subject: [PATCH 910/925] add more Copyright notes Signed-off-by: Nikolaj Bjorner --- examples/c++/example.cpp | 6 ++++++ examples/c/test_capi.c | 6 ++++++ examples/interp/iz3.cpp | 6 ++++++ examples/maxsat/maxsat.c | 6 ++++++ examples/tptp/tptp5.cpp | 6 ++++++ examples/tptp/tptp5.h | 6 ++++++ examples/tptp/tptp5.lex.cpp | 6 ++++++ scripts/mk_copyright.py | 11 +++++++---- scripts/trackall.sh | 2 ++ src/api/ml/z3_stubs.c | 6 ++++++ 10 files changed, 57 insertions(+), 4 deletions(-) diff --git a/examples/c++/example.cpp b/examples/c++/example.cpp index c20800f25..660db61d8 100644 --- a/examples/c++/example.cpp +++ b/examples/c++/example.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include #include"z3++.h" diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c index c0ea70453..cb63fe623 100644 --- a/examples/c/test_capi.c +++ b/examples/c/test_capi.c @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include #include #include diff --git a/examples/interp/iz3.cpp b/examples/interp/iz3.cpp index 6d631ebc9..9f55c1ec6 100755 --- a/examples/interp/iz3.cpp +++ b/examples/interp/iz3.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include #include #include diff --git a/examples/maxsat/maxsat.c b/examples/maxsat/maxsat.c index 5ca707811..f04c25e2c 100644 --- a/examples/maxsat/maxsat.c +++ b/examples/maxsat/maxsat.c @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + /* Simple MAXSAT solver on top of the Z3 API. */ diff --git a/examples/tptp/tptp5.cpp b/examples/tptp/tptp5.cpp index 3b8d2364d..0ed92801d 100644 --- a/examples/tptp/tptp5.cpp +++ b/examples/tptp/tptp5.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #include #include #include diff --git a/examples/tptp/tptp5.h b/examples/tptp/tptp5.h index 69fe79b28..948664243 100644 --- a/examples/tptp/tptp5.h +++ b/examples/tptp/tptp5.h @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #ifndef TPTP5_H_ #define TPTP5_H_ diff --git a/examples/tptp/tptp5.lex.cpp b/examples/tptp/tptp5.lex.cpp index 639d92750..afeebb30a 100644 --- a/examples/tptp/tptp5.lex.cpp +++ b/examples/tptp/tptp5.lex.cpp @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + #line 2 "tptp5.lex.cpp" #line 4 "tptp5.lex.cpp" diff --git a/scripts/mk_copyright.py b/scripts/mk_copyright.py index f7a4cb8fd..5ac185de0 100644 --- a/scripts/mk_copyright.py +++ b/scripts/mk_copyright.py @@ -1,3 +1,5 @@ +# Copyright (c) 2015 Microsoft Corporation + import os import re @@ -42,13 +44,14 @@ def add_cr(file): ous.close() os.system("move %s %s" % (tmp, file)) -def add_missing_cr(): - for root, dirs, files in os.walk('src'): +def add_missing_cr(dir): + for root, dirs, files in os.walk(dir): for f in files: - if f.endswith('.cpp') or f.endswith('.h'): + if f.endswith('.cpp') or f.endswith('.h') or f.endswith('.c'): path = "%s\\%s" % (root, f) if not has_cr(path): print "Missing CR for %s" % path add_cr(path) -add_missing_cr() +add_missing_cr('src') +add_missing_cr('examples') diff --git a/scripts/trackall.sh b/scripts/trackall.sh index d8351af24..5e637100d 100755 --- a/scripts/trackall.sh +++ b/scripts/trackall.sh @@ -1,7 +1,9 @@ #!/bin/bash +# Copyright (c) 2015 Microsoft Corporation # Script for "cloning" (and tracking) all branches at codeplex. # On Windows, this script must be executed in the "git Bash" console. + for branch in `git branch -a | grep remotes | grep -v HEAD | grep -v master`; do git branch --track ${branch##*/} $branch done diff --git a/src/api/ml/z3_stubs.c b/src/api/ml/z3_stubs.c index 6286e94c7..7222158bb 100644 --- a/src/api/ml/z3_stubs.c +++ b/src/api/ml/z3_stubs.c @@ -1,3 +1,9 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + /* File generated from z3.idl */ #include From e6ffa5d2a5155666c02eca038148f992b12903bd Mon Sep 17 00:00:00 2001 From: Alex Horn Date: Wed, 10 Jun 2015 19:59:57 +0100 Subject: [PATCH 911/925] Enable datalog plugin for AST extensions Signed-off-by: Alex Horn --- src/cmd_context/cmd_context.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 50afc1735..c8d5e8cab 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -621,6 +621,7 @@ void cmd_context::init_manager_core(bool new_manager) { register_plugin(symbol("seq"), alloc(seq_decl_plugin), logic_has_seq()); register_plugin(symbol("pb"), alloc(pb_decl_plugin), !has_logic()); register_plugin(symbol("fpa"), alloc(fpa_decl_plugin), logic_has_fpa()); + register_plugin(symbol("datalog_relation"), alloc(datalog::dl_decl_plugin), !has_logic()); } else { // the manager was created by an external module From e0068e406509022d1befdf02dd7990d0a0787764 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 10 Jun 2015 12:01:47 -0700 Subject: [PATCH 912/925] C/right on python scripts Signed-off-by: Nikolaj Bjorner --- doc/mk_api_doc.py | 2 ++ examples/python/example.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/doc/mk_api_doc.py b/doc/mk_api_doc.py index 1b498fb19..e45f56134 100644 --- a/doc/mk_api_doc.py +++ b/doc/mk_api_doc.py @@ -1,3 +1,5 @@ +# Copyright (c) Microsoft Corporation 2015 + import os import shutil import re diff --git a/examples/python/example.py b/examples/python/example.py index 879c17c43..e0c9374e7 100644 --- a/examples/python/example.py +++ b/examples/python/example.py @@ -1,3 +1,5 @@ +# Copyright (c) Microsoft Corporation 2015 + from z3 import * x = Real('x') From 9b7c5658c8f9b7e42607d3e56cb339821b1f12eb Mon Sep 17 00:00:00 2001 From: Alex Horn Date: Wed, 10 Jun 2015 20:06:09 +0100 Subject: [PATCH 913/925] Ignore min aggregation functions in compiler for now Signed-off-by: Alex Horn --- src/muz/rel/dl_compiler.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/muz/rel/dl_compiler.cpp b/src/muz/rel/dl_compiler.cpp index 59ba260a4..76b7f7c36 100644 --- a/src/muz/rel/dl_compiler.cpp +++ b/src/muz/rel/dl_compiler.cpp @@ -597,7 +597,8 @@ namespace datalog { unsigned ft_len = r->get_tail_size(); // full tail ptr_vector tail; for (unsigned tail_index = ut_len; tail_index < ft_len; ++tail_index) { - tail.push_back(r->get_tail(tail_index)); + if (!r->is_min_tail(tail_index)) + tail.push_back(r->get_tail(tail_index)); } expr_ref_vector binding(m); From 132f984d5142bdc676da614796bd59da2a06caa1 Mon Sep 17 00:00:00 2001 From: Alex Horn Date: Wed, 10 Jun 2015 20:19:14 +0100 Subject: [PATCH 914/925] Add syntactical min checker The purpose of this patch is to find out more about the "shape" of the constraints in our benchmarks. In particular, we would like to determine whether aggregation and negation, together, appear in recursive rules. Signed-off-by: Alex Horn --- src/muz/base/dl_rule_set.cpp | 45 +++++++++++++++++++++++++++++++++++- src/muz/base/dl_rule_set.h | 2 +- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/muz/base/dl_rule_set.cpp b/src/muz/base/dl_rule_set.cpp index ad3b512a3..555b592ef 100644 --- a/src/muz/base/dl_rule_set.cpp +++ b/src/muz/base/dl_rule_set.cpp @@ -400,7 +400,7 @@ namespace datalog { SASSERT(!is_closed()); //the rule_set is not already closed m_deps.populate(*this); m_stratifier = alloc(rule_stratifier, m_deps); - if (!stratified_negation()) { + if (!stratified_negation() || !check_min()) { m_stratifier = 0; m_deps.reset(); return false; @@ -441,6 +441,49 @@ namespace datalog { return true; } + bool rule_set::check_min() { + // For now, we check the following: + // + // if a min aggregation function occurs in an SCC, is this SCC + // free of any other non-monotonic functions, e.g. negation? + const unsigned NEG_BIT = 1U << 0; + const unsigned MIN_BIT = 1U << 1; + + ptr_vector::const_iterator it = m_rules.c_ptr(); + ptr_vector::const_iterator end = m_rules.c_ptr() + m_rules.size(); + unsigned_vector component_status(m_stratifier->get_strats().size()); + + for (; it != end; it++) { + rule * r = *it; + app * head = r->get_head(); + func_decl * head_decl = head->get_decl(); + unsigned head_strat = get_predicate_strat(head_decl); + unsigned n = r->get_tail_size(); + for (unsigned i = 0; i < n; i++) { + func_decl * tail_decl = r->get_tail(i)->get_decl(); + unsigned strat = get_predicate_strat(tail_decl); + + if (r->is_neg_tail(i)) { + SASSERT(strat < component_status.size()); + component_status[strat] |= NEG_BIT; + } + + if (r->is_min_tail(i)) { + SASSERT(strat < component_status.size()); + component_status[strat] |= MIN_BIT; + } + } + } + + const unsigned CONFLICT = NEG_BIT | MIN_BIT; + for (unsigned k = 0; k < component_status.size(); ++k) { + if (component_status[k] == CONFLICT) + return false; + } + + return true; + } + void rule_set::replace_rules(const rule_set & src) { if (this != &src) { reset(); diff --git a/src/muz/base/dl_rule_set.h b/src/muz/base/dl_rule_set.h index 5201d9257..a7d09b099 100644 --- a/src/muz/base/dl_rule_set.h +++ b/src/muz/base/dl_rule_set.h @@ -179,7 +179,7 @@ namespace datalog { void compute_deps(); void compute_tc_deps(); bool stratified_negation(); - + bool check_min(); public: rule_set(context & ctx); rule_set(const rule_set & rs); From 565c0f785f6672e15d1675cf5973446d0d9b6c34 Mon Sep 17 00:00:00 2001 From: Alex Horn Date: Thu, 11 Jun 2015 08:59:57 +0100 Subject: [PATCH 915/925] Fix memory leaks Signed-off-by: Alex Horn --- src/muz/rel/dl_base.cpp | 4 ++++ src/muz/rel/dl_instruction.cpp | 1 + src/muz/rel/dl_relation_manager.cpp | 4 +++- src/muz/rel/dl_table_relation.cpp | 3 +++ 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/muz/rel/dl_base.cpp b/src/muz/rel/dl_base.cpp index a00c50d9e..6eba021f1 100644 --- a/src/muz/rel/dl_base.cpp +++ b/src/muz/rel/dl_base.cpp @@ -518,6 +518,7 @@ namespace datalog { relation_manager & manager = t.get_manager(); table_join_fn * join_fn = manager.mk_join_fn(t, t, m_group_by_cols, m_group_by_cols); table_base * join_table = (*join_fn)(t, t); + dealloc(join_fn); table_base::iterator join_table_it = join_table->begin(); table_base::iterator join_table_end = join_table->end(); @@ -545,6 +546,8 @@ namespace datalog { table_transformer_fn * project_fn = manager.mk_project_fn(*join_table, cols); table_base * gt_table = (*project_fn)(*join_table); + dealloc(project_fn); + join_table->deallocate(); for (unsigned k = 0; k < cols.size(); ++k) { cols[k] = k; @@ -555,6 +558,7 @@ namespace datalog { table_base * result = t.clone(); table_intersection_filter_fn * diff_fn = manager.mk_filter_by_negation_fn(*result, *gt_table, cols, cols); (*diff_fn)(*result, *gt_table); + dealloc(diff_fn); gt_table->deallocate(); return result; } diff --git a/src/muz/rel/dl_instruction.cpp b/src/muz/rel/dl_instruction.cpp index c903519ce..77ba387bb 100644 --- a/src/muz/rel/dl_instruction.cpp +++ b/src/muz/rel/dl_instruction.cpp @@ -916,6 +916,7 @@ namespace datalog { const relation_signature & r_sig = s.get_signature(); table_min_fn * fn = r_manager.mk_min_fn(source_t, m_group_by_cols, m_min_col); table_base * target_t = (*fn)(source_t); + dealloc(fn); TRACE("dl", tout << "% "; diff --git a/src/muz/rel/dl_relation_manager.cpp b/src/muz/rel/dl_relation_manager.cpp index 95b35899e..2b78baf05 100644 --- a/src/muz/rel/dl_relation_manager.cpp +++ b/src/muz/rel/dl_relation_manager.cpp @@ -354,7 +354,9 @@ namespace datalog { return product_relation_plugin::get_plugin(*this).mk_empty(s); } - + /** + The newly created object takes ownership of the \c table object. + */ relation_base * relation_manager::mk_table_relation(const relation_signature & s, table_base * table) { SASSERT(s.size()==table->get_signature().size()); return get_table_relation_plugin(table->get_plugin()).mk_from_table(s, table); diff --git a/src/muz/rel/dl_table_relation.cpp b/src/muz/rel/dl_table_relation.cpp index 364c29367..d42d071aa 100644 --- a/src/muz/rel/dl_table_relation.cpp +++ b/src/muz/rel/dl_table_relation.cpp @@ -63,6 +63,9 @@ namespace datalog { return alloc(table_relation, *this, s, t); } + /** + The newly created object takes ownership of the \c t object. + */ relation_base * table_relation_plugin::mk_from_table(const relation_signature & s, table_base * t) { if (&t->get_plugin() == &m_table_plugin) return alloc(table_relation, *this, s, t); From 5bd55420a4e40315e07df3d46971f7be333e8f1d Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 11 Jun 2015 12:53:22 +0100 Subject: [PATCH 916/925] C API parameter annotation fix --- src/api/z3_api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 4746d4a33..06997d99c 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -6945,7 +6945,7 @@ END_MLAPI_EXCLUDE def_API('Z3_tactic_apply_ex', APPLY_RESULT, (_in(CONTEXT), _in(TACTIC), _in(GOAL), _in(PARAMS))) */ - Z3_apply_result Z3_API Z3_tactic_apply_ex(Z3_context c, Z3_tactic t, Z3_goal g, Z3_params p); + Z3_apply_result Z3_API Z3_tactic_apply_ex(__in Z3_context c, __in Z3_tactic t, __in Z3_goal g, __in Z3_params p); #ifdef CorML3 /** From c8a123b7dd21284fb71f516fd39abae8f3fdaf26 Mon Sep 17 00:00:00 2001 From: Alex Horn Date: Thu, 11 Jun 2015 16:16:47 +0100 Subject: [PATCH 917/925] Disable a few rule transformations For this prototype, we need to disable three rule transformations, namely coi_filter, similarity_compressor, rule_inliner. But disabling the inliner causes problems with the tracer in the datalog interpreter. Since a new proprocessor is underway, we skip the problematic trace outputs for now. Signed-off-by: Alex Horn --- src/muz/rel/dl_instruction.cpp | 4 ++-- src/muz/rel/rel_context.cpp | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/muz/rel/dl_instruction.cpp b/src/muz/rel/dl_instruction.cpp index 77ba387bb..f93f88a76 100644 --- a/src/muz/rel/dl_instruction.cpp +++ b/src/muz/rel/dl_instruction.cpp @@ -553,7 +553,7 @@ namespace datalog { if (r.fast_empty()) { ctx.make_empty(m_reg); } - TRACE("dl_verbose", r.display(tout <<"post-filter-interpreted:\n");); + //TRACE("dl_verbose", r.display(tout <<"post-filter-interpreted:\n");); return true; } @@ -610,7 +610,7 @@ namespace datalog { if (ctx.reg(m_res)->fast_empty()) { ctx.make_empty(m_res); } - TRACE("dl_verbose", reg.display(tout << "post-filter-interpreted-and-project:\n");); + //TRACE("dl_verbose", reg.display(tout << "post-filter-interpreted-and-project:\n");); return true; } diff --git a/src/muz/rel/rel_context.cpp b/src/muz/rel/rel_context.cpp index c3ffdceae..44f59486e 100644 --- a/src/muz/rel/rel_context.cpp +++ b/src/muz/rel/rel_context.cpp @@ -292,17 +292,23 @@ namespace datalog { void rel_context::transform_rules() { rule_transformer transf(m_context); +#ifdef _MIN_DONE_ transf.register_plugin(alloc(mk_coi_filter, m_context)); +#endif transf.register_plugin(alloc(mk_filter_rules, m_context)); transf.register_plugin(alloc(mk_simple_joins, m_context)); if (m_context.unbound_compressor()) { transf.register_plugin(alloc(mk_unbound_compressor, m_context)); } +#ifdef _MIN_DONE_ if (m_context.similarity_compressor()) { transf.register_plugin(alloc(mk_similarity_compressor, m_context)); } +#endif transf.register_plugin(alloc(mk_partial_equivalence_transformer, m_context)); +#ifdef _MIN_DONE_ transf.register_plugin(alloc(mk_rule_inliner, m_context)); +#endif transf.register_plugin(alloc(mk_interp_tail_simplifier, m_context)); transf.register_plugin(alloc(mk_separate_negated_tails, m_context)); From 8c097044e87e4db52bd808cf8a8e20b3d5b1a0c3 Mon Sep 17 00:00:00 2001 From: Alex Horn Date: Thu, 11 Jun 2015 16:23:26 +0100 Subject: [PATCH 918/925] Add basic compiler support for min aggregation function Signed-off-by: Alex Horn --- src/muz/rel/dl_compiler.cpp | 48 +++++++++++++++++++++++++++++++++++++ src/muz/rel/dl_compiler.h | 18 ++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/src/muz/rel/dl_compiler.cpp b/src/muz/rel/dl_compiler.cpp index 76b7f7c36..c35985e98 100644 --- a/src/muz/rel/dl_compiler.cpp +++ b/src/muz/rel/dl_compiler.cpp @@ -73,6 +73,12 @@ namespace datalog { vars.get_cols2(), removed_cols.size(), removed_cols.c_ptr(), result)); } + void compiler::make_min(reg_idx source, reg_idx & target, const unsigned_vector & group_by_cols, + const unsigned min_col, instruction_block & acc) { + target = get_register(m_reg_signatures[source], true, source); + acc.push_back(instruction::mk_min(source, target, group_by_cols, min_col)); + } + void compiler::make_filter_interpreted_and_project(reg_idx src, app_ref & cond, const unsigned_vector & removed_cols, reg_idx & result, bool reuse, instruction_block & acc) { SASSERT(!removed_cols.empty()); @@ -440,6 +446,30 @@ namespace datalog { get_local_indexes_for_projection(t2, counter, t1->get_num_args(), res); } + void compiler::find_min_aggregates(const rule * r, ptr_vector& min_aggregates) { + unsigned ut_len = r->get_uninterpreted_tail_size(); + unsigned ft_len = r->get_tail_size(); // full tail + func_decl * aggregate; + for (unsigned tail_index = ut_len; tail_index < ft_len; ++tail_index) { + aggregate = r->get_tail(tail_index)->get_decl(); + if (dl_decl_plugin::is_aggregate(aggregate)) { + min_aggregates.push_back(aggregate); + } + } + } + + bool compiler::prepare_min_aggregate(const func_decl * decl, const ptr_vector& min_aggregates, + unsigned_vector & group_by_cols, unsigned & min_col) { + for (unsigned i = 0; i < min_aggregates.size(); ++i) { + if (dl_decl_plugin::min_func_decl(min_aggregates[i]) == decl) { + group_by_cols = dl_decl_plugin::group_by_cols(min_aggregates[i]); + min_col = dl_decl_plugin::min_col(min_aggregates[i]); + return true; + } + } + return false; + } + void compiler::compile_rule_evaluation_run(rule * r, reg_idx head_reg, const reg_idx * tail_regs, reg_idx delta_reg, bool use_widening, instruction_block & acc) { @@ -465,6 +495,12 @@ namespace datalog { // whether to dealloc the previous result bool dealloc = true; + // setup information for min aggregation + ptr_vector min_aggregates; + find_min_aggregates(r, min_aggregates); + unsigned_vector group_by_cols; + unsigned min_col; + if(pt_len == 2) { reg_idx t1_reg=tail_regs[0]; reg_idx t2_reg=tail_regs[1]; @@ -473,6 +509,14 @@ namespace datalog { SASSERT(m_reg_signatures[t1_reg].size()==a1->get_num_args()); SASSERT(m_reg_signatures[t2_reg].size()==a2->get_num_args()); + if (prepare_min_aggregate(a1->get_decl(), min_aggregates, group_by_cols, min_col)) { + make_min(t1_reg, single_res, group_by_cols, min_col, acc); + } + + if (prepare_min_aggregate(a2->get_decl(), min_aggregates, group_by_cols, min_col)) { + make_min(t2_reg, single_res, group_by_cols, min_col, acc); + } + variable_intersection a1a2(m_context.get_manager()); a1a2.populate(a1,a2); @@ -514,6 +558,10 @@ namespace datalog { single_res = tail_regs[0]; dealloc = false; + if (prepare_min_aggregate(a->get_decl(), min_aggregates, group_by_cols, min_col)) { + make_min(single_res, single_res, group_by_cols, min_col, acc); + } + SASSERT(m_reg_signatures[single_res].size() == a->get_num_args()); unsigned n=a->get_num_args(); diff --git a/src/muz/rel/dl_compiler.h b/src/muz/rel/dl_compiler.h index 4902b9387..a9e37a8a3 100644 --- a/src/muz/rel/dl_compiler.h +++ b/src/muz/rel/dl_compiler.h @@ -120,6 +120,22 @@ namespace datalog { instruction_observer m_instruction_observer; expr_free_vars m_free_vars; + /** + \brief Finds all the min aggregation functions in the premise of a given rule. + */ + static void find_min_aggregates(const rule * r, ptr_vector& min_aggregates); + + /** + \brief Decides whether a predicate is subject to a min aggregation function. + + If \c decl is subject to a min aggregation function, the output parameters are written + with the neccessary information. + + \returns true if the output paramaters have been written + */ + static bool prepare_min_aggregate(const func_decl * decl, const ptr_vector& min_aggregates, + unsigned_vector & group_by_cols, unsigned & min_col); + /** If true, the union operation on the underlying structure only provides the information whether the updated relation has changed or not. In this case we do not get anything @@ -146,6 +162,8 @@ namespace datalog { void make_join(reg_idx t1, reg_idx t2, const variable_intersection & vars, reg_idx & result, bool reuse_t1, instruction_block & acc); + void make_min(reg_idx source, reg_idx & target, const unsigned_vector & group_by_cols, + const unsigned min_col, instruction_block & acc); void make_join_project(reg_idx t1, reg_idx t2, const variable_intersection & vars, const unsigned_vector & removed_cols, reg_idx & result, bool reuse_t1, instruction_block & acc); void make_filter_interpreted_and_project(reg_idx src, app_ref & cond, From 31cb81111d8a60cadbdfd70f82f59edc3c65ca9c Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 11 Jun 2015 16:56:36 +0100 Subject: [PATCH 919/925] Bugfix for fp.roundToIntegral --- src/ast/fpa/fpa2bv_converter.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 13f406aeb..4c199ebc6 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -1767,11 +1767,19 @@ void fpa2bv_converter::mk_round_to_integral(func_decl * f, unsigned num, expr * m_simp.mk_ite(c52, v52, res_sig, res_sig); m_simp.mk_ite(c51, v51, res_sig, res_sig); res_sig = m_bv_util.mk_concat(res_sig, m_bv_util.mk_numeral(0, 3)); // rounding bits are all 0. - res_exp = m_bv_util.mk_bv_add(m_bv_util.mk_zero_extend(2, res_exp), m_bv_util.mk_extract(ebits+1, 0, shift)); + + SASSERT(m_bv_util.get_bv_size(res_exp) == ebits); + SASSERT(m_bv_util.get_bv_size(shift) == sbits + 1); + + expr_ref e_shift(m); + e_shift = (ebits + 2 <= sbits + 1) ? m_bv_util.mk_extract(ebits + 1, 0, shift) : + m_bv_util.mk_sign_extend((ebits + 2) - (sbits + 1), shift); + SASSERT(m_bv_util.get_bv_size(e_shift) == ebits + 2); + res_exp = m_bv_util.mk_bv_add(m_bv_util.mk_zero_extend(2, res_exp), e_shift); SASSERT(m_bv_util.get_bv_size(res_sgn) == 1); - SASSERT(m_bv_util.get_bv_size(res_sig) == sbits+4); - SASSERT(m_bv_util.get_bv_size(res_exp) == ebits+2); + SASSERT(m_bv_util.get_bv_size(res_sig) == sbits + 4); + SASSERT(m_bv_util.get_bv_size(res_exp) == ebits + 2); // CMW: We use the rounder for normalization. round(f->get_range(), rm, res_sgn, res_sig, res_exp, v6); From 868b430b8bf0150ff7d7597f649e6bfa3899d3d1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 11 Jun 2015 10:19:29 -0700 Subject: [PATCH 920/925] use scoped pointers instead of explicit deallocation (robust under exceptions) Signed-off-by: Nikolaj Bjorner --- src/muz/rel/dl_base.cpp | 15 +++++---------- src/muz/rel/dl_instruction.cpp | 3 +-- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/muz/rel/dl_base.cpp b/src/muz/rel/dl_base.cpp index 6eba021f1..6dc7f2f6e 100644 --- a/src/muz/rel/dl_base.cpp +++ b/src/muz/rel/dl_base.cpp @@ -516,9 +516,8 @@ namespace datalog { */ virtual table_base * reference_implementation(const table_base & t) { relation_manager & manager = t.get_manager(); - table_join_fn * join_fn = manager.mk_join_fn(t, t, m_group_by_cols, m_group_by_cols); - table_base * join_table = (*join_fn)(t, t); - dealloc(join_fn); + scoped_ptr join_fn = manager.mk_join_fn(t, t, m_group_by_cols, m_group_by_cols); + scoped_rel join_table = (*join_fn)(t, t); table_base::iterator join_table_it = join_table->begin(); table_base::iterator join_table_end = join_table->end(); @@ -544,10 +543,8 @@ namespace datalog { SASSERT(cols[k] < join_table->num_columns()); } - table_transformer_fn * project_fn = manager.mk_project_fn(*join_table, cols); - table_base * gt_table = (*project_fn)(*join_table); - dealloc(project_fn); - join_table->deallocate(); + scoped_ptr project_fn = manager.mk_project_fn(*join_table, cols); + scoped_rel gt_table = (*project_fn)(*join_table); for (unsigned k = 0; k < cols.size(); ++k) { cols[k] = k; @@ -556,10 +553,8 @@ namespace datalog { } table_base * result = t.clone(); - table_intersection_filter_fn * diff_fn = manager.mk_filter_by_negation_fn(*result, *gt_table, cols, cols); + scoped_ptr diff_fn = manager.mk_filter_by_negation_fn(*result, *gt_table, cols, cols); (*diff_fn)(*result, *gt_table); - dealloc(diff_fn); - gt_table->deallocate(); return result; } diff --git a/src/muz/rel/dl_instruction.cpp b/src/muz/rel/dl_instruction.cpp index f93f88a76..f8145b922 100644 --- a/src/muz/rel/dl_instruction.cpp +++ b/src/muz/rel/dl_instruction.cpp @@ -914,9 +914,8 @@ namespace datalog { relation_manager & r_manager = s.get_manager(); const relation_signature & r_sig = s.get_signature(); - table_min_fn * fn = r_manager.mk_min_fn(source_t, m_group_by_cols, m_min_col); + scoped_ptr fn = r_manager.mk_min_fn(source_t, m_group_by_cols, m_min_col); table_base * target_t = (*fn)(source_t); - dealloc(fn); TRACE("dl", tout << "% "; From ca31c979fe2fb13ac5bf25dbd072b729d35de5cb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 11 Jun 2015 12:00:21 -0700 Subject: [PATCH 921/925] re-enable transformations Signed-off-by: Nikolaj Bjorner --- src/muz/rel/rel_context.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/muz/rel/rel_context.cpp b/src/muz/rel/rel_context.cpp index 44f59486e..d2a2f0181 100644 --- a/src/muz/rel/rel_context.cpp +++ b/src/muz/rel/rel_context.cpp @@ -290,6 +290,8 @@ namespace datalog { return res; } +#define _MIN_DONE_ 1 + void rel_context::transform_rules() { rule_transformer transf(m_context); #ifdef _MIN_DONE_ From f45fcbe2829e152bf35adc6a3b241089a91ded24 Mon Sep 17 00:00:00 2001 From: Aleksandar Zeljic Date: Fri, 12 Jun 2015 11:47:58 +0200 Subject: [PATCH 922/925] Added support for patching of models containing toIntegral, max, min. --- src/tactic/fpa/fpa2bv_approx_tactic.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/tactic/fpa/fpa2bv_approx_tactic.cpp b/src/tactic/fpa/fpa2bv_approx_tactic.cpp index 77a87ae31..211da9dc7 100644 --- a/src/tactic/fpa/fpa2bv_approx_tactic.cpp +++ b/src/tactic/fpa/fpa2bv_approx_tactic.cpp @@ -384,6 +384,24 @@ class fpa2bv_approx_tactic: public tactic { mpf_mngr.abs(est_arg_val[0], est_rhs_value); break; } + case OP_FPA_MIN: + { + mpf_mngr.minimum( arg_val[1], arg_val[2], rhs_value); + mpf_mngr.minimum( est_arg_val[1], est_arg_val[2], est_rhs_value); + break; + } + case OP_FPA_MAX: + { + mpf_mngr.maximum( arg_val[1], arg_val[2], rhs_value); + mpf_mngr.maximum( est_arg_val[1], est_arg_val[2], est_rhs_value); + break; + } + case OP_FPA_ROUND_TO_INTEGRAL: + { + mpf_mngr.round_to_integral(rm,arg_val[1],rhs_value); + mpf_mngr.round_to_integral(rm,est_arg_val[1],est_rhs_value); + break; + } default: NOT_IMPLEMENTED_YET(); break; From f84d6bf5bb2c031478dfa72c10bcbb957995dc7f Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 12 Jun 2015 12:58:07 +0100 Subject: [PATCH 923/925] Bugfix for QF_FP tactic --- src/tactic/fpa/qffp_tactic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tactic/fpa/qffp_tactic.cpp b/src/tactic/fpa/qffp_tactic.cpp index fbce1668e..485e837ee 100644 --- a/src/tactic/fpa/qffp_tactic.cpp +++ b/src/tactic/fpa/qffp_tactic.cpp @@ -53,7 +53,7 @@ struct has_fp_to_real_predicate { class has_fp_to_real_probe : public probe { public: virtual result operator()(goal const & g) { - return !test(g); + return test(g); } virtual ~has_fp_to_real_probe() {} From 6980fb3035c08905d1de7cada591843cd4dd5448 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 12 Jun 2015 12:58:19 +0100 Subject: [PATCH 924/925] Bugfix for distinct of floats. --- src/ast/fpa/fpa2bv_converter.cpp | 14 ++++++++++++++ src/ast/fpa/fpa2bv_converter.h | 1 + src/ast/fpa/fpa2bv_rewriter.h | 11 +++++++++-- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 4c199ebc6..baba7b701 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -93,6 +93,20 @@ void fpa2bv_converter::mk_ite(expr * c, expr * t, expr * f, expr_ref & result) { mk_fp(sgn, e, s, result); } +void fpa2bv_converter::mk_distinct(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { + // Note: in SMT there is only one NaN, so multiple of them are considered + // equal, thus (distinct NaN NaN) is false, even if the two NaNs have + // different bitwise representations (see also mk_eq). + result = m.mk_true(); + for (unsigned i = 0; i < num; i++) { + for (unsigned j = i+1; j < num; j++) { + expr_ref eq(m); + mk_eq(args[i], args[j], eq); + m_simp.mk_and(result, m.mk_not(eq), result); + } + } +} + void fpa2bv_converter::mk_numeral(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 0); SASSERT(f->get_num_parameters() == 1); diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index 4b3c1a6ca..b0881a364 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -80,6 +80,7 @@ public: void mk_eq(expr * a, expr * b, expr_ref & result); void mk_ite(expr * c, expr * t, expr * f, expr_ref & result); + void mk_distinct(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_rounding_mode(func_decl * f, expr_ref & result); void mk_numeral(func_decl * f, unsigned num, expr * const * args, expr_ref & result); diff --git a/src/ast/fpa/fpa2bv_rewriter.h b/src/ast/fpa/fpa2bv_rewriter.h index ed885a4cc..fa88c227c 100644 --- a/src/ast/fpa/fpa2bv_rewriter.h +++ b/src/ast/fpa/fpa2bv_rewriter.h @@ -103,8 +103,7 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { } return BR_FAILED; } - - if (m().is_ite(f)) { + else if (m().is_ite(f)) { SASSERT(num == 3); if (m_conv.is_float(args[1])) { m_conv.mk_ite(args[0], args[1], args[2], result); @@ -112,6 +111,14 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { } return BR_FAILED; } + else if (m().is_distinct(f)) { + sort * ds = f->get_domain()[0]; + if (m_conv.is_float(ds) || m_conv.is_rm(ds)) { + m_conv.mk_distinct(f, num, args, result); + return BR_DONE; + } + return BR_FAILED; + } if (m_conv.is_float_family(f)) { switch (f->get_decl_kind()) { From 421b3af8bdae31d7cc4bda3380fe4e0d2196540a Mon Sep 17 00:00:00 2001 From: Aleksandar Zeljic Date: Fri, 12 Jun 2015 18:35:32 +0200 Subject: [PATCH 925/925] Minor additions and cleanup to the outdated code. --- src/tactic/fpa/fpa2bv_approx_tactic.cpp | 4 ++ src/tactic/fpa/fpa2bv_rewriter_prec.h | 87 +++++++++++++++++-------- 2 files changed, 63 insertions(+), 28 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_approx_tactic.cpp b/src/tactic/fpa/fpa2bv_approx_tactic.cpp index 211da9dc7..4d52a11ca 100644 --- a/src/tactic/fpa/fpa2bv_approx_tactic.cpp +++ b/src/tactic/fpa/fpa2bv_approx_tactic.cpp @@ -30,6 +30,7 @@ #include"fpa2bv_converter_prec.h" #include"fpa2bv_model_converter.h" #include"fpa2bv_converter.h" +#include"propagate_values_tactic.h" #include"fpa2bv_rewriter_prec.h" #include"fpa2bv_approx_tactic.h" #include"const_intro_rewriter.h" @@ -402,6 +403,7 @@ class fpa2bv_approx_tactic: public tactic { mpf_mngr.round_to_integral(rm,est_arg_val[1],est_rhs_value); break; } + default: NOT_IMPLEMENTED_YET(); break; @@ -880,6 +882,8 @@ class fpa2bv_approx_tactic: public tactic { SASSERT(g->is_well_sorted()); + simplify(g); + //fpa2bv fpa2bv_rewriter_prec fpa2bv_rw(*m_temp_manager, fpa2bv, m_params); fpa2bv_rw.m_cfg.set_mappings(&const2prec_map); diff --git a/src/tactic/fpa/fpa2bv_rewriter_prec.h b/src/tactic/fpa/fpa2bv_rewriter_prec.h index 1e3cf71ac..051790ac3 100644 --- a/src/tactic/fpa/fpa2bv_rewriter_prec.h +++ b/src/tactic/fpa/fpa2bv_rewriter_prec.h @@ -75,9 +75,7 @@ struct fpa2bv_rewriter_prec_cfg : public default_rewriter_cfg { bool max_steps_exceeded(unsigned num_steps) const { cooperate("fpa2bv"); - if (memory::get_allocation_size() > m_max_memory) - throw tactic_exception(TACTIC_MAX_MEMORY_MSG); - return num_steps > m_max_steps; + return num_steps > m_max_steps; } br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { @@ -93,14 +91,20 @@ struct fpa2bv_rewriter_prec_cfg : public default_rewriter_cfg { return BR_DONE; } - if (m().is_eq(f)) { - SASSERT(num == 2); - if (m_conv.is_float(args[0])) { - m_conv.mk_eq(args[0], args[1], result); - return BR_DONE; - } - return BR_FAILED; - } + if (m().is_eq(f)) { + SASSERT(num == 2); + //SASSERT(m().get_sort(args[0]) == m().get_sort(args[1])); + sort * ds = f->get_domain()[0]; + if (m_conv.is_float(ds)) { + m_conv.mk_eq(args[0], args[1], result); + return BR_DONE; + } + else if (m_conv.is_rm(ds)) { + result = m().mk_eq(args[0], args[1]); + return BR_DONE; + } + return BR_FAILED; + } if (m().is_ite(f)) { SASSERT(num == 3); @@ -125,10 +129,9 @@ struct fpa2bv_rewriter_prec_cfg : public default_rewriter_cfg { case OP_FPA_NUM: m_conv.mk_numeral(f, num, args, result); return BR_DONE; case OP_FPA_PLUS_INF: m_conv.mk_pinf(f, result); return BR_DONE; case OP_FPA_MINUS_INF: m_conv.mk_ninf(f, result); return BR_DONE; - case OP_FPA_NAN: m_conv.mk_nan(f, result); return BR_DONE; - case OP_FPA_PLUS_ZERO: m_conv.mk_pzero(f, result); return BR_DONE; + case OP_FPA_PLUS_ZERO: m_conv.mk_pzero(f, result); return BR_DONE; case OP_FPA_MINUS_ZERO: m_conv.mk_nzero(f, result); return BR_DONE; - //AZ: Added precision, if precision is MAX_PRECISION uses the regular implementation of the methods + case OP_FPA_NAN: m_conv.mk_nan(f, result); return BR_DONE; case OP_FPA_ADD: m_conv.mk_add(f,get_precision(f), num, args, result);return BR_DONE; case OP_FPA_SUB: @@ -141,14 +144,14 @@ struct fpa2bv_rewriter_prec_cfg : public default_rewriter_cfg { m_conv.mk_div(f, get_precision(f), num, args, result); return BR_DONE; case OP_FPA_REM: m_conv.mk_remainder(f, get_precision(f), num, args, result); return BR_DONE; - case OP_FPA_FMA: + case OP_FPA_ABS: m_conv.mk_abs(f, get_precision(f), num, args, result); return BR_DONE; + case OP_FPA_MIN: m_conv.mk_min(f, get_precision(f), num, args, result); return BR_DONE; + case OP_FPA_MAX: m_conv.mk_max(f, get_precision(f), num, args, result); return BR_DONE; + case OP_FPA_FMA: m_conv.mk_fusedma(f, get_precision(f), num, args, result); return BR_DONE; case OP_FPA_SQRT: m_conv.mk_sqrt(f, get_precision(f), num, args, result); return BR_DONE; - case OP_FPA_ABS: m_conv.mk_abs(f, get_precision(f), num, args, result); return BR_DONE; - case OP_FPA_MIN: m_conv.mk_min(f, get_precision(f), num, args, result); return BR_DONE; - case OP_FPA_MAX: m_conv.mk_max(f, get_precision(f), num, args, result); return BR_DONE; - case OP_FPA_ROUND_TO_INTEGRAL: m_conv.mk_round_to_integral(f, get_precision(f), num, args, result); return BR_DONE; + case OP_FPA_ROUND_TO_INTEGRAL: m_conv.mk_round_to_integral(f, get_precision(f), num, args, result); return BR_DONE; case OP_FPA_EQ: m_conv.mk_float_eq(f, num, args, result); return BR_DONE; case OP_FPA_LT: m_conv.mk_float_lt(f, num, args, result); return BR_DONE; case OP_FPA_GT: m_conv.mk_float_gt(f, num, args, result); return BR_DONE; @@ -159,17 +162,45 @@ struct fpa2bv_rewriter_prec_cfg : public default_rewriter_cfg { case OP_FPA_IS_INF: m_conv.mk_is_inf(f, num, args, result); return BR_DONE; case OP_FPA_IS_NORMAL: m_conv.mk_is_normal(f, num, args, result); return BR_DONE; case OP_FPA_IS_SUBNORMAL: m_conv.mk_is_subnormal(f, num, args, result); return BR_DONE; - case OP_FPA_IS_NEGATIVE: m_conv.mk_is_negative(f, num, args, result); return BR_DONE; case OP_FPA_IS_POSITIVE: m_conv.mk_is_positive(f, num, args, result); return BR_DONE; + case OP_FPA_IS_NEGATIVE: m_conv.mk_is_negative(f, num, args, result); return BR_DONE; case OP_FPA_TO_FP: m_conv.mk_to_fp(f, num, args, result); return BR_DONE; - case OP_FPA_TO_IEEE_BV: m_conv.mk_to_ieee_bv(f, num, args, result); return BR_DONE; - default: - TRACE("fpa2bv", tout << "unsupported operator: " << f->get_name() << "\n"; - for (unsigned i = 0; i < num; i++) tout << mk_ismt2_pp(args[i], m()) << std::endl;); - throw tactic_exception("NYI"); - } - } - return BR_FAILED; + case OP_FPA_TO_FP_UNSIGNED: m_conv.mk_to_fp_unsigned(f, num, args, result); return BR_DONE; + case OP_FPA_FP: m_conv.mk_fp(f, num, args, result); return BR_DONE; + case OP_FPA_TO_UBV: m_conv.mk_to_ubv(f, num, args, result); return BR_DONE; + case OP_FPA_TO_SBV: m_conv.mk_to_sbv(f, num, args, result); return BR_DONE; + case OP_FPA_TO_REAL: m_conv.mk_to_real(f, num, args, result); return BR_DONE; + case OP_FPA_TO_IEEE_BV: m_conv.mk_to_ieee_bv(f, num, args, result); return BR_DONE; + case OP_FPA_INTERNAL_BVWRAP: + case OP_FPA_INTERNAL_BVUNWRAP: + case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED: + case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED: + case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED: return BR_FAILED; + default: + TRACE("fpa2bv", tout << "unsupported operator: " << f->get_name() << "\n"; + for (unsigned i = 0; i < num; i++) tout << mk_ismt2_pp(args[i], m()) << std::endl;); + NOT_IMPLEMENTED_YET(); + } + } + + if (f->get_family_id() == null_family_id) + { + bool is_float_uf = m_conv.is_float(f->get_range()); + unsigned i = 0; + while (!is_float_uf && i < num) + { + is_float_uf = m_conv.is_float(f->get_domain()[i]); + i++; + } + + if (is_float_uf) + { + m_conv.mk_uninterpreted_function(f, num, args, result); + return BR_DONE; + } + } + + return BR_FAILED; } bool pre_visit(expr * t)