diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp
index 3d8580178..a2299aec3 100644
--- a/src/api/api_opt.cpp
+++ b/src/api/api_opt.cpp
@@ -218,6 +218,34 @@ extern "C" {
Z3_CATCH_RETURN(0);
}
+ // get lower value or current approximation
+ Z3_ast_vector Z3_API Z3_optimize_get_lower_as_vector(Z3_context c, Z3_optimize o, unsigned idx) {
+ Z3_TRY;
+ LOG_Z3_optimize_get_lower_as_vector(c, o, idx);
+ RESET_ERROR_CODE();
+ expr_ref_vector es(mk_c(c)->m());
+ to_optimize_ptr(o)->get_lower(idx, es);
+ Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m());
+ mk_c(c)->save_object(v);
+ v->m_ast_vector.append(es.size(), (ast*const*)es.c_ptr());
+ RETURN_Z3(of_ast_vector(v));
+ Z3_CATCH_RETURN(0);
+ }
+
+ // get upper or current approximation
+ Z3_ast_vector Z3_API Z3_optimize_get_upper_as_vector(Z3_context c, Z3_optimize o, unsigned idx) {
+ Z3_TRY;
+ LOG_Z3_optimize_get_upper_as_vector(c, o, idx);
+ RESET_ERROR_CODE();
+ expr_ref_vector es(mk_c(c)->m());
+ to_optimize_ptr(o)->get_upper(idx, es);
+ Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m());
+ mk_c(c)->save_object(v);
+ v->m_ast_vector.append(es.size(), (ast*const*)es.c_ptr());
+ RETURN_Z3(of_ast_vector(v));
+ Z3_CATCH_RETURN(0);
+ }
+
Z3_string Z3_API Z3_optimize_to_string(Z3_context c, Z3_optimize o) {
Z3_TRY;
LOG_Z3_optimize_to_string(c, o);
diff --git a/src/api/dotnet/Optimize.cs b/src/api/dotnet/Optimize.cs
index c8954a473..99dd9aac0 100644
--- a/src/api/dotnet/Optimize.cs
+++ b/src/api/dotnet/Optimize.cs
@@ -144,6 +144,23 @@ namespace Microsoft.Z3
{
get { return Lower; }
}
+
+ ///
+ /// Retrieve a lower bound for the objective handle.
+ ///
+ public ArithExpr[] LowerAsVector
+ {
+ get { return opt.GetLowerAsVector(handle); }
+ }
+
+ ///
+ /// Retrieve an upper bound for the objective handle.
+ ///
+ public ArithExpr[] UpperAsVector
+ {
+ get { return opt.GetUpperAsVector(handle); }
+ }
+
}
///
@@ -255,6 +272,25 @@ namespace Microsoft.Z3
return (ArithExpr)Expr.Create(Context, Native.Z3_optimize_get_upper(Context.nCtx, NativeObject, index));
}
+ ///
+ /// 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));
+ return v.ToArithExprArray();
+ }
+
+
+ ///
+ /// 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
///
diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py
index 6729d99b5..a0aba95d6 100644
--- a/src/api/python/z3/z3.py
+++ b/src/api/python/z3/z3.py
@@ -6719,12 +6719,24 @@ class OptimizeObjective:
opt = self._opt
return _to_expr_ref(Z3_optimize_get_upper(opt.ctx.ref(), opt.optimize, self._value), opt.ctx)
+ def lower_values(self):
+ opt = self._opt
+ return AstVector(Z3_optimize_get_lower_as_vector(opt.ctx.ref(), opt.optimize, self._value), opt.ctx)
+
+ def upper_values(self):
+ opt = self._opt
+ return AstVector(Z3_optimize_get_upper_as_vector(opt.ctx.ref(), opt.optimize, self._value), opt.ctx)
+
def value(self):
if self._is_max:
return self.upper()
else:
return self.lower()
+ def __str__(self):
+ return "%s:%s" % (self._value, self._is_max)
+
+
class Optimize(Z3PPObject):
"""Optimize API provides methods for solving using objective functions and weighted soft constraints"""
@@ -6829,6 +6841,16 @@ class Optimize(Z3PPObject):
raise Z3Exception("Expecting objective handle returned by maximize/minimize")
return obj.upper()
+ def lower_values(self, obj):
+ if not isinstance(obj, OptimizeObjective):
+ raise Z3Exception("Expecting objective handle returned by maximize/minimize")
+ return obj.lower_values()
+
+ def upper_values(self, obj):
+ if not isinstance(obj, OptimizeObjective):
+ raise Z3Exception("Expecting objective handle returned by maximize/minimize")
+ return obj.upper_values()
+
def from_file(self, filename):
"""Parse assertions and objectives from a file"""
Z3_optimize_from_file(self.ctx.ref(), self.optimize, filename)
diff --git a/src/api/z3_optimization.h b/src/api/z3_optimization.h
index f7a9a8fe9..795b4b8fd 100644
--- a/src/api/z3_optimization.h
+++ b/src/api/z3_optimization.h
@@ -186,6 +186,33 @@ extern "C" {
*/
Z3_ast Z3_API Z3_optimize_get_upper(Z3_context c, Z3_optimize o, unsigned idx);
+
+ /**
+ \brief Retrieve lower bound value or approximation for the i'th optimization objective.
+ The returned vector is of length 3. It always contains numerals.
+ The three numerals are coefficients a, b, c and encode the result of \c Z3_optimize_get_lower
+ a * infinity + b + c * epsilon.
+
+ \param c - context
+ \param o - optimization context
+ \param idx - index of optimization objective
+
+ def_API('Z3_optimize_get_lower_as_vector', AST_VECTOR, (_in(CONTEXT), _in(OPTIMIZE), _in(UINT)))
+ */
+ Z3_ast_vector Z3_API Z3_optimize_get_lower_as_vector(Z3_context c, Z3_optimize o, unsigned idx);
+
+ /**
+ \brief Retrieve upper bound value or approximation for the i'th optimization objective.
+
+ \param c - context
+ \param o - optimization context
+ \param idx - index of optimization objective
+
+ def_API('Z3_optimize_get_upper_as_vector', AST_VECTOR, (_in(CONTEXT), _in(OPTIMIZE), _in(UINT)))
+ */
+ Z3_ast_vector Z3_API Z3_optimize_get_upper_as_vector(Z3_context c, Z3_optimize o, unsigned idx);
+
+
/**
\brief Print the current context as a string.
\param c - context.
diff --git a/src/cmd_context/tactic_cmds.cpp b/src/cmd_context/tactic_cmds.cpp
index 2f7b1ea6e..2b60486f7 100644
--- a/src/cmd_context/tactic_cmds.cpp
+++ b/src/cmd_context/tactic_cmds.cpp
@@ -223,7 +223,7 @@ public:
cmd_context::scoped_watch sw(ctx);
lbool r = l_undef;
try {
- r = check_sat(t, g, md, result->labels, pr, core, reason_unknown);
+ r = check_sat(t, g, md, result->labels, pr, core, reason_unknown);
ctx.display_sat_result(r);
result->set_status(r);
if (r == l_undef) {
diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp
index 56b152caa..ebe56381a 100644
--- a/src/opt/opt_context.cpp
+++ b/src/opt/opt_context.cpp
@@ -1290,6 +1290,15 @@ namespace opt {
return to_expr(get_upper_as_num(idx));
}
+ void context::to_exprs(inf_eps const& n, expr_ref_vector& es) {
+ rational inf = n.get_infinity();
+ rational r = n.get_rational();
+ rational eps = n.get_infinitesimal();
+ es.push_back(m_arith.mk_numeral(inf, inf.is_int()));
+ es.push_back(m_arith.mk_numeral(r, r.is_int()));
+ es.push_back(m_arith.mk_numeral(eps, eps.is_int()));
+ }
+
expr_ref context::to_expr(inf_eps const& n) {
rational inf = n.get_infinity();
rational r = n.get_rational();
@@ -1455,9 +1464,10 @@ namespace opt {
void context::validate_maxsat(symbol const& id) {
maxsmt& ms = *m_maxsmts.find(id);
+ TRACE("opt", tout << "Validate: " << id << "\n";);
for (unsigned i = 0; i < m_objectives.size(); ++i) {
objective const& obj = m_objectives[i];
- if (obj.m_id == id) {
+ if (obj.m_id == id && obj.m_type == O_MAXSMT) {
SASSERT(obj.m_type == O_MAXSMT);
rational value(0);
expr_ref val(m);
diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h
index 461506258..f51f75830 100644
--- a/src/opt/opt_context.h
+++ b/src/opt/opt_context.h
@@ -207,6 +207,9 @@ namespace opt {
expr_ref get_lower(unsigned idx);
expr_ref get_upper(unsigned idx);
+ void get_lower(unsigned idx, expr_ref_vector& es) { to_exprs(get_lower_as_num(idx), es); }
+ void get_upper(unsigned idx, expr_ref_vector& es) { to_exprs(get_upper_as_num(idx), es); }
+
std::string to_string() const;
@@ -238,6 +241,7 @@ namespace opt {
lbool adjust_unknown(lbool r);
bool scoped_lex();
expr_ref to_expr(inf_eps const& n);
+ void to_exprs(inf_eps const& n, expr_ref_vector& es);
void reset_maxsmts();
void import_scoped_state();
diff --git a/src/smt/tactic/smt_tactic.cpp b/src/smt/tactic/smt_tactic.cpp
index bd2c72c3e..ee3171d03 100644
--- a/src/smt/tactic/smt_tactic.cpp
+++ b/src/smt/tactic/smt_tactic.cpp
@@ -25,6 +25,9 @@ Notes:
#include"filter_model_converter.h"
#include"ast_util.h"
#include"solver2tactic.h"
+#include"smt_solver.h"
+#include"solver.h"
+#include"mus.h"
typedef obj_map expr2expr_map;
@@ -159,6 +162,8 @@ public:
ref fmc;
if (in->unsat_core_enabled()) {
extract_clauses_and_dependencies(in, clauses, assumptions, bool2dep, fmc);
+ TRACE("mus", in->display_with_dependencies(tout);
+ tout << clauses << "\n";);
if (in->proofs_enabled() && !assumptions.empty())
throw tactic_exception("smt tactic does not support simultaneous generation of proofs and unsat cores");
for (unsigned i = 0; i < clauses.size(); ++i) {
@@ -224,8 +229,26 @@ public:
pr = m_ctx->get_proof();
if (in->unsat_core_enabled()) {
unsigned sz = m_ctx->get_unsat_core_size();
+ expr_ref_vector _core(m);
+ for (unsigned i = 0; i < sz; ++i) {
+ _core.push_back(m_ctx->get_unsat_core_expr(i));
+ }
+ if (sz > 0 && smt_params_helper(m_params_ref).core_minimize()) {
+ std::cout << "size1 " << sz << " " << clauses << "\n";
+ ref slv = mk_smt_solver(m, m_params_ref, m_logic);
+ slv->assert_expr(clauses);
+ mus mus(*slv.get());
+ mus.add_soft(_core.size(), _core.c_ptr());
+ lbool got_core = mus.get_mus(_core);
+ sz = _core.size();
+ std::cout << "size2 " << sz << "\n";
+ if (got_core != l_true) {
+ r = l_undef;
+ goto undef_case;
+ }
+ }
for (unsigned i = 0; i < sz; i++) {
- expr * b = m_ctx->get_unsat_core_expr(i);
+ expr * b = _core[i].get();
SASSERT(is_uninterp_const(b) && m.is_bool(b));
expr * d = bool2dep.find(b);
lcore = m.mk_join(lcore, m.mk_leaf(d));
@@ -236,6 +259,7 @@ public:
return;
}
case l_undef:
+ undef_case:
if (m_ctx->canceled()) {
throw tactic_exception(Z3_CANCELED_MSG);
}
diff --git a/src/solver/mus.cpp b/src/solver/mus.cpp
index 91d47386e..d536a191b 100644
--- a/src/solver/mus.cpp
+++ b/src/solver/mus.cpp
@@ -89,6 +89,7 @@ struct mus::imp {
lbool get_mus1(expr_ref_vector& mus) {
ptr_vector unknown(m_lit2expr.size(), m_lit2expr.c_ptr());
ptr_vector core_exprs;
+ TRACE("mus", m_solver.display(tout););
while (!unknown.empty()) {
IF_VERBOSE(12, verbose_stream() << "(mus reducing core: " << unknown.size() << " new core: " << mus.size() << ")\n";);
TRACE("mus", display_vec(tout << "core: ", unknown); display_vec(tout << "mus: ", mus););
diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp
index b0a4c0e4f..e451f57d4 100644
--- a/src/solver/tactic2solver.cpp
+++ b/src/solver/tactic2solver.cpp
@@ -290,3 +290,5 @@ solver_factory * mk_tactic2solver_factory(tactic * t) {
solver_factory * mk_tactic_factory2solver_factory(tactic_factory * f) {
return alloc(tactic_factory2solver_factory, f);
}
+
+
diff --git a/src/tactic/tactic.cpp b/src/tactic/tactic.cpp
index 67fce1486..ac63a2d24 100644
--- a/src/tactic/tactic.cpp
+++ b/src/tactic/tactic.cpp
@@ -23,7 +23,6 @@ Notes:
#include"model_v2_pp.h"
-
struct tactic_report::imp {
char const * m_id;
goal const & m_goal;
@@ -175,6 +174,7 @@ void exec(tactic & t, goal_ref const & in, goal_ref_buffer & result, model_conve
}
}
+
lbool check_sat(tactic & t, goal_ref & g, model_ref & md, labels_vec & labels, proof_ref & pr, expr_dependency_ref & core, std::string & reason_unknown) {
bool models_enabled = g->models_enabled();
bool proofs_enabled = g->proofs_enabled();