mirror of
https://github.com/Z3Prover/z3
synced 2025-04-24 17:45:32 +00:00
Merge branch 'master' into polysat
This commit is contained in:
commit
59c3234fb8
196 changed files with 4705 additions and 4168 deletions
|
@ -22,7 +22,7 @@ A tactic for performing Ackermann reduction for bit-vector formulas
|
|||
### Long Description
|
||||
|
||||
The Ackermann reduction replaces uninterpreted functions $f(t_1), f(t_2)$
|
||||
by fresh variables $f_1, f_2$ and addes axioms $t_1 \simeq t_2 \implies f_1 \simeq f_2$.
|
||||
by fresh variables $f_1, f_2$ and adds axioms $t_1 \simeq t_2 \implies f_1 \simeq f_2$.
|
||||
The reduction has the effect of eliminating uninterpreted functions. When the reduction
|
||||
produces a pure bit-vector benchmark, it allows Z3 to use a specialized SAT solver.
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ Revision History:
|
|||
|
||||
/** \brief
|
||||
Information about how a formula is being converted into
|
||||
a formula without uninterpreted function symbols via ackermannization.
|
||||
a formula without uninterpreted function symbols via ackermannization.
|
||||
|
||||
The intended use is that new terms are added via set_abstr.
|
||||
Once all terms are abstracted, call seal.
|
||||
|
|
|
@ -231,7 +231,7 @@ namespace api {
|
|||
void handle_exception(z3_exception & ex);
|
||||
char const * get_exception_msg() const { return m_exception_msg.c_str(); }
|
||||
|
||||
// Interrupt the current interruptable object
|
||||
// Interrupt the current interruptible object
|
||||
void interrupt();
|
||||
|
||||
void invoke_error_handler(Z3_error_code c);
|
||||
|
|
|
@ -742,7 +742,7 @@ extern "C" {
|
|||
fpa_util & fu = ctx->fpautil();
|
||||
if (!ctx->bvutil().is_bv(to_expr(bv)) ||
|
||||
!fu.is_float(to_sort(s))) {
|
||||
SET_ERROR_CODE(Z3_INVALID_ARG, "bv sort the flaot sort expected");
|
||||
SET_ERROR_CODE(Z3_INVALID_ARG, "bv sort the float sort expected");
|
||||
return nullptr;
|
||||
}
|
||||
expr * a = fu.mk_to_fp(to_sort(s), to_expr(bv));
|
||||
|
|
|
@ -1092,15 +1092,15 @@ extern "C" {
|
|||
Z3_CATCH;
|
||||
}
|
||||
|
||||
void Z3_API Z3_solver_propagate_consequence(Z3_context c, Z3_solver_callback s, unsigned num_fixed, Z3_ast const* fixed_ids, unsigned num_eqs, Z3_ast const* eq_lhs, Z3_ast const* eq_rhs, Z3_ast conseq) {
|
||||
bool Z3_API Z3_solver_propagate_consequence(Z3_context c, Z3_solver_callback s, unsigned num_fixed, Z3_ast const* fixed_ids, unsigned num_eqs, Z3_ast const* eq_lhs, Z3_ast const* eq_rhs, Z3_ast conseq) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_solver_propagate_consequence(c, s, num_fixed, fixed_ids, num_eqs, eq_lhs, eq_rhs, conseq);
|
||||
RESET_ERROR_CODE();
|
||||
expr* const * _fixed_ids = (expr* const*) fixed_ids;
|
||||
expr* const * _eq_lhs = (expr*const*) eq_lhs;
|
||||
expr* const * _eq_rhs = (expr*const*) eq_rhs;
|
||||
reinterpret_cast<user_propagator::callback*>(s)->propagate_cb(num_fixed, _fixed_ids, num_eqs, _eq_lhs, _eq_rhs, to_expr(conseq));
|
||||
Z3_CATCH;
|
||||
return reinterpret_cast<user_propagator::callback*>(s)->propagate_cb(num_fixed, _fixed_ids, num_eqs, _eq_lhs, _eq_rhs, to_expr(conseq));
|
||||
Z3_CATCH_RETURN(false);
|
||||
}
|
||||
|
||||
void Z3_API Z3_solver_propagate_created(Z3_context c, Z3_solver s, Z3_created_eh created_eh) {
|
||||
|
|
|
@ -320,7 +320,7 @@ namespace z3 {
|
|||
/**
|
||||
\brief Create a recursive datatype over a single sort.
|
||||
\c name is the name of the recursive datatype
|
||||
\c n - the numer of constructors of the datatype
|
||||
\c n - the number of constructors of the datatype
|
||||
\c cs - the \c n constructors used to define the datatype
|
||||
|
||||
References to the datatype can be created using \ref datatype_sort.
|
||||
|
@ -4496,14 +4496,14 @@ namespace z3 {
|
|||
Z3_solver_propagate_consequence(ctx(), cb, fixed.size(), _fixed.ptr(), lhs.size(), _lhs.ptr(), _rhs.ptr(), conseq);
|
||||
}
|
||||
|
||||
void propagate(expr_vector const& fixed, expr const& conseq) {
|
||||
bool propagate(expr_vector const& fixed, expr const& conseq) {
|
||||
assert(cb);
|
||||
assert((Z3_context)conseq.ctx() == (Z3_context)ctx());
|
||||
array<Z3_ast> _fixed(fixed);
|
||||
Z3_solver_propagate_consequence(ctx(), cb, _fixed.size(), _fixed.ptr(), 0, nullptr, nullptr, conseq);
|
||||
return Z3_solver_propagate_consequence(ctx(), cb, _fixed.size(), _fixed.ptr(), 0, nullptr, nullptr, conseq);
|
||||
}
|
||||
|
||||
void propagate(expr_vector const& fixed,
|
||||
bool propagate(expr_vector const& fixed,
|
||||
expr_vector const& lhs, expr_vector const& rhs,
|
||||
expr const& conseq) {
|
||||
assert(cb);
|
||||
|
@ -4513,7 +4513,7 @@ namespace z3 {
|
|||
array<Z3_ast> _lhs(lhs);
|
||||
array<Z3_ast> _rhs(rhs);
|
||||
|
||||
Z3_solver_propagate_consequence(ctx(), cb, _fixed.size(), _fixed.ptr(), lhs.size(), _lhs.ptr(), _rhs.ptr(), conseq);
|
||||
return Z3_solver_propagate_consequence(ctx(), cb, _fixed.size(), _fixed.ptr(), lhs.size(), _lhs.ptr(), _rhs.ptr(), conseq);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -3770,7 +3770,7 @@ namespace Microsoft.Z3
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a simplifie that applies <paramref name="t1"/> and
|
||||
/// Create a simplifier that applies <paramref name="t1"/> and
|
||||
/// then <paramref name="t2"/>.
|
||||
/// </summary>
|
||||
public Simplifier AndThen(Simplifier t1, Simplifier t2, params Simplifier[] ts)
|
||||
|
|
|
@ -97,7 +97,7 @@ namespace Microsoft.Z3
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Symbols's hash code.
|
||||
/// The Symbol's hash code.
|
||||
/// </summary>
|
||||
/// <returns>A hash code</returns>
|
||||
public override int GetHashCode()
|
||||
|
|
|
@ -58,7 +58,7 @@ namespace Microsoft.Z3
|
|||
public delegate void CreatedEh(Expr term);
|
||||
|
||||
/// <summary>
|
||||
/// Delegate type for callback into solver's branching. The values can be overriden by calling <see cref="NextSplit" />.
|
||||
/// Delegate type for callback into solver's branching. The values can be overridden by calling <see cref="NextSplit" />.
|
||||
/// </summary>
|
||||
/// <param name="term">A bit-vector or Boolean used for branching</param>
|
||||
/// <param name="idx">If the term is a bit-vector, then an index into the bit-vector being branched on</param>
|
||||
|
@ -252,11 +252,29 @@ namespace Microsoft.Z3
|
|||
|
||||
/// <summary>
|
||||
/// Propagate consequence
|
||||
/// <returns>
|
||||
/// <see langword="true" /> if the propagated expression is new for the solver;
|
||||
/// <see langword="false" /> if the propagation was ignored
|
||||
/// </returns>
|
||||
/// </summary>
|
||||
public void Propagate(IEnumerable<Expr> terms, Expr conseq)
|
||||
public bool Propagate(IEnumerable<Expr> terms, Expr conseq)
|
||||
{
|
||||
return Propagate(terms, new EqualityPairs(), conseq);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Propagate consequence
|
||||
/// <returns>
|
||||
/// <see langword="true" /> if the propagated expression is new for the solver;
|
||||
/// <see langword="false" /> if the propagation was ignored
|
||||
/// </returns>
|
||||
/// </summary>
|
||||
public bool Propagate(IEnumerable<Expr> terms, EqualityPairs equalities, Expr conseq)
|
||||
{
|
||||
var nTerms = Z3Object.ArrayToNative(terms.ToArray());
|
||||
Native.Z3_solver_propagate_consequence(ctx.nCtx, this.callback, (uint)nTerms.Length, nTerms, 0u, null, null, conseq.NativeObject);
|
||||
var nLHS = Z3Object.ArrayToNative(equalities.LHS.ToArray());
|
||||
var nRHS = Z3Object.ArrayToNative(equalities.RHS.ToArray());
|
||||
return Native.Z3_solver_propagate_consequence(ctx.nCtx, this.callback, (uint)nTerms.Length, nTerms, (uint)equalities.Count, nLHS, nRHS, conseq.NativeObject) != 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -375,4 +393,72 @@ namespace Microsoft.Z3
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A list of equalities used as justifications for propagation
|
||||
/// </summary>
|
||||
public class EqualityPairs {
|
||||
|
||||
readonly List<Expr> lhsList = new List<Expr>();
|
||||
readonly List<Expr> rhsList = new List<Expr>();
|
||||
|
||||
/// <summary>
|
||||
/// The left hand sides of the equalities
|
||||
/// </summary>
|
||||
public Expr[] LHS => lhsList.ToArray();
|
||||
|
||||
/// <summary>
|
||||
/// The right hand sides of the equalities
|
||||
/// </summary>
|
||||
public Expr[] RHS => rhsList.ToArray();
|
||||
|
||||
/// <summary>
|
||||
/// The number of equalities
|
||||
/// </summary>
|
||||
public int Count => lhsList.Count;
|
||||
|
||||
/// <summary>
|
||||
/// Adds an equality to the list. The sorts of the arguments have to be the same.
|
||||
/// <param name="lhs">The left hand side of the equality</param>
|
||||
/// <param name="rhs">The right hand side of the equality</param>
|
||||
/// </summary>
|
||||
public void Add(Expr lhs, Expr rhs) {
|
||||
lhsList.Add(lhs);
|
||||
rhsList.Add(rhs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if two equality lists are equal.
|
||||
/// The function does not take symmetries, shuffling, or duplicates into account.
|
||||
/// </summary>
|
||||
public override bool Equals(object obj) {
|
||||
if (ReferenceEquals(this, obj))
|
||||
return true;
|
||||
if (!(obj is EqualityPairs other))
|
||||
return false;
|
||||
if (lhsList.Count != other.lhsList.Count)
|
||||
return false;
|
||||
for (int i = 0; i < lhsList.Count; i++) {
|
||||
if (!lhsList[i].Equals(other.lhsList[i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a hash code for the list of equalities
|
||||
/// </summary>
|
||||
public override int GetHashCode() {
|
||||
int hash = lhsList.Count;
|
||||
unchecked {
|
||||
for (int i = 0; i < lhsList.Count; i++) {
|
||||
hash ^= lhsList[i].GetHashCode();
|
||||
hash *= 17;
|
||||
hash ^= rhsList[i].GetHashCode();
|
||||
hash *= 29;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2309,7 +2309,7 @@ public class Context implements AutoCloseable {
|
|||
|
||||
/**
|
||||
* Create the empty regular expression.
|
||||
* Coresponds to re.none
|
||||
* Corresponds to re.none
|
||||
*/
|
||||
public final <R extends Sort> ReExpr<R> mkEmptyRe(ReSort<R> s)
|
||||
{
|
||||
|
|
|
@ -28,7 +28,7 @@ import java.util.Map;
|
|||
*
|
||||
* <p><b>Mechanics: </b>once an object is created, a metadata is stored for it in
|
||||
* {@code referenceMap}, and a {@link PhantomReference} is created with a
|
||||
* reference to {@code referenceQueue}.
|
||||
* reference to {@code referenceQueue}.
|
||||
* Once the object becomes strongly unreachable, the phantom reference gets
|
||||
* added by JVM to the {@code referenceQueue}.
|
||||
* After each object creation, we iterate through the available objects in
|
||||
|
|
|
@ -226,6 +226,7 @@ DLL_VIS JNIEXPORT void JNICALL Java_com_microsoft_z3_Native_propagateAdd(JNIEnv
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
DLL_VIS JNIEXPORT bool JNICALL Java_com_microsoft_z3_Native_propagateNextSplit(JNIEnv * jenv, jclass cls, jobject jobj, jlong ctx, jlong solver, jlong javainfo, jlong e, long idx, int phase) {
|
||||
JavaInfo *info = (JavaInfo*)javainfo;
|
||||
Z3_solver_callback cb = info->cb;
|
||||
|
|
|
@ -166,7 +166,7 @@ public class Quantifier extends BoolExpr
|
|||
* @param sorts Sorts of bound variables.
|
||||
* @param names Names of bound variables
|
||||
* @param body Body of quantifier
|
||||
* @param weight Weight used to indicate priority for qunatifier instantiation
|
||||
* @param weight Weight used to indicate priority for quantifier instantiation
|
||||
* @param patterns Nullable patterns
|
||||
* @param noPatterns Nullable noPatterns
|
||||
* @param quantifierID Nullable quantifierID
|
||||
|
|
|
@ -13,7 +13,7 @@ Then run `npm i` to install dependencies, `npm run build:ts` to build the TypeSc
|
|||
|
||||
### Build on your own
|
||||
|
||||
Consult the file [build-wasm.ts](https://github.com/Z3Prover/z3/blob/master/src/api/js/scripts/build-wasm.ts) for configurations used for building wasm.
|
||||
Consult the file [build-wasm.ts](https://github.com/Z3Prover/z3/blob/master/src/api/js/scripts/build-wasm.ts) for configurations used for building wasm.
|
||||
|
||||
## Tests
|
||||
|
||||
|
|
|
@ -350,7 +350,7 @@ for (let fn of functions) {
|
|||
param.sizeIndex = defParams[idx].sizeIndex;
|
||||
if (!param.isArray && param.isPtr) {
|
||||
// not clear why some things are written as `int * x` and others `int x[]`
|
||||
// but we can jsut cast
|
||||
// but we can just cast
|
||||
param.isArray = true;
|
||||
param.isPtr = false;
|
||||
}
|
||||
|
|
|
@ -223,7 +223,7 @@ correctly found by gcc.
|
|||
|
||||
I specifically left the cygwin part of the code intact as I have no
|
||||
idea what the original author meant by this, neither do I use or
|
||||
tested this patch in the cygwin or mingw environemt. I think that this
|
||||
tested this patch in the cygwin or mingw environment. I think that this
|
||||
code is rather outdated and shouldn't really work. E.g., in the
|
||||
--staticlib mode adding z3linkdep (which is libz3-static.a) as an
|
||||
argument to `ocamlmklib` will yield the following broken archive
|
||||
|
|
|
@ -292,7 +292,7 @@ if 'bdist_wheel' in sys.argv and '--plat-name' not in sys.argv:
|
|||
distos = RELEASE_METADATA[2]
|
||||
if distos in ('debian', 'ubuntu'):
|
||||
raise Exception(
|
||||
"Linux binary distributions must be built on centos to conform to PEP 513 or alpine if targetting musl"
|
||||
"Linux binary distributions must be built on centos to conform to PEP 513 or alpine if targeting musl"
|
||||
)
|
||||
elif distos == 'glibc':
|
||||
if arch == 'x64':
|
||||
|
|
|
@ -5385,7 +5385,7 @@ def EnumSort(name, values, ctx=None):
|
|||
"""
|
||||
if z3_debug():
|
||||
_z3_assert(isinstance(name, str), "Name must be a string")
|
||||
_z3_assert(all([isinstance(v, str) for v in values]), "Eumeration sort values must be strings")
|
||||
_z3_assert(all([isinstance(v, str) for v in values]), "Enumeration sort values must be strings")
|
||||
_z3_assert(len(values) > 0, "At least one value expected")
|
||||
ctx = _get_ctx(ctx)
|
||||
num = len(values)
|
||||
|
@ -11286,6 +11286,8 @@ def Plus(re):
|
|||
>>> print(simplify(InRe("", re)))
|
||||
False
|
||||
"""
|
||||
if z3_debug():
|
||||
_z3_assert(is_expr(re), "expression expected")
|
||||
return ReRef(Z3_mk_re_plus(re.ctx_ref(), re.as_ast()), re.ctx)
|
||||
|
||||
|
||||
|
@ -11299,6 +11301,8 @@ def Option(re):
|
|||
>>> print(simplify(InRe("aa", re)))
|
||||
False
|
||||
"""
|
||||
if z3_debug():
|
||||
_z3_assert(is_expr(re), "expression expected")
|
||||
return ReRef(Z3_mk_re_option(re.ctx_ref(), re.as_ast()), re.ctx)
|
||||
|
||||
|
||||
|
@ -11317,6 +11321,8 @@ def Star(re):
|
|||
>>> print(simplify(InRe("", re)))
|
||||
True
|
||||
"""
|
||||
if z3_debug():
|
||||
_z3_assert(is_expr(re), "expression expected")
|
||||
return ReRef(Z3_mk_re_star(re.ctx_ref(), re.as_ast()), re.ctx)
|
||||
|
||||
|
||||
|
@ -11330,6 +11336,8 @@ def Loop(re, lo, hi=0):
|
|||
>>> print(simplify(InRe("", re)))
|
||||
False
|
||||
"""
|
||||
if z3_debug():
|
||||
_z3_assert(is_expr(re), "expression expected")
|
||||
return ReRef(Z3_mk_re_loop(re.ctx_ref(), re.as_ast(), lo, hi), re.ctx)
|
||||
|
||||
|
||||
|
@ -11343,11 +11351,17 @@ def Range(lo, hi, ctx=None):
|
|||
"""
|
||||
lo = _coerce_seq(lo, ctx)
|
||||
hi = _coerce_seq(hi, ctx)
|
||||
if z3_debug():
|
||||
_z3_assert(is_expr(lo), "expression expected")
|
||||
_z3_assert(is_expr(hi), "expression expected")
|
||||
return ReRef(Z3_mk_re_range(lo.ctx_ref(), lo.ast, hi.ast), lo.ctx)
|
||||
|
||||
def Diff(a, b, ctx=None):
|
||||
"""Create the difference regular expression
|
||||
"""
|
||||
if z3_debug():
|
||||
_z3_assert(is_expr(a), "expression expected")
|
||||
_z3_assert(is_expr(b), "expression expected")
|
||||
return ReRef(Z3_mk_re_diff(a.ctx_ref(), a.ast, b.ast), a.ctx)
|
||||
|
||||
def AllChar(regex_sort, ctx=None):
|
||||
|
@ -11690,7 +11704,7 @@ class UserPropagateBase:
|
|||
num_eqs = len(eqs)
|
||||
_lhs, _num_lhs = _to_ast_array([x for x, y in eqs])
|
||||
_rhs, _num_rhs = _to_ast_array([y for x, y in eqs])
|
||||
Z3_solver_propagate_consequence(e.ctx.ref(), ctypes.c_void_p(
|
||||
return Z3_solver_propagate_consequence(e.ctx.ref(), ctypes.c_void_p(
|
||||
self.cb), num_fixed, _ids, num_eqs, _lhs, _rhs, e.ast)
|
||||
|
||||
def conflict(self, deps = [], eqs = []):
|
||||
|
|
|
@ -275,7 +275,7 @@ def prove(claim, assume=None, verbose=0):
|
|||
|
||||
def get_models(f, k):
|
||||
"""
|
||||
Returns the first k models satisfiying f.
|
||||
Returns the first k models satisfying f.
|
||||
If f is not satisfiable, returns False.
|
||||
If f cannot be solved, returns None
|
||||
If f is satisfiable, returns the first k models
|
||||
|
@ -485,7 +485,7 @@ def model_str(m, as_str=True):
|
|||
x = 10, y = 3
|
||||
|
||||
EXAMPLES:
|
||||
see doctest exampels from function prove()
|
||||
see doctest examples from function prove()
|
||||
|
||||
"""
|
||||
if z3_debug():
|
||||
|
|
|
@ -2172,7 +2172,7 @@ extern "C" {
|
|||
\brief Query constructor for declared functions.
|
||||
|
||||
\param c logical context.
|
||||
\param constr constructor container. The container must have been passed in to a #Z3_mk_datatype call.
|
||||
\param constr constructor container. The container must have been passed into a #Z3_mk_datatype call.
|
||||
\param num_fields number of accessor fields in the constructor.
|
||||
\param constructor constructor function declaration, allocated by user.
|
||||
\param tester constructor test function declaration, allocated by user.
|
||||
|
@ -2317,7 +2317,7 @@ extern "C" {
|
|||
\param args constants that are used as arguments to the recursive function in the definition.
|
||||
\param body body of the recursive function
|
||||
|
||||
After declaring a recursive function or a collection of mutually recursive functions, use
|
||||
After declaring a recursive function or a collection of mutually recursive functions, use
|
||||
this function to provide the definition for the recursive function.
|
||||
|
||||
\sa Z3_mk_rec_func_decl
|
||||
|
@ -3614,7 +3614,7 @@ extern "C" {
|
|||
|
||||
/**
|
||||
\brief Retrieve the string constant stored in \c s.
|
||||
Characters outside the basic printiable ASCII range are escaped.
|
||||
Characters outside the basic printable ASCII range are escaped.
|
||||
|
||||
\pre Z3_is_string(c, s)
|
||||
|
||||
|
@ -4897,7 +4897,7 @@ extern "C" {
|
|||
/**
|
||||
\brief Return a hash code for the given AST.
|
||||
The hash code is structural but two different AST objects can map to the same hash.
|
||||
The result of \c Z3_get_ast_id returns an indentifier that is unique over the
|
||||
The result of \c Z3_get_ast_id returns an identifier that is unique over the
|
||||
set of live AST objects.
|
||||
|
||||
def_API('Z3_get_ast_hash', UINT, (_in(CONTEXT), _in(AST)))
|
||||
|
@ -5346,7 +5346,7 @@ extern "C" {
|
|||
Z3_ast const to[]);
|
||||
|
||||
/**
|
||||
\brief Substitute funcions in \c from with new expressions in \c to.
|
||||
\brief Substitute functions in \c from with new expressions in \c to.
|
||||
|
||||
The expressions in \c to can have free variables. The free variable in \c to at index 0
|
||||
refers to the first argument of \c from, the free variable at index 1 corresponds to the second argument.
|
||||
|
@ -7026,13 +7026,13 @@ extern "C" {
|
|||
Z3_on_clause_eh on_clause_eh);
|
||||
|
||||
/**
|
||||
\brief register a user-properator with the solver.
|
||||
\brief register a user-propagator with the solver.
|
||||
|
||||
\param c - context.
|
||||
\param s - solver object.
|
||||
\param user_context - a context used to maintain state for callbacks.
|
||||
\param push_eh - a callback invoked when scopes are pushed
|
||||
\param pop_eh - a callback invoked when scopes are poped
|
||||
\param pop_eh - a callback invoked when scopes are popped
|
||||
\param fresh_eh - a solver may spawn new solvers internally. This callback is used to produce a fresh user_context to be associated with fresh solvers.
|
||||
|
||||
def_API('Z3_solver_propagate_init', VOID, (_in(CONTEXT), _in(SOLVER), _in(VOID_PTR), _fnptr(Z3_push_eh), _fnptr(Z3_pop_eh), _fnptr(Z3_fresh_eh)))
|
||||
|
@ -7147,14 +7147,18 @@ extern "C" {
|
|||
|
||||
/**
|
||||
\brief propagate a consequence based on fixed values.
|
||||
This is a callback a client may invoke during the fixed_eh callback.
|
||||
This is a callback a client may invoke during the fixed_eh callback.
|
||||
The callback adds a propagation consequence based on the fixed values of the
|
||||
\c ids.
|
||||
|
||||
def_API('Z3_solver_propagate_consequence', VOID, (_in(CONTEXT), _in(SOLVER_CALLBACK), _in(UINT), _in_array(2, AST), _in(UINT), _in_array(4, AST), _in_array(4, AST), _in(AST)))
|
||||
\c ids.
|
||||
The solver might discard the propagation in case it is true in the current state.
|
||||
The function returns false in this case; otw. the function returns true.
|
||||
At least one propagation in the final callback has to return true in order to
|
||||
prevent the solver from finishing.
|
||||
|
||||
def_API('Z3_solver_propagate_consequence', BOOL, (_in(CONTEXT), _in(SOLVER_CALLBACK), _in(UINT), _in_array(2, AST), _in(UINT), _in_array(4, AST), _in_array(4, AST), _in(AST)))
|
||||
*/
|
||||
|
||||
void Z3_API Z3_solver_propagate_consequence(Z3_context c, Z3_solver_callback cb, unsigned num_fixed, Z3_ast const* fixed, unsigned num_eqs, Z3_ast const* eq_lhs, Z3_ast const* eq_rhs, Z3_ast conseq);
|
||||
|
||||
bool Z3_API Z3_solver_propagate_consequence(Z3_context c, Z3_solver_callback cb, unsigned num_fixed, Z3_ast const* fixed, unsigned num_eqs, Z3_ast const* eq_lhs, Z3_ast const* eq_rhs, Z3_ast conseq);
|
||||
|
||||
/**
|
||||
\brief Check whether the assertions in a given solver are consistent or not.
|
||||
|
|
|
@ -72,7 +72,7 @@ struct z3_replayer::imp {
|
|||
|
||||
void check_arg(unsigned pos, value_kind k) const {
|
||||
if (pos >= m_args.size()) {
|
||||
TRACE("z3_replayer", tout << "too few arguments " << m_args.size() << " expecting " << kind2string(k) << "\n";);
|
||||
TRACE("z3_replayer", tout << pos << " too few arguments " << m_args.size() << " expecting " << kind2string(k) << "\n";);
|
||||
throw z3_replayer_exception("invalid argument reference");
|
||||
}
|
||||
if (m_args[pos].m_kind != k) {
|
||||
|
|
|
@ -370,7 +370,7 @@ inline func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, bool is_real) {
|
|||
if (is_real) {
|
||||
return m_manager->mk_func_decl(symbol("^0"), m_real_decl, m_real_decl, m_real_decl, func_decl_info(m_family_id, OP_POWER0));
|
||||
}
|
||||
return m_manager->mk_func_decl(symbol("^0"), m_int_decl, m_int_decl, m_int_decl, func_decl_info(m_family_id, OP_POWER0));
|
||||
return m_manager->mk_func_decl(symbol("^0"), m_int_decl, m_int_decl, m_real_decl, func_decl_info(m_family_id, OP_POWER0));
|
||||
case OP_TO_REAL: return m_to_real_decl;
|
||||
case OP_TO_INT: return m_to_int_decl;
|
||||
case OP_IS_INT: return m_is_int_decl;
|
||||
|
@ -834,7 +834,7 @@ bool arith_util::is_considered_uninterpreted(func_decl* f, unsigned n, expr* con
|
|||
func_decl* arith_util::mk_ipower0() {
|
||||
sort* s = mk_int();
|
||||
sort* rs[2] = { s, s };
|
||||
return m_manager.mk_func_decl(arith_family_id, OP_POWER0, 0, nullptr, 2, rs, s);
|
||||
return m_manager.mk_func_decl(arith_family_id, OP_POWER0, 0, nullptr, 2, rs, mk_real());
|
||||
}
|
||||
|
||||
func_decl* arith_util::mk_rpower0() {
|
||||
|
|
|
@ -1378,6 +1378,7 @@ void ast_manager::init() {
|
|||
ENSURE(model_value_family_id == mk_family_id("model-value"));
|
||||
ENSURE(user_sort_family_id == mk_family_id("user-sort"));
|
||||
ENSURE(arith_family_id == mk_family_id("arith"));
|
||||
ENSURE(poly_family_id == mk_family_id("polymorphic"));
|
||||
basic_decl_plugin * plugin = alloc(basic_decl_plugin);
|
||||
register_plugin(basic_family_id, plugin);
|
||||
m_bool_sort = plugin->mk_bool_sort();
|
||||
|
@ -2019,6 +2020,11 @@ sort * ast_manager::mk_uninterpreted_sort(symbol const & name, unsigned num_para
|
|||
return plugin->mk_sort(kind, num_parameters, parameters);
|
||||
}
|
||||
|
||||
sort * ast_manager::mk_type_var(symbol const& name) {
|
||||
sort_info si(poly_family_id, 0);
|
||||
return mk_sort(name, &si);
|
||||
}
|
||||
|
||||
func_decl * ast_manager::mk_func_decl(symbol const & name, unsigned arity, sort * const * domain, sort * range,
|
||||
bool assoc, bool comm, bool inj) {
|
||||
func_decl_info info(null_family_id, null_decl_kind);
|
||||
|
|
|
@ -85,6 +85,7 @@ const family_id user_sort_family_id = 4;
|
|||
const family_id last_builtin_family_id = 4;
|
||||
|
||||
const family_id arith_family_id = 5;
|
||||
const family_id poly_family_id = 6;
|
||||
|
||||
// -----------------------------------
|
||||
//
|
||||
|
@ -622,6 +623,7 @@ public:
|
|||
sort_size const & get_num_elements() const { return get_info()->get_num_elements(); }
|
||||
void set_num_elements(sort_size const& s) { get_info()->set_num_elements(s); }
|
||||
unsigned get_size() const { return get_obj_size(); }
|
||||
bool is_type_var() const { return get_family_id() == poly_family_id; }
|
||||
};
|
||||
|
||||
// -----------------------------------
|
||||
|
@ -1709,6 +1711,8 @@ public:
|
|||
|
||||
sort * mk_uninterpreted_sort(symbol const & name) { return mk_uninterpreted_sort(name, 0, nullptr); }
|
||||
|
||||
sort * mk_type_var(symbol const& name);
|
||||
|
||||
sort * mk_sort(symbol const & name, sort_info const & info) {
|
||||
if (info.get_family_id() == null_family_id) {
|
||||
return mk_uninterpreted_sort(name);
|
||||
|
|
|
@ -651,7 +651,7 @@ func_decl * bv_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p
|
|||
for (unsigned i = 0; i < num_args; ++i) {
|
||||
if (args[i]->get_sort() != r->get_domain(i)) {
|
||||
std::ostringstream buffer;
|
||||
buffer << "Argument " << mk_pp(args[i], m) << " at position " << i << " has sort " << mk_pp(args[i]->get_sort(), m) << " it does does not match declaration " << mk_pp(r, m);
|
||||
buffer << "Argument " << mk_pp(args[i], m) << " at position " << i << " has sort " << mk_pp(args[i]->get_sort(), m) << " it does not match declaration " << mk_pp(r, m);
|
||||
m.raise_exception(buffer.str());
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -96,7 +96,7 @@ enum bv_op_kind {
|
|||
OP_BUMUL_OVFL, // unsigned multiplication overflow predicate (negation of OP_BUMUL_NO_OVFL)
|
||||
OP_BSMUL_OVFL, // signed multiplication over/underflow predicate
|
||||
|
||||
OP_BSDIV_OVFL, // signed division overflow perdicate
|
||||
OP_BSDIV_OVFL, // signed division overflow predicate
|
||||
|
||||
OP_BNEG_OVFL, // negation overflow predicate
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ Module Name:
|
|||
|
||||
Abstract:
|
||||
|
||||
char_plugin for unicode suppport
|
||||
char_plugin for unicode support
|
||||
|
||||
Author:
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ Module Name:
|
|||
|
||||
Abstract:
|
||||
|
||||
char_plugin for unicode suppport
|
||||
char_plugin for unicode support
|
||||
|
||||
Author:
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ public:
|
|||
*
|
||||
* x = t -> fresh
|
||||
* x := if(fresh, t, diff(t))
|
||||
* where diff is a diagnonalization function available in domains of size > 1.
|
||||
* where diff is a diagonalization function available in domains of size > 1.
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -807,7 +807,7 @@ bool iexpr_inverter::uncnstr(unsigned num, expr * const * args) const {
|
|||
|
||||
/**
|
||||
\brief Create a fresh variable for abstracting (f args[0] ... args[num-1])
|
||||
Return true if it a new variable was created, and false if the variable already existed for this
|
||||
Return true if a new variable was created, and false if the variable already existed for this
|
||||
application. Store the variable in v
|
||||
*/
|
||||
void iexpr_inverter::mk_fresh_uncnstr_var_for(sort * s, expr_ref & v) {
|
||||
|
|
|
@ -275,7 +275,7 @@ namespace datatype {
|
|||
}
|
||||
parameter const & name = parameters[0];
|
||||
if (!name.is_symbol()) {
|
||||
TRACE("datatype", tout << "expected symol parameter at position " << 0 << " got: " << name << "\n";);
|
||||
TRACE("datatype", tout << "expected symbol parameter at position " << 0 << " got: " << name << "\n";);
|
||||
throw invalid_datatype();
|
||||
}
|
||||
for (unsigned i = 1; i < num_parameters; ++i) {
|
||||
|
|
|
@ -52,7 +52,7 @@ namespace datatype {
|
|||
class accessor {
|
||||
symbol m_name;
|
||||
sort_ref m_range;
|
||||
unsigned m_index; // reference to recursive data-type may only get resolved after all mutually recursive data-types are procssed.
|
||||
unsigned m_index; // reference to recursive data-type may only get resolved after all mutually recursive data-types are processed.
|
||||
constructor* m_constructor{ nullptr };
|
||||
public:
|
||||
accessor(ast_manager& m, symbol const& n, sort* range):
|
||||
|
|
|
@ -19,7 +19,7 @@ Notes:
|
|||
- data structures form the (legacy) SMT solver.
|
||||
- it still uses eager path compression.
|
||||
|
||||
NB. The worklist is in reality inheritied from the legacy SMT solver.
|
||||
NB. The worklist is in reality inherited from the legacy SMT solver.
|
||||
It is claimed to have the same effect as delayed congruence table reconstruction from egg.
|
||||
Similar to the legacy solver, parents are partially deduplicated.
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ Author:
|
|||
Notes:
|
||||
|
||||
- congruence closure justifications are given a timestamp so it is easy to sort them.
|
||||
See the longer descriptoin in euf_proof_checker.cpp
|
||||
See the longer description in euf_proof_checker.cpp
|
||||
|
||||
--*/
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ bool macro_finder::is_arith_macro(expr * n, proof * pr, bool deps_valid, expr_de
|
|||
// functions introduced within macros are Skolem functions
|
||||
// To avoid unsound expansion of these as macros (because they
|
||||
// appear in model conversions and are therefore not fully
|
||||
// replacable) we prevent these from being treated as macro functions.
|
||||
// replaceable) we prevent these from being treated as macro functions.
|
||||
if (m_macro_manager.contains(f) || f->is_skolem())
|
||||
return false;
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ Revision History:
|
|||
where T[X] does not contain f.
|
||||
|
||||
This class is responsible for storing macros and expanding them.
|
||||
It has support for backtracking and tagging declarations in an expression as forbidded for being macros.
|
||||
It has support for backtracking and tagging declarations in an expression as forbidden for being macros.
|
||||
*/
|
||||
class macro_manager {
|
||||
ast_manager & m;
|
||||
|
|
|
@ -207,7 +207,7 @@ void defined_names::impl::mk_definition(expr * e, app * n, sort_ref_buffer & var
|
|||
// the instantiation rules for store(a, i, v) are:
|
||||
// store(a, i, v)[j] = if i = j then v else a[j] with patterns {a[j], store(a, i, v)} { store(a, i, v)[j] }
|
||||
// The first pattern is not included.
|
||||
// TBD use a model-based scheme for exracting instantiations instead of
|
||||
// TBD use a model-based scheme for extracting instantiations instead of
|
||||
// using multi-patterns.
|
||||
//
|
||||
|
||||
|
|
|
@ -109,6 +109,7 @@ pattern_inference_cfg::pattern_inference_cfg(ast_manager & m, pattern_inference_
|
|||
m_le(),
|
||||
m_nested_arith_only(true),
|
||||
m_block_loop_patterns(params.m_pi_block_loop_patterns),
|
||||
m_decompose_patterns(params.m_pi_decompose_patterns),
|
||||
m_candidates(m),
|
||||
m_pattern_weight_lt(m_candidates_info),
|
||||
m_collect(m, *this),
|
||||
|
@ -407,6 +408,9 @@ bool pattern_inference_cfg::pattern_weight_lt::operator()(expr * n1, expr * n2)
|
|||
|
||||
|
||||
app* pattern_inference_cfg::mk_pattern(app* candidate) {
|
||||
if (!m_decompose_patterns)
|
||||
return m.mk_pattern(candidate);
|
||||
|
||||
auto has_var_arg = [&](expr* e) {
|
||||
if (!is_app(e))
|
||||
return false;
|
||||
|
|
|
@ -20,6 +20,7 @@ Revision History:
|
|||
|
||||
#include "ast/ast.h"
|
||||
#include "ast/rewriter/rewriter.h"
|
||||
#include "ast/rewriter/rewriter_def.h"
|
||||
#include "params/pattern_inference_params.h"
|
||||
#include "util/vector.h"
|
||||
#include "util/uint_set.h"
|
||||
|
@ -69,6 +70,7 @@ class pattern_inference_cfg : public default_rewriter_cfg {
|
|||
expr * const * m_no_patterns;
|
||||
bool m_nested_arith_only;
|
||||
bool m_block_loop_patterns;
|
||||
bool m_decompose_patterns;
|
||||
|
||||
struct info {
|
||||
uint_set m_free_vars;
|
||||
|
|
|
@ -260,7 +260,7 @@ class reduce_hypotheses {
|
|||
{ cls.push_back(cls_fact->get_arg(i)); }
|
||||
} else { cls.push_back(cls_fact); }
|
||||
|
||||
// construct new resovent
|
||||
// construct new resolvent
|
||||
ptr_buffer<expr> new_fact_cls;
|
||||
bool found;
|
||||
// XXX quadratic
|
||||
|
@ -604,7 +604,7 @@ public:
|
|||
// -- otherwise, the fact has not changed. nothing to simplify
|
||||
SASSERT(m.get_fact(tmp) == m.get_fact(m.get_parent(p, i)));
|
||||
parents.push_back(tmp);
|
||||
// remember that we have this derivation while we have not poped the trail
|
||||
// remember that we have this derivation while we have not popped the trail
|
||||
// but only if the proof is closed (i.e., a real unit)
|
||||
if (is_closed(tmp) && !m_units.contains(m.get_fact(tmp))) {
|
||||
m_units.insert(m.get_fact(tmp), tmp);
|
||||
|
|
|
@ -1121,7 +1121,7 @@ bool arith_rewriter::divides(expr* num, expr* den, expr_ref& result) {
|
|||
if (m_util.is_numeral(arg, num_r)) num_e = arg;
|
||||
}
|
||||
for (expr* arg : args2) {
|
||||
// dont remove divisor on (div (* -1 x) (* -1 y)) because rewriting would diverge.
|
||||
// don't remove divisor on (div (* -1 x) (* -1 y)) because rewriting would diverge.
|
||||
if (mark.is_marked(arg) && (!m_util.is_numeral(arg, num_r) || !num_r.is_minus_one())) {
|
||||
result = remove_divisor(arg, num, den);
|
||||
return true;
|
||||
|
@ -1569,21 +1569,48 @@ br_status arith_rewriter::mk_to_real_core(expr * arg, expr_ref & result) {
|
|||
}
|
||||
|
||||
br_status arith_rewriter::mk_is_int(expr * arg, expr_ref & result) {
|
||||
numeral a;
|
||||
if (m_util.is_numeral(arg, a)) {
|
||||
result = a.is_int() ? m.mk_true() : m.mk_false();
|
||||
numeral n;
|
||||
|
||||
if (m_util.is_numeral(arg, n)) {
|
||||
result = n.is_int() ? m.mk_true() : m.mk_false();
|
||||
return BR_DONE;
|
||||
}
|
||||
else if (m_util.is_to_real(arg)) {
|
||||
|
||||
if (m_util.is_to_real(arg)) {
|
||||
result = m.mk_true();
|
||||
return BR_DONE;
|
||||
}
|
||||
else {
|
||||
result = m.mk_eq(m.mk_app(get_fid(), OP_TO_REAL,
|
||||
m.mk_app(get_fid(), OP_TO_INT, arg)),
|
||||
arg);
|
||||
return BR_REWRITE3;
|
||||
|
||||
ptr_buffer<expr> todo;
|
||||
todo.push_back(arg);
|
||||
expr_fast_mark1 mark;
|
||||
for (unsigned i = 0; i < todo.size(); ++i) {
|
||||
expr* e = todo[i];
|
||||
if (mark.is_marked(e))
|
||||
continue;
|
||||
mark.mark(e, true);
|
||||
if (m_util.is_to_real(e))
|
||||
continue;
|
||||
if (m_util.is_numeral(e, n)) {
|
||||
if (n.is_int())
|
||||
continue;
|
||||
goto bail;
|
||||
}
|
||||
if (m_util.is_mul(e) || m_util.is_add(e) || m_util.is_sub(e) || m_util.is_uminus(e)) {
|
||||
for (expr* a : *to_app(e))
|
||||
todo.push_back(a);
|
||||
continue;
|
||||
}
|
||||
goto bail;
|
||||
}
|
||||
result = m.mk_true();
|
||||
return BR_DONE;
|
||||
|
||||
bail:
|
||||
result = m.mk_eq(m.mk_app(get_fid(), OP_TO_REAL,
|
||||
m.mk_app(get_fid(), OP_TO_INT, arg)),
|
||||
arg);
|
||||
return BR_REWRITE3;
|
||||
}
|
||||
|
||||
br_status arith_rewriter::mk_abs_core(expr * arg, expr_ref & result) {
|
||||
|
@ -1592,7 +1619,7 @@ br_status arith_rewriter::mk_abs_core(expr * arg, expr_ref & result) {
|
|||
}
|
||||
|
||||
|
||||
// Return true if t is of the form c*Pi where c is a numeral.
|
||||
// Return true if t is of the form c*Pi where c is a numeral.
|
||||
// Store c into k
|
||||
bool arith_rewriter::is_pi_multiple(expr * t, rational & k) {
|
||||
if (m_util.is_pi(t)) {
|
||||
|
@ -1603,7 +1630,7 @@ bool arith_rewriter::is_pi_multiple(expr * t, rational & k) {
|
|||
return m_util.is_mul(t, a, b) && m_util.is_pi(b) && m_util.is_numeral(a, k);
|
||||
}
|
||||
|
||||
// Return true if t is of the form (+ s c*Pi) where c is a numeral.
|
||||
// Return true if t is of the form (+ s c*Pi) where c is a numeral.
|
||||
// Store c into k, and c*Pi into m.
|
||||
bool arith_rewriter::is_pi_offset(expr * t, rational & k, expr * & m) {
|
||||
if (m_util.is_add(t)) {
|
||||
|
@ -1916,7 +1943,7 @@ br_status arith_rewriter::mk_tan_core(expr * arg, expr_ref & result) {
|
|||
br_status arith_rewriter::mk_asin_core(expr * arg, expr_ref & result) {
|
||||
// Remark: we assume that ForAll x : asin(-x) == asin(x).
|
||||
// Mathematica uses this as an axiom. Although asin is an underspecified function for x < -1 or x > 1.
|
||||
// Actually, in Mathematica, asin(x) is a total function that returns a complex number fo x < -1 or x > 1.
|
||||
// Actually, in Mathematica, asin(x) is a total function that returns a complex number for x < -1 or x > 1.
|
||||
rational k;
|
||||
if (is_numeral(arg, k)) {
|
||||
if (k.is_zero()) {
|
||||
|
|
|
@ -26,6 +26,7 @@ Notes:
|
|||
void bool_rewriter::updt_params(params_ref const & _p) {
|
||||
bool_rewriter_params p(_p);
|
||||
m_flat_and_or = p.flat_and_or();
|
||||
m_sort_disjunctions = p.sort_disjunctions();
|
||||
m_elim_and = p.elim_and();
|
||||
m_elim_ite = p.elim_ite();
|
||||
m_local_ctx = p.local_ctx();
|
||||
|
@ -183,7 +184,7 @@ br_status bool_rewriter::mk_flat_and_core(unsigned num_args, expr * const * args
|
|||
}
|
||||
|
||||
br_status bool_rewriter::mk_nflat_or_core(unsigned num_args, expr * const * args, expr_ref & result) {
|
||||
bool s = false;
|
||||
bool s = false; // whether we have canceled some disjuncts or found some out or order
|
||||
ptr_buffer<expr> buffer;
|
||||
expr_fast_mark1 neg_lits;
|
||||
expr_fast_mark2 pos_lits;
|
||||
|
@ -292,8 +293,10 @@ br_status bool_rewriter::mk_nflat_or_core(unsigned num_args, expr * const * args
|
|||
return st;
|
||||
#endif
|
||||
if (s) {
|
||||
ast_lt lt;
|
||||
std::sort(buffer.begin(), buffer.end(), lt);
|
||||
if (m_sort_disjunctions) {
|
||||
ast_lt lt;
|
||||
std::sort(buffer.begin(), buffer.end(), lt);
|
||||
}
|
||||
result = m().mk_or(sz, buffer.data());
|
||||
return BR_DONE;
|
||||
}
|
||||
|
@ -329,7 +332,7 @@ br_status bool_rewriter::mk_flat_or_core(unsigned num_args, expr * const * args,
|
|||
}
|
||||
}
|
||||
if (mk_nflat_or_core(flat_args.size(), flat_args.data(), result) == BR_FAILED) {
|
||||
if (!ordered) {
|
||||
if (m_sort_disjunctions && !ordered) {
|
||||
ast_lt lt;
|
||||
std::sort(flat_args.begin(), flat_args.end(), lt);
|
||||
}
|
||||
|
@ -662,12 +665,19 @@ br_status bool_rewriter::try_ite_value(app * ite, app * val, expr_ref & result)
|
|||
SASSERT(m().is_value(val));
|
||||
|
||||
if (m().are_distinct(val, e)) {
|
||||
mk_eq(t, val, result);
|
||||
if (get_depth(t) < 500)
|
||||
mk_eq(t, val, result);
|
||||
else
|
||||
result = m().mk_eq(t, val);
|
||||
|
||||
result = m().mk_and(result, cond);
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
if (m().are_distinct(val, t)) {
|
||||
mk_eq(e, val, result);
|
||||
if (get_depth(e) < 500)
|
||||
mk_eq(e, val, result);
|
||||
else
|
||||
result = m().mk_eq(e, val);
|
||||
result = m().mk_and(result, m().mk_not(cond));
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ class bool_rewriter {
|
|||
ast_manager & m_manager;
|
||||
hoist_rewriter m_hoist;
|
||||
bool m_flat_and_or = false;
|
||||
bool m_sort_disjunctions = true;
|
||||
bool m_local_ctx = false;
|
||||
bool m_elim_and = false;
|
||||
bool m_blast_distinct = false;
|
||||
|
|
|
@ -307,7 +307,7 @@ namespace euf {
|
|||
}
|
||||
};
|
||||
SASSERT(e);
|
||||
if (num_scopes() > 0)
|
||||
if (num_scopes() > 0 && m_canonical.size() > n->get_id())
|
||||
m_trail.push(vtrail(m_canonical, n->get_id()));
|
||||
m_canonical.setx(n->get_id(), e);
|
||||
m_epochs.setx(n->get_id(), m_epoch, 0);
|
||||
|
|
|
@ -1394,14 +1394,13 @@ void cmd_context::reset_macros() {
|
|||
}
|
||||
|
||||
void cmd_context::reset_cmds() {
|
||||
for (auto& kv : m_cmds) {
|
||||
kv.m_value->reset(*this);
|
||||
for (auto& [k,v] : m_cmds) {
|
||||
v->reset(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void cmd_context::finalize_cmds() {
|
||||
for (auto& kv : m_cmds) {
|
||||
cmd * c = kv.m_value;
|
||||
for (auto& [k,c] : m_cmds) {
|
||||
c->finalize(*this);
|
||||
dealloc(c);
|
||||
}
|
||||
|
@ -1433,6 +1432,7 @@ void cmd_context::reset(bool finalize) {
|
|||
m_builtin_decls.reset();
|
||||
m_extra_builtin_decls.reset();
|
||||
m_check_logic.reset();
|
||||
m_proof_cmds = nullptr;
|
||||
reset_object_refs();
|
||||
reset_cmds();
|
||||
reset_psort_decls();
|
||||
|
|
|
@ -43,6 +43,7 @@ Proof checker for clauses created during search.
|
|||
#include "util/small_object_allocator.h"
|
||||
#include "ast/ast_util.h"
|
||||
#include "ast/ast_ll_pp.h"
|
||||
#include "ast/arith_decl_plugin.h"
|
||||
#include "smt/smt_solver.h"
|
||||
#include "sat/sat_solver.h"
|
||||
#include "sat/sat_drat.h"
|
||||
|
@ -63,6 +64,7 @@ class proof_trim {
|
|||
vector<expr_ref_vector> m_clauses;
|
||||
bool_vector m_is_infer;
|
||||
symbol m_rup;
|
||||
bool m_empty = false;
|
||||
|
||||
void mk_clause(expr_ref_vector const& clause) {
|
||||
trim.init_clause();
|
||||
|
@ -121,25 +123,32 @@ public:
|
|||
*/
|
||||
|
||||
void infer(expr_ref_vector const& clause, app* hint) {
|
||||
if (m_empty)
|
||||
return;
|
||||
|
||||
if (hint && !is_rup(hint) && m_checker.check(hint)) {
|
||||
auto clause1 = m_checker.clause(hint);
|
||||
if (clause1.size() != clause.size()) {
|
||||
mk_clause(clause1);
|
||||
trim.assume(m_clauses.size());
|
||||
clause1.push_back(hint);
|
||||
trim.assume(m_clauses.size());
|
||||
m_clauses.push_back(clause1);
|
||||
m_is_infer.push_back(true);
|
||||
mk_clause(clause);
|
||||
trim.infer(m_clauses.size());
|
||||
m_clauses.push_back(clause);
|
||||
m_clauses.back().push_back(hint);
|
||||
m_is_infer.push_back(true);
|
||||
if (clause.empty())
|
||||
|
||||
if (clause.empty()) {
|
||||
mk_clause(clause);
|
||||
trim.infer(m_clauses.size());
|
||||
m_clauses.push_back(clause);
|
||||
m_clauses.back().push_back(hint);
|
||||
m_is_infer.push_back(true);
|
||||
m_empty = true;
|
||||
do_trim(std::cout);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
mk_clause(clause);
|
||||
if (is_rup(hint))
|
||||
trim.infer(m_clauses.size());
|
||||
|
@ -149,20 +158,32 @@ public:
|
|||
if (hint)
|
||||
m_clauses.back().push_back(hint);
|
||||
m_is_infer.push_back(true);
|
||||
if (clause.empty())
|
||||
if (clause.empty()) {
|
||||
m_empty = true;
|
||||
do_trim(std::cout);
|
||||
}
|
||||
}
|
||||
|
||||
void updt_params(params_ref const& p) {
|
||||
trim.updt_params(p);
|
||||
}
|
||||
|
||||
expr_ref mk_dep(unsigned id, unsigned_vector const& deps) {
|
||||
arith_util a(m);
|
||||
expr_ref_vector args(m);
|
||||
args.push_back(a.mk_int(id));
|
||||
for (auto d : deps)
|
||||
args.push_back(a.mk_int(d));
|
||||
return expr_ref(m.mk_app(symbol("deps"), args.size(), args.data(), m.mk_proof_sort()), m);
|
||||
}
|
||||
|
||||
void do_trim(std::ostream& out) {
|
||||
ast_pp_util pp(m);
|
||||
auto ids = trim.trim();
|
||||
for (unsigned id : ids) {
|
||||
auto const& clause = m_clauses[id];
|
||||
for (auto const& [id, deps] : ids) {
|
||||
auto& clause = m_clauses[id];
|
||||
bool is_infer = m_is_infer[id];
|
||||
clause.push_back(mk_dep(id, deps));
|
||||
for (expr* e : clause)
|
||||
pp.collect(e);
|
||||
|
||||
|
@ -258,8 +279,12 @@ public:
|
|||
}
|
||||
|
||||
void add_literal(expr* e) override {
|
||||
if (m.is_proof(e))
|
||||
m_proof_hint = to_app(e);
|
||||
if (m.is_proof(e)) {
|
||||
if (!m_proof_hint)
|
||||
m_proof_hint = to_app(e);
|
||||
}
|
||||
else if (!m.is_bool(e))
|
||||
throw default_exception("literal should be either a Proof or Bool");
|
||||
else
|
||||
m_lits.push_back(e);
|
||||
}
|
||||
|
|
|
@ -348,6 +348,26 @@ std::ostream& psort_user_decl::display(std::ostream & out) const {
|
|||
return out << ")";
|
||||
}
|
||||
|
||||
// -------------------
|
||||
// psort_type_var_decl
|
||||
|
||||
psort_type_var_decl::psort_type_var_decl(unsigned id, pdecl_manager & m, symbol const & n):
|
||||
psort_decl(id, 0, m, n) {
|
||||
m_psort_kind = PSORT_TV;
|
||||
}
|
||||
|
||||
void psort_type_var_decl::finalize(pdecl_manager & m) {
|
||||
psort_decl::finalize(m);
|
||||
}
|
||||
|
||||
sort * psort_type_var_decl::instantiate(pdecl_manager & m, unsigned n, sort * const * s) {
|
||||
return m.m().mk_type_var(m_name);
|
||||
}
|
||||
|
||||
std::ostream& psort_type_var_decl::display(std::ostream & out) const {
|
||||
return out << "(declare-type-var " << m_name << ")";
|
||||
}
|
||||
|
||||
// -------------------
|
||||
// psort_dt_decl
|
||||
|
||||
|
@ -969,6 +989,10 @@ psort_decl * pdecl_manager::mk_psort_dt_decl(unsigned num_params, symbol const &
|
|||
return new (a().allocate(sizeof(psort_dt_decl))) psort_dt_decl(m_id_gen.mk(), num_params, *this, n);
|
||||
}
|
||||
|
||||
psort_decl * pdecl_manager::mk_psort_type_var_decl(symbol const & n) {
|
||||
return new (a().allocate(sizeof(psort_type_var_decl))) psort_type_var_decl(m_id_gen.mk(), *this, n);
|
||||
}
|
||||
|
||||
|
||||
psort_decl * pdecl_manager::mk_psort_builtin_decl(symbol const & n, family_id fid, decl_kind k) {
|
||||
return new (a().allocate(sizeof(psort_builtin_decl))) psort_builtin_decl(m_id_gen.mk(), *this, n, fid, k);
|
||||
|
|
|
@ -62,7 +62,7 @@ class psort_inst_cache;
|
|||
*/
|
||||
class psort : public pdecl {
|
||||
protected:
|
||||
psort_inst_cache * m_inst_cache;
|
||||
psort_inst_cache* m_inst_cache;
|
||||
friend class pdecl_manager;
|
||||
psort(unsigned id, unsigned num_params):pdecl(id, num_params), m_inst_cache(nullptr) {}
|
||||
bool is_psort() const override { return true; }
|
||||
|
@ -86,7 +86,7 @@ typedef ptr_hashtable<psort, psort_hash_proc, psort_eq_proc> psort_table;
|
|||
|
||||
#define PSORT_DECL_VAR_PARAMS UINT_MAX
|
||||
|
||||
typedef enum { PSORT_BASE = 0, PSORT_USER, PSORT_BUILTIN, PSORT_DT } psort_decl_kind;
|
||||
typedef enum { PSORT_BASE = 0, PSORT_USER, PSORT_BUILTIN, PSORT_DT, PSORT_TV } psort_decl_kind;
|
||||
|
||||
class psort_decl : public pdecl {
|
||||
protected:
|
||||
|
@ -123,7 +123,19 @@ public:
|
|||
sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s) override;
|
||||
std::ostream& display(std::ostream & out) const override;
|
||||
};
|
||||
|
||||
|
||||
class psort_type_var_decl : public psort_decl {
|
||||
protected:
|
||||
friend class pdecl_manager;
|
||||
psort * m_def;
|
||||
psort_type_var_decl(unsigned id, pdecl_manager & m, symbol const & n);
|
||||
size_t obj_size() const override { return sizeof(psort_type_var_decl); }
|
||||
void finalize(pdecl_manager & m) override;
|
||||
public:
|
||||
sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s) override;
|
||||
std::ostream& display(std::ostream & out) const override;
|
||||
};
|
||||
|
||||
class psort_builtin_decl : public psort_decl {
|
||||
protected:
|
||||
friend class pdecl_manager;
|
||||
|
@ -304,6 +316,7 @@ public:
|
|||
psort_decl * mk_psort_dt_decl(unsigned num_params, symbol const & n);
|
||||
psort_decl * mk_psort_user_decl(unsigned num_params, symbol const & n, psort * def);
|
||||
psort_decl * mk_psort_builtin_decl(symbol const & n, family_id fid, decl_kind k);
|
||||
psort_decl * mk_psort_type_var_decl(symbol const& n);
|
||||
paccessor_decl * mk_paccessor_decl(unsigned num_params, symbol const & s, ptype const & p);
|
||||
pconstructor_decl * mk_pconstructor_decl(unsigned num_params, symbol const & s, symbol const & r, unsigned num, paccessor_decl * const * as);
|
||||
pdatatype_decl * mk_pdatatype_decl(unsigned num_params, symbol const & s, unsigned num, pconstructor_decl * const * cs);
|
||||
|
|
4
src/math/lp/.clang-format
Normal file
4
src/math/lp/.clang-format
Normal file
|
@ -0,0 +1,4 @@
|
|||
BasedOnStyle: Google
|
||||
IndentWidth: 4
|
||||
ColumnLimit: 0
|
||||
NamespaceIndentation: All
|
|
@ -19,6 +19,7 @@ Revision History:
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#pragma once
|
||||
|
||||
#include "util/vector.h"
|
||||
|
|
|
@ -17,6 +17,7 @@ Revision History:
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
|
||||
#pragma once
|
||||
#include "util/vector.h"
|
||||
|
|
|
@ -18,6 +18,7 @@ Revision History:
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#include <string>
|
||||
#include "math/lp/static_matrix.h"
|
||||
namespace lp {
|
||||
|
|
|
@ -17,6 +17,7 @@ Revision History:
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#include "math/lp/numeric_pair.h"
|
||||
#include "math/lp/core_solver_pretty_printer_def.h"
|
||||
template lp::core_solver_pretty_printer<lp::mpq, lp::mpq>::core_solver_pretty_printer(const lp::lp_core_solver_base<lp::mpq, lp::mpq> &, std::ostream & out);
|
||||
|
|
|
@ -17,6 +17,7 @@ Revision History:
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#pragma once
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
|
|
@ -17,6 +17,7 @@ Revision History:
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#pragma once
|
||||
|
||||
#include <limits>
|
||||
|
@ -279,9 +280,9 @@ template <typename T, typename X> void core_solver_pretty_printer<T, X>::print()
|
|||
print_row(i);
|
||||
}
|
||||
m_out << std::endl;
|
||||
if (m_core_solver.inf_set().size()) {
|
||||
if (m_core_solver.inf_heap().size()) {
|
||||
m_out << "inf columns: ";
|
||||
print_vector(m_core_solver.inf_set(), m_out);
|
||||
print_vector(m_core_solver.inf_heap(), m_out);
|
||||
m_out << std::endl;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include "math/lp/nex.h"
|
||||
|
|
|
@ -17,6 +17,7 @@ Revision History:
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#include "math/lp/lp_settings.h"
|
||||
#include "math/lp/dense_matrix_def.h"
|
||||
#ifdef Z3DEBUG
|
||||
|
|
|
@ -17,6 +17,7 @@ Revision History:
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#pragma once
|
||||
#ifdef Z3DEBUG
|
||||
#include "util/vector.h"
|
||||
|
|
|
@ -17,6 +17,7 @@ Revision History:
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#pragma once
|
||||
|
||||
#include "math/lp/lp_settings.h"
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
replaced rooted_mons.h and rooted_mon, rooted_mon_tabled
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
|
||||
#include "math/lp/emonics.h"
|
||||
#include "math/lp/nla_defs.h"
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
to replace rooted_mons.h and rooted_mon, rooted_mon_tabled
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
|
||||
#pragma once
|
||||
#include "math/lp/lp_utils.h"
|
||||
|
|
|
@ -17,6 +17,7 @@ Revision History:
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#pragma once
|
||||
#include "math/lp/lp_utils.h"
|
||||
#include "util/map.h"
|
||||
|
@ -48,6 +49,15 @@ public:
|
|||
SASSERT(m_vector.empty());
|
||||
m_set.insert(j);
|
||||
}
|
||||
|
||||
void remove(constraint_index j) {
|
||||
m_set.remove(j);
|
||||
unsigned i = 0;
|
||||
for (auto& p : m_vector)
|
||||
if (p.first != j)
|
||||
m_vector[i++] = p;
|
||||
m_vector.shrink(i);
|
||||
}
|
||||
|
||||
void add_expl(const explanation& e) {
|
||||
if (e.m_vector.empty()) {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#pragma once
|
||||
#include "util/rational.h"
|
||||
#include "math/lp/monic.h"
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#include "math/lp/factorization_factory_imp.h"
|
||||
#include "math/lp/nla_core.h"
|
||||
namespace nla {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#pragma once
|
||||
#include "math/lp/factorization.h"
|
||||
namespace nla {
|
||||
|
|
|
@ -17,6 +17,7 @@ Revision History:
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#pragma once
|
||||
#include <functional>
|
||||
namespace lp {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#include "math/lp/gomory.h"
|
||||
#include "math/lp/int_solver.h"
|
||||
#include "math/lp/lar_solver.h"
|
||||
|
|
|
@ -15,6 +15,7 @@ Author:
|
|||
|
||||
Revision History:
|
||||
--*/
|
||||
// clang-format off
|
||||
#pragma once
|
||||
#include "math/lp/lar_term.h"
|
||||
#include "math/lp/lia_move.h"
|
||||
|
|
|
@ -26,6 +26,7 @@ Revision History:
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#pragma once
|
||||
#include "math/lp/numeric_pair.h"
|
||||
#include "util/ext_gcd.h"
|
||||
|
|
|
@ -9,6 +9,7 @@ Author:
|
|||
Lev Nachmanson (levnach)
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#include "math/lp/int_solver.h"
|
||||
#include "math/lp/lar_solver.h"
|
||||
#include "math/lp/hnf_cutter.h"
|
||||
|
|
|
@ -14,6 +14,7 @@ Author:
|
|||
Lev Nachmanson (levnach)
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
|
||||
#pragma once
|
||||
#include "math/lp/lar_term.h"
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
|
||||
#include "math/lp/horner.h"
|
||||
#include "math/lp/nla_core.h"
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#pragma once
|
||||
|
||||
#include "math/lp/nla_common.h"
|
||||
|
|
|
@ -17,6 +17,7 @@ Revision History:
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#pragma once
|
||||
#include "math/lp/lp_settings.h"
|
||||
#include "math/lp/lar_constraints.h"
|
||||
|
|
|
@ -17,6 +17,7 @@ Revision History:
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
|
||||
#pragma once
|
||||
#include "util/vector.h"
|
||||
|
|
|
@ -17,6 +17,7 @@ Revision History:
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#pragma once
|
||||
|
||||
namespace lp {
|
||||
|
|
|
@ -17,6 +17,7 @@ Revision History:
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#include "util/vector.h"
|
||||
#include "math/lp/indexed_vector_def.h"
|
||||
namespace lp {
|
||||
|
|
|
@ -17,6 +17,7 @@ Revision History:
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
|
||||
#pragma once
|
||||
#include "util/vector.h"
|
||||
|
|
|
@ -17,6 +17,7 @@ Revision History:
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#pragma once
|
||||
|
||||
#include "util/vector.h"
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
Revision History:
|
||||
--*/
|
||||
|
||||
// clang-format off
|
||||
#include "math/lp/int_solver.h"
|
||||
#include "math/lp/lar_solver.h"
|
||||
#include "math/lp/int_branch.h"
|
||||
|
@ -63,7 +63,7 @@ int int_branch::find_inf_int_base_column() {
|
|||
mpq small_value(1024);
|
||||
unsigned n = 0;
|
||||
lar_core_solver & lcs = lra.m_mpq_lar_core_solver;
|
||||
unsigned prev_usage = 0; // to quiet down the compile
|
||||
unsigned prev_usage = 0; // to quiet down the compiler
|
||||
unsigned k = 0;
|
||||
unsigned usage;
|
||||
unsigned j;
|
||||
|
|
|
@ -15,6 +15,7 @@ Author:
|
|||
|
||||
Revision History:
|
||||
--*/
|
||||
// clang-format off
|
||||
#pragma once
|
||||
|
||||
#include "math/lp/lar_solver.h"
|
||||
|
|
|
@ -15,6 +15,7 @@ Author:
|
|||
|
||||
Revision History:
|
||||
--*/
|
||||
// clang-format off
|
||||
|
||||
#include "math/lp/int_solver.h"
|
||||
#include "math/lp/lar_solver.h"
|
||||
|
|
|
@ -19,6 +19,7 @@ Author:
|
|||
|
||||
Revision History:
|
||||
--*/
|
||||
// clang-format off
|
||||
#pragma once
|
||||
|
||||
#include "math/lp/lia_move.h"
|
||||
|
|
|
@ -45,6 +45,7 @@ Accumulative:
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
|
||||
#include "math/lp/int_solver.h"
|
||||
#include "math/lp/lar_solver.h"
|
||||
|
|
|
@ -24,6 +24,7 @@ Author:
|
|||
|
||||
Revision History:
|
||||
--*/
|
||||
// clang-format off
|
||||
#pragma once
|
||||
|
||||
#include "math/lp/lia_move.h"
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
Copyright (c) 2017 Microsoft Corporation
|
||||
Author: Lev Nachmanson
|
||||
*/
|
||||
|
||||
#include <utility>
|
||||
// clang-format off
|
||||
#include "math/lp/int_solver.h"
|
||||
#include "math/lp/lar_solver.h"
|
||||
#include "math/lp/lp_utils.h"
|
||||
|
@ -14,56 +13,204 @@
|
|||
|
||||
namespace lp {
|
||||
|
||||
int_solver::patcher::patcher(int_solver& lia):
|
||||
lia(lia),
|
||||
lra(lia.lra),
|
||||
lrac(lia.lrac),
|
||||
m_num_nbasic_patches(0),
|
||||
m_patch_cost(0),
|
||||
m_next_patch(0),
|
||||
m_delay(0)
|
||||
{}
|
||||
int_solver::patcher::patcher(int_solver& lia):
|
||||
lia(lia),
|
||||
lra(lia.lra),
|
||||
lrac(lia.lrac)
|
||||
{}
|
||||
|
||||
void int_solver::patcher::remove_fixed_vars_from_base() {
|
||||
unsigned num = lra.A_r().column_count();
|
||||
for (unsigned v = 0; v < num; v++) {
|
||||
if (!lia.is_base(v) || !lia.is_fixed(v))
|
||||
continue;
|
||||
auto const & r = lra.basic2row(v);
|
||||
for (auto const& c : r) {
|
||||
if (c.var() != v && !lia.is_fixed(c.var())) {
|
||||
lra.pivot(c.var(), v);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsigned int_solver::patcher::count_non_int() {
|
||||
unsigned non_int = 0;
|
||||
for (auto j : lra.r_basis())
|
||||
if (lra.column_is_int(j) && !lra.column_value_is_int(j))
|
||||
++non_int;
|
||||
return non_int;
|
||||
}
|
||||
|
||||
lia_move int_solver::patcher::patch_basic_columns() {
|
||||
remove_fixed_vars_from_base();
|
||||
lia.settings().stats().m_patches++;
|
||||
lp_assert(lia.is_feasible());
|
||||
|
||||
// unsigned non_int_before, non_int_after;
|
||||
|
||||
// non_int_before = count_non_int();
|
||||
|
||||
|
||||
// unsigned num = lra.A_r().column_count();
|
||||
for (unsigned j : lra.r_basis())
|
||||
if (!lra.get_value(j).is_int())
|
||||
patch_basic_column(j);
|
||||
// non_int_after = count_non_int();
|
||||
// verbose_stream() << non_int_before << " -> " << non_int_after << "\n";
|
||||
|
||||
if (!lia.has_inf_int()) {
|
||||
lia.settings().stats().m_patches_success++;
|
||||
return lia_move::sat;
|
||||
}
|
||||
return lia_move::undef;
|
||||
}
|
||||
|
||||
// clang-format on
|
||||
/**
|
||||
* \brief find integral and minimal, in the absolute values, deltas such that x - alpha*delta is integral too.
|
||||
*/
|
||||
bool get_patching_deltas(const rational& x, const rational& alpha,
|
||||
rational& delta_plus, rational& delta_minus) {
|
||||
auto a1 = numerator(alpha);
|
||||
auto a2 = denominator(alpha);
|
||||
auto x1 = numerator(x);
|
||||
auto x2 = denominator(x);
|
||||
if (!divides(x2, a2))
|
||||
return false;
|
||||
|
||||
// delta has to be integral.
|
||||
// We need to find delta such that x1/x2 + (a1/a2)*delta is integral (we are going to flip the delta sign later).
|
||||
// Then a2*x1/x2 + a1*delta is integral, but x2 and x1 are coprime:
|
||||
// that means that t = a2/x2 is
|
||||
// integral. We established that a2 = x2*t Then x1 + a1*delta*(x2/a2) = x1
|
||||
// + a1*(delta/t) is integral. Taking into account that t and a1 are
|
||||
// coprime we have delta = t*k, where k is an integer.
|
||||
rational t = a2 / x2;
|
||||
// std::cout << "t = " << t << std::endl;
|
||||
// Now we have x1/x2 + (a1/x2)*k is integral, or (x1 + a1*k)/x2 is integral.
|
||||
// It is equivalent to x1 + a1*k = x2*m, where m is an integer
|
||||
// We know that a2 and a1 are coprime, and x2 divides a2, so x2 and a1 are
|
||||
// coprime. We can find u and v such that u*a1 + v*x2 = 1.
|
||||
rational u, v;
|
||||
gcd(a1, x2, u, v);
|
||||
lp_assert(gcd(a1, x2, u, v).is_one());
|
||||
// std::cout << "u = " << u << ", v = " << v << std::endl;
|
||||
// std::cout << "x= " << (x1 / x2) << std::endl;
|
||||
// std::cout << "x + (a1 / a2) * (-u * t) * x1 = "
|
||||
// << x + (a1 / a2) * (-u * t) * x1 << std::endl;
|
||||
lp_assert((x + (a1 / a2) * (-u * t) * x1).is_int());
|
||||
// 1 = (u- l*x2 ) * a1 + (v + l*a1)*x2, for every integer l.
|
||||
rational d = u * t * x1;
|
||||
// We can prove that x+alpha*d is integral,
|
||||
// and any other delta, satisfying x+alpha*delta, is equal to d modulo a2.
|
||||
delta_plus = mod(d, a2);
|
||||
lp_assert(delta_plus > 0);
|
||||
delta_minus = delta_plus - a2;
|
||||
lp_assert(delta_minus < 0);
|
||||
|
||||
bool int_solver::patcher::should_apply() {
|
||||
#if 1
|
||||
return true;
|
||||
#else
|
||||
if (m_delay == 0) {
|
||||
return true;
|
||||
}
|
||||
--m_delay;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
/**
|
||||
* \brief try to patch the basic column v
|
||||
*/
|
||||
bool int_solver::patcher::patch_basic_column_on_row_cell(unsigned v, row_cell<mpq> const& c) {
|
||||
if (v == c.var())
|
||||
return false;
|
||||
if (!lra.column_is_int(c.var())) // could use real to patch integer
|
||||
return false;
|
||||
if (c.coeff().is_int())
|
||||
return false;
|
||||
mpq a = fractional_part(c.coeff());
|
||||
mpq r = fractional_part(lra.get_value(v));
|
||||
lp_assert(0 < r && r < 1);
|
||||
lp_assert(0 < a && a < 1);
|
||||
mpq delta_plus, delta_minus;
|
||||
if (!get_patching_deltas(r, a, delta_plus, delta_minus))
|
||||
return false;
|
||||
|
||||
lia_move int_solver::patcher::operator()() {
|
||||
return patch_nbasic_columns();
|
||||
}
|
||||
if (lia.random() % 2) {
|
||||
return try_patch_column(v, c.var(), delta_plus) ||
|
||||
try_patch_column(v, c.var(), delta_minus);
|
||||
} else {
|
||||
return try_patch_column(v, c.var(), delta_minus) ||
|
||||
try_patch_column(v, c.var(), delta_plus);
|
||||
}
|
||||
}
|
||||
// clang-format off
|
||||
|
||||
bool int_solver::patcher::try_patch_column(unsigned v, unsigned j, mpq const& delta) {
|
||||
const auto & A = lra.A_r();
|
||||
if (delta < 0) {
|
||||
if (lia.has_lower(j) && lia.get_value(j) + impq(delta) < lra.get_lower_bound(j))
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
if (lia.has_upper(j) && lia.get_value(j) + impq(delta) > lra.get_upper_bound(j))
|
||||
return false;
|
||||
}
|
||||
for (auto const& c : A.column(j)) {
|
||||
unsigned row_index = c.var();
|
||||
unsigned i = lrac.m_r_basis[row_index];
|
||||
auto old_val = lia.get_value(i);
|
||||
auto new_val = old_val - impq(c.coeff()*delta);
|
||||
if (lia.has_lower(i) && new_val < lra.get_lower_bound(i))
|
||||
return false;
|
||||
if (lia.has_upper(i) && new_val > lra.get_upper_bound(i))
|
||||
return false;
|
||||
if (old_val.is_int() && !new_val.is_int()){
|
||||
return false; // do not waste resources on this case
|
||||
}
|
||||
lp_assert(i != v || new_val.is_int())
|
||||
}
|
||||
|
||||
lra.set_value_for_nbasic_column(j, lia.get_value(j) + impq(delta));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void int_solver::patcher::patch_basic_column(unsigned v) {
|
||||
SASSERT(!lia.is_fixed(v));
|
||||
for (auto const& c : lra.basic2row(v))
|
||||
if (patch_basic_column_on_row_cell(v, c))
|
||||
return;
|
||||
}
|
||||
|
||||
lia_move int_solver::patcher::patch_nbasic_columns() {
|
||||
lia.settings().stats().m_patches++;
|
||||
lp_assert(lia.is_feasible());
|
||||
m_num_nbasic_patches = 0;
|
||||
m_patch_cost = 0;
|
||||
for (unsigned j : lia.lrac.m_r_nbasis) {
|
||||
patch_nbasic_column(j);
|
||||
lia_move int_solver::patcher::patch_nbasic_columns() {
|
||||
remove_fixed_vars_from_base();
|
||||
lia.settings().stats().m_patches++;
|
||||
lp_assert(lia.is_feasible());
|
||||
m_patch_success = 0;
|
||||
m_patch_fail = 0;
|
||||
m_num_ones = 0;
|
||||
m_num_divides = 0;
|
||||
//unsigned non_int_before = count_non_int();
|
||||
|
||||
unsigned num = lra.A_r().column_count();
|
||||
for (unsigned v = 0; v < num; v++) {
|
||||
if (lia.is_base(v))
|
||||
continue;
|
||||
patch_nbasic_column(v);
|
||||
}
|
||||
unsigned num_fixed = 0;
|
||||
for (unsigned v = 0; v < num; v++)
|
||||
if (lia.is_fixed(v))
|
||||
++num_fixed;
|
||||
|
||||
lp_assert(lia.is_feasible());
|
||||
//verbose_stream() << "patch " << m_patch_success << " fails " << m_patch_fail << " ones " << m_num_ones << " divides " << m_num_divides << " num fixed " << num_fixed << "\n";
|
||||
//lra.display(verbose_stream());
|
||||
//exit(0);
|
||||
//unsigned non_int_after = count_non_int();
|
||||
|
||||
// verbose_stream() << non_int_before << " -> " << non_int_after << "\n";
|
||||
if (!lia.has_inf_int()) {
|
||||
lia.settings().stats().m_patches_success++;
|
||||
return lia_move::sat;
|
||||
}
|
||||
return lia_move::undef;
|
||||
}
|
||||
lp_assert(lia.is_feasible());
|
||||
if (!lia.has_inf_int()) {
|
||||
lia.settings().stats().m_patches_success++;
|
||||
m_delay = 0;
|
||||
m_next_patch = 0;
|
||||
return lia_move::sat;
|
||||
}
|
||||
if (m_patch_cost > 0 && m_num_nbasic_patches * 10 < m_patch_cost) {
|
||||
m_delay = std::min(20u, m_next_patch++);
|
||||
}
|
||||
else {
|
||||
m_delay = 0;
|
||||
m_next_patch = 0;
|
||||
}
|
||||
return lia_move::undef;
|
||||
}
|
||||
|
||||
void int_solver::patcher::patch_nbasic_column(unsigned j) {
|
||||
impq & val = lrac.m_r_x[j];
|
||||
|
@ -71,17 +218,48 @@ void int_solver::patcher::patch_nbasic_column(unsigned j) {
|
|||
impq l, u;
|
||||
mpq m;
|
||||
bool has_free = lia.get_freedom_interval_for_column(j, inf_l, l, inf_u, u, m);
|
||||
m_patch_cost += lra.A_r().number_of_non_zeroes_in_column(j);
|
||||
if (!has_free) {
|
||||
if (!has_free)
|
||||
return;
|
||||
}
|
||||
bool m_is_one = m.is_one();
|
||||
bool val_is_int = lia.value_is_int(j);
|
||||
|
||||
#if 0
|
||||
const auto & A = lra.A_r();
|
||||
#endif
|
||||
// check whether value of j is already a multiple of m.
|
||||
if (val_is_int && (m_is_one || (val.x / m).is_int())) {
|
||||
if (m_is_one)
|
||||
++m_num_ones;
|
||||
else
|
||||
++m_num_divides;
|
||||
#if 0
|
||||
for (auto c : A.column(j)) {
|
||||
unsigned row_index = c.var();
|
||||
unsigned i = lrac.m_r_basis[row_index];
|
||||
if (!lia.get_value(i).is_int() ||
|
||||
(lia.has_lower(i) && lia.get_value(i) < lra.get_lower_bound(i)) ||
|
||||
(lia.has_upper(i) && lia.get_value(i) > lra.get_upper_bound(i))) {
|
||||
verbose_stream() << "skip " << j << " " << m << ": ";
|
||||
lia.display_row(verbose_stream(), A.m_rows[row_index]);
|
||||
verbose_stream() << "\n";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (!m_is_one) {
|
||||
// lia.display_column(verbose_stream(), j);
|
||||
for (auto c : A.column(j)) {
|
||||
continue;
|
||||
unsigned row_index = c.var();
|
||||
lia.display_row(verbose_stream(), A.m_rows[row_index]);
|
||||
verbose_stream() << "\n";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TRACE("patch_int",
|
||||
tout << "TARGET j" << j << " -> [";
|
||||
if (inf_l) tout << "-oo"; else tout << l;
|
||||
|
@ -89,9 +267,33 @@ void int_solver::patcher::patch_nbasic_column(unsigned j) {
|
|||
if (inf_u) tout << "oo"; else tout << u;
|
||||
tout << "]";
|
||||
tout << ", m: " << m << ", val: " << val << ", is_int: " << lra.column_is_int(j) << "\n";);
|
||||
|
||||
#if 0
|
||||
verbose_stream() << "path " << m << " ";
|
||||
if (!inf_l) verbose_stream() << "infl " << l.x << " ";
|
||||
if (!inf_u) verbose_stream() << "infu " << u.x << " ";
|
||||
verbose_stream() << "\n";
|
||||
if (m.is_big() || (!inf_l && l.x.is_big()) || (!inf_u && u.x.is_big())) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
verbose_stream() << "TARGET v" << j << " -> [";
|
||||
if (inf_l) verbose_stream() << "-oo"; else verbose_stream() << ceil(l.x) << " " << l << "\n";
|
||||
verbose_stream() << ", ";
|
||||
if (inf_u) verbose_stream() << "oo"; else verbose_stream() << floor(u.x) << " " << u << "\n";
|
||||
verbose_stream() << "]";
|
||||
verbose_stream() << ", m: " << m << ", val: " << val << ", is_int: " << lra.column_is_int(j) << "\n";
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
if (!inf_l)
|
||||
l = impq(ceil(l));
|
||||
if (!inf_u)
|
||||
u = impq(floor(u));
|
||||
#endif
|
||||
|
||||
if (!inf_l) {
|
||||
l = impq(m_is_one ? ceil(l) : m * ceil(l / m));
|
||||
if (inf_u || l <= u) {
|
||||
|
@ -99,8 +301,23 @@ void int_solver::patcher::patch_nbasic_column(unsigned j) {
|
|||
lra.set_value_for_nbasic_column(j, l);
|
||||
}
|
||||
else {
|
||||
--m_num_nbasic_patches;
|
||||
//verbose_stream() << "fail: " << j << " " << m << "\n";
|
||||
++m_patch_fail;
|
||||
TRACE("patch_int", tout << "not patching " << l << "\n";);
|
||||
#if 0
|
||||
verbose_stream() << "not patched\n";
|
||||
for (auto c : A.column(j)) {
|
||||
unsigned row_index = c.var();
|
||||
unsigned i = lrac.m_r_basis[row_index];
|
||||
if (!lia.get_value(i).is_int() ||
|
||||
(lia.has_lower(i) && lia.get_value(i) < lra.get_lower_bound(i)) ||
|
||||
(lia.has_upper(i) && lia.get_value(i) > lra.get_upper_bound(i))) {
|
||||
lia.display_row(verbose_stream(), A.m_rows[row_index]);
|
||||
verbose_stream() << "\n";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (!inf_u) {
|
||||
|
@ -112,7 +329,21 @@ void int_solver::patcher::patch_nbasic_column(unsigned j) {
|
|||
lra.set_value_for_nbasic_column(j, impq(0));
|
||||
TRACE("patch_int", tout << "patching with 0\n";);
|
||||
}
|
||||
++m_num_nbasic_patches;
|
||||
++m_patch_success;
|
||||
#if 0
|
||||
verbose_stream() << "patched " << j << "\n";
|
||||
for (auto c : A.column(j)) {
|
||||
unsigned row_index = c.var();
|
||||
unsigned i = lrac.m_r_basis[row_index];
|
||||
if (!lia.get_value(i).is_int() ||
|
||||
(lia.has_lower(i) && lia.get_value(i) < lra.get_lower_bound(i)) ||
|
||||
(lia.has_upper(i) && lia.get_value(i) > lra.get_upper_bound(i))) {
|
||||
lia.display_row(verbose_stream(), A.m_rows[row_index]);
|
||||
verbose_stream() << "\n";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
int_solver::int_solver(lar_solver& lar_slv) :
|
||||
|
@ -326,7 +557,7 @@ static void set_upper(impq & u, bool & inf_u, impq const & v) {
|
|||
|
||||
// this function assumes that all basic columns dependend on j are feasible
|
||||
bool int_solver::get_freedom_interval_for_column(unsigned j, bool & inf_l, impq & l, bool & inf_u, impq & u, mpq & m) {
|
||||
if (lrac.m_r_heading[j] >= 0) // the basic var
|
||||
if (lrac.m_r_heading[j] >= 0 || is_fixed(j)) // basic or fixed var
|
||||
return false;
|
||||
|
||||
TRACE("random_update", display_column(tout, j) << ", is_int = " << column_is_int(j) << "\n";);
|
||||
|
@ -361,10 +592,9 @@ bool int_solver::get_freedom_interval_for_column(unsigned j, bool & inf_l, impq
|
|||
unsigned i = lrac.m_r_basis[row_index];
|
||||
impq const & xi = get_value(i);
|
||||
lp_assert(lrac.m_r_solver.column_is_feasible(i));
|
||||
if (column_is_int(i) && !a.is_int())
|
||||
if (column_is_int(i) && !a.is_int() && xi.is_int())
|
||||
m = lcm(m, denominator(a));
|
||||
|
||||
|
||||
|
||||
if (!inf_l && !inf_u) {
|
||||
if (l == u)
|
||||
continue;
|
||||
|
@ -372,15 +602,15 @@ bool int_solver::get_freedom_interval_for_column(unsigned j, bool & inf_l, impq
|
|||
|
||||
if (a.is_neg()) {
|
||||
if (has_lower(i))
|
||||
set_lower(l, inf_l, delta(a, xi, lrac.m_r_lower_bounds()[i]));
|
||||
set_lower(l, inf_l, delta(a, xi, lra.get_lower_bound(i)));
|
||||
if (has_upper(i))
|
||||
set_upper(u, inf_u, delta(a, xi, lrac.m_r_upper_bounds()[i]));
|
||||
set_upper(u, inf_u, delta(a, xi, lra.get_upper_bound(i)));
|
||||
}
|
||||
else {
|
||||
if (has_upper(i))
|
||||
set_lower(l, inf_l, delta(a, xi, lrac.m_r_upper_bounds()[i]));
|
||||
set_lower(l, inf_l, delta(a, xi, lra.get_upper_bound(i)));
|
||||
if (has_lower(i))
|
||||
set_upper(u, inf_u, delta(a, xi, lrac.m_r_lower_bounds()[i]));
|
||||
set_upper(u, inf_u, delta(a, xi, lra.get_lower_bound(i)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -479,14 +709,11 @@ bool int_solver::at_upper(unsigned j) const {
|
|||
}
|
||||
|
||||
std::ostream & int_solver::display_row(std::ostream & out, lp::row_strip<rational> const & row) const {
|
||||
bool first = true;
|
||||
bool first = true;
|
||||
auto & rslv = lrac.m_r_solver;
|
||||
for (const auto &c : row)
|
||||
{
|
||||
if (is_fixed(c.var()))
|
||||
{
|
||||
if (!get_value(c.var()).is_zero())
|
||||
{
|
||||
for (const auto &c : row) {
|
||||
if (is_fixed(c.var())) {
|
||||
if (!get_value(c.var()).is_zero()) {
|
||||
impq val = get_value(c.var()) * c.coeff();
|
||||
if (!first && val.is_pos())
|
||||
out << "+";
|
||||
|
@ -505,17 +732,11 @@ for (const auto &c : row)
|
|||
}
|
||||
else if (c.coeff().is_minus_one())
|
||||
out << "-";
|
||||
else
|
||||
{
|
||||
if (c.coeff().is_pos())
|
||||
{
|
||||
if (!first)
|
||||
out << "+";
|
||||
}
|
||||
else {
|
||||
if (c.coeff().is_pos() && !first)
|
||||
out << "+";
|
||||
if (c.coeff().is_big())
|
||||
{
|
||||
out << " b*";
|
||||
}
|
||||
else
|
||||
out << c.coeff();
|
||||
}
|
||||
|
@ -523,8 +744,7 @@ for (const auto &c : row)
|
|||
first = false;
|
||||
}
|
||||
out << "\n";
|
||||
for (const auto &c : row)
|
||||
{
|
||||
for (const auto &c : row) {
|
||||
if (is_fixed(c.var()))
|
||||
continue;
|
||||
rslv.print_column_info(c.var(), out);
|
||||
|
@ -533,14 +753,13 @@ for (const auto &c : row)
|
|||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream& int_solver::display_row_info(std::ostream & out, unsigned row_index) const {
|
||||
auto & rslv = lrac.m_r_solver;
|
||||
auto const& row = rslv.m_A.m_rows[row_index];
|
||||
return display_row(out, row);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool int_solver::shift_var(unsigned j, unsigned range) {
|
||||
if (is_fixed(j) || is_base(j))
|
||||
return false;
|
||||
|
@ -549,11 +768,13 @@ bool int_solver::shift_var(unsigned j, unsigned range) {
|
|||
bool inf_l = false, inf_u = false;
|
||||
impq l, u;
|
||||
mpq m;
|
||||
VERIFY(get_freedom_interval_for_column(j, inf_l, l, inf_u, u, m) || settings().get_cancel_flag());
|
||||
if (!get_freedom_interval_for_column(j, inf_l, l, inf_u, u, m))
|
||||
return false;
|
||||
if (settings().get_cancel_flag())
|
||||
return false;
|
||||
const impq & x = get_value(j);
|
||||
// x, the value of j column, might be shifted on a multiple of m
|
||||
|
||||
if (inf_l && inf_u) {
|
||||
impq new_val = m * impq(random() % (range + 1)) + x;
|
||||
lra.set_value_for_nbasic_column(j, new_val);
|
||||
|
@ -570,6 +791,7 @@ bool int_solver::shift_var(unsigned j, unsigned range) {
|
|||
if (!inf_l && !inf_u && l >= u)
|
||||
return false;
|
||||
|
||||
|
||||
if (inf_u) {
|
||||
SASSERT(!inf_l);
|
||||
impq new_val = x + m * impq(random() % (range + 1));
|
||||
|
@ -640,21 +862,14 @@ int int_solver::select_int_infeasible_var() {
|
|||
unsigned n = 0;
|
||||
lar_core_solver & lcs = lra.m_mpq_lar_core_solver;
|
||||
unsigned prev_usage = 0; // to quiet down the compile
|
||||
unsigned k = 0;
|
||||
unsigned usage;
|
||||
unsigned j;
|
||||
|
||||
enum state { small_box, is_small_value, any_value, not_found };
|
||||
state st = not_found;
|
||||
|
||||
// 1. small box
|
||||
// 2. small value
|
||||
// 3. any value
|
||||
for (; k < lra.r_basis().size(); k++) {
|
||||
j = lra.r_basis()[k];
|
||||
for (unsigned j : lra.r_basis()) {
|
||||
if (!column_is_int_inf(j))
|
||||
continue;
|
||||
usage = lra.usage_in_terms(j);
|
||||
unsigned usage = lra.usage_in_terms(j);
|
||||
if (is_boxed(j) && (new_range = lcs.m_r_upper_bounds()[j].x - lcs.m_r_lower_bounds()[j].x - rational(2*usage)) <= small_value) {
|
||||
SASSERT(!is_fixed(j));
|
||||
if (st != small_box) {
|
||||
|
@ -688,12 +903,12 @@ int int_solver::select_int_infeasible_var() {
|
|||
continue;
|
||||
SASSERT(st == not_found || st == any_value);
|
||||
st = any_value;
|
||||
if (n == 0 /*|| usage > prev_usage*/) {
|
||||
if (n == 0 || usage > prev_usage) {
|
||||
result = j;
|
||||
prev_usage = usage;
|
||||
n = 1;
|
||||
}
|
||||
else if (usage > 0 && /*usage == prev_usage && */ (random() % (++n) == 0))
|
||||
else if (usage > 0 && usage == prev_usage && (random() % (++n) == 0))
|
||||
result = j;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ Revision History:
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#pragma once
|
||||
#include "math/lp/lp_settings.h"
|
||||
#include "math/lp/static_matrix.h"
|
||||
|
@ -44,17 +45,23 @@ class int_solver {
|
|||
int_solver& lia;
|
||||
lar_solver& lra;
|
||||
lar_core_solver& lrac;
|
||||
unsigned m_num_nbasic_patches;
|
||||
unsigned m_patch_cost;
|
||||
unsigned m_next_patch;
|
||||
unsigned m_delay;
|
||||
unsigned m_patch_success = 0;
|
||||
unsigned m_patch_fail = 0;
|
||||
unsigned m_num_ones = 0;
|
||||
unsigned m_num_divides = 0;
|
||||
public:
|
||||
patcher(int_solver& lia);
|
||||
bool should_apply();
|
||||
lia_move operator()();
|
||||
bool should_apply() const { return true; }
|
||||
lia_move operator()() { return patch_basic_columns(); }
|
||||
void patch_nbasic_column(unsigned j);
|
||||
bool patch_basic_column_on_row_cell(unsigned v, row_cell<mpq> const& c);
|
||||
void patch_basic_column(unsigned j);
|
||||
bool try_patch_column(unsigned v, unsigned j, mpq const& delta);
|
||||
unsigned count_non_int();
|
||||
private:
|
||||
void remove_fixed_vars_from_base();
|
||||
lia_move patch_nbasic_columns();
|
||||
lia_move patch_basic_columns();
|
||||
};
|
||||
|
||||
lar_solver& lra;
|
||||
|
|
|
@ -17,6 +17,7 @@ Revision History:
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
|
||||
#pragma once
|
||||
#include <utility>
|
||||
|
|
|
@ -17,6 +17,7 @@ Revision History:
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
|
|
@ -5,6 +5,7 @@ Author:
|
|||
Lev Nachmanson (levnach)
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#pragma once
|
||||
#include "util/vector.h"
|
||||
#include <string>
|
||||
|
@ -16,7 +17,7 @@ Author:
|
|||
#include "math/lp/stacked_vector.h"
|
||||
#include "util/stacked_value.h"
|
||||
namespace lp {
|
||||
|
||||
// clang-format off
|
||||
class lar_core_solver {
|
||||
vector<std::pair<mpq, unsigned>> m_infeasible_linear_combination;
|
||||
int m_infeasible_sum_sign; // todo: get rid of this field
|
||||
|
@ -93,6 +94,8 @@ public:
|
|||
|
||||
void solve();
|
||||
|
||||
void pivot(int entering, int leaving) { m_r_solver.pivot(entering, leaving); }
|
||||
|
||||
bool lower_bounds_are_set() const { return true; }
|
||||
|
||||
const indexed_vector<mpq> & get_pivot_row() const {
|
||||
|
|
|
@ -9,6 +9,7 @@ Revision History:
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
@ -85,8 +86,8 @@ unsigned lar_core_solver::get_number_of_non_ints() const {
|
|||
void lar_core_solver::solve() {
|
||||
TRACE("lar_solver", tout << m_r_solver.get_status() << "\n";);
|
||||
lp_assert(m_r_solver.non_basic_columns_are_set_correctly());
|
||||
lp_assert(m_r_solver.inf_set_is_correct());
|
||||
TRACE("find_feas_stats", tout << "infeasibles = " << m_r_solver.inf_set_size() << ", int_infs = " << get_number_of_non_ints() << std::endl;);
|
||||
lp_assert(m_r_solver.inf_heap_is_correct());
|
||||
TRACE("find_feas_stats", tout << "infeasibles = " << m_r_solver.inf_heap_size() << ", int_infs = " << get_number_of_non_ints() << std::endl;);
|
||||
if (m_r_solver.current_x_is_feasible() && m_r_solver.m_look_for_feasible_solution_only) {
|
||||
m_r_solver.set_status(lp_status::OPTIMAL);
|
||||
TRACE("lar_solver", tout << m_r_solver.get_status() << "\n";);
|
||||
|
@ -117,11 +118,9 @@ void lar_core_solver::solve() {
|
|||
}
|
||||
lp_assert(r_basis_is_OK());
|
||||
lp_assert(m_r_solver.non_basic_columns_are_set_correctly());
|
||||
lp_assert(m_r_solver.inf_set_is_correct());
|
||||
|
||||
TRACE("lar_solver", tout << m_r_solver.get_status() << "\n";);
|
||||
}
|
||||
|
||||
lp_assert(m_r_solver.inf_heap_is_correct());
|
||||
|
||||
TRACE("lar_solver", tout << m_r_solver.get_status() << "\n";);
|
||||
}
|
||||
|
||||
} // namespace lp
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Copyright (c) 2017 Microsoft Corporation
|
||||
Author: Nikolaj Bjorner, Lev Nachmanson
|
||||
*/
|
||||
|
||||
// clang-format off
|
||||
#include "math/lp/lar_solver.h"
|
||||
#include "smt/params/smt_params_helper.hpp"
|
||||
|
||||
|
@ -41,7 +41,6 @@ namespace lp {
|
|||
for (auto t : m_terms)
|
||||
delete t;
|
||||
}
|
||||
|
||||
|
||||
bool lar_solver::sizes_are_correct() const {
|
||||
lp_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_column_types.size());
|
||||
|
@ -50,7 +49,6 @@ namespace lp {
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
std::ostream& lar_solver::print_implied_bound(const implied_bound& be, std::ostream& out) const {
|
||||
out << "implied bound\n";
|
||||
unsigned v = be.m_j;
|
||||
|
@ -215,7 +213,7 @@ namespace lp {
|
|||
|
||||
void lar_solver::fill_explanation_from_crossed_bounds_column(explanation& evidence) const {
|
||||
lp_assert(static_cast<int>(get_column_type(m_crossed_bounds_column)) >= static_cast<int>(column_type::boxed));
|
||||
lp_assert(!m_mpq_lar_core_solver.m_r_solver.column_is_feasible(m_crossed_bounds_column));
|
||||
lp_assert(!column_is_feasible(m_crossed_bounds_column));
|
||||
|
||||
// this is the case when the lower bound is in conflict with the upper one
|
||||
const ul_pair& ul = m_columns_to_ul_pairs[m_crossed_bounds_column];
|
||||
|
@ -244,6 +242,14 @@ namespace lp {
|
|||
set.erase(j);
|
||||
}
|
||||
|
||||
void lar_solver::clean_popped_elements_for_heap(unsigned n, lpvar_heap& heap) {
|
||||
vector<int> to_remove;
|
||||
for (unsigned j : heap)
|
||||
if (j >= n)
|
||||
to_remove.push_back(j);
|
||||
for (unsigned j : to_remove)
|
||||
heap.erase(j);
|
||||
}
|
||||
|
||||
|
||||
void lar_solver::pop(unsigned k) {
|
||||
|
@ -271,7 +277,7 @@ namespace lp {
|
|||
|
||||
unsigned m = A_r().row_count();
|
||||
clean_popped_elements(m, m_rows_with_changed_bounds);
|
||||
clean_inf_set_of_r_solver_after_pop();
|
||||
clean_inf_heap_of_r_solver_after_pop();
|
||||
lp_assert(
|
||||
m_settings.simplex_strategy() == simplex_strategy_enum::undecided ||
|
||||
m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau());
|
||||
|
@ -328,7 +334,7 @@ namespace lp {
|
|||
|
||||
void lar_solver::set_costs_to_zero(const lar_term& term) {
|
||||
auto& rslv = m_mpq_lar_core_solver.m_r_solver;
|
||||
auto& jset = m_mpq_lar_core_solver.m_r_solver.inf_set(); // hijack this set that should be empty right now
|
||||
auto& jset = m_mpq_lar_core_solver.m_r_solver.inf_heap(); // hijack this set that should be empty right now
|
||||
lp_assert(jset.empty());
|
||||
|
||||
for (lar_term::ival p : term) {
|
||||
|
@ -667,16 +673,16 @@ namespace lp {
|
|||
m_mpq_lar_core_solver.m_r_solver.add_delta_to_x_and_track_feasibility(bj, -A_r().get_val(c) * delta);
|
||||
TRACE("change_x_del",
|
||||
tout << "changed basis column " << bj << ", it is " <<
|
||||
(m_mpq_lar_core_solver.m_r_solver.column_is_feasible(bj) ? "feas" : "inf") << std::endl;);
|
||||
(column_is_feasible(bj) ? "feas" : "inf") << std::endl;);
|
||||
}
|
||||
}
|
||||
|
||||
void lar_solver::update_x_and_inf_costs_for_column_with_changed_bounds(unsigned j) {
|
||||
if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) {
|
||||
if (costs_are_used()) {
|
||||
bool was_infeas = m_mpq_lar_core_solver.m_r_solver.inf_set_contains(j);
|
||||
bool was_infeas = m_mpq_lar_core_solver.m_r_solver.inf_heap_contains(j);
|
||||
m_mpq_lar_core_solver.m_r_solver.track_column_feasibility(j);
|
||||
if (was_infeas != m_mpq_lar_core_solver.m_r_solver.inf_set_contains(j))
|
||||
if (was_infeas != m_mpq_lar_core_solver.m_r_solver.inf_heap_contains(j))
|
||||
m_basic_columns_with_changed_cost.insert(j);
|
||||
}
|
||||
else {
|
||||
|
@ -1293,12 +1299,12 @@ namespace lp {
|
|||
lp_assert(m_mpq_lar_core_solver.m_r_solver.basis_heading_is_correct());
|
||||
}
|
||||
|
||||
void lar_solver::clean_inf_set_of_r_solver_after_pop() {
|
||||
void lar_solver::clean_inf_heap_of_r_solver_after_pop() {
|
||||
vector<unsigned> became_feas;
|
||||
clean_popped_elements(A_r().column_count(), m_mpq_lar_core_solver.m_r_solver.inf_set());
|
||||
clean_popped_elements_for_heap(A_r().column_count(), m_mpq_lar_core_solver.m_r_solver.inf_heap());
|
||||
std::unordered_set<unsigned> basic_columns_with_changed_cost;
|
||||
m_inf_index_copy.reset();
|
||||
for (auto j : m_mpq_lar_core_solver.m_r_solver.inf_set())
|
||||
for (auto j : m_mpq_lar_core_solver.m_r_solver.inf_heap())
|
||||
m_inf_index_copy.push_back(j);
|
||||
for (auto j : m_inf_index_copy) {
|
||||
if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) {
|
||||
|
@ -1316,16 +1322,16 @@ namespace lp {
|
|||
lp_assert(m_mpq_lar_core_solver.m_r_solver.m_basis_heading[j] < 0);
|
||||
m_mpq_lar_core_solver.m_r_solver.m_d[j] -= m_mpq_lar_core_solver.m_r_solver.m_costs[j];
|
||||
m_mpq_lar_core_solver.m_r_solver.m_costs[j] = zero_of_type<mpq>();
|
||||
m_mpq_lar_core_solver.m_r_solver.remove_column_from_inf_set(j);
|
||||
m_mpq_lar_core_solver.m_r_solver.remove_column_from_inf_heap(j);
|
||||
}
|
||||
became_feas.clear();
|
||||
for (unsigned j : m_mpq_lar_core_solver.m_r_solver.inf_set()) {
|
||||
for (unsigned j : m_mpq_lar_core_solver.m_r_solver.inf_heap()) {
|
||||
lp_assert(m_mpq_lar_core_solver.m_r_heading[j] >= 0);
|
||||
if (m_mpq_lar_core_solver.m_r_solver.column_is_feasible(j))
|
||||
if (column_is_feasible(j))
|
||||
became_feas.push_back(j);
|
||||
}
|
||||
for (unsigned j : became_feas)
|
||||
m_mpq_lar_core_solver.m_r_solver.remove_column_from_inf_set(j);
|
||||
m_mpq_lar_core_solver.m_r_solver.remove_column_from_inf_heap(j);
|
||||
|
||||
}
|
||||
|
||||
|
@ -1346,8 +1352,8 @@ namespace lp {
|
|||
}
|
||||
|
||||
bool lar_solver::term_is_int(const vector<std::pair<mpq, unsigned int>>& coeffs) const {
|
||||
for (auto const& p : coeffs)
|
||||
if (!(column_is_int(p.second) && p.first.is_int()))
|
||||
for (auto const& [coeff, v] : coeffs)
|
||||
if (!(column_is_int(v) && coeff.is_int()))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
@ -1374,66 +1380,6 @@ namespace lp {
|
|||
return m_mpq_lar_core_solver.column_is_free(j);
|
||||
}
|
||||
|
||||
// column is at lower or upper bound, lower and upper bound are different.
|
||||
// the lower/upper bound is not strict.
|
||||
// the LP obtained by making the bound strict is infeasible
|
||||
// -> the column has to be fixed
|
||||
bool lar_solver::is_fixed_at_bound(column_index const& j) {
|
||||
if (column_is_fixed(j))
|
||||
return false;
|
||||
mpq val;
|
||||
if (!has_value(j, val))
|
||||
return false;
|
||||
lp::lconstraint_kind k;
|
||||
if (column_has_upper_bound(j) &&
|
||||
get_upper_bound(j).x == val) {
|
||||
verbose_stream() << "check upper " << j << "\n";
|
||||
push();
|
||||
if (column_is_int(j))
|
||||
k = LE, val -= 1;
|
||||
else
|
||||
k = LT;
|
||||
auto ci = mk_var_bound(j, k, val);
|
||||
update_column_type_and_bound(j, k, val, ci);
|
||||
auto st = find_feasible_solution();
|
||||
pop(1);
|
||||
return st == lp_status::INFEASIBLE;
|
||||
}
|
||||
if (column_has_lower_bound(j) &&
|
||||
get_lower_bound(j).x == val) {
|
||||
verbose_stream() << "check lower " << j << "\n";
|
||||
push();
|
||||
if (column_is_int(j))
|
||||
k = GE, val += 1;
|
||||
else
|
||||
k = GT;
|
||||
auto ci = mk_var_bound(j, k, val);
|
||||
update_column_type_and_bound(j, k, val, ci);
|
||||
auto st = find_feasible_solution();
|
||||
pop(1);
|
||||
return st == lp_status::INFEASIBLE;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool lar_solver::has_fixed_at_bound() {
|
||||
verbose_stream() << "has-fixed-at-bound\n";
|
||||
unsigned num_fixed = 0;
|
||||
for (unsigned j = 0; j < A_r().m_columns.size(); ++j) {
|
||||
auto ci = column_index(j);
|
||||
if (is_fixed_at_bound(ci)) {
|
||||
++num_fixed;
|
||||
verbose_stream() << "fixed " << j << "\n";
|
||||
}
|
||||
}
|
||||
verbose_stream() << "num fixed " << num_fixed << "\n";
|
||||
if (num_fixed > 0)
|
||||
find_feasible_solution();
|
||||
return num_fixed > 0;
|
||||
}
|
||||
|
||||
|
||||
// below is the initialization functionality of lar_solver
|
||||
|
||||
bool lar_solver::strategy_is_undecided() const {
|
||||
|
@ -1504,7 +1450,7 @@ namespace lp {
|
|||
m_mpq_lar_core_solver.m_r_x.resize(j + 1);
|
||||
m_mpq_lar_core_solver.m_r_lower_bounds.increase_size_by_one();
|
||||
m_mpq_lar_core_solver.m_r_upper_bounds.increase_size_by_one();
|
||||
m_mpq_lar_core_solver.m_r_solver.inf_set_increase_size_by_one();
|
||||
m_mpq_lar_core_solver.m_r_solver.inf_heap_increase_size_by_one();
|
||||
m_mpq_lar_core_solver.m_r_solver.m_costs.resize(j + 1);
|
||||
m_mpq_lar_core_solver.m_r_solver.m_d.resize(j + 1);
|
||||
lp_assert(m_mpq_lar_core_solver.m_r_heading.size() == j); // as A().column_count() on the entry to the method
|
||||
|
@ -1609,6 +1555,18 @@ namespace lp {
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief ensure there is a column index corresponding to vi
|
||||
* If vi is already a column, just return vi
|
||||
* If vi is for a term, then create a row that uses the term.
|
||||
*/
|
||||
var_index lar_solver::ensure_column(var_index vi) {
|
||||
if (lp::tv::is_term(vi))
|
||||
return to_column(vi);
|
||||
else
|
||||
return vi;
|
||||
}
|
||||
|
||||
|
||||
void lar_solver::add_row_from_term_no_constraint(const lar_term* term, unsigned term_ext_index) {
|
||||
TRACE("dump_terms", print_term(*term, tout) << std::endl;);
|
||||
|
@ -1780,13 +1738,20 @@ namespace lp {
|
|||
lconstraint_kind kind,
|
||||
const mpq& right_side,
|
||||
constraint_index constr_index) {
|
||||
TRACE("lar_solver_feas", tout << "j = " << j << " was " << (this->column_is_feasible(j)?"feas":"non-feas") << std::endl;);
|
||||
m_constraints.activate(constr_index);
|
||||
if (column_has_upper_bound(j))
|
||||
update_column_type_and_bound_with_ub(j, kind, right_side, constr_index);
|
||||
else
|
||||
update_column_type_and_bound_with_no_ub(j, kind, right_side, constr_index);
|
||||
TRACE("lar_solver_feas", tout << "j = " << j << " became " << (this->column_is_feasible(j)?"feas":"non-feas") << ", and " << (this->column_is_bounded(j)? "bounded":"non-bounded") << std::endl;);
|
||||
}
|
||||
|
||||
// clang-format on
|
||||
void lar_solver::insert_to_columns_with_changed_bounds(unsigned j) {
|
||||
m_columns_with_changed_bounds.insert(j);
|
||||
TRACE("lar_solver", tout << "column " << j << (column_is_feasible(j) ? " feas" : " non-feas") << "\n";);
|
||||
}
|
||||
// clang-format off
|
||||
void lar_solver::update_column_type_and_bound_check_on_equal(unsigned j,
|
||||
lconstraint_kind kind,
|
||||
const mpq& right_side,
|
||||
|
@ -1876,117 +1841,111 @@ namespace lp {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// clang-format on
|
||||
void lar_solver::update_bound_with_ub_lb(var_index j, lconstraint_kind kind, const mpq& right_side, constraint_index ci) {
|
||||
lp_assert(column_has_lower_bound(j) && column_has_upper_bound(j));
|
||||
lp_assert(m_mpq_lar_core_solver.m_column_types[j] == column_type::boxed ||
|
||||
m_mpq_lar_core_solver.m_column_types[j] == column_type::fixed);
|
||||
m_mpq_lar_core_solver.m_column_types[j] == column_type::fixed);
|
||||
|
||||
mpq y_of_bound(0);
|
||||
switch (kind) {
|
||||
case LT:
|
||||
y_of_bound = -1;
|
||||
case LE:
|
||||
{
|
||||
auto up = numeric_pair<mpq>(right_side, y_of_bound);
|
||||
if (up < m_mpq_lar_core_solver.m_r_lower_bounds[j]) {
|
||||
set_infeasible_column(j);
|
||||
case LT:
|
||||
y_of_bound = -1;
|
||||
case LE: {
|
||||
auto up = numeric_pair<mpq>(right_side, y_of_bound);
|
||||
if (up < m_mpq_lar_core_solver.m_r_lower_bounds[j]) {
|
||||
set_infeasible_column(j);
|
||||
}
|
||||
if (up >= m_mpq_lar_core_solver.m_r_upper_bounds[j]) return;
|
||||
m_mpq_lar_core_solver.m_r_upper_bounds[j] = up;
|
||||
set_upper_bound_witness(j, ci);
|
||||
insert_to_columns_with_changed_bounds(j);
|
||||
break;
|
||||
}
|
||||
if (up >= m_mpq_lar_core_solver.m_r_upper_bounds[j]) return;
|
||||
m_mpq_lar_core_solver.m_r_upper_bounds[j] = up;
|
||||
set_upper_bound_witness(j, ci);
|
||||
insert_to_columns_with_changed_bounds(j);
|
||||
}
|
||||
break;
|
||||
case GT:
|
||||
y_of_bound = 1;
|
||||
case GE:
|
||||
{
|
||||
auto low = numeric_pair<mpq>(right_side, y_of_bound);
|
||||
if (low > m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
|
||||
set_infeasible_column(j);
|
||||
case GT:
|
||||
y_of_bound = 1;
|
||||
case GE: {
|
||||
auto low = numeric_pair<mpq>(right_side, y_of_bound);
|
||||
if (low > m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
|
||||
set_infeasible_column(j);
|
||||
}
|
||||
if (low < m_mpq_lar_core_solver.m_r_lower_bounds[j]) {
|
||||
return;
|
||||
}
|
||||
m_mpq_lar_core_solver.m_r_lower_bounds[j] = low;
|
||||
set_lower_bound_witness(j, ci);
|
||||
m_mpq_lar_core_solver.m_column_types[j] = (low == m_mpq_lar_core_solver.m_r_upper_bounds[j] ? column_type::fixed : column_type::boxed);
|
||||
insert_to_columns_with_changed_bounds(j);
|
||||
break;
|
||||
}
|
||||
case EQ: {
|
||||
auto v = numeric_pair<mpq>(right_side, zero_of_type<mpq>());
|
||||
if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j] || v < m_mpq_lar_core_solver.m_r_lower_bounds[j]) {
|
||||
set_infeasible_column(j);
|
||||
}
|
||||
set_upper_bound_witness(j, ci);
|
||||
set_lower_bound_witness(j, ci);
|
||||
m_mpq_lar_core_solver.m_r_upper_bounds[j] = m_mpq_lar_core_solver.m_r_lower_bounds[j] = v;
|
||||
break;
|
||||
}
|
||||
if (low < m_mpq_lar_core_solver.m_r_lower_bounds[j]) {
|
||||
return;
|
||||
}
|
||||
m_mpq_lar_core_solver.m_r_lower_bounds[j] = low;
|
||||
insert_to_columns_with_changed_bounds(j);
|
||||
set_lower_bound_witness(j, ci);
|
||||
m_mpq_lar_core_solver.m_column_types[j] = (low == m_mpq_lar_core_solver.m_r_upper_bounds[j] ? column_type::fixed : column_type::boxed);
|
||||
}
|
||||
break;
|
||||
case EQ:
|
||||
{
|
||||
auto v = numeric_pair<mpq>(right_side, zero_of_type<mpq>());
|
||||
if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j] || v < m_mpq_lar_core_solver.m_r_lower_bounds[j]) {
|
||||
set_infeasible_column(j);
|
||||
}
|
||||
set_upper_bound_witness(j, ci);
|
||||
set_lower_bound_witness(j, ci);
|
||||
m_mpq_lar_core_solver.m_r_upper_bounds[j] = m_mpq_lar_core_solver.m_r_lower_bounds[j] = v;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
if (m_mpq_lar_core_solver.m_r_upper_bounds[j] == m_mpq_lar_core_solver.m_r_lower_bounds[j]) {
|
||||
m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed;
|
||||
}
|
||||
}
|
||||
// clang-format off
|
||||
void lar_solver::update_bound_with_no_ub_lb(var_index j, lconstraint_kind kind, const mpq& right_side, constraint_index ci) {
|
||||
lp_assert(column_has_lower_bound(j) && !column_has_upper_bound(j));
|
||||
lp_assert(m_mpq_lar_core_solver.m_column_types[j] == column_type::lower_bound);
|
||||
|
||||
mpq y_of_bound(0);
|
||||
switch (kind) {
|
||||
case LT:
|
||||
y_of_bound = -1;
|
||||
case LE:
|
||||
{
|
||||
auto up = numeric_pair<mpq>(right_side, y_of_bound);
|
||||
if (up < m_mpq_lar_core_solver.m_r_lower_bounds[j]) {
|
||||
set_infeasible_column(j);
|
||||
}
|
||||
m_mpq_lar_core_solver.m_r_upper_bounds[j] = up;
|
||||
set_upper_bound_witness(j, ci);
|
||||
insert_to_columns_with_changed_bounds(j);
|
||||
m_mpq_lar_core_solver.m_column_types[j] = (up == m_mpq_lar_core_solver.m_r_lower_bounds[j] ? column_type::fixed : column_type::boxed);
|
||||
}
|
||||
break;
|
||||
case GT:
|
||||
y_of_bound = 1;
|
||||
case GE:
|
||||
{
|
||||
auto low = numeric_pair<mpq>(right_side, y_of_bound);
|
||||
if (low < m_mpq_lar_core_solver.m_r_lower_bounds[j]) {
|
||||
return;
|
||||
}
|
||||
m_mpq_lar_core_solver.m_r_lower_bounds[j] = low;
|
||||
insert_to_columns_with_changed_bounds(j);
|
||||
set_lower_bound_witness(j, ci);
|
||||
}
|
||||
break;
|
||||
case EQ:
|
||||
{
|
||||
auto v = numeric_pair<mpq>(right_side, zero_of_type<mpq>());
|
||||
if (v < m_mpq_lar_core_solver.m_r_lower_bounds[j]) {
|
||||
set_infeasible_column(j);
|
||||
case LT:
|
||||
y_of_bound = -1;
|
||||
case LE: {
|
||||
auto up = numeric_pair<mpq>(right_side, y_of_bound);
|
||||
if (up < m_mpq_lar_core_solver.m_r_lower_bounds[j]) {
|
||||
set_infeasible_column(j);
|
||||
}
|
||||
m_mpq_lar_core_solver.m_r_upper_bounds[j] = up;
|
||||
set_upper_bound_witness(j, ci);
|
||||
m_mpq_lar_core_solver.m_column_types[j] = (up == m_mpq_lar_core_solver.m_r_lower_bounds[j] ? column_type::fixed : column_type::boxed);
|
||||
insert_to_columns_with_changed_bounds(j);
|
||||
break;
|
||||
}
|
||||
case GT:
|
||||
y_of_bound = 1;
|
||||
case GE: {
|
||||
auto low = numeric_pair<mpq>(right_side, y_of_bound);
|
||||
if (low < m_mpq_lar_core_solver.m_r_lower_bounds[j]) {
|
||||
return;
|
||||
}
|
||||
m_mpq_lar_core_solver.m_r_lower_bounds[j] = low;
|
||||
set_lower_bound_witness(j, ci);
|
||||
insert_to_columns_with_changed_bounds(j);
|
||||
break;
|
||||
}
|
||||
case EQ: {
|
||||
auto v = numeric_pair<mpq>(right_side, zero_of_type<mpq>());
|
||||
if (v < m_mpq_lar_core_solver.m_r_lower_bounds[j]) {
|
||||
set_infeasible_column(j);
|
||||
}
|
||||
|
||||
set_upper_bound_witness(j, ci);
|
||||
set_lower_bound_witness(j, ci);
|
||||
m_mpq_lar_core_solver.m_r_upper_bounds[j] = m_mpq_lar_core_solver.m_r_lower_bounds[j] = v;
|
||||
m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed;
|
||||
break;
|
||||
}
|
||||
|
||||
set_upper_bound_witness(j, ci);
|
||||
set_lower_bound_witness(j, ci);
|
||||
m_mpq_lar_core_solver.m_r_upper_bounds[j] = m_mpq_lar_core_solver.m_r_lower_bounds[j] = v;
|
||||
m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
void lar_solver::update_bound_with_ub_no_lb(var_index j, lconstraint_kind kind, const mpq& right_side, constraint_index ci) {
|
||||
lp_assert(!column_has_lower_bound(j) && column_has_upper_bound(j));
|
||||
lp_assert(m_mpq_lar_core_solver.m_column_types[j] == column_type::upper_bound);
|
||||
|
@ -2012,9 +1971,10 @@ namespace lp {
|
|||
set_infeasible_column(j);
|
||||
}
|
||||
m_mpq_lar_core_solver.m_r_lower_bounds[j] = low;
|
||||
insert_to_columns_with_changed_bounds(j);
|
||||
set_lower_bound_witness(j, ci);
|
||||
m_mpq_lar_core_solver.m_column_types[j] = (low == m_mpq_lar_core_solver.m_r_upper_bounds[j] ? column_type::fixed : column_type::boxed);
|
||||
insert_to_columns_with_changed_bounds(j);
|
||||
|
||||
}
|
||||
break;
|
||||
case EQ:
|
||||
|
@ -2035,48 +1995,44 @@ namespace lp {
|
|||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
// clang-format on
|
||||
void lar_solver::update_bound_with_no_ub_no_lb(var_index j, lconstraint_kind kind, const mpq& right_side, constraint_index ci) {
|
||||
lp_assert(!column_has_lower_bound(j) && !column_has_upper_bound(j));
|
||||
insert_to_columns_with_changed_bounds(j);
|
||||
|
||||
mpq y_of_bound(0);
|
||||
switch (kind) {
|
||||
case LT:
|
||||
y_of_bound = -1;
|
||||
case LE:
|
||||
{
|
||||
auto up = numeric_pair<mpq>(right_side, y_of_bound);
|
||||
m_mpq_lar_core_solver.m_r_upper_bounds[j] = up;
|
||||
set_upper_bound_witness(j, ci);
|
||||
m_mpq_lar_core_solver.m_column_types[j] = column_type::upper_bound;
|
||||
}
|
||||
break;
|
||||
case GT:
|
||||
y_of_bound = 1;
|
||||
case GE:
|
||||
{
|
||||
auto low = numeric_pair<mpq>(right_side, y_of_bound);
|
||||
m_mpq_lar_core_solver.m_r_lower_bounds[j] = low;
|
||||
insert_to_columns_with_changed_bounds(j);
|
||||
set_lower_bound_witness(j, ci);
|
||||
m_mpq_lar_core_solver.m_column_types[j] = column_type::lower_bound;
|
||||
}
|
||||
break;
|
||||
case EQ:
|
||||
{
|
||||
auto v = numeric_pair<mpq>(right_side, zero_of_type<mpq>());
|
||||
set_upper_bound_witness(j, ci);
|
||||
set_lower_bound_witness(j, ci);
|
||||
m_mpq_lar_core_solver.m_r_upper_bounds[j] = m_mpq_lar_core_solver.m_r_lower_bounds[j] = v;
|
||||
m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed;
|
||||
break;
|
||||
}
|
||||
case LT:
|
||||
y_of_bound = -1;
|
||||
case LE: {
|
||||
auto up = numeric_pair<mpq>(right_side, y_of_bound);
|
||||
m_mpq_lar_core_solver.m_r_upper_bounds[j] = up;
|
||||
set_upper_bound_witness(j, ci);
|
||||
m_mpq_lar_core_solver.m_column_types[j] = column_type::upper_bound;
|
||||
} break;
|
||||
case GT:
|
||||
y_of_bound = 1;
|
||||
case GE: {
|
||||
auto low = numeric_pair<mpq>(right_side, y_of_bound);
|
||||
m_mpq_lar_core_solver.m_r_lower_bounds[j] = low;
|
||||
set_lower_bound_witness(j, ci);
|
||||
m_mpq_lar_core_solver.m_column_types[j] = column_type::lower_bound;
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
} break;
|
||||
case EQ: {
|
||||
auto v = numeric_pair<mpq>(right_side, zero_of_type<mpq>());
|
||||
set_upper_bound_witness(j, ci);
|
||||
set_lower_bound_witness(j, ci);
|
||||
m_mpq_lar_core_solver.m_r_upper_bounds[j] = m_mpq_lar_core_solver.m_r_lower_bounds[j] = v;
|
||||
m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
insert_to_columns_with_changed_bounds(j);
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
bool lar_solver::column_corresponds_to_term(unsigned j) const {
|
||||
return tv::is_term(m_var_register.local_to_external(j));
|
||||
}
|
||||
|
@ -2180,8 +2136,8 @@ namespace lp {
|
|||
}
|
||||
|
||||
bool lar_solver::get_equality_and_right_side_for_term_on_current_x(tv const& t, mpq& rs, constraint_index& ci, bool& upper_bound) const {
|
||||
lp_assert(t.is_term())
|
||||
unsigned j;
|
||||
lp_assert(t.is_term());
|
||||
unsigned j;
|
||||
bool is_int;
|
||||
if (!m_var_register.external_is_used(t.index(), j, is_int))
|
||||
return false; // the term does not have a bound because it does not correspond to a column
|
||||
|
|
|
@ -17,30 +17,32 @@
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#pragma once
|
||||
#include "util/vector.h"
|
||||
#include <utility>
|
||||
#include "util/debug.h"
|
||||
#include "util/buffer.h"
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <stack>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
#include "math/lp/bound_analyzer_on_row.h"
|
||||
#include "math/lp/implied_bound.h"
|
||||
#include "math/lp/int_solver.h"
|
||||
#include "math/lp/lar_constraints.h"
|
||||
#include "math/lp/lar_core_solver.h"
|
||||
#include "math/lp/numeric_pair.h"
|
||||
#include "math/lp/lp_primal_core_solver.h"
|
||||
#include "math/lp/random_updater.h"
|
||||
#include "util/stacked_value.h"
|
||||
#include "math/lp/stacked_vector.h"
|
||||
#include "math/lp/implied_bound.h"
|
||||
#include "math/lp/bound_analyzer_on_row.h"
|
||||
#include "math/lp/int_solver.h"
|
||||
#include "math/lp/nra_solver.h"
|
||||
#include "math/lp/lp_types.h"
|
||||
#include "math/lp/lp_bound_propagator.h"
|
||||
#include "math/lp/lp_primal_core_solver.h"
|
||||
#include "math/lp/lp_types.h"
|
||||
#include "math/lp/nra_solver.h"
|
||||
#include "math/lp/numeric_pair.h"
|
||||
#include "math/lp/random_updater.h"
|
||||
#include "math/lp/stacked_vector.h"
|
||||
#include "util/buffer.h"
|
||||
#include "util/debug.h"
|
||||
#include "util/stacked_value.h"
|
||||
#include "util/vector.h"
|
||||
|
||||
namespace lp {
|
||||
|
||||
|
@ -48,10 +50,9 @@ class int_branch;
|
|||
class int_solver;
|
||||
class lar_solver : public column_namer {
|
||||
struct term_hasher {
|
||||
std::size_t operator()(const lar_term &t) const
|
||||
{
|
||||
using std::size_t;
|
||||
std::size_t operator()(const lar_term& t) const {
|
||||
using std::hash;
|
||||
using std::size_t;
|
||||
using std::string;
|
||||
size_t seed = 0;
|
||||
int i = 0;
|
||||
|
@ -66,110 +67,106 @@ class lar_solver : public column_namer {
|
|||
};
|
||||
|
||||
struct term_comparer {
|
||||
bool operator()(const lar_term &a, const lar_term& b) const
|
||||
{
|
||||
return a == b;
|
||||
bool operator()(const lar_term& a, const lar_term& b) const {
|
||||
return a == b;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//////////////////// fields //////////////////////////
|
||||
lp_settings m_settings;
|
||||
lp_status m_status = lp_status::UNKNOWN;
|
||||
stacked_value<simplex_strategy_enum> m_simplex_strategy;
|
||||
lp_settings m_settings;
|
||||
lp_status m_status = lp_status::UNKNOWN;
|
||||
stacked_value<simplex_strategy_enum> m_simplex_strategy;
|
||||
// such can be found at the initialization step: u < l
|
||||
stacked_value<int> m_crossed_bounds_column;
|
||||
lar_core_solver m_mpq_lar_core_solver;
|
||||
int_solver * m_int_solver = nullptr;
|
||||
bool m_need_register_terms = false;
|
||||
var_register m_var_register;
|
||||
var_register m_term_register;
|
||||
stacked_vector<ul_pair> m_columns_to_ul_pairs;
|
||||
constraint_set m_constraints;
|
||||
stacked_value<int> m_crossed_bounds_column;
|
||||
lar_core_solver m_mpq_lar_core_solver;
|
||||
int_solver* m_int_solver = nullptr;
|
||||
bool m_need_register_terms = false;
|
||||
var_register m_var_register;
|
||||
var_register m_term_register;
|
||||
stacked_vector<ul_pair> m_columns_to_ul_pairs;
|
||||
constraint_set m_constraints;
|
||||
// the set of column indices j such that bounds have changed for j
|
||||
u_set m_columns_with_changed_bounds;
|
||||
u_set m_rows_with_changed_bounds;
|
||||
unsigned_vector m_row_bounds_to_replay;
|
||||
|
||||
u_set m_basic_columns_with_changed_cost;
|
||||
u_set m_columns_with_changed_bounds;
|
||||
u_set m_rows_with_changed_bounds;
|
||||
unsigned_vector m_row_bounds_to_replay;
|
||||
|
||||
u_set m_basic_columns_with_changed_cost;
|
||||
// these are basic columns with the value changed, so the corresponding row in the tableau
|
||||
// does not sum to zero anymore
|
||||
u_set m_incorrect_columns;
|
||||
// copy of m_r_solver.inf_set()
|
||||
unsigned_vector m_inf_index_copy;
|
||||
stacked_value<unsigned> m_term_count;
|
||||
vector<lar_term*> m_terms;
|
||||
indexed_vector<mpq> m_column_buffer;
|
||||
u_set m_incorrect_columns;
|
||||
// copy of m_r_solver.inf_heap()
|
||||
unsigned_vector m_inf_index_copy;
|
||||
stacked_value<unsigned> m_term_count;
|
||||
vector<lar_term*> m_terms;
|
||||
indexed_vector<mpq> m_column_buffer;
|
||||
std::unordered_map<lar_term, std::pair<mpq, unsigned>, term_hasher, term_comparer>
|
||||
m_normalized_terms_to_columns;
|
||||
vector<impq> m_backup_x;
|
||||
stacked_vector<unsigned> m_usage_in_terms;
|
||||
m_normalized_terms_to_columns;
|
||||
vector<impq> m_backup_x;
|
||||
stacked_vector<unsigned> m_usage_in_terms;
|
||||
// ((x[j], is_int(j))->j) for fixed j, used in equalities propagation
|
||||
// maps values to integral fixed vars
|
||||
map<mpq, unsigned, obj_hash<mpq>, default_eq<mpq>> m_fixed_var_table_int;
|
||||
map<mpq, unsigned, obj_hash<mpq>, default_eq<mpq>> m_fixed_var_table_int;
|
||||
// maps values to non-integral fixed vars
|
||||
map<mpq, unsigned, obj_hash<mpq>, default_eq<mpq>> m_fixed_var_table_real;
|
||||
map<mpq, unsigned, obj_hash<mpq>, default_eq<mpq>> m_fixed_var_table_real;
|
||||
// end of fields
|
||||
|
||||
////////////////// methods ////////////////////////////////
|
||||
|
||||
static bool valid_index(unsigned j) { return static_cast<int>(j) >= 0;}
|
||||
const lar_term & get_term(unsigned j) const;
|
||||
|
||||
static bool valid_index(unsigned j) { return static_cast<int>(j) >= 0; }
|
||||
const lar_term& get_term(unsigned j) const;
|
||||
bool row_has_a_big_num(unsigned i) const;
|
||||
// init region
|
||||
bool strategy_is_undecided() const;
|
||||
void register_new_ext_var_index(unsigned ext_v, bool is_int);
|
||||
bool term_is_int(const lar_term * t) const;
|
||||
bool term_is_int(const vector<std::pair<mpq, unsigned int>> & coeffs) const;
|
||||
bool term_is_int(const lar_term* t) const;
|
||||
bool term_is_int(const vector<std::pair<mpq, unsigned int>>& coeffs) const;
|
||||
void add_non_basic_var_to_core_fields(unsigned ext_j, bool is_int);
|
||||
void add_new_var_to_core_fields_for_mpq(bool register_in_basis);
|
||||
mpq adjust_bound_for_int(lpvar j, lconstraint_kind&, const mpq&);
|
||||
|
||||
// terms
|
||||
bool all_vars_are_registered(const vector<std::pair<mpq, var_index>> & coeffs);
|
||||
var_index add_term_undecided(const vector<std::pair<mpq, var_index>> & coeffs);
|
||||
bool term_coeffs_are_ok(const vector<std::pair<mpq, var_index>> & coeffs);
|
||||
bool all_vars_are_registered(const vector<std::pair<mpq, var_index>>& coeffs);
|
||||
var_index add_term_undecided(const vector<std::pair<mpq, var_index>>& coeffs);
|
||||
bool term_coeffs_are_ok(const vector<std::pair<mpq, var_index>>& coeffs);
|
||||
void push_term(lar_term* t);
|
||||
void add_row_from_term_no_constraint(const lar_term * term, unsigned term_ext_index);
|
||||
void add_row_from_term_no_constraint(const lar_term* term, unsigned term_ext_index);
|
||||
void add_basic_var_to_core_fields();
|
||||
bool compare_values(impq const& lhs, lconstraint_kind k, const mpq & rhs);
|
||||
bool compare_values(impq const& lhs, lconstraint_kind k, const mpq& rhs);
|
||||
|
||||
inline void clear_columns_with_changed_bounds() { m_columns_with_changed_bounds.clear(); }
|
||||
inline void increase_by_one_columns_with_changed_bounds() { m_columns_with_changed_bounds.increase_size_by_one(); }
|
||||
inline void insert_to_columns_with_changed_bounds(unsigned j) { m_columns_with_changed_bounds.insert(j); }
|
||||
|
||||
void update_column_type_and_bound_check_on_equal(unsigned j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_index, unsigned&);
|
||||
void update_column_type_and_bound(unsigned j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_index);
|
||||
void update_column_type_and_bound_with_ub(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_index);
|
||||
void update_column_type_and_bound_with_no_ub(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_index);
|
||||
void update_bound_with_ub_lb(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_index);
|
||||
void update_bound_with_no_ub_lb(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_index);
|
||||
void update_bound_with_ub_no_lb(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_index);
|
||||
void update_bound_with_no_ub_no_lb(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_index);
|
||||
void insert_to_columns_with_changed_bounds(unsigned j);
|
||||
void update_column_type_and_bound_check_on_equal(unsigned j, lconstraint_kind kind, const mpq& right_side, constraint_index constr_index, unsigned&);
|
||||
void update_column_type_and_bound(unsigned j, lconstraint_kind kind, const mpq& right_side, constraint_index constr_index);
|
||||
void update_column_type_and_bound_with_ub(var_index j, lconstraint_kind kind, const mpq& right_side, constraint_index constr_index);
|
||||
void update_column_type_and_bound_with_no_ub(var_index j, lconstraint_kind kind, const mpq& right_side, constraint_index constr_index);
|
||||
void update_bound_with_ub_lb(var_index j, lconstraint_kind kind, const mpq& right_side, constraint_index constr_index);
|
||||
void update_bound_with_no_ub_lb(var_index j, lconstraint_kind kind, const mpq& right_side, constraint_index constr_index);
|
||||
void update_bound_with_ub_no_lb(var_index j, lconstraint_kind kind, const mpq& right_side, constraint_index constr_index);
|
||||
void update_bound_with_no_ub_no_lb(var_index j, lconstraint_kind kind, const mpq& right_side, constraint_index constr_index);
|
||||
void register_in_fixed_var_table(unsigned, unsigned&);
|
||||
void remove_non_fixed_from_fixed_var_table();
|
||||
constraint_index add_var_bound_on_constraint_for_term(var_index j, lconstraint_kind kind, const mpq & right_side);
|
||||
constraint_index add_var_bound_on_constraint_for_term(var_index j, lconstraint_kind kind, const mpq& right_side);
|
||||
inline void set_infeasible_column(unsigned j) {
|
||||
set_status(lp_status::INFEASIBLE);
|
||||
m_crossed_bounds_column = j;
|
||||
}
|
||||
constraint_index add_constraint_from_term_and_create_new_column_row(unsigned term_j, const lar_term* term,
|
||||
lconstraint_kind kind, const mpq & right_side);
|
||||
lconstraint_kind kind, const mpq& right_side);
|
||||
unsigned row_of_basic_column(unsigned) const;
|
||||
void decide_on_strategy_and_adjust_initial_state();
|
||||
void adjust_initial_state();
|
||||
void adjust_initial_state_for_tableau_rows();
|
||||
bool sizes_are_correct() const;
|
||||
bool implied_bound_is_correctly_explained(implied_bound const & be, const vector<std::pair<mpq, unsigned>> & explanation) const;
|
||||
|
||||
bool implied_bound_is_correctly_explained(implied_bound const& be, const vector<std::pair<mpq, unsigned>>& explanation) const;
|
||||
|
||||
void substitute_basis_var_in_terms_for_row(unsigned i);
|
||||
|
||||
|
||||
template <typename T>
|
||||
unsigned calculate_implied_bounds_for_row(unsigned row_index, lp_bound_propagator<T> & bp) {
|
||||
|
||||
if (A_r().m_rows[row_index].size() > settings().max_row_length_for_bound_propagation || row_has_a_big_num(row_index))
|
||||
unsigned calculate_implied_bounds_for_row(unsigned row_index, lp_bound_propagator<T>& bp) {
|
||||
if (A_r().m_rows[row_index].size() > settings().max_row_length_for_bound_propagation || row_has_a_big_num(row_index))
|
||||
return 0;
|
||||
|
||||
|
||||
return bound_analyzer_on_row<row_strip<mpq>, lp_bound_propagator<T>>::analyze_row(
|
||||
A_r().m_rows[row_index],
|
||||
null_ci,
|
||||
|
@ -177,27 +174,28 @@ class lar_solver : public column_namer {
|
|||
row_index,
|
||||
bp);
|
||||
}
|
||||
|
||||
|
||||
static void clean_popped_elements_for_heap(unsigned n, lpvar_heap& set);
|
||||
static void clean_popped_elements(unsigned n, u_set& set);
|
||||
bool maximize_term_on_tableau(const lar_term & term,
|
||||
impq &term_max);
|
||||
bool maximize_term_on_tableau(const lar_term& term,
|
||||
impq& term_max);
|
||||
bool costs_are_zeros_for_r_solver() const;
|
||||
bool reduced_costs_are_zeroes_for_r_solver() const;
|
||||
void set_costs_to_zero(const lar_term & term);
|
||||
void prepare_costs_for_r_solver(const lar_term & term);
|
||||
bool maximize_term_on_corrected_r_solver(lar_term & term, impq &term_max);
|
||||
void set_costs_to_zero(const lar_term& term);
|
||||
void prepare_costs_for_r_solver(const lar_term& term);
|
||||
bool maximize_term_on_corrected_r_solver(lar_term& term, impq& term_max);
|
||||
void pop_core_solver_params();
|
||||
void pop_core_solver_params(unsigned k);
|
||||
void set_upper_bound_witness(var_index j, constraint_index ci);
|
||||
void set_lower_bound_witness(var_index j, constraint_index ci);
|
||||
void substitute_terms_in_linear_expression( const vector<std::pair<mpq, var_index>>& left_side_with_terms,
|
||||
vector<std::pair<mpq, var_index>> &left_side) const;
|
||||
|
||||
void substitute_terms_in_linear_expression(const vector<std::pair<mpq, var_index>>& left_side_with_terms,
|
||||
vector<std::pair<mpq, var_index>>& left_side) const;
|
||||
|
||||
void detect_rows_of_bound_change_column_for_nbasic_column_tableau(unsigned j);
|
||||
bool use_tableau_costs() const;
|
||||
bool tableau_with_costs() const;
|
||||
bool costs_are_used() const;
|
||||
void change_basic_columns_dependend_on_a_given_nb_column(unsigned j, const numeric_pair<mpq> & delta);
|
||||
void change_basic_columns_dependend_on_a_given_nb_column(unsigned j, const numeric_pair<mpq>& delta);
|
||||
void update_x_and_inf_costs_for_column_with_changed_bounds(unsigned j);
|
||||
unsigned num_changed_bounds() const { return m_rows_with_changed_bounds.size(); }
|
||||
void insert_row_with_changed_bounds(unsigned rid);
|
||||
|
@ -209,19 +207,19 @@ class lar_solver : public column_namer {
|
|||
numeric_pair<mpq> get_basic_var_value_from_row(unsigned i);
|
||||
bool all_constrained_variables_are_registered(const vector<std::pair<mpq, var_index>>& left_side);
|
||||
bool all_constraints_hold() const;
|
||||
bool constraint_holds(const lar_base_constraint & constr, std::unordered_map<var_index, mpq> & var_map) const;
|
||||
static void register_in_map(std::unordered_map<var_index, mpq> & coeffs, const lar_base_constraint & cn, const mpq & a);
|
||||
static void register_monoid_in_map(std::unordered_map<var_index, mpq> & coeffs, const mpq & a, unsigned j);
|
||||
bool the_left_sides_sum_to_zero(const vector<std::pair<mpq, unsigned>> & evidence) const;
|
||||
bool constraint_holds(const lar_base_constraint& constr, std::unordered_map<var_index, mpq>& var_map) const;
|
||||
static void register_in_map(std::unordered_map<var_index, mpq>& coeffs, const lar_base_constraint& cn, const mpq& a);
|
||||
static void register_monoid_in_map(std::unordered_map<var_index, mpq>& coeffs, const mpq& a, unsigned j);
|
||||
bool the_left_sides_sum_to_zero(const vector<std::pair<mpq, unsigned>>& evidence) const;
|
||||
bool explanation_is_correct(explanation&) const;
|
||||
bool inf_explanation_is_correct() const;
|
||||
mpq sum_of_right_sides_of_explanation(explanation &) const;
|
||||
mpq sum_of_right_sides_of_explanation(explanation&) const;
|
||||
void get_infeasibility_explanation_for_inf_sign(
|
||||
explanation & exp,
|
||||
const vector<std::pair<mpq, unsigned>> & inf_row,
|
||||
explanation& exp,
|
||||
const vector<std::pair<mpq, unsigned>>& inf_row,
|
||||
int inf_sign) const;
|
||||
mpq get_left_side_val(const lar_base_constraint & cns, const std::unordered_map<var_index, mpq> & var_map) const;
|
||||
void fill_var_set_for_random_update(unsigned sz, var_index const * vars, vector<unsigned>& column_list);
|
||||
mpq get_left_side_val(const lar_base_constraint& cns, const std::unordered_map<var_index, mpq>& var_map) const;
|
||||
void fill_var_set_for_random_update(unsigned sz, var_index const* vars, vector<unsigned>& column_list);
|
||||
bool column_represents_row_in_tableau(unsigned j);
|
||||
void make_sure_that_the_bottom_right_elem_not_zero_in_tableau(unsigned i, unsigned j);
|
||||
void remove_last_row_and_column_from_tableau(unsigned j);
|
||||
|
@ -230,25 +228,25 @@ class lar_solver : public column_namer {
|
|||
void remove_last_column_from_basis_tableau(unsigned j);
|
||||
void remove_last_column_from_tableau();
|
||||
void pop_tableau();
|
||||
void clean_inf_set_of_r_solver_after_pop();
|
||||
void clean_inf_heap_of_r_solver_after_pop();
|
||||
inline bool column_value_is_integer(unsigned j) const { return get_column_value(j).is_int(); }
|
||||
bool model_is_int_feasible() const;
|
||||
|
||||
bool bound_is_integer_for_integer_column(unsigned j, const mpq & right_side) const;
|
||||
inline lar_core_solver & get_core_solver() { return m_mpq_lar_core_solver; }
|
||||
|
||||
bool bound_is_integer_for_integer_column(unsigned j, const mpq& right_side) const;
|
||||
inline lar_core_solver& get_core_solver() { return m_mpq_lar_core_solver; }
|
||||
var_index to_column(unsigned ext_j) const;
|
||||
void fix_terms_with_rounded_columns();
|
||||
bool remove_from_basis(unsigned);
|
||||
lar_term get_term_to_maximize(unsigned ext_j) const;
|
||||
bool sum_first_coords(const lar_term& t, mpq & val) const;
|
||||
bool sum_first_coords(const lar_term& t, mpq& val) const;
|
||||
void register_normalized_term(const lar_term&, lpvar);
|
||||
void deregister_normalized_term(const lar_term&);
|
||||
|
||||
mutable std::unordered_set<impq> m_set_of_different_pairs;
|
||||
mutable std::unordered_set<mpq> m_set_of_different_singles;
|
||||
mutable std::unordered_set<mpq> m_set_of_different_singles;
|
||||
mutable mpq m_delta;
|
||||
|
||||
public:
|
||||
public:
|
||||
// this function just looks at the status
|
||||
bool is_feasible() const;
|
||||
|
||||
|
@ -256,7 +254,6 @@ public:
|
|||
return m_fixed_var_table_int;
|
||||
}
|
||||
|
||||
|
||||
const map<mpq, unsigned, obj_hash<mpq>, default_eq<mpq>>& fixed_var_table_real() const {
|
||||
return m_fixed_var_table_real;
|
||||
}
|
||||
|
@ -265,11 +262,12 @@ public:
|
|||
return m_fixed_var_table_real;
|
||||
}
|
||||
|
||||
bool find_in_fixed_tables(const rational& mpq, bool is_int, unsigned & j) const {
|
||||
return is_int? fixed_var_table_int().find(mpq, j) : fixed_var_table_real().find(mpq, j);
|
||||
bool find_in_fixed_tables(const rational& mpq, bool is_int, unsigned& j) const {
|
||||
return is_int ? fixed_var_table_int().find(mpq, j) : fixed_var_table_real().find(mpq, j);
|
||||
}
|
||||
|
||||
template <typename T> void remove_non_fixed_from_table(T&);
|
||||
|
||||
template <typename T>
|
||||
void remove_non_fixed_from_table(T&);
|
||||
|
||||
unsigned external_to_column_index(unsigned) const;
|
||||
|
||||
|
@ -282,38 +280,38 @@ public:
|
|||
inline void set_column_value_test(unsigned j, const impq& v) {
|
||||
set_column_value(j, v);
|
||||
}
|
||||
|
||||
|
||||
var_index add_named_var(unsigned ext_j, bool is_integer, const std::string&);
|
||||
|
||||
lp_status maximize_term(unsigned j_or_term, impq &term_max);
|
||||
lp_status maximize_term(unsigned j_or_term, impq& term_max);
|
||||
|
||||
inline core_solver_pretty_printer<lp::mpq, lp::impq> pp(std::ostream& out) const {
|
||||
return core_solver_pretty_printer<lp::mpq, lp::impq>(m_mpq_lar_core_solver.m_r_solver, out);
|
||||
inline core_solver_pretty_printer<lp::mpq, lp::impq> pp(std::ostream& out) const {
|
||||
return core_solver_pretty_printer<lp::mpq, lp::impq>(m_mpq_lar_core_solver.m_r_solver, out);
|
||||
}
|
||||
|
||||
void get_infeasibility_explanation(explanation &) const;
|
||||
void get_infeasibility_explanation(explanation&) const;
|
||||
|
||||
inline void backup_x() { m_backup_x = m_mpq_lar_core_solver.m_r_x; }
|
||||
|
||||
inline void restore_x() { m_mpq_lar_core_solver.m_r_x = m_backup_x; }
|
||||
|
||||
template <typename T>
|
||||
void explain_implied_bound(const implied_bound & ib, lp_bound_propagator<T> & bp) {
|
||||
void explain_implied_bound(const implied_bound& ib, lp_bound_propagator<T>& bp) {
|
||||
unsigned i = ib.m_row_or_term_index;
|
||||
int bound_sign = (ib.m_is_lower_bound ? 1 : -1);
|
||||
int j_sign = (ib.m_coeff_before_j_is_pos ? 1 : -1) * bound_sign;
|
||||
unsigned bound_j = ib.m_j;
|
||||
if (tv::is_term(bound_j))
|
||||
if (tv::is_term(bound_j))
|
||||
bound_j = m_var_register.external_to_local(bound_j);
|
||||
|
||||
for (auto const& r : get_row(i)) {
|
||||
unsigned j = r.var();
|
||||
if (j == bound_j)
|
||||
if (j == bound_j)
|
||||
continue;
|
||||
mpq const& a = r.coeff();
|
||||
int a_sign = is_pos(a) ? 1 : -1;
|
||||
int sign = j_sign * a_sign;
|
||||
const ul_pair & ul = m_columns_to_ul_pairs[j];
|
||||
const ul_pair& ul = m_columns_to_ul_pairs[j];
|
||||
auto witness = sign > 0 ? ul.upper_bound_witness() : ul.lower_bound_witness();
|
||||
lp_assert(is_valid(witness));
|
||||
bp.consume(a, witness);
|
||||
|
@ -327,13 +325,13 @@ public:
|
|||
}
|
||||
|
||||
// lp_assert(implied_bound_is_correctly_explained(ib, explanation)); }
|
||||
constraint_index mk_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side);
|
||||
constraint_index mk_var_bound(var_index j, lconstraint_kind kind, const mpq& right_side);
|
||||
void activate_check_on_equal(constraint_index, var_index&);
|
||||
void activate(constraint_index);
|
||||
void random_update(unsigned sz, var_index const * vars);
|
||||
void random_update(unsigned sz, var_index const* vars);
|
||||
void mark_rows_for_bound_prop(lpvar j);
|
||||
template <typename T>
|
||||
void propagate_bounds_for_touched_rows(lp_bound_propagator<T> & bp) {
|
||||
void propagate_bounds_for_touched_rows(lp_bound_propagator<T>& bp) {
|
||||
unsigned num_prop = 0;
|
||||
for (unsigned i : m_rows_with_changed_bounds) {
|
||||
num_prop += calculate_implied_bounds_for_row(i, bp);
|
||||
|
@ -347,7 +345,7 @@ public:
|
|||
bp.clear_for_eq();
|
||||
for (unsigned i : m_rows_with_changed_bounds) {
|
||||
unsigned offset_eqs = stats().m_offset_eqs;
|
||||
bp.cheap_eq_tree(i);
|
||||
bp.cheap_eq_tree(i);
|
||||
if (settings().get_cancel_flag())
|
||||
return;
|
||||
if (stats().m_offset_eqs > offset_eqs)
|
||||
|
@ -358,74 +356,74 @@ public:
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
void check_missed_propagations(lp_bound_propagator<T> & bp) {
|
||||
for (unsigned i = 0; i < A_r().row_count(); i++)
|
||||
if (!m_rows_with_changed_bounds.contains(i))
|
||||
void check_missed_propagations(lp_bound_propagator<T>& bp) {
|
||||
for (unsigned i = 0; i < A_r().row_count(); i++)
|
||||
if (!m_rows_with_changed_bounds.contains(i))
|
||||
if (0 < calculate_implied_bounds_for_row(i, bp)) {
|
||||
verbose_stream() << i << ": " << get_row(i) << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
bool is_fixed_at_bound(column_index const& j);
|
||||
bool has_fixed_at_bound();
|
||||
|
||||
bool is_fixed(column_index const& j) const { return column_is_fixed(j); }
|
||||
bool is_fixed(column_index const& j) const { return column_is_fixed(j); }
|
||||
inline column_index to_column_index(unsigned v) const { return column_index(external_to_column_index(v)); }
|
||||
bool external_is_used(unsigned) const;
|
||||
void pop(unsigned k);
|
||||
bool compare_values(var_index j, lconstraint_kind kind, const mpq & right_side);
|
||||
var_index add_term(const vector<std::pair<mpq, var_index>> & coeffs, unsigned ext_i);
|
||||
bool compare_values(var_index j, lconstraint_kind kind, const mpq& right_side);
|
||||
var_index add_term(const vector<std::pair<mpq, var_index>>& coeffs, unsigned ext_i);
|
||||
void register_existing_terms();
|
||||
constraint_index add_var_bound(var_index, lconstraint_kind, const mpq &);
|
||||
constraint_index add_var_bound_check_on_equal(var_index, lconstraint_kind, const mpq &, var_index&);
|
||||
|
||||
var_index ensure_column(var_index vi);
|
||||
constraint_index add_var_bound(var_index, lconstraint_kind, const mpq&);
|
||||
constraint_index add_var_bound_check_on_equal(var_index, lconstraint_kind, const mpq&, var_index&);
|
||||
|
||||
var_index add_var(unsigned ext_j, bool is_integer);
|
||||
void set_cut_strategy(unsigned cut_frequency);
|
||||
inline unsigned column_count() const { return A_r().column_count(); }
|
||||
inline var_index local_to_external(var_index idx) const {
|
||||
return tv::is_term(idx)?
|
||||
m_term_register.local_to_external(idx) : m_var_register.local_to_external(idx);
|
||||
return tv::is_term(idx) ? m_term_register.local_to_external(idx) : m_var_register.local_to_external(idx);
|
||||
}
|
||||
bool column_corresponds_to_term(unsigned) const;
|
||||
const lar_term& column_to_term(unsigned j) const {
|
||||
SASSERT(column_corresponds_to_term(j));
|
||||
return get_term(column2tv(to_column_index(j)));
|
||||
}
|
||||
|
||||
inline unsigned row_count() const { return A_r().row_count(); }
|
||||
bool var_is_registered(var_index vj) const;
|
||||
void clear_inf_set() {
|
||||
m_mpq_lar_core_solver.m_r_solver.inf_set().clear();
|
||||
void clear_inf_heap() {
|
||||
m_mpq_lar_core_solver.m_r_solver.inf_heap().clear();
|
||||
}
|
||||
inline void remove_column_from_inf_set(unsigned j) {
|
||||
m_mpq_lar_core_solver.m_r_solver.remove_column_from_inf_set(j);
|
||||
|
||||
void pivot(int entering, int leaving) {
|
||||
m_mpq_lar_core_solver.pivot(entering, leaving);
|
||||
}
|
||||
|
||||
template <typename ChangeReport>
|
||||
void change_basic_columns_dependend_on_a_given_nb_column_report(unsigned j,
|
||||
const numeric_pair<mpq> & delta,
|
||||
const numeric_pair<mpq>& delta,
|
||||
const ChangeReport& after) {
|
||||
|
||||
for (const auto & c : A_r().m_columns[j]) {
|
||||
unsigned bj = m_mpq_lar_core_solver.m_r_basis[c.var()];
|
||||
if (tableau_with_costs()) {
|
||||
m_basic_columns_with_changed_cost.insert(bj);
|
||||
}
|
||||
m_mpq_lar_core_solver.m_r_solver.add_delta_to_x_and_track_feasibility(bj, - A_r().get_val(c) * delta);
|
||||
after(bj);
|
||||
TRACE("change_x_del",
|
||||
tout << "changed basis column " << bj << ", it is " <<
|
||||
( m_mpq_lar_core_solver.m_r_solver.column_is_feasible(bj)? "feas":"inf") << std::endl;);
|
||||
}
|
||||
}
|
||||
for (const auto& c : A_r().m_columns[j]) {
|
||||
unsigned bj = m_mpq_lar_core_solver.m_r_basis[c.var()];
|
||||
if (tableau_with_costs())
|
||||
m_basic_columns_with_changed_cost.insert(bj);
|
||||
m_mpq_lar_core_solver.m_r_solver.add_delta_to_x_and_track_feasibility(bj, -A_r().get_val(c) * delta);
|
||||
after(bj);
|
||||
TRACE("change_x_del",
|
||||
tout << "changed basis column " << bj << ", it is " << (m_mpq_lar_core_solver.m_r_solver.column_is_feasible(bj) ? "feas" : "inf") << std::endl;);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ChangeReport>
|
||||
void set_value_for_nbasic_column_report(unsigned j,
|
||||
const impq & new_val,
|
||||
const impq& new_val,
|
||||
const ChangeReport& after) {
|
||||
|
||||
lp_assert(!is_base(j));
|
||||
auto & x = m_mpq_lar_core_solver.m_r_x[j];
|
||||
auto& x = m_mpq_lar_core_solver.m_r_x[j];
|
||||
auto delta = new_val - x;
|
||||
x = new_val;
|
||||
after(j);
|
||||
change_basic_columns_dependend_on_a_given_nb_column_report(j, delta, after);
|
||||
}
|
||||
|
||||
|
||||
template <typename Blocker, typename ChangeReport>
|
||||
bool try_to_patch(lpvar j, const mpq& val,
|
||||
const Blocker& is_blocked,
|
||||
|
@ -442,8 +440,8 @@ public:
|
|||
impq delta = get_column_value(j) - ival;
|
||||
for (auto c : A_r().column(j)) {
|
||||
unsigned row_index = c.var();
|
||||
const mpq & a = c.coeff();
|
||||
unsigned rj = m_mpq_lar_core_solver.m_r_basis[row_index];
|
||||
const mpq& a = c.coeff();
|
||||
unsigned rj = m_mpq_lar_core_solver.m_r_basis[row_index];
|
||||
impq rj_new_val = a * delta + get_column_value(rj);
|
||||
// if (column_is_int(rj) && !rj_new_val.is_int())
|
||||
// return false;
|
||||
|
@ -460,65 +458,63 @@ public:
|
|||
|
||||
inline bool column_has_lower_bound(unsigned j) const {
|
||||
return m_mpq_lar_core_solver.m_r_solver.column_has_lower_bound(j);
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
constraint_index get_column_upper_bound_witness(unsigned j) const {
|
||||
inline constraint_index get_column_upper_bound_witness(unsigned j) const {
|
||||
if (tv::is_term(j)) {
|
||||
j = m_var_register.external_to_local(j);
|
||||
}
|
||||
return m_columns_to_ul_pairs()[j].upper_bound_witness();
|
||||
}
|
||||
|
||||
inline
|
||||
const impq& get_upper_bound(column_index j) const {
|
||||
inline const impq& get_upper_bound(column_index j) const {
|
||||
return m_mpq_lar_core_solver.m_r_solver.m_upper_bounds[j];
|
||||
}
|
||||
|
||||
inline
|
||||
const impq& get_lower_bound(column_index j) const {
|
||||
inline const impq& get_lower_bound(column_index j) const {
|
||||
return m_mpq_lar_core_solver.m_r_solver.m_lower_bounds[j];
|
||||
}
|
||||
bool has_lower_bound(var_index var, constraint_index& ci, mpq& value, bool& is_strict) const;
|
||||
bool has_lower_bound(var_index var, constraint_index& ci, mpq& value, bool& is_strict) const;
|
||||
bool has_upper_bound(var_index var, constraint_index& ci, mpq& value, bool& is_strict) const;
|
||||
bool has_value(var_index var, mpq& value) const;
|
||||
bool fetch_normalized_term_column(const lar_term& t, std::pair<mpq, lpvar>& ) const;
|
||||
bool fetch_normalized_term_column(const lar_term& t, std::pair<mpq, lpvar>&) const;
|
||||
unsigned map_term_index_to_column_index(unsigned j) const;
|
||||
bool column_is_fixed(unsigned j) const;
|
||||
bool column_is_free(unsigned j) const;
|
||||
bool column_is_feasible(unsigned j) const { return m_mpq_lar_core_solver.m_r_solver.column_is_feasible(j);}
|
||||
unsigned column_to_reported_index(unsigned j) const;
|
||||
lp_settings & settings();
|
||||
lp_settings const & settings() const;
|
||||
lp_settings& settings();
|
||||
lp_settings const& settings() const;
|
||||
statistics& stats();
|
||||
|
||||
|
||||
void updt_params(params_ref const& p);
|
||||
column_type get_column_type(unsigned j) const { return m_mpq_lar_core_solver.m_column_types()[j]; }
|
||||
const impq & get_lower_bound(unsigned j) const { return m_mpq_lar_core_solver.m_r_lower_bounds()[j]; }
|
||||
const impq & get_upper_bound(unsigned j) const { return m_mpq_lar_core_solver.m_r_upper_bounds()[j]; }
|
||||
const impq& get_lower_bound(unsigned j) const { return m_mpq_lar_core_solver.m_r_lower_bounds()[j]; }
|
||||
const impq& get_upper_bound(unsigned j) const { return m_mpq_lar_core_solver.m_r_upper_bounds()[j]; }
|
||||
std::ostream& print_terms(std::ostream& out) const;
|
||||
std::ostream& print_term(lar_term const& term, std::ostream & out) const;
|
||||
static std::ostream& print_term_as_indices(lar_term const& term, std::ostream & out);
|
||||
std::ostream& print_constraint_indices_only(const lar_base_constraint * c, std::ostream & out) const;
|
||||
std::ostream& print_implied_bound(const implied_bound& be, std::ostream & out) const;
|
||||
std::ostream& print_term(lar_term const& term, std::ostream& out) const;
|
||||
static std::ostream& print_term_as_indices(lar_term const& term, std::ostream& out);
|
||||
std::ostream& print_constraint_indices_only(const lar_base_constraint* c, std::ostream& out) const;
|
||||
std::ostream& print_implied_bound(const implied_bound& be, std::ostream& out) const;
|
||||
std::ostream& print_values(std::ostream& out) const;
|
||||
std::ostream& display(std::ostream& out) const;
|
||||
|
||||
bool init_model() const;
|
||||
mpq get_value(column_index const& j) const;
|
||||
mpq get_tv_value(tv const& t) const;
|
||||
const impq & get_tv_ivalue(tv const& t) const;
|
||||
void get_model(std::unordered_map<var_index, mpq> & variable_values) const;
|
||||
const impq& get_tv_ivalue(tv const& t) const;
|
||||
void get_model(std::unordered_map<var_index, mpq>& variable_values) const;
|
||||
void get_rid_of_inf_eps();
|
||||
void get_model_do_not_care_about_diff_vars(std::unordered_map<var_index, mpq> & variable_values) const;
|
||||
void get_model_do_not_care_about_diff_vars(std::unordered_map<var_index, mpq>& variable_values) const;
|
||||
std::string get_variable_name(var_index vi) const override;
|
||||
void set_variable_name(var_index vi, std::string);
|
||||
inline unsigned number_of_vars() const { return m_var_register.size(); }
|
||||
inline bool is_base(unsigned j) const { return m_mpq_lar_core_solver.m_r_heading[j] >= 0; }
|
||||
inline const impq & column_lower_bound(unsigned j) const {
|
||||
inline const impq& column_lower_bound(unsigned j) const {
|
||||
return m_mpq_lar_core_solver.lower_bound(j);
|
||||
}
|
||||
|
||||
inline const impq & column_upper_bound(unsigned j) const {
|
||||
inline const impq& column_upper_bound(unsigned j) const {
|
||||
return m_mpq_lar_core_solver.upper_bound(j);
|
||||
}
|
||||
|
||||
|
@ -531,9 +527,9 @@ public:
|
|||
}
|
||||
|
||||
std::pair<constraint_index, constraint_index> add_equality(lpvar j, lpvar k);
|
||||
|
||||
inline void get_bound_constraint_witnesses_for_column(unsigned j, constraint_index & lc, constraint_index & uc) const {
|
||||
const ul_pair & ul = m_columns_to_ul_pairs[j];
|
||||
|
||||
inline void get_bound_constraint_witnesses_for_column(unsigned j, constraint_index& lc, constraint_index& uc) const {
|
||||
const ul_pair& ul = m_columns_to_ul_pairs[j];
|
||||
lc = ul.lower_bound_witness();
|
||||
uc = ul.upper_bound_witness();
|
||||
}
|
||||
|
@ -550,19 +546,19 @@ public:
|
|||
inline tv column2tv(column_index const& c) const {
|
||||
return tv::raw(column_to_reported_index(c));
|
||||
}
|
||||
|
||||
|
||||
inline std::ostream& print_column_info(unsigned j, std::ostream& out) const {
|
||||
m_mpq_lar_core_solver.m_r_solver.print_column_info(j, out);
|
||||
if (tv::is_term(j)) {
|
||||
print_term_as_indices(get_term(j), out) << "\n";
|
||||
|
||||
} else if (column_corresponds_to_term(j)) {
|
||||
|
||||
} else if (column_corresponds_to_term(j)) {
|
||||
const lar_term& t = get_term(m_var_register.local_to_external(j));
|
||||
print_term_as_indices(t, out) << "\n";
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
void subst_known_terms(lar_term*);
|
||||
|
||||
inline std::ostream& print_column_bound_info(unsigned j, std::ostream& out) const {
|
||||
|
@ -573,67 +569,68 @@ public:
|
|||
|
||||
inline bool has_inf_int() const {
|
||||
for (unsigned j = 0; j < column_count(); j++) {
|
||||
if (column_is_int(j) && ! column_value_is_int(j))
|
||||
if (column_is_int(j) && !column_value_is_int(j))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
inline const vector<lar_term*> & terms() const { return m_terms; }
|
||||
inline const vector<lar_term*>& terms() const { return m_terms; }
|
||||
inline lar_term const& term(unsigned i) const { return *m_terms[i]; }
|
||||
inline void set_int_solver(int_solver * int_slv) { m_int_solver = int_slv; }
|
||||
inline int_solver * get_int_solver() { return m_int_solver; }
|
||||
inline const int_solver * get_int_solver() const { return m_int_solver; }
|
||||
inline const lar_term & get_term(tv const& t) const { lp_assert(t.is_term()); return *m_terms[t.id()]; }
|
||||
lp_status find_feasible_solution();
|
||||
inline void set_int_solver(int_solver* int_slv) { m_int_solver = int_slv; }
|
||||
inline int_solver* get_int_solver() { return m_int_solver; }
|
||||
inline const int_solver* get_int_solver() const { return m_int_solver; }
|
||||
inline const lar_term& get_term(tv const& t) const {
|
||||
lp_assert(t.is_term());
|
||||
return *m_terms[t.id()];
|
||||
}
|
||||
lp_status find_feasible_solution();
|
||||
void move_non_basic_columns_to_bounds(bool);
|
||||
bool move_non_basic_column_to_bounds(unsigned j, bool);
|
||||
inline bool r_basis_has_inf_int() const {
|
||||
for (unsigned j : r_basis()) {
|
||||
if (column_is_int(j) && ! column_value_is_int(j))
|
||||
if (column_is_int(j) && !column_value_is_int(j))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void round_to_integer_solution();
|
||||
inline const row_strip<mpq> & get_row(unsigned i) const { return A_r().m_rows[i]; }
|
||||
inline const row_strip<mpq> & basic2row(unsigned i) const { return A_r().m_rows[row_of_basic_column(i)]; }
|
||||
inline const column_strip & get_column(unsigned i) const { return A_r().m_columns[i]; }
|
||||
inline const row_strip<mpq>& get_row(unsigned i) const { return A_r().m_rows[i]; }
|
||||
inline const row_strip<mpq>& basic2row(unsigned i) const { return A_r().m_rows[row_of_basic_column(i)]; }
|
||||
inline const column_strip& get_column(unsigned i) const { return A_r().m_columns[i]; }
|
||||
bool row_is_correct(unsigned i) const;
|
||||
bool ax_is_correct() const;
|
||||
bool get_equality_and_right_side_for_term_on_current_x(tv const& t, mpq &rs, constraint_index& ci, bool &upper_bound) const;
|
||||
bool get_equality_and_right_side_for_term_on_current_x(tv const& t, mpq& rs, constraint_index& ci, bool& upper_bound) const;
|
||||
bool var_is_int(var_index v) const;
|
||||
inline const vector<int> & r_heading() const { return m_mpq_lar_core_solver.m_r_heading; }
|
||||
inline const vector<unsigned> & r_basis() const { return m_mpq_lar_core_solver.r_basis(); }
|
||||
inline const vector<unsigned> & r_nbasis() const { return m_mpq_lar_core_solver.r_nbasis(); }
|
||||
inline bool column_is_real(unsigned j) const { return !column_is_int(j); }
|
||||
inline const vector<int>& r_heading() const { return m_mpq_lar_core_solver.m_r_heading; }
|
||||
inline const vector<unsigned>& r_basis() const { return m_mpq_lar_core_solver.r_basis(); }
|
||||
inline const vector<unsigned>& r_nbasis() const { return m_mpq_lar_core_solver.r_nbasis(); }
|
||||
inline bool column_is_real(unsigned j) const { return !column_is_int(j); }
|
||||
lp_status get_status() const;
|
||||
bool has_changed_columns() const { return !m_columns_with_changed_bounds.empty(); }
|
||||
bool has_changed_columns() const { return !m_columns_with_changed_bounds.empty(); }
|
||||
void set_status(lp_status s);
|
||||
lp_status solve();
|
||||
void fill_explanation_from_crossed_bounds_column(explanation & evidence) const;
|
||||
void fill_explanation_from_crossed_bounds_column(explanation& evidence) const;
|
||||
bool term_is_used_as_row(unsigned term) const;
|
||||
bool tighten_term_bounds_by_delta(tv const& t, const impq&);
|
||||
lar_solver();
|
||||
void set_track_pivoted_rows(bool v);
|
||||
bool get_track_pivoted_rows() const;
|
||||
bool get_track_pivoted_rows() const;
|
||||
~lar_solver() override;
|
||||
const vector<impq>& r_x() const { return m_mpq_lar_core_solver.m_r_x; }
|
||||
bool column_is_int(unsigned j) const;
|
||||
inline bool column_value_is_int(unsigned j) const { return m_mpq_lar_core_solver.m_r_x[j].is_int(); }
|
||||
inline static_matrix<mpq, impq> & A_r() { return m_mpq_lar_core_solver.m_r_A; }
|
||||
inline const static_matrix<mpq, impq> & A_r() const { return m_mpq_lar_core_solver.m_r_A; }
|
||||
inline static_matrix<mpq, impq>& A_r() { return m_mpq_lar_core_solver.m_r_A; }
|
||||
inline const static_matrix<mpq, impq>& A_r() const { return m_mpq_lar_core_solver.m_r_A; }
|
||||
// columns
|
||||
bool column_is_int(column_index const& j) const { return column_is_int((unsigned)j); }
|
||||
// const impq& get_ivalue(column_index const& j) const { return get_column_value(j); }
|
||||
// const impq& get_ivalue(column_index const& j) const { return get_column_value(j); }
|
||||
const impq& get_column_value(column_index const& j) const { return m_mpq_lar_core_solver.m_r_x[j]; }
|
||||
inline
|
||||
var_index external_to_local(unsigned j) const {
|
||||
inline var_index external_to_local(unsigned j) const {
|
||||
var_index local_j;
|
||||
if (m_var_register.external_is_used(j, local_j) ||
|
||||
m_term_register.external_is_used(j, local_j)) {
|
||||
return local_j;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -644,6 +641,5 @@ public:
|
|||
}
|
||||
friend int_solver;
|
||||
friend int_branch;
|
||||
|
||||
};
|
||||
}
|
||||
} // namespace lp
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#pragma once
|
||||
#include "math/lp/indexed_vector.h"
|
||||
#include "util/map.h"
|
||||
|
|
|
@ -17,6 +17,7 @@ Revision History:
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#pragma once
|
||||
namespace lp {
|
||||
enum class lia_move {
|
||||
|
|
|
@ -7,6 +7,7 @@ Author:
|
|||
Nikolaj Bjorner (nbjorner)
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#pragma once
|
||||
|
||||
#include "util/inf_rational.h"
|
||||
|
|
|
@ -4,39 +4,40 @@
|
|||
Nikolaj Bjorner (nbjorner)
|
||||
Lev Nachmanson (levnach)
|
||||
*/
|
||||
//clang-format off
|
||||
#pragma once
|
||||
#include "math/lp/lp_settings.h"
|
||||
#include <utility>
|
||||
|
||||
#include "math/lp/lp_settings.h"
|
||||
#include "util/uint_set.h"
|
||||
namespace lp {
|
||||
template <typename T>
|
||||
class lp_bound_propagator {
|
||||
class edge; // forward definition
|
||||
class edge; // forward definition
|
||||
// vertex represents a column
|
||||
// The set of vertices is organised in a tree.
|
||||
// The set of vertices is organized in a tree.
|
||||
// The edges of the tree are rows,
|
||||
// Vertices with m_neg set to false grow with the same rate as the root.
|
||||
// Vertices with m_neq set to true diminish with the same rate as the roow grows.
|
||||
// When two vertices with the same m_neg have the same value of columns
|
||||
// then we have an equality betweet the columns.
|
||||
class vertex {
|
||||
unsigned m_column;
|
||||
vector<edge> m_edges;
|
||||
edge m_edge_from_parent;
|
||||
unsigned m_level; // the distance in hops to the root;
|
||||
// it is handy to find the common ancestor
|
||||
public:
|
||||
// then we have an equality between the columns.
|
||||
class vertex {
|
||||
unsigned m_column;
|
||||
vector<edge> m_edges;
|
||||
edge m_edge_from_parent;
|
||||
unsigned m_level; // the distance in hops to the root;
|
||||
// it is handy to find the common ancestor
|
||||
public:
|
||||
vertex() {}
|
||||
vertex(unsigned column) :
|
||||
m_column(column),
|
||||
m_level(0)
|
||||
{}
|
||||
vertex(unsigned column) : m_column(column),
|
||||
m_level(0) {}
|
||||
unsigned column() const { return m_column; }
|
||||
const vertex* parent() const { return m_edge_from_parent.source(); }
|
||||
vertex* parent() { return m_edge_from_parent.source(); }
|
||||
unsigned level() const { return m_level; }
|
||||
void set_edge_from_parent(edge &e) { m_edge_from_parent = e; }
|
||||
void set_edge_from_parent(edge& e) { m_edge_from_parent = e; }
|
||||
const edge& edge_from_parent() const { return m_edge_from_parent; }
|
||||
|
||||
|
||||
void add_child(int row, vertex* child) {
|
||||
SASSERT(*this != *child);
|
||||
SASSERT(child->parent() == nullptr);
|
||||
|
@ -45,7 +46,7 @@ class lp_bound_propagator {
|
|||
child->set_edge_from_parent(e);
|
||||
child->m_level = m_level + 1;
|
||||
}
|
||||
const vector<edge> & edges() const { return m_edges; }
|
||||
const vector<edge>& edges() const { return m_edges; }
|
||||
bool operator==(const vertex& o) const {
|
||||
return m_column == o.m_column;
|
||||
}
|
||||
|
@ -58,7 +59,8 @@ class lp_bound_propagator {
|
|||
vertex* m_source;
|
||||
vertex* m_target;
|
||||
int m_row;
|
||||
public:
|
||||
|
||||
public:
|
||||
edge(vertex* source, vertex* target, int row) : m_source(source), m_target(target), m_row(row) {}
|
||||
edge() : m_source(nullptr), m_target(nullptr), m_row(-1) {}
|
||||
const vertex* source() const { return m_source; }
|
||||
|
@ -69,57 +71,58 @@ class lp_bound_propagator {
|
|||
edge reverse() const { return edge(m_target, m_source, m_row); }
|
||||
};
|
||||
|
||||
static int other(int x, int y, int z) { SASSERT(x == z || y == z); return x == z ? y : x; }
|
||||
std::ostream& print_vert(std::ostream & out, const vertex* v) const {
|
||||
static int other(int x, int y, int z) {
|
||||
SASSERT(x == z || y == z);
|
||||
return x == z ? y : x;
|
||||
}
|
||||
std::ostream& print_vert(std::ostream& out, const vertex* v) const {
|
||||
out << "(c = " << v->column() << ", parent = {";
|
||||
if (v->parent())
|
||||
out << "(" << v->parent()->column() << ")";
|
||||
else
|
||||
out << "null";
|
||||
out << "} , lvl = " << v->level();
|
||||
if (m_pol.contains(v->column()))
|
||||
out << (pol(v) == -1? " -":" +");
|
||||
out << "null";
|
||||
out << "} , lvl = " << v->level();
|
||||
if (m_pol.contains(v->column()))
|
||||
out << (pol(v) == -1 ? " -" : " +");
|
||||
else
|
||||
out << " not in m_pol";
|
||||
out << ')';
|
||||
return out;
|
||||
}
|
||||
|
||||
hashtable<unsigned, u_hash, u_eq> m_visited_rows;
|
||||
hashtable<unsigned, u_hash, u_eq> m_visited_columns;
|
||||
u_map<vertex*> m_vertices;
|
||||
vertex* m_root = nullptr;
|
||||
hashtable<unsigned, u_hash, u_eq> m_visited_rows;
|
||||
hashtable<unsigned, u_hash, u_eq> m_visited_columns;
|
||||
u_map<vertex*> m_vertices;
|
||||
vertex* m_root = nullptr;
|
||||
// At some point we can find a row with a single vertex non fixed vertex
|
||||
// then we can fix the whole tree,
|
||||
// by adjusting the vertices offsets, so they become absolute.
|
||||
// If the tree is fixed then in addition to checking with the m_vals_to_verts
|
||||
// we are going to check with the m_fixed_var_tables.
|
||||
const vertex* m_fixed_vertex = nullptr;
|
||||
explanation m_fixed_vertex_explanation;
|
||||
const vertex* m_fixed_vertex = nullptr;
|
||||
explanation m_fixed_vertex_explanation;
|
||||
// a pair (o, j) belongs to m_vals_to_verts iff x[j] = x[m_root->column()] + o
|
||||
map<mpq, const vertex*, obj_hash<mpq>, default_eq<mpq>> m_vals_to_verts;
|
||||
map<mpq, const vertex*, obj_hash<mpq>, default_eq<mpq>> m_vals_to_verts;
|
||||
// a pair (o, j) belongs to m_vals_to_verts_neg iff -x[j] = x[m_root->column()] + o
|
||||
map<mpq, const vertex*, obj_hash<mpq>, default_eq<mpq>> m_vals_to_verts_neg;
|
||||
map<mpq, const vertex*, obj_hash<mpq>, default_eq<mpq>> m_vals_to_verts_neg;
|
||||
// x[m_root->column()] - m_pol[j].pol()*x[j] == const;
|
||||
// to bind polarity and the vertex in the table
|
||||
u_map<int> m_pol;
|
||||
u_map<int> m_pol;
|
||||
// if m_pos.contains(j) then x[j] = x[m_root->column()] + o
|
||||
uint_set m_pos;
|
||||
|
||||
uint_set m_pos;
|
||||
|
||||
// these maps map a column index to the corresponding index in ibounds
|
||||
std::unordered_map<unsigned, unsigned> m_improved_lower_bounds;
|
||||
std::unordered_map<unsigned, unsigned> m_improved_upper_bounds;
|
||||
|
||||
T& m_imp;
|
||||
vector<implied_bound> m_ibounds;
|
||||
std::unordered_map<unsigned, unsigned> m_improved_lower_bounds;
|
||||
std::unordered_map<unsigned, unsigned> m_improved_upper_bounds;
|
||||
|
||||
T& m_imp;
|
||||
vector<implied_bound> m_ibounds;
|
||||
|
||||
map<mpq, unsigned, obj_hash<mpq>, default_eq<mpq>> m_val2fixed_row;
|
||||
|
||||
map<mpq, unsigned, obj_hash<mpq>, default_eq<mpq>> m_val2fixed_row;
|
||||
|
||||
bool is_fixed_row(unsigned r, unsigned & x) {
|
||||
bool is_fixed_row(unsigned r, unsigned& x) {
|
||||
x = UINT_MAX;
|
||||
const auto & row = lp().get_row(r);
|
||||
const auto& row = lp().get_row(r);
|
||||
for (unsigned k = 0; k < row.size(); k++) {
|
||||
const auto& c = row[k];
|
||||
if (column_is_fixed(c.var()))
|
||||
|
@ -130,7 +133,7 @@ class lp_bound_propagator {
|
|||
}
|
||||
return x != UINT_MAX;
|
||||
}
|
||||
|
||||
|
||||
void try_add_equation_with_internal_fixed_tables(unsigned r1) {
|
||||
SASSERT(m_fixed_vertex);
|
||||
unsigned v1, v2;
|
||||
|
@ -154,8 +157,8 @@ class lp_bound_propagator {
|
|||
TRACE("eq", print_row(tout, r1); print_row(tout, r2); tout << v1 << " == " << v2 << " = " << val(v1) << "\n");
|
||||
add_eq_on_columns(ex, v1, v2, true);
|
||||
}
|
||||
|
||||
void try_add_equation_with_lp_fixed_tables(unsigned row_index, const vertex *v) {
|
||||
|
||||
void try_add_equation_with_lp_fixed_tables(unsigned row_index, const vertex* v) {
|
||||
SASSERT(m_fixed_vertex);
|
||||
unsigned v_j = v->column();
|
||||
unsigned j = null_lpvar;
|
||||
|
@ -163,23 +166,24 @@ class lp_bound_propagator {
|
|||
try_add_equation_with_internal_fixed_tables(row_index);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
TRACE("cheap_eq",
|
||||
tout << "v_j = "; lp().print_column_info(v_j, tout) << std::endl;
|
||||
tout << "v_j = ";
|
||||
lp().print_column_info(v_j, tout) << std::endl;
|
||||
tout << "v = "; print_vert(tout, v) << std::endl;
|
||||
tout << "found j " << j << std::endl; lp().print_column_info(j, tout)<< std::endl;
|
||||
tout << "found j " << j << std::endl; lp().print_column_info(j, tout) << std::endl;
|
||||
tout << "found j = " << j << std::endl;);
|
||||
vector<edge> path = connect_in_tree(v, m_fixed_vertex);
|
||||
explanation ex = get_explanation_from_path(path);
|
||||
ex.add_expl(m_fixed_vertex_explanation);
|
||||
explain_fixed_column(j, ex);
|
||||
add_eq_on_columns(ex, j, v_j, true);
|
||||
add_eq_on_columns(ex, j, v_j, true);
|
||||
}
|
||||
|
||||
void try_add_equation_with_val_table(const vertex *v) {
|
||||
void try_add_equation_with_val_table(const vertex* v) {
|
||||
SASSERT(m_fixed_vertex);
|
||||
unsigned v_j = v->column();
|
||||
const vertex *u = nullptr;
|
||||
const vertex* u = nullptr;
|
||||
if (!m_vals_to_verts.find(val(v_j), u)) {
|
||||
m_vals_to_verts.insert(val(v_j), v);
|
||||
return;
|
||||
|
@ -187,7 +191,7 @@ class lp_bound_propagator {
|
|||
unsigned j = u->column();
|
||||
if (j == v_j || is_int(j) != is_int(v_j))
|
||||
return;
|
||||
|
||||
|
||||
TRACE("cheap_eq", tout << "found j=" << j << " for v=";
|
||||
print_vert(tout, v) << "\n in m_vals_to_verts\n";);
|
||||
vector<edge> path = connect_in_tree(u, v);
|
||||
|
@ -198,7 +202,7 @@ class lp_bound_propagator {
|
|||
|
||||
static bool not_set(unsigned j) { return j == UINT_MAX; }
|
||||
static bool is_set(unsigned j) { return j != UINT_MAX; }
|
||||
|
||||
|
||||
void create_root(unsigned row_index) {
|
||||
SASSERT(!m_root && !m_fixed_vertex);
|
||||
unsigned x, y;
|
||||
|
@ -210,31 +214,30 @@ class lp_bound_propagator {
|
|||
}
|
||||
TRACE("cheap_eq", print_row(tout, row_index););
|
||||
m_root = alloc_v(x);
|
||||
set_polarity(m_root, 1); // keep m_root in the positive table
|
||||
set_polarity(m_root, 1); // keep m_root in the positive table
|
||||
if (not_set(y)) {
|
||||
set_fixed_vertex(m_root);
|
||||
explain_fixed_in_row(row_index, m_fixed_vertex_explanation);
|
||||
}
|
||||
else {
|
||||
vertex *v = add_child_with_check(row_index, y, m_root, polarity);
|
||||
} else {
|
||||
vertex* v = add_child_with_check(row_index, y, m_root, polarity);
|
||||
if (v)
|
||||
explore_under(v);
|
||||
}
|
||||
explore_under(m_root);
|
||||
}
|
||||
|
||||
void explore_under(vertex * v) {
|
||||
void explore_under(vertex* v) {
|
||||
check_for_eq_and_add_to_val_tables(v);
|
||||
go_over_vertex_column(v);
|
||||
}
|
||||
|
||||
// In case of only one non fixed column, and the function returns true,
|
||||
// this column would be represened by x.
|
||||
bool is_tree_offset_row(unsigned row_index, unsigned & x, unsigned & y, int & polarity) const {
|
||||
x = y = UINT_MAX;
|
||||
bool is_tree_offset_row(unsigned row_index, unsigned& x, unsigned& y, int& polarity) const {
|
||||
x = y = UINT_MAX;
|
||||
const row_cell<mpq>* x_cell = nullptr;
|
||||
const row_cell<mpq>* y_cell = nullptr;
|
||||
const auto & row = lp().get_row(row_index);
|
||||
const auto& row = lp().get_row(row_index);
|
||||
for (unsigned k = 0; k < row.size(); k++) {
|
||||
const auto& c = row[k];
|
||||
if (column_is_fixed(c.var()))
|
||||
|
@ -242,25 +245,21 @@ class lp_bound_propagator {
|
|||
if (not_set(x)) {
|
||||
if (c.coeff().is_one() || c.coeff().is_minus_one()) {
|
||||
x = c.var();
|
||||
x_cell = & c;
|
||||
}
|
||||
else
|
||||
x_cell = &c;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
else if (not_set(y)) {
|
||||
} else if (not_set(y)) {
|
||||
if (c.coeff().is_one() || c.coeff().is_minus_one()) {
|
||||
y = c.var();
|
||||
y_cell = & c;
|
||||
}
|
||||
else
|
||||
y_cell = &c;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
else
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
if (is_set(x)) {
|
||||
if (is_set(y))
|
||||
polarity = x_cell->coeff().is_pos() == y_cell->coeff().is_pos()? -1 : 1;
|
||||
polarity = x_cell->coeff().is_pos() == y_cell->coeff().is_pos() ? -1 : 1;
|
||||
else
|
||||
polarity = 1;
|
||||
return true;
|
||||
|
@ -268,18 +267,18 @@ class lp_bound_propagator {
|
|||
return false;
|
||||
}
|
||||
|
||||
void go_over_vertex_column(vertex * v) {
|
||||
void go_over_vertex_column(vertex* v) {
|
||||
lpvar j = v->column();
|
||||
if (!check_insert(m_visited_columns, j))
|
||||
return;
|
||||
|
||||
for (const auto & c : lp().get_column(j)) {
|
||||
|
||||
for (const auto& c : lp().get_column(j)) {
|
||||
unsigned row_index = c.var();
|
||||
if (!check_insert(m_visited_rows, row_index))
|
||||
continue;
|
||||
vertex* u = get_child_from_row(row_index, v);
|
||||
if (u)
|
||||
explore_under(u);
|
||||
if (u)
|
||||
explore_under(u);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -295,21 +294,18 @@ class lp_bound_propagator {
|
|||
m_pol.reset();
|
||||
m_vertices.reset();
|
||||
}
|
||||
|
||||
|
||||
struct reset_cheap_eq {
|
||||
lp_bound_propagator& p;
|
||||
reset_cheap_eq(lp_bound_propagator& p):p(p) {}
|
||||
reset_cheap_eq(lp_bound_propagator& p) : p(p) {}
|
||||
~reset_cheap_eq() { p.reset_cheap_eq_eh(); }
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
|
||||
lp_bound_propagator(T& imp):
|
||||
m_imp(imp) {}
|
||||
public:
|
||||
lp_bound_propagator(T& imp) : m_imp(imp) {}
|
||||
|
||||
const vector<implied_bound>& ibounds() const { return m_ibounds; }
|
||||
|
||||
|
||||
void init() {
|
||||
m_improved_upper_bounds.clear();
|
||||
m_improved_lower_bounds.clear();
|
||||
|
@ -318,24 +314,24 @@ public:
|
|||
|
||||
const lar_solver& lp() const { return m_imp.lp(); }
|
||||
lar_solver& lp() { return m_imp.lp(); }
|
||||
|
||||
|
||||
column_type get_column_type(unsigned j) const {
|
||||
return m_imp.lp().get_column_type(j);
|
||||
}
|
||||
|
||||
const impq & get_lower_bound(unsigned j) const {
|
||||
|
||||
const impq& get_lower_bound(unsigned j) const {
|
||||
return m_imp.lp().get_lower_bound(j);
|
||||
}
|
||||
|
||||
const mpq & get_lower_bound_rational(unsigned j) const {
|
||||
const mpq& get_lower_bound_rational(unsigned j) const {
|
||||
return m_imp.lp().get_lower_bound(j).x;
|
||||
}
|
||||
|
||||
const impq & get_upper_bound(unsigned j) const {
|
||||
|
||||
const impq& get_upper_bound(unsigned j) const {
|
||||
return m_imp.lp().get_upper_bound(j);
|
||||
}
|
||||
|
||||
const mpq & get_upper_bound_rational(unsigned j) const {
|
||||
const mpq& get_upper_bound_rational(unsigned j) const {
|
||||
return m_imp.lp().get_upper_bound(j).x;
|
||||
}
|
||||
|
||||
|
@ -343,40 +339,37 @@ public:
|
|||
bool column_is_fixed(lpvar j) const {
|
||||
return lp().column_is_fixed(j) && get_lower_bound(j).y.is_zero();
|
||||
}
|
||||
|
||||
void try_add_bound(mpq const& v, unsigned j, bool is_low, bool coeff_before_j_is_pos, unsigned row_or_term_index, bool strict) {
|
||||
j = m_imp.lp().column_to_reported_index(j);
|
||||
|
||||
lconstraint_kind kind = is_low? GE : LE;
|
||||
void try_add_bound(mpq const& v, unsigned j, bool is_low, bool coeff_before_j_is_pos, unsigned row_or_term_index, bool strict) {
|
||||
j = m_imp.lp().column_to_reported_index(j);
|
||||
|
||||
lconstraint_kind kind = is_low ? GE : LE;
|
||||
if (strict)
|
||||
kind = static_cast<lconstraint_kind>(kind / 2);
|
||||
|
||||
|
||||
if (!m_imp.bound_is_interesting(j, kind, v))
|
||||
return;
|
||||
unsigned k; // index to ibounds
|
||||
unsigned k; // index to ibounds
|
||||
if (is_low) {
|
||||
if (try_get_value(m_improved_lower_bounds, j, k)) {
|
||||
auto & found_bound = m_ibounds[k];
|
||||
auto& found_bound = m_ibounds[k];
|
||||
if (v > found_bound.m_bound || (v == found_bound.m_bound && !found_bound.m_strict && strict)) {
|
||||
found_bound = implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict);
|
||||
TRACE("try_add_bound", m_imp.lp().print_implied_bound(found_bound, tout););
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
m_improved_lower_bounds[j] = m_ibounds.size();
|
||||
m_ibounds.push_back(implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict));
|
||||
TRACE("try_add_bound", m_imp.lp().print_implied_bound(m_ibounds.back(), tout););
|
||||
}
|
||||
}
|
||||
else { // the upper bound case
|
||||
} else { // the upper bound case
|
||||
if (try_get_value(m_improved_upper_bounds, j, k)) {
|
||||
auto & found_bound = m_ibounds[k];
|
||||
auto& found_bound = m_ibounds[k];
|
||||
if (v < found_bound.m_bound || (v == found_bound.m_bound && !found_bound.m_strict && strict)) {
|
||||
found_bound = implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict);
|
||||
TRACE("try_add_bound", m_imp.lp().print_implied_bound(found_bound, tout););
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
m_improved_upper_bounds[j] = m_ibounds.size();
|
||||
m_ibounds.push_back(implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict));
|
||||
TRACE("try_add_bound", m_imp.lp().print_implied_bound(m_ibounds.back(), tout););
|
||||
|
@ -388,18 +381,18 @@ public:
|
|||
m_imp.consume(a, ci);
|
||||
}
|
||||
|
||||
const mpq& val(unsigned j) const {
|
||||
return lp().get_column_value(j).x;
|
||||
const mpq& val(unsigned j) const {
|
||||
return lp().get_column_value(j).x;
|
||||
}
|
||||
|
||||
|
||||
const mpq& val(const vertex* v) const {
|
||||
return val(v->column());
|
||||
}
|
||||
|
||||
bool tree_contains_r(vertex* root, vertex *v) const {
|
||||
|
||||
bool tree_contains_r(vertex* root, vertex* v) const {
|
||||
if (*root == *v)
|
||||
return true;
|
||||
for (auto e : root->edges())
|
||||
for (auto e : root->edges())
|
||||
if (tree_contains_r(e.target(), v))
|
||||
return true;
|
||||
return false;
|
||||
|
@ -415,7 +408,7 @@ public:
|
|||
m_pol.insert(j, p);
|
||||
}
|
||||
|
||||
void check_and_set_polarity(vertex* v, int polarity, unsigned row_index, vertex*v_parent) {
|
||||
void check_and_set_polarity(vertex* v, int polarity, unsigned row_index, vertex* v_parent) {
|
||||
int prev_pol;
|
||||
if (!m_pol.find(v->column(), prev_pol)) {
|
||||
set_polarity(v, polarity);
|
||||
|
@ -429,106 +422,107 @@ public:
|
|||
m_fixed_vertex_explanation = get_explanation_from_path(path);
|
||||
explain_fixed_in_row(row_index, m_fixed_vertex_explanation);
|
||||
set_fixed_vertex(v);
|
||||
TRACE("cheap_eq",
|
||||
tout << "polarity switch: " << polarity << "\nv = "; print_vert(tout , v) << "\nu = "; tout << "fixed vertex explanation\n";
|
||||
for (auto p : m_fixed_vertex_explanation)
|
||||
lp().constraints().display(tout, [this](lpvar j) { return lp().get_variable_name(j);}, p.ci()););
|
||||
|
||||
TRACE("cheap_eq",
|
||||
tout << "polarity switch: " << polarity << "\nv = ";
|
||||
print_vert(tout, v) << "\nu = "; tout << "fixed vertex explanation\n";
|
||||
for (auto p
|
||||
: m_fixed_vertex_explanation)
|
||||
lp()
|
||||
.constraints()
|
||||
.display(
|
||||
tout, [this](lpvar j) { return lp().get_variable_name(j); }, p.ci()););
|
||||
}
|
||||
|
||||
bool tree_contains(vertex *v) const {
|
||||
|
||||
bool tree_contains(vertex* v) const {
|
||||
if (!m_root)
|
||||
return false;
|
||||
return tree_contains_r(m_root, v);
|
||||
}
|
||||
|
||||
vertex * alloc_v(unsigned column) {
|
||||
vertex * v = alloc(vertex, column);
|
||||
|
||||
vertex* alloc_v(unsigned column) {
|
||||
vertex* v = alloc(vertex, column);
|
||||
m_vertices.insert(column, v);
|
||||
SASSERT(!tree_contains(v));
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
unsigned column(unsigned row, unsigned index) {
|
||||
return lp().get_row(row)[index].var();
|
||||
}
|
||||
|
||||
bool fixed_phase() const { return m_fixed_vertex; }
|
||||
|
||||
|
||||
|
||||
// Returns the vertex to start exploration from, or nullptr.
|
||||
// It is assumed that parent->column() is present in the row
|
||||
vertex* get_child_from_row(unsigned row_index, vertex* parent) {
|
||||
TRACE("cheap_eq_det", print_row(tout, row_index););
|
||||
unsigned x, y; int row_polarity;
|
||||
unsigned x, y;
|
||||
int row_polarity;
|
||||
if (!is_tree_offset_row(row_index, x, y, row_polarity)) {
|
||||
TRACE("cheap_eq_det", tout << "not an offset row\n"; );
|
||||
TRACE("cheap_eq_det", tout << "not an offset row\n";);
|
||||
return nullptr;
|
||||
}
|
||||
if (not_set(y)) { // there is only one fixed variable in the row
|
||||
if (not_set(y)) { // there is only one fixed variable in the row
|
||||
if (!fixed_phase()) {
|
||||
set_fixed_vertex(parent);
|
||||
explain_fixed_in_row(row_index, m_fixed_vertex_explanation);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
SASSERT(is_set(x) && is_set(y));
|
||||
unsigned col = other(x, y, parent->column());
|
||||
return add_child_with_check(row_index, col, parent, row_polarity);
|
||||
}
|
||||
|
||||
vertex * add_child_with_check(unsigned row_index, unsigned col, vertex* parent, int row_polarity) {
|
||||
vertex* add_child_with_check(unsigned row_index, unsigned col, vertex* parent, int row_polarity) {
|
||||
vertex* vy;
|
||||
if (m_vertices.find(col, vy)) {
|
||||
SASSERT(vy != nullptr);
|
||||
if (!fixed_phase()) {
|
||||
check_and_set_polarity(vy, pol(parent) * row_polarity, row_index, parent);
|
||||
check_and_set_polarity(vy, pol(parent) * row_polarity, row_index, parent);
|
||||
}
|
||||
return nullptr; // it is not a new vertex
|
||||
}
|
||||
return nullptr; // it is not a new vertex
|
||||
}
|
||||
vy = alloc_v(col);
|
||||
parent->add_child(row_index, vy);
|
||||
if (!fixed_phase())
|
||||
check_and_set_polarity(vy, row_polarity * pol(parent), row_index, parent);
|
||||
return vy;
|
||||
return vy;
|
||||
}
|
||||
|
||||
bool is_equal(lpvar j, lpvar k) const {
|
||||
bool is_equal(lpvar j, lpvar k) const {
|
||||
return m_imp.is_equal(col_to_imp(j), col_to_imp(k));
|
||||
}
|
||||
|
||||
void check_for_eq_and_add_to_val_table(vertex* v, map<mpq, const vertex*, obj_hash<mpq>, default_eq<mpq>>& table) {
|
||||
void check_for_eq_and_add_to_val_table(vertex* v, map<mpq, const vertex*, obj_hash<mpq>, default_eq<mpq>>& table) {
|
||||
TRACE("cheap_eq", tout << "v = "; print_vert(tout, v) << "\n";);
|
||||
const vertex *k; // the other vertex
|
||||
const vertex* k; // the other vertex
|
||||
if (table.find(val(v), k)) {
|
||||
TRACE("cheap_eq", tout << "found k " ; print_vert(tout, k) << "\n";);
|
||||
TRACE("cheap_eq", tout << "found k "; print_vert(tout, k) << "\n";);
|
||||
if (k->column() != v->column() &&
|
||||
is_int(k->column()) == is_int(v->column()) &&
|
||||
!is_equal(k->column(), v->column())) {
|
||||
report_eq(k, v);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
TRACE("cheap_eq", tout << "no report\n";);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
TRACE("cheap_eq", tout << "registered: " << val(v) << " -> { "; print_vert(tout, v) << "} \n";);
|
||||
table.insert(val(v), v);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void check_for_eq_and_add_to_val_tables(vertex* v) {
|
||||
TRACE("cheap_eq_det", print_vert(tout, v) << "\n";);
|
||||
if (!fixed_phase()) {
|
||||
if (pol(v->column()) == -1)
|
||||
check_for_eq_and_add_to_val_table(v, m_vals_to_verts_neg);
|
||||
else
|
||||
else
|
||||
check_for_eq_and_add_to_val_table(v, m_vals_to_verts);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void clear_for_eq() {
|
||||
m_visited_rows.reset();
|
||||
m_visited_columns.reset();
|
||||
|
@ -542,41 +536,40 @@ public:
|
|||
|
||||
std::ostream& print_path(const vector<edge>& path, std::ostream& out) const {
|
||||
out << "path = \n";
|
||||
for (const edge& k : path)
|
||||
for (const edge& k : path)
|
||||
print_edge(k, out) << "\n";
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
// we have v_i and v_j, indices of vertices at the same offsets
|
||||
void report_eq(const vertex* v_i, const vertex* v_j) {
|
||||
SASSERT(v_i != v_j);
|
||||
SASSERT(lp().get_column_value(v_i->column()) == lp().get_column_value(v_j->column()));
|
||||
TRACE("cheap_eq", tout << v_i->column() << " = " << v_j->column() << "\nu = ";
|
||||
print_vert(tout, v_i) << "\nv = "; print_vert(tout, v_j) <<"\n");
|
||||
|
||||
print_vert(tout, v_i) << "\nv = "; print_vert(tout, v_j) << "\n");
|
||||
|
||||
vector<edge> path = connect_in_tree(v_i, v_j);
|
||||
lp::explanation exp = get_explanation_from_path(path);
|
||||
add_eq_on_columns(exp, v_i->column(), v_j->column(), false);
|
||||
|
||||
}
|
||||
|
||||
std::ostream& print_expl(std::ostream & out, const explanation& exp) const {
|
||||
for (auto p : exp)
|
||||
lp().constraints().display(out, [this](lpvar j) { return lp().get_variable_name(j);}, p.ci());
|
||||
std::ostream& print_expl(std::ostream& out, const explanation& exp) const {
|
||||
for (auto p : exp)
|
||||
lp().constraints().display(
|
||||
out, [this](lpvar j) { return lp().get_variable_name(j); }, p.ci());
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
bool add_eq_on_columns(const explanation& exp, lpvar j, lpvar k, bool is_fixed) {
|
||||
SASSERT(j != k);
|
||||
unsigned je = lp().column_to_reported_index(j);
|
||||
unsigned ke = lp().column_to_reported_index(k);
|
||||
TRACE("cheap_eq",
|
||||
tout << "reporting eq " << j << ", " << k << "\n";
|
||||
TRACE("cheap_eq",
|
||||
tout << "reporting eq " << j << ", " << k << "\n";
|
||||
tout << "reported idx " << je << ", " << ke << "\n";
|
||||
print_expl(tout, exp);
|
||||
tout << "theory_vars v" << lp().local_to_external(je) << " == v" << lp().local_to_external(ke) << "\n";
|
||||
);
|
||||
|
||||
tout << "theory_vars v" << lp().local_to_external(je) << " == v" << lp().local_to_external(ke) << "\n";);
|
||||
|
||||
bool added = m_imp.add_eq(je, ke, exp, is_fixed);
|
||||
if (added) {
|
||||
if (is_fixed)
|
||||
|
@ -600,75 +593,75 @@ public:
|
|||
bool is_int(lpvar j) const {
|
||||
return lp().column_is_int(j);
|
||||
}
|
||||
|
||||
|
||||
explanation get_explanation_from_path(vector<edge>& path) const {
|
||||
explanation ex;
|
||||
for (edge &e : path)
|
||||
for (edge& e : path)
|
||||
explain_fixed_in_row(e.row(), ex);
|
||||
return ex;
|
||||
}
|
||||
|
||||
void explain_fixed_in_row(unsigned row, explanation& ex) const {
|
||||
TRACE("cheap_eq", tout << lp().get_row(row) << std::endl);
|
||||
for (const auto & c : lp().get_row(row))
|
||||
if (lp().is_fixed(c.var()))
|
||||
for (const auto& c : lp().get_row(row))
|
||||
if (lp().is_fixed(c.var()))
|
||||
explain_fixed_column(c.var(), ex);
|
||||
}
|
||||
|
||||
void explain_fixed_column(unsigned j, explanation & ex) const {
|
||||
void explain_fixed_column(unsigned j, explanation& ex) const {
|
||||
SASSERT(column_is_fixed(j));
|
||||
constraint_index lc, uc;
|
||||
constraint_index lc, uc;
|
||||
lp().get_bound_constraint_witnesses_for_column(j, lc, uc);
|
||||
ex.push_back(lc);
|
||||
ex.push_back(uc);
|
||||
ex.push_back(uc);
|
||||
}
|
||||
|
||||
|
||||
vector<edge> connect_in_tree(const vertex* u, const vertex* v) const {
|
||||
vector<edge> path;
|
||||
TRACE("cheap_eq_details", tout << "u = " ; print_vert(tout, u); tout << "\nv = ";print_vert(tout, v) << "\n";);
|
||||
TRACE("cheap_eq_details", tout << "u = "; print_vert(tout, u); tout << "\nv = "; print_vert(tout, v) << "\n";);
|
||||
vector<edge> v_branch;
|
||||
// equalize the levels
|
||||
while (u->level() > v->level()) {
|
||||
path.push_back(u->edge_from_parent().reverse());
|
||||
u = u->parent();
|
||||
}
|
||||
|
||||
|
||||
while (u->level() < v->level()) {
|
||||
v_branch.push_back(v->edge_from_parent());
|
||||
v = v->parent();
|
||||
}
|
||||
SASSERT(u->level() == v->level());
|
||||
TRACE("cheap_eq_details", tout << "u = " ; print_vert(tout, u); tout << "\nv = "; print_vert(tout, v) << "\n";);
|
||||
TRACE("cheap_eq_details", tout << "u = "; print_vert(tout, u); tout << "\nv = "; print_vert(tout, v) << "\n";);
|
||||
while (u != v) {
|
||||
path.push_back(u->edge_from_parent().reverse());
|
||||
v_branch.push_back(v->edge_from_parent());
|
||||
u = u->parent();
|
||||
v = v->parent();
|
||||
}
|
||||
for (unsigned i = v_branch.size(); i--; ) {
|
||||
path.push_back(v_branch[i]);
|
||||
for (unsigned i = v_branch.size(); i--;) {
|
||||
path.push_back(v_branch[i]);
|
||||
}
|
||||
TRACE("cheap_eq", print_path(path, tout););
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
bool tree_is_correct() const {
|
||||
std::unordered_set<int> vs;
|
||||
return tree_is_correct(m_root, vs);
|
||||
}
|
||||
|
||||
|
||||
bool tree_is_correct(vertex* v, std::unordered_set<int>& visited_verts) const {
|
||||
if (fixed_phase())
|
||||
return true;
|
||||
if (visited_verts.find(v->column()) != visited_verts.end())
|
||||
if (visited_verts.find(v->column()) != visited_verts.end())
|
||||
return false;
|
||||
visited_verts.insert(v->column());
|
||||
for (auto e : v->edges())
|
||||
for (auto e : v->edges())
|
||||
if (!tree_is_correct(e.target(), visited_verts))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
std::ostream& print_tree(std::ostream & out, vertex* v) const {
|
||||
std::ostream& print_tree(std::ostream& out, vertex* v) const {
|
||||
print_vert(out, v);
|
||||
out << "\nchildren :\n";
|
||||
for (auto c : v->edges()) {
|
||||
|
@ -683,75 +676,74 @@ public:
|
|||
try_add_equation_with_lp_fixed_tables(row_index, v);
|
||||
try_add_equation_with_val_table(v);
|
||||
}
|
||||
|
||||
|
||||
void handle_fixed_phase(unsigned row_index) {
|
||||
if (!fixed_phase())
|
||||
return;
|
||||
const vertex* v = m_root;
|
||||
try_add_equation_with_fixed_tables(row_index, v);
|
||||
for (auto e: v->edges())
|
||||
for (auto e : v->edges())
|
||||
try_add_equation_with_fixed_tables(row_index, e.target());
|
||||
}
|
||||
|
||||
|
||||
void cheap_eq_tree(unsigned row_index) {
|
||||
reset_cheap_eq _reset(*this);
|
||||
TRACE("cheap_eq_det", tout << "row_index = " << row_index << "\n";);
|
||||
if (!check_insert(m_visited_rows, row_index))
|
||||
if (!check_insert(m_visited_rows, row_index))
|
||||
return;
|
||||
create_root(row_index);
|
||||
if (!m_root)
|
||||
return;
|
||||
|
||||
TRACE("cheap_eq", tout << "tree = "; print_tree(tout, m_root) << "\n";);
|
||||
|
||||
TRACE("cheap_eq", tout << "tree = "; print_tree(tout, m_root) << "\n";);
|
||||
SASSERT(tree_is_correct());
|
||||
handle_fixed_phase(row_index);
|
||||
|
||||
|
||||
TRACE("cheap_eq",
|
||||
tout << "done for row_index " << row_index << "\n";
|
||||
tout << "tree size = " << verts_size(););
|
||||
}
|
||||
|
||||
std::ostream& print_row(std::ostream & out, unsigned row_index) const {
|
||||
unsigned x, y; int polarity;
|
||||
std::ostream& print_row(std::ostream& out, unsigned row_index) const {
|
||||
unsigned x, y;
|
||||
int polarity;
|
||||
if (true || !is_tree_offset_row(row_index, x, y, polarity))
|
||||
return lp().get_int_solver()->display_row_info(out, row_index);
|
||||
|
||||
|
||||
bool first = true;
|
||||
for (const auto &c: lp().A_r().m_rows[row_index]) {
|
||||
for (const auto& c : lp().A_r().m_rows[row_index]) {
|
||||
if (lp().column_is_fixed(c.var()))
|
||||
continue;
|
||||
if (c.coeff().is_one()) {
|
||||
if (!first)
|
||||
out << "+";
|
||||
}
|
||||
else if (c.coeff().is_minus_one())
|
||||
out << "-";
|
||||
if (!first)
|
||||
out << "+";
|
||||
} else if (c.coeff().is_minus_one())
|
||||
out << "-";
|
||||
out << lp().get_variable_name(c.var()) << " ";
|
||||
first = false;
|
||||
first = false;
|
||||
}
|
||||
out << "\n";
|
||||
return out;
|
||||
}
|
||||
|
||||
void set_fixed_vertex(vertex *v) {
|
||||
|
||||
void set_fixed_vertex(vertex* v) {
|
||||
TRACE("cheap_eq", if (v) print_vert(tout, v); else tout << "set m_fixed_vertex to nullptr"; tout << "\n";);
|
||||
SASSERT(!m_fixed_vertex || v == nullptr);
|
||||
m_fixed_vertex = v;
|
||||
}
|
||||
|
||||
|
||||
unsigned verts_size() const {
|
||||
return subtree_size(m_root);
|
||||
}
|
||||
|
||||
unsigned subtree_size(vertex* v) const {
|
||||
unsigned r = 1; // 1 for v
|
||||
unsigned r = 1; // 1 for v
|
||||
for (auto e : v->edges())
|
||||
r += subtree_size(e.target());
|
||||
return r;
|
||||
}
|
||||
|
||||
void delete_tree(vertex * v) {
|
||||
|
||||
void delete_tree(vertex* v) {
|
||||
for (auto p : v->edges())
|
||||
delete_tree(p.target());
|
||||
dealloc(v);
|
||||
|
@ -763,7 +755,6 @@ public:
|
|||
return false;
|
||||
table.insert(j);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
} // namespace lp
|
||||
|
|
|
@ -17,6 +17,7 @@ Revision History:
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
@ -63,8 +64,8 @@ template bool lp::lp_core_solver_base<lp::mpq, lp::numeric_pair<lp::mpq> >::colu
|
|||
template bool lp::lp_core_solver_base<lp::mpq, lp::numeric_pair<lp::mpq>>::pivot_column_tableau(unsigned int, unsigned int);
|
||||
template bool lp::lp_core_solver_base<lp::mpq, lp::mpq>::pivot_column_tableau(unsigned int, unsigned int);
|
||||
template void lp::lp_core_solver_base<lp::mpq, lp::numeric_pair<lp::mpq> >::transpose_rows_tableau(unsigned int, unsigned int);
|
||||
template bool lp::lp_core_solver_base<lp::mpq, lp::numeric_pair<lp::mpq> >::inf_set_is_correct() const;
|
||||
template bool lp::lp_core_solver_base<lp::mpq, lp::mpq>::inf_set_is_correct() const;
|
||||
template bool lp::lp_core_solver_base<lp::mpq, lp::numeric_pair<lp::mpq> >::inf_heap_is_correct() const;
|
||||
template bool lp::lp_core_solver_base<lp::mpq, lp::mpq>::inf_heap_is_correct() const;
|
||||
template bool lp::lp_core_solver_base<lp::mpq, lp::numeric_pair<lp::mpq> >::remove_from_basis(unsigned int);
|
||||
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ Revision History:
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#pragma once
|
||||
#include <set>
|
||||
#include "util/vector.h"
|
||||
|
@ -28,9 +29,13 @@ Revision History:
|
|||
#include "math/lp/permutation_matrix.h"
|
||||
#include "math/lp/column_namer.h"
|
||||
#include "math/lp/u_set.h"
|
||||
|
||||
#include "util/heap.h"
|
||||
|
||||
namespace lp {
|
||||
struct lpvar_lt {
|
||||
bool operator()(lpvar v1, lpvar v2) const { return v1 < v2; }
|
||||
};
|
||||
typedef heap<lpvar_lt> lpvar_heap;
|
||||
template <typename T, typename X>
|
||||
X dot_product(const vector<T> & a, const vector<X> & b) {
|
||||
lp_assert(a.size() == b.size());
|
||||
|
@ -50,25 +55,25 @@ private:
|
|||
lp_status m_status;
|
||||
public:
|
||||
bool current_x_is_feasible() const {
|
||||
TRACE("feas",
|
||||
if (m_inf_set.size()) {
|
||||
tout << "column " << *m_inf_set.begin() << " is infeasible" << std::endl;
|
||||
print_column_info(*m_inf_set.begin(), tout);
|
||||
TRACE("feas_bug",
|
||||
if (!m_inf_heap.empty()) {
|
||||
tout << "column " << *m_inf_heap.begin() << " is infeasible" << std::endl;
|
||||
print_column_info(*m_inf_heap.begin(), tout);
|
||||
} else {
|
||||
tout << "x is feasible\n";
|
||||
}
|
||||
);
|
||||
return m_inf_set.size() == 0;
|
||||
return m_inf_heap.empty();
|
||||
}
|
||||
bool current_x_is_infeasible() const { return m_inf_set.size() != 0; }
|
||||
bool current_x_is_infeasible() const { return m_inf_heap.size() != 0; }
|
||||
private:
|
||||
u_set m_inf_set;
|
||||
lpvar_heap m_inf_heap;
|
||||
public:
|
||||
const u_set& inf_set() const { return m_inf_set; }
|
||||
u_set& inf_set() { return m_inf_set; }
|
||||
void inf_set_increase_size_by_one() { m_inf_set.increase_size_by_one(); }
|
||||
bool inf_set_contains(unsigned j) const { return m_inf_set.contains(j); }
|
||||
unsigned inf_set_size() const { return m_inf_set.size(); }
|
||||
const lpvar_heap& inf_heap() const { return m_inf_heap; }
|
||||
lpvar_heap& inf_heap() { return m_inf_heap; }
|
||||
void inf_heap_increase_size_by_one() { m_inf_heap.reserve(m_inf_heap.size() + 1); }
|
||||
bool inf_heap_contains(unsigned j) const { return m_inf_heap.contains(j); }
|
||||
unsigned inf_heap_size() const { return m_inf_heap.size(); }
|
||||
indexed_vector<T> m_pivot_row; // this is the real pivot row of the simplex tableu
|
||||
static_matrix<T, X> & m_A; // the matrix A
|
||||
// vector<X> const & m_b; // the right side
|
||||
|
@ -255,7 +260,7 @@ public:
|
|||
|
||||
bool calc_current_x_is_feasible_include_non_basis() const;
|
||||
|
||||
bool inf_set_is_correct() const;
|
||||
bool inf_heap_is_correct() const;
|
||||
|
||||
bool column_is_dual_feasible(unsigned j) const;
|
||||
|
||||
|
@ -304,9 +309,9 @@ public:
|
|||
case column_type::boxed:
|
||||
if (x < m_lower_bounds[j]) {
|
||||
delta = m_lower_bounds[j] - x;
|
||||
ret = true;;
|
||||
ret = true;
|
||||
}
|
||||
if (x > m_upper_bounds[j]) {
|
||||
else if (x > m_upper_bounds[j]) {
|
||||
delta = m_upper_bounds[j] - x;
|
||||
ret = true;
|
||||
}
|
||||
|
@ -526,63 +531,55 @@ public:
|
|||
swap(m_basis_heading, m_basis[i], m_basis[ii]);
|
||||
}
|
||||
|
||||
bool column_is_in_inf_set(unsigned j) const {
|
||||
return m_inf_set.contains(j);
|
||||
bool column_is_in_inf_heap(unsigned j) const {
|
||||
return m_inf_heap.contains(j);
|
||||
}
|
||||
|
||||
bool column_is_base(unsigned j) const {
|
||||
return m_basis_heading[j] >= 0;
|
||||
}
|
||||
|
||||
|
||||
void update_x_with_feasibility_tracking(unsigned j, const X & v) {
|
||||
TRACE("lar_solver", tout << "j = " << j << ", v = " << v << "\n";);
|
||||
m_x[j] = v;
|
||||
track_column_feasibility(j);
|
||||
}
|
||||
|
||||
void add_delta_to_x_and_track_feasibility(unsigned j, const X & del) {
|
||||
TRACE("lar_solver", tout << "del = " << del << ", was x[" << j << "] = " << m_x[j] << "\n";);
|
||||
TRACE("lar_solver_feas_bug", tout << "del = " << del << ", was x[" << j << "] = " << m_x[j] << "\n";);
|
||||
m_x[j] += del;
|
||||
TRACE("lar_solver", tout << "became x[" << j << "] = " << m_x[j] << "\n";);
|
||||
TRACE("lar_solver_feas_bug", tout << "became x[" << j << "] = " << m_x[j] << "\n";);
|
||||
track_column_feasibility(j);
|
||||
}
|
||||
|
||||
void update_x(unsigned j, const X & v) {
|
||||
TRACE("lar_solver", tout << "j = " << j << ", v = " << v << "\n";);
|
||||
m_x[j] = v;
|
||||
TRACE("lar_solver_feas", tout << "not tracking feas j = " << j << ", v = " << v << (column_is_feasible(j)? " feas":" non-feas") << "\n";);
|
||||
}
|
||||
|
||||
void add_delta_to_x(unsigned j, const X & delta) {
|
||||
TRACE("lar_solver", tout << "j = " << j << ", delta = " << delta << "\n";);
|
||||
void add_delta_to_x(unsigned j, const X& delta) {
|
||||
m_x[j] += delta;
|
||||
TRACE("lar_solver_feas", tout << "not tracking feas j = " << j << " v = " << m_x[j] << " delta = " << delta << (column_is_feasible(j) ? " feas" : " non-feas") << "\n";);
|
||||
}
|
||||
|
||||
|
||||
void track_column_feasibility(unsigned j) {
|
||||
if (column_is_feasible(j))
|
||||
remove_column_from_inf_set(j);
|
||||
remove_column_from_inf_heap(j);
|
||||
else
|
||||
insert_column_into_inf_set(j);
|
||||
insert_column_into_inf_heap(j);
|
||||
}
|
||||
void insert_column_into_inf_set(unsigned j) {
|
||||
TRACE("lar_solver", tout << "j = " << j << "\n";);
|
||||
m_inf_set.insert(j);
|
||||
void insert_column_into_inf_heap(unsigned j) {
|
||||
if (!m_inf_heap.contains(j)) {
|
||||
m_inf_heap.insert(j);
|
||||
TRACE("lar_solver_inf_heap", tout << "insert into inf_heap j = " << j << "\n";);
|
||||
}
|
||||
lp_assert(!column_is_feasible(j));
|
||||
}
|
||||
void remove_column_from_inf_set(unsigned j) {
|
||||
TRACE("lar_solver", tout << "j = " << j << "\n";);
|
||||
m_inf_set.erase(j);
|
||||
void remove_column_from_inf_heap(unsigned j) {
|
||||
if (m_inf_heap.contains(j)) {
|
||||
TRACE("lar_solver_inf_heap", tout << "insert into heap j = " << j << "\n";);
|
||||
m_inf_heap.erase(j);
|
||||
}
|
||||
lp_assert(column_is_feasible(j));
|
||||
}
|
||||
|
||||
void resize_inf_set(unsigned size) {
|
||||
TRACE("lar_solver",);
|
||||
m_inf_set.resize(size);
|
||||
}
|
||||
|
||||
void clear_inf_set() {
|
||||
TRACE("lar_solver",);
|
||||
m_inf_set.clear();
|
||||
void clear_inf_heap() {
|
||||
TRACE("lar_solver_feas",);
|
||||
m_inf_heap.clear();
|
||||
}
|
||||
|
||||
bool costs_on_nbasis_are_zeros() const {
|
||||
|
|
|
@ -17,6 +17,7 @@ Revision History:
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
|
@ -42,7 +43,7 @@ lp_core_solver_base(static_matrix<T, X> & A,
|
|||
m_total_iterations(0),
|
||||
m_iters_with_no_cost_growing(0),
|
||||
m_status(lp_status::FEASIBLE),
|
||||
m_inf_set(A.column_count()),
|
||||
m_inf_heap(std::max(static_cast<unsigned>(1024), A.column_count())),
|
||||
m_pivot_row(A.column_count()),
|
||||
m_A(A),
|
||||
m_basis(basis),
|
||||
|
@ -250,9 +251,9 @@ template <typename T, typename X> bool lp_core_solver_base<T, X>::calc_current_x
|
|||
return true;
|
||||
}
|
||||
|
||||
template <typename T, typename X> bool lp_core_solver_base<T, X>::inf_set_is_correct() const {
|
||||
template <typename T, typename X> bool lp_core_solver_base<T, X>::inf_heap_is_correct() const {
|
||||
for (unsigned j = 0; j < this->m_n(); j++) {
|
||||
bool belongs_to_set = m_inf_set.contains(j);
|
||||
bool belongs_to_set = m_inf_heap.contains(j);
|
||||
bool is_feas = column_is_feasible(j);
|
||||
if (is_feas == belongs_to_set) {
|
||||
TRACE("lp_core", tout << "incorrectly set column in inf set "; print_column_info(j, tout) << "\n";);
|
||||
|
|
|
@ -17,6 +17,7 @@ Revision History:
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue