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:
commit
f698efa403
92 changed files with 8030 additions and 1822 deletions
|
@ -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
|
||||
################################################################################
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ z3_add_component(interp
|
|||
SOURCES
|
||||
iz3base.cpp
|
||||
iz3checker.cpp
|
||||
iz3foci.cpp
|
||||
iz3interp.cpp
|
||||
iz3mgr.cpp
|
||||
iz3pp.cpp
|
||||
|
|
|
@ -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})
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
35
contrib/cmake/src/util/lp/CMakeLists.txt
Normal file
35
contrib/cmake/src/util/lp/CMakeLists.txt
Normal 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})
|
|
@ -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')
|
||||
|
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,4 +3,4 @@
|
|||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
|
||||
</startup>
|
||||
</configuration>
|
||||
</configuration>
|
||||
|
|
|
@ -75,4 +75,4 @@
|
|||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -344,4 +344,4 @@
|
|||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Code.Contract" version="1.0.0" targetFramework="net35" />
|
||||
</packages>
|
||||
</packages>
|
||||
|
|
|
@ -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},
|
||||
)
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
110
src/shell/lp_frontend.cpp
Normal 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
7
src/shell/lp_frontend.h
Normal 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);
|
|
@ -44,4 +44,4 @@ public:
|
|||
|
||||
void install_smt2_extra_cmds(cmd_context & ctx) {
|
||||
ctx.insert(alloc(include_cmd));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
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
97
src/smt/theory_lra.h
Normal 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);
|
||||
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
144
src/test/argument_parser.h
Normal 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
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
396
src/test/smt_reader.h
Normal 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;
|
||||
}
|
||||
};
|
||||
}
|
73
src/test/test_file_reader.h
Normal file
73
src/test/test_file_reader.h
Normal 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();
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{ }
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
43
src/util/lp/conversion_helper.h
Normal file
43
src/util/lp/conversion_helper.h
Normal 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;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
576
src/util/lp/init_lar_solver.h
Normal file
576
src/util/lp/init_lar_solver.h
Normal 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();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
:
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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(); }
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
12
src/util/lp/lp_params.pyg
Normal 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')
|
||||
))
|
||||
|
||||
|
||||
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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&);
|
||||
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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> &);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()),
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>&);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {}
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
21
src/util/sstream.h
Normal 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; }
|
||||
};
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue