3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-26 18:45:33 +00:00

Merge branch 'master' of https://github.com/z3prover/z3 into opt

This commit is contained in:
Nikolaj Bjorner 2017-05-22 12:59:36 -07:00
commit f698efa403
92 changed files with 8030 additions and 1822 deletions

View file

@ -274,18 +274,6 @@ else()
message(STATUS "Not using libgmp")
endif()
################################################################################
# FOCI2 support
################################################################################
# FIXME: What is this?
option(USE_FOCI2 "Use FOCI2" OFF)
if (USE_FOCI2)
message(FATAL_ERROR "TODO")
message(STATUS "Using FOCI2")
else()
message(STATUS "Not using FOCI2")
endif()
################################################################################
# OpenMP support
################################################################################
@ -318,6 +306,23 @@ else()
set(USE_OPENMP OFF CACHE BOOL "Use OpenMP" FORCE)
endif()
################################################################################
# API Log sync
################################################################################
option(API_LOG_SYNC
"Use locking when logging Z3 API calls (experimental)"
OFF
)
if (API_LOG_SYNC)
if (NOT USE_OPENMP)
message(FATAL_ERROR "API_LOG_SYNC feature requires OpenMP")
endif()
list(APPEND Z3_COMPONENT_CXX_DEFINES "-DZ3_LOG_SYNC")
message(STATUS "Using API_LOG_SYNC")
else()
message(STATUS "Not using API_LOG_SYNC")
endif()
################################################################################
# FP math
################################################################################

View file

@ -1,4 +1,4 @@
# Z3's CMake build system
# Z3's CMake build system
[CMake](https://cmake.org/) is a "meta build system" that reads a description
of the project written in the ``CMakeLists.txt`` files and emits a build
@ -293,6 +293,7 @@ The following useful options can be passed to CMake whilst configuring.
* ``ALWAYS_BUILD_DOCS`` - BOOL. If set to ``TRUE`` and ``BUILD_DOCUMENTATION`` is ``TRUE`` then documentation for API bindings will always be built.
Disabling this is useful for faster incremental builds. The documentation can be manually built by invoking the ``api_docs`` target.
* ``LINK_TIME_OPTIMIZATION`` - BOOL. If set to ``TRUE`` link time optimization will be enabled.
* ``API_LOG_SYNC`` - BOOL. If set to ``TRUE`` will enable experimental API log sync feature.
On the command line these can be passed to ``cmake`` using the ``-D`` option. In ``ccmake`` and ``cmake-gui`` these can be set in the user interface.

View file

@ -2,7 +2,6 @@ z3_add_component(interp
SOURCES
iz3base.cpp
iz3checker.cpp
iz3foci.cpp
iz3interp.cpp
iz3mgr.cpp
iz3pp.cpp

View file

@ -132,13 +132,5 @@ target_include_directories(test-z3 PRIVATE ${Z3_COMPONENT_EXTRA_INCLUDE_DIRS})
z3_append_linker_flag_list_to_target(test-z3 ${Z3_DEPENDENT_EXTRA_CXX_LINK_FLAGS})
z3_add_component_dependencies_to_target(test-z3 ${z3_test_expanded_deps})
add_executable(lp_tst lp_main.cpp lp.cpp $<TARGET_OBJECTS:util> $<TARGET_OBJECTS:lp>)
target_compile_definitions(lp_tst PRIVATE ${Z3_COMPONENT_CXX_DEFINES})
target_compile_options(lp_tst PRIVATE ${Z3_COMPONENT_CXX_FLAGS})
target_include_directories(lp_tst PRIVATE ${Z3_COMPONENT_EXTRA_INCLUDE_DIRS})
target_link_libraries(lp_tst PRIVATE ${Z3_DEPENDENT_LIBS})
z3_append_linker_flag_list_to_target(lp_tst ${Z3_DEPENDENT_EXTRA_CXX_LINK_FLAGS})

View file

@ -0,0 +1,35 @@
z3_add_component(lp
SOURCES
lp_utils.cpp
binary_heap_priority_queue_instances.cpp
binary_heap_upair_queue_instances.cpp
bound_propagator.cpp
core_solver_pretty_printer_instances.cpp
dense_matrix_instances.cpp
eta_matrix_instances.cpp
indexed_vector_instances.cpp
lar_core_solver_instances.cpp
lp_core_solver_base_instances.cpp
lp_dual_core_solver_instances.cpp
lp_dual_simplex_instances.cpp
lp_primal_core_solver_instances.cpp
lp_primal_simplex_instances.cpp
lp_settings_instances.cpp
lp_solver_instances.cpp
lu_instances.cpp
matrix_instances.cpp
permutation_matrix_instances.cpp
quick_xplain.cpp
row_eta_matrix_instances.cpp
scaler_instances.cpp
sparse_matrix_instances.cpp
square_dense_submatrix_instances.cpp
static_matrix_instances.cpp
random_updater_instances.cpp
COMPONENT_DEPENDENCIES
util
PYG_FILES
lp_params.pyg
)
include_directories(${src_SOURCE_DIR})

View file

@ -96,8 +96,6 @@ VER_BUILD=None
VER_REVISION=None
PREFIX=sys.prefix
GMP=False
FOCI2=False
FOCI2LIB=''
VS_PAR=False
VS_PAR_NUM=8
GPROF=False
@ -257,13 +255,6 @@ def test_gmp(cc):
t.commit()
return exec_compiler_cmd([cc, CPPFLAGS, 'tstgmp.cpp', LDFLAGS, '-lgmp']) == 0
def test_foci2(cc,foci2lib):
if is_verbose():
print("Testing FOCI2...")
t = TempFile('tstfoci2.cpp')
t.add('#include<foci2.h>\nint main() { foci2 *f = foci2::create("lia"); return 0; }\n')
t.commit()
return exec_compiler_cmd([cc, CPPFLAGS, '-Isrc/interp', 'tstfoci2.cpp', LDFLAGS, foci2lib]) == 0
def test_openmp(cc):
if not USE_OMP:
@ -650,7 +641,6 @@ def display_help(exit_code):
if not IS_WINDOWS:
print(" -g, --gmp use GMP.")
print(" --gprof enable gprof")
print(" -f <path> --foci2=<path> use foci2 library at path")
print(" --noomp disable OpenMP and all features that require it.")
print(" --log-sync synchronize access to API log files to enable multi-thread API logging.")
print("")
@ -678,13 +668,13 @@ def display_help(exit_code):
# Parse configuration option for mk_make script
def parse_options():
global VERBOSE, DEBUG_MODE, IS_WINDOWS, VS_X64, ONLY_MAKEFILES, SHOW_CPPS, VS_PROJ, TRACE, VS_PAR, VS_PAR_NUM
global DOTNET_ENABLED, DOTNET_KEY_FILE, JAVA_ENABLED, ML_ENABLED, STATIC_LIB, STATIC_BIN, PREFIX, GMP, FOCI2, FOCI2LIB, PYTHON_PACKAGE_DIR, GPROF, GIT_HASH, GIT_DESCRIBE, PYTHON_INSTALL_ENABLED, PYTHON_ENABLED
global DOTNET_ENABLED, DOTNET_KEY_FILE, JAVA_ENABLED, ML_ENABLED, STATIC_LIB, STATIC_BIN, PREFIX, GMP, PYTHON_PACKAGE_DIR, GPROF, GIT_HASH, GIT_DESCRIBE, PYTHON_INSTALL_ENABLED, PYTHON_ENABLED
global LINUX_X64, SLOW_OPTIMIZE, USE_OMP, LOG_SYNC
try:
options, remainder = getopt.gnu_getopt(sys.argv[1:],
'b:df:sxhmcvtnp:gj',
['build=', 'debug', 'silent', 'x64', 'help', 'makefiles', 'showcpp', 'vsproj',
'trace', 'dotnet', 'dotnet-key=', 'staticlib', 'prefix=', 'gmp', 'foci2=', 'java', 'parallel=', 'gprof',
'trace', 'dotnet', 'dotnet-key=', 'staticlib', 'prefix=', 'gmp', 'java', 'parallel=', 'gprof',
'githash=', 'git-describe', 'x86', 'ml', 'optimize', 'noomp', 'pypkgdir=', 'python', 'staticbin', 'log-sync'])
except:
print("ERROR: Invalid command line option")
@ -735,9 +725,6 @@ def parse_options():
VS_PAR_NUM = int(arg)
elif opt in ('-g', '--gmp'):
GMP = True
elif opt in ('-f', '--foci2'):
FOCI2 = True
FOCI2LIB = arg
elif opt in ('-j', '--java'):
JAVA_ENABLED = True
elif opt == '--gprof':
@ -778,7 +765,7 @@ def extract_c_includes(fname):
root_file_name = m1.group(1)
slash_pos = root_file_name.rfind('/')
if slash_pos >= 0 and root_file_name.find("..") < 0 : #it is a hack for lp include files that behave as continued from "src"
print(root_file_name)
# print(root_file_name)
root_file_name = root_file_name[slash_pos+1:]
result.append(root_file_name)
elif not system_inc_pat.match(line) and non_std_inc_pat.match(line):
@ -1004,7 +991,7 @@ class Component:
out.write('%s =' % include_defs)
for dep in self.deps:
out.write(' -I%s' % get_component(dep).to_src_dir)
out.write(' -I..\src')
out.write(' -I%s' % os.path.join(REV_BUILD_DIR,"src"))
out.write('\n')
mk_dir(os.path.join(BUILD_DIR, self.build_dir))
if VS_PAR and IS_WINDOWS:
@ -1181,7 +1168,6 @@ class ExeComponent(Component):
for dep in deps:
c_dep = get_component(dep)
out.write(' ' + c_dep.get_link_name())
out.write(' ' + FOCI2LIB)
out.write(' $(LINK_EXTRA_FLAGS)\n')
out.write('%s: %s\n\n' % (self.name, exefile))
@ -1307,7 +1293,6 @@ class DLLComponent(Component):
if dep not in self.reexports:
c_dep = get_component(dep)
out.write(' ' + c_dep.get_link_name())
out.write(' ' + FOCI2LIB)
out.write(' $(SLINK_EXTRA_FLAGS)')
if IS_WINDOWS:
out.write(' /DEF:%s.def' % os.path.join(self.to_src_dir, self.name))
@ -2307,7 +2292,7 @@ def mk_config():
if ONLY_MAKEFILES:
return
config = open(os.path.join(BUILD_DIR, 'config.mk'), 'w')
global CXX, CC, GMP, FOCI2, CPPFLAGS, CXXFLAGS, LDFLAGS, EXAMP_DEBUG_FLAG, FPMATH_FLAGS, HAS_OMP, LOG_SYNC
global CXX, CC, GMP, CPPFLAGS, CXXFLAGS, LDFLAGS, EXAMP_DEBUG_FLAG, FPMATH_FLAGS, HAS_OMP, LOG_SYNC
if IS_WINDOWS:
config.write(
'CC=cl\n'
@ -2417,14 +2402,6 @@ def mk_config():
SLIBEXTRAFLAGS = '%s -lgmp' % SLIBEXTRAFLAGS
else:
CPPFLAGS = '%s -D_MP_INTERNAL' % CPPFLAGS
if FOCI2:
if test_foci2(CXX,FOCI2LIB):
LDFLAGS = '%s %s' % (LDFLAGS,FOCI2LIB)
SLIBEXTRAFLAGS = '%s %s' % (SLIBEXTRAFLAGS,FOCI2LIB)
CPPFLAGS = '%s -D_FOCI2' % CPPFLAGS
else:
print("FAILED\n")
FOCI2 = False
if GIT_HASH:
CPPFLAGS = '%s -DZ3GITHASH=%s' % (CPPFLAGS, GIT_HASH)
CXXFLAGS = '%s -std=c++11' % CXXFLAGS
@ -2959,7 +2936,11 @@ def get_platform_toolset_str():
if len(tokens) < 2:
return default
else:
return 'v' + tokens[0] + tokens[1]
if tokens[0] == "15":
# Visual Studio 2017 reports 15.* but the PlatformToolsetVersion is 141
return "v141"
else:
return 'v' + tokens[0] + tokens[1]
def mk_vs_proj_property_groups(f, name, target_ext, type):
f.write(' <ItemGroup Label="ProjectConfigurations">\n')

View file

@ -62,4 +62,4 @@ namespace System.Diagnostics.Contracts
public static void EndContractBlock() { }
public static T ValueAtReturn<T>(out T v) { T[] t = new T[1]; v = t[0]; return v; }
}
}
}

View file

@ -3,4 +3,4 @@
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
</configuration>
</configuration>

View file

@ -75,4 +75,4 @@
<Target Name="AfterBuild">
</Target>
-->
</Project>
</Project>

View file

@ -344,4 +344,4 @@
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
</Project>

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Code.Contract" version="1.0.0" targetFramework="net35" />
</packages>
</packages>

View file

@ -164,6 +164,6 @@ setup(
package_data={
'z3': [os.path.join('lib', '*'), os.path.join('include', '*.h'), os.path.join('include', 'c++', '*.h')]
},
scripts=[os.path.join('bin', EXECUTABLE_FILE)],
data_files=[('bin',[os.path.join('bin',EXECUTABLE_FILE)])],
cmdclass={'build': build, 'develop': develop, 'sdist': sdist, 'bdist_egg': bdist_egg},
)

View file

@ -1300,8 +1300,10 @@ class BoolSortRef(SortRef):
if isinstance(val, bool):
return BoolVal(val, self.ctx)
if __debug__:
_z3_assert(is_expr(val), "True, False or Z3 Boolean expression expected. Received %s" % val)
_z3_assert(self.eq(val.sort()), "Value cannot be converted into a Z3 Boolean value")
if not is_expr(val):
_z3_assert(is_expr(val), "True, False or Z3 Boolean expression expected. Received %s" % val)
if not self.eq(val.sort()):
_z3_assert(self.eq(val.sort()), "Value cannot be converted into a Z3 Boolean value")
return val
def subsort(self, other):

View file

@ -440,24 +440,16 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
* (seq.unit (_ BitVector 8)) ==> String constant
*/
br_status seq_rewriter::mk_seq_unit(expr* e, expr_ref& result) {
sort * s = m().get_sort(e);
bv_util bvu(m());
if (is_sort_of(s, bvu.get_family_id(), BV_SORT)) {
// specifically we want (_ BitVector 8)
rational n_val;
unsigned int n_size;
if (bvu.is_numeral(e, n_val, n_size)) {
if (n_size == 8) {
// convert to string constant
char ch = (char)n_val.get_int32();
TRACE("seq", tout << "rewrite seq.unit of 8-bit value " << n_val.to_string() << " to string constant \"" << ch << "\"" << std::endl;);
char s_tmp[2] = {ch, '\0'};
symbol s(s_tmp);
result = m_util.str.mk_string(s);
return BR_DONE;
}
}
rational n_val;
unsigned int n_size;
// specifically we want (_ BitVector 8)
if (bvu.is_bv(e) && bvu.is_numeral(e, n_val, n_size) && n_size == 8) {
// convert to string constant
zstring str(n_val.get_unsigned());
TRACE("seq", tout << "rewrite seq.unit of 8-bit value " << n_val.to_string() << " to string constant \"" << str<< "\"" << std::endl;);
result = m_util.str.mk_string(str);
return BR_DONE;
}
return BR_FAILED;
@ -1431,37 +1423,10 @@ br_status seq_rewriter::mk_re_star(expr* a, expr_ref& result) {
}
/*
* (re.range c_1 c_n) = (re.union (str.to.re c1) (str.to.re c2) ... (str.to.re cn))
* (re.range c_1 c_n)
*/
br_status seq_rewriter::mk_re_range(expr* lo, expr* hi, expr_ref& result) {
return BR_FAILED;
TRACE("seq", tout << "rewrite re.range [" << mk_pp(lo, m()) << " " << mk_pp(hi, m()) << "]\n";);
zstring str_lo, str_hi;
if (m_util.str.is_string(lo, str_lo) && m_util.str.is_string(hi, str_hi)) {
if (str_lo.length() == 1 && str_hi.length() == 1) {
unsigned int c1 = str_lo[0];
unsigned int c2 = str_hi[0];
if (c1 > c2) {
// exchange c1 and c2
unsigned int tmp = c1;
c2 = c1;
c1 = tmp;
}
zstring s(c1);
expr_ref acc(m_util.re.mk_to_re(m_util.str.mk_string(s)), m());
for (unsigned int ch = c1 + 1; ch <= c2; ++ch) {
zstring s_ch(ch);
expr_ref acc2(m_util.re.mk_to_re(m_util.str.mk_string(s_ch)), m());
acc = m_util.re.mk_union(acc, acc2);
}
result = acc;
return BR_REWRITE2;
} else {
m().raise_exception("string constants in re.range must have length 1");
}
}
return BR_FAILED;
}
/*
@ -1506,6 +1471,7 @@ br_status seq_rewriter::mk_re_opt(expr* a, expr_ref& result) {
}
br_status seq_rewriter::mk_eq_core(expr * l, expr * r, expr_ref & result) {
TRACE("seq", tout << mk_pp(l, m()) << " = " << mk_pp(r, m()) << "\n";);
expr_ref_vector lhs(m()), rhs(m()), res(m());
bool changed = false;
if (!reduce_eq(l, r, lhs, rhs, changed)) {

View file

@ -876,6 +876,36 @@ bool seq_decl_plugin::is_value(app* e) const {
}
}
bool seq_decl_plugin::are_equal(app* a, app* b) const {
if (a == b) return true;
// handle concatenations
return false;
}
bool seq_decl_plugin::are_distinct(app* a, app* b) const {
if (a == b) {
return false;
}
if (is_app_of(a, m_family_id, OP_STRING_CONST) &&
is_app_of(b, m_family_id, OP_STRING_CONST)) {
return true;
}
if (is_app_of(a, m_family_id, OP_SEQ_UNIT) &&
is_app_of(b, m_family_id, OP_SEQ_UNIT)) {
return true;
}
if (is_app_of(a, m_family_id, OP_SEQ_EMPTY) &&
is_app_of(b, m_family_id, OP_SEQ_UNIT)) {
return true;
}
if (is_app_of(b, m_family_id, OP_SEQ_EMPTY) &&
is_app_of(a, m_family_id, OP_SEQ_UNIT)) {
return true;
}
return false;
}
expr* seq_decl_plugin::get_some_value(sort* s) {
seq_util util(*m_manager);
if (util.is_seq(s)) {

View file

@ -182,7 +182,11 @@ public:
virtual bool is_value(app * e) const;
virtual bool is_unique_value(app * e) const { return is_value(e); }
virtual bool is_unique_value(app * e) const { return false; }
virtual bool are_equal(app* a, app* b) const;
virtual bool are_distinct(app* a, app* b) const;
virtual expr * get_some_value(sort * s);

View file

@ -1,75 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
foci2.h
Abstract:
An interface class for foci2.
Author:
Ken McMillan (kenmcmil)
Revision History:
--*/
#ifndef FOCI2_H
#define FOCI2_H
#include <vector>
#include <string>
#ifdef _WINDOWS
#define FOCI2_EXPORT __declspec(dllexport)
#else
#define FOCI2_EXPORT __attribute__ ((visibility ("default")))
#endif
class foci2 {
public:
virtual ~foci2(){}
typedef int ast;
typedef int symb;
/** Built-in operators */
enum ops {
And = 0, Or, Not, Iff, Ite, Equal, Plus, Times, Floor, Leq, Div, Bool, Int, Array, Tsym, Fsym, Forall, Exists, Distinct, LastOp
};
virtual symb mk_func(const std::string &s) = 0;
virtual symb mk_pred(const std::string &s) = 0;
virtual ast mk_op(ops op, const std::vector<ast> args) = 0;
virtual ast mk_op(ops op, ast) = 0;
virtual ast mk_op(ops op, ast, ast) = 0;
virtual ast mk_op(ops op, ast, ast, ast) = 0;
virtual ast mk_int(const std::string &) = 0;
virtual ast mk_rat(const std::string &) = 0;
virtual ast mk_true() = 0;
virtual ast mk_false() = 0;
virtual ast mk_app(symb,const std::vector<ast> args) = 0;
virtual bool get_func(ast, symb &) = 0;
virtual bool get_pred(ast, symb &) = 0;
virtual bool get_op(ast, ops &) = 0;
virtual bool get_true(ast id) = 0;
virtual bool get_false(ast id) = 0;
virtual bool get_int(ast id, std::string &res) = 0;
virtual bool get_rat(ast id, std::string &res) = 0;
virtual const std::string &get_symb(symb) = 0;
virtual int get_num_args(ast) = 0;
virtual ast get_arg(ast, int) = 0;
virtual void show_ast(ast) = 0;
virtual bool interpolate(const std::vector<ast> &frames, std::vector<ast> &itps, std::vector<int> parents) = 0;
FOCI2_EXPORT static foci2 *create(const std::string &);
};
#endif

View file

@ -1,25 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
foci2.cpp
Abstract:
Fake foci2, to be replaced
Author:
Ken McMillan (kenmcmil)
Revision History:
--*/
#include "foci2.h"
FOCI2_EXPORT foci2 *foci2::create(const std::string &){
return 0;
}

View file

@ -1,75 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
foci2.h
Abstract:
An interface class for foci2.
Author:
Ken McMillan (kenmcmil)
Revision History:
--*/
#ifndef FOCI2_H
#define FOCI2_H
#include <vector>
#include <string>
#ifdef WIN32
#define FOCI2_EXPORT __declspec(dllexport)
#else
#define FOCI2_EXPORT __attribute__ ((visibility ("default")))
#endif
class foci2 {
public:
virtual ~foci2(){}
typedef int ast;
typedef int symb;
/** Built-in operators */
enum ops {
And = 0, Or, Not, Iff, Ite, Equal, Plus, Times, Floor, Leq, Div, Bool, Int, Array, Tsym, Fsym, Forall, Exists, Distinct, LastOp
};
virtual symb mk_func(const std::string &s) = 0;
virtual symb mk_pred(const std::string &s) = 0;
virtual ast mk_op(ops op, const std::vector<ast> args) = 0;
virtual ast mk_op(ops op, ast) = 0;
virtual ast mk_op(ops op, ast, ast) = 0;
virtual ast mk_op(ops op, ast, ast, ast) = 0;
virtual ast mk_int(const std::string &) = 0;
virtual ast mk_rat(const std::string &) = 0;
virtual ast mk_true() = 0;
virtual ast mk_false() = 0;
virtual ast mk_app(symb,const std::vector<ast> args) = 0;
virtual bool get_func(ast, symb &) = 0;
virtual bool get_pred(ast, symb &) = 0;
virtual bool get_op(ast, ops &) = 0;
virtual bool get_true(ast id) = 0;
virtual bool get_false(ast id) = 0;
virtual bool get_int(ast id, std::string &res) = 0;
virtual bool get_rat(ast id, std::string &res) = 0;
virtual const std::string &get_symb(symb) = 0;
virtual int get_num_args(ast) = 0;
virtual ast get_arg(ast, int) = 0;
virtual void show_ast(ast) = 0;
virtual bool interpolate(const std::vector<ast> &frames, std::vector<ast> &itps, std::vector<int> parents) = 0;
FOCI2_EXPORT static foci2 *create(const std::string &);
};
#endif

View file

@ -1,356 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
iz3foci.cpp
Abstract:
Implements a secondary solver using foci2.
Author:
Ken McMillan (kenmcmil)
Revision History:
--*/
#include <sstream>
#include <iostream>
#include "iz3hash.h"
#include "foci2.h"
#include "iz3foci.h"
using namespace stl_ext;
class iz3foci_impl : public iz3secondary {
int frames;
int *parents;
foci2 *foci;
foci2::symb select_op;
foci2::symb store_op;
foci2::symb mod_op;
public:
iz3foci_impl(iz3mgr *mgr, int _frames, int *_parents) : iz3secondary(*mgr) {
frames = _frames;
parents = _parents;
foci = 0;
}
typedef hash_map<ast,foci2::ast> AstToNode;
AstToNode ast_to_node; // maps Z3 ast's to foci expressions
typedef hash_map<foci2::ast,ast> NodeToAst;
NodeToAst node_to_ast; // maps Z3 ast's to foci expressions
// We only use this for FuncDeclToSymbol, which has no range destructor
struct symb_hash {
size_t operator()(const symb &s) const {
return (size_t) s;
}
};
typedef hash_map<symb,foci2::symb> FuncDeclToSymbol;
FuncDeclToSymbol func_decl_to_symbol; // maps Z3 func decls to symbols
typedef hash_map<foci2::symb,symb> SymbolToFuncDecl;
SymbolToFuncDecl symbol_to_func_decl; // maps symbols to Z3 func decls
int from_symb(symb func){
std::string name = string_of_symbol(func);
bool is_bool = is_bool_type(get_range_type(func));
foci2::symb f;
if(is_bool)
f = foci->mk_pred(name);
else
f = foci->mk_func(name);
symbol_to_func_decl[f] = func;
func_decl_to_symbol[func] = f;
return f;
}
// create a symbol corresponding to a DeBruijn index of a particular type
// the type has to be encoded into the name because the same index can
// occur with different types
foci2::symb make_deBruijn_symbol(int index, type ty){
std::ostringstream s;
// s << "#" << index << "#" << type;
return foci->mk_func(s.str());
}
int from_Z3_ast(ast t){
std::pair<ast,foci2::ast> foo(t,0);
std::pair<AstToNode::iterator, bool> bar = ast_to_node.insert(foo);
int &res = bar.first->second;
if(!bar.second) return res;
int nargs = num_args(t);
std::vector<foci2::ast> args(nargs);
for(int i = 0; i < nargs; i++)
args[i] = from_Z3_ast(arg(t,i));
switch(op(t)){
case True:
res = foci->mk_true(); break;
case False:
res = foci->mk_false(); break;
case And:
res = foci->mk_op(foci2::And,args); break;
case Or:
res = foci->mk_op(foci2::Or,args); break;
case Not:
res = foci->mk_op(foci2::Not,args[0]); break;
case Iff:
res = foci->mk_op(foci2::Iff,args); break;
case OP_OEQ: // bit of a mystery, this one...
if(args[0] == args[1]) res = foci->mk_true();
else res = foci->mk_op(foci2::Iff,args);
break;
case Ite:
if(is_bool_type(get_type(t)))
res = foci->mk_op(foci2::And,foci->mk_op(foci2::Or,foci->mk_op(foci2::Not,args[0]),args[1]),foci->mk_op(foci2::Or,args[0],args[2]));
else
res = foci->mk_op(foci2::Ite,args);
break;
case Equal:
res = foci->mk_op(foci2::Equal,args); break;
case Implies:
args[0] = foci->mk_op(foci2::Not,args[0]); res = foci->mk_op(foci2::Or,args); break;
case Xor:
res = foci->mk_op(foci2::Not,foci->mk_op(foci2::Iff,args)); break;
case Leq:
res = foci->mk_op(foci2::Leq,args); break;
case Geq:
std::swap(args[0],args[1]); res = foci->mk_op(foci2::Leq,args); break;
case Gt:
res = foci->mk_op(foci2::Not,foci->mk_op(foci2::Leq,args)); break;
case Lt:
std::swap(args[0],args[1]); res = foci->mk_op(foci2::Not,foci->mk_op(foci2::Leq,args)); break;
case Plus:
res = foci->mk_op(foci2::Plus,args); break;
case Sub:
args[1] = foci->mk_op(foci2::Times,foci->mk_int("-1"),args[1]); res = foci->mk_op(foci2::Plus,args); break;
case Uminus:
res = foci->mk_op(foci2::Times,foci->mk_int("-1"),args[0]); break;
case Times:
res = foci->mk_op(foci2::Times,args); break;
case Idiv:
res = foci->mk_op(foci2::Div,args); break;
case Mod:
res = foci->mk_app(mod_op,args); break;
case Select:
res = foci->mk_app(select_op,args); break;
case Store:
res = foci->mk_app(store_op,args); break;
case Distinct:
res = foci->mk_op(foci2::Distinct,args); break;
case Uninterpreted: {
symb func = sym(t);
FuncDeclToSymbol::iterator it = func_decl_to_symbol.find(func);
foci2::symb f = (it == func_decl_to_symbol.end()) ? from_symb(func) : it->second;
if(foci->get_symb(f).substr(0,3) == "lbl" && args.size()==1) // HACK to handle Z3 labels
res = args[0];
else if(foci->get_symb(f).substr(0,3) == "lbl" && args.size()==0) // HACK to handle Z3 labels
res = foci->mk_true();
else res = foci->mk_app(f,args);
break;
}
case Numeral: {
std::string s = string_of_numeral(t);
res = foci->mk_int(s);
break;
}
case Forall:
case Exists: {
bool is_forall = op(t) == Forall;
foci2::ops qop = is_forall ? foci2::Forall : foci2::Exists;
int bvs = get_quantifier_num_bound(t);
std::vector<int> foci_bvs(bvs);
for(int i = 0; i < bvs; i++){
std::string name = get_quantifier_bound_name(t,i);
//Z3_string name = Z3_get_symbol_string(ctx,sym);
// type ty = get_quantifier_bound_type(t,i);
foci2::symb f = foci->mk_func(name);
foci2::ast v = foci->mk_app(f,std::vector<foci2::ast>());
foci_bvs[i] = v;
}
foci2::ast body = from_Z3_ast(get_quantifier_body(t));
foci_bvs.push_back(body);
res = foci->mk_op(qop,foci_bvs);
node_to_ast[res] = t; // desperate
break;
}
case Variable: { // a deBruijn index
int index = get_variable_index_value(t);
type ty = get_type(t);
foci2::symb symbol = make_deBruijn_symbol(index,ty);
res = foci->mk_app(symbol,std::vector<foci2::ast>());
break;
}
default:
{
std::cerr << "iZ3: unsupported Z3 operator in expression\n ";
print_expr(std::cerr,t);
std::cerr << "\n";
SASSERT(0 && "iZ3: unsupported Z3 operator");
}
}
return res;
}
// convert an expr to Z3 ast
ast to_Z3_ast(foci2::ast i){
std::pair<foci2::ast,ast> foo(i,ast());
std::pair<NodeToAst::iterator,bool> bar = node_to_ast.insert(foo);
if(!bar.second) return bar.first->second;
ast &res = bar.first->second;
if(i < 0){
res = mk_not(to_Z3_ast(-i));
return res;
}
// get the arguments
unsigned n = foci->get_num_args(i);
std::vector<ast> args(n);
for(unsigned j = 0; j < n; j++)
args[j] = to_Z3_ast(foci->get_arg(i,j));
// handle operators
foci2::ops o;
foci2::symb f;
std::string nval;
if(foci->get_true(i))
res = mk_true();
else if(foci->get_false(i))
res = mk_false();
else if(foci->get_op(i,o)){
switch(o){
case foci2::And:
res = make(And,args); break;
case foci2::Or:
res = make(Or,args); break;
case foci2::Not:
res = mk_not(args[0]); break;
case foci2::Iff:
res = make(Iff,args[0],args[1]); break;
case foci2::Ite:
res = make(Ite,args[0],args[1],args[2]); break;
case foci2::Equal:
res = make(Equal,args[0],args[1]); break;
case foci2::Plus:
res = make(Plus,args); break;
case foci2::Times:
res = make(Times,args); break;
case foci2::Div:
res = make(Idiv,args[0],args[1]); break;
case foci2::Leq:
res = make(Leq,args[0],args[1]); break;
case foci2::Distinct:
res = make(Distinct,args);
break;
case foci2::Tsym:
res = mk_true();
break;
case foci2::Fsym:
res = mk_false();
break;
case foci2::Forall:
case foci2::Exists:
{
int nargs = n;
std::vector<ast> bounds(nargs-1);
for(int i = 0; i < nargs-1; i++)
bounds[i] = args[i];
opr oz = o == foci2::Forall ? Forall : Exists;
res = make_quant(oz,bounds,args[nargs-1]);
}
break;
default:
SASSERT(false && "unknown built-in op");
}
}
else if(foci->get_int(i,nval)){
res = make_int(nval);
}
else if(foci->get_func(i,f)){
if(f == select_op){
SASSERT(n == 2);
res = make(Select,args[0],args[1]);
}
else if(f == store_op){
SASSERT(n == 3);
res = make(Store,args[0],args[1],args[2]);
}
else if(f == mod_op){
SASSERT(n == 2);
res = make(Mod,args[0],args[1]);
}
else {
std::pair<int,symb> foo(f,(symb)0);
std::pair<SymbolToFuncDecl::iterator,bool> bar = symbol_to_func_decl.insert(foo);
symb &func_decl = bar.first->second;
if(bar.second){
std::cout << "unknown function symbol:\n";
foci->show_ast(i);
SASSERT(0);
}
res = make(func_decl,args);
}
}
else {
std::cerr << "iZ3: unknown FOCI expression kind\n";
SASSERT(0 && "iZ3: unknown FOCI expression kind");
}
return res;
}
int interpolate(const std::vector<ast> &cnsts, std::vector<ast> &itps){
SASSERT((int)cnsts.size() == frames);
std::string lia("lia");
#ifdef _FOCI2
foci = foci2::create(lia);
#else
foci = 0;
#endif
if(!foci){
std::cerr << "iZ3: cannot find foci lia solver.\n";
SASSERT(0);
}
select_op = foci->mk_func("select");
store_op = foci->mk_func("store");
mod_op = foci->mk_func("mod");
std::vector<foci2::ast> foci_cnsts(frames), foci_itps(frames-1), foci_parents;
if(parents)
foci_parents.resize(frames);
for(int i = 0; i < frames; i++){
foci_cnsts[i] = from_Z3_ast(cnsts[i]);
if(parents)
foci_parents[i] = parents[i];
}
int res = foci->interpolate(foci_cnsts, foci_itps, foci_parents);
if(res == 0){
SASSERT((int)foci_itps.size() == frames-1);
itps.resize(frames-1);
for(int i = 0; i < frames-1; i++){
// foci->show_ast(foci_itps[i]);
itps[i] = to_Z3_ast(foci_itps[i]);
}
}
ast_to_node.clear();
node_to_ast.clear();
func_decl_to_symbol.clear();
symbol_to_func_decl.clear();
delete foci;
return res;
}
};
iz3secondary *iz3foci::create(iz3mgr *mgr, int num, int *parents){
return new iz3foci_impl(mgr,num,parents);
}

View file

@ -1,32 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
iz3foci.h
Abstract:
Implements a secondary solver using foci2.
Author:
Ken McMillan (kenmcmil)
Revision History:
--*/
#ifndef IZ3FOCI_H
#define IZ3FOCI_H
#include "iz3secondary.h"
/** Secondary prover based on Cadence FOCI. */
class iz3foci {
public:
static iz3secondary *create(iz3mgr *mgr, int num, int *parents);
};
#endif

View file

@ -35,7 +35,6 @@
#include "iz3profiling.h"
#include "iz3translate.h"
#include "iz3foci.h"
#include "iz3proof.h"
#include "iz3hash.h"
#include "iz3interp.h"
@ -167,22 +166,6 @@ struct frame_reducer {
#endif
#if 0
static lbool test_secondary(context ctx,
int num,
ast *cnsts,
ast *interps,
int *parents = 0
){
iz3secondary *sp = iz3foci::create(ctx,num,parents);
std::vector<ast> frames(num), interpolants(num-1);
std::copy(cnsts,cnsts+num,frames.begin());
int res = sp->interpolate(frames,interpolants);
if(res == 0)
std::copy(interpolants.begin(),interpolants.end(),interps);
return res ? L_TRUE : L_FALSE;
}
#endif
template<class T>
struct killme {
@ -213,11 +196,7 @@ public:
const std::vector<int> &parents,
std::vector<ast> &interps
){
int num = cnsts.size();
iz3secondary *sp = iz3foci::create(this,num,(int *)(parents.empty()?0:&parents[0]));
int res = sp->interpolate(cnsts, interps);
if(res != 0)
throw iz3_exception("secondary failed");
throw iz3_exception("secondary interpolating prover not supported");
}
void proof_to_interpolant(z3pf proof,
@ -248,10 +227,9 @@ public:
if(is_linear(parents_vec))
parents_vec.clear();
// create a secondary prover
iz3secondary *sp = iz3foci::create(this,num,parents_vec.empty()?0:&parents_vec[0]);
sp_killer.set(sp); // kill this on exit
// secondary prover no longer supported
iz3secondary *sp = NULL;
#define BINARY_INTERPOLATION
#ifndef BINARY_INTERPOLATION
// create a translator

View file

@ -53,12 +53,8 @@ class iz3translation : public iz3base {
: iz3base(mgr,_cnsts,_parents,_theory) {}
};
//#define IZ3_TRANSLATE_DIRECT2
#ifdef _FOCI2
#define IZ3_TRANSLATE_DIRECT
#else
// To use a secondary prover, define IZ3_TRANSLATE_DIRECT instead of this
#define IZ3_TRANSLATE_FULL
#endif
#endif

View file

@ -332,7 +332,7 @@ public:
}
}
// get the lits of a Z3 clause as foci terms
// get the lits of a Z3 clause as secondary prover terms
void get_Z3_lits(ast t, std::vector<ast> &lits){
opr dk = op(t);
if(dk == False)
@ -666,9 +666,9 @@ public:
#endif
// interpolate using secondary prover
profiling::timer_start("foci");
profiling::timer_start("secondary prover");
int sat = secondary->interpolate(preds,itps);
profiling::timer_stop("foci");
profiling::timer_stop("secondary prover");
std::cout << "lemma done" << std::endl;
@ -1495,7 +1495,7 @@ public:
return find_nll(new_proofs);
}
// translate a Z3 proof term into a foci proof term
// translate a Z3 proof term into a secondary prover proof term
Iproof::node translate_main(ast proof, non_local_lits *nll, bool expect_clause = true){
non_local_lits *old_nll = nll;

110
src/shell/lp_frontend.cpp Normal file
View file

@ -0,0 +1,110 @@
/*++
Copyright (c) 2016 Microsoft Corporation
Author:
Lev Nachmanson 2016-10-27
--*/
#include "lp_params.hpp"
#include "util/lp/lp_settings.h"
#include "util/lp/mps_reader.h"
#include "timeout.h"
#include "cancel_eh.h"
#include "scoped_timer.h"
#include "rlimit.h"
#include "gparams.h"
#include <signal.h>
static lean::lp_solver<double, double>* g_solver = 0;
static void display_statistics() {
if (g_solver && g_solver->settings().print_statistics) {
// TBD display relevant information about statistics
}
}
static void STD_CALL on_ctrl_c(int) {
signal (SIGINT, SIG_DFL);
#pragma omp critical (g_display_stats)
{
display_statistics();
}
raise(SIGINT);
}
static void on_timeout() {
#pragma omp critical (g_display_stats)
{
display_statistics();
exit(0);
}
}
struct front_end_resource_limit : public lean::lp_resource_limit {
reslimit& m_reslim;
front_end_resource_limit(reslimit& lim):
m_reslim(lim)
{}
virtual bool get_cancel_flag() { return !m_reslim.inc(); }
};
void run_solver(lp_params & params, char const * mps_file_name) {
reslimit rlim;
unsigned timeout = gparams::get().get_uint("timeout", 0);
unsigned rlimit = gparams::get().get_uint("rlimit", 0);
front_end_resource_limit lp_limit(rlim);
scoped_rlimit _rlimit(rlim, rlimit);
cancel_eh<reslimit> eh(rlim);
scoped_timer timer(timeout, &eh);
std::string fn(mps_file_name);
lean::mps_reader<double, double> reader(fn);
reader.set_message_stream(&std::cout); // can be redirected
reader.read();
if (!reader.is_ok()) {
std::cerr << "cannot process " << mps_file_name << std::endl;
return;
}
lean::lp_solver<double, double> * solver = reader.create_solver(false); // false - to create the primal solver
solver->settings().set_resource_limit(lp_limit);
g_solver = solver;
if (params.min()) {
solver->flip_costs();
}
solver->settings().set_message_ostream(&std::cout);
solver->settings().report_frequency = params.rep_freq();
solver->settings().print_statistics = params.print_stats();
solver->find_maximal_solution();
*(solver->settings().get_message_ostream()) << "status is " << lp_status_to_string(solver->get_status()) << std::endl;
if (solver->get_status() == lean::OPTIMAL) {
if (params.min()) {
solver->flip_costs();
}
solver->print_model(std::cout);
}
// #pragma omp critical (g_display_stats)
{
display_statistics();
register_on_timeout_proc(0);
g_solver = 0;
}
delete solver;
}
unsigned read_mps_file(char const * mps_file_name) {
signal(SIGINT, on_ctrl_c);
register_on_timeout_proc(on_timeout);
lp_params p;
param_descrs r;
p.collect_param_descrs(r);
run_solver(p, mps_file_name);
return 0;
}

7
src/shell/lp_frontend.h Normal file
View file

@ -0,0 +1,7 @@
/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Author: Lev Nachmanson
*/
#pragma once
unsigned read_mps_file(char const * mps_file_name);

View file

@ -44,4 +44,4 @@ public:
void install_smt2_extra_cmds(cmd_context & ctx) {
ctx.insert(alloc(include_cmd));
}
}

View file

@ -471,12 +471,16 @@ namespace smt {
setup_r_arith();
}
void setup::setup_QF_LIRA(static_features const& st) {
setup_mi_arith();
}
void setup::setup_QF_LIA() {
TRACE("setup", tout << "setup_QF_LIA(st)\n";);
m_params.m_relevancy_lvl = 0;
m_params.m_arith_expand_eqs = true;
m_params.m_arith_reflect = false;
m_params.m_arith_propagate_eqs = false;
m_params.m_arith_propagate_eqs = false;
m_params.m_nnf_cnf = false;
setup_i_arith();
}
@ -720,10 +724,9 @@ namespace smt {
}
void setup::setup_r_arith() {
m_context.register_plugin(alloc(smt::theory_mi_arith, m_manager, m_params));
// Disabled in initial commit of LRA additions
// m_context.register_plugin(alloc(smt::theory_lra, m_manager, m_params));
// to disable theory lra
// m_context.register_plugin(alloc(smt::theory_mi_arith, m_manager, m_params));
m_context.register_plugin(alloc(smt::theory_lra, m_manager, m_params));
}
void setup::setup_mi_arith() {
@ -937,7 +940,9 @@ namespace smt {
}
if (st.num_theories() == 1 && is_arith(st)) {
if (st.m_has_real)
if ((st.m_has_int && st.m_has_real) || (st.m_num_non_linear != 0))
setup_QF_LIRA(st);
else if (st.m_has_real)
setup_QF_LRA(st);
else
setup_QF_LIA(st);

View file

@ -65,6 +65,7 @@ namespace smt {
void setup_QF_LRA();
void setup_QF_LRA(static_features const & st);
void setup_QF_LIA();
void setup_QF_LIRA(static_features const& st);
void setup_QF_LIA(static_features const & st);
void setup_QF_UFLIA();
void setup_QF_UFLIA(static_features & st);

View file

@ -21,6 +21,7 @@ Notes:
#include"smt_kernel.h"
#include"smt_params.h"
#include"smt_params_helper.hpp"
#include"lp_params.hpp"
#include"rewriter_types.h"
#include"filter_model_converter.h"
#include"ast_util.h"
@ -64,6 +65,10 @@ public:
return m_params;
}
params_ref & params() {
return m_params_ref;
}
void updt_params_core(params_ref const & p) {
m_candidate_models = p.get_bool("candidate_models", false);
m_fail_if_inconclusive = p.get_bool("fail_if_inconclusive", true);
@ -73,6 +78,7 @@ public:
TRACE("smt_tactic", tout << "updt_params: " << p << "\n";);
updt_params_core(p);
fparams().updt_params(p);
m_params_ref.copy(p);
m_logic = p.get_sym(symbol("logic"), m_logic);
if (m_logic != symbol::null && m_ctx) {
m_ctx->set_logic(m_logic);
@ -84,6 +90,7 @@ public:
r.insert("candidate_models", CPK_BOOL, "(default: false) create candidate models even when quantifier or theory reasoning is incomplete.");
r.insert("fail_if_inconclusive", CPK_BOOL, "(default: true) fail if found unsat (sat) for under (over) approximated goal.");
smt_params_helper::collect_param_descrs(r);
lp_params::collect_param_descrs(r);
}
@ -112,10 +119,12 @@ public:
struct scoped_init_ctx {
smt_tactic & m_owner;
smt_params m_params; // smt-setup overwrites parameters depending on the current assertions.
params_ref m_params_ref;
scoped_init_ctx(smt_tactic & o, ast_manager & m):m_owner(o) {
m_params = o.fparams();
smt::kernel * new_ctx = alloc(smt::kernel, m, m_params);
m_params_ref = o.params();
smt::kernel * new_ctx = alloc(smt::kernel, m, m_params, m_params_ref);
TRACE("smt_tactic", tout << "logic: " << o.m_logic << "\n";);
new_ctx->set_logic(o.m_logic);
if (o.m_callback) {

2615
src/smt/theory_lra.cpp Normal file

File diff suppressed because it is too large Load diff

97
src/smt/theory_lra.h Normal file
View file

@ -0,0 +1,97 @@
/*++
Copyright (c) 2016 Microsoft Corporation
Module Name:
theory_lra.h
Abstract:
<abstract>
Author:
Lev Nachmanson (levnach) 2016-25-3
Nikolaj Bjorner (nbjorner)
Revision History:
--*/
#pragma once
#include "theory_opt.h"
namespace smt {
class theory_lra : public theory, public theory_opt {
class imp;
imp* m_imp;
public:
theory_lra(ast_manager& m, theory_arith_params& ap);
virtual ~theory_lra();
virtual theory* mk_fresh(context* new_ctx);
virtual char const* get_name() const { return "lra"; }
virtual void init(context * ctx);
virtual bool internalize_atom(app * atom, bool gate_ctx);
virtual bool internalize_term(app * term);
virtual void internalize_eq_eh(app * atom, bool_var v);
virtual void assign_eh(bool_var v, bool is_true);
virtual void new_eq_eh(theory_var v1, theory_var v2);
virtual bool use_diseqs() const;
virtual void new_diseq_eh(theory_var v1, theory_var v2);
virtual void push_scope_eh();
virtual void pop_scope_eh(unsigned num_scopes);
virtual void restart_eh();
virtual void relevant_eh(app* e);
virtual void init_search_eh();
virtual final_check_status final_check_eh();
virtual bool is_shared(theory_var v) const;
virtual bool can_propagate();
virtual void propagate();
virtual justification * why_is_diseq(theory_var v1, theory_var v2);
// virtual void flush_eh();
virtual void reset_eh();
virtual void init_model(model_generator & m);
virtual model_value_proc * mk_value(enode * n, model_generator & mg);
virtual bool get_value(enode* n, expr_ref& r);
virtual bool validate_eq_in_model(theory_var v1, theory_var v2, bool is_true) const;
virtual void display(std::ostream & out) const;
virtual void collect_statistics(::statistics & st) const;
// optimization
virtual inf_eps value(theory_var);
virtual inf_eps maximize(theory_var v, expr_ref& blocker, bool& has_shared);
virtual theory_var add_objective(app* term);
virtual expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_rational const& val);
};
}

View file

@ -2176,6 +2176,8 @@ bool theory_seq::simplify_and_solve_eqs() {
return m_new_propagation || ctx.inconsistent();
}
void theory_seq::internalize_eq_eh(app * atom, bool_var v) {}
bool theory_seq::internalize_term(app* term) {
context & ctx = get_context();

View file

@ -343,7 +343,7 @@ namespace smt {
virtual final_check_status final_check_eh();
virtual bool internalize_atom(app* atom, bool) { return internalize_term(atom); }
virtual bool internalize_term(app*);
virtual void internalize_eq_eh(app * atom, bool_var v) {}
virtual void internalize_eq_eh(app * atom, bool_var v);
virtual void new_eq_eh(theory_var, theory_var);
virtual void new_diseq_eh(theory_var, theory_var);
virtual void assign_eh(bool_var v, bool is_true);

View file

@ -60,6 +60,7 @@ namespace smt {
totalCacheAccessCount(0),
cacheHitCount(0),
cacheMissCount(0),
m_fresh_id(0),
m_find(*this),
m_trail_stack(*this)
{
@ -441,7 +442,12 @@ namespace smt {
}
app * theory_str::mk_fresh_const(char const* name, sort* s) {
return u.mk_skolem(symbol(name), 0, 0, s);
string_buffer<64> buffer;
buffer << name;
buffer << "!tmp";
buffer << m_fresh_id;
m_fresh_id++;
return u.mk_skolem(symbol(buffer.c_str()), 0, 0, s);
}
@ -5552,8 +5558,8 @@ namespace smt {
for (; arg1_grdItor != groundedMap[arg1DeAlias].end(); arg1_grdItor++) {
std::vector<expr*> ndVec;
ndVec.insert(ndVec.end(), arg0_grdItor->first.begin(), arg0_grdItor->first.end());
int arg0VecSize = arg0_grdItor->first.size();
int arg1VecSize = arg1_grdItor->first.size();
size_t arg0VecSize = arg0_grdItor->first.size();
size_t arg1VecSize = arg1_grdItor->first.size();
if (arg0VecSize > 0 && arg1VecSize > 0 && u.str.is_string(arg0_grdItor->first[arg0VecSize - 1]) && u.str.is_string(arg1_grdItor->first[0])) {
ndVec.pop_back();
ndVec.push_back(mk_concat(arg0_grdItor->first[arg0VecSize - 1], arg1_grdItor->first[0]));
@ -5645,8 +5651,8 @@ namespace smt {
}
bool theory_str::is_partial_in_grounded_concat(const std::vector<expr*> & strVec, const std::vector<expr*> & subStrVec) {
int strCnt = strVec.size();
int subStrCnt = subStrVec.size();
size_t strCnt = strVec.size();
size_t subStrCnt = subStrVec.size();
if (strCnt == 0 || subStrCnt == 0) {
return false;
@ -5717,7 +5723,7 @@ namespace smt {
}
// tail nodes
int tailIdx = i + subStrCnt - 1;
size_t tailIdx = i + subStrCnt - 1;
zstring subStrTailVal;
if (u.str.is_string(subStrVec[subStrCnt - 1], subStrTailVal)) {
zstring strTailVal;
@ -5908,8 +5914,14 @@ namespace smt {
app * n2_curr = to_app(n2);
// case 0: n1_curr is const string, n2_curr is const string
if (u.str.is_string(n1_curr) && u.str.is_string(n2_curr)) {
if (n1_curr != n2_curr) {
zstring n1_curr_str, n2_curr_str;
if (u.str.is_string(n1_curr, n1_curr_str) && u.str.is_string(n2_curr, n2_curr_str)) {
TRACE("str", tout << "checking string constants: n1=" << n1_curr_str << ", n2=" << n2_curr_str << std::endl;);
if (n1_curr_str == n2_curr_str) {
// TODO(mtrberzi) potential correction: if n1_curr != n2_curr,
// assert that these two terms are in fact equal, because they ought to be
return true;
} else {
return false;
}
}
@ -6864,7 +6876,7 @@ namespace smt {
// easiest case. we will search within these bounds
} else if (upper_bound_exists && !lower_bound_exists) {
// search between 0 and the upper bound
v_lower_bound == rational::zero();
v_lower_bound = rational::zero();
} else if (lower_bound_exists && !upper_bound_exists) {
// check some finite portion of the search space
v_upper_bound = v_lower_bound + rational(10);
@ -8251,7 +8263,7 @@ namespace smt {
}
}
if (lId == -1)
lId = mLMap.size();
lId = static_cast<int>(mLMap.size());
for (std::set<expr*>::iterator itor2 = nSet.begin(); itor2 != nSet.end(); itor2++) {
bool itorHasEqcValue = false;
get_eqc_value(*itor2, itorHasEqcValue);
@ -8290,7 +8302,7 @@ namespace smt {
}
}
if (rId == -1)
rId = mRMap.size();
rId = static_cast<int>(mRMap.size());
for (itor2 = nSet.begin(); itor2 != nSet.end(); itor2++) {
bool rHasEqcValue = false;
get_eqc_value(*itor2, rHasEqcValue);
@ -9182,7 +9194,7 @@ namespace smt {
// ----------------------------------------------------------------------------------------
int len = atoi(lenStr.encode().c_str());
bool coverAll = false;
svector<int_vector> options;
vector<int_vector, true, long long> options;
int_vector base;
TRACE("str", tout
@ -9227,16 +9239,16 @@ namespace smt {
);
// ----------------------------------------------------------------------------------------
ptr_vector<expr> orList;
ptr_vector<expr> andList;
for (long long i = l; i < h; i++) {
orList.push_back(m.mk_eq(val_indicator, mk_string(longlong_to_string(i).c_str()) ));
if (m_params.m_AggressiveValueTesting) {
literal l = mk_eq(val_indicator, mk_string(longlong_to_string(i).c_str()), false);
ctx.mark_as_relevant(l);
ctx.force_phase(l);
literal lit = mk_eq(val_indicator, mk_string(longlong_to_string(i).c_str()), false);
ctx.mark_as_relevant(lit);
ctx.force_phase(lit);
}
zstring aStr = gen_val_string(len, options[i - l]);

View file

@ -350,6 +350,8 @@ protected:
unsigned long cacheHitCount;
unsigned long cacheMissCount;
unsigned m_fresh_id;
// cache mapping each string S to Length(S)
obj_map<expr, app*> length_ast_map;

View file

@ -22,7 +22,6 @@ Notes:
#include"solve_eqs_tactic.h"
#include"elim_uncnstr_tactic.h"
#include"smt_tactic.h"
// include"mip_tactic.h"
#include"recover_01_tactic.h"
#include"ctx_simplify_tactic.h"
#include"probe_arith.h"
@ -72,5 +71,18 @@ tactic * mk_qflra_tactic(ast_manager & m, params_ref const & p) {
// using_params(mk_smt_tactic(), pivot_p)),
// p);
#if 0
params_ref simplex_0, simplex_1, simplex_2;
simplex_0.set_uint("lp.simplex_strategy", 0);
simplex_1.set_uint("lp.simplex_strategy", 1);
simplex_2.set_uint("lp.simplex_strategy", 2);
return par(using_params(mk_smt_tactic(), simplex_0),
using_params(mk_smt_tactic(), simplex_1),
using_params(mk_smt_tactic(), simplex_2));
#else
return using_params(using_params(mk_smt_tactic(), pivot_p), p);
#endif
}

144
src/test/argument_parser.h Normal file
View file

@ -0,0 +1,144 @@
/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Lev Nachmanson
*/
#include <unordered_map>
#include <vector>
#include <string>
#include <set>
#include <iostream>
namespace lean {
class argument_parser {
std::unordered_map<std::string, std::string> m_options;
std::unordered_map<std::string, std::string> m_options_with_after_string;
std::set<std::string> m_used_options;
std::unordered_map<std::string, std::string> m_used_options_with_after_string;
std::vector<std::string> m_free_args;
std::vector<std::string> m_args;
public:
std::string m_error_message;
argument_parser(unsigned argn, char * const* args) {
for (unsigned i = 0; i < argn; i++) {
m_args.push_back(std::string(args[i]));
}
}
void add_option(std::string s) {
add_option_with_help_string(s, "");
}
void add_option_with_help_string(std::string s, std::string help_string) {
m_options[s]=help_string;
}
void add_option_with_after_string(std::string s) {
add_option_with_after_string_with_help(s, "");
}
void add_option_with_after_string_with_help(std::string s, std::string help_string) {
m_options_with_after_string[s]=help_string;
}
bool parse() {
bool status_is_ok = true;
for (unsigned i = 0; i < m_args.size(); i++) {
std::string ar = m_args[i];
if (m_options.find(ar) != m_options.end() )
m_used_options.insert(ar);
else if (m_options_with_after_string.find(ar) != m_options_with_after_string.end()) {
if (i == m_args.size() - 1) {
m_error_message = "Argument is missing after "+ar;
return false;
}
i++;
m_used_options_with_after_string[ar] = m_args[i];
} else {
if (starts_with(ar, "-") || starts_with(ar, "//"))
status_is_ok = false;
m_free_args.push_back(ar);
}
}
return status_is_ok;
}
bool contains(std::unordered_map<std::string, std::string> & m, std::string s) {
return m.find(s) != m.end();
}
bool contains(std::set<std::string> & m, std::string s) {
return m.find(s) != m.end();
}
bool option_is_used(std::string option) {
return contains(m_used_options, option) || contains(m_used_options_with_after_string, option);
}
std::string get_option_value(std::string option) {
auto t = m_used_options_with_after_string.find(option);
if (t != m_used_options_with_after_string.end()){
return t->second;
}
return std::string();
}
bool starts_with(std::string s, char const * prefix) {
return starts_with(s, std::string(prefix));
}
bool starts_with(std::string s, std::string prefix) {
return s.substr(0, prefix.size()) == prefix;
}
std::string usage_string() {
std::string ret = "";
std::vector<std::string> unknown_options;
for (auto t : m_free_args) {
if (starts_with(t, "-") || starts_with(t, "\\")) {
unknown_options.push_back(t);
}
}
if (unknown_options.size()) {
ret = "Unknown options:";
}
for (auto unknownOption : unknown_options) {
ret += unknownOption;
ret += ",";
}
ret += "\n";
ret += "Usage:\n";
for (auto allowed_option : m_options)
ret += allowed_option.first + " " + (allowed_option.second.size() == 0 ? std::string("") : std::string("/") + allowed_option.second) + std::string("\n");
for (auto s : m_options_with_after_string) {
ret += s.first + " " + (s.second.size() == 0? " \"option value\"":("\""+ s.second+"\"")) + "\n";
}
return ret;
}
void print() {
if (m_used_options.size() == 0 && m_used_options_with_after_string.size() == 0 && m_free_args.size() == 0) {
std::cout << "no options are given" << std::endl;
return;
}
std::cout << "options are: " << std::endl;
for (std::string s : m_used_options) {
std::cout << s << std::endl;
}
for (auto & t : m_used_options_with_after_string) {
std::cout << t.first << " " << t.second << std::endl;
}
if (m_free_args.size() > 0) {
std::cout << "free arguments are: " << std::endl;
for (auto & t : m_free_args) {
std::cout << t << " " << std::endl;
}
}
}
};
}

3236
src/test/lp.cpp Normal file

File diff suppressed because it is too large Load diff

396
src/test/smt_reader.h Normal file
View file

@ -0,0 +1,396 @@
/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Lev Nachmanson
*/
#pragma once
// reads an MPS file reperesenting a Mixed Integer Program
#include <string>
#include <vector>
#include <unordered_map>
#include "util/lp/lp_primal_simplex.h"
#include "util/lp/lp_dual_simplex.h"
#include "util/lp/lar_solver.h"
#include <iostream>
#include <fstream>
#include <functional>
#include <algorithm>
#include "util/lp/mps_reader.h"
#include "util/lp/ul_pair.h"
#include "util/lp/lar_constraints.h"
#include <sstream>
#include <cstdlib>
namespace lean {
template<typename T>
T from_string(const std::string& str) {
std::istringstream ss(str);
T ret;
ss >> ret;
return ret;
}
class smt_reader {
public:
struct lisp_elem {
std::string m_head;
std::vector<lisp_elem> m_elems;
void print() {
if (m_elems.size()) {
std::cout << '(';
std::cout << m_head << ' ';
for (auto & el : m_elems)
el.print();
std::cout << ')';
} else {
std::cout << " " << m_head;
}
}
unsigned size() const { return static_cast<unsigned>(m_elems.size()); }
bool is_simple() const { return size() == 0; }
};
struct formula_constraint {
lconstraint_kind m_kind;
std::vector<std::pair<mpq, std::string>> m_coeffs;
mpq m_right_side;
void add_pair(mpq c, std::string name) {
m_coeffs.push_back(make_pair(c, name));
}
formula_constraint() : m_right_side(numeric_traits<mpq>::zero()) {}
};
lisp_elem m_formula_lisp_elem;
std::unordered_map<std::string, unsigned> m_name_to_var_index;
std::vector<formula_constraint> m_constraints;
bool m_is_OK;
unsigned m_line_number;
std::string m_file_name;
std::ifstream m_file_stream;
std::string m_line;
smt_reader(std::string file_name):
m_is_OK(true),
m_line_number(0),
m_file_name(file_name),
m_file_stream(file_name) {
}
void set_error() {
std::cout << "setting error" << std::endl;
m_is_OK = false;
}
bool is_ok() {
return m_is_OK;
}
bool prefix(const char * pr) {
return m_line.find(pr) == 0;
}
int first_separator() {
unsigned blank_pos = static_cast<unsigned>(m_line.find(' '));
unsigned br_pos = static_cast<unsigned>(m_line.find('('));
unsigned reverse_br_pos = static_cast<unsigned>(m_line.find(')'));
return std::min(blank_pos, std::min(br_pos, reverse_br_pos));
}
void fill_lisp_elem(lisp_elem & lm) {
if (m_line[0] == '(')
fill_nested_elem(lm);
else
fill_simple_elem(lm);
}
void fill_simple_elem(lisp_elem & lm) {
int separator = first_separator();
lean_assert(-1 != separator && separator != 0);
lm.m_head = m_line.substr(0, separator);
m_line = m_line.substr(separator);
}
void fill_nested_elem(lisp_elem & lm) {
lean_assert(m_line[0] == '(');
m_line = m_line.substr(1);
int separator = first_separator();
lm.m_head = m_line.substr(0, separator);
m_line = m_line.substr(lm.m_head.size());
eat_blanks();
while (m_line.size()) {
if (m_line[0] == '(') {
lisp_elem el;
fill_nested_elem(el);
lm.m_elems.push_back(el);
} else {
if (m_line[0] == ')') {
m_line = m_line.substr(1);
break;
}
lisp_elem el;
fill_simple_elem(el);
lm.m_elems.push_back(el);
}
eat_blanks();
}
}
void eat_blanks() {
while (m_line.size()) {
if (m_line[0] == ' ')
m_line = m_line.substr(1);
else
break;
}
}
void fill_formula_elem() {
fill_lisp_elem(m_formula_lisp_elem);
}
void parse_line() {
if (m_line.find(":formula") == 0) {
int first_br = static_cast<int>(m_line.find('('));
if (first_br == -1) {
std::cout << "empty formula" << std::endl;
return;
}
m_line = m_line.substr(first_br);
fill_formula_elem();
}
}
void set_constraint_kind(formula_constraint & c, lisp_elem & el) {
if (el.m_head == "=") {
c.m_kind = EQ;
} else if (el.m_head == ">=") {
c.m_kind = GE;
} else if (el.m_head == "<=") {
c.m_kind = LE;
} else if (el.m_head == ">") {
c.m_kind = GT;
} else if (el.m_head == "<") {
c.m_kind = LT;
} else {
std::cout << "kind " << el.m_head << " is not supported " << std::endl;
set_error();
}
}
void adjust_rigth_side(formula_constraint & /* c*/, lisp_elem & /*el*/) {
// lean_assert(el.m_head == "0"); // do nothing for the time being
}
void set_constraint_coeffs(formula_constraint & c, lisp_elem & el) {
lean_assert(el.m_elems.size() == 2);
set_constraint_coeffs_on_coeff_element(c, el.m_elems[0]);
adjust_rigth_side(c, el.m_elems[1]);
}
bool is_integer(std::string & s) {
if (s.size() == 0) return false;
return atoi(s.c_str()) != 0 || isdigit(s.c_str()[0]);
}
void add_complex_sum_elem(formula_constraint & c, lisp_elem & el) {
if (el.m_head == "*") {
add_mult_elem(c, el.m_elems);
} else if (el.m_head == "~") {
lisp_elem & minel = el.m_elems[0];
lean_assert(minel.is_simple());
c.m_right_side += mpq(str_to_int(minel.m_head));
} else {
std::cout << "unexpected input " << el.m_head << std::endl;
set_error();
return;
}
}
std::string get_name(lisp_elem & name) {
lean_assert(name.is_simple());
lean_assert(!is_integer(name.m_head));
return name.m_head;
}
void add_mult_elem(formula_constraint & c, std::vector<lisp_elem> & els) {
lean_assert(els.size() == 2);
mpq coeff = get_coeff(els[0]);
std::string col_name = get_name(els[1]);
c.add_pair(coeff, col_name);
}
mpq get_coeff(lisp_elem & le) {
if (le.is_simple()) {
return mpq(str_to_int(le.m_head));
} else {
lean_assert(le.m_head == "~");
lean_assert(le.size() == 1);
lisp_elem & el = le.m_elems[0];
lean_assert(el.is_simple());
return -mpq(str_to_int(el.m_head));
}
}
int str_to_int(std::string & s) {
lean_assert(is_integer(s));
return atoi(s.c_str());
}
void add_sum_elem(formula_constraint & c, lisp_elem & el) {
if (el.size()) {
add_complex_sum_elem(c, el);
} else {
lean_assert(is_integer(el.m_head));
int v = atoi(el.m_head.c_str());
mpq vr(v);
c.m_right_side -= vr;
}
}
void add_sum(formula_constraint & c, std::vector<lisp_elem> & sum_els) {
for (auto & el : sum_els)
add_sum_elem(c, el);
}
void set_constraint_coeffs_on_coeff_element(formula_constraint & c, lisp_elem & el) {
if (el.m_head == "*") {
add_mult_elem(c, el.m_elems);
} else if (el.m_head == "+") {
add_sum(c, el.m_elems);
} else {
lean_assert(false); // unexpected input
}
}
void create_constraint(lisp_elem & el) {
formula_constraint c;
set_constraint_kind(c, el);
set_constraint_coeffs(c, el);
m_constraints.push_back(c);
}
void fill_constraints() {
if (m_formula_lisp_elem.m_head != "and") {
std::cout << "unexpected top element " << m_formula_lisp_elem.m_head << std::endl;
set_error();
return;
}
for (auto & el : m_formula_lisp_elem.m_elems)
create_constraint(el);
}
void read() {
if (!m_file_stream.is_open()){
std::cout << "cannot open file " << m_file_name << std::endl;
set_error();
return;
}
while (m_is_OK && getline(m_file_stream, m_line)) {
parse_line();
m_line_number++;
}
m_file_stream.close();
fill_constraints();
}
/*
void fill_lar_solver_on_row(row * row, lar_solver *solver) {
if (row->m_name != m_cost_row_name) {
lar_constraint c(get_lar_relation_from_row(row->m_type), row->m_right_side);
for (auto s : row->m_row_columns) {
var_index i = solver->add_var(s.first);
c.add_variable_to_constraint(i, s.second);
}
solver->add_constraint(&c);
} else {
// ignore the cost row
}
}
void fill_lar_solver_on_rows(lar_solver * solver) {
for (auto row_it : m_rows) {
fill_lar_solver_on_row(row_it.second, solver);
}
}
void create_low_constraint_for_var(column* col, bound * b, lar_solver *solver) {
lar_constraint c(GE, b->m_low);
var_index i = solver->add_var(col->m_name);
c.add_variable_to_constraint(i, numeric_traits<T>::one());
solver->add_constraint(&c);
}
void create_upper_constraint_for_var(column* col, bound * b, lar_solver *solver) {
lar_constraint c(LE, b->m_upper);
var_index i = solver->add_var(col->m_name);
c.add_variable_to_constraint(i, numeric_traits<T>::one());
solver->add_constraint(&c);
}
void create_equality_contraint_for_var(column* col, bound * b, lar_solver *solver) {
lar_constraint c(EQ, b->m_fixed_value);
var_index i = solver->add_var(col->m_name);
c.add_variable_to_constraint(i, numeric_traits<T>::one());
solver->add_constraint(&c);
}
void fill_lar_solver_on_columns(lar_solver * solver) {
for (auto s : m_columns) {
mps_reader::column * col = s.second;
solver->add_var(col->m_name);
auto b = col->m_bound;
if (b == nullptr) return;
if (b->m_free) continue;
if (b->m_low_is_set) {
create_low_constraint_for_var(col, b, solver);
}
if (b->m_upper_is_set) {
create_upper_constraint_for_var(col, b, solver);
}
if (b->m_value_is_fixed) {
create_equality_contraint_for_var(col, b, solver);
}
}
}
*/
unsigned register_name(std::string s) {
auto it = m_name_to_var_index.find(s);
if (it!= m_name_to_var_index.end())
return it->second;
unsigned ret = static_cast<unsigned>(m_name_to_var_index.size());
m_name_to_var_index[s] = ret;
return ret;
}
void add_constraint_to_solver(lar_solver * solver, formula_constraint & fc) {
vector<std::pair<mpq, var_index>> ls;
for (auto & it : fc.m_coeffs) {
ls.push_back(std::make_pair(it.first, solver->add_var(register_name(it.second))));
}
solver->add_constraint(ls, fc.m_kind, fc.m_right_side);
}
void fill_lar_solver(lar_solver * solver) {
for (formula_constraint & fc : m_constraints)
add_constraint_to_solver(solver, fc);
}
lar_solver * create_lar_solver() {
lar_solver * ls = new lar_solver();
fill_lar_solver(ls);
return ls;
}
};
}

View file

@ -0,0 +1,73 @@
/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Lev Nachmanson
*/
#pragma once
// reads a text file
#include <string>
#include <vector>
#include <unordered_map>
#include <iostream>
#include <fstream>
#include "util/lp/lp_utils.h"
#include "util/lp/lp_solver.h"
namespace lean {
template <typename T>
struct test_result {
lp_status m_status;
T m_cost;
std::unordered_map<std::string, T> column_values;
};
template <typename T>
class test_file_reader {
struct raw_blob {
std::vector<std::string> m_unparsed_strings;
std::vector<raw_blob> m_blobs;
};
struct test_file_blob {
std::string m_name;
std::string m_content;
std::unordered_map<std::string, std::string> m_table;
std::unordered_map<std::string, test_file_blob> m_blobs;
test_result<T> * get_test_result() {
test_result<T> * tr = new test_result<T>();
throw "not impl";
return tr;
}
};
std::ifstream m_file_stream;
public:
// constructor
test_file_reader(std::string file_name) : m_file_stream(file_name) {
if (!m_file_stream.is_open()) {
std::cout << "cannot open file " << "\'" << file_name << "\'" << std::endl;
}
}
raw_blob scan_to_row_blob() {
}
test_file_blob scan_row_blob_to_test_file_blob(raw_blob /* rblob */) {
}
test_result<T> * get_test_result() {
if (!m_file_stream.is_open()) {
return nullptr;
}
raw_blob rblob = scan_to_row_blob();
test_file_blob tblob = scan_row_blob_to_test_file_blob(rblob);
return tblob.get_test_result();
}
};
}

View file

@ -83,8 +83,8 @@ unsigned string_hash(const char * str, unsigned length, unsigned init_value) {
Z3_fallthrough;
case 1 :
a+=str[0];
Z3_fallthrough;
/* case 0: nothing left to add */
break;
}
mix(a,b,c);
/*-------------------------------------------- report the result */

View file

@ -16,8 +16,7 @@ class binary_heap_priority_queue {
// indexing for A starts from 1
vector<unsigned> m_heap; // keeps the elements of the queue
vector<int> m_heap_inverse; // o = m_heap[m_heap_inverse[o]]
unsigned m_heap_size = 0;
unsigned m_heap_size;
// is is the child place in heap
void swap_with_parent(unsigned i);
void put_at(unsigned i, unsigned h);
@ -29,7 +28,7 @@ public:
public:
void remove(unsigned o);
unsigned size() const { return m_heap_size; }
binary_heap_priority_queue(): m_heap(1) {} // the empty constructror
binary_heap_priority_queue(): m_heap(1), m_heap_size(0) {} // the empty constructror
// n is the initial queue capacity.
// The capacity will be enlarged two times automatically if needed
binary_heap_priority_queue(unsigned n);

View file

@ -83,7 +83,8 @@ template <typename T> void binary_heap_priority_queue<T>::remove(unsigned o) {
template <typename T> binary_heap_priority_queue<T>::binary_heap_priority_queue(unsigned n) :
m_priorities(n),
m_heap(n + 1), // because the indexing for A starts from 1
m_heap_inverse(n, -1)
m_heap_inverse(n, -1),
m_heap_size(0)
{ }

View file

@ -20,8 +20,8 @@ template <typename T>
class binary_heap_upair_queue {
binary_heap_priority_queue<T> m_q;
std::unordered_map<upair, unsigned> m_pairs_to_index;
vector<upair> m_pairs; // inverse to index
vector<unsigned> m_available_spots;
svector<upair> m_pairs; // inverse to index
svector<unsigned> m_available_spots;
public:
binary_heap_upair_queue(unsigned size);

View file

@ -18,12 +18,13 @@ namespace lean {
class bound_analyzer_on_row {
linear_combination_iterator<mpq> & m_it;
unsigned m_row_or_term_index;
int m_column_of_u = -1; // index of an unlimited from above monoid
// -1 means that such a value is not found, -2 means that at least two of such monoids were found
int m_column_of_l = -1; // index of an unlimited from below monoid
impq m_rs;
bound_propagator & m_bp;
bound_propagator & m_bp;
unsigned m_row_or_term_index;
int m_column_of_u; // index of an unlimited from above monoid
// -1 means that such a value is not found, -2 means that at least two of such monoids were found
int m_column_of_l; // index of an unlimited from below monoid
impq m_rs;
public :
// constructor
bound_analyzer_on_row(
@ -34,9 +35,11 @@ public :
)
:
m_it(it),
m_bp(bp),
m_row_or_term_index(row_or_term_index),
m_rs(rs),
m_bp(bp)
m_column_of_u(-1),
m_column_of_l(-1),
m_rs(rs)
{}
@ -250,7 +253,6 @@ public :
if (str)
strict = true;
}
bound /= l_coeff;
if (is_pos(l_coeff)) {
limit_j(m_column_of_l, bound, true, false, strict);

View file

@ -15,26 +15,26 @@ inline bool is_valid(unsigned j) { return static_cast<int>(j) >= 0;}
template <typename T>
class column_info {
std::string m_name;
bool m_low_bound_is_set = false;
bool m_low_bound_is_strict = false;
bool m_upper_bound_is_set = false;
bool m_upper_bound_is_strict = false;
T m_low_bound;
T m_upper_bound;
T m_cost = numeric_traits<T>::zero();
T m_fixed_value;
bool m_is_fixed = false;
unsigned m_column_index = static_cast<unsigned>(-1);
bool m_low_bound_is_set;
bool m_low_bound_is_strict;
bool m_upper_bound_is_set;
bool m_upper_bound_is_strict;
T m_low_bound;
T m_upper_bound;
T m_fixed_value;
bool m_is_fixed;
T m_cost;
unsigned m_column_index;
public:
bool operator==(const column_info & c) const {
return m_name == c.m_name &&
return m_name == c.m_name &&
m_low_bound_is_set == c.m_low_bound_is_set &&
m_low_bound_is_strict == c.m_low_bound_is_strict &&
m_upper_bound_is_set == c.m_upper_bound_is_set&&
m_upper_bound_is_strict == c.m_upper_bound_is_strict&&
(!m_low_bound_is_set || m_low_bound == c.m_low_bound) &&
(!m_upper_bound_is_set || m_upper_bound == c.m_upper_bound) &&
m_cost == c.m_cost&&
m_cost == c.m_cost &&
m_is_fixed == c.m_is_fixed &&
(!m_is_fixed || m_fixed_value == c.m_fixed_value) &&
m_column_index == c.m_column_index;
@ -44,9 +44,24 @@ public:
m_column_index = j;
}
// the default constructor
column_info() {}
column_info(unsigned column_index) : m_column_index(column_index) {
column_info():
m_low_bound_is_set(false),
m_low_bound_is_strict(false),
m_upper_bound_is_set (false),
m_upper_bound_is_strict (false),
m_is_fixed(false),
m_cost(numeric_traits<T>::zero()),
m_column_index(static_cast<unsigned>(-1))
{}
column_info(unsigned column_index) :
m_low_bound_is_set(false),
m_low_bound_is_strict(false),
m_upper_bound_is_set (false),
m_upper_bound_is_strict (false),
m_is_fixed(false),
m_cost(numeric_traits<T>::zero()),
m_column_index(column_index) {
}
column_info(const column_info & ci) {

View file

@ -0,0 +1,43 @@
/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Author: Lev Nachmanson
*/
#pragma once
namespace lean {
template <typename V>
struct conversion_helper {
static V get_low_bound(const column_info<mpq> & ci) {
return V(ci.get_low_bound(), ci.low_bound_is_strict()? 1 : 0);
}
static V get_upper_bound(const column_info<mpq> & ci) {
return V(ci.get_upper_bound(), ci.upper_bound_is_strict()? -1 : 0);
}
};
template<>
struct conversion_helper <double> {
static double get_upper_bound(const column_info<mpq> & ci) {
if (!ci.upper_bound_is_strict())
return ci.get_upper_bound().get_double();
double eps = 0.00001;
if (!ci.low_bound_is_set())
return ci.get_upper_bound().get_double() - eps;
eps = std::min((ci.get_upper_bound() - ci.get_low_bound()).get_double() / 1000, eps);
return ci.get_upper_bound().get_double() - eps;
}
static double get_low_bound(const column_info<mpq> & ci) {
if (!ci.low_bound_is_strict())
return ci.get_low_bound().get_double();
double eps = 0.00001;
if (!ci.upper_bound_is_set())
return ci.get_low_bound().get_double() + eps;
eps = std::min((ci.get_upper_bound() - ci.get_low_bound()).get_double() / 1000, eps);
return ci.get_low_bound().get_double() + eps;
}
};
}

View file

@ -16,7 +16,6 @@ template <typename T, typename X> class lp_core_solver_base; // forward definiti
template <typename T, typename X>
class core_solver_pretty_printer {
std::ostream & m_out;
template<typename A> using vector = vector<A>;
typedef std::string string;
lp_core_solver_base<T, X> & m_core_solver;
vector<unsigned> m_column_widths;
@ -34,15 +33,15 @@ class core_solver_pretty_printer {
std::string m_cost_title;
std::string m_basis_heading_title;
std::string m_x_title;
std::string m_low_bounds_title = "low";
std::string m_upp_bounds_title = "upp";
std::string m_exact_norm_title = "exact cn";
std::string m_approx_norm_title = "approx cn";
std::string m_low_bounds_title;
std::string m_upp_bounds_title;
std::string m_exact_norm_title;
std::string m_approx_norm_title;
unsigned ncols() { return m_core_solver.m_A.column_count(); }
unsigned nrows() { return m_core_solver.m_A.row_count(); }
unsigned m_artificial_start = std::numeric_limits<unsigned>::max();
unsigned m_artificial_start;
indexed_vector<T> m_w_buff;
indexed_vector<T> m_ed_buff;
vector<T> m_exact_column_norms;

View file

@ -23,6 +23,12 @@ core_solver_pretty_printer<T, X>::core_solver_pretty_printer(lp_core_solver_base
m_rs(ncols(), zero_of_type<X>()),
m_w_buff(core_solver.m_w),
m_ed_buff(core_solver.m_ed) {
m_low_bounds_title = "low";
m_upp_bounds_title = "upp";
m_exact_norm_title = "exact cn";
m_approx_norm_title = "approx cn";
m_artificial_start = std::numeric_limits<unsigned>::max();
m_column_widths.resize(core_solver.m_A.column_count(), 0),
init_m_A_and_signs();
init_costs();

View file

@ -0,0 +1,576 @@
/*
Copyright (c) 2017 Microsoft Corporation
Author: Lev Nachmanson
*/
// here we are inside lean::lar_solver class
bool strategy_is_undecided() const {
return m_settings.simplex_strategy() == simplex_strategy_enum::undecided;
}
var_index add_var(unsigned ext_j) {
var_index i;
lean_assert (ext_j < m_terms_start_index);
if (ext_j >= m_terms_start_index)
throw 0; // todo : what is the right way to exit?
if (try_get_val(m_ext_vars_to_columns, ext_j, i)) {
return i;
}
lean_assert(m_vars_to_ul_pairs.size() == A_r().column_count());
i = A_r().column_count();
m_vars_to_ul_pairs.push_back (ul_pair(static_cast<unsigned>(-1)));
add_non_basic_var_to_core_fields(ext_j);
lean_assert(sizes_are_correct());
return i;
}
void register_new_ext_var_index(unsigned ext_v) {
lean_assert(!contains(m_ext_vars_to_columns, ext_v));
unsigned j = static_cast<unsigned>(m_ext_vars_to_columns.size());
m_ext_vars_to_columns[ext_v] = j;
lean_assert(m_columns_to_ext_vars_or_term_indices.size() == j);
m_columns_to_ext_vars_or_term_indices.push_back(ext_v);
}
void add_non_basic_var_to_core_fields(unsigned ext_j) {
register_new_ext_var_index(ext_j);
m_mpq_lar_core_solver.m_column_types.push_back(column_type::free_column);
m_columns_with_changed_bound.increase_size_by_one();
add_new_var_to_core_fields_for_mpq(false);
if (use_lu())
add_new_var_to_core_fields_for_doubles(false);
}
void add_new_var_to_core_fields_for_doubles(bool register_in_basis) {
unsigned j = A_d().column_count();
A_d().add_column();
lean_assert(m_mpq_lar_core_solver.m_d_x.size() == j);
// lean_assert(m_mpq_lar_core_solver.m_d_low_bounds.size() == j && m_mpq_lar_core_solver.m_d_upper_bounds.size() == j); // restore later
m_mpq_lar_core_solver.m_d_x.resize(j + 1 );
m_mpq_lar_core_solver.m_d_low_bounds.resize(j + 1);
m_mpq_lar_core_solver.m_d_upper_bounds.resize(j + 1);
lean_assert(m_mpq_lar_core_solver.m_d_heading.size() == j); // as A().column_count() on the entry to the method
if (register_in_basis) {
A_d().add_row();
m_mpq_lar_core_solver.m_d_heading.push_back(m_mpq_lar_core_solver.m_d_basis.size());
m_mpq_lar_core_solver.m_d_basis.push_back(j);
}else {
m_mpq_lar_core_solver.m_d_heading.push_back(- static_cast<int>(m_mpq_lar_core_solver.m_d_nbasis.size()) - 1);
m_mpq_lar_core_solver.m_d_nbasis.push_back(j);
}
}
void add_new_var_to_core_fields_for_mpq(bool register_in_basis) {
unsigned j = A_r().column_count();
A_r().add_column();
lean_assert(m_mpq_lar_core_solver.m_r_x.size() == j);
// lean_assert(m_mpq_lar_core_solver.m_r_low_bounds.size() == j && m_mpq_lar_core_solver.m_r_upper_bounds.size() == j); // restore later
m_mpq_lar_core_solver.m_r_x.resize(j + 1);
m_mpq_lar_core_solver.m_r_low_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.m_inf_set.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);
lean_assert(m_mpq_lar_core_solver.m_r_heading.size() == j); // as A().column_count() on the entry to the method
if (register_in_basis) {
A_r().add_row();
m_mpq_lar_core_solver.m_r_heading.push_back(m_mpq_lar_core_solver.m_r_basis.size());
m_mpq_lar_core_solver.m_r_basis.push_back(j);
if (m_settings.bound_propagation())
m_rows_with_changed_bounds.insert(A_r().row_count() - 1);
} else {
m_mpq_lar_core_solver.m_r_heading.push_back(- static_cast<int>(m_mpq_lar_core_solver.m_r_nbasis.size()) - 1);
m_mpq_lar_core_solver.m_r_nbasis.push_back(j);
}
}
var_index add_term_undecided(const vector<std::pair<mpq, var_index>> & coeffs,
const mpq &m_v) {
m_terms.push_back(new lar_term(coeffs, m_v));
m_orig_terms.push_back(new lar_term(coeffs, m_v));
return m_terms_start_index + m_terms.size() - 1;
}
// terms
var_index add_term(const vector<std::pair<mpq, var_index>> & coeffs,
const mpq &m_v) {
if (strategy_is_undecided())
return add_term_undecided(coeffs, m_v);
m_terms.push_back(new lar_term(coeffs, m_v));
m_orig_terms.push_back(new lar_term(coeffs, m_v));
unsigned adjusted_term_index = m_terms.size() - 1;
var_index ret = m_terms_start_index + adjusted_term_index;
if (use_tableau() && !coeffs.empty()) {
add_row_for_term(m_orig_terms.back(), ret);
if (m_settings.bound_propagation())
m_rows_with_changed_bounds.insert(A_r().row_count() - 1);
}
lean_assert(m_ext_vars_to_columns.size() == A_r().column_count());
return ret;
}
void add_row_for_term(const lar_term * term, unsigned term_ext_index) {
lean_assert(sizes_are_correct());
add_row_from_term_no_constraint(term, term_ext_index);
lean_assert(sizes_are_correct());
}
void add_row_from_term_no_constraint(const lar_term * term, unsigned term_ext_index) {
register_new_ext_var_index(term_ext_index);
// j will be a new variable
unsigned j = A_r().column_count();
ul_pair ul(j);
m_vars_to_ul_pairs.push_back(ul);
add_basic_var_to_core_fields();
if (use_tableau()) {
auto it = iterator_on_term_with_basis_var(*term, j);
A_r().fill_last_row_with_pivoting(it,
m_mpq_lar_core_solver.m_r_solver.m_basis_heading);
m_mpq_lar_core_solver.m_r_solver.m_b.resize(A_r().column_count(), zero_of_type<mpq>());
} else {
fill_last_row_of_A_r(A_r(), term);
}
m_mpq_lar_core_solver.m_r_x[j] = get_basic_var_value_from_row_directly(A_r().row_count() - 1);
if (use_lu())
fill_last_row_of_A_d(A_d(), term);
}
void add_basic_var_to_core_fields() {
bool use_lu = m_mpq_lar_core_solver.need_to_presolve_with_double_solver();
lean_assert(!use_lu || A_r().column_count() == A_d().column_count());
m_mpq_lar_core_solver.m_column_types.push_back(column_type::free_column);
m_columns_with_changed_bound.increase_size_by_one();
m_rows_with_changed_bounds.increase_size_by_one();
add_new_var_to_core_fields_for_mpq(true);
if (use_lu)
add_new_var_to_core_fields_for_doubles(true);
}
constraint_index add_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side) {
constraint_index ci = m_constraints.size();
if (!is_term(j)) { // j is a var
auto vc = new lar_var_constraint(j, kind, right_side);
m_constraints.push_back(vc);
update_column_type_and_bound(j, kind, right_side, ci);
} else {
add_var_bound_on_constraint_for_term(j, kind, right_side, ci);
}
lean_assert(sizes_are_correct());
return ci;
}
void update_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_index) {
switch(m_mpq_lar_core_solver.m_column_types[j]) {
case column_type::free_column:
update_free_column_type_and_bound(j, kind, right_side, constr_index);
break;
case column_type::boxed:
update_boxed_column_type_and_bound(j, kind, right_side, constr_index);
break;
case column_type::low_bound:
update_low_bound_column_type_and_bound(j, kind, right_side, constr_index);
break;
case column_type::upper_bound:
update_upper_bound_column_type_and_bound(j, kind, right_side, constr_index);
break;
case column_type::fixed:
update_fixed_column_type_and_bound(j, kind, right_side, constr_index);
break;
default:
lean_assert(false); // cannot be here
}
}
void add_var_bound_on_constraint_for_term(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) {
lean_assert(is_term(j));
unsigned adjusted_term_index = adjust_term_index(j);
unsigned term_j;
if (try_get_val(m_ext_vars_to_columns, j, term_j)) {
mpq rs = right_side - m_orig_terms[adjusted_term_index]->m_v;
m_constraints.push_back(new lar_term_constraint(m_orig_terms[adjusted_term_index], kind, right_side));
update_column_type_and_bound(term_j, kind, rs, ci);
}
else {
add_constraint_from_term_and_create_new_column_row(j, m_orig_terms[adjusted_term_index], kind, right_side);
}
}
void add_constraint_from_term_and_create_new_column_row(unsigned term_j, const lar_term* term,
lconstraint_kind kind, const mpq & right_side) {
add_row_from_term_no_constraint(term, term_j);
unsigned j = A_r().column_count() - 1;
update_column_type_and_bound(j, kind, right_side - term->m_v, m_constraints.size());
m_constraints.push_back(new lar_term_constraint(term, kind, right_side));
lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size());
}
void decide_on_strategy_and_adjust_initial_state() {
lean_assert(strategy_is_undecided());
if (m_vars_to_ul_pairs.size() > m_settings.column_number_threshold_for_using_lu_in_lar_solver) {
m_settings.simplex_strategy() = simplex_strategy_enum::lu;
} else {
m_settings.simplex_strategy() = simplex_strategy_enum::tableau_rows; // todo: when to switch to tableau_costs?
}
adjust_initial_state();
}
void adjust_initial_state() {
switch (m_settings.simplex_strategy()) {
case simplex_strategy_enum::lu:
adjust_initial_state_for_lu();
break;
case simplex_strategy_enum::tableau_rows:
adjust_initial_state_for_tableau_rows();
break;
case simplex_strategy_enum::tableau_costs:
lean_assert(false); // not implemented
case simplex_strategy_enum::undecided:
adjust_initial_state_for_tableau_rows();
break;
}
}
void adjust_initial_state_for_lu() {
copy_from_mpq_matrix(A_d());
unsigned n = A_d().column_count();
m_mpq_lar_core_solver.m_d_x.resize(n);
m_mpq_lar_core_solver.m_d_low_bounds.resize(n);
m_mpq_lar_core_solver.m_d_upper_bounds.resize(n);
m_mpq_lar_core_solver.m_d_heading = m_mpq_lar_core_solver.m_r_heading;
m_mpq_lar_core_solver.m_d_basis = m_mpq_lar_core_solver.m_r_basis;
/*
unsigned j = A_d().column_count();
A_d().add_column();
lean_assert(m_mpq_lar_core_solver.m_d_x.size() == j);
// lean_assert(m_mpq_lar_core_solver.m_d_low_bounds.size() == j && m_mpq_lar_core_solver.m_d_upper_bounds.size() == j); // restore later
m_mpq_lar_core_solver.m_d_x.resize(j + 1 );
m_mpq_lar_core_solver.m_d_low_bounds.resize(j + 1);
m_mpq_lar_core_solver.m_d_upper_bounds.resize(j + 1);
lean_assert(m_mpq_lar_core_solver.m_d_heading.size() == j); // as A().column_count() on the entry to the method
if (register_in_basis) {
A_d().add_row();
m_mpq_lar_core_solver.m_d_heading.push_back(m_mpq_lar_core_solver.m_d_basis.size());
m_mpq_lar_core_solver.m_d_basis.push_back(j);
}else {
m_mpq_lar_core_solver.m_d_heading.push_back(- static_cast<int>(m_mpq_lar_core_solver.m_d_nbasis.size()) - 1);
m_mpq_lar_core_solver.m_d_nbasis.push_back(j);
}*/
}
void adjust_initial_state_for_tableau_rows() {
for (unsigned j = 0; j < m_terms.size(); j++) {
if (contains(m_ext_vars_to_columns, j + m_terms_start_index))
continue;
add_row_from_term_no_constraint(m_terms[j], j + m_terms_start_index);
}
}
// this fills the last row of A_d and sets the basis column: -1 in the last column of the row
void fill_last_row_of_A_d(static_matrix<double, double> & A, const lar_term* ls) {
lean_assert(A.row_count() > 0);
lean_assert(A.column_count() > 0);
unsigned last_row = A.row_count() - 1;
lean_assert(A.m_rows[last_row].empty());
for (auto & t : ls->m_coeffs) {
lean_assert(!is_zero(t.second));
var_index j = t.first;
A.set(last_row, j, - t.second.get_double());
}
unsigned basis_j = A.column_count() - 1;
A.set(last_row, basis_j, - 1 );
}
void update_free_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_ind) {
mpq y_of_bound(0);
switch (kind) {
case LT:
y_of_bound = -1;
case LE:
m_mpq_lar_core_solver.m_column_types[j] = column_type::upper_bound;
lean_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::upper_bound);
lean_assert(m_mpq_lar_core_solver.m_r_upper_bounds.size() > j);
{
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, constr_ind);
break;
case GT:
y_of_bound = 1;
case GE:
m_mpq_lar_core_solver.m_column_types[j] = column_type::low_bound;
lean_assert(m_mpq_lar_core_solver.m_r_upper_bounds.size() > j);
{
auto low = numeric_pair<mpq>(right_side, y_of_bound);
m_mpq_lar_core_solver.m_r_low_bounds[j] = low;
}
set_low_bound_witness(j, constr_ind);
break;
case EQ:
m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed;
m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = numeric_pair<mpq>(right_side, zero_of_type<mpq>());
set_upper_bound_witness(j, constr_ind);
set_low_bound_witness(j, constr_ind);
break;
default:
lean_unreachable();
}
m_columns_with_changed_bound.insert(j);
}
void update_upper_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) {
lean_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::upper_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_upper_bounds()[j]) {
m_mpq_lar_core_solver.m_r_upper_bounds[j] = up;
set_upper_bound_witness(j, ci);
m_columns_with_changed_bound.insert(j);
}
}
break;
case GT:
y_of_bound = 1;
case GE:
m_mpq_lar_core_solver.m_column_types[j] = column_type::boxed;
{
auto low = numeric_pair<mpq>(right_side, y_of_bound);
m_mpq_lar_core_solver.m_r_low_bounds[j] = low;
set_low_bound_witness(j, ci);
m_columns_with_changed_bound.insert(j);
if (low > m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
m_status = INFEASIBLE;
m_infeasible_column_index = j;
} else {
m_mpq_lar_core_solver.m_column_types[j] = m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j]? column_type::boxed : column_type::fixed;
}
}
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]) {
m_status = INFEASIBLE;
set_low_bound_witness(j, ci);
m_infeasible_column_index = j;
} else {
m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = v;
m_columns_with_changed_bound.insert(j);
set_low_bound_witness(j, ci);
set_upper_bound_witness(j, ci);
m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed;
}
break;
}
break;
default:
lean_unreachable();
}
}
void update_boxed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) {
lean_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::boxed && m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_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);
if (up < m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
m_mpq_lar_core_solver.m_r_upper_bounds[j] = up;
set_upper_bound_witness(j, ci);
m_columns_with_changed_bound.insert(j);
}
if (up < m_mpq_lar_core_solver.m_r_low_bounds[j]) {
m_status = INFEASIBLE;
lean_assert(false);
m_infeasible_column_index = j;
} else {
if (m_mpq_lar_core_solver.m_r_low_bounds()[j] == m_mpq_lar_core_solver.m_r_upper_bounds()[j])
m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed;
}
}
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_low_bounds[j]) {
m_mpq_lar_core_solver.m_r_low_bounds[j] = low;
m_columns_with_changed_bound.insert(j);
set_low_bound_witness(j, ci);
}
if (low > m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
m_status = INFEASIBLE;
m_infeasible_column_index = j;
} else if ( low == m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed;
}
}
break;
case EQ:
{
auto v = numeric_pair<mpq>(right_side, zero_of_type<mpq>());
if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) {
m_status = INFEASIBLE;
m_infeasible_column_index = j;
set_upper_bound_witness(j, ci);
} else if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
m_status = INFEASIBLE;
m_infeasible_column_index = j;
set_low_bound_witness(j, ci);
} else {
m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = v;
set_low_bound_witness(j, ci);
set_upper_bound_witness(j, ci);
m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed;
m_columns_with_changed_bound.insert(j);
}
break;
}
default:
lean_unreachable();
}
}
void update_low_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) {
lean_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::low_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);
m_mpq_lar_core_solver.m_r_upper_bounds[j] = up;
set_upper_bound_witness(j, ci);
m_columns_with_changed_bound.insert(j);
if (up < m_mpq_lar_core_solver.m_r_low_bounds[j]) {
m_status = INFEASIBLE;
m_infeasible_column_index = j;
} else {
m_mpq_lar_core_solver.m_column_types[j] = m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j]? column_type::boxed : column_type::fixed;
}
}
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_low_bounds[j]) {
m_mpq_lar_core_solver.m_r_low_bounds[j] = low;
m_columns_with_changed_bound.insert(j);
set_low_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_low_bounds[j]) {
m_status = INFEASIBLE;
m_infeasible_column_index = j;
set_upper_bound_witness(j, ci);
} else {
m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = v;
set_low_bound_witness(j, ci);
set_upper_bound_witness(j, ci);
m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed;
}
m_columns_with_changed_bound.insert(j);
break;
}
default:
lean_unreachable();
}
}
void update_fixed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) {
lean_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::fixed && m_mpq_lar_core_solver.m_r_low_bounds()[j] == m_mpq_lar_core_solver.m_r_upper_bounds()[j]));
lean_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_r_low_bounds()[j].y.is_zero() && m_mpq_lar_core_solver.m_r_upper_bounds()[j].y.is_zero()));
auto v = numeric_pair<mpq>(right_side, mpq(0));
mpq y_of_bound(0);
switch (kind) {
case LT:
if (v <= m_mpq_lar_core_solver.m_r_low_bounds[j]) {
m_status = INFEASIBLE;
m_infeasible_column_index = j;
set_upper_bound_witness(j, ci);
}
break;
case LE:
{
if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) {
m_status = INFEASIBLE;
m_infeasible_column_index = j;
set_upper_bound_witness(j, ci);
}
}
break;
case GT:
{
if (v >= m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
m_status = INFEASIBLE;
m_infeasible_column_index =j;
set_low_bound_witness(j, ci);
}
}
break;
case GE:
{
if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
m_status = INFEASIBLE;
m_infeasible_column_index = j;
set_low_bound_witness(j, ci);
}
}
break;
case EQ:
{
if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) {
m_status = INFEASIBLE;
m_infeasible_column_index = j;
set_upper_bound_witness(j, ci);
} else if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
m_status = INFEASIBLE;
m_infeasible_column_index = j;
set_low_bound_witness(j, ci);
}
break;
}
default:
lean_unreachable();
}
}

View file

@ -11,7 +11,7 @@ template <typename T, typename X>
struct iterator_on_column:linear_combination_iterator<T> {
const vector<column_cell>& m_column; // the offset in term coeffs
const static_matrix<T, X> & m_A;
int m_i = -1; // the initial offset in the column
int m_i; // the initial offset in the column
unsigned size() const { return m_column.size(); }
iterator_on_column(const vector<column_cell>& column, const static_matrix<T,X> & A) // the offset in term coeffs
:

View file

@ -8,8 +8,11 @@ namespace lean {
template <typename T>
struct iterator_on_indexed_vector:linear_combination_iterator<T> {
const indexed_vector<T> & m_v;
unsigned m_offset = 0;
iterator_on_indexed_vector(const indexed_vector<T> & v) : m_v(v){}
unsigned m_offset;
iterator_on_indexed_vector(const indexed_vector<T> & v) :
m_v(v),
m_offset(0)
{}
unsigned size() const { return m_v.m_index.size(); }
bool next(T & a, unsigned & i) {
if (m_offset >= m_v.m_index.size())

View file

@ -7,12 +7,14 @@
namespace lean {
template <typename T>
struct iterator_on_pivot_row:linear_combination_iterator<T> {
bool m_basis_returned = false;
bool m_basis_returned;
const indexed_vector<T> & m_v;
unsigned m_basis_j;
iterator_on_indexed_vector<T> m_it;
unsigned size() const { return m_it.size(); }
iterator_on_pivot_row(const indexed_vector<T> & v, unsigned basis_j) : m_v(v), m_basis_j(basis_j), m_it(v) {}
iterator_on_pivot_row(const indexed_vector<T> & v, unsigned basis_j) :
m_basis_returned(false),
m_v(v), m_basis_j(basis_j), m_it(v) {}
bool next(T & a, unsigned & i) {
if (m_basis_returned == false) {
m_basis_returned = true;

View file

@ -8,8 +8,8 @@ namespace lean {
template <typename T>
struct iterator_on_row:linear_combination_iterator<T> {
const vector<row_cell<T>> & m_row;
unsigned m_i= 0; // offset
iterator_on_row(const vector<row_cell<T>> & row) : m_row(row)
unsigned m_i; // offset
iterator_on_row(const vector<row_cell<T>> & row) : m_row(row), m_i(0)
{}
unsigned size() const { return m_row.size(); }
bool next(T & a, unsigned & i) {

View file

@ -8,14 +8,15 @@
#include "util/lp/lar_term.h"
namespace lean {
struct iterator_on_term_with_basis_var:linear_combination_iterator<mpq> {
std::unordered_map<unsigned, mpq>::const_iterator m_i; // the offset in term coeffs
bool m_term_j_returned = false;
const lar_term & m_term;
unsigned m_term_j;
std::unordered_map<unsigned, mpq>::const_iterator m_i; // the offset in term coeffs
bool m_term_j_returned;
unsigned m_term_j;
unsigned size() const {return static_cast<unsigned>(m_term.m_coeffs.size() + 1);}
iterator_on_term_with_basis_var(const lar_term & t, unsigned term_j) :
m_i(t.m_coeffs.begin()),
m_term(t),
m_i(t.m_coeffs.begin()),
m_term_j_returned(false),
m_term_j(term_j) {}
bool next(mpq & a, unsigned & i) {

View file

@ -25,7 +25,7 @@ class lar_core_solver {
// to grow and is set to -1 otherwise
int m_sign_of_entering_delta;
vector<std::pair<mpq, unsigned>> m_infeasible_linear_combination;
int m_infeasible_sum_sign = 0; // todo: get rid of this field
int m_infeasible_sum_sign; // todo: get rid of this field
vector<numeric_pair<mpq>> m_right_sides_dummy;
vector<mpq> m_costs_dummy;
vector<double> m_d_right_sides_dummy;
@ -216,8 +216,6 @@ public:
void pop(unsigned k) {
m_stacked_simplex_strategy.pop(k);
bool use_tableau = m_stacked_simplex_strategy() != simplex_strategy_enum::no_tableau;
// rationals
if (!settings().use_tableau())
m_r_A.pop(k);
@ -232,7 +230,7 @@ public:
m_r_x.resize(m_r_A.column_count());
m_r_solver.m_costs.resize(m_r_A.column_count());
m_r_solver.m_d.resize(m_r_A.column_count());
if(!use_tableau)
if(!settings().use_tableau())
pop_markowitz_counts(k);
m_d_A.pop(k);
if (m_d_solver.m_factorization != nullptr) {
@ -242,13 +240,14 @@ public:
m_d_x.resize(m_d_A.column_count());
pop_basis(k);
m_stacked_simplex_strategy.pop(k);
settings().simplex_strategy() = m_stacked_simplex_strategy;
lean_assert(m_r_solver.basis_heading_is_correct());
lean_assert(!need_to_presolve_with_double_solver() || m_d_solver.basis_heading_is_correct());
}
bool need_to_presolve_with_double_solver() const {
return settings().presolve_with_double_solver_for_lar && !settings().use_tableau();
return settings().simplex_strategy() == simplex_strategy_enum::lu;
}
template <typename L>
@ -368,7 +367,7 @@ public:
s.m_x[j] = s.m_low_bounds[j];
break;
case column_type::boxed:
if (my_random() % 2) {
if (settings().random_next() % 2) {
s.m_x[j] = s.m_low_bounds[j];
} else {
s.m_x[j] = s.m_upper_bounds[j];
@ -600,7 +599,7 @@ public:
}
if (no_r_lu()) { // it is the case where m_d_solver gives a degenerated basis, we need to roll back
std::cout << "no_r_lu" << std::endl;
// std::cout << "no_r_lu" << std::endl;
catch_up_in_lu_in_reverse(changes_of_basis, m_r_solver);
m_r_solver.find_feasible_solution();
m_d_basis = m_r_basis;
@ -774,8 +773,8 @@ public:
}
mpq find_delta_for_strict_bounds() const{
mpq delta = numeric_traits<mpq>::one();
mpq find_delta_for_strict_bounds(const mpq & initial_delta) const{
mpq delta = initial_delta;
for (unsigned j = 0; j < m_r_A.column_count(); j++ ) {
if (low_bound_is_set(j))
update_delta(delta, m_r_low_bounds[j], m_r_x[j]);

View file

@ -14,7 +14,8 @@ namespace lean {
lar_core_solver::lar_core_solver(
lp_settings & settings,
const column_namer & column_names
):
):
m_infeasible_sum_sign(0),
m_r_solver(m_r_A,
m_right_sides_dummy,
m_r_x,

View file

@ -29,86 +29,37 @@
#include "util/lp/iterator_on_term_with_basis_var.h"
#include "util/lp/iterator_on_row.h"
#include "util/lp/quick_xplain.h"
#include "util/lp/conversion_helper.h"
namespace lean {
template <typename V>
struct conversion_helper {
static V get_low_bound(const column_info<mpq> & ci) {
return V(ci.get_low_bound(), ci.low_bound_is_strict()? 1 : 0);
}
static V get_upper_bound(const column_info<mpq> & ci) {
return V(ci.get_upper_bound(), ci.upper_bound_is_strict()? -1 : 0);
}
};
template<>
struct conversion_helper <double> {
static double conversion_helper <double>::get_upper_bound(const column_info<mpq> & ci) {
if (!ci.upper_bound_is_strict())
return ci.get_upper_bound().get_double();
double eps = 0.00001;
if (!ci.low_bound_is_set())
return ci.get_upper_bound().get_double() - eps;
eps = std::min((ci.get_upper_bound() - ci.get_low_bound()).get_double() / 1000, eps);
return ci.get_upper_bound().get_double() - eps;
}
static double get_low_bound(const column_info<mpq> & ci) {
if (!ci.low_bound_is_strict())
return ci.get_low_bound().get_double();
double eps = 0.00001;
if (!ci.upper_bound_is_set())
return ci.get_low_bound().get_double() + eps;
eps = std::min((ci.get_upper_bound() - ci.get_low_bound()).get_double() / 1000, eps);
return ci.get_low_bound().get_double() + eps;
}
};
struct constraint_index_and_column_struct {
int m_ci = -1;
int m_j = -1;
constraint_index_and_column_struct() {}
constraint_index_and_column_struct(unsigned ci, unsigned j):
m_ci(static_cast<int>(ci)),
m_j(static_cast<int>(j))
{}
bool operator==(const constraint_index_and_column_struct & a) const { return a.m_ci == m_ci && a.m_j == m_j; }
bool operator!=(const constraint_index_and_column_struct & a) const { return ! (*this == a);}
};
class lar_solver : public column_namer {
//////////////////// fields //////////////////////////
lp_settings m_settings;
stacked_value<lp_status> m_status = OPTIMAL;
std::unordered_map<unsigned, var_index> m_ext_vars_to_columns;
vector<unsigned> m_columns_to_ext_vars_or_term_indices;
stacked_vector<ul_pair> m_vars_to_ul_pairs;
vector<lar_base_constraint*> m_constraints;
stacked_value<unsigned> m_constraint_count;
indexed_vector<mpq> m_incoming_buffer;
lp_settings m_settings;
stacked_value<lp_status> m_status;
stacked_value<simplex_strategy_enum> m_simplex_strategy;
std::unordered_map<unsigned, var_index> m_ext_vars_to_columns;
vector<unsigned> m_columns_to_ext_vars_or_term_indices;
stacked_vector<ul_pair> m_vars_to_ul_pairs;
vector<lar_base_constraint*> m_constraints;
stacked_value<unsigned> m_constraint_count;
// the set of column indices j such that bounds have changed for j
int_set m_columns_with_changed_bound;
int_set m_rows_with_changed_bounds;
int_set m_basic_columns_with_changed_cost;
stacked_value<int> m_infeasible_column_index = -1; // such can be found at the initialization step
stacked_value<unsigned> m_term_count;
public: // debug remove later
vector<lar_term*> m_terms;
private:
vector<lar_term*> m_orig_terms;
const var_index m_terms_start_index = 1000000;
indexed_vector<mpq> m_column_buffer;
std::function<column_type (unsigned)> m_column_type_function = [this] (unsigned j) {return m_mpq_lar_core_solver.m_column_types()[j];};
int_set m_columns_with_changed_bound;
int_set m_rows_with_changed_bounds;
int_set m_basic_columns_with_changed_cost;
stacked_value<int> m_infeasible_column_index; // such can be found at the initialization step
stacked_value<unsigned> m_term_count;
vector<lar_term*> m_terms;
vector<lar_term*> m_orig_terms;
const var_index m_terms_start_index;
indexed_vector<mpq> m_column_buffer;
public:
lar_core_solver m_mpq_lar_core_solver;
unsigned constraint_count() const {
return m_constraints.size();
}
const lar_base_constraint& get_constraint(unsigned ci) const {
return *(m_constraints[ci]);
}
unsigned constraint_count() const {
return m_constraints.size();
}
const lar_base_constraint& get_constraint(unsigned ci) const {
return *(m_constraints[ci]);
}
////////////////// methods ////////////////////////////////
static_matrix<mpq, numeric_pair<mpq>> & A_r() { return m_mpq_lar_core_solver.m_r_A;}
@ -128,10 +79,11 @@ public:
}
lar_solver() : m_mpq_lar_core_solver(
m_settings,
*this
) {}
lar_solver() : m_status(OPTIMAL),
m_infeasible_column_index(-1),
m_terms_start_index(1000000),
m_mpq_lar_core_solver(m_settings, *this)
{}
void set_propagate_bounds_on_pivoted_rows_mode(bool v) {
m_mpq_lar_core_solver.m_r_solver.m_pivoted_rows = v? (& m_rows_with_changed_bounds) : nullptr;
@ -146,25 +98,8 @@ public:
delete t;
}
var_index add_var(unsigned ext_j) {
var_index i;
lean_assert (ext_j < m_terms_start_index);
if (ext_j >= m_terms_start_index)
throw 0; // todo : what is the right was to exit?
if (try_get_val(m_ext_vars_to_columns, ext_j, i)) {
return i;
}
lean_assert(m_vars_to_ul_pairs.size() == A_r().column_count());
i = A_r().column_count();
m_vars_to_ul_pairs.push_back (ul_pair(static_cast<unsigned>(-1)));
register_new_ext_var_index(ext_j);
add_non_basic_var_to_core_fields();
lean_assert(sizes_are_correct());
return i;
}
#include "util/lp/init_lar_solver.h"
numeric_pair<mpq> const& get_value(var_index vi) const { return m_mpq_lar_core_solver.m_r_x[vi]; }
bool is_term(var_index j) const {
@ -177,98 +112,16 @@ public:
}
bool need_to_presolve_with_doubles() const { return m_mpq_lar_core_solver.need_to_presolve_with_double_solver(); }
void add_row_from_term_no_constraint(const lar_term * term) {
// j will be a new variable
unsigned j = A_r().column_count();
ul_pair ul(j);
m_vars_to_ul_pairs.push_back(ul);
add_basic_var_to_core_fields();
if (use_tableau()) {
auto it = iterator_on_term_with_basis_var(*term, j);
A_r().fill_last_row_with_pivoting(it,
m_mpq_lar_core_solver.m_r_solver.m_basis_heading);
m_mpq_lar_core_solver.m_r_solver.m_b.resize(A_r().column_count(), zero_of_type<mpq>());
} else {
fill_last_row_of_A_r(A_r(), term);
}
m_mpq_lar_core_solver.m_r_x[j] = get_basic_var_value_from_row_directly(A_r().row_count() - 1);
if (need_to_presolve_with_doubles())
fill_last_row_of_A_d(A_d(), term);
}
bool use_lu() const { return m_settings.simplex_strategy() == simplex_strategy_enum::lu; }
void add_constraint_from_term_and_create_new_column_row(unsigned term_j, const lar_term* term,
lconstraint_kind kind, const mpq & right_side) {
lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size());
// j will be a new variable
unsigned j = A_r().column_count();
ul_pair ul(j);
m_vars_to_ul_pairs.push_back(ul);
add_basic_var_to_core_fields();
if (!m_settings.use_tableau()) {
fill_last_row_of_A_r(A_r(), term);
}
else {
auto it = iterator_on_term_with_basis_var(*term, j);
A_r().fill_last_row_with_pivoting(it,
m_mpq_lar_core_solver.m_r_solver.m_basis_heading);
m_mpq_lar_core_solver.m_r_solver.m_b.resize(A_r().column_count(), zero_of_type<mpq>());
}
m_mpq_lar_core_solver.m_r_x[A_r().column_count() - 1] = get_basic_var_value_from_row_directly(A_r().row_count() - 1);
fill_last_row_of_A_d(A_d(), term);
register_new_ext_var_index(term_j);
// m_constraints.size() is the index of the constrained that is about to be added
update_column_type_and_bound(j, kind, right_side - term->m_v, m_constraints.size());
m_constraints.push_back(new lar_term_constraint(term, kind, right_side));
lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size());
}
void add_var_bound_on_constraint_for_term(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) {
lean_assert(is_term(j));
unsigned adjusted_term_index = adjust_term_index(j);
unsigned term_j;
if (try_get_val(m_ext_vars_to_columns, j, term_j)) {
mpq rs = right_side - m_orig_terms[adjusted_term_index]->m_v;
m_constraints.push_back(new lar_term_constraint(m_orig_terms[adjusted_term_index], kind, right_side));
update_column_type_and_bound(term_j, kind, rs, ci);
}
else {
add_constraint_from_term_and_create_new_column_row(j, m_orig_terms[adjusted_term_index], kind, right_side);
}
}
void add_row_for_term(const lar_term * term) {
lean_assert(sizes_are_correct());
add_row_from_term_no_constraint(term);
lean_assert(sizes_are_correct());
}
bool sizes_are_correct() const {
lean_assert(!m_mpq_lar_core_solver.need_to_presolve_with_double_solver() || A_r().column_count() == A_d().column_count());
lean_assert(strategy_is_undecided() || !m_mpq_lar_core_solver.need_to_presolve_with_double_solver() || A_r().column_count() == A_d().column_count());
lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_column_types.size());
lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size());
lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_x.size());
return true;
}
constraint_index add_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side) {
lean_assert(sizes_are_correct());
constraint_index ci = m_constraints.size();
if (!is_term(j)) { // j is a var
auto vc = new lar_var_constraint(j, kind, right_side);
m_constraints.push_back(vc);
update_column_type_and_bound(j, kind, right_side, ci);
} else {
add_var_bound_on_constraint_for_term(j, kind, right_side, ci);
}
lean_assert(sizes_are_correct());
return ci;
}
void print_implied_bound(const implied_bound& be, std::ostream & out) const {
out << "implied bound\n";
@ -490,10 +343,10 @@ public:
// new linear_combination_iterator_on_vector<mpq>(m_terms[adjust_term_index(term_index)]->coeffs_as_vector());
}
unsigned adjust_column_index_to_term_index(unsigned j) const {
unsigned ext_var_or_term = m_columns_to_ext_vars_or_term_indices[j];
return ext_var_or_term < m_terms_start_index ? j : ext_var_or_term;
}
unsigned adjust_column_index_to_term_index(unsigned j) const {
unsigned ext_var_or_term = m_columns_to_ext_vars_or_term_indices[j];
return ext_var_or_term < m_terms_start_index ? j : ext_var_or_term;
}
void propagate_bounds_on_a_term(const lar_term& t, bound_propagator & bp, unsigned term_offset) {
lean_assert(false); // not implemented
@ -561,6 +414,9 @@ public:
void set_status(lp_status s) {m_status = s;}
lp_status find_feasible_solution() {
if (strategy_is_undecided())
decide_on_strategy_and_adjust_initial_state();
m_mpq_lar_core_solver.m_r_solver.m_look_for_feasible_solution_only = true;
return solve();
}
@ -599,7 +455,8 @@ public:
return ret;
}
void push() {
lean_assert(sizes_are_correct());
m_simplex_strategy = m_settings.simplex_strategy();
m_simplex_strategy.push();
m_status.push();
m_vars_to_ul_pairs.push();
m_infeasible_column_index.push();
@ -608,7 +465,6 @@ public:
m_term_count.push();
m_constraint_count = m_constraints.size();
m_constraint_count.push();
lean_assert(sizes_are_correct());
}
static void clean_large_elements_after_pop(unsigned n, int_set& set) {
@ -627,8 +483,7 @@ public:
void pop(unsigned k) {
lean_assert(sizes_are_correct());
int n_was = static_cast<int>(m_ext_vars_to_columns.size());
int n_was = static_cast<int>(m_ext_vars_to_columns.size());
m_status.pop(k);
m_infeasible_column_index.pop(k);
unsigned n = m_vars_to_ul_pairs.peek_size(k);
@ -645,7 +500,8 @@ public:
unsigned m = A_r().row_count();
clean_large_elements_after_pop(m, m_rows_with_changed_bounds);
clean_inf_set_of_r_solver_after_pop();
lean_assert(!use_tableau() || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau());
lean_assert(m_settings.simplex_strategy() == simplex_strategy_enum::undecided ||
(!use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau());
lean_assert(ax_is_correct());
@ -662,7 +518,9 @@ public:
}
m_terms.resize(m_term_count);
m_orig_terms.resize(m_term_count);
lean_assert(sizes_are_correct());
m_simplex_strategy.pop(k);
m_settings.simplex_strategy() = m_simplex_strategy;
lean_assert(sizes_are_correct());
lean_assert((!m_settings.use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau());
}
@ -676,6 +534,9 @@ public:
bool maximize_term_on_tableau(const vector<std::pair<mpq, var_index>> & term,
impq &term_max) {
if (settings().simplex_strategy() == simplex_strategy_enum::undecided)
decide_on_strategy_and_adjust_initial_state();
m_mpq_lar_core_solver.solve();
if (m_mpq_lar_core_solver.m_r_solver.get_status() == UNBOUNDED)
return false;
@ -747,13 +608,13 @@ public:
bool maximize_term_on_corrected_r_solver(const vector<std::pair<mpq, var_index>> & term,
impq &term_max) {
settings().backup_costs = false;
switch (settings().m_simplex_strategy) {
switch (settings().simplex_strategy()) {
case simplex_strategy_enum::tableau_rows:
prepare_costs_for_r_solver(term);
settings().m_simplex_strategy = simplex_strategy_enum::tableau_costs;
settings().simplex_strategy() = simplex_strategy_enum::tableau_costs;
{
bool ret = maximize_term_on_tableau(term, term_max);
settings().m_simplex_strategy = simplex_strategy_enum::tableau_rows;
settings().simplex_strategy() = simplex_strategy_enum::tableau_rows;
set_costs_to_zero(term);
m_mpq_lar_core_solver.m_r_solver.set_status(OPTIMAL);
return ret;
@ -767,7 +628,7 @@ public:
return ret;
}
case simplex_strategy_enum::no_tableau:
case simplex_strategy_enum::lu:
lean_assert(false); // not implemented
return false;
default:
@ -786,24 +647,6 @@ public:
var_index add_term(const vector<std::pair<mpq, var_index>> & coeffs,
const mpq &m_v) {
lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size());
m_terms.push_back(new lar_term(coeffs, m_v));
m_orig_terms.push_back(new lar_term(coeffs, m_v));
unsigned adjusted_term_index = m_terms.size() - 1;
if (use_tableau() && !coeffs.empty()) {
register_new_ext_var_index(m_terms_start_index + adjusted_term_index);
add_row_for_term(m_orig_terms.back());
if (m_settings.bound_propagation())
m_rows_with_changed_bounds.insert(A_r().row_count() - 1);
}
lean_assert(m_ext_vars_to_columns.size() == A_r().column_count());
lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size());
return m_terms_start_index + adjusted_term_index;
}
const lar_term & get_term(unsigned j) const {
lean_assert(j >= m_terms_start_index);
return *m_terms[j - m_terms_start_index];
@ -818,78 +661,6 @@ public:
A_d().pop(k);
}
void add_new_var_to_core_fields_for_mpq(bool register_in_basis) {
unsigned j = A_r().column_count();
A_r().add_column();
lean_assert(m_mpq_lar_core_solver.m_r_x.size() == j);
// lean_assert(m_mpq_lar_core_solver.m_r_low_bounds.size() == j && m_mpq_lar_core_solver.m_r_upper_bounds.size() == j); // restore later
m_mpq_lar_core_solver.m_r_x.resize(j + 1);
m_mpq_lar_core_solver.m_r_low_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.m_inf_set.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);
lean_assert(m_mpq_lar_core_solver.m_r_heading.size() == j); // as A().column_count() on the entry to the method
if (register_in_basis) {
A_r().add_row();
m_mpq_lar_core_solver.m_r_heading.push_back(m_mpq_lar_core_solver.m_r_basis.size());
m_mpq_lar_core_solver.m_r_basis.push_back(j);
if (m_settings.bound_propagation())
m_rows_with_changed_bounds.insert(A_r().row_count() - 1);
} else {
m_mpq_lar_core_solver.m_r_heading.push_back(- static_cast<int>(m_mpq_lar_core_solver.m_r_nbasis.size()) - 1);
m_mpq_lar_core_solver.m_r_nbasis.push_back(j);
}
}
void add_new_var_to_core_fields_for_doubles(bool register_in_basis) {
unsigned j = A_d().column_count();
A_d().add_column();
lean_assert(m_mpq_lar_core_solver.m_d_x.size() == j);
// lean_assert(m_mpq_lar_core_solver.m_d_low_bounds.size() == j && m_mpq_lar_core_solver.m_d_upper_bounds.size() == j); // restore later
m_mpq_lar_core_solver.m_d_x.resize(j + 1 );
m_mpq_lar_core_solver.m_d_low_bounds.resize(j + 1);
m_mpq_lar_core_solver.m_d_upper_bounds.resize(j + 1);
lean_assert(m_mpq_lar_core_solver.m_d_heading.size() == j); // as A().column_count() on the entry to the method
if (register_in_basis) {
A_d().add_row();
m_mpq_lar_core_solver.m_d_heading.push_back(m_mpq_lar_core_solver.m_d_basis.size());
m_mpq_lar_core_solver.m_d_basis.push_back(j);
}else {
m_mpq_lar_core_solver.m_d_heading.push_back(- static_cast<int>(m_mpq_lar_core_solver.m_d_nbasis.size()) - 1);
m_mpq_lar_core_solver.m_d_nbasis.push_back(j);
}
}
void add_basic_var_to_core_fields() {
bool need_to_presolve_with_doubles = m_mpq_lar_core_solver.need_to_presolve_with_double_solver();
lean_assert(!need_to_presolve_with_doubles || A_r().column_count() == A_d().column_count());
m_mpq_lar_core_solver.m_column_types.push_back(column_type::free_column);
m_columns_with_changed_bound.increase_size_by_one();
m_rows_with_changed_bounds.increase_size_by_one();
add_new_var_to_core_fields_for_mpq(true);
if (need_to_presolve_with_doubles)
add_new_var_to_core_fields_for_doubles(true);
}
void add_non_basic_var_to_core_fields() {
lean_assert(!m_mpq_lar_core_solver.need_to_presolve_with_double_solver() || A_r().column_count() == A_d().column_count());
m_mpq_lar_core_solver.m_column_types.push_back(column_type::free_column);
m_columns_with_changed_bound.increase_size_by_one();
add_new_var_to_core_fields_for_mpq(false);
if (m_mpq_lar_core_solver.need_to_presolve_with_double_solver())
add_new_var_to_core_fields_for_doubles(false);
}
void register_new_ext_var_index(unsigned s) {
lean_assert(!contains(m_ext_vars_to_columns, s));
unsigned j = static_cast<unsigned>(m_ext_vars_to_columns.size());
m_ext_vars_to_columns[s] = j;
lean_assert(m_columns_to_ext_vars_or_term_indices.size() == j);
m_columns_to_ext_vars_or_term_indices.push_back(s);
}
void set_upper_bound_witness(var_index j, constraint_index ci) {
ul_pair ul = m_vars_to_ul_pairs[j];
@ -903,312 +674,6 @@ public:
m_vars_to_ul_pairs[j] = ul;
}
void update_free_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_ind) {
mpq y_of_bound(0);
switch (kind) {
case LT:
y_of_bound = -1;
case LE:
m_mpq_lar_core_solver.m_column_types[j] = column_type::upper_bound;
lean_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::upper_bound);
lean_assert(m_mpq_lar_core_solver.m_r_upper_bounds.size() > j);
{
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, constr_ind);
break;
case GT:
y_of_bound = 1;
case GE:
m_mpq_lar_core_solver.m_column_types[j] = column_type::low_bound;
lean_assert(m_mpq_lar_core_solver.m_r_upper_bounds.size() > j);
{
auto low = numeric_pair<mpq>(right_side, y_of_bound);
m_mpq_lar_core_solver.m_r_low_bounds[j] = low;
}
set_low_bound_witness(j, constr_ind);
break;
case EQ:
m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed;
m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = numeric_pair<mpq>(right_side, zero_of_type<mpq>());
set_upper_bound_witness(j, constr_ind);
set_low_bound_witness(j, constr_ind);
break;
default:
lean_unreachable();
}
m_columns_with_changed_bound.insert(j);
}
void update_upper_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) {
lean_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::upper_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_upper_bounds()[j]) {
m_mpq_lar_core_solver.m_r_upper_bounds[j] = up;
set_upper_bound_witness(j, ci);
m_columns_with_changed_bound.insert(j);
}
}
break;
case GT:
y_of_bound = 1;
case GE:
m_mpq_lar_core_solver.m_column_types[j] = column_type::boxed;
{
auto low = numeric_pair<mpq>(right_side, y_of_bound);
m_mpq_lar_core_solver.m_r_low_bounds[j] = low;
set_low_bound_witness(j, ci);
m_columns_with_changed_bound.insert(j);
if (low > m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
m_status = INFEASIBLE;
m_infeasible_column_index = j;
} else {
m_mpq_lar_core_solver.m_column_types[j] = m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j]? column_type::boxed : column_type::fixed;
}
}
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]) {
m_status = INFEASIBLE;
set_low_bound_witness(j, ci);
m_infeasible_column_index = j;
} else {
m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = v;
m_columns_with_changed_bound.insert(j);
set_low_bound_witness(j, ci);
set_upper_bound_witness(j, ci);
m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed;
}
break;
}
break;
default:
lean_unreachable();
}
}
void update_boxed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) {
lean_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::boxed && m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_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);
if (up < m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
m_mpq_lar_core_solver.m_r_upper_bounds[j] = up;
set_upper_bound_witness(j, ci);
m_columns_with_changed_bound.insert(j);
}
if (up < m_mpq_lar_core_solver.m_r_low_bounds[j]) {
m_status = INFEASIBLE;
lean_assert(false);
m_infeasible_column_index = j;
} else {
if (m_mpq_lar_core_solver.m_r_low_bounds()[j] == m_mpq_lar_core_solver.m_r_upper_bounds()[j])
m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed;
}
}
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_low_bounds[j]) {
m_mpq_lar_core_solver.m_r_low_bounds[j] = low;
m_columns_with_changed_bound.insert(j);
set_low_bound_witness(j, ci);
}
if (low > m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
m_status = INFEASIBLE;
m_infeasible_column_index = j;
} else if ( low == m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed;
}
}
break;
case EQ:
{
auto v = numeric_pair<mpq>(right_side, zero_of_type<mpq>());
if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) {
m_status = INFEASIBLE;
m_infeasible_column_index = j;
set_upper_bound_witness(j, ci);
} else if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
m_status = INFEASIBLE;
m_infeasible_column_index = j;
set_low_bound_witness(j, ci);
} else {
m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = v;
set_low_bound_witness(j, ci);
set_upper_bound_witness(j, ci);
m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed;
m_columns_with_changed_bound.insert(j);
}
break;
}
default:
lean_unreachable();
}
}
void update_low_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) {
lean_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::low_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);
m_mpq_lar_core_solver.m_r_upper_bounds[j] = up;
set_upper_bound_witness(j, ci);
m_columns_with_changed_bound.insert(j);
if (up < m_mpq_lar_core_solver.m_r_low_bounds[j]) {
m_status = INFEASIBLE;
m_infeasible_column_index = j;
} else {
m_mpq_lar_core_solver.m_column_types[j] = m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j]? column_type::boxed : column_type::fixed;
}
}
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_low_bounds[j]) {
m_mpq_lar_core_solver.m_r_low_bounds[j] = low;
m_columns_with_changed_bound.insert(j);
set_low_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_low_bounds[j]) {
m_status = INFEASIBLE;
m_infeasible_column_index = j;
set_upper_bound_witness(j, ci);
} else {
m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = v;
set_low_bound_witness(j, ci);
set_upper_bound_witness(j, ci);
m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed;
}
m_columns_with_changed_bound.insert(j);
break;
}
default:
lean_unreachable();
}
}
void update_fixed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) {
lean_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::fixed && m_mpq_lar_core_solver.m_r_low_bounds()[j] == m_mpq_lar_core_solver.m_r_upper_bounds()[j]));
lean_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_r_low_bounds()[j].y.is_zero() && m_mpq_lar_core_solver.m_r_upper_bounds()[j].y.is_zero()));
auto v = numeric_pair<mpq>(right_side, mpq(0));
mpq y_of_bound(0);
switch (kind) {
case LT:
if (v <= m_mpq_lar_core_solver.m_r_low_bounds[j]) {
m_status = INFEASIBLE;
m_infeasible_column_index = j;
set_upper_bound_witness(j, ci);
}
break;
case LE:
{
if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) {
m_status = INFEASIBLE;
m_infeasible_column_index = j;
set_upper_bound_witness(j, ci);
}
}
break;
case GT:
{
if (v >= m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
m_status = INFEASIBLE;
m_infeasible_column_index =j;
set_low_bound_witness(j, ci);
}
}
break;
case GE:
{
if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
m_status = INFEASIBLE;
m_infeasible_column_index = j;
set_low_bound_witness(j, ci);
}
}
break;
case EQ:
{
if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) {
m_status = INFEASIBLE;
m_infeasible_column_index = j;
set_upper_bound_witness(j, ci);
} else if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
m_status = INFEASIBLE;
m_infeasible_column_index = j;
set_low_bound_witness(j, ci);
}
break;
}
default:
lean_unreachable();
}
}
void update_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_index) {
switch(m_mpq_lar_core_solver.m_column_types[j]) {
case column_type::free_column:
update_free_column_type_and_bound(j, kind, right_side, constr_index);
break;
case column_type::boxed:
update_boxed_column_type_and_bound(j, kind, right_side, constr_index);
break;
case column_type::low_bound:
update_low_bound_column_type_and_bound(j, kind, right_side, constr_index);
break;
case column_type::upper_bound:
update_upper_bound_column_type_and_bound(j, kind, right_side, constr_index);
break;
case column_type::fixed:
update_fixed_column_type_and_bound(j, kind, right_side, constr_index);
break;
default:
lean_assert(false); // cannot be here
}
}
void substitute_terms(const mpq & mult,
const vector<std::pair<mpq, var_index>>& left_side_with_terms,
@ -1247,8 +712,9 @@ public:
bool use_tableau() const { return m_settings.use_tableau(); }
bool use_tableau_costs() const { return m_settings.simplex_strategy() == simplex_strategy_enum::tableau_costs; }
bool use_tableau_costs() const {
return m_settings.simplex_strategy() == simplex_strategy_enum::tableau_costs;
}
void detect_rows_of_column_with_bound_change(unsigned j) {
if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { // it is a basic column
@ -1485,23 +951,6 @@ public:
unsigned basis_j = A.column_count() - 1;
A.set(last_row, basis_j, mpq(1));
}
// this fills the last row of A_d and sets the basis column: -1 in the last column of the row
void fill_last_row_of_A_d(static_matrix<double, double> & A, const lar_term* ls) {
lean_assert(A.row_count() > 0);
lean_assert(A.column_count() > 0);
unsigned last_row = A.row_count() - 1;
lean_assert(A.m_rows[last_row].empty());
for (auto & t : ls->m_coeffs) {
lean_assert(!is_zero(t.second));
var_index j = t.first;
A.set(last_row, j, - t.second.get_double());
}
unsigned basis_j = A.column_count() - 1;
A.set(last_row, basis_j, - 1 );
}
template <typename U, typename V>
void create_matrix_A(static_matrix<U, V> & matr) {
@ -1518,8 +967,8 @@ public:
template <typename U, typename V>
void copy_from_mpq_matrix(static_matrix<U, V> & matr) {
lean_assert(matr.row_count() == A_r().row_count());
lean_assert(matr.column_count() == A_r().column_count());
matr.m_rows.resize(A_r().row_count());
matr.m_columns.resize(A_r().column_count());
for (unsigned i = 0; i < matr.row_count(); i++) {
for (auto & it : A_r().m_rows[i]) {
matr.set(i, it.m_j, convert_struct<U, mpq>::convert(it.get_val()));
@ -1734,58 +1183,6 @@ public:
return ret;
}
// template <typename U, typename V>
// void prepare_core_solver_fields_with_signature(static_matrix<U, V> & A, vector<V> & x,
// vector<V> & low_bound,
// vector<V> & upper_bound, const lar_solution_signature & signature) {
// create_matrix_A_r(A);
// fill_bounds_for_core_solver(low_bound, upper_bound);
// if (m_status == INFEASIBLE) {
// lean_assert(false); // not implemented
// }
// resize_and_init_x_with_signature(x, low_bound, upper_bound, signature);
// lean_assert(A.column_count() == x.size());
// }
// void find_solution_signature_with_doubles(lar_solution_signature & signature) {
// static_matrix<double, double> A;
// vector<double> x, low_bounds, upper_bounds;
// lean_assert(false); // not implemented
// // prepare_core_solver_fields<double, double>(A, x, low_bounds, upper_bounds);
// vector<double> column_scale_vector;
// vector<double> right_side_vector(A.row_count(), 0);
// scaler<double, double > scaler(right_side_vector,
// A,
// m_settings.scaling_minimum,
// m_settings.scaling_maximum,
// column_scale_vector,
// m_settings);
// if (!scaler.scale()) {
// // the scale did not succeed, unscaling
// A.clear();
// create_matrix_A_r(A);
// for (auto & s : column_scale_vector)
// s = 1.0;
// }
// vector<double> costs(A.column_count());
// auto core_solver = lp_primal_core_solver<double, double>(A,
// right_side_vector,
// x,
// m_mpq_lar_core_solver.m_basis,
// m_mpq_lar_core_solver.m_nbasis,
// m_mpq_lar_core_solver.m_heading,
// costs,
// m_mpq_lar_core_solver.m_column_types(),
// low_bounds,
// upper_bounds,
// m_settings,
// *this);
// core_solver.find_feasible_solution();
// extract_signature_from_lp_core_solver(core_solver, signature);
// }
bool has_lower_bound(var_index var, constraint_index& ci, mpq& value, bool& is_strict) {
if (var >= m_vars_to_ul_pairs.size()) {
@ -1862,12 +1259,29 @@ public:
void get_model(std::unordered_map<var_index, mpq> & variable_values) const {
mpq delta = mpq(1, 2); // start from 0.5 to have less clashes
lean_assert(m_status == OPTIMAL);
mpq delta = m_mpq_lar_core_solver.find_delta_for_strict_bounds();
for (unsigned i = 0; i < m_mpq_lar_core_solver.m_r_x.size(); i++ ) {
const numeric_pair<mpq> & rp = m_mpq_lar_core_solver.m_r_x[i];
variable_values[i] = rp.x + delta * rp.y;
}
unsigned i;
do {
// different pairs have to produce different singleton values
std::unordered_set<impq> set_of_different_pairs;
std::unordered_set<mpq> set_of_different_singles;
delta = m_mpq_lar_core_solver.find_delta_for_strict_bounds(delta);
for (i = 0; i < m_mpq_lar_core_solver.m_r_x.size(); i++ ) {
const numeric_pair<mpq> & rp = m_mpq_lar_core_solver.m_r_x[i];
set_of_different_pairs.insert(rp);
mpq x = rp.x + delta * rp.y;
set_of_different_singles.insert(x);
if (set_of_different_pairs.size()
!= set_of_different_singles.size()) {
delta /= mpq(2);
break;
}
variable_values[i] = x;
}
} while (i != m_mpq_lar_core_solver.m_r_x.size());
}

View file

@ -16,7 +16,7 @@ struct linear_combination_iterator {
template <typename T>
struct linear_combination_iterator_on_vector : linear_combination_iterator<T> {
vector<std::pair<T, unsigned>> & m_vector;
int m_offset = 0;
int m_offset;
bool next(T & a, unsigned & i) {
if(m_offset >= m_vector.size())
return false;
@ -40,7 +40,10 @@ struct linear_combination_iterator_on_vector : linear_combination_iterator<T> {
linear_combination_iterator<T> * clone() {
return new linear_combination_iterator_on_vector(m_vector);
}
linear_combination_iterator_on_vector(vector<std::pair<T, unsigned>> & vec): m_vector(vec) {}
linear_combination_iterator_on_vector(vector<std::pair<T, unsigned>> & vec):
m_vector(vec),
m_offset(0)
{}
unsigned size() const { return m_vector.size(); }
};

View file

@ -17,7 +17,8 @@ namespace lean {
template <typename T, typename X> // X represents the type of the x variable and the bounds
class lp_core_solver_base {
unsigned m_total_iterations = 0;
unsigned m_total_iterations;
unsigned m_iters_with_no_cost_growing;
unsigned inc_total_iterations() { ++m_settings.st().m_total_iterations; return m_total_iterations++; }
private:
lp_status m_status;
@ -25,40 +26,39 @@ public:
bool current_x_is_feasible() const { return m_inf_set.size() == 0; }
bool current_x_is_infeasible() const { return m_inf_set.size() != 0; }
int_set m_inf_set;
bool m_using_infeas_costs = false;
bool m_using_infeas_costs;
vector<unsigned> m_columns_nz; // m_columns_nz[i] keeps an approximate value of non zeroes the i-th column
vector<unsigned> m_rows_nz; // m_rows_nz[i] keeps an approximate value of non zeroes in the i-th row
indexed_vector<T> m_pivot_row_of_B_1; // the pivot row of the reverse of B
indexed_vector<T> m_pivot_row; // this is the real pivot row of the simplex tableu
vector<unsigned> m_columns_nz; // m_columns_nz[i] keeps an approximate value of non zeroes the i-th column
vector<unsigned> m_rows_nz; // m_rows_nz[i] keeps an approximate value of non zeroes in the i-th row
indexed_vector<T> m_pivot_row_of_B_1; // the pivot row of the reverse of B
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> & m_b; // the right side
vector<unsigned> & m_basis;
vector<unsigned>& m_nbasis;
vector<int>& m_basis_heading;
vector<X> & m_x; // a feasible solution, the fist time set in the constructor
vector<T> & m_costs;
lp_settings & m_settings;
vector<T> m_y; // the buffer for yB = cb
vector<X> & m_b; // the right side
vector<unsigned> & m_basis;
vector<unsigned>& m_nbasis;
vector<int>& m_basis_heading;
vector<X> & m_x; // a feasible solution, the fist time set in the constructor
vector<T> & m_costs;
lp_settings & m_settings;
vector<T> m_y; // the buffer for yB = cb
// a device that is able to solve Bx=c, xB=d, and change the basis
lu<T, X> * m_factorization = nullptr;
const column_namer & m_column_names;
indexed_vector<T> m_w; // the vector featuring in 24.3 of the Chvatal book
vector<T> m_d; // the vector of reduced costs
indexed_vector<T> m_ed; // the solution of B*m_ed = a
unsigned m_iters_with_no_cost_growing = 0;
lu<T, X> * m_factorization;
const column_namer & m_column_names;
indexed_vector<T> m_w; // the vector featuring in 24.3 of the Chvatal book
vector<T> m_d; // the vector of reduced costs
indexed_vector<T> m_ed; // the solution of B*m_ed = a
const vector<column_type> & m_column_types;
const vector<X> & m_low_bounds;
const vector<X> & m_upper_bounds;
vector<T> m_column_norms; // the approximate squares of column norms that help choosing a profitable column
vector<X> m_copy_of_xB;
unsigned m_basis_sort_counter = 0;
vector<T> m_steepest_edge_coefficients;
vector<unsigned> m_trace_of_basis_change_vector; // the even positions are entering, the odd positions are leaving
bool m_tracing_basis_changes = false;
int_set* m_pivoted_rows = nullptr;
bool m_look_for_feasible_solution_only = false;
const vector<X> & m_low_bounds;
const vector<X> & m_upper_bounds;
vector<T> m_column_norms; // the approximate squares of column norms that help choosing a profitable column
vector<X> m_copy_of_xB;
unsigned m_basis_sort_counter;
vector<T> m_steepest_edge_coefficients;
vector<unsigned> m_trace_of_basis_change_vector; // the even positions are entering, the odd positions are leaving
bool m_tracing_basis_changes;
int_set* m_pivoted_rows;
bool m_look_for_feasible_solution_only;
void start_tracing_basis_changes() {
m_trace_of_basis_change_vector.resize(0);
m_tracing_basis_changes = true;
@ -348,7 +348,7 @@ public:
if (x_is_at_bound(j))
break; // we should preserve x if possible
// snap randomly
if (my_random() % 2 == 1)
if (m_settings.random_next() % 2 == 1)
m_x[j] = m_low_bounds[j];
else
m_x[j] = m_upper_bounds[j];
@ -678,6 +678,13 @@ public:
lean_assert(is_zero(this->m_costs[j]));
}
return true;
}
}
unsigned & iters_with_no_cost_growing() {
return m_iters_with_no_cost_growing;
}
const unsigned & iters_with_no_cost_growing() const {
return m_iters_with_no_cost_growing;
}
};
}

View file

@ -22,8 +22,11 @@ lp_core_solver_base(static_matrix<T, X> & A,
const vector<column_type> & column_types,
const vector<X> & low_bound_values,
const vector<X> & upper_bound_values):
m_total_iterations(0),
m_iters_with_no_cost_growing(0),
m_status(FEASIBLE),
m_inf_set(A.column_count()),
m_using_infeas_costs(false),
m_pivot_row_of_B_1(A.row_count()),
m_pivot_row(A.column_count()),
m_A(A),
@ -45,7 +48,11 @@ lp_core_solver_base(static_matrix<T, X> & A,
m_upper_bounds(upper_bound_values),
m_column_norms(m_n()),
m_copy_of_xB(m_m()),
m_steepest_edge_coefficients(A.column_count()) {
m_basis_sort_counter(0),
m_steepest_edge_coefficients(A.column_count()),
m_tracing_basis_changes(false),
m_pivoted_rows(nullptr),
m_look_for_feasible_solution_only(false) {
lean_assert(bounds_for_boxed_are_set_correctly());
init();
init_basis_heading_and_non_basic_columns_vector();
@ -57,10 +64,9 @@ allocate_basis_heading() { // the rest of initilization will be handled by the f
lean_assert(basis_heading_is_correct());
}
template <typename T, typename X> void lp_core_solver_base<T, X>::
init() {
my_random_init(m_settings.random_seed);
init() {
allocate_basis_heading();
if (!use_tableau())
if (m_settings.use_lu())
init_factorization(m_factorization, m_A, m_basis, m_settings);
}
@ -527,13 +533,19 @@ update_basis_and_x(int entering, int leaving, X const & tt) {
init_factorization(m_factorization, m_A, m_basis, m_settings);
if (!find_x_by_solving()) {
restore_x(entering, tt);
lean_assert(!A_mult_x_is_off());
if(A_mult_x_is_off()) {
m_status = FLOATING_POINT_ERROR;
m_iters_with_no_cost_growing++;
return false;
}
init_factorization(m_factorization, m_A, m_basis, m_settings);
m_iters_with_no_cost_growing++;
if (m_factorization->get_status() != LU_status::OK) {
std::stringstream s;
s << "failing refactor on off_result for entering = " << entering << ", leaving = " << leaving << " total_iterations = " << total_iterations();
throw_exception(s.str());
// s << "failing refactor on off_result for entering = " << entering << ", leaving = " << leaving << " total_iterations = " << total_iterations();
m_status = FLOATING_POINT_ERROR;
return false;
}
return false;
}

View file

@ -429,7 +429,7 @@ template <typename T, typename X> bool lp_dual_core_solver<T, X>::basis_change_a
if (snap_runaway_nonbasic_column(m_p)) {
if (!this->find_x_by_solving()) {
revert_to_previous_basis();
this->m_iters_with_no_cost_growing++;
this->iters_with_no_cost_growing()++;
return false;
}
}
@ -437,7 +437,7 @@ template <typename T, typename X> bool lp_dual_core_solver<T, X>::basis_change_a
if (!problem_is_dual_feasible()) {
// todo : shift the costs!!!!
revert_to_previous_basis();
this->m_iters_with_no_cost_growing++;
this->iters_with_no_cost_growing()++;
return false;
}
@ -537,7 +537,7 @@ template <typename T, typename X> unsigned lp_dual_core_solver<T, X>::get_number
if (this->m_m() > 300) {
s = (unsigned)((s / 100.0) * this->m_settings.percent_of_entering_to_check);
}
return my_random() % s + 1;
return this->m_settings.random_next() % s + 1;
}
template <typename T, typename X> bool lp_dual_core_solver<T, X>::delta_keeps_the_sign(int initial_delta_sign, const T & delta) {
@ -715,7 +715,7 @@ template <typename T, typename X> void lp_dual_core_solver<T, X>::update_xb_afte
template <typename T, typename X> void lp_dual_core_solver<T, X>::one_iteration() {
unsigned number_of_rows_to_try = get_number_of_rows_to_try_for_leaving();
unsigned offset_in_rows = my_random() % this->m_m();
unsigned offset_in_rows = this->m_settings.random_next() % this->m_m();
if (this->get_status() == TENTATIVE_DUAL_UNBOUNDED) {
number_of_rows_to_try = this->m_m();
} else {
@ -730,14 +730,14 @@ template <typename T, typename X> void lp_dual_core_solver<T, X>::solve() { // s
lean_assert(problem_is_dual_feasible());
lean_assert(this->basis_heading_is_correct());
this->set_total_iterations(0);
this->m_iters_with_no_cost_growing = 0;
this->iters_with_no_cost_growing() = 0;
do {
if (this->print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over("", *this->m_settings.get_message_ostream())){
return;
}
one_iteration();
} while (this->get_status() != FLOATING_POINT_ERROR && this->get_status() != DUAL_UNBOUNDED && this->get_status() != OPTIMAL &&
this->m_iters_with_no_cost_growing <= this->m_settings.max_number_of_iterations_with_no_improvements
this->iters_with_no_cost_growing() <= this->m_settings.max_number_of_iterations_with_no_improvements
&& this->total_iterations() <= this->m_settings.max_total_number_of_iterations);
}
}

View file

@ -11,7 +11,7 @@ namespace lean {
template <typename T, typename X>
class lp_dual_simplex: public lp_solver<T, X> {
lp_dual_core_solver<T, X> * m_core_solver = nullptr;
lp_dual_core_solver<T, X> * m_core_solver;
vector<T> m_b_copy;
vector<T> m_low_bounds; // We don't have a convention here that all low bounds are zeros. At least it does not hold for the first stage solver
vector<column_type> m_column_types_of_core_solver;
@ -24,6 +24,7 @@ public:
}
}
lp_dual_simplex() : m_core_solver(nullptr) {}
void decide_on_status_after_stage1();

12
src/util/lp/lp_params.pyg Normal file
View file

@ -0,0 +1,12 @@
def_module_params('lp',
export=True,
params=(
('rep_freq', UINT, 0, 'the report frequency, in how many iterations print the cost and other info '),
('min', BOOL, False, 'minimize cost'),
('print_stats', BOOL, False, 'print statistic'),
('simplex_strategy', UINT, 0, 'simplex strategy for the solver'),
('bprop_on_pivoted_rows', BOOL, True, 'propagate bounds on rows changed by the pivot operation')
))

View file

@ -32,21 +32,21 @@ class lp_primal_core_solver:public lp_core_solver_base<T, X> {
public:
// m_sign_of_entering is set to 1 if the entering variable needs
// to grow and is set to -1 otherwise
unsigned m_column_norm_update_counter;
T m_enter_price_eps;
int m_sign_of_entering_delta;
unsigned m_column_norm_update_counter;
T m_enter_price_eps;
int m_sign_of_entering_delta;
vector<breakpoint<X>> m_breakpoints;
binary_heap_priority_queue<X> m_breakpoint_indices_queue;
indexed_vector<T> m_beta; // see Swietanowski working vector beta for column norms
T m_epsilon_of_reduced_cost = T(1)/T(10000000);
vector<T> m_costs_backup;
T m_converted_harris_eps;
unsigned m_inf_row_index_for_tableau;
bool m_bland_mode_tableau;
int_set m_left_basis_tableau;
unsigned m_bland_mode_threshold = 1000;
unsigned m_left_basis_repeated;
vector<unsigned> m_leaving_candidates;
T m_epsilon_of_reduced_cost;
vector<T> m_costs_backup;
T m_converted_harris_eps;
unsigned m_inf_row_index_for_tableau;
bool m_bland_mode_tableau;
int_set m_left_basis_tableau;
unsigned m_bland_mode_threshold;
unsigned m_left_basis_repeated;
vector<unsigned> m_leaving_candidates;
// T m_converted_harris_eps = convert_struct<T, double>::convert(this->m_settings.harris_feasibility_tolerance);
std::list<unsigned> m_non_basis_list;
void sort_non_basis();
@ -76,10 +76,10 @@ public:
// choices.clear();
// choices.push_back(i);
// len = row_len;
// if (my_random() % 10) break;
// if (m_settings.random_next() % 10) break;
// } else if (row_len == len) {
// choices.push_back(i);
// if (my_random() % 10) break;
// if (m_settings.random_next() % 10) break;
// }
// }
@ -89,7 +89,7 @@ public:
// if (choices.size() == 1)
// return choices[0];
// unsigned k = my_random() % choices.size();
// unsigned k = this->m_settings.random_next() % choices.size();
// return choices[k];
// #endif
// }
@ -287,7 +287,7 @@ public:
choices.clear();
choices.push_back(&rc);
} else if (damage == num_of_non_free_basics &&
this->m_A.m_columns[j].size() <= len && (my_random() % 2)) {
this->m_A.m_columns[j].size() <= len && (this->m_settings.random_next() % 2)) {
choices.push_back(&rc);
len = this->m_A.m_columns[j].size();
}
@ -299,7 +299,7 @@ public:
return -1;
}
const row_cell<T>* rc = choices.size() == 1? choices[0] :
choices[my_random() % choices.size()];
choices[this->m_settings.random_next() % choices.size()];
a_ent = rc->m_value;
return rc->m_j;
@ -423,7 +423,7 @@ public:
void find_feasible_solution();
bool is_tiny() const {return this->m_m < 10 && this->m_n < 20;}
// bool is_tiny() const {return this->m_m < 10 && this->m_n < 20;}
void one_iteration();
void one_iteration_tableau();
@ -905,7 +905,9 @@ public:
column_type_array,
low_bound_values,
upper_bound_values),
m_beta(A.row_count()) {
m_beta(A.row_count()),
m_epsilon_of_reduced_cost(T(1)/T(10000000)),
m_bland_mode_threshold(1000) {
if (!(numeric_traits<T>::precise())) {
m_converted_harris_eps = convert_struct<T, double>::convert(this->m_settings.harris_feasibility_tolerance);

View file

@ -199,7 +199,7 @@ int lp_primal_core_solver<T, X>::choose_entering_column_presize(unsigned number_
entering_iter = non_basis_iter;
if (number_of_benefitial_columns_to_go_over)
number_of_benefitial_columns_to_go_over--;
} else if (t == j_nz && my_random() % 2 == 0) {
} else if (t == j_nz && this->m_settings.random_next() % 2 == 0) {
entering_iter = non_basis_iter;
}
}// while (number_of_benefitial_columns_to_go_over && initial_offset_in_non_basis != offset_in_nb);
@ -268,7 +268,7 @@ template <typename T, typename X> int lp_primal_core_solver<T, X>::advance_on_so
if (slope_at_entering * m_sign_of_entering_delta > - m_epsilon_of_reduced_cost) { // the slope started to increase infeasibility
break;
} else {
if ((numeric_traits<T>::precise() == false) || ( numeric_traits<T>::is_zero(slope_at_entering) && my_random() % 2 == 0)) {
if ((numeric_traits<T>::precise() == false) || ( numeric_traits<T>::is_zero(slope_at_entering) && this->m_settings.random_next() % 2 == 0)) {
// it is not cost benefitial to advance the delta more, so just break to increas the randomness
break;
}
@ -307,7 +307,7 @@ find_leaving_on_harris_theta(X const & harris_theta, X & t) {
// we also know that harris_theta is limited, so we will find a leaving
zero_harris_eps();
unsigned steps = this->m_ed.m_index.size();
unsigned k = my_random() % steps;
unsigned k = this->m_settings.random_next() % steps;
unsigned initial_k = k;
do {
unsigned i = this->m_ed.m_index[k];
@ -398,7 +398,7 @@ template <typename T, typename X> int lp_primal_core_solver<T, X>::find_leaving_
return find_leaving_and_t_with_breakpoints(entering, t);
bool unlimited = true;
unsigned steps = this->m_ed.m_index.size();
unsigned k = my_random() % steps;
unsigned k = this->m_settings.random_next() % steps;
unsigned initial_k = k;
unsigned row_min_nz = this->m_n() + 1;
m_leaving_candidates.clear();
@ -454,7 +454,7 @@ template <typename T, typename X> int lp_primal_core_solver<T, X>::find_leaving_
t = ratio;
return entering;
}
k = my_random() % m_leaving_candidates.size();
k = this->m_settings.random_next() % m_leaving_candidates.size();
return m_leaving_candidates[k];
}
@ -628,7 +628,7 @@ template <typename T, typename X> void lp_primal_core_solver<T, X>::backup_an
template <typename T, typename X> void lp_primal_core_solver<T, X>::init_run() {
this->m_basis_sort_counter = 0; // to initiate the sort of the basis
this->set_total_iterations(0);
this->m_iters_with_no_cost_growing = 0;
this->iters_with_no_cost_growing() = 0;
init_inf_set();
if (this->current_x_is_feasible() && this->m_look_for_feasible_solution_only)
return;
@ -664,7 +664,7 @@ void lp_primal_core_solver<T, X>::advance_on_entering_equal_leaving(int entering
this->init_lu();
if (!this->find_x_by_solving()) {
this->restore_x(entering, t * m_sign_of_entering_delta);
this->m_iters_with_no_cost_growing++;
this->iters_with_no_cost_growing()++;
LP_OUT(this->m_settings, "failing in advance_on_entering_equal_leaving for entering = " << entering << std::endl);
return;
}
@ -679,7 +679,7 @@ void lp_primal_core_solver<T, X>::advance_on_entering_equal_leaving(int entering
if (need_to_switch_costs() ||!this->current_x_is_feasible()) {
init_reduced_costs();
}
this->m_iters_with_no_cost_growing = 0;
this->iters_with_no_cost_growing() = 0;
}
template <typename T, typename X>void lp_primal_core_solver<T, X>::advance_on_entering_and_leaving(int entering, int leaving, X & t) {
@ -699,14 +699,14 @@ template <typename T, typename X>void lp_primal_core_solver<T, X>::advance_on_en
if (!pivot_compare_result){;}
else if (pivot_compare_result == 2) { // the sign is changed, cannot continue
this->set_status(UNSTABLE);
this->m_iters_with_no_cost_growing++;
this->iters_with_no_cost_growing()++;
return;
} else {
lean_assert(pivot_compare_result == 1);
this->init_lu();
if (this->m_factorization == nullptr || this->m_factorization->get_status() != LU_status::OK) {
this->set_status(UNSTABLE);
this->m_iters_with_no_cost_growing++;
this->iters_with_no_cost_growing()++;
return;
}
}
@ -728,7 +728,7 @@ template <typename T, typename X>void lp_primal_core_solver<T, X>::advance_on_en
}
if (!is_zero(t)) {
this->m_iters_with_no_cost_growing = 0;
this->iters_with_no_cost_growing() = 0;
init_infeasibility_after_update_x_if_inf(leaving);
}
@ -783,7 +783,7 @@ template <typename T, typename X> void lp_primal_core_solver<T, X>::advance_on_e
this->init_lu();
init_reduced_costs();
if (refresh_result == 2) {
this->m_iters_with_no_cost_growing++;
this->iters_with_no_cost_growing()++;
return;
}
}
@ -833,7 +833,7 @@ template <typename T, typename X> unsigned lp_primal_core_solver<T, X>::get_num
if (ret == 0) {
return 0;
}
return std::max(static_cast<unsigned>(my_random() % ret), 1u);
return std::max(static_cast<unsigned>(this->m_settings.random_next() % ret), 1u);
}
template <typename T, typename X> void lp_primal_core_solver<T, X>::print_column_norms(std::ostream & out) {
@ -934,7 +934,7 @@ template <typename T, typename X> unsigned lp_primal_core_solver<T, X>::solve()
&&
this->get_status() != INFEASIBLE
&&
this->m_iters_with_no_cost_growing <= this->m_settings.max_number_of_iterations_with_no_improvements
this->iters_with_no_cost_growing() <= this->m_settings.max_number_of_iterations_with_no_improvements
&&
this->total_iterations() <= this->m_settings.max_total_number_of_iterations
&&
@ -961,7 +961,7 @@ template <typename T, typename X> void lp_primal_core_solver<T, X>::init_column_
for (unsigned j = 0; j < this->m_n(); j++) {
this->m_column_norms[j] = T(static_cast<int>(this->m_A.m_columns[j].size() + 1))
+ T(static_cast<int>(my_random() % 10000)) / T(100000);
+ T(static_cast<int>(this->m_settings.random_next() % 10000)) / T(100000);
}
}

View file

@ -11,14 +11,17 @@
#include "util/lp/lp_primal_core_solver.hpp"
#include "util/lp/lp_primal_core_solver_tableau.hpp"
namespace lean {
template void lp_primal_core_solver<double, double>::find_feasible_solution();
template void lean::lp_primal_core_solver<lean::mpq, lean::numeric_pair<lean::mpq> >::find_feasible_solution();
template unsigned lp_primal_core_solver<double, double>::solve();
template unsigned lp_primal_core_solver<double, double>::solve_with_tableau();
template unsigned lp_primal_core_solver<mpq, mpq>::solve();
template unsigned lp_primal_core_solver<mpq, numeric_pair<mpq> >::solve();
template void lean::lp_primal_core_solver<double, double>::clear_breakpoints();
template bool lean::lp_primal_core_solver<lean::mpq, lean::mpq>::update_basis_and_x_tableau(int, int, lean::mpq const&);
template bool lean::lp_primal_core_solver<double, double>::update_basis_and_x_tableau(int, int, double const&);
template bool lean::lp_primal_core_solver<lean::mpq, lean::numeric_pair<lean::mpq> >::update_basis_and_x_tableau(int, int, lean::numeric_pair<lean::mpq> const&);
}

View file

@ -62,7 +62,7 @@ template <typename T, typename X> int lp_primal_core_solver<T, X>::choose_enteri
if (number_of_benefitial_columns_to_go_over)
number_of_benefitial_columns_to_go_over--;
}
else if (t == j_nz && my_random() % 2 == 0) {
else if (t == j_nz && this->m_settings.random_next() % 2 == 0) {
entering_iter = non_basis_iter;
}
}// while (number_of_benefitial_columns_to_go_over && initial_offset_in_non_basis != offset_in_nb);
@ -169,7 +169,7 @@ unsigned lp_primal_core_solver<T, X>::solve_with_tableau() {
&&
this->get_status() != INFEASIBLE
&&
this->m_iters_with_no_cost_growing <= this->m_settings.max_number_of_iterations_with_no_improvements
this->iters_with_no_cost_growing() <= this->m_settings.max_number_of_iterations_with_no_improvements
&&
this->total_iterations() <= this->m_settings.max_total_number_of_iterations
&&
@ -202,7 +202,7 @@ template <typename T, typename X>void lp_primal_core_solver<T, X>::advance_on_en
}
this->update_basis_and_x_tableau(entering, leaving, t);
lean_assert(this->A_mult_x_is_off() == false);
this->m_iters_with_no_cost_growing = 0;
this->iters_with_no_cost_growing() = 0;
} else {
this->pivot_column_tableau(entering, this->m_basis_heading[leaving]);
this->change_basis(entering, leaving);
@ -233,7 +233,7 @@ void lp_primal_core_solver<T, X>::advance_on_entering_equal_leaving_tableau(int
if (need_to_switch_costs()) {
init_reduced_costs_tableau();
}
this->m_iters_with_no_cost_growing = 0;
this->iters_with_no_cost_growing() = 0;
}
template <typename T, typename X> int lp_primal_core_solver<T, X>::find_leaving_and_t_tableau(unsigned entering, X & t) {
unsigned k = 0;
@ -293,7 +293,7 @@ template <typename T, typename X> int lp_primal_core_solver<T, X>::find_leaving_
}
if (m_leaving_candidates.size() == 1)
return m_leaving_candidates[0];
k = my_random() % m_leaving_candidates.size();
k = this->m_settings.random_next() % m_leaving_candidates.size();
return m_leaving_candidates[k];
}
template <typename T, typename X> void lp_primal_core_solver<T, X>::init_run_tableau() {
@ -302,7 +302,7 @@ template <typename T, typename X> void lp_primal_core_solver<T, X>::init_run_tab
lean_assert(basis_columns_are_set_correctly());
this->m_basis_sort_counter = 0; // to initiate the sort of the basis
this->set_total_iterations(0);
this->m_iters_with_no_cost_growing = 0;
this->iters_with_no_cost_growing() = 0;
lean_assert(this->inf_set_is_correct());
if (this->current_x_is_feasible() && this->m_look_for_feasible_solution_only)
return;
@ -315,7 +315,7 @@ template <typename T, typename X> void lp_primal_core_solver<T, X>::init_run_tab
this->m_column_norm_update_counter = 0;
init_column_norms();
}
if (this->m_settings.m_simplex_strategy == simplex_strategy_enum::tableau_rows)
if (this->m_settings.simplex_strategy() == simplex_strategy_enum::tableau_rows)
init_tableau_rows();
lean_assert(this->reduced_costs_are_correct_tableau());
lean_assert(!this->need_to_pivot_to_basis_tableau());

View file

@ -15,7 +15,7 @@
namespace lean {
template <typename T, typename X>
class lp_primal_simplex: public lp_solver<T, X> {
lp_primal_core_solver<T, X> * m_core_solver = nullptr;
lp_primal_core_solver<T, X> * m_core_solver;
vector<X> m_low_bounds;
private:
unsigned original_rows() { return this->m_external_rows_to_core_solver_rows.size(); }
@ -28,7 +28,7 @@ private:
void set_scaled_costs();
public:
lp_primal_simplex() {}
lp_primal_simplex(): m_core_solver(nullptr) {}
column_info<T> * get_or_create_column_info(unsigned column);

View file

@ -25,9 +25,10 @@ enum class column_type {
};
enum class simplex_strategy_enum {
undecided = 3,
tableau_rows = 0,
tableau_costs = 1,
no_tableau = 2
lu = 2
};
std::string column_type_to_string(column_type t);
@ -70,8 +71,6 @@ template <typename X> bool is_epsilon_small(const X & v, const double& eps);
int get_millisecond_count();
int get_millisecond_span(int start_time);
unsigned my_random();
void my_random_init(long unsigned seed);
class lp_resource_limit {
@ -105,49 +104,50 @@ private:
default_lp_resource_limit m_default_resource_limit;
lp_resource_limit* m_resource_limit;
// used for debug output
std::ostream* m_debug_out = &std::cout;
std::ostream* m_debug_out;
// used for messages, for example, the computation progress messages
std::ostream* m_message_out = &std::cout;
std::ostream* m_message_out;
stats m_stats;
random_gen m_rand;
public:
unsigned reps_in_scaler = 20;
unsigned reps_in_scaler;
// when the absolute value of an element is less than pivot_epsilon
// in pivoting, we treat it as a zero
double pivot_epsilon = 0.00000001;
double pivot_epsilon;
// see Chatal, page 115
double positive_price_epsilon = 1e-7;
double positive_price_epsilon;
// a quatation "if some choice of the entering vairable leads to an eta matrix
// whose diagonal element in the eta column is less than e2 (entering_diag_epsilon) in magnitude, the this choice is rejected ...
double entering_diag_epsilon = 1e-8;
int c_partial_pivoting = 10; // this is the constant c from page 410
unsigned depth_of_rook_search = 4;
bool using_partial_pivoting = true;
double entering_diag_epsilon;
int c_partial_pivoting; // this is the constant c from page 410
unsigned depth_of_rook_search;
bool using_partial_pivoting;
// dissertation of Achim Koberstein
// if Bx - b is different at any component more that refactor_epsilon then we refactor
double refactor_tolerance = 1e-4;
double pivot_tolerance = 1e-6;
double zero_tolerance = 1e-12;
double drop_tolerance = 1e-14;
double tolerance_for_artificials = 1e-4;
double can_be_taken_to_basis_tolerance = 0.00001;
double refactor_tolerance;
double pivot_tolerance;
double zero_tolerance;
double drop_tolerance;
double tolerance_for_artificials;
double can_be_taken_to_basis_tolerance;
unsigned percent_of_entering_to_check = 5; // we try to find a profitable column in a percentage of the columns
bool use_scaling = true;
double scaling_maximum = 1;
double scaling_minimum = 0.5;
double harris_feasibility_tolerance = 1e-7; // page 179 of Istvan Maros
double ignore_epsilon_of_harris = 10e-5;
unsigned max_number_of_iterations_with_no_improvements = 2000000;
unsigned max_total_number_of_iterations = 20000000;
double time_limit = std::numeric_limits<double>::max(); // the maximum time limit of the total run time in seconds
unsigned percent_of_entering_to_check; // we try to find a profitable column in a percentage of the columns
bool use_scaling;
double scaling_maximum;
double scaling_minimum;
double harris_feasibility_tolerance; // page 179 of Istvan Maros
double ignore_epsilon_of_harris;
unsigned max_number_of_iterations_with_no_improvements;
unsigned max_total_number_of_iterations;
double time_limit; // the maximum time limit of the total run time in seconds
// dual section
double dual_feasibility_tolerance = 1e-7; // // page 71 of the PhD thesis of Achim Koberstein
double primal_feasibility_tolerance = 1e-7; // page 71 of the PhD thesis of Achim Koberstein
double relative_primal_feasibility_tolerance = 1e-9; // page 71 of the PhD thesis of Achim Koberstein
double dual_feasibility_tolerance; // // page 71 of the PhD thesis of Achim Koberstein
double primal_feasibility_tolerance; // page 71 of the PhD thesis of Achim Koberstein
double relative_primal_feasibility_tolerance; // page 71 of the PhD thesis of Achim Koberstein
bool m_bound_propagation = true;
bool m_bound_propagation;
bool bound_progation() const {
return m_bound_propagation;
@ -157,7 +157,52 @@ public:
return m_bound_propagation;
}
lp_settings() : m_default_resource_limit(*this), m_resource_limit(&m_default_resource_limit) {}
lp_settings() : m_default_resource_limit(*this),
m_resource_limit(&m_default_resource_limit),
m_debug_out( &std::cout),
m_message_out(&std::cout),
reps_in_scaler(20),
pivot_epsilon(0.00000001),
positive_price_epsilon(1e-7),
entering_diag_epsilon ( 1e-8),
c_partial_pivoting ( 10), // this is the constant c from page 410
depth_of_rook_search ( 4),
using_partial_pivoting ( true),
// dissertation of Achim Koberstein
// if Bx - b is different at any component more that refactor_epsilon then we refactor
refactor_tolerance ( 1e-4),
pivot_tolerance ( 1e-6),
zero_tolerance ( 1e-12),
drop_tolerance ( 1e-14),
tolerance_for_artificials ( 1e-4),
can_be_taken_to_basis_tolerance ( 0.00001),
percent_of_entering_to_check ( 5),// we try to find a profitable column in a percentage of the columns
use_scaling ( true),
scaling_maximum ( 1),
scaling_minimum ( 0.5),
harris_feasibility_tolerance ( 1e-7), // page 179 of Istvan Maros
ignore_epsilon_of_harris ( 10e-5),
max_number_of_iterations_with_no_improvements ( 2000000),
max_total_number_of_iterations ( 20000000),
time_limit ( std::numeric_limits<double>::max()), // the maximum time limit of the total run time in seconds
// dual section
dual_feasibility_tolerance ( 1e-7), // // page 71 of the PhD thesis of Achim Koberstein
primal_feasibility_tolerance ( 1e-7), // page 71 of the PhD thesis of Achim Koberstein
relative_primal_feasibility_tolerance ( 1e-9), // page 71 of the PhD thesis of Achim Koberstein
m_bound_propagation ( true),
presolve_with_double_solver_for_lar(true),
m_simplex_strategy(simplex_strategy_enum::tableau_rows),
report_frequency(1000),
print_statistics(false),
column_norms_update_frequency(12000),
scale_with_ratio(true),
density_threshold(0.7),
use_breakpoints_in_feasibility_search(false),
max_row_length_for_bound_propagation(300),
backup_costs(true),
column_number_threshold_for_using_lu_in_lar_solver(4000)
{}
void set_resource_limit(lp_resource_limit& lim) { m_resource_limit = &lim; }
bool get_cancel_flag() const { return m_resource_limit->get_cancel_flag(); }
@ -226,8 +271,8 @@ public:
return is_eps_small_general<T>(t, tolerance_for_artificials);
}
// the method of lar solver to use
bool presolve_with_double_solver_for_lar = true;
simplex_strategy_enum m_simplex_strategy = simplex_strategy_enum::tableau_rows;
bool presolve_with_double_solver_for_lar;
simplex_strategy_enum m_simplex_strategy;
simplex_strategy_enum simplex_strategy() const {
return m_simplex_strategy;
}
@ -236,27 +281,33 @@ public:
return m_simplex_strategy;
}
bool use_lu() const {
return m_simplex_strategy == simplex_strategy_enum::lu;
}
bool use_tableau() const {
return m_simplex_strategy != simplex_strategy_enum::no_tableau;
return m_simplex_strategy == simplex_strategy_enum::tableau_rows ||
m_simplex_strategy == simplex_strategy_enum::tableau_costs;
}
bool use_tableau_rows() const {
return m_simplex_strategy == simplex_strategy_enum::tableau_rows;
}
int report_frequency = 1000;
bool print_statistics = false;
unsigned column_norms_update_frequency = 12000;
bool scale_with_ratio = true;
double density_threshold = 0.7; // need to tune it up, todo
int report_frequency;
bool print_statistics;
unsigned column_norms_update_frequency;
bool scale_with_ratio;
double density_threshold; // need to tune it up, todo
#ifdef LEAN_DEBUG
static unsigned ddd; // used for debugging
#endif
bool use_breakpoints_in_feasibility_search = false;
unsigned random_seed = 1;
static unsigned long random_next;
unsigned max_row_length_for_bound_propagation = 300;
bool backup_costs = true;
bool use_breakpoints_in_feasibility_search;
unsigned random_next() { return m_rand(); }
void random_seed(unsigned s) { m_rand.set_seed(s); }
unsigned max_row_length_for_bound_propagation;
bool backup_costs;
unsigned column_number_threshold_for_using_lu_in_lar_solver;
}; // end of lp_settings class

View file

@ -67,15 +67,6 @@ int get_millisecond_span(int start_time) {
void my_random_init(long unsigned seed) {
lp_settings::random_next = seed;
}
unsigned my_random() {
lp_settings::random_next = lp_settings::random_next * 1103515245 + 12345;
return((unsigned)(lp_settings::random_next/65536) % 32768);
}
template <typename T>
bool vectors_are_equal(T * a, vector<T> &b, unsigned n) {
if (numeric_traits<T>::precise()) {
@ -126,7 +117,6 @@ bool vectors_are_equal(const vector<T> & a, const vector<T> &b) {
}
return true;
}
unsigned long lp_settings::random_next = 1;
#ifdef LEAN_DEBUG
unsigned lp_settings::ddd = 0;
#endif

View file

@ -39,10 +39,10 @@ protected:
T get_column_cost_value(unsigned j, column_info<T> * ci) const;
public:
unsigned m_total_iterations;
static_matrix<T, X>* m_A = nullptr; // this is the matrix of constraints
static_matrix<T, X>* m_A; // this is the matrix of constraints
vector<T> m_b; // the right side vector
unsigned m_first_stage_iterations = 0;
unsigned m_second_stage_iterations = 0;
unsigned m_first_stage_iterations;
unsigned m_second_stage_iterations;
std::unordered_map<unsigned, lp_constraint<T, X>> m_constraints;
std::unordered_map<var_index, column_info<T>*> m_map_from_var_index_to_column_info;
std::unordered_map<unsigned, std::unordered_map<unsigned, T> > m_A_values;
@ -52,8 +52,8 @@ public:
std::unordered_map<unsigned, unsigned> m_core_solver_columns_to_external_columns;
vector<T> m_column_scale;
std::unordered_map<unsigned, std::string> m_name_map;
unsigned m_artificials = 0;
unsigned m_slacks = 0;
unsigned m_artificials;
unsigned m_slacks;
vector<column_type> m_column_types;
vector<T> m_costs;
vector<T> m_x;
@ -63,10 +63,17 @@ public:
vector<int> m_heading;
lp_status m_status = lp_status::UNKNOWN;
lp_status m_status;
lp_settings m_settings;
lp_solver() {}
lp_solver():
m_A(nullptr), // this is the matrix of constraints
m_first_stage_iterations (0),
m_second_stage_iterations (0),
m_artificials (0),
m_slacks (0),
m_status(lp_status::UNKNOWN)
{}
unsigned row_count() const { return this->m_A->row_count(); }
@ -232,14 +239,6 @@ protected:
out << "extended A[" << this->m_A->row_count() << "," << this->m_A->column_count() << "]" << std::endl;
}
struct row_tighten_stats {
unsigned n_of_new_bounds = 0;
unsigned n_of_fixed = 0;
bool is_obsolete = false;
};
public:
lp_settings & settings() { return m_settings;}
void print_model(std::ostream & s) const {

View file

@ -110,25 +110,25 @@ enum class LU_status { OK, Degenerated};
// Using Suhl-Suhl method described in the dissertation of Achim Koberstein, Chapter 5
template <typename T, typename X>
class lu {
LU_status m_status = LU_status::OK;
LU_status m_status;
public:
// the fields
unsigned m_dim;
unsigned m_dim;
static_matrix<T, X> const &m_A;
permutation_matrix<T, X> m_Q;
permutation_matrix<T, X> m_R;
permutation_matrix<T, X> m_r_wave;
sparse_matrix<T, X> m_U;
permutation_matrix<T, X> m_Q;
permutation_matrix<T, X> m_R;
permutation_matrix<T, X> m_r_wave;
sparse_matrix<T, X> m_U;
square_dense_submatrix<T, X>* m_dense_LU;
vector<tail_matrix<T, X> *> m_tail;
lp_settings & m_settings;
bool m_failure = false;
indexed_vector<T> m_row_eta_work_vector;
indexed_vector<T> m_w_for_extension;
indexed_vector<T> m_y_copy;
indexed_vector<unsigned> m_ii; //to optimize the work with the m_index fields
unsigned m_refactor_counter = 0;
lp_settings & m_settings;
bool m_failure;
indexed_vector<T> m_row_eta_work_vector;
indexed_vector<T> m_w_for_extension;
indexed_vector<T> m_y_copy;
indexed_vector<unsigned> m_ii; //to optimize the work with the m_index fields
unsigned m_refactor_counter;
// constructor
// if A is an m by n matrix then basis has length m and values in [0,n); the values are all different
// they represent the set of m columns

View file

@ -111,6 +111,7 @@ template <typename T, typename X>
lu<T, X>::lu(static_matrix<T, X> const & A,
vector<unsigned>& basis,
lp_settings & settings):
m_status(LU_status::OK),
m_dim(A.row_count()),
m_A(A),
m_Q(m_dim),
@ -118,7 +119,9 @@ lu<T, X>::lu(static_matrix<T, X> const & A,
m_r_wave(m_dim),
m_U(A, basis), // create the square matrix that eventually will be factorized
m_settings(settings),
m_row_eta_work_vector(A.row_count()){
m_failure(false),
m_row_eta_work_vector(A.row_count()),
m_refactor_counter(0) {
lean_assert(!(numeric_traits<T>::precise() && settings.use_tableau()));
#ifdef LEAN_DEBUG
debug_test_of_basis(A, basis);
@ -602,13 +605,13 @@ void lu<T, X>::process_column(int j) {
unsigned pi, pj;
bool success = m_U.get_pivot_for_column(pi, pj, m_settings.c_partial_pivoting, j);
if (!success) {
LP_OUT(m_settings, "get_pivot returned false: cannot find the pivot for column " << j << std::endl);
// LP_OUT(m_settings, "get_pivot returned false: cannot find the pivot for column " << j << std::endl);
m_failure = true;
return;
}
if (static_cast<int>(pi) == -1) {
LP_OUT(m_settings, "cannot find the pivot for column " << j << std::endl);
// LP_OUT(m_settings, "cannot find the pivot for column " << j << std::endl);
m_failure = true;
return;
}

View file

@ -93,22 +93,28 @@ template <typename T, typename X>
class mps_reader {
enum row_type { Cost, Less_or_equal, Greater_or_equal, Equal };
struct bound {
bool m_low_is_set = true;
T m_low;
bool m_upper_is_set = false;
T m_upper;
bool m_value_is_fixed = false;
T m_fixed_value;
bool m_free = false;
T m_low;
T m_upper;
bool m_low_is_set;
bool m_upper_is_set;
bool m_value_is_fixed;
T m_fixed_value;
bool m_free;
// constructor
bound() : m_low(numeric_traits<T>::zero()) {} // it seems all mps files I have seen have the default low value 0 on a variable
bound() : m_low(numeric_traits<T>::zero()),
m_low_is_set(true),
m_upper_is_set(false),
m_value_is_fixed(false),
m_free(false) {} // it seems all mps files I have seen have the default low value 0 on a variable
};
struct column {
std::string m_name;
bound * m_bound = nullptr;
bound * m_bound;
unsigned m_index;
column(std::string name, unsigned index): m_name(name), m_index(index) {
column(std::string name, unsigned index): m_name(name),
m_bound(nullptr),
m_index(index) {
}
};
@ -116,15 +122,21 @@ class mps_reader {
row_type m_type;
std::string m_name;
std::unordered_map<std::string, T> m_row_columns;
T m_right_side = numeric_traits<T>::zero();
unsigned m_index;
T m_range = numeric_traits<T>::zero();
row(row_type type, std::string name, unsigned index) : m_type(type), m_name(name), m_index(index) {
T m_right_side;
T m_range;
row(row_type type, std::string name, unsigned index) :
m_type(type),
m_name(name),
m_index(index),
m_right_side(zero_of_type<T>()),
m_range(zero_of_type<T>())
{
}
};
bool m_is_OK;
std::string m_file_name;
bool m_is_OK = true;
std::unordered_map<std::string, row *> m_rows;
std::unordered_map<std::string, column *> m_columns;
std::unordered_map<std::string, unsigned> m_names_to_var_index;
@ -133,9 +145,9 @@ class mps_reader {
std::string m_cost_row_name;
std::ifstream m_file_stream;
// needed to adjust the index row
unsigned m_cost_line_count = 0;
unsigned m_line_number = 0;
std::ostream * m_message_stream = & std::cout;
unsigned m_cost_line_count;
unsigned m_line_number;
std::ostream * m_message_stream;
void set_m_ok_to_false() {
*m_message_stream << "setting m_is_OK to false" << std::endl;
@ -639,11 +651,11 @@ class mps_reader {
/*
If rhs is a constraint's right-hand-side value and range is the constraint's range value, then the range interval is defined according to the following table:
sense interval
G [rhs, rhs + |range|]
L [rhs - |range|, rhs]
E [rhs, rhs + |range|] if range ¡Ý 0 [rhs - |range|, rhs] if range < 0
E [rhs, rhs + |range|] if range > 0,
[rhs - |range|, rhs] if range < 0
where |range| is range's absolute value.
*/
@ -737,8 +749,12 @@ public:
}
mps_reader(std::string file_name):
m_file_name(file_name), m_file_stream(file_name) {
}
m_is_OK(true),
m_file_name(file_name),
m_file_stream(file_name),
m_cost_line_count(0),
m_line_number(0),
m_message_stream(& std::cout) {}
void read() {
if (!m_file_stream.is_open()){
set_m_ok_to_false();
@ -784,7 +800,7 @@ public:
auto it = m_names_to_var_index.find(s);
if (it != m_names_to_var_index.end())
return it->second;
unsigned ret = m_names_to_var_index.size();
unsigned ret = static_cast<unsigned>(m_names_to_var_index.size());
m_names_to_var_index[s] = ret;
return ret;
}

View file

@ -101,16 +101,14 @@ struct numeric_pair {
numeric_pair(T xp, T yp) : x(xp), y(yp) {}
template <typename X>
numeric_pair(const X & n) : x(n), y(0) {
}
template <typename X>
numeric_pair(const numeric_pair<X> & n) : x(n.x), y(n.y) {}
numeric_pair(const numeric_pair<T> & n) : x(n.x), y(n.y) {}
template <typename X, typename Y>
numeric_pair(X xp, Y yp) : numeric_pair(convert_struct<T, X>::convert(xp), convert_struct<T, Y>::convert(yp)) {}
numeric_pair(X xp, Y yp) : x(convert_struct<T, X>::convert(xp)), y(convert_struct<T, Y>::convert(yp)) {}
bool operator<(const numeric_pair& a) const {
return x < a.x || (x == a.x && y < a.y);

View file

@ -132,42 +132,4 @@ class permutation_matrix : public tail_matrix<T, X> {
}; // end of the permutation class
#ifdef LEAN_DEBUG
template <typename T, typename X>
class permutation_generator {
unsigned m_n;
permutation_generator* m_lower;
bool m_done = false;
permutation_matrix<T, X> m_current;
unsigned m_last;
public:
permutation_generator(unsigned n);
permutation_generator(const permutation_generator & o);
bool move_next();
~permutation_generator() {
if (m_lower != nullptr) {
delete m_lower;
}
}
permutation_matrix<T, X> *current() {
return &m_current;
}
};
template <typename T, typename X>
inline unsigned number_of_inversions(permutation_matrix<T, X> & p);
template <typename T, typename X>
int sign(permutation_matrix<T, X> & p) {
return is_even(number_of_inversions(p))? 1: -1;
}
template <typename T, typename X>
T det_val_on_perm(permutation_matrix<T, X>* u, const matrix<T, X>& m);
template <typename T, typename X>
T determinant(const matrix<T, X>& m);
#endif
}

View file

@ -320,100 +320,4 @@ template <typename T, typename X> bool permutation_matrix<T, X>::is_identity() c
}
#ifdef LEAN_DEBUG
template <typename T, typename X>
permutation_generator<T, X>::permutation_generator(unsigned n): m_n(n), m_current(n) {
lean_assert(n > 0);
if (n > 1) {
m_lower = new permutation_generator(n - 1);
} else {
m_lower = nullptr;
}
m_last = 0;
}
template <typename T, typename X>
permutation_generator<T, X>::permutation_generator(const permutation_generator & o): m_n(o.m_n), m_done(o.m_done), m_current(o.m_current), m_last(o.m_last) {
if (m_lower != nullptr) {
m_lower = new permutation_generator(o.m_lower);
} else {
m_lower = nullptr;
}
}
template <typename T, typename X> bool
permutation_generator<T, X>::move_next() {
if (m_done) {
return false;
}
if (m_lower == nullptr) {
if (m_last == 0) {
m_last++;
return true;
} else {
m_done = true;
return false;
}
} else {
if (m_last < m_n && m_last > 0) {
m_current[m_last - 1] = m_current[m_last];
m_current[m_last] = m_n - 1;
m_last++;
return true;
} else {
if (m_lower -> move_next()) {
auto lower_curr = m_lower -> current();
for ( unsigned i = 1; i < m_n; i++ ){
m_current[i] = (*lower_curr)[i - 1];
}
m_current[0] = m_n - 1;
m_last = 1;
return true;
} else {
m_done = true;
return false;
}
}
}
}
template <typename T, typename X>
inline unsigned number_of_inversions(permutation_matrix<T, X> & p) {
unsigned ret = 0;
unsigned n = p.size();
for (unsigned i = 0; i < n; i++) {
for (unsigned j = i + 1; j < n; j++) {
if (p[i] > p[j]) {
ret++;
}
}
}
return ret;
}
template <typename T, typename X>
T det_val_on_perm(permutation_matrix<T, X>* u, const matrix<T, X>& m) {
unsigned n = m.row_count();
T ret = numeric_traits<T>::one();
for (unsigned i = 0; i < n; i++) {
unsigned j = (*u)[i];
ret *= m(i, j);
}
return ret * sign(*u);
}
template <typename T, typename X>
T determinant(const matrix<T, X>& m) {
lean_assert(m.column_count() == m.row_count());
unsigned n = m.row_count();
permutation_generator<T, X> allp(n);
T ret = numeric_traits<T>::zero();
while (allp.move_next()){
ret += det_val_on_perm(allp.current(), m);
}
return ret;
}
#endif
}

View file

@ -46,11 +46,6 @@ template void lean::permutation_matrix<lean::mpq, lean::numeric_pair<lean::mpq>
template void lean::permutation_matrix<lean::mpq, lean::numeric_pair<lean::mpq> >::apply_reverse_from_left_to_T(vector<lean::mpq>&);
template void lean::permutation_matrix<lean::mpq, lean::numeric_pair<lean::mpq> >::apply_reverse_from_right_to_T(vector<lean::mpq >&);
template void lean::permutation_matrix<double, double>::multiply_by_permutation_from_right(lean::permutation_matrix<double, double>&);
#ifdef LEAN_DEBUG
template bool lean::permutation_generator<double, double>::move_next();
template lean::permutation_generator<double, double>::permutation_generator(unsigned int);
#endif
template lean::permutation_matrix<double, double>::permutation_matrix(unsigned int);
template void lean::permutation_matrix<double, double>::apply_reverse_from_left_to_X(vector<double> &);
template void lean::permutation_matrix< lean::mpq, lean::mpq>::apply_reverse_from_left_to_X(vector<lean::mpq> &);

View file

@ -16,12 +16,14 @@ namespace lean {
template <typename T> struct numeric_pair; // forward definition
class lar_core_solver; // forward definition
class random_updater {
unsigned range = 100000;
struct interval {
bool upper_bound_is_set = false;
bool upper_bound_is_set;
numeric_pair<mpq> upper_bound;
bool low_bound_is_set = false;
bool low_bound_is_set;
numeric_pair<mpq> low_bound;
interval() : upper_bound_is_set(false),
low_bound_is_set(false) {}
void set_low_bound(const numeric_pair<mpq> & v) {
if (low_bound_is_set) {
low_bound = std::max(v, low_bound);
@ -58,6 +60,7 @@ class random_updater {
};
std::set<var_index> m_var_set;
lar_core_solver & m_core_solver;
unsigned range;
linear_combination_iterator<mpq>* m_column_j; // the actual column
interval find_shift_interval(unsigned j);
interval get_interval_of_non_basic_var(unsigned j);

View file

@ -12,7 +12,9 @@ namespace lean {
random_updater::random_updater(
lar_core_solver & lar_core_solver,
const vector<unsigned> & column_indices) : m_core_solver(lar_core_solver) {
const vector<unsigned> & column_indices) :
m_core_solver(lar_core_solver),
range(100000) {
for (unsigned j : column_indices)
add_column_to_sets(j);
}
@ -134,7 +136,7 @@ void random_updater::shift_var(unsigned j, interval & r) {
}
numeric_pair<mpq> random_updater::get_random_from_interval(interval & r) {
unsigned rand = my_random();
unsigned rand = m_core_solver.settings().random_next();
if ((!r.low_bound_is_set) && (!r.upper_bound_is_set))
return numeric_pair<mpq>(rand % range, 0);
if (r.low_bound_is_set && (!r.upper_bound_is_set))
@ -180,11 +182,11 @@ void random_updater::add_value(numeric_pair<mpq>& v) {
}
void random_updater::remove_value(numeric_pair<mpq>& v) {
auto it = m_values.find(v);
std::unordered_map<numeric_pair<mpq>, unsigned>::iterator it = m_values.find(v);
lean_assert(it != m_values.end());
it->second--;
if (it->second == 0)
m_values.erase(it);
m_values.erase((std::unordered_map<numeric_pair<mpq>, unsigned>::const_iterator)it);
}
void random_updater::add_column_to_sets(unsigned j) {

View file

@ -30,10 +30,10 @@ class sparse_matrix
#endif
{
struct col_header {
unsigned m_shortened_markovitz = 0;
unsigned m_shortened_markovitz;
vector<indexed_value<T>> m_values; // the actual column values
col_header() {}
col_header(): m_shortened_markovitz(0) {}
void shorten_markovich_by_one() {
m_shortened_markovitz++;
@ -44,17 +44,17 @@ class sparse_matrix
}
};
unsigned m_n_of_active_elems = 0;
unsigned m_n_of_active_elems;
binary_heap_upair_queue<unsigned> m_pivot_queue;
public:
vector<vector<indexed_value<T>>> m_rows;
vector<col_header> m_columns;
permutation_matrix<T, X> m_row_permutation;
permutation_matrix<T, X> m_column_permutation;
vector<col_header> m_columns;
permutation_matrix<T, X> m_row_permutation;
permutation_matrix<T, X> m_column_permutation;
// m_work_pivot_vector[j] = offset of elementh of j-th column in the row we are pivoting to
// if the column is not present then m_work_pivot_vector[j] is -1
vector<int> m_work_pivot_vector;
vector<bool> m_processed;
vector<int> m_work_pivot_vector;
vector<bool> m_processed;
unsigned get_n_of_active_elems() const { return m_n_of_active_elems; }
#ifdef LEAN_DEBUG

View file

@ -36,6 +36,7 @@ void sparse_matrix<T, X>::copy_B(static_matrix<T, X> const &A, vector<unsigned>
// constructor that copies columns of the basis from A
template <typename T, typename X>
sparse_matrix<T, X>::sparse_matrix(static_matrix<T, X> const &A, vector<unsigned> & basis) :
m_n_of_active_elems(0),
m_pivot_queue(A.row_count()),
m_row_permutation(A.row_count()),
m_column_permutation(A.row_count()),

View file

@ -20,7 +20,7 @@ public:
}
#ifdef LEAN_DEBUG
T operator[] (unsigned i) const {
for (auto t : m_data) {
for (auto &t : m_data) {
if (t.first == i) return t.second;
}
return numeric_traits<T>::zero();

View file

@ -42,7 +42,7 @@ public:
unsigned m_index_start;
unsigned m_dim;
vector<T> m_v;
sparse_matrix<T, X> * m_parent = nullptr;
sparse_matrix<T, X> * m_parent;
permutation_matrix<T, X> m_row_permutation;
indexed_vector<T> m_work_vector;
public:

View file

@ -29,7 +29,6 @@ template <typename T, typename X> void static_matrix<T, X>::scan_row_ii_to_offse
template <typename T, typename X> bool static_matrix<T, X>::pivot_row_to_row_given_cell(unsigned i, column_cell & c, unsigned pivot_col) {
// std::cout << "ddd = " << ++lp_settings::ddd<< std::endl;
unsigned ii = c.m_i;
lean_assert(i < row_count() && ii < column_count());
lean_assert(i != ii);

View file

@ -63,5 +63,7 @@ template void static_matrix<mpq, numeric_pair<mpq> >::set(unsigned int, unsigned
template bool lean::static_matrix<double, double>::pivot_row_to_row_given_cell(unsigned int, column_cell &, unsigned int);
template bool lean::static_matrix<lean::mpq, lean::mpq>::pivot_row_to_row_given_cell(unsigned int, column_cell& , unsigned int);
template bool lean::static_matrix<lean::mpq, lean::numeric_pair<lean::mpq> >::pivot_row_to_row_given_cell(unsigned int, column_cell&, unsigned int);
template void lean::static_matrix<lean::mpq, lean::numeric_pair<lean::mpq> >::remove_element(vector<lean::row_cell<lean::mpq>, true, unsigned int>&, lean::row_cell<lean::mpq>&);
}

View file

@ -32,14 +32,14 @@ inline bool compare(const std::pair<mpq, var_index> & a, const std::pair<mpq, va
}
class ul_pair {
constraint_index m_low_bound_witness = static_cast<constraint_index>(-1);
constraint_index m_upper_bound_witness = static_cast<constraint_index>(-1);
constraint_index m_low_bound_witness;
constraint_index m_upper_bound_witness;
public:
constraint_index& low_bound_witness() {return m_low_bound_witness;}
constraint_index low_bound_witness() const {return m_low_bound_witness;}
constraint_index& upper_bound_witness() { return m_upper_bound_witness;}
constraint_index upper_bound_witness() const {return m_upper_bound_witness;}
row_index m_i = static_cast<row_index>(-1);
row_index m_i;
bool operator!=(const ul_pair & p) const {
return !(*this == p);
}
@ -50,8 +50,15 @@ public:
m_i == p.m_i;
}
// empty constructor
ul_pair(){}
ul_pair(row_index ri) : m_i(ri) {}
ul_pair() :
m_low_bound_witness(static_cast<constraint_index>(-1)),
m_upper_bound_witness(static_cast<constraint_index>(-1)),
m_i(static_cast<row_index>(-1))
{}
ul_pair(row_index ri) :
m_low_bound_witness(static_cast<constraint_index>(-1)),
m_upper_bound_witness(static_cast<constraint_index>(-1)),
m_i(ri) {}
ul_pair(const ul_pair & o): m_low_bound_witness(o.m_low_bound_witness), m_upper_bound_witness(o.m_upper_bound_witness), m_i(o.m_i) {}
};

View file

@ -497,7 +497,9 @@ public:
STRACE("mpz", tout << "[mpz] 0 - " << to_string(a) << " == ";);
if (is_small(a) && a.m_val == INT_MIN) {
// neg(INT_MIN) is not a small int
MPZ_BEGIN_CRITICAL();
set_big_i64(a, - static_cast<long long>(INT_MIN));
MPZ_END_CRITICAL();
return;
}
#ifndef _MP_GMP
@ -518,7 +520,9 @@ public:
if (a.m_val < 0) {
if (a.m_val == INT_MIN) {
// abs(INT_MIN) is not a small int
MPZ_BEGIN_CRITICAL();
set_big_i64(a, - static_cast<long long>(INT_MIN));
MPZ_END_CRITICAL();
}
else
a.m_val = -a.m_val;

View file

@ -68,6 +68,7 @@ void small_object_allocator::reset() {
#define MASK ((1 << PTR_ALIGNMENT) - 1)
void small_object_allocator::deallocate(size_t size, void * p) {
if (size == 0) return;
@ -92,6 +93,7 @@ void small_object_allocator::deallocate(size_t size, void * p) {
m_free_list[slot_id] = p;
}
void * small_object_allocator::allocate(size_t size) {
if (size == 0) return 0;
@ -100,8 +102,9 @@ void * small_object_allocator::allocate(size_t size) {
return memory::allocate(size);
#endif
m_alloc_size += size;
if (size >= SMALL_OBJ_SIZE - (1 << PTR_ALIGNMENT))
if (size >= SMALL_OBJ_SIZE - (1 << PTR_ALIGNMENT)) {
return memory::allocate(size);
}
#ifdef Z3DEBUG
size_t osize = size;
#endif

21
src/util/sstream.h Normal file
View file

@ -0,0 +1,21 @@
/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#pragma once
#include <sstream>
#include <string>
namespace lean {
/** \brief Wrapper for std::ostringstream */
class sstream {
std::ostringstream m_strm;
public:
std::string str() const { return m_strm.str(); }
template<typename T> sstream & operator<<(T const & t) { m_strm << t; return *this; }
};
}