diff --git a/.travis.yml b/.travis.yml index 3764f8dac..50d63e593 100644 --- a/.travis.yml +++ b/.travis.yml @@ -60,17 +60,15 @@ env: - LINUX_BASE=ubuntu_14.04 C_COMPILER=/usr/bin/gcc-4.8 CXX_COMPILER=/usr/bin/g++-4.8 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug # macOS (a.k.a OSX) support -# FIXME: macOS support is temporarily disabled due to @wintersteiger 's concerns. -# See https://github.com/Z3Prover/z3/pull/1207#issuecomment-322200998 -# matrix: -# include: -# # For now just test a single configuration. macOS builds on TravisCI are -# # very slow so we should keep the number of configurations we test on this -# # OS to a minimum. -# - os: osx -# osx_image: xcode8.3 -# # Note: Apple Clang does not support OpenMP -# env: Z3_BUILD_TYPE=RelWithDebInfo USE_OPENMP=0 +matrix: + include: + # For now just test a single configuration. macOS builds on TravisCI are + # very slow so we should keep the number of configurations we test on this + # OS to a minimum. + - os: osx + osx_image: xcode8.3 + # Note: Apple Clang does not support OpenMP + env: Z3_BUILD_TYPE=RelWithDebInfo USE_OPENMP=0 script: # Use `travis_wait` when doing LTO builds because this configuration will # have long link times during which it will not show any output which diff --git a/src/ackermannization/ackr_model_converter.cpp b/src/ackermannization/ackr_model_converter.cpp index 0697686eb..a7c021913 100644 --- a/src/ackermannization/ackr_model_converter.cpp +++ b/src/ackermannization/ackr_model_converter.cpp @@ -3,13 +3,13 @@ Copyright (c) 2015 Microsoft Corporation Module Name: -ackr_model_converter.cpp + ackr_model_converter.cpp Abstract: Author: -Mikolas Janota + Mikolas Janota Revision History: --*/ @@ -22,8 +22,8 @@ Revision History: class ackr_model_converter : public model_converter { public: ackr_model_converter(ast_manager & m, - const ackr_info_ref& info, - model_ref& abstr_model) + const ackr_info_ref& info, + model_ref& abstr_model) : m(m) , info(info) , abstr_model(abstr_model) @@ -31,7 +31,7 @@ public: { } ackr_model_converter(ast_manager & m, - const ackr_info_ref& info) + const ackr_info_ref& info) : m(m) , info(info) , fixed_model(false) @@ -51,8 +51,6 @@ public: virtual void operator()(model_ref & md) { operator()(md, 0); } - //void display(std::ostream & out); - virtual model_converter * translate(ast_translation & translator) { ackr_info_ref retv_info = info->translate(translator); if (fixed_model) { @@ -63,42 +61,45 @@ public: return alloc(ackr_model_converter, translator.to(), retv_info); } } + protected: - ast_manager& m; + ast_manager & m; const ackr_info_ref info; model_ref abstr_model; bool fixed_model; void convert(model * source, model * destination); void add_entry(model_evaluator & evaluator, - app* term, expr* value, - obj_map& interpretations); + app* term, expr* value, + obj_map& interpretations); void convert_constants(model * source, model * destination); }; void ackr_model_converter::convert(model * source, model * destination) { destination->copy_func_interps(*source); destination->copy_usort_interps(*source); - convert_constants(source,destination); + convert_constants(source, destination); } void ackr_model_converter::convert_constants(model * source, model * destination) { TRACE("ackr_model", tout << "converting constants\n";); obj_map interpretations; model_evaluator evaluator(*source); + evaluator.set_model_completion(true); for (unsigned i = 0; i < source->get_num_constants(); i++) { func_decl * const c = source->get_constant(i); app * const term = info->find_term(c); expr * value = source->get_const_interp(c); - if(!term) { + if (!term) { destination->register_decl(c, value); - } else { + } + else { add_entry(evaluator, term, value, interpretations); } } obj_map::iterator e = interpretations.end(); for (obj_map::iterator i = interpretations.begin(); - i!=e; ++i) { + i != e; ++i) { func_decl* const fd = i->m_key; func_interp* const fi = i->get_value(); fi->set_else(m.get_some_value(fd->get_range())); @@ -107,34 +108,40 @@ void ackr_model_converter::convert_constants(model * source, model * destination } void ackr_model_converter::add_entry(model_evaluator & evaluator, - app* term, expr* value, - obj_map& interpretations) { + app* term, expr* value, + obj_map& interpretations) { TRACE("ackr_model", tout << "add_entry" - << mk_ismt2_pp(term, m, 2) - << "->" - << mk_ismt2_pp(value, m, 2) << "\n"; + << mk_ismt2_pp(term, m, 2) + << "->" + << mk_ismt2_pp(value, m, 2) << "\n"; ); - func_interp* fi = 0; + func_interp * fi = 0; func_decl * const declaration = term->get_decl(); const unsigned sz = declaration->get_arity(); SASSERT(sz == term->get_num_args()); - if (!interpretations.find(declaration, fi)) { - fi = alloc(func_interp,m,sz); - interpretations.insert(declaration, fi); + if (!interpretations.find(declaration, fi)) { + fi = alloc(func_interp, m, sz); + interpretations.insert(declaration, fi); } expr_ref_vector args(m); for (unsigned gi = 0; gi < sz; ++gi) { - expr * const arg = term->get_arg(gi); - expr_ref aarg(m); - info->abstract(arg, aarg); - expr_ref arg_value(m); - evaluator(aarg,arg_value); - args.push_back(arg_value); + expr * const arg = term->get_arg(gi); + expr_ref aarg(m); + info->abstract(arg, aarg); + expr_ref arg_value(m); + evaluator(aarg, arg_value); + args.push_back(arg_value); } if (fi->get_entry(args.c_ptr()) == 0) { + TRACE("ackr_model", + tout << mk_ismt2_pp(declaration, m) << " args: " << std::endl; + for (unsigned i = 0; i < args.size(); i++) + tout << mk_ismt2_pp(args.get(i), m) << std::endl; + tout << " -> " << mk_ismt2_pp(value, m) << "\n"; ); fi->insert_new_entry(args.c_ptr(), value); - } else { + } + else { TRACE("ackr_model", tout << "entry already present\n";); } } diff --git a/src/ackermannization/ackr_model_converter.h b/src/ackermannization/ackr_model_converter.h index cee7472aa..659b45926 100644 --- a/src/ackermannization/ackr_model_converter.h +++ b/src/ackermannization/ackr_model_converter.h @@ -3,13 +3,13 @@ Copyright (c) 2015 Microsoft Corporation Module Name: -ackr_model_converter.h + ackr_model_converter.h Abstract: Author: -Mikolas Janota + Mikolas Janota Revision History: --*/ @@ -19,7 +19,7 @@ Revision History: #include "tactic/model_converter.h" #include "ackermannization/ackr_info.h" -model_converter * mk_ackr_model_converter(ast_manager & m, const ackr_info_ref& info, model_ref& abstr_model); -model_converter * mk_ackr_model_converter(ast_manager & m, const ackr_info_ref& info); +model_converter * mk_ackr_model_converter(ast_manager & m, const ackr_info_ref & info, model_ref & abstr_model); +model_converter * mk_ackr_model_converter(ast_manager & m, const ackr_info_ref & info); #endif /* LACKR_MODEL_CONVERTER_H_ */ diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index ab93c3cbd..e22603225 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1204,16 +1204,8 @@ extern "C" { case OP_FPA_TO_SBV: return Z3_OP_FPA_TO_SBV; case OP_FPA_TO_REAL: return Z3_OP_FPA_TO_REAL; case OP_FPA_TO_IEEE_BV: return Z3_OP_FPA_TO_IEEE_BV; - case OP_FPA_INTERNAL_MIN_I: return Z3_OP_FPA_MIN_I; - case OP_FPA_INTERNAL_MAX_I: return Z3_OP_FPA_MAX_I; - case OP_FPA_INTERNAL_BV2RM: - case OP_FPA_INTERNAL_BVWRAP: - case OP_FPA_INTERNAL_MIN_UNSPECIFIED: - case OP_FPA_INTERNAL_MAX_UNSPECIFIED: - case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED: - case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED: - case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED: - case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED: + case OP_FPA_BVWRAP: return Z3_OP_FPA_BVWRAP; + case OP_FPA_BV2RM: return Z3_OP_FPA_BV2RM; return Z3_OP_UNINTERPRETED; default: return Z3_OP_INTERNAL; diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 7bfe19cf3..d09129d37 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -354,7 +354,7 @@ namespace z3 { Z3_error_code check_error() const { return m_ctx->check_error(); } friend void check_context(object const & a, object const & b); }; - inline void check_context(object const & a, object const & b) { assert(a.m_ctx == b.m_ctx); } + inline void check_context(object const & a, object const & b) { (void)a; (void)b; assert(a.m_ctx == b.m_ctx); } class symbol : public object { Z3_symbol m_sym; diff --git a/src/api/dll/dll.cpp b/src/api/dll/dll.cpp index a0bd25d2e..74dc48153 100644 --- a/src/api/dll/dll.cpp +++ b/src/api/dll/dll.cpp @@ -15,16 +15,16 @@ Copyright (c) 2015 Microsoft Corporation BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved - ) + ) { - switch (ul_reason_for_call) - { - case DLL_PROCESS_ATTACH: - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: - case DLL_PROCESS_DETACH: - break; - } + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } return TRUE; } diff --git a/src/api/dotnet/CMakeLists.txt b/src/api/dotnet/CMakeLists.txt index 93f5929d9..add1b0ded 100644 --- a/src/api/dotnet/CMakeLists.txt +++ b/src/api/dotnet/CMakeLists.txt @@ -43,78 +43,78 @@ add_custom_command(OUTPUT "${Z3_DOTNET_CONST_FILE}" ) set(Z3_DOTNET_ASSEMBLY_SOURCES_IN_SRC_TREE - AlgebraicNum.cs - ApplyResult.cs - ArithExpr.cs - ArithSort.cs - ArrayExpr.cs - ArraySort.cs - AST.cs - ASTMap.cs - ASTVector.cs - BitVecExpr.cs - BitVecNum.cs - BitVecSort.cs - BoolExpr.cs - BoolSort.cs - Constructor.cs - ConstructorList.cs - Context.cs - DatatypeExpr.cs - DatatypeSort.cs - Deprecated.cs - EnumSort.cs - Expr.cs - FiniteDomainExpr.cs - FiniteDomainNum.cs - FiniteDomainSort.cs - Fixedpoint.cs - FPExpr.cs - FPNum.cs - FPRMExpr.cs - FPRMNum.cs - FPRMSort.cs - FPSort.cs - FuncDecl.cs - FuncInterp.cs - Global.cs - Goal.cs - IDecRefQueue.cs - InterpolationContext.cs - IntExpr.cs - IntNum.cs - IntSort.cs - IntSymbol.cs - ListSort.cs - Log.cs - Model.cs - Optimize.cs - ParamDescrs.cs - Params.cs - Pattern.cs - Probe.cs - Quantifier.cs - RatNum.cs - RealExpr.cs - RealSort.cs - ReExpr.cs - RelationSort.cs - ReSort.cs - SeqExpr.cs - SeqSort.cs - SetSort.cs - Solver.cs - Sort.cs - Statistics.cs - Status.cs - StringSymbol.cs - Symbol.cs - Tactic.cs - TupleSort.cs - UninterpretedSort.cs - Version.cs - Z3Exception.cs - Z3Object.cs + AlgebraicNum.cs + ApplyResult.cs + ArithExpr.cs + ArithSort.cs + ArrayExpr.cs + ArraySort.cs + AST.cs + ASTMap.cs + ASTVector.cs + BitVecExpr.cs + BitVecNum.cs + BitVecSort.cs + BoolExpr.cs + BoolSort.cs + Constructor.cs + ConstructorList.cs + Context.cs + DatatypeExpr.cs + DatatypeSort.cs + Deprecated.cs + EnumSort.cs + Expr.cs + FiniteDomainExpr.cs + FiniteDomainNum.cs + FiniteDomainSort.cs + Fixedpoint.cs + FPExpr.cs + FPNum.cs + FPRMExpr.cs + FPRMNum.cs + FPRMSort.cs + FPSort.cs + FuncDecl.cs + FuncInterp.cs + Global.cs + Goal.cs + IDecRefQueue.cs + InterpolationContext.cs + IntExpr.cs + IntNum.cs + IntSort.cs + IntSymbol.cs + ListSort.cs + Log.cs + Model.cs + Optimize.cs + ParamDescrs.cs + Params.cs + Pattern.cs + Probe.cs + Quantifier.cs + RatNum.cs + RealExpr.cs + RealSort.cs + ReExpr.cs + RelationSort.cs + ReSort.cs + SeqExpr.cs + SeqSort.cs + SetSort.cs + Solver.cs + Sort.cs + Statistics.cs + Status.cs + StringSymbol.cs + Symbol.cs + Tactic.cs + TupleSort.cs + UninterpretedSort.cs + Version.cs + Z3Exception.cs + Z3Object.cs ) set(Z3_DOTNET_ASSEMBLY_SOURCES "") diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index a6614a202..2bf1c44c5 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -126,7 +126,7 @@ namespace Microsoft.Z3 private BoolSort m_boolSort = null; private IntSort m_intSort = null; private RealSort m_realSort = null; - private SeqSort m_stringSort = null; + private SeqSort m_stringSort = null; /// /// Retrieves the Boolean sort of the context. @@ -2426,7 +2426,7 @@ namespace Microsoft.Z3 public SeqExpr IntToString(Expr e) { Contract.Requires(e != null); - Contract.Requires(e is ArithExpr); + Contract.Requires(e is ArithExpr); Contract.Ensures(Contract.Result() != null); return new SeqExpr(this, Native.Z3_mk_int_to_str(nCtx, e.NativeObject)); } @@ -2690,7 +2690,7 @@ namespace Microsoft.Z3 /// /// Create a range expression. /// - public ReExpr MkRange(SeqExpr lo, SeqExpr hi) + public ReExpr MkRange(SeqExpr lo, SeqExpr hi) { Contract.Requires(lo != null); Contract.Requires(hi != null); diff --git a/src/api/dotnet/Expr.cs b/src/api/dotnet/Expr.cs index 6c52b83c8..4fd306052 100644 --- a/src/api/dotnet/Expr.cs +++ b/src/api/dotnet/Expr.cs @@ -809,55 +809,55 @@ namespace Microsoft.Z3 /// Check whether expression is a concatentation. /// /// a Boolean - public bool IsConcat { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_CONCAT; } } + public bool IsConcat { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_CONCAT; } } /// /// Check whether expression is a prefix. /// /// a Boolean - public bool IsPrefix { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_PREFIX; } } + public bool IsPrefix { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_PREFIX; } } /// /// Check whether expression is a suffix. /// /// a Boolean - public bool IsSuffix { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_SUFFIX; } } + public bool IsSuffix { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_SUFFIX; } } /// /// Check whether expression is a contains. /// /// a Boolean - public bool IsContains { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_CONTAINS; } } + public bool IsContains { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_CONTAINS; } } /// /// Check whether expression is an extract. /// /// a Boolean - public bool IsExtract { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_EXTRACT; } } + public bool IsExtract { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_EXTRACT; } } /// /// Check whether expression is a replace. /// /// a Boolean - public bool IsReplace { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_REPLACE; } } + public bool IsReplace { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_REPLACE; } } /// /// Check whether expression is an at. /// /// a Boolean - public bool IsAt { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_AT; } } + public bool IsAt { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_AT; } } /// /// Check whether expression is a sequence length. /// /// a Boolean - public bool IsLength { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_LENGTH; } } + public bool IsLength { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_LENGTH; } } /// /// Check whether expression is a sequence index. /// /// a Boolean - public bool IsIndex { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_INDEX; } } + public bool IsIndex { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_SEQ_INDEX; } } #endregion diff --git a/src/api/dotnet/Optimize.cs b/src/api/dotnet/Optimize.cs index 99dd9aac0..9d0636425 100644 --- a/src/api/dotnet/Optimize.cs +++ b/src/api/dotnet/Optimize.cs @@ -123,7 +123,7 @@ namespace Microsoft.Z3 /// /// Retrieve a lower bound for the objective handle. - /// + /// public ArithExpr Lower { get { return opt.GetLower(handle); } @@ -131,7 +131,7 @@ namespace Microsoft.Z3 /// /// Retrieve an upper bound for the objective handle. - /// + /// public ArithExpr Upper { get { return opt.GetUpper(handle); } @@ -139,7 +139,7 @@ namespace Microsoft.Z3 /// /// Retrieve the value of an objective. - /// + /// public ArithExpr Value { get { return Lower; } @@ -147,7 +147,7 @@ namespace Microsoft.Z3 /// /// Retrieve a lower bound for the objective handle. - /// + /// public ArithExpr[] LowerAsVector { get { return opt.GetLowerAsVector(handle); } @@ -155,7 +155,7 @@ namespace Microsoft.Z3 /// /// Retrieve an upper bound for the objective handle. - /// + /// public ArithExpr[] UpperAsVector { get { return opt.GetUpperAsVector(handle); } @@ -240,7 +240,7 @@ 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. - /// + /// public Handle MkMaximize(ArithExpr e) { return new Handle(this, Native.Z3_optimize_maximize(Context.nCtx, NativeObject, e.NativeObject)); @@ -249,7 +249,7 @@ namespace Microsoft.Z3 /// /// Declare an arithmetical minimization objective. /// Similar to MkMaximize. - /// + /// public Handle MkMinimize(ArithExpr e) { return new Handle(this, Native.Z3_optimize_minimize(Context.nCtx, NativeObject, e.NativeObject)); @@ -257,7 +257,7 @@ namespace Microsoft.Z3 /// /// Retrieve a lower bound for the objective handle. - /// + /// private ArithExpr GetLower(uint index) { return (ArithExpr)Expr.Create(Context, Native.Z3_optimize_get_lower(Context.nCtx, NativeObject, index)); @@ -266,7 +266,7 @@ namespace Microsoft.Z3 /// /// Retrieve an upper bound for the objective handle. - /// + /// private ArithExpr GetUpper(uint index) { return (ArithExpr)Expr.Create(Context, Native.Z3_optimize_get_upper(Context.nCtx, NativeObject, index)); @@ -274,7 +274,7 @@ namespace Microsoft.Z3 /// /// Retrieve a lower bound for the objective handle. - /// + /// private ArithExpr[] GetLowerAsVector(uint index) { ASTVector v = new ASTVector(Context, Native.Z3_optimize_get_lower_as_vector(Context.nCtx, NativeObject, index)); @@ -284,29 +284,29 @@ namespace Microsoft.Z3 /// /// Retrieve an upper bound for the objective handle. - /// + /// private ArithExpr[] GetUpperAsVector(uint index) { ASTVector v = new ASTVector(Context, Native.Z3_optimize_get_upper_as_vector(Context.nCtx, NativeObject, index)); return v.ToArithExprArray(); } - /// - /// Return a string the describes why the last to check returned unknown - /// - public String ReasonUnknown - { + /// + /// Return a string the describes why the last to check returned unknown + /// + public String ReasonUnknown + { get { Contract.Ensures(Contract.Result() != null); return Native.Z3_optimize_get_reason_unknown(Context.nCtx, NativeObject); } - } + } /// /// 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/api/dotnet/dotnet35/Microsoft.Z3.NET35.sln b/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.sln index b6e252684..1e33f136e 100644 --- a/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.sln +++ b/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.sln @@ -8,41 +8,41 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example", "Example\Example.csproj", "{2A8E577B-7B6D-4CA9-832A-CA2EEC314812}" EndProject Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|x64.ActiveCfg = Debug|Any CPU - {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|x64.Build.0 = Debug|Any CPU - {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|x86.ActiveCfg = Debug|Any CPU - {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|x86.Build.0 = Debug|Any CPU - {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|Any CPU.Build.0 = Release|Any CPU - {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x64.ActiveCfg = Release|x64 - {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x64.Build.0 = Release|x64 - {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x86.ActiveCfg = Release|Any CPU - {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x86.Build.0 = Release|Any CPU - {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|x64.ActiveCfg = Debug|Any CPU - {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|x64.Build.0 = Debug|Any CPU - {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|x86.ActiveCfg = Debug|Any CPU - {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|x86.Build.0 = Debug|Any CPU - {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|Any CPU.Build.0 = Release|Any CPU - {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|x64.ActiveCfg = Release|x64 - {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|x64.Build.0 = Release|x64 - {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|x86.ActiveCfg = Release|Any CPU - {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|x86.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|x64.ActiveCfg = Debug|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|x64.Build.0 = Debug|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|x86.ActiveCfg = Debug|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|x86.Build.0 = Debug|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|Any CPU.Build.0 = Release|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x64.ActiveCfg = Release|x64 + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x64.Build.0 = Release|x64 + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x86.ActiveCfg = Release|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x86.Build.0 = Release|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|x64.ActiveCfg = Debug|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|x64.Build.0 = Debug|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|x86.ActiveCfg = Debug|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|x86.Build.0 = Debug|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|Any CPU.Build.0 = Release|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|x64.ActiveCfg = Release|x64 + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|x64.Build.0 = Release|x64 + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|x86.ActiveCfg = Release|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection EndGlobal diff --git a/src/api/java/ASTVector.java b/src/api/java/ASTVector.java index 4d9ab291a..b78f714b2 100644 --- a/src/api/java/ASTVector.java +++ b/src/api/java/ASTVector.java @@ -131,7 +131,7 @@ public class ASTVector extends Z3Object { Expr[] res = new Expr[n]; for (int i = 0; i < n; i++) res[i] = Expr.create(getContext(), get(i).getNativeObject()); - return res; + return res; } /** diff --git a/src/api/java/AlgebraicNum.java b/src/api/java/AlgebraicNum.java index 6725d3937..7369e06e3 100644 --- a/src/api/java/AlgebraicNum.java +++ b/src/api/java/AlgebraicNum.java @@ -22,57 +22,57 @@ package com.microsoft.z3; **/ public class AlgebraicNum extends ArithExpr { - /** - * Return a upper bound for a given real algebraic number. The interval - * isolating the number is smaller than 1/10^{@code precision}. - * - * @see Expr#isAlgebraicNumber - * @param precision the precision of the result - * - * @return A numeral Expr of sort Real - * @throws Z3Exception on error - **/ - public RatNum toUpper(int precision) - { + /** + * Return a upper bound for a given real algebraic number. The interval + * isolating the number is smaller than 1/10^{@code precision}. + * + * @see Expr#isAlgebraicNumber + * @param precision the precision of the result + * + * @return A numeral Expr of sort Real + * @throws Z3Exception on error + **/ + public RatNum toUpper(int precision) + { - return new RatNum(getContext(), Native.getAlgebraicNumberUpper(getContext() - .nCtx(), getNativeObject(), precision)); - } + return new RatNum(getContext(), Native.getAlgebraicNumberUpper(getContext() + .nCtx(), getNativeObject(), precision)); + } - /** - * Return a lower bound for the given real algebraic number. The interval - * isolating the number is smaller than 1/10^{@code precision}. - * - * @see Expr#isAlgebraicNumber - * @param precision precision - * - * @return A numeral Expr of sort Real - * @throws Z3Exception on error - **/ - public RatNum toLower(int precision) - { + /** + * Return a lower bound for the given real algebraic number. The interval + * isolating the number is smaller than 1/10^{@code precision}. + * + * @see Expr#isAlgebraicNumber + * @param precision precision + * + * @return A numeral Expr of sort Real + * @throws Z3Exception on error + **/ + public RatNum toLower(int precision) + { - return new RatNum(getContext(), Native.getAlgebraicNumberLower(getContext() - .nCtx(), getNativeObject(), precision)); - } + return new RatNum(getContext(), Native.getAlgebraicNumberLower(getContext() + .nCtx(), getNativeObject(), precision)); + } - /** - * Returns a string representation in decimal notation. - * Remarks: The result has at most {@code precision} decimal places. - * @param precision precision - * @return String - * @throws Z3Exception on error - **/ - public String toDecimal(int precision) - { + /** + * Returns a string representation in decimal notation. + * Remarks: The result has at most {@code precision} decimal places. + * @param precision precision + * @return String + * @throws Z3Exception on error + **/ + public String toDecimal(int precision) + { - return Native.getNumeralDecimalString(getContext().nCtx(), getNativeObject(), - precision); - } + return Native.getNumeralDecimalString(getContext().nCtx(), getNativeObject(), + precision); + } - AlgebraicNum(Context ctx, long obj) - { - super(ctx, obj); + AlgebraicNum(Context ctx, long obj) + { + super(ctx, obj); - } + } } diff --git a/src/api/java/Context.java b/src/api/java/Context.java index 09683b4a4..a0a738fdb 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -1898,8 +1898,8 @@ public class Context implements AutoCloseable { */ public SeqExpr mkEmptySeq(Sort s) { - checkContextMatch(s); - return (SeqExpr) Expr.create(this, Native.mkSeqEmpty(nCtx(), s.getNativeObject())); + checkContextMatch(s); + return (SeqExpr) Expr.create(this, Native.mkSeqEmpty(nCtx(), s.getNativeObject())); } /** @@ -1907,8 +1907,8 @@ public class Context implements AutoCloseable { */ public SeqExpr mkUnit(Expr elem) { - checkContextMatch(elem); - return (SeqExpr) Expr.create(this, Native.mkSeqUnit(nCtx(), elem.getNativeObject())); + checkContextMatch(elem); + return (SeqExpr) Expr.create(this, Native.mkSeqUnit(nCtx(), elem.getNativeObject())); } /** @@ -1916,7 +1916,7 @@ public class Context implements AutoCloseable { */ public SeqExpr mkString(String s) { - return (SeqExpr) Expr.create(this, Native.mkString(nCtx(), s)); + return (SeqExpr) Expr.create(this, Native.mkString(nCtx(), s)); } /** @@ -1924,8 +1924,8 @@ public class Context implements AutoCloseable { */ public SeqExpr mkConcat(SeqExpr... t) { - checkContextMatch(t); - return (SeqExpr) Expr.create(this, Native.mkSeqConcat(nCtx(), t.length, AST.arrayToNative(t))); + checkContextMatch(t); + return (SeqExpr) Expr.create(this, Native.mkSeqConcat(nCtx(), t.length, AST.arrayToNative(t))); } @@ -1934,8 +1934,8 @@ public class Context implements AutoCloseable { */ public IntExpr mkLength(SeqExpr s) { - checkContextMatch(s); - return (IntExpr) Expr.create(this, Native.mkSeqLength(nCtx(), s.getNativeObject())); + checkContextMatch(s); + return (IntExpr) Expr.create(this, Native.mkSeqLength(nCtx(), s.getNativeObject())); } /** @@ -1943,8 +1943,8 @@ public class Context implements AutoCloseable { */ public BoolExpr mkPrefixOf(SeqExpr s1, SeqExpr s2) { - checkContextMatch(s1, s2); - return (BoolExpr) Expr.create(this, Native.mkSeqPrefix(nCtx(), s1.getNativeObject(), s2.getNativeObject())); + checkContextMatch(s1, s2); + return (BoolExpr) Expr.create(this, Native.mkSeqPrefix(nCtx(), s1.getNativeObject(), s2.getNativeObject())); } /** @@ -1952,8 +1952,8 @@ public class Context implements AutoCloseable { */ public BoolExpr mkSuffixOf(SeqExpr s1, SeqExpr s2) { - checkContextMatch(s1, s2); - return (BoolExpr)Expr.create(this, Native.mkSeqSuffix(nCtx(), s1.getNativeObject(), s2.getNativeObject())); + checkContextMatch(s1, s2); + return (BoolExpr)Expr.create(this, Native.mkSeqSuffix(nCtx(), s1.getNativeObject(), s2.getNativeObject())); } /** @@ -1961,8 +1961,8 @@ public class Context implements AutoCloseable { */ public BoolExpr mkContains(SeqExpr s1, SeqExpr s2) { - checkContextMatch(s1, s2); - return (BoolExpr) Expr.create(this, Native.mkSeqContains(nCtx(), s1.getNativeObject(), s2.getNativeObject())); + checkContextMatch(s1, s2); + return (BoolExpr) Expr.create(this, Native.mkSeqContains(nCtx(), s1.getNativeObject(), s2.getNativeObject())); } /** @@ -1970,8 +1970,8 @@ public class Context implements AutoCloseable { */ public SeqExpr mkAt(SeqExpr s, IntExpr index) { - checkContextMatch(s, index); - return (SeqExpr) Expr.create(this, Native.mkSeqAt(nCtx(), s.getNativeObject(), index.getNativeObject())); + checkContextMatch(s, index); + return (SeqExpr) Expr.create(this, Native.mkSeqAt(nCtx(), s.getNativeObject(), index.getNativeObject())); } /** @@ -1979,8 +1979,8 @@ public class Context implements AutoCloseable { */ public SeqExpr mkExtract(SeqExpr s, IntExpr offset, IntExpr length) { - checkContextMatch(s, offset, length); - return (SeqExpr) Expr.create(this, Native.mkSeqExtract(nCtx(), s.getNativeObject(), offset.getNativeObject(), length.getNativeObject())); + checkContextMatch(s, offset, length); + return (SeqExpr) Expr.create(this, Native.mkSeqExtract(nCtx(), s.getNativeObject(), offset.getNativeObject(), length.getNativeObject())); } /** @@ -1988,8 +1988,8 @@ public class Context implements AutoCloseable { */ public IntExpr mkIndexOf(SeqExpr s, SeqExpr substr, ArithExpr offset) { - checkContextMatch(s, substr, offset); - return (IntExpr)Expr.create(this, Native.mkSeqIndex(nCtx(), s.getNativeObject(), substr.getNativeObject(), offset.getNativeObject())); + checkContextMatch(s, substr, offset); + return (IntExpr)Expr.create(this, Native.mkSeqIndex(nCtx(), s.getNativeObject(), substr.getNativeObject(), offset.getNativeObject())); } /** @@ -1997,8 +1997,8 @@ public class Context implements AutoCloseable { */ public SeqExpr mkReplace(SeqExpr s, SeqExpr src, SeqExpr dst) { - checkContextMatch(s, src, dst); - return (SeqExpr) Expr.create(this, Native.mkSeqReplace(nCtx(), s.getNativeObject(), src.getNativeObject(), dst.getNativeObject())); + checkContextMatch(s, src, dst); + return (SeqExpr) Expr.create(this, Native.mkSeqReplace(nCtx(), s.getNativeObject(), src.getNativeObject(), dst.getNativeObject())); } /** @@ -2006,8 +2006,8 @@ public class Context implements AutoCloseable { */ public ReExpr mkToRe(SeqExpr s) { - checkContextMatch(s); - return (ReExpr) Expr.create(this, Native.mkSeqToRe(nCtx(), s.getNativeObject())); + checkContextMatch(s); + return (ReExpr) Expr.create(this, Native.mkSeqToRe(nCtx(), s.getNativeObject())); } @@ -2016,8 +2016,8 @@ public class Context implements AutoCloseable { */ public BoolExpr mkInRe(SeqExpr s, ReExpr re) { - checkContextMatch(s, re); - return (BoolExpr) Expr.create(this, Native.mkSeqInRe(nCtx(), s.getNativeObject(), re.getNativeObject())); + checkContextMatch(s, re); + return (BoolExpr) Expr.create(this, Native.mkSeqInRe(nCtx(), s.getNativeObject(), re.getNativeObject())); } /** @@ -2025,8 +2025,8 @@ public class Context implements AutoCloseable { */ public ReExpr mkStar(ReExpr re) { - checkContextMatch(re); - return (ReExpr) Expr.create(this, Native.mkReStar(nCtx(), re.getNativeObject())); + checkContextMatch(re); + return (ReExpr) Expr.create(this, Native.mkReStar(nCtx(), re.getNativeObject())); } /** @@ -2034,7 +2034,7 @@ public class Context implements AutoCloseable { */ public ReExpr mkLoop(ReExpr re, int lo, int hi) { - return (ReExpr) Expr.create(this, Native.mkReLoop(nCtx(), re.getNativeObject(), lo, hi)); + return (ReExpr) Expr.create(this, Native.mkReLoop(nCtx(), re.getNativeObject(), lo, hi)); } /** @@ -2042,7 +2042,7 @@ public class Context implements AutoCloseable { */ public ReExpr mkLoop(ReExpr re, int lo) { - return (ReExpr) Expr.create(this, Native.mkReLoop(nCtx(), re.getNativeObject(), lo, 0)); + return (ReExpr) Expr.create(this, Native.mkReLoop(nCtx(), re.getNativeObject(), lo, 0)); } @@ -2051,8 +2051,8 @@ public class Context implements AutoCloseable { */ public ReExpr mkPlus(ReExpr re) { - checkContextMatch(re); - return (ReExpr) Expr.create(this, Native.mkRePlus(nCtx(), re.getNativeObject())); + checkContextMatch(re); + return (ReExpr) Expr.create(this, Native.mkRePlus(nCtx(), re.getNativeObject())); } /** @@ -2060,8 +2060,8 @@ public class Context implements AutoCloseable { */ public ReExpr mkOption(ReExpr re) { - checkContextMatch(re); - return (ReExpr) Expr.create(this, Native.mkReOption(nCtx(), re.getNativeObject())); + checkContextMatch(re); + return (ReExpr) Expr.create(this, Native.mkReOption(nCtx(), re.getNativeObject())); } @@ -2070,8 +2070,8 @@ public class Context implements AutoCloseable { */ public ReExpr mkComplement(ReExpr re) { - checkContextMatch(re); - return (ReExpr) Expr.create(this, Native.mkReComplement(nCtx(), re.getNativeObject())); + checkContextMatch(re); + return (ReExpr) Expr.create(this, Native.mkReComplement(nCtx(), re.getNativeObject())); } /** @@ -2079,8 +2079,8 @@ public class Context implements AutoCloseable { */ public ReExpr mkConcat(ReExpr... t) { - checkContextMatch(t); - return (ReExpr) Expr.create(this, Native.mkReConcat(nCtx(), t.length, AST.arrayToNative(t))); + checkContextMatch(t); + return (ReExpr) Expr.create(this, Native.mkReConcat(nCtx(), t.length, AST.arrayToNative(t))); } /** @@ -2088,8 +2088,8 @@ public class Context implements AutoCloseable { */ public ReExpr mkUnion(ReExpr... t) { - checkContextMatch(t); - return (ReExpr) Expr.create(this, Native.mkReUnion(nCtx(), t.length, AST.arrayToNative(t))); + checkContextMatch(t); + return (ReExpr) Expr.create(this, Native.mkReUnion(nCtx(), t.length, AST.arrayToNative(t))); } /** @@ -2097,8 +2097,8 @@ public class Context implements AutoCloseable { */ public ReExpr mkIntersect(ReExpr... t) { - checkContextMatch(t); - return (ReExpr) Expr.create(this, Native.mkReIntersect(nCtx(), t.length, AST.arrayToNative(t))); + checkContextMatch(t); + return (ReExpr) Expr.create(this, Native.mkReIntersect(nCtx(), t.length, AST.arrayToNative(t))); } /** @@ -2106,8 +2106,8 @@ public class Context implements AutoCloseable { */ public ReExpr MkRange(SeqExpr lo, SeqExpr hi) { - checkContextMatch(lo, hi); - return (ReExpr) Expr.create(this, Native.mkReRange(nCtx(), lo.getNativeObject(), hi.getNativeObject())); + checkContextMatch(lo, hi); + return (ReExpr) Expr.create(this, Native.mkReRange(nCtx(), lo.getNativeObject(), hi.getNativeObject())); } @@ -2116,8 +2116,8 @@ public class Context implements AutoCloseable { */ public BoolExpr mkAtMost(BoolExpr[] args, int k) { - checkContextMatch(args); - return (BoolExpr) Expr.create(this, Native.mkAtmost(nCtx(), args.length, AST.arrayToNative(args), k)); + checkContextMatch(args); + return (BoolExpr) Expr.create(this, Native.mkAtmost(nCtx(), args.length, AST.arrayToNative(args), k)); } /** @@ -2125,8 +2125,8 @@ public class Context implements AutoCloseable { */ public BoolExpr mkAtLeast(BoolExpr[] args, int k) { - checkContextMatch(args); - return (BoolExpr) Expr.create(this, Native.mkAtleast(nCtx(), args.length, AST.arrayToNative(args), k)); + checkContextMatch(args); + return (BoolExpr) Expr.create(this, Native.mkAtleast(nCtx(), args.length, AST.arrayToNative(args), k)); } /** @@ -2134,8 +2134,8 @@ public class Context implements AutoCloseable { */ public BoolExpr mkPBLe(int[] coeffs, BoolExpr[] args, int k) { - checkContextMatch(args); - return (BoolExpr) Expr.create(this, Native.mkPble(nCtx(), args.length, AST.arrayToNative(args), coeffs, k)); + checkContextMatch(args); + return (BoolExpr) Expr.create(this, Native.mkPble(nCtx(), args.length, AST.arrayToNative(args), coeffs, k)); } /** @@ -2143,8 +2143,8 @@ public class Context implements AutoCloseable { */ public BoolExpr mkPBGe(int[] coeffs, BoolExpr[] args, int k) { - checkContextMatch(args); - return (BoolExpr) Expr.create(this, Native.mkPbge(nCtx(), args.length, AST.arrayToNative(args), coeffs, k)); + checkContextMatch(args); + return (BoolExpr) Expr.create(this, Native.mkPbge(nCtx(), args.length, AST.arrayToNative(args), coeffs, k)); } /** @@ -2152,8 +2152,8 @@ public class Context implements AutoCloseable { */ public BoolExpr mkPBEq(int[] coeffs, BoolExpr[] args, int k) { - checkContextMatch(args); - return (BoolExpr) Expr.create(this, Native.mkPbeq(nCtx(), args.length, AST.arrayToNative(args), coeffs, k)); + checkContextMatch(args); + return (BoolExpr) Expr.create(this, Native.mkPbeq(nCtx(), args.length, AST.arrayToNative(args), coeffs, k)); } @@ -3990,15 +3990,15 @@ public class Context implements AutoCloseable { void checkContextMatch(Z3Object other1, Z3Object other2) { - checkContextMatch(other1); - checkContextMatch(other2); + checkContextMatch(other1); + checkContextMatch(other2); } void checkContextMatch(Z3Object other1, Z3Object other2, Z3Object other3) { - checkContextMatch(other1); - checkContextMatch(other2); - checkContextMatch(other3); + checkContextMatch(other1); + checkContextMatch(other2); + checkContextMatch(other3); } void checkContextMatch(Z3Object[] arr) diff --git a/src/api/java/EnumSort.java b/src/api/java/EnumSort.java index ce2f8d578..e0bd0f617 100644 --- a/src/api/java/EnumSort.java +++ b/src/api/java/EnumSort.java @@ -65,7 +65,7 @@ public class EnumSort extends Sort **/ public Expr getConst(int inx) { - return getContext().mkApp(getConstDecl(inx)); + return getContext().mkApp(getConstDecl(inx)); } /** diff --git a/src/api/java/Expr.java b/src/api/java/Expr.java index 6cabbb1b8..d3793a24b 100644 --- a/src/api/java/Expr.java +++ b/src/api/java/Expr.java @@ -1287,7 +1287,7 @@ public class Expr extends AST */ public String getString() { - return Native.getString(getContext().nCtx(), getNativeObject()); + return Native.getString(getContext().nCtx(), getNativeObject()); } /** diff --git a/src/api/java/Model.java b/src/api/java/Model.java index 60abb001d..9c7013aca 100644 --- a/src/api/java/Model.java +++ b/src/api/java/Model.java @@ -200,7 +200,7 @@ public class Model extends Z3Object { * Remarks: This function may fail if {@code t} contains * quantifiers, is partial (MODEL_PARTIAL enabled), or if {@code t} is not well-sorted. In this case a * {@code ModelEvaluationFailedException} is thrown. - * @param t the expression to evaluate + * @param t the expression to evaluate * @param completion An expression {@code completion} When this flag * is enabled, a model value will be assigned to any constant or function * that does not have an interpretation in the model. diff --git a/src/api/java/Optimize.java b/src/api/java/Optimize.java index bc2232888..3edbff73e 100644 --- a/src/api/java/Optimize.java +++ b/src/api/java/Optimize.java @@ -213,7 +213,7 @@ public class Optimize extends Z3Object { * 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. - **/ + **/ public Handle MkMaximize(ArithExpr e) { return new Handle(this, Native.optimizeMaximize(getContext().nCtx(), getNativeObject(), e.getNativeObject())); @@ -285,8 +285,7 @@ public class Optimize extends Z3Object { **/ public String getReasonUnknown() { - return Native.optimizeGetReasonUnknown(getContext().nCtx(), - getNativeObject()); + return Native.optimizeGetReasonUnknown(getContext().nCtx(), getNativeObject()); } /** @@ -304,7 +303,7 @@ public class Optimize extends Z3Object { */ public void fromFile(String file) { - Native.optimizeFromFile(getContext().nCtx(), getNativeObject(), file); + Native.optimizeFromFile(getContext().nCtx(), getNativeObject(), file); } /** @@ -312,7 +311,7 @@ public class Optimize extends Z3Object { */ public void fromString(String s) { - Native.optimizeFromString(getContext().nCtx(), getNativeObject(), s); + Native.optimizeFromString(getContext().nCtx(), getNativeObject(), s); } diff --git a/src/api/java/ParamDescrs.java b/src/api/java/ParamDescrs.java index 0008515e3..fdaf29647 100644 --- a/src/api/java/ParamDescrs.java +++ b/src/api/java/ParamDescrs.java @@ -49,7 +49,7 @@ public class ParamDescrs extends Z3Object { public String getDocumentation(Symbol name) { - return Native.paramDescrsGetDocumentation(getContext().nCtx(), getNativeObject(), name.getNativeObject()); + return Native.paramDescrsGetDocumentation(getContext().nCtx(), getNativeObject(), name.getNativeObject()); } /** diff --git a/src/api/java/Solver.java b/src/api/java/Solver.java index a98fcbf94..19f3b01da 100644 --- a/src/api/java/Solver.java +++ b/src/api/java/Solver.java @@ -302,7 +302,7 @@ public class Solver extends Z3Object { */ public Solver translate(Context ctx) { - return new Solver(ctx, Native.solverTranslate(getContext().nCtx(), getNativeObject(), ctx.nCtx())); + return new Solver(ctx, Native.solverTranslate(getContext().nCtx(), getNativeObject(), ctx.nCtx())); } /** diff --git a/src/api/java/Sort.java b/src/api/java/Sort.java index e7a186ad2..a89417059 100644 --- a/src/api/java/Sort.java +++ b/src/api/java/Sort.java @@ -35,12 +35,8 @@ public class Sort extends AST if (!(o instanceof Sort)) return false; Sort other = (Sort) o; - return (getContext().nCtx() == other.getContext().nCtx()) && - (Native.isEqSort( - getContext().nCtx(), - getNativeObject(), - other.getNativeObject() - )); + return (getContext().nCtx() == other.getContext().nCtx()) && + (Native.isEqSort(getContext().nCtx(), getNativeObject(), other.getNativeObject())); } /** diff --git a/src/api/ml/z3native_stubs.c.pre b/src/api/ml/z3native_stubs.c.pre index 1b1ea3fde..c1c772c85 100644 --- a/src/api/ml/z3native_stubs.c.pre +++ b/src/api/ml/z3native_stubs.c.pre @@ -25,34 +25,34 @@ extern "C" { #include #define CAMLlocal6(X1,X2,X3,X4,X5,X6) \ - CAMLlocal5(X1,X2,X3,X4,X5); \ + CAMLlocal5(X1,X2,X3,X4,X5); \ CAMLlocal1(X6) -#define CAMLlocal7(X1,X2,X3,X4,X5,X6,X7) \ - CAMLlocal5(X1,X2,X3,X4,X5); \ +#define CAMLlocal7(X1,X2,X3,X4,X5,X6,X7) \ + CAMLlocal5(X1,X2,X3,X4,X5); \ CAMLlocal2(X6,X7) -#define CAMLlocal8(X1,X2,X3,X4,X5,X6,X7,X8) \ - CAMLlocal5(X1,X2,X3,X4,X5); \ +#define CAMLlocal8(X1,X2,X3,X4,X5,X6,X7,X8) \ + CAMLlocal5(X1,X2,X3,X4,X5); \ CAMLlocal3(X6,X7,X8) -#define CAMLparam6(X1,X2,X3,X4,X5,X6) \ - CAMLparam5(X1,X2,X3,X4,X5); \ +#define CAMLparam6(X1,X2,X3,X4,X5,X6) \ + CAMLparam5(X1,X2,X3,X4,X5); \ CAMLxparam1(X6) -#define CAMLparam7(X1,X2,X3,X4,X5,X6,X7) \ - CAMLparam5(X1,X2,X3,X4,X5); \ +#define CAMLparam7(X1,X2,X3,X4,X5,X6,X7) \ + CAMLparam5(X1,X2,X3,X4,X5); \ CAMLxparam2(X6,X7) -#define CAMLparam8(X1,X2,X3,X4,X5,X6,X7,X8) \ - CAMLparam5(X1,X2,X3,X4,X5); \ +#define CAMLparam8(X1,X2,X3,X4,X5,X6,X7,X8) \ + CAMLparam5(X1,X2,X3,X4,X5); \ CAMLxparam3(X6,X7,X8) -#define CAMLparam9(X1,X2,X3,X4,X5,X6,X7,X8,X9) \ - CAMLparam5(X1,X2,X3,X4,X5); \ +#define CAMLparam9(X1,X2,X3,X4,X5,X6,X7,X8,X9) \ + CAMLparam5(X1,X2,X3,X4,X5); \ CAMLxparam4(X6,X7,X8,X9) -#define CAMLparam12(X1,X2,X3,X4,X5,X6,X7,X8,X9,X10,X11,X12) \ - CAMLparam5(X1,X2,X3,X4,X5); \ - CAMLxparam5(X6,X7,X8,X9,X10); \ +#define CAMLparam12(X1,X2,X3,X4,X5,X6,X7,X8,X9,X10,X11,X12) \ + CAMLparam5(X1,X2,X3,X4,X5); \ + CAMLxparam5(X6,X7,X8,X9,X10); \ CAMLxparam2(X11,X12) -#define CAMLparam13(X1,X2,X3,X4,X5,X6,X7,X8,X9,X10,X11,X12,X13) \ - CAMLparam5(X1,X2,X3,X4,X5); \ - CAMLxparam5(X6,X7,X8,X9,X10); \ +#define CAMLparam13(X1,X2,X3,X4,X5,X6,X7,X8,X9,X10,X11,X12,X13) \ + CAMLparam5(X1,X2,X3,X4,X5); \ + CAMLxparam5(X6,X7,X8,X9,X10); \ CAMLxparam3(X11,X12,X13) diff --git a/src/api/ml/z3native_stubs.h b/src/api/ml/z3native_stubs.h index ef81ac239..ec498dafe 100644 --- a/src/api/ml/z3native_stubs.h +++ b/src/api/ml/z3native_stubs.h @@ -36,5 +36,5 @@ Notes: #define DLL_LOCAL #endif #endif - + #endif diff --git a/src/api/z3_api.h b/src/api/z3_api.h index efca9286a..77ea9bed0 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -397,23 +397,23 @@ typedef enum (xor3 l1 l2 l3) <=> (xor (xor l1 l2) l3) - Z3_OP_BSMUL_NO_OVFL: a predicate to check that bit-wise signed multiplication does not overflow. - Signed multiplication overflows if the operands have the same sign and the result of multiplication + Signed multiplication overflows if the operands have the same sign and the result of multiplication does not fit within the available bits. \sa Z3_mk_bvmul_no_overflow. - Z3_OP_BUMUL_NO_OVFL: check that bit-wise unsigned multiplication does not overflow. Unsigned multiplication overflows if the result does not fit within the available bits. \sa Z3_mk_bvmul_no_overflow. - + - Z3_OP_BSMUL_NO_UDFL: check that bit-wise signed multiplication does not underflow. Signed multiplication underflows if the operands have opposite signs and the result of multiplication does not fit within the avaialble bits. Z3_mk_bvmul_no_underflow. - - - Z3_OP_BSDIV_I: Binary signed division. + + - Z3_OP_BSDIV_I: Binary signed division. It has the same semantics as Z3_OP_BSDIV, but created in a context where the second operand can be assumed to be non-zero. - Z3_OP_BUDIV_I: Binary unsigned division. It has the same semantics as Z3_OP_BUDIV, but created in a context where the second operand can be assumed to be non-zero. - + - Z3_OP_BSREM_I: Binary signed remainder. It has the same semantics as Z3_OP_BSREM, but created in a context where the second operand can be assumed to be non-zero. @@ -979,7 +979,23 @@ typedef enum - Z3_OP_FPA_TO_IEEE_BV: Floating-point conversion to IEEE-754 bit-vector - - Z3_OP_INTERNAL: internal (often interpreted) symbol, but no additional information is exposed. Tools may use the string representation of the function declaration to obtain more information. + - Z3_OP_FPA_BVWRAP: (Implicitly) represents the internal bitvector- + representation of a floating-point term (used for the lazy encoding + of non-relevant terms in theory_fpa) + + - Z3_OP_FPA_BV2RM: Conversion of a 3-bit bit-vector term to a + floating-point rouding-mode term + + The conversion uses the following values: + 0 = 000 = Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN, + 1 = 001 = Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY, + 2 = 010 = Z3_OP_FPA_RM_TOWARD_POSITIVE, + 3 = 011 = Z3_OP_FPA_RM_TOWARD_NEGATIVE, + 4 = 100 = Z3_OP_FPA_RM_TOWARD_ZERO. + + - Z3_OP_INTERNAL: internal (often interpreted) symbol, but no additional + information is exposed. Tools may use the string representation of the + function declaration to obtain more information. - Z3_OP_UNINTERPRETED: kind used for uninterpreted symbols. */ @@ -1263,8 +1279,8 @@ typedef enum { Z3_OP_FPA_TO_IEEE_BV, - Z3_OP_FPA_MIN_I, - Z3_OP_FPA_MAX_I, + Z3_OP_FPA_BVWRAP, + Z3_OP_FPA_BV2RM, Z3_OP_INTERNAL, @@ -3361,7 +3377,7 @@ extern "C" { \brief Convert string to integer. def_API('Z3_mk_str_to_int' ,AST ,(_in(CONTEXT), _in(AST))) - */ + */ Z3_ast Z3_API Z3_mk_str_to_int(Z3_context c, Z3_ast s); @@ -3369,7 +3385,7 @@ extern "C" { \brief Integer to string conversion. def_API('Z3_mk_int_to_str' ,AST ,(_in(CONTEXT), _in(AST))) - */ + */ Z3_ast Z3_API Z3_mk_int_to_str(Z3_context c, Z3_ast s); /** @@ -4859,12 +4875,12 @@ extern "C" { Z3_func_decl Z3_API Z3_get_as_array_func_decl(Z3_context c, Z3_ast a); /** - \brief Create a fresh func_interp object, add it to a model for a specified function. - It has reference count 0. + \brief Create a fresh func_interp object, add it to a model for a specified function. + It has reference count 0. \param c context \param m model - \param f function declaration + \param f function declaration \param default_value default value for function interpretation def_API('Z3_add_func_interp', FUNC_INTERP, (_in(CONTEXT), _in(MODEL), _in(FUNC_DECL), _in(AST))) @@ -4950,7 +4966,7 @@ extern "C" { \param args list of arguments. They should be constant values (such as integers) and be of the same types as the domain of the function. \param value value of the function when the parameters match args. - It is assumed that entries added to a function cover disjoint arguments. + It is assumed that entries added to a function cover disjoint arguments. If an two entries are added with the same arguments, only the second insertion survives and the first inserted entry is removed. diff --git a/src/api/z3_ast_containers.h b/src/api/z3_ast_containers.h index 027976c07..c423a3286 100644 --- a/src/api/z3_ast_containers.h +++ b/src/api/z3_ast_containers.h @@ -197,4 +197,4 @@ extern "C" { } #endif // __cplusplus -#endif \ No newline at end of file +#endif diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index bb81c1eba..c98307ee0 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1714,8 +1714,15 @@ ast * ast_manager::register_node_core(ast * n) { SASSERT(m_ast_table.contains(n)); } + n->m_id = is_decl(n) ? m_decl_id_gen.mk() : m_expr_id_gen.mk(); + static unsigned count = 0; + if (n->m_id == 404) { + ++count; + //if (count == 2) SASSERT(false); + } + TRACE("ast", tout << "Object " << n->m_id << " was created.\n";); TRACE("mk_var_bug", tout << "mk_ast: " << n->m_id << "\n";); // increment reference counters diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index abb4ae959..e4a875005 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -584,6 +584,8 @@ class smt2_printer { string_buffer<> buf; buf.append("(:var "); buf.append(v->get_idx()); + //buf.append(" "); + //buf.append(v->get_sort()->get_name().str().c_str()); buf.append(")"); f = mk_string(m(), buf.c_str()); } diff --git a/src/ast/bv_decl_plugin.cpp b/src/ast/bv_decl_plugin.cpp index b5c79f662..fcf9a9f8f 100644 --- a/src/ast/bv_decl_plugin.cpp +++ b/src/ast/bv_decl_plugin.cpp @@ -738,6 +738,7 @@ void bv_decl_plugin::get_op_names(svector & op_names, symbol const op_names.push_back(builtin_name("ext_rotate_right",OP_EXT_ROTATE_RIGHT)); op_names.push_back(builtin_name("int2bv",OP_INT2BV)); op_names.push_back(builtin_name("bv2int",OP_BV2INT)); + op_names.push_back(builtin_name("bv2nat",OP_BV2INT)); op_names.push_back(builtin_name("mkbv",OP_MKBV)); } } diff --git a/src/ast/fpa/bv2fpa_converter.cpp b/src/ast/fpa/bv2fpa_converter.cpp index 7e4f2f133..93bd79571 100644 --- a/src/ast/fpa/bv2fpa_converter.cpp +++ b/src/ast/fpa/bv2fpa_converter.cpp @@ -62,8 +62,8 @@ bv2fpa_converter::bv2fpa_converter(ast_manager & m, fpa2bv_converter & conv) : m.inc_ref(it->m_key); m.inc_ref(it->m_value); } - for (obj_map >::iterator it = conv.m_min_max_specials.begin(); - it != conv.m_min_max_specials.end(); + for (obj_map >::iterator it = conv.m_min_max_ufs.begin(); + it != conv.m_min_max_ufs.end(); it++) { m_specials.insert(it->m_key, it->m_value); m.inc_ref(it->m_key); @@ -120,9 +120,9 @@ expr_ref bv2fpa_converter::convert_bv2fp(sort * s, expr * sgn, expr * exp, expr res = m_fpa_util.mk_value(fp_val); TRACE("bv2fpa", tout << "[" << mk_ismt2_pp(sgn, m) << - " " << mk_ismt2_pp(exp, m) << - " " << mk_ismt2_pp(sig, m) << "] == " << - mk_ismt2_pp(res, m) << std::endl;); + " " << mk_ismt2_pp(exp, m) << + " " << mk_ismt2_pp(sig, m) << "] == " << + mk_ismt2_pp(res, m) << std::endl;); m_fpa_util.fm().del(fp_val); return res; @@ -263,7 +263,7 @@ func_interp * bv2fpa_converter::convert_func_interp(model_core * mc, func_decl * unsigned arity = bv_f->get_arity(); func_interp * bv_fi = mc->get_func_interp(bv_f); - if (bv_fi != 0) { + if (bv_fi) { fpa_rewriter rw(m); expr_ref ai(m); result = alloc(func_interp, m, arity); @@ -285,15 +285,31 @@ func_interp * bv2fpa_converter::convert_func_interp(model_core * mc, func_decl * bv_fres = bv_fe->get_result(); ft_fres = rebuild_floats(mc, rng, to_app(bv_fres)); m_th_rw(ft_fres); - result->insert_new_entry(new_args.c_ptr(), ft_fres); + TRACE("bv2fpa", + for (unsigned i = 0; i < new_args.size(); i++) + tout << mk_ismt2_pp(bv_args[i], m) << " == " << + mk_ismt2_pp(new_args[i], m) << std::endl; + tout << mk_ismt2_pp(bv_fres, m) << " == " << mk_ismt2_pp(ft_fres, m) << std::endl;); + func_entry * fe = result->get_entry(new_args.c_ptr()); + if (fe == 0) + result->insert_new_entry(new_args.c_ptr(), ft_fres); + else { + // The BV model may have multiple equivalent entries using different + // representations of NaN. We can only keep one and we check that + // the results for all those entries are the same. + if (ft_fres != fe->get_result()) + throw default_exception("BUG: UF function entries disagree with each other"); + } } app_ref bv_els(m); expr_ref ft_els(m); bv_els = (app*)bv_fi->get_else(); - ft_els = rebuild_floats(mc, rng, bv_els); - m_th_rw(ft_els); - result->set_else(ft_els); + if (bv_els != 0) { + ft_els = rebuild_floats(mc, rng, bv_els); + m_th_rw(ft_els); + result->set_else(ft_els); + } } return result; @@ -382,7 +398,7 @@ void bv2fpa_converter::convert_rm_consts(model_core * mc, model_core * target_mo expr * bvval = to_app(val)->get_arg(0); expr_ref fv(m); fv = convert_bv2rm(mc, to_app(bvval)); - TRACE("bv2fpa", tout << var->get_name() << " == " << mk_ismt2_pp(fv, m) << ")" << std::endl;); + TRACE("bv2fpa", tout << var->get_name() << " == " << mk_ismt2_pp(fv, m) << std::endl;); target_model->register_decl(var, fv); seen.insert(to_app(bvval)->get_decl()); } @@ -447,14 +463,34 @@ void bv2fpa_converter::convert_uf2bvuf(model_core * mc, model_core * target_mode } } else { - func_interp * fmv = convert_func_interp(mc, f, it->m_value); - if (fmv) target_model->register_decl(f, fmv); + if (it->get_key().get_family_id() == m_fpa_util.get_fid()) { + // it->m_value contains the model for the unspecified cases of it->m_key. + + func_interp * fmv = convert_func_interp(mc, f, it->m_value); + if (fmv) { +#if 0 + // Upon request, add this 'recursive' definition? + unsigned n = fmv->get_arity(); + expr_ref_vector args(m); + for (unsigned i = 0; i < n; i++) + args.push_back(m.mk_var(i, f->get_domain()[i])); + fmv->set_else(m.mk_app(it->m_key, n, args.c_ptr())); +#else + + fmv->set_else(0); +#endif + target_model->register_decl(f, fmv); + } + } + else { + func_interp * fmv = convert_func_interp(mc, f, it->m_value); + if (fmv) target_model->register_decl(f, fmv); + } } } } void bv2fpa_converter::display(std::ostream & out) { - out << "(fpa2bv-model-converter"; for (obj_map::iterator it = m_const2bv.begin(); it != m_const2bv.end(); it++) { @@ -488,7 +524,6 @@ void bv2fpa_converter::display(std::ostream & out) { out << mk_ismt2_pp(it->m_value.first, m, indent) << "; " << mk_ismt2_pp(it->m_value.second, m, indent) << ")"; } - out << ")"; } bv2fpa_converter * bv2fpa_converter::translate(ast_translation & translator) { @@ -536,23 +571,3 @@ bv2fpa_converter * bv2fpa_converter::translate(ast_translation & translator) { return res; } -void bv2fpa_converter::convert(model_core * mc, model_core * float_mdl) { - TRACE("bv2fpa", tout << "BV Model: " << std::endl; - for (unsigned i = 0; i < mc->get_num_constants(); i++) - tout << mc->get_constant(i)->get_name() << " --> " << - mk_ismt2_pp(mc->get_const_interp(mc->get_constant(i)), m) << std::endl; - for (unsigned i = 0; i < mc->get_num_functions(); i++) { - func_decl * f = mc->get_function(i); - tout << f->get_name() << "(...) := " << std::endl; - func_interp * fi = mc->get_func_interp(f); - for (unsigned j = 0; j < fi->num_entries(); j++) { - func_entry const * fe = fi->get_entry(j); - for (unsigned k = 0; k < f->get_arity(); k++) { - tout << mk_ismt2_pp(fe->get_arg(k), m) << " "; - } - tout << "--> " << mk_ismt2_pp(fe->get_result(), m) << std::endl; - } - tout << "else " << mk_ismt2_pp(fi->get_else(), m) << std::endl; - }); - -} diff --git a/src/ast/fpa/bv2fpa_converter.h b/src/ast/fpa/bv2fpa_converter.h index 943f544ca..caf36c1fc 100644 --- a/src/ast/fpa/bv2fpa_converter.h +++ b/src/ast/fpa/bv2fpa_converter.h @@ -50,7 +50,6 @@ public: expr_ref convert_bv2rm(expr * eval_v); expr_ref convert_bv2rm(model_core * mc, app * val); - void convert(model_core * mc, model_core * float_mdl); void convert_consts(model_core * mc, model_core * target_model, obj_hashtable & seen); void convert_rm_consts(model_core * mc, model_core * target_model, obj_hashtable & seen); void convert_min_max_specials(model_core * mc, model_core * target_model, obj_hashtable & seen); diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 1a4698fa4..f09ddcd42 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -230,39 +230,7 @@ void fpa2bv_converter::mk_var(unsigned base_inx, sort * srt, expr_ref & result) result = m_util.mk_fp(sgn, e, s); } -void fpa2bv_converter::mk_function_output(sort * rng, func_decl * fbv, expr * const * new_args, expr_ref & result) { - if (m_util.is_float(rng)) { - unsigned ebits = m_util.get_ebits(rng); - unsigned sbits = m_util.get_sbits(rng); - unsigned bv_sz = ebits + sbits; - - app_ref na(m); - na = m.mk_app(fbv, fbv->get_arity(), new_args); - result = m_util.mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, na), - m_bv_util.mk_extract(bv_sz - 2, sbits - 1, na), - m_bv_util.mk_extract(sbits - 2, 0, na)); - } - else if (m_util.is_rm(rng)) { - app_ref na(m); - na = m.mk_app(fbv, fbv->get_arity(), new_args); - result = m_util.mk_bv2rm(na); - } - else - result = m.mk_app(fbv, fbv->get_arity(), new_args); -} - -func_decl * fpa2bv_converter::get_bv_uf(func_decl * f, sort * bv_rng, unsigned arity) { - func_decl * res; - if (!m_uf2bvuf.find(f, res)) { - res = m.mk_fresh_func_decl(f->get_name(), symbol("bv"), arity, f->get_domain(), bv_rng); - m_uf2bvuf.insert(f, res); - m.inc_ref(f); - m.inc_ref(res); - TRACE("fpa2bv", tout << "New UF func_decl: " << std::endl << mk_ismt2_pp(res, m) << std::endl;); - } - return res; -} -void fpa2bv_converter::mk_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result) +void fpa2bv_converter::mk_uf(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { TRACE("fpa2bv", tout << "UF: " << mk_ismt2_pp(f, m) << std::endl; ); @@ -278,7 +246,7 @@ void fpa2bv_converter::mk_function(func_decl * f, unsigned num, expr * const * a unsigned sbits = m_util.get_sbits(rng); unsigned bv_sz = ebits+sbits; bv_rng = m_bv_util.mk_sort(bv_sz); - func_decl * bv_f = get_bv_uf(f, bv_rng, num); + func_decl * bv_f = mk_bv_uf(f, f->get_domain(), bv_rng); bv_app = m.mk_app(bv_f, num, args); flt_app = m_util.mk_fp(m_bv_util.mk_extract(bv_sz-1, bv_sz-1, bv_app), m_bv_util.mk_extract(sbits+ebits-2, sbits-1, bv_app), @@ -291,7 +259,7 @@ void fpa2bv_converter::mk_function(func_decl * f, unsigned num, expr * const * a sort_ref bv_rng(m); expr_ref new_eq(m); bv_rng = m_bv_util.mk_sort(3); - func_decl * bv_f = get_bv_uf(f, bv_rng, num); + func_decl * bv_f = mk_bv_uf(f, f->get_domain(), bv_rng); bv_app = m.mk_app(bv_f, num, args); flt_app = m_util.mk_bv2rm(bv_app); new_eq = m.mk_eq(fapp, flt_app); @@ -1211,61 +1179,89 @@ void fpa2bv_converter::mk_abs(sort * s, expr_ref & x, expr_ref & result) { } void fpa2bv_converter::mk_min(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { - expr_ref x(m), y(m); - x = args[0]; - y = args[1]; - - expr_ref x_is_zero(m), y_is_zero(m), both_are_zero(m); - x_is_zero = m_util.mk_is_zero(x); - y_is_zero = m_util.mk_is_zero(y); - both_are_zero = m.mk_and(x_is_zero, y_is_zero); - - expr_ref x_is_positive(m), x_is_negative(m), y_is_positive(m), y_is_negative(m), pn(m), np(m), pn_or_np(m); - x_is_positive = m_util.mk_is_positive(x); - x_is_negative = m_util.mk_is_negative(x); - y_is_positive = m_util.mk_is_positive(y); - y_is_negative = m_util.mk_is_negative(y); - pn = m.mk_and(x_is_positive, y_is_negative); - np = m.mk_and(x_is_negative, y_is_positive); - pn_or_np = m.mk_or(pn, np); - - expr_ref c(m), v(m); - c = m.mk_and(both_are_zero, pn_or_np); - v = m.mk_app(m_util.get_family_id(), OP_FPA_INTERNAL_MIN_UNSPECIFIED, x, y); - - // Note: This requires BR_REWRITE_FULL afterwards. - expr_ref min_i(m); - min_i = m.mk_app(m_util.get_family_id(), OP_FPA_INTERNAL_MIN_I, x, y); - m_simp.mk_ite(c, v, min_i, result); -} - -void fpa2bv_converter::mk_min_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 2); + unsigned ebits = m_util.get_ebits(f->get_range()); + unsigned sbits = m_util.get_sbits(f->get_range()); expr * x = args[0], * y = args[1]; - expr * x_sgn, * x_sig, * x_exp; - expr * y_sgn, * y_sig, * y_exp; + 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 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); + expr_ref bv0(m), bv1(m); + bv0 = m_bv_util.mk_numeral(0, 1); + bv1 = m_bv_util.mk_numeral(1, 1); + + expr_ref x_is_nan(m), y_is_nan(m), x_is_zero(m), y_is_zero(m), xy_are_zero(m); mk_is_nan(x, x_is_nan); mk_is_nan(y, y_is_nan); - mk_pzero(f, pzero); + mk_is_zero(x, x_is_zero); + mk_is_zero(y, y_is_zero); + xy_are_zero = m.mk_and(x_is_zero, y_is_zero); - expr_ref sgn_eq(m), sgn_diff(m); - sgn_eq = m.mk_eq(x_sgn, y_sgn); - sgn_diff = m.mk_not(sgn_eq); + expr_ref x_is_pos(m), x_is_neg(m); + expr_ref y_is_pos(m), y_is_neg(m); + expr_ref pn(m), np(m), pn_or_np_zeros(m); + mk_is_pos(x, x_is_pos); + mk_is_pos(y, y_is_pos); + mk_is_neg(x, x_is_neg); + mk_is_neg(y, y_is_neg); + pn_or_np_zeros = m.mk_and(xy_are_zero, m.mk_not(m.mk_eq(x_sgn, y_sgn))); - expr_ref lt(m); - mk_float_lt(f, num, args, lt); + expr_ref unspec(m); + unspec = mk_min_max_unspecified(f, x, y); - mk_ite(lt, x, y, result); - mk_ite(both_zero, y, result, result); + expr_ref x_lt_y(m); + mk_float_lt(f, num, args, x_lt_y); + + mk_ite(x_lt_y, x, y, result); + mk_ite(xy_are_zero, y, result, result); + mk_ite(pn_or_np_zeros, unspec, result, result); + mk_ite(y_is_nan, x, result, result); + mk_ite(x_is_nan, y, result, 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); + unsigned ebits = m_util.get_ebits(f->get_range()); + unsigned sbits = m_util.get_sbits(f->get_range()); + + 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 x_is_nan(m), y_is_nan(m), x_is_zero(m), y_is_zero(m), xy_are_zero(m); + mk_is_nan(x, x_is_nan); + mk_is_nan(y, y_is_nan); + mk_is_zero(x, x_is_zero); + mk_is_zero(y, y_is_zero); + xy_are_zero = m.mk_and(x_is_zero, y_is_zero); + + expr_ref x_is_pos(m), x_is_neg(m); + expr_ref y_is_pos(m), y_is_neg(m); + expr_ref pn(m), np(m), pn_or_np_zeros(m); + mk_is_pos(x, x_is_pos); + mk_is_pos(y, y_is_pos); + mk_is_neg(x, x_is_neg); + mk_is_neg(y, y_is_neg); + pn_or_np_zeros = m.mk_and(xy_are_zero, m.mk_not(m.mk_eq(x_sgn, y_sgn))); + + expr_ref unspec(m); + unspec = mk_min_max_unspecified(f, x, y); + + expr_ref x_gt_y(m); + mk_float_gt(f, num, args, x_gt_y); + + mk_ite(x_gt_y, x, y, result); + mk_ite(xy_are_zero, y, result, result); + mk_ite(pn_or_np_zeros, unspec, result, result); mk_ite(y_is_nan, x, result, result); mk_ite(x_is_nan, y, result, result); @@ -1281,10 +1277,10 @@ expr_ref fpa2bv_converter::mk_min_max_unspecified(func_decl * f, expr * x, expr // There is no "hardware interpretation" for fp.min/fp.max. std::pair decls(0, 0); - if (!m_min_max_specials.find(f, decls)) { + if (!m_min_max_ufs.find(f, decls)) { decls.first = m.mk_fresh_const(0, m_bv_util.mk_sort(1)); decls.second = m.mk_fresh_const(0, m_bv_util.mk_sort(1)); - m_min_max_specials.insert(f, decls); + m_min_max_ufs.insert(f, decls); m.inc_ref(f); m.inc_ref(decls.first); m.inc_ref(decls.second); @@ -1303,68 +1299,6 @@ expr_ref fpa2bv_converter::mk_min_max_unspecified(func_decl * f, expr * x, expr return res; } -void fpa2bv_converter::mk_max(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { - expr_ref x(m), y(m); - x = args[0]; - y = args[1]; - - expr_ref x_is_zero(m), y_is_zero(m), both_are_zero(m); - x_is_zero = m_util.mk_is_zero(x); - y_is_zero = m_util.mk_is_zero(y); - both_are_zero = m.mk_and(x_is_zero, y_is_zero); - - expr_ref x_is_positive(m), x_is_negative(m), y_is_positive(m), y_is_negative(m), pn(m), np(m), pn_or_np(m); - x_is_positive = m_util.mk_is_positive(x); - x_is_negative = m_util.mk_is_negative(x); - y_is_positive = m_util.mk_is_positive(y); - y_is_negative = m_util.mk_is_negative(y); - pn = m.mk_and(x_is_positive, y_is_negative); - np = m.mk_and(x_is_negative, y_is_positive); - pn_or_np = m.mk_or(pn, np); - - expr_ref c(m), v(m); - c = m.mk_and(both_are_zero, pn_or_np); - v = m.mk_app(m_util.get_family_id(), OP_FPA_INTERNAL_MAX_UNSPECIFIED, x, y); - - // Note: This requires BR_REWRITE_FULL afterwards. - expr_ref max_i(m); - max_i = m.mk_app(m_util.get_family_id(), OP_FPA_INTERNAL_MAX_I, x, y); - m_simp.mk_ite(c, v, max_i, result); -} - -void fpa2bv_converter::mk_max_i(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; - 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); - 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); - mk_is_nan(x, x_is_nan); - mk_is_nan(y, y_is_nan); - mk_pzero(f, pzero); - - expr_ref sgn_diff(m), sgn_eq(m); - sgn_eq = m.mk_eq(x_sgn, y_sgn); - sgn_diff = m.mk_not(sgn_eq); - - expr_ref gt(m); - mk_float_gt(f, num, args, gt); - - mk_ite(gt, x, y, result); - mk_ite(both_zero, y, result, result); - mk_ite(y_is_nan, x, result, result); - mk_ite(x_is_nan, y, result, result); - - SASSERT(is_well_sorted(m, result)); -} - void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 4); SASSERT(m_util.is_bv2rm(args[0])); @@ -2855,8 +2789,7 @@ void fpa2bv_converter::mk_to_real(func_decl * f, unsigned num, expr * const * ar tout << "exp2 = " << mk_ismt2_pp(exp2, m) << std::endl;); expr_ref unspec(m); - unspec = mk_to_real_unspecified(ebits, sbits); - + mk_to_real_unspecified(f, num, args, unspec); result = m.mk_ite(x_is_zero, zero, res); result = m.mk_ite(x_is_inf, unspec, result); result = m.mk_ite(x_is_nan, unspec, result); @@ -3151,59 +3084,43 @@ void fpa2bv_converter::mk_to_ieee_bv(func_decl * f, unsigned num, expr * const * unsigned ebits = m_util.get_ebits(fp_srt); unsigned sbits = m_util.get_sbits(fp_srt); - expr_ref nanv(m); - if (m_hi_fp_unspecified) - // The "hardware interpretation" is 01...10...01. - nanv = m_bv_util.mk_concat(m_bv_util.mk_numeral(0, 1), - m_bv_util.mk_concat(m_bv_util.mk_numeral(-1, ebits), - m_bv_util.mk_concat(m_bv_util.mk_numeral(0, sbits - 2), - m_bv_util.mk_numeral(1, 1)))); - else { - app_ref unspec(m); - unspec = m_util.mk_internal_to_ieee_bv_unspecified(ebits, sbits); - mk_to_ieee_bv_unspecified(unspec->get_decl(), 0, 0, nanv); - } + expr_ref unspec(m); + mk_to_ieee_bv_unspecified(f, num, args, unspec); expr_ref sgn_e_s(m); - sgn_e_s = m_bv_util.mk_concat(m_bv_util.mk_concat(sgn, e), s); - m_simp.mk_ite(x_is_nan, nanv, sgn_e_s, result); + join_fp(x, sgn_e_s); + m_simp.mk_ite(x_is_nan, unspec, sgn_e_s, result); TRACE("fpa2bv_to_ieee_bv", tout << "result=" << mk_ismt2_pp(result, m) << std::endl;); SASSERT(is_well_sorted(m, result)); } void fpa2bv_converter::mk_to_ieee_bv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { - SASSERT(num == 0); - unsigned ebits = f->get_parameter(0).get_int(); - unsigned sbits = f->get_parameter(1).get_int(); + SASSERT(num == 1); + SASSERT(m_util.is_float(args[0])); + unsigned ebits = f->get_domain()[0]->get_parameter(0).get_int(); + unsigned sbits = f->get_domain()[0]->get_parameter(1).get_int(); - if (m_hi_fp_unspecified) { - result = m_bv_util.mk_concat(m_bv_util.mk_concat( - m_bv_util.mk_numeral(0, 1), - m_bv_util.mk_numeral(-1, ebits)), - m_bv_util.mk_numeral(1, sbits-1)); - } + if (m_hi_fp_unspecified) + mk_nan(f->get_range(), result); else { - func_decl * fd; - if (m_uf2bvuf.find(f, fd)) - result = m.mk_const(fd); - else { - fd = m.mk_fresh_func_decl(0, 0, 0, f->get_range()); - m_uf2bvuf.insert(f, fd); - m.inc_ref(f); - m.inc_ref(fd); - result = m.mk_const(fd); + expr * n = args[0]; + expr_ref n_bv(m); + join_fp(n, n_bv); - expr_ref exp_bv(m), exp_all_ones(m); - exp_bv = m_bv_util.mk_extract(ebits+sbits-2, sbits-1, result); - exp_all_ones = m.mk_eq(exp_bv, m_bv_util.mk_numeral(-1, ebits)); - m_extra_assertions.push_back(exp_all_ones); + sort * domain[1] = { m.get_sort(n_bv) }; + func_decl * f_bv = mk_bv_uf(f, domain, f->get_range()); + result = m.mk_app(f_bv, n_bv); - expr_ref sig_bv(m), sig_is_non_zero(m); - sig_bv = m_bv_util.mk_extract(sbits-2, 0, result); - sig_is_non_zero = m.mk_not(m.mk_eq(sig_bv, m_bv_util.mk_numeral(0, sbits-1))); - m_extra_assertions.push_back(sig_is_non_zero); - } + expr_ref exp_bv(m), exp_all_ones(m); + exp_bv = m_bv_util.mk_extract(ebits+sbits-2, sbits-1, result); + exp_all_ones = m.mk_eq(exp_bv, m_bv_util.mk_numeral(-1, ebits)); + m_extra_assertions.push_back(exp_all_ones); + + expr_ref sig_bv(m), sig_is_non_zero(m); + sig_bv = m_bv_util.mk_extract(sbits-2, 0, result); + sig_is_non_zero = m.mk_not(m.mk_eq(sig_bv, m_bv_util.mk_numeral(0, sbits-1))); + m_extra_assertions.push_back(sig_is_non_zero); } TRACE("fpa2bv_to_ieee_bv_unspecified", tout << "result=" << mk_ismt2_pp(result, m) << std::endl;); @@ -3238,18 +3155,13 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args mk_is_nzero(x, x_is_nzero); // NaN, Inf, or negative (except -0) -> unspecified - expr_ref c1(m), v1(m); - if (!is_signed) { - c1 = m.mk_or(x_is_nan, x_is_inf, m.mk_and(x_is_neg, m.mk_not(x_is_nzero))); - v1 = mk_to_ubv_unspecified(ebits, sbits, bv_sz); - } - else { - c1 = m.mk_or(x_is_nan, x_is_inf); - v1 = mk_to_sbv_unspecified(ebits, sbits, bv_sz); - } + expr_ref c1(m), v1(m), unspec_v(m); + c1 = m.mk_or(x_is_nan, x_is_inf); + mk_to_bv_unspecified(f, num, args, unspec_v); + v1 = unspec_v; dbg_decouple("fpa2bv_to_bv_c1", c1); - // +-Zero -> 0 + // +-0 -> 0 expr_ref c2(m), v2(m); c2 = x_is_zero; v2 = m_bv_util.mk_numeral(rational(0), bv_srt); @@ -3270,60 +3182,57 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args SASSERT(m_bv_util.get_bv_size(exp) == ebits); SASSERT(m_bv_util.get_bv_size(lz) == ebits); - unsigned sig_sz = m_bv_util.get_bv_size(sig); - SASSERT(sig_sz == sbits); + unsigned sig_sz = sbits; if (sig_sz < (bv_sz + 3)) - sig = m_bv_util.mk_concat(sig, m_bv_util.mk_numeral(0, bv_sz - sig_sz + 3)); + sig = m_bv_util.mk_concat(sig, m_bv_util.mk_numeral(0, bv_sz-sig_sz+3)); sig_sz = m_bv_util.get_bv_size(sig); SASSERT(sig_sz >= (bv_sz + 3)); - expr_ref exp_m_lz(m), e_m_lz_m_bv_sz(m), shift(m), bv0_e2(m), shift_abs(m), shift_le_0(m); - exp_m_lz = m_bv_util.mk_bv_sub(m_bv_util.mk_sign_extend(2, exp), - m_bv_util.mk_zero_extend(2, lz)); - e_m_lz_m_bv_sz = m_bv_util.mk_bv_sub(exp_m_lz, - m_bv_util.mk_numeral(bv_sz - 1, ebits + 2)); - shift = m_bv_util.mk_bv_neg(e_m_lz_m_bv_sz); - bv0_e2 = m_bv_util.mk_numeral(0, ebits + 2); - shift_le_0 = m_bv_util.mk_sle(shift, bv0_e2); - shift_abs = m.mk_ite(shift_le_0, e_m_lz_m_bv_sz, shift); - SASSERT(m_bv_util.get_bv_size(shift) == ebits + 2); - SASSERT(m_bv_util.get_bv_size(shift_abs) == ebits + 2); - dbg_decouple("fpa2bv_to_bv_shift", shift); - dbg_decouple("fpa2bv_to_bv_shift_abs", shift_abs); - // x is of the form +- [1].[sig][r][g][s] ... and at least bv_sz + 3 long - // [1][ ... sig ... ][r][g][ ... s ...] - // [ ... ubv ... ][r][g][ ... s ... ] - 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); + expr_ref exp_m_lz(m), e_m_lz_m_bv_sz(m), shift(m), is_neg_shift(m), big_sig(m); + exp_m_lz = m_bv_util.mk_bv_sub(m_bv_util.mk_sign_extend(2, exp), + m_bv_util.mk_zero_extend(2, lz)); - expr_ref c_in_limits(m); - if (!is_signed) - c_in_limits = m_bv_util.mk_sle(bv0_e2, shift); - else { - expr_ref one_sle_shift(m), one_eq_shift(m), p2(m), sig_is_p2(m), shift1_and_sig_p2(m); - one_sle_shift = m_bv_util.mk_sle(m_bv_util.mk_numeral(1, ebits + 2), shift); - one_eq_shift = m.mk_eq(m_bv_util.mk_numeral(0, ebits + 2), shift); - p2 = m_bv_util.mk_concat(bv1, m_bv_util.mk_numeral(0, sig_sz-1)); - sig_is_p2 = m.mk_eq(sig, p2); - shift1_and_sig_p2 = m.mk_and(one_eq_shift, sig_is_p2); - c_in_limits = m.mk_or(one_sle_shift, shift1_and_sig_p2); + // big_sig is +- [... bv_sz+2 bits ...].[r][g][ ... sbits-1 ... ] + big_sig = m_bv_util.mk_zero_extend(bv_sz+2, sig); + unsigned big_sig_sz = sig_sz+bv_sz+2; + SASSERT(m_bv_util.get_bv_size(big_sig) == big_sig_sz); + + is_neg_shift = m_bv_util.mk_sle(exp_m_lz, m_bv_util.mk_numeral(0, ebits+2)); + shift = m.mk_ite(is_neg_shift, m_bv_util.mk_bv_neg(exp_m_lz), exp_m_lz); + if (ebits+2 < big_sig_sz) + shift = m_bv_util.mk_zero_extend(big_sig_sz-ebits-2, shift); + else if (ebits+2 > big_sig_sz) { + expr_ref upper(m); + upper = m_bv_util.mk_extract(big_sig_sz, ebits+2, shift); + shift = m_bv_util.mk_extract(ebits+1, 0, shift); + shift = m.mk_ite(m.mk_eq(upper, m_bv_util.mk_numeral(0, m_bv_util.get_bv_size(upper))), + shift, + m_bv_util.mk_numeral(big_sig_sz-1, ebits+2)); } - dbg_decouple("fpa2bv_to_bv_in_limits", c_in_limits); + dbg_decouple("fpa2bv_to_bv_shift_uncapped", shift); + SASSERT(m_bv_util.get_bv_size(shift) == m_bv_util.get_bv_size(big_sig)); + dbg_decouple("fpa2bv_to_bv_big_sig", big_sig); - expr_ref r_shifted_sig(m), l_shifted_sig(m); - r_shifted_sig = m_bv_util.mk_bv_lshr(sig, shift_abs); - l_shifted_sig = m_bv_util.mk_bv_shl(sig, m_bv_util.mk_bv_sub( - m_bv_util.mk_numeral(m_bv_util.get_bv_size(sig), m_bv_util.get_bv_size(sig)), - shift_abs)); - dbg_decouple("fpa2bv_to_bv_r_shifted_sig", r_shifted_sig); - dbg_decouple("fpa2bv_to_bv_l_shifted_sig", l_shifted_sig); + expr_ref shift_limit(m); + shift_limit = m_bv_util.mk_numeral(bv_sz+2, m_bv_util.get_bv_size(shift)); + shift = m.mk_ite(m_bv_util.mk_ule(shift, shift_limit), shift, shift_limit); + dbg_decouple("fpa2bv_to_bv_shift_limit", shift_limit); + dbg_decouple("fpa2bv_to_bv_is_neg_shift", is_neg_shift); + dbg_decouple("fpa2bv_to_bv_shift", shift); - expr_ref last(m), round(m), sticky(m); - last = m_bv_util.mk_extract(sig_sz - bv_sz - 0, sig_sz - bv_sz - 0, r_shifted_sig); - round = m_bv_util.mk_extract(sig_sz - bv_sz - 1, sig_sz - bv_sz - 1, r_shifted_sig); - sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, l_shifted_sig.get()); + expr_ref big_sig_shifted(m), int_part(m), last(m), round(m), stickies(m), sticky(m); + big_sig_shifted = m.mk_ite(is_neg_shift, m_bv_util.mk_bv_lshr(big_sig, shift), + m_bv_util.mk_bv_shl(big_sig, shift)); + int_part = m_bv_util.mk_extract(big_sig_sz-1, big_sig_sz-(bv_sz+3), big_sig_shifted); + SASSERT(m_bv_util.get_bv_size(int_part) == bv_sz+3); + last = m_bv_util.mk_extract(big_sig_sz-(bv_sz+3), big_sig_sz-(bv_sz+3), big_sig_shifted); + round = m_bv_util.mk_extract(big_sig_sz-(bv_sz+4), big_sig_sz-(bv_sz+4), big_sig_shifted); + stickies = m_bv_util.mk_extract(big_sig_sz-(bv_sz+5), 0, big_sig_shifted); + sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, stickies.get()); + dbg_decouple("fpa2bv_to_bv_big_sig_shifted", big_sig_shifted); + dbg_decouple("fpa2bv_to_bv_int_part", int_part); dbg_decouple("fpa2bv_to_bv_last", last); dbg_decouple("fpa2bv_to_bv_round", round); dbg_decouple("fpa2bv_to_bv_sticky", sticky); @@ -3333,33 +3242,31 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args SASSERT(m_bv_util.get_bv_size(rounding_decision) == 1); dbg_decouple("fpa2bv_to_bv_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, r_shifted_sig)); - inc = m_bv_util.mk_zero_extend(1, m_bv_util.mk_zero_extend(bv_sz - 1, rounding_decision)); - pre_rounded = m_bv_util.mk_bv_add(unrounded_sig, inc); + expr_ref inc(m), pre_rounded(m); + inc = m_bv_util.mk_zero_extend(bv_sz+2, rounding_decision); + pre_rounded = m_bv_util.mk_bv_add(int_part, inc); dbg_decouple("fpa2bv_to_bv_inc", inc); dbg_decouple("fpa2bv_to_bv_pre_rounded", pre_rounded); - expr_ref rnd_overflow(m), rnd(m), rnd_has_overflown(m); - rnd_overflow = m_bv_util.mk_extract(bv_sz, bv_sz, pre_rounded); - rnd = m_bv_util.mk_extract(bv_sz - 1, 0, pre_rounded); - rnd_has_overflown = m.mk_eq(rnd_overflow, bv1); - dbg_decouple("fpa2bv_to_bv_rnd_has_overflown", rnd_has_overflown); + pre_rounded = m.mk_ite(x_is_neg, m_bv_util.mk_bv_neg(pre_rounded), pre_rounded); - if (is_signed) { - expr_ref sgn_eq_1(m), neg_rnd(m); - sgn_eq_1 = m.mk_eq(sgn, bv1); - neg_rnd = m_bv_util.mk_bv_neg(rnd); - m_simp.mk_ite(sgn_eq_1, neg_rnd, rnd, rnd); + expr_ref ll(m), ul(m), in_range(m); + if (!is_signed) { + ll = m_bv_util.mk_numeral(0, bv_sz+3); + ul = m_bv_util.mk_zero_extend(3, m_bv_util.mk_numeral(-1, bv_sz)); } + else { + ll = m_bv_util.mk_sign_extend(3, m_bv_util.mk_concat(bv1, m_bv_util.mk_numeral(0, bv_sz-1))); + ul = m_bv_util.mk_zero_extend(4, m_bv_util.mk_numeral(-1, bv_sz-1)); + } + in_range = m.mk_and(m_bv_util.mk_sle(ll, pre_rounded), m_bv_util.mk_sle(pre_rounded, ul)); + dbg_decouple("fpa2bv_to_bv_in_range", in_range); - dbg_decouple("fpa2bv_to_bv_rnd", rnd); + expr_ref rounded(m); + rounded = m_bv_util.mk_extract(bv_sz-1, 0, pre_rounded); + dbg_decouple("fpa2bv_to_bv_rounded", rounded); - expr_ref unspec(m); - unspec = is_signed ? mk_to_sbv_unspecified(ebits, sbits, bv_sz) : - mk_to_ubv_unspecified(ebits, sbits, bv_sz); - result = m.mk_ite(rnd_has_overflown, unspec, rnd); - result = m.mk_ite(c_in_limits, result, unspec); + result = m.mk_ite(m.mk_not(in_range), unspec_v, rounded); result = m.mk_ite(c2, v2, result); result = m.mk_ite(c1, v1, result); @@ -3378,85 +3285,42 @@ void fpa2bv_converter::mk_to_sbv(func_decl * f, unsigned num, expr * const * arg mk_to_bv(f, num, args, true, result); } -void fpa2bv_converter::mk_to_ubv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { - SASSERT(num == 0); - unsigned width = m_bv_util.get_bv_size(f->get_range()); +void fpa2bv_converter::mk_to_bv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { + SASSERT(num == 2); + SASSERT(m_util.is_bv2rm(args[0])); + SASSERT(m_util.is_float(args[1])); if (m_hi_fp_unspecified) - result = m_bv_util.mk_numeral(0, width); + result = m_bv_util.mk_numeral(0, m_bv_util.get_bv_size(f->get_range())); else { - func_decl * fd; - if (!m_uf2bvuf.find(f, fd)) { - fd = m.mk_fresh_func_decl(0, 0, 0, f->get_range()); - m_uf2bvuf.insert(f, fd); - m.inc_ref(f); - m.inc_ref(fd); - } - result = m.mk_const(fd); + expr * rm_bv = to_app(args[0])->get_arg(0); + expr * n = args[1]; + expr_ref n_bv(m); + join_fp(n, n_bv); + + sort * domain[2] = { m.get_sort(rm_bv), m.get_sort(n_bv) }; + func_decl * f_bv = mk_bv_uf(f, domain, f->get_range()); + result = m.mk_app(f_bv, rm_bv, n_bv); } - TRACE("fpa2bv_to_ubv_unspecified", tout << "result=" << mk_ismt2_pp(result, m) << std::endl;); + TRACE("fpa2bv_to_bv_unspecified", tout << "result=" << mk_ismt2_pp(result, m) << std::endl;); SASSERT(is_well_sorted(m, result)); } -expr_ref fpa2bv_converter::mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width) { - expr_ref res(m); - app_ref u(m); - u = m_util.mk_internal_to_ubv_unspecified(ebits, sbits, width); - mk_to_sbv_unspecified(u->get_decl(), 0, 0, res); - return res; -} - -void fpa2bv_converter::mk_to_sbv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { - SASSERT(num == 0); - unsigned width = m_bv_util.get_bv_size(f->get_range()); - - if (m_hi_fp_unspecified) - result = m_bv_util.mk_numeral(0, width); - else { - func_decl * fd; - if (!m_uf2bvuf.find(f, fd)) { - fd = m.mk_fresh_func_decl(0, 0, 0, f->get_range()); - m_uf2bvuf.insert(f, fd); - m.inc_ref(f); - m.inc_ref(fd); - } - result = m.mk_const(fd); - } - - TRACE("fpa2bv_to_sbv_unspecified", tout << "result=" << mk_ismt2_pp(result, m) << std::endl;); - SASSERT(is_well_sorted(m, result)); -} - -expr_ref fpa2bv_converter::mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width) { - expr_ref res(m); - app_ref u(m); - u = m_util.mk_internal_to_sbv_unspecified(ebits, sbits, width); - mk_to_sbv_unspecified(u->get_decl(), 0, 0, res); - return res; -} - void fpa2bv_converter::mk_to_real_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { + SASSERT(num == 1); + if (m_hi_fp_unspecified) result = m_arith_util.mk_numeral(rational(0), false); else { - func_decl * fd; - if (!m_uf2bvuf.find(f, fd)) { - fd = m.mk_fresh_func_decl(0, 0, 0, f->get_range()); - m_uf2bvuf.insert(f, fd); - m.inc_ref(f); - m.inc_ref(fd); - } - result = m.mk_const(fd); - } -} + expr * n = args[0]; + expr_ref n_bv(m); + join_fp(n, n_bv); -expr_ref fpa2bv_converter::mk_to_real_unspecified(unsigned ebits, unsigned sbits) { - expr_ref res(m); - app_ref u(m); - u = m_util.mk_internal_to_real_unspecified(ebits, sbits); - mk_to_real_unspecified(u->get_decl(), 0, 0, res); - return res; + sort * domain[1] = { m.get_sort(n_bv) }; + func_decl * f_bv = mk_bv_uf(f, domain, f->get_range()); + result = m.mk_app(f_bv, n_bv); + } } void fpa2bv_converter::mk_fp(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { @@ -3467,6 +3331,7 @@ void fpa2bv_converter::mk_fp(func_decl * f, unsigned num, expr * const * args, e result = m_util.mk_fp(args[0], args[1], args[2]); TRACE("fpa2bv_mk_fp", tout << "mk_fp result = " << mk_ismt2_pp(result, m) << std::endl;); } + void fpa2bv_converter::split_fp(expr * e, expr * & sgn, expr * & exp, expr * & sig) const { SASSERT(m_util.is_fp(e)); SASSERT(to_app(e)->get_num_args() == 3); @@ -3485,6 +3350,14 @@ void fpa2bv_converter::split_fp(expr * e, expr_ref & sgn, expr_ref & exp, expr_r sig = e_sig; } +void fpa2bv_converter::join_fp(expr * e, expr_ref & res) { + SASSERT(m_util.is_fp(e)); + SASSERT(to_app(e)->get_num_args() == 3); + expr *sgn, *exp, *sig; + split_fp(e, sgn, exp, sig); + res = m_bv_util.mk_concat(m_bv_util.mk_concat(sgn, exp), sig); +} + void fpa2bv_converter::mk_is_nan(expr * e, expr_ref & result) { expr * sgn, * sig, * exp; split_fp(e, sgn, exp, sig); @@ -4051,7 +3924,7 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & // put the sticky bit into the significand. expr_ref ext_sticky(m); ext_sticky = m_bv_util.mk_zero_extend(sbits+1, sticky); - expr * tmp[] = { sig, ext_sticky }; + expr * tmp[2] = { sig, ext_sticky }; sig = m_bv_util.mk_bv_or(2, tmp); SASSERT(is_well_sorted(m, sig)); SASSERT(m_bv_util.get_bv_size(sig) == sbits+2); @@ -4221,13 +4094,25 @@ void fpa2bv_converter::reset(void) { dec_ref_map_key_values(m, m_const2bv); dec_ref_map_key_values(m, m_rm_const2bv); dec_ref_map_key_values(m, m_uf2bvuf); - for (obj_map >::iterator it = m_min_max_specials.begin(); - it != m_min_max_specials.end(); + for (obj_map >::iterator it = m_min_max_ufs.begin(); + it != m_min_max_ufs.end(); it++) { m.dec_ref(it->m_key); m.dec_ref(it->m_value.first); m.dec_ref(it->m_value.second); } - m_min_max_specials.reset(); + m_min_max_ufs.reset(); m_extra_assertions.reset(); } + +func_decl * fpa2bv_converter::mk_bv_uf(func_decl * f, sort * const * domain, sort * range) { + func_decl * res; + if (!m_uf2bvuf.find(f, res)) { + res = m.mk_fresh_func_decl(0, f->get_arity(), domain, range); + m_uf2bvuf.insert(f, res); + m.inc_ref(f); + m.inc_ref(res); + TRACE("fpa2bv", tout << "New UF func_decl: " << std::endl << mk_ismt2_pp(res, m) << std::endl;); + } + return res; +} diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index 1e3e5d9b3..f0e50ba2d 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -53,7 +53,7 @@ protected: const2bv_t m_const2bv; const2bv_t m_rm_const2bv; uf2bvuf_t m_uf2bvuf; - special_t m_min_max_specials; + special_t m_min_max_ufs; friend class fpa2bv_model_converter; friend class bv2fpa_converter; @@ -76,6 +76,7 @@ public: void split_fp(expr * e, expr * & sgn, expr * & exp, expr * & sig) const; void split_fp(expr * e, expr_ref & sgn, expr_ref & exp, expr_ref & sig) const; + void join_fp(expr * e, expr_ref & res); void mk_eq(expr * a, expr * b, expr_ref & result); void mk_ite(expr * c, expr * t, expr * f, expr_ref & result); @@ -86,7 +87,7 @@ public: void mk_numeral(sort * s, mpf const & v, expr_ref & result); virtual void mk_const(func_decl * f, expr_ref & result); virtual void mk_rm_const(func_decl * f, expr_ref & result); - virtual void mk_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + virtual void mk_uf(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_var(unsigned base_inx, sort * srt, expr_ref & result); void mk_pinf(func_decl * f, expr_ref & result); @@ -138,27 +139,23 @@ public: void mk_to_fp_real_int(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_to_ubv(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - void mk_to_ubv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_to_sbv(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - void mk_to_sbv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + void mk_to_bv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_to_real(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_to_real_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void set_unspecified_fp_hi(bool v) { m_hi_fp_unspecified = v; } void mk_min(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - void mk_min_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - virtual expr_ref mk_min_max_unspecified(func_decl * f, expr * x, expr * y); - void mk_max(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - void mk_max_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + expr_ref mk_min_max_unspecified(func_decl * f, expr * x, expr * y); void reset(void); void dbg_decouple(const char * prefix, expr_ref & e); expr_ref_vector m_extra_assertions; - special_t const & get_min_max_specials() const { return m_min_max_specials; }; + special_t const & get_min_max_specials() const { return m_min_max_ufs; }; const2bv_t const & get_const2bv() const { return m_const2bv; }; const2bv_t const & get_rm_const2bv() const { return m_rm_const2bv; }; uf2bvuf_t const & get_uf2bvuf() const { return m_uf2bvuf; }; @@ -202,12 +199,6 @@ protected: void mk_to_bv(func_decl * f, unsigned num, expr * const * args, bool is_signed, expr_ref & result); - sort_ref replace_float_sorts(sort * s); - func_decl_ref replace_function(func_decl * f); - expr_ref replace_float_arg(expr * a); - void mk_function_output(sort * rng, func_decl * fbv, expr * const * new_args, expr_ref & result); - func_decl * get_bv_uf(func_decl * f, sort * bv_rng, unsigned arity); - private: void mk_nan(sort * s, expr_ref & result); void mk_nzero(sort * s, expr_ref & result); @@ -227,9 +218,7 @@ private: void mk_to_fp_float(sort * s, expr * rm, expr * x, expr_ref & result); - expr_ref mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width); - expr_ref mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width); - expr_ref mk_to_real_unspecified(unsigned ebits, unsigned sbits); + func_decl * mk_bv_uf(func_decl * f, sort * const * domain, sort * range); }; #endif diff --git a/src/ast/fpa/fpa2bv_rewriter.cpp b/src/ast/fpa/fpa2bv_rewriter.cpp index 0e3899c53..6c96d92c1 100644 --- a/src/ast/fpa/fpa2bv_rewriter.cpp +++ b/src/ast/fpa/fpa2bv_rewriter.cpp @@ -124,6 +124,8 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co case OP_FPA_DIV: m_conv.mk_div(f, num, args, result); return BR_DONE; case OP_FPA_REM: m_conv.mk_rem(f, num, args, result); return BR_DONE; case OP_FPA_ABS: m_conv.mk_abs(f, num, args, result); return BR_DONE; + case OP_FPA_MIN: m_conv.mk_min(f, num, args, result); return BR_DONE; + case OP_FPA_MAX: m_conv.mk_max(f, num, args, result); return BR_DONE; case OP_FPA_FMA: m_conv.mk_fma(f, num, args, result); return BR_DONE; case OP_FPA_SQRT: m_conv.mk_sqrt(f, num, args, result); return BR_DONE; case OP_FPA_ROUND_TO_INTEGRAL: m_conv.mk_round_to_integral(f, num, args, result); return BR_DONE; @@ -143,24 +145,12 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co 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_INTERNAL_TO_UBV_UNSPECIFIED: m_conv.mk_to_ubv_unspecified(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_INTERNAL_TO_SBV_UNSPECIFIED: m_conv.mk_to_sbv_unspecified(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_INTERNAL_TO_REAL_UNSPECIFIED: m_conv.mk_to_real_unspecified(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_TO_IEEE_BV_UNSPECIFIED: m_conv.mk_to_ieee_bv_unspecified(f, num, args, result); return BR_DONE; - case OP_FPA_MIN: m_conv.mk_min(f, num, args, result); return BR_REWRITE_FULL; - case OP_FPA_MAX: m_conv.mk_max(f, num, args, result); return BR_REWRITE_FULL; - - case OP_FPA_INTERNAL_MIN_UNSPECIFIED: - case OP_FPA_INTERNAL_MAX_UNSPECIFIED: result = m_conv.mk_min_max_unspecified(f, args[0], args[1]); return BR_DONE; - case OP_FPA_INTERNAL_MIN_I: m_conv.mk_min_i(f, num, args, result); return BR_DONE; - case OP_FPA_INTERNAL_MAX_I: m_conv.mk_max_i(f, num, args, result); return BR_DONE; - - case OP_FPA_INTERNAL_BVWRAP: - case OP_FPA_INTERNAL_BV2RM: + case OP_FPA_BVWRAP: + case OP_FPA_BV2RM: return BR_FAILED; default: @@ -173,7 +163,7 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co { SASSERT(!m_conv.is_float_family(f)); if (m_conv.fu().contains_floats(f)) { - m_conv.mk_function(f, num, args, result); + m_conv.mk_uf(f, num, args, result); return BR_DONE; } } diff --git a/src/ast/fpa_decl_plugin.cpp b/src/ast/fpa_decl_plugin.cpp index fc69c5f89..9d298b413 100644 --- a/src/ast/fpa_decl_plugin.cpp +++ b/src/ast/fpa_decl_plugin.cpp @@ -361,10 +361,6 @@ func_decl * fpa_decl_plugin::mk_binary_decl(decl_kind k, unsigned num_parameters case OP_FPA_REM: name = "fp.rem"; break; case OP_FPA_MIN: name = "fp.min"; break; case OP_FPA_MAX: name = "fp.max"; break; - case OP_FPA_INTERNAL_MIN_I: name = "fp.min_i"; break; - case OP_FPA_INTERNAL_MAX_I: name = "fp.max_i"; break; - case OP_FPA_INTERNAL_MIN_UNSPECIFIED: name = "fp.min_unspecified"; break; - case OP_FPA_INTERNAL_MAX_UNSPECIFIED: name = "fp.max_unspecified"; break; default: UNREACHABLE(); break; @@ -676,10 +672,10 @@ func_decl * fpa_decl_plugin::mk_to_ieee_bv(decl_kind k, unsigned num_parameters, return m_manager->mk_func_decl(name, 1, domain, bv_srt, func_decl_info(m_family_id, k)); } -func_decl * fpa_decl_plugin::mk_internal_bv2rm(decl_kind k, unsigned num_parameters, parameter const * parameters, +func_decl * fpa_decl_plugin::mk_bv2rm(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { if (arity != 1) - m_manager->raise_exception("invalid number of arguments to internal_rm"); + m_manager->raise_exception("invalid number of arguments to bv2rm"); if (!is_sort_of(domain[0], m_bv_fid, BV_SORT) || domain[0]->get_parameter(0).get_int() != 3) m_manager->raise_exception("sort mismatch, expected argument of sort bitvector, size 3"); if (!is_rm_sort(range)) @@ -690,7 +686,7 @@ func_decl * fpa_decl_plugin::mk_internal_bv2rm(decl_kind k, unsigned num_paramet return m_manager->mk_func_decl(symbol("rm"), 1, &bv_srt, range, func_decl_info(m_family_id, k, num_parameters, parameters)); } -func_decl * fpa_decl_plugin::mk_internal_bv_wrap(decl_kind k, unsigned num_parameters, parameter const * parameters, +func_decl * fpa_decl_plugin::mk_bv_wrap(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { if (arity != 1) m_manager->raise_exception("invalid number of arguments to bv_wrap"); @@ -711,65 +707,6 @@ func_decl * fpa_decl_plugin::mk_internal_bv_wrap(decl_kind k, unsigned num_param } } -func_decl * fpa_decl_plugin::mk_internal_to_ubv_unspecified( - decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range) { - if (arity != 0) - m_manager->raise_exception("invalid number of arguments to fp.to_ubv_unspecified"); - if (num_parameters != 3) - m_manager->raise_exception("invalid number of parameters to fp.to_ubv_unspecified; expecting 3"); - if (!parameters[0].is_int() || !parameters[1].is_int() || !parameters[2].is_int()) - m_manager->raise_exception("invalid parameters type provided to fp.to_ubv_unspecified; expecting 3 integers"); - - sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, ¶meters[2]); - return m_manager->mk_func_decl(symbol("fp.to_ubv_unspecified"), 0, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters)); -} - -func_decl * fpa_decl_plugin::mk_internal_to_sbv_unspecified( - decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range) { - if (arity != 0) - m_manager->raise_exception("invalid number of arguments to fp.to_sbv_unspecified"); - if (num_parameters != 3) - m_manager->raise_exception("invalid number of parameters to fp.to_sbv_unspecified; expecting 3"); - if (!parameters[0].is_int() || !parameters[1].is_int() || !parameters[2].is_int()) - m_manager->raise_exception("invalid parameters type provided to fp.to_sbv_unspecified; expecting 3 integers"); - - sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, ¶meters[2]); - return m_manager->mk_func_decl(symbol("fp.to_sbv_unspecified"), 0, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters)); -} - -func_decl * fpa_decl_plugin::mk_internal_to_real_unspecified( - decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range) { - if (arity != 0) - m_manager->raise_exception("invalid number of arguments to fp.to_real_unspecified"); - if (num_parameters != 2) - m_manager->raise_exception("invalid number of parameters to fp.to_real_unspecified; expecting 2"); - if (!parameters[0].is_int() || !parameters[1].is_int()) - m_manager->raise_exception("invalid parameters type provided to fp.to_real_unspecified; expecting 2 integers"); - if (!is_sort_of(range, m_arith_fid, REAL_SORT)) - m_manager->raise_exception("sort mismatch, expected range of Real sort"); - - return m_manager->mk_func_decl(symbol("fp.to_real_unspecified"), 0, domain, m_real_sort, func_decl_info(m_family_id, k, num_parameters, parameters)); -} - -func_decl * fpa_decl_plugin::mk_internal_to_ieee_bv_unspecified( - decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range) { - if (arity != 0) - m_manager->raise_exception("invalid number of arguments to fp.to_ieee_bv_unspecified; expecting none"); - if (num_parameters != 2) - m_manager->raise_exception("invalid number of parameters to fp.to_ieee_bv_unspecified; expecting 2"); - if (!parameters[0].is_int() || !parameters[1].is_int()) - m_manager->raise_exception("invalid parameters type provided to fp.to_ieee_bv_unspecified; expecting 2 integers"); - - parameter width_p[1] = { parameter(parameters[0].get_int() + parameters[1].get_int()) }; - sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, width_p); - return m_manager->mk_func_decl(symbol("fp.to_ieee_bv_unspecified"), 0, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters)); -} - - func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { switch (k) { @@ -835,25 +772,11 @@ func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, case OP_FPA_TO_IEEE_BV: return mk_to_ieee_bv(k, num_parameters, parameters, arity, domain, range); - case OP_FPA_INTERNAL_BVWRAP: - return mk_internal_bv_wrap(k, num_parameters, parameters, arity, domain, range); - case OP_FPA_INTERNAL_BV2RM: - return mk_internal_bv2rm(k, num_parameters, parameters, arity, domain, range); + case OP_FPA_BVWRAP: + return mk_bv_wrap(k, num_parameters, parameters, arity, domain, range); + case OP_FPA_BV2RM: + return mk_bv2rm(k, num_parameters, parameters, arity, domain, range); - case OP_FPA_INTERNAL_MIN_I: - case OP_FPA_INTERNAL_MAX_I: - case OP_FPA_INTERNAL_MIN_UNSPECIFIED: - case OP_FPA_INTERNAL_MAX_UNSPECIFIED: - return mk_binary_decl(k, num_parameters, parameters, arity, domain, range); - - case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED: - return mk_internal_to_ubv_unspecified(k, num_parameters, parameters, arity, domain, range); - case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED: - return mk_internal_to_sbv_unspecified(k, num_parameters, parameters, arity, domain, range); - case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED: - return mk_internal_to_real_unspecified(k, num_parameters, parameters, arity, domain, range); - case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED: - return mk_internal_to_ieee_bv_unspecified(k, num_parameters, parameters, arity, domain, range); default: m_manager->raise_exception("unsupported floating point operator"); return 0; @@ -1054,30 +977,6 @@ app * fpa_util::mk_nzero(unsigned ebits, unsigned sbits) { return mk_value(v); } -app * fpa_util::mk_internal_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width) { - parameter ps[] = { parameter(ebits), parameter(sbits), parameter(width) }; - sort * range = m_bv_util.mk_sort(width); - return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED, 3, ps, 0, 0, range); -} - -app * fpa_util::mk_internal_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width) { - parameter ps[] = { parameter(ebits), parameter(sbits), parameter(width) }; - sort * range = m_bv_util.mk_sort(width); - return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED, 3, ps, 0, 0, range); -} - -app * fpa_util::mk_internal_to_ieee_bv_unspecified(unsigned ebits, unsigned sbits) { - parameter ps[] = { parameter(ebits), parameter(sbits) }; - sort * range = m_bv_util.mk_sort(ebits+sbits); - return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED, 2, ps, 0, 0, range); -} - -app * fpa_util::mk_internal_to_real_unspecified(unsigned ebits, unsigned sbits) { - parameter ps[] = { parameter(ebits), parameter(sbits) }; - sort * range = m_a_util.mk_real(); - return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED, 2, ps, 0, 0, range); -} - bool fpa_util::contains_floats(ast * a) { switch (a->get_kind()) { case AST_APP: { diff --git a/src/ast/fpa_decl_plugin.h b/src/ast/fpa_decl_plugin.h index 0cba3ae62..4e86c9d3f 100644 --- a/src/ast/fpa_decl_plugin.h +++ b/src/ast/fpa_decl_plugin.h @@ -86,18 +86,8 @@ enum fpa_op_kind { /* Extensions */ OP_FPA_TO_IEEE_BV, - /* Internal use only */ - OP_FPA_INTERNAL_BVWRAP, - OP_FPA_INTERNAL_BV2RM, - - OP_FPA_INTERNAL_MIN_I, - OP_FPA_INTERNAL_MAX_I, - OP_FPA_INTERNAL_MIN_UNSPECIFIED, - OP_FPA_INTERNAL_MAX_UNSPECIFIED, - OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED, - OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED, - OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED, - OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED, + OP_FPA_BVWRAP, + OP_FPA_BV2RM, LAST_FLOAT_OP }; @@ -164,40 +154,16 @@ class fpa_decl_plugin : public decl_plugin { func_decl * mk_to_ieee_bv(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range); - func_decl * mk_internal_bv2rm(decl_kind k, unsigned num_parameters, parameter const * parameters, + func_decl * mk_bv2rm(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range); - func_decl * mk_internal_bv_wrap(decl_kind k, unsigned num_parameters, parameter const * parameters, + func_decl * mk_bv_wrap(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range); - func_decl * mk_internal_bv_unwrap(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); - func_decl * mk_internal_to_ubv_unspecified(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); - func_decl * mk_internal_to_sbv_unspecified(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); - func_decl * mk_internal_to_real_unspecified(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); - func_decl * mk_internal_to_ieee_bv_unspecified(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); virtual void set_manager(ast_manager * m, family_id id); unsigned mk_id(mpf const & v); void recycled_id(unsigned id); - virtual bool is_considered_uninterpreted(func_decl * f) { - if (f->get_family_id() != get_family_id()) - return false; - switch (f->get_decl_kind()) - { - case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED: - case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED: - case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED: - case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED: - return true; - default: - return false; - } - return false; - } + virtual bool is_considered_uninterpreted(func_decl * f) { return false; } public: fpa_decl_plugin(); @@ -251,6 +217,7 @@ public: family_id get_fid() const { return m_fid; } family_id get_family_id() const { return m_fid; } arith_util & au() { return m_a_util; } + bv_util & bu() { return m_bv_util; } fpa_decl_plugin & plugin() { return *m_plugin; } sort * mk_float_sort(unsigned ebits, unsigned sbits); @@ -375,35 +342,18 @@ public: app * mk_bv2rm(expr * bv3) { SASSERT(m_bv_util.is_bv(bv3) && m_bv_util.get_bv_size(bv3) == 3); - return m().mk_app(m_fid, OP_FPA_INTERNAL_BV2RM, 0, 0, 1, &bv3, mk_rm_sort()); + return m().mk_app(m_fid, OP_FPA_BV2RM, 0, 0, 1, &bv3, mk_rm_sort()); } - app * mk_internal_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width); - app * mk_internal_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width); - app * mk_internal_to_ieee_bv_unspecified(unsigned ebits, unsigned sbits); - app * mk_internal_to_real_unspecified(unsigned ebits, unsigned sbits); - bool is_bvwrap(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_BVWRAP); } - bool is_bvwrap(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_BVWRAP; } - bool is_bv2rm(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_BV2RM); } - bool is_bv2rm(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_BV2RM; } + bool is_bvwrap(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_BVWRAP); } + bool is_bv2rm(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_BV2RM); } + bool is_to_ubv(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_TO_UBV); } + bool is_to_sbv(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_TO_SBV); } - bool is_min_interpreted(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MIN_I); } - bool is_min_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MIN_UNSPECIFIED); } - bool is_max_interpreted(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MAX_I); } - bool is_max_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MAX_UNSPECIFIED); } - bool is_to_ubv_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED); } - bool is_to_sbv_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED); } - bool is_to_ieee_bv_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED); } - bool is_to_real_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED); } - - bool is_min_interpreted(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MIN_I; } - bool is_min_unspecified(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MIN_UNSPECIFIED; } - bool is_max_interpreted(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MAX_I; } - bool is_max_unspecified(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MAX_UNSPECIFIED; } - bool is_to_ubv_unspecified(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED; } - bool is_to_sbv_unspecified(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED; } - bool is_to_ieee_bv_unspecified(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED; } - bool is_to_real_unspecified(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED; } + bool is_bvwrap(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_BVWRAP; } + bool is_bv2rm(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_BV2RM; } + bool is_to_ubv(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_TO_UBV; } + bool is_to_sbv(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_TO_SBV; } bool contains_floats(ast * a); }; diff --git a/src/ast/normal_forms/pull_quant.cpp b/src/ast/normal_forms/pull_quant.cpp index 56bada7c1..239fd9008 100644 --- a/src/ast/normal_forms/pull_quant.cpp +++ b/src/ast/normal_forms/pull_quant.cpp @@ -244,7 +244,7 @@ struct pull_quant::imp { quantifier * q1 = m_manager.update_quantifier(to_quantifier(n), new_expr); proof * p1 = 0; if (n != q1) { - proof * p0 = m_manager.mk_pull_quant(to_quantifier(n)->get_expr(), to_quantifier(new_expr)); + proof * p0 = m_manager.mk_pull_quant(n, to_quantifier(new_expr)); p1 = m_manager.mk_quant_intro(to_quantifier(n), q1, p0); } proof * p2 = q1 == r ? 0 : m_manager.mk_pull_quant(q1, to_quantifier(r)); diff --git a/src/ast/rewriter/arith_rewriter.h b/src/ast/rewriter/arith_rewriter.h index 9b12875d5..65fbfb43f 100644 --- a/src/ast/rewriter/arith_rewriter.h +++ b/src/ast/rewriter/arith_rewriter.h @@ -56,7 +56,6 @@ class arith_rewriter : public poly_rewriter { bool m_anum_simp; bool m_elim_rem; bool m_eq2ineq; - bool m_process_all_eqs; unsigned m_max_degree; void get_coeffs_gcd(expr * t, numeral & g, bool & first, unsigned & num_consts); diff --git a/src/ast/rewriter/array_rewriter_params.pyg b/src/ast/rewriter/array_rewriter_params.pyg index a43fadecf..3b4af7fb7 100644 --- a/src/ast/rewriter/array_rewriter_params.pyg +++ b/src/ast/rewriter/array_rewriter_params.pyg @@ -2,5 +2,5 @@ def_module_params(module_name='rewriter', class_name='array_rewriter_params', export=True, params=(("expand_select_store", BOOL, False, "replace a (select (store ...) ...) term by an if-then-else term"), - ("expand_store_eq", BOOL, False, "reduce (store ...) = (store ...) with a common base into selects"), + ("expand_store_eq", BOOL, False, "reduce (store ...) = (store ...) with a common base into selects"), ("sort_store", BOOL, False, "sort nested stores when the indices are known to be different"))) diff --git a/src/ast/rewriter/bit2int.h b/src/ast/rewriter/bit2int.h index fe15d1ec5..fbbf2e6d1 100644 --- a/src/ast/rewriter/bit2int.h +++ b/src/ast/rewriter/bit2int.h @@ -75,7 +75,7 @@ protected: bool mk_mul(expr* a, expr* b, expr_ref& result); bool mk_comp(eq_type ty, expr* e1, expr* e2, expr_ref& result); bool mk_add(expr* e1, expr* e2, expr_ref& result); - + expr * get_cached(expr * n) const; bool is_cached(expr * n) const { return get_cached(n) != 0; } void cache_result(expr * n, expr * r); diff --git a/src/ast/rewriter/bv_bounds.h b/src/ast/rewriter/bv_bounds.h index 3d8ec9ebb..4a7226fa7 100644 --- a/src/ast/rewriter/bv_bounds.h +++ b/src/ast/rewriter/bv_bounds.h @@ -38,7 +38,7 @@ public: bv_bounds(ast_manager& m) : m_m(m), m_bv_util(m), m_okay(true) {}; ~bv_bounds(); public: // bounds addition methods - br_status rewrite(unsigned limit, func_decl * f, unsigned num, expr * const * args, expr_ref& result); + br_status rewrite(unsigned limit, func_decl * f, unsigned num, expr * const * args, expr_ref& result); /** \brief Add a constraint to the system. @@ -82,7 +82,7 @@ protected: bv_util m_bv_util; bool m_okay; bool is_sat(app * v); - bool is_sat_core(app * v); +bool is_sat_core(app * v); inline bool in_range(app *v, numeral l); inline bool is_constant_add(unsigned bv_sz, expr * e, app*& v, numeral& val); void record_singleton(app * v, numeral& singleton_value); @@ -94,7 +94,7 @@ protected: inline bool bv_bounds::is_okay() { return m_okay; } inline bool bv_bounds::to_bound(const expr * e) const { - return is_app(e) && m_bv_util.is_bv(e) + return is_app(e) && m_bv_util.is_bv(e) && !m_bv_util.is_bv_add(e) && !m_bv_util.is_numeral(e); } diff --git a/src/ast/rewriter/fpa_rewriter.cpp b/src/ast/rewriter/fpa_rewriter.cpp index 563437b99..818336c75 100644 --- a/src/ast/rewriter/fpa_rewriter.cpp +++ b/src/ast/rewriter/fpa_rewriter.cpp @@ -94,21 +94,8 @@ br_status fpa_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con case OP_FPA_TO_IEEE_BV: SASSERT(num_args == 1); st = mk_to_ieee_bv(f, args[0], result); break; case OP_FPA_TO_REAL: SASSERT(num_args == 1); st = mk_to_real(args[0], result); break; - case OP_FPA_INTERNAL_MIN_I: - case OP_FPA_INTERNAL_MAX_I: - case OP_FPA_INTERNAL_MIN_UNSPECIFIED: - case OP_FPA_INTERNAL_MAX_UNSPECIFIED: - SASSERT(num_args == 2); st = BR_FAILED; break; - - case OP_FPA_INTERNAL_BVWRAP: SASSERT(num_args == 1); st = mk_bvwrap(args[0], result); break; - case OP_FPA_INTERNAL_BV2RM: SASSERT(num_args == 1); st = mk_bv2rm(args[0], result); break; - - case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED: - case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED: - case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED: - case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED: - st = BR_FAILED; - break; + case OP_FPA_BVWRAP: SASSERT(num_args == 1); st = mk_bvwrap(args[0], result); break; + case OP_FPA_BV2RM: SASSERT(num_args == 1); st = mk_bv2rm(args[0], result); break; default: NOT_IMPLEMENTED_YET(); @@ -116,49 +103,10 @@ br_status fpa_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con return st; } -br_status fpa_rewriter::mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width, expr_ref & result) { - bv_util bu(m()); - if (m_hi_fp_unspecified) { - // The "hardware interpretation" is 0. - result = bu.mk_numeral(0, width); - return BR_DONE; - } - else { - result = m_util.mk_internal_to_ubv_unspecified(ebits, sbits, width); - return BR_REWRITE1; - } -} - -br_status fpa_rewriter::mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width, expr_ref & result) { - bv_util bu(m()); - if (m_hi_fp_unspecified) { - // The "hardware interpretation" is 0. - result = bu.mk_numeral(0, width); - return BR_DONE; - } - else { - result = m_util.mk_internal_to_sbv_unspecified(ebits, sbits, width); - return BR_REWRITE1; - } -} - -br_status fpa_rewriter::mk_to_real_unspecified(unsigned ebits, unsigned sbits, expr_ref & result) { - if (m_hi_fp_unspecified) { - // The "hardware interpretation" is 0. - result = m_util.au().mk_numeral(rational(0), false); - return BR_DONE; - } - else { - result = m_util.mk_internal_to_real_unspecified(ebits, sbits); - return BR_REWRITE1; - } -} - br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { SASSERT(f->get_num_parameters() == 2); SASSERT(f->get_parameter(0).is_int()); SASSERT(f->get_parameter(1).is_int()); - bv_util bu(m()); scoped_mpf v(m_fm); mpf_rounding_mode rmv; rational r1, r2, r3; @@ -167,7 +115,7 @@ br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const unsigned sbits = f->get_parameter(1).get_int(); if (num_args == 1) { - if (bu.is_numeral(args[0], r1, bvs1)) { + if (m_util.bu().is_numeral(args[0], r1, bvs1)) { // BV -> float SASSERT(bvs1 == sbits + ebits); unsynch_mpz_manager & mpzm = m_fm.mpz_manager(); @@ -226,10 +174,10 @@ br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const // TRACE("fp_rewriter", tout << "result: " << result << std::endl; ); return BR_DONE; } - else if (bu.is_numeral(args[1], r1, bvs1)) { + else if (m_util.bu().is_numeral(args[1], r1, bvs1)) { // rm + signed bv -> float TRACE("fp_rewriter", tout << "r1: " << r1 << std::endl;); - r1 = bu.norm(r1, bvs1, true); + r1 = m_util.bu().norm(r1, bvs1, true); TRACE("fp_rewriter", tout << "r1 norm: " << r1 << std::endl;); m_fm.set(v, ebits, sbits, rmv, r1.to_mpq()); result = m_util.mk_value(v); @@ -265,9 +213,9 @@ br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const result = m_util.mk_value(v); return BR_DONE; } - else if (bu.is_numeral(args[0], r1, bvs1) && - bu.is_numeral(args[1], r2, bvs2) && - bu.is_numeral(args[2], r3, bvs3)) { + else if (m_util.bu().is_numeral(args[0], r1, bvs1) && + m_util.bu().is_numeral(args[1], r2, bvs2) && + m_util.bu().is_numeral(args[2], r3, bvs3)) { // 3 BV -> float SASSERT(m_fm.mpz_manager().is_one(r2.to_mpq().denominator())); SASSERT(m_fm.mpz_manager().is_one(r3.to_mpq().denominator())); @@ -290,7 +238,6 @@ br_status fpa_rewriter::mk_to_fp_unsigned(func_decl * f, expr * arg1, expr * arg SASSERT(f->get_num_parameters() == 2); SASSERT(f->get_parameter(0).is_int()); SASSERT(f->get_parameter(1).is_int()); - bv_util bu(m()); unsigned ebits = f->get_parameter(0).get_int(); unsigned sbits = f->get_parameter(1).get_int(); mpf_rounding_mode rmv; @@ -298,7 +245,7 @@ br_status fpa_rewriter::mk_to_fp_unsigned(func_decl * f, expr * arg1, expr * arg unsigned bvs; if (m_util.is_rm_numeral(arg1, rmv) && - bu.is_numeral(arg2, r, bvs)) { + m_util.bu().is_numeral(arg2, r, bvs)) { scoped_mpf v(m_fm); m_fm.set(v, ebits, sbits, rmv, r.to_mpq()); result = m_util.mk_value(v); @@ -331,6 +278,7 @@ br_status fpa_rewriter::mk_sub(expr * arg1, expr * arg2, expr * arg3, expr_ref & br_status fpa_rewriter::mk_mul(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) { mpf_rounding_mode rm; + if (m_util.is_rm_numeral(arg1, rm)) { scoped_mpf v2(m_fm), v3(m_fm); if (m_util.is_numeral(arg2, v2) && m_util.is_numeral(arg3, v3)) { @@ -346,6 +294,7 @@ br_status fpa_rewriter::mk_mul(expr * arg1, expr * arg2, expr * arg3, expr_ref & br_status fpa_rewriter::mk_div(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) { mpf_rounding_mode rm; + if (m_util.is_rm_numeral(arg1, rm)) { scoped_mpf v2(m_fm), v3(m_fm); if (m_util.is_numeral(arg2, v2) && m_util.is_numeral(arg3, v3)) { @@ -355,7 +304,6 @@ br_status fpa_rewriter::mk_div(expr * arg1, expr * arg2, expr * arg3, expr_ref & return BR_DONE; } } - return BR_FAILED; } @@ -393,6 +341,7 @@ br_status fpa_rewriter::mk_neg(expr * arg1, expr_ref & result) { br_status fpa_rewriter::mk_rem(expr * arg1, expr * arg2, expr_ref & result) { scoped_mpf v1(m_fm), v2(m_fm); + if (m_util.is_numeral(arg1, v1) && m_util.is_numeral(arg2, v2)) { scoped_mpf t(m_fm); m_fm.rem(v1, v2, t); @@ -431,27 +380,16 @@ br_status fpa_rewriter::mk_min(expr * arg1, expr * arg2, expr_ref & result) { scoped_mpf v1(m_fm), v2(m_fm); if (m_util.is_numeral(arg1, v1) && m_util.is_numeral(arg2, v2)) { - if (m_fm.is_zero(v1) && m_fm.is_zero(v2) && m_fm.sgn(v1) != m_fm.sgn(v2)) { - result = m().mk_app(get_fid(), OP_FPA_INTERNAL_MIN_UNSPECIFIED, arg1, arg2); - return BR_REWRITE1; - } - else { - scoped_mpf r(m_fm); - m_fm.minimum(v1, v2, r); - result = m_util.mk_value(r); - return BR_DONE; - } - } - else { - expr_ref c(m()), v(m()); - c = m().mk_and(m().mk_and(m_util.mk_is_zero(arg1), m_util.mk_is_zero(arg2)), - m().mk_or(m().mk_and(m_util.mk_is_positive(arg1), m_util.mk_is_negative(arg2)), - m().mk_and(m_util.mk_is_negative(arg1), m_util.mk_is_positive(arg2)))); - v = m().mk_app(get_fid(), OP_FPA_INTERNAL_MIN_UNSPECIFIED, arg1, arg2); + if (m_fm.is_zero(v1) && m_fm.is_zero(v2) && m_fm.sgn(v1) != m_fm.sgn(v2)) + return BR_FAILED; - result = m().mk_ite(c, v, m().mk_app(get_fid(), OP_FPA_INTERNAL_MIN_I, arg1, arg2)); - return BR_REWRITE_FULL; + scoped_mpf r(m_fm); + m_fm.minimum(v1, v2, r); + result = m_util.mk_value(r); + return BR_DONE; } + + return BR_FAILED; } br_status fpa_rewriter::mk_max(expr * arg1, expr * arg2, expr_ref & result) { @@ -466,31 +404,21 @@ br_status fpa_rewriter::mk_max(expr * arg1, expr * arg2, expr_ref & result) { scoped_mpf v1(m_fm), v2(m_fm); if (m_util.is_numeral(arg1, v1) && m_util.is_numeral(arg2, v2)) { - if (m_fm.is_zero(v1) && m_fm.is_zero(v2) && m_fm.sgn(v1) != m_fm.sgn(v2)) { - result = m().mk_app(get_fid(), OP_FPA_INTERNAL_MAX_UNSPECIFIED, arg1, arg2); - return BR_REWRITE1; - } - else { - scoped_mpf r(m_fm); - m_fm.maximum(v1, v2, r); - result = m_util.mk_value(r); - return BR_DONE; - } - } - else { - expr_ref c(m()), v(m()); - c = m().mk_and(m().mk_and(m_util.mk_is_zero(arg1), m_util.mk_is_zero(arg2)), - m().mk_or(m().mk_and(m_util.mk_is_positive(arg1), m_util.mk_is_negative(arg2)), - m().mk_and(m_util.mk_is_negative(arg1), m_util.mk_is_positive(arg2)))); - v = m().mk_app(get_fid(), OP_FPA_INTERNAL_MAX_UNSPECIFIED, arg1, arg2); + if (m_fm.is_zero(v1) && m_fm.is_zero(v2) && m_fm.sgn(v1) != m_fm.sgn(v2)) + return BR_FAILED; - result = m().mk_ite(c, v, m().mk_app(get_fid(), OP_FPA_INTERNAL_MAX_I, arg1, arg2)); - return BR_REWRITE_FULL; + scoped_mpf r(m_fm); + m_fm.maximum(v1, v2, r); + result = m_util.mk_value(r); + return BR_DONE; } + + return BR_FAILED; } br_status fpa_rewriter::mk_fma(expr * arg1, expr * arg2, expr * arg3, expr * arg4, expr_ref & result) { mpf_rounding_mode rm; + if (m_util.is_rm_numeral(arg1, rm)) { scoped_mpf v2(m_fm), v3(m_fm), v4(m_fm); if (m_util.is_numeral(arg2, v2) && m_util.is_numeral(arg3, v3) && m_util.is_numeral(arg4, v4)) { @@ -506,6 +434,7 @@ br_status fpa_rewriter::mk_fma(expr * arg1, expr * arg2, expr * arg3, expr * arg br_status fpa_rewriter::mk_sqrt(expr * arg1, expr * arg2, expr_ref & result) { mpf_rounding_mode rm; + if (m_util.is_rm_numeral(arg1, rm)) { scoped_mpf v2(m_fm); if (m_util.is_numeral(arg2, v2)) { @@ -521,6 +450,7 @@ br_status fpa_rewriter::mk_sqrt(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); if (m_util.is_numeral(arg2, v2)) { @@ -588,7 +518,6 @@ br_status fpa_rewriter::mk_lt(expr * arg1, expr * arg2, expr_ref & result) { return BR_DONE; } - // TODO: more simplifications return BR_FAILED; } @@ -652,6 +581,7 @@ br_status fpa_rewriter::mk_is_pzero(expr * arg1, expr_ref & result) { br_status fpa_rewriter::mk_is_nan(expr * arg1, expr_ref & result) { scoped_mpf v(m_fm); + if (m_util.is_numeral(arg1, v)) { result = (m_fm.is_nan(v)) ? m().mk_true() : m().mk_false(); return BR_DONE; @@ -662,6 +592,7 @@ br_status fpa_rewriter::mk_is_nan(expr * arg1, expr_ref & result) { br_status fpa_rewriter::mk_is_inf(expr * arg1, expr_ref & result) { scoped_mpf v(m_fm); + if (m_util.is_numeral(arg1, v)) { result = (m_fm.is_inf(v)) ? m().mk_true() : m().mk_false(); return BR_DONE; @@ -672,6 +603,7 @@ br_status fpa_rewriter::mk_is_inf(expr * arg1, expr_ref & result) { br_status fpa_rewriter::mk_is_normal(expr * arg1, expr_ref & result) { scoped_mpf v(m_fm); + if (m_util.is_numeral(arg1, v)) { result = (m_fm.is_normal(v)) ? m().mk_true() : m().mk_false(); return BR_DONE; @@ -682,6 +614,7 @@ br_status fpa_rewriter::mk_is_normal(expr * arg1, expr_ref & result) { br_status fpa_rewriter::mk_is_subnormal(expr * arg1, expr_ref & result) { scoped_mpf v(m_fm); + if (m_util.is_numeral(arg1, v)) { result = (m_fm.is_denormal(v)) ? m().mk_true() : m().mk_false(); return BR_DONE; @@ -692,6 +625,7 @@ br_status fpa_rewriter::mk_is_subnormal(expr * arg1, expr_ref & result) { br_status fpa_rewriter::mk_is_negative(expr * arg1, expr_ref & result) { scoped_mpf v(m_fm); + if (m_util.is_numeral(arg1, v)) { result = (m_fm.is_neg(v)) ? m().mk_true() : m().mk_false(); return BR_DONE; @@ -702,6 +636,7 @@ br_status fpa_rewriter::mk_is_negative(expr * arg1, expr_ref & result) { br_status fpa_rewriter::mk_is_positive(expr * arg1, expr_ref & result) { scoped_mpf v(m_fm); + if (m_util.is_numeral(arg1, v)) { result = (m_fm.is_neg(v) || m_fm.is_nan(v)) ? m().mk_false() : m().mk_true(); return BR_DONE; @@ -714,6 +649,7 @@ br_status fpa_rewriter::mk_is_positive(expr * arg1, expr_ref & result) { // This the SMT = br_status fpa_rewriter::mk_eq_core(expr * arg1, expr * arg2, expr_ref & result) { scoped_mpf v1(m_fm), v2(m_fm); + if (m_util.is_numeral(arg1, v1) && m_util.is_numeral(arg2, v2)) { // Note: == is the floats-equality, here we need normal equality. result = (m_fm.is_nan(v1) && m_fm.is_nan(v2)) ? m().mk_true() : @@ -727,10 +663,10 @@ br_status fpa_rewriter::mk_eq_core(expr * arg1, expr * arg2, expr_ref & result) } br_status fpa_rewriter::mk_bv2rm(expr * arg, expr_ref & result) { - bv_util bu(m()); rational bv_val; unsigned sz = 0; - if (bu.is_numeral(arg, bv_val, sz)) { + + if (m_util.bu().is_numeral(arg, bv_val, sz)) { SASSERT(bv_val.is_uint64()); switch (bv_val.get_uint64()) { case BV_RM_TIES_TO_AWAY: result = m_util.mk_round_nearest_ties_to_away(); break; @@ -749,13 +685,12 @@ br_status fpa_rewriter::mk_bv2rm(expr * arg, expr_ref & result) { br_status fpa_rewriter::mk_fp(expr * sgn, expr * exp, expr * sig, expr_ref & result) { unsynch_mpz_manager & mpzm = m_fm.mpz_manager(); - bv_util bu(m()); rational rsgn, rexp, rsig; unsigned bvsz_sgn, bvsz_exp, bvsz_sig; - if (bu.is_numeral(sgn, rsgn, bvsz_sgn) && - bu.is_numeral(sig, rsig, bvsz_sig) && - bu.is_numeral(exp, rexp, bvsz_exp)) { + if (m_util.bu().is_numeral(sgn, rsgn, bvsz_sgn) && + m_util.bu().is_numeral(sig, rsig, bvsz_sig) && + m_util.bu().is_numeral(exp, rexp, bvsz_exp)) { SASSERT(mpzm.is_one(rexp.to_mpq().denominator())); SASSERT(mpzm.is_one(rsig.to_mpq().denominator())); scoped_mpf v(m_fm); @@ -772,7 +707,7 @@ br_status fpa_rewriter::mk_fp(expr * sgn, expr * exp, expr * sig, expr_ref & res return BR_FAILED; } -br_status fpa_rewriter::mk_to_ubv(func_decl * f, expr * arg1, expr * arg2, expr_ref & result) { +br_status fpa_rewriter::mk_to_bv(func_decl * f, expr * arg1, expr * arg2, bool is_signed, expr_ref & result) { SASSERT(f->get_num_parameters() == 1); SASSERT(f->get_parameter(0).is_int()); int bv_sz = f->get_parameter(0).get_int(); @@ -781,10 +716,9 @@ br_status fpa_rewriter::mk_to_ubv(func_decl * f, expr * arg1, expr * arg2, expr_ if (m_util.is_rm_numeral(arg1, rmv) && m_util.is_numeral(arg2, v)) { - const mpf & x = v.get(); - if (m_fm.is_nan(v) || m_fm.is_inf(v) || m_fm.is_neg(v)) - return mk_to_ubv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result); + if (m_fm.is_nan(v) || m_fm.is_inf(v)) + return mk_to_bv_unspecified(f, result); bv_util bu(m()); scoped_mpq q(m_fm.mpq_manager()); @@ -792,51 +726,41 @@ br_status fpa_rewriter::mk_to_ubv(func_decl * f, expr * arg1, expr * arg2, expr_ rational r(q); rational ul, ll; - ul = m_fm.m_powers2.m1(bv_sz); - ll = rational(0); + if (!is_signed) { + ul = m_fm.m_powers2.m1(bv_sz); + ll = rational(0); + } + else { + ul = m_fm.m_powers2.m1(bv_sz - 1); + ll = -m_fm.m_powers2(bv_sz - 1); + } if (r >= ll && r <= ul) { result = bu.mk_numeral(r, bv_sz); return BR_DONE; } else - return mk_to_ubv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result); - + return mk_to_bv_unspecified(f, result); } return BR_FAILED; } -br_status fpa_rewriter::mk_to_sbv(func_decl * f, expr * arg1, expr * arg2, expr_ref & result) { - SASSERT(f->get_num_parameters() == 1); - SASSERT(f->get_parameter(0).is_int()); - int bv_sz = f->get_parameter(0).get_int(); - mpf_rounding_mode rmv; - scoped_mpf v(m_fm); - - if (m_util.is_rm_numeral(arg1, rmv) && - m_util.is_numeral(arg2, v)) { - const mpf & x = v.get(); - - if (m_fm.is_nan(v) || m_fm.is_inf(v)) - return mk_to_sbv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result); - - bv_util bu(m()); - scoped_mpq q(m_fm.mpq_manager()); - m_fm.to_sbv_mpq(rmv, v, q); - - rational r(q); - rational ul, ll; - ul = m_fm.m_powers2.m1(bv_sz - 1); - ll = - m_fm.m_powers2(bv_sz - 1); - if (r >= ll && r <= ul) { - result = bu.mk_numeral(r, bv_sz); - return BR_DONE; - } - else - return mk_to_sbv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result); +br_status fpa_rewriter::mk_to_bv_unspecified(func_decl * f, expr_ref & result) { + if (m_hi_fp_unspecified) { + unsigned bv_sz = m_util.bu().get_bv_size(f->get_range()); + result = m_util.bu().mk_numeral(0, bv_sz); + return BR_DONE; } + else + return BR_FAILED; +} - return BR_FAILED; +br_status fpa_rewriter::mk_to_ubv(func_decl * f, expr * arg1, expr * arg2, expr_ref & result) { + return mk_to_bv(f, arg1, arg2, false, result); +} + +br_status fpa_rewriter::mk_to_sbv(func_decl * f, expr * arg1, expr * arg2, expr_ref & result) { + return mk_to_bv(f, arg1, arg2, true, result); } br_status fpa_rewriter::mk_to_ieee_bv(func_decl * f, expr * arg, expr_ref & result) { @@ -855,11 +779,8 @@ br_status fpa_rewriter::mk_to_ieee_bv(func_decl * f, expr * arg, expr_ref & resu bu.mk_numeral(0, x.get_sbits() - 2), bu.mk_numeral(1, 1) }; result = bu.mk_concat(4, args); + return BR_REWRITE1; } - else - result = m_util.mk_internal_to_ieee_bv_unspecified(x.get_ebits(), x.get_sbits()); - - return BR_REWRITE1; } else { scoped_mpz rz(m_fm.mpq_manager()); @@ -877,15 +798,17 @@ br_status fpa_rewriter::mk_to_real(expr * arg, expr_ref & result) { if (m_util.is_numeral(arg, v)) { if (m_fm.is_nan(v) || m_fm.is_inf(v)) { - const mpf & x = v.get(); - result = m_util.mk_internal_to_real_unspecified(x.get_ebits(), x.get_sbits()); + if (m_hi_fp_unspecified) { + result = m_util.au().mk_numeral(rational(0), false); + return BR_DONE; + } } else { scoped_mpq r(m_fm.mpq_manager()); m_fm.to_rational(v, r); result = m_util.au().mk_numeral(r.get(), false); + return BR_DONE; } - return BR_DONE; } return BR_FAILED; diff --git a/src/ast/rewriter/fpa_rewriter.h b/src/ast/rewriter/fpa_rewriter.h index 45710122c..cfa1bea52 100644 --- a/src/ast/rewriter/fpa_rewriter.h +++ b/src/ast/rewriter/fpa_rewriter.h @@ -21,8 +21,9 @@ Notes: #include "ast/ast.h" #include "ast/rewriter/rewriter.h" -#include "util/params.h" #include "ast/fpa_decl_plugin.h" +#include "ast/expr_map.h" +#include "util/params.h" #include "util/mpf.h" class fpa_rewriter { @@ -33,6 +34,9 @@ class fpa_rewriter { app * mk_eq_nan(expr * arg); app * mk_neq_nan(expr * arg); + br_status mk_to_bv(func_decl * f, expr * arg1, expr * arg2, bool is_signed, expr_ref & result); + br_status mk_to_bv_unspecified(func_decl * f, expr_ref & result); + public: fpa_rewriter(ast_manager & m, params_ref const & p = params_ref()); ~fpa_rewriter(); @@ -73,22 +77,17 @@ public: br_status mk_is_negative(expr * arg1, expr_ref & result); br_status mk_is_positive(expr * arg1, expr_ref & result); - br_status mk_to_ieee_bv(expr * arg1, expr_ref & result); - br_status mk_to_fp(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result); br_status mk_to_fp_unsigned(func_decl * f, expr * arg1, expr * arg2, expr_ref & result); br_status mk_bv2rm(expr * arg, expr_ref & result); br_status mk_fp(expr * sgn, expr * exp, expr * sig, expr_ref & result); - br_status mk_to_fp_unsigned(expr * arg1, expr * arg2, expr_ref & result); br_status mk_to_ubv(func_decl * f, expr * arg1, expr * arg2, expr_ref & result); br_status mk_to_sbv(func_decl * f, expr * arg1, expr * arg2, expr_ref & result); br_status mk_to_ieee_bv(func_decl * f, expr * arg, expr_ref & result); br_status mk_to_real(expr * arg, expr_ref & result); - - br_status mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned with, expr_ref & result); - br_status mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned with, expr_ref & result); - br_status mk_to_real_unspecified(unsigned ebits, unsigned sbits, expr_ref & result); + br_status mk_min_i(func_decl * f, expr * arg1, expr * arg2, expr_ref & result); + br_status mk_max_i(func_decl * f, expr * arg1, expr * arg2, expr_ref & result); br_status mk_bvwrap(expr * arg, expr_ref & result); }; diff --git a/src/ast/rewriter/fpa_rewriter_params.pyg b/src/ast/rewriter/fpa_rewriter_params.pyg index f0cfbdf55..487c50a85 100644 --- a/src/ast/rewriter/fpa_rewriter_params.pyg +++ b/src/ast/rewriter/fpa_rewriter_params.pyg @@ -1,5 +1,5 @@ def_module_params(module_name='rewriter', class_name='fpa_rewriter_params', export=True, - params=(("hi_fp_unspecified", BOOL, False, "use the 'hardware interpretation' for unspecified values in fp.to_ubv, fp.to_sbv, fp.to_real, and fp.to_ieee_bv"), + params=(("hi_fp_unspecified", BOOL, False, "use the 'hardware interpretation' for unspecified values in fp.to_ubv, fp.to_sbv, fp.to_real, and fp.to_ieee_bv"), )) diff --git a/src/ast/rewriter/poly_rewriter_def.h b/src/ast/rewriter/poly_rewriter_def.h index 39c4a1078..3bb963a7f 100644 --- a/src/ast/rewriter/poly_rewriter_def.h +++ b/src/ast/rewriter/poly_rewriter_def.h @@ -686,7 +686,7 @@ br_status poly_rewriter::mk_sub(unsigned num_args, expr * const * args, return BR_DONE; } set_curr_sort(m().get_sort(args[0])); - expr * minus_one = mk_numeral(numeral(-1)); + expr_ref minus_one(mk_numeral(numeral(-1)), m()); ptr_buffer new_args; new_args.push_back(args[0]); for (unsigned i = 1; i < num_args; i++) { @@ -1010,7 +1010,6 @@ bool poly_rewriter::is_var_plus_ground(expr * n, bool & inv, var * & v, stop = true; } if (is_ground(arg)) { - TRACE("model_checker_bug", tout << "pushing:\n" << mk_pp(arg, m()) << "\n";); args.push_back(arg); } else if (is_var(arg)) { diff --git a/src/ast/rewriter/rewriter_def.h b/src/ast/rewriter/rewriter_def.h index 42f268379..f5f72674d 100644 --- a/src/ast/rewriter/rewriter_def.h +++ b/src/ast/rewriter/rewriter_def.h @@ -42,6 +42,10 @@ void rewriter_tpl::process_var(var * v) { unsigned index = m_bindings.size() - idx - 1; var * r = (var*)(m_bindings[index]); if (r != 0) { + CTRACE("rewriter", v->get_sort() != m().get_sort(r), + tout << expr_ref(v, m()) << ":" << sort_ref(v->get_sort(), m()) << " != " << expr_ref(r, m()) << ":" << sort_ref(m().get_sort(r), m()); + tout << "index " << index << " bindings " << m_bindings.size() << "\n"; + display_bindings(tout);); SASSERT(v->get_sort() == m().get_sort(r)); if (!is_ground(r) && m_shifts[index] != m_bindings.size()) { diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index dd431bf85..a2ca12b24 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -736,7 +736,6 @@ ast_manager & th_rewriter::m() const { void th_rewriter::updt_params(params_ref const & p) { m_params = p; m_imp->cfg().updt_params(p); - IF_VERBOSE(10, verbose_stream() << p << "\n";); } void th_rewriter::get_param_descrs(param_descrs & r) { diff --git a/src/cmd_context/check_logic.cpp b/src/cmd_context/check_logic.cpp index 1aace7716..dd08ac9db 100644 --- a/src/cmd_context/check_logic.cpp +++ b/src/cmd_context/check_logic.cpp @@ -37,6 +37,7 @@ struct check_logic::imp { datatype_util m_dt_util; pb_util m_pb_util; bool m_uf; // true if the logic supports uninterpreted functions + bool m_dt; // true if the lgoic supports dattypes bool m_arrays; // true if the logic supports arbitrary arrays bool m_bv_arrays; // true if the logic supports only bv arrays bool m_reals; // true if the logic supports reals @@ -53,6 +54,7 @@ struct check_logic::imp { void reset() { m_uf = false; + m_dt = false; m_arrays = false; m_bv_arrays = false; m_reals = false; @@ -105,6 +107,10 @@ struct check_logic::imp { m_uf = true; m_bvs = true; } + else if (logic == "QF_DT") { + m_uf = true; + m_dt = true; + } else if (logic == "QF_AUFLIA") { m_uf = true; m_arrays = true; @@ -187,6 +193,7 @@ struct check_logic::imp { m_bvs = true; m_uf = true; m_ints = true; + m_dt = true; m_nonlinear = true; // non-linear 0-1 variables may get eliminated } else { @@ -443,7 +450,7 @@ struct check_logic::imp { else if (fid == m_seq_util.get_family_id()) { // nothing to check } - else if (fid == m_dt_util.get_family_id() && m_logic == "QF_FD") { + else if (fid == m_dt_util.get_family_id() && m_dt) { // nothing to check } else if (fid == m_pb_util.get_family_id() && m_logic == "QF_FD") { diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index c0e1c9f9c..260d49174 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -202,7 +202,7 @@ func_decl * func_decls::find(unsigned arity, sort * const * domain, sort * range if (f->get_arity() != arity) continue; unsigned i = 0; - for (i = 0; i < arity; i++) { + for (i = 0; domain && i < arity; i++) { if (f->get_domain(i) != domain[i]) break; } @@ -937,7 +937,7 @@ static builtin_decl const & peek_builtin_decl(builtin_decl const & first, family func_decl * cmd_context::find_func_decl(symbol const & s, unsigned num_indices, unsigned const * indices, unsigned arity, sort * const * domain, sort * range) const { builtin_decl d; - if (m_builtin_decls.find(s, d)) { + if (domain && m_builtin_decls.find(s, d)) { family_id fid = d.m_fid; decl_kind k = d.m_decl; // Hack: if d.m_next != 0, we use domain[0] (if available) to decide which plugin we use. @@ -961,7 +961,7 @@ func_decl * cmd_context::find_func_decl(symbol const & s, unsigned num_indices, return f; } - if (contains_macro(s, arity, domain)) + if (domain && contains_macro(s, arity, domain)) throw cmd_exception("invalid function declaration reference, named expressions (aka macros) cannot be referenced ", s); if (num_indices > 0) @@ -1545,6 +1545,26 @@ void cmd_context::reset_assertions() { } +void cmd_context::display_dimacs() { + if (m_solver) { + try { + gparams::set("sat.dimacs.display", "true"); + params_ref p; + m_solver->updt_params(p); + m_solver->check_sat(0, nullptr); + } + catch (...) { + gparams::set("sat.dimacs.display", "false"); + params_ref p; + m_solver->updt_params(p); + throw; + } + gparams::set("sat.dimacs.display", "false"); + params_ref p; + m_solver->updt_params(p); + } +} + void cmd_context::display_model(model_ref& mdl) { if (mdl) { model_params p; @@ -1609,12 +1629,16 @@ void cmd_context::set_diagnostic_stream(char const * name) { } } -struct contains_array_op_proc { +struct contains_underspecified_op_proc { struct found {}; family_id m_array_fid; - contains_array_op_proc(ast_manager & m):m_array_fid(m.mk_family_id("array")) {} + datatype_util m_dt; + + contains_underspecified_op_proc(ast_manager & m):m_array_fid(m.mk_family_id("array")), m_dt(m) {} void operator()(var * n) {} void operator()(app * n) { + if (m_dt.is_accessor(n->get_decl())) + throw found(); if (n->get_family_id() != m_array_fid) return; decl_kind k = n->get_decl_kind(); @@ -1665,6 +1689,16 @@ void cmd_context::complete_model() { } } + for (unsigned i = 0; i < md->get_num_functions(); i++) { + func_decl * f = md->get_function(i); + func_interp * fi = md->get_func_interp(f); + IF_VERBOSE(12, verbose_stream() << "(model.completion " << f->get_name() << ")\n"; ); + if (fi->is_partial()) { + sort * range = f->get_range(); + fi->set_else(m().get_some_value(range)); + } + } + for (auto kd : m_func_decls) { symbol const & k = kd.m_key; func_decls & v = kd.m_value; @@ -1703,7 +1737,7 @@ void cmd_context::validate_model() { p.set_bool("completion", true); model_evaluator evaluator(*(md.get()), p); evaluator.set_expand_array_equalities(false); - contains_array_op_proc contains_array(m()); + contains_underspecified_op_proc contains_underspecified(m()); { scoped_rlimit _rlimit(m().limit(), 0); cancel_eh eh(m().limit()); @@ -1729,9 +1763,9 @@ void cmd_context::validate_model() { continue; } try { - for_each_expr(contains_array, r); + for_each_expr(contains_underspecified, r); } - catch (contains_array_op_proc::found) { + catch (contains_underspecified_op_proc::found) { continue; } TRACE("model_validate", model_smt2_pp(tout, *this, *(md.get()), 0);); @@ -1948,13 +1982,13 @@ void cmd_context::dt_eh::operator()(sort * dt, pdecl* pd) { TRACE("new_dt_eh", tout << "new datatype: "; m_owner.pm().display(tout, dt); tout << "\n";); for (func_decl * c : *m_dt_util.get_datatype_constructors(dt)) { TRACE("new_dt_eh", tout << "new constructor: " << c->get_name() << "\n";); - m_owner.insert(c); + m_owner.insert(c); func_decl * r = m_dt_util.get_constructor_recognizer(c); m_owner.insert(r); TRACE("new_dt_eh", tout << "new recognizer: " << r->get_name() << "\n";); for (func_decl * a : *m_dt_util.get_constructor_accessors(c)) { TRACE("new_dt_eh", tout << "new accessor: " << a->get_name() << "\n";); - m_owner.insert(a); + m_owner.insert(a); } } if (m_owner.m_scopes.size() > 0) { diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index 5883a8d8e..b60f590a9 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -419,6 +419,7 @@ public: void display_assertions(); void display_statistics(bool show_total_time = false, double total_time = 0.0); + void display_dimacs(); void reset(bool finalize = false); void assert_expr(expr * t); void assert_expr(symbol const & name, expr * t); diff --git a/src/cmd_context/extra_cmds/dbg_cmds.cpp b/src/cmd_context/extra_cmds/dbg_cmds.cpp index 7d20685ac..dfdfa6175 100644 --- a/src/cmd_context/extra_cmds/dbg_cmds.cpp +++ b/src/cmd_context/extra_cmds/dbg_cmds.cpp @@ -31,7 +31,6 @@ Notes: #include "ast/rewriter/var_subst.h" #include "util/gparams.h" -#ifndef _EXTERNAL_RELEASE BINARY_SYM_CMD(get_quantifier_body_cmd, "dbg-get-qbody", @@ -343,10 +342,19 @@ public: } }; -#endif +class print_dimacs_cmd : public cmd { +public: + print_dimacs_cmd():cmd("display-dimacs") {} + virtual char const * get_usage() const { return ""; } + virtual char const * get_descr(cmd_context & ctx) const { return "print benchmark in DIMACS format"; } + virtual unsigned get_arity() const { return 0; } + virtual void prepare(cmd_context & ctx) {} + virtual void execute(cmd_context & ctx) { ctx.display_dimacs(); } +}; + void install_dbg_cmds(cmd_context & ctx) { -#ifndef _EXTERNAL_RELEASE + ctx.insert(alloc(print_dimacs_cmd)); ctx.insert(alloc(get_quantifier_body_cmd)); ctx.insert(alloc(set_cmd)); ctx.insert(alloc(pp_var_cmd)); @@ -369,5 +377,4 @@ void install_dbg_cmds(cmd_context & ctx) { ctx.insert(alloc(instantiate_cmd)); ctx.insert(alloc(instantiate_nested_cmd)); ctx.insert(alloc(set_next_id)); -#endif } diff --git a/src/cmd_context/tactic_cmds.cpp b/src/cmd_context/tactic_cmds.cpp index 3eafc6bbd..cbc90c62c 100644 --- a/src/cmd_context/tactic_cmds.cpp +++ b/src/cmd_context/tactic_cmds.cpp @@ -197,6 +197,9 @@ public: } virtual void execute(cmd_context & ctx) { + if (!m_tactic) { + throw cmd_exception("check-sat-using needs a tactic argument"); + } params_ref p = ctx.params().merge_default_params(ps()); tactic_ref tref = using_params(sexpr2tactic(ctx, m_tactic), p); tref->set_logic(ctx.get_logic()); diff --git a/src/duality/duality.h b/src/duality/duality.h index 0ef6be30e..657fa18b4 100644 --- a/src/duality/duality.h +++ b/src/duality/duality.h @@ -21,6 +21,7 @@ #pragma once #include "duality/duality_wrapper.h" +#include #include #include @@ -41,9 +42,9 @@ namespace Duality { typedef expr Term; Z3User(context &_ctx) : ctx(_ctx){} - + const char *string_of_int(int n); - + Term conjoin(const std::vector &args); Term sum(const std::vector &args); @@ -130,58 +131,58 @@ namespace Duality { /** This class represents a relation post-fixed point (RPFP) problem as * a "problem graph". The graph consists of Nodes and hyper-edges. - * + * * A node consists of * - Annotation, a symbolic relation * - Bound, a symbolic relation giving an upper bound on Annotation - * + * * * A hyper-edge consists of: * - Children, a sequence of children Nodes, * - F, a symbolic relational transformer, * - Parent, a single parent Node. - * + * * The graph is "solved" when: * - For every Node n, n.Annotation subseteq n.Bound * - For every hyperedge e, e.F(e.Children.Annotation) subseteq e.Parent.Annotation - * + * * where, if x is a sequence of Nodes, x.Annotation is the sequences * of Annotations of the nodes in the sequence. - * + * * A symbolic Transformer consists of * - RelParams, a sequence of relational symbols * - IndParams, a sequence of individual symbols * - Formula, a formula over RelParams and IndParams - * + * * A Transformer t represents a function that takes sequence R of relations * and yields the relation lambda (t.Indparams). Formula(R/RelParams). - * + * * As a special case, a nullary Transformer (where RelParams is the empty sequence) * represents a fixed relation. - * + * * An RPFP consists of * - Nodes, a set of Nodes * - Edges, a set of hyper-edges * - Context, a prover context that contains formula AST's - * + * * Multiple RPFP's can use the same Context, but you should be careful - * that only one RPFP asserts constraints in the context at any time. - * + * that only one RPFP asserts constraints in the context at any time. + * * */ class RPFP : public Z3User { public: - + class Edge; class Node; bool HornClauses; - + /** Interface class for interpolating solver. */ class LogicSolver { public: - + context *ctx; /** Z3 context for formulas */ solver *slvr; /** Z3 solver */ bool need_goals; /** Can the solver use the goal tree to optimize interpolants? */ @@ -191,7 +192,7 @@ namespace Duality { "assumptions" are currently asserted in the solver. The return value indicates whether the assertions are satisfiable. In the UNSAT case, a tree interpolant is returned in "interpolants". - In the SAT case, a model is returned. + In the SAT case, a model is returned. */ virtual @@ -201,7 +202,7 @@ namespace Duality { TermTree *goals = 0, bool weak = false ) = 0; - + /** Declare a constant in the background theory. */ virtual void declare_constant(const func_decl &f) = 0; @@ -319,7 +320,7 @@ namespace Duality { virtual void declare_constant(const func_decl &f){ bckg.insert(f); } - + /** Is this a background constant? */ virtual bool is_constant(const func_decl &f){ return bckg.find(f) != bckg.end(); @@ -344,9 +345,9 @@ namespace Duality { static iZ3LogicSolver *CreateLogicSolver(config &_config){ return new iZ3LogicSolver(_config); } -#endif +#endif - /** Create a logic solver from a low-level Z3 context. + /** Create a logic solver from a low-level Z3 context. Only use this if you know what you're doing. */ static iZ3LogicSolver *CreateLogicSolver(context c){ return new iZ3LogicSolver(c); @@ -357,7 +358,7 @@ namespace Duality { protected: int nodeCount; int edgeCount; - + class stack_entry { public: @@ -365,8 +366,8 @@ namespace Duality { std::list nodes; std::list > constraints; }; - - + + public: model dualModel; protected: @@ -375,14 +376,14 @@ namespace Duality { std::vector axioms; // only saved here for printing purposes solver &aux_solver; hash_set *proof_core; - + public: /** Construct an RPFP graph with a given interpolating prover context. It is allowed to have multiple RPFP's use the same context, but you should never have teo RPFP's with the same conext asserting nodes or edges at the same time. Note, if you create axioms in one RPFP, them create a second RPFP with the same context, the second will - inherit the axioms. + inherit the axioms. */ RPFP(LogicSolver *_ls) : Z3User(*(_ls->ctx)), dualModel(*(_ls->ctx)), aux_solver(_ls->aux_solver) @@ -396,7 +397,7 @@ namespace Duality { } virtual ~RPFP(); - + /** Symbolic representation of a relational transformer */ class Transformer { @@ -406,12 +407,12 @@ namespace Duality { Term Formula; RPFP *owner; hash_map labels; - + Transformer *Clone() { return new Transformer(*this); } - + void SetEmpty(){ Formula = owner->ctx.bool_val(false); } @@ -451,7 +452,7 @@ namespace Duality { void Complement(){ Formula = !Formula; } - + void Simplify(){ Formula = Formula.simplify(); } @@ -459,7 +460,7 @@ namespace Duality { Transformer(const std::vector &_RelParams, const std::vector &_IndParams, const Term &_Formula, RPFP *_owner) : RelParams(_RelParams), IndParams(_IndParams), Formula(_Formula) {owner = _owner;} }; - + /** Create a symbolic transformer. */ Transformer CreateTransformer(const std::vector &_RelParams, const std::vector &_IndParams, const Term &_Formula) { @@ -469,13 +470,13 @@ namespace Duality { // t.labels = foo.Item2; return Transformer(_RelParams,_IndParams,_Formula,this); } - + /** Create a relation (nullary relational transformer) */ Transformer CreateRelation(const std::vector &_IndParams, const Term &_Formula) { return CreateTransformer(std::vector(), _IndParams, _Formula); } - + /** A node in the RPFP graph */ class Node { @@ -491,17 +492,17 @@ namespace Duality { Term dual; Node *map; unsigned recursion_bound; - + Node(const FuncDecl &_Name, const Transformer &_Annotation, const Transformer &_Bound, const Transformer &_Underapprox, const Term &_dual, RPFP *_owner, int _number) : Name(_Name), Annotation(_Annotation), Bound(_Bound), Underapprox(_Underapprox), dual(_dual) {owner = _owner; number = _number; Outgoing = 0; recursion_bound = UINT_MAX;} }; - + /** Create a node in the graph. The input is a term R(v_1...v_n) * where R is an arbitrary relational symbol and v_1...v_n are * arbitary distinct variables. The names are only of mnemonic value, * however, the number and type of arguments determine the type * of the relation at this node. */ - + Node *CreateNode(const Term &t) { std::vector _IndParams; @@ -517,9 +518,9 @@ namespace Duality { nodes.push_back(n); return n; } - + /** Clone a node (can be from another graph). */ - + Node *CloneNode(Node *old) { Node *n = new Node(old->Name, @@ -534,7 +535,7 @@ namespace Duality { n->map = old; return n; } - + /** Delete a node. You can only do this if not connected to any edges.*/ void DeleteNode(Node *node){ if(node->Outgoing || !node->Incoming.empty()) @@ -549,7 +550,7 @@ namespace Duality { } /** This class represents a hyper-edge in the RPFP graph */ - + class Edge { public: @@ -565,15 +566,15 @@ namespace Duality { Edge *map; Term labeled; std::vector constraints; - + Edge(Node *_Parent, const Transformer &_F, const std::vector &_Children, RPFP *_owner, int _number) : F(_F), Parent(_Parent), Children(_Children), dual(expr(_owner->ctx)) { owner = _owner; number = _number; } }; - - + + /** Create a hyper-edge. */ Edge *CreateEdge(Node *_Parent, const Transformer &_F, const std::vector &_Children) { @@ -584,8 +585,8 @@ namespace Duality { edges.push_back(e); return e; } - - + + /** Delete a hyper-edge and unlink it from any nodes. */ void DeleteEdge(Edge *edge){ if(edge->Parent) @@ -607,19 +608,19 @@ namespace Duality { } delete edge; } - + /** Create an edge that lower-bounds its parent. */ Edge *CreateLowerBoundEdge(Node *_Parent) { return CreateEdge(_Parent, _Parent->Annotation, std::vector()); } - + /** For incremental solving, asserts the constraint associated * with this edge in the SMT context. If this edge is removed, * you must pop the context accordingly. The second argument is * the number of pushes we are inside. */ - + virtual void AssertEdge(Edge *e, int persist = 0, bool with_children = false, bool underapprox = false); /* Constrain an edge by the annotation of one of its children. */ @@ -629,19 +630,19 @@ namespace Duality { /** For incremental solving, asserts the negation of the upper bound associated * with a node. * */ - + void AssertNode(Node *n); - /** Assert a constraint on an edge in the SMT context. + /** Assert a constraint on an edge in the SMT context. */ void ConstrainEdge(Edge *e, const Term &t); - + /** Fix the truth values of atomic propositions in the given edge to their values in the current assignment. */ void FixCurrentState(Edge *root); - + void FixCurrentStateFull(Edge *edge, const expr &extra); - + void FixCurrentStateFull(Edge *edge, const std::vector &assumps, const hash_map &renaming); /** Declare a constant in the background theory. */ @@ -660,78 +661,78 @@ namespace Duality { #if 0 /** Do not call this. */ - + void RemoveAxiom(const Term &t); #endif /** Solve an RPFP graph. This means either strengthen the annotation * so that the bound at the given root node is satisfied, or - * show that this cannot be done by giving a dual solution - * (i.e., a counterexample). - * + * show that this cannot be done by giving a dual solution + * (i.e., a counterexample). + * * In the current implementation, this only works for graphs that * are: * - tree-like - * + * * - closed. - * + * * In a tree-like graph, every nod has out most one incoming and one out-going edge, * and there are no cycles. In a closed graph, every node has exactly one out-going * edge. This means that the leaves of the tree are all hyper-edges with no * children. Such an edge represents a relation (nullary transformer) and thus * a lower bound on its parent. The parameter root must be the root of this tree. - * + * * If Solve returns LBool.False, this indicates success. The annotation of the tree - * has been updated to satisfy the upper bound at the root. - * + * has been updated to satisfy the upper bound at the root. + * * If Solve returns LBool.True, this indicates a counterexample. For each edge, * you can then call Eval to determine the values of symbols in the transformer formula. * You can also call Empty on a node to determine if its value in the counterexample * is the empty relation. - * + * * \param root The root of the tree - * \param persist Number of context pops through which result should persist - * - * + * \param persist Number of context pops through which result should persist + * + * */ lbool Solve(Node *root, int persist); - + /** Same as Solve, but annotates only a single node. */ lbool SolveSingleNode(Node *root, Node *node); /** Get the constraint tree (but don't solve it) */ - + TermTree *GetConstraintTree(Node *root, Node *skip_descendant = 0); - + /** Dispose of the dual model (counterexample) if there is one. */ - + void DisposeDualModel(); /** Check satisfiability of asserted edges and nodes. Same functionality as - * Solve, except no primal solution (interpolant) is generated in the unsat case. */ - - check_result Check(Node *root, std::vector underapproxes = std::vector(), + * Solve, except no primal solution (interpolant) is generated in the unsat case. */ + + check_result Check(Node *root, std::vector underapproxes = std::vector(), std::vector *underapprox_core = 0); /** Update the model, attempting to make the propositional literals in assumps true. If possible, return sat, else return unsat and keep the old model. */ - + check_result CheckUpdateModel(Node *root, std::vector assumps); /** Determines the value in the counterexample of a symbol occuring in the transformer formula of * a given edge. */ - + Term Eval(Edge *e, Term t); - + /** Return the fact derived at node p in a counterexample. */ Term EvalNode(Node *p); - + /** Returns true if the given node is empty in the primal solution. For proecudure summaries, this means that the procedure is not called in the current counter-model. */ - + bool Empty(Node *p); /** Compute an underapproximation of every node in a tree rooted at "root", @@ -747,11 +748,11 @@ namespace Duality { void InterpolateByCases(Node *root, Node *node); /** Push a scope. Assertions made after Push can be undone by Pop. */ - + void Push(); /** Exception thrown when bad clause is encountered */ - + struct bad_clause { std::string msg; int i; @@ -777,7 +778,7 @@ namespace Duality { // thrown on internal error struct Bad { }; - + // thrown on more serious internal error struct ReallyBad { }; @@ -786,56 +787,56 @@ namespace Duality { struct greedy_reduce_failed {}; /** Pop a scope (see Push). Note, you cannot pop axioms. */ - + void Pop(int num_scopes); - + /** Erase the proof by performing a Pop, Push and re-assertion of all the popped constraints */ void PopPush(); /** Return true if the given edge is used in the proof of unsat. Can be called only after Solve or Check returns an unsat result. */ - + bool EdgeUsedInProof(Edge *edge); /** Convert a collection of clauses to Nodes and Edges in the RPFP. - + Predicate unknowns are uninterpreted predicates not occurring in the background theory. - - Clauses are of the form - + + Clauses are of the form + B => P(t_1,...,t_k) - + where P is a predicate unknown and predicate unknowns occur only positivey in H and only under existential quantifiers in prenex form. - + Each predicate unknown maps to a node. Each clause maps to an edge. Let C be a clause B => P(t_1,...,t_k) where the sequence of predicate unknowns occurring in B (in order of occurrence) is P_1..P_n. The clause maps to a transformer T where: - + T.Relparams = P_1..P_n T.Indparams = x_1...x+k T.Formula = B /\ t_1 = x_1 /\ ... /\ t_k = x_k - + Throws exception bad_clause(msg,i) if a clause i is in the wrong form. - + */ - + struct label_struct { symbol name; expr value; bool pos; - label_struct(const symbol &s, const expr &e, bool b) - : name(s), value(e), pos(b) {} + label_struct(const symbol &s, const expr &e, bool b) + : name(s), value(e), pos(b) {} }; - + #ifdef _WINDOWS __declspec(dllexport) #endif @@ -847,7 +848,7 @@ namespace Duality { void WriteCounterexample(std::ostream &s, Node *node); - enum FileFormat {DualityFormat, SMT2Format, HornFormat}; + enum FileFormat {DualityFormat, SMT2Format, HornFormat}; /** Write the RPFP to a file (currently in SMTLIB 1.2 format) */ void WriteProblemToFile(std::string filename, FileFormat format = DualityFormat); @@ -870,9 +871,9 @@ namespace Duality { /** Fuse a vector of transformers. If the total number of inputs of the transformers is N, then the result is an N-ary transfomer whose output is the union of the outputs of the given transformers. The is, suppose we have a vetor of transfoermers - {T_i(r_i1,...,r_iN(i) : i=1..M}. The the result is a transformer - - F(r_11,...,r_iN(1),...,r_M1,...,r_MN(M)) = + {T_i(r_i1,...,r_iN(i) : i=1..M}. The the result is a transformer + + F(r_11,...,r_iN(1),...,r_M1,...,r_MN(M)) = T_1(r_11,...,r_iN(1)) U ... U T_M(r_M1,...,r_MN(M)) */ @@ -921,7 +922,7 @@ namespace Duality { } protected: - + void ClearProofCore(){ if(proof_core) delete proof_core; @@ -929,7 +930,7 @@ namespace Duality { } Term SuffixVariable(const Term &t, int n); - + Term HideVariable(const Term &t, int n); void RedVars(Node *node, Term &b, std::vector &v); @@ -958,16 +959,16 @@ namespace Duality { #if 0 void WriteInterps(System.IO.StreamWriter f, TermTree t); -#endif +#endif void WriteEdgeVars(Edge *e, hash_map &memo, const Term &t, std::ostream &s); void WriteEdgeAssignment(std::ostream &s, Edge *e); - + // Scan the clause body for occurrences of the predicate unknowns - - Term ScanBody(hash_map &memo, + + Term ScanBody(hash_map &memo, const Term &t, hash_map &pmap, std::vector &res, @@ -1035,7 +1036,7 @@ namespace Duality { void ConstrainEdgeLocalized(Edge *e, const Term &t); void GreedyReduce(solver &s, std::vector &conjuncts); - + void NegateLits(std::vector &lits); expr SimplifyOr(std::vector &lits); @@ -1053,7 +1054,7 @@ namespace Duality { void GetGroundLitsUnderQuants(hash_set *memo, const Term &f, std::vector &res, int under); Term StrengthenFormulaByCaseSplitting(const Term &f, std::vector &case_lits); - + expr NegateLit(const expr &f); expr GetEdgeFormula(Edge *e, int persist, bool with_children, bool underapprox); @@ -1065,7 +1066,7 @@ namespace Duality { expr UnhoistPullRec(hash_map & memo, const expr &w, hash_map & init_defs, hash_map & const_params, hash_map &const_params_inv, std::vector &new_params); void AddParamsToTransformer(Transformer &trans, const std::vector ¶ms); - + expr AddParamsToApp(const expr &app, const func_decl &new_decl, const std::vector ¶ms); expr GetRelRec(hash_set &memo, const expr &t, const func_decl &rel); @@ -1081,7 +1082,7 @@ namespace Duality { void UnhoistLoop(Edge *loop_edge, Edge *init_edge); void Unhoist(); - + Term ElimIteRec(hash_map &memo, const Term &t, std::vector &cnsts); Term ElimIte(const Term &t); @@ -1089,11 +1090,11 @@ namespace Duality { void MarkLiveNodes(hash_map > &outgoing, hash_set &live_nodes, Node *node); virtual void slvr_add(const expr &e); - + virtual void slvr_pop(int i); virtual void slvr_push(); - + virtual check_result slvr_check(unsigned n = 0, expr * const assumptions = 0, unsigned *core_size = 0, expr *core = 0); virtual lbool ls_interpolate_tree(TermTree *assumptions, @@ -1105,14 +1106,14 @@ namespace Duality { virtual bool proof_core_contains(const expr &e); }; - + /** RPFP solver base class. */ class Solver { - + public: - + class Counterexample { private: RPFP *tree; @@ -1148,18 +1149,18 @@ namespace Duality { Counterexample &operator=(const Counterexample &); Counterexample(const Counterexample &); }; - + /** Solve the problem. You can optionally give an old counterexample to use as a guide. This is chiefly useful for abstraction refinement metholdologies, and is only used as a heuristic. */ - + virtual bool Solve() = 0; - + virtual Counterexample &GetCounterexample() = 0; - + virtual bool SetOption(const std::string &option, const std::string &value) = 0; - + /** Learn heuristic information from another solver. This is chiefly useful for abstraction refinement, when we want to solve a series of similar problems. */ @@ -1184,7 +1185,7 @@ namespace Duality { /** Object thrown on cancellation */ struct Canceled {}; - + /** Object thrown on incompleteness */ struct Incompleteness {}; }; @@ -1235,16 +1236,16 @@ namespace Duality { public: /** appends assumption literals for edge to lits. if with_children is true, - includes that annotation of the edge's children. - */ + includes that annotation of the edge's children. + */ void AssertEdgeCache(Edge *e, std::vector &lits, bool with_children = false); - + /** appends assumption literals for node to lits */ void AssertNodeCache(Node *, std::vector lits); /** check assumption lits, and return core */ check_result CheckCore(const std::vector &assumps, std::vector &core); - + /** Clone another RPFP into this one, keeping a map */ void Clone(RPFP *other); @@ -1287,7 +1288,7 @@ namespace Duality { uptr slvr; }; hash_map edge_solvers; - + #ifdef LIMIT_STACK_WEIGHT struct weight_counter { int val; @@ -1296,7 +1297,7 @@ namespace Duality { std::swap(val,other.val); } }; - + struct big_stack_entry { weight_counter weight_added; std::vector new_alits; @@ -1319,11 +1320,11 @@ namespace Duality { void ConstrainEdgeLocalizedCache(Edge *e, const Term &tl, std::vector &lits); virtual void slvr_add(const expr &e); - + virtual void slvr_pop(int i); virtual void slvr_push(); - + virtual check_result slvr_check(unsigned n = 0, expr * const assumptions = 0, unsigned *core_size = 0, expr *core = 0); virtual lbool ls_interpolate_tree(TermTree *assumptions, @@ -1348,7 +1349,7 @@ namespace Duality { scoped_solver_for_edge(RPFP_caching *_rpfp, Edge *edge, bool models = false, bool axioms = false){ rpfp = _rpfp; orig_slvr = rpfp->ls->slvr; - es = &(rpfp->SolverForEdge(edge,models,axioms)); + es = &(rpfp->SolverForEdge(edge,models,axioms)); rpfp->ls->slvr = es->slvr.get(); rpfp->AssumptionLits.swap(es->AssumptionLits); } diff --git a/src/duality/duality_wrapper.h b/src/duality/duality_wrapper.h index 8ea8017a2..96c49b36b 100644 --- a/src/duality/duality_wrapper.h +++ b/src/duality/duality_wrapper.h @@ -176,7 +176,7 @@ namespace Duality { m_datalog_fid = m().mk_family_id("datalog_relation"); } ~context() { } - + ast_manager &m() const {return *(ast_manager *)&mgr;} void set(char const * param, char const * value) { m_config.set(param,value); } @@ -186,13 +186,13 @@ namespace Duality { symbol str_symbol(char const * s); symbol int_symbol(int n); - + sort bool_sort(); sort int_sort(); sort real_sort(); sort bv_sort(unsigned sz); sort array_sort(sort d, sort r); - + 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(char const * name, sort const & domain, sort const & range); @@ -210,22 +210,22 @@ namespace Duality { expr int_const(char const * name); expr real_const(char const * name); expr bv_const(char const * name, unsigned sz); - + expr bool_val(bool b); - + expr int_val(int n); expr int_val(unsigned n); expr int_val(char const * n); - + expr real_val(int n, int d); expr real_val(int n); expr real_val(unsigned n); expr real_val(char const * n); - + expr bv_val(int n, unsigned sz); expr bv_val(unsigned n, unsigned sz); expr bv_val(char const * n, unsigned sz); - + expr num_val(int n, sort const & s); expr mki(family_id fid, ::decl_kind dk, int n, ::expr **args); @@ -281,17 +281,17 @@ namespace Duality { object(object const & s):m_ctx(s.m_ctx) {} context & ctx() const { return *m_ctx; } friend void check_context(object const & a, object const & b) { assert(a.m_ctx == b.m_ctx); } - ast_manager &m() const {return m_ctx->m();} + ast_manager &m() const {return m_ctx->m();} }; class symbol : public object { ::symbol m_sym; public: - symbol(context & c, ::symbol s):object(c), m_sym(s) {} - symbol(symbol const & s):object(s), m_sym(s.m_sym) {} + symbol(context & c, ::symbol s):object(c), m_sym(s) {} + symbol(symbol const & s):object(s), m_sym(s.m_sym) {} symbol & operator=(symbol const & s) { m_ctx = s.m_ctx; m_sym = s.m_sym; return *this; } - operator ::symbol() const {return m_sym;} - std::string str() const { + operator ::symbol() const {return m_sym;} + std::string str() const { if (m_sym.is_numerical()) { std::ostringstream buffer; buffer << m_sym.get_num(); @@ -300,13 +300,13 @@ namespace Duality { else { return m_sym.bare_str(); } - } - friend std::ostream & operator<<(std::ostream & out, symbol const & s){ + } + friend std::ostream & operator<<(std::ostream & out, symbol const & s) { return out << s.str(); - } - friend bool operator==(const symbol &x, const symbol &y){ + } + friend bool operator==(const symbol &x, const symbol &y) { return x.m_sym == y.m_sym; - } + } }; class params : public config {}; @@ -318,7 +318,7 @@ namespace Duality { public: ::ast * const &raw() const {return _ast;} ast_i(context & c, ::ast *a = 0) : object(c) {_ast = a;} - + ast_i(){_ast = 0;} bool eq(const ast_i &other) const { return _ast == other._ast; @@ -345,19 +345,19 @@ namespace Duality { operator ::ast*() const { return raw(); } friend bool eq(ast const & a, ast const & b) { return a.raw() == b.raw(); } - + ast(context &c, ::ast *a = 0) : ast_i(c,a) { if(_ast) m().inc_ref(a); } - + ast() {} - + ast(const ast &other) : ast_i(other) { if(_ast) m().inc_ref(_ast); } - + ast &operator=(const ast &other) { if(_ast) m().dec_ref(_ast); @@ -367,7 +367,7 @@ namespace Duality { m().inc_ref(_ast); return *this; } - + ~ast(){ if(_ast) m().dec_ref(_ast); @@ -386,15 +386,15 @@ namespace Duality { sort & operator=(sort const & s) { return static_cast(ast::operator=(s)); } bool is_bool() const { return m().is_bool(*this); } - bool is_int() const { return ctx().get_sort_kind(*this) == IntSort; } - bool is_real() const { return ctx().get_sort_kind(*this) == RealSort; } + bool is_int() const { return ctx().get_sort_kind(*this) == IntSort; } + bool is_real() const { return ctx().get_sort_kind(*this) == RealSort; } bool is_arith() const; - bool is_array() const { return ctx().get_sort_kind(*this) == ArraySort; } - bool is_datatype() const; - bool is_relation() const; - bool is_finite_domain() const; + bool is_array() const { return ctx().get_sort_kind(*this) == ArraySort; } + bool is_datatype() const; + bool is_relation() const; + bool is_finite_domain() const; + - sort array_domain() const; sort array_range() const; @@ -404,7 +404,7 @@ namespace Duality { } }; - + class func_decl : public ast { public: func_decl() : ast() {} @@ -413,7 +413,7 @@ namespace Duality { func_decl(func_decl const & s):ast(s) {} operator ::func_decl*() const { return to_func_decl(*this); } func_decl & operator=(func_decl const & s) { return static_cast(ast::operator=(s)); } - + unsigned arity() const; sort domain(unsigned i) const; sort range() const; @@ -434,9 +434,9 @@ namespace Duality { expr operator()(expr const & a1, expr const & a2, expr const & a3, expr const & a4) const; expr operator()(expr const & a1, expr const & a2, expr const & a3, expr const & a4, expr const & a5) const; - func_decl get_func_decl_parameter(unsigned idx){ + func_decl get_func_decl_parameter(unsigned idx){ return func_decl(ctx(),to_func_decl(to_func_decl(raw())->get_parameters()[idx].get_ast())); - } + } }; @@ -447,8 +447,8 @@ namespace Duality { expr(context & c, ::ast *n):ast(c, n) {} expr(expr const & n):ast(n) {} expr & operator=(expr const & n) { return static_cast(ast::operator=(n)); } - operator ::expr*() const { return to_expr(raw()); } - unsigned get_id() const {return to_expr(raw())->get_id();} + operator ::expr*() const { return to_expr(raw()); } + unsigned get_id() const {return to_expr(raw())->get_id();} sort get_sort() const { return sort(ctx(),m().get_sort(to_expr(raw()))); } @@ -460,27 +460,27 @@ namespace Duality { bool is_datatype() const { return get_sort().is_datatype(); } bool is_relation() const { return get_sort().is_relation(); } bool is_finite_domain() const { return get_sort().is_finite_domain(); } - bool is_true() const {return is_app() && decl().get_decl_kind() == True; } + bool is_true() const {return is_app() && decl().get_decl_kind() == True; } bool is_numeral() const { return is_app() && decl().get_decl_kind() == OtherArith && m().is_unique_value(to_expr(raw())); - } - bool is_app() const {return raw()->get_kind() == AST_APP;} + } + bool is_app() const {return raw()->get_kind() == AST_APP;} bool is_quantifier() const {return raw()->get_kind() == AST_QUANTIFIER;} bool is_var() const {return raw()->get_kind() == AST_VAR;} - bool is_label (bool &pos,std::vector &names) const ; - bool is_ground() const {return to_app(raw())->is_ground();} - bool has_quantifiers() const {return to_app(raw())->has_quantifiers();} - bool has_free(int idx) const { + bool is_label (bool &pos,std::vector &names) const ; + bool is_ground() const {return to_app(raw())->is_ground();} + bool has_quantifiers() const {return to_app(raw())->has_quantifiers();} + bool has_free(int idx) const { used_vars proc; proc.process(to_expr(raw())); return proc.contains(idx); - } - unsigned get_max_var_idx_plus_1() const { + } + unsigned get_max_var_idx_plus_1() const { used_vars proc; proc.process(to_expr(raw())); return proc.get_max_found_var_idx_plus_1(); - } + } // operator Z3_app() const { assert(is_app()); return reinterpret_cast(m_ast); } func_decl decl() const {return func_decl(ctx(),to_app(raw())->get_decl());} @@ -493,11 +493,11 @@ namespace Duality { return 1; case AST_VAR: return 0; - default:; + default:; } SASSERT(0); return 0; - } + } expr arg(unsigned i) const { ast_kind dk = raw()->get_kind(); switch(dk){ @@ -509,25 +509,25 @@ namespace Duality { } assert(0); return expr(); - } + } expr body() const { return ctx().cook(to_quantifier(raw())->get_expr()); - } + } friend expr operator!(expr const & a) { // ::expr *e = a; return expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_NOT,a)); - } + } friend expr operator&&(expr const & a, expr const & b) { return expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_AND,a,b)); - } + } friend expr operator||(expr const & a, expr const & b) { return expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_OR,a,b)); } - + friend expr implies(expr const & a, expr const & b) { return expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_IMPLIES,a,b)); } @@ -546,12 +546,12 @@ namespace Duality { friend expr operator*(expr const & a, expr const & b) { return a.ctx().make(Times,a,b); // expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_MUL,a,b)); - } + } friend expr operator/(expr const & a, expr const & b) { return a.ctx().make(Div,a,b); // expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_DIV,a,b)); } - + friend expr operator-(expr const & a) { return a.ctx().make(Uminus,a); // expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_UMINUS,a)); } @@ -562,71 +562,71 @@ namespace Duality { friend expr operator<=(expr const & a, expr const & b) { return a.ctx().make(Leq,a,b); // expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_LE,a,b)); - } + } friend expr operator>=(expr const & a, expr const & b) { return a.ctx().make(Geq,a,b); //expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_GE,a,b)); } - + friend expr operator<(expr const & a, expr const & b) { return a.ctx().make(Lt,a,b); expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_LT,a,b)); } - + friend expr operator>(expr const & a, expr const & b) { return a.ctx().make(Gt,a,b); expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_GT,a,b)); - } + } expr simplify() const; expr simplify(params const & p) const; - + expr qe_lite() const; - expr qe_lite(const std::set &idxs, bool index_of_bound) const; + expr qe_lite(const std::set &idxs, bool index_of_bound) const; - friend expr clone_quantifier(const expr &, const expr &); + friend expr clone_quantifier(const expr &, const expr &); friend expr clone_quantifier(const expr &q, const expr &b, const std::vector &patterns); - friend expr clone_quantifier(decl_kind, const expr &, const expr &); + friend expr clone_quantifier(decl_kind, const expr &, const expr &); friend std::ostream & operator<<(std::ostream & out, expr const & m){ m.ctx().print_expr(out,m); return out; - } + } - void get_patterns(std::vector &pats) const ; + void get_patterns(std::vector &pats) const ; - unsigned get_quantifier_num_bound() const { + unsigned get_quantifier_num_bound() const { return to_quantifier(raw())->get_num_decls(); - } + } - unsigned get_index_value() const { + unsigned get_index_value() const { var* va = to_var(raw()); return va->get_idx(); - } + } bool is_quantifier_forall() const { return to_quantifier(raw())->is_forall(); - } + } - sort get_quantifier_bound_sort(unsigned n) const { + sort get_quantifier_bound_sort(unsigned n) const { return sort(ctx(),to_quantifier(raw())->get_decl_sort(n)); - } + } - symbol get_quantifier_bound_name(unsigned n) const { + symbol get_quantifier_bound_name(unsigned n) const { return symbol(ctx(),to_quantifier(raw())->get_decl_names()[n]); - } + } - friend expr forall(const std::vector &quants, const expr &body); + friend expr forall(const std::vector &quants, const expr &body); - friend expr exists(const std::vector &quants, const expr &body); + friend expr exists(const std::vector &quants, const expr &body); }; - + typedef ::decl_kind pfrule; - + class proof : public ast { public: proof(context & c):ast(c) {} @@ -643,15 +643,15 @@ namespace Duality { unsigned num_prems() const { return to_app(raw())->get_num_args() - 1; } - + expr conc() const { return ctx().cook(to_app(raw())->get_arg(num_prems())); } - + proof prem(unsigned i) const { return proof(ctx(),to_app(to_app(raw())->get_arg(i))); } - + void get_assumptions(std::vector &assumps); }; @@ -675,12 +675,12 @@ namespace Duality { T back() const { return operator[](size() - 1); } void pop_back() { assert(size() > 0); resize(size() - 1); } bool empty() const { return size() == 0; } - ast_vector_tpl & operator=(ast_vector_tpl const & s) { - Z3_ast_vector_inc_ref(s.ctx(), s.m_vector); + ast_vector_tpl & operator=(ast_vector_tpl const & s) { + Z3_ast_vector_inc_ref(s.ctx(), s.m_vector); // Z3_ast_vector_dec_ref(ctx(), m_vector); - m_ctx = s.m_ctx; + m_ctx = s.m_ctx; m_vector = s.m_vector; - return *this; + return *this; } friend std::ostream & operator<<(std::ostream & out, ast_vector_tpl const & v) { out << Z3_ast_vector_to_string(v.ctx(), v); return out; } }; @@ -705,9 +705,9 @@ namespace Duality { ~func_interp() { } operator ::func_interp *() const { return m_interp; } func_interp & operator=(func_interp const & s) { - m_ctx = s.m_ctx; + m_ctx = s.m_ctx; m_interp = s.m_interp; - return *this; + return *this; } unsigned num_entries() const { return m_interp->num_entries(); } expr get_arg(unsigned ent, unsigned arg) const { @@ -729,32 +729,32 @@ namespace Duality { m_model = m; } public: - model(context & c, ::model * m = 0):object(c), m_model(m) { } - model(model const & s):object(s), m_model(s.m_model) { } - ~model() { } + model(context & c, ::model * m = 0):object(c), m_model(m) { } + model(model const & s):object(s), m_model(s.m_model) { } + ~model() { } operator ::model *() const { return m_model.get(); } model & operator=(model const & s) { // ::model *_inc_ref(s.ctx(), s.m_model); // ::model *_dec_ref(ctx(), m_model); - m_ctx = s.m_ctx; + m_ctx = s.m_ctx; m_model = s.m_model.get(); - return *this; + return *this; } model & operator=(::model *s) { - m_model = s; - return *this; + m_model = s; + return *this; } - bool null() const {return !m_model;} - + bool null() const {return !m_model;} + expr eval(expr const & n, bool model_completion=true) const { ::model * _m = m_model.get(); expr_ref result(ctx().m()); _m->eval(n, result, model_completion); return expr(ctx(), result); } - + void show() const; - void show_hash() const; + void show_hash() const; unsigned num_consts() const {return m_model.get()->get_num_constants();} unsigned num_funcs() const {return m_model.get()->get_num_functions();} @@ -765,11 +765,11 @@ namespace Duality { expr get_const_interp(func_decl f) const { return ctx().cook(m_model->get_const_interp(to_func_decl(f.raw()))); - } + } func_interp get_func_interp(func_decl f) const { return func_interp(ctx(),m_model->get_func_interp(to_func_decl(f.raw()))); - } + } #if 0 friend std::ostream & operator<<(std::ostream & out, model const & m) { out << Z3_model_to_string(m.ctx(), m); return out; } @@ -792,9 +792,9 @@ namespace Duality { stats & operator=(stats const & s) { Z3_stats_inc_ref(s.ctx(), s.m_stats); if (m_stats) Z3_stats_dec_ref(ctx(), m_stats); - m_ctx = s.m_ctx; + m_ctx = s.m_ctx; m_stats = s.m_stats; - return *this; + return *this; } unsigned size() const { return Z3_stats_size(ctx(), m_stats); } std::string key(unsigned i) const { Z3_string s = Z3_stats_get_key(ctx(), m_stats, i); check_error(); return s; } @@ -820,7 +820,7 @@ namespace Duality { void assert_cnst(const expr &cnst); }; - inline std::ostream & operator<<(std::ostream & out, check_result r) { + inline std::ostream & operator<<(std::ostream & out, check_result r) { if (r == unsat) out << "unsat"; else if (r == sat) out << "sat"; else out << "unknown"; @@ -837,54 +837,54 @@ namespace Duality { protected: ::solver *m_solver; model the_model; - bool canceled; - proof_gen_mode m_mode; - bool extensional; + bool canceled; + proof_gen_mode m_mode; + bool extensional; public: solver(context & c, bool extensional = false, bool models = true); - solver(context & c, ::solver *s):object(c),the_model(c) { m_solver = s; canceled = false;} - solver(solver const & s):object(s), the_model(s.the_model) { m_solver = s.m_solver; canceled = false;} + solver(context & c, ::solver *s):object(c),the_model(c) { m_solver = s; canceled = false;} + solver(solver const & s):object(s), the_model(s.the_model) { m_solver = s.m_solver; canceled = false;} ~solver() { if(m_solver) dealloc(m_solver); - } - operator ::solver*() const { return m_solver; } - solver & operator=(solver const & s) { - m_ctx = s.m_ctx; - m_solver = s.m_solver; - the_model = s.the_model; - m_mode = s.m_mode; - return *this; } - struct cancel_exception {}; - void checkpoint(){ + operator ::solver*() const { return m_solver; } + solver & operator=(solver const & s) { + m_ctx = s.m_ctx; + m_solver = s.m_solver; + the_model = s.the_model; + m_mode = s.m_mode; + return *this; + } + struct cancel_exception {}; + void checkpoint(){ if(canceled) throw(cancel_exception()); - } + } // void set(params const & p) { Z3_solver_set_params(ctx(), m_solver, p); check_error(); } void push() { scoped_proof_mode spm(m(),m_mode); m_solver->push(); } void pop(unsigned n = 1) { scoped_proof_mode spm(m(),m_mode); m_solver->pop(n); } // void reset() { Z3_solver_reset(ctx(), m_solver); check_error(); } void add(expr const & e) { scoped_proof_mode spm(m(),m_mode); m_solver->assert_expr(e); } - check_result check() { - scoped_proof_mode spm(m(),m_mode); + check_result check() { + scoped_proof_mode spm(m(),m_mode); checkpoint(); lbool r = m_solver->check_sat(0,0); model_ref m; m_solver->get_model(m); the_model = m.get(); return to_check_result(r); - } - check_result check_keep_model(unsigned n, expr * const assumptions, unsigned *core_size = 0, expr *core = 0) { - scoped_proof_mode spm(m(),m_mode); + } + check_result check_keep_model(unsigned n, expr * const assumptions, unsigned *core_size = 0, expr *core = 0) { + scoped_proof_mode spm(m(),m_mode); model old_model(the_model); check_result res = check(n,assumptions,core_size,core); if(the_model == 0) the_model = old_model; return res; - } + } check_result check(unsigned n, expr * const assumptions, unsigned *core_size = 0, expr *core = 0) { - scoped_proof_mode spm(m(),m_mode); + scoped_proof_mode spm(m(),m_mode); checkpoint(); std::vector< ::expr *> _assumptions(n); for (unsigned i = 0; i < n; i++) { @@ -892,7 +892,7 @@ namespace Duality { } the_model = 0; lbool r = m_solver->check_sat(n, VEC2PTR(_assumptions)); - + if(core_size && core){ ptr_vector< ::expr> _core; m_solver->get_unsat_core(_core); @@ -905,20 +905,20 @@ namespace Duality { m_solver->get_model(m); the_model = m.get(); - return to_check_result(r); + return to_check_result(r); } #if 0 - check_result check(expr_vector assumptions) { - scoped_proof_mode spm(m(),m_mode); + check_result check(expr_vector assumptions) { + scoped_proof_mode spm(m(),m_mode); unsigned n = assumptions.size(); z3array _assumptions(n); for (unsigned i = 0; i < n; i++) { check_context(*this, assumptions[i]); _assumptions[i] = assumptions[i]; } - Z3_lbool r = Z3_check_assumptions(ctx(), m_solver, n, _assumptions.ptr()); - check_error(); - return to_check_result(r); + Z3_lbool r = Z3_check_assumptions(ctx(), m_solver, n, _assumptions.ptr()); + check_error(); + return to_check_result(r); } #endif model get_model() const { return model(ctx(), the_model); } @@ -930,27 +930,26 @@ namespace Duality { #endif // expr proof() const { Z3_ast r = Z3_solver_proof(ctx(), m_solver); check_error(); return expr(ctx(), r); } // friend std::ostream & operator<<(std::ostream & out, solver const & s) { out << Z3_solver_to_string(s.ctx(), s); return out; } - - int get_num_decisions(); + int get_num_decisions(); - void cancel(){ - scoped_proof_mode spm(m(),m_mode); + void cancel(){ + scoped_proof_mode spm(m(),m_mode); canceled = true; m().limit().cancel(); - } + } - unsigned get_scope_level(){ scoped_proof_mode spm(m(),m_mode); return m_solver->get_scope_level();} + unsigned get_scope_level(){ scoped_proof_mode spm(m(),m_mode); return m_solver->get_scope_level();} - void show(); - void print(const char *filename); - void show_assertion_ids(); + void show(); + void print(const char *filename); + void show_assertion_ids(); - proof get_proof(){ - scoped_proof_mode spm(m(),m_mode); + proof get_proof(){ + scoped_proof_mode spm(m(),m_mode); return proof(ctx(),m_solver->get_proof()); - } + } - bool extensional_array_theory() {return extensional;} + bool extensional_array_theory() {return extensional;} }; #if 0 @@ -969,20 +968,20 @@ namespace Duality { goal & operator=(goal const & s) { Z3_goal_inc_ref(s.ctx(), s.m_goal); Z3_goal_dec_ref(ctx(), m_goal); - m_ctx = s.m_ctx; + m_ctx = s.m_ctx; m_goal = s.m_goal; - return *this; + return *this; } void add(expr const & f) { check_context(*this, f); Z3_goal_assert(ctx(), m_goal, f); check_error(); } unsigned size() const { return Z3_goal_size(ctx(), m_goal); } expr operator[](unsigned i) const { Z3_ast r = Z3_goal_formula(ctx(), m_goal, i); check_error(); return expr(ctx(), r); } Z3_goal_prec precision() const { return Z3_goal_precision(ctx(), m_goal); } bool inconsistent() const { return Z3_goal_inconsistent(ctx(), m_goal) != 0; } - unsigned depth() const { return Z3_goal_depth(ctx(), m_goal); } + unsigned depth() const { return Z3_goal_depth(ctx(), m_goal); } void reset() { Z3_goal_reset(ctx(), m_goal); } unsigned num_exprs() const { Z3_goal_num_exprs(ctx(), m_goal); } - bool is_decided_sat() const { return Z3_goal_is_decided_sat(ctx(), m_goal) != 0; } - bool is_decided_unsat() const { return Z3_goal_is_decided_unsat(ctx(), m_goal) != 0; } + bool is_decided_sat() const { return Z3_goal_is_decided_sat(ctx(), m_goal) != 0; } + bool is_decided_unsat() const { return Z3_goal_is_decided_unsat(ctx(), m_goal) != 0; } friend std::ostream & operator<<(std::ostream & out, goal const & g) { out << Z3_goal_to_string(g.ctx(), g); return out; } }; @@ -1000,15 +999,15 @@ namespace Duality { apply_result & operator=(apply_result const & s) { Z3_apply_result_inc_ref(s.ctx(), s.m_apply_result); Z3_apply_result_dec_ref(ctx(), m_apply_result); - m_ctx = s.m_ctx; + m_ctx = s.m_ctx; m_apply_result = s.m_apply_result; - return *this; + return *this; } unsigned size() const { return Z3_apply_result_get_num_subgoals(ctx(), m_apply_result); } goal operator[](unsigned i) const { Z3_goal r = Z3_apply_result_get_subgoal(ctx(), m_apply_result, i); check_error(); return goal(ctx(), r); } goal operator[](int i) const { assert(i >= 0); return this->operator[](static_cast(i)); } - model convert_model(model const & m, unsigned i = 0) const { - check_context(*this, m); + model convert_model(model const & m, unsigned i = 0) const { + check_context(*this, m); Z3_model new_m = Z3_apply_result_convert_model(ctx(), m_apply_result, i, m); check_error(); return model(ctx(), new_m); @@ -1031,16 +1030,16 @@ namespace Duality { tactic & operator=(tactic const & s) { Z3_tactic_inc_ref(s.ctx(), s.m_tactic); Z3_tactic_dec_ref(ctx(), m_tactic); - m_ctx = s.m_ctx; + m_ctx = s.m_ctx; m_tactic = s.m_tactic; - return *this; + return *this; } solver mk_solver() const { Z3_solver r = Z3_mk_solver_from_tactic(ctx(), m_tactic); check_error(); return solver(ctx(), r); } - apply_result apply(goal const & g) const { + apply_result apply(goal const & g) const { check_context(*this, g); - Z3_apply_result r = Z3_tactic_apply(ctx(), m_tactic, g); - check_error(); - return apply_result(ctx(), r); + Z3_apply_result r = Z3_tactic_apply(ctx(), m_tactic, g); + check_error(); + return apply_result(ctx(), r); } apply_result operator()(goal const & g) const { return apply(g); @@ -1091,45 +1090,45 @@ namespace Duality { probe & operator=(probe const & s) { Z3_probe_inc_ref(s.ctx(), s.m_probe); Z3_probe_dec_ref(ctx(), m_probe); - m_ctx = s.m_ctx; + m_ctx = s.m_ctx; m_probe = s.m_probe; - return *this; + return *this; } double apply(goal const & g) const { double r = Z3_probe_apply(ctx(), m_probe, g); check_error(); return r; } double operator()(goal const & g) const { return apply(g); } - friend probe operator<=(probe const & p1, probe const & p2) { - check_context(p1, p2); Z3_probe r = Z3_probe_le(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); + friend probe operator<=(probe const & p1, probe const & p2) { + check_context(p1, p2); Z3_probe r = Z3_probe_le(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); } friend probe operator<=(probe const & p1, double p2) { return p1 <= probe(p1.ctx(), p2); } friend probe operator<=(double p1, probe const & p2) { return probe(p2.ctx(), p1) <= p2; } - friend probe operator>=(probe const & p1, probe const & p2) { - check_context(p1, p2); Z3_probe r = Z3_probe_ge(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); + friend probe operator>=(probe const & p1, probe const & p2) { + check_context(p1, p2); Z3_probe r = Z3_probe_ge(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); } friend probe operator>=(probe const & p1, double p2) { return p1 >= probe(p1.ctx(), p2); } friend probe operator>=(double p1, probe const & p2) { return probe(p2.ctx(), p1) >= p2; } - friend probe operator<(probe const & p1, probe const & p2) { - check_context(p1, p2); Z3_probe r = Z3_probe_lt(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); + friend probe operator<(probe const & p1, probe const & p2) { + check_context(p1, p2); Z3_probe r = Z3_probe_lt(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); } friend probe operator<(probe const & p1, double p2) { return p1 < probe(p1.ctx(), p2); } friend probe operator<(double p1, probe const & p2) { return probe(p2.ctx(), p1) < p2; } - friend probe operator>(probe const & p1, probe const & p2) { - check_context(p1, p2); Z3_probe r = Z3_probe_gt(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); + friend probe operator>(probe const & p1, probe const & p2) { + check_context(p1, p2); Z3_probe r = Z3_probe_gt(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); } friend probe operator>(probe const & p1, double p2) { return p1 > probe(p1.ctx(), p2); } friend probe operator>(double p1, probe const & p2) { return probe(p2.ctx(), p1) > p2; } - friend probe operator==(probe const & p1, probe const & p2) { - check_context(p1, p2); Z3_probe r = Z3_probe_eq(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); + friend probe operator==(probe const & p1, probe const & p2) { + check_context(p1, p2); Z3_probe r = Z3_probe_eq(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); } friend probe operator==(probe const & p1, double p2) { return p1 == probe(p1.ctx(), p2); } friend probe operator==(double p1, probe const & p2) { return probe(p2.ctx(), p1) == p2; } - friend probe operator&&(probe const & p1, probe const & p2) { - check_context(p1, p2); Z3_probe r = Z3_probe_and(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); + friend probe operator&&(probe const & p1, probe const & p2) { + check_context(p1, p2); Z3_probe r = Z3_probe_and(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); } - friend probe operator||(probe const & p1, probe const & p2) { - check_context(p1, p2); Z3_probe r = Z3_probe_or(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); + friend probe operator||(probe const & p1, probe const & p2) { + check_context(p1, p2); Z3_probe r = Z3_probe_or(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); } friend probe operator!(probe const & p) { - Z3_probe r = Z3_probe_not(p.ctx(), p); p.check_error(); return probe(p.ctx(), r); + Z3_probe r = Z3_probe_not(p.ctx(), p); p.check_error(); return probe(p.ctx(), r); } }; @@ -1159,15 +1158,15 @@ namespace Duality { inline symbol context::int_symbol(int n) { ::symbol r = ::symbol(n); return symbol(*this, r); } inline sort context::bool_sort() { - ::sort *s = m().mk_sort(m_basic_fid, BOOL_SORT); + ::sort *s = m().mk_sort(m_basic_fid, BOOL_SORT); return sort(*this, s); } inline sort context::int_sort() { - ::sort *s = m().mk_sort(m_arith_fid, INT_SORT); + ::sort *s = m().mk_sort(m_arith_fid, INT_SORT); return sort(*this, s); } inline sort context::real_sort() { - ::sort *s = m().mk_sort(m_arith_fid, REAL_SORT); + ::sort *s = m().mk_sort(m_arith_fid, REAL_SORT); return sort(*this, s); } inline sort context::array_sort(sort d, sort r) { @@ -1188,7 +1187,7 @@ namespace Duality { inline func_decl context::function(char const * name, unsigned arity, sort const * domain, sort const & range) { return function(str_symbol(name), arity, domain, range); } - + inline func_decl context::function(char const * name, sort const & domain, sort const & range) { sort args[1] = { domain }; return function(name, 1, args, range); @@ -1196,7 +1195,7 @@ namespace Duality { inline func_decl context::function(char const * name, sort const & d1, sort const & d2, sort const & range) { sort args[2] = { d1, d2 }; - return function(name, 2, args, range); + return function(name, 2, args, range); } inline func_decl context::function(char const * name, sort const & d1, sort const & d2, sort const & d3, sort const & range) { @@ -1208,7 +1207,7 @@ namespace Duality { sort args[4] = { d1, d2, d3, d4 }; return function(name, 4, args, range); } - + inline func_decl context::function(char const * name, sort const & d1, sort const & d2, sort const & d3, sort const & d4, sort const & d5, sort const & range) { sort args[5] = { d1, d2, d3, d4, d5 }; return function(name, 5, args, range); @@ -1217,7 +1216,7 @@ namespace Duality { inline expr context::constant(symbol const & name, sort const & s) { ::expr *r = m().mk_const(m().mk_const_decl(name, s)); - return expr(*this, r); + return expr(*this, r); } inline expr context::constant(char const * name, sort const & s) { return constant(str_symbol(name), s); } inline expr context::bool_const(char const * name) { return constant(name, bool_sort()); } @@ -1250,11 +1249,11 @@ namespace Duality { expr args[5] = {a1,a2,a3,a4,a5}; return operator()(5,args); } - - + + inline expr select(expr const & a, expr const & i) { return a.ctx().make(Select,a,i); } inline expr store(expr const & a, expr const & i, expr const & v) { return a.ctx().make(Store,a,i,v); } - + inline expr forall(const std::vector &quants, const expr &body){ return body.ctx().make_quant(Forall,quants,body); } @@ -1304,7 +1303,7 @@ namespace Duality { } inline void setTerm(expr t){term = t;} - + inline void addTerm(expr t){terms.push_back(t);} inline void setChildren(const std::vector & _children){ @@ -1326,7 +1325,7 @@ namespace Duality { std::vector children; int num; }; - + typedef context interpolating_context; class interpolating_solver : public solver { @@ -1336,7 +1335,7 @@ namespace Duality { { weak_mode = false; } - + public: lbool interpolate(const std::vector &assumptions, std::vector &interpolants, @@ -1344,41 +1343,41 @@ namespace Duality { literals &lits, bool incremental ); - + lbool interpolate_tree(TermTree *assumptions, TermTree *&interpolants, model &_model, literals &lits, bool incremental ); - + bool read_interpolation_problem(const std::string &file_name, std::vector &assumptions, std::vector &theory, std::string &error_message ); - + void write_interpolation_problem(const std::string &file_name, const std::vector &assumptions, const std::vector &theory ); - + void AssertInterpolationAxiom(const expr &expr); void RemoveInterpolationAxiom(const expr &expr); - + void SetWeakInterpolants(bool weak); void SetPrintToFile(const std::string &file_name); - + const std::vector &GetInterpolationAxioms() {return theory;} const char *profile(); - + private: bool weak_mode; std::string print_filename; std::vector theory; }; - - + + inline expr context::cook(::expr *a) {return expr(*this,a);} inline std::vector context::cook(ptr_vector< ::expr> v) { diff --git a/src/interp/iz3base.h b/src/interp/iz3base.h index ac171aa9e..15f613730 100755 --- a/src/interp/iz3base.h +++ b/src/interp/iz3base.h @@ -66,35 +66,35 @@ class iz3base : public iz3mgr, public scopes { /** Constructor */ - iz3base(ast_manager &_m_manager, - const std::vector &_cnsts, - const std::vector &_parents, - const std::vector &_theory) - : iz3mgr(_m_manager), scopes(_parents) { + iz3base(ast_manager &_m_manager, + const std::vector &_cnsts, + const std::vector &_parents, + const std::vector &_theory) + : iz3mgr(_m_manager), scopes(_parents) { initialize(_cnsts,_parents,_theory); weak = false; } - iz3base(const iz3mgr& other, - const std::vector &_cnsts, - const std::vector &_parents, - const std::vector &_theory) - : iz3mgr(other), scopes(_parents) { + iz3base(const iz3mgr& other, + const std::vector &_cnsts, + const std::vector &_parents, + const std::vector &_theory) + : iz3mgr(other), scopes(_parents) { initialize(_cnsts,_parents,_theory); weak = false; } - iz3base(const iz3mgr& other, - const std::vector > &_cnsts, - const std::vector &_parents, - const std::vector &_theory) - : iz3mgr(other), scopes(_parents) { + iz3base(const iz3mgr& other, + const std::vector > &_cnsts, + const std::vector &_parents, + const std::vector &_theory) + : iz3mgr(other), scopes(_parents) { initialize(_cnsts,_parents,_theory); weak = false; } - iz3base(const iz3mgr& other) - : iz3mgr(other), scopes() { + iz3base(const iz3mgr& other) + : iz3mgr(other), scopes() { weak = false; } diff --git a/src/interp/iz3checker.h b/src/interp/iz3checker.h index 175b5a43a..d89db3011 100644 --- a/src/interp/iz3checker.h +++ b/src/interp/iz3checker.h @@ -24,26 +24,26 @@ #include "solver/solver.h" 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); 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); bool iz3check(iz3mgr &mgr, - solver *s, - std::ostream &err, - const std::vector &cnsts, - const std::vector &parents, - const std::vector &interps, - const ptr_vector &theory); + solver *s, + std::ostream &err, + const std::vector &cnsts, + const std::vector &parents, + const std::vector &interps, + const ptr_vector &theory); #endif diff --git a/src/interp/iz3hash.h b/src/interp/iz3hash.h index 483c7ca49..c796a247b 100644 --- a/src/interp/iz3hash.h +++ b/src/interp/iz3hash.h @@ -468,10 +468,10 @@ namespace hash_space { : hashtable,Key,HashFun,proj1,EqFun>(7) {} Value &operator[](const Key& key) { - std::pair kvp(key,Value()); - return - hashtable,Key,HashFun,proj1,EqFun>:: - lookup(kvp,true)->val.second; + std::pair kvp(key,Value()); + return + hashtable,Key,HashFun,proj1,EqFun>:: + lookup(kvp,true)->val.second; } }; diff --git a/src/interp/iz3interp.h b/src/interp/iz3interp.h index 9763208f1..a4e1024a9 100644 --- a/src/interp/iz3interp.h +++ b/src/interp/iz3interp.h @@ -73,22 +73,22 @@ typedef interpolation_options_struct *interpolation_options; representation, for compatibility with the old API. */ 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 = 0); + ast *proof, + const ptr_vector &cnsts, + const ::vector &parents, + ptr_vector &interps, + const ptr_vector &theory, + interpolation_options_struct * options = 0); /* Same as above, but each constraint is a vector of formulas. */ 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 = 0); + ast *proof, + const vector > &cnsts, + const ::vector &parents, + ptr_vector &interps, + const ptr_vector &theory, + interpolation_options_struct * options = 0); /* Compute an interpolant from a proof. This version uses the ast representation, for compatibility with the new API. Here, cnsts is @@ -98,11 +98,11 @@ void iz3interpolate(ast_manager &_m_manager, proof, so it can be considered a hint. */ 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); /* Compute an interpolant from an ast representing an interpolation @@ -112,12 +112,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); #endif diff --git a/src/interp/iz3pp.h b/src/interp/iz3pp.h index eec88d35e..7b3405f9b 100644 --- a/src/interp/iz3pp.h +++ b/src/interp/iz3pp.h @@ -30,7 +30,7 @@ struct iz3pp_bad_tree: public iz3_exception { }; 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); #endif diff --git a/src/interp/iz3scopes.h b/src/interp/iz3scopes.h index 745256e57..ece30dc25 100755 --- a/src/interp/iz3scopes.h +++ b/src/interp/iz3scopes.h @@ -105,7 +105,7 @@ class scopes { void range_add(int i, range &n){ #if 0 - if(i < n.lo) n.lo = i; + if(i < n.lo) n.lo = i; if(i > n.hi) n.hi = i; #else range rng; rng.lo = i; rng.hi = i; @@ -119,7 +119,7 @@ class scopes { int thing = tree_lca(rng1.lo,rng2.hi); if(thing == rng1.lo) frame = rng1.lo; else frame = tree_gcd(thing,rng1.hi); - return frame; + return frame; } #else diff --git a/src/interp/iz3translate.h b/src/interp/iz3translate.h index 3430d11b3..519a252e0 100755 --- a/src/interp/iz3translate.h +++ b/src/interp/iz3translate.h @@ -47,9 +47,9 @@ class iz3translation : public iz3base { protected: iz3translation(iz3mgr &mgr, - const std::vector > &_cnsts, - const std::vector &_parents, - const std::vector &_theory) + const std::vector > &_cnsts, + const std::vector &_parents, + const std::vector &_theory) : iz3base(mgr,_cnsts,_parents,_theory) {} }; diff --git a/src/math/automata/automaton.h b/src/math/automata/automaton.h index 07d6d31ec..41fc19907 100644 --- a/src/math/automata/automaton.h +++ b/src/math/automata/automaton.h @@ -478,7 +478,7 @@ public: unsigned out_degree(unsigned state) const { return m_delta[state].size(); } move const& get_move_from(unsigned state) const { SASSERT(m_delta[state].size() == 1); return m_delta[state][0]; } move const& get_move_to(unsigned state) const { SASSERT(m_delta_inv[state].size() == 1); return m_delta_inv[state][0]; } - moves const& get_moves_from(unsigned state) const { return m_delta[state]; } + moves const& get_moves_from(unsigned state) const { return m_delta[state]; } moves const& get_moves_to(unsigned state) const { return m_delta_inv[state]; } bool initial_state_is_source() const { return m_delta_inv[m_init].empty(); } bool is_final_state(unsigned s) const { return m_final_set.contains(s); } diff --git a/src/math/automata/boolean_algebra.h b/src/math/automata/boolean_algebra.h index e49d414c4..d54ff5d1a 100644 --- a/src/math/automata/boolean_algebra.h +++ b/src/math/automata/boolean_algebra.h @@ -40,9 +40,7 @@ template class boolean_algebra : public positive_boolean_algebra { public: virtual ~boolean_algebra() {} - virtual T mk_not(T x) = 0; - //virtual lbool are_equivalent(T x, T y) = 0; - //virtual T simplify(T x) = 0; + virtual T mk_not(T x) = 0; }; #endif diff --git a/src/math/automata/symbolic_automata_def.h b/src/math/automata/symbolic_automata_def.h index c89080d3d..3be6a1da0 100644 --- a/src/math/automata/symbolic_automata_def.h +++ b/src/math/automata/symbolic_automata_def.h @@ -451,7 +451,15 @@ typename symbolic_automata::automaton_t* symbolic_automata::mk_produ } } if (mvs1.empty()) { - return alloc(automaton_t, m); + if (a.is_final_state(a.init()) && b.is_final_state(b.init())) { + // special case: automaton has no moves, but the initial state is final on both sides + // this results in the automaton which accepts the empty sequence and nothing else + final.clear(); + final.push_back(0); + return alloc(automaton_t, m, 0, final, mvs1); + } else { + return alloc(automaton_t, m); + } } else { return alloc(automaton_t, m, 0, final, mvs1); diff --git a/src/math/polynomial/polynomial.h b/src/math/polynomial/polynomial.h index 138331ef3..43b3c1138 100644 --- a/src/math/polynomial/polynomial.h +++ b/src/math/polynomial/polynomial.h @@ -63,8 +63,8 @@ namespace polynomial { public: void set_degree(var x, unsigned d) { m_var2degree.setx(x, d, 0); } unsigned degree(var x) const { return m_var2degree.get(x, 0); } - void display(std::ostream & out) const; - friend std::ostream & operator<<(std::ostream & out, var2degree const & ideal) { ideal.display(out); return out; } + void display(std::ostream & out) const; + friend std::ostream & operator<<(std::ostream & out, var2degree const & ideal) { ideal.display(out); return out; } }; template diff --git a/src/math/polynomial/upolynomial.h b/src/math/polynomial/upolynomial.h index e0df0dd31..f8efae465 100644 --- a/src/math/polynomial/upolynomial.h +++ b/src/math/polynomial/upolynomial.h @@ -434,11 +434,11 @@ namespace upolynomial { m().reset(r[i]); } for (unsigned i = 0; i < sz; i++) { - typename polynomial::monomial * mon = pm.get_monomial(p, i); - if (pm.size(mon) == 0) { + typename polynomial::monomial * mon = pm.get_monomial(p, i); + if (pm.size(mon) == 0) { m().set(r[0], pm.coeff(p, i)); - } else if (pm.size(mon) == 1 && pm.get_var(mon, 0) == x) { - unsigned m_deg_x = pm.degree(mon, 0); + } else if (pm.size(mon) == 1 && pm.get_var(mon, 0) == x) { + unsigned m_deg_x = pm.degree(mon, 0); m().set(r[m_deg_x], pm.coeff(p, i)); } } diff --git a/src/model/func_interp.cpp b/src/model/func_interp.cpp index 2ead63e0a..6699ef0e2 100644 --- a/src/model/func_interp.cpp +++ b/src/model/func_interp.cpp @@ -140,7 +140,6 @@ void func_interp::set_else(expr * e) { return; reset_interp_cache(); - ptr_vector args; while (e && is_fi_entry_expr(e, args)) { TRACE("func_interp", tout << "fi entry expr: " << mk_ismt2_pp(e, m()) << std::endl;); diff --git a/src/model/model_core.cpp b/src/model/model_core.cpp index 2fd2d8746..f94558097 100644 --- a/src/model/model_core.cpp +++ b/src/model/model_core.cpp @@ -86,13 +86,13 @@ void model_core::register_decl(func_decl * d, func_interp * fi) { void model_core::unregister_decl(func_decl * d) { decl2expr::obj_map_entry * ec = m_interp.find_core(d); if (ec && ec->get_data().m_value != 0) { - m_manager.dec_ref(ec->get_data().m_key); - m_manager.dec_ref(ec->get_data().m_value); + m_manager.dec_ref(ec->get_data().m_key); + m_manager.dec_ref(ec->get_data().m_value); m_interp.remove(d); m_const_decls.erase(d); return; } - + decl2finterp::obj_map_entry * ef = m_finterp.find_core(d); if (ef && ef->get_data().m_value != 0) { m_manager.dec_ref(ef->get_data().m_key); diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index 2b8f8abd6..32ed1e236 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -33,9 +33,11 @@ Revision History: #include "ast/ast_pp.h" #include "ast/ast_util.h" #include "model/model_smt2_pp.h" +#include "ast/rewriter/var_subst.h" struct evaluator_cfg : public default_rewriter_cfg { + ast_manager & m; model_core & m_model; bool_rewriter m_b_rw; arith_rewriter m_a_rw; @@ -53,6 +55,7 @@ struct evaluator_cfg : public default_rewriter_cfg { bool m_array_equalities; evaluator_cfg(ast_manager & m, model_core & md, params_ref const & p): + m(m), m_model(md), m_b_rw(m), // We must allow customers to set parameters for arithmetic rewriter/evaluator. @@ -74,6 +77,7 @@ struct evaluator_cfg : public default_rewriter_cfg { m_ar_rw.set_expand_select_store(true); m_ar_rw.set_expand_select_ite(true); updt_params(p); + //add_unspecified_function_models(md); } void updt_params(params_ref const & _p) { @@ -85,10 +89,8 @@ struct evaluator_cfg : public default_rewriter_cfg { m_array_equalities = p.array_equalities(); } - ast_manager & m() const { return m_model.get_manager(); } - - bool evaluate(func_decl* f, unsigned num, expr * const * args, expr_ref & result) { - func_interp* fi = m_model.get_func_interp(f); + bool evaluate(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { + func_interp * fi = m_model.get_func_interp(f); return (fi != 0) && eval_fi(fi, num, args, result); } @@ -101,9 +103,8 @@ struct evaluator_cfg : public default_rewriter_cfg { bool actuals_are_values = true; - for (unsigned i = 0; actuals_are_values && i < num; i++) { - actuals_are_values = m().is_value(args[i]); - } + for (unsigned i = 0; actuals_are_values && i < num; i++) + actuals_are_values = m.is_value(args[i]); if (!actuals_are_values) return false; // let get_macro handle it @@ -120,7 +121,7 @@ struct evaluator_cfg : public default_rewriter_cfg { br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { result_pr = 0; family_id fid = f->get_family_id(); - bool is_uninterp = fid != null_family_id && m().get_plugin(fid)->is_considered_uninterpreted(f); + bool is_uninterp = fid != null_family_id && m.get_plugin(fid)->is_considered_uninterpreted(f); if (num == 0 && (fid == null_family_id || is_uninterp)) { expr * val = m_model.get_const_interp(f); if (val != 0) { @@ -145,7 +146,7 @@ struct evaluator_cfg : public default_rewriter_cfg { if (k == OP_EQ) { // theory dispatch for = SASSERT(num == 2); - family_id s_fid = m().get_sort(args[0])->get_family_id(); + family_id s_fid = m.get_sort(args[0])->get_family_id(); if (s_fid == m_a_rw.get_fid()) st = m_a_rw.mk_eq_core(args[0], args[1], result); else if (s_fid == m_bv_rw.get_fid()) @@ -178,16 +179,18 @@ struct evaluator_cfg : public default_rewriter_cfg { st = m_f_rw.mk_app_core(f, num, args, result); else if (fid == m_seq_rw.get_fid()) st = m_seq_rw.mk_app_core(f, num, args, result); - else if (fid == m().get_label_family_id() && num == 1) { + else if (fid == m.get_label_family_id() && num == 1) { result = args[0]; st = BR_DONE; } else if (evaluate(f, num, args, result)) { TRACE("model_evaluator", tout << "reduce_app " << f->get_name() << "\n"; - for (unsigned i = 0; i < num; i++) tout << mk_ismt2_pp(args[i], m()) << "\n"; - tout << "---->\n" << mk_ismt2_pp(result, m()) << "\n";); + for (unsigned i = 0; i < num; i++) tout << mk_ismt2_pp(args[i], m) << "\n"; + tout << "---->\n" << mk_ismt2_pp(result, m) << "\n";); return BR_DONE; } + if (st == BR_FAILED && !m.is_builtin_family_id(fid)) + st = evaluate_partial_theory_func(f, num, args, result, result_pr); if (st == BR_DONE && is_app(result)) { app* a = to_app(result); if (evaluate(a->get_decl(), a->get_num_args(), a->get_args(), result)) { @@ -200,14 +203,14 @@ struct evaluator_cfg : public default_rewriter_cfg { void expand_value(expr_ref& val) { vector stores; - expr_ref else_case(m()); + expr_ref else_case(m); bool _unused; if (m_ar.is_array(val) && extract_array_func_interp(val, stores, else_case, _unused)) { - sort* srt = m().get_sort(val); + sort* srt = m.get_sort(val); val = m_ar.mk_const_array(srt, else_case); for (unsigned i = stores.size(); i > 0; ) { --i; - expr_ref_vector args(m()); + expr_ref_vector args(m); args.push_back(val); args.append(stores[i].size(), stores[i].c_ptr()); val = m_ar.mk_store(args.size(), args.c_ptr()); @@ -220,6 +223,7 @@ struct evaluator_cfg : public default_rewriter_cfg { #define TRACE_MACRO TRACE("model_evaluator", tout << "get_macro for " << f->get_name() << " (model completion: " << m_model_completion << ")\n";); func_interp * fi = m_model.get_func_interp(f); + if (fi != 0) { TRACE_MACRO; if (fi->is_partial()) { @@ -228,31 +232,52 @@ struct evaluator_cfg : public default_rewriter_cfg { expr * val = m_model.get_some_value(s); fi->set_else(val); } - else { + else return false; - } } - def = fi->get_interp(); + def = fi->get_interp(); SASSERT(def != 0); return true; } if (m_model_completion && (f->get_family_id() == null_family_id || - m().get_plugin(f->get_family_id())->is_considered_uninterpreted(f))) + m.get_plugin(f->get_family_id())->is_considered_uninterpreted(f))) { TRACE_MACRO; sort * s = f->get_range(); expr * val = m_model.get_some_value(s); - func_interp * new_fi = alloc(func_interp, m(), f->get_arity()); + func_interp * new_fi = alloc(func_interp, m, f->get_arity()); new_fi->set_else(val); m_model.register_decl(f, new_fi); def = val; return true; } + return false; } + br_status evaluate_partial_theory_func(func_decl * f, + unsigned num, expr * const * args, + expr_ref & result, proof_ref & result_pr) { + SASSERT(f != 0); + SASSERT(!m.is_builtin_family_id(f->get_family_id())); + result = 0; + result_pr = 0; + + func_interp * fi = m_model.get_func_interp(f); + if (fi) { + if (fi->is_partial()) + fi->set_else(m.get_some_value(f->get_range())); + + var_subst vs(m, false); + vs(fi->get_interp(), num, args, result); + return BR_REWRITE_FULL; + } + + return BR_FAILED; + } + bool max_steps_exceeded(unsigned num_steps) const { cooperate("model evaluator"); @@ -266,7 +291,7 @@ struct evaluator_cfg : public default_rewriter_cfg { br_status mk_array_eq(expr* a, expr* b, expr_ref& result) { if (a == b) { - result = m().mk_true(); + result = m.mk_true(); return BR_DONE; } if (!m_array_equalities) { @@ -275,19 +300,19 @@ struct evaluator_cfg : public default_rewriter_cfg { vector stores1, stores2; bool args_are_unique1, args_are_unique2; - expr_ref else1(m()), else2(m()); + expr_ref else1(m), else2(m); if (extract_array_func_interp(a, stores1, else1, args_are_unique1) && extract_array_func_interp(b, stores2, else2, args_are_unique2)) { - expr_ref_vector conj(m()), args1(m()), args2(m()); - if (m().are_equal(else1, else2)) { + expr_ref_vector conj(m), args1(m), args2(m); + if (m.are_equal(else1, else2)) { // no op } - else if (m().are_distinct(else1, else2) && !(m().get_sort(else1)->get_info()->get_num_elements().is_finite())) { - result = m().mk_false(); + else if (m.are_distinct(else1, else2) && !(m.get_sort(else1)->get_info()->get_num_elements().is_finite())) { + result = m.mk_false(); return BR_DONE; } else { - conj.push_back(m().mk_eq(else1, else2)); + conj.push_back(m.mk_eq(else1, else2)); } if (args_are_unique1 && args_are_unique2 && !stores1.empty()) { return mk_array_eq_core(stores1, else1, stores2, else2, conj, result); @@ -300,11 +325,11 @@ struct evaluator_cfg : public default_rewriter_cfg { for (unsigned i = 0; i < stores1.size(); ++i) { args1.resize(1); args1.append(stores1[i].size() - 1, stores1[i].c_ptr()); args2.resize(1); args2.append(stores1[i].size() - 1, stores1[i].c_ptr()); - expr_ref s1(m_ar.mk_select(args1.size(), args1.c_ptr()), m()); - expr_ref s2(m_ar.mk_select(args2.size(), args2.c_ptr()), m()); - conj.push_back(m().mk_eq(s1, s2)); + expr_ref s1(m_ar.mk_select(args1.size(), args1.c_ptr()), m); + expr_ref s2(m_ar.mk_select(args2.size(), args2.c_ptr()), m); + conj.push_back(m.mk_eq(s1, s2)); } - result = m().mk_and(conj.size(), conj.c_ptr()); + result = m.mk_and(conj.size(), conj.c_ptr()); return BR_REWRITE_FULL; } return BR_FAILED; @@ -362,15 +387,15 @@ struct evaluator_cfg : public default_rewriter_cfg { if (table1.find(stores2[i].c_ptr(), args)) { switch (compare(args[arity], val)) { case l_true: table1.remove(args); break; - case l_false: result = m().mk_false(); return BR_DONE; - default: conj.push_back(m().mk_eq(val, args[arity])); break; + case l_false: result = m.mk_false(); return BR_DONE; + default: conj.push_back(m.mk_eq(val, args[arity])); break; } } else { switch (compare(else1, val)) { case l_true: break; - case l_false: result = m().mk_false(); return BR_DONE; - default: conj.push_back(m().mk_eq(else1, val)); break; + case l_false: result = m.mk_false(); return BR_DONE; + default: conj.push_back(m.mk_eq(else1, val)); break; } } } @@ -378,8 +403,8 @@ struct evaluator_cfg : public default_rewriter_cfg { for (; it != end; ++it) { switch (compare((*it)[arity], else2)) { case l_true: break; - case l_false: result = m().mk_false(); return BR_DONE; - default: conj.push_back(m().mk_eq((*it)[arity], else2)); break; + case l_false: result = m.mk_false(); return BR_DONE; + default: conj.push_back(m.mk_eq((*it)[arity], else2)); break; } } result = mk_and(conj); @@ -387,8 +412,8 @@ struct evaluator_cfg : public default_rewriter_cfg { } lbool compare(expr* a, expr* b) { - if (m().are_equal(a, b)) return l_true; - if (m().are_distinct(a, b)) return l_false; + if (m.are_equal(a, b)) return l_true; + if (m.are_distinct(a, b)) return l_false; return l_undef; } @@ -396,8 +421,8 @@ struct evaluator_cfg : public default_rewriter_cfg { bool args_are_values(expr_ref_vector const& store, bool& are_unique) { bool are_values = true; for (unsigned j = 0; are_values && j + 1 < store.size(); ++j) { - are_values = m().is_value(store[j]); - are_unique &= m().is_unique_value(store[j]); + are_values = m.is_value(store[j]); + are_unique &= m.is_unique_value(store[j]); } SASSERT(!are_unique || are_values); return are_values; @@ -408,10 +433,10 @@ struct evaluator_cfg : public default_rewriter_cfg { SASSERT(m_ar.is_array(a)); bool are_values = true; are_unique = true; - TRACE("model_evaluator", tout << mk_pp(a, m()) << "\n";); + TRACE("model_evaluator", tout << mk_pp(a, m) << "\n";); while (m_ar.is_store(a)) { - expr_ref_vector store(m()); + expr_ref_vector store(m); store.append(to_app(a)->get_num_args()-1, to_app(a)->get_args()+1); are_values &= args_are_values(store, are_unique); stores.push_back(store); @@ -424,7 +449,7 @@ struct evaluator_cfg : public default_rewriter_cfg { } if (!m_ar.is_as_array(a)) { - TRACE("model_evaluator", tout << "no translation: " << mk_pp(a, m()) << "\n";); + TRACE("model_evaluator", tout << "no translation: " << mk_pp(a, m) << "\n";); return false; } @@ -434,13 +459,13 @@ struct evaluator_cfg : public default_rewriter_cfg { unsigned arity = f->get_arity(); unsigned base_sz = stores.size(); for (unsigned i = 0; i < sz; ++i) { - expr_ref_vector store(m()); + 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("model_evaluator", tout << "could not extract array interpretation: " << mk_pp(a, m()) << "\n" << mk_pp(store[j].get(), m()) << "\n";); + TRACE("model_evaluator", tout << "could not extract array interpretation: " << mk_pp(a, m) << "\n" << mk_pp(store[j].get(), m) << "\n";); return false; } } @@ -448,18 +473,18 @@ struct evaluator_cfg : public default_rewriter_cfg { } else_case = g->get_else(); if (!else_case) { - TRACE("model_evaluator", tout << "no else case " << mk_pp(a, m()) << "\n"; - /*model_smt2_pp(tout, m(), m_model, 0);*/ + TRACE("model_evaluator", tout << "no else case " << mk_pp(a, m) << "\n"; + /*model_smt2_pp(tout, m, m_model, 0);*/ ); return false; } if (!is_ground(else_case)) { - TRACE("model_evaluator", tout << "non-ground else case " << mk_pp(a, m()) << "\n" << else_case << "\n";); + TRACE("model_evaluator", tout << "non-ground else case " << mk_pp(a, m) << "\n" << else_case << "\n";); return false; } for (unsigned i = stores.size(); are_values && i > base_sz; ) { --i; - if (m().are_equal(else_case, stores[i].back())) { + if (m.are_equal(else_case, stores[i].back())) { for (unsigned j = i + 1; j < stores.size(); ++j) { stores[j-1].reset(); stores[j-1].append(stores[j]); @@ -469,7 +494,7 @@ struct evaluator_cfg : public default_rewriter_cfg { } are_values &= args_are_values(stores[i], are_unique); } - TRACE("model_evaluator", tout << "else case: " << mk_pp(else_case, m()) << "\n";); + TRACE("model_evaluator", tout << "else case: " << mk_pp(else_case, m) << "\n";); return true; } diff --git a/src/muz/base/dl_context.h b/src/muz/base/dl_context.h index 738c2559e..129277514 100644 --- a/src/muz/base/dl_context.h +++ b/src/muz/base/dl_context.h @@ -54,7 +54,7 @@ namespace datalog { MEMOUT, INPUT_ERROR, APPROX, - BOUNDED, + BOUNDED, CANCELED }; @@ -318,7 +318,7 @@ namespace datalog { \brief Retrieve predicates */ func_decl_set const& get_predicates() const { return m_preds; } - ast_ref_vector const &get_pinned() const {return m_pinned; } + ast_ref_vector const &get_pinned() const {return m_pinned; } bool is_predicate(func_decl* pred) const { return m_preds.contains(pred); } bool is_predicate(expr * e) const { return is_app(e) && is_predicate(to_app(e)->get_decl()); } @@ -534,7 +534,7 @@ namespace datalog { \brief retrieve proof from derivation of the query. \pre engine == 'pdr' || engine == 'duality'- this option is only supported - for PDR mode and Duality mode. + for PDR mode and Duality mode. */ proof_ref get_proof(); diff --git a/src/muz/base/dl_engine_base.h b/src/muz/base/dl_engine_base.h index 9c20c712d..576ed7f6b 100644 --- a/src/muz/base/dl_engine_base.h +++ b/src/muz/base/dl_engine_base.h @@ -32,7 +32,7 @@ namespace datalog { QBMC_ENGINE, TAB_ENGINE, CLP_ENGINE, - DUALITY_ENGINE, + DUALITY_ENGINE, DDNF_ENGINE, LAST_ENGINE }; diff --git a/src/muz/base/fixedpoint_params.pyg b/src/muz/base/fixedpoint_params.pyg index 110f081b0..0c2f03460 100644 --- a/src/muz/base/fixedpoint_params.pyg +++ b/src/muz/base/fixedpoint_params.pyg @@ -4,7 +4,7 @@ def_module_params('fixedpoint', params=(('timeout', UINT, UINT_MAX, 'set timeout'), ('engine', SYMBOL, 'auto-config', 'Select: auto-config, datalog, duality, pdr, bmc, spacer'), - ('datalog.default_table', SYMBOL, 'sparse', + ('datalog.default_table', SYMBOL, 'sparse', 'default table implementation: sparse, hashtable, bitvector, interval'), ('datalog.default_relation', SYMBOL, 'pentagon', 'default relation implementation: external_relation, pentagon'), @@ -56,18 +56,18 @@ def_module_params('fixedpoint', "table columns, if it would have been empty otherwise"), ('datalog.subsumption', BOOL, True, "if true, removes/filters predicates with total transitions"), - ('duality.full_expand', BOOL, False, 'Fully expand derivation trees'), - ('duality.no_conj', BOOL, False, 'No forced covering (conjectures)'), - ('duality.feasible_edges', BOOL, True, + ('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, + ('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 instantiation'), - ('duality.batch_expand', BOOL, False, 'use batch expansion'), - ('duality.conjecture_file', STRING, '', 'save conjectures to file'), + ('duality.profile', BOOL, False, 'profile run time'), + ('duality.mbqi', BOOL, True, 'use model-based quantifier instantiation'), + ('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, @@ -92,9 +92,9 @@ def_module_params('fixedpoint', "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, + ('pdr.use_convex_closure_generalizer', BOOL, False, "generalize using convex closures of lemmas"), - ('pdr.use_convex_interior_generalizer', BOOL, False, + ('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"), @@ -104,7 +104,7 @@ def_module_params('fixedpoint', ('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'), + ('pdr.utvpi', BOOL, True, 'Enable UTVPI strategy'), ('print_fixedpoint_extensions', BOOL, True, "use SMT-LIB2 fixedpoint extensions, instead of pure SMT2, " + "when printing rules"), @@ -123,7 +123,7 @@ def_module_params('fixedpoint', ('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', + ('tab.selection', SYMBOL, 'weight', 'selection method for tabular strategy: weight (default), first, var-use'), ('xform.bit_blast', BOOL, False, 'bit-blast bit-vectors'), @@ -140,7 +140,7 @@ def_module_params('fixedpoint', ('xform.unfold_rules', UINT, 0, "unfold rules statically using iterative squarring"), ('xform.slice', BOOL, True, "simplify clause set using slicing"), - ('xform.karr', BOOL, False, + ('xform.karr', BOOL, False, "Add linear invariants to clauses using Karr's method"), ('spacer.use_eqclass', BOOL, False, "Generalizes equalities to equivalence classes"), ('xform.transform_arrays', BOOL, False, @@ -153,24 +153,24 @@ def_module_params('fixedpoint', "Gives the number of quantifiers per array"), ('xform.instantiate_arrays.slice_technique', SYMBOL, "no-slicing", "=> GetId(i) = i, => GetId(i) = true"), - ('xform.quantify_arrays', BOOL, False, + ('xform.quantify_arrays', BOOL, False, "create quantified Horn clauses from clauses with arrays"), - ('xform.instantiate_quantifiers', BOOL, False, + ('xform.instantiate_quantifiers', BOOL, False, "instantiate quantified Horn clauses using E-matching heuristic"), ('xform.coalesce_rules', BOOL, False, "coalesce rules"), ('xform.tail_simplifier_pve', BOOL, True, "propagate_variable_equivalences"), ('xform.subsumption_checker', BOOL, True, "Enable subsumption checker (no support for model conversion)"), - ('xform.coi', BOOL, True, "use cone of influence simplificaiton"), - ('duality.enable_restarts', BOOL, False, 'DUALITY: enable restarts'), + ('xform.coi', BOOL, True, "use cone of influence simplification"), + ('duality.enable_restarts', BOOL, False, 'DUALITY: enable restarts'), ('spacer.order_children', UINT, 0, 'SPACER: order of enqueuing children in non-linear rules : 0 (original), 1 (reverse)'), ('spacer.eager_reach_check', BOOL, True, 'SPACER: eagerly check if a query is reachable using reachability facts of predecessors'), ('spacer.use_lemma_as_cti', BOOL, False, 'SPACER: use a lemma instead of a CTI in flexible_trace'), ('spacer.reset_obligation_queue', BOOL, True, 'SPACER: reset obligation queue when entering a new level'), ('spacer.init_reach_facts', BOOL, True, 'SPACER: initialize reachability facts with false'), ('spacer.use_array_eq_generalizer', BOOL, True, 'SPACER: attempt to generalize lemmas with array equalities'), - ('spacer.use_derivations', BOOL, True, 'SPACER: using derivation mechanism to cache intermediate results for non-linear rules'), + ('spacer.use_derivations', BOOL, True, 'SPACER: using derivation mechanism to cache intermediate results for non-linear rules'), ('xform.array_blast', BOOL, False, "try to eliminate local array terms using Ackermannization -- some array terms may remain"), - ('xform.array_blast_full', BOOL, False, "eliminate all local array variables by QE"), + ('xform.array_blast_full', BOOL, False, "eliminate all local array variables by QE"), ('spacer.skip_propagate', BOOL, False, "Skip propagate/pushing phase. Turns PDR into a BMC that returns either reachable or unknown"), ('spacer.max_level', UINT, UINT_MAX, "Maximum level to explore"), ('spacer.elim_aux', BOOL, True, "Eliminate auxiliary variables in reachability facts"), diff --git a/src/muz/duality/duality_dl_interface.h b/src/muz/duality/duality_dl_interface.h index 21291a45b..506642217 100644 --- a/src/muz/duality/duality_dl_interface.h +++ b/src/muz/duality/duality_dl_interface.h @@ -37,7 +37,7 @@ namespace Duality { class dl_interface : public datalog::engine_base { duality_data *_d; - datalog::context &m_ctx; + datalog::context &m_ctx; public: dl_interface(datalog::context& ctx); @@ -69,7 +69,7 @@ namespace Duality { proof_ref get_proof(); - duality_data *dd(){return _d;} + duality_data *dd(){return _d;} private: void display_certificate_non_const(std::ostream& out); diff --git a/src/muz/pdr/pdr_generalizers.h b/src/muz/pdr/pdr_generalizers.h index 3d0fe6ccd..e0feda310 100644 --- a/src/muz/pdr/pdr_generalizers.h +++ b/src/muz/pdr/pdr_generalizers.h @@ -88,7 +88,7 @@ namespace pdr { virtual ~core_convex_hull_generalizer() {} virtual void operator()(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores); virtual void operator()(model_node& n, expr_ref_vector& core, bool& uses_level); - }; + }; class core_multi_generalizer : public core_generalizer { core_bool_inductive_generalizer m_gen; diff --git a/src/muz/rel/dl_mk_similarity_compressor.h b/src/muz/rel/dl_mk_similarity_compressor.h index 68410831c..096305c59 100644 --- a/src/muz/rel/dl_mk_similarity_compressor.h +++ b/src/muz/rel/dl_mk_similarity_compressor.h @@ -53,7 +53,7 @@ namespace datalog { */ class mk_similarity_compressor : public rule_transformer::plugin { - context & m_context; + context & m_context; ast_manager & m_manager; /** number of similar rules necessary for a group to be introduced */ unsigned m_threshold_count; diff --git a/src/muz/rel/dl_mk_simple_joins.h b/src/muz/rel/dl_mk_simple_joins.h index 4d422e651..cf4522c22 100644 --- a/src/muz/rel/dl_mk_simple_joins.h +++ b/src/muz/rel/dl_mk_simple_joins.h @@ -49,7 +49,7 @@ namespace datalog { We say that a rule containing C_i's is a rule with a "big tail". */ class mk_simple_joins : public rule_transformer::plugin { - context & m_context; + context & m_context; rule_manager & rm; public: mk_simple_joins(context & ctx); diff --git a/src/muz/spacer/spacer_qe_project.cpp b/src/muz/spacer/spacer_qe_project.cpp index 8dbf87ca5..dd6472224 100644 --- a/src/muz/spacer/spacer_qe_project.cpp +++ b/src/muz/spacer/spacer_qe_project.cpp @@ -1209,7 +1209,7 @@ namespace qe { void operator()(model& mdl, app_ref_vector& vars, expr_ref& fml) { expr_map map (m); - operator()(mdl, vars, fml, map); + operator()(mdl, vars, fml, map); } void operator()(model& mdl, app_ref_vector& vars, expr_ref& fml, expr_map& map) { diff --git a/src/muz/transforms/dl_mk_magic_sets.h b/src/muz/transforms/dl_mk_magic_sets.h index eef40fd71..73b5e94f6 100644 --- a/src/muz/transforms/dl_mk_magic_sets.h +++ b/src/muz/transforms/dl_mk_magic_sets.h @@ -93,7 +93,7 @@ namespace datalog { typedef obj_map pred_adornment_map; typedef obj_map pred2pred; - context & m_context; + context & m_context; ast_manager & m; rule_manager& rm; ast_ref_vector m_pinned; diff --git a/src/muz/transforms/dl_mk_unbound_compressor.h b/src/muz/transforms/dl_mk_unbound_compressor.h index febb4bd46..6f53e0707 100644 --- a/src/muz/transforms/dl_mk_unbound_compressor.h +++ b/src/muz/transforms/dl_mk_unbound_compressor.h @@ -50,7 +50,7 @@ namespace datalog { typedef hashtable > in_progress_table; typedef svector todo_stack; - context & m_context; + context & m_context; ast_manager & m; rule_manager & rm; rule_ref_vector m_rules; diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index 7ca2be4aa..89264a9c8 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -96,6 +96,9 @@ public: } virtual void execute(cmd_context & ctx) { + if (!m_formula) { + throw cmd_exception("assert-soft requires a formulas as argument."); + } symbol w("weight"); rational weight = ps().get_rat(symbol("weight"), rational::one()); symbol id = ps().get_sym(symbol("id"), symbol::null); diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index 13bf51313..cfcc5e47e 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=(('optsmt_engine', SYMBOL, 'basic', "select optimization engine: 'basic', 'farkas', 'symba'"), - ('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'core_maxsat', 'wmax', 'maxres', 'pd-maxres'"), + ('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'core_maxsat', 'wmax', 'maxres', 'pd-maxres'"), ('priority', SYMBOL, 'lex', "select how to priortize objectives: 'lex' (lexicographic), 'pareto', or 'box'"), ('dump_benchmarks', BOOL, False, 'dump benchmarks for profiling'), ('timeout', UINT, UINT_MAX, 'timeout (in milliseconds) (UINT_MAX and 0 mean no timeout)'), diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index 681c3d597..b8ad7e610 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -24,6 +24,7 @@ Revision History: #include "ast/ast_pp.h" #include "ast/well_sorted.h" #include "ast/rewriter/rewriter.h" +#include "ast/rewriter/var_subst.h" #include "ast/has_free_vars.h" #include "ast/ast_smt2_pp.h" #include "parsers/smt2/smt2parser.h" @@ -68,6 +69,7 @@ namespace smt2 { scoped_ptr m_bv_util; scoped_ptr m_arith_util; + scoped_ptr m_datatype_util; scoped_ptr m_seq_util; scoped_ptr m_pattern_validator; scoped_ptr m_var_shifter; @@ -108,6 +110,7 @@ namespace smt2 { symbol m_check_sat_assuming; symbol m_define_fun_rec; symbol m_define_funs_rec; + symbol m_match; symbol m_underscore; typedef std::pair named_expr; @@ -135,7 +138,7 @@ namespace smt2 { typedef psort_frame sort_frame; - enum expr_frame_kind { EF_APP, EF_LET, EF_LET_DECL, EF_QUANT, EF_ATTR_EXPR, EF_PATTERN }; + enum expr_frame_kind { EF_APP, EF_LET, EF_LET_DECL, EF_MATCH, EF_QUANT, EF_ATTR_EXPR, EF_PATTERN }; struct expr_frame { expr_frame_kind m_kind; @@ -172,6 +175,10 @@ namespace smt2 { m_expr_spos(expr_spos) {} }; + struct match_frame : public expr_frame { + match_frame():expr_frame(EF_MATCH) {} + }; + struct let_frame : public expr_frame { bool m_in_decls; unsigned m_sym_spos; @@ -275,6 +282,12 @@ namespace smt2 { return *(m_arith_util.get()); } + datatype_util & dtutil() { + if (m_datatype_util.get() == 0) + m_datatype_util = alloc(datatype_util, m()); + return *(m_datatype_util.get()); + } + seq_util & sutil() { if (m_seq_util.get() == 0) m_seq_util = alloc(seq_util, m()); @@ -389,6 +402,7 @@ namespace smt2 { bool curr_id_is_underscore() const { SASSERT(curr_is_identifier()); return curr_id() == m_underscore; } bool curr_id_is_as() const { SASSERT(curr_is_identifier()); return curr_id() == m_as; } + bool curr_id_is_match() const { SASSERT(curr_is_identifier()); return curr_id() == m_match; } bool curr_id_is_forall() const { SASSERT(curr_is_identifier()); return curr_id() == m_forall; } bool curr_id_is_exists() const { SASSERT(curr_is_identifier()); return curr_id() == m_exists; } bool curr_id_is_bang() const { SASSERT(curr_is_identifier()); return curr_id() == m_bang; } @@ -1258,6 +1272,23 @@ namespace smt2 { return num; } + void push_let_frame() { + next(); + check_lparen_next("invalid let declaration, '(' expected"); + void * mem = m_stack.allocate(sizeof(let_frame)); + new (mem) let_frame(symbol_stack().size(), expr_stack().size()); + m_num_expr_frames++; + } + + void push_bang_frame(expr_frame * curr) { + TRACE("consume_attributes", tout << "begin bang, expr_stack.size(): " << expr_stack().size() << "\n";); + next(); + void * mem = m_stack.allocate(sizeof(attr_expr_frame)); + new (mem) attr_expr_frame(curr, symbol_stack().size(), expr_stack().size()); + m_num_expr_frames++; + } + + void push_quant_frame(bool is_forall) { SASSERT(curr_is_identifier()); SASSERT(curr_id_is_forall() || curr_id_is_exists()); @@ -1273,6 +1304,202 @@ namespace smt2 { throw parser_exception("invalid quantifier, list of sorted variables is empty"); } + /** + * SMT-LIB 2.6 pattern matches are of the form + * (match t ((p1 t1) ... (pm+1 tm+1))) + */ + void push_match_frame() { + SASSERT(curr_is_identifier()); + SASSERT(curr_id() == m_match); + next(); + void * mem = m_stack.allocate(sizeof(match_frame)); + new (mem) match_frame(); + unsigned num_frames = m_num_expr_frames; + + parse_expr(); + expr_ref t(expr_stack().back(), m()); + expr_stack().pop_back(); + expr_ref_vector patterns(m()), cases(m()); + sort* srt = m().get_sort(t); + + check_lparen_next("pattern bindings should be enclosed in a parenthesis"); + while (!curr_is_rparen()) { + m_env.begin_scope(); + unsigned num_bindings = m_num_bindings; + check_lparen_next("invalid pattern binding, '(' expected"); + parse_match_pattern(srt); + patterns.push_back(expr_stack().back()); + expr_stack().pop_back(); + parse_expr(); + cases.push_back(expr_stack().back()); + expr_stack().pop_back(); + m_num_bindings = num_bindings; + m_env.end_scope(); + check_rparen_next("invalid pattern binding, ')' expected"); + } + next(); + m_num_expr_frames = num_frames + 1; + expr_stack().push_back(compile_patterns(t, patterns, cases)); + } + + void pop_match_frame(match_frame* fr) { + m_stack.deallocate(fr); + m_num_expr_frames--; + } + + expr_ref compile_patterns(expr* t, expr_ref_vector const& patterns, expr_ref_vector const& cases) { + expr_ref result(m()); + var_subst sub(m(), false); + TRACE("parse_expr", tout << "term\n" << expr_ref(t, m()) << "\npatterns\n" << patterns << "\ncases\n" << cases << "\n";); + check_patterns(patterns, m().get_sort(t)); + for (unsigned i = patterns.size(); i > 0; ) { + --i; + expr_ref_vector subst(m()); + expr_ref cond = bind_match(t, patterns[i], subst); + expr_ref new_case(m()); + if (subst.empty()) { + new_case = cases[i]; + } + else { + sub(cases[i], subst.size(), subst.c_ptr(), new_case); + inv_var_shifter inv(m()); + inv(new_case, subst.size(), new_case); + } + if (result) { + result = m().mk_ite(cond, new_case, result); + } + else { + // pattern match binding is ignored. + result = new_case; + } + } + TRACE("parse_expr", tout << result << "\n";); + return result; + } + + void check_patterns(expr_ref_vector const& patterns, sort* s) { + if (!dtutil().is_datatype(s)) + throw parser_exception("pattern matching is only supported for algebraic datatypes"); + ptr_vector const& cons = *dtutil().get_datatype_constructors(s); + for (expr * arg : patterns) if (is_var(arg)) return; + if (patterns.size() < cons.size()) + throw parser_exception("non-exhaustive pattern match"); + ast_fast_mark1 marked; + for (expr * arg : patterns) + marked.mark(to_app(arg)->get_decl(), true); + for (func_decl * f : cons) + if (!marked.is_marked(f)) + throw parser_exception("a constructor is missing from pattern match"); + } + + // compute match condition and substitution + // t is shifted by size of subst. + expr_ref bind_match(expr* t, expr* pattern, expr_ref_vector& subst) { + expr_ref tsh(m()); + if (is_var(pattern)) { + shifter()(t, 1, tsh); + subst.push_back(tsh); + return expr_ref(m().mk_true(), m()); + } + else { + SASSERT(is_app(pattern)); + func_decl * f = to_app(pattern)->get_decl(); + func_decl * r = dtutil().get_constructor_recognizer(f); + ptr_vector const * acc = dtutil().get_constructor_accessors(f); + shifter()(t, acc->size(), tsh); + for (func_decl* a : *acc) { + subst.push_back(m().mk_app(a, tsh)); + } + return expr_ref(m().mk_app(r, t), m()); + } + } + + /** + * parse a match pattern + * (C x1 .... xn) + * C + * _ + * x + */ + + bool parse_constructor_pattern(sort * srt) { + if (!curr_is_lparen()) { + return false; + } + next(); + svector vars; + expr_ref_vector args(m()); + symbol C(check_identifier_next("constructor symbol expected")); + while (!curr_is_rparen()) { + symbol v(check_identifier_next("variable symbol expected")); + if (v != m_underscore && vars.contains(v)) { + throw parser_exception("unexpected repeated variable in pattern expression"); + } + vars.push_back(v); + } + next(); + + // now have C, vars + // look up constructor C, + // create bound variables based on constructor type. + // store expression in expr_stack(). + // ensure that bound variables are adjusted to vars + + func_decl* f = m_ctx.find_func_decl(C, 0, nullptr, vars.size(), nullptr, srt); + if (!f) { + throw parser_exception("expecting a constructor that has been declared"); + } + if (!dtutil().is_constructor(f)) { + throw parser_exception("expecting a constructor"); + } + if (f->get_arity() != vars.size()) { + throw parser_exception("mismatching number of variables supplied to constructor"); + } + m_num_bindings += vars.size(); + for (unsigned i = 0; i < vars.size(); ++i) { + var * v = m().mk_var(i, f->get_domain(i)); + args.push_back(v); + if (vars[i] != m_underscore) { + m_env.insert(vars[i], local(v, m_num_bindings)); + } + } + expr_stack().push_back(m().mk_app(f, args.size(), args.c_ptr())); + return true; + } + + void parse_match_pattern(sort* srt) { + if (parse_constructor_pattern(srt)) { + // done + } + else if (curr_id() == m_underscore) { + // we have a wild-card. + // store dummy variable in expr_stack() + next(); + var* v = m().mk_var(0, srt); + expr_stack().push_back(v); + } + else { + symbol xC(check_identifier_next("constructor symbol or variable expected")); + // check if xC is a constructor, otherwise make it a variable + // of sort srt. + try { + func_decl* f = m_ctx.find_func_decl(xC, 0, nullptr, 0, nullptr, srt); + if (!dtutil().is_constructor(f)) { + throw parser_exception("expecting a constructor, got a previously declared function"); + } + if (f->get_arity() > 0) { + throw parser_exception("constructor expects arguments, but no arguments were supplied in pattern"); + } + expr_stack().push_back(m().mk_const(f)); + } + catch (cmd_exception &) { + var* v = m().mk_var(0, srt); + expr_stack().push_back(v); + m_env.insert(xC, local(v, m_num_bindings++)); + } + } + } + symbol parse_indexed_identifier_core() { check_underscore_next("invalid indexed identifier, '_' expected"); check_identifier("invalid indexed identifier, symbol expected"); @@ -1564,8 +1791,7 @@ namespace smt2 { new (mem) app_frame(f, expr_spos, param_spos, has_as); m_num_expr_frames++; } - - // return true if a new frame was created. + void push_expr_frame(expr_frame * curr) { SASSERT(curr_is_lparen()); next(); @@ -1573,11 +1799,7 @@ namespace smt2 { if (curr_is_identifier()) { TRACE("push_expr_frame", tout << "push_expr_frame(), curr_id(): " << curr_id() << "\n";); if (curr_id_is_let()) { - next(); - check_lparen_next("invalid let declaration, '(' expected"); - void * mem = m_stack.allocate(sizeof(let_frame)); - new (mem) let_frame(symbol_stack().size(), expr_stack().size()); - m_num_expr_frames++; + push_let_frame(); } else if (curr_id_is_forall()) { push_quant_frame(true); @@ -1586,19 +1808,17 @@ namespace smt2 { push_quant_frame(false); } else if (curr_id_is_bang()) { - TRACE("consume_attributes", tout << "begin bang, expr_stack.size(): " << expr_stack().size() << "\n";); - next(); - void * mem = m_stack.allocate(sizeof(attr_expr_frame)); - new (mem) attr_expr_frame(curr, symbol_stack().size(), expr_stack().size()); - m_num_expr_frames++; + push_bang_frame(curr); } else if (curr_id_is_as() || curr_id_is_underscore()) { - TRACE("push_expr_frame", tout << "push_expr_frame(): parse_qualified_name\n";); parse_qualified_name(); } else if (curr_id_is_root_obj()) { parse_root_obj(); } + else if (curr_id_is_match()) { + push_match_frame(); + } else { push_app_frame(); } @@ -1773,6 +1993,9 @@ namespace smt2 { m_stack.deallocate(static_cast(fr)); m_num_expr_frames--; break; + case EF_MATCH: + pop_match_frame(static_cast(fr)); + break; case EF_QUANT: pop_quant_frame(static_cast(fr)); break; @@ -2232,8 +2455,10 @@ namespace smt2 { throw cmd_exception("invalid assert command, expression required as argument"); } expr * f = expr_stack().back(); - if (!m().is_bool(f)) + if (!m().is_bool(f)) { + TRACE("smt2parser", tout << expr_ref(f, m()) << "\n";); throw cmd_exception("invalid assert command, term is not Boolean"); + } if (f == m_last_named_expr.second) { m_ctx.assert_expr(m_last_named_expr.first, f); } @@ -2730,6 +2955,7 @@ namespace smt2 { m_check_sat_assuming("check-sat-assuming"), m_define_fun_rec("define-fun-rec"), m_define_funs_rec("define-funs-rec"), + m_match("match"), m_underscore("_"), m_num_open_paren(0), m_current_file(filename) { diff --git a/src/sat/CMakeLists.txt b/src/sat/CMakeLists.txt index 16d4962d8..c506c04e0 100644 --- a/src/sat/CMakeLists.txt +++ b/src/sat/CMakeLists.txt @@ -3,7 +3,6 @@ z3_add_component(sat ba_solver.cpp dimacs.cpp sat_asymm_branch.cpp - sat_ccc.cpp sat_clause.cpp sat_clause_set.cpp sat_clause_use_list.cpp diff --git a/src/sat/sat_ccc.cpp b/src/sat/sat_ccc.cpp deleted file mode 100644 index ee087a60f..000000000 --- a/src/sat/sat_ccc.cpp +++ /dev/null @@ -1,604 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - sat_ccc.cpp - -Abstract: - - A variant of Concurrent Cube and Conquer - -Author: - - Nikolaj Bjorner (nbjorner) 2017-4-17 - -Notes: - - The cube process spawns conquer threads to search parts of the - state space. - The conquer threads have two modes: - - emulation mode - where they try to outpace the cuber on the same search tree - - complement mode - where they solve a sub-branch not yet explored by the cuber. - When the conquer thread returns a solved cube it is processed in the following ways: - - ignore if solved_id \not\in decisions - - mark d as closed if d \in decisions, such that d is marked by solved id - - backjump otherwise, conquer thread has solved a branch attempted by the cuber - ---*/ - -#include "sat_solver.h" -#include "sat_lookahead.h" -#include "sat_ccc.h" - -using namespace sat; - -// ------------ -// cuber - -ccc::cuber::cuber(ccc& c): m_ccc(c), m_lh(alloc(lookahead, c.m_s)), m_branch_id(0) {} - -lbool ccc::cuber::search() { - while (true) { - m_branch_id = 0; - m_last_closure_level = 1000; - - m_lh->init_search(); - m_lh->m_model.reset(); - - lookahead::scoped_level _sl(*m_lh.get(), m_lh->c_fixed_truth); - m_lh->m_search_mode = lookahead_mode::searching; - lbool r = research(); - if (r == l_true) { - m_ccc.m_model = m_lh->get_model(); - } - if (false && r == l_undef) { - continue; - } - m_lh->collect_statistics(m_ccc.m_lh_stats); - return r; - } -} - -lbool ccc::cuber::research() { - m_ccc.m_s.checkpoint(); - - if (m_lh->inconsistent()) { - return l_false; - } - - if (pop_lookahead()) { - return l_undef; - } - - if (get_solved()) { - return l_false; - } - - m_lh->inc_istamp(); - literal l = m_lh->choose(); - if (m_lh->inconsistent()) { - return l_false; - } - - if (l == null_literal) { - return l_true; - } - - if (!m_decisions.empty()) { - m_ccc.put_decision(m_decisions.back()); - } - - - // update trail and m_decisions - - ++m_lh->m_stats.m_decisions; - unsigned parent_id = m_decisions.empty() ? 0 : m_decisions.back().m_id; - unsigned spawn_id = spawn_conquer(); - unsigned branch1 = m_branch_id++; - unsigned branch2 = m_branch_id++; - decision d(branch1, m_decisions.size() + 1, l, parent_id, spawn_id); - m_decisions.push_back(d); - - IF_VERBOSE(2, d.pp(verbose_stream() << "select " << m_last_closure_level << " ") << "\n";); - IF_VERBOSE(2, verbose_stream() << "select " << pp_prefix(m_lh->m_prefix, m_lh->m_trail_lim.size()) << ": " << l << " " << m_lh->m_trail.size() << "\n";); - IF_VERBOSE(3, pp(verbose_stream(), m_decisions) << "\n"; ); - - TRACE("sat", tout << "choose: " << l << "\n";); - m_lh->push(l, m_lh->c_fixed_truth); - lbool r = research(); - if (r == l_false) { - m_lh->pop(); - if (m_decisions.back().is_closed()) { - // branch was solved by a spawned conquer process - IF_VERBOSE(1, m_decisions.back().pp(verbose_stream() << "closed ") << "\n";); - r = l_false; - m_decisions.pop_back(); - } - else { - if (spawn_id > 0) { - free_conquer(spawn_id); - m_last_closure_level *= 3; - m_last_closure_level /= 4; - } - m_lh->inc_istamp(); - m_lh->flip_prefix(); - m_lh->push(~l, m_lh->c_fixed_truth); - m_decisions.back().negate(); - m_decisions.back().m_id = branch2; - m_decisions.back().m_spawn_id = 0; - r = research(); - if (r == l_false) { - m_lh->pop(); - m_decisions.pop_back(); - } - } - } - return r; -} - -bool ccc::cuber::pop_lookahead() { - return false; - - scoped_ptr new_lh; - bool result = false; - #pragma omp critical (ccc_new_lh) - { - if (m_ccc.m_new_lh) { - new_lh = m_ccc.m_new_lh.detach(); - result = true; - } - } - if (new_lh) { - m_lh->collect_statistics(m_ccc.m_lh_stats); - m_lh = new_lh.detach(); - } - return result; -} - -void ccc::cuber::update_closure_level(decision const& d, int offset) { - m_last_closure_level = (d.m_depth + 3*m_last_closure_level) / 4; - if (m_last_closure_level >= static_cast(abs(offset))) { - m_last_closure_level += offset; - } -} - -unsigned ccc::cuber::spawn_conquer() { - unsigned result = 0; - // - // decisions must have been solved at a higher level by a conquer thread - // - if (!m_free_threads.empty()) { - if (m_last_closure_level <= m_decisions.size()) { - result = m_free_threads.back(); - ++m_ccc.m_ccc_stats.m_spawn_opened; - m_free_threads.pop_back(); - } - else { - IF_VERBOSE(1, verbose_stream() << m_last_closure_level << " " << m_decisions.size() << "\n";); - } - } - return result; -} - - -void ccc::cuber::free_conquer(unsigned id) { - if (id != 0) { - m_free_threads.push_back(id); - } -} - - -bool ccc::cuber::get_solved() { - // check if CDCL solver got ahead. - bool do_pop = false; - solution sol; - while (true) { - bool is_empty = true; - #pragma omp critical (ccc_solved) - { - if (do_pop) m_ccc.m_solved.pop_front(); - if (!m_ccc.m_solved.empty()) { - sol = m_ccc.m_solved.top(); - is_empty = false; - } - } - if (is_empty) { - return false; - } - do_pop = true; - unsigned branch_id = sol.m_branch_id; - unsigned thread_id = sol.m_thread_id; - bool found = false; - for (unsigned i = m_decisions.size(); i > 0; ) { - --i; - decision& d = m_decisions[i]; - if (branch_id == d.m_id) { - if (d.m_spawn_id == thread_id && thread_id != 0) { - SASSERT(d.m_spawn_id > 0); - IF_VERBOSE(2, d.pp(verbose_stream() << thread_id << ": spawn close ") << "\n";); - ++m_ccc.m_ccc_stats.m_spawn_closed; - d.close(); - free_conquer(thread_id); - update_closure_level(d, -1); - break; - } - else { - IF_VERBOSE(2, d.pp(verbose_stream() << thread_id << ": conquer ") << "\n";); - ++m_ccc.m_ccc_stats.m_cdcl_closed; - update_closure_level(d, 1); - return true; - } - } - // branch is even, d has moved to the next branch - if (branch_id == (d.m_id & ~0x1) && d.m_spawn_id == thread_id && thread_id != 0) { - IF_VERBOSE(1, d.pp(verbose_stream() << thread_id << ": spawn conquer ") << "\n";); - ++m_ccc.m_ccc_stats.m_cdcl_closed; - update_closure_level(d, 1); - return true; - } - } - } -} - -// --------------------- -// conquer state machine - -lbool ccc::conquer::search() { - try { - if (s.inconsistent()) return l_false; - s.init_search(); - s.propagate(false); - if (s.inconsistent()) return l_false; - s.cleanup(); - s.simplify_problem(); - if (s.inconsistent()) return l_false; - - while (true) { - SASSERT(!s.inconsistent()); - - lbool r = bounded_search(); - if (r != l_undef) - return r; - - s.restart(); - s.simplify_problem(); - if (s.check_inconsistent()) return l_false; - s.gc(); - push_lookahead(); - } - } - catch (solver::abort_solver) { - return l_undef; - } -} - -void ccc::conquer::replay_decisions() { - s.propagate(true); - for (unsigned i = s.scope_lvl(); !s.inconsistent() && i < m_decisions.size(); ++i) { - decision const& d = m_decisions[i]; - IF_VERBOSE(2, verbose_stream() << thread_id << ": replay " << d.get_literal(thread_id) << " " << s.value(d.get_literal(thread_id)) << "\n";); - - if (!push_decision(d)) { - // negation of decision is implied. - IF_VERBOSE(1, d.pp(verbose_stream() << thread_id << ": backjump to level " << i << " ") << "\n";); - while (m_decisions.size() > i) { - pop_decision(m_decisions.back()); - m_decisions.pop_back(); - } - break; - } - - if (d.m_spawn_id == thread_id && d.is_left()) { - // we pushed the right branch on this thread. - IF_VERBOSE(1, d.pp(verbose_stream() << thread_id << ": skip left branch on level " << i + 1 << " ") << "\n";); - break; - } - } -} - -void ccc::conquer::pop_decision(decision const& d) { - unsigned tid = 0; - if (d.is_spawned(thread_id)) { - tid = thread_id; - m_spawned = false; - IF_VERBOSE(1, d.pp(verbose_stream() << thread_id << ": retire spawn ") << "\n";); - } - #pragma omp critical (ccc_solved) - { - m_ccc.m_solved.push(solution(tid, d.m_id)); - } -} - -void ccc::conquer::push_lookahead() { - return; - - #pragma omp critical (ccc_new_lh) - { - if (!m_ccc.m_new_lh && m_ccc.m_num_clauses > s.num_clauses()) { - std::cout << "push " << s.num_clauses() << "\n"; - m_ccc.m_new_lh = alloc(lookahead, s); - m_ccc.m_num_clauses = s.num_clauses(); - } - } -} - -bool ccc::conquer::push_decision(decision const& d) { - literal lit = d.get_literal(thread_id); - switch (s.value(lit)) { - case l_false: - //TBD: - s.m_restart_threshold = s.m_config.m_restart_initial; - //s.m_conflicts_since_last_restart = 0; - return false; - case l_true: - s.push(); - break; - case l_undef: - s.push(); - s.assign(lit, justification()); - s.propagate(true); - break; - } - m_spawned |= d.is_spawned(thread_id); - return true; -} - -bool ccc::conquer::cube_decision() { - decision d; - bool use_cube_decision = false; - SASSERT(s.m_qhead == s.m_trail.size()); - - while (true) { - if (!m_ccc.get_decision(thread_id, d)) { - return false; - } - - if (d.is_spawned(thread_id)) IF_VERBOSE(1, d.pp(verbose_stream() << thread_id << " ") << "\n";); - - if (!m_decisions.empty() && m_decisions.back().m_depth + 1 < d.m_depth) { - if (d.is_spawned(thread_id)) { - pop_decision(d); - } - } - else { - break; - } - } - SASSERT(m_decisions.empty() || m_decisions.back().m_depth + 1 >= d.m_depth); - - if (!m_decisions.empty() && m_decisions.back().is_spawned(thread_id) && m_decisions.back().m_depth == d.m_depth) { - SASSERT(d.m_spawn_id == 0); - SASSERT(m_decisions.back().is_left()); - SASSERT(!d.is_left()); - IF_VERBOSE(1, verbose_stream() << thread_id << " inherit spawn\n";); - m_decisions.back().m_spawn_id = 0; - m_spawned = false; - } - SASSERT(m_decisions.empty() || m_decisions.back().m_depth + 1 >= d.m_depth); - - while (!m_decisions.empty() && m_decisions.back().m_depth >= d.m_depth) { - // check_non_model("cube decision", m_decisions); - if (m_decisions.back().is_spawned(thread_id)) { - pop_decision(m_decisions.back()); - } - m_decisions.pop_back(); - } - - SASSERT(m_decisions.empty() || m_decisions.back().m_depth + 1 == d.m_depth); - SASSERT(m_decisions.empty() || m_decisions.back().m_id == d.m_parent); - if (m_spawned) { - m_decisions.push_back(d); - return true; - } - - s.pop_reinit(s.scope_lvl() - m_decisions.size()); - SASSERT(s.m_qhead == s.m_trail.size()); - SASSERT(s.scope_lvl() == m_decisions.size()); - literal lit = d.get_literal(thread_id); - IF_VERBOSE(2, d.pp(verbose_stream() << thread_id << ": cube ") << "\n";); - IF_VERBOSE(3, pp(verbose_stream() << thread_id << ": push ", m_decisions) << " @ " << s.scope_lvl() << " " << s.value(lit) << "\n"; - if (s.value(lit) == l_false) verbose_stream() << "level: " << s.lvl(lit) << "\n";); - - if (push_decision(d)) { - m_decisions.push_back(d); - } - else { - pop_decision(d); - } - - return true; -} - -lbool ccc::conquer::bounded_search() { - while (true) { - s.checkpoint(); - bool done = false; - while (!done) { - replay_decisions(); - lbool is_sat = s.propagate_and_backjump_step(done); - if (is_sat != l_true) return is_sat; - } - - s.gc(); - - if (!cube_decision() && !s.decide()) { - lbool is_sat = s.final_check(); - if (is_sat != l_undef) { - return is_sat; - } - } - } -} - -// -------------- -// shared state - -std::ostream& ccc::decision::pp(std::ostream& out) const { - out << "(" - << "id:" << m_id - << " l:" << m_literal - << " d:" << m_depth; - if (m_spawn_id != 0) { - out << " s:" << m_spawn_id; - } - out << ") "; - return out; -} - -std::ostream& ccc::pp(std::ostream& out, svector const& v) { - for (unsigned i = 0; i < v.size(); ++i) { - v[i].pp(out); - } - return out; -} - -bool ccc::get_decision(unsigned thread_id, decision& d) { - SASSERT(0 < thread_id && thread_id <= m_decisions.size()); - bool result = false; - #pragma omp critical (ccc_decisions) - { - if (!m_decisions[thread_id - 1].empty()) { - d = m_decisions[thread_id - 1].pop_front(); - result = true; - } - } - return result; -} - -void ccc::put_decision(decision const& d) { - for (unsigned i = 0; i < m_num_conquer; ++i) { - #pragma omp critical (ccc_decisions) - { - while (false && !m_decisions[i].empty()) { // introduces contention. - decision d = m_decisions[i].back(); - if (d.m_depth < d.m_depth || d.m_spawn_id != 0) { - break; - } - m_decisions[i].pop_back(); - } - m_decisions[i].push(d); - } - } -} - -lbool ccc::search() { - enum par_exception_kind { - DEFAULT_EX, - ERROR_EX - }; - - // set_model(); - - m_cancel = false; - - scoped_limits scoped_rlimit(m_s.rlimit()); - ptr_vector solvers; - int finished_id = -1; - std::string ex_msg; - par_exception_kind ex_kind; - unsigned error_code = 0; - lbool result = l_undef; - m_decisions.reset(); - - cuber cuber(*this); - - m_num_conquer = m_s.m_config.m_num_threads; - int num_threads = 1 + m_num_conquer; // for ccc-infinity only two threads. - - for (int i = 1; i < num_threads; ++i) { - m_s.m_params.set_uint("random_seed", m_s.m_rand()); - conquer* s1 = alloc(conquer, *this, m_s.m_params, i); - solvers.push_back(s1); - s1->s.copy(m_s); - scoped_rlimit.push_child(&(s1->m_limit)); - m_decisions.push_back(queue()); - } - for (unsigned i = 1; i < m_num_conquer; ++i) { - cuber.m_free_threads.push_back(i); - } - - #pragma omp parallel for - for (int i = 0; i < num_threads; ++i) { - try { - lbool r = l_undef; - if (i == 0) { - r = cuber.search(); - } - else { - r = solvers[i-1]->search(); - } - bool first = false; - #pragma omp critical (par_solver) - { - if (finished_id == -1) { - finished_id = i; - first = true; - result = r; - } - } - if (first) { - for (unsigned j = 0; j < solvers.size(); ++j) { - solvers[j]->m_limit.cancel(); - } - // cancel lookahead solver: - m_cancel = true; - } - } - catch (z3_error & err) { - error_code = err.error_code(); - ex_kind = ERROR_EX; - } - catch (z3_exception & ex) { - ex_msg = ex.msg(); - ex_kind = DEFAULT_EX; - } - } - - if (finished_id > 0 && result == l_true) { - // set model from auxiliary solver - m_model = solvers[finished_id - 1]->s.get_model(); - } - - for (unsigned i = 0; i < solvers.size(); ++i) { - solvers[i]->s.collect_statistics(m_lh_stats); - dealloc(solvers[i]); - } - - if (finished_id == -1) { - switch (ex_kind) { - case ERROR_EX: throw z3_error(error_code); - default: throw default_exception(ex_msg.c_str()); - } - } - -#if 0 - if (result == l_true) { - for (unsigned i = 1; i < m_model.size(); ++i) { - std::cout << "push_model(" << i << ", " << (m_model[i] > 0 ? "false" : "true") << ");\n"; - } - } -#endif - - return result; -} - - -#if 0 -void ccc::push_model(unsigned v, bool sign) { - if (m_values.size() <= v) { - m_values.resize(v + 1); - } - m_values[v] = sign; -} - -void ccc::check_non_model(char const* fn, svector const& decisions) { - for (unsigned i = 0; i < decisions.size(); ++i) { - decision d = decisions[i]; - literal lit = d.m_literal; - if (m_values[lit.var()] != lit.sign()) return; - } - - IF_VERBOSE(1, pp(verbose_stream() << "backtracking from model " << fn << " ", decisions) << "\n";); -} -#endif diff --git a/src/sat/sat_ccc.h b/src/sat/sat_ccc.h deleted file mode 100644 index 95602a441..000000000 --- a/src/sat/sat_ccc.h +++ /dev/null @@ -1,150 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - sat_ccc.h - -Abstract: - - A variant of Concurrent Cube and Conquer - -Author: - - Nikolaj Bjorner (nbjorner) 2017-4-17 - -Notes: - ---*/ -#ifndef _SAT_CCC_H_ -#define _SAT_CCC_H_ - -#include "util/queue.h" - -namespace sat { - - - class ccc { - struct decision { - unsigned m_id; // unique identifier for decision - unsigned m_depth; // depth of decision - literal m_literal; // decision literal - unsigned m_parent; // id of parent - int m_spawn_id; // thread id of conquer thread processing complented branch. - // = 0 if not spawned. - // > 0 if active spawn is in progress - // < 0 if thread has closed the branch - decision(unsigned id, unsigned d, literal last, unsigned parent_id, unsigned spawn): - m_id(id), m_depth(d), m_literal(last), m_parent(parent_id), m_spawn_id(spawn) {} - decision(): - m_id(0), m_depth(0), m_literal(null_literal), m_parent(0), m_spawn_id(0) {} - - void close() { SASSERT(m_spawn_id > 0); m_spawn_id = -m_spawn_id; } - bool is_closed() const { return m_spawn_id < 0; } - void negate() { m_literal.neg(); } - bool is_left() const { return 0 == (m_id & 0x1); } - bool is_spawned(unsigned thread_id) const { return m_spawn_id == thread_id; } - - // the left branch has an even branch_id. - // the branch is spawned if it is even and the spawn_id is the same as the thread_id, and furthermore it is exploring the left branch. - // it may explore the right branch, but is then not in a spawned mode. - // we retain the spawn id so that the spawned thread can be re-spun. - literal get_literal(unsigned thread_id) const { return ((m_id & 0x1) == 0 && thread_id == m_spawn_id) ? ~m_literal : m_literal; } - std::ostream& pp(std::ostream& out) const; - }; - - struct solution { - unsigned m_thread_id; - unsigned m_branch_id; - solution(unsigned t, unsigned s): m_thread_id(t), m_branch_id(s) {} - solution(): m_thread_id(0), m_branch_id(0) {} - }; - - struct stats { - unsigned m_spawn_closed; - unsigned m_spawn_opened; - unsigned m_cdcl_closed; - stats() { reset(); } - void reset() { - memset(this, 0, sizeof(*this)); - } - }; - - struct conquer { - reslimit m_limit; - ccc& m_ccc; - solver s; - svector m_decisions; - unsigned thread_id; - bool m_spawned; - conquer(ccc& super, params_ref const& p, unsigned tid): m_ccc(super), s(p, m_limit), thread_id(tid), m_spawned(false) {} - - lbool search(); - bool cube_decision(); - lbool bounded_search(); - bool push_decision(decision const& d); - void pop_decision(decision const& d); - void push_lookahead(); - void replay_decisions(); - }; - - struct cuber { - ccc& m_ccc; - scoped_ptr m_lh; - unsigned m_branch_id; - unsigned m_last_closure_level; - unsigned_vector m_free_threads; - svector m_decisions; - - cuber(ccc& c); - lbool search(); - lbool research(); - bool get_solved(); - void update_closure_level(decision const& d, int offset); - unsigned spawn_conquer(); - void free_conquer(unsigned thread_id); - bool pop_lookahead(); - }; - - solver& m_s; - queue m_solved; - vector > m_decisions; - scoped_ptr m_new_lh; - unsigned m_num_clauses; - unsigned m_num_conquer; - model m_model; - volatile bool m_cancel; - ::statistics m_lh_stats; - stats m_ccc_stats; - - void put_decision(decision const& d); - bool get_decision(unsigned thread_id, decision& d); - - static std::ostream& pp(std::ostream& out, svector const& v); - - void push_model(unsigned v, bool sign); - void set_model(); - bool trail_in_model(literal_vector const& trail) const; - - void check_non_model(char const* fn, svector const& decisions); - - - public: - - ccc(solver& s): m_s(s), m_num_clauses(s.num_clauses()) {} - - lbool search(); - - model const& get_model() const { return m_model; } - - void collect_statistics(::statistics& st) { - st.copy(m_lh_stats); - st.update("ccc-spawn-closed", m_ccc_stats.m_spawn_closed); - st.update("ccc-cdcl-closed", m_ccc_stats.m_cdcl_closed); - st.update("ccc-spawn-opened", m_ccc_stats.m_spawn_opened); - } - }; -} - -#endif - diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index b2ef3760c..dd6cea3f8 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -39,7 +39,6 @@ namespace sat { m_local_search = 0; m_lookahead_search = false; m_lookahead_simplify = false; - m_ccc = false; updt_params(p); } @@ -86,9 +85,11 @@ namespace sat { m_local_search = p.local_search(); m_local_search_threads = p.local_search_threads(); m_lookahead_simplify = p.lookahead_simplify(); + m_lookahead_cube = p.lookahead_cube(); m_lookahead_search = p.lookahead_search(); m_lookahead_reward = p.lookahead_reward(); - m_ccc = p.ccc(); + m_lookahead_cube_fraction = p.lookahead_cube_fraction(); + m_lookahead_cube_cutoff = p.lookahead_cube_cutoff(); // These parameters are not exposed m_simplify_mult1 = _p.get_uint("simplify_mult1", 300); @@ -166,6 +167,7 @@ namespace sat { else { throw sat_param_exception("invalid PB solver: solver, totalizer, circuit, sorting"); } + m_dimacs_display = p.dimacs_display(); } void config::collect_param_descrs(param_descrs & r) { diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 71d5e2c9f..fc93e50ea 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -75,8 +75,10 @@ namespace sat { bool m_local_search; bool m_lookahead_search; bool m_lookahead_simplify; + bool m_lookahead_cube; + unsigned m_lookahead_cube_cutoff; + double m_lookahead_cube_fraction; symbol m_lookahead_reward; - bool m_ccc; unsigned m_simplify_mult1; double m_simplify_mult2; @@ -96,6 +98,8 @@ namespace sat { symbol m_drat_file; bool m_drat_check; + bool m_dimacs_display; + symbol m_always_true; symbol m_always_false; symbol m_caching; diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 50cb68431..7205b9ac3 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1710,6 +1710,47 @@ namespace sat { return true; } + void lookahead::cube() { + m_model.reset(); + scoped_level _sl(*this, c_fixed_truth); + literal_vector trail; + m_search_mode = lookahead_mode::searching; + double freevars_threshold = 0; + while (true) { + TRACE("sat", display(tout);); + inc_istamp(); + checkpoint(); + literal l = choose(); + if (inconsistent()) { + freevars_threshold = m_freevars.size(); + if (!backtrack(trail)) return; + continue; + } + unsigned depth = m_trail_lim.size(); + if (l == null_literal || + (m_config.m_cube_cutoff != 0 && depth == m_config.m_cube_cutoff) || + (m_config.m_cube_cutoff == 0 && m_freevars.size() < freevars_threshold)) { + display_cube(std::cout); + set_conflict(); + if (!backtrack(trail)) return; + freevars_threshold *= (1.0 - pow(m_config.m_cube_fraction, depth)); + continue; + } + TRACE("sat", tout << "choose: " << l << " " << trail << "\n";); + ++m_stats.m_decisions; + IF_VERBOSE(1, printf("\r"); + std::stringstream strm; + strm << pp_prefix(m_prefix, m_trail_lim.size()); + for (unsigned i = 0; i < 50; ++i) strm << " "; + printf(strm.str().c_str()); + fflush(stdout); + ); + push(l, c_fixed_truth); + trail.push_back(l); + SASSERT(inconsistent() || !is_unsat()); + } + } + lbool lookahead::search() { m_model.reset(); scoped_level _sl(*this, c_fixed_truth); @@ -1719,10 +1760,6 @@ namespace sat { TRACE("sat", display(tout);); inc_istamp(); checkpoint(); - if (inconsistent()) { - if (!backtrack(trail)) return l_false; - continue; - } literal l = choose(); if (inconsistent()) { if (!backtrack(trail)) return l_false; @@ -1764,6 +1801,14 @@ namespace sat { } } + std::ostream& lookahead::display_cube(std::ostream& out) const { + out << "c"; + for (literal l : m_assumptions) { + out << " " << ~l; + } + return out << "\n"; + } + std::ostream& lookahead::display_binary(std::ostream& out) const { for (unsigned i = 0; i < m_binary.size(); ++i) { literal_vector const& lits = m_binary[i]; @@ -1818,7 +1863,7 @@ namespace sat { literal lookahead::choose() { literal l = null_literal; - while (l == null_literal) { + while (l == null_literal && !inconsistent()) { pre_select(); if (m_lookahead.empty()) { break; @@ -2013,6 +2058,8 @@ namespace sat { else { warning_msg("Reward type not recognized"); } + m_config.m_cube_cutoff = m_s.m_config.m_lookahead_cube_cutoff; + m_config.m_cube_fraction = m_s.m_config.m_lookahead_cube_fraction; } void lookahead::collect_statistics(statistics& st) const { diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 8ec44abcf..0bd6e39d4 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -84,6 +84,8 @@ namespace sat { unsigned m_dl_max_iterations; unsigned m_tc1_limit; reward_t m_reward_type; + unsigned m_cube_cutoff; + double m_cube_fraction; config() { m_max_hlevel = 50; @@ -95,6 +97,8 @@ namespace sat { m_dl_max_iterations = 32; m_tc1_limit = 10000000; m_reward_type = ternary_reward; + m_cube_cutoff = 0; + m_cube_fraction = 0.4; } }; @@ -446,6 +450,8 @@ namespace sat { std::ostream& display_clauses(std::ostream& out) const; std::ostream& display_values(std::ostream& out) const; std::ostream& display_lookahead(std::ostream& out) const; + std::ostream& display_cube(std::ostream& out) const; + void init_search(); void checkpoint(); @@ -474,6 +480,14 @@ namespace sat { return search(); } + /** + \brief create cubes to std-out in DIMACS form. + The cubes are controlled using cut-depth and cut-fraction parameters. + If cut-depth != 0, then it is used to control the depth of cuts. + Otherwise, cut-fraction gives an adaptive threshold for creating cuts. + */ + void cube(); + literal select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars); /** \brief simplify set of clauses by extracting units from a lookahead at base level. diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index b856921b2..ab35b3c56 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -34,8 +34,11 @@ def_module_params('sat', ('atmost1_encoding', SYMBOL, 'grouped', 'encoding used for at-most-1 constraints grouped, bimander, ordered'), ('local_search_threads', UINT, 0, 'number of local search threads to find satisfiable solution'), ('local_search', BOOL, False, 'use local search instead of CDCL'), + ('lookahead_cube', BOOL, False, 'use lookahead solver to create cubes'), + ('lookahead.cube.fraction', DOUBLE, 0.4, 'adaptive fraction to create lookahead cubes. Used when lookahead_cube is true'), + ('lookahead.cube.cutoff', UINT, 0, 'cut-off depth to create cubes. Only enabled when non-zero. Used when lookahead_cube is true.'), ('lookahead_search', BOOL, False, 'use lookahead solver'), ('lookahead_simplify', BOOL, False, 'use lookahead solver during simplification'), ('lookahead.reward', SYMBOL, 'heuleu', 'select lookahead heuristic: ternary, hs (Heule Schur), heuleu (Heule Unit), or unit'), - ('ccc', BOOL, False, 'use Concurrent Cube and Conquer solver') - )) + ('dimacs.display', BOOL, False, 'display SAT instance in DIMACS format and return unknown instead of solving'))) + diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 05420bf8a..5e054bdaf 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -20,7 +20,6 @@ Revision History: #include "sat/sat_solver.h" #include "sat/sat_integrity_checker.h" #include "sat/sat_lookahead.h" -#include "sat/sat_ccc.h" #include "util/luby.h" #include "util/trace.h" #include "util/max_cliques.h" @@ -847,16 +846,25 @@ namespace sat { pop_to_base_level(); IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver)\n";); SASSERT(at_base_lvl()); + if (m_config.m_dimacs_display) { + display_dimacs(std::cout); + for (unsigned i = 0; i < num_lits; ++lits) { + std::cout << dimacs_lit(lits[i]) << " 0\n"; + } + return l_undef; + } if (m_config.m_lookahead_search && num_lits == 0) { return lookahead_search(); } + if (m_config.m_lookahead_cube && num_lits == 0) { + lookahead_cube(); + return l_undef; + } if (m_config.m_local_search) { return do_local_search(num_lits, lits); } - if (m_config.m_ccc && num_lits == 0) { - return do_ccc(); - } if ((m_config.m_num_threads > 1 || m_config.m_local_search_threads > 0) && !m_par) { + SASSERT(scope_lvl() == 0); return check_par(num_lits, lits); } flet _searching(m_searching, true); @@ -913,13 +921,6 @@ namespace sat { if (check_inconsistent()) return l_false; gc(); -#if 0 - if (m_clauses.size() < 65000) { - return do_ccc(); - return lookahead_search(); - } -#endif - if (m_config.m_restart_max <= m_restarts) { m_reason_unknown = "sat.max.restarts"; IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-restarts\")\n";); @@ -951,12 +952,16 @@ namespace sat { return r; } - lbool solver::do_ccc() { - ccc c(*this); - lbool r = c.search(); - m_model = c.get_model(); - c.collect_statistics(m_aux_stats); - return r; + void solver::lookahead_cube() { + lookahead lh(*this); + try { + lh.cube(); + } + catch (z3_exception&) { + lh.collect_statistics(m_aux_stats); + throw; + } + lh.collect_statistics(m_aux_stats); } lbool solver::lookahead_search() { @@ -1497,10 +1502,7 @@ namespace sat { } void solver::sort_watch_lits() { - vector::iterator it = m_watches.begin(); - vector::iterator end = m_watches.end(); - for (; it != end; ++it) { - watch_list & wlist = *it; + for (watch_list & wlist : m_watches) { std::stable_sort(wlist.begin(), wlist.end(), watched_lt()); } } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 9bb4b0caf..ab2dd7a1f 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -403,6 +403,7 @@ namespace sat { void exchange_par(); lbool check_par(unsigned num_lits, literal const* lits); lbool lookahead_search(); + void lookahead_cube(); lbool do_local_search(unsigned num_lits, literal const* lits); lbool do_ccc(); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index bf6049356..1fbabcf13 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -149,7 +149,6 @@ public: virtual void set_progress_callback(progress_callback * callback) {} - void display_weighted(std::ostream& out, unsigned sz, expr * const * assumptions, unsigned const* weights) { if (weights != 0) { for (unsigned i = 0; i < sz; ++i) m_weights.push_back(weights[i]); @@ -212,6 +211,11 @@ public: init_reason_unknown(); r = m_solver.check(m_asms.size(), m_asms.c_ptr()); + if (r == l_undef && m_solver.get_config().m_dimacs_display) { + for (auto const& kv : m_map) { + std::cout << "c " << kv.m_value << " " << mk_pp(kv.m_key, m) << "\n"; + } + } switch (r) { case l_true: @@ -806,14 +810,12 @@ private: } 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(); - for (; it != end; ++it) { - expr * n = it->m_key; + for (auto const& kv : m_map) { + expr * n = kv.m_key; if (is_app(n) && to_app(n)->get_num_args() > 0) { continue; } - sat::bool_var v = it->m_value; + sat::bool_var v = kv.m_value; 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/sat/tactic/sat_tactic.cpp b/src/sat/tactic/sat_tactic.cpp index 61ab46a88..e049df8a7 100644 --- a/src/sat/tactic/sat_tactic.cpp +++ b/src/sat/tactic/sat_tactic.cpp @@ -16,11 +16,11 @@ Author: Notes: --*/ +#include "ast/ast_pp.h" #include "tactic/tactical.h" +#include "tactic/filter_model_converter.h" #include "sat/tactic/goal2sat.h" #include "sat/sat_solver.h" -#include "tactic/filter_model_converter.h" -#include "ast/ast_smt2_pp.h" #include "model/model_v2_pp.h" class sat_tactic : public tactic { @@ -56,11 +56,9 @@ class sat_tactic : public tactic { 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(); - for (; it != end; ++it) { - if (!is_uninterp_const(it->m_key)) - tout << mk_ismt2_pp(it->m_key, m) << "\n"; + for (auto const& kv : map) { + if (!is_uninterp_const(kv.m_key)) + tout << mk_ismt2_pp(kv.m_key, m) << "\n"; }); g->reset(); g->m().compact_memory(); @@ -70,6 +68,11 @@ class sat_tactic : public tactic { TRACE("sat_dimacs", m_solver.display_dimacs(tout);); dep2assumptions(dep2asm, assumptions); lbool r = m_solver.check(assumptions.size(), assumptions.c_ptr()); + if (r == l_undef && m_solver.get_config().m_dimacs_display) { + for (auto const& kv : map) { + std::cout << "c " << kv.m_value << " " << mk_pp(kv.m_key, g->m()) << "\n"; + } + } if (r == l_false) { expr_dependency * lcore = 0; if (produce_core) { @@ -90,11 +93,9 @@ class sat_tactic : public tactic { model_ref md = alloc(model, m); sat::model const & ll_m = 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; + for (auto const& kv : map) { + expr * n = kv.m_key; + sat::bool_var v = kv.m_value; TRACE("sat_tactic", tout << "extracting value of " << mk_ismt2_pp(n, m) << "\nvar: " << v << "\n";); switch (sat::value_at(v, ll_m)) { case l_true: @@ -126,17 +127,15 @@ class sat_tactic : public tactic { 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); + for (auto const& kv : dep2asm) { + assumptions.push_back(kv.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); + for (auto const& kv : dep2asm) { + lit2asm.insert(kv.m_value.index(), kv.m_key); } } }; diff --git a/src/shell/lp_frontend.cpp b/src/shell/lp_frontend.cpp index 490c361d5..95f9e1eb3 100644 --- a/src/shell/lp_frontend.cpp +++ b/src/shell/lp_frontend.cpp @@ -1,7 +1,7 @@ /*++ Copyright (c) 2016 Microsoft Corporation -Author: +Author: Lev Nachmanson 2016-10-27 @@ -54,7 +54,7 @@ struct front_end_resource_limit : public lp::lp_resource_limit { void run_solver(lp_params & params, char const * mps_file_name) { - reslimit rlim; + reslimit rlim; unsigned timeout = gparams::get().get_uint("timeout", 0); unsigned rlimit = gparams::get().get_uint("rlimit", 0); front_end_resource_limit lp_limit(rlim); @@ -80,19 +80,20 @@ void run_solver(lp_params & params, char const * mps_file_name) { solver->settings().set_message_ostream(&std::cout); solver->settings().report_frequency = params.rep_freq(); solver->settings().print_statistics = params.print_stats(); - solver->settings().simplex_strategy() = lp::simplex_strategy_enum::lu; + solver->settings().simplex_strategy() = lp:: simplex_strategy_enum::lu; + solver->find_maximal_solution(); *(solver->settings().get_message_ostream()) << "status is " << lp_status_to_string(solver->get_status()) << std::endl; - if (solver->get_status() == lp::lp_status::OPTIMAL) { + if (solver->get_status() == lp::OPTIMAL) { if (params.min()) { solver->flip_costs(); } solver->print_model(std::cout); } - + // #pragma omp critical (g_display_stats) - { + { display_statistics(); register_on_timeout_proc(0); g_solver = 0; diff --git a/src/smt/database.smt b/src/smt/database.smt index 2f5e5e1c9..27955badf 100644 --- a/src/smt/database.smt +++ b/src/smt/database.smt @@ -11,7 +11,7 @@ :formula (forall (a Int) (i Int) (e Int) (= (?select (?store a i e) i) e) :pats { (?store a i e) } - :weight { 0 }) + :weight { 0 }) :formula (forall (a Int) (i Int) (j Int) (e Int) (or (= i j) (= (?select (?store a i e) j) (?select a j))) diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index 67d1f045d..44e858219 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 & out_edges = m_out_edges[current]; + neighbours.reset(); + 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; @@ -968,7 +968,7 @@ public: } 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) { + for (; it2 != end2; ++it2) { edge_id e_id = *it2; edge & e = m_edges[e_id]; SASSERT(e.get_target() == current); @@ -980,19 +980,19 @@ public: void dfs_undirected(dl_var start, svector & threads) { threads.reset(); threads.resize(get_num_nodes()); - uint_set discovered, explored; - svector nodes; + uint_set discovered, explored; + svector nodes; discovered.insert(start); - nodes.push_back(start); - dl_var prev = start; - while(!nodes.empty()) { - dl_var current = nodes.back(); + nodes.push_back(start); + dl_var prev = start; + while(!nodes.empty()) { + dl_var current = nodes.back(); SASSERT(discovered.contains(current) && !explored.contains(current)); - svector neighbours; - get_neighbours_undirected(current, neighbours); + svector neighbours; + get_neighbours_undirected(current, neighbours); SASSERT(!neighbours.empty()); bool found = false; - for (unsigned i = 0; i < neighbours.size(); ++i) { + for (unsigned i = 0; i < neighbours.size(); ++i) { dl_var next = neighbours[i]; DEBUG_CODE( edge_id id; @@ -1002,18 +1002,18 @@ public: threads[prev] = next; prev = next; discovered.insert(next); - nodes.push_back(next); + nodes.push_back(next); found = true; break; } - } + } SASSERT(!nodes.empty()); if (!found) { explored.insert(current); nodes.pop_back(); } - } - threads[prev] = start; + } + threads[prev] = start; } void bfs_undirected(dl_var start, svector & parents, svector & depths) { @@ -1022,31 +1022,31 @@ public: parents[start] = -1; depths.reset(); depths.resize(get_num_nodes()); - uint_set visited; - std::deque nodes; - visited.insert(start); - nodes.push_front(start); - while(!nodes.empty()) { + 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)); + SASSERT(visited.contains(current)); svector neighbours; - get_neighbours_undirected(current, neighbours); + get_neighbours_undirected(current, neighbours); SASSERT(!neighbours.empty()); - for (unsigned i = 0; i < neighbours.size(); ++i) { - dl_var next = neighbours[i]; + 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 (!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); + parents[next] = current; + depths[next] = depths[current] + 1; + visited.insert(next); + nodes.push_front(next); } - } - } + } + } } template diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index 2aa9d6095..497aab8db 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -1753,10 +1753,6 @@ namespace smt { m_use_filters(use_filters) { } - context & get_context() { - return m_context; - } - /** \brief Create a new code tree for the given quantifier. @@ -2020,26 +2016,20 @@ namespace smt { void execute(code_tree * t) { TRACE("trigger_bug", tout << "execute for code tree:\n"; t->display(tout);); init(t); - enode_vector::const_iterator it = t->get_candidates().begin(); - enode_vector::const_iterator end = t->get_candidates().end(); if (t->filter_candidates()) { - for (; it != end; ++it) { - enode * app = *it; + for (enode * app : t->get_candidates()) { if (!app->is_marked() && app->is_cgr()) { execute_core(t, app); app->set_mark(); } } - it = t->get_candidates().begin(); - for (; it != end; ++it) { - enode * app = *it; + for (enode * app : t->get_candidates()) { if (app->is_marked()) app->unset_mark(); } } else { - for (; it != end; ++it) { - enode * app = *it; + for (enode * app : t->get_candidates()) { TRACE("trigger_bug", tout << "candidate\n" << mk_ismt2_pp(app->get_owner(), m_ast_manager) << "\n";); if (app->is_cgr()) { TRACE("trigger_bug", tout << "is_cgr\n";); @@ -2825,15 +2815,13 @@ namespace smt { } // end of execute_core void display_trees(std::ostream & out, const ptr_vector & trees) { - ptr_vector::const_iterator it = trees.begin(); - ptr_vector::const_iterator end = trees.end(); unsigned lbl = 0; - for (; it != end; ++it, ++lbl) { - code_tree * tree = *it; + for (code_tree* tree : trees) { if (tree) { out << "tree for f" << lbl << "\n"; out << *tree; } + ++lbl; } } diff --git a/src/smt/proto_model/datatype_factory.cpp b/src/smt/proto_model/datatype_factory.cpp index 03f008fe6..550b694da 100644 --- a/src/smt/proto_model/datatype_factory.cpp +++ b/src/smt/proto_model/datatype_factory.cpp @@ -38,7 +38,7 @@ expr * datatype_factory::get_some_value(sort * s) { } expr * r = m_manager.mk_app(c, args.size(), args.c_ptr()); register_value(r); - TRACE("datatype_factory", tout << mk_pp(r, m_util.get_manager()) << "\n";); + TRACE("datatype", tout << mk_pp(r, m_util.get_manager()) << "\n";); return r; } @@ -48,7 +48,7 @@ expr * datatype_factory::get_some_value(sort * s) { expr * datatype_factory::get_last_fresh_value(sort * s) { expr * val = 0; if (m_last_fresh_value.find(s, val)) { - TRACE("datatype_factory", tout << "cached fresh value: " << mk_pp(val, m_manager) << "\n";); + TRACE("datatype", tout << "cached fresh value: " << mk_pp(val, m_manager) << "\n";); return val; } value_set * set = get_value_set(s); @@ -68,7 +68,7 @@ bool datatype_factory::is_subterm_of_last_value(app* e) { } contains_app contains(m_manager, e); bool result = contains(last); - TRACE("datatype_factory", tout << mk_pp(e, m_manager) << " in " << mk_pp(last, m_manager) << " " << result << "\n";); + TRACE("datatype", tout << mk_pp(e, m_manager) << " in " << mk_pp(last, m_manager) << " " << result << "\n";); return result; } @@ -126,7 +126,7 @@ expr * datatype_factory::get_almost_fresh_value(sort * s) { m_last_fresh_value.insert(s, new_value); } } - TRACE("datatype_factory", tout << "almost fresh: " << mk_pp(new_value, m_manager) << "\n";); + TRACE("datatype", tout << "almost fresh: " << mk_pp(new_value, m_manager) << "\n";); return new_value; } } @@ -136,7 +136,7 @@ expr * datatype_factory::get_almost_fresh_value(sort * s) { expr * datatype_factory::get_fresh_value(sort * s) { - TRACE("datatype_factory", tout << "generating fresh value for: " << s->get_name() << "\n";); + TRACE("datatype", tout << "generating fresh value for: " << s->get_name() << "\n";); value_set * set = get_value_set(s); // Approach 0) // if no value for s was generated so far, then used get_some_value @@ -144,7 +144,7 @@ expr * datatype_factory::get_fresh_value(sort * s) { expr * val = get_some_value(s); if (m_util.is_recursive(s)) m_last_fresh_value.insert(s, val); - TRACE("datatype_factory", tout << "0. result: " << mk_pp(val, m_manager) << "\n";); + TRACE("datatype", tout << "0. result: " << mk_pp(val, m_manager) << "\n";); return val; } // Approach 1) @@ -171,13 +171,13 @@ expr * datatype_factory::get_fresh_value(sort * s) { } expr_ref new_value(m_manager); new_value = m_manager.mk_app(constructor, args.size(), args.c_ptr()); - CTRACE("datatype_factory", found_fresh_arg && set->contains(new_value), tout << mk_pp(new_value, m_manager) << "\n";); + CTRACE("datatype", found_fresh_arg && set->contains(new_value), tout << mk_pp(new_value, m_manager) << "\n";); SASSERT(!found_fresh_arg || !set->contains(new_value)); if (!set->contains(new_value)) { register_value(new_value); if (m_util.is_recursive(s)) m_last_fresh_value.insert(s, new_value); - TRACE("datatype_factory", tout << "1. result: " << mk_pp(new_value, m_manager) << "\n";); + TRACE("datatype", tout << "1. result: " << mk_pp(new_value, m_manager) << "\n";); return new_value; } } @@ -188,16 +188,16 @@ expr * datatype_factory::get_fresh_value(sort * s) { if (m_util.is_recursive(s)) { while(true) { ++num_iterations; - TRACE("datatype_factory", tout << mk_pp(get_last_fresh_value(s), m_manager) << "\n";); + TRACE("datatype", tout << mk_pp(get_last_fresh_value(s), m_manager) << "\n";); ptr_vector const & constructors = *m_util.get_datatype_constructors(s); for (func_decl * constructor : constructors) { expr_ref_vector args(m_manager); bool found_sibling = false; unsigned num = constructor->get_arity(); - TRACE("datatype_factory", tout << "checking constructor: " << constructor->get_name() << "\n";); + TRACE("datatype", tout << "checking constructor: " << constructor->get_name() << "\n";); for (unsigned i = 0; i < num; i++) { sort * s_arg = constructor->get_domain(i); - TRACE("datatype_factory", tout << mk_pp(s, m_manager) << " " + TRACE("datatype", tout << mk_pp(s, m_manager) << " " << mk_pp(s_arg, m_manager) << " are_siblings " << m_util.are_siblings(s, s_arg) << " is_datatype " << m_util.is_datatype(s_arg) << " found_sibling " @@ -212,7 +212,7 @@ expr * datatype_factory::get_fresh_value(sort * s) { maybe_new_arg = get_fresh_value(s_arg); } if (!maybe_new_arg) { - TRACE("datatype_factory", + TRACE("datatype", tout << "no argument found for " << mk_pp(s_arg, m_manager) << "\n";); maybe_new_arg = m_model.get_some_value(s_arg); found_sibling = false; @@ -229,11 +229,11 @@ expr * datatype_factory::get_fresh_value(sort * s) { if (found_sibling) { expr_ref new_value(m_manager); new_value = m_manager.mk_app(constructor, args.size(), args.c_ptr()); - TRACE("datatype_factory", tout << "potential new value: " << mk_pp(new_value, m_manager) << "\n";); + TRACE("datatype", tout << "potential new value: " << mk_pp(new_value, m_manager) << "\n";); m_last_fresh_value.insert(s, new_value); if (!set->contains(new_value)) { register_value(new_value); - TRACE("datatype_factory", tout << "2. result: " << mk_pp(new_value, m_manager) << "\n";); + TRACE("datatype", tout << "2. result: " << mk_pp(new_value, m_manager) << "\n";); return new_value; } } diff --git a/src/smt/qi_queue.cpp b/src/smt/qi_queue.cpp index f77fde29a..2a8d9d199 100644 --- a/src/smt/qi_queue.cpp +++ b/src/smt/qi_queue.cpp @@ -148,11 +148,8 @@ namespace smt { } void qi_queue::instantiate() { - svector::iterator it = m_new_entries.begin(); - svector::iterator end = m_new_entries.end(); unsigned since_last_check = 0; - for (; it != end; ++it) { - entry & curr = *it; + for (entry & curr : m_new_entries) { fingerprint * f = curr.m_qb; quantifier * qa = static_cast(f->get_data()); diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 0ad47bfd0..011f222f3 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -4387,9 +4387,17 @@ namespace smt { expr* fn = to_app(q->get_pattern(0))->get_arg(0); expr* body = to_app(q->get_pattern(1))->get_arg(0); SASSERT(is_app(fn)); + // reverse argument order so that variable 0 starts at the beginning. + expr_ref_vector subst(m); + for (expr* arg : *to_app(fn)) { + subst.push_back(arg); + } + expr_ref bodyr(m); + var_subst sub(m, false); + sub(body, subst.size(), subst.c_ptr(), bodyr); func_decl* f = to_app(fn)->get_decl(); func_interp* fi = alloc(func_interp, m, f->get_arity()); - fi->set_else(body); + fi->set_else(bodyr); m_model->register_decl(f, fi); } } diff --git a/src/smt/smt_enode.h b/src/smt/smt_enode.h index 4b3a64d90..f471314fa 100644 --- a/src/smt/smt_enode.h +++ b/src/smt/smt_enode.h @@ -40,10 +40,10 @@ namespace smt { /** \ brief Use sparse maps in SMT solver. - Define this to use hash maps rather than vectors over ast - nodes. This is useful in the case there are many solvers, each - referencing few nodes from a large ast manager. There is some - unknown performance penalty for this. */ + Define this to use hash maps rather than vectors over ast + nodes. This is useful in the case there are many solvers, each + referencing few nodes from a large ast manager. There is some + unknown performance penalty for this. */ // #define SPARSE_MAP diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index b1e268776..56d164bcc 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -198,19 +198,19 @@ namespace smt { if (get_depth(n) > DEEP_EXPR_THRESHOLD) { // if the expression is deep, then execute topological sort to avoid // stack overflow. + // a caveat is that theory internalizers do rely on recursive descent so + // internalization over these follows top-down TRACE("deep_internalize", tout << "expression is deep: #" << n->get_id() << "\n" << mk_ll_pp(n, m_manager);); svector sorted_exprs; top_sort_expr(n, sorted_exprs); - TRACE("deep_internalize", - svector::const_iterator it = sorted_exprs.begin(); - svector::const_iterator end = sorted_exprs.end(); - for (; it != end; ++it) { - tout << "#" << it->first->get_id() << " " << it->second << "\n"; - }); - svector::const_iterator it = sorted_exprs.begin(); - svector::const_iterator end = sorted_exprs.end(); - for (; it != end; ++it) - internalize(it->first, it->second); + TRACE("deep_internalize", for (auto & kv : sorted_exprs) tout << "#" << kv.first->get_id() << " " << kv.second << "\n"; ); + for (auto & kv : sorted_exprs) { + expr* e = kv.first; + if (!is_app(e) || + to_app(e)->get_family_id() == null_family_id || + to_app(e)->get_family_id() == m_manager.get_basic_family_id()) + internalize(e, kv.second); + } } SASSERT(m_manager.is_bool(n)); if (is_gate(m_manager, n)) { diff --git a/src/smt/smt_quantifier.h b/src/smt/smt_quantifier.h index a55c895e6..d89f3f6a4 100644 --- a/src/smt/smt_quantifier.h +++ b/src/smt/smt_quantifier.h @@ -149,7 +149,7 @@ namespace smt { /** \brief Is "model based" instantiate allowed to instantiate this quantifier? */ - virtual bool mbqi_enabled(quantifier *q) const {return true;} + virtual bool mbqi_enabled(quantifier *q) const {return true;} /** \brief Give a change to the plugin to adjust the interpretation of unintepreted functions. diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index d3dc95b01..858ff2a31 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -125,6 +125,8 @@ namespace smt { setup_QF_FPBV(); else if (m_logic == "QF_S") setup_QF_S(); + else if (m_logic == "QF_DT") + setup_QF_DT(); else setup_unknown(); } @@ -190,6 +192,8 @@ namespace smt { setup_AUFLIRA(); else if (m_logic == "UFNIA") setup_UFNIA(); + else if (m_logic == "QF_DT") + setup_QF_DT(); else if (m_logic == "LRA") setup_LRA(); else @@ -210,6 +214,10 @@ namespace smt { m_params.m_random_initial_activity = IA_RANDOM; } + void setup::setup_QF_DT() { + setup_QF_UF(); + } + void setup::setup_QF_BVRE() { setup_QF_BV(); setup_QF_LIA(); diff --git a/src/smt/smt_setup.h b/src/smt/smt_setup.h index a3bb29195..924c2caec 100644 --- a/src/smt/smt_setup.h +++ b/src/smt/smt_setup.h @@ -54,6 +54,7 @@ namespace smt { // setup_(static_features & st) can only be used if the logical context will perform a single // check. // + void setup_QF_DT(); void setup_QF_UF(); void setup_QF_UF(static_features const & st); void setup_QF_RDL(); diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 065671378..ae7bd95fd 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -109,8 +109,10 @@ namespace smt { } virtual void assert_expr(expr * t, expr * a) { + if (m_name2assertion.contains(a)) { + throw default_exception("named assertion defined twice"); + } solver_na2as::assert_expr(t, a); - SASSERT(!m_name2assertion.contains(a)); get_manager().inc_ref(t); m_name2assertion.insert(a, t); } diff --git a/src/smt/smt_theory.h b/src/smt/smt_theory.h index 71eedc1a7..2ee0db322 100644 --- a/src/smt/smt_theory.h +++ b/src/smt/smt_theory.h @@ -192,7 +192,7 @@ namespace smt { virtual lbool validate_unsat_core(expr_ref_vector & unsat_core) { return l_false; } - + /** \brief This method is invoked before the search starts. */ diff --git a/src/smt/theory_dense_diff_logic_def.h b/src/smt/theory_dense_diff_logic_def.h index ad7727a89..064bdd433 100644 --- a/src/smt/theory_dense_diff_logic_def.h +++ b/src/smt/theory_dense_diff_logic_def.h @@ -151,14 +151,15 @@ namespace smt { m_autil.is_numeral(rhs, _k); numeral offset(_k); app * s, * t; - if (m_autil.is_add(lhs) && to_app(lhs)->get_num_args() == 2 && is_times_minus_one(to_app(lhs)->get_arg(1), s)) { - t = to_app(to_app(lhs)->get_arg(0)); + expr *arg1, *arg2; + if (m_autil.is_add(lhs, arg1, arg2) && is_times_minus_one(arg2, s)) { + t = to_app(arg1); } - else if (m_autil.is_add(lhs) && to_app(lhs)->get_num_args() == 2 && is_times_minus_one(to_app(lhs)->get_arg(0), s)) { - t = to_app(to_app(lhs)->get_arg(1)); + else if (m_autil.is_add(lhs, arg1, arg2) && is_times_minus_one(arg1, s)) { + t = to_app(arg2); } - else if (m_autil.is_mul(lhs) && to_app(lhs)->get_num_args() == 2 && m_autil.is_minus_one(to_app(lhs)->get_arg(0))) { - s = to_app(to_app(lhs)->get_arg(1)); + else if (m_autil.is_mul(lhs, arg1, arg2) && m_autil.is_minus_one(arg1)) { + s = to_app(arg2); t = mk_zero_for(s); } else if (!m_autil.is_arith_expr(lhs)) { @@ -170,6 +171,7 @@ namespace smt { found_non_diff_logic_expr(n); return false; } + TRACE("arith", tout << expr_ref(lhs, get_manager()) << " " << expr_ref(s, get_manager()) << " " << expr_ref(t, get_manager()) << "\n";); source = internalize_term_core(s); target = internalize_term_core(t); if (source == null_theory_var || target == null_theory_var) { diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index 02cc8860f..a7153234c 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -733,7 +733,6 @@ theory_var theory_diff_logic::mk_term(app* n) { 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); } diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index dfd295220..cc9b0017d 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -119,6 +119,7 @@ namespace smt { SASSERT(m_conversions.empty()); SASSERT(m_is_added_to_model.empty()); } + void theory_fpa::init(context * ctx) { smt::theory::init(ctx); m_is_initialized = true; @@ -237,7 +238,7 @@ namespace smt { if (m_fpa_util.is_fp(e)) { expr * cargs[3] = { to_app(e)->get_arg(0), to_app(e)->get_arg(1), to_app(e)->get_arg(2) }; - expr_ref tmp(m_bv_util.mk_concat(3, cargs), m); + expr_ref tmp(m_bv_util.mk_concat(3, cargs), m); m_th_rw(tmp); res = to_app(tmp); } @@ -255,7 +256,7 @@ namespace smt { } func_decl_ref wrap_fd(m); - wrap_fd = m.mk_func_decl(get_family_id(), OP_FPA_INTERNAL_BVWRAP, 0, 0, 1, &es, bv_srt); + wrap_fd = m.mk_func_decl(get_family_id(), OP_FPA_BVWRAP, 0, 0, 1, &es, bv_srt); res = m.mk_app(wrap_fd, e); } @@ -883,26 +884,4 @@ namespace smt { out << r->get_id() << " --> " << mk_ismt2_pp(n, m) << std::endl; } } - - bool theory_fpa::include_func_interp(func_decl * f) { - TRACE("t_fpa", tout << "f = " << mk_ismt2_pp(f, get_manager()) << std::endl;); - - if (f->get_family_id() == get_family_id()) { - bool include = - m_fpa_util.is_min_unspecified(f) || - m_fpa_util.is_max_unspecified(f) || - m_fpa_util.is_to_ubv_unspecified(f) || - m_fpa_util.is_to_sbv_unspecified(f) || - m_fpa_util.is_to_ieee_bv_unspecified(f) || - m_fpa_util.is_to_real_unspecified(f); - if (include && !m_is_added_to_model.contains(f)) { - m_is_added_to_model.insert(f); - get_manager().inc_ref(f); - return true; - } - return false; - } - else - return true; - } }; diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index 5fcb8637c..9e9801ee0 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -82,7 +82,7 @@ namespace smt { m_th(*th) {} virtual ~fpa2bv_converter_wrapped() {} virtual void mk_const(func_decl * f, expr_ref & result); - virtual void mk_rm_const(func_decl * f, expr_ref & result); + virtual void mk_rm_const(func_decl * f, expr_ref & result); }; class fpa_value_proc : public model_value_proc { @@ -108,7 +108,7 @@ namespace smt { result.append(m_deps); } - virtual app * mk_value(model_generator & mg, ptr_vector & values); + virtual app * mk_value(model_generator & mg, ptr_vector & values); }; class fpa_rm_value_proc : public model_value_proc { @@ -158,7 +158,6 @@ namespace smt { virtual char const * get_name() const { return "fpa"; } virtual model_value_proc * mk_value(enode * n, model_generator & mg); - virtual bool include_func_interp(func_decl * f); void assign_eh(bool_var v, bool is_true); virtual void relevant_eh(app * n); @@ -179,9 +178,6 @@ namespace smt { expr_ref convert_atom(expr * e); expr_ref convert_term(expr * e); expr_ref convert_conversion_term(expr * e); - expr_ref convert_unwrap(expr * e); - - void add_trail(ast * a); void attach_new_th_var(enode * n); void assert_cnstr(expr * e); diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 1f97697c2..2ad257fd7 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -45,7 +45,7 @@ namespace smt { typedef trail_stack th_trail_stack; typedef std::pair expr_dep; typedef obj_map eqdep_map_t; - typedef union_find th_union_find; + typedef union_find th_union_find; class seq_value_proc; @@ -298,8 +298,8 @@ namespace smt { scoped_vector m_eqs; // set of current equations. scoped_vector m_nqs; // set of current disequalities. scoped_vector m_ncs; // set of non-contains constraints. - unsigned m_eq_id; - th_union_find m_find; + unsigned m_eq_id; + th_union_find m_find; seq_factory* m_factory; // value factory exclusion_table m_exclude; // set of asserted disequalities. @@ -584,7 +584,7 @@ namespace smt { // model building app* mk_value(app* a); - th_trail_stack& get_trail_stack() { return m_trail_stack; } + th_trail_stack& get_trail_stack() { return m_trail_stack; } void merge_eh(theory_var, theory_var, theory_var v1, theory_var v2) {} void after_merge_eh(theory_var r1, theory_var r2, theory_var v1, theory_var v2) { } void unmerge_eh(theory_var v1, theory_var v2) {} diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 88b044a90..8a141665c 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -4748,11 +4748,11 @@ namespace smt { context& ctx = get_context(); ast_manager & m = get_manager(); - // safety - if (!ctx.e_internalized(e)) { + // safety + if (!ctx.e_internalized(e)) { return false; - } - + } + // if an integer constant exists in the eqc, it should be the root enode * en_e = ctx.get_enode(e); enode * root_e = en_e->get_root(); @@ -7028,7 +7028,7 @@ namespace smt { ast_manager & m = get_manager(); if (lenTester_fvar_map.contains(lenTester)) { expr * fVar = lenTester_fvar_map[lenTester]; - expr_ref toAssert(gen_len_val_options_for_free_var(fVar, lenTester, lenTesterValue), m); + expr_ref toAssert(gen_len_val_options_for_free_var(fVar, lenTester, lenTesterValue), m); TRACE("str", tout << "asserting more length tests for free variable " << mk_ismt2_pp(fVar, m) << std::endl;); if (toAssert) { assert_axiom(toAssert); diff --git a/src/smt/watch_list.cpp b/src/smt/watch_list.cpp index 2ff75c418..edd6923d7 100644 --- a/src/smt/watch_list.cpp +++ b/src/smt/watch_list.cpp @@ -36,10 +36,10 @@ namespace smt { void watch_list::expand() { if (m_data == 0) { - unsigned size = DEFAULT_WATCH_LIST_SIZE + HEADER_SIZE; + unsigned size = DEFAULT_WATCH_LIST_SIZE + HEADER_SIZE; unsigned * mem = reinterpret_cast(alloc_svect(char, size)); #ifdef _AMD64_ - ++mem; // make sure data is aligned in 64 bit machines + ++mem; // make sure data is aligned in 64 bit machines #endif *mem = 0; ++mem; @@ -62,9 +62,9 @@ namespace smt { unsigned * mem = reinterpret_cast(alloc_svect(char, new_capacity + HEADER_SIZE)); unsigned curr_end_cls = end_cls_core(); #ifdef _AMD64_ - ++mem; // make sure data is aligned in 64 bit machines + ++mem; // make sure data is aligned in 64 bit machines #endif - *mem = curr_end_cls; + *mem = curr_end_cls; ++mem; SASSERT(bin_bytes <= new_capacity); unsigned new_begin_bin = new_capacity - bin_bytes; diff --git a/src/solver/smt_logics.cpp b/src/solver/smt_logics.cpp index 75cd0f2bb..874f1cfcc 100644 --- a/src/solver/smt_logics.cpp +++ b/src/solver/smt_logics.cpp @@ -141,7 +141,7 @@ bool smt_logics::logic_has_fpa(symbol const & s) { } bool smt_logics::logic_has_uf(symbol const & s) { - return s == "QF_UF" || s == "UF"; + return s == "QF_UF" || s == "UF" || s == "QF_DT"; } bool smt_logics::logic_has_horn(symbol const& s) { @@ -153,5 +153,5 @@ bool smt_logics::logic_has_pb(symbol const& s) { } bool smt_logics::logic_has_datatype(symbol const& s) { - return s == "QF_FD" || s == "ALL"; + return s == "QF_FD" || s == "ALL" || s == "QF_DT"; } diff --git a/src/tactic/arith/probe_arith.cpp b/src/tactic/arith/probe_arith.cpp index c2de64484..edd4483e7 100644 --- a/src/tactic/arith/probe_arith.cpp +++ b/src/tactic/arith/probe_arith.cpp @@ -392,24 +392,27 @@ struct is_non_nira_functor { is_non_nira_functor(ast_manager & _m, bool _int, bool _real, bool _quant, bool linear):m(_m), u(m), m_int(_int), m_real(_real), m_quant(_quant), m_linear(linear) {} - void throw_found() { + void throw_found(expr* e) { + TRACE("probe", tout << expr_ref(e, m) << ": " << sort_ref(m.get_sort(e), m) << "\n";); throw found(); } void operator()(var * x) { if (!m_quant) - throw_found(); + throw_found(x); sort * s = x->get_sort(); if (m_int && u.is_int(s)) return; if (m_real && u.is_real(s)) return; - throw_found(); + if (m.is_bool(s)) + return; + throw_found(x); } - void operator()(quantifier *) { + void operator()(quantifier * q) { if (!m_quant) - throw_found(); + throw_found(q); } bool compatible_sort(app * n) const { @@ -424,7 +427,7 @@ struct is_non_nira_functor { void operator()(app * n) { if (!compatible_sort(n)) - throw_found(); + throw_found(n); family_id fid = n->get_family_id(); if (fid == m.get_basic_family_id()) return; @@ -437,39 +440,39 @@ struct is_non_nira_functor { case OP_MUL: if (m_linear) { if (n->get_num_args() != 2) - throw_found(); + throw_found(n); if (!u.is_numeral(n->get_arg(0))) - throw_found(); + throw_found(n); } return; case OP_IDIV: case OP_DIV: case OP_REM: case OP_MOD: if (m_linear && !u.is_numeral(n->get_arg(1))) - throw_found(); + throw_found(n); return; case OP_IS_INT: if (m_real) - throw_found(); + throw_found(n); return; case OP_TO_INT: case OP_TO_REAL: return; case OP_POWER: if (m_linear) - throw_found(); + throw_found(n); return; case OP_IRRATIONAL_ALGEBRAIC_NUM: if (m_linear || !m_real) - throw_found(); + throw_found(n); return; default: - throw_found(); + throw_found(n); } return; } if (is_uninterp_const(n)) return; - throw_found(); + throw_found(n); } }; diff --git a/src/tactic/fpa/fpa2bv_model_converter.cpp b/src/tactic/fpa/fpa2bv_model_converter.cpp index 8ebb3375d..5e952eb6e 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.cpp +++ b/src/tactic/fpa/fpa2bv_model_converter.cpp @@ -33,12 +33,29 @@ model_converter * fpa2bv_model_converter::translate(ast_translation & translator } void fpa2bv_model_converter::convert(model_core * mc, model * float_mdl) { + TRACE("fpa2bv_mc", tout << "BV Model: " << std::endl; + for (unsigned i = 0; i < mc->get_num_constants(); i++) + tout << mc->get_constant(i)->get_name() << " --> " << + mk_ismt2_pp(mc->get_const_interp(mc->get_constant(i)), m) << std::endl; + for (unsigned i = 0; i < mc->get_num_functions(); i++) { + func_decl * f = mc->get_function(i); + tout << f->get_name() << "(...) := " << std::endl; + func_interp * fi = mc->get_func_interp(f); + for (unsigned j = 0; j < fi->num_entries(); j++) { + func_entry const * fe = fi->get_entry(j); + for (unsigned k = 0; k < f->get_arity(); k++) + tout << mk_ismt2_pp(fe->get_arg(k), m) << " "; + tout << "--> " << mk_ismt2_pp(fe->get_result(), m) << std::endl; + } + tout << "else " << mk_ismt2_pp(fi->get_else(), m) << std::endl; + }); + obj_hashtable seen; m_bv2fp->convert_consts(mc, float_mdl, seen); m_bv2fp->convert_rm_consts(mc, float_mdl, seen); m_bv2fp->convert_min_max_specials(mc, float_mdl, seen); m_bv2fp->convert_uf2bvuf(mc, float_mdl, seen); - + // Keep all the non-float constants. unsigned sz = mc->get_num_constants(); for (unsigned i = 0; i < sz; i++) { @@ -46,7 +63,7 @@ void fpa2bv_model_converter::convert(model_core * mc, model * float_mdl) { if (!seen.contains(c)) float_mdl->register_decl(c, mc->get_const_interp(c)); } - + // And keep everything else sz = mc->get_num_functions(); for (unsigned i = 0; i < sz; i++) { @@ -57,7 +74,7 @@ void fpa2bv_model_converter::convert(model_core * mc, model * float_mdl) { float_mdl->register_decl(f, val); } } - + sz = mc->get_num_uninterpreted_sorts(); for (unsigned i = 0; i < sz; i++) { sort * s = mc->get_uninterpreted_sort(i); diff --git a/src/tactic/fpa/fpa2bv_model_converter.h b/src/tactic/fpa/fpa2bv_model_converter.h index 465aaa1e4..989caaa58 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.h +++ b/src/tactic/fpa/fpa2bv_model_converter.h @@ -26,7 +26,7 @@ Notes: class fpa2bv_model_converter : public model_converter { ast_manager & m; bv2fpa_converter * m_bv2fp; - + public: fpa2bv_model_converter(ast_manager & m, fpa2bv_converter & conv): m(m), @@ -53,10 +53,10 @@ public: virtual model_converter * translate(ast_translation & translator); protected: - fpa2bv_model_converter(ast_manager & m) : + fpa2bv_model_converter(ast_manager & m) : m(m), m_bv2fp(0) {} - + void convert(model_core * mc, model * float_mdl); }; diff --git a/src/tactic/sls/sls_params.pyg b/src/tactic/sls/sls_params.pyg index bf5bd181a..05405ef24 100644 --- a/src/tactic/sls/sls_params.pyg +++ b/src/tactic/sls/sls_params.pyg @@ -2,25 +2,25 @@ def_module_params('sls', export=True, description='Experimental Stochastic Local Search Solver (for QFBV only).', params=(max_memory_param(), - ('max_restarts', UINT, UINT_MAX, 'maximum number of restarts'), - ('walksat', BOOL, 1, 'use walksat assertion selection (instead of gsat)'), - ('walksat_ucb', BOOL, 1, 'use bandit heuristic for walksat assertion selection (instead of random)'), - ('walksat_ucb_constant', DOUBLE, 20.0, 'the ucb constant c in the term score + c * f(touched)'), - ('walksat_ucb_init', BOOL, 0, 'initialize total ucb touched to formula size'), - ('walksat_ucb_forget', DOUBLE, 1.0, 'scale touched by this factor every base restart interval'), - ('walksat_ucb_noise', DOUBLE, 0.0002, 'add noise 0 <= 256 * ucb_noise to ucb score for assertion selection'), - ('walksat_repick', BOOL, 1, 'repick assertion if randomizing in local minima'), - ('scale_unsat', DOUBLE, 0.5, 'scale score of unsat expressions by this factor'), - ('paws_init', UINT, 40, 'initial/minimum assertion weights'), - ('paws_sp', UINT, 52, 'smooth assertion weights with probability paws_sp / 1024'), - ('wp', UINT, 100, 'random walk with probability wp / 1024'), - ('vns_mc', UINT, 0, 'in local minima, try Monte Carlo sampling vns_mc many 2-bit-flips per bit'), - ('vns_repick', BOOL, 0, 'in local minima, try picking a different assertion (only for walksat)'), - ('restart_base', UINT, 100, 'base restart interval given by moves per run'), - ('restart_init', BOOL, 0, 'initialize to 0 or random value (= 1) after restart'), - ('early_prune', BOOL, 1, 'use early pruning for score prediction'), - ('random_offset', BOOL, 1, 'use random offset for candidate evaluation'), - ('rescore', BOOL, 1, 'rescore/normalize top-level score every base restart interval'), - ('track_unsat', BOOL, 0, 'keep a list of unsat assertions as done in SAT - currently disabled internally'), - ('random_seed', UINT, 0, 'random seed') - )) + ('max_restarts', UINT, UINT_MAX, 'maximum number of restarts'), + ('walksat', BOOL, 1, 'use walksat assertion selection (instead of gsat)'), + ('walksat_ucb', BOOL, 1, 'use bandit heuristic for walksat assertion selection (instead of random)'), + ('walksat_ucb_constant', DOUBLE, 20.0, 'the ucb constant c in the term score + c * f(touched)'), + ('walksat_ucb_init', BOOL, 0, 'initialize total ucb touched to formula size'), + ('walksat_ucb_forget', DOUBLE, 1.0, 'scale touched by this factor every base restart interval'), + ('walksat_ucb_noise', DOUBLE, 0.0002, 'add noise 0 <= 256 * ucb_noise to ucb score for assertion selection'), + ('walksat_repick', BOOL, 1, 'repick assertion if randomizing in local minima'), + ('scale_unsat', DOUBLE, 0.5, 'scale score of unsat expressions by this factor'), + ('paws_init', UINT, 40, 'initial/minimum assertion weights'), + ('paws_sp', UINT, 52, 'smooth assertion weights with probability paws_sp / 1024'), + ('wp', UINT, 100, 'random walk with probability wp / 1024'), + ('vns_mc', UINT, 0, 'in local minima, try Monte Carlo sampling vns_mc many 2-bit-flips per bit'), + ('vns_repick', BOOL, 0, 'in local minima, try picking a different assertion (only for walksat)'), + ('restart_base', UINT, 100, 'base restart interval given by moves per run'), + ('restart_init', BOOL, 0, 'initialize to 0 or random value (= 1) after restart'), + ('early_prune', BOOL, 1, 'use early pruning for score prediction'), + ('random_offset', BOOL, 1, 'use random offset for candidate evaluation'), + ('rescore', BOOL, 1, 'rescore/normalize top-level score every base restart interval'), + ('track_unsat', BOOL, 0, 'keep a list of unsat assertions as done in SAT - currently disabled internally'), + ('random_seed', UINT, 0, 'random seed') + )) diff --git a/src/tactic/sls/sls_tracker.h b/src/tactic/sls/sls_tracker.h index 651e4ef14..4ad5c65f4 100644 --- a/src/tactic/sls/sls_tracker.h +++ b/src/tactic/sls/sls_tracker.h @@ -68,7 +68,7 @@ private: typedef obj_map scores_type; typedef obj_map > uplinks_type; typedef obj_map > occ_type; - obj_hashtable m_top_expr; + obj_hashtable m_top_expr; scores_type m_scores; uplinks_type m_uplinks; entry_point_type m_entry_points; @@ -85,11 +85,11 @@ private: unsigned m_touched; double m_scale_unsat; unsigned m_paws_init; - obj_map m_where_false; - expr** m_list_false; + obj_map m_where_false; + expr** m_list_false; unsigned m_track_unsat; obj_map m_weights; - double m_top_sum; + double m_top_sum; obj_hashtable m_temp_seen; public: @@ -450,7 +450,7 @@ public: m_list_false = new expr*[sz]; for (unsigned i = 0; i < sz; i++) { - if (m_mpz_manager.eq(get_value(as[i]), m_zero)) + if (m_mpz_manager.eq(get_value(as[i]), m_zero)) break_assertion(as[i]); } } @@ -462,7 +462,7 @@ public: // initialize weights if (!m_weights.contains(e)) - m_weights.insert(e, m_paws_init); + m_weights.insert(e, m_paws_init); // positive/negative occurrences used for early pruning setup_occs(as[i]); @@ -1075,7 +1075,7 @@ public: unsigned cnt_unsat = 0; for (unsigned i = 0; i < sz; i++) - if (m_mpz_manager.neq(get_value(as[i]), m_one) && (get_random_uint(16) % ++cnt_unsat == 0)) pos = i; + if (m_mpz_manager.neq(get_value(as[i]), m_one) && (get_random_uint(16) % ++cnt_unsat == 0)) pos = i; if (pos == static_cast(-1)) return 0; } @@ -1092,7 +1092,7 @@ public: unsigned cnt_unsat = 0, pos = -1; for (unsigned i = 0; i < sz; i++) - if ((i != m_last_pos) && m_mpz_manager.neq(get_value(as[i]), m_one) && (get_random_uint(16) % ++cnt_unsat == 0)) pos = i; + if ((i != m_last_pos) && m_mpz_manager.neq(get_value(as[i]), m_one) && (get_random_uint(16) % ++cnt_unsat == 0)) pos = i; if (pos == static_cast(-1)) return 0; diff --git a/src/test/argument_parser.h b/src/test/argument_parser.h new file mode 100644 index 000000000..c8566ce34 --- /dev/null +++ b/src/test/argument_parser.h @@ -0,0 +1,157 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ + +#include +#include +#include +#include +#include + +namespace lp { +class argument_parser { + std::unordered_map m_options; + std::unordered_map m_options_with_after_string; + std::set m_used_options; + std::unordered_map m_used_options_with_after_string; + std::vector m_free_args; + std::vector m_args; + +public: + std::string m_error_message; + argument_parser(unsigned argn, char * const* args) { + for (unsigned i = 0; i < argn; i++) { + m_args.push_back(std::string(args[i])); + } + } + + void add_option(std::string s) { + add_option_with_help_string(s, ""); + } + + void add_option_with_help_string(std::string s, std::string help_string) { + m_options[s]=help_string; + } + + void add_option_with_after_string(std::string s) { + add_option_with_after_string_with_help(s, ""); + } + + void add_option_with_after_string_with_help(std::string s, std::string help_string) { + m_options_with_after_string[s]=help_string; + } + + + bool parse() { + bool status_is_ok = true; + for (unsigned i = 0; i < m_args.size(); i++) { + std::string ar = m_args[i]; + if (m_options.find(ar) != m_options.end() ) + m_used_options.insert(ar); + else if (m_options_with_after_string.find(ar) != m_options_with_after_string.end()) { + if (i == m_args.size() - 1) { + m_error_message = "Argument is missing after "+ar; + return false; + } + i++; + m_used_options_with_after_string[ar] = m_args[i]; + } else { + if (starts_with(ar, "-") || starts_with(ar, "//")) + status_is_ok = false; + + m_free_args.push_back(ar); + } + } + return status_is_ok; + } + + bool contains(std::unordered_map & m, std::string s) { + return m.find(s) != m.end(); + } + + bool contains(std::set & m, std::string s) { + return m.find(s) != m.end(); + } + + bool option_is_used(std::string option) { + return contains(m_used_options, option) || contains(m_used_options_with_after_string, option); + } + + std::string get_option_value(std::string option) { + auto t = m_used_options_with_after_string.find(option); + if (t != m_used_options_with_after_string.end()){ + return t->second; + } + return std::string(); + } + + bool starts_with(std::string s, char const * prefix) { + return starts_with(s, std::string(prefix)); + } + + bool starts_with(std::string s, std::string prefix) { + return s.substr(0, prefix.size()) == prefix; + } + + std::string usage_string() { + std::string ret = ""; + std::vector unknown_options; + for (auto t : m_free_args) { + if (starts_with(t, "-") || starts_with(t, "\\")) { + unknown_options.push_back(t); + } + } + if (unknown_options.size()) { + ret = "Unknown options:"; + } + for (auto unknownOption : unknown_options) { + ret += unknownOption; + ret += ","; + } + ret += "\n"; + ret += "Usage:\n"; + for (auto allowed_option : m_options) + ret += allowed_option.first + " " + (allowed_option.second.size() == 0 ? std::string("") : std::string("/") + allowed_option.second) + std::string("\n"); + for (auto s : m_options_with_after_string) { + ret += s.first + " " + (s.second.size() == 0? " \"option value\"":("\""+ s.second+"\"")) + "\n"; + } + return ret; + } + + void print() { + if (m_used_options.size() == 0 && m_used_options_with_after_string.size() == 0 && m_free_args.size() == 0) { + std::cout << "no options are given" << std::endl; + return; + } + std::cout << "options are: " << std::endl; + for (std::string s : m_used_options) { + std::cout << s << std::endl; + } + for (auto & t : m_used_options_with_after_string) { + std::cout << t.first << " " << t.second << std::endl; + } + if (m_free_args.size() > 0) { + std::cout << "free arguments are: " << std::endl; + for (auto & t : m_free_args) { + std::cout << t << " " << std::endl; + } + } + } +}; +} diff --git a/src/test/bit_vector.cpp b/src/test/bit_vector.cpp index e920fadee..487f6cdd0 100644 --- a/src/test/bit_vector.cpp +++ b/src/test/bit_vector.cpp @@ -27,36 +27,36 @@ static void tst1() { unsigned n = rand()%10000; for (unsigned i = 0; i < n; i++) { int op = rand()%6; - if (op <= 1) { - bool val = (rand()%2) != 0; - v1.push_back(val); - v2.push_back(val); - ENSURE(v1.size() == v2.size()); - } - else if (op <= 3) { - ENSURE(v1.size() == v2.size()); - if (v1.size() > 0) { - bool val = (rand()%2) != 0; - unsigned idx = rand()%v1.size(); - ENSURE(v1.get(idx) == v2[idx]); - v1.set(idx, val); - v2[idx] = val; - ENSURE(v1.get(idx) == v2[idx]); - } - } - else if (op <= 4) { - ENSURE(v1.size() == v2.size()); - if (v1.size() > 0) { - unsigned idx = rand()%v1.size(); - VERIFY(v1.get(idx) == v2[idx]); - } - } - else if (op <= 5) { - ENSURE(v1.size() == v2.size()); - for (unsigned j = 0; j < v1.size(); j++) { - ENSURE(v1.get(j) == v2[j]); - } - } + if (op <= 1) { + bool val = (rand()%2) != 0; + v1.push_back(val); + v2.push_back(val); + ENSURE(v1.size() == v2.size()); + } + else if (op <= 3) { + ENSURE(v1.size() == v2.size()); + if (v1.size() > 0) { + bool val = (rand()%2) != 0; + unsigned idx = rand()%v1.size(); + ENSURE(v1.get(idx) == v2[idx]); + v1.set(idx, val); + v2[idx] = val; + ENSURE(v1.get(idx) == v2[idx]); + } + } + else if (op <= 4) { + ENSURE(v1.size() == v2.size()); + if (v1.size() > 0) { + unsigned idx = rand()%v1.size(); + VERIFY(v1.get(idx) == v2[idx]); + } + } + else if (op <= 5) { + ENSURE(v1.size() == v2.size()); + for (unsigned j = 0; j < v1.size(); j++) { + ENSURE(v1.get(j) == v2[j]); + } + } } } @@ -309,6 +309,6 @@ void tst_bit_vector() { tst2(); for (unsigned i = 0; i < 20; i++) { std::cerr << i << std::endl; - tst1(); + tst1(); } } diff --git a/src/test/ddnf.cpp b/src/test/ddnf.cpp index 3f8e748be..09f1a4cf9 100644 --- a/src/test/ddnf.cpp +++ b/src/test/ddnf.cpp @@ -200,6 +200,20 @@ void tst_ddnf(char ** argv, int argc, int& i) { dealloc(ddnf); } - +void tst_ddnf1() { + enable_trace("ddnf"); + unsigned W = 2; + datalog::ddnf_core ddnf(W); + tbv_manager& tbvm = ddnf.get_tbv_manager(); + tbv* tXX = tbvm.allocate("xx"); + tbv* t1X = tbvm.allocate("1x"); + tbv* tX1 = tbvm.allocate("x1"); + tbv* t11 = tbvm.allocate("11"); + ddnf.insert(*tXX); + ddnf.insert(*t11); + ddnf.insert(*tX1); + ddnf.insert(*t1X); + ddnf.display(std::cout); +} diff --git a/src/test/diff_logic.cpp b/src/test/diff_logic.cpp index e79c93cf2..0564fbfbe 100644 --- a/src/test/diff_logic.cpp +++ b/src/test/diff_logic.cpp @@ -33,7 +33,7 @@ template class dl_graph; typedef dl_graph dlg; struct tst_dl_functor { - smt::literal_vector m_literals; + smt::literal_vector m_literals; void operator()(smt::literal l) { m_literals.push_back(l); } diff --git a/src/test/expr_rand.cpp b/src/test/expr_rand.cpp index 388a178f4..f1b20ba8e 100644 --- a/src/test/expr_rand.cpp +++ b/src/test/expr_rand.cpp @@ -98,8 +98,8 @@ void tst_expr_rand(char** argv, int argc, int& i) { i += 1; if (i + 1 < argc && 0 == strncmp(argv[i+1],"/rs:",3)) { rand_seed = atol(argv[i+1]+4); - std::cout << "random seed:" << rand_seed << "\n"; - i += 1; + std::cout << "random seed:" << rand_seed << "\n"; + i += 1; } if (i + 1 < argc && 0 == strcmp(argv[i+1],"/arith")) { diff --git a/src/test/lp.cpp b/src/test/lp.cpp new file mode 100644 index 000000000..0f4186252 --- /dev/null +++ b/src/test/lp.cpp @@ -0,0 +1,3257 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ + +#include +#if _LINUX_ +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "util/lp/lp_utils.h" +#include "util/lp/lp_primal_simplex.h" +#include "util/lp/mps_reader.h" +#include "test/smt_reader.h" +#include "util/lp/binary_heap_priority_queue.h" +#include "test/argument_parser.h" +#include "test/test_file_reader.h" +#include "util/lp/indexed_value.h" +#include "util/lp/lar_solver.h" +#include "util/lp/numeric_pair.h" +#include "util/lp/binary_heap_upair_queue.h" +#include "util/lp/stacked_value.h" +#include "util/lp/stacked_unordered_set.h" +#include "util/lp/int_set.h" +#include "util/stopwatch.h" + +namespace lp { + unsigned seed = 1; + + random_gen g_rand; + static unsigned my_random() { + return g_rand(); + } +struct simple_column_namer:public column_namer +{ + std::string get_column_name(unsigned j) const override { + return std::string("x") + T_to_string(j); + } +}; + + +template +void test_matrix(sparse_matrix & a) { + auto m = a.dimension(); + +// copy a to b in the reversed order + sparse_matrix b(m); + std::cout << "copy b to a"<< std::endl; + for (int row = m - 1; row >= 0; row--) + for (int col = m - 1; col >= 0; col --) { + b(row, col) = (T const&) a(row, col); + } + + + std::cout << "zeroing b in the reverse order"<< std::endl; + for (int row = m - 1; row >= 0; row--) + for (int col = m - 1; col >= 0; col --) + b.set(row, col, T(0)); + + + + for (unsigned row = 0; row < m; row ++) + for (unsigned col = 0; col < m; col ++) + a.set(row, col, T(0)); + + + unsigned i = my_random() % m; + unsigned j = my_random() % m; + + auto t = T(1); + + a.set(i, j, t); + + SASSERT(a.get(i, j) == t); + + unsigned j1; + if (j < m - 1) { + j1 = m - 1; + a.set(i, j1, T(2)); + } +} + +void tst1() { + std::cout << "testing the minimial matrix with 1 row and 1 column" << std::endl; + sparse_matrix m0(1); + m0.set(0, 0, 1); + // print_matrix(m0); + m0.set(0, 0, 0); + // print_matrix(m0); + test_matrix(m0); + + unsigned rows = 2; + sparse_matrix m(rows); + std::cout << "setting m(0,1)=" << std::endl; + + m.set(0, 1, 11); + m.set(0, 0, 12); + + // print_matrix(m); + + test_matrix(m); + + sparse_matrix m1(2); + m1.set(0, 0, 2); + m1.set(1, 0, 3); + // print_matrix(m1); + std::cout << " zeroing matrix 2 by 2" << std::endl; + m1.set(0, 0, 0); + m1.set(1, 0, 0); + // print_matrix(m1); + + test_matrix(m1); + + + std::cout << "printing zero matrix 3 by 1" << std::endl; + sparse_matrix m2(3); + // print_matrix(m2); + + m2.set(0, 0, 1); + m2.set(2, 0, 2); + std::cout << "printing matrix 3 by 1 with a gap" << std::endl; + // print_matrix(m2); + + test_matrix(m2); + + sparse_matrix m10by9(10); + m10by9.set(0, 1, 1); + + m10by9(0, 1) = 4; + + double test = m10by9(0, 1); + + std::cout << "got " << test << std::endl; + + + m10by9.set(0, 8, 8); + m10by9.set(3, 4, 7); + m10by9.set(3, 2, 5); + m10by9.set(3, 8, 99); + m10by9.set(3, 2, 6); + m10by9.set(1, 8, 9); + m10by9.set(4, 0, 40); + m10by9.set(0, 0, 10); + + std::cout << "printing matrix 10 by 9" << std::endl; + // print_matrix(m10by9); + + + test_matrix(m10by9); + std::cout <<"zeroing m10by9\n"; +#ifdef Z3DEBUG + for (unsigned int i = 0; i < m10by9.dimension(); i++) + for (unsigned int j = 0; j < m10by9.column_count(); j++) + m10by9.set(i, j, 0); +#endif + // print_matrix(m10by9); +} + +vector allocate_basis_heading(unsigned count) { // the rest of initilization will be handled by lu_QR + vector basis_heading(count, -1); + return basis_heading; +} + + +void init_basic_part_of_basis_heading(vector & basis, vector & basis_heading) { + SASSERT(basis_heading.size() >= basis.size()); + unsigned m = basis.size(); + for (unsigned i = 0; i < m; i++) { + unsigned column = basis[i]; + basis_heading[column] = i; + } +} + +void init_non_basic_part_of_basis_heading(vector & basis_heading, vector & non_basic_columns) { + non_basic_columns.clear(); + for (int j = basis_heading.size(); j--;){ + if (basis_heading[j] < 0) { + non_basic_columns.push_back(j); + // the index of column j in m_nbasis is (- basis_heading[j] - 1) + basis_heading[j] = - static_cast(non_basic_columns.size()); + } + } +} +void init_basis_heading_and_non_basic_columns_vector(vector & basis, + vector & basis_heading, + vector & non_basic_columns) { + init_basic_part_of_basis_heading(basis, basis_heading); + init_non_basic_part_of_basis_heading(basis_heading, non_basic_columns); +} + +void change_basis(unsigned entering, unsigned leaving, vector& basis, vector& nbasis, vector & basis_heading) { + int place_in_basis = basis_heading[leaving]; + int place_in_non_basis = - basis_heading[entering] - 1; + basis_heading[entering] = place_in_basis; + basis_heading[leaving] = -place_in_non_basis - 1; + basis[place_in_basis] = entering; + nbasis[place_in_non_basis] = leaving; +} + + +#ifdef Z3DEBUG +void test_small_lu(lp_settings & settings) { + std::cout << " test_small_lu" << std::endl; + static_matrix m(3, 6); + vector basis(3); + basis[0] = 0; + basis[1] = 1; + basis[2] = 3; + + m(0, 0) = 1; m(0, 2)= 3.9; m(2, 3) = 11; m(0, 5) = -3; + m(1, 1) = 4; m(1, 4) = 7; + m(2, 0) = 1.8; m(2, 2) = 5; m(2, 4) = 2; m(2, 5) = 8; + +#ifdef Z3DEBUG + print_matrix(m, std::cout); +#endif + vector heading = allocate_basis_heading(m.column_count()); + vector non_basic_columns; + init_basis_heading_and_non_basic_columns_vector(basis, heading, non_basic_columns); + lu l(m, basis, settings); + SASSERT(l.is_correct(basis)); + indexed_vector w(m.row_count()); + std::cout << "entering 2, leaving 0" << std::endl; + l.prepare_entering(2, w); // to init vector w + l.replace_column(0, w, heading[0]); + change_basis(2, 0, basis, non_basic_columns, heading); + // #ifdef Z3DEBUG + // std::cout << "we were factoring " << std::endl; + // print_matrix(get_B(l)); + // #endif + SASSERT(l.is_correct(basis)); + std::cout << "entering 4, leaving 3" << std::endl; + l.prepare_entering(4, w); // to init vector w + l.replace_column(0, w, heading[3]); + change_basis(4, 3, basis, non_basic_columns, heading); + std::cout << "we were factoring " << std::endl; +#ifdef Z3DEBUG + { + auto bl = get_B(l, basis); + print_matrix(&bl, std::cout); + } +#endif + SASSERT(l.is_correct(basis)); + + std::cout << "entering 5, leaving 1" << std::endl; + l.prepare_entering(5, w); // to init vector w + l.replace_column(0, w, heading[1]); + change_basis(5, 1, basis, non_basic_columns, heading); + std::cout << "we were factoring " << std::endl; +#ifdef Z3DEBUG + { + auto bl = get_B(l, basis); + print_matrix(&bl, std::cout); + } +#endif + SASSERT(l.is_correct(basis)); + std::cout << "entering 3, leaving 2" << std::endl; + l.prepare_entering(3, w); // to init vector w + l.replace_column(0, w, heading[2]); + change_basis(3, 2, basis, non_basic_columns, heading); + std::cout << "we were factoring " << std::endl; +#ifdef Z3DEBUG + { + auto bl = get_B(l, basis); + print_matrix(&bl, std::cout); + } +#endif + SASSERT(l.is_correct(basis)); + + m.add_row(); + m.add_column(); + m.add_row(); + m.add_column(); + for (unsigned i = 0; i < m.column_count(); i++) { + m(3, i) = i; + m(4, i) = i * i; // to make the rows linearly independent + } + unsigned j = m.column_count() ; + basis.push_back(j-2); + heading.push_back(basis.size() - 1); + basis.push_back(j-1); + heading.push_back(basis.size() - 1); + + auto columns_to_replace = l.get_set_of_columns_to_replace_for_add_last_rows(heading); + l.add_last_rows_to_B(heading, columns_to_replace); + std::cout << "here" << std::endl; + SASSERT(l.is_correct(basis)); +} + +#endif + +void fill_long_row(sparse_matrix &m, int i) { + int n = m.dimension(); + for (int j = 0; j < n; j ++) { + m (i, (j + i) % n) = j * j; + } +} + +void fill_long_row(static_matrix &m, int i) { + int n = m.column_count(); + for (int j = 0; j < n; j ++) { + m (i, (j + i) % n) = j * j; + } +} + + +void fill_long_row_exp(sparse_matrix &m, int i) { + int n = m.dimension(); + + for (int j = 0; j < n; j ++) { + m(i, j) = my_random() % 20; + } +} + +void fill_long_row_exp(static_matrix &m, int i) { + int n = m.column_count(); + + for (int j = 0; j < n; j ++) { + m(i, j) = my_random() % 20; + } +} + +void fill_larger_sparse_matrix_exp(sparse_matrix & m){ + for ( unsigned i = 0; i < m.dimension(); i++ ) + fill_long_row_exp(m, i); +} + +void fill_larger_sparse_matrix_exp(static_matrix & m){ + for ( unsigned i = 0; i < m.row_count(); i++ ) + fill_long_row_exp(m, i); +} + + +void fill_larger_sparse_matrix(sparse_matrix & m){ + for ( unsigned i = 0; i < m.dimension(); i++ ) + fill_long_row(m, i); +} + +void fill_larger_sparse_matrix(static_matrix & m){ + for ( unsigned i = 0; i < m.row_count(); i++ ) + fill_long_row(m, i); +} + + +int perm_id = 0; + +#ifdef Z3DEBUG +void test_larger_lu_exp(lp_settings & settings) { + std::cout << " test_larger_lu_exp" << std::endl; + static_matrix m(6, 12); + vector basis(6); + basis[0] = 1; + basis[1] = 3; + basis[2] = 0; + basis[3] = 4; + basis[4] = 5; + basis[5] = 6; + + + fill_larger_sparse_matrix_exp(m); + // print_matrix(m); + vector heading = allocate_basis_heading(m.column_count()); + vector non_basic_columns; + init_basis_heading_and_non_basic_columns_vector(basis, heading, non_basic_columns); + lu l(m, basis, settings); + + dense_matrix left_side = l.get_left_side(basis); + dense_matrix right_side = l.get_right_side(); + SASSERT(left_side == right_side); + int leaving = 3; + int entering = 8; + for (unsigned i = 0; i < m.row_count(); i++) { + std::cout << static_cast(m(i, entering)) << std::endl; + } + + indexed_vector w(m.row_count()); + + l.prepare_entering(entering, w); + l.replace_column(0, w, heading[leaving]); + change_basis(entering, leaving, basis, non_basic_columns, heading); + SASSERT(l.is_correct(basis)); + + l.prepare_entering(11, w); // to init vector w + l.replace_column(0, w, heading[0]); + change_basis(11, 0, basis, non_basic_columns, heading); + SASSERT(l.is_correct(basis)); +} + +void test_larger_lu_with_holes(lp_settings & settings) { + std::cout << " test_larger_lu_with_holes" << std::endl; + static_matrix m(8, 9); + vector basis(8); + for (unsigned i = 0; i < m.row_count(); i++) { + basis[i] = i; + } + m(0, 0) = 1; m(0, 1) = 2; m(0, 2) = 3; m(0, 3) = 4; m(0, 4) = 5; m(0, 8) = 99; + /* */ m(1, 1) =- 6; m(1, 2) = 7; m(1, 3) = 8; m(1, 4) = 9; + /* */ m(2, 2) = 10; + /* */ m(3, 2) = 11; m(3, 3) = -12; + /* */ m(4, 2) = 13; m(4, 3) = 14; m(4, 4) = 15; + // the rest of the matrix is denser + m(5, 4) = 28; m(5, 5) = -18; m(5, 6) = 19; m(5, 7) = 25; + /* */ m(6, 5) = 20; m(6, 6) = -21; + /* */ m(7, 5) = 22; m(7, 6) = 23; m(7, 7) = 24; m(7, 8) = 88; + print_matrix(m, std::cout); + vector heading = allocate_basis_heading(m.column_count()); + vector non_basic_columns; + init_basis_heading_and_non_basic_columns_vector(basis, heading, non_basic_columns); + lu l(m, basis, settings); + std::cout << "printing factorization" << std::endl; + for (int i = l.tail_size() - 1; i >=0; i--) { + auto lp = l.get_lp_matrix(i); + lp->set_number_of_columns(m.row_count()); + lp->set_number_of_rows(m.row_count()); + print_matrix( lp, std::cout); + } + + dense_matrix left_side = l.get_left_side(basis); + dense_matrix right_side = l.get_right_side(); + if (!(left_side == right_side)) { + std::cout << "different sides" << std::endl; + } + + indexed_vector w(m.row_count()); + l.prepare_entering(8, w); // to init vector w + l.replace_column(0, w, heading[0]); + change_basis(8, 0, basis, non_basic_columns, heading); + SASSERT(l.is_correct(basis)); +} + + +void test_larger_lu(lp_settings& settings) { + std::cout << " test_larger_lu" << std::endl; + static_matrix m(6, 12); + vector basis(6); + basis[0] = 1; + basis[1] = 3; + basis[2] = 0; + basis[3] = 4; + basis[4] = 5; + basis[5] = 6; + + + fill_larger_sparse_matrix(m); + print_matrix(m, std::cout); + + vector heading = allocate_basis_heading(m.column_count()); + vector non_basic_columns; + init_basis_heading_and_non_basic_columns_vector(basis, heading, non_basic_columns); + auto l = lu (m, basis, settings); + // std::cout << "printing factorization" << std::endl; + // for (int i = lu.tail_size() - 1; i >=0; i--) { + // auto lp = lu.get_lp_matrix(i); + // lp->set_number_of_columns(m.row_count()); + // lp->set_number_of_rows(m.row_count()); + // print_matrix(* lp); + // } + + dense_matrix left_side = l.get_left_side(basis); + dense_matrix right_side = l.get_right_side(); + if (!(left_side == right_side)) { + std::cout << "left side" << std::endl; + print_matrix(&left_side, std::cout); + std::cout << "right side" << std::endl; + print_matrix(&right_side, std::cout); + + std::cout << "different sides" << std::endl; + std::cout << "initial factorization is incorrect" << std::endl; + exit(1); + } + indexed_vector w(m.row_count()); + l.prepare_entering(9, w); // to init vector w + l.replace_column(0, w, heading[0]); + change_basis(9, 0, basis, non_basic_columns, heading); + SASSERT(l.is_correct(basis)); +} + + +void test_lu(lp_settings & settings) { + test_small_lu(settings); + test_larger_lu(settings); + test_larger_lu_with_holes(settings); + test_larger_lu_exp(settings); +} +#endif + + + + + + +void init_b(vector & b, sparse_matrix & m, vector& x) { + for (unsigned i = 0; i < m.dimension(); i++) { + b.push_back(m.dot_product_with_row(i, x)); + } +} + +void init_b(vector & b, static_matrix & m, vector & x) { + for (unsigned i = 0; i < m.row_count(); i++) { + b.push_back(m.dot_product_with_row(i, x)); + } +} + + +void test_lp_0() { + std::cout << " test_lp_0 " << std::endl; + static_matrix m_(3, 7); + m_(0, 0) = 3; m_(0, 1) = 2; m_(0, 2) = 1; m_(0, 3) = 2; m_(0, 4) = 1; + m_(1, 0) = 1; m_(1, 1) = 1; m_(1, 2) = 1; m_(1, 3) = 1; m_(1, 5) = 1; + m_(2, 0) = 4; m_(2, 1) = 3; m_(2, 2) = 3; m_(2, 3) = 4; m_(2, 6) = 1; + vector x_star(7); + x_star[0] = 225; x_star[1] = 117; x_star[2] = 420; + x_star[3] = x_star[4] = x_star[5] = x_star[6] = 0; + vector b; + init_b(b, m_, x_star); + vector basis(3); + basis[0] = 0; basis[1] = 1; basis[2] = 2; + vector costs(7); + costs[0] = 19; + costs[1] = 13; + costs[2] = 12; + costs[3] = 17; + costs[4] = 0; + costs[5] = 0; + costs[6] = 0; + + vector column_types(7, column_type::low_bound); + vector upper_bound_values; + lp_settings settings; + simple_column_namer cn; + vector nbasis; + vector heading; + + lp_primal_core_solver lpsolver(m_, b, x_star, basis, nbasis, heading, costs, column_types, upper_bound_values, settings, cn); + + lpsolver.solve(); +} + +void test_lp_1() { + std::cout << " test_lp_1 " << std::endl; + static_matrix m(4, 7); + m(0, 0) = 1; m(0, 1) = 3; m(0, 2) = 1; m(0, 3) = 1; + m(1, 0) = -1; m(1, 2) = 3; m(1, 4) = 1; + m(2, 0) = 2; m(2, 1) = -1; m(2, 2) = 2; m(2, 5) = 1; + m(3, 0) = 2; m(3, 1) = 3; m(3, 2) = -1; m(3, 6) = 1; +#ifdef Z3DEBUG + print_matrix(m, std::cout); +#endif + vector x_star(7); + x_star[0] = 0; x_star[1] = 0; x_star[2] = 0; + x_star[3] = 3; x_star[4] = 2; x_star[5] = 4; x_star[6] = 2; + + vector basis(4); + basis[0] = 3; basis[1] = 4; basis[2] = 5; basis[3] = 6; + + vector b; + b.push_back(3); + b.push_back(2); + b.push_back(4); + b.push_back(2); + + vector costs(7); + costs[0] = 5; + costs[1] = 5; + costs[2] = 3; + costs[3] = 0; + costs[4] = 0; + costs[5] = 0; + costs[6] = 0; + + + + vector column_types(7, column_type::low_bound); + vector upper_bound_values; + + std::cout << "calling lp\n"; + lp_settings settings; + simple_column_namer cn; + + vector nbasis; + vector heading; + + lp_primal_core_solver lpsolver(m, b, + x_star, + basis, + nbasis, heading, + costs, + column_types, upper_bound_values, settings, cn); + + lpsolver.solve(); +} + + +void test_lp_primal_core_solver() { + test_lp_0(); + test_lp_1(); +} + + +#ifdef Z3DEBUG +template +void test_swap_rows_with_permutation(sparse_matrix& m){ + std::cout << "testing swaps" << std::endl; + unsigned dim = m.row_count(); + dense_matrix original(&m); + permutation_matrix q(dim); + print_matrix(m, std::cout); + SASSERT(original == q * m); + for (int i = 0; i < 100; i++) { + unsigned row1 = my_random() % dim; + unsigned row2 = my_random() % dim; + if (row1 == row2) continue; + std::cout << "swap " << row1 << " " << row2 << std::endl; + m.swap_rows(row1, row2); + q.transpose_from_left(row1, row2); + SASSERT(original == q * m); + print_matrix(m, std::cout); + std::cout << std::endl; + } +} +#endif +template +void fill_matrix(sparse_matrix& m); // forward definition +#ifdef Z3DEBUG +template +void test_swap_cols_with_permutation(sparse_matrix& m){ + std::cout << "testing swaps" << std::endl; + unsigned dim = m.row_count(); + dense_matrix original(&m); + permutation_matrix q(dim); + print_matrix(m, std::cout); + SASSERT(original == q * m); + for (int i = 0; i < 100; i++) { + unsigned row1 = my_random() % dim; + unsigned row2 = my_random() % dim; + if (row1 == row2) continue; + std::cout << "swap " << row1 << " " << row2 << std::endl; + m.swap_rows(row1, row2); + q.transpose_from_right(row1, row2); + SASSERT(original == q * m); + print_matrix(m, std::cout); + std::cout << std::endl; + } +} + + +template +void test_swap_rows(sparse_matrix& m, unsigned i0, unsigned i1){ + std::cout << "test_swap_rows(" << i0 << "," << i1 << ")" << std::endl; + sparse_matrix mcopy(m.dimension()); + for (unsigned i = 0; i < m.dimension(); i++) + for (unsigned j = 0; j < m.dimension(); j++) { + mcopy(i, j)= m(i, j); + } + std::cout << "swapping rows "<< i0 << "," << i1 << std::endl; + m.swap_rows(i0, i1); + + for (unsigned j = 0; j < m.dimension(); j++) { + SASSERT(mcopy(i0, j) == m(i1, j)); + SASSERT(mcopy(i1, j) == m(i0, j)); + } +} +template +void test_swap_columns(sparse_matrix& m, unsigned i0, unsigned i1){ + std::cout << "test_swap_columns(" << i0 << "," << i1 << ")" << std::endl; + sparse_matrix mcopy(m.dimension()); + for (unsigned i = 0; i < m.dimension(); i++) + for (unsigned j = 0; j < m.dimension(); j++) { + mcopy(i, j)= m(i, j); + } + m.swap_columns(i0, i1); + + for (unsigned j = 0; j < m.dimension(); j++) { + SASSERT(mcopy(j, i0) == m(j, i1)); + SASSERT(mcopy(j, i1) == m(j, i0)); + } + + for (unsigned i = 0; i < m.dimension(); i++) { + if (i == i0 || i == i1) + continue; + for (unsigned j = 0; j < m.dimension(); j++) { + SASSERT(mcopy(j, i)== m(j, i)); + } + } +} +#endif + +template +void fill_matrix(sparse_matrix& m){ + int v = 0; + for (int i = m.dimension() - 1; i >= 0; i--) { + for (int j = m.dimension() - 1; j >=0; j--){ + m(i, j) = v++; + } + } +} + +void test_pivot_like_swaps_and_pivot(){ + sparse_matrix m(10); + fill_matrix(m); + // print_matrix(m); +// pivot at 2,7 + m.swap_columns(0, 7); + // print_matrix(m); + m.swap_rows(2, 0); + // print_matrix(m); + for (unsigned i = 1; i < m.dimension(); i++) { + m(i, 0) = 0; + } + // print_matrix(m); + +// say pivot at 3,4 + m.swap_columns(1, 4); + // print_matrix(m); + m.swap_rows(1, 3); + // print_matrix(m); + + vector row; + double alpha = 2.33; + unsigned pivot_row = 1; + unsigned target_row = 2; + unsigned pivot_row_0 = 3; + double beta = 3.1; + m(target_row, 3) = 0; + m(target_row, 5) = 0; + m(pivot_row, 6) = 0; +#ifdef Z3DEBUG + print_matrix(m, std::cout); +#endif + + for (unsigned j = 0; j < m.dimension(); j++) { + row.push_back(m(target_row, j) + alpha * m(pivot_row, j) + beta * m(pivot_row_0, j)); + } + + for (auto & t : row) { + std::cout << t << ","; + } + std::cout << std::endl; + lp_settings settings; + m.pivot_row_to_row(pivot_row, alpha, target_row, settings); + m.pivot_row_to_row(pivot_row_0, beta, target_row, settings); + // print_matrix(m); + for (unsigned j = 0; j < m.dimension(); j++) { + SASSERT(abs(row[j] - m(target_row, j)) < 0.00000001); + } +} + +#ifdef Z3DEBUG +void test_swap_rows() { + sparse_matrix m(10); + fill_matrix(m); + // print_matrix(m); + test_swap_rows(m, 3, 5); + + test_swap_rows(m, 1, 3); + + + test_swap_rows(m, 1, 3); + + test_swap_rows(m, 1, 7); + + test_swap_rows(m, 3, 7); + + test_swap_rows(m, 0, 7); + + m(0, 4) = 1; + // print_matrix(m); + test_swap_rows(m, 0, 7); + +// go over some corner cases + sparse_matrix m0(2); + test_swap_rows(m0, 0, 1); + m0(0, 0) = 3; + test_swap_rows(m0, 0, 1); + m0(1, 0) = 3; + test_swap_rows(m0, 0, 1); + + + sparse_matrix m1(10); + test_swap_rows(m1, 0, 1); + m1(0, 0) = 3; + test_swap_rows(m1, 0, 1); + m1(1, 0) = 3; + m1(0, 3) = 5; + m1(1, 3) = 4; + m1(1, 8) = 8; + m1(1, 9) = 8; + + test_swap_rows(m1, 0, 1); + + sparse_matrix m2(3); + test_swap_rows(m2, 0, 1); + m2(0, 0) = 3; + test_swap_rows(m2, 0, 1); + m2(2, 0) = 3; + test_swap_rows(m2, 0, 2); +} + +void fill_uniformly(sparse_matrix & m, unsigned dim) { + int v = 0; + for (unsigned i = 0; i < dim; i++) { + for (unsigned j = 0; j < dim; j++) { + m(i, j) = v++; + } + } +} + +void fill_uniformly(dense_matrix & m, unsigned dim) { + int v = 0; + for (unsigned i = 0; i < dim; i++) { + for (unsigned j = 0; j < dim; j++) { + m.set_elem(i, j, v++); + } + } +} + +void sparse_matrix_with_permutaions_test() { + unsigned dim = 4; + sparse_matrix m(dim); + fill_uniformly(m, dim); + dense_matrix dm(dim, dim); + fill_uniformly(dm, dim); + dense_matrix dm0(dim, dim); + fill_uniformly(dm0, dim); + permutation_matrix q0(dim); + q0[0] = 1; + q0[1] = 0; + q0[2] = 3; + q0[3] = 2; + permutation_matrix q1(dim); + q1[0] = 1; + q1[1] = 2; + q1[2] = 3; + q1[3] = 0; + permutation_matrix p0(dim); + p0[0] = 1; + p0[1] = 0; + p0[2] = 3; + p0[3] = 2; + permutation_matrix p1(dim); + p1[0] = 1; + p1[1] = 2; + p1[2] = 3; + p1[3] = 0; + + m.multiply_from_left(q0); + for (unsigned i = 0; i < dim; i++) { + for (unsigned j = 0; j < dim; j++) { + SASSERT(m(i, j) == dm0.get_elem(q0[i], j)); + } + } + + auto q0_dm = q0 * dm; + SASSERT(m == q0_dm); + + m.multiply_from_left(q1); + for (unsigned i = 0; i < dim; i++) { + for (unsigned j = 0; j < dim; j++) { + SASSERT(m(i, j) == dm0.get_elem(q0[q1[i]], j)); + } + } + + + auto q1_q0_dm = q1 * q0_dm; + + SASSERT(m == q1_q0_dm); + + m.multiply_from_right(p0); + + for (unsigned i = 0; i < dim; i++) { + for (unsigned j = 0; j < dim; j++) { + SASSERT(m(i, j) == dm0.get_elem(q0[q1[i]], p0[j])); + } + } + + auto q1_q0_dm_p0 = q1_q0_dm * p0; + + SASSERT(m == q1_q0_dm_p0); + + m.multiply_from_right(p1); + + for (unsigned i = 0; i < dim; i++) { + for (unsigned j = 0; j < dim; j++) { + SASSERT(m(i, j) == dm0.get_elem(q0[q1[i]], p1[p0[j]])); + } + } + + auto q1_q0_dm_p0_p1 = q1_q0_dm_p0 * p1; + SASSERT(m == q1_q0_dm_p0_p1); + + m.multiply_from_right(p1); + for (unsigned i = 0; i < dim; i++) { + for (unsigned j = 0; j < dim; j++) { + SASSERT(m(i, j) == dm0.get_elem(q0[q1[i]], p1[p1[p0[j]]])); + } + } + auto q1_q0_dm_p0_p1_p1 = q1_q0_dm_p0_p1 * p1; + + SASSERT(m == q1_q0_dm_p0_p1_p1); +} + +void test_swap_columns() { + sparse_matrix m(10); + fill_matrix(m); + // print_matrix(m); + + test_swap_columns(m, 3, 5); + + test_swap_columns(m, 1, 3); + + test_swap_columns(m, 1, 3); + + // print_matrix(m); + test_swap_columns(m, 1, 7); + + test_swap_columns(m, 3, 7); + + test_swap_columns(m, 0, 7); + + test_swap_columns(m, 0, 7); + +// go over some corner cases + sparse_matrix m0(2); + test_swap_columns(m0, 0, 1); + m0(0, 0) = 3; + test_swap_columns(m0, 0, 1); + m0(0, 1) = 3; + test_swap_columns(m0, 0, 1); + + + sparse_matrix m1(10); + test_swap_columns(m1, 0, 1); + m1(0, 0) = 3; + test_swap_columns(m1, 0, 1); + m1(0, 1) = 3; + m1(3, 0) = 5; + m1(3, 1) = 4; + m1(8, 1) = 8; + m1(9, 1) = 8; + + test_swap_columns(m1, 0, 1); + + sparse_matrix m2(3); + test_swap_columns(m2, 0, 1); + m2(0, 0) = 3; + test_swap_columns(m2, 0, 1); + m2(0, 2) = 3; + test_swap_columns(m2, 0, 2); +} + + + +void test_swap_operations() { + test_swap_rows(); + test_swap_columns(); +} + +void test_dense_matrix() { + dense_matrix d(3, 2); + d.set_elem(0, 0, 1); + d.set_elem(1, 1, 2); + d.set_elem(2, 0, 3); + // print_matrix(d); + + dense_matrix unit(2, 2); + d.set_elem(0, 0, 1); + d.set_elem(1, 1, 1); + + dense_matrix c = d * unit; + + // print_matrix(d); + + dense_matrix perm(3, 3); + perm.set_elem(0, 1, 1); + perm.set_elem(1, 0, 1); + perm.set_elem(2, 2, 1); + auto c1 = perm * d; + // print_matrix(c1); + + + dense_matrix p2(2, 2); + p2.set_elem(0, 1, 1); + p2.set_elem(1, 0, 1); + auto c2 = d * p2; +} +#endif + + + +vector> vector_of_permutaions() { + vector> ret; + { + permutation_matrix p0(5); + p0[0] = 1; p0[1] = 2; p0[2] = 3; p0[3] = 4; + p0[4] = 0; + ret.push_back(p0); + } + { + permutation_matrix p0(5); + p0[0] = 2; p0[1] = 0; p0[2] = 1; p0[3] = 4; + p0[4] = 3; + ret.push_back(p0); + } + return ret; +} + +void test_apply_reverse_from_right_to_perm(permutation_matrix & l) { + permutation_matrix p(5); + p[0] = 4; p[1] = 2; p[2] = 0; p[3] = 3; + p[4] = 1; + + permutation_matrix pclone(5); + pclone[0] = 4; pclone[1] = 2; pclone[2] = 0; pclone[3] = 3; + pclone[4] = 1; + + p.multiply_by_reverse_from_right(l); +#ifdef Z3DEBUG + auto rev = l.get_inverse(); + auto rs = pclone * rev; + SASSERT(p == rs); +#endif +} + +void test_apply_reverse_from_right() { + auto vec = vector_of_permutaions(); + for (unsigned i = 0; i < vec.size(); i++) { + test_apply_reverse_from_right_to_perm(vec[i]); + } +} + +void test_permutations() { + std::cout << "test permutations" << std::endl; + test_apply_reverse_from_right(); + vector v; v.resize(5, 0); + v[1] = 1; + v[3] = 3; + permutation_matrix p(5); + p[0] = 4; p[1] = 2; p[2] = 0; p[3] = 3; + p[4] = 1; + + indexed_vector vi(5); + vi.set_value(1, 1); + vi.set_value(3, 3); + + p.apply_reverse_from_right_to_T(v); + p.apply_reverse_from_right_to_T(vi); + SASSERT(vectors_are_equal(v, vi.m_data)); + SASSERT(vi.is_OK()); +} + +void lp_solver_test() { + // lp_revised_solver lp_revised; + // lp_revised.get_minimal_solution(); +} + +bool get_int_from_args_parser(const char * option, argument_parser & args_parser, unsigned & n) { + std::string s = args_parser.get_option_value(option); + if (s.size() > 0) { + n = atoi(s.c_str()); + return true; + } + return false; +} + +bool get_double_from_args_parser(const char * option, argument_parser & args_parser, double & n) { + std::string s = args_parser.get_option_value(option); + if (s.size() > 0) { + n = atof(s.c_str()); + return true; + } + return false; +} + + +void update_settings(argument_parser & args_parser, lp_settings& settings) { + unsigned n; + settings.m_simplex_strategy = simplex_strategy_enum::lu; + if (get_int_from_args_parser("--rep_frq", args_parser, n)) + settings.report_frequency = n; + else + settings.report_frequency = args_parser.option_is_used("--mpq")? 80: 1000; + + settings.print_statistics = true; + + if (get_int_from_args_parser("--percent_for_enter", args_parser, n)) + settings.percent_of_entering_to_check = n; + if (get_int_from_args_parser("--partial_pivot", args_parser, n)) { + std::cout << "setting partial pivot constant to " << n << std::endl; + settings.c_partial_pivoting = n; + } + if (get_int_from_args_parser("--density", args_parser, n)) { + double density = static_cast(n) / 100.0; + std::cout << "setting density to " << density << std::endl; + settings.density_threshold = density; + } + if (get_int_from_args_parser("--maxng", args_parser, n)) + settings.max_number_of_iterations_with_no_improvements = n; + double d; + if (get_double_from_args_parser("--harris_toler", args_parser, d)) { + std::cout << "setting harris_feasibility_tolerance to " << d << std::endl; + settings.harris_feasibility_tolerance = d; + } + if (get_int_from_args_parser("--random_seed", args_parser, n)) { + settings.random_seed(n); + } + if (get_int_from_args_parser("--simplex_strategy", args_parser, n)) { + settings.simplex_strategy() = static_cast(n); + } +} + +template +void setup_solver(unsigned max_iterations, unsigned time_limit, bool look_for_min, argument_parser & args_parser, lp_solver * solver) { + if (max_iterations > 0) + solver->set_max_iterations_per_stage(max_iterations); + + if (time_limit > 0) + solver->set_time_limit(time_limit); + + if (look_for_min) + solver->flip_costs(); + + update_settings(args_parser, solver->settings()); +} + +bool values_are_one_percent_close(double a, double b); + +void print_x(mps_reader & reader, lp_solver * solver) { + for (auto name : reader.column_names()) { + std::cout << name << "=" << solver->get_column_value_by_name(name) << ' '; + } + std::cout << std::endl; +} + +void compare_solutions(mps_reader & reader, lp_solver * solver, lp_solver * solver0) { + for (auto name : reader.column_names()) { + double a = solver->get_column_value_by_name(name); + double b = solver0->get_column_value_by_name(name); + if (!values_are_one_percent_close(a, b)) { + std::cout << "different values for " << name << ":" << a << " and " << b << std::endl; + } + } +} + + +void solve_mps_double(std::string file_name, bool look_for_min, unsigned max_iterations, unsigned time_limit, bool dual, bool compare_with_primal, argument_parser & args_parser) { + mps_reader reader(file_name); + reader.read(); + if (!reader.is_ok()) { + std::cout << "cannot process " << file_name << std::endl; + return; + } + + lp_solver * solver = reader.create_solver(dual); + setup_solver(max_iterations, time_limit, look_for_min, args_parser, solver); + stopwatch sw; + sw.start(); + if (dual) { + std::cout << "solving for dual" << std::endl; + } + solver->find_maximal_solution(); + sw.stop(); + double span = sw.get_seconds(); + std::cout << "Status: " << lp_status_to_string(solver->get_status()) << std::endl; + if (solver->get_status() == lp_status::OPTIMAL) { + if (reader.column_names().size() < 20) { + print_x(reader, solver); + } + double cost = solver->get_current_cost(); + if (look_for_min) { + cost = -cost; + } + std::cout << "cost = " << cost << std::endl; + } + std::cout << "processed in " << span / 1000.0 << " seconds, running for " << solver->m_total_iterations << " iterations" << " one iter for " << (double)span/solver->m_total_iterations << " ms" << std::endl; + if (compare_with_primal) { + auto * primal_solver = reader.create_solver(false); + setup_solver(max_iterations, time_limit, look_for_min, args_parser, primal_solver); + primal_solver->find_maximal_solution(); + if (solver->get_status() != primal_solver->get_status()) { + std::cout << "statuses are different: dual " << lp_status_to_string(solver->get_status()) << " primal = " << lp_status_to_string(primal_solver->get_status()) << std::endl; + } else { + if (solver->get_status() == lp_status::OPTIMAL) { + double cost = solver->get_current_cost(); + if (look_for_min) { + cost = -cost; + } + double primal_cost = primal_solver->get_current_cost(); + if (look_for_min) { + primal_cost = -primal_cost; + } + std::cout << "primal cost = " << primal_cost << std::endl; + if (!values_are_one_percent_close(cost, primal_cost)) { + compare_solutions(reader, primal_solver, solver); + print_x(reader, primal_solver); + std::cout << "dual cost is " << cost << ", but primal cost is " << primal_cost << std::endl; + SASSERT(false); + } + } + } + delete primal_solver; + } + delete solver; +} + +void solve_mps_rational(std::string file_name, bool look_for_min, unsigned max_iterations, unsigned time_limit, bool dual, argument_parser & args_parser) { + mps_reader reader(file_name); + reader.read(); + if (reader.is_ok()) { + auto * solver = reader.create_solver(dual); + setup_solver(max_iterations, time_limit, look_for_min, args_parser, solver); + stopwatch sw; + sw.start(); + solver->find_maximal_solution(); + std::cout << "Status: " << lp_status_to_string(solver->get_status()) << std::endl; + + if (solver->get_status() == lp_status::OPTIMAL) { + // for (auto name: reader.column_names()) { + // std::cout << name << "=" << solver->get_column_value_by_name(name) << ' '; + // } + lp::mpq cost = solver->get_current_cost(); + if (look_for_min) { + cost = -cost; + } + std::cout << "cost = " << cost.get_double() << std::endl; + } + std::cout << "processed in " << sw.get_current_seconds() / 1000.0 << " seconds, running for " << solver->m_total_iterations << " iterations" << std::endl; + delete solver; + } else { + std::cout << "cannot process " << file_name << std::endl; + } +} +void get_time_limit_and_max_iters_from_parser(argument_parser & args_parser, unsigned & time_limit, unsigned & max_iters); // forward definition + +void solve_mps(std::string file_name, bool look_for_min, unsigned max_iterations, unsigned time_limit, bool solve_for_rational, bool dual, bool compare_with_primal, argument_parser & args_parser) { + if (!solve_for_rational) { + std::cout << "solving " << file_name << std::endl; + solve_mps_double(file_name, look_for_min, max_iterations, time_limit, dual, compare_with_primal, args_parser); + } + else { + std::cout << "solving " << file_name << " in rationals " << std::endl; + solve_mps_rational(file_name, look_for_min, max_iterations, time_limit, dual, args_parser); + } +} + +void solve_mps(std::string file_name, argument_parser & args_parser) { + bool look_for_min = args_parser.option_is_used("--min"); + unsigned max_iterations, time_limit; + bool solve_for_rational = args_parser.option_is_used("--mpq"); + bool dual = args_parser.option_is_used("--dual"); + bool compare_with_primal = args_parser.option_is_used("--compare_with_primal"); + get_time_limit_and_max_iters_from_parser(args_parser, time_limit, max_iterations); + solve_mps(file_name, look_for_min, max_iterations, time_limit, solve_for_rational, dual, compare_with_primal, args_parser); +} + +void solve_mps_in_rational(std::string file_name, bool dual, argument_parser & /*args_parser*/) { + std::cout << "solving " << file_name << std::endl; + + mps_reader reader(file_name); + reader.read(); + if (reader.is_ok()) { + auto * solver = reader.create_solver(dual); + solver->find_maximal_solution(); + std::cout << "status is " << lp_status_to_string(solver->get_status()) << std::endl; + if (solver->get_status() == lp_status::OPTIMAL) { + if (reader.column_names().size() < 20) { + for (auto name : reader.column_names()) { + std::cout << name << "=" << solver->get_column_value_by_name(name).get_double() << ' '; + } + } + std::cout << std::endl << "cost = " << numeric_traits::get_double(solver->get_current_cost()) << std::endl; + } + delete solver; + } else { + std::cout << "cannot process " << file_name << std::endl; + } +} + +void test_upair_queue() { + int n = 10; + binary_heap_upair_queue q(2); + std::unordered_map m; + for (int k = 0; k < 100; k++) { + int i = my_random()%n; + int j = my_random()%n; + q.enqueue(i, j, my_random()%n); + } + + q.remove(5, 5); + + while (!q.is_empty()) { + unsigned i, j; + q.dequeue(i, j); + } +} + +void test_binary_priority_queue() { + std::cout << "testing binary_heap_priority_queue..."; + auto q = binary_heap_priority_queue(10); + q.enqueue(2, 2); + q.enqueue(1, 1); + q.enqueue(9, 9); + q.enqueue(8, 8); + q.enqueue(5, 25); + q.enqueue(3, 3); + q.enqueue(4, 4); + q.enqueue(7, 30); + q.enqueue(6, 6); + q.enqueue(0, 0); + q.enqueue(5, 5); + q.enqueue(7, 7); + + for (unsigned i = 0; i < 10; i++) { + unsigned de = q.dequeue(); + SASSERT(i == de); + std::cout << de << std::endl; + } + q.enqueue(2, 2); + q.enqueue(1, 1); + q.enqueue(9, 9); + q.enqueue(8, 8); + q.enqueue(5, 5); + q.enqueue(3, 3); + q.enqueue(4, 4); + q.enqueue(7, 2); + q.enqueue(0, 1); + q.enqueue(6, 6); + q.enqueue(7, 7); + q.enqueue(33, 1000); + q.enqueue(20, 0); + q.dequeue(); + q.remove(33); + q.enqueue(0, 0); +#ifdef Z3DEBUG + unsigned t = 0; + while (q.size() > 0) { + unsigned d =q.dequeue(); + SASSERT(t++ == d); + std::cout << d << std::endl; + } +#endif + test_upair_queue(); + std::cout << " done" << std::endl; +} + +bool solution_is_feasible(std::string file_name, const std::unordered_map & solution) { + mps_reader reader(file_name); + reader.read(); + if (reader.is_ok()) { + lp_primal_simplex * solver = static_cast *>(reader.create_solver(false)); + return solver->solution_is_feasible(solution); + } + return false; +} + + +void solve_mps_with_known_solution(std::string file_name, std::unordered_map * solution, lp_status status, bool dual) { + std::cout << "solving " << file_name << std::endl; + mps_reader reader(file_name); + reader.read(); + if (reader.is_ok()) { + auto * solver = reader.create_solver(dual); + solver->find_maximal_solution(); + std::cout << "status is " << lp_status_to_string(solver->get_status()) << std::endl; + if (status != solver->get_status()){ + std::cout << "status should be " << lp_status_to_string(status) << std::endl; + SASSERT(status == solver->get_status()); + throw "status is wrong"; + } + if (solver->get_status() == lp_status::OPTIMAL) { + std::cout << "cost = " << solver->get_current_cost() << std::endl; + if (solution != nullptr) { + for (auto it : *solution) { + if (fabs(it.second - solver->get_column_value_by_name(it.first)) >= 0.000001) { + std::cout << "expected:" << it.first << "=" << + it.second <<", got " << solver->get_column_value_by_name(it.first) << std::endl; + } + SASSERT(fabs(it.second - solver->get_column_value_by_name(it.first)) < 0.000001); + } + } + if (reader.column_names().size() < 20) { + for (auto name : reader.column_names()) { + std::cout << name << "=" << solver->get_column_value_by_name(name) << ' '; + } + std::cout << std::endl; + } + } + delete solver; + } else { + std::cout << "cannot process " << file_name << std::endl; + } +} + +int get_random_rows() { + return 5 + my_random() % 2; +} + +int get_random_columns() { + return 5 + my_random() % 3; +} + +int get_random_int() { + return -1 + my_random() % 2; // (1.0 + RAND_MAX); +} + +void add_random_row(lp_primal_simplex * solver, int cols, int row) { + solver->add_constraint(lp_relation::Greater_or_equal, 1, row); + for (int i = 0; i < cols; i++) { + solver->set_row_column_coefficient(row, i, get_random_int()); + } +} + +void add_random_cost(lp_primal_simplex * solver, int cols) { + for (int i = 0; i < cols; i++) { + solver->set_cost_for_column(i, get_random_int()); + } +} + +lp_primal_simplex * generate_random_solver() { + int rows = get_random_rows(); + int cols = get_random_columns(); + auto * solver = new lp_primal_simplex(); + for (int i = 0; i < rows; i++) { + add_random_row(solver, cols, i); + } + add_random_cost(solver, cols); + return solver; +} + + + +void random_test_on_i(unsigned i) { + if (i % 1000 == 0) { + std::cout << "."; + } + srand(i); + auto *solver = generate_random_solver(); + solver->find_maximal_solution(); + // std::cout << lp_status_to_string(solver->get_status()) << std::endl; + delete solver; +} + +void random_test() { + for (unsigned i = 0; i < std::numeric_limits::max(); i++) { + try { + random_test_on_i(i); + } + catch (const char * error) { + std::cout << "i = " << i << ", throwing at ' " << error << "'" << std::endl; + break; + } + } +} + +#if _LINUX_ +void fill_file_names(vector &file_names, std::set & minimums) { + char *home_dir = getenv("HOME"); + if (home_dir == nullptr) { + std::cout << "cannot find home directory, don't know how to find the files"; + return; + } + std::string home_dir_str(home_dir); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/l0redund.mps"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/l1.mps"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/l2.mps"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/l3.mps"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/l4.mps"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/l4fix.mps"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/plan.mps"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/samp2.mps"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/murtagh.mps"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/l0.mps"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/AFIRO.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SC50B.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SC50A.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/KB2.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SC105.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/STOCFOR1.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/ADLITTLE.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/BLEND.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCAGR7.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SC205.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SHARE2B.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/RECIPELP.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/LOTFI.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/VTP-BASE.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SHARE1B.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/BOEING2.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/BORE3D.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCORPION.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/CAPRI.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/BRANDY.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCAGR25.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCTAP1.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/ISRAEL.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCFXM1.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/BANDM.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/E226.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/AGG.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/GROW7.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/ETAMACRO.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/FINNIS.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCSD1.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/STANDATA.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/STANDGUB.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/BEACONFD.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/STAIR.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/STANDMPS.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/GFRD-PNC.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCRS8.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/BOEING1.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/MODSZK1.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/DEGEN2.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/FORPLAN.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/AGG2.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/AGG3.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCFXM2.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SHELL.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/PILOT4.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCSD6.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SHIP04S.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SEBA.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/GROW15.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/FFFFF800.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/BNL1.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/PEROLD.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/QAP8.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCFXM3.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SHIP04L.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/GANGES.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCTAP2.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/GROW22.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SHIP08S.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/PILOT-WE.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/MAROS.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/STOCFOR2.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/25FV47.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SHIP12S.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCSD8.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/FIT1P.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCTAP3.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SIERRA.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/PILOTNOV.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/CZPROB.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/FIT1D.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/PILOT-JA.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SHIP08L.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/BNL2.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/NESM.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/CYCLE.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/acc-tight5.mps"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SHIP12L.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/DEGEN3.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/GREENBEA.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/GREENBEB.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/80BAU3B.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/TRUSS.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/D2Q06C.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/WOODW.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/QAP12.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/D6CUBE.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/PILOT.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/DFL001.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/WOOD1P.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/FIT2P.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/PILOT87.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/STOCFOR3.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/QAP15.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/FIT2D.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/MAROS-R7.SIF"); + minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/FIT2P.SIF"); + minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/DFL001.SIF"); + minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/D2Q06C.SIF"); + minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/80BAU3B.SIF"); + minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/GREENBEB.SIF"); + minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/GREENBEA.SIF"); + minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/BNL2.SIF"); + minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/SHIP08L.SIF"); + minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/FIT1D.SIF"); + minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/SCTAP3.SIF"); + minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/SCSD8.SIF"); + minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/SCSD6.SIF"); + minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/MAROS-R7.SIF"); +} + +void test_out_dir(std::string out_dir) { + auto *out_dir_p = opendir(out_dir.c_str()); + if (out_dir_p == nullptr) { + std::cout << "creating directory " << out_dir << std::endl; +#ifdef LEAN_WINDOWS + int res = mkdir(out_dir.c_str()); +#else + int res = mkdir(out_dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); +#endif + if (res) { + std::cout << "Cannot open output directory \"" << out_dir << "\"" << std::endl; + } + return; + } + closedir(out_dir_p); +} + +void find_dir_and_file_name(std::string a, std::string & dir, std::string& fn) { + // todo: make it system independent + size_t last_slash_pos = a.find_last_of("/"); + if (last_slash_pos >= a.size()) { + std::cout << "cannot find file name in " << a << std::endl; + throw; + } + dir = a.substr(0, last_slash_pos); + // std::cout << "dir = " << dir << std::endl; + fn = a.substr(last_slash_pos + 1); + // std::cout << "fn = " << fn << std::endl; +} + +void process_test_file(std::string test_dir, std::string test_file_name, argument_parser & args_parser, std::string out_dir, unsigned max_iters, unsigned time_limit, unsigned & successes, unsigned & failures, unsigned & inconclusives); + +void solve_some_mps(argument_parser & args_parser) { + unsigned max_iters, time_limit; + get_time_limit_and_max_iters_from_parser(args_parser, time_limit, max_iters); + unsigned successes = 0; + unsigned failures = 0; + unsigned inconclusives = 0; + std::set minimums; + vector file_names; + fill_file_names(file_names, minimums); + bool solve_for_rational = args_parser.option_is_used("--mpq"); + bool dual = args_parser.option_is_used("--dual"); + bool compare_with_primal = args_parser.option_is_used("--compare_with_primal"); + bool compare_with_glpk = args_parser.option_is_used("--compare_with_glpk"); + if (compare_with_glpk) { + std::string out_dir = args_parser.get_option_value("--out_dir"); + if (out_dir.size() == 0) { + out_dir = "/tmp/test"; + } + test_out_dir(out_dir); + for (auto& a : file_names) { + try { + std::string file_dir; + std::string file_name; + find_dir_and_file_name(a, file_dir, file_name); + process_test_file(file_dir, file_name, args_parser, out_dir, max_iters, time_limit, successes, failures, inconclusives); + } + catch(const char *s){ + std::cout<< "exception: "<< s << std::endl; + } + } + std::cout << "comparing with glpk: successes " << successes << ", failures " << failures << ", inconclusives " << inconclusives << std::endl; + return; + } + if (!solve_for_rational) { + solve_mps(file_names[6], false, 0, time_limit, false, dual, compare_with_primal, args_parser); + solve_mps_with_known_solution(file_names[3], nullptr, INFEASIBLE, dual); // chvatal: 135(d) + std::unordered_map sol; + sol["X1"] = 0; + sol["X2"] = 6; + sol["X3"] = 0; + sol["X4"] = 15; + sol["X5"] = 2; + sol["X6"] = 1; + sol["X7"] = 1; + sol["X8"] = 0; + solve_mps_with_known_solution(file_names[9], &sol, OPTIMAL, dual); + solve_mps_with_known_solution(file_names[0], &sol, OPTIMAL, dual); + sol.clear(); + sol["X1"] = 25.0/14.0; + // sol["X2"] = 0; + // sol["X3"] = 0; + // sol["X4"] = 0; + // sol["X5"] = 0; + // sol["X6"] = 0; + // sol["X7"] = 9.0/14.0; + solve_mps_with_known_solution(file_names[5], &sol, OPTIMAL, dual); // chvatal: 135(e) + solve_mps_with_known_solution(file_names[4], &sol, OPTIMAL, dual); // chvatal: 135(e) + solve_mps_with_known_solution(file_names[2], nullptr, UNBOUNDED, dual); // chvatal: 135(c) + solve_mps_with_known_solution(file_names[1], nullptr, UNBOUNDED, dual); // chvatal: 135(b) + solve_mps(file_names[8], false, 0, time_limit, false, dual, compare_with_primal, args_parser); + // return; + for (auto& s : file_names) { + try { + solve_mps(s, minimums.find(s) != minimums.end(), max_iters, time_limit, false, dual, compare_with_primal, args_parser); + } + catch(const char *s){ + std::cout<< "exception: "<< s << std::endl; + } + } + } else { + // unsigned i = 0; + for (auto& s : file_names) { + // if (i++ > 9) return; + try { + solve_mps_in_rational(s, dual, args_parser); + } + catch(const char *s){ + std::cout<< "exception: "<< s << std::endl; + } + } + } +} +#endif + +void solve_rational() { + lp_primal_simplex solver; + solver.add_constraint(lp_relation::Equal, lp::mpq(7), 0); + solver.add_constraint(lp_relation::Equal, lp::mpq(-3), 1); + + // setting the cost + int cost[] = {-3, -1, -1, 2, -1, 1, 1, -4}; + std::string var_names[8] = {"x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8"}; + + for (unsigned i = 0; i < 8; i++) { + solver.set_cost_for_column(i, lp::mpq(cost[i])); + solver.give_symbolic_name_to_column(var_names[i], i); + } + + int row0[] = {1, 0, 3, 1, -5, -2 , 4, -6}; + for (unsigned i = 0; i < 8; i++) { + solver.set_row_column_coefficient(0, i, lp::mpq(row0[i])); + } + + int row1[] = {0, 1, -2, -1, 4, 1, -3, 5}; + for (unsigned i = 0; i < 8; i++) { + solver.set_row_column_coefficient(1, i, lp::mpq(row1[i])); + } + + int bounds[] = {8, 6, 4, 15, 2, 10, 10, 3}; + for (unsigned i = 0; i < 8; i++) { + solver.set_low_bound(i, lp::mpq(0)); + solver.set_upper_bound(i, lp::mpq(bounds[i])); + } + + std::unordered_map expected_sol; + expected_sol["x1"] = lp::mpq(0); + expected_sol["x2"] = lp::mpq(6); + expected_sol["x3"] = lp::mpq(0); + expected_sol["x4"] = lp::mpq(15); + expected_sol["x5"] = lp::mpq(2); + expected_sol["x6"] = lp::mpq(1); + expected_sol["x7"] = lp::mpq(1); + expected_sol["x8"] = lp::mpq(0); + solver.find_maximal_solution(); + SASSERT(solver.get_status() == OPTIMAL); + for (auto it : expected_sol) { + SASSERT(it.second == solver.get_column_value_by_name(it.first)); + } +} + + +std::string read_line(bool & end, std::ifstream & file) { + std::string s; + if (!getline(file, s)) { + end = true; + return std::string(); + } + end = false; + return s; +} + +bool contains(std::string const & s, char const * pattern) { + return s.find(pattern) != std::string::npos; +} + + +std::unordered_map * get_solution_from_glpsol_output(std::string & file_name) { + std::ifstream file(file_name); + if (!file.is_open()){ + std::cerr << "cannot open " << file_name << std::endl; + return nullptr; + } + std::string s; + bool end; + do { + s = read_line(end, file); + if (end) { + std::cerr << "unexpected file end " << file_name << std::endl; + return nullptr; + } + if (contains(s, "Column name")){ + break; + } + } while (true); + + read_line(end, file); + if (end) { + std::cerr << "unexpected file end " << file_name << std::endl; + return nullptr; + } + + auto ret = new std::unordered_map(); + + do { + s = read_line(end, file); + if (end) { + std::cerr << "unexpected file end " << file_name << std::endl; + return nullptr; + } + auto split = string_split(s, " \t", false); + if (split.size() == 0) { + return ret; + } + + SASSERT(split.size() > 3); + (*ret)[split[1]] = atof(split[3].c_str()); + } while (true); +} + + + +void test_init_U() { + static_matrix m(3, 7); + m(0, 0) = 10; m(0, 1) = 11; m(0, 2) = 12; m(0, 3) = 13; m(0, 4) = 14; + m(1, 0) = 20; m(1, 1) = 21; m(1, 2) = 22; m(1, 3) = 23; m(1, 5) = 24; + m(2, 0) = 30; m(2, 1) = 31; m(2, 2) = 32; m(2, 3) = 33; m(2, 6) = 34; +#ifdef Z3DEBUG + print_matrix(m, std::cout); +#endif + vector basis(3); + basis[0] = 1; + basis[1] = 2; + basis[2] = 4; + + sparse_matrix u(m, basis); + + for (unsigned i = 0; i < 3; i++) { + for (unsigned j = 0; j < 3; j ++) { + SASSERT(m(i, basis[j]) == u(i, j)); + } + } + + // print_matrix(m); + // print_matrix(u); +} + +void test_replace_column() { + sparse_matrix m(10); + fill_matrix(m); + m.swap_columns(0, 7); + m.swap_columns(6, 3); + m.swap_rows(2, 0); + for (unsigned i = 1; i < m.dimension(); i++) { + m(i, 0) = 0; + } + + indexed_vector w(m.dimension()); + for (unsigned i = 0; i < m.dimension(); i++) { + w.set_value(i % 3, i); + } + + lp_settings settings; + + for (unsigned column_to_replace = 0; column_to_replace < m.dimension(); column_to_replace ++) { + m.replace_column(column_to_replace, w, settings); + for (unsigned i = 0; i < m.dimension(); i++) { + SASSERT(abs(w[i] - m(i, column_to_replace)) < 0.00000001); + } + } +} + + +void setup_args_parser(argument_parser & parser) { + parser.add_option_with_help_string("-xyz_sample", "run a small interactive scenario"); + parser.add_option_with_after_string_with_help("--density", "the percentage of non-zeroes in the matrix below which it is not dense"); + parser.add_option_with_after_string_with_help("--harris_toler", "harris tolerance"); + parser.add_option_with_help_string("--test_swaps", "test row swaps with a permutation"); + parser.add_option_with_help_string("--test_perm", "test permutaions"); + parser.add_option_with_after_string_with_help("--checklu", "the file name for lu checking"); + parser.add_option_with_after_string_with_help("--partial_pivot", "the partial pivot constant, a number somewhere between 10 and 100"); + parser.add_option_with_after_string_with_help("--percent_for_enter", "which percent of columns check for entering column"); + parser.add_option_with_help_string("--totalinf", "minimizes the total infeasibility instead of diminishin infeasibility of the rows"); + parser.add_option_with_after_string_with_help("--rep_frq", "the report frequency, in how many iterations print the cost and other info "); + parser.add_option_with_help_string("--smt", "smt file format"); + parser.add_option_with_after_string_with_help("--filelist", "the file containing the list of files"); + parser.add_option_with_after_string_with_help("--file", "the input file name"); + parser.add_option_with_after_string_with_help("--random_seed", "random seed"); + parser.add_option_with_help_string("--bp", "bound propogation"); + parser.add_option_with_help_string("--min", "will look for the minimum for the given file if --file is used; the default is looking for the max"); + parser.add_option_with_help_string("--max", "will look for the maximum for the given file if --file is used; it is the default behavior"); + parser.add_option_with_after_string_with_help("--max_iters", "maximum total iterations in a core solver stage"); + parser.add_option_with_after_string_with_help("--time_limit", "time limit in seconds"); + parser.add_option_with_help_string("--mpq", "solve for rational numbers"); + parser.add_option_with_after_string_with_help("--simplex_strategy", "sets simplex strategy for rational number"); + parser.add_option_with_help_string("--test_lu", "test the work of the factorization"); + parser.add_option_with_help_string("--test_small_lu", "test the work of the factorization on a smallish matrix"); + parser.add_option_with_help_string("--test_larger_lu", "test the work of the factorization"); + parser.add_option_with_help_string("--test_larger_lu_with_holes", "test the work of the factorization"); + parser.add_option_with_help_string("--test_lp_0", "solve a small lp"); + parser.add_option_with_help_string("--solve_some_mps", "solves a list of mps problems"); + parser.add_option_with_after_string_with_help("--test_file_directory", "loads files from the directory for testing"); + parser.add_option_with_help_string("--compare_with_glpk", "compares the results by running glpsol"); + parser.add_option_with_after_string_with_help("--out_dir", "setting the output directory for tests, if not set /tmp is used"); + parser.add_option_with_help_string("--dual", "using the dual simplex solver"); + parser.add_option_with_help_string("--compare_with_primal", "using the primal simplex solver for comparison"); + parser.add_option_with_help_string("--lar", "test lar_solver"); + parser.add_option_with_after_string_with_help("--maxng", "max iterations without progress"); + parser.add_option_with_help_string("-tbq", "test binary queue"); + parser.add_option_with_help_string("--randomize_lar", "test randomize funclionality"); + parser.add_option_with_help_string("--smap", "test stacked_map"); + parser.add_option_with_help_string("--term", "simple term test"); + parser.add_option_with_help_string("--eti"," run a small evidence test for total infeasibility scenario"); + parser.add_option_with_help_string("--row_inf", "forces row infeasibility search"); + parser.add_option_with_help_string("-pd", "presolve with double solver"); + parser.add_option_with_help_string("--test_int_set", "test int_set"); + parser.add_option_with_help_string("--test_mpq", "test rationals"); + parser.add_option_with_help_string("--test_mpq_np", "test rationals"); + parser.add_option_with_help_string("--test_mpq_np_plus", "test rationals using plus instead of +="); +} + +struct fff { int a; int b;}; + +void test_stacked_map_itself() { + vector v(3,0); + for(auto u : v) + std::cout << u << std::endl; + + std::unordered_map foo; + fff l; + l.a = 0; + l.b =1; + foo[1] = l; + int r = 1; + int k = foo[r].a; + std::cout << k << std::endl; + + stacked_map m; + m[0] = 3; + m[1] = 4; + m.push(); + m[1] = 5; + m[2] = 2; + m.pop(); + m.erase(2); + m[2] = 3; + m.erase(1); + m.push(); + m[3] = 100; + m[4] = 200; + m.erase(1); + m.push(); + m[5] = 300; + m[6] = 400; + m[5] = 301; + m.erase(5); + m[3] = 122; + + m.pop(2); + m.pop(); +} + +void test_stacked_unsigned() { + std::cout << "test stacked unsigned" << std::endl; + stacked_value v(0); + v = 1; + v = 2; + v.push(); + v = 3; + v = 4; + v.pop(); + SASSERT(v == 2); + v ++; + v++; + std::cout << "before push v=" << v << std::endl; + v.push(); + v++; + v.push(); + v+=1; + std::cout << "v = " << v << std::endl; + v.pop(2); + SASSERT(v == 4); + const unsigned & rr = v; + std::cout << rr << std:: endl; + +} + +void test_stacked_value() { + test_stacked_unsigned(); +} + +void test_stacked_vector() { + std::cout << "test_stacked_vector" << std::endl; + stacked_vector v; + v.push(); + v.push_back(0); + v.push_back(1); + v.push(); + v[0] = 3; + v[0] = 0; + v.push_back(2); + v.push_back(3); + v.push_back(34); + v.push(); + v[1]=3; + v[2] = 3; + v.push(); + v[0]= 7; + v[1] = 9; + v.pop(2); + if (v.size()) + v[v.size() -1 ] = 7; + v.push(); + v.push_back(33); + v[0] = 13; + v.pop(); + +} + +void test_stacked_set() { +#ifdef Z3DEBUG + std::cout << "test_stacked_set" << std::endl; + stacked_unordered_set s; + s.insert(1); + s.insert(2); + s.insert(3); + std::unordered_set scopy = s(); + s.push(); + s.insert(4); + s.pop(); + SASSERT(s() == scopy); + s.push(); + s.push(); + s.insert(4); + s.insert(5); + s.push(); + s.insert(4); + s.pop(3); + SASSERT(s() == scopy); +#endif +} + +void test_stacked() { + std::cout << "test_stacked_map()" << std::endl; + test_stacked_map_itself(); + test_stacked_value(); + test_stacked_vector(); + test_stacked_set(); + +} + +char * find_home_dir() { + #ifdef _WINDOWS + #else + char * home_dir = getenv("HOME"); + if (home_dir == nullptr) { + std::cout << "cannot find home directory" << std::endl; + return nullptr; + } + #endif + return nullptr; +} + + +template +void print_chunk(T * arr, unsigned len) { + for (unsigned i = 0; i < len; i++) { + std::cout << arr[i] << ", "; + } + std::cout << std::endl; +} + +struct mem_cpy_place_holder { + static void mem_copy_hook(int * destination, unsigned num) { + if (destination == nullptr || num == 0) { + throw "bad parameters"; + } + } +}; + +void finalize(unsigned ret) { + /* + finalize_util_module(); + finalize_numerics_module(); + */ + // return ret; +} + +void get_time_limit_and_max_iters_from_parser(argument_parser & args_parser, unsigned & time_limit, unsigned & max_iters) { + std::string s = args_parser.get_option_value("--max_iters"); + if (s.size() > 0) { + max_iters = atoi(s.c_str()); + } else { + max_iters = 0; + } + + std::string time_limit_string = args_parser.get_option_value("--time_limit"); + if (time_limit_string.size() > 0) { + time_limit = atoi(time_limit_string.c_str()); + } else { + time_limit = 0; + } +} + + +std::string create_output_file_name(bool minimize, std::string file_name, bool use_mpq) { + std::string ret = file_name + "_lp_tst_" + (minimize?"min":"max"); + if (use_mpq) return ret + "_mpq.out"; + return ret + ".out"; +} + +std::string create_output_file_name_for_glpsol(bool minimize, std::string file_name){ + return file_name + (minimize?"_min":"_max") + "_glpk_out"; +} + +int run_glpk(std::string file_name, std::string glpk_out_file_name, bool minimize, unsigned time_limit) { + std::string minmax(minimize?"--min":"--max"); + std::string tmlim = time_limit > 0 ? std::string(" --tmlim ") + std::to_string(time_limit)+ " ":std::string(); + std::string command_line = std::string("glpsol --nointopt --nomip ") + minmax + tmlim + + " -o " + glpk_out_file_name +" " + file_name + " > /dev/null"; + return system(command_line.c_str()); +} + +std::string get_status(std::string file_name) { + std::ifstream f(file_name); + if (!f.is_open()) { + std::cout << "cannot open " << file_name << std::endl; + throw 0; + } + std::string str; + while (getline(f, str)) { + if (str.find("Status") != std::string::npos) { + vector tokens = split_and_trim(str); + if (tokens.size() != 2) { + std::cout << "unexpected Status string " << str << std::endl; + throw 0; + } + return tokens[1]; + } + } + std::cout << "cannot find the status line in " << file_name << std::endl; + throw 0; +} + +// returns true if the costs should be compared too +bool compare_statuses(std::string glpk_out_file_name, std::string lp_out_file_name, unsigned & successes, unsigned & failures) { + std::string glpk_status = get_status(glpk_out_file_name); + std::string lp_tst_status = get_status(lp_out_file_name); + + if (glpk_status != lp_tst_status) { + if (glpk_status == "UNDEFINED" && (lp_tst_status == "UNBOUNDED" || lp_tst_status == "INFEASIBLE")) { + successes++; + return false; + } else { + std::cout << "glpsol and lp_tst disagree: glpsol status is " << glpk_status; + std::cout << " but lp_tst status is " << lp_tst_status << std::endl; + failures++; + return false; + } + } + return lp_tst_status == "OPTIMAL"; +} + +double get_glpk_cost(std::string file_name) { + std::ifstream f(file_name); + if (!f.is_open()) { + std::cout << "cannot open " << file_name << std::endl; + throw 0; + } + std::string str; + while (getline(f, str)) { + if (str.find("Objective") != std::string::npos) { + vector tokens = split_and_trim(str); + if (tokens.size() != 5) { + std::cout << "unexpected Objective std::string " << str << std::endl; + throw 0; + } + return atof(tokens[3].c_str()); + } + } + std::cout << "cannot find the Objective line in " << file_name << std::endl; + throw 0; +} + +double get_lp_tst_cost(std::string file_name) { + std::ifstream f(file_name); + if (!f.is_open()) { + std::cout << "cannot open " << file_name << std::endl; + throw 0; + } + std::string str; + std::string cost_string; + while (getline(f, str)) { + if (str.find("cost") != std::string::npos) { + cost_string = str; + } + } + if (cost_string.size() == 0) { + std::cout << "cannot find the cost line in " << file_name << std::endl; + throw 0; + } + + vector tokens = split_and_trim(cost_string); + if (tokens.size() != 3) { + std::cout << "unexpected cost string " << cost_string << std::endl; + throw 0; + } + return atof(tokens[2].c_str()); +} + +bool values_are_one_percent_close(double a, double b) { + double maxval = std::max(fabs(a), fabs(b)); + if (maxval < 0.000001) { + return true; + } + + double one_percent = maxval / 100; + return fabs(a - b) <= one_percent; +} + +// returns true if both are optimal +void compare_costs(std::string glpk_out_file_name, + std::string lp_out_file_name, + unsigned & successes, + unsigned & failures) { + double a = get_glpk_cost(glpk_out_file_name); + double b = get_lp_tst_cost(lp_out_file_name); + + if (values_are_one_percent_close(a, b)) { + successes++; + } else { + failures++; + std::cout << "glpsol cost is " << a << " lp_tst cost is " << b << std::endl; + } +} + + + +void compare_with_glpk(std::string glpk_out_file_name, std::string lp_out_file_name, unsigned & successes, unsigned & failures, std::string /*lp_file_name*/) { +#ifdef CHECK_GLPK_SOLUTION + std::unordered_map * solution_table = get_solution_from_glpsol_output(glpk_out_file_name); + if (solution_is_feasible(lp_file_name, *solution_table)) { + std::cout << "glpk solution is feasible" << std::endl; + } else { + std::cout << "glpk solution is infeasible" << std::endl; + } + delete solution_table; +#endif + if (compare_statuses(glpk_out_file_name, lp_out_file_name, successes, failures)) { + compare_costs(glpk_out_file_name, lp_out_file_name, successes, failures); + } +} +void test_lar_on_file(std::string file_name, argument_parser & args_parser); + +void process_test_file(std::string test_dir, std::string test_file_name, argument_parser & args_parser, std::string out_dir, unsigned max_iters, unsigned time_limit, unsigned & successes, unsigned & failures, unsigned & inconclusives) { + bool use_mpq = args_parser.option_is_used("--mpq"); + bool minimize = args_parser.option_is_used("--min"); + std::string full_lp_tst_out_name = out_dir + "/" + create_output_file_name(minimize, test_file_name, use_mpq); + + std::string input_file_name = test_dir + "/" + test_file_name; + if (input_file_name[input_file_name.size() - 1] == '~') { + // std::cout << "ignoring " << input_file_name << std::endl; + return; + } + std::cout <<"processing " << input_file_name << std::endl; + + std::ofstream out(full_lp_tst_out_name); + if (!out.is_open()) { + std::cout << "cannot open file " << full_lp_tst_out_name << std::endl; + throw 0; + } + std::streambuf *coutbuf = std::cout.rdbuf(); // save old buffer + std::cout.rdbuf(out.rdbuf()); // redirect std::cout to dir_entry->d_name! + bool dual = args_parser.option_is_used("--dual"); + try { + if (args_parser.option_is_used("--lar")) + test_lar_on_file(input_file_name, args_parser); + else + solve_mps(input_file_name, minimize, max_iters, time_limit, use_mpq, dual, false, args_parser); + } + catch(...) { + std::cout << "catching the failure" << std::endl; + failures++; + std::cout.rdbuf(coutbuf); // reset to standard output again + return; + } + std::cout.rdbuf(coutbuf); // reset to standard output again + + if (args_parser.option_is_used("--compare_with_glpk")) { + std::string glpk_out_file_name = out_dir + "/" + create_output_file_name_for_glpsol(minimize, std::string(test_file_name)); + int glpk_exit_code = run_glpk(input_file_name, glpk_out_file_name, minimize, time_limit); + if (glpk_exit_code != 0) { + std::cout << "glpk failed" << std::endl; + inconclusives++; + } else { + compare_with_glpk(glpk_out_file_name, full_lp_tst_out_name, successes, failures, input_file_name); + } + } +} +/* + int my_readdir(DIR *dirp, struct dirent * +#ifndef LEAN_WINDOWS + entry +#endif + , struct dirent **result) { +#ifdef LEAN_WINDOWS + *result = readdir(dirp); // NOLINT + return *result != nullptr? 0 : 1; +#else + return readdir_r(dirp, entry, result); +#endif +} +*/ +/* +vector> get_file_list_of_dir(std::string test_file_dir) { + DIR *dir; + if ((dir = opendir(test_file_dir.c_str())) == nullptr) { + std::cout << "Cannot open directory " << test_file_dir << std::endl; + throw 0; + } + vector> ret; + struct dirent entry; + struct dirent* result; + int return_code; + for (return_code = my_readdir(dir, &entry, &result); +#ifndef LEAN_WINDOWS + result != nullptr && +#endif + return_code == 0; + return_code = my_readdir(dir, &entry, &result)) { + DIR *tmp_dp = opendir(result->d_name); + struct stat file_record; + if (tmp_dp == nullptr) { + std::string s = test_file_dir+ "/" + result->d_name; + int stat_ret = stat(s.c_str(), & file_record); + if (stat_ret!= -1) { + ret.push_back(make_pair(result->d_name, file_record.st_size)); + } else { + perror("stat"); + exit(1); + } + } else { + closedir(tmp_dp); + } + } + closedir(dir); + return ret; +} +*/ +/* +struct file_size_comp { + unordered_map& m_file_sizes; + file_size_comp(unordered_map& fs) :m_file_sizes(fs) {} + int operator()(std::string a, std::string b) { + std::cout << m_file_sizes.size() << std::endl; + std::cout << a << std::endl; + std::cout << b << std::endl; + + auto ls = m_file_sizes.find(a); + std::cout << "fa" << std::endl; + auto rs = m_file_sizes.find(b); + std::cout << "fb" << std::endl; + if (ls != m_file_sizes.end() && rs != m_file_sizes.end()) { + std::cout << "fc " << std::endl; + int r = (*ls < *rs? -1: (*ls > *rs)? 1 : 0); + std::cout << "calc r " << std::endl; + return r; + } else { + std::cout << "sc " << std::endl; + return 0; + } + } +}; + +*/ +struct sort_pred { + bool operator()(const std::pair &left, const std::pair &right) { + return left.second < right.second; + } +}; + + +void test_files_from_directory(std::string test_file_dir, argument_parser & args_parser) { + /* + std::cout << "loading files from directory \"" << test_file_dir << "\"" << std::endl; + std::string out_dir = args_parser.get_option_value("--out_dir"); + if (out_dir.size() == 0) { + out_dir = "/tmp/test"; + } + DIR *out_dir_p = opendir(out_dir.c_str()); + if (out_dir_p == nullptr) { + std::cout << "Cannot open output directory \"" << out_dir << "\"" << std::endl; + return; + } + closedir(out_dir_p); + vector> files = get_file_list_of_dir(test_file_dir); + std::sort(files.begin(), files.end(), sort_pred()); + unsigned max_iters, time_limit; + get_time_limit_and_max_iters_from_parser(args_parser, time_limit, max_iters); + unsigned successes = 0, failures = 0, inconclusives = 0; + for (auto & t : files) { + process_test_file(test_file_dir, t.first, args_parser, out_dir, max_iters, time_limit, successes, failures, inconclusives); + } + std::cout << "comparing with glpk: successes " << successes << ", failures " << failures << ", inconclusives " << inconclusives << std::endl; + */ +} + + +std::unordered_map get_solution_map(lp_solver * lps, mps_reader & reader) { + std::unordered_map ret; + for (auto it : reader.column_names()) { + ret[it] = lps->get_column_value_by_name(it); + } + return ret; +} + +void run_lar_solver(argument_parser & args_parser, lar_solver * solver, mps_reader * reader) { + std::string maxng = args_parser.get_option_value("--maxng"); + if (maxng.size() > 0) { + solver->settings().max_number_of_iterations_with_no_improvements = atoi(maxng.c_str()); + } + if (args_parser.option_is_used("-pd")){ + solver->settings().presolve_with_double_solver_for_lar = true; + } + + std::string iter = args_parser.get_option_value("--max_iters"); + if (iter.size() > 0) { + solver->settings().max_total_number_of_iterations = atoi(iter.c_str()); + } + if (args_parser.option_is_used("--compare_with_primal")){ + if (reader == nullptr) { + std::cout << "cannot compare with primal, the reader is null " << std::endl; + return; + } + auto * lps = reader->create_solver(false); + lps->find_maximal_solution(); + std::unordered_map sol = get_solution_map(lps, *reader); + std::cout << "status = " << lp_status_to_string(solver->get_status()) << std::endl; + return; + } + stopwatch sw; + sw.start(); + lp_status status = solver->solve(); + std::cout << "status is " << lp_status_to_string(status) << ", processed for " << sw.get_current_seconds() <<" seconds, and " << solver->get_total_iterations() << " iterations" << std::endl; + if (solver->get_status() == INFEASIBLE) { + vector> evidence; + solver->get_infeasibility_explanation(evidence); + } + if (args_parser.option_is_used("--randomize_lar")) { + if (solver->get_status() != OPTIMAL) { + std::cout << "cannot check randomize on an infeazible problem" << std::endl; + return; + } + std::cout << "checking randomize" << std::endl; + vector all_vars = solver->get_list_of_all_var_indices(); + unsigned m = all_vars.size(); + if (m > 100) + m = 100; + + var_index *vars = new var_index[m]; + for (unsigned i = 0; i < m; i++) + vars[i]=all_vars[i]; + + solver->random_update(m, vars); + delete []vars; + } +} + +lar_solver * create_lar_solver_from_file(std::string file_name, argument_parser & args_parser) { + if (args_parser.option_is_used("--smt")) { + smt_reader reader(file_name); + reader.read(); + if (!reader.is_ok()){ + std::cout << "cannot process " << file_name << std::endl; + return nullptr; + } + return reader.create_lar_solver(); + } + mps_reader reader(file_name); + reader.read(); + if (!reader.is_ok()) { + std::cout << "cannot process " << file_name << std::endl; + return nullptr; + } + return reader.create_lar_solver(); +} + +void test_lar_on_file(std::string file_name, argument_parser & args_parser) { + lar_solver * solver = create_lar_solver_from_file(file_name, args_parser); + mps_reader reader(file_name); + mps_reader * mps_reader = nullptr; + reader.read(); + if (reader.is_ok()) { + mps_reader = & reader; + run_lar_solver(args_parser, solver, mps_reader); + } + delete solver; +} + +vector get_file_names_from_file_list(std::string filelist) { + std::ifstream file(filelist); + if (!file.is_open()) { + std::cout << "cannot open " << filelist << std::endl; + return vector(); + } + vector ret; + bool end; + do { + std::string s = read_line(end, file); + if (end) + break; + if (s.size() == 0) + break; + ret.push_back(s); + } while (true); + return ret; +} + +void test_lar_solver(argument_parser & args_parser) { + + std::string file_name = args_parser.get_option_value("--file"); + if (file_name.size() > 0) { + test_lar_on_file(file_name, args_parser); + return; + } + + std::string file_list = args_parser.get_option_value("--filelist"); + if (file_list.size() > 0) { + for (std::string fn : get_file_names_from_file_list(file_list)) + test_lar_on_file(fn, args_parser); + return; + } +} + +void test_numeric_pair() { + numeric_pair a; + numeric_pair b(2, lp::mpq(6, 2)); + a = b; + numeric_pair c(0.1, 0.5); + a += 2*c; + a -= c; + SASSERT (a == b + c); + numeric_pair d = a * 2; + std::cout << a << std::endl; + SASSERT(b == b); + SASSERT(b < a); + SASSERT(b <= a); + SASSERT(a > b); + SASSERT(a != b); + SASSERT(a >= b); + SASSERT(-a < b); + SASSERT(a < 2 * b); + SASSERT(b + b > a); + SASSERT(lp::mpq(2.1) * b + b > a); + SASSERT(-b * lp::mpq(2.1) - b < lp::mpq(0.99) * a); + std::cout << - b * lp::mpq(2.1) - b << std::endl; + SASSERT(-b *(lp::mpq(2.1) + 1) == - b * lp::mpq(2.1) - b); +} + +void get_matrix_dimensions(std::ifstream & f, unsigned & m, unsigned & n) { + std::string line; + getline(f, line); + getline(f, line); + vector r = split_and_trim(line); + m = atoi(r[1].c_str()); + getline(f, line); + r = split_and_trim(line); + n = atoi(r[1].c_str()); +} + +void read_row_cols(unsigned i, static_matrix& A, std::ifstream & f) { + do { + std::string line; + getline(f, line); + if (line== "row_end") + break; + auto r = split_and_trim(line); + SASSERT(r.size() == 4); + unsigned j = atoi(r[1].c_str()); + double v = atof(r[3].c_str()); + A.set(i, j, v); + } while (true); +} + +bool read_row(static_matrix & A, std::ifstream & f) { + std::string line; + getline(f, line); + if (static_cast(line.find("row")) == -1) + return false; + auto r = split_and_trim(line); + if (r[0] != "row") + std::cout << "wrong row line" << line << std::endl; + unsigned i = atoi(r[1].c_str()); + read_row_cols(i, A, f); + return true; +} + +void read_rows(static_matrix& A, std::ifstream & f) { + while (read_row(A, f)) {} +} + +void read_basis(vector & basis, std::ifstream & f) { + std::cout << "reading basis" << std::endl; + std::string line; + getline(f, line); + SASSERT(line == "basis_start"); + do { + getline(f, line); + if (line == "basis_end") + break; + unsigned j = atoi(line.c_str()); + basis.push_back(j); + } while (true); +} + +void read_indexed_vector(indexed_vector & v, std::ifstream & f) { + std::string line; + getline(f, line); + SASSERT(line == "vector_start"); + do { + getline(f, line); + if (line == "vector_end") break; + auto r = split_and_trim(line); + unsigned i = atoi(r[0].c_str()); + double val = atof(r[1].c_str()); + v.set_value(val, i); + std::cout << "setting value " << i << " = " << val << std::endl; + } while (true); +} + +void check_lu_from_file(std::string lufile_name) { + std::ifstream f(lufile_name); + if (!f.is_open()) { + std::cout << "cannot open file " << lufile_name << std::endl; + } + unsigned m, n; + get_matrix_dimensions(f, m, n); + std::cout << "init matrix " << m << " by " << n << std::endl; + static_matrix A(m, n); + read_rows(A, f); + vector basis; + read_basis(basis, f); + indexed_vector v(m); + // read_indexed_vector(v, f); + f.close(); + vector basis_heading; + lp_settings settings; + vector non_basic_columns; + lu lsuhl(A, basis, settings); + indexed_vector d(A.row_count()); + unsigned entering = 26; + lsuhl.solve_Bd(entering, d, v); +#ifdef Z3DEBUG + auto B = get_B(lsuhl, basis); + vector a(m); + A.copy_column_to_vector(entering, a); + indexed_vector cd(d); + B.apply_from_left(cd.m_data, settings); + SASSERT(vectors_are_equal(cd.m_data , a)); +#endif +} + +void test_square_dense_submatrix() { + std::cout << "testing square_dense_submatrix" << std::endl; + unsigned parent_dim = 7; + sparse_matrix parent(parent_dim); + fill_matrix(parent); + unsigned index_start = 3; + square_dense_submatrix d; + d.init(&parent, index_start); + for (unsigned i = index_start; i < parent_dim; i++) + for (unsigned j = index_start; j < parent_dim; j++) + d[i][j] = i*3+j*2; +#ifdef Z3DEBUG + unsigned dim = parent_dim - index_start; + dense_matrix m(dim, dim); + for (unsigned i = index_start; i < parent_dim; i++) + for (unsigned j = index_start; j < parent_dim; j++) + m[i-index_start][j-index_start] = d[i][j]; + print_matrix(&m, std::cout); +#endif + for (unsigned i = index_start; i < parent_dim; i++) + for (unsigned j = index_start; j < parent_dim; j++) + d[i][j] = d[j][i]; +#ifdef Z3DEBUG + for (unsigned i = index_start; i < parent_dim; i++) + for (unsigned j = index_start; j < parent_dim; j++) + m[i-index_start][j-index_start] = d[i][j]; + + print_matrix(&m, std::cout); + std::cout << std::endl; +#endif +} + + + +void print_st(lp_status status) { + std::cout << lp_status_to_string(status) << std::endl; +} + + + +void test_term() { + lar_solver solver; + unsigned _x = 0; + unsigned _y = 1; + var_index x = solver.add_var(_x); + var_index y = solver.add_var(_y); + + vector> term_ls; + term_ls.push_back(std::pair((int)1, x)); + term_ls.push_back(std::pair((int)1, y)); + var_index z = solver.add_term(term_ls, mpq(3)); + + vector> ls; + ls.push_back(std::pair((int)1, x)); + ls.push_back(std::pair((int)1, y)); + ls.push_back(std::pair((int)1, z)); + + solver.add_constraint(ls, lconstraint_kind::EQ, mpq(0)); + auto status = solver.solve(); + std::cout << lp_status_to_string(status) << std::endl; + std::unordered_map model; + solver.get_model(model); + + for (auto & t : model) { + std::cout << solver.get_variable_name(t.first) << " = " << t.second.get_double() << ","; + } + std::cout << std::endl; + +} + +void test_evidence_for_total_inf_simple(argument_parser & args_parser) { + lar_solver solver; + var_index x = solver.add_var(0); + var_index y = solver.add_var(1); + solver.add_var_bound(x, LE, -mpq(1)); + solver.add_var_bound(y, GE, mpq(0)); + vector> ls; + + ls.push_back(std::pair((int)1, x)); + ls.push_back(std::pair((int)1, y)); + solver.add_constraint(ls, GE, mpq(1)); + ls.pop_back(); + ls.push_back(std::pair(-(int)1, y)); + solver.add_constraint(ls, lconstraint_kind::GE, mpq(0)); + auto status = solver.solve(); + std::cout << lp_status_to_string(status) << std::endl; + std::unordered_map model; + SASSERT(solver.get_status() == INFEASIBLE); +} +void test_bound_propagation_one_small_sample1() { + /* +(<= (+ a (* (- 1.0) b)) 0.0) +(<= (+ b (* (- 1.0) x_13)) 0.0) +--> (<= (+ a (* (- 1.0) c)) 0.0) + +the inequality on (<= a c) is obtained from a triangle inequality (<= a b) (<= b c). +If b becomes basic variable, then it is likely the old solver ends up with a row that implies (<= a c). + a - b <= 0.0 + b - c <= 0.0 + + got to get a <= c + */ + std::function bound_is_relevant = + [&](unsigned j, bool is_low_bound, bool strict, const rational& bound_val) { + return true; + }; + lar_solver ls; + unsigned a = ls.add_var(0); + unsigned b = ls.add_var(1); + unsigned c = ls.add_var(2); + vector> coeffs; + coeffs.push_back(std::pair(1, a)); + coeffs.push_back(std::pair(-1, c)); + ls.add_term(coeffs, zero_of_type()); + coeffs.pop_back(); + coeffs.push_back(std::pair(-1, b)); + ls.add_term(coeffs, zero_of_type()); + coeffs.clear(); + coeffs.push_back(std::pair(1, a)); + coeffs.push_back(std::pair(-1, b)); + ls.add_constraint(coeffs, LE, zero_of_type()); + coeffs.clear(); + coeffs.push_back(std::pair(1, b)); + coeffs.push_back(std::pair(-1, c)); + ls.add_constraint(coeffs, LE, zero_of_type()); + vector ev; + ls.add_var_bound(a, LE, mpq(1)); + ls.solve(); + lp_bound_propagator bp(ls); + ls.propagate_bounds_for_touched_rows(bp); + std::cout << " bound ev from test_bound_propagation_one_small_sample1" << std::endl; + for (auto & be : bp.m_ibounds) { + std::cout << "bound\n"; + ls.print_implied_bound(be, std::cout); + } +} + +void test_bound_propagation_one_small_samples() { + test_bound_propagation_one_small_sample1(); + /* + (>= x_46 0.0) +(<= x_29 0.0) +(not (<= x_68 0.0)) +(<= (+ (* (/ 1001.0 1998.0) x_10) (* (- 1.0) x_151) x_68) (- (/ 1001.0 999.0))) +(<= (+ (* (/ 1001.0 999.0) x_9) + (* (- 1.0) x_152) + (* (/ 1001.0 999.0) x_151) + (* (/ 1001.0 999.0) x_68)) + (- (/ 1502501.0 999000.0))) +(not (<= (+ (* (/ 999.0 2.0) x_10) (* (- 1.0) x_152) (* (- (/ 999.0 2.0)) x_151)) + (/ 1001.0 2.0))) +(not (<= x_153 0.0))z +(>= (+ x_9 (* (- (/ 1001.0 999.0)) x_10) (* (- 1.0) x_153) (* (- 1.0) x_68)) + (/ 5003.0 1998.0)) +--> (not (<= (+ x_10 x_46 (* (- 1.0) x_29)) 0.0)) + +and + +(<= (+ a (* (- 1.0) b)) 0.0) +(<= (+ b (* (- 1.0) x_13)) 0.0) +--> (<= (+ a (* (- 1.0) x_13)) 0.0) + +In the first case, there typically are no atomic formulas for bounding x_10. So there is never some +basic lemma of the form (>= x46 0), (<= x29 0), (>= x10 0) -> (not (<= (+ x10 x46 (- x29)) 0)). +Instead the bound on x_10 falls out from a bigger blob of constraints. + +In the second case, the inequality on (<= x19 x13) is obtained from a triangle inequality (<= x19 x9) (<= x9 x13). +If x9 becomes basic variable, then it is likely the old solver ends up with a row that implies (<= x19 x13). + */ +} +void test_bound_propagation_one_row() { + lar_solver ls; + unsigned x0 = ls.add_var(0); + unsigned x1 = ls.add_var(1); + vector> c; + c.push_back(std::pair(1, x0)); + c.push_back(std::pair(-1, x1)); + ls.add_constraint(c, EQ, one_of_type()); + vector ev; + ls.add_var_bound(x0, LE, mpq(1)); + ls.solve(); + lp_bound_propagator bp(ls); + ls.propagate_bounds_for_touched_rows(bp); +} +void test_bound_propagation_one_row_with_bounded_vars() { + lar_solver ls; + unsigned x0 = ls.add_var(0); + unsigned x1 = ls.add_var(1); + vector> c; + c.push_back(std::pair(1, x0)); + c.push_back(std::pair(-1, x1)); + ls.add_constraint(c, EQ, one_of_type()); + vector ev; + ls.add_var_bound(x0, GE, mpq(-3)); + ls.add_var_bound(x0, LE, mpq(3)); + ls.add_var_bound(x0, LE, mpq(1)); + ls.solve(); + lp_bound_propagator bp(ls); + ls.propagate_bounds_for_touched_rows(bp); +} +void test_bound_propagation_one_row_mixed() { + lar_solver ls; + unsigned x0 = ls.add_var(0); + unsigned x1 = ls.add_var(1); + vector> c; + c.push_back(std::pair(1, x0)); + c.push_back(std::pair(-1, x1)); + ls.add_constraint(c, EQ, one_of_type()); + vector ev; + ls.add_var_bound(x1, LE, mpq(1)); + ls.solve(); + lp_bound_propagator bp(ls); + ls.propagate_bounds_for_touched_rows(bp); +} + +void test_bound_propagation_two_rows() { + lar_solver ls; + unsigned x = ls.add_var(0); + unsigned y = ls.add_var(1); + unsigned z = ls.add_var(2); + vector> c; + c.push_back(std::pair(1, x)); + c.push_back(std::pair(2, y)); + c.push_back(std::pair(3, z)); + ls.add_constraint(c, GE, one_of_type()); + c.clear(); + c.push_back(std::pair(3, x)); + c.push_back(std::pair(2, y)); + c.push_back(std::pair(1, z)); + ls.add_constraint(c, GE, one_of_type()); + ls.add_var_bound(x, LE, mpq(2)); + vector ev; + ls.add_var_bound(y, LE, mpq(1)); + ls.solve(); + lp_bound_propagator bp(ls); + ls.propagate_bounds_for_touched_rows(bp); +} + +void test_total_case_u() { + std::cout << "test_total_case_u\n"; + lar_solver ls; + unsigned x = ls.add_var(0); + unsigned y = ls.add_var(1); + unsigned z = ls.add_var(2); + vector> c; + c.push_back(std::pair(1, x)); + c.push_back(std::pair(2, y)); + c.push_back(std::pair(3, z)); + ls.add_constraint(c, LE, one_of_type()); + ls.add_var_bound(x, GE, zero_of_type()); + ls.add_var_bound(y, GE, zero_of_type()); + vector ev; + ls.add_var_bound(z, GE, zero_of_type()); + ls.solve(); + lp_bound_propagator bp(ls); + ls.propagate_bounds_for_touched_rows(bp); +} +bool contains_j_kind(unsigned j, lconstraint_kind kind, const mpq & rs, const vector & ev) { + for (auto & e : ev) { + if (e.m_j == j && e.m_bound == rs && e.kind() == kind) + return true; + } + return false; +} +void test_total_case_l(){ + std::cout << "test_total_case_l\n"; + lar_solver ls; + unsigned x = ls.add_var(0); + unsigned y = ls.add_var(1); + unsigned z = ls.add_var(2); + vector> c; + c.push_back(std::pair(1, x)); + c.push_back(std::pair(2, y)); + c.push_back(std::pair(3, z)); + ls.add_constraint(c, GE, one_of_type()); + ls.add_var_bound(x, LE, one_of_type()); + ls.add_var_bound(y, LE, one_of_type()); + ls.settings().presolve_with_double_solver_for_lar = true; + vector ev; + ls.add_var_bound(z, LE, zero_of_type()); + ls.solve(); + lp_bound_propagator bp(ls); + ls.propagate_bounds_for_touched_rows(bp); + SASSERT(ev.size() == 4); + SASSERT(contains_j_kind(x, GE, - one_of_type(), ev)); +} +void test_bound_propagation() { + test_total_case_u(); + test_bound_propagation_one_small_samples(); + test_bound_propagation_one_row(); + test_bound_propagation_one_row_with_bounded_vars(); + test_bound_propagation_two_rows(); + test_bound_propagation_one_row_mixed(); + test_total_case_l(); + +} + +void test_int_set() { + int_set s(4); + s.insert(2); + s.print(std::cout); + s.insert(1); + s.insert(2); + s.print(std::cout); + SASSERT(s.contains(2)); + SASSERT(s.size() == 2); + s.erase(2); + SASSERT(s.size() == 1); + s.erase(2); + SASSERT(s.size() == 1); + s.print(std::cout); + s.insert(3); + s.insert(2); + s.clear(); + SASSERT(s.size() == 0); + + +} + +void test_rationals_no_numeric_pairs() { + stopwatch sw; + + vector c; + for (unsigned j = 0; j < 10; j ++) + c.push_back(mpq(my_random()%100, 1 + my_random()%100 )); + + vector x; + for (unsigned j = 0; j < 10; j ++) + x.push_back(mpq(my_random()%100, 1 + my_random()%100 )); + + unsigned k = 500000; + mpq r=zero_of_type(); + sw.start(); + + for (unsigned j = 0; j < k; j++){ + mpq val = zero_of_type(); + for (unsigned j=0;j< c.size(); j++){ + val += c[j]*x[j]; + } + + r += val; + } + + sw.stop(); + std::cout << "operation with rationals no pairs " << sw.get_seconds() << std::endl; + std::cout << T_to_string(r) << std::endl; +} + +void test_rationals_no_numeric_pairs_plus() { + stopwatch sw; + + vector c; + for (unsigned j = 0; j < 10; j ++) + c.push_back(mpq(my_random()%100, 1 + my_random()%100 )); + + vector x; + for (unsigned j = 0; j < 10; j ++) + x.push_back(mpq(my_random()%100, 1 + my_random()%100 )); + + unsigned k = 500000; + mpq r=zero_of_type(); + sw.start(); + + for (unsigned j = 0; j < k; j++){ + mpq val = zero_of_type(); + for (unsigned j=0;j< c.size(); j++){ + val = val + c[j]*x[j]; + } + + r = r + val; + } + + sw.stop(); + std::cout << "operation with rationals no pairs " << sw.get_seconds() << std::endl; + std::cout << T_to_string(r) << std::endl; +} + + + +void test_rationals() { + stopwatch sw; + + vector c; + for (unsigned j = 0; j < 10; j ++) + c.push_back(mpq(my_random()%100, 1 + my_random()%100)); + + + + vector> x; + for (unsigned j = 0; j < 10; j ++) + x.push_back(mpq(my_random()%100, 1 + my_random()%100 )); + + std::cout << "x = "; + print_vector(x, std::cout); + + unsigned k = 1000000; + numeric_pair r=zero_of_type>(); + sw.start(); + + for (unsigned j = 0; j < k; j++) { + for (unsigned i = 0; i < c.size(); i++) { + r+= c[i] * x[i]; + } + } + sw.stop(); + std::cout << "operation with rationals " << sw.get_seconds() << std::endl; + std::cout << T_to_string(r) << std::endl; +} + +void test_lp_local(int argn, char**argv) { + std::cout << "resize\n"; + vector r; + r.resize(1); + + // initialize_util_module(); + // initialize_numerics_module(); + int ret; + argument_parser args_parser(argn, argv); + setup_args_parser(args_parser); + if (!args_parser.parse()) { + std::cout << args_parser.m_error_message << std::endl; + std::cout << args_parser.usage_string(); + ret = 1; + return finalize(ret); + } + + args_parser.print(); + + if (args_parser.option_is_used("--test_mpq")) { + test_rationals(); + return finalize(0); + } + + if (args_parser.option_is_used("--test_mpq_np")) { + test_rationals_no_numeric_pairs(); + return finalize(0); + } + + if (args_parser.option_is_used("--test_mpq_np_plus")) { + test_rationals_no_numeric_pairs_plus(); + return finalize(0); + } + + + + if (args_parser.option_is_used("--test_int_set")) { + test_int_set(); + return finalize(0); + } + if (args_parser.option_is_used("--bp")) { + test_bound_propagation(); + return finalize(0); + } + + + std::string lufile = args_parser.get_option_value("--checklu"); + if (lufile.size()) { + check_lu_from_file(lufile); + return finalize(0); + } + +#ifdef Z3DEBUG + if (args_parser.option_is_used("--test_swaps")) { + sparse_matrix m(10); + fill_matrix(m); + test_swap_rows_with_permutation(m); + test_swap_cols_with_permutation(m); + return finalize(0); + } +#endif + if (args_parser.option_is_used("--test_perm")) { + test_permutations(); + return finalize(0); + } + if (args_parser.option_is_used("--test_file_directory")) { + test_files_from_directory(args_parser.get_option_value("--test_file_directory"), args_parser); + return finalize(0); + } + std::string file_list = args_parser.get_option_value("--filelist"); + if (file_list.size() > 0) { + for (std::string fn : get_file_names_from_file_list(file_list)) + solve_mps(fn, args_parser); + return finalize(0); + } + + if (args_parser.option_is_used("-tbq")) { + test_binary_priority_queue(); + ret = 0; + return finalize(ret); + } + +#ifdef Z3DEBUG + lp_settings settings; + update_settings(args_parser, settings); + if (args_parser.option_is_used("--test_lu")) { + test_lu(settings); + ret = 0; + return finalize(ret); + } + + if (args_parser.option_is_used("--test_small_lu")) { + test_small_lu(settings); + ret = 0; + return finalize(ret); + } + + if (args_parser.option_is_used("--lar")){ + std::cout <<"calling test_lar_solver" << std::endl; + test_lar_solver(args_parser); + return finalize(0); + } + + + + if (args_parser.option_is_used("--test_larger_lu")) { + test_larger_lu(settings); + ret = 0; + return finalize(ret); + } + + if (args_parser.option_is_used("--test_larger_lu_with_holes")) { + test_larger_lu_with_holes(settings); + ret = 0; + return finalize(ret); + } +#endif + if (args_parser.option_is_used("--eti")) { + test_evidence_for_total_inf_simple(args_parser); + ret = 0; + return finalize(ret); + } + + + if (args_parser.option_is_used("--test_lp_0")) { + test_lp_0(); + ret = 0; + return finalize(ret); + } + + if (args_parser.option_is_used("--smap")) { + test_stacked(); + ret = 0; + return finalize(ret); + } + if (args_parser.option_is_used("--term")) { + test_term(); + ret = 0; + return finalize(ret); + } + unsigned max_iters; + unsigned time_limit; + get_time_limit_and_max_iters_from_parser(args_parser, time_limit, max_iters); + bool dual = args_parser.option_is_used("--dual"); + bool solve_for_rational = args_parser.option_is_used("--mpq"); + std::string file_name = args_parser.get_option_value("--file"); + if (file_name.size() > 0) { + solve_mps(file_name, args_parser.option_is_used("--min"), max_iters, time_limit, solve_for_rational, dual, args_parser.option_is_used("--compare_with_primal"), args_parser); + ret = 0; + return finalize(ret); + } + + if (args_parser.option_is_used("--solve_some_mps")) { +#if _LINUX_ + solve_some_mps(args_parser); +#endif + ret = 0; + return finalize(ret); + } + // lp::ccc = 0; + return finalize(0); + test_init_U(); + test_replace_column(); +#ifdef Z3DEBUG + sparse_matrix_with_permutaions_test(); + test_dense_matrix(); + test_swap_operations(); + test_permutations(); + test_pivot_like_swaps_and_pivot(); +#endif + tst1(); + std::cout << "done with LP tests\n"; + return finalize(0); // has_violations() ? 1 : 0); +} +} +void tst_lp(char ** argv, int argc, int& i) { + lp::test_lp_local(argc - 2, argv + 2); +} diff --git a/src/test/main.cpp b/src/test/main.cpp index 613c11532..4aeba26c5 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -16,20 +16,20 @@ // and print "PASS" to indicate success. // -#define TST(MODULE) { \ - std::string s("test "); \ - s += #MODULE; \ - void tst_##MODULE(); \ +#define TST(MODULE) { \ + std::string s("test "); \ + s += #MODULE; \ + void tst_##MODULE(); \ if (do_display_usage) \ std::cout << #MODULE << "\n"; \ - for (int i = 0; i < argc; i++) \ - if (test_all || strcmp(argv[i], #MODULE) == 0) { \ + for (int i = 0; i < argc; i++) \ + if (test_all || strcmp(argv[i], #MODULE) == 0) { \ enable_trace(#MODULE); \ - enable_debug(#MODULE); \ - timeit timeit(true, s.c_str()); \ - tst_##MODULE(); \ + enable_debug(#MODULE); \ + timeit timeit(true, s.c_str()); \ + tst_##MODULE(); \ std::cout << "PASS" << std::endl; \ - } \ + } \ } #define TST_ARGV(MODULE) { \ @@ -39,13 +39,13 @@ if (do_display_usage) \ std::cout << #MODULE << "\n"; \ for (int i = 0; i < argc; i++) \ - if (strcmp(argv[i], #MODULE) == 0) { \ + if (strcmp(argv[i], #MODULE) == 0) { \ enable_trace(#MODULE); \ - enable_debug(#MODULE); \ - timeit timeit(true, s.c_str()); \ - tst_##MODULE(argv, argc, i); \ + enable_debug(#MODULE); \ + timeit timeit(true, s.c_str()); \ + tst_##MODULE(argv, argc, i); \ std::cout << "PASS" << std::endl; \ - } \ + } \ } void error(const char * msg) { @@ -78,48 +78,48 @@ void parse_cmd_line_args(int argc, char ** argv, bool& do_display_usage, bool& t while (i < argc) { char * arg = argv[i]; char * eq_pos = 0; - - if (arg[0] == '-' || arg[0] == '/') { - char * opt_name = arg + 1; - char * opt_arg = 0; - char * colon = strchr(arg, ':'); - if (colon) { - opt_arg = colon + 1; - *colon = 0; - } - if (strcmp(opt_name, "h") == 0 || + + if (arg[0] == '-' || arg[0] == '/') { + char * opt_name = arg + 1; + char * opt_arg = 0; + char * colon = strchr(arg, ':'); + if (colon) { + opt_arg = colon + 1; + *colon = 0; + } + if (strcmp(opt_name, "h") == 0 || strcmp(opt_name, "?") == 0) { - display_usage(); + display_usage(); do_display_usage = true; return; - } - else if (strcmp(opt_name, "v") == 0) { - if (!opt_arg) - error("option argument (/v:level) is missing."); - long lvl = strtol(opt_arg, 0, 10); - set_verbosity_level(lvl); - } - else if (strcmp(opt_name, "w") == 0) { + } + else if (strcmp(opt_name, "v") == 0) { + if (!opt_arg) + error("option argument (/v:level) is missing."); + long lvl = strtol(opt_arg, 0, 10); + set_verbosity_level(lvl); + } + else if (strcmp(opt_name, "w") == 0) { enable_warning_messages(true); - } - else if (strcmp(opt_name, "a") == 0) { + } + else if (strcmp(opt_name, "a") == 0) { test_all = true; - } + } #ifdef _TRACE - else if (strcmp(opt_name, "tr") == 0) { - if (!opt_arg) - error("option argument (/tr:tag) is missing."); - enable_trace(opt_arg); - } + else if (strcmp(opt_name, "tr") == 0) { + if (!opt_arg) + error("option argument (/tr:tag) is missing."); + enable_trace(opt_arg); + } #endif #ifdef Z3DEBUG - else if (strcmp(opt_name, "dbg") == 0) { - if (!opt_arg) - error("option argument (/dbg:tag) is missing."); - enable_debug(opt_arg); - } + else if (strcmp(opt_name, "dbg") == 0) { + if (!opt_arg) + error("option argument (/dbg:tag) is missing."); + enable_debug(opt_arg); + } #endif - } + } else if (arg[0] != '"' && (eq_pos = strchr(arg, '='))) { char * key = arg; *eq_pos = 0; @@ -131,7 +131,7 @@ void parse_cmd_line_args(int argc, char ** argv, bool& do_display_usage, bool& t std::cerr << ex.msg() << "\n"; } } - i++; + i++; } } @@ -238,6 +238,7 @@ int main(int argc, char ** argv) { TST(sat_user_scope); TST(pdr); TST_ARGV(ddnf); + TST(ddnf1); TST(model_evaluator); TST(get_consequences); TST(pb2bv); diff --git a/src/test/model_based_opt.cpp b/src/test/model_based_opt.cpp index 2f8cf9941..7b3b95afd 100644 --- a/src/test/model_based_opt.cpp +++ b/src/test/model_based_opt.cpp @@ -54,7 +54,7 @@ static void add_random_ineq(opt::model_based_opt& mbo, continue; } unsigned sign = r(2); - coeff = sign == 0 ? coeff : -coeff; + coeff = sign == 0 ? coeff : -coeff; vars.push_back(var(x, rational(coeff))); value += coeff*values[x]; } diff --git a/src/test/optional.cpp b/src/test/optional.cpp index 2ef922444..d698f7289 100644 --- a/src/test/optional.cpp +++ b/src/test/optional.cpp @@ -36,11 +36,11 @@ struct OptFoo { int m_y; OptFoo(int x, int y):m_x(x), m_y(y) { - TRACE("optional", tout << "OptFoo created: " << m_x << " : " << m_y << "\n";); + TRACE("optional", tout << "OptFoo created: " << m_x << " : " << m_y << "\n";); } ~OptFoo() { - TRACE("optional", tout << "OptFoo deleted: " << m_x << " : " << m_y << "\n";); + TRACE("optional", tout << "OptFoo deleted: " << m_x << " : " << m_y << "\n";); } }; diff --git a/src/test/smt_reader.h b/src/test/smt_reader.h new file mode 100644 index 000000000..437cb7a6b --- /dev/null +++ b/src/test/smt_reader.h @@ -0,0 +1,409 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ + +#pragma once + +// reads an MPS file reperesenting a Mixed Integer Program +#include +#include +#include +#include "util/lp/lp_primal_simplex.h" +#include "util/lp/lp_dual_simplex.h" +#include "util/lp/lar_solver.h" +#include +#include +#include +#include +#include "util/lp/mps_reader.h" +#include "util/lp/ul_pair.h" +#include "util/lp/lar_constraints.h" +#include +#include +namespace lp { + + template + T from_string(const std::string& str) { + std::istringstream ss(str); + T ret; + ss >> ret; + return ret; + } + + class smt_reader { + public: + struct lisp_elem { + std::string m_head; + std::vector m_elems; + void print() { + if (m_elems.size()) { + std::cout << '('; + std::cout << m_head << ' '; + for (auto & el : m_elems) + el.print(); + + std::cout << ')'; + } else { + std::cout << " " << m_head; + } + } + unsigned size() const { return static_cast(m_elems.size()); } + bool is_simple() const { return size() == 0; } + }; + struct formula_constraint { + lconstraint_kind m_kind; + std::vector> m_coeffs; + mpq m_right_side; + void add_pair(mpq c, std::string name) { + m_coeffs.push_back(make_pair(c, name)); + } + formula_constraint() : m_right_side(numeric_traits::zero()) {} + }; + + lisp_elem m_formula_lisp_elem; + + std::unordered_map m_name_to_var_index; + std::vector m_constraints; + bool m_is_OK; + unsigned m_line_number; + std::string m_file_name; + std::ifstream m_file_stream; + std::string m_line; + smt_reader(std::string file_name): + m_is_OK(true), + m_line_number(0), + m_file_name(file_name), + m_file_stream(file_name) { + } + + void set_error() { + std::cout << "setting error" << std::endl; + m_is_OK = false; + } + + bool is_ok() { + return m_is_OK; + } + + bool prefix(const char * pr) { + return m_line.find(pr) == 0; + } + + int first_separator() { + unsigned blank_pos = static_cast(m_line.find(' ')); + unsigned br_pos = static_cast(m_line.find('(')); + unsigned reverse_br_pos = static_cast(m_line.find(')')); + return std::min(blank_pos, std::min(br_pos, reverse_br_pos)); + } + + void fill_lisp_elem(lisp_elem & lm) { + if (m_line[0] == '(') + fill_nested_elem(lm); + else + fill_simple_elem(lm); + } + + void fill_simple_elem(lisp_elem & lm) { + int separator = first_separator(); + SASSERT(-1 != separator && separator != 0); + lm.m_head = m_line.substr(0, separator); + m_line = m_line.substr(separator); + } + + void fill_nested_elem(lisp_elem & lm) { + SASSERT(m_line[0] == '('); + m_line = m_line.substr(1); + int separator = first_separator(); + lm.m_head = m_line.substr(0, separator); + m_line = m_line.substr(lm.m_head.size()); + eat_blanks(); + while (m_line.size()) { + if (m_line[0] == '(') { + lisp_elem el; + fill_nested_elem(el); + lm.m_elems.push_back(el); + } else { + if (m_line[0] == ')') { + m_line = m_line.substr(1); + break; + } + lisp_elem el; + fill_simple_elem(el); + lm.m_elems.push_back(el); + } + eat_blanks(); + } + } + + void eat_blanks() { + while (m_line.size()) { + if (m_line[0] == ' ') + m_line = m_line.substr(1); + else + break; + } + } + + void fill_formula_elem() { + fill_lisp_elem(m_formula_lisp_elem); + } + + void parse_line() { + if (m_line.find(":formula") == 0) { + int first_br = static_cast(m_line.find('(')); + if (first_br == -1) { + std::cout << "empty formula" << std::endl; + return; + } + m_line = m_line.substr(first_br); + fill_formula_elem(); + } + } + + void set_constraint_kind(formula_constraint & c, lisp_elem & el) { + if (el.m_head == "=") { + c.m_kind = EQ; + } else if (el.m_head == ">=") { + c.m_kind = GE; + } else if (el.m_head == "<=") { + c.m_kind = LE; + } else if (el.m_head == ">") { + c.m_kind = GT; + } else if (el.m_head == "<") { + c.m_kind = LT; + } else { + std::cout << "kind " << el.m_head << " is not supported " << std::endl; + set_error(); + } + } + + void adjust_rigth_side(formula_constraint & /* c*/, lisp_elem & /*el*/) { + // SASSERT(el.m_head == "0"); // do nothing for the time being + } + + void set_constraint_coeffs(formula_constraint & c, lisp_elem & el) { + SASSERT(el.m_elems.size() == 2); + set_constraint_coeffs_on_coeff_element(c, el.m_elems[0]); + adjust_rigth_side(c, el.m_elems[1]); + } + + + bool is_integer(std::string & s) { + if (s.size() == 0) return false; + return atoi(s.c_str()) != 0 || isdigit(s.c_str()[0]); + } + + void add_complex_sum_elem(formula_constraint & c, lisp_elem & el) { + if (el.m_head == "*") { + add_mult_elem(c, el.m_elems); + } else if (el.m_head == "~") { + lisp_elem & minel = el.m_elems[0]; + SASSERT(minel.is_simple()); + c.m_right_side += mpq(str_to_int(minel.m_head)); + } else { + std::cout << "unexpected input " << el.m_head << std::endl; + set_error(); + return; + } + } + + std::string get_name(lisp_elem & name) { + SASSERT(name.is_simple()); + SASSERT(!is_integer(name.m_head)); + return name.m_head; + } + + + void add_mult_elem(formula_constraint & c, std::vector & els) { + SASSERT(els.size() == 2); + mpq coeff = get_coeff(els[0]); + std::string col_name = get_name(els[1]); + c.add_pair(coeff, col_name); + } + + mpq get_coeff(lisp_elem & le) { + if (le.is_simple()) { + return mpq(str_to_int(le.m_head)); + } else { + SASSERT(le.m_head == "~"); + SASSERT(le.size() == 1); + lisp_elem & el = le.m_elems[0]; + SASSERT(el.is_simple()); + return -mpq(str_to_int(el.m_head)); + } + } + + int str_to_int(std::string & s) { + SASSERT(is_integer(s)); + return atoi(s.c_str()); + } + + void add_sum_elem(formula_constraint & c, lisp_elem & el) { + if (el.size()) { + add_complex_sum_elem(c, el); + } else { + SASSERT(is_integer(el.m_head)); + int v = atoi(el.m_head.c_str()); + mpq vr(v); + c.m_right_side -= vr; + } + } + + void add_sum(formula_constraint & c, std::vector & sum_els) { + for (auto & el : sum_els) + add_sum_elem(c, el); + } + + void set_constraint_coeffs_on_coeff_element(formula_constraint & c, lisp_elem & el) { + if (el.m_head == "*") { + add_mult_elem(c, el.m_elems); + } else if (el.m_head == "+") { + add_sum(c, el.m_elems); + } else { + SASSERT(false); // unexpected input + } + } + + void create_constraint(lisp_elem & el) { + formula_constraint c; + set_constraint_kind(c, el); + set_constraint_coeffs(c, el); + m_constraints.push_back(c); + } + + void fill_constraints() { + if (m_formula_lisp_elem.m_head != "and") { + std::cout << "unexpected top element " << m_formula_lisp_elem.m_head << std::endl; + set_error(); + return; + } + for (auto & el : m_formula_lisp_elem.m_elems) + create_constraint(el); + } + + void read() { + if (!m_file_stream.is_open()){ + std::cout << "cannot open file " << m_file_name << std::endl; + set_error(); + return; + } + while (m_is_OK && getline(m_file_stream, m_line)) { + parse_line(); + m_line_number++; + } + + m_file_stream.close(); + fill_constraints(); + } + + /* + void fill_lar_solver_on_row(row * row, lar_solver *solver) { + if (row->m_name != m_cost_row_name) { + lar_constraint c(get_lar_relation_from_row(row->m_type), row->m_right_side); + for (auto s : row->m_row_columns) { + var_index i = solver->add_var(s.first); + c.add_variable_to_constraint(i, s.second); + } + solver->add_constraint(&c); + } else { + // ignore the cost row + } + } + + + void fill_lar_solver_on_rows(lar_solver * solver) { + for (auto row_it : m_rows) { + fill_lar_solver_on_row(row_it.second, solver); + } + } + + void create_low_constraint_for_var(column* col, bound * b, lar_solver *solver) { + lar_constraint c(GE, b->m_low); + var_index i = solver->add_var(col->m_name); + c.add_variable_to_constraint(i, numeric_traits::one()); + solver->add_constraint(&c); + } + + void create_upper_constraint_for_var(column* col, bound * b, lar_solver *solver) { + lar_constraint c(LE, b->m_upper); + var_index i = solver->add_var(col->m_name); + c.add_variable_to_constraint(i, numeric_traits::one()); + solver->add_constraint(&c); + } + + void create_equality_contraint_for_var(column* col, bound * b, lar_solver *solver) { + lar_constraint c(EQ, b->m_fixed_value); + var_index i = solver->add_var(col->m_name); + c.add_variable_to_constraint(i, numeric_traits::one()); + solver->add_constraint(&c); + } + + void fill_lar_solver_on_columns(lar_solver * solver) { + for (auto s : m_columns) { + mps_reader::column * col = s.second; + solver->add_var(col->m_name); + auto b = col->m_bound; + if (b == nullptr) return; + + if (b->m_free) continue; + + if (b->m_low_is_set) { + create_low_constraint_for_var(col, b, solver); + } + if (b->m_upper_is_set) { + create_upper_constraint_for_var(col, b, solver); + } + if (b->m_value_is_fixed) { + create_equality_contraint_for_var(col, b, solver); + } + } + } + */ + + unsigned register_name(std::string s) { + auto it = m_name_to_var_index.find(s); + if (it!= m_name_to_var_index.end()) + return it->second; + + unsigned ret = static_cast(m_name_to_var_index.size()); + m_name_to_var_index[s] = ret; + return ret; + } + + void add_constraint_to_solver(lar_solver * solver, formula_constraint & fc) { + vector> ls; + for (auto & it : fc.m_coeffs) { + ls.push_back(std::make_pair(it.first, solver->add_var(register_name(it.second)))); + } + solver->add_constraint(ls, fc.m_kind, fc.m_right_side); + } + + void fill_lar_solver(lar_solver * solver) { + for (formula_constraint & fc : m_constraints) + add_constraint_to_solver(solver, fc); + } + + + lar_solver * create_lar_solver() { + lar_solver * ls = new lar_solver(); + fill_lar_solver(ls); + return ls; + } + }; +} diff --git a/src/test/sorting_network.cpp b/src/test/sorting_network.cpp index 7cc046304..b5c8dc165 100644 --- a/src/test/sorting_network.cpp +++ b/src/test/sorting_network.cpp @@ -15,8 +15,6 @@ Copyright (c) 2015 Microsoft Corporation #include "smt/smt_kernel.h" #include "smt/params/smt_params.h" - - struct ast_ext { ast_manager& m; ast_ext(ast_manager& m):m(m) {} diff --git a/src/test/test_file_reader.h b/src/test/test_file_reader.h new file mode 100644 index 000000000..74dad419b --- /dev/null +++ b/src/test/test_file_reader.h @@ -0,0 +1,87 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ + +#pragma once + +// reads a text file +#include +#include +#include +#include +#include +#include "util/lp/lp_utils.h" +#include "util/lp/lp_solver.h" + +namespace lp { + +template +struct test_result { + lp_status m_status; + T m_cost; + std::unordered_map column_values; +}; + +template +class test_file_reader { + struct raw_blob { + std::vector m_unparsed_strings; + std::vector m_blobs; + }; + + struct test_file_blob { + std::string m_name; + std::string m_content; + std::unordered_map m_table; + std::unordered_map m_blobs; + + test_result * get_test_result() { + test_result * tr = new test_result(); + throw "not impl"; + return tr; + } + }; + std::ifstream m_file_stream; +public: + // constructor + test_file_reader(std::string file_name) : m_file_stream(file_name) { + if (!m_file_stream.is_open()) { + std::cout << "cannot open file " << "\'" << file_name << "\'" << std::endl; + } + } + + raw_blob scan_to_row_blob() { + } + + test_file_blob scan_row_blob_to_test_file_blob(raw_blob /* rblob */) { + } + + test_result * get_test_result() { + if (!m_file_stream.is_open()) { + return nullptr; + } + + raw_blob rblob = scan_to_row_blob(); + + test_file_blob tblob = scan_row_blob_to_test_file_blob(rblob); + + return tblob.get_test_result(); + } +}; +} diff --git a/src/util/dependency.h b/src/util/dependency.h index d6df6d7bf..5055399bc 100644 --- a/src/util/dependency.h +++ b/src/util/dependency.h @@ -201,7 +201,7 @@ public: m_todo.push_back(d); unsigned qhead = 0; while (qhead < m_todo.size()) { - 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/hash.h b/src/util/hash.h index 7fce04ca8..bc6117cac 100644 --- a/src/util/hash.h +++ b/src/util/hash.h @@ -236,7 +236,7 @@ template struct ptr_hash { typedef T * data; unsigned operator()(T * ptr) const { - return get_ptr_hash(ptr); + return get_ptr_hash(ptr); } }; diff --git a/src/util/inf_eps_rational.h b/src/util/inf_eps_rational.h index 72212d33c..c184623ca 100644 --- a/src/util/inf_eps_rational.h +++ b/src/util/inf_eps_rational.h @@ -119,12 +119,12 @@ class inf_eps_rational { bool is_rational() const { return m_infty.is_zero() && m_r.is_rational(); } int64 get_int64() const { - SASSERT(is_int64()); + SASSERT(is_int64()); return m_r.get_int64(); } uint64 get_uint64() const { - SASSERT(is_uint64()); + SASSERT(is_uint64()); return m_r.get_uint64(); } @@ -168,45 +168,45 @@ class inf_eps_rational { inf_eps_rational & operator=(const inf_eps_rational & r) { m_infty = r.m_infty; m_r = r.m_r; - return *this; + return *this; } 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) { m_infty += r.m_infty; m_r += r.m_r; - return *this; + return *this; } inf_eps_rational & operator-=(const inf_eps_rational & r) { m_infty -= r.m_infty; m_r -= r.m_r; - return *this; + return *this; } inf_eps_rational & operator-=(const inf_rational & r) { m_r -= r; - return *this; + return *this; } inf_eps_rational & operator+=(const inf_rational & r) { m_r += r; - return *this; + return *this; } inf_eps_rational & operator+=(const rational & r) { m_r += r; - return *this; + return *this; } inf_eps_rational & operator-=(const rational & r) { m_r -= r; - return *this; + return *this; } inf_eps_rational & operator*=(const rational & r1) { diff --git a/src/util/inf_int_rational.h b/src/util/inf_int_rational.h index ce871b0d5..c9c82052e 100644 --- a/src/util/inf_int_rational.h +++ b/src/util/inf_int_rational.h @@ -110,12 +110,12 @@ class inf_int_rational { bool is_rational() const { return m_second == 0; } int64 get_int64() const { - SASSERT(is_int64()); + SASSERT(is_int64()); return m_first.get_int64(); } uint64 get_uint64() const { - SASSERT(is_uint64()); + SASSERT(is_uint64()); return m_first.get_uint64(); } @@ -132,7 +132,7 @@ class inf_int_rational { inf_int_rational & operator=(const inf_int_rational & r) { m_first = r.m_first; m_second = r.m_second; - return *this; + return *this; } inf_int_rational & operator=(const rational & r) { @@ -154,7 +154,7 @@ class inf_int_rational { inf_int_rational & operator+=(const inf_int_rational & r) { m_first += r.m_first; m_second += r.m_second; - return *this; + return *this; } inf_int_rational & operator*=(const rational & r) { @@ -163,7 +163,7 @@ class inf_int_rational { } m_first *= r; m_second *= r.get_int32(); - return *this; + return *this; } @@ -171,17 +171,17 @@ class inf_int_rational { inf_int_rational & operator-=(const inf_int_rational & r) { m_first -= r.m_first; m_second -= r.m_second; - return *this; + return *this; } inf_int_rational & operator+=(const rational & r) { m_first += r; - return *this; + return *this; } inf_int_rational & operator-=(const rational & r) { m_first -= r; - return *this; + return *this; } inf_int_rational & operator++() { diff --git a/src/util/inf_rational.h b/src/util/inf_rational.h index c17c4312b..d49e45f50 100644 --- a/src/util/inf_rational.h +++ b/src/util/inf_rational.h @@ -123,12 +123,12 @@ class inf_rational { bool is_rational() const { return m_second.is_zero(); } int64 get_int64() const { - SASSERT(is_int64()); + SASSERT(is_int64()); return m_first.get_int64(); } uint64 get_uint64() const { - SASSERT(is_uint64()); + SASSERT(is_uint64()); return m_first.get_uint64(); } @@ -145,7 +145,7 @@ class inf_rational { inf_rational & operator=(const inf_rational & r) { m_first = r.m_first; m_second = r.m_second; - return *this; + return *this; } inf_rational & operator=(const rational & r) { @@ -167,23 +167,23 @@ class inf_rational { inf_rational & operator+=(const inf_rational & r) { m_first += r.m_first; m_second += r.m_second; - return *this; + return *this; } inf_rational & operator-=(const inf_rational & r) { m_first -= r.m_first; m_second -= r.m_second; - return *this; + return *this; } inf_rational & operator+=(const rational & r) { m_first += r; - return *this; + return *this; } inf_rational & operator-=(const rational & r) { m_first -= r; - return *this; + return *this; } inf_rational & operator*=(const rational & r1) { diff --git a/src/util/inf_s_integer.h b/src/util/inf_s_integer.h index 6cf1d4225..067000202 100644 --- a/src/util/inf_s_integer.h +++ b/src/util/inf_s_integer.h @@ -67,7 +67,7 @@ class inf_s_integer { inf_s_integer & operator=(const inf_s_integer & r) { m_first = r.m_first; m_second = r.m_second; - return *this; + return *this; } inf_s_integer & operator=(const rational & r) { m_first = static_cast(r.get_int64()); @@ -90,20 +90,20 @@ class inf_s_integer { inf_s_integer & operator+=(const inf_s_integer & r) { m_first += r.m_first; m_second += r.m_second; - return *this; + return *this; } inf_s_integer & operator-=(const inf_s_integer & r) { m_first -= r.m_first; m_second -= r.m_second; - return *this; + return *this; } inf_s_integer & operator+=(const s_integer & r) { m_first += r.get_int(); - return *this; + return *this; } inf_s_integer & operator-=(const s_integer & r) { m_first -= r.get_int(); - return *this; + return *this; } inf_s_integer & operator*=(const s_integer & r1) { m_first *= r1.get_int(); diff --git a/src/util/lp/lp_primal_core_solver_tableau.hpp b/src/util/lp/lp_primal_core_solver_tableau.hpp deleted file mode 100644 index 2dfbcea0a..000000000 --- a/src/util/lp/lp_primal_core_solver_tableau.hpp +++ /dev/null @@ -1,392 +0,0 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ -// this is a part of lp_primal_core_solver that deals with the tableau -#include "util/lp/lp_primal_core_solver.h" -namespace lp { -template void lp_primal_core_solver::one_iteration_tableau() { - int entering = choose_entering_column_tableau(); - if (entering == -1) { - decide_on_status_when_cannot_find_entering(); - } - else { - advance_on_entering_tableau(entering); - } - lp_assert(this->inf_set_is_correct()); -} - -template void lp_primal_core_solver::advance_on_entering_tableau(int entering) { - X t; - int leaving = find_leaving_and_t_tableau(entering, t); - if (leaving == -1) { - this->set_status(lp_status::UNBOUNDED); - return; - } - advance_on_entering_and_leaving_tableau(entering, leaving, t); -} -/* -template int lp_primal_core_solver::choose_entering_column_tableau_rows() { - int i = find_inf_row(); - if (i == -1) - return -1; - return find_shortest_beneficial_column_in_row(i); - } -*/ - template int lp_primal_core_solver::choose_entering_column_tableau() { - //this moment m_y = cB * B(-1) - unsigned number_of_benefitial_columns_to_go_over = get_number_of_non_basic_column_to_try_for_enter(); - - lp_assert(numeric_traits::precise()); - if (number_of_benefitial_columns_to_go_over == 0) - return -1; - if (this->m_basis_sort_counter == 0) { - sort_non_basis(); - this->m_basis_sort_counter = 20; - } - else { - this->m_basis_sort_counter--; - } - unsigned j_nz = this->m_m() + 1; // this number is greater than the max column size - std::list::iterator entering_iter = m_non_basis_list.end(); - for (auto non_basis_iter = m_non_basis_list.begin(); number_of_benefitial_columns_to_go_over && non_basis_iter != m_non_basis_list.end(); ++non_basis_iter) { - unsigned j = *non_basis_iter; - if (!column_is_benefitial_for_entering_basis(j)) - continue; - - // if we are here then j is a candidate to enter the basis - unsigned t = this->m_A.number_of_non_zeroes_in_column(j); - if (t < j_nz) { - j_nz = t; - entering_iter = non_basis_iter; - if (number_of_benefitial_columns_to_go_over) - number_of_benefitial_columns_to_go_over--; - } - else if (t == j_nz && this->m_settings.random_next() % 2 == 0) { - entering_iter = non_basis_iter; - } - }// while (number_of_benefitial_columns_to_go_over && initial_offset_in_non_basis != offset_in_nb); - if (entering_iter == m_non_basis_list.end()) - return -1; - unsigned entering = *entering_iter; - m_sign_of_entering_delta = this->m_d[entering] > 0 ? 1 : -1; - if (this->m_using_infeas_costs && this->m_settings.use_breakpoints_in_feasibility_search) - m_sign_of_entering_delta = -m_sign_of_entering_delta; - m_non_basis_list.erase(entering_iter); - m_non_basis_list.push_back(entering); - return entering; - -} - - - - -template -unsigned lp_primal_core_solver::solve_with_tableau() { - init_run_tableau(); - if (this->current_x_is_feasible() && this->m_look_for_feasible_solution_only) { - this->set_status(lp_status::FEASIBLE); - return 0; - } - - if ((!numeric_traits::precise()) && this->A_mult_x_is_off()) { - this->set_status(lp_status::FLOATING_POINT_ERROR); - return 0; - } - do { - if (this->print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over((this->m_using_infeas_costs? "inf t" : "feas t"), * this->m_settings.get_message_ostream())) { - return this->total_iterations(); - } - if (this->m_settings.use_tableau_rows()) { - one_iteration_tableau_rows(); - } - else - one_iteration_tableau(); - switch (this->get_status()) { - case lp_status::OPTIMAL: // double check that we are at optimum - case lp_status::INFEASIBLE: - if (this->m_look_for_feasible_solution_only && this->current_x_is_feasible()) - break; - if (!numeric_traits::precise()) { - if(this->m_look_for_feasible_solution_only) - break; - this->init_lu(); - - if (this->m_factorization->get_status() != LU_status::OK) { - this->set_status(lp_status::FLOATING_POINT_ERROR); - break; - } - init_reduced_costs(); - if (choose_entering_column(1) == -1) { - decide_on_status_when_cannot_find_entering(); - break; - } - this->set_status(lp_status::UNKNOWN); - } else { // precise case - if ((!this->infeasibility_costs_are_correct())) { - init_reduced_costs_tableau(); // forcing recalc - if (choose_entering_column_tableau() == -1) { - decide_on_status_when_cannot_find_entering(); - break; - } - this->set_status(lp_status::UNKNOWN); - } - } - break; - case lp_status::TENTATIVE_UNBOUNDED: - this->init_lu(); - if (this->m_factorization->get_status() != LU_status::OK) { - this->set_status(lp_status::FLOATING_POINT_ERROR); - break; - } - - init_reduced_costs(); - break; - case lp_status::UNBOUNDED: - if (this->current_x_is_infeasible()) { - init_reduced_costs(); - this->set_status(lp_status::UNKNOWN); - } - break; - - case lp_status::UNSTABLE: - lp_assert(! (numeric_traits::precise())); - this->init_lu(); - if (this->m_factorization->get_status() != LU_status::OK) { - this->set_status(lp_status::FLOATING_POINT_ERROR); - break; - } - init_reduced_costs(); - break; - - default: - break; // do nothing - } - } while (this->get_status() != lp_status::FLOATING_POINT_ERROR - && - this->get_status() != lp_status::UNBOUNDED - && - this->get_status() != lp_status::OPTIMAL - && - this->get_status() != lp_status::INFEASIBLE - && - this->iters_with_no_cost_growing() <= this->m_settings.max_number_of_iterations_with_no_improvements - && - this->total_iterations() <= this->m_settings.max_total_number_of_iterations - && - !(this->current_x_is_feasible() && this->m_look_for_feasible_solution_only)); - - lp_assert(this->get_status() == lp_status::FLOATING_POINT_ERROR - || - this->current_x_is_feasible() == false - || - this->calc_current_x_is_feasible_include_non_basis()); - return this->total_iterations(); - -} -template void lp_primal_core_solver::advance_on_entering_and_leaving_tableau(int entering, int leaving, X & t) { - CASSERT("A_off", this->A_mult_x_is_off() == false); - lp_assert(leaving >= 0 && entering >= 0); - lp_assert((this->m_settings.simplex_strategy() == - simplex_strategy_enum::tableau_rows) || - m_non_basis_list.back() == static_cast(entering)); - lp_assert(this->m_using_infeas_costs || !is_neg(t)); - lp_assert(entering != leaving || !is_zero(t)); // otherwise nothing changes - if (entering == leaving) { - advance_on_entering_equal_leaving_tableau(entering, t); - return; - } - if (!is_zero(t)) { - if (this->current_x_is_feasible() || !this->m_settings.use_breakpoints_in_feasibility_search ) { - if (m_sign_of_entering_delta == -1) - t = -t; - } - this->update_basis_and_x_tableau(entering, leaving, t); - CASSERT("A_off", this->A_mult_x_is_off() == false); - this->iters_with_no_cost_growing() = 0; - } else { - this->pivot_column_tableau(entering, this->m_basis_heading[leaving]); - this->change_basis(entering, leaving); - } - - if (this->m_look_for_feasible_solution_only && this->current_x_is_feasible()) - return; - - if (this->m_settings.simplex_strategy() != simplex_strategy_enum::tableau_rows) { - if (need_to_switch_costs()) { - this->init_reduced_costs_tableau(); - } - - lp_assert(!need_to_switch_costs()); - std::list::iterator it = m_non_basis_list.end(); - it--; - * it = static_cast(leaving); - } -} - -template -void lp_primal_core_solver::advance_on_entering_equal_leaving_tableau(int entering, X & t) { - CASSERT("A_off", !this->A_mult_x_is_off() ); - this->update_x_tableau(entering, t * m_sign_of_entering_delta); - if (this->m_look_for_feasible_solution_only && this->current_x_is_feasible()) - return; - - if (need_to_switch_costs()) { - init_reduced_costs_tableau(); - } - this->iters_with_no_cost_growing() = 0; -} -template int lp_primal_core_solver::find_leaving_and_t_tableau(unsigned entering, X & t) { - unsigned k = 0; - bool unlimited = true; - unsigned row_min_nz = this->m_n() + 1; - m_leaving_candidates.clear(); - auto & col = this->m_A.m_columns[entering]; - unsigned col_size = col.size(); - for (;k < col_size && unlimited; k++) { - const column_cell & c = col[k]; - unsigned i = c.m_i; - const T & ed = this->m_A.get_val(c); - lp_assert(!numeric_traits::is_zero(ed)); - unsigned j = this->m_basis[i]; - limit_theta_on_basis_column(j, - ed * m_sign_of_entering_delta, t, unlimited); - if (!unlimited) { - m_leaving_candidates.push_back(j); - row_min_nz = this->m_A.m_rows[i].size(); - } - } - if (unlimited) { - if (try_jump_to_another_bound_on_entering_unlimited(entering, t)) - return entering; - return -1; - } - - X ratio; - for (;k < col_size; k++) { - const column_cell & c = col[k]; - unsigned i = c.m_i; - const T & ed = this->m_A.get_val(c); - lp_assert(!numeric_traits::is_zero(ed)); - unsigned j = this->m_basis[i]; - unlimited = true; - limit_theta_on_basis_column(j, -ed * m_sign_of_entering_delta, ratio, unlimited); - if (unlimited) continue; - unsigned i_nz = this->m_A.m_rows[i].size(); - if (ratio < t) { - t = ratio; - m_leaving_candidates.clear(); - m_leaving_candidates.push_back(j); - row_min_nz = i_nz; - } else if (ratio == t && i_nz < row_min_nz) { - m_leaving_candidates.clear(); - m_leaving_candidates.push_back(j); - row_min_nz = this->m_A.m_rows[i].size(); - } else if (ratio == t && i_nz == row_min_nz) { - m_leaving_candidates.push_back(j); - } - } - - ratio = t; - unlimited = false; - if (try_jump_to_another_bound_on_entering(entering, t, ratio, unlimited)) { - t = ratio; - return entering; - } - if (m_leaving_candidates.size() == 1) - return m_leaving_candidates[0]; - k = this->m_settings.random_next() % m_leaving_candidates.size(); - return m_leaving_candidates[k]; -} -template void lp_primal_core_solver::init_run_tableau() { - // print_matrix(&(this->m_A), std::cout); - CASSERT("A_off", this->A_mult_x_is_off() == false); - lp_assert(basis_columns_are_set_correctly()); - this->m_basis_sort_counter = 0; // to initiate the sort of the basis - this->set_total_iterations(0); - this->iters_with_no_cost_growing() = 0; - lp_assert(this->inf_set_is_correct()); - if (this->current_x_is_feasible() && this->m_look_for_feasible_solution_only) - return; - if (this->m_settings.backup_costs) - backup_and_normalize_costs(); - m_epsilon_of_reduced_cost = numeric_traits::precise() ? zero_of_type() : T(1) / T(10000000); - if (this->m_settings.use_breakpoints_in_feasibility_search) - m_breakpoint_indices_queue.resize(this->m_n()); - if (!numeric_traits::precise()) { - this->m_column_norm_update_counter = 0; - init_column_norms(); - } - if (this->m_settings.simplex_strategy() == simplex_strategy_enum::tableau_rows) - init_tableau_rows(); - lp_assert(this->reduced_costs_are_correct_tableau()); - lp_assert(!this->need_to_pivot_to_basis_tableau()); -} - -template bool lp_primal_core_solver:: -update_basis_and_x_tableau(int entering, int leaving, X const & tt) { - lp_assert(this->use_tableau()); - update_x_tableau(entering, tt); - this->pivot_column_tableau(entering, this->m_basis_heading[leaving]); - this->change_basis(entering, leaving); - return true; -} -template void lp_primal_core_solver:: -update_x_tableau(unsigned entering, const X& delta) { - this->add_delta_to_x_and_call_tracker(entering, delta); - if (!this->m_using_infeas_costs) { - for (const auto & c : this->m_A.m_columns[entering]) { - unsigned i = c.m_i; - this->update_x_with_delta_and_track_feasibility(this->m_basis[i], - delta * this->m_A.get_val(c)); - } - } else { // m_using_infeas_costs == true - lp_assert(this->column_is_feasible(entering)); - lp_assert(this->m_costs[entering] == zero_of_type()); - // m_d[entering] can change because of the cost change for basic columns. - for (const auto & c : this->m_A.m_columns[entering]) { - unsigned i = c.m_i; - unsigned j = this->m_basis[i]; - this->add_delta_to_x_and_call_tracker(j, -delta * this->m_A.get_val(c)); - update_inf_cost_for_column_tableau(j); - if (is_zero(this->m_costs[j])) - this->remove_column_from_inf_set(j); - else - this->insert_column_into_inf_set(j); - } - } - CASSERT("A_off", this->A_mult_x_is_off() == false); -} - -template void lp_primal_core_solver:: -update_inf_cost_for_column_tableau(unsigned j) { - lp_assert(this->m_settings.simplex_strategy() != simplex_strategy_enum::tableau_rows); - lp_assert(this->m_using_infeas_costs); - T new_cost = get_infeasibility_cost_for_column(j); - T delta = this->m_costs[j] - new_cost; - if (is_zero(delta)) - return; - this->m_costs[j] = new_cost; - update_reduced_cost_for_basic_column_cost_change(delta, j); -} - -template void lp_primal_core_solver::init_reduced_costs_tableau() { - if (this->current_x_is_infeasible() && !this->m_using_infeas_costs) { - init_infeasibility_costs(); - } else if (this->current_x_is_feasible() && this->m_using_infeas_costs) { - if (this->m_look_for_feasible_solution_only) - return; - this->m_costs = m_costs_backup; - this->m_using_infeas_costs = false; - } - unsigned size = this->m_basis_heading.size(); - for (unsigned j = 0; j < size; j++) { - if (this->m_basis_heading[j] >= 0) - this->m_d[j] = zero_of_type(); - else { - T& d = this->m_d[j] = this->m_costs[j]; - for (auto & cc : this->m_A.m_columns[j]) { - d -= this->m_costs[this->m_basis[cc.m_i]] * this->m_A.get_val(cc); - } - } - } -} -} diff --git a/src/util/map.h b/src/util/map.h index 0d2acf11b..3a59c8975 100644 --- a/src/util/map.h +++ b/src/util/map.h @@ -135,7 +135,7 @@ public: value const& get(key const& k, value const& default_value) const { entry* e = find_core(k); if (e) { - return e->get_data().m_value; + return e->get_data().m_value; } else { return default_value; diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 7287b69cf..5e7233110 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -1217,12 +1217,18 @@ void mpf_manager::to_sbv_mpq(mpf_rounding_mode rm, const mpf & x, scoped_mpq & o default: UNREACHABLE(); } if (inc) m_mpz_manager.inc(z); + TRACE("mpf_dbg_sbv", + tout << "SBV: (" << to_string(x) << ") == " << m_mpq_manager.to_string(z) << std::endl; + tout << "sign=" << t.sign() << " last=" << last << " round=" << round << + " sticky=" << sticky << " inc=" << inc << std::endl; ); } else m_mpz_manager.mul2k(z, (unsigned) e); m_mpq_manager.set(o, z); if (x.sign) m_mpq_manager.neg(o); + + TRACE("mpf_dbg", tout << "SBV = " << m_mpq_manager.to_string(o) << std::endl;); } void mpf_manager::to_ieee_bv_mpz(const mpf & x, scoped_mpz & o) { @@ -1248,6 +1254,8 @@ void mpf_manager::to_ieee_bv_mpz(const mpf & x, scoped_mpz & o) { m_mpz_manager.mul2k(o, sbits - 1); m_mpz_manager.add(o, sig(x), o); } + + TRACE("mpf_dbg", tout << "IEEE_BV = " << m_mpz_manager.to_string(o) << std::endl;); } void mpf_manager::renormalize(unsigned ebits, unsigned sbits, mpf_exp_t & exp, mpz & sig) { diff --git a/src/util/rational.h b/src/util/rational.h index ca294e234..803c562ad 100644 --- a/src/util/rational.h +++ b/src/util/rational.h @@ -422,7 +422,7 @@ inline bool operator>(rational const & r1, rational const & r2) { } inline bool operator<(rational const & r1, int r2) { - return r1 < rational(r2); + return r1 < rational(r2); } inline bool operator<=(rational const & r1, rational const & r2) { @@ -450,11 +450,11 @@ inline rational operator+(rational const & r1, rational const & r2) { } inline rational operator+(int r1, rational const & r2) { - return rational(r1) + r2; + return rational(r1) + r2; } inline rational operator+(rational const & r1, int r2) { - return r1 + rational(r2); + return r1 + rational(r2); } @@ -463,11 +463,11 @@ inline rational operator-(rational const & r1, rational const & r2) { } inline rational operator-(rational const & r1, int r2) { - return r1 - rational(r2); + return r1 - rational(r2); } inline rational operator-(int r1, rational const & r2) { - return rational(r1) - r2; + return rational(r1) - r2; } inline rational operator-(rational const & r) { @@ -492,11 +492,11 @@ inline rational operator/(rational const & r1, rational const & r2) { } inline rational operator/(rational const & r1, int r2) { - return r1 / rational(r2); + return r1 / rational(r2); } -inline rational operator/(int r1, rational const & r2) { - return rational(r1) / r2; +inline rational operator/(int r1, rational const & r2) { + return rational(r1) / r2; } inline rational power(rational const & r, unsigned p) { diff --git a/src/util/stopwatch.h b/src/util/stopwatch.h index 7a9066030..7f2ed3245 100644 --- a/src/util/stopwatch.h +++ b/src/util/stopwatch.h @@ -110,7 +110,7 @@ public: mach_timespec_t _stop; clock_get_time(m_host_clock, &_stop); m_time += (_stop.tv_sec - m_start.tv_sec) * 1000000000ull; - m_time += (_stop.tv_nsec - m_start.tv_nsec); + m_time += (_stop.tv_nsec - m_start.tv_nsec); m_running = false; } } @@ -163,8 +163,8 @@ public: struct timespec _stop; clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &_stop); m_time += (_stop.tv_sec - m_start.tv_sec) * 1000000000ull; - if (m_time != 0 || _stop.tv_nsec >= m_start.tv_nsec) - m_time += (_stop.tv_nsec - m_start.tv_nsec); + if (m_time != 0 || _stop.tv_nsec >= m_start.tv_nsec) + m_time += (_stop.tv_nsec - m_start.tv_nsec); m_running = false; } } diff --git a/src/util/util.h b/src/util/util.h index a741eedb6..facd5a3cb 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -154,13 +154,13 @@ template char (*ArraySizer(T (&)[N]))[N]; template void display(std::ostream & out, const IT & begin, const IT & end, const char * sep, bool & first) { for(IT it = begin; it != end; ++it) { - if (first) { - first = false; - } - else { - out << sep; - } - out << *it; + if (first) { + first = false; + } + else { + out << sep; + } + out << *it; } } @@ -173,9 +173,9 @@ void display(std::ostream & out, const IT & begin, const IT & end, const char * template struct delete_proc { void operator()(T * ptr) { - if (ptr) { - dealloc(ptr); - } + if (ptr) { + dealloc(ptr); + } } };