mirror of
https://github.com/Z3Prover/z3
synced 2025-06-06 06:03:23 +00:00
Merge branch 'opt' of https://github.com/NikolajBjorner/z3 into opt
This commit is contained in:
commit
db4bbecb27
174 changed files with 30440 additions and 922 deletions
|
@ -188,6 +188,7 @@ endif()
|
||||||
# Note for some reason we have to leave off ``-D`` here otherwise
|
# Note for some reason we have to leave off ``-D`` here otherwise
|
||||||
# we get ``-D-DZ3DEBUG`` passed to the compiler
|
# we get ``-D-DZ3DEBUG`` passed to the compiler
|
||||||
list(APPEND Z3_COMPONENT_CXX_DEFINES $<$<CONFIG:Debug>:Z3DEBUG>)
|
list(APPEND Z3_COMPONENT_CXX_DEFINES $<$<CONFIG:Debug>:Z3DEBUG>)
|
||||||
|
list(APPEND Z3_COMPONENT_CXX_DEFINES $<$<CONFIG:Debug>:LEAN_DEBUG>)
|
||||||
list(APPEND Z3_COMPONENT_CXX_DEFINES $<$<CONFIG:Release>:_EXTERNAL_RELEASE>)
|
list(APPEND Z3_COMPONENT_CXX_DEFINES $<$<CONFIG:Release>:_EXTERNAL_RELEASE>)
|
||||||
list(APPEND Z3_COMPONENT_CXX_DEFINES $<$<CONFIG:RelWithDebInfo>:_EXTERNAL_RELEASE>)
|
list(APPEND Z3_COMPONENT_CXX_DEFINES $<$<CONFIG:RelWithDebInfo>:_EXTERNAL_RELEASE>)
|
||||||
|
|
||||||
|
@ -213,6 +214,16 @@ endif()
|
||||||
################################################################################
|
################################################################################
|
||||||
include(${CMAKE_SOURCE_DIR}/cmake/z3_add_cxx_flag.cmake)
|
include(${CMAKE_SOURCE_DIR}/cmake/z3_add_cxx_flag.cmake)
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# C++ language version
|
||||||
|
################################################################################
|
||||||
|
# FIXME: Use CMake's own mechanism for selecting language version
|
||||||
|
if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang"))
|
||||||
|
z3_add_cxx_flag("-std=c++11" REQUIRED)
|
||||||
|
else()
|
||||||
|
message(AUTHOR_WARNING "Not setting C++ language version for compiler")
|
||||||
|
endif()
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# Platform detection
|
# Platform detection
|
||||||
################################################################################
|
################################################################################
|
||||||
|
@ -245,6 +256,7 @@ else()
|
||||||
message(FATAL_ERROR "Platform \"${CMAKE_SYSTEM_NAME}\" not recognised")
|
message(FATAL_ERROR "Platform \"${CMAKE_SYSTEM_NAME}\" not recognised")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
list(APPEND Z3_COMPONENT_EXTRA_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/src")
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# GNU multiple precision library support
|
# GNU multiple precision library support
|
||||||
|
@ -263,18 +275,6 @@ else()
|
||||||
message(STATUS "Not using libgmp")
|
message(STATUS "Not using libgmp")
|
||||||
endif()
|
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
|
# OpenMP support
|
||||||
################################################################################
|
################################################################################
|
||||||
|
@ -288,6 +288,7 @@ if (USE_OPENMP)
|
||||||
message(WARNING "OpenMP support was requested but your compiler doesn't support it")
|
message(WARNING "OpenMP support was requested but your compiler doesn't support it")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (OPENMP_FOUND)
|
if (OPENMP_FOUND)
|
||||||
list(APPEND Z3_COMPONENT_CXX_FLAGS ${OpenMP_CXX_FLAGS})
|
list(APPEND Z3_COMPONENT_CXX_FLAGS ${OpenMP_CXX_FLAGS})
|
||||||
# GCC and Clang need to have additional flags passed to the linker.
|
# GCC and Clang need to have additional flags passed to the linker.
|
||||||
|
@ -306,6 +307,23 @@ else()
|
||||||
set(USE_OPENMP OFF CACHE BOOL "Use OpenMP" FORCE)
|
set(USE_OPENMP OFF CACHE BOOL "Use OpenMP" FORCE)
|
||||||
endif()
|
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
|
# FP math
|
||||||
################################################################################
|
################################################################################
|
||||||
|
@ -326,6 +344,8 @@ if (("${TARGET_ARCHITECTURE}" STREQUAL "x86_64") OR ("${TARGET_ARCHITECTURE}" ST
|
||||||
unset(SSE_FLAGS)
|
unset(SSE_FLAGS)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# FIXME: Remove "x.." when CMP0054 is set to NEW
|
# FIXME: Remove "x.." when CMP0054 is set to NEW
|
||||||
if ("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC")
|
if ("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC")
|
||||||
# This is the default for MSVC already but to replicate the
|
# This is the default for MSVC already but to replicate the
|
||||||
|
|
|
@ -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
|
[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
|
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.
|
* ``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.
|
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.
|
* ``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.
|
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.
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ endforeach()
|
||||||
# raised if you try to declare a component is dependent on another component
|
# raised if you try to declare a component is dependent on another component
|
||||||
# that has not yet been declared.
|
# that has not yet been declared.
|
||||||
add_subdirectory(util)
|
add_subdirectory(util)
|
||||||
|
add_subdirectory(util/lp)
|
||||||
add_subdirectory(math/polynomial)
|
add_subdirectory(math/polynomial)
|
||||||
add_subdirectory(sat)
|
add_subdirectory(sat)
|
||||||
add_subdirectory(nlsat)
|
add_subdirectory(nlsat)
|
||||||
|
|
|
@ -2,7 +2,6 @@ z3_add_component(interp
|
||||||
SOURCES
|
SOURCES
|
||||||
iz3base.cpp
|
iz3base.cpp
|
||||||
iz3checker.cpp
|
iz3checker.cpp
|
||||||
iz3foci.cpp
|
|
||||||
iz3interp.cpp
|
iz3interp.cpp
|
||||||
iz3mgr.cpp
|
iz3mgr.cpp
|
||||||
iz3pp.cpp
|
iz3pp.cpp
|
||||||
|
|
|
@ -27,6 +27,7 @@ add_executable(shell
|
||||||
opt_frontend.cpp
|
opt_frontend.cpp
|
||||||
smtlib_frontend.cpp
|
smtlib_frontend.cpp
|
||||||
z3_log_frontend.cpp
|
z3_log_frontend.cpp
|
||||||
|
lp_frontend.cpp
|
||||||
# FIXME: shell should really link against libz3 but it can't due to requiring
|
# FIXME: shell should really link against libz3 but it can't due to requiring
|
||||||
# use of some hidden symbols. Also libz3 has the ``api_dll`` component which
|
# use of some hidden symbols. Also libz3 has the ``api_dll`` component which
|
||||||
# we don't want (I think).
|
# we don't want (I think).
|
||||||
|
|
|
@ -55,6 +55,7 @@ z3_add_component(smt
|
||||||
theory_dl.cpp
|
theory_dl.cpp
|
||||||
theory_dummy.cpp
|
theory_dummy.cpp
|
||||||
theory_fpa.cpp
|
theory_fpa.cpp
|
||||||
|
theory_lra.cpp
|
||||||
theory_opt.cpp
|
theory_opt.cpp
|
||||||
theory_pb.cpp
|
theory_pb.cpp
|
||||||
theory_seq.cpp
|
theory_seq.cpp
|
||||||
|
@ -69,6 +70,7 @@ z3_add_component(smt
|
||||||
euclid
|
euclid
|
||||||
fpa
|
fpa
|
||||||
grobner
|
grobner
|
||||||
|
lp
|
||||||
macros
|
macros
|
||||||
normal_forms
|
normal_forms
|
||||||
parser_util
|
parser_util
|
||||||
|
|
|
@ -119,6 +119,7 @@ add_executable(test-z3
|
||||||
upolynomial.cpp
|
upolynomial.cpp
|
||||||
var_subst.cpp
|
var_subst.cpp
|
||||||
vector.cpp
|
vector.cpp
|
||||||
|
lp.cpp
|
||||||
${z3_test_extra_object_files}
|
${z3_test_extra_object_files}
|
||||||
)
|
)
|
||||||
z3_add_install_tactic_rule(${z3_test_deps})
|
z3_add_install_tactic_rule(${z3_test_deps})
|
||||||
|
@ -130,3 +131,6 @@ target_link_libraries(test-z3 PRIVATE ${Z3_DEPENDENT_LIBS})
|
||||||
target_include_directories(test-z3 PRIVATE ${Z3_COMPONENT_EXTRA_INCLUDE_DIRS})
|
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_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})
|
z3_add_component_dependencies_to_target(test-z3 ${z3_test_expanded_deps})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
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})
|
|
@ -11,6 +11,7 @@ from mk_util import *
|
||||||
def init_project_def():
|
def init_project_def():
|
||||||
set_version(4, 5, 1, 0)
|
set_version(4, 5, 1, 0)
|
||||||
add_lib('util', [])
|
add_lib('util', [])
|
||||||
|
add_lib('lp', ['util'], 'util/lp')
|
||||||
add_lib('polynomial', ['util'], 'math/polynomial')
|
add_lib('polynomial', ['util'], 'math/polynomial')
|
||||||
add_lib('sat', ['util'])
|
add_lib('sat', ['util'])
|
||||||
add_lib('nlsat', ['polynomial', 'sat'])
|
add_lib('nlsat', ['polynomial', 'sat'])
|
||||||
|
@ -52,7 +53,7 @@ def init_project_def():
|
||||||
add_lib('smt_params', ['ast', 'simplifier', 'pattern', 'bit_blaster'], 'smt/params')
|
add_lib('smt_params', ['ast', 'simplifier', 'pattern', 'bit_blaster'], 'smt/params')
|
||||||
add_lib('proto_model', ['model', 'simplifier', 'smt_params'], 'smt/proto_model')
|
add_lib('proto_model', ['model', 'simplifier', 'smt_params'], 'smt/proto_model')
|
||||||
add_lib('smt', ['bit_blaster', 'macros', 'normal_forms', 'cmd_context', 'proto_model',
|
add_lib('smt', ['bit_blaster', 'macros', 'normal_forms', 'cmd_context', 'proto_model',
|
||||||
'substitution', 'grobner', 'euclid', 'simplex', 'proof_checker', 'pattern', 'parser_util', 'fpa'])
|
'substitution', 'grobner', 'euclid', 'simplex', 'proof_checker', 'pattern', 'parser_util', 'fpa', 'lp'])
|
||||||
add_lib('bv_tactics', ['tactic', 'bit_blaster', 'core_tactics'], 'tactic/bv')
|
add_lib('bv_tactics', ['tactic', 'bit_blaster', 'core_tactics'], 'tactic/bv')
|
||||||
add_lib('fuzzing', ['ast'], 'test/fuzzing')
|
add_lib('fuzzing', ['ast'], 'test/fuzzing')
|
||||||
add_lib('smt_tactic', ['smt'], 'smt/tactic')
|
add_lib('smt_tactic', ['smt'], 'smt/tactic')
|
||||||
|
|
|
@ -96,8 +96,6 @@ VER_BUILD=None
|
||||||
VER_REVISION=None
|
VER_REVISION=None
|
||||||
PREFIX=sys.prefix
|
PREFIX=sys.prefix
|
||||||
GMP=False
|
GMP=False
|
||||||
FOCI2=False
|
|
||||||
FOCI2LIB=''
|
|
||||||
VS_PAR=False
|
VS_PAR=False
|
||||||
VS_PAR_NUM=8
|
VS_PAR_NUM=8
|
||||||
GPROF=False
|
GPROF=False
|
||||||
|
@ -257,13 +255,6 @@ def test_gmp(cc):
|
||||||
t.commit()
|
t.commit()
|
||||||
return exec_compiler_cmd([cc, CPPFLAGS, 'tstgmp.cpp', LDFLAGS, '-lgmp']) == 0
|
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):
|
def test_openmp(cc):
|
||||||
if not USE_OMP:
|
if not USE_OMP:
|
||||||
|
@ -650,7 +641,6 @@ def display_help(exit_code):
|
||||||
if not IS_WINDOWS:
|
if not IS_WINDOWS:
|
||||||
print(" -g, --gmp use GMP.")
|
print(" -g, --gmp use GMP.")
|
||||||
print(" --gprof enable gprof")
|
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(" --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(" --log-sync synchronize access to API log files to enable multi-thread API logging.")
|
||||||
print("")
|
print("")
|
||||||
|
@ -678,13 +668,13 @@ def display_help(exit_code):
|
||||||
# Parse configuration option for mk_make script
|
# Parse configuration option for mk_make script
|
||||||
def parse_options():
|
def parse_options():
|
||||||
global VERBOSE, DEBUG_MODE, IS_WINDOWS, VS_X64, ONLY_MAKEFILES, SHOW_CPPS, VS_PROJ, TRACE, VS_PAR, VS_PAR_NUM
|
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
|
global LINUX_X64, SLOW_OPTIMIZE, USE_OMP, LOG_SYNC
|
||||||
try:
|
try:
|
||||||
options, remainder = getopt.gnu_getopt(sys.argv[1:],
|
options, remainder = getopt.gnu_getopt(sys.argv[1:],
|
||||||
'b:df:sxhmcvtnp:gj',
|
'b:df:sxhmcvtnp:gj',
|
||||||
['build=', 'debug', 'silent', 'x64', 'help', 'makefiles', 'showcpp', 'vsproj',
|
['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'])
|
'githash=', 'git-describe', 'x86', 'ml', 'optimize', 'noomp', 'pypkgdir=', 'python', 'staticbin', 'log-sync'])
|
||||||
except:
|
except:
|
||||||
print("ERROR: Invalid command line option")
|
print("ERROR: Invalid command line option")
|
||||||
|
@ -735,9 +725,6 @@ def parse_options():
|
||||||
VS_PAR_NUM = int(arg)
|
VS_PAR_NUM = int(arg)
|
||||||
elif opt in ('-g', '--gmp'):
|
elif opt in ('-g', '--gmp'):
|
||||||
GMP = True
|
GMP = True
|
||||||
elif opt in ('-f', '--foci2'):
|
|
||||||
FOCI2 = True
|
|
||||||
FOCI2LIB = arg
|
|
||||||
elif opt in ('-j', '--java'):
|
elif opt in ('-j', '--java'):
|
||||||
JAVA_ENABLED = True
|
JAVA_ENABLED = True
|
||||||
elif opt == '--gprof':
|
elif opt == '--gprof':
|
||||||
|
@ -775,7 +762,12 @@ def extract_c_includes(fname):
|
||||||
for line in f:
|
for line in f:
|
||||||
m1 = std_inc_pat.match(line)
|
m1 = std_inc_pat.match(line)
|
||||||
if m1:
|
if m1:
|
||||||
result.append(m1.group(1))
|
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)
|
||||||
|
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):
|
elif not system_inc_pat.match(line) and non_std_inc_pat.match(line):
|
||||||
raise MKException("Invalid #include directive at '%s':%s" % (fname, line))
|
raise MKException("Invalid #include directive at '%s':%s" % (fname, line))
|
||||||
linenum = linenum + 1
|
linenum = linenum + 1
|
||||||
|
@ -999,6 +991,7 @@ class Component:
|
||||||
out.write('%s =' % include_defs)
|
out.write('%s =' % include_defs)
|
||||||
for dep in self.deps:
|
for dep in self.deps:
|
||||||
out.write(' -I%s' % get_component(dep).to_src_dir)
|
out.write(' -I%s' % get_component(dep).to_src_dir)
|
||||||
|
out.write(' -I%s' % os.path.join(REV_BUILD_DIR,"src"))
|
||||||
out.write('\n')
|
out.write('\n')
|
||||||
mk_dir(os.path.join(BUILD_DIR, self.build_dir))
|
mk_dir(os.path.join(BUILD_DIR, self.build_dir))
|
||||||
if VS_PAR and IS_WINDOWS:
|
if VS_PAR and IS_WINDOWS:
|
||||||
|
@ -1175,7 +1168,6 @@ class ExeComponent(Component):
|
||||||
for dep in deps:
|
for dep in deps:
|
||||||
c_dep = get_component(dep)
|
c_dep = get_component(dep)
|
||||||
out.write(' ' + c_dep.get_link_name())
|
out.write(' ' + c_dep.get_link_name())
|
||||||
out.write(' ' + FOCI2LIB)
|
|
||||||
out.write(' $(LINK_EXTRA_FLAGS)\n')
|
out.write(' $(LINK_EXTRA_FLAGS)\n')
|
||||||
out.write('%s: %s\n\n' % (self.name, exefile))
|
out.write('%s: %s\n\n' % (self.name, exefile))
|
||||||
|
|
||||||
|
@ -1301,7 +1293,6 @@ class DLLComponent(Component):
|
||||||
if dep not in self.reexports:
|
if dep not in self.reexports:
|
||||||
c_dep = get_component(dep)
|
c_dep = get_component(dep)
|
||||||
out.write(' ' + c_dep.get_link_name())
|
out.write(' ' + c_dep.get_link_name())
|
||||||
out.write(' ' + FOCI2LIB)
|
|
||||||
out.write(' $(SLINK_EXTRA_FLAGS)')
|
out.write(' $(SLINK_EXTRA_FLAGS)')
|
||||||
if IS_WINDOWS:
|
if IS_WINDOWS:
|
||||||
out.write(' /DEF:%s.def' % os.path.join(self.to_src_dir, self.name))
|
out.write(' /DEF:%s.def' % os.path.join(self.to_src_dir, self.name))
|
||||||
|
@ -2301,7 +2292,7 @@ def mk_config():
|
||||||
if ONLY_MAKEFILES:
|
if ONLY_MAKEFILES:
|
||||||
return
|
return
|
||||||
config = open(os.path.join(BUILD_DIR, 'config.mk'), 'w')
|
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:
|
if IS_WINDOWS:
|
||||||
config.write(
|
config.write(
|
||||||
'CC=cl\n'
|
'CC=cl\n'
|
||||||
|
@ -2411,14 +2402,6 @@ def mk_config():
|
||||||
SLIBEXTRAFLAGS = '%s -lgmp' % SLIBEXTRAFLAGS
|
SLIBEXTRAFLAGS = '%s -lgmp' % SLIBEXTRAFLAGS
|
||||||
else:
|
else:
|
||||||
CPPFLAGS = '%s -D_MP_INTERNAL' % CPPFLAGS
|
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:
|
if GIT_HASH:
|
||||||
CPPFLAGS = '%s -DZ3GITHASH=%s' % (CPPFLAGS, GIT_HASH)
|
CPPFLAGS = '%s -DZ3GITHASH=%s' % (CPPFLAGS, GIT_HASH)
|
||||||
CXXFLAGS = '%s -std=c++11' % CXXFLAGS
|
CXXFLAGS = '%s -std=c++11' % CXXFLAGS
|
||||||
|
@ -2952,6 +2935,10 @@ def get_platform_toolset_str():
|
||||||
tokens = lline.split('.')
|
tokens = lline.split('.')
|
||||||
if len(tokens) < 2:
|
if len(tokens) < 2:
|
||||||
return default
|
return default
|
||||||
|
else:
|
||||||
|
if tokens[0] == "15":
|
||||||
|
# Visual Studio 2017 reports 15.* but the PlatformToolsetVersion is 141
|
||||||
|
return "v141"
|
||||||
else:
|
else:
|
||||||
return 'v' + tokens[0] + tokens[1]
|
return 'v' + tokens[0] + tokens[1]
|
||||||
|
|
||||||
|
|
|
@ -164,6 +164,6 @@ setup(
|
||||||
package_data={
|
package_data={
|
||||||
'z3': [os.path.join('lib', '*'), os.path.join('include', '*.h'), os.path.join('include', 'c++', '*.h')]
|
'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},
|
cmdclass={'build': build, 'develop': develop, 'sdist': sdist, 'bdist_egg': bdist_egg},
|
||||||
)
|
)
|
||||||
|
|
|
@ -1300,7 +1300,9 @@ class BoolSortRef(SortRef):
|
||||||
if isinstance(val, bool):
|
if isinstance(val, bool):
|
||||||
return BoolVal(val, self.ctx)
|
return BoolVal(val, self.ctx)
|
||||||
if __debug__:
|
if __debug__:
|
||||||
|
if not is_expr(val):
|
||||||
_z3_assert(is_expr(val), "True, False or Z3 Boolean expression expected. Received %s" % 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")
|
_z3_assert(self.eq(val.sort()), "Value cannot be converted into a Z3 Boolean value")
|
||||||
return val
|
return val
|
||||||
|
|
||||||
|
|
|
@ -305,6 +305,7 @@ public:
|
||||||
MATCH_UNARY(is_uminus);
|
MATCH_UNARY(is_uminus);
|
||||||
MATCH_UNARY(is_to_real);
|
MATCH_UNARY(is_to_real);
|
||||||
MATCH_UNARY(is_to_int);
|
MATCH_UNARY(is_to_int);
|
||||||
|
MATCH_UNARY(is_is_int);
|
||||||
MATCH_BINARY(is_sub);
|
MATCH_BINARY(is_sub);
|
||||||
MATCH_BINARY(is_add);
|
MATCH_BINARY(is_add);
|
||||||
MATCH_BINARY(is_mul);
|
MATCH_BINARY(is_mul);
|
||||||
|
@ -377,6 +378,9 @@ public:
|
||||||
app * mk_real(int i) {
|
app * mk_real(int i) {
|
||||||
return mk_numeral(rational(i), false);
|
return mk_numeral(rational(i), false);
|
||||||
}
|
}
|
||||||
|
app * mk_real(rational const& r) {
|
||||||
|
return mk_numeral(r, false);
|
||||||
|
}
|
||||||
app * mk_le(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_LE, arg1, arg2); }
|
app * mk_le(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_LE, arg1, arg2); }
|
||||||
app * mk_ge(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_GE, arg1, arg2); }
|
app * mk_ge(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_GE, arg1, arg2); }
|
||||||
app * mk_lt(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_LT, arg1, arg2); }
|
app * mk_lt(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_LT, arg1, arg2); }
|
||||||
|
|
|
@ -44,9 +44,12 @@ void ast_pp_util::display_decls(std::ostream& out) {
|
||||||
}
|
}
|
||||||
n = coll.get_num_decls();
|
n = coll.get_num_decls();
|
||||||
for (unsigned i = 0; i < n; ++i) {
|
for (unsigned i = 0; i < n; ++i) {
|
||||||
ast_smt2_pp(out, coll.get_func_decls()[i], env);
|
func_decl* f = coll.get_func_decls()[i];
|
||||||
|
if (f->get_family_id() == null_family_id) {
|
||||||
|
ast_smt2_pp(out, f, env);
|
||||||
out << "\n";
|
out << "\n";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ast_pp_util::display_asserts(std::ostream& out, expr_ref_vector const& fmls, bool neat) {
|
void ast_pp_util::display_asserts(std::ostream& out, expr_ref_vector const& fmls, bool neat) {
|
||||||
|
|
|
@ -26,6 +26,7 @@ Notes:
|
||||||
#include"ast_pp.h"
|
#include"ast_pp.h"
|
||||||
#include"lbool.h"
|
#include"lbool.h"
|
||||||
#include"uint_set.h"
|
#include"uint_set.h"
|
||||||
|
#include"gparams.h"
|
||||||
|
|
||||||
const unsigned g_primes[7] = { 2, 3, 5, 7, 11, 13, 17};
|
const unsigned g_primes[7] = { 2, 3, 5, 7, 11, 13, 17};
|
||||||
|
|
||||||
|
@ -54,6 +55,8 @@ struct pb2bv_rewriter::imp {
|
||||||
vector<rational> m_coeffs;
|
vector<rational> m_coeffs;
|
||||||
bool m_keep_cardinality_constraints;
|
bool m_keep_cardinality_constraints;
|
||||||
bool m_keep_pb_constraints;
|
bool m_keep_pb_constraints;
|
||||||
|
bool m_pb_num_system;
|
||||||
|
bool m_pb_totalizer;
|
||||||
unsigned m_min_arity;
|
unsigned m_min_arity;
|
||||||
|
|
||||||
template<lbool is_le>
|
template<lbool is_le>
|
||||||
|
@ -114,23 +117,24 @@ struct pb2bv_rewriter::imp {
|
||||||
return expr_ref((is_le == l_false)?m.mk_true():m.mk_false(), m);
|
return expr_ref((is_le == l_false)?m.mk_true():m.mk_false(), m);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
if (m_pb_totalizer) {
|
||||||
expr_ref result(m);
|
expr_ref result(m);
|
||||||
switch (is_le) {
|
switch (is_le) {
|
||||||
case l_true: if (mk_le_tot(sz, args, k, result)) return result; else break;
|
case l_true: if (mk_le_tot(sz, args, k, result)) return result; else break;
|
||||||
case l_false: if (mk_ge_tot(sz, args, k, result)) return result; else break;
|
case l_false: if (mk_ge_tot(sz, args, k, result)) return result; else break;
|
||||||
case l_undef: break;
|
case l_undef: break;
|
||||||
}
|
}
|
||||||
#endif
|
}
|
||||||
|
|
||||||
#if 0
|
if (m_pb_num_system) {
|
||||||
expr_ref result(m);
|
expr_ref result(m);
|
||||||
switch (is_le) {
|
switch (is_le) {
|
||||||
case l_true: if (mk_le(sz, args, k, result)) return result; else break;
|
case l_true: if (mk_le(sz, args, k, result)) return result; else break;
|
||||||
case l_false: if (mk_ge(sz, args, k, result)) return result; else break;
|
case l_false: if (mk_ge(sz, args, k, result)) return result; else break;
|
||||||
case l_undef: if (mk_eq(sz, args, k, result)) return result; else break;
|
case l_undef: if (mk_eq(sz, args, k, result)) return result; else break;
|
||||||
}
|
}
|
||||||
#endif
|
}
|
||||||
|
|
||||||
// fall back to divide and conquer encoding.
|
// fall back to divide and conquer encoding.
|
||||||
SASSERT(k.is_pos());
|
SASSERT(k.is_pos());
|
||||||
expr_ref zero(m), bound(m);
|
expr_ref zero(m), bound(m);
|
||||||
|
@ -397,22 +401,31 @@ struct pb2bv_rewriter::imp {
|
||||||
for (unsigned j = 0; j + lim - 1 < out.size(); j += n) {
|
for (unsigned j = 0; j + lim - 1 < out.size(); j += n) {
|
||||||
expr_ref tmp(m);
|
expr_ref tmp(m);
|
||||||
tmp = out[j + lim - 1];
|
tmp = out[j + lim - 1];
|
||||||
if (j + n < out.size()) {
|
if (j + n - 1 < out.size()) {
|
||||||
tmp = m.mk_and(tmp, m.mk_not(out[j + n]));
|
tmp = m.mk_and(tmp, m.mk_not(out[j + n - 1]));
|
||||||
}
|
}
|
||||||
ors.push_back(tmp);
|
ors.push_back(tmp);
|
||||||
}
|
}
|
||||||
return ::mk_or(ors);
|
return ::mk_or(ors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// x0 + 5x1 + 3x2 >= k
|
||||||
|
// x0 x1 x1 -> s0 s1 s2
|
||||||
|
// s2 x1 x2 -> s3 s4 s5
|
||||||
|
// k = 7: s5 or (s4 & not s2 & s0)
|
||||||
|
// k = 6: s4
|
||||||
|
// k = 5: s4 or (s3 & not s2 & s1)
|
||||||
|
// k = 4: s4 or (s3 & not s2 & s0)
|
||||||
|
// k = 3: s3
|
||||||
|
//
|
||||||
bool mk_ge(unsigned sz, expr * const* args, rational bound, expr_ref& result) {
|
bool mk_ge(unsigned sz, expr * const* args, rational bound, expr_ref& result) {
|
||||||
if (!create_basis()) return false;
|
if (!create_basis()) return false;
|
||||||
if (!bound.is_unsigned()) return false;
|
if (!bound.is_unsigned()) return false;
|
||||||
vector<rational> coeffs(m_coeffs);
|
vector<rational> coeffs(m_coeffs);
|
||||||
result = m.mk_true();
|
result = m.mk_true();
|
||||||
expr_ref_vector carry(m), new_carry(m);
|
expr_ref_vector carry(m), new_carry(m);
|
||||||
for (unsigned i = 0; i < m_base.size(); ++i) {
|
m_base.push_back(bound + rational::one());
|
||||||
rational b_i = m_base[i];
|
for (rational b_i : m_base) {
|
||||||
unsigned B = b_i.get_unsigned();
|
unsigned B = b_i.get_unsigned();
|
||||||
unsigned d_i = (bound % b_i).get_unsigned();
|
unsigned d_i = (bound % b_i).get_unsigned();
|
||||||
bound = div(bound, b_i);
|
bound = div(bound, b_i);
|
||||||
|
@ -425,7 +438,7 @@ struct pb2bv_rewriter::imp {
|
||||||
coeffs[j] = div(coeffs[j], b_i);
|
coeffs[j] = div(coeffs[j], b_i);
|
||||||
}
|
}
|
||||||
TRACE("pb", tout << "Carry: " << carry << "\n";
|
TRACE("pb", tout << "Carry: " << carry << "\n";
|
||||||
for (unsigned j = 0; j < coeffs.size(); ++j) tout << coeffs[j] << " ";
|
for (auto c : coeffs) tout << c << " ";
|
||||||
tout << "\n";
|
tout << "\n";
|
||||||
);
|
);
|
||||||
ptr_vector<expr> out;
|
ptr_vector<expr> out;
|
||||||
|
@ -434,7 +447,7 @@ struct pb2bv_rewriter::imp {
|
||||||
expr_ref gt = mod_ge(out, B, d_i + 1);
|
expr_ref gt = mod_ge(out, B, d_i + 1);
|
||||||
expr_ref ge = mod_ge(out, B, d_i);
|
expr_ref ge = mod_ge(out, B, d_i);
|
||||||
result = mk_or(gt, mk_and(ge, result));
|
result = mk_or(gt, mk_and(ge, result));
|
||||||
TRACE("pb", tout << result << "\n";);
|
TRACE("pb", tout << "b: " << b_i << " d: " << d_i << " gt: " << gt << " ge: " << ge << " " << result << "\n";);
|
||||||
|
|
||||||
new_carry.reset();
|
new_carry.reset();
|
||||||
for (unsigned j = B - 1; j < out.size(); j += B) {
|
for (unsigned j = B - 1; j < out.size(); j += B) {
|
||||||
|
@ -443,7 +456,7 @@ struct pb2bv_rewriter::imp {
|
||||||
carry.reset();
|
carry.reset();
|
||||||
carry.append(new_carry);
|
carry.append(new_carry);
|
||||||
}
|
}
|
||||||
TRACE("pb", tout << result << "\n";);
|
TRACE("pb", tout << "bound: " << bound << " Carry: " << carry << " result: " << result << "\n";);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -491,6 +504,7 @@ struct pb2bv_rewriter::imp {
|
||||||
for (unsigned i = 0; i < sz; ++i) {
|
for (unsigned i = 0; i < sz; ++i) {
|
||||||
m_coeffs.push_back(pb.get_coeff(f, i));
|
m_coeffs.push_back(pb.get_coeff(f, i));
|
||||||
}
|
}
|
||||||
|
CTRACE("pb", k.is_neg(), tout << expr_ref(m.mk_app(f, sz, args), m) << "\n";);
|
||||||
SASSERT(!k.is_neg());
|
SASSERT(!k.is_neg());
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case OP_PB_GE:
|
case OP_PB_GE:
|
||||||
|
@ -567,6 +581,8 @@ struct pb2bv_rewriter::imp {
|
||||||
m_args(m),
|
m_args(m),
|
||||||
m_keep_cardinality_constraints(false),
|
m_keep_cardinality_constraints(false),
|
||||||
m_keep_pb_constraints(false),
|
m_keep_pb_constraints(false),
|
||||||
|
m_pb_num_system(false),
|
||||||
|
m_pb_totalizer(false),
|
||||||
m_min_arity(2)
|
m_min_arity(2)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
@ -761,6 +777,14 @@ struct pb2bv_rewriter::imp {
|
||||||
void keep_pb_constraints(bool f) {
|
void keep_pb_constraints(bool f) {
|
||||||
m_keep_pb_constraints = f;
|
m_keep_pb_constraints = f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pb_num_system(bool f) {
|
||||||
|
m_pb_num_system = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pb_totalizer(bool f) {
|
||||||
|
m_pb_totalizer = f;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct card2bv_rewriter_cfg : public default_rewriter_cfg {
|
struct card2bv_rewriter_cfg : public default_rewriter_cfg {
|
||||||
|
@ -774,6 +798,8 @@ struct pb2bv_rewriter::imp {
|
||||||
card2bv_rewriter_cfg(imp& i, ast_manager & m):m_r(i, m) {}
|
card2bv_rewriter_cfg(imp& i, ast_manager & m):m_r(i, m) {}
|
||||||
void keep_cardinality_constraints(bool f) { m_r.keep_cardinality_constraints(f); }
|
void keep_cardinality_constraints(bool f) { m_r.keep_cardinality_constraints(f); }
|
||||||
void keep_pb_constraints(bool f) { m_r.keep_pb_constraints(f); }
|
void keep_pb_constraints(bool f) { m_r.keep_pb_constraints(f); }
|
||||||
|
void pb_num_system(bool f) { m_r.pb_num_system(f); }
|
||||||
|
void pb_totalizer(bool f) { m_r.pb_totalizer(f); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class card_pb_rewriter : public rewriter_tpl<card2bv_rewriter_cfg> {
|
class card_pb_rewriter : public rewriter_tpl<card2bv_rewriter_cfg> {
|
||||||
|
@ -784,27 +810,62 @@ struct pb2bv_rewriter::imp {
|
||||||
m_cfg(i, m) {}
|
m_cfg(i, m) {}
|
||||||
void keep_cardinality_constraints(bool f) { m_cfg.keep_cardinality_constraints(f); }
|
void keep_cardinality_constraints(bool f) { m_cfg.keep_cardinality_constraints(f); }
|
||||||
void keep_pb_constraints(bool f) { m_cfg.keep_pb_constraints(f); }
|
void keep_pb_constraints(bool f) { m_cfg.keep_pb_constraints(f); }
|
||||||
|
void pb_num_system(bool f) { m_cfg.pb_num_system(f); }
|
||||||
|
void pb_totalizer(bool f) { m_cfg.pb_totalizer(f); }
|
||||||
};
|
};
|
||||||
|
|
||||||
card_pb_rewriter m_rw;
|
card_pb_rewriter m_rw;
|
||||||
|
|
||||||
|
bool keep_cardinality() const {
|
||||||
|
params_ref const& p = m_params;
|
||||||
|
return
|
||||||
|
p.get_bool("keep_cardinality_constraints", false) ||
|
||||||
|
p.get_bool("sat.cardinality.solver", false) ||
|
||||||
|
p.get_bool("cardinality.solver", false) ||
|
||||||
|
gparams::get_module("sat").get_bool("cardinality.solver", false) ||
|
||||||
|
keep_pb();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool keep_pb() const {
|
||||||
|
params_ref const& p = m_params;
|
||||||
|
return
|
||||||
|
p.get_bool("keep_pb_constraints", false) ||
|
||||||
|
p.get_bool("sat.pb.solver", false) ||
|
||||||
|
p.get_bool("pb.solver", false) ||
|
||||||
|
gparams::get_module("sat").get_bool("pb.solver", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pb_num_system() const {
|
||||||
|
return m_params.get_bool("pb_num_system", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pb_totalizer() const {
|
||||||
|
return m_params.get_bool("pb_totalizer", false);
|
||||||
|
}
|
||||||
|
|
||||||
imp(ast_manager& m, params_ref const& p):
|
imp(ast_manager& m, params_ref const& p):
|
||||||
m(m), m_params(p), m_lemmas(m),
|
m(m), m_params(p), m_lemmas(m),
|
||||||
m_fresh(m),
|
m_fresh(m),
|
||||||
m_num_translated(0),
|
m_num_translated(0),
|
||||||
m_rw(*this, m) {
|
m_rw(*this, m) {
|
||||||
m_rw.keep_cardinality_constraints(p.get_bool("keep_cardinality_constraints", false));
|
m_rw.keep_cardinality_constraints(keep_cardinality());
|
||||||
m_rw.keep_pb_constraints(p.get_bool("keep_pb_constraints", false));
|
m_rw.keep_pb_constraints(keep_pb());
|
||||||
|
m_rw.pb_num_system(pb_num_system());
|
||||||
|
m_rw.pb_totalizer(pb_totalizer());
|
||||||
}
|
}
|
||||||
|
|
||||||
void updt_params(params_ref const & p) {
|
void updt_params(params_ref const & p) {
|
||||||
m_params.append(p);
|
m_params.append(p);
|
||||||
m_rw.keep_cardinality_constraints(m_params.get_bool("keep_cardinality_constraints", false));
|
m_rw.keep_cardinality_constraints(keep_cardinality());
|
||||||
m_rw.keep_pb_constraints(m_params.get_bool("keep_pb_constraints", false));
|
m_rw.keep_pb_constraints(keep_pb());
|
||||||
|
m_rw.pb_num_system(pb_num_system());
|
||||||
|
m_rw.pb_totalizer(pb_totalizer());
|
||||||
}
|
}
|
||||||
void collect_param_descrs(param_descrs& r) const {
|
void collect_param_descrs(param_descrs& r) const {
|
||||||
r.insert("keep_cardinality_constraints", CPK_BOOL, "(default: true) retain cardinality constraints (don't bit-blast them) and use built-in cardinality solver");
|
r.insert("keep_cardinality_constraints", CPK_BOOL, "(default: true) retain cardinality constraints (don't bit-blast them) and use built-in cardinality solver");
|
||||||
r.insert("keep_pb_constraints", CPK_BOOL, "(default: true) retain pb constraints (don't bit-blast them) and use built-in pb solver");
|
r.insert("keep_pb_constraints", CPK_BOOL, "(default: true) retain pb constraints (don't bit-blast them) and use built-in pb solver");
|
||||||
|
r.insert("pb_num_system", CPK_BOOL, "(default: false) use pb number system encoding");
|
||||||
|
r.insert("pb_totalizer", CPK_BOOL, "(default: false) use pb totalizer encoding");
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned get_num_steps() const { return m_rw.get_num_steps(); }
|
unsigned get_num_steps() const { return m_rw.get_num_steps(); }
|
||||||
|
|
|
@ -232,6 +232,7 @@ br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_eq = f->get_decl_kind() == OP_PB_EQ;
|
bool is_eq = f->get_decl_kind() == OP_PB_EQ;
|
||||||
|
br_status st = BR_DONE;
|
||||||
|
|
||||||
pb_ast_rewriter_util pbu(m);
|
pb_ast_rewriter_util pbu(m);
|
||||||
pb_rewriter_util<pb_ast_rewriter_util> util(pbu);
|
pb_rewriter_util<pb_ast_rewriter_util> util(pbu);
|
||||||
|
@ -249,11 +250,14 @@ br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons
|
||||||
default: {
|
default: {
|
||||||
bool all_unit = true;
|
bool all_unit = true;
|
||||||
unsigned sz = vec.size();
|
unsigned sz = vec.size();
|
||||||
|
rational slack(0);
|
||||||
m_args.reset();
|
m_args.reset();
|
||||||
m_coeffs.reset();
|
m_coeffs.reset();
|
||||||
for (unsigned i = 0; i < sz; ++i) {
|
for (unsigned i = 0; i < sz; ++i) {
|
||||||
m_args.push_back(vec[i].first);
|
m_args.push_back(vec[i].first);
|
||||||
m_coeffs.push_back(vec[i].second);
|
m_coeffs.push_back(vec[i].second);
|
||||||
|
SASSERT(vec[i].second.is_pos());
|
||||||
|
slack += vec[i].second;
|
||||||
all_unit &= m_coeffs.back().is_one();
|
all_unit &= m_coeffs.back().is_one();
|
||||||
}
|
}
|
||||||
if (is_eq) {
|
if (is_eq) {
|
||||||
|
@ -271,7 +275,42 @@ br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons
|
||||||
result = mk_and(m, sz, m_args.c_ptr());
|
result = mk_and(m, sz, m_args.c_ptr());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result = m_util.mk_ge(sz, m_coeffs.c_ptr(), m_args.c_ptr(), k);
|
expr_ref_vector conj(m), disj(m);
|
||||||
|
for (unsigned i = 0; i < m_args.size(); ++i) {
|
||||||
|
rational& c = m_coeffs[i];
|
||||||
|
if (slack < c + k) {
|
||||||
|
conj.push_back(m_args[i]);
|
||||||
|
slack -= c;
|
||||||
|
k -= c;
|
||||||
|
}
|
||||||
|
else if (c >= k) {
|
||||||
|
slack -= c;
|
||||||
|
disj.push_back(m_args[i]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
m_args[i] = m_args.back();
|
||||||
|
m_coeffs[i] = m_coeffs.back();
|
||||||
|
--i;
|
||||||
|
m_args.pop_back();
|
||||||
|
m_coeffs.pop_back();
|
||||||
|
}
|
||||||
|
sz = m_coeffs.size();
|
||||||
|
if (slack < k) {
|
||||||
|
conj.push_back(m.mk_false());
|
||||||
|
}
|
||||||
|
else if (k.is_pos() && sz > 0) {
|
||||||
|
conj.push_back(m_util.mk_ge(sz, m_coeffs.c_ptr(), m_args.c_ptr(), k));
|
||||||
|
}
|
||||||
|
result = mk_and(conj);
|
||||||
|
if (!disj.empty()) {
|
||||||
|
disj.push_back(result);
|
||||||
|
result = mk_or(disj);
|
||||||
|
}
|
||||||
|
if (!disj.empty() || conj.size() > 1) {
|
||||||
|
st = BR_REWRITE3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -286,7 +325,7 @@ br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons
|
||||||
TRACE("pb_validate",
|
TRACE("pb_validate",
|
||||||
validate_rewrite(f, num_args, args, result););
|
validate_rewrite(f, num_args, args, result););
|
||||||
|
|
||||||
return BR_DONE;
|
return st;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -440,25 +440,17 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
|
||||||
* (seq.unit (_ BitVector 8)) ==> String constant
|
* (seq.unit (_ BitVector 8)) ==> String constant
|
||||||
*/
|
*/
|
||||||
br_status seq_rewriter::mk_seq_unit(expr* e, expr_ref& result) {
|
br_status seq_rewriter::mk_seq_unit(expr* e, expr_ref& result) {
|
||||||
sort * s = m().get_sort(e);
|
|
||||||
bv_util bvu(m());
|
bv_util bvu(m());
|
||||||
|
|
||||||
if (is_sort_of(s, bvu.get_family_id(), BV_SORT)) {
|
|
||||||
// specifically we want (_ BitVector 8)
|
|
||||||
rational n_val;
|
rational n_val;
|
||||||
unsigned int n_size;
|
unsigned int n_size;
|
||||||
if (bvu.is_numeral(e, n_val, n_size)) {
|
// specifically we want (_ BitVector 8)
|
||||||
if (n_size == 8) {
|
if (bvu.is_bv(e) && bvu.is_numeral(e, n_val, n_size) && n_size == 8) {
|
||||||
// convert to string constant
|
// convert to string constant
|
||||||
char ch = (char)n_val.get_int32();
|
zstring str(n_val.get_unsigned());
|
||||||
TRACE("seq", tout << "rewrite seq.unit of 8-bit value " << n_val.to_string() << " to string constant \"" << ch << "\"" << std::endl;);
|
TRACE("seq", tout << "rewrite seq.unit of 8-bit value " << n_val.to_string() << " to string constant \"" << str<< "\"" << std::endl;);
|
||||||
char s_tmp[2] = {ch, '\0'};
|
result = m_util.str.mk_string(str);
|
||||||
symbol s(s_tmp);
|
|
||||||
result = m_util.str.mk_string(s);
|
|
||||||
return BR_DONE;
|
return BR_DONE;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return BR_FAILED;
|
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) {
|
br_status seq_rewriter::mk_re_range(expr* lo, expr* hi, expr_ref& result) {
|
||||||
return BR_FAILED;
|
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) {
|
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());
|
expr_ref_vector lhs(m()), rhs(m()), res(m());
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
if (!reduce_eq(l, r, lhs, rhs, changed)) {
|
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) {
|
expr* seq_decl_plugin::get_some_value(sort* s) {
|
||||||
seq_util util(*m_manager);
|
seq_util util(*m_manager);
|
||||||
if (util.is_seq(s)) {
|
if (util.is_seq(s)) {
|
||||||
|
|
|
@ -182,7 +182,11 @@ public:
|
||||||
|
|
||||||
virtual bool is_value(app * e) const;
|
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);
|
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 "iz3profiling.h"
|
||||||
#include "iz3translate.h"
|
#include "iz3translate.h"
|
||||||
#include "iz3foci.h"
|
|
||||||
#include "iz3proof.h"
|
#include "iz3proof.h"
|
||||||
#include "iz3hash.h"
|
#include "iz3hash.h"
|
||||||
#include "iz3interp.h"
|
#include "iz3interp.h"
|
||||||
|
@ -167,22 +166,6 @@ struct frame_reducer {
|
||||||
#endif
|
#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>
|
template<class T>
|
||||||
struct killme {
|
struct killme {
|
||||||
|
@ -213,11 +196,7 @@ public:
|
||||||
const std::vector<int> &parents,
|
const std::vector<int> &parents,
|
||||||
std::vector<ast> &interps
|
std::vector<ast> &interps
|
||||||
){
|
){
|
||||||
int num = cnsts.size();
|
throw iz3_exception("secondary interpolating prover not supported");
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void proof_to_interpolant(z3pf proof,
|
void proof_to_interpolant(z3pf proof,
|
||||||
|
@ -248,9 +227,8 @@ public:
|
||||||
if(is_linear(parents_vec))
|
if(is_linear(parents_vec))
|
||||||
parents_vec.clear();
|
parents_vec.clear();
|
||||||
|
|
||||||
// create a secondary prover
|
// secondary prover no longer supported
|
||||||
iz3secondary *sp = iz3foci::create(this,num,parents_vec.empty()?0:&parents_vec[0]);
|
iz3secondary *sp = NULL;
|
||||||
sp_killer.set(sp); // kill this on exit
|
|
||||||
|
|
||||||
#define BINARY_INTERPOLATION
|
#define BINARY_INTERPOLATION
|
||||||
#ifndef BINARY_INTERPOLATION
|
#ifndef BINARY_INTERPOLATION
|
||||||
|
|
|
@ -53,12 +53,8 @@ class iz3translation : public iz3base {
|
||||||
: iz3base(mgr,_cnsts,_parents,_theory) {}
|
: iz3base(mgr,_cnsts,_parents,_theory) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
//#define IZ3_TRANSLATE_DIRECT2
|
// To use a secondary prover, define IZ3_TRANSLATE_DIRECT instead of this
|
||||||
#ifdef _FOCI2
|
|
||||||
#define IZ3_TRANSLATE_DIRECT
|
|
||||||
#else
|
|
||||||
#define IZ3_TRANSLATE_FULL
|
#define IZ3_TRANSLATE_FULL
|
||||||
#endif
|
|
||||||
|
|
||||||
#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){
|
void get_Z3_lits(ast t, std::vector<ast> &lits){
|
||||||
opr dk = op(t);
|
opr dk = op(t);
|
||||||
if(dk == False)
|
if(dk == False)
|
||||||
|
@ -666,9 +666,9 @@ public:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// interpolate using secondary prover
|
// interpolate using secondary prover
|
||||||
profiling::timer_start("foci");
|
profiling::timer_start("secondary prover");
|
||||||
int sat = secondary->interpolate(preds,itps);
|
int sat = secondary->interpolate(preds,itps);
|
||||||
profiling::timer_stop("foci");
|
profiling::timer_stop("secondary prover");
|
||||||
|
|
||||||
std::cout << "lemma done" << std::endl;
|
std::cout << "lemma done" << std::endl;
|
||||||
|
|
||||||
|
@ -1495,7 +1495,7 @@ public:
|
||||||
return find_nll(new_proofs);
|
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){
|
Iproof::node translate_main(ast proof, non_local_lits *nll, bool expect_clause = true){
|
||||||
non_local_lits *old_nll = nll;
|
non_local_lits *old_nll = nll;
|
||||||
|
|
|
@ -26,6 +26,7 @@ Notes:
|
||||||
#include "theory_diff_logic.h"
|
#include "theory_diff_logic.h"
|
||||||
#include "theory_dense_diff_logic.h"
|
#include "theory_dense_diff_logic.h"
|
||||||
#include "theory_pb.h"
|
#include "theory_pb.h"
|
||||||
|
#include "theory_lra.h"
|
||||||
#include "ast_pp.h"
|
#include "ast_pp.h"
|
||||||
#include "ast_smt_pp.h"
|
#include "ast_smt_pp.h"
|
||||||
#include "pp_params.hpp"
|
#include "pp_params.hpp"
|
||||||
|
@ -143,6 +144,9 @@ namespace opt {
|
||||||
else if (typeid(smt::theory_dense_si&) == typeid(*arith_theory)) {
|
else if (typeid(smt::theory_dense_si&) == typeid(*arith_theory)) {
|
||||||
return dynamic_cast<smt::theory_dense_si&>(*arith_theory);
|
return dynamic_cast<smt::theory_dense_si&>(*arith_theory);
|
||||||
}
|
}
|
||||||
|
else if (typeid(smt::theory_lra&) == typeid(*arith_theory)) {
|
||||||
|
return dynamic_cast<smt::theory_lra&>(*arith_theory);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
return dynamic_cast<smt::theory_mi_arith&>(*arith_theory);
|
return dynamic_cast<smt::theory_mi_arith&>(*arith_theory);
|
||||||
|
@ -401,6 +405,14 @@ namespace opt {
|
||||||
return th.mk_ge(m_fm, v, val);
|
return th.mk_ge(m_fm, v, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (typeid(smt::theory_lra) == typeid(opt)) {
|
||||||
|
smt::theory_lra& th = dynamic_cast<smt::theory_lra&>(opt);
|
||||||
|
SASSERT(val.is_finite());
|
||||||
|
return th.mk_ge(m_fm, v, val.get_numeral());
|
||||||
|
}
|
||||||
|
|
||||||
|
// difference logic?
|
||||||
if (typeid(smt::theory_dense_si) == typeid(opt) &&
|
if (typeid(smt::theory_dense_si) == typeid(opt) &&
|
||||||
val.get_infinitesimal().is_zero()) {
|
val.get_infinitesimal().is_zero()) {
|
||||||
smt::theory_dense_si& th = dynamic_cast<smt::theory_dense_si&>(opt);
|
smt::theory_dense_si& th = dynamic_cast<smt::theory_dense_si&>(opt);
|
||||||
|
|
|
@ -46,6 +46,8 @@ namespace sat {
|
||||||
m_lit(lit),
|
m_lit(lit),
|
||||||
m_k(k),
|
m_k(k),
|
||||||
m_size(wlits.size()),
|
m_size(wlits.size()),
|
||||||
|
m_slack(0),
|
||||||
|
m_num_watch(0),
|
||||||
m_max_sum(0) {
|
m_max_sum(0) {
|
||||||
for (unsigned i = 0; i < wlits.size(); ++i) {
|
for (unsigned i = 0; i < wlits.size(); ++i) {
|
||||||
m_wlits[i] = wlits[i];
|
m_wlits[i] = wlits[i];
|
||||||
|
@ -237,7 +239,6 @@ namespace sat {
|
||||||
p.negate();
|
p.negate();
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE("sat", display(tout << "init watch: ", p, true););
|
|
||||||
SASSERT(p.lit() == null_literal || value(p.lit()) == l_true);
|
SASSERT(p.lit() == null_literal || value(p.lit()) == l_true);
|
||||||
unsigned sz = p.size(), bound = p.k();
|
unsigned sz = p.size(), bound = p.k();
|
||||||
|
|
||||||
|
@ -249,7 +250,7 @@ namespace sat {
|
||||||
p.swap(i, j);
|
p.swap(i, j);
|
||||||
}
|
}
|
||||||
if (slack < bound) {
|
if (slack < bound) {
|
||||||
slack += p[i].first;
|
slack += p[j].first;
|
||||||
++num_watch;
|
++num_watch;
|
||||||
}
|
}
|
||||||
++j;
|
++j;
|
||||||
|
@ -266,7 +267,7 @@ namespace sat {
|
||||||
if (slack < bound) {
|
if (slack < bound) {
|
||||||
literal lit = p[j].second;
|
literal lit = p[j].second;
|
||||||
SASSERT(value(p[j].second) == l_false);
|
SASSERT(value(p[j].second) == l_false);
|
||||||
for (unsigned i = j + 1; j < sz; ++i) {
|
for (unsigned i = j + 1; i < sz; ++i) {
|
||||||
if (lvl(lit) < lvl(p[i].second)) {
|
if (lvl(lit) < lvl(p[i].second)) {
|
||||||
lit = p[i].second;
|
lit = p[i].second;
|
||||||
}
|
}
|
||||||
|
@ -280,6 +281,7 @@ namespace sat {
|
||||||
p.set_slack(slack);
|
p.set_slack(slack);
|
||||||
p.set_num_watch(num_watch);
|
p.set_num_watch(num_watch);
|
||||||
}
|
}
|
||||||
|
TRACE("sat", display(tout << "init watch: ", p, true););
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -296,7 +298,7 @@ namespace sat {
|
||||||
Lw = Lw u {l_s}
|
Lw = Lw u {l_s}
|
||||||
Lu = Lu \ {l_s}
|
Lu = Lu \ {l_s}
|
||||||
}
|
}
|
||||||
if (Sw < bound) conflict
|
if (Sw < k) conflict
|
||||||
while (Sw < k + a_max) {
|
while (Sw < k + a_max) {
|
||||||
assign (l_max)
|
assign (l_max)
|
||||||
a_max = max { ai | li in Lw, li = undef }
|
a_max = max { ai | li in Lw, li = undef }
|
||||||
|
@ -308,7 +310,19 @@ namespace sat {
|
||||||
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
void card_extension::add_index(pb& p, unsigned index, literal lit) {
|
||||||
|
if (value(lit) == l_undef) {
|
||||||
|
m_pb_undef.push_back(index);
|
||||||
|
if (p[index].first > m_a_max) {
|
||||||
|
m_a_max = p[index].first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lbool card_extension::add_assign(pb& p, literal alit) {
|
lbool card_extension::add_assign(pb& p, literal alit) {
|
||||||
|
|
||||||
|
TRACE("sat", display(tout << "assign: " << alit << "\n", p, true););
|
||||||
|
SASSERT(!s().inconsistent());
|
||||||
unsigned sz = p.size();
|
unsigned sz = p.size();
|
||||||
unsigned bound = p.k();
|
unsigned bound = p.k();
|
||||||
unsigned num_watch = p.num_watch();
|
unsigned num_watch = p.num_watch();
|
||||||
|
@ -316,63 +330,43 @@ namespace sat {
|
||||||
SASSERT(value(alit) == l_false);
|
SASSERT(value(alit) == l_false);
|
||||||
SASSERT(p.lit() == null_literal || value(p.lit()) == l_true);
|
SASSERT(p.lit() == null_literal || value(p.lit()) == l_true);
|
||||||
SASSERT(num_watch <= sz);
|
SASSERT(num_watch <= sz);
|
||||||
|
SASSERT(num_watch > 0);
|
||||||
unsigned index = 0;
|
unsigned index = 0;
|
||||||
unsigned a_max = 0;
|
m_a_max = 0;
|
||||||
unsigned max_index = 0;
|
|
||||||
m_pb_undef.reset();
|
m_pb_undef.reset();
|
||||||
for (; index < num_watch; ++index) {
|
for (; index < num_watch; ++index) {
|
||||||
literal lit = p[index].second;
|
literal lit = p[index].second;
|
||||||
if (lit == alit) {
|
if (lit == alit) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (value(lit) == l_undef) {
|
add_index(p, index, lit);
|
||||||
m_pb_undef.push_back(index);
|
|
||||||
if (p[index].first > a_max) {
|
|
||||||
a_max = p[index].first;
|
|
||||||
max_index = index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
SASSERT(index < num_watch);
|
||||||
|
|
||||||
for (unsigned j = index + 1; a_max == 0 && j < num_watch; ++j) {
|
unsigned index1 = index + 1;
|
||||||
literal lit = p[j].second;
|
for (; m_a_max == 0 && index1 < num_watch; ++index1) {
|
||||||
if (value(lit) == l_undef) {
|
add_index(p, index1, p[index1].second);
|
||||||
m_pb_undef.push_back(j);
|
|
||||||
a_max = p[j].first;
|
|
||||||
max_index = j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (unsigned j = num_watch; a_max == 0 && j < sz; ++j) {
|
|
||||||
literal lit = p[j].second;
|
|
||||||
if (value(lit) == l_undef) {
|
|
||||||
p.swap(j, num_watch);
|
|
||||||
m_pb_undef.push_back(num_watch);
|
|
||||||
a_max = p[num_watch].first;
|
|
||||||
max_index = num_watch;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned val = p[index].first;
|
unsigned val = p[index].first;
|
||||||
SASSERT(num_watch > 0);
|
|
||||||
SASSERT(index < num_watch);
|
|
||||||
SASSERT(value(p[index].second) == l_false);
|
SASSERT(value(p[index].second) == l_false);
|
||||||
SASSERT(val <= slack);
|
SASSERT(val <= slack);
|
||||||
slack -= val;
|
slack -= val;
|
||||||
// find literals to swap with:
|
// find literals to swap with:
|
||||||
for (unsigned j = num_watch; j < sz && slack < bound + a_max; ++j) {
|
for (unsigned j = num_watch; j < sz && slack < bound + m_a_max; ++j) {
|
||||||
if (value(p[j].second) != l_false) {
|
literal lit = p[j].second;
|
||||||
|
if (value(lit) != l_false) {
|
||||||
slack += p[j].first;
|
slack += p[j].first;
|
||||||
watch_literal(p, p[j]);
|
watch_literal(p, p[j]);
|
||||||
p.swap(num_watch, j);
|
p.swap(num_watch, j);
|
||||||
if (value(p[num_watch].second) == l_undef && a_max < p[num_watch].first) {
|
add_index(p, num_watch, lit);
|
||||||
m_pb_undef.push_back(num_watch);
|
|
||||||
a_max = p[num_watch].first;
|
|
||||||
max_index = num_watch;
|
|
||||||
}
|
|
||||||
++num_watch;
|
++num_watch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SASSERT(!s().inconsistent());
|
||||||
|
DEBUG_CODE(for (auto idx : m_pb_undef) { SASSERT(value(p[idx].second) == l_undef); });
|
||||||
|
|
||||||
if (slack < bound) {
|
if (slack < bound) {
|
||||||
// maintain watching the literal
|
// maintain watching the literal
|
||||||
slack += val;
|
slack += val;
|
||||||
|
@ -385,34 +379,38 @@ namespace sat {
|
||||||
}
|
}
|
||||||
|
|
||||||
// swap out the watched literal.
|
// swap out the watched literal.
|
||||||
p.set_slack(slack);
|
|
||||||
--num_watch;
|
--num_watch;
|
||||||
SASSERT(num_watch > 0);
|
SASSERT(num_watch > 0);
|
||||||
|
p.set_slack(slack);
|
||||||
p.set_num_watch(num_watch);
|
p.set_num_watch(num_watch);
|
||||||
p.swap(num_watch, index);
|
p.swap(num_watch, index);
|
||||||
if (num_watch == max_index) {
|
|
||||||
max_index = index;
|
|
||||||
}
|
|
||||||
|
|
||||||
SASSERT(max_index < sz);
|
if (slack < bound + m_a_max) {
|
||||||
while (slack < bound + a_max && !s().inconsistent()) {
|
TRACE("sat", display(tout, p, false); for(auto j : m_pb_undef) tout << j << "\n";);
|
||||||
// variable at max-index must be assigned to true.
|
literal_vector to_assign;
|
||||||
assign(p, p[max_index].second);
|
while (!m_pb_undef.empty()) {
|
||||||
|
index1 = m_pb_undef.back();
|
||||||
a_max = 0;
|
literal lit = p[index1].second;
|
||||||
// find the next a_max among m_pb_undef
|
TRACE("sat", tout << index1 << " " << lit << "\n";);
|
||||||
while (!m_pb_undef.empty() && l_undef != value(p[m_pb_undef.back()].second)) {
|
if (slack >= bound + p[index1].first) {
|
||||||
m_pb_undef.pop_back();
|
|
||||||
}
|
|
||||||
if (m_pb_undef.empty()) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
max_index = m_pb_undef.back();
|
|
||||||
a_max = p[max_index].first;
|
|
||||||
m_pb_undef.pop_back();
|
m_pb_undef.pop_back();
|
||||||
|
to_assign.push_back(lit);
|
||||||
}
|
}
|
||||||
|
|
||||||
return s().inconsistent() ? l_false : l_true;
|
for (literal lit : to_assign) {
|
||||||
|
if (s().inconsistent()) break;
|
||||||
|
if (value(lit) == l_undef) {
|
||||||
|
assign(p, lit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TRACE("sat", display(tout << "assign: " << alit << "\n", p, true););
|
||||||
|
|
||||||
|
return l_undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
void card_extension::watch_literal(pb& p, wliteral l) {
|
void card_extension::watch_literal(pb& p, wliteral l) {
|
||||||
|
@ -467,6 +465,7 @@ namespace sat {
|
||||||
set_conflict(p, lit);
|
set_conflict(p, lit);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
SASSERT(validate_unit_propagation(p, lit));
|
||||||
m_stats.m_num_pb_propagations++;
|
m_stats.m_num_pb_propagations++;
|
||||||
m_num_propagations_since_pop++;
|
m_num_propagations_since_pop++;
|
||||||
if (s().m_config.m_drat) {
|
if (s().m_config.m_drat) {
|
||||||
|
@ -483,7 +482,8 @@ namespace sat {
|
||||||
}
|
}
|
||||||
|
|
||||||
void card_extension::display(std::ostream& out, pb const& p, bool values) const {
|
void card_extension::display(std::ostream& out, pb const& p, bool values) const {
|
||||||
out << p.lit() << "[" << p.size() << "]";
|
if (p.lit() != null_literal) out << p.lit();
|
||||||
|
out << "[watch: " << p.num_watch() << ", slack: " << p.slack() << "]";
|
||||||
if (p.lit() != null_literal && values) {
|
if (p.lit() != null_literal && values) {
|
||||||
out << "@(" << value(p.lit());
|
out << "@(" << value(p.lit());
|
||||||
if (value(p.lit()) != l_undef) {
|
if (value(p.lit()) != l_undef) {
|
||||||
|
@ -514,7 +514,7 @@ namespace sat {
|
||||||
}
|
}
|
||||||
|
|
||||||
void card_extension::asserted_pb(literal l, ptr_vector<pb>* pbs, pb* p0) {
|
void card_extension::asserted_pb(literal l, ptr_vector<pb>* pbs, pb* p0) {
|
||||||
TRACE("sat", tout << l << " " << !is_tag_empty(pbs) << " " << (p0 != 0) << "\n";);
|
TRACE("sat", tout << "literal: " << l << " has pb: " << !is_tag_empty(pbs) << " p0 != 0: " << (p0 != 0) << "\n";);
|
||||||
if (!is_tag_empty(pbs)) {
|
if (!is_tag_empty(pbs)) {
|
||||||
ptr_vector<pb>::iterator begin = pbs->begin();
|
ptr_vector<pb>::iterator begin = pbs->begin();
|
||||||
ptr_vector<pb>::iterator it = begin, it2 = it, end = pbs->end();
|
ptr_vector<pb>::iterator it = begin, it2 = it, end = pbs->end();
|
||||||
|
@ -524,20 +524,28 @@ namespace sat {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
switch (add_assign(p, ~l)) {
|
switch (add_assign(p, ~l)) {
|
||||||
case l_false: // conflict
|
|
||||||
for (; it != end; ++it, ++it2) {
|
|
||||||
*it2 = *it;
|
|
||||||
}
|
|
||||||
SASSERT(s().inconsistent());
|
|
||||||
pbs->set_end(it2);
|
|
||||||
return;
|
|
||||||
case l_true: // unit propagation, keep watching the literal
|
case l_true: // unit propagation, keep watching the literal
|
||||||
if (it2 != it) {
|
if (it2 != it) {
|
||||||
*it2 = *it;
|
*it2 = *it;
|
||||||
}
|
}
|
||||||
++it2;
|
++it2;
|
||||||
break;
|
break;
|
||||||
|
case l_false: // conflict.
|
||||||
|
SASSERT(s().inconsistent());
|
||||||
|
for (; it != end; ++it, ++it2) {
|
||||||
|
*it2 = *it;
|
||||||
|
}
|
||||||
|
pbs->set_end(it2);
|
||||||
|
return;
|
||||||
case l_undef: // watch literal was swapped
|
case l_undef: // watch literal was swapped
|
||||||
|
if (s().inconsistent()) {
|
||||||
|
++it;
|
||||||
|
for (; it != end; ++it, ++it2) {
|
||||||
|
*it2 = *it;
|
||||||
|
}
|
||||||
|
pbs->set_end(it2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -844,6 +852,7 @@ namespace sat {
|
||||||
literal consequent = s().m_not_l;
|
literal consequent = s().m_not_l;
|
||||||
justification js = s().m_conflict;
|
justification js = s().m_conflict;
|
||||||
TRACE("sat", tout << consequent << " " << js << "\n";);
|
TRACE("sat", tout << consequent << " " << js << "\n";);
|
||||||
|
TRACE("sat", s().display(tout););
|
||||||
m_conflict_lvl = s().get_max_lvl(consequent, js);
|
m_conflict_lvl = s().get_max_lvl(consequent, js);
|
||||||
if (consequent != null_literal) {
|
if (consequent != null_literal) {
|
||||||
consequent.neg();
|
consequent.neg();
|
||||||
|
@ -942,7 +951,7 @@ namespace sat {
|
||||||
m_bound += offset;
|
m_bound += offset;
|
||||||
inc_coeff(consequent, offset);
|
inc_coeff(consequent, offset);
|
||||||
get_pb_antecedents(consequent, p, m_lemma);
|
get_pb_antecedents(consequent, p, m_lemma);
|
||||||
TRACE("sat", tout << m_lemma << "\n";);
|
TRACE("sat", display(tout, p, true); tout << m_lemma << "\n";);
|
||||||
for (unsigned i = 0; i < m_lemma.size(); ++i) {
|
for (unsigned i = 0; i < m_lemma.size(); ++i) {
|
||||||
process_antecedent(~m_lemma[i], offset);
|
process_antecedent(~m_lemma[i], offset);
|
||||||
}
|
}
|
||||||
|
@ -989,6 +998,7 @@ namespace sat {
|
||||||
SASSERT(lvl(v) == m_conflict_lvl);
|
SASSERT(lvl(v) == m_conflict_lvl);
|
||||||
s().reset_mark(v);
|
s().reset_mark(v);
|
||||||
--idx;
|
--idx;
|
||||||
|
TRACE("sat", tout << "Unmark: v" << v << "\n";);
|
||||||
--m_num_marks;
|
--m_num_marks;
|
||||||
js = s().m_justification[v];
|
js = s().m_justification[v];
|
||||||
offset = get_abs_coeff(v);
|
offset = get_abs_coeff(v);
|
||||||
|
@ -1015,7 +1025,6 @@ namespace sat {
|
||||||
|
|
||||||
m_lemma.reset();
|
m_lemma.reset();
|
||||||
|
|
||||||
#if 1
|
|
||||||
m_lemma.push_back(null_literal);
|
m_lemma.push_back(null_literal);
|
||||||
for (unsigned i = 0; 0 <= slack && i < m_active_vars.size(); ++i) {
|
for (unsigned i = 0; 0 <= slack && i < m_active_vars.size(); ++i) {
|
||||||
bool_var v = m_active_vars[i];
|
bool_var v = m_active_vars[i];
|
||||||
|
@ -1038,6 +1047,7 @@ namespace sat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
if (jus.size() > 1) {
|
if (jus.size() > 1) {
|
||||||
std::cout << jus.size() << "\n";
|
std::cout << jus.size() << "\n";
|
||||||
for (unsigned i = 0; i < jus.size(); ++i) {
|
for (unsigned i = 0; i < jus.size(); ++i) {
|
||||||
|
@ -1047,6 +1057,7 @@ namespace sat {
|
||||||
active2pb(m_A);
|
active2pb(m_A);
|
||||||
display(std::cout, m_A);
|
display(std::cout, m_A);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
if (slack >= 0) {
|
if (slack >= 0) {
|
||||||
|
@ -1057,7 +1068,7 @@ namespace sat {
|
||||||
if (m_lemma[0] == null_literal) {
|
if (m_lemma[0] == null_literal) {
|
||||||
m_lemma[0] = m_lemma.back();
|
m_lemma[0] = m_lemma.back();
|
||||||
m_lemma.pop_back();
|
m_lemma.pop_back();
|
||||||
unsigned level = lvl(m_lemma[0]);
|
unsigned level = m_lemma.empty() ? 0 : lvl(m_lemma[0]);
|
||||||
for (unsigned i = 1; i < m_lemma.size(); ++i) {
|
for (unsigned i = 1; i < m_lemma.size(); ++i) {
|
||||||
if (lvl(m_lemma[i]) > level) {
|
if (lvl(m_lemma[i]) > level) {
|
||||||
level = lvl(m_lemma[i]);
|
level = lvl(m_lemma[i]);
|
||||||
|
@ -1066,37 +1077,6 @@ namespace sat {
|
||||||
}
|
}
|
||||||
IF_VERBOSE(2, verbose_stream() << "(sat.card set level to " << level << " < " << m_conflict_lvl << ")\n";);
|
IF_VERBOSE(2, verbose_stream() << "(sat.card set level to " << level << " < " << m_conflict_lvl << ")\n";);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
++idx;
|
|
||||||
while (0 <= slack) {
|
|
||||||
literal lit = lits[idx];
|
|
||||||
bool_var v = lit.var();
|
|
||||||
if (m_active_var_set.contains(v)) {
|
|
||||||
int coeff = get_coeff(v);
|
|
||||||
if (coeff < 0 && !lit.sign()) {
|
|
||||||
slack += coeff;
|
|
||||||
m_lemma.push_back(~lit);
|
|
||||||
}
|
|
||||||
else if (coeff > 0 && lit.sign()) {
|
|
||||||
slack -= coeff;
|
|
||||||
m_lemma.push_back(~lit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (idx == 0 && slack >= 0) {
|
|
||||||
IF_VERBOSE(2, verbose_stream() << "(sat.card non-asserting)\n";);
|
|
||||||
goto bail_out;
|
|
||||||
}
|
|
||||||
SASSERT(idx > 0 || slack < 0);
|
|
||||||
--idx;
|
|
||||||
}
|
|
||||||
if (m_lemma.size() >= 2 && lvl(m_lemma[1]) == m_conflict_lvl) {
|
|
||||||
// TRACE("sat", tout << "Bail out on no progress " << lit << "\n";);
|
|
||||||
IF_VERBOSE(2, verbose_stream() << "(sat.card bail non-asserting resolvent)\n";);
|
|
||||||
goto bail_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
SASSERT(slack < 0);
|
SASSERT(slack < 0);
|
||||||
|
|
||||||
|
@ -1153,6 +1133,7 @@ namespace sat {
|
||||||
|
|
||||||
if (level > 0 && !s().is_marked(v) && level == m_conflict_lvl) {
|
if (level > 0 && !s().is_marked(v) && level == m_conflict_lvl) {
|
||||||
s().mark(v);
|
s().mark(v);
|
||||||
|
TRACE("sat", tout << "Mark: v" << v << "\n";);
|
||||||
++m_num_marks;
|
++m_num_marks;
|
||||||
}
|
}
|
||||||
inc_coeff(l, offset);
|
inc_coeff(l, offset);
|
||||||
|
@ -1347,20 +1328,30 @@ namespace sat {
|
||||||
void card_extension::get_pb_antecedents(literal l, pb const& p, literal_vector& r) {
|
void card_extension::get_pb_antecedents(literal l, pb const& p, literal_vector& r) {
|
||||||
if (p.lit() != null_literal) r.push_back(p.lit());
|
if (p.lit() != null_literal) r.push_back(p.lit());
|
||||||
SASSERT(p.lit() == null_literal || value(p.lit()) == l_true);
|
SASSERT(p.lit() == null_literal || value(p.lit()) == l_true);
|
||||||
unsigned k = p.k();
|
TRACE("sat", display(tout, p, true););
|
||||||
unsigned max_sum = p.max_sum();
|
|
||||||
for (unsigned i = p.size(); i > 0 && max_sum >= k; ) {
|
// unsigned coeff = get_coeff(p, l);
|
||||||
--i;
|
unsigned coeff = 0;
|
||||||
|
for (unsigned j = 0; j < p.num_watch(); ++j) {
|
||||||
|
if (p[j].second == l) {
|
||||||
|
coeff = p[j].first;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsigned slack = p.slack() - coeff;
|
||||||
|
unsigned i = p.num_watch();
|
||||||
|
|
||||||
|
// skip entries that are not required for unit propagation.
|
||||||
|
// slack - coeff + w_head < k
|
||||||
|
unsigned h = 0;
|
||||||
|
for (; i < p.size() && p[i].first + h + slack < p.k(); ++i) {
|
||||||
|
h += p[i].first;
|
||||||
|
}
|
||||||
|
for (; i < p.size(); ++i) {
|
||||||
literal lit = p[i].second;
|
literal lit = p[i].second;
|
||||||
if (lit == l) {
|
SASSERT(l_false == value(lit));
|
||||||
max_sum -= p[i].first;
|
r.push_back(~lit);
|
||||||
}
|
}
|
||||||
else if (value(lit) == l_false) {
|
|
||||||
r.push_back(~p[i].second);
|
|
||||||
max_sum -= p[i].first;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SASSERT(max_sum < k);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void card_extension::get_card_antecedents(literal l, card const& c, literal_vector& r) {
|
void card_extension::get_card_antecedents(literal l, card const& c, literal_vector& r) {
|
||||||
|
@ -1720,7 +1711,9 @@ namespace sat {
|
||||||
std::ostream& card_extension::display_justification(std::ostream& out, ext_justification_idx idx) const {
|
std::ostream& card_extension::display_justification(std::ostream& out, ext_justification_idx idx) const {
|
||||||
if (is_card_index(idx)) {
|
if (is_card_index(idx)) {
|
||||||
card& c = index2card(idx);
|
card& c = index2card(idx);
|
||||||
out << "bound " << c.lit() << ": ";
|
out << "bound ";
|
||||||
|
if (c.lit() != null_literal) out << c.lit();
|
||||||
|
out << ": ";
|
||||||
for (unsigned i = 0; i < c.size(); ++i) {
|
for (unsigned i = 0; i < c.size(); ++i) {
|
||||||
out << c[i] << " ";
|
out << c[i] << " ";
|
||||||
}
|
}
|
||||||
|
@ -1728,14 +1721,18 @@ namespace sat {
|
||||||
}
|
}
|
||||||
else if (is_xor_index(idx)) {
|
else if (is_xor_index(idx)) {
|
||||||
xor& x = index2xor(idx);
|
xor& x = index2xor(idx);
|
||||||
out << "xor " << x.lit() << ": ";
|
out << "xor ";
|
||||||
|
if (x.lit() != null_literal) out << x.lit();
|
||||||
|
out << ": ";
|
||||||
for (unsigned i = 0; i < x.size(); ++i) {
|
for (unsigned i = 0; i < x.size(); ++i) {
|
||||||
out << x[i] << " ";
|
out << x[i] << " ";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (is_pb_index(idx)) {
|
else if (is_pb_index(idx)) {
|
||||||
pb& p = index2pb(idx);
|
pb& p = index2pb(idx);
|
||||||
out << "pb " << p.lit() << ": ";
|
out << "pb ";
|
||||||
|
if (p.lit() != null_literal) out << p.lit();
|
||||||
|
out << ": ";
|
||||||
for (unsigned i = 0; i < p.size(); ++i) {
|
for (unsigned i = 0; i < p.size(); ++i) {
|
||||||
out << p[i].first << "*" << p[i].second << " ";
|
out << p[i].first << "*" << p[i].second << " ";
|
||||||
}
|
}
|
||||||
|
@ -1776,6 +1773,21 @@ namespace sat {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
bool card_extension::validate_unit_propagation(pb const& p, literal alit) {
|
||||||
|
if (p.lit() != null_literal && value(p.lit()) != l_true) return false;
|
||||||
|
|
||||||
|
unsigned sum = 0;
|
||||||
|
TRACE("sat", display(tout << "validate: " << alit << "\n", p, true););
|
||||||
|
for (unsigned i = 0; i < p.size(); ++i) {
|
||||||
|
literal lit = p[i].second;
|
||||||
|
lbool val = value(lit);
|
||||||
|
if (val != l_false && lit != alit) {
|
||||||
|
sum += p[i].first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sum < p.k();
|
||||||
|
}
|
||||||
|
|
||||||
bool card_extension::validate_lemma() {
|
bool card_extension::validate_lemma() {
|
||||||
int val = -m_bound;
|
int val = -m_bound;
|
||||||
normalize_active_coeffs();
|
normalize_active_coeffs();
|
||||||
|
|
|
@ -232,10 +232,12 @@ namespace sat {
|
||||||
|
|
||||||
|
|
||||||
// pb functionality
|
// pb functionality
|
||||||
|
unsigned m_a_max;
|
||||||
void copy_pb(card_extension& result);
|
void copy_pb(card_extension& result);
|
||||||
void asserted_pb(literal l, ptr_vector<pb>* pbs, pb* p);
|
void asserted_pb(literal l, ptr_vector<pb>* pbs, pb* p);
|
||||||
void init_watch(pb& p, bool is_true);
|
void init_watch(pb& p, bool is_true);
|
||||||
lbool add_assign(pb& p, literal alit);
|
lbool add_assign(pb& p, literal alit);
|
||||||
|
void add_index(pb& p, unsigned index, literal lit);
|
||||||
void watch_literal(pb& p, wliteral lit);
|
void watch_literal(pb& p, wliteral lit);
|
||||||
void clear_watch(pb& p);
|
void clear_watch(pb& p);
|
||||||
void set_conflict(pb& p, literal lit);
|
void set_conflict(pb& p, literal lit);
|
||||||
|
@ -280,6 +282,7 @@ namespace sat {
|
||||||
bool validate_assign(literal_vector const& lits, literal lit);
|
bool validate_assign(literal_vector const& lits, literal lit);
|
||||||
bool validate_lemma();
|
bool validate_lemma();
|
||||||
bool validate_unit_propagation(card const& c);
|
bool validate_unit_propagation(card const& c);
|
||||||
|
bool validate_unit_propagation(pb const& p, literal lit);
|
||||||
bool validate_conflict(literal_vector const& lits, ineq& p);
|
bool validate_conflict(literal_vector const& lits, ineq& p);
|
||||||
|
|
||||||
ineq m_A, m_B, m_C;
|
ineq m_A, m_B, m_C;
|
||||||
|
|
|
@ -1938,6 +1938,8 @@ namespace sat {
|
||||||
void solver::learn_lemma_and_backjump() {
|
void solver::learn_lemma_and_backjump() {
|
||||||
TRACE("sat_lemma", tout << "new lemma size: " << m_lemma.size() << "\n" << m_lemma << "\n";);
|
TRACE("sat_lemma", tout << "new lemma size: " << m_lemma.size() << "\n" << m_lemma << "\n";);
|
||||||
|
|
||||||
|
unsigned new_scope_lvl = 0;
|
||||||
|
if (!m_lemma.empty()) {
|
||||||
if (m_config.m_minimize_lemmas) {
|
if (m_config.m_minimize_lemmas) {
|
||||||
minimize_lemma();
|
minimize_lemma();
|
||||||
reset_lemma_var_marks();
|
reset_lemma_var_marks();
|
||||||
|
@ -1950,12 +1952,12 @@ namespace sat {
|
||||||
|
|
||||||
literal_vector::iterator it = m_lemma.begin();
|
literal_vector::iterator it = m_lemma.begin();
|
||||||
literal_vector::iterator end = m_lemma.end();
|
literal_vector::iterator end = m_lemma.end();
|
||||||
unsigned new_scope_lvl = 0;
|
|
||||||
++it;
|
++it;
|
||||||
for(; it != end; ++it) {
|
for(; it != end; ++it) {
|
||||||
bool_var var = (*it).var();
|
bool_var var = (*it).var();
|
||||||
new_scope_lvl = std::max(new_scope_lvl, lvl(var));
|
new_scope_lvl = std::max(new_scope_lvl, lvl(var));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsigned glue = num_diff_levels(m_lemma.size(), m_lemma.c_ptr());
|
unsigned glue = num_diff_levels(m_lemma.size(), m_lemma.c_ptr());
|
||||||
|
|
||||||
|
@ -2390,6 +2392,7 @@ namespace sat {
|
||||||
assigned at level 0.
|
assigned at level 0.
|
||||||
*/
|
*/
|
||||||
void solver::minimize_lemma() {
|
void solver::minimize_lemma() {
|
||||||
|
SASSERT(!m_lemma.empty());
|
||||||
SASSERT(m_unmark.empty());
|
SASSERT(m_unmark.empty());
|
||||||
//m_unmark.reset();
|
//m_unmark.reset();
|
||||||
updt_lemma_lvl_set();
|
updt_lemma_lvl_set();
|
||||||
|
|
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);
|
|
@ -35,8 +35,9 @@ Revision History:
|
||||||
#include"error_codes.h"
|
#include"error_codes.h"
|
||||||
#include"gparams.h"
|
#include"gparams.h"
|
||||||
#include"env_params.h"
|
#include"env_params.h"
|
||||||
|
#include "lp_frontend.h"
|
||||||
|
|
||||||
typedef enum { IN_UNSPECIFIED, IN_SMTLIB, IN_SMTLIB_2, IN_DATALOG, IN_DIMACS, IN_WCNF, IN_OPB, IN_Z3_LOG } input_kind;
|
typedef enum { IN_UNSPECIFIED, IN_SMTLIB, IN_SMTLIB_2, IN_DATALOG, IN_DIMACS, IN_WCNF, IN_OPB, IN_Z3_LOG, IN_MPS } input_kind;
|
||||||
|
|
||||||
std::string g_aux_input_file;
|
std::string g_aux_input_file;
|
||||||
char const * g_input_file = 0;
|
char const * g_input_file = 0;
|
||||||
|
@ -342,6 +343,10 @@ int STD_CALL main(int argc, char ** argv) {
|
||||||
else if (strcmp(ext, "smt") == 0) {
|
else if (strcmp(ext, "smt") == 0) {
|
||||||
g_input_kind = IN_SMTLIB;
|
g_input_kind = IN_SMTLIB;
|
||||||
}
|
}
|
||||||
|
else if (strcmp(ext, "mps") == 0 || strcmp(ext, "sif") == 0 ||
|
||||||
|
strcmp(ext, "MPS") == 0 || strcmp(ext, "SIF") == 0) {
|
||||||
|
g_input_kind = IN_MPS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch (g_input_kind) {
|
switch (g_input_kind) {
|
||||||
|
@ -367,6 +372,9 @@ int STD_CALL main(int argc, char ** argv) {
|
||||||
case IN_Z3_LOG:
|
case IN_Z3_LOG:
|
||||||
replay_z3_log(g_input_file);
|
replay_z3_log(g_input_file);
|
||||||
break;
|
break;
|
||||||
|
case IN_MPS:
|
||||||
|
return_value = read_mps_file(g_input_file);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ Revision History:
|
||||||
#include"smt_setup.h"
|
#include"smt_setup.h"
|
||||||
#include"static_features.h"
|
#include"static_features.h"
|
||||||
#include"theory_arith.h"
|
#include"theory_arith.h"
|
||||||
|
#include"theory_lra.h"
|
||||||
#include"theory_dense_diff_logic.h"
|
#include"theory_dense_diff_logic.h"
|
||||||
#include"theory_diff_logic.h"
|
#include"theory_diff_logic.h"
|
||||||
#include"theory_utvpi.h"
|
#include"theory_utvpi.h"
|
||||||
|
@ -442,7 +443,7 @@ namespace smt {
|
||||||
m_params.m_arith_propagate_eqs = false;
|
m_params.m_arith_propagate_eqs = false;
|
||||||
m_params.m_eliminate_term_ite = true;
|
m_params.m_eliminate_term_ite = true;
|
||||||
m_params.m_nnf_cnf = false;
|
m_params.m_nnf_cnf = false;
|
||||||
setup_mi_arith();
|
setup_r_arith();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup::setup_QF_LRA(static_features const & st) {
|
void setup::setup_QF_LRA(static_features const & st) {
|
||||||
|
@ -467,6 +468,10 @@ namespace smt {
|
||||||
m_params.m_restart_adaptive = false;
|
m_params.m_restart_adaptive = false;
|
||||||
}
|
}
|
||||||
m_params.m_arith_small_lemma_size = 32;
|
m_params.m_arith_small_lemma_size = 32;
|
||||||
|
setup_r_arith();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup::setup_QF_LIRA(static_features const& st) {
|
||||||
setup_mi_arith();
|
setup_mi_arith();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -539,7 +544,7 @@ namespace smt {
|
||||||
m_params.m_relevancy_lvl = 0;
|
m_params.m_relevancy_lvl = 0;
|
||||||
m_params.m_arith_reflect = false;
|
m_params.m_arith_reflect = false;
|
||||||
m_params.m_nnf_cnf = false;
|
m_params.m_nnf_cnf = false;
|
||||||
setup_mi_arith();
|
setup_r_arith();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup::setup_QF_BV() {
|
void setup::setup_QF_BV() {
|
||||||
|
@ -718,6 +723,12 @@ namespace smt {
|
||||||
m_context.register_plugin(alloc(smt::theory_i_arith, m_manager, m_params));
|
m_context.register_plugin(alloc(smt::theory_i_arith, m_manager, m_params));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setup::setup_r_arith() {
|
||||||
|
// 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() {
|
void setup::setup_mi_arith() {
|
||||||
if (m_params.m_arith_mode == AS_OPTINF) {
|
if (m_params.m_arith_mode == AS_OPTINF) {
|
||||||
m_context.register_plugin(alloc(smt::theory_inf_arith, m_manager, m_params));
|
m_context.register_plugin(alloc(smt::theory_inf_arith, m_manager, m_params));
|
||||||
|
@ -929,7 +940,9 @@ namespace smt {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (st.num_theories() == 1 && is_arith(st)) {
|
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);
|
setup_QF_LRA(st);
|
||||||
else
|
else
|
||||||
setup_QF_LIA(st);
|
setup_QF_LIA(st);
|
||||||
|
|
|
@ -65,6 +65,7 @@ namespace smt {
|
||||||
void setup_QF_LRA();
|
void setup_QF_LRA();
|
||||||
void setup_QF_LRA(static_features const & st);
|
void setup_QF_LRA(static_features const & st);
|
||||||
void setup_QF_LIA();
|
void setup_QF_LIA();
|
||||||
|
void setup_QF_LIRA(static_features const& st);
|
||||||
void setup_QF_LIA(static_features const & st);
|
void setup_QF_LIA(static_features const & st);
|
||||||
void setup_QF_UFLIA();
|
void setup_QF_UFLIA();
|
||||||
void setup_QF_UFLIA(static_features & st);
|
void setup_QF_UFLIA(static_features & st);
|
||||||
|
@ -99,6 +100,7 @@ namespace smt {
|
||||||
void setup_card();
|
void setup_card();
|
||||||
void setup_i_arith();
|
void setup_i_arith();
|
||||||
void setup_mi_arith();
|
void setup_mi_arith();
|
||||||
|
void setup_r_arith();
|
||||||
void setup_fpa();
|
void setup_fpa();
|
||||||
void setup_str();
|
void setup_str();
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ namespace smt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void theory::display_app(std::ostream & out, app * n) const {
|
std::ostream& theory::display_app(std::ostream & out, app * n) const {
|
||||||
func_decl * d = n->get_decl();
|
func_decl * d = n->get_decl();
|
||||||
if (n->get_num_args() == 0) {
|
if (n->get_num_args() == 0) {
|
||||||
out << d->get_name();
|
out << d->get_name();
|
||||||
|
@ -73,9 +73,10 @@ namespace smt {
|
||||||
else {
|
else {
|
||||||
out << "#" << n->get_id();
|
out << "#" << n->get_id();
|
||||||
}
|
}
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
void theory::display_flat_app(std::ostream & out, app * n) const {
|
std::ostream& theory::display_flat_app(std::ostream & out, app * n) const {
|
||||||
func_decl * d = n->get_decl();
|
func_decl * d = n->get_decl();
|
||||||
if (n->get_num_args() == 0) {
|
if (n->get_num_args() == 0) {
|
||||||
out << d->get_name();
|
out << d->get_name();
|
||||||
|
@ -106,6 +107,7 @@ namespace smt {
|
||||||
else {
|
else {
|
||||||
out << "#" << n->get_id();
|
out << "#" << n->get_id();
|
||||||
}
|
}
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool theory::is_relevant_and_shared(enode * n) const {
|
bool theory::is_relevant_and_shared(enode * n) const {
|
||||||
|
|
|
@ -338,13 +338,13 @@ namespace smt {
|
||||||
virtual void collect_statistics(::statistics & st) const {
|
virtual void collect_statistics(::statistics & st) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void display_app(std::ostream & out, app * n) const;
|
std::ostream& display_app(std::ostream & out, app * n) const;
|
||||||
|
|
||||||
void display_flat_app(std::ostream & out, app * n) const;
|
std::ostream& display_flat_app(std::ostream & out, app * n) const;
|
||||||
|
|
||||||
void display_var_def(std::ostream & out, theory_var v) const { return display_app(out, get_enode(v)->get_owner()); }
|
std::ostream& display_var_def(std::ostream & out, theory_var v) const { return display_app(out, get_enode(v)->get_owner()); }
|
||||||
|
|
||||||
void display_var_flat_def(std::ostream & out, theory_var v) const { return display_flat_app(out, get_enode(v)->get_owner()); }
|
std::ostream& display_var_flat_def(std::ostream & out, theory_var v) const { return display_flat_app(out, get_enode(v)->get_owner()); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Assume eqs between variable that are equal with respect to the given table.
|
\brief Assume eqs between variable that are equal with respect to the given table.
|
||||||
|
|
|
@ -21,6 +21,7 @@ Notes:
|
||||||
#include"smt_kernel.h"
|
#include"smt_kernel.h"
|
||||||
#include"smt_params.h"
|
#include"smt_params.h"
|
||||||
#include"smt_params_helper.hpp"
|
#include"smt_params_helper.hpp"
|
||||||
|
#include"lp_params.hpp"
|
||||||
#include"rewriter_types.h"
|
#include"rewriter_types.h"
|
||||||
#include"filter_model_converter.h"
|
#include"filter_model_converter.h"
|
||||||
#include"ast_util.h"
|
#include"ast_util.h"
|
||||||
|
@ -64,6 +65,10 @@ public:
|
||||||
return m_params;
|
return m_params;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
params_ref & params() {
|
||||||
|
return m_params_ref;
|
||||||
|
}
|
||||||
|
|
||||||
void updt_params_core(params_ref const & p) {
|
void updt_params_core(params_ref const & p) {
|
||||||
m_candidate_models = p.get_bool("candidate_models", false);
|
m_candidate_models = p.get_bool("candidate_models", false);
|
||||||
m_fail_if_inconclusive = p.get_bool("fail_if_inconclusive", true);
|
m_fail_if_inconclusive = p.get_bool("fail_if_inconclusive", true);
|
||||||
|
@ -73,6 +78,7 @@ public:
|
||||||
TRACE("smt_tactic", tout << "updt_params: " << p << "\n";);
|
TRACE("smt_tactic", tout << "updt_params: " << p << "\n";);
|
||||||
updt_params_core(p);
|
updt_params_core(p);
|
||||||
fparams().updt_params(p);
|
fparams().updt_params(p);
|
||||||
|
m_params_ref.copy(p);
|
||||||
m_logic = p.get_sym(symbol("logic"), m_logic);
|
m_logic = p.get_sym(symbol("logic"), m_logic);
|
||||||
if (m_logic != symbol::null && m_ctx) {
|
if (m_logic != symbol::null && m_ctx) {
|
||||||
m_ctx->set_logic(m_logic);
|
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("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.");
|
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);
|
smt_params_helper::collect_param_descrs(r);
|
||||||
|
lp_params::collect_param_descrs(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -112,10 +119,12 @@ public:
|
||||||
struct scoped_init_ctx {
|
struct scoped_init_ctx {
|
||||||
smt_tactic & m_owner;
|
smt_tactic & m_owner;
|
||||||
smt_params m_params; // smt-setup overwrites parameters depending on the current assertions.
|
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) {
|
scoped_init_ctx(smt_tactic & o, ast_manager & m):m_owner(o) {
|
||||||
m_params = o.fparams();
|
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";);
|
TRACE("smt_tactic", tout << "logic: " << o.m_logic << "\n";);
|
||||||
new_ctx->set_logic(o.m_logic);
|
new_ctx->set_logic(o.m_logic);
|
||||||
if (o.m_callback) {
|
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();
|
return m_new_propagation || ctx.inconsistent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void theory_seq::internalize_eq_eh(app * atom, bool_var v) {}
|
||||||
|
|
||||||
|
|
||||||
bool theory_seq::internalize_term(app* term) {
|
bool theory_seq::internalize_term(app* term) {
|
||||||
context & ctx = get_context();
|
context & ctx = get_context();
|
||||||
|
|
|
@ -343,7 +343,7 @@ namespace smt {
|
||||||
virtual final_check_status final_check_eh();
|
virtual final_check_status final_check_eh();
|
||||||
virtual bool internalize_atom(app* atom, bool) { return internalize_term(atom); }
|
virtual bool internalize_atom(app* atom, bool) { return internalize_term(atom); }
|
||||||
virtual bool internalize_term(app*);
|
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_eq_eh(theory_var, theory_var);
|
||||||
virtual void new_diseq_eh(theory_var, theory_var);
|
virtual void new_diseq_eh(theory_var, theory_var);
|
||||||
virtual void assign_eh(bool_var v, bool is_true);
|
virtual void assign_eh(bool_var v, bool is_true);
|
||||||
|
|
|
@ -60,6 +60,7 @@ namespace smt {
|
||||||
totalCacheAccessCount(0),
|
totalCacheAccessCount(0),
|
||||||
cacheHitCount(0),
|
cacheHitCount(0),
|
||||||
cacheMissCount(0),
|
cacheMissCount(0),
|
||||||
|
m_fresh_id(0),
|
||||||
m_find(*this),
|
m_find(*this),
|
||||||
m_trail_stack(*this)
|
m_trail_stack(*this)
|
||||||
{
|
{
|
||||||
|
@ -441,7 +442,12 @@ namespace smt {
|
||||||
}
|
}
|
||||||
|
|
||||||
app * theory_str::mk_fresh_const(char const* name, sort* s) {
|
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++) {
|
for (; arg1_grdItor != groundedMap[arg1DeAlias].end(); arg1_grdItor++) {
|
||||||
std::vector<expr*> ndVec;
|
std::vector<expr*> ndVec;
|
||||||
ndVec.insert(ndVec.end(), arg0_grdItor->first.begin(), arg0_grdItor->first.end());
|
ndVec.insert(ndVec.end(), arg0_grdItor->first.begin(), arg0_grdItor->first.end());
|
||||||
int arg0VecSize = arg0_grdItor->first.size();
|
size_t arg0VecSize = arg0_grdItor->first.size();
|
||||||
int arg1VecSize = arg1_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])) {
|
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.pop_back();
|
||||||
ndVec.push_back(mk_concat(arg0_grdItor->first[arg0VecSize - 1], arg1_grdItor->first[0]));
|
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) {
|
bool theory_str::is_partial_in_grounded_concat(const std::vector<expr*> & strVec, const std::vector<expr*> & subStrVec) {
|
||||||
int strCnt = strVec.size();
|
size_t strCnt = strVec.size();
|
||||||
int subStrCnt = subStrVec.size();
|
size_t subStrCnt = subStrVec.size();
|
||||||
|
|
||||||
if (strCnt == 0 || subStrCnt == 0) {
|
if (strCnt == 0 || subStrCnt == 0) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -5717,7 +5723,7 @@ namespace smt {
|
||||||
}
|
}
|
||||||
|
|
||||||
// tail nodes
|
// tail nodes
|
||||||
int tailIdx = i + subStrCnt - 1;
|
size_t tailIdx = i + subStrCnt - 1;
|
||||||
zstring subStrTailVal;
|
zstring subStrTailVal;
|
||||||
if (u.str.is_string(subStrVec[subStrCnt - 1], subStrTailVal)) {
|
if (u.str.is_string(subStrVec[subStrCnt - 1], subStrTailVal)) {
|
||||||
zstring strTailVal;
|
zstring strTailVal;
|
||||||
|
@ -5908,8 +5914,14 @@ namespace smt {
|
||||||
app * n2_curr = to_app(n2);
|
app * n2_curr = to_app(n2);
|
||||||
|
|
||||||
// case 0: n1_curr is const string, n2_curr is const string
|
// 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)) {
|
zstring n1_curr_str, n2_curr_str;
|
||||||
if (n1_curr != n2_curr) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6864,7 +6876,7 @@ namespace smt {
|
||||||
// easiest case. we will search within these bounds
|
// easiest case. we will search within these bounds
|
||||||
} else if (upper_bound_exists && !lower_bound_exists) {
|
} else if (upper_bound_exists && !lower_bound_exists) {
|
||||||
// search between 0 and the upper bound
|
// 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) {
|
} else if (lower_bound_exists && !upper_bound_exists) {
|
||||||
// check some finite portion of the search space
|
// check some finite portion of the search space
|
||||||
v_upper_bound = v_lower_bound + rational(10);
|
v_upper_bound = v_lower_bound + rational(10);
|
||||||
|
@ -8251,7 +8263,7 @@ namespace smt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (lId == -1)
|
if (lId == -1)
|
||||||
lId = mLMap.size();
|
lId = static_cast<int>(mLMap.size());
|
||||||
for (std::set<expr*>::iterator itor2 = nSet.begin(); itor2 != nSet.end(); itor2++) {
|
for (std::set<expr*>::iterator itor2 = nSet.begin(); itor2 != nSet.end(); itor2++) {
|
||||||
bool itorHasEqcValue = false;
|
bool itorHasEqcValue = false;
|
||||||
get_eqc_value(*itor2, itorHasEqcValue);
|
get_eqc_value(*itor2, itorHasEqcValue);
|
||||||
|
@ -8290,7 +8302,7 @@ namespace smt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (rId == -1)
|
if (rId == -1)
|
||||||
rId = mRMap.size();
|
rId = static_cast<int>(mRMap.size());
|
||||||
for (itor2 = nSet.begin(); itor2 != nSet.end(); itor2++) {
|
for (itor2 = nSet.begin(); itor2 != nSet.end(); itor2++) {
|
||||||
bool rHasEqcValue = false;
|
bool rHasEqcValue = false;
|
||||||
get_eqc_value(*itor2, rHasEqcValue);
|
get_eqc_value(*itor2, rHasEqcValue);
|
||||||
|
@ -9182,7 +9194,7 @@ namespace smt {
|
||||||
// ----------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------
|
||||||
int len = atoi(lenStr.encode().c_str());
|
int len = atoi(lenStr.encode().c_str());
|
||||||
bool coverAll = false;
|
bool coverAll = false;
|
||||||
svector<int_vector> options;
|
vector<int_vector, true, long long> options;
|
||||||
int_vector base;
|
int_vector base;
|
||||||
|
|
||||||
TRACE("str", tout
|
TRACE("str", tout
|
||||||
|
@ -9234,9 +9246,9 @@ namespace smt {
|
||||||
for (long long i = l; i < h; i++) {
|
for (long long i = l; i < h; i++) {
|
||||||
orList.push_back(m.mk_eq(val_indicator, mk_string(longlong_to_string(i).c_str()) ));
|
orList.push_back(m.mk_eq(val_indicator, mk_string(longlong_to_string(i).c_str()) ));
|
||||||
if (m_params.m_AggressiveValueTesting) {
|
if (m_params.m_AggressiveValueTesting) {
|
||||||
literal l = mk_eq(val_indicator, mk_string(longlong_to_string(i).c_str()), false);
|
literal lit = mk_eq(val_indicator, mk_string(longlong_to_string(i).c_str()), false);
|
||||||
ctx.mark_as_relevant(l);
|
ctx.mark_as_relevant(lit);
|
||||||
ctx.force_phase(l);
|
ctx.force_phase(lit);
|
||||||
}
|
}
|
||||||
|
|
||||||
zstring aStr = gen_val_string(len, options[i - l]);
|
zstring aStr = gen_val_string(len, options[i - l]);
|
||||||
|
@ -10059,7 +10071,7 @@ namespace smt {
|
||||||
}
|
}
|
||||||
TRACE("str", tout << "last bounds are [" << lastBounds.lowerBound << " | " << lastBounds.midPoint << " | " << lastBounds.upperBound << "]!" << lastBounds.windowSize << std::endl;);
|
TRACE("str", tout << "last bounds are [" << lastBounds.lowerBound << " | " << lastBounds.midPoint << " | " << lastBounds.upperBound << "]!" << lastBounds.windowSize << std::endl;);
|
||||||
binary_search_info newBounds;
|
binary_search_info newBounds;
|
||||||
expr * newTester;
|
expr * newTester = 0;
|
||||||
if (lastTesterConstant == "more") {
|
if (lastTesterConstant == "more") {
|
||||||
// special case: if the midpoint, upper bound, and window size are all equal,
|
// special case: if the midpoint, upper bound, and window size are all equal,
|
||||||
// we double the window size and adjust the bounds
|
// we double the window size and adjust the bounds
|
||||||
|
|
|
@ -350,6 +350,8 @@ protected:
|
||||||
unsigned long cacheHitCount;
|
unsigned long cacheHitCount;
|
||||||
unsigned long cacheMissCount;
|
unsigned long cacheMissCount;
|
||||||
|
|
||||||
|
unsigned m_fresh_id;
|
||||||
|
|
||||||
// cache mapping each string S to Length(S)
|
// cache mapping each string S to Length(S)
|
||||||
obj_map<expr, app*> length_ast_map;
|
obj_map<expr, app*> length_ast_map;
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ Notes:
|
||||||
#include "solver_na2as.h"
|
#include "solver_na2as.h"
|
||||||
#include "tactic.h"
|
#include "tactic.h"
|
||||||
#include "pb2bv_rewriter.h"
|
#include "pb2bv_rewriter.h"
|
||||||
|
#include "th_rewriter.h"
|
||||||
#include "filter_model_converter.h"
|
#include "filter_model_converter.h"
|
||||||
#include "ast_pp.h"
|
#include "ast_pp.h"
|
||||||
#include "model_smt2_pp.h"
|
#include "model_smt2_pp.h"
|
||||||
|
@ -29,6 +30,7 @@ class pb2bv_solver : public solver_na2as {
|
||||||
params_ref m_params;
|
params_ref m_params;
|
||||||
mutable expr_ref_vector m_assertions;
|
mutable expr_ref_vector m_assertions;
|
||||||
mutable ref<solver> m_solver;
|
mutable ref<solver> m_solver;
|
||||||
|
mutable th_rewriter m_th_rewriter;
|
||||||
mutable pb2bv_rewriter m_rewriter;
|
mutable pb2bv_rewriter m_rewriter;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -39,6 +41,7 @@ public:
|
||||||
m_params(p),
|
m_params(p),
|
||||||
m_assertions(m),
|
m_assertions(m),
|
||||||
m_solver(s),
|
m_solver(s),
|
||||||
|
m_th_rewriter(m, p),
|
||||||
m_rewriter(m, p)
|
m_rewriter(m, p)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -121,10 +124,11 @@ public:
|
||||||
private:
|
private:
|
||||||
void flush_assertions() const {
|
void flush_assertions() const {
|
||||||
proof_ref proof(m);
|
proof_ref proof(m);
|
||||||
expr_ref fml(m);
|
expr_ref fml1(m), fml(m);
|
||||||
expr_ref_vector fmls(m);
|
expr_ref_vector fmls(m);
|
||||||
for (unsigned i = 0; i < m_assertions.size(); ++i) {
|
for (unsigned i = 0; i < m_assertions.size(); ++i) {
|
||||||
m_rewriter(m_assertions[i].get(), fml, proof);
|
m_th_rewriter(m_assertions[i].get(), fml1, proof);
|
||||||
|
m_rewriter(fml1, fml, proof);
|
||||||
m_solver->assert_expr(fml);
|
m_solver->assert_expr(fml);
|
||||||
}
|
}
|
||||||
m_rewriter.flush_side_constraints(fmls);
|
m_rewriter.flush_side_constraints(fmls);
|
||||||
|
|
|
@ -22,7 +22,6 @@ Notes:
|
||||||
#include"solve_eqs_tactic.h"
|
#include"solve_eqs_tactic.h"
|
||||||
#include"elim_uncnstr_tactic.h"
|
#include"elim_uncnstr_tactic.h"
|
||||||
#include"smt_tactic.h"
|
#include"smt_tactic.h"
|
||||||
// include"mip_tactic.h"
|
|
||||||
#include"recover_01_tactic.h"
|
#include"recover_01_tactic.h"
|
||||||
#include"ctx_simplify_tactic.h"
|
#include"ctx_simplify_tactic.h"
|
||||||
#include"probe_arith.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)),
|
// using_params(mk_smt_tactic(), pivot_p)),
|
||||||
// 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);
|
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
|
@ -240,6 +240,7 @@ int main(int argc, char ** argv) {
|
||||||
TST(pdr);
|
TST(pdr);
|
||||||
TST_ARGV(ddnf);
|
TST_ARGV(ddnf);
|
||||||
TST(model_evaluator);
|
TST(model_evaluator);
|
||||||
|
TST_ARGV(lp);
|
||||||
TST(get_consequences);
|
TST(get_consequences);
|
||||||
TST(pb2bv);
|
TST(pb2bv);
|
||||||
TST_ARGV(sat_lookahead);
|
TST_ARGV(sat_lookahead);
|
||||||
|
|
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;
|
Z3_fallthrough;
|
||||||
case 1 :
|
case 1 :
|
||||||
a+=str[0];
|
a+=str[0];
|
||||||
Z3_fallthrough;
|
|
||||||
/* case 0: nothing left to add */
|
/* case 0: nothing left to add */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
mix(a,b,c);
|
mix(a,b,c);
|
||||||
/*-------------------------------------------- report the result */
|
/*-------------------------------------------- report the result */
|
||||||
|
|
70
src/util/lp/binary_heap_priority_queue.h
Normal file
70
src/util/lp/binary_heap_priority_queue.h
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include "util/vector.h"
|
||||||
|
#include "util/debug.h"
|
||||||
|
#include "util/lp/lp_utils.h"
|
||||||
|
namespace lean {
|
||||||
|
// the elements with the smallest priority are dequeued first
|
||||||
|
template <typename T>
|
||||||
|
class binary_heap_priority_queue {
|
||||||
|
vector<T> m_priorities;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
// is is the child place in heap
|
||||||
|
void swap_with_parent(unsigned i);
|
||||||
|
void put_at(unsigned i, unsigned h);
|
||||||
|
void decrease_priority(unsigned o, T newPriority);
|
||||||
|
public:
|
||||||
|
#ifdef LEAN_DEBUG
|
||||||
|
bool is_consistent() const;
|
||||||
|
#endif
|
||||||
|
public:
|
||||||
|
void remove(unsigned o);
|
||||||
|
unsigned size() const { return m_heap_size; }
|
||||||
|
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);
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
for (unsigned i = 0; i < m_heap_size; i++) {
|
||||||
|
unsigned o = m_heap[i+1];
|
||||||
|
m_heap_inverse[o] = -1;
|
||||||
|
}
|
||||||
|
m_heap_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resize(unsigned n);
|
||||||
|
void put_to_heap(unsigned i, unsigned o);
|
||||||
|
|
||||||
|
void enqueue_new(unsigned o, const T& priority);
|
||||||
|
|
||||||
|
// This method can work with an element that is already in the queue.
|
||||||
|
// In this case the priority will be changed and the queue adjusted.
|
||||||
|
void enqueue(unsigned o, const T & priority);
|
||||||
|
void change_priority_for_existing(unsigned o, const T & priority);
|
||||||
|
T get_priority(unsigned o) const { return m_priorities[o]; }
|
||||||
|
bool is_empty() const { return m_heap_size == 0; }
|
||||||
|
|
||||||
|
/// return the first element of the queue and removes it from the queue
|
||||||
|
unsigned dequeue_and_get_priority(T & priority);
|
||||||
|
void fix_heap_under(unsigned i);
|
||||||
|
void put_the_last_at_the_top_and_fix_the_heap();
|
||||||
|
/// return the first element of the queue and removes it from the queue
|
||||||
|
unsigned dequeue();
|
||||||
|
unsigned peek() const {
|
||||||
|
lean_assert(m_heap_size > 0);
|
||||||
|
return m_heap[1];
|
||||||
|
}
|
||||||
|
#ifdef LEAN_DEBUG
|
||||||
|
void print(std::ostream & out);
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
}
|
194
src/util/lp/binary_heap_priority_queue.hpp
Normal file
194
src/util/lp/binary_heap_priority_queue.hpp
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#include "util/vector.h"
|
||||||
|
#include "util/lp/binary_heap_priority_queue.h"
|
||||||
|
namespace lean {
|
||||||
|
// is is the child place in heap
|
||||||
|
template <typename T> void binary_heap_priority_queue<T>::swap_with_parent(unsigned i) {
|
||||||
|
unsigned parent = m_heap[i >> 1];
|
||||||
|
put_at(i >> 1, m_heap[i]);
|
||||||
|
put_at(i, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void binary_heap_priority_queue<T>::put_at(unsigned i, unsigned h) {
|
||||||
|
m_heap[i] = h;
|
||||||
|
m_heap_inverse[h] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void binary_heap_priority_queue<T>::decrease_priority(unsigned o, T newPriority) {
|
||||||
|
m_priorities[o] = newPriority;
|
||||||
|
int i = m_heap_inverse[o];
|
||||||
|
while (i > 1) {
|
||||||
|
if (m_priorities[m_heap[i]] < m_priorities[m_heap[i >> 1]])
|
||||||
|
swap_with_parent(i);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
i >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LEAN_DEBUG
|
||||||
|
template <typename T> bool binary_heap_priority_queue<T>::is_consistent() const {
|
||||||
|
for (int i = 0; i < m_heap_inverse.size(); i++) {
|
||||||
|
int i_index = m_heap_inverse[i];
|
||||||
|
lean_assert(i_index <= static_cast<int>(m_heap_size));
|
||||||
|
lean_assert(i_index == -1 || m_heap[i_index] == i);
|
||||||
|
}
|
||||||
|
for (unsigned i = 1; i < m_heap_size; i++) {
|
||||||
|
unsigned ch = i << 1;
|
||||||
|
for (int k = 0; k < 2; k++) {
|
||||||
|
if (ch > m_heap_size) break;
|
||||||
|
if (!(m_priorities[m_heap[i]] <= m_priorities[m_heap[ch]])){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ch++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
template <typename T> void binary_heap_priority_queue<T>::remove(unsigned o) {
|
||||||
|
T priority_of_o = m_priorities[o];
|
||||||
|
int o_in_heap = m_heap_inverse[o];
|
||||||
|
if (o_in_heap == -1) {
|
||||||
|
return; // nothing to do
|
||||||
|
}
|
||||||
|
lean_assert(static_cast<unsigned>(o_in_heap) <= m_heap_size);
|
||||||
|
if (static_cast<unsigned>(o_in_heap) < m_heap_size) {
|
||||||
|
put_at(o_in_heap, m_heap[m_heap_size--]);
|
||||||
|
if (m_priorities[m_heap[o_in_heap]] > priority_of_o) {
|
||||||
|
fix_heap_under(o_in_heap);
|
||||||
|
} else { // we need to propogate the m_heap[o_in_heap] up
|
||||||
|
unsigned i = o_in_heap;
|
||||||
|
while (i > 1) {
|
||||||
|
unsigned ip = i >> 1;
|
||||||
|
if (m_priorities[m_heap[i]] < m_priorities[m_heap[ip]])
|
||||||
|
swap_with_parent(i);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
i = ip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lean_assert(static_cast<unsigned>(o_in_heap) == m_heap_size);
|
||||||
|
m_heap_size--;
|
||||||
|
}
|
||||||
|
m_heap_inverse[o] = -1;
|
||||||
|
// lean_assert(is_consistent());
|
||||||
|
}
|
||||||
|
// n is the initial queue capacity.
|
||||||
|
// The capacity will be enlarged two times automatically if needed
|
||||||
|
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_size(0)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T> void binary_heap_priority_queue<T>::resize(unsigned n) {
|
||||||
|
m_priorities.resize(n);
|
||||||
|
m_heap.resize(n + 1);
|
||||||
|
m_heap_inverse.resize(n, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void binary_heap_priority_queue<T>::put_to_heap(unsigned i, unsigned o) {
|
||||||
|
m_heap[i] = o;
|
||||||
|
m_heap_inverse[o] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void binary_heap_priority_queue<T>::enqueue_new(unsigned o, const T& priority) {
|
||||||
|
m_heap_size++;
|
||||||
|
int i = m_heap_size;
|
||||||
|
lean_assert(o < m_priorities.size());
|
||||||
|
m_priorities[o] = priority;
|
||||||
|
put_at(i, o);
|
||||||
|
while (i > 1 && m_priorities[m_heap[i >> 1]] > priority) {
|
||||||
|
swap_with_parent(i);
|
||||||
|
i >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// This method can work with an element that is already in the queue.
|
||||||
|
// In this case the priority will be changed and the queue adjusted.
|
||||||
|
template <typename T> void binary_heap_priority_queue<T>::enqueue(unsigned o, const T & priority) {
|
||||||
|
if (o >= m_priorities.size()) {
|
||||||
|
resize(o << 1); // make the size twice larger
|
||||||
|
}
|
||||||
|
if (m_heap_inverse[o] == -1)
|
||||||
|
enqueue_new(o, priority);
|
||||||
|
else
|
||||||
|
change_priority_for_existing(o, priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void binary_heap_priority_queue<T>::change_priority_for_existing(unsigned o, const T & priority) {
|
||||||
|
if (m_priorities[o] > priority) {
|
||||||
|
decrease_priority(o, priority);
|
||||||
|
} else {
|
||||||
|
m_priorities[o] = priority;
|
||||||
|
fix_heap_under(m_heap_inverse[o]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// return the first element of the queue and removes it from the queue
|
||||||
|
template <typename T> unsigned binary_heap_priority_queue<T>::dequeue_and_get_priority(T & priority) {
|
||||||
|
lean_assert(m_heap_size != 0);
|
||||||
|
int ret = m_heap[1];
|
||||||
|
priority = m_priorities[ret];
|
||||||
|
put_the_last_at_the_top_and_fix_the_heap();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void binary_heap_priority_queue<T>::fix_heap_under(unsigned i) {
|
||||||
|
while (true) {
|
||||||
|
unsigned smallest = i;
|
||||||
|
unsigned l = i << 1;
|
||||||
|
if (l <= m_heap_size && m_priorities[m_heap[l]] < m_priorities[m_heap[i]])
|
||||||
|
smallest = l;
|
||||||
|
unsigned r = l + 1;
|
||||||
|
if (r <= m_heap_size && m_priorities[m_heap[r]] < m_priorities[m_heap[smallest]])
|
||||||
|
smallest = r;
|
||||||
|
if (smallest != i)
|
||||||
|
swap_with_parent(smallest);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
i = smallest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void binary_heap_priority_queue<T>::put_the_last_at_the_top_and_fix_the_heap() {
|
||||||
|
if (m_heap_size > 1) {
|
||||||
|
put_at(1, m_heap[m_heap_size--]);
|
||||||
|
fix_heap_under(1);
|
||||||
|
} else {
|
||||||
|
m_heap_size--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// return the first element of the queue and removes it from the queue
|
||||||
|
template <typename T> unsigned binary_heap_priority_queue<T>::dequeue() {
|
||||||
|
lean_assert(m_heap_size > 0);
|
||||||
|
int ret = m_heap[1];
|
||||||
|
put_the_last_at_the_top_and_fix_the_heap();
|
||||||
|
m_heap_inverse[ret] = -1;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#ifdef LEAN_DEBUG
|
||||||
|
template <typename T> void binary_heap_priority_queue<T>::print(std::ostream & out) {
|
||||||
|
vector<int> index;
|
||||||
|
vector<T> prs;
|
||||||
|
while (size()) {
|
||||||
|
T prior;
|
||||||
|
int j = dequeue_and_get_priority(prior);
|
||||||
|
index.push_back(j);
|
||||||
|
prs.push_back(prior);
|
||||||
|
out << "(" << j << ", " << prior << ")";
|
||||||
|
}
|
||||||
|
out << std::endl;
|
||||||
|
// restore the queue
|
||||||
|
for (int i = 0; i < index.size(); i++)
|
||||||
|
enqueue(index[i], prs[i]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
26
src/util/lp/binary_heap_priority_queue_instances.cpp
Normal file
26
src/util/lp/binary_heap_priority_queue_instances.cpp
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#include "util/lp/numeric_pair.h"
|
||||||
|
#include "util/lp/binary_heap_priority_queue.hpp"
|
||||||
|
namespace lean {
|
||||||
|
template binary_heap_priority_queue<int>::binary_heap_priority_queue(unsigned int);
|
||||||
|
template unsigned binary_heap_priority_queue<int>::dequeue();
|
||||||
|
template void binary_heap_priority_queue<int>::enqueue(unsigned int, int const&);
|
||||||
|
template void binary_heap_priority_queue<double>::enqueue(unsigned int, double const&);
|
||||||
|
template void binary_heap_priority_queue<mpq>::enqueue(unsigned int, mpq const&);
|
||||||
|
template void binary_heap_priority_queue<int>::remove(unsigned int);
|
||||||
|
template unsigned binary_heap_priority_queue<numeric_pair<mpq> >::dequeue();
|
||||||
|
template unsigned binary_heap_priority_queue<double>::dequeue();
|
||||||
|
template unsigned binary_heap_priority_queue<mpq>::dequeue();
|
||||||
|
template void binary_heap_priority_queue<numeric_pair<mpq> >::enqueue(unsigned int, numeric_pair<mpq> const&);
|
||||||
|
template void binary_heap_priority_queue<numeric_pair<mpq> >::resize(unsigned int);
|
||||||
|
template void lean::binary_heap_priority_queue<double>::resize(unsigned int);
|
||||||
|
template binary_heap_priority_queue<unsigned int>::binary_heap_priority_queue(unsigned int);
|
||||||
|
template void binary_heap_priority_queue<unsigned>::resize(unsigned int);
|
||||||
|
template unsigned binary_heap_priority_queue<unsigned int>::dequeue();
|
||||||
|
template void binary_heap_priority_queue<unsigned int>::enqueue(unsigned int, unsigned int const&);
|
||||||
|
template void binary_heap_priority_queue<unsigned int>::remove(unsigned int);
|
||||||
|
template void lean::binary_heap_priority_queue<mpq>::resize(unsigned int);
|
||||||
|
}
|
50
src/util/lp/binary_heap_upair_queue.h
Normal file
50
src/util/lp/binary_heap_upair_queue.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <queue>
|
||||||
|
#include "util/vector.h"
|
||||||
|
#include <set>
|
||||||
|
#include <utility>
|
||||||
|
#include "util/lp/binary_heap_priority_queue.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef std::pair<unsigned, unsigned> upair;
|
||||||
|
|
||||||
|
namespace lean {
|
||||||
|
template <typename T>
|
||||||
|
class binary_heap_upair_queue {
|
||||||
|
binary_heap_priority_queue<T> m_q;
|
||||||
|
std::unordered_map<upair, unsigned> m_pairs_to_index;
|
||||||
|
svector<upair> m_pairs; // inverse to index
|
||||||
|
svector<unsigned> m_available_spots;
|
||||||
|
public:
|
||||||
|
binary_heap_upair_queue(unsigned size);
|
||||||
|
|
||||||
|
unsigned dequeue_available_spot();
|
||||||
|
bool is_empty() const { return m_q.is_empty(); }
|
||||||
|
|
||||||
|
unsigned size() const {return m_q.size(); }
|
||||||
|
|
||||||
|
bool contains(unsigned i, unsigned j) const { return m_pairs_to_index.find(std::make_pair(i, j)) != m_pairs_to_index.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove(unsigned i, unsigned j);
|
||||||
|
bool ij_index_is_new(unsigned ij_index) const;
|
||||||
|
void enqueue(unsigned i, unsigned j, const T & priority);
|
||||||
|
void dequeue(unsigned & i, unsigned &j);
|
||||||
|
T get_priority(unsigned i, unsigned j) const;
|
||||||
|
#ifdef LEAN_DEBUG
|
||||||
|
bool pair_to_index_is_a_bijection() const;
|
||||||
|
bool available_spots_are_correct() const;
|
||||||
|
bool is_correct() const {
|
||||||
|
return m_q.is_consistent() && pair_to_index_is_a_bijection() && available_spots_are_correct();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
void resize(unsigned size) { m_q.resize(size); }
|
||||||
|
};
|
||||||
|
}
|
110
src/util/lp/binary_heap_upair_queue.hpp
Normal file
110
src/util/lp/binary_heap_upair_queue.hpp
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
#include "util/lp/lp_utils.h"
|
||||||
|
#include "util/lp/binary_heap_upair_queue.h"
|
||||||
|
namespace lean {
|
||||||
|
template <typename T> binary_heap_upair_queue<T>::binary_heap_upair_queue(unsigned size) : m_q(size), m_pairs(size) {
|
||||||
|
for (unsigned i = 0; i < size; i++)
|
||||||
|
m_available_spots.push_back(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> unsigned
|
||||||
|
binary_heap_upair_queue<T>::dequeue_available_spot() {
|
||||||
|
lean_assert(m_available_spots.empty() == false);
|
||||||
|
unsigned ret = m_available_spots.back();
|
||||||
|
m_available_spots.pop_back();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void binary_heap_upair_queue<T>::remove(unsigned i, unsigned j) {
|
||||||
|
upair p(i, j);
|
||||||
|
auto it = m_pairs_to_index.find(p);
|
||||||
|
if (it == m_pairs_to_index.end())
|
||||||
|
return; // nothing to do
|
||||||
|
m_q.remove(it->second);
|
||||||
|
m_available_spots.push_back(it->second);
|
||||||
|
m_pairs_to_index.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T> bool binary_heap_upair_queue<T>::ij_index_is_new(unsigned ij_index) const {
|
||||||
|
for (auto it : m_pairs_to_index) {
|
||||||
|
if (it.second == ij_index)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void binary_heap_upair_queue<T>::enqueue(unsigned i, unsigned j, const T & priority) {
|
||||||
|
upair p(i, j);
|
||||||
|
auto it = m_pairs_to_index.find(p);
|
||||||
|
unsigned ij_index;
|
||||||
|
if (it == m_pairs_to_index.end()) {
|
||||||
|
// it is a new pair, let us find a spot for it
|
||||||
|
if (m_available_spots.empty()) {
|
||||||
|
// we ran out of empty spots
|
||||||
|
unsigned size_was = static_cast<unsigned>(m_pairs.size());
|
||||||
|
unsigned new_size = size_was << 1;
|
||||||
|
for (unsigned i = size_was; i < new_size; i++)
|
||||||
|
m_available_spots.push_back(i);
|
||||||
|
m_pairs.resize(new_size);
|
||||||
|
}
|
||||||
|
ij_index = dequeue_available_spot();
|
||||||
|
// lean_assert(ij_index<m_pairs.size() && ij_index_is_new(ij_index));
|
||||||
|
m_pairs[ij_index] = p;
|
||||||
|
m_pairs_to_index[p] = ij_index;
|
||||||
|
} else {
|
||||||
|
ij_index = it->second;
|
||||||
|
}
|
||||||
|
m_q.enqueue(ij_index, priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void binary_heap_upair_queue<T>::dequeue(unsigned & i, unsigned &j) {
|
||||||
|
lean_assert(!m_q.is_empty());
|
||||||
|
unsigned ij_index = m_q.dequeue();
|
||||||
|
upair & p = m_pairs[ij_index];
|
||||||
|
i = p.first;
|
||||||
|
j = p.second;
|
||||||
|
m_available_spots.push_back(ij_index);
|
||||||
|
m_pairs_to_index.erase(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T> T binary_heap_upair_queue<T>::get_priority(unsigned i, unsigned j) const {
|
||||||
|
auto it = m_pairs_to_index.find(std::make_pair(i, j));
|
||||||
|
if (it == m_pairs_to_index.end())
|
||||||
|
return T(0xFFFFFF); // big number
|
||||||
|
return m_q.get_priority(it->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LEAN_DEBUG
|
||||||
|
template <typename T> bool binary_heap_upair_queue<T>::pair_to_index_is_a_bijection() const {
|
||||||
|
std::set<int> tmp;
|
||||||
|
for (auto p : m_pairs_to_index) {
|
||||||
|
unsigned j = p.second;
|
||||||
|
unsigned size = tmp.size();
|
||||||
|
tmp.insert(j);
|
||||||
|
if (tmp.size() == size)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> bool binary_heap_upair_queue<T>::available_spots_are_correct() const {
|
||||||
|
std::set<int> tmp;
|
||||||
|
for (auto p : m_available_spots){
|
||||||
|
tmp.insert(p);
|
||||||
|
}
|
||||||
|
if (tmp.size() != m_available_spots.size())
|
||||||
|
return false;
|
||||||
|
for (auto it : m_pairs_to_index)
|
||||||
|
if (tmp.find(it.second) != tmp.end())
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
17
src/util/lp/binary_heap_upair_queue_instances.cpp
Normal file
17
src/util/lp/binary_heap_upair_queue_instances.cpp
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#include "util/lp/binary_heap_upair_queue.hpp"
|
||||||
|
namespace lean {
|
||||||
|
template binary_heap_upair_queue<int>::binary_heap_upair_queue(unsigned int);
|
||||||
|
template binary_heap_upair_queue<unsigned int>::binary_heap_upair_queue(unsigned int);
|
||||||
|
template unsigned binary_heap_upair_queue<int>::dequeue_available_spot();
|
||||||
|
template unsigned binary_heap_upair_queue<unsigned int>::dequeue_available_spot();
|
||||||
|
template void binary_heap_upair_queue<int>::enqueue(unsigned int, unsigned int, int const&);
|
||||||
|
template void binary_heap_upair_queue<int>::remove(unsigned int, unsigned int);
|
||||||
|
template void binary_heap_upair_queue<unsigned int>::remove(unsigned int, unsigned int);
|
||||||
|
template void binary_heap_upair_queue<int>::dequeue(unsigned int&, unsigned int&);
|
||||||
|
template void binary_heap_upair_queue<unsigned int>::enqueue(unsigned int, unsigned int, unsigned int const&);
|
||||||
|
template void binary_heap_upair_queue<unsigned int>::dequeue(unsigned int&, unsigned int&);
|
||||||
|
}
|
335
src/util/lp/bound_analyzer_on_row.h
Normal file
335
src/util/lp/bound_analyzer_on_row.h
Normal file
|
@ -0,0 +1,335 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include "util/vector.h"
|
||||||
|
#include "util/lp/linear_combination_iterator.h"
|
||||||
|
#include "implied_bound.h"
|
||||||
|
#include "test_bound_analyzer.h"
|
||||||
|
#include <functional>
|
||||||
|
#include "util/lp/bound_propagator.h"
|
||||||
|
// We have an equality : sum by j of row[j]*x[j] = rs
|
||||||
|
// We try to pin a var by pushing the total by using the variable bounds
|
||||||
|
// In a loop we drive the partial sum down, denoting the variables of this process by _u.
|
||||||
|
// In the same loop trying to pin variables by pushing the partial sum up, denoting the variable related to it by _l
|
||||||
|
namespace lean {
|
||||||
|
|
||||||
|
class bound_analyzer_on_row {
|
||||||
|
|
||||||
|
linear_combination_iterator<mpq> & m_it;
|
||||||
|
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(
|
||||||
|
linear_combination_iterator<mpq> &it,
|
||||||
|
const numeric_pair<mpq>& rs,
|
||||||
|
unsigned row_or_term_index,
|
||||||
|
bound_propagator & bp
|
||||||
|
)
|
||||||
|
:
|
||||||
|
m_it(it),
|
||||||
|
m_bp(bp),
|
||||||
|
m_row_or_term_index(row_or_term_index),
|
||||||
|
m_column_of_u(-1),
|
||||||
|
m_column_of_l(-1),
|
||||||
|
m_rs(rs)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned j;
|
||||||
|
void analyze() {
|
||||||
|
|
||||||
|
mpq a; unsigned j;
|
||||||
|
while (((m_column_of_l != -2) || (m_column_of_u != -2)) && m_it.next(a, j))
|
||||||
|
analyze_bound_on_var_on_coeff(j, a);
|
||||||
|
|
||||||
|
if (m_column_of_u >= 0)
|
||||||
|
limit_monoid_u_from_below();
|
||||||
|
else if (m_column_of_u == -1)
|
||||||
|
limit_all_monoids_from_below();
|
||||||
|
|
||||||
|
if (m_column_of_l >= 0)
|
||||||
|
limit_monoid_l_from_above();
|
||||||
|
else if (m_column_of_l == -1)
|
||||||
|
limit_all_monoids_from_above();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bound_is_available(unsigned j, bool low_bound) {
|
||||||
|
return (low_bound && low_bound_is_available(j)) ||
|
||||||
|
(!low_bound && upper_bound_is_available(j));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool upper_bound_is_available(unsigned j) const {
|
||||||
|
switch (m_bp.get_column_type(j))
|
||||||
|
{
|
||||||
|
case column_type::fixed:
|
||||||
|
case column_type::boxed:
|
||||||
|
case column_type::upper_bound:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool low_bound_is_available(unsigned j) const {
|
||||||
|
switch (m_bp.get_column_type(j))
|
||||||
|
{
|
||||||
|
case column_type::fixed:
|
||||||
|
case column_type::boxed:
|
||||||
|
case column_type::low_bound:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const impq & ub(unsigned j) const {
|
||||||
|
lean_assert(upper_bound_is_available(j));
|
||||||
|
return m_bp.get_upper_bound(j);
|
||||||
|
}
|
||||||
|
const impq & lb(unsigned j) const {
|
||||||
|
lean_assert(low_bound_is_available(j));
|
||||||
|
return m_bp.get_low_bound(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const mpq & monoid_max_no_mult(bool a_is_pos, unsigned j, bool & strict) const {
|
||||||
|
if (a_is_pos) {
|
||||||
|
strict = !is_zero(ub(j).y);
|
||||||
|
return ub(j).x;
|
||||||
|
}
|
||||||
|
strict = !is_zero(lb(j).y);
|
||||||
|
return lb(j).x;
|
||||||
|
}
|
||||||
|
mpq monoid_max(const mpq & a, unsigned j) const {
|
||||||
|
if (is_pos(a)) {
|
||||||
|
return a * ub(j).x;
|
||||||
|
}
|
||||||
|
return a * lb(j).x;
|
||||||
|
}
|
||||||
|
mpq monoid_max(const mpq & a, unsigned j, bool & strict) const {
|
||||||
|
if (is_pos(a)) {
|
||||||
|
strict = !is_zero(ub(j).y);
|
||||||
|
return a * ub(j).x;
|
||||||
|
}
|
||||||
|
strict = !is_zero(lb(j).y);
|
||||||
|
return a * lb(j).x;
|
||||||
|
}
|
||||||
|
const mpq & monoid_min_no_mult(bool a_is_pos, unsigned j, bool & strict) const {
|
||||||
|
if (!a_is_pos) {
|
||||||
|
strict = !is_zero(ub(j).y);
|
||||||
|
return ub(j).x;
|
||||||
|
}
|
||||||
|
strict = !is_zero(lb(j).y);
|
||||||
|
return lb(j).x;
|
||||||
|
}
|
||||||
|
|
||||||
|
mpq monoid_min(const mpq & a, unsigned j, bool& strict) const {
|
||||||
|
if (is_neg(a)) {
|
||||||
|
strict = !is_zero(ub(j).y);
|
||||||
|
return a * ub(j).x;
|
||||||
|
}
|
||||||
|
|
||||||
|
strict = !is_zero(lb(j).y);
|
||||||
|
return a * lb(j).x;
|
||||||
|
}
|
||||||
|
|
||||||
|
mpq monoid_min(const mpq & a, unsigned j) const {
|
||||||
|
if (is_neg(a)) {
|
||||||
|
return a * ub(j).x;
|
||||||
|
}
|
||||||
|
|
||||||
|
return a * lb(j).x;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void limit_all_monoids_from_above() {
|
||||||
|
int strict = 0;
|
||||||
|
mpq total;
|
||||||
|
lean_assert(is_zero(total));
|
||||||
|
m_it.reset();
|
||||||
|
mpq a; unsigned j;
|
||||||
|
while (m_it.next(a, j)) {
|
||||||
|
bool str;
|
||||||
|
total -= monoid_min(a, j, str);
|
||||||
|
if (str)
|
||||||
|
strict++;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_it.reset();
|
||||||
|
while (m_it.next(a, j)) {
|
||||||
|
bool str;
|
||||||
|
bool a_is_pos = is_pos(a);
|
||||||
|
mpq bound = total / a + monoid_min_no_mult(a_is_pos, j, str);
|
||||||
|
if (a_is_pos) {
|
||||||
|
limit_j(j, bound, true, false, strict - static_cast<int>(str) > 0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
limit_j(j, bound, false, true, strict - static_cast<int>(str) > 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void limit_all_monoids_from_below() {
|
||||||
|
int strict = 0;
|
||||||
|
mpq total;
|
||||||
|
lean_assert(is_zero(total));
|
||||||
|
m_it.reset();
|
||||||
|
mpq a; unsigned j;
|
||||||
|
while (m_it.next(a, j)) {
|
||||||
|
bool str;
|
||||||
|
total -= monoid_max(a, j, str);
|
||||||
|
if (str)
|
||||||
|
strict++;
|
||||||
|
}
|
||||||
|
m_it.reset();
|
||||||
|
while (m_it.next(a, j)) {
|
||||||
|
bool str;
|
||||||
|
bool a_is_pos = is_pos(a);
|
||||||
|
mpq bound = total / a + monoid_max_no_mult(a_is_pos, j, str);
|
||||||
|
bool astrict = strict - static_cast<int>(str) > 0;
|
||||||
|
if (a_is_pos) {
|
||||||
|
limit_j(j, bound, true, true, astrict);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
limit_j(j, bound, false, false, astrict);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void limit_monoid_u_from_below() {
|
||||||
|
// we are going to limit from below the monoid m_column_of_u,
|
||||||
|
// every other monoid is impossible to limit from below
|
||||||
|
mpq u_coeff, a;
|
||||||
|
unsigned j;
|
||||||
|
mpq bound = -m_rs.x;
|
||||||
|
m_it.reset();
|
||||||
|
bool strict = false;
|
||||||
|
while (m_it.next(a, j)) {
|
||||||
|
if (j == static_cast<unsigned>(m_column_of_u)) {
|
||||||
|
u_coeff = a;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bool str;
|
||||||
|
bound -= monoid_max(a, j, str);
|
||||||
|
if (str)
|
||||||
|
strict = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bound /= u_coeff;
|
||||||
|
|
||||||
|
if (numeric_traits<impq>::is_pos(u_coeff)) {
|
||||||
|
limit_j(m_column_of_u, bound, true, true, strict);
|
||||||
|
} else {
|
||||||
|
limit_j(m_column_of_u, bound, false, false, strict);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void limit_monoid_l_from_above() {
|
||||||
|
// we are going to limit from above the monoid m_column_of_l,
|
||||||
|
// every other monoid is impossible to limit from above
|
||||||
|
mpq l_coeff, a;
|
||||||
|
unsigned j;
|
||||||
|
mpq bound = -m_rs.x;
|
||||||
|
bool strict = false;
|
||||||
|
m_it.reset();
|
||||||
|
while (m_it.next(a, j)) {
|
||||||
|
if (j == static_cast<unsigned>(m_column_of_l)) {
|
||||||
|
l_coeff = a;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool str;
|
||||||
|
bound -= monoid_min(a, j, str);
|
||||||
|
if (str)
|
||||||
|
strict = true;
|
||||||
|
}
|
||||||
|
bound /= l_coeff;
|
||||||
|
if (is_pos(l_coeff)) {
|
||||||
|
limit_j(m_column_of_l, bound, true, false, strict);
|
||||||
|
} else {
|
||||||
|
limit_j(m_column_of_l, bound, false, true, strict);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// // it is the coefficent before the bounded column
|
||||||
|
// void provide_evidence(bool coeff_is_pos) {
|
||||||
|
// /*
|
||||||
|
// auto & be = m_ibounds.back();
|
||||||
|
// bool low_bound = be.m_low_bound;
|
||||||
|
// if (!coeff_is_pos)
|
||||||
|
// low_bound = !low_bound;
|
||||||
|
// auto it = m_it.clone();
|
||||||
|
// mpq a; unsigned j;
|
||||||
|
// while (it->next(a, j)) {
|
||||||
|
// if (be.m_j == j) continue;
|
||||||
|
// lean_assert(bound_is_available(j, is_neg(a) ? low_bound : !low_bound));
|
||||||
|
// be.m_vector_of_bound_signatures.emplace_back(a, j, numeric_traits<impq>::
|
||||||
|
// is_neg(a)? low_bound: !low_bound);
|
||||||
|
// }
|
||||||
|
// delete it;
|
||||||
|
// */
|
||||||
|
// }
|
||||||
|
|
||||||
|
void limit_j(unsigned j, const mpq& u, bool coeff_before_j_is_pos, bool is_low_bound, bool strict){
|
||||||
|
m_bp.try_add_bound(u, j, is_low_bound, coeff_before_j_is_pos, m_row_or_term_index, strict);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void advance_u(unsigned j) {
|
||||||
|
if (m_column_of_u == -1)
|
||||||
|
m_column_of_u = j;
|
||||||
|
else
|
||||||
|
m_column_of_u = -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void advance_l(unsigned j) {
|
||||||
|
if (m_column_of_l == -1)
|
||||||
|
m_column_of_l = j;
|
||||||
|
else
|
||||||
|
m_column_of_l = -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void analyze_bound_on_var_on_coeff(int j, const mpq &a) {
|
||||||
|
switch (m_bp.get_column_type(j)) {
|
||||||
|
case column_type::low_bound:
|
||||||
|
if (numeric_traits<mpq>::is_pos(a))
|
||||||
|
advance_u(j);
|
||||||
|
else
|
||||||
|
advance_l(j);
|
||||||
|
break;
|
||||||
|
case column_type::upper_bound:
|
||||||
|
if(numeric_traits<mpq>::is_neg(a))
|
||||||
|
advance_u(j);
|
||||||
|
else
|
||||||
|
advance_l(j);
|
||||||
|
break;
|
||||||
|
case column_type::free_column:
|
||||||
|
advance_u(j);
|
||||||
|
advance_l(j);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void analyze_row(linear_combination_iterator<mpq> &it,
|
||||||
|
const numeric_pair<mpq>& rs,
|
||||||
|
unsigned row_or_term_index,
|
||||||
|
bound_propagator & bp
|
||||||
|
) {
|
||||||
|
bound_analyzer_on_row a(it, rs, row_or_term_index, bp);
|
||||||
|
a.analyze();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
47
src/util/lp/bound_propagator.cpp
Normal file
47
src/util/lp/bound_propagator.cpp
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#include "util/lp/lar_solver.h"
|
||||||
|
namespace lean {
|
||||||
|
bound_propagator::bound_propagator(lar_solver & ls):
|
||||||
|
m_lar_solver(ls) {}
|
||||||
|
column_type bound_propagator::get_column_type(unsigned j) const {
|
||||||
|
return m_lar_solver.m_mpq_lar_core_solver.m_column_types()[j];
|
||||||
|
}
|
||||||
|
const impq & bound_propagator::get_low_bound(unsigned j) const {
|
||||||
|
return m_lar_solver.m_mpq_lar_core_solver.m_r_low_bounds()[j];
|
||||||
|
}
|
||||||
|
const impq & bound_propagator::get_upper_bound(unsigned j) const {
|
||||||
|
return m_lar_solver.m_mpq_lar_core_solver.m_r_upper_bounds()[j];
|
||||||
|
}
|
||||||
|
void bound_propagator::try_add_bound(const mpq & v, unsigned j, bool is_low, bool coeff_before_j_is_pos, unsigned row_or_term_index, bool strict) {
|
||||||
|
j = m_lar_solver.adjust_column_index_to_term_index(j);
|
||||||
|
lconstraint_kind kind = is_low? GE : LE;
|
||||||
|
if (strict)
|
||||||
|
kind = static_cast<lconstraint_kind>(kind / 2);
|
||||||
|
|
||||||
|
if (!bound_is_interesting(j, kind, v))
|
||||||
|
return;
|
||||||
|
unsigned k; // index to ibounds
|
||||||
|
if (is_low) {
|
||||||
|
if (try_get_val(m_improved_low_bounds, j, k)) {
|
||||||
|
auto & found_bound = m_ibounds[k];
|
||||||
|
if (v > found_bound.m_bound || (v == found_bound.m_bound && found_bound.m_strict == false && strict))
|
||||||
|
found_bound = implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict);
|
||||||
|
} else {
|
||||||
|
m_improved_low_bounds[j] = m_ibounds.size();
|
||||||
|
m_ibounds.push_back(implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict));
|
||||||
|
}
|
||||||
|
} else { // the upper bound case
|
||||||
|
if (try_get_val(m_improved_upper_bounds, j, k)) {
|
||||||
|
auto & found_bound = m_ibounds[k];
|
||||||
|
if (v < found_bound.m_bound || (v == found_bound.m_bound && found_bound.m_strict == false && strict))
|
||||||
|
found_bound = implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict);
|
||||||
|
} else {
|
||||||
|
m_improved_upper_bounds[j] = m_ibounds.size();
|
||||||
|
m_ibounds.push_back(implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
27
src/util/lp/bound_propagator.h
Normal file
27
src/util/lp/bound_propagator.h
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include "util/lp/lp_settings.h"
|
||||||
|
namespace lean {
|
||||||
|
class lar_solver;
|
||||||
|
class bound_propagator {
|
||||||
|
std::unordered_map<unsigned, unsigned> m_improved_low_bounds; // these maps map a column index to the corresponding index in ibounds
|
||||||
|
std::unordered_map<unsigned, unsigned> m_improved_upper_bounds;
|
||||||
|
lar_solver & m_lar_solver;
|
||||||
|
public:
|
||||||
|
vector<implied_bound> m_ibounds;
|
||||||
|
public:
|
||||||
|
bound_propagator(lar_solver & ls);
|
||||||
|
column_type get_column_type(unsigned) const;
|
||||||
|
const impq & get_low_bound(unsigned) const;
|
||||||
|
const impq & get_upper_bound(unsigned) const;
|
||||||
|
void try_add_bound(const mpq & v, unsigned j, bool is_low, bool coeff_before_j_is_pos, unsigned row_or_term_index, bool strict);
|
||||||
|
virtual bool bound_is_interesting(unsigned vi,
|
||||||
|
lean::lconstraint_kind kind,
|
||||||
|
const rational & bval) {return true;}
|
||||||
|
unsigned number_of_found_bounds() const { return m_ibounds.size(); }
|
||||||
|
virtual void consume(mpq const& v, unsigned j) { std::cout << "doh\n"; }
|
||||||
|
};
|
||||||
|
}
|
20
src/util/lp/breakpoint.h
Normal file
20
src/util/lp/breakpoint.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace lean {
|
||||||
|
enum breakpoint_type {
|
||||||
|
low_break, upper_break, fixed_break
|
||||||
|
};
|
||||||
|
template <typename X>
|
||||||
|
struct breakpoint {
|
||||||
|
unsigned m_j; // the basic column
|
||||||
|
breakpoint_type m_type;
|
||||||
|
X m_delta;
|
||||||
|
breakpoint(){}
|
||||||
|
breakpoint(unsigned j, X delta, breakpoint_type type):m_j(j), m_type(type), m_delta(delta) {}
|
||||||
|
};
|
||||||
|
}
|
250
src/util/lp/column_info.h
Normal file
250
src/util/lp/column_info.h
Normal file
|
@ -0,0 +1,250 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "util/vector.h"
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <string>
|
||||||
|
#include <algorithm>
|
||||||
|
#include "util/lp/lp_settings.h"
|
||||||
|
namespace lean {
|
||||||
|
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;
|
||||||
|
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 &&
|
||||||
|
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_is_fixed == c.m_is_fixed &&
|
||||||
|
(!m_is_fixed || m_fixed_value == c.m_fixed_value) &&
|
||||||
|
m_column_index == c.m_column_index;
|
||||||
|
}
|
||||||
|
bool operator!=(const column_info & c) const { return !((*this) == c); }
|
||||||
|
void set_column_index(unsigned j) {
|
||||||
|
m_column_index = j;
|
||||||
|
}
|
||||||
|
// the default constructor
|
||||||
|
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) {
|
||||||
|
m_name = ci.m_name;
|
||||||
|
m_low_bound_is_set = ci.m_low_bound_is_set;
|
||||||
|
m_low_bound_is_strict = ci.m_low_bound_is_strict;
|
||||||
|
m_upper_bound_is_set = ci.m_upper_bound_is_set;
|
||||||
|
m_upper_bound_is_strict = ci.m_upper_bound_is_strict;
|
||||||
|
m_low_bound = ci.m_low_bound;
|
||||||
|
m_upper_bound = ci.m_upper_bound;
|
||||||
|
m_cost = ci.m_cost;
|
||||||
|
m_fixed_value = ci.m_fixed_value;
|
||||||
|
m_is_fixed = ci.m_is_fixed;
|
||||||
|
m_column_index = ci.m_column_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned get_column_index() const {
|
||||||
|
return m_column_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
column_type get_column_type() const {
|
||||||
|
return m_is_fixed? column_type::fixed : (m_low_bound_is_set? (m_upper_bound_is_set? column_type::boxed : column_type::low_bound) : (m_upper_bound_is_set? column_type::upper_bound: column_type::free_column));
|
||||||
|
}
|
||||||
|
|
||||||
|
column_type get_column_type_no_flipping() const {
|
||||||
|
if (m_is_fixed) {
|
||||||
|
return column_type::fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_low_bound_is_set) {
|
||||||
|
return m_upper_bound_is_set? column_type::boxed: column_type::low_bound;
|
||||||
|
}
|
||||||
|
// we are flipping the bounds!
|
||||||
|
return m_upper_bound_is_set? column_type::upper_bound
|
||||||
|
: column_type::free_column;
|
||||||
|
}
|
||||||
|
|
||||||
|
T get_low_bound() const {
|
||||||
|
lean_assert(m_low_bound_is_set);
|
||||||
|
return m_low_bound;
|
||||||
|
}
|
||||||
|
T get_upper_bound() const {
|
||||||
|
lean_assert(m_upper_bound_is_set);
|
||||||
|
return m_upper_bound;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool low_bound_is_set() const {
|
||||||
|
return m_low_bound_is_set;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool upper_bound_is_set() const {
|
||||||
|
return m_upper_bound_is_set;
|
||||||
|
}
|
||||||
|
|
||||||
|
T get_shift() {
|
||||||
|
if (is_fixed()) {
|
||||||
|
return m_fixed_value;
|
||||||
|
}
|
||||||
|
if (is_flipped()){
|
||||||
|
return m_upper_bound;
|
||||||
|
}
|
||||||
|
return m_low_bound_is_set? m_low_bound : numeric_traits<T>::zero();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_flipped() {
|
||||||
|
return m_upper_bound_is_set && !m_low_bound_is_set;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool adjusted_low_bound_is_set() {
|
||||||
|
return !is_flipped()? low_bound_is_set(): upper_bound_is_set();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool adjusted_upper_bound_is_set() {
|
||||||
|
return !is_flipped()? upper_bound_is_set(): low_bound_is_set();
|
||||||
|
}
|
||||||
|
|
||||||
|
T get_adjusted_upper_bound() {
|
||||||
|
return get_upper_bound() - get_low_bound();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_fixed() const {
|
||||||
|
return m_is_fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_free() {
|
||||||
|
return !m_low_bound_is_set && !m_upper_bound_is_set;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_fixed_value(T v) {
|
||||||
|
m_is_fixed = true;
|
||||||
|
m_fixed_value = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
T get_fixed_value() const {
|
||||||
|
lean_assert(m_is_fixed);
|
||||||
|
return m_fixed_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
T get_cost() const {
|
||||||
|
return m_cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_cost(T const & cost) {
|
||||||
|
m_cost = cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_name(std::string const & s) {
|
||||||
|
m_name = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_name() const {
|
||||||
|
return m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_low_bound(T const & l) {
|
||||||
|
m_low_bound = l;
|
||||||
|
m_low_bound_is_set = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_upper_bound(T const & l) {
|
||||||
|
m_upper_bound = l;
|
||||||
|
m_upper_bound_is_set = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unset_low_bound() {
|
||||||
|
m_low_bound_is_set = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unset_upper_bound() {
|
||||||
|
m_upper_bound_is_set = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unset_fixed() {
|
||||||
|
m_is_fixed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool low_bound_holds(T v) {
|
||||||
|
return !low_bound_is_set() || v >= m_low_bound -T(0.0000001);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool upper_bound_holds(T v) {
|
||||||
|
return !upper_bound_is_set() || v <= m_upper_bound + T(0.000001);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bounds_hold(T v) {
|
||||||
|
return low_bound_holds(v) && upper_bound_holds(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool adjusted_bounds_hold(T v) {
|
||||||
|
return adjusted_low_bound_holds(v) && adjusted_upper_bound_holds(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool adjusted_low_bound_holds(T v) {
|
||||||
|
return !adjusted_low_bound_is_set() || v >= -T(0.0000001);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool adjusted_upper_bound_holds(T v) {
|
||||||
|
return !adjusted_upper_bound_is_set() || v <= get_adjusted_upper_bound() + T(0.000001);
|
||||||
|
}
|
||||||
|
bool is_infeasible() {
|
||||||
|
if ((!upper_bound_is_set()) || (!low_bound_is_set()))
|
||||||
|
return false;
|
||||||
|
// ok, both bounds are set
|
||||||
|
bool at_least_one_is_strict = upper_bound_is_strict() || low_bound_is_strict();
|
||||||
|
if (!at_least_one_is_strict)
|
||||||
|
return get_upper_bound() < get_low_bound();
|
||||||
|
// at least on bound is strict
|
||||||
|
return get_upper_bound() <= get_low_bound(); // the equality is impossible
|
||||||
|
}
|
||||||
|
bool low_bound_is_strict() const {
|
||||||
|
return m_low_bound_is_strict;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_low_bound_strict(bool val) {
|
||||||
|
m_low_bound_is_strict = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool upper_bound_is_strict() const {
|
||||||
|
return m_upper_bound_is_strict;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_upper_bound_strict(bool val) {
|
||||||
|
m_upper_bound_is_strict = val;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
82
src/util/lp/column_namer.h
Normal file
82
src/util/lp/column_namer.h
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
#pragma once
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#include <string>
|
||||||
|
#include "util/lp/linear_combination_iterator.h"
|
||||||
|
namespace lean {
|
||||||
|
class column_namer {
|
||||||
|
public:
|
||||||
|
virtual std::string get_column_name(unsigned j) const = 0;
|
||||||
|
template <typename T>
|
||||||
|
void print_linear_iterator(linear_combination_iterator<T>* it, std::ostream & out) const {
|
||||||
|
vector<std::pair<T, unsigned>> coeff;
|
||||||
|
T a;
|
||||||
|
unsigned i;
|
||||||
|
while (it->next(a, i)) {
|
||||||
|
coeff.emplace_back(a, i);
|
||||||
|
}
|
||||||
|
print_linear_combination_of_column_indices(coeff, out);
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
void print_linear_iterator_indices_only(linear_combination_iterator<T>* it, std::ostream & out) const {
|
||||||
|
vector<std::pair<T, unsigned>> coeff;
|
||||||
|
T a;
|
||||||
|
unsigned i;
|
||||||
|
while (it->next(a, i)) {
|
||||||
|
coeff.emplace_back(a, i);
|
||||||
|
}
|
||||||
|
print_linear_combination_of_column_indices_only(coeff, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void print_linear_combination_of_column_indices_only(const vector<std::pair<T, unsigned>> & coeffs, std::ostream & out) const {
|
||||||
|
bool first = true;
|
||||||
|
for (const auto & it : coeffs) {
|
||||||
|
auto val = it.first;
|
||||||
|
if (first) {
|
||||||
|
first = false;
|
||||||
|
} else {
|
||||||
|
if (numeric_traits<T>::is_pos(val)) {
|
||||||
|
out << " + ";
|
||||||
|
} else {
|
||||||
|
out << " - ";
|
||||||
|
val = -val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (val == -numeric_traits<T>::one())
|
||||||
|
out << " - ";
|
||||||
|
else if (val != numeric_traits<T>::one())
|
||||||
|
out << T_to_string(val);
|
||||||
|
|
||||||
|
out << "_" << it.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void print_linear_combination_of_column_indices(const vector<std::pair<T, unsigned>> & coeffs, std::ostream & out) const {
|
||||||
|
bool first = true;
|
||||||
|
for (const auto & it : coeffs) {
|
||||||
|
auto val = it.first;
|
||||||
|
if (first) {
|
||||||
|
first = false;
|
||||||
|
} else {
|
||||||
|
if (numeric_traits<T>::is_pos(val)) {
|
||||||
|
out << " + ";
|
||||||
|
} else {
|
||||||
|
out << " - ";
|
||||||
|
val = -val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (val == -numeric_traits<T>::one())
|
||||||
|
out << " - ";
|
||||||
|
else if (val != numeric_traits<T>::one())
|
||||||
|
out << val;
|
||||||
|
|
||||||
|
out << get_column_name(it.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
117
src/util/lp/core_solver_pretty_printer.h
Normal file
117
src/util/lp/core_solver_pretty_printer.h
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <limits>
|
||||||
|
#include <string>
|
||||||
|
#include <algorithm>
|
||||||
|
#include "util/vector.h"
|
||||||
|
#include <ostream>
|
||||||
|
#include "util/lp/lp_settings.h"
|
||||||
|
#include "util/lp/indexed_vector.h"
|
||||||
|
namespace lean {
|
||||||
|
template <typename T, typename X> class lp_core_solver_base; // forward definition
|
||||||
|
|
||||||
|
template <typename T, typename X>
|
||||||
|
class core_solver_pretty_printer {
|
||||||
|
std::ostream & m_out;
|
||||||
|
typedef std::string string;
|
||||||
|
lp_core_solver_base<T, X> & m_core_solver;
|
||||||
|
vector<unsigned> m_column_widths;
|
||||||
|
vector<vector<string>> m_A;
|
||||||
|
vector<vector<string>> m_signs;
|
||||||
|
vector<string> m_costs;
|
||||||
|
vector<string> m_cost_signs;
|
||||||
|
vector<string> m_lows; // low bounds
|
||||||
|
vector<string> m_upps; // upper bounds
|
||||||
|
vector<string> m_lows_signs;
|
||||||
|
vector<string> m_upps_signs;
|
||||||
|
unsigned m_rs_width;
|
||||||
|
vector<X> m_rs;
|
||||||
|
unsigned m_title_width;
|
||||||
|
std::string m_cost_title;
|
||||||
|
std::string m_basis_heading_title;
|
||||||
|
std::string m_x_title;
|
||||||
|
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;
|
||||||
|
indexed_vector<T> m_w_buff;
|
||||||
|
indexed_vector<T> m_ed_buff;
|
||||||
|
vector<T> m_exact_column_norms;
|
||||||
|
|
||||||
|
public:
|
||||||
|
core_solver_pretty_printer(lp_core_solver_base<T, X > & core_solver, std::ostream & out);
|
||||||
|
|
||||||
|
void init_costs();
|
||||||
|
|
||||||
|
~core_solver_pretty_printer();
|
||||||
|
void init_rs_width();
|
||||||
|
|
||||||
|
T current_column_norm();
|
||||||
|
|
||||||
|
void init_m_A_and_signs();
|
||||||
|
|
||||||
|
void init_column_widths();
|
||||||
|
|
||||||
|
void adjust_width_with_low_bound(unsigned column, unsigned & w);
|
||||||
|
void adjust_width_with_upper_bound(unsigned column, unsigned & w);
|
||||||
|
|
||||||
|
void adjust_width_with_bounds(unsigned column, unsigned & w);
|
||||||
|
|
||||||
|
void adjust_width_with_basis_heading(unsigned column, unsigned & w) {
|
||||||
|
w = std::max(w, (unsigned)T_to_string(m_core_solver.m_basis_heading[column]).size());
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned get_column_width(unsigned column);
|
||||||
|
|
||||||
|
unsigned regular_cell_width(unsigned row, unsigned column, std::string name) {
|
||||||
|
return regular_cell_string(row, column, name).size();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string regular_cell_string(unsigned row, unsigned column, std::string name);
|
||||||
|
|
||||||
|
|
||||||
|
void set_coeff(vector<string>& row, vector<string> & row_signs, unsigned col, const T & t, string name);
|
||||||
|
|
||||||
|
void print_x();
|
||||||
|
|
||||||
|
std::string get_low_bound_string(unsigned j);
|
||||||
|
|
||||||
|
std::string get_upp_bound_string(unsigned j);
|
||||||
|
|
||||||
|
|
||||||
|
void print_lows();
|
||||||
|
|
||||||
|
void print_upps();
|
||||||
|
|
||||||
|
string get_exact_column_norm_string(unsigned col) {
|
||||||
|
return T_to_string(m_exact_column_norms[col]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_exact_norms();
|
||||||
|
|
||||||
|
void print_approx_norms();
|
||||||
|
|
||||||
|
void print();
|
||||||
|
|
||||||
|
void print_basis_heading();
|
||||||
|
|
||||||
|
void print_bottom_line() {
|
||||||
|
m_out << "----------------------" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_cost();
|
||||||
|
|
||||||
|
void print_given_rows(vector<string> & row, vector<string> & signs, X rst);
|
||||||
|
|
||||||
|
void print_row(unsigned i);
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
383
src/util/lp/core_solver_pretty_printer.hpp
Normal file
383
src/util/lp/core_solver_pretty_printer.hpp
Normal file
|
@ -0,0 +1,383 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#include <limits>
|
||||||
|
#include <string>
|
||||||
|
#include <algorithm>
|
||||||
|
#include "util/lp/lp_utils.h"
|
||||||
|
#include "util/lp/lp_core_solver_base.h"
|
||||||
|
#include "util/lp/core_solver_pretty_printer.h"
|
||||||
|
#include "util/lp/numeric_pair.h"
|
||||||
|
namespace lean {
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T, typename X>
|
||||||
|
core_solver_pretty_printer<T, X>::core_solver_pretty_printer(lp_core_solver_base<T, X > & core_solver, std::ostream & out):
|
||||||
|
m_out(out),
|
||||||
|
m_core_solver(core_solver),
|
||||||
|
m_A(core_solver.m_A.row_count(), vector<string>(core_solver.m_A.column_count(), "")),
|
||||||
|
m_signs(core_solver.m_A.row_count(), vector<string>(core_solver.m_A.column_count(), " ")),
|
||||||
|
m_costs(ncols(), ""),
|
||||||
|
m_cost_signs(ncols(), " "),
|
||||||
|
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();
|
||||||
|
init_column_widths();
|
||||||
|
init_rs_width();
|
||||||
|
m_cost_title = "costs";
|
||||||
|
m_basis_heading_title = "heading";
|
||||||
|
m_x_title = "x*";
|
||||||
|
m_title_width = static_cast<unsigned>(std::max(std::max(m_cost_title.size(), std::max(m_basis_heading_title.size(), m_x_title.size())), m_approx_norm_title.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X> void core_solver_pretty_printer<T, X>::init_costs() {
|
||||||
|
if (!m_core_solver.use_tableau()) {
|
||||||
|
vector<T> local_y(m_core_solver.m_m());
|
||||||
|
m_core_solver.solve_yB(local_y);
|
||||||
|
for (unsigned i = 0; i < ncols(); i++) {
|
||||||
|
if (m_core_solver.m_basis_heading[i] < 0) {
|
||||||
|
T t = m_core_solver.m_costs[i] - m_core_solver.m_A.dot_product_with_column(local_y, i);
|
||||||
|
set_coeff(m_costs, m_cost_signs, i, t, m_core_solver.column_name(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (unsigned i = 0; i < ncols(); i++) {
|
||||||
|
if (m_core_solver.m_basis_heading[i] < 0) {
|
||||||
|
set_coeff(m_costs, m_cost_signs, i, m_core_solver.m_d[i], m_core_solver.column_name(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X> core_solver_pretty_printer<T, X>::~core_solver_pretty_printer() {
|
||||||
|
m_core_solver.m_w = m_w_buff;
|
||||||
|
m_core_solver.m_ed = m_ed_buff;
|
||||||
|
}
|
||||||
|
template <typename T, typename X> void core_solver_pretty_printer<T, X>::init_rs_width() {
|
||||||
|
m_rs_width = static_cast<unsigned>(T_to_string(m_core_solver.get_cost()).size());
|
||||||
|
for (unsigned i = 0; i < nrows(); i++) {
|
||||||
|
unsigned wt = static_cast<unsigned>(T_to_string(m_rs[i]).size());
|
||||||
|
if (wt > m_rs_width) {
|
||||||
|
m_rs_width = wt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X> T core_solver_pretty_printer<T, X>::current_column_norm() {
|
||||||
|
T ret = zero_of_type<T>();
|
||||||
|
for (auto i : m_core_solver.m_ed.m_index)
|
||||||
|
ret += m_core_solver.m_ed[i] * m_core_solver.m_ed[i];
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X> void core_solver_pretty_printer<T, X>::init_m_A_and_signs() {
|
||||||
|
if (numeric_traits<T>::precise() && m_core_solver.m_settings.use_tableau()) {
|
||||||
|
for (unsigned column = 0; column < ncols(); column++) {
|
||||||
|
vector<T> t(nrows(), zero_of_type<T>());
|
||||||
|
for (const auto & c : m_core_solver.m_A.m_columns[column]){
|
||||||
|
t[c.m_i] = m_core_solver.m_A.get_val(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
string name = m_core_solver.column_name(column);
|
||||||
|
for (unsigned row = 0; row < nrows(); row ++) {
|
||||||
|
set_coeff(
|
||||||
|
m_A[row],
|
||||||
|
m_signs[row],
|
||||||
|
column,
|
||||||
|
t[row],
|
||||||
|
name);
|
||||||
|
m_rs[row] += t[row] * m_core_solver.m_x[column];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (unsigned column = 0; column < ncols(); column++) {
|
||||||
|
m_core_solver.solve_Bd(column); // puts the result into m_core_solver.m_ed
|
||||||
|
string name = m_core_solver.column_name(column);
|
||||||
|
for (unsigned row = 0; row < nrows(); row ++) {
|
||||||
|
set_coeff(
|
||||||
|
m_A[row],
|
||||||
|
m_signs[row],
|
||||||
|
column,
|
||||||
|
m_core_solver.m_ed[row],
|
||||||
|
name);
|
||||||
|
m_rs[row] += m_core_solver.m_ed[row] * m_core_solver.m_x[column];
|
||||||
|
}
|
||||||
|
if (!m_core_solver.use_tableau())
|
||||||
|
m_exact_column_norms.push_back(current_column_norm() + T(1)); // a conversion missing 1 -> T
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X> void core_solver_pretty_printer<T, X>::init_column_widths() {
|
||||||
|
for (unsigned i = 0; i < ncols(); i++) {
|
||||||
|
m_column_widths[i] = get_column_width(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X> void core_solver_pretty_printer<T, X>::adjust_width_with_low_bound(unsigned column, unsigned & w) {
|
||||||
|
if (!m_core_solver.low_bounds_are_set()) return;
|
||||||
|
w = std::max(w, (unsigned)T_to_string(m_core_solver.low_bound_value(column)).size());
|
||||||
|
}
|
||||||
|
template <typename T, typename X> void core_solver_pretty_printer<T, X>::adjust_width_with_upper_bound(unsigned column, unsigned & w) {
|
||||||
|
w = std::max(w, (unsigned)T_to_string(m_core_solver.upper_bound_value(column)).size());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X> void core_solver_pretty_printer<T, X>::adjust_width_with_bounds(unsigned column, unsigned & w) {
|
||||||
|
switch (m_core_solver.get_column_type(column)) {
|
||||||
|
case column_type::fixed:
|
||||||
|
case column_type::boxed:
|
||||||
|
adjust_width_with_low_bound(column, w);
|
||||||
|
adjust_width_with_upper_bound(column, w);
|
||||||
|
break;
|
||||||
|
case column_type::low_bound:
|
||||||
|
adjust_width_with_low_bound(column, w);
|
||||||
|
break;
|
||||||
|
case column_type::upper_bound:
|
||||||
|
adjust_width_with_upper_bound(column, w);
|
||||||
|
break;
|
||||||
|
case column_type::free_column:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
lean_assert(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T, typename X> unsigned core_solver_pretty_printer<T, X>:: get_column_width(unsigned column) {
|
||||||
|
unsigned w = static_cast<unsigned>(std::max((size_t)m_costs[column].size(), T_to_string(m_core_solver.m_x[column]).size()));
|
||||||
|
adjust_width_with_bounds(column, w);
|
||||||
|
adjust_width_with_basis_heading(column, w);
|
||||||
|
for (unsigned i = 0; i < nrows(); i++) {
|
||||||
|
unsigned cellw = static_cast<unsigned>(m_A[i][column].size());
|
||||||
|
if (cellw > w) {
|
||||||
|
w = cellw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!m_core_solver.use_tableau()) {
|
||||||
|
w = std::max(w, (unsigned)T_to_string(m_exact_column_norms[column]).size());
|
||||||
|
if (m_core_solver.m_column_norms.size() > 0)
|
||||||
|
w = std::max(w, (unsigned)T_to_string(m_core_solver.m_column_norms[column]).size());
|
||||||
|
}
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X> std::string core_solver_pretty_printer<T, X>::regular_cell_string(unsigned row, unsigned /* column */, std::string name) {
|
||||||
|
T t = fabs(m_core_solver.m_ed[row]);
|
||||||
|
if ( t == 1) return name;
|
||||||
|
return T_to_string(t) + name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T, typename X> void core_solver_pretty_printer<T, X>::set_coeff(vector<string>& row, vector<string> & row_signs, unsigned col, const T & t, string name) {
|
||||||
|
if (numeric_traits<T>::is_zero(t)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (col > 0) {
|
||||||
|
if (t > 0) {
|
||||||
|
row_signs[col] = "+";
|
||||||
|
row[col] = t != 1? T_to_string(t) + name : name;
|
||||||
|
} else {
|
||||||
|
row_signs[col] = "-";
|
||||||
|
row[col] = t != -1? T_to_string(-t) + name: name;
|
||||||
|
}
|
||||||
|
} else { // col == 0
|
||||||
|
if (t == -1) {
|
||||||
|
row[col] = "-" + name;
|
||||||
|
} else if (t == 1) {
|
||||||
|
row[col] = name;
|
||||||
|
} else {
|
||||||
|
row[col] = T_to_string(t) + name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X> void core_solver_pretty_printer<T, X>::print_x() {
|
||||||
|
if (ncols() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int blanks = m_title_width + 1 - static_cast<int>(m_x_title.size());
|
||||||
|
m_out << m_x_title;
|
||||||
|
print_blanks(blanks, m_out);
|
||||||
|
|
||||||
|
auto bh = m_core_solver.m_x;
|
||||||
|
for (unsigned i = 0; i < ncols(); i++) {
|
||||||
|
string s = T_to_string(bh[i]);
|
||||||
|
int blanks = m_column_widths[i] - static_cast<int>(s.size());
|
||||||
|
print_blanks(blanks, m_out);
|
||||||
|
m_out << s << " "; // the column interval
|
||||||
|
}
|
||||||
|
m_out << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X> std::string core_solver_pretty_printer<T, X>::get_low_bound_string(unsigned j) {
|
||||||
|
switch (m_core_solver.get_column_type(j)){
|
||||||
|
case column_type::boxed:
|
||||||
|
case column_type::low_bound:
|
||||||
|
case column_type::fixed:
|
||||||
|
if (m_core_solver.low_bounds_are_set())
|
||||||
|
return T_to_string(m_core_solver.low_bound_value(j));
|
||||||
|
else
|
||||||
|
return std::string("0");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X> std::string core_solver_pretty_printer<T, X>::get_upp_bound_string(unsigned j) {
|
||||||
|
switch (m_core_solver.get_column_type(j)){
|
||||||
|
case column_type::boxed:
|
||||||
|
case column_type::upper_bound:
|
||||||
|
case column_type::fixed:
|
||||||
|
return T_to_string(m_core_solver.upper_bound_value(j));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T, typename X> void core_solver_pretty_printer<T, X>::print_lows() {
|
||||||
|
if (ncols() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int blanks = m_title_width + 1 - static_cast<unsigned>(m_low_bounds_title.size());
|
||||||
|
m_out << m_low_bounds_title;
|
||||||
|
print_blanks(blanks, m_out);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < ncols(); i++) {
|
||||||
|
string s = get_low_bound_string(i);
|
||||||
|
int blanks = m_column_widths[i] - static_cast<unsigned>(s.size());
|
||||||
|
print_blanks(blanks, m_out);
|
||||||
|
m_out << s << " "; // the column interval
|
||||||
|
}
|
||||||
|
m_out << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X> void core_solver_pretty_printer<T, X>::print_upps() {
|
||||||
|
if (ncols() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int blanks = m_title_width + 1 - static_cast<unsigned>(m_upp_bounds_title.size());
|
||||||
|
m_out << m_upp_bounds_title;
|
||||||
|
print_blanks(blanks, m_out);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < ncols(); i++) {
|
||||||
|
string s = get_upp_bound_string(i);
|
||||||
|
int blanks = m_column_widths[i] - static_cast<unsigned>(s.size());
|
||||||
|
print_blanks(blanks, m_out);
|
||||||
|
m_out << s << " "; // the column interval
|
||||||
|
}
|
||||||
|
m_out << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X> void core_solver_pretty_printer<T, X>::print_exact_norms() {
|
||||||
|
if (m_core_solver.use_tableau()) return;
|
||||||
|
int blanks = m_title_width + 1 - static_cast<int>(m_exact_norm_title.size());
|
||||||
|
m_out << m_exact_norm_title;
|
||||||
|
print_blanks(blanks, m_out);
|
||||||
|
for (unsigned i = 0; i < ncols(); i++) {
|
||||||
|
string s = get_exact_column_norm_string(i);
|
||||||
|
int blanks = m_column_widths[i] - static_cast<int>(s.size());
|
||||||
|
print_blanks(blanks, m_out);
|
||||||
|
m_out << s << " ";
|
||||||
|
}
|
||||||
|
m_out << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X> void core_solver_pretty_printer<T, X>::print_approx_norms() {
|
||||||
|
if (m_core_solver.use_tableau()) return;
|
||||||
|
int blanks = m_title_width + 1 - static_cast<int>(m_approx_norm_title.size());
|
||||||
|
m_out << m_approx_norm_title;
|
||||||
|
print_blanks(blanks, m_out);
|
||||||
|
for (unsigned i = 0; i < ncols(); i++) {
|
||||||
|
string s = T_to_string(m_core_solver.m_column_norms[i]);
|
||||||
|
int blanks = m_column_widths[i] - static_cast<int>(s.size());
|
||||||
|
print_blanks(blanks, m_out);
|
||||||
|
m_out << s << " ";
|
||||||
|
}
|
||||||
|
m_out << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X> void core_solver_pretty_printer<T, X>::print() {
|
||||||
|
for (unsigned i = 0; i < nrows(); i++) {
|
||||||
|
print_row(i);
|
||||||
|
}
|
||||||
|
print_bottom_line();
|
||||||
|
print_cost();
|
||||||
|
print_x();
|
||||||
|
print_basis_heading();
|
||||||
|
print_lows();
|
||||||
|
print_upps();
|
||||||
|
print_exact_norms();
|
||||||
|
if (m_core_solver.m_column_norms.size() > 0)
|
||||||
|
print_approx_norms();
|
||||||
|
m_out << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X> void core_solver_pretty_printer<T, X>::print_basis_heading() {
|
||||||
|
int blanks = m_title_width + 1 - static_cast<int>(m_basis_heading_title.size());
|
||||||
|
m_out << m_basis_heading_title;
|
||||||
|
print_blanks(blanks, m_out);
|
||||||
|
|
||||||
|
if (ncols() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto bh = m_core_solver.m_basis_heading;
|
||||||
|
for (unsigned i = 0; i < ncols(); i++) {
|
||||||
|
string s = T_to_string(bh[i]);
|
||||||
|
int blanks = m_column_widths[i] - static_cast<unsigned>(s.size());
|
||||||
|
print_blanks(blanks, m_out);
|
||||||
|
m_out << s << " "; // the column interval
|
||||||
|
}
|
||||||
|
m_out << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X> void core_solver_pretty_printer<T, X>::print_cost() {
|
||||||
|
int blanks = m_title_width + 1 - static_cast<int>(m_cost_title.size());
|
||||||
|
m_out << m_cost_title;
|
||||||
|
print_blanks(blanks, m_out);
|
||||||
|
print_given_rows(m_costs, m_cost_signs, m_core_solver.get_cost());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X> void core_solver_pretty_printer<T, X>::print_given_rows(vector<string> & row, vector<string> & signs, X rst) {
|
||||||
|
for (unsigned col = 0; col < row.size(); col++) {
|
||||||
|
unsigned width = m_column_widths[col];
|
||||||
|
string s = row[col];
|
||||||
|
int number_of_blanks = width - static_cast<unsigned>(s.size());
|
||||||
|
lean_assert(number_of_blanks >= 0);
|
||||||
|
print_blanks(number_of_blanks, m_out);
|
||||||
|
m_out << s << ' ';
|
||||||
|
if (col < row.size() - 1) {
|
||||||
|
m_out << signs[col + 1] << ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_out << '=';
|
||||||
|
|
||||||
|
string rs = T_to_string(rst);
|
||||||
|
int nb = m_rs_width - static_cast<int>(rs.size());
|
||||||
|
lean_assert(nb >= 0);
|
||||||
|
print_blanks(nb + 1, m_out);
|
||||||
|
m_out << rs << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X> void core_solver_pretty_printer<T, X>::print_row(unsigned i){
|
||||||
|
print_blanks(m_title_width + 1, m_out);
|
||||||
|
auto row = m_A[i];
|
||||||
|
auto sign_row = m_signs[i];
|
||||||
|
auto rs = m_rs[i];
|
||||||
|
print_given_rows(row, sign_row, rs);
|
||||||
|
}
|
||||||
|
}
|
15
src/util/lp/core_solver_pretty_printer_instances.cpp
Normal file
15
src/util/lp/core_solver_pretty_printer_instances.cpp
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#include "util/lp/numeric_pair.h"
|
||||||
|
#include "util/lp/core_solver_pretty_printer.hpp"
|
||||||
|
template lean::core_solver_pretty_printer<double, double>::core_solver_pretty_printer(lean::lp_core_solver_base<double, double> &, std::ostream & out);
|
||||||
|
template void lean::core_solver_pretty_printer<double, double>::print();
|
||||||
|
template lean::core_solver_pretty_printer<double, double>::~core_solver_pretty_printer();
|
||||||
|
template lean::core_solver_pretty_printer<lean::mpq, lean::mpq>::core_solver_pretty_printer(lean::lp_core_solver_base<lean::mpq, lean::mpq> &, std::ostream & out);
|
||||||
|
template void lean::core_solver_pretty_printer<lean::mpq, lean::mpq>::print();
|
||||||
|
template lean::core_solver_pretty_printer<lean::mpq, lean::mpq>::~core_solver_pretty_printer();
|
||||||
|
template lean::core_solver_pretty_printer<lean::mpq, lean::numeric_pair<lean::mpq> >::core_solver_pretty_printer(lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> > &, std::ostream & out);
|
||||||
|
template lean::core_solver_pretty_printer<lean::mpq, lean::numeric_pair<lean::mpq> >::~core_solver_pretty_printer();
|
||||||
|
template void lean::core_solver_pretty_printer<lean::mpq, lean::numeric_pair<lean::mpq> >::print();
|
92
src/util/lp/dense_matrix.h
Normal file
92
src/util/lp/dense_matrix.h
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#ifdef LEAN_DEBUG
|
||||||
|
#include "util/vector.h"
|
||||||
|
#include "util/lp/matrix.h"
|
||||||
|
namespace lean {
|
||||||
|
// used for debugging purposes only
|
||||||
|
template <typename T, typename X>
|
||||||
|
class dense_matrix: public matrix<T, X> {
|
||||||
|
public:
|
||||||
|
struct ref {
|
||||||
|
unsigned m_i;
|
||||||
|
dense_matrix & m_s;
|
||||||
|
ref(unsigned i, dense_matrix & s) :m_i(i * s.m_n), m_s(s){}
|
||||||
|
T & operator[] (unsigned j) {
|
||||||
|
return m_s.m_values[m_i + j];
|
||||||
|
}
|
||||||
|
const T & operator[] (unsigned j) const {
|
||||||
|
return m_s.m_v[m_i + j];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ref operator[] (unsigned i) {
|
||||||
|
return ref(i, *this);
|
||||||
|
}
|
||||||
|
unsigned m_m; // number of rows
|
||||||
|
unsigned m_n; // number of const
|
||||||
|
vector<T> m_values;
|
||||||
|
dense_matrix(unsigned m, unsigned n);
|
||||||
|
|
||||||
|
dense_matrix operator*=(matrix<T, X> const & a) {
|
||||||
|
lean_assert(column_count() == a.row_count());
|
||||||
|
dense_matrix c(row_count(), a.column_count());
|
||||||
|
for (unsigned i = 0; i < row_count(); i++) {
|
||||||
|
for (unsigned j = 0; j < a.column_count(); j++) {
|
||||||
|
T v = numeric_traits<T>::zero();
|
||||||
|
for (unsigned k = 0; k < a.column_count(); k++) {
|
||||||
|
v += get_elem(i, k) * a(k, j);
|
||||||
|
}
|
||||||
|
c.set_elem(i, j, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*this = c;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
dense_matrix & operator=(matrix<T, X> const & other);
|
||||||
|
|
||||||
|
dense_matrix & operator=(dense_matrix const & other);
|
||||||
|
|
||||||
|
dense_matrix(matrix<T, X> const * other);
|
||||||
|
void apply_from_right(T * w);
|
||||||
|
|
||||||
|
void apply_from_right(vector <T> & w);
|
||||||
|
|
||||||
|
T * apply_from_left_with_different_dims(vector<T> & w);
|
||||||
|
void apply_from_left(vector<T> & w , lp_settings & ) { apply_from_left(w); }
|
||||||
|
|
||||||
|
void apply_from_left(vector<T> & w);
|
||||||
|
|
||||||
|
void apply_from_left(X * w, lp_settings & );
|
||||||
|
|
||||||
|
void apply_from_left_to_X(vector<X> & w, lp_settings & );
|
||||||
|
|
||||||
|
virtual void set_number_of_rows(unsigned /*m*/) {}
|
||||||
|
virtual void set_number_of_columns(unsigned /*n*/) { }
|
||||||
|
|
||||||
|
T get_elem(unsigned i, unsigned j) const { return m_values[i * m_n + j]; }
|
||||||
|
|
||||||
|
unsigned row_count() const { return m_m; }
|
||||||
|
unsigned column_count() const { return m_n; }
|
||||||
|
|
||||||
|
void set_elem(unsigned i, unsigned j, const T& val) { m_values[i * m_n + j] = val; }
|
||||||
|
|
||||||
|
// This method pivots row i to row i0 by muliplying row i by
|
||||||
|
// alpha and adding it to row i0.
|
||||||
|
void pivot_row_to_row(unsigned i, const T& alpha, unsigned i0,
|
||||||
|
const double & pivot_epsilon);
|
||||||
|
|
||||||
|
void swap_columns(unsigned a, unsigned b);
|
||||||
|
|
||||||
|
void swap_rows(unsigned a, unsigned b);
|
||||||
|
|
||||||
|
void multiply_row_by_constant(unsigned row, T & t);
|
||||||
|
|
||||||
|
};
|
||||||
|
template <typename T, typename X>
|
||||||
|
dense_matrix<T, X> operator* (matrix<T, X> & a, matrix<T, X> & b);
|
||||||
|
}
|
||||||
|
#endif
|
186
src/util/lp/dense_matrix.hpp
Normal file
186
src/util/lp/dense_matrix.hpp
Normal file
|
@ -0,0 +1,186 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#include "util/lp/lp_settings.h"
|
||||||
|
#ifdef LEAN_DEBUG
|
||||||
|
#include "util/vector.h"
|
||||||
|
#include "util/lp/numeric_pair.h"
|
||||||
|
#include "util/lp/dense_matrix.h"
|
||||||
|
namespace lean {
|
||||||
|
template <typename T> void print_vector(const vector<T> & t, std::ostream & out);
|
||||||
|
template <typename T, typename X> dense_matrix<T, X>::dense_matrix(unsigned m, unsigned n) : m_m(m), m_n(n), m_values(m * n, numeric_traits<T>::zero()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X> dense_matrix<T, X>&
|
||||||
|
dense_matrix<T, X>::operator=(matrix<T, X> const & other){
|
||||||
|
if ( this == & other)
|
||||||
|
return *this;
|
||||||
|
m_values = new T[m_m * m_n];
|
||||||
|
for (unsigned i = 0; i < m_m; i ++)
|
||||||
|
for (unsigned j = 0; j < m_n; j++)
|
||||||
|
m_values[i * m_n + j] = other.get_elem(i, j);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X> dense_matrix<T, X>&
|
||||||
|
dense_matrix<T, X>::operator=(dense_matrix const & other){
|
||||||
|
if ( this == & other)
|
||||||
|
return *this;
|
||||||
|
m_m = other.m_m;
|
||||||
|
m_n = other.m_n;
|
||||||
|
m_values.resize(m_m * m_n);
|
||||||
|
for (unsigned i = 0; i < m_m; i ++)
|
||||||
|
for (unsigned j = 0; j < m_n; j++)
|
||||||
|
m_values[i * m_n + j] = other.get_elem(i, j);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X> dense_matrix<T, X>::dense_matrix(matrix<T, X> const * other) :
|
||||||
|
m_m(other->row_count()),
|
||||||
|
m_n(other->column_count()) {
|
||||||
|
m_values.resize(m_m*m_n);
|
||||||
|
for (unsigned i = 0; i < m_m; i++)
|
||||||
|
for (unsigned j = 0; j < m_n; j++)
|
||||||
|
m_values[i * m_n + j] = other->get_elem(i, j);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X> void dense_matrix<T, X>::apply_from_right(T * w) {
|
||||||
|
T * t = new T[m_m];
|
||||||
|
for (int i = 0; i < m_m; i ++) {
|
||||||
|
T v = numeric_traits<T>::zero();
|
||||||
|
for (int j = 0; j < m_m; j++) {
|
||||||
|
v += w[j]* get_elem(j, i);
|
||||||
|
}
|
||||||
|
t[i] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < m_m; i++) {
|
||||||
|
w[i] = t[i];
|
||||||
|
}
|
||||||
|
delete [] t;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X> void dense_matrix<T, X>::apply_from_right(vector <T> & w) {
|
||||||
|
vector<T> t(m_m, numeric_traits<T>::zero());
|
||||||
|
for (unsigned i = 0; i < m_m; i ++) {
|
||||||
|
auto & v = t[i];
|
||||||
|
for (unsigned j = 0; j < m_m; j++)
|
||||||
|
v += w[j]* get_elem(j, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < m_m; i++)
|
||||||
|
w[i] = t[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X> T* dense_matrix<T, X>::
|
||||||
|
apply_from_left_with_different_dims(vector<T> & w) {
|
||||||
|
T * t = new T[m_m];
|
||||||
|
for (int i = 0; i < m_m; i ++) {
|
||||||
|
T v = numeric_traits<T>::zero();
|
||||||
|
for (int j = 0; j < m_n; j++) {
|
||||||
|
v += w[j]* get_elem(i, j);
|
||||||
|
}
|
||||||
|
t[i] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X> void dense_matrix<T, X>::apply_from_left(vector<T> & w) {
|
||||||
|
T * t = new T[m_m];
|
||||||
|
for (unsigned i = 0; i < m_m; i ++) {
|
||||||
|
T v = numeric_traits<T>::zero();
|
||||||
|
for (unsigned j = 0; j < m_m; j++) {
|
||||||
|
v += w[j]* get_elem(i, j);
|
||||||
|
}
|
||||||
|
t[i] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < m_m; i ++) {
|
||||||
|
w[i] = t[i];
|
||||||
|
}
|
||||||
|
delete [] t;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X> void dense_matrix<T, X>::apply_from_left(X * w, lp_settings & ) {
|
||||||
|
T * t = new T[m_m];
|
||||||
|
for (int i = 0; i < m_m; i ++) {
|
||||||
|
T v = numeric_traits<T>::zero();
|
||||||
|
for (int j = 0; j < m_m; j++) {
|
||||||
|
v += w[j]* get_elem(i, j);
|
||||||
|
}
|
||||||
|
t[i] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < m_m; i ++) {
|
||||||
|
w[i] = t[i];
|
||||||
|
}
|
||||||
|
delete [] t;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X> void dense_matrix<T, X>::apply_from_left_to_X(vector<X> & w, lp_settings & ) {
|
||||||
|
vector<X> t(m_m);
|
||||||
|
for (int i = 0; i < m_m; i ++) {
|
||||||
|
X v = zero_of_type<X>();
|
||||||
|
for (int j = 0; j < m_m; j++) {
|
||||||
|
v += w[j]* get_elem(i, j);
|
||||||
|
}
|
||||||
|
t[i] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < m_m; i ++) {
|
||||||
|
w[i] = t[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method pivots row i to row i0 by muliplying row i by
|
||||||
|
// alpha and adding it to row i0.
|
||||||
|
template <typename T, typename X> void dense_matrix<T, X>::pivot_row_to_row(unsigned i, const T& alpha, unsigned i0,
|
||||||
|
const double & pivot_epsilon) {
|
||||||
|
for (unsigned j = 0; j < m_n; j++) {
|
||||||
|
m_values[i0 * m_n + j] += m_values[i * m_n + j] * alpha;
|
||||||
|
if (fabs(m_values[i0 + m_n + j]) < pivot_epsilon) {
|
||||||
|
m_values[i0 + m_n + j] = numeric_traits<T>::zero();;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X> void dense_matrix<T, X>::swap_columns(unsigned a, unsigned b) {
|
||||||
|
for (unsigned i = 0; i < m_m; i++) {
|
||||||
|
T t = get_elem(i, a);
|
||||||
|
set_elem(i, a, get_elem(i, b));
|
||||||
|
set_elem(i, b, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X> void dense_matrix<T, X>::swap_rows(unsigned a, unsigned b) {
|
||||||
|
for (unsigned i = 0; i < m_n; i++) {
|
||||||
|
T t = get_elem(a, i);
|
||||||
|
set_elem(a, i, get_elem(b, i));
|
||||||
|
set_elem(b, i, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X> void dense_matrix<T, X>::multiply_row_by_constant(unsigned row, T & t) {
|
||||||
|
for (unsigned i = 0; i < m_n; i++) {
|
||||||
|
set_elem(row, i, t * get_elem(row, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename X>
|
||||||
|
dense_matrix<T, X> operator* (matrix<T, X> & a, matrix<T, X> & b){
|
||||||
|
lean_assert(a.column_count() == b.row_count());
|
||||||
|
dense_matrix<T, X> ret(a.row_count(), b.column_count());
|
||||||
|
for (unsigned i = 0; i < ret.m_m; i++)
|
||||||
|
for (unsigned j = 0; j< ret.m_n; j++) {
|
||||||
|
T v = numeric_traits<T>::zero();
|
||||||
|
for (unsigned k = 0; k < a.column_count(); k ++){
|
||||||
|
v += (a.get_elem(i, k) * b.get_elem(k, j));
|
||||||
|
}
|
||||||
|
ret.set_elem(i, j, v);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
24
src/util/lp/dense_matrix_instances.cpp
Normal file
24
src/util/lp/dense_matrix_instances.cpp
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#include "util/lp/lp_settings.h"
|
||||||
|
#include "util/lp/dense_matrix.hpp"
|
||||||
|
#ifdef LEAN_DEBUG
|
||||||
|
#include "util/vector.h"
|
||||||
|
template lean::dense_matrix<double, double> lean::operator*<double, double>(lean::matrix<double, double>&, lean::matrix<double, double>&);
|
||||||
|
template void lean::dense_matrix<double, double>::apply_from_left(vector<double> &);
|
||||||
|
template lean::dense_matrix<double, double>::dense_matrix(lean::matrix<double, double> const*);
|
||||||
|
template lean::dense_matrix<double, double>::dense_matrix(unsigned int, unsigned int);
|
||||||
|
template lean::dense_matrix<double, double>& lean::dense_matrix<double, double>::operator=(lean::dense_matrix<double, double> const&);
|
||||||
|
template lean::dense_matrix<lean::mpq, lean::numeric_pair<lean::mpq> >::dense_matrix(lean::matrix<lean::mpq, lean::numeric_pair<lean::mpq> > const*);
|
||||||
|
template void lean::dense_matrix<lean::mpq, lean::numeric_pair<lean::mpq> >::apply_from_left(vector<lean::mpq>&);
|
||||||
|
template lean::dense_matrix<lean::mpq, lean::mpq> lean::operator*<lean::mpq, lean::mpq>(lean::matrix<lean::mpq, lean::mpq>&, lean::matrix<lean::mpq, lean::mpq>&);
|
||||||
|
template lean::dense_matrix<lean::mpq, lean::mpq> & lean::dense_matrix<lean::mpq, lean::mpq>::operator=(lean::dense_matrix<lean::mpq, lean::mpq> const&);
|
||||||
|
template lean::dense_matrix<lean::mpq, lean::numeric_pair<lean::mpq> >::dense_matrix(unsigned int, unsigned int);
|
||||||
|
template lean::dense_matrix<lean::mpq, lean::numeric_pair<lean::mpq> >& lean::dense_matrix<lean::mpq, lean::numeric_pair<lean::mpq> >::operator=(lean::dense_matrix<lean::mpq, lean::numeric_pair<lean::mpq> > const&);
|
||||||
|
template lean::dense_matrix<lean::mpq, lean::numeric_pair<lean::mpq> > lean::operator*<lean::mpq, lean::numeric_pair<lean::mpq> >(lean::matrix<lean::mpq, lean::numeric_pair<lean::mpq> >&, lean::matrix<lean::mpq, lean::numeric_pair<lean::mpq> >&);
|
||||||
|
template void lean::dense_matrix<lean::mpq, lean::numeric_pair< lean::mpq> >::apply_from_right( vector< lean::mpq> &);
|
||||||
|
template void lean::dense_matrix<double,double>::apply_from_right(class vector<double> &);
|
||||||
|
template void lean::dense_matrix<lean::mpq, lean::mpq>::apply_from_left(vector<lean::mpq>&);
|
||||||
|
#endif
|
83
src/util/lp/eta_matrix.h
Normal file
83
src/util/lp/eta_matrix.h
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "util/vector.h"
|
||||||
|
#include "util/lp/tail_matrix.h"
|
||||||
|
#include "util/lp/permutation_matrix.h"
|
||||||
|
namespace lean {
|
||||||
|
|
||||||
|
// This is the sum of a unit matrix and a one-column matrix
|
||||||
|
template <typename T, typename X>
|
||||||
|
class eta_matrix
|
||||||
|
: public tail_matrix<T, X> {
|
||||||
|
#ifdef LEAN_DEBUG
|
||||||
|
unsigned m_length;
|
||||||
|
#endif
|
||||||
|
unsigned m_column_index;
|
||||||
|
public:
|
||||||
|
sparse_vector<T> m_column_vector;
|
||||||
|
T m_diagonal_element;
|
||||||
|
#ifdef LEAN_DEBUG
|
||||||
|
eta_matrix(unsigned column_index, unsigned length):
|
||||||
|
#else
|
||||||
|
eta_matrix(unsigned column_index):
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef LEAN_DEBUG
|
||||||
|
m_length(length),
|
||||||
|
#endif
|
||||||
|
m_column_index(column_index) {}
|
||||||
|
|
||||||
|
bool is_dense() const { return false; }
|
||||||
|
|
||||||
|
void print(std::ostream & out) {
|
||||||
|
print_matrix(*this, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_unit() {
|
||||||
|
return m_column_vector.size() == 0 && m_diagonal_element == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool set_diagonal_element(T const & diagonal_element) {
|
||||||
|
m_diagonal_element = diagonal_element;
|
||||||
|
return !lp_settings::is_eps_small_general(diagonal_element, 1e-12);
|
||||||
|
}
|
||||||
|
|
||||||
|
const T & get_diagonal_element() const {
|
||||||
|
return m_diagonal_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply_from_left(vector<X> & w, lp_settings & );
|
||||||
|
|
||||||
|
template <typename L>
|
||||||
|
void apply_from_left_local(indexed_vector<L> & w, lp_settings & settings);
|
||||||
|
|
||||||
|
void apply_from_left_to_T(indexed_vector<T> & w, lp_settings & settings) {
|
||||||
|
apply_from_left_local(w, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void push_back(unsigned row_index, T val ) {
|
||||||
|
lean_assert(row_index != m_column_index);
|
||||||
|
m_column_vector.push_back(row_index, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply_from_right(vector<T> & w);
|
||||||
|
void apply_from_right(indexed_vector<T> & w);
|
||||||
|
|
||||||
|
T get_elem(unsigned i, unsigned j) const;
|
||||||
|
#ifdef LEAN_DEBUG
|
||||||
|
unsigned row_count() const { return m_length; }
|
||||||
|
unsigned column_count() const { return m_length; }
|
||||||
|
void set_number_of_rows(unsigned m) { m_length = m; }
|
||||||
|
void set_number_of_columns(unsigned n) { m_length = n; }
|
||||||
|
#endif
|
||||||
|
void divide_by_diagonal_element() {
|
||||||
|
m_column_vector.divide(m_diagonal_element);
|
||||||
|
}
|
||||||
|
void conjugate_by_permutation(permutation_matrix<T, X> & p);
|
||||||
|
};
|
||||||
|
}
|
136
src/util/lp/eta_matrix.hpp
Normal file
136
src/util/lp/eta_matrix.hpp
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "util/vector.h"
|
||||||
|
#include "util/lp/eta_matrix.h"
|
||||||
|
namespace lean {
|
||||||
|
|
||||||
|
// This is the sum of a unit matrix and a one-column matrix
|
||||||
|
template <typename T, typename X>
|
||||||
|
void eta_matrix<T, X>::apply_from_left(vector<X> & w, lp_settings & ) {
|
||||||
|
auto & w_at_column_index = w[m_column_index];
|
||||||
|
for (auto & it : m_column_vector.m_data) {
|
||||||
|
w[it.first] += w_at_column_index * it.second;
|
||||||
|
}
|
||||||
|
w_at_column_index /= m_diagonal_element;
|
||||||
|
}
|
||||||
|
template <typename T, typename X>
|
||||||
|
template <typename L>
|
||||||
|
void eta_matrix<T, X>::
|
||||||
|
apply_from_left_local(indexed_vector<L> & w, lp_settings & settings) {
|
||||||
|
const L w_at_column_index = w[m_column_index];
|
||||||
|
if (is_zero(w_at_column_index)) return;
|
||||||
|
|
||||||
|
if (settings.abs_val_is_smaller_than_drop_tolerance(w[m_column_index] /= m_diagonal_element)) {
|
||||||
|
w[m_column_index] = zero_of_type<L>();
|
||||||
|
w.erase_from_index(m_column_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto & it : m_column_vector.m_data) {
|
||||||
|
unsigned i = it.first;
|
||||||
|
if (is_zero(w[i])) {
|
||||||
|
L v = w[i] = w_at_column_index * it.second;
|
||||||
|
if (settings.abs_val_is_smaller_than_drop_tolerance(v)) {
|
||||||
|
w[i] = zero_of_type<L>();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
w.m_index.push_back(i);
|
||||||
|
} else {
|
||||||
|
L v = w[i] += w_at_column_index * it.second;
|
||||||
|
if (settings.abs_val_is_smaller_than_drop_tolerance(v)) {
|
||||||
|
w[i] = zero_of_type<L>();
|
||||||
|
w.erase_from_index(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template <typename T, typename X>
|
||||||
|
void eta_matrix<T, X>::apply_from_right(vector<T> & w) {
|
||||||
|
#ifdef LEAN_DEBUG
|
||||||
|
// dense_matrix<T, X> deb(*this);
|
||||||
|
// auto clone_w = clone_vector<T>(w, get_number_of_rows());
|
||||||
|
// deb.apply_from_right(clone_w);
|
||||||
|
#endif
|
||||||
|
T t = w[m_column_index] / m_diagonal_element;
|
||||||
|
for (auto & it : m_column_vector.m_data) {
|
||||||
|
t += w[it.first] * it.second;
|
||||||
|
}
|
||||||
|
w[m_column_index] = t;
|
||||||
|
#ifdef LEAN_DEBUG
|
||||||
|
// lean_assert(vectors_are_equal<T>(clone_w, w, get_number_of_rows()));
|
||||||
|
// delete clone_w;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
template <typename T, typename X>
|
||||||
|
void eta_matrix<T, X>::apply_from_right(indexed_vector<T> & w) {
|
||||||
|
if (w.m_index.size() == 0)
|
||||||
|
return;
|
||||||
|
#ifdef LEAN_DEBUG
|
||||||
|
// vector<T> wcopy(w.m_data);
|
||||||
|
// apply_from_right(wcopy);
|
||||||
|
#endif
|
||||||
|
T & t = w[m_column_index];
|
||||||
|
t /= m_diagonal_element;
|
||||||
|
bool was_in_index = (!numeric_traits<T>::is_zero(t));
|
||||||
|
|
||||||
|
for (auto & it : m_column_vector.m_data) {
|
||||||
|
t += w[it.first] * it.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numeric_traits<T>::precise() ) {
|
||||||
|
if (!numeric_traits<T>::is_zero(t)) {
|
||||||
|
if (!was_in_index)
|
||||||
|
w.m_index.push_back(m_column_index);
|
||||||
|
} else {
|
||||||
|
if (was_in_index)
|
||||||
|
w.erase_from_index(m_column_index);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!lp_settings::is_eps_small_general(t, 1e-14)) {
|
||||||
|
if (!was_in_index)
|
||||||
|
w.m_index.push_back(m_column_index);
|
||||||
|
} else {
|
||||||
|
if (was_in_index)
|
||||||
|
w.erase_from_index(m_column_index);
|
||||||
|
t = zero_of_type<T>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LEAN_DEBUG
|
||||||
|
// lean_assert(w.is_OK());
|
||||||
|
// lean_assert(vectors_are_equal<T>(wcopy, w.m_data));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#ifdef LEAN_DEBUG
|
||||||
|
template <typename T, typename X>
|
||||||
|
T eta_matrix<T, X>::get_elem(unsigned i, unsigned j) const {
|
||||||
|
if (j == m_column_index){
|
||||||
|
if (i == j) {
|
||||||
|
return 1 / m_diagonal_element;
|
||||||
|
}
|
||||||
|
return m_column_vector[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return i == j ? numeric_traits<T>::one() : numeric_traits<T>::zero();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
template <typename T, typename X>
|
||||||
|
void eta_matrix<T, X>::conjugate_by_permutation(permutation_matrix<T, X> & p) {
|
||||||
|
// this = p * this * p(-1)
|
||||||
|
#ifdef LEAN_DEBUG
|
||||||
|
// auto rev = p.get_reverse();
|
||||||
|
// auto deb = ((*this) * rev);
|
||||||
|
// deb = p * deb;
|
||||||
|
#endif
|
||||||
|
m_column_index = p.get_rev(m_column_index);
|
||||||
|
for (auto & pair : m_column_vector.m_data) {
|
||||||
|
pair.first = p.get_rev(pair.first);
|
||||||
|
}
|
||||||
|
#ifdef LEAN_DEBUG
|
||||||
|
// lean_assert(deb == *this);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
28
src/util/lp/eta_matrix_instances.cpp
Normal file
28
src/util/lp/eta_matrix_instances.cpp
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#include <memory>
|
||||||
|
#include "util/vector.h"
|
||||||
|
#include "util/lp/numeric_pair.h"
|
||||||
|
#include "util/lp/eta_matrix.hpp"
|
||||||
|
#ifdef LEAN_DEBUG
|
||||||
|
template double lean::eta_matrix<double, double>::get_elem(unsigned int, unsigned int) const;
|
||||||
|
template lean::mpq lean::eta_matrix<lean::mpq, lean::mpq>::get_elem(unsigned int, unsigned int) const;
|
||||||
|
template lean::mpq lean::eta_matrix<lean::mpq, lean::numeric_pair<lean::mpq> >::get_elem(unsigned int, unsigned int) const;
|
||||||
|
#endif
|
||||||
|
template void lean::eta_matrix<double, double>::apply_from_left(vector<double>&, lean::lp_settings&);
|
||||||
|
template void lean::eta_matrix<double, double>::apply_from_right(vector<double>&);
|
||||||
|
template void lean::eta_matrix<double, double>::conjugate_by_permutation(lean::permutation_matrix<double, double>&);
|
||||||
|
template void lean::eta_matrix<lean::mpq, lean::mpq>::apply_from_left(vector<lean::mpq>&, lean::lp_settings&);
|
||||||
|
template void lean::eta_matrix<lean::mpq, lean::mpq>::apply_from_right(vector<lean::mpq>&);
|
||||||
|
template void lean::eta_matrix<lean::mpq, lean::mpq>::conjugate_by_permutation(lean::permutation_matrix<lean::mpq, lean::mpq>&);
|
||||||
|
template void lean::eta_matrix<lean::mpq, lean::numeric_pair<lean::mpq> >::apply_from_left(vector<lean::numeric_pair<lean::mpq> >&, lean::lp_settings&);
|
||||||
|
template void lean::eta_matrix<lean::mpq, lean::numeric_pair<lean::mpq> >::apply_from_right(vector<lean::mpq>&);
|
||||||
|
template void lean::eta_matrix<lean::mpq, lean::numeric_pair<lean::mpq> >::conjugate_by_permutation(lean::permutation_matrix<lean::mpq, lean::numeric_pair<lean::mpq> >&);
|
||||||
|
template void lean::eta_matrix<double, double>::apply_from_left_local<double>(lean::indexed_vector<double>&, lean::lp_settings&);
|
||||||
|
template void lean::eta_matrix<lean::mpq, lean::mpq>::apply_from_left_local<lean::mpq>(lean::indexed_vector<lean::mpq>&, lean::lp_settings&);
|
||||||
|
template void lean::eta_matrix<lean::mpq, lean::numeric_pair<lean::mpq> >::apply_from_left_local<lean::mpq>(lean::indexed_vector<lean::mpq>&, lean::lp_settings&);
|
||||||
|
template void lean::eta_matrix<lean::mpq, lean::numeric_pair<lean::mpq> >::apply_from_right(lean::indexed_vector<lean::mpq>&);
|
||||||
|
template void lean::eta_matrix<lean::mpq, lean::mpq>::apply_from_right(lean::indexed_vector<lean::mpq>&);
|
||||||
|
template void lean::eta_matrix<double, double>::apply_from_right(lean::indexed_vector<double>&);
|
39
src/util/lp/hash_helper.h
Normal file
39
src/util/lp/hash_helper.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <utility>
|
||||||
|
#include <functional>
|
||||||
|
#include "util/numerics/mpq.h"
|
||||||
|
#ifdef __CLANG__
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wmismatched-tags"
|
||||||
|
#endif
|
||||||
|
namespace std {
|
||||||
|
template<>
|
||||||
|
struct hash<lean::mpq> {
|
||||||
|
inline size_t operator()(const lean::mpq & v) const {
|
||||||
|
return v.hash();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline void hash_combine(std::size_t & seed, const T & v) {
|
||||||
|
seed ^= std::hash<T>()(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
template<typename S, typename T> struct hash<pair<S, T>> {
|
||||||
|
inline size_t operator()(const pair<S, T> & v) const {
|
||||||
|
size_t seed = 0;
|
||||||
|
hash_combine(seed, v.first);
|
||||||
|
hash_combine(seed, v.second);
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#ifdef __CLANG__
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
42
src/util/lp/implied_bound.h
Normal file
42
src/util/lp/implied_bound.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include "util/lp/lp_settings.h"
|
||||||
|
#include "util/lp/lar_constraints.h"
|
||||||
|
namespace lean {
|
||||||
|
struct implied_bound {
|
||||||
|
mpq m_bound;
|
||||||
|
unsigned m_j; // the column for which the bound has been found
|
||||||
|
bool m_is_low_bound;
|
||||||
|
bool m_coeff_before_j_is_pos;
|
||||||
|
unsigned m_row_or_term_index;
|
||||||
|
bool m_strict;
|
||||||
|
|
||||||
|
lconstraint_kind kind() const {
|
||||||
|
lconstraint_kind k = m_is_low_bound? GE : LE;
|
||||||
|
if (m_strict)
|
||||||
|
k = static_cast<lconstraint_kind>(k / 2);
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
bool operator==(const implied_bound & o) const {
|
||||||
|
return m_j == o.m_j && m_is_low_bound == o.m_is_low_bound && m_bound == o.m_bound &&
|
||||||
|
m_coeff_before_j_is_pos == o.m_coeff_before_j_is_pos &&
|
||||||
|
m_row_or_term_index == o.m_row_or_term_index && m_strict == o.m_strict;
|
||||||
|
}
|
||||||
|
implied_bound(){}
|
||||||
|
implied_bound(const mpq & a,
|
||||||
|
unsigned j,
|
||||||
|
bool low_bound,
|
||||||
|
bool coeff_before_j_is_pos,
|
||||||
|
unsigned row_or_term_index,
|
||||||
|
bool strict):
|
||||||
|
m_bound(a),
|
||||||
|
m_j(j),
|
||||||
|
m_is_low_bound(low_bound),
|
||||||
|
m_coeff_before_j_is_pos(coeff_before_j_is_pos),
|
||||||
|
m_row_or_term_index(row_or_term_index),
|
||||||
|
m_strict(strict) {}
|
||||||
|
};
|
||||||
|
}
|
55
src/util/lp/indexed_value.h
Normal file
55
src/util/lp/indexed_value.h
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace lean {
|
||||||
|
template <typename T>
|
||||||
|
class indexed_value {
|
||||||
|
public:
|
||||||
|
T m_value;
|
||||||
|
// the idea is that m_index for a row element gives its column, and for a column element its row
|
||||||
|
unsigned m_index;
|
||||||
|
// m_other point is the offset of the corresponding element in its vector : for a row element it point to the column element offset,
|
||||||
|
// for a column element it points to the row element offset
|
||||||
|
unsigned m_other;
|
||||||
|
indexed_value() {}
|
||||||
|
indexed_value(T v, unsigned i) : m_value(v), m_index(i) {}
|
||||||
|
indexed_value(T v, unsigned i, unsigned other) :
|
||||||
|
m_value(v), m_index(i), m_other(other) {
|
||||||
|
}
|
||||||
|
|
||||||
|
indexed_value(const indexed_value & iv) {
|
||||||
|
m_value = iv.m_value;
|
||||||
|
m_index = iv.m_index;
|
||||||
|
m_other = iv.m_other;
|
||||||
|
}
|
||||||
|
|
||||||
|
indexed_value & operator=(const indexed_value & right_side) {
|
||||||
|
m_value = right_side.m_value;
|
||||||
|
m_index = right_side.m_index;
|
||||||
|
m_other = right_side.m_other;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const T & value() const {
|
||||||
|
return m_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_value(T val) {
|
||||||
|
m_value = val;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#ifdef LEAN_DEBUG
|
||||||
|
template <typename X>
|
||||||
|
bool check_vector_for_small_values(indexed_vector<X> & w, lp_settings & settings) {
|
||||||
|
for (unsigned i : w.m_index) {
|
||||||
|
const X & v = w[i];
|
||||||
|
if ((!is_zero(v)) && settings.abs_val_is_smaller_than_drop_tolerance(v))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
169
src/util/lp/indexed_vector.h
Normal file
169
src/util/lp/indexed_vector.h
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "util/vector.h"
|
||||||
|
#include "util/debug.h"
|
||||||
|
#include <string>
|
||||||
|
#include <iomanip>
|
||||||
|
#include "util/lp/lp_utils.h"
|
||||||
|
#include "util/lp/lp_settings.h"
|
||||||
|
#include <unordered_set>
|
||||||
|
namespace lean {
|
||||||
|
|
||||||
|
template <typename T> void print_vector(const vector<T> & t, std::ostream & out);
|
||||||
|
template <typename T> void print_vector(const buffer<T> & t, std::ostream & out);
|
||||||
|
template <typename T> void print_sparse_vector(const vector<T> & t, std::ostream & out);
|
||||||
|
|
||||||
|
void print_vector(const vector<mpq> & t, std::ostream & out);
|
||||||
|
template <typename T>
|
||||||
|
class indexed_vector {
|
||||||
|
public:
|
||||||
|
// m_index points to non-zero elements of m_data
|
||||||
|
vector<T> m_data;
|
||||||
|
vector<unsigned> m_index;
|
||||||
|
indexed_vector(unsigned data_size) {
|
||||||
|
m_data.resize(data_size, numeric_traits<T>::zero());
|
||||||
|
}
|
||||||
|
|
||||||
|
indexed_vector& operator=(const indexed_vector<T>& y) {
|
||||||
|
for (unsigned i: m_index)
|
||||||
|
m_data[i] = zero_of_type<T>();
|
||||||
|
|
||||||
|
m_index = y.m_index;
|
||||||
|
|
||||||
|
m_data.resize(y.data_size());
|
||||||
|
for (unsigned i : m_index)
|
||||||
|
m_data[i] = y[i];
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const indexed_vector<T>& y) const {
|
||||||
|
std::unordered_set<unsigned> y_index;
|
||||||
|
for (unsigned i : y.m_index)
|
||||||
|
y_index.insert(i);
|
||||||
|
|
||||||
|
std::unordered_set<unsigned> this_index;
|
||||||
|
for (unsigned i : m_index)
|
||||||
|
this_index.insert(i);
|
||||||
|
|
||||||
|
for (unsigned i : y.m_index) {
|
||||||
|
if (this_index.find(i) == this_index.end())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned i : m_index) {
|
||||||
|
if (y_index.find(i) == y_index.end())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return vectors_are_equal(m_data, m_data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
indexed_vector() {}
|
||||||
|
|
||||||
|
void resize(unsigned data_size);
|
||||||
|
unsigned data_size() const {
|
||||||
|
return m_data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned size() {
|
||||||
|
return m_index.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_value(const T& value, unsigned index);
|
||||||
|
void set_value_as_in_dictionary(unsigned index) {
|
||||||
|
lean_assert(index < m_data.size());
|
||||||
|
T & loc = m_data[index];
|
||||||
|
if (is_zero(loc)) {
|
||||||
|
m_index.push_back(index);
|
||||||
|
loc = one_of_type<T>(); // use as a characteristic function
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
void clear_all();
|
||||||
|
const T& operator[] (unsigned i) const {
|
||||||
|
return m_data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
T& operator[] (unsigned i) {
|
||||||
|
return m_data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void clean_up() {
|
||||||
|
#if 0==1
|
||||||
|
for (unsigned k = 0; k < m_index.size(); k++) {
|
||||||
|
unsigned i = m_index[k];
|
||||||
|
T & v = m_data[i];
|
||||||
|
if (lp_settings::is_eps_small_general(v, 1e-14)) {
|
||||||
|
v = zero_of_type<T>();
|
||||||
|
m_index.erase(m_index.begin() + k--);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
vector<unsigned> index_copy;
|
||||||
|
for (unsigned i : m_index) {
|
||||||
|
T & v = m_data[i];
|
||||||
|
if (!lp_settings::is_eps_small_general(v, 1e-14)) {
|
||||||
|
index_copy.push_back(i);
|
||||||
|
} else if (!numeric_traits<T>::is_zero(v)) {
|
||||||
|
v = zero_of_type<T>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_index = index_copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void erase_from_index(unsigned j);
|
||||||
|
|
||||||
|
void add_value_at_index_with_drop_tolerance(unsigned j, const T& val_to_add) {
|
||||||
|
T & v = m_data[j];
|
||||||
|
bool was_zero = is_zero(v);
|
||||||
|
v += val_to_add;
|
||||||
|
if (lp_settings::is_eps_small_general(v, 1e-14)) {
|
||||||
|
v = zero_of_type<T>();
|
||||||
|
if (!was_zero) {
|
||||||
|
erase_from_index(j);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (was_zero)
|
||||||
|
m_index.push_back(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_value_at_index(unsigned j, const T& val_to_add) {
|
||||||
|
T & v = m_data[j];
|
||||||
|
bool was_zero = is_zero(v);
|
||||||
|
v += val_to_add;
|
||||||
|
if (is_zero(v)) {
|
||||||
|
if (!was_zero)
|
||||||
|
erase_from_index(j);
|
||||||
|
} else {
|
||||||
|
if (was_zero)
|
||||||
|
m_index.push_back(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void restore_index_and_clean_from_data() {
|
||||||
|
m_index.resize(0);
|
||||||
|
for (unsigned i = 0; i < m_data.size(); i++) {
|
||||||
|
T & v = m_data[i];
|
||||||
|
if (lp_settings::is_eps_small_general(v, 1e-14)) {
|
||||||
|
v = zero_of_type<T>();
|
||||||
|
} else {
|
||||||
|
m_index.push_back(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LEAN_DEBUG
|
||||||
|
bool is_OK() const;
|
||||||
|
void print(std::ostream & out);
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
}
|
110
src/util/lp/indexed_vector.hpp
Normal file
110
src/util/lp/indexed_vector.hpp
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#include "util/vector.h"
|
||||||
|
#include "util/lp/indexed_vector.h"
|
||||||
|
#include "util/lp/lp_settings.h"
|
||||||
|
namespace lean {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void print_vector(const vector<T> & t, std::ostream & out) {
|
||||||
|
for (unsigned i = 0; i < t.size(); i++)
|
||||||
|
out << t[i] << " ";
|
||||||
|
out << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void print_vector(const buffer<T> & t, std::ostream & out) {
|
||||||
|
for (unsigned i = 0; i < t.size(); i++)
|
||||||
|
out << t[i] << " ";
|
||||||
|
out << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void print_sparse_vector(const vector<T> & t, std::ostream & out) {
|
||||||
|
for (unsigned i = 0; i < t.size(); i++) {
|
||||||
|
if (is_zero(t[i]))continue;
|
||||||
|
out << "[" << i << "] = " << t[i] << ", ";
|
||||||
|
}
|
||||||
|
out << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_vector(const vector<mpq> & t, std::ostream & out) {
|
||||||
|
for (unsigned i = 0; i < t.size(); i++)
|
||||||
|
out << t[i].get_double() << std::setprecision(3) << " ";
|
||||||
|
out << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void indexed_vector<T>::resize(unsigned data_size) {
|
||||||
|
clear();
|
||||||
|
m_data.resize(data_size, numeric_traits<T>::zero());
|
||||||
|
lean_assert(is_OK());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void indexed_vector<T>::set_value(const T& value, unsigned index) {
|
||||||
|
m_data[index] = value;
|
||||||
|
lean_assert(std::find(m_index.begin(), m_index.end(), index) == m_index.end());
|
||||||
|
m_index.push_back(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void indexed_vector<T>::clear() {
|
||||||
|
for (unsigned i : m_index)
|
||||||
|
m_data[i] = numeric_traits<T>::zero();
|
||||||
|
m_index.resize(0);
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
void indexed_vector<T>::clear_all() {
|
||||||
|
unsigned i = m_data.size();
|
||||||
|
while (i--) m_data[i] = numeric_traits<T>::zero();
|
||||||
|
m_index.resize(0);
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
void indexed_vector<T>::erase_from_index(unsigned j) {
|
||||||
|
auto it = std::find(m_index.begin(), m_index.end(), j);
|
||||||
|
if (it != m_index.end())
|
||||||
|
m_index.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LEAN_DEBUG
|
||||||
|
template <typename T>
|
||||||
|
bool indexed_vector<T>::is_OK() const {
|
||||||
|
return true;
|
||||||
|
const double drop_eps = 1e-14;
|
||||||
|
for (unsigned i = 0; i < m_data.size(); i++) {
|
||||||
|
if (!is_zero(m_data[i]) && lp_settings::is_eps_small_general(m_data[i], drop_eps)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (lp_settings::is_eps_small_general(m_data[i], drop_eps) != (std::find(m_index.begin(), m_index.end(), i) == m_index.end())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_set<unsigned> s;
|
||||||
|
for (unsigned i : m_index) {
|
||||||
|
//no duplicates!!!
|
||||||
|
if (s.find(i) != s.end())
|
||||||
|
return false;
|
||||||
|
s.insert(i);
|
||||||
|
if (i >= m_data.size())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
void indexed_vector<T>::print(std::ostream & out) {
|
||||||
|
out << "m_index " << std::endl;
|
||||||
|
for (unsigned i = 0; i < m_index.size(); i++) {
|
||||||
|
out << m_index[i] << " ";
|
||||||
|
}
|
||||||
|
out << std::endl;
|
||||||
|
print_vector(m_data, out);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
36
src/util/lp/indexed_vector_instances.cpp
Normal file
36
src/util/lp/indexed_vector_instances.cpp
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#include "util/vector.h"
|
||||||
|
#include "util/lp/indexed_vector.hpp"
|
||||||
|
namespace lean {
|
||||||
|
template void indexed_vector<double>::clear();
|
||||||
|
template void indexed_vector<double>::clear_all();
|
||||||
|
template void indexed_vector<double>::erase_from_index(unsigned int);
|
||||||
|
template void indexed_vector<double>::set_value(const double&, unsigned int);
|
||||||
|
template void indexed_vector<mpq>::clear();
|
||||||
|
template void indexed_vector<unsigned>::clear();
|
||||||
|
template void indexed_vector<mpq>::clear_all();
|
||||||
|
template void indexed_vector<mpq>::erase_from_index(unsigned int);
|
||||||
|
template void indexed_vector<mpq>::resize(unsigned int);
|
||||||
|
template void indexed_vector<unsigned>::resize(unsigned int);
|
||||||
|
template void indexed_vector<mpq>::set_value(const mpq&, unsigned int);
|
||||||
|
template void indexed_vector<unsigned>::set_value(const unsigned&, unsigned int);
|
||||||
|
#ifdef LEAN_DEBUG
|
||||||
|
template bool indexed_vector<double>::is_OK() const;
|
||||||
|
template bool indexed_vector<mpq>::is_OK() const;
|
||||||
|
template bool indexed_vector<lean::numeric_pair<mpq> >::is_OK() const;
|
||||||
|
template void lean::indexed_vector< lean::mpq>::print(std::basic_ostream<char,struct std::char_traits<char> > &);
|
||||||
|
template void lean::indexed_vector<double>::print(std::basic_ostream<char,struct std::char_traits<char> > &);
|
||||||
|
template void lean::indexed_vector<lean::numeric_pair<lean::mpq> >::print(std::ostream&);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
template void lean::print_vector<double>(vector<double> const&, std::ostream&);
|
||||||
|
template void lean::print_vector<unsigned int>(vector<unsigned int> const&, std::ostream&);
|
||||||
|
template void lean::print_vector<std::string>(vector<std::string> const&, std::ostream&);
|
||||||
|
template void lean::print_vector<lean::numeric_pair<lean::mpq> >(vector<lean::numeric_pair<lean::mpq>> const&, std::ostream&);
|
||||||
|
template void lean::indexed_vector<double>::resize(unsigned int);
|
||||||
|
template void lean::print_vector< lean::mpq>(vector< lean::mpq> const &, std::basic_ostream<char, std::char_traits<char> > &);
|
||||||
|
template void lean::print_vector<std::pair<lean::mpq, unsigned int> >(vector<std::pair<lean::mpq, unsigned int>> const&, std::ostream&);
|
||||||
|
template void lean::indexed_vector<lean::numeric_pair<lean::mpq> >::erase_from_index(unsigned int);
|
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();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
66
src/util/lp/int_set.h
Normal file
66
src/util/lp/int_set.h
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include "util/vector.h"
|
||||||
|
#include "util/lp/indexed_vector.h"
|
||||||
|
#include <ostream>
|
||||||
|
namespace lean {
|
||||||
|
// serves at a set of non-negative integers smaller than the set size
|
||||||
|
class int_set {
|
||||||
|
vector<int> m_data;
|
||||||
|
public:
|
||||||
|
vector<int> m_index;
|
||||||
|
int_set(unsigned size): m_data(size, -1) {}
|
||||||
|
int_set() {}
|
||||||
|
bool contains(unsigned j) const {
|
||||||
|
if (j >= m_data.size())
|
||||||
|
return false;
|
||||||
|
return m_data[j] >= 0;
|
||||||
|
}
|
||||||
|
void insert(unsigned j) {
|
||||||
|
lean_assert(j < m_data.size());
|
||||||
|
if (contains(j)) return;
|
||||||
|
m_data[j] = m_index.size();
|
||||||
|
m_index.push_back(j);
|
||||||
|
}
|
||||||
|
void erase(unsigned j) {
|
||||||
|
if (!contains(j)) return;
|
||||||
|
unsigned pos_j = m_data[j];
|
||||||
|
unsigned last_pos = m_index.size() - 1;
|
||||||
|
int last_j = m_index[last_pos];
|
||||||
|
if (last_pos != pos_j) {
|
||||||
|
// move last to j spot
|
||||||
|
m_data[last_j] = pos_j;
|
||||||
|
m_index[pos_j] = last_j;
|
||||||
|
}
|
||||||
|
m_index.pop_back();
|
||||||
|
m_data[j] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resize(unsigned size) {
|
||||||
|
m_data.resize(size, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void increase_size_by_one() {
|
||||||
|
resize(m_data.size() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned data_size() const { return m_data.size(); }
|
||||||
|
unsigned size() const { return m_index.size();}
|
||||||
|
bool is_empty() const { return size() == 0; }
|
||||||
|
void clear() {
|
||||||
|
for (unsigned j : m_index)
|
||||||
|
m_data[j] = -1;
|
||||||
|
m_index.resize(0);
|
||||||
|
}
|
||||||
|
void print(std::ostream & out ) const {
|
||||||
|
for (unsigned j : m_index) {
|
||||||
|
out << j << " ";
|
||||||
|
}
|
||||||
|
out << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
50
src/util/lp/iterator_on_column.h
Normal file
50
src/util/lp/iterator_on_column.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include "util/lp/linear_combination_iterator.h"
|
||||||
|
#include "util/lp/static_matrix.h"
|
||||||
|
#include "util/lp/lar_term.h"
|
||||||
|
namespace lean {
|
||||||
|
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; // 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
|
||||||
|
:
|
||||||
|
m_column(column),
|
||||||
|
m_A(A),
|
||||||
|
m_i(-1) {}
|
||||||
|
|
||||||
|
bool next(mpq & a, unsigned & i) {
|
||||||
|
if (++m_i >= static_cast<int>(m_column.size()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const column_cell& c = m_column[m_i];
|
||||||
|
a = m_A.get_val(c);
|
||||||
|
i = c.m_i;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool next(unsigned & i) {
|
||||||
|
if (++m_i >= static_cast<int>(m_column.size()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const column_cell& c = m_column[m_i];
|
||||||
|
i = c.m_i;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
m_i = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
linear_combination_iterator<mpq> * clone() {
|
||||||
|
iterator_on_column * r = new iterator_on_column(m_column, m_A);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
38
src/util/lp/iterator_on_indexed_vector.h
Normal file
38
src/util/lp/iterator_on_indexed_vector.h
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include "util/lp/linear_combination_iterator.h"
|
||||||
|
namespace lean {
|
||||||
|
template <typename T>
|
||||||
|
struct iterator_on_indexed_vector:linear_combination_iterator<T> {
|
||||||
|
const indexed_vector<T> & m_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())
|
||||||
|
return false;
|
||||||
|
i = m_v.m_index[m_offset++];
|
||||||
|
a = m_v.m_data[i];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool next(unsigned & i) {
|
||||||
|
if (m_offset >= m_v.m_index.size())
|
||||||
|
return false;
|
||||||
|
i = m_v.m_index[m_offset++];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void reset() {
|
||||||
|
m_offset = 0;
|
||||||
|
}
|
||||||
|
linear_combination_iterator<T>* clone() {
|
||||||
|
return new iterator_on_indexed_vector(m_v);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
44
src/util/lp/iterator_on_pivot_row.h
Normal file
44
src/util/lp/iterator_on_pivot_row.h
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include "util/lp/iterator_on_indexed_vector.h"
|
||||||
|
namespace lean {
|
||||||
|
template <typename T>
|
||||||
|
struct iterator_on_pivot_row:linear_combination_iterator<T> {
|
||||||
|
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_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;
|
||||||
|
a = one_of_type<T>();
|
||||||
|
i = m_basis_j;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return m_it.next(a, i);
|
||||||
|
}
|
||||||
|
bool next(unsigned & i) {
|
||||||
|
if (m_basis_returned == false) {
|
||||||
|
m_basis_returned = true;
|
||||||
|
i = m_basis_j;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return m_it.next(i);
|
||||||
|
}
|
||||||
|
void reset() {
|
||||||
|
m_basis_returned = false;
|
||||||
|
m_it.reset();
|
||||||
|
}
|
||||||
|
linear_combination_iterator<T> * clone() {
|
||||||
|
iterator_on_pivot_row * r = new iterator_on_pivot_row(m_v, m_basis_j);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
37
src/util/lp/iterator_on_row.h
Normal file
37
src/util/lp/iterator_on_row.h
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include "util/lp/linear_combination_iterator.h"
|
||||||
|
namespace lean {
|
||||||
|
template <typename T>
|
||||||
|
struct iterator_on_row:linear_combination_iterator<T> {
|
||||||
|
const vector<row_cell<T>> & m_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) {
|
||||||
|
if (m_i == m_row.size())
|
||||||
|
return false;
|
||||||
|
auto &c = m_row[m_i++];
|
||||||
|
i = c.m_j;
|
||||||
|
a = c.get_val();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool next(unsigned & i) {
|
||||||
|
if (m_i == m_row.size())
|
||||||
|
return false;
|
||||||
|
auto &c = m_row[m_i++];
|
||||||
|
i = c.m_j;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void reset() {
|
||||||
|
m_i = 0;
|
||||||
|
}
|
||||||
|
linear_combination_iterator<T>* clone() {
|
||||||
|
return new iterator_on_row(m_row);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
57
src/util/lp/iterator_on_term_with_basis_var.h
Normal file
57
src/util/lp/iterator_on_term_with_basis_var.h
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include "util/lp/linear_combination_iterator.h"
|
||||||
|
#include "util/lp/numeric_pair.h"
|
||||||
|
#include "util/lp/lar_term.h"
|
||||||
|
namespace lean {
|
||||||
|
struct iterator_on_term_with_basis_var:linear_combination_iterator<mpq> {
|
||||||
|
const lar_term & m_term;
|
||||||
|
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_term(t),
|
||||||
|
m_i(t.m_coeffs.begin()),
|
||||||
|
m_term_j_returned(false),
|
||||||
|
m_term_j(term_j) {}
|
||||||
|
|
||||||
|
bool next(mpq & a, unsigned & i) {
|
||||||
|
if (m_term_j_returned == false) {
|
||||||
|
m_term_j_returned = true;
|
||||||
|
a = - one_of_type<mpq>();
|
||||||
|
i = m_term_j;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (m_i == m_term.m_coeffs.end())
|
||||||
|
return false;
|
||||||
|
i = m_i->first;
|
||||||
|
a = m_i->second;
|
||||||
|
m_i++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool next(unsigned & i) {
|
||||||
|
if (m_term_j_returned == false) {
|
||||||
|
m_term_j_returned = true;
|
||||||
|
i = m_term_j;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (m_i == m_term.m_coeffs.end())
|
||||||
|
return false;
|
||||||
|
i = m_i->first;
|
||||||
|
m_i++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void reset() {
|
||||||
|
m_term_j_returned = false;
|
||||||
|
m_i = m_term.m_coeffs.begin();
|
||||||
|
}
|
||||||
|
linear_combination_iterator<mpq> * clone() {
|
||||||
|
iterator_on_term_with_basis_var * r = new iterator_on_term_with_basis_var(m_term, m_term_j);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
86
src/util/lp/lar_constraints.h
Normal file
86
src/util/lp/lar_constraints.h
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "util/vector.h"
|
||||||
|
#include <utility>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <string>
|
||||||
|
#include <algorithm>
|
||||||
|
#include "util/lp/lp_utils.h"
|
||||||
|
#include "util/lp/ul_pair.h"
|
||||||
|
#include "util/lp/lar_term.h"
|
||||||
|
namespace lean {
|
||||||
|
inline lconstraint_kind flip_kind(lconstraint_kind t) {
|
||||||
|
return static_cast<lconstraint_kind>( - static_cast<int>(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string lconstraint_kind_string(lconstraint_kind t) {
|
||||||
|
switch (t) {
|
||||||
|
case LE: return std::string("<=");
|
||||||
|
case LT: return std::string("<");
|
||||||
|
case GE: return std::string(">=");
|
||||||
|
case GT: return std::string(">");
|
||||||
|
case EQ: return std::string("=");
|
||||||
|
}
|
||||||
|
lean_unreachable();
|
||||||
|
return std::string(); // it is unreachable
|
||||||
|
}
|
||||||
|
|
||||||
|
class lar_base_constraint {
|
||||||
|
public:
|
||||||
|
lconstraint_kind m_kind;
|
||||||
|
mpq m_right_side;
|
||||||
|
virtual vector<std::pair<mpq, var_index>> get_left_side_coefficients() const = 0;
|
||||||
|
lar_base_constraint() {}
|
||||||
|
lar_base_constraint(lconstraint_kind kind, const mpq& right_side) :m_kind(kind), m_right_side(right_side) {}
|
||||||
|
|
||||||
|
virtual unsigned size() const = 0;
|
||||||
|
virtual ~lar_base_constraint(){}
|
||||||
|
virtual mpq get_free_coeff_of_left_side() const { return zero_of_type<mpq>();}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lar_var_constraint: public lar_base_constraint {
|
||||||
|
unsigned m_j;
|
||||||
|
vector<std::pair<mpq, var_index>> get_left_side_coefficients() const {
|
||||||
|
vector<std::pair<mpq, var_index>> ret;
|
||||||
|
ret.push_back(std::make_pair(one_of_type<mpq>(), m_j));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
unsigned size() const { return 1;}
|
||||||
|
lar_var_constraint(unsigned j, lconstraint_kind kind, const mpq& right_side) : lar_base_constraint(kind, right_side), m_j(j) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct lar_term_constraint: public lar_base_constraint {
|
||||||
|
const lar_term * m_term;
|
||||||
|
vector<std::pair<mpq, var_index>> get_left_side_coefficients() const {
|
||||||
|
return m_term->coeffs_as_vector();
|
||||||
|
}
|
||||||
|
unsigned size() const { return m_term->size();}
|
||||||
|
lar_term_constraint(const lar_term *t, lconstraint_kind kind, const mpq& right_side) : lar_base_constraint(kind, right_side), m_term(t) { }
|
||||||
|
virtual mpq get_free_coeff_of_left_side() const { return m_term->m_v;}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class lar_constraint : public lar_base_constraint {
|
||||||
|
public:
|
||||||
|
vector<std::pair<mpq, var_index>> m_coeffs;
|
||||||
|
lar_constraint() {}
|
||||||
|
lar_constraint(const vector<std::pair<mpq, var_index>> & left_side, lconstraint_kind kind, const mpq & right_side)
|
||||||
|
: lar_base_constraint(kind, right_side), m_coeffs(left_side) {}
|
||||||
|
|
||||||
|
lar_constraint(const lar_base_constraint & c) {
|
||||||
|
lean_assert(false); // should not be called : todo!
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned size() const {
|
||||||
|
return static_cast<unsigned>(m_coeffs.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<std::pair<mpq, var_index>> get_left_side_coefficients() const { return m_coeffs; }
|
||||||
|
};
|
||||||
|
}
|
801
src/util/lp/lar_core_solver.h
Normal file
801
src/util/lp/lar_core_solver.h
Normal file
|
@ -0,0 +1,801 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include "util/vector.h"
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include "util/lp/lp_core_solver_base.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include "util/lp/indexed_vector.h"
|
||||||
|
#include "util/lp/binary_heap_priority_queue.h"
|
||||||
|
#include "util/lp/breakpoint.h"
|
||||||
|
#include "util/lp/stacked_unordered_set.h"
|
||||||
|
#include "util/lp/lp_primal_core_solver.h"
|
||||||
|
#include "util/lp/stacked_vector.h"
|
||||||
|
#include "util/lp/lar_solution_signature.h"
|
||||||
|
#include "util/lp/iterator_on_column.h"
|
||||||
|
#include "util/lp/iterator_on_indexed_vector.h"
|
||||||
|
#include "util/lp/stacked_value.h"
|
||||||
|
namespace lean {
|
||||||
|
|
||||||
|
class lar_core_solver {
|
||||||
|
// m_sign_of_entering is set to 1 if the entering variable needs
|
||||||
|
// 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; // 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;
|
||||||
|
vector<double> m_d_costs_dummy;
|
||||||
|
public:
|
||||||
|
stacked_value<simplex_strategy_enum> m_stacked_simplex_strategy;
|
||||||
|
stacked_vector<column_type> m_column_types;
|
||||||
|
// r - solver fields, for rational numbers
|
||||||
|
vector<numeric_pair<mpq>> m_r_x; // the solution
|
||||||
|
stacked_vector<numeric_pair<mpq>> m_r_low_bounds;
|
||||||
|
stacked_vector<numeric_pair<mpq>> m_r_upper_bounds;
|
||||||
|
static_matrix<mpq, numeric_pair<mpq>> m_r_A;
|
||||||
|
stacked_vector<unsigned> m_r_pushed_basis;
|
||||||
|
vector<unsigned> m_r_basis;
|
||||||
|
vector<unsigned> m_r_nbasis;
|
||||||
|
vector<int> m_r_heading;
|
||||||
|
stacked_vector<unsigned> m_r_columns_nz;
|
||||||
|
stacked_vector<unsigned> m_r_rows_nz;
|
||||||
|
|
||||||
|
// d - solver fields, for doubles
|
||||||
|
vector<double> m_d_x; // the solution in doubles
|
||||||
|
vector<double> m_d_low_bounds;
|
||||||
|
vector<double> m_d_upper_bounds;
|
||||||
|
static_matrix<double, double> m_d_A;
|
||||||
|
stacked_vector<unsigned> m_d_pushed_basis;
|
||||||
|
vector<unsigned> m_d_basis;
|
||||||
|
vector<unsigned> m_d_nbasis;
|
||||||
|
vector<int> m_d_heading;
|
||||||
|
|
||||||
|
|
||||||
|
lp_primal_core_solver<mpq, numeric_pair<mpq>> m_r_solver; // solver in rational numbers
|
||||||
|
|
||||||
|
lp_primal_core_solver<double, double> m_d_solver; // solver in doubles
|
||||||
|
|
||||||
|
lar_core_solver(
|
||||||
|
lp_settings & settings,
|
||||||
|
const column_namer & column_names
|
||||||
|
);
|
||||||
|
|
||||||
|
lp_settings & settings() { return m_r_solver.m_settings;}
|
||||||
|
const lp_settings & settings() const { return m_r_solver.m_settings;}
|
||||||
|
|
||||||
|
int get_infeasible_sum_sign() const { return m_infeasible_sum_sign; }
|
||||||
|
|
||||||
|
const vector<std::pair<mpq, unsigned>> & get_infeasibility_info(int & inf_sign) const {
|
||||||
|
inf_sign = m_infeasible_sum_sign;
|
||||||
|
return m_infeasible_linear_combination;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fill_not_improvable_zero_sum_from_inf_row();
|
||||||
|
|
||||||
|
column_type get_column_type(unsigned j) { return m_column_types[j];}
|
||||||
|
|
||||||
|
void init_costs(bool first_time);
|
||||||
|
|
||||||
|
void init_cost_for_column(unsigned j);
|
||||||
|
|
||||||
|
// returns m_sign_of_alpha_r
|
||||||
|
int column_is_out_of_bounds(unsigned j);
|
||||||
|
|
||||||
|
void calculate_pivot_row(unsigned i);
|
||||||
|
|
||||||
|
void print_pivot_row(std::ostream & out, unsigned row_index) const { // remove later debug !!!!
|
||||||
|
for (unsigned j : m_r_solver.m_pivot_row.m_index) {
|
||||||
|
if (numeric_traits<mpq>::is_pos(m_r_solver.m_pivot_row.m_data[j]))
|
||||||
|
out << "+";
|
||||||
|
out << m_r_solver.m_pivot_row.m_data[j] << m_r_solver.column_name(j) << " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
out << " +" << m_r_solver.column_name(m_r_solver.m_basis[row_index]) << std::endl;
|
||||||
|
|
||||||
|
for (unsigned j : m_r_solver.m_pivot_row.m_index) {
|
||||||
|
m_r_solver.print_column_bound_info(j, out);
|
||||||
|
}
|
||||||
|
m_r_solver.print_column_bound_info(m_r_solver.m_basis[row_index], out);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void advance_on_sorted_breakpoints(unsigned entering);
|
||||||
|
|
||||||
|
void change_slope_on_breakpoint(unsigned entering, breakpoint<numeric_pair<mpq>> * b, mpq & slope_at_entering);
|
||||||
|
|
||||||
|
bool row_is_infeasible(unsigned row);
|
||||||
|
|
||||||
|
bool row_is_evidence(unsigned row);
|
||||||
|
|
||||||
|
bool find_evidence_row();
|
||||||
|
|
||||||
|
void prefix_r();
|
||||||
|
|
||||||
|
void prefix_d();
|
||||||
|
|
||||||
|
unsigned m_m() const {
|
||||||
|
return m_r_A.row_count();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned m_n() const {
|
||||||
|
return m_r_A.column_count();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_tiny() const { return this->m_m() < 10 && this->m_n() < 20; }
|
||||||
|
|
||||||
|
bool is_empty() const { return this->m_m() == 0 && this->m_n() == 0; }
|
||||||
|
|
||||||
|
template <typename L>
|
||||||
|
int get_sign(const L & v) {
|
||||||
|
return v > zero_of_type<L>() ? 1 : (v < zero_of_type<L>() ? -1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void fill_evidence(unsigned row);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void solve();
|
||||||
|
|
||||||
|
bool low_bounds_are_set() const { return true; }
|
||||||
|
|
||||||
|
const indexed_vector<mpq> & get_pivot_row() const {
|
||||||
|
return m_r_solver.m_pivot_row;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fill_not_improvable_zero_sum();
|
||||||
|
|
||||||
|
void pop_basis(unsigned k) {
|
||||||
|
if (!settings().use_tableau()) {
|
||||||
|
m_r_pushed_basis.pop(k);
|
||||||
|
m_r_basis = m_r_pushed_basis();
|
||||||
|
m_r_solver.init_basis_heading_and_non_basic_columns_vector();
|
||||||
|
m_d_pushed_basis.pop(k);
|
||||||
|
m_d_basis = m_d_pushed_basis();
|
||||||
|
m_d_solver.init_basis_heading_and_non_basic_columns_vector();
|
||||||
|
} else {
|
||||||
|
m_d_basis = m_r_basis;
|
||||||
|
m_d_nbasis = m_r_nbasis;
|
||||||
|
m_d_heading = m_r_heading;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void push() {
|
||||||
|
lean_assert(m_r_solver.basis_heading_is_correct());
|
||||||
|
lean_assert(!need_to_presolve_with_double_solver() || m_d_solver.basis_heading_is_correct());
|
||||||
|
lean_assert(m_column_types.size() == m_r_A.column_count());
|
||||||
|
m_stacked_simplex_strategy = settings().simplex_strategy();
|
||||||
|
m_stacked_simplex_strategy.push();
|
||||||
|
m_column_types.push();
|
||||||
|
// rational
|
||||||
|
if (!settings().use_tableau())
|
||||||
|
m_r_A.push();
|
||||||
|
m_r_low_bounds.push();
|
||||||
|
m_r_upper_bounds.push();
|
||||||
|
if (!settings().use_tableau()) {
|
||||||
|
push_vector(m_r_pushed_basis, m_r_basis);
|
||||||
|
push_vector(m_r_columns_nz, m_r_solver.m_columns_nz);
|
||||||
|
push_vector(m_r_rows_nz, m_r_solver.m_rows_nz);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_d_A.push();
|
||||||
|
if (!settings().use_tableau())
|
||||||
|
push_vector(m_d_pushed_basis, m_d_basis);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename K>
|
||||||
|
void push_vector(stacked_vector<K> & pushed_vector, const vector<K> & vector) {
|
||||||
|
lean_assert(pushed_vector.size() <= vector.size());
|
||||||
|
for (unsigned i = 0; i < vector.size();i++) {
|
||||||
|
if (i == pushed_vector.size()) {
|
||||||
|
pushed_vector.push_back(vector[i]);
|
||||||
|
} else {
|
||||||
|
pushed_vector[i] = vector[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pushed_vector.push();
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_markowitz_counts(unsigned k) {
|
||||||
|
m_r_columns_nz.pop(k);
|
||||||
|
m_r_rows_nz.pop(k);
|
||||||
|
m_r_solver.m_columns_nz.resize(m_r_columns_nz.size());
|
||||||
|
m_r_solver.m_rows_nz.resize(m_r_rows_nz.size());
|
||||||
|
for (unsigned i = 0; i < m_r_columns_nz.size(); i++)
|
||||||
|
m_r_solver.m_columns_nz[i] = m_r_columns_nz[i];
|
||||||
|
for (unsigned i = 0; i < m_r_rows_nz.size(); i++)
|
||||||
|
m_r_solver.m_rows_nz[i] = m_r_rows_nz[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void pop(unsigned k) {
|
||||||
|
// rationals
|
||||||
|
if (!settings().use_tableau())
|
||||||
|
m_r_A.pop(k);
|
||||||
|
m_r_low_bounds.pop(k);
|
||||||
|
m_r_upper_bounds.pop(k);
|
||||||
|
m_column_types.pop(k);
|
||||||
|
|
||||||
|
if (m_r_solver.m_factorization != nullptr) {
|
||||||
|
delete m_r_solver.m_factorization;
|
||||||
|
m_r_solver.m_factorization = nullptr;
|
||||||
|
}
|
||||||
|
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(!settings().use_tableau())
|
||||||
|
pop_markowitz_counts(k);
|
||||||
|
m_d_A.pop(k);
|
||||||
|
if (m_d_solver.m_factorization != nullptr) {
|
||||||
|
delete m_d_solver.m_factorization;
|
||||||
|
m_d_solver.m_factorization = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
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().simplex_strategy() == simplex_strategy_enum::lu;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename L>
|
||||||
|
bool is_zero_vector(const vector<L> & b) {
|
||||||
|
for (const L & m: b)
|
||||||
|
if (!is_zero(m)) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool update_xj_and_get_delta(unsigned j, non_basic_column_value_position pos_type, numeric_pair<mpq> & delta) {
|
||||||
|
auto & x = m_r_x[j];
|
||||||
|
switch (pos_type) {
|
||||||
|
case at_low_bound:
|
||||||
|
if (x == m_r_solver.m_low_bounds[j])
|
||||||
|
return false;
|
||||||
|
delta = m_r_solver.m_low_bounds[j] - x;
|
||||||
|
m_r_solver.m_x[j] = m_r_solver.m_low_bounds[j];
|
||||||
|
break;
|
||||||
|
case at_fixed:
|
||||||
|
case at_upper_bound:
|
||||||
|
if (x == m_r_solver.m_upper_bounds[j])
|
||||||
|
return false;
|
||||||
|
delta = m_r_solver.m_upper_bounds[j] - x;
|
||||||
|
x = m_r_solver.m_upper_bounds[j];
|
||||||
|
break;
|
||||||
|
case free_of_bounds: {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case not_at_bound:
|
||||||
|
switch (m_column_types[j]) {
|
||||||
|
case column_type::free_column:
|
||||||
|
return false;
|
||||||
|
case column_type::upper_bound:
|
||||||
|
delta = m_r_solver.m_upper_bounds[j] - x;
|
||||||
|
x = m_r_solver.m_upper_bounds[j];
|
||||||
|
break;
|
||||||
|
case column_type::low_bound:
|
||||||
|
delta = m_r_solver.m_low_bounds[j] - x;
|
||||||
|
x = m_r_solver.m_low_bounds[j];
|
||||||
|
break;
|
||||||
|
case column_type::boxed:
|
||||||
|
if (x > m_r_solver.m_upper_bounds[j]) {
|
||||||
|
delta = m_r_solver.m_upper_bounds[j] - x;
|
||||||
|
x += m_r_solver.m_upper_bounds[j];
|
||||||
|
} else {
|
||||||
|
delta = m_r_solver.m_low_bounds[j] - x;
|
||||||
|
x = m_r_solver.m_low_bounds[j];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case column_type::fixed:
|
||||||
|
delta = m_r_solver.m_low_bounds[j] - x;
|
||||||
|
x = m_r_solver.m_low_bounds[j];
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
lean_assert(false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
lean_unreachable();
|
||||||
|
}
|
||||||
|
m_r_solver.remove_column_from_inf_set(j);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void prepare_solver_x_with_signature_tableau(const lar_solution_signature & signature) {
|
||||||
|
lean_assert(m_r_solver.inf_set_is_correct());
|
||||||
|
for (auto &t : signature) {
|
||||||
|
unsigned j = t.first;
|
||||||
|
if (m_r_heading[j] >= 0)
|
||||||
|
continue;
|
||||||
|
auto pos_type = t.second;
|
||||||
|
numeric_pair<mpq> delta;
|
||||||
|
if (!update_xj_and_get_delta(j, pos_type, delta))
|
||||||
|
continue;
|
||||||
|
for (const auto & cc : m_r_solver.m_A.m_columns[j]){
|
||||||
|
unsigned i = cc.m_i;
|
||||||
|
unsigned jb = m_r_solver.m_basis[i];
|
||||||
|
m_r_solver.m_x[jb] -= delta * m_r_solver.m_A.get_val(cc);
|
||||||
|
m_r_solver.update_column_in_inf_set(jb);
|
||||||
|
}
|
||||||
|
lean_assert(m_r_solver.A_mult_x_is_off() == false);
|
||||||
|
}
|
||||||
|
lean_assert(m_r_solver.inf_set_is_correct());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename L, typename K>
|
||||||
|
void prepare_solver_x_with_signature(const lar_solution_signature & signature, lp_primal_core_solver<L,K> & s) {
|
||||||
|
for (auto &t : signature) {
|
||||||
|
unsigned j = t.first;
|
||||||
|
lean_assert(m_r_heading[j] < 0);
|
||||||
|
auto pos_type = t.second;
|
||||||
|
switch (pos_type) {
|
||||||
|
case at_low_bound:
|
||||||
|
s.m_x[j] = s.m_low_bounds[j];
|
||||||
|
break;
|
||||||
|
case at_fixed:
|
||||||
|
case at_upper_bound:
|
||||||
|
s.m_x[j] = s.m_upper_bounds[j];
|
||||||
|
break;
|
||||||
|
case free_of_bounds: {
|
||||||
|
s.m_x[j] = zero_of_type<K>();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
case not_at_bound:
|
||||||
|
switch (m_column_types[j]) {
|
||||||
|
case column_type::free_column:
|
||||||
|
lean_assert(false); // unreachable
|
||||||
|
case column_type::upper_bound:
|
||||||
|
s.m_x[j] = s.m_upper_bounds[j];
|
||||||
|
break;
|
||||||
|
case column_type::low_bound:
|
||||||
|
s.m_x[j] = s.m_low_bounds[j];
|
||||||
|
break;
|
||||||
|
case column_type::boxed:
|
||||||
|
if (settings().random_next() % 2) {
|
||||||
|
s.m_x[j] = s.m_low_bounds[j];
|
||||||
|
} else {
|
||||||
|
s.m_x[j] = s.m_upper_bounds[j];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case column_type::fixed:
|
||||||
|
s.m_x[j] = s.m_low_bounds[j];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
lean_assert(false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
lean_unreachable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lean_assert(is_zero_vector(s.m_b));
|
||||||
|
s.solve_Ax_eq_b();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename L, typename K>
|
||||||
|
void catch_up_in_lu_in_reverse(const vector<unsigned> & trace_of_basis_change, lp_primal_core_solver<L,K> & cs) {
|
||||||
|
// recover the previous working basis
|
||||||
|
for (unsigned i = trace_of_basis_change.size(); i > 0; i-= 2) {
|
||||||
|
unsigned entering = trace_of_basis_change[i-1];
|
||||||
|
unsigned leaving = trace_of_basis_change[i-2];
|
||||||
|
cs.change_basis_unconditionally(entering, leaving);
|
||||||
|
}
|
||||||
|
cs.init_lu();
|
||||||
|
}
|
||||||
|
|
||||||
|
//basis_heading is the basis heading of the solver owning trace_of_basis_change
|
||||||
|
// here we compact the trace as we go to avoid unnecessary column changes
|
||||||
|
template <typename L, typename K>
|
||||||
|
void catch_up_in_lu(const vector<unsigned> & trace_of_basis_change, const vector<int> & basis_heading, lp_primal_core_solver<L,K> & cs) {
|
||||||
|
if (cs.m_factorization == nullptr || cs.m_factorization->m_refactor_counter + trace_of_basis_change.size()/2 >= 200) {
|
||||||
|
for (unsigned i = 0; i < trace_of_basis_change.size(); i+= 2) {
|
||||||
|
unsigned entering = trace_of_basis_change[i];
|
||||||
|
unsigned leaving = trace_of_basis_change[i+1];
|
||||||
|
cs.change_basis_unconditionally(entering, leaving);
|
||||||
|
}
|
||||||
|
if (cs.m_factorization != nullptr)
|
||||||
|
delete cs.m_factorization;
|
||||||
|
cs.m_factorization = nullptr;
|
||||||
|
} else {
|
||||||
|
indexed_vector<L> w(cs.m_A.row_count());
|
||||||
|
// the queues of delayed indices
|
||||||
|
std::queue<unsigned> entr_q, leav_q;
|
||||||
|
auto * l = cs.m_factorization;
|
||||||
|
lean_assert(l->get_status() == LU_status::OK);
|
||||||
|
for (unsigned i = 0; i < trace_of_basis_change.size(); i+= 2) {
|
||||||
|
unsigned entering = trace_of_basis_change[i];
|
||||||
|
unsigned leaving = trace_of_basis_change[i+1];
|
||||||
|
bool good_e = basis_heading[entering] >= 0 && cs.m_basis_heading[entering] < 0;
|
||||||
|
bool good_l = basis_heading[leaving] < 0 && cs.m_basis_heading[leaving] >= 0;
|
||||||
|
if (!good_e && !good_l) continue;
|
||||||
|
if (good_e && !good_l) {
|
||||||
|
while (!leav_q.empty() && cs.m_basis_heading[leav_q.front()] < 0)
|
||||||
|
leav_q.pop();
|
||||||
|
if (!leav_q.empty()) {
|
||||||
|
leaving = leav_q.front();
|
||||||
|
leav_q.pop();
|
||||||
|
} else {
|
||||||
|
entr_q.push(entering);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if (!good_e && good_l) {
|
||||||
|
while (!entr_q.empty() && cs.m_basis_heading[entr_q.front()] >= 0)
|
||||||
|
entr_q.pop();
|
||||||
|
if (!entr_q.empty()) {
|
||||||
|
entering = entr_q.front();
|
||||||
|
entr_q.pop();
|
||||||
|
} else {
|
||||||
|
leav_q.push(leaving);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lean_assert(cs.m_basis_heading[entering] < 0);
|
||||||
|
lean_assert(cs.m_basis_heading[leaving] >= 0);
|
||||||
|
if (l->get_status() == LU_status::OK) {
|
||||||
|
l->prepare_entering(entering, w); // to init vector w
|
||||||
|
l->replace_column(zero_of_type<L>(), w, cs.m_basis_heading[leaving]);
|
||||||
|
}
|
||||||
|
cs.change_basis_unconditionally(entering, leaving);
|
||||||
|
}
|
||||||
|
if (l->get_status() != LU_status::OK) {
|
||||||
|
delete l;
|
||||||
|
cs.m_factorization = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cs.m_factorization == nullptr) {
|
||||||
|
if (numeric_traits<L>::precise())
|
||||||
|
init_factorization(cs.m_factorization, cs.m_A, cs.m_basis, settings());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool no_r_lu() const {
|
||||||
|
return m_r_solver.m_factorization == nullptr || m_r_solver.m_factorization->get_status() == LU_status::Degenerated;
|
||||||
|
}
|
||||||
|
|
||||||
|
void solve_on_signature_tableau(const lar_solution_signature & signature, const vector<unsigned> & changes_of_basis) {
|
||||||
|
r_basis_is_OK();
|
||||||
|
lean_assert(settings().use_tableau());
|
||||||
|
bool r = catch_up_in_lu_tableau(changes_of_basis, m_d_solver.m_basis_heading);
|
||||||
|
|
||||||
|
if (!r) { // it is the case where m_d_solver gives a degenerated basis
|
||||||
|
prepare_solver_x_with_signature_tableau(signature); // still are going to use the signature partially
|
||||||
|
m_r_solver.find_feasible_solution();
|
||||||
|
m_d_basis = m_r_basis;
|
||||||
|
m_d_heading = m_r_heading;
|
||||||
|
m_d_nbasis = m_r_nbasis;
|
||||||
|
delete m_d_solver.m_factorization;
|
||||||
|
m_d_solver.m_factorization = nullptr;
|
||||||
|
} else {
|
||||||
|
prepare_solver_x_with_signature_tableau(signature);
|
||||||
|
m_r_solver.start_tracing_basis_changes();
|
||||||
|
m_r_solver.find_feasible_solution();
|
||||||
|
if (settings().get_cancel_flag())
|
||||||
|
return;
|
||||||
|
m_r_solver.stop_tracing_basis_changes();
|
||||||
|
// and now catch up in the double solver
|
||||||
|
lean_assert(m_r_solver.total_iterations() >= m_r_solver.m_trace_of_basis_change_vector.size() /2);
|
||||||
|
catch_up_in_lu(m_r_solver.m_trace_of_basis_change_vector, m_r_solver.m_basis_heading, m_d_solver);
|
||||||
|
}
|
||||||
|
lean_assert(r_basis_is_OK());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool adjust_x_of_column(unsigned j) {
|
||||||
|
/*
|
||||||
|
if (m_r_solver.m_basis_heading[j] >= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_r_solver.column_is_feasible(j)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_r_solver.snap_column_to_bound_tableau(j);
|
||||||
|
lean_assert(m_r_solver.column_is_feasible(j));
|
||||||
|
m_r_solver.m_inf_set.erase(j);
|
||||||
|
*/
|
||||||
|
lean_assert(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool catch_up_in_lu_tableau(const vector<unsigned> & trace_of_basis_change, const vector<int> & basis_heading) {
|
||||||
|
lean_assert(r_basis_is_OK());
|
||||||
|
// the queues of delayed indices
|
||||||
|
std::queue<unsigned> entr_q, leav_q;
|
||||||
|
for (unsigned i = 0; i < trace_of_basis_change.size(); i+= 2) {
|
||||||
|
unsigned entering = trace_of_basis_change[i];
|
||||||
|
unsigned leaving = trace_of_basis_change[i+1];
|
||||||
|
bool good_e = basis_heading[entering] >= 0 && m_r_solver.m_basis_heading[entering] < 0;
|
||||||
|
bool good_l = basis_heading[leaving] < 0 && m_r_solver.m_basis_heading[leaving] >= 0;
|
||||||
|
if (!good_e && !good_l) continue;
|
||||||
|
if (good_e && !good_l) {
|
||||||
|
while (!leav_q.empty() && m_r_solver.m_basis_heading[leav_q.front()] < 0)
|
||||||
|
leav_q.pop();
|
||||||
|
if (!leav_q.empty()) {
|
||||||
|
leaving = leav_q.front();
|
||||||
|
leav_q.pop();
|
||||||
|
} else {
|
||||||
|
entr_q.push(entering);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if (!good_e && good_l) {
|
||||||
|
while (!entr_q.empty() && m_r_solver.m_basis_heading[entr_q.front()] >= 0)
|
||||||
|
entr_q.pop();
|
||||||
|
if (!entr_q.empty()) {
|
||||||
|
entering = entr_q.front();
|
||||||
|
entr_q.pop();
|
||||||
|
} else {
|
||||||
|
leav_q.push(leaving);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lean_assert(m_r_solver.m_basis_heading[entering] < 0);
|
||||||
|
lean_assert(m_r_solver.m_basis_heading[leaving] >= 0);
|
||||||
|
m_r_solver.change_basis_unconditionally(entering, leaving);
|
||||||
|
if(!m_r_solver.pivot_column_tableau(entering, m_r_solver.m_basis_heading[entering])) {
|
||||||
|
// unroll the last step
|
||||||
|
m_r_solver.change_basis_unconditionally(leaving, entering);
|
||||||
|
#ifdef LEAN_DEBUG
|
||||||
|
bool t =
|
||||||
|
#endif
|
||||||
|
m_r_solver.pivot_column_tableau(leaving, m_r_solver.m_basis_heading[leaving]);
|
||||||
|
#ifdef LEAN_DEBUG
|
||||||
|
lean_assert(t);
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lean_assert(r_basis_is_OK());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool r_basis_is_OK() const {
|
||||||
|
#ifdef LEAN_DEBUG
|
||||||
|
if (!m_r_solver.m_settings.use_tableau())
|
||||||
|
return true;
|
||||||
|
for (unsigned j : m_r_solver.m_basis) {
|
||||||
|
lean_assert(m_r_solver.m_A.m_columns[j].size() == 1);
|
||||||
|
lean_assert(m_r_solver.m_A.get_val(m_r_solver.m_A.m_columns[j][0]) == one_of_type<mpq>());
|
||||||
|
}
|
||||||
|
for (unsigned j =0; j < m_r_solver.m_basis_heading.size(); j++) {
|
||||||
|
if (m_r_solver.m_basis_heading[j] >= 0) continue;
|
||||||
|
if (m_r_solver.m_column_types[j] == column_type::fixed) continue;
|
||||||
|
lean_assert(static_cast<unsigned>(- m_r_solver.m_basis_heading[j] - 1) < m_r_solver.m_column_types.size());
|
||||||
|
lean_assert( m_r_solver.m_basis_heading[j] <= -1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void solve_on_signature(const lar_solution_signature & signature, const vector<unsigned> & changes_of_basis) {
|
||||||
|
lean_assert(!settings().use_tableau());
|
||||||
|
if (m_r_solver.m_factorization == nullptr) {
|
||||||
|
for (unsigned j = 0; j < changes_of_basis.size(); j+=2) {
|
||||||
|
unsigned entering = changes_of_basis[j];
|
||||||
|
unsigned leaving = changes_of_basis[j + 1];
|
||||||
|
m_r_solver.change_basis_unconditionally(entering, leaving);
|
||||||
|
}
|
||||||
|
init_factorization(m_r_solver.m_factorization, m_r_A, m_r_basis, settings());
|
||||||
|
} else {
|
||||||
|
catch_up_in_lu(changes_of_basis, m_d_solver.m_basis_heading, m_r_solver);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
catch_up_in_lu_in_reverse(changes_of_basis, m_r_solver);
|
||||||
|
m_r_solver.find_feasible_solution();
|
||||||
|
m_d_basis = m_r_basis;
|
||||||
|
m_d_heading = m_r_heading;
|
||||||
|
m_d_nbasis = m_r_nbasis;
|
||||||
|
delete m_d_solver.m_factorization;
|
||||||
|
m_d_solver.m_factorization = nullptr;
|
||||||
|
} else {
|
||||||
|
prepare_solver_x_with_signature(signature, m_r_solver);
|
||||||
|
m_r_solver.start_tracing_basis_changes();
|
||||||
|
m_r_solver.find_feasible_solution();
|
||||||
|
if (settings().get_cancel_flag())
|
||||||
|
return;
|
||||||
|
m_r_solver.stop_tracing_basis_changes();
|
||||||
|
// and now catch up in the double solver
|
||||||
|
lean_assert(m_r_solver.total_iterations() >= m_r_solver.m_trace_of_basis_change_vector.size() /2);
|
||||||
|
catch_up_in_lu(m_r_solver.m_trace_of_basis_change_vector, m_r_solver.m_basis_heading, m_d_solver);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void create_double_matrix(static_matrix<double, double> & A) {
|
||||||
|
for (unsigned i = 0; i < m_r_A.row_count(); i++) {
|
||||||
|
auto & row = m_r_A.m_rows[i];
|
||||||
|
for (row_cell<mpq> & c : row) {
|
||||||
|
A.set(i, c.m_j, c.get_val().get_double());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fill_basis_d(
|
||||||
|
vector<unsigned>& basis_d,
|
||||||
|
vector<int>& heading_d,
|
||||||
|
vector<unsigned>& nbasis_d){
|
||||||
|
basis_d = m_r_basis;
|
||||||
|
heading_d = m_r_heading;
|
||||||
|
nbasis_d = m_r_nbasis;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename L, typename K>
|
||||||
|
void extract_signature_from_lp_core_solver(const lp_primal_core_solver<L, K> & solver, lar_solution_signature & signature) {
|
||||||
|
signature.clear();
|
||||||
|
lean_assert(signature.size() == 0);
|
||||||
|
for (unsigned j = 0; j < solver.m_basis_heading.size(); j++) {
|
||||||
|
if (solver.m_basis_heading[j] < 0) {
|
||||||
|
signature[j] = solver.get_non_basic_column_value_position(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_bounds_for_double_solver() {
|
||||||
|
unsigned n = m_n();
|
||||||
|
m_d_low_bounds.resize(n);
|
||||||
|
m_d_upper_bounds.resize(n);
|
||||||
|
double delta = find_delta_for_strict_boxed_bounds().get_double();
|
||||||
|
if (delta > 0.000001)
|
||||||
|
delta = 0.000001;
|
||||||
|
for (unsigned j = 0; j < n; j++) {
|
||||||
|
if (low_bound_is_set(j)) {
|
||||||
|
const auto & lb = m_r_solver.m_low_bounds[j];
|
||||||
|
m_d_low_bounds[j] = lb.x.get_double() + delta * lb.y.get_double();
|
||||||
|
}
|
||||||
|
if (upper_bound_is_set(j)) {
|
||||||
|
const auto & ub = m_r_solver.m_upper_bounds[j];
|
||||||
|
m_d_upper_bounds[j] = ub.x.get_double() + delta * ub.y.get_double();
|
||||||
|
lean_assert(!low_bound_is_set(j) || (m_d_upper_bounds[j] >= m_d_low_bounds[j]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void scale_problem_for_doubles(
|
||||||
|
static_matrix<double, double>& A,
|
||||||
|
vector<double> & low_bounds,
|
||||||
|
vector<double> & upper_bounds) {
|
||||||
|
vector<double> column_scale_vector;
|
||||||
|
vector<double> right_side_vector(A.column_count());
|
||||||
|
settings().reps_in_scaler = 5;
|
||||||
|
scaler<double, double > scaler(right_side_vector,
|
||||||
|
A,
|
||||||
|
settings().scaling_minimum,
|
||||||
|
settings().scaling_maximum,
|
||||||
|
column_scale_vector,
|
||||||
|
settings());
|
||||||
|
if (! scaler.scale()) {
|
||||||
|
// the scale did not succeed, unscaling
|
||||||
|
A.clear();
|
||||||
|
create_double_matrix(A);
|
||||||
|
} else {
|
||||||
|
for (unsigned j = 0; j < A.column_count(); j++) {
|
||||||
|
if (m_r_solver.column_has_upper_bound(j)) {
|
||||||
|
upper_bounds[j] /= column_scale_vector[j];
|
||||||
|
}
|
||||||
|
if (m_r_solver.column_has_low_bound(j)) {
|
||||||
|
low_bounds[j] /= column_scale_vector[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// returns the trace of basis changes
|
||||||
|
vector<unsigned> find_solution_signature_with_doubles(lar_solution_signature & signature) {
|
||||||
|
if (m_d_solver.m_factorization == nullptr || m_d_solver.m_factorization->get_status() != LU_status::OK) {
|
||||||
|
vector<unsigned> ret;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
get_bounds_for_double_solver();
|
||||||
|
|
||||||
|
extract_signature_from_lp_core_solver(m_r_solver, signature);
|
||||||
|
prepare_solver_x_with_signature(signature, m_d_solver);
|
||||||
|
m_d_solver.start_tracing_basis_changes();
|
||||||
|
m_d_solver.find_feasible_solution();
|
||||||
|
if (settings().get_cancel_flag())
|
||||||
|
return vector<unsigned>();
|
||||||
|
|
||||||
|
m_d_solver.stop_tracing_basis_changes();
|
||||||
|
extract_signature_from_lp_core_solver(m_d_solver, signature);
|
||||||
|
return m_d_solver.m_trace_of_basis_change_vector;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool low_bound_is_set(unsigned j) const {
|
||||||
|
switch (m_column_types[j]) {
|
||||||
|
case column_type::free_column:
|
||||||
|
case column_type::upper_bound:
|
||||||
|
return false;
|
||||||
|
case column_type::low_bound:
|
||||||
|
case column_type::boxed:
|
||||||
|
case column_type::fixed:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
lean_assert(false);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool upper_bound_is_set(unsigned j) const {
|
||||||
|
switch (m_column_types[j]) {
|
||||||
|
case column_type::free_column:
|
||||||
|
case column_type::low_bound:
|
||||||
|
return false;
|
||||||
|
case column_type::upper_bound:
|
||||||
|
case column_type::boxed:
|
||||||
|
case column_type::fixed:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
lean_assert(false);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_delta(mpq& delta, numeric_pair<mpq> const& l, numeric_pair<mpq> const& u) const {
|
||||||
|
lean_assert(l <= u);
|
||||||
|
if (l.x < u.x && l.y > u.y) {
|
||||||
|
mpq delta1 = (u.x - l.x) / (l.y - u.y);
|
||||||
|
if (delta1 < delta) {
|
||||||
|
delta = delta1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lean_assert(l.x + delta * l.y <= u.x + delta * u.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
mpq find_delta_for_strict_boxed_bounds() const{
|
||||||
|
mpq delta = numeric_traits<mpq>::one();
|
||||||
|
for (unsigned j = 0; j < m_r_A.column_count(); j++ ) {
|
||||||
|
if (m_column_types()[j] != column_type::boxed)
|
||||||
|
continue;
|
||||||
|
update_delta(delta, m_r_low_bounds[j], m_r_upper_bounds[j]);
|
||||||
|
|
||||||
|
}
|
||||||
|
return delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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]);
|
||||||
|
if (upper_bound_is_set(j))
|
||||||
|
update_delta(delta, m_r_x[j], m_r_upper_bounds[j]);
|
||||||
|
}
|
||||||
|
return delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_column_row_nz_for_r_solver() {
|
||||||
|
m_r_solver.init_column_row_non_zeroes();
|
||||||
|
}
|
||||||
|
|
||||||
|
linear_combination_iterator<mpq> * get_column_iterator(unsigned j) {
|
||||||
|
if (settings().use_tableau()) {
|
||||||
|
return new iterator_on_column<mpq, numeric_pair<mpq>>(m_r_solver.m_A.m_columns[j], m_r_solver.m_A);
|
||||||
|
} else {
|
||||||
|
m_r_solver.solve_Bd(j);
|
||||||
|
return new iterator_on_indexed_vector<mpq>(m_r_solver.m_ed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
293
src/util/lp/lar_core_solver.hpp
Normal file
293
src/util/lp/lar_core_solver.hpp
Normal file
|
@ -0,0 +1,293 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#include <string>
|
||||||
|
#include "util/vector.h"
|
||||||
|
#include "util/lp/lar_core_solver.h"
|
||||||
|
#include "util/lp/lar_solution_signature.h"
|
||||||
|
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,
|
||||||
|
m_r_basis,
|
||||||
|
m_r_nbasis,
|
||||||
|
m_r_heading,
|
||||||
|
m_costs_dummy,
|
||||||
|
m_column_types(),
|
||||||
|
m_r_low_bounds(),
|
||||||
|
m_r_upper_bounds(),
|
||||||
|
settings,
|
||||||
|
column_names),
|
||||||
|
m_d_solver(m_d_A,
|
||||||
|
m_d_right_sides_dummy,
|
||||||
|
m_d_x,
|
||||||
|
m_d_basis,
|
||||||
|
m_d_nbasis,
|
||||||
|
m_d_heading,
|
||||||
|
m_d_costs_dummy,
|
||||||
|
m_column_types(),
|
||||||
|
m_d_low_bounds,
|
||||||
|
m_d_upper_bounds,
|
||||||
|
settings,
|
||||||
|
column_names){}
|
||||||
|
|
||||||
|
void lar_core_solver::init_costs(bool first_time) {
|
||||||
|
lean_assert(false); // should not be called
|
||||||
|
// lean_assert(this->m_x.size() >= this->m_n());
|
||||||
|
// lean_assert(this->m_column_types.size() >= this->m_n());
|
||||||
|
// if (first_time)
|
||||||
|
// this->m_costs.resize(this->m_n());
|
||||||
|
// X inf = this->m_infeasibility;
|
||||||
|
// this->m_infeasibility = zero_of_type<X>();
|
||||||
|
// for (unsigned j = this->m_n(); j--;)
|
||||||
|
// init_cost_for_column(j);
|
||||||
|
// if (!(first_time || inf >= this->m_infeasibility)) {
|
||||||
|
// LP_OUT(this->m_settings, "iter = " << this->total_iterations() << std::endl);
|
||||||
|
// LP_OUT(this->m_settings, "inf was " << T_to_string(inf) << " and now " << T_to_string(this->m_infeasibility) << std::endl);
|
||||||
|
// lean_assert(false);
|
||||||
|
// }
|
||||||
|
// if (inf == this->m_infeasibility)
|
||||||
|
// this->m_iters_with_no_cost_growing++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void lar_core_solver::init_cost_for_column(unsigned j) {
|
||||||
|
/*
|
||||||
|
// If j is a breakpoint column, then we set the cost zero.
|
||||||
|
// When anylyzing an entering column candidate we update the cost of the breakpoints columns to get the left or the right derivative if the infeasibility function
|
||||||
|
const numeric_pair<mpq> & x = this->m_x[j];
|
||||||
|
// set zero cost for each non-basis column
|
||||||
|
if (this->m_basis_heading[j] < 0) {
|
||||||
|
this->m_costs[j] = numeric_traits<T>::zero();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// j is a basis column
|
||||||
|
switch (this->m_column_types[j]) {
|
||||||
|
case fixed:
|
||||||
|
case column_type::boxed:
|
||||||
|
if (x > this->m_upper_bounds[j]) {
|
||||||
|
this->m_costs[j] = 1;
|
||||||
|
this->m_infeasibility += x - this->m_upper_bounds[j];
|
||||||
|
} else if (x < this->m_low_bounds[j]) {
|
||||||
|
this->m_infeasibility += this->m_low_bounds[j] - x;
|
||||||
|
this->m_costs[j] = -1;
|
||||||
|
} else {
|
||||||
|
this->m_costs[j] = numeric_traits<T>::zero();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case low_bound:
|
||||||
|
if (x < this->m_low_bounds[j]) {
|
||||||
|
this->m_costs[j] = -1;
|
||||||
|
this->m_infeasibility += this->m_low_bounds[j] - x;
|
||||||
|
} else {
|
||||||
|
this->m_costs[j] = numeric_traits<T>::zero();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case upper_bound:
|
||||||
|
if (x > this->m_upper_bounds[j]) {
|
||||||
|
this->m_costs[j] = 1;
|
||||||
|
this->m_infeasibility += x - this->m_upper_bounds[j];
|
||||||
|
} else {
|
||||||
|
this->m_costs[j] = numeric_traits<T>::zero();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case free_column:
|
||||||
|
this->m_costs[j] = numeric_traits<T>::zero();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
lean_assert(false);
|
||||||
|
break;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// returns m_sign_of_alpha_r
|
||||||
|
int lar_core_solver::column_is_out_of_bounds(unsigned j) {
|
||||||
|
/*
|
||||||
|
switch (this->m_column_type[j]) {
|
||||||
|
case fixed:
|
||||||
|
case column_type::boxed:
|
||||||
|
if (this->x_below_low_bound(j)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (this->x_above_upper_bound(j)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
case low_bound:
|
||||||
|
if (this->x_below_low_bound(j)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
case upper_bound:
|
||||||
|
if (this->x_above_upper_bound(j)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
}*/
|
||||||
|
lean_assert(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void lar_core_solver::calculate_pivot_row(unsigned i) {
|
||||||
|
lean_assert(!m_r_solver.use_tableau());
|
||||||
|
lean_assert(m_r_solver.m_pivot_row.is_OK());
|
||||||
|
m_r_solver.m_pivot_row_of_B_1.clear();
|
||||||
|
m_r_solver.m_pivot_row_of_B_1.resize(m_r_solver.m_m());
|
||||||
|
m_r_solver.m_pivot_row.clear();
|
||||||
|
m_r_solver.m_pivot_row.resize(m_r_solver.m_n());
|
||||||
|
if (m_r_solver.m_settings.use_tableau()) {
|
||||||
|
unsigned basis_j = m_r_solver.m_basis[i];
|
||||||
|
for (auto & c : m_r_solver.m_A.m_rows[i]) {
|
||||||
|
if (c.m_j != basis_j)
|
||||||
|
m_r_solver.m_pivot_row.set_value(c.get_val(), c.m_j);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_r_solver.calculate_pivot_row_of_B_1(i);
|
||||||
|
m_r_solver.calculate_pivot_row_when_pivot_row_of_B1_is_ready(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void lar_core_solver::prefix_r() {
|
||||||
|
if (!m_r_solver.m_settings.use_tableau()) {
|
||||||
|
m_r_solver.m_copy_of_xB.resize(m_r_solver.m_n());
|
||||||
|
m_r_solver.m_ed.resize(m_r_solver.m_m());
|
||||||
|
m_r_solver.m_pivot_row.resize(m_r_solver.m_n());
|
||||||
|
m_r_solver.m_pivot_row_of_B_1.resize(m_r_solver.m_m());
|
||||||
|
m_r_solver.m_w.resize(m_r_solver.m_m());
|
||||||
|
m_r_solver.m_y.resize(m_r_solver.m_m());
|
||||||
|
m_r_solver.m_rows_nz.resize(m_r_solver.m_m(), 0);
|
||||||
|
m_r_solver.m_columns_nz.resize(m_r_solver.m_n(), 0);
|
||||||
|
init_column_row_nz_for_r_solver();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_r_solver.m_b.resize(m_r_solver.m_m());
|
||||||
|
if (m_r_solver.m_settings.simplex_strategy() != simplex_strategy_enum::tableau_rows) {
|
||||||
|
if(m_r_solver.m_settings.use_breakpoints_in_feasibility_search)
|
||||||
|
m_r_solver.m_breakpoint_indices_queue.resize(m_r_solver.m_n());
|
||||||
|
m_r_solver.m_costs.resize(m_r_solver.m_n());
|
||||||
|
m_r_solver.m_d.resize(m_r_solver.m_n());
|
||||||
|
m_r_solver.m_using_infeas_costs = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void lar_core_solver::prefix_d() {
|
||||||
|
m_d_solver.m_b.resize(m_d_solver.m_m());
|
||||||
|
m_d_solver.m_breakpoint_indices_queue.resize(m_d_solver.m_n());
|
||||||
|
m_d_solver.m_copy_of_xB.resize(m_d_solver.m_n());
|
||||||
|
m_d_solver.m_costs.resize(m_d_solver.m_n());
|
||||||
|
m_d_solver.m_d.resize(m_d_solver.m_n());
|
||||||
|
m_d_solver.m_ed.resize(m_d_solver.m_m());
|
||||||
|
m_d_solver.m_pivot_row.resize(m_d_solver.m_n());
|
||||||
|
m_d_solver.m_pivot_row_of_B_1.resize(m_d_solver.m_m());
|
||||||
|
m_d_solver.m_w.resize(m_d_solver.m_m());
|
||||||
|
m_d_solver.m_y.resize(m_d_solver.m_m());
|
||||||
|
m_d_solver.m_steepest_edge_coefficients.resize(m_d_solver.m_n());
|
||||||
|
m_d_solver.m_column_norms.clear();
|
||||||
|
m_d_solver.m_column_norms.resize(m_d_solver.m_n(), 2);
|
||||||
|
m_d_solver.m_inf_set.clear();
|
||||||
|
m_d_solver.m_inf_set.resize(m_d_solver.m_n());
|
||||||
|
}
|
||||||
|
|
||||||
|
void lar_core_solver::fill_not_improvable_zero_sum_from_inf_row() {
|
||||||
|
lean_assert(m_r_solver.A_mult_x_is_off() == false);
|
||||||
|
unsigned bj = m_r_basis[m_r_solver.m_inf_row_index_for_tableau];
|
||||||
|
m_infeasible_sum_sign = m_r_solver.inf_sign_of_column(bj);
|
||||||
|
m_infeasible_linear_combination.clear();
|
||||||
|
for (auto & rc : m_r_solver.m_A.m_rows[m_r_solver.m_inf_row_index_for_tableau]) {
|
||||||
|
m_infeasible_linear_combination.push_back(std::make_pair( rc.get_val(), rc.m_j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void lar_core_solver::fill_not_improvable_zero_sum() {
|
||||||
|
if (m_r_solver.m_settings.simplex_strategy() == simplex_strategy_enum::tableau_rows) {
|
||||||
|
fill_not_improvable_zero_sum_from_inf_row();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// reusing the existing mechanism for row_feasibility_loop
|
||||||
|
m_infeasible_sum_sign = m_r_solver.m_settings.use_breakpoints_in_feasibility_search? -1 : 1;
|
||||||
|
m_infeasible_linear_combination.clear();
|
||||||
|
for (auto j : m_r_solver.m_basis) {
|
||||||
|
const mpq & cost_j = m_r_solver.m_costs[j];
|
||||||
|
if (!numeric_traits<mpq>::is_zero(cost_j)) {
|
||||||
|
m_infeasible_linear_combination.push_back(std::make_pair(cost_j, j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// m_costs are expressed by m_d ( additional costs), substructing the latter gives 0
|
||||||
|
for (unsigned j = 0; j < m_r_solver.m_n(); j++) {
|
||||||
|
if (m_r_solver.m_basis_heading[j] >= 0) continue;
|
||||||
|
const mpq & d_j = m_r_solver.m_d[j];
|
||||||
|
if (!numeric_traits<mpq>::is_zero(d_j)) {
|
||||||
|
m_infeasible_linear_combination.push_back(std::make_pair(-d_j, j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void lar_core_solver::solve() {
|
||||||
|
lean_assert(m_r_solver.non_basic_columns_are_set_correctly());
|
||||||
|
lean_assert(m_r_solver.inf_set_is_correct());
|
||||||
|
if (m_r_solver.current_x_is_feasible() && m_r_solver.m_look_for_feasible_solution_only) {
|
||||||
|
m_r_solver.set_status(OPTIMAL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
++settings().st().m_need_to_solve_inf;
|
||||||
|
lean_assert(!m_r_solver.A_mult_x_is_off());
|
||||||
|
lean_assert((!settings().use_tableau()) || r_basis_is_OK());
|
||||||
|
if (need_to_presolve_with_double_solver()) {
|
||||||
|
prefix_d();
|
||||||
|
lar_solution_signature solution_signature;
|
||||||
|
vector<unsigned> changes_of_basis = find_solution_signature_with_doubles(solution_signature);
|
||||||
|
if (m_d_solver.get_status() == TIME_EXHAUSTED) {
|
||||||
|
m_r_solver.set_status(TIME_EXHAUSTED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (settings().use_tableau())
|
||||||
|
solve_on_signature_tableau(solution_signature, changes_of_basis);
|
||||||
|
else
|
||||||
|
solve_on_signature(solution_signature, changes_of_basis);
|
||||||
|
lean_assert(!settings().use_tableau() || r_basis_is_OK());
|
||||||
|
} else {
|
||||||
|
if (!settings().use_tableau()) {
|
||||||
|
bool snapped = m_r_solver.snap_non_basic_x_to_bound();
|
||||||
|
lean_assert(m_r_solver.non_basic_columns_are_set_correctly());
|
||||||
|
if (snapped)
|
||||||
|
m_r_solver.solve_Ax_eq_b();
|
||||||
|
}
|
||||||
|
if (m_r_solver.m_look_for_feasible_solution_only)
|
||||||
|
m_r_solver.find_feasible_solution();
|
||||||
|
else
|
||||||
|
m_r_solver.solve();
|
||||||
|
lean_assert(!settings().use_tableau() || r_basis_is_OK());
|
||||||
|
}
|
||||||
|
if (m_r_solver.get_status() == INFEASIBLE) {
|
||||||
|
fill_not_improvable_zero_sum();
|
||||||
|
} else if (m_r_solver.get_status() != UNBOUNDED) {
|
||||||
|
m_r_solver.set_status(OPTIMAL);
|
||||||
|
}
|
||||||
|
lean_assert(r_basis_is_OK());
|
||||||
|
lean_assert(m_r_solver.non_basic_columns_are_set_correctly());
|
||||||
|
lean_assert(m_r_solver.inf_set_is_correct());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
10
src/util/lp/lar_core_solver_instances.cpp
Normal file
10
src/util/lp/lar_core_solver_instances.cpp
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#include <utility>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include "util/vector.h"
|
||||||
|
#include <functional>
|
||||||
|
#include "util/lp/lar_core_solver.hpp"
|
13
src/util/lp/lar_solution_signature.h
Normal file
13
src/util/lp/lar_solution_signature.h
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "util/vector.h"
|
||||||
|
#include "util/debug.h"
|
||||||
|
#include "util/lp/lp_settings.h"
|
||||||
|
#include <unordered_map>
|
||||||
|
namespace lean {
|
||||||
|
typedef std::unordered_map<unsigned, non_basic_column_value_position> lar_solution_signature;
|
||||||
|
}
|
1549
src/util/lp/lar_solver.h
Normal file
1549
src/util/lp/lar_solver.h
Normal file
File diff suppressed because it is too large
Load diff
64
src/util/lp/lar_term.h
Normal file
64
src/util/lp/lar_term.h
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include "util/lp/indexed_vector.h"
|
||||||
|
namespace lean {
|
||||||
|
struct lar_term {
|
||||||
|
// the term evaluates to sum of m_coeffs + m_v
|
||||||
|
std::unordered_map<unsigned, mpq> m_coeffs;
|
||||||
|
mpq m_v;
|
||||||
|
lar_term() {}
|
||||||
|
void add_to_map(unsigned j, const mpq& c) {
|
||||||
|
auto it = m_coeffs.find(j);
|
||||||
|
if (it == m_coeffs.end()) {
|
||||||
|
m_coeffs.emplace(j, c);
|
||||||
|
} else {
|
||||||
|
it->second += c;
|
||||||
|
if (is_zero(it->second))
|
||||||
|
m_coeffs.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned size() const { return static_cast<unsigned>(m_coeffs.size()); }
|
||||||
|
|
||||||
|
const std::unordered_map<unsigned, mpq> & coeffs() const {
|
||||||
|
return m_coeffs;
|
||||||
|
}
|
||||||
|
|
||||||
|
lar_term(const vector<std::pair<mpq, unsigned>>& coeffs,
|
||||||
|
const mpq & v) : m_v(v) {
|
||||||
|
for (const auto & p : coeffs) {
|
||||||
|
add_to_map(p.second, p.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool operator==(const lar_term & a) const { return false; } // take care not to create identical terms
|
||||||
|
bool operator!=(const lar_term & a) const { return ! (*this == a);}
|
||||||
|
// some terms get used in add constraint
|
||||||
|
// it is the same as the offset in the m_constraints
|
||||||
|
|
||||||
|
vector<std::pair<mpq, unsigned>> coeffs_as_vector() const {
|
||||||
|
vector<std::pair<mpq, unsigned>> ret;
|
||||||
|
for (const auto & p : m_coeffs) {
|
||||||
|
ret.push_back(std::make_pair(p.second, p.first));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// j is the basic variable to substitute
|
||||||
|
void subst(unsigned j, indexed_vector<mpq> & li) {
|
||||||
|
auto it = m_coeffs.find(j);
|
||||||
|
if (it == m_coeffs.end()) return;
|
||||||
|
const mpq & b = it->second;
|
||||||
|
for (unsigned it_j :li.m_index) {
|
||||||
|
add_to_map(it_j, - b * li.m_data[it_j]);
|
||||||
|
}
|
||||||
|
m_coeffs.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool contains(unsigned j) const {
|
||||||
|
return m_coeffs.find(j) != m_coeffs.end();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
50
src/util/lp/linear_combination_iterator.h
Normal file
50
src/util/lp/linear_combination_iterator.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
namespace lean {
|
||||||
|
template <typename T>
|
||||||
|
struct linear_combination_iterator {
|
||||||
|
virtual bool next(T & a, unsigned & i) = 0;
|
||||||
|
virtual bool next(unsigned & i) = 0;
|
||||||
|
virtual void reset() = 0;
|
||||||
|
virtual linear_combination_iterator * clone() = 0;
|
||||||
|
virtual ~linear_combination_iterator(){}
|
||||||
|
virtual unsigned size() const = 0;
|
||||||
|
};
|
||||||
|
template <typename T>
|
||||||
|
struct linear_combination_iterator_on_vector : linear_combination_iterator<T> {
|
||||||
|
vector<std::pair<T, unsigned>> & m_vector;
|
||||||
|
int m_offset;
|
||||||
|
bool next(T & a, unsigned & i) {
|
||||||
|
if(m_offset >= m_vector.size())
|
||||||
|
return false;
|
||||||
|
auto & p = m_vector[m_offset];
|
||||||
|
a = p.first;
|
||||||
|
i = p.second;
|
||||||
|
m_offset++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool next(unsigned & i) {
|
||||||
|
if(m_offset >= m_vector.size())
|
||||||
|
return false;
|
||||||
|
auto & p = m_vector[m_offset];
|
||||||
|
i = p.second;
|
||||||
|
m_offset++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() {m_offset = 0;}
|
||||||
|
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),
|
||||||
|
m_offset(0)
|
||||||
|
{}
|
||||||
|
unsigned size() const { return m_vector.size(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
690
src/util/lp/lp_core_solver_base.h
Normal file
690
src/util/lp/lp_core_solver_base.h
Normal file
|
@ -0,0 +1,690 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <set>
|
||||||
|
#include "util/vector.h"
|
||||||
|
#include <string>
|
||||||
|
#include "util/lp/lp_utils.h"
|
||||||
|
#include "util/lp/core_solver_pretty_printer.h"
|
||||||
|
#include "util/lp/numeric_pair.h"
|
||||||
|
#include "util/lp/static_matrix.h"
|
||||||
|
#include "util/lp/lu.h"
|
||||||
|
#include "util/lp/permutation_matrix.h"
|
||||||
|
#include "util/lp/column_namer.h"
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
// a device that is able to solve Bx=c, xB=d, and change the basis
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop_tracing_basis_changes() {
|
||||||
|
m_tracing_basis_changes = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void trace_basis_change(unsigned entering, unsigned leaving) {
|
||||||
|
unsigned size = m_trace_of_basis_change_vector.size();
|
||||||
|
if (size >= 2 && m_trace_of_basis_change_vector[size-2] == leaving
|
||||||
|
&& m_trace_of_basis_change_vector[size -1] == entering) {
|
||||||
|
m_trace_of_basis_change_vector.pop_back();
|
||||||
|
m_trace_of_basis_change_vector.pop_back();
|
||||||
|
} else {
|
||||||
|
m_trace_of_basis_change_vector.push_back(entering);
|
||||||
|
m_trace_of_basis_change_vector.push_back(leaving);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned m_m() const { return m_A.row_count(); } // it is the length of basis. The matrix m_A has m_m rows and the dimension of the matrix A is m_m
|
||||||
|
unsigned m_n() const { return m_A.column_count(); } // the number of columns in the matrix m_A
|
||||||
|
|
||||||
|
lp_core_solver_base(static_matrix<T, X> & A,
|
||||||
|
vector<X> & b, // the right side vector
|
||||||
|
vector<unsigned> & basis,
|
||||||
|
vector<unsigned> & nbasis,
|
||||||
|
vector<int> & heading,
|
||||||
|
vector<X> & x,
|
||||||
|
vector<T> & costs,
|
||||||
|
lp_settings & settings,
|
||||||
|
const column_namer& column_names,
|
||||||
|
const vector<column_type> & column_types,
|
||||||
|
const vector<X> & low_bound_values,
|
||||||
|
const vector<X> & upper_bound_values);
|
||||||
|
|
||||||
|
void allocate_basis_heading();
|
||||||
|
void init();
|
||||||
|
|
||||||
|
virtual ~lp_core_solver_base() {
|
||||||
|
if (m_factorization != nullptr)
|
||||||
|
delete m_factorization;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<unsigned> & non_basis() {
|
||||||
|
return m_nbasis;
|
||||||
|
}
|
||||||
|
|
||||||
|
const vector<unsigned> & non_basis() const { return m_nbasis; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void set_status(lp_status status) {
|
||||||
|
m_status = status;
|
||||||
|
}
|
||||||
|
lp_status get_status() const{
|
||||||
|
return m_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fill_cb(T * y);
|
||||||
|
|
||||||
|
void fill_cb(vector<T> & y);
|
||||||
|
|
||||||
|
void solve_yB(vector<T> & y);
|
||||||
|
|
||||||
|
void solve_Bd(unsigned entering);
|
||||||
|
|
||||||
|
void solve_Bd(unsigned entering, indexed_vector<T> & column);
|
||||||
|
|
||||||
|
void pretty_print(std::ostream & out);
|
||||||
|
|
||||||
|
void save_state(T * w_buffer, T * d_buffer);
|
||||||
|
|
||||||
|
void restore_state(T * w_buffer, T * d_buffer);
|
||||||
|
|
||||||
|
X get_cost() {
|
||||||
|
return dot_product(m_costs, m_x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void copy_m_w(T * buffer);
|
||||||
|
|
||||||
|
void restore_m_w(T * buffer);
|
||||||
|
|
||||||
|
// needed for debugging
|
||||||
|
void copy_m_ed(T * buffer);
|
||||||
|
|
||||||
|
void restore_m_ed(T * buffer);
|
||||||
|
|
||||||
|
bool A_mult_x_is_off() const;
|
||||||
|
|
||||||
|
bool A_mult_x_is_off_on_index(const vector<unsigned> & index) const;
|
||||||
|
// from page 182 of Istvan Maros's book
|
||||||
|
void calculate_pivot_row_of_B_1(unsigned pivot_row);
|
||||||
|
|
||||||
|
void calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned pivot_row);
|
||||||
|
|
||||||
|
void update_x(unsigned entering, const X & delta);
|
||||||
|
|
||||||
|
const T & get_var_value(unsigned j) const {
|
||||||
|
return m_x[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_statistics(char const* str, X cost, std::ostream & message_stream);
|
||||||
|
|
||||||
|
bool print_statistics_with_iterations_and_check_that_the_time_is_over(std::ostream & message_stream);
|
||||||
|
|
||||||
|
bool print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const* str, std::ostream & message_stream);
|
||||||
|
|
||||||
|
bool print_statistics_with_cost_and_check_that_the_time_is_over(X cost, std::ostream & message_stream);
|
||||||
|
|
||||||
|
unsigned total_iterations() const { return m_total_iterations; }
|
||||||
|
|
||||||
|
void set_total_iterations(unsigned s) { m_total_iterations = s; }
|
||||||
|
|
||||||
|
void set_non_basic_x_to_correct_bounds();
|
||||||
|
|
||||||
|
bool at_bound(const X &x, const X & bound) const {
|
||||||
|
return !below_bound(x, bound) && !above_bound(x, bound);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool need_to_pivot_to_basis_tableau() const {
|
||||||
|
lean_assert(m_A.is_correct());
|
||||||
|
unsigned m = m_A.row_count();
|
||||||
|
for (unsigned i = 0; i < m; i++) {
|
||||||
|
unsigned bj = m_basis[i];
|
||||||
|
lean_assert(m_A.m_columns[bj].size() > 0);
|
||||||
|
if (m_A.m_columns[bj].size() > 1 || m_A.get_val(m_A.m_columns[bj][0]) != one_of_type<mpq>()) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool reduced_costs_are_correct_tableau() const {
|
||||||
|
if (m_settings.simplex_strategy() == simplex_strategy_enum::tableau_rows)
|
||||||
|
return true;
|
||||||
|
lean_assert(m_A.is_correct());
|
||||||
|
if (m_using_infeas_costs) {
|
||||||
|
if (infeasibility_costs_are_correct() == false) {
|
||||||
|
std::cout << "infeasibility_costs_are_correct() does not hold" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned n = m_A.column_count();
|
||||||
|
for (unsigned j = 0; j < n; j++) {
|
||||||
|
if (m_basis_heading[j] >= 0) {
|
||||||
|
if (!is_zero(m_d[j])) {
|
||||||
|
|
||||||
|
std::cout << "case a\n";
|
||||||
|
print_column_info(j, std::cout);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto d = m_costs[j];
|
||||||
|
for (auto & cc : this->m_A.m_columns[j]) {
|
||||||
|
d -= this->m_costs[this->m_basis[cc.m_i]] * this->m_A.get_val(cc);
|
||||||
|
}
|
||||||
|
if (m_d[j] != d) {
|
||||||
|
std::cout << "case b\n";
|
||||||
|
print_column_info(j, std::cout);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool below_bound(const X & x, const X & bound) const {
|
||||||
|
if (precise()) return x < bound;
|
||||||
|
return below_bound_numeric<X>(x, bound, m_settings.primal_feasibility_tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool above_bound(const X & x, const X & bound) const {
|
||||||
|
if (precise()) return x > bound;
|
||||||
|
return above_bound_numeric<X>(x, bound, m_settings.primal_feasibility_tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool x_below_low_bound(unsigned p) const {
|
||||||
|
return below_bound(m_x[p], m_low_bounds[p]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool infeasibility_costs_are_correct() const;
|
||||||
|
bool infeasibility_cost_is_correct_for_column(unsigned j) const;
|
||||||
|
|
||||||
|
bool x_above_low_bound(unsigned p) const {
|
||||||
|
return above_bound(m_x[p], m_low_bounds[p]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool x_below_upper_bound(unsigned p) const {
|
||||||
|
return below_bound(m_x[p], m_upper_bounds[p]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool x_above_upper_bound(unsigned p) const {
|
||||||
|
return above_bound(m_x[p], m_upper_bounds[p]);
|
||||||
|
}
|
||||||
|
bool x_is_at_low_bound(unsigned j) const {
|
||||||
|
return at_bound(m_x[j], m_low_bounds[j]);
|
||||||
|
}
|
||||||
|
bool x_is_at_upper_bound(unsigned j) const {
|
||||||
|
return at_bound(m_x[j], m_upper_bounds[j]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool x_is_at_bound(unsigned j) const {
|
||||||
|
return x_is_at_low_bound(j) || x_is_at_upper_bound(j);
|
||||||
|
}
|
||||||
|
bool column_is_feasible(unsigned j) const;
|
||||||
|
|
||||||
|
bool calc_current_x_is_feasible_include_non_basis() const;
|
||||||
|
|
||||||
|
bool inf_set_is_correct() const;
|
||||||
|
|
||||||
|
bool column_is_dual_feasible(unsigned j) const;
|
||||||
|
|
||||||
|
bool d_is_not_negative(unsigned j) const;
|
||||||
|
|
||||||
|
bool d_is_not_positive(unsigned j) const;
|
||||||
|
|
||||||
|
|
||||||
|
bool time_is_over();
|
||||||
|
|
||||||
|
void rs_minus_Anx(vector<X> & rs);
|
||||||
|
|
||||||
|
bool find_x_by_solving();
|
||||||
|
|
||||||
|
bool update_basis_and_x(int entering, int leaving, X const & tt);
|
||||||
|
|
||||||
|
bool basis_has_no_doubles() const;
|
||||||
|
|
||||||
|
bool non_basis_has_no_doubles() const;
|
||||||
|
|
||||||
|
bool basis_is_correctly_represented_in_heading() const ;
|
||||||
|
bool non_basis_is_correctly_represented_in_heading() const ;
|
||||||
|
|
||||||
|
bool basis_heading_is_correct() const;
|
||||||
|
|
||||||
|
void restore_x_and_refactor(int entering, int leaving, X const & t);
|
||||||
|
|
||||||
|
void restore_x(unsigned entering, X const & t);
|
||||||
|
|
||||||
|
void fill_reduced_costs_from_m_y_by_rows();
|
||||||
|
|
||||||
|
void copy_rs_to_xB(vector<X> & rs);
|
||||||
|
virtual bool low_bounds_are_set() const { return false; }
|
||||||
|
X low_bound_value(unsigned j) const { return m_low_bounds[j]; }
|
||||||
|
X upper_bound_value(unsigned j) const { return m_upper_bounds[j]; }
|
||||||
|
|
||||||
|
column_type get_column_type(unsigned j) const {return m_column_types[j]; }
|
||||||
|
|
||||||
|
bool pivot_row_element_is_too_small_for_ratio_test(unsigned j) {
|
||||||
|
return m_settings.abs_val_is_smaller_than_pivot_tolerance(m_pivot_row[j]);
|
||||||
|
}
|
||||||
|
|
||||||
|
X bound_span(unsigned j) const {
|
||||||
|
return m_upper_bounds[j] - m_low_bounds[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string column_name(unsigned column) const;
|
||||||
|
|
||||||
|
void copy_right_side(vector<X> & rs);
|
||||||
|
|
||||||
|
void add_delta_to_xB(vector<X> & del);
|
||||||
|
|
||||||
|
void find_error_in_BxB(vector<X>& rs);
|
||||||
|
|
||||||
|
// recalculates the projection of x to B, such that Ax = b, whereab is the right side
|
||||||
|
void solve_Ax_eq_b();
|
||||||
|
|
||||||
|
bool snap_non_basic_x_to_bound() {
|
||||||
|
bool ret = false;
|
||||||
|
for (unsigned j : non_basis())
|
||||||
|
ret = snap_column_to_bound(j) || ret;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool snap_column_to_bound(unsigned j) {
|
||||||
|
switch (m_column_types[j]) {
|
||||||
|
case column_type::fixed:
|
||||||
|
if (x_is_at_bound(j))
|
||||||
|
break;
|
||||||
|
m_x[j] = m_low_bounds[j];
|
||||||
|
return true;
|
||||||
|
case column_type::boxed:
|
||||||
|
if (x_is_at_bound(j))
|
||||||
|
break; // we should preserve x if possible
|
||||||
|
// snap randomly
|
||||||
|
if (m_settings.random_next() % 2 == 1)
|
||||||
|
m_x[j] = m_low_bounds[j];
|
||||||
|
else
|
||||||
|
m_x[j] = m_upper_bounds[j];
|
||||||
|
return true;
|
||||||
|
case column_type::low_bound:
|
||||||
|
if (x_is_at_low_bound(j))
|
||||||
|
break;
|
||||||
|
m_x[j] = m_low_bounds[j];
|
||||||
|
return true;
|
||||||
|
case column_type::upper_bound:
|
||||||
|
if (x_is_at_upper_bound(j))
|
||||||
|
break;
|
||||||
|
m_x[j] = m_upper_bounds[j];
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool make_column_feasible(unsigned j, numeric_pair<mpq> & delta) {
|
||||||
|
lean_assert(m_basis_heading[j] < 0);
|
||||||
|
auto & x = m_x[j];
|
||||||
|
switch (m_column_types[j]) {
|
||||||
|
case column_type::fixed:
|
||||||
|
lean_assert(m_low_bounds[j] == m_upper_bounds[j]);
|
||||||
|
if (x != m_low_bounds[j]) {
|
||||||
|
delta = m_low_bounds[j] - x;
|
||||||
|
x = m_low_bounds[j];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case column_type::boxed:
|
||||||
|
if (x < m_low_bounds[j]) {
|
||||||
|
delta = m_low_bounds[j] - x;
|
||||||
|
x = m_low_bounds[j];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (x > m_upper_bounds[j]) {
|
||||||
|
delta = m_upper_bounds[j] - x;
|
||||||
|
x = m_upper_bounds[j];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case column_type::low_bound:
|
||||||
|
if (x < m_low_bounds[j]) {
|
||||||
|
delta = m_low_bounds[j] - x;
|
||||||
|
x = m_low_bounds[j];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case column_type::upper_bound:
|
||||||
|
if (x > m_upper_bounds[j]) {
|
||||||
|
delta = m_upper_bounds[j] - x;
|
||||||
|
x = m_upper_bounds[j];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case column_type::free_column:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
lean_assert(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void snap_non_basic_x_to_bound_and_free_to_zeroes();
|
||||||
|
void snap_xN_to_bounds_and_fill_xB();
|
||||||
|
|
||||||
|
void snap_xN_to_bounds_and_free_columns_to_zeroes();
|
||||||
|
|
||||||
|
void init_reduced_costs_for_one_iteration();
|
||||||
|
|
||||||
|
non_basic_column_value_position get_non_basic_column_value_position(unsigned j) const;
|
||||||
|
|
||||||
|
void init_lu();
|
||||||
|
int pivots_in_column_and_row_are_different(int entering, int leaving) const;
|
||||||
|
void pivot_fixed_vars_from_basis();
|
||||||
|
bool pivot_for_tableau_on_basis();
|
||||||
|
bool pivot_row_for_tableau_on_basis(unsigned row);
|
||||||
|
void init_basic_part_of_basis_heading() {
|
||||||
|
unsigned m = m_basis.size();
|
||||||
|
for (unsigned i = 0; i < m; i++) {
|
||||||
|
unsigned column = m_basis[i];
|
||||||
|
m_basis_heading[column] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_non_basic_part_of_basis_heading() {
|
||||||
|
this->m_nbasis.clear();
|
||||||
|
for (int j = m_basis_heading.size(); j--;){
|
||||||
|
if (m_basis_heading[j] < 0) {
|
||||||
|
m_nbasis.push_back(j);
|
||||||
|
// the index of column j in m_nbasis is (- basis_heading[j] - 1)
|
||||||
|
m_basis_heading[j] = - static_cast<int>(m_nbasis.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_basis_heading_and_non_basic_columns_vector() {
|
||||||
|
m_basis_heading.resize(0);
|
||||||
|
m_basis_heading.resize(m_n(), -1);
|
||||||
|
init_basic_part_of_basis_heading();
|
||||||
|
init_non_basic_part_of_basis_heading();
|
||||||
|
}
|
||||||
|
|
||||||
|
void change_basis_unconditionally(unsigned entering, unsigned leaving) {
|
||||||
|
lean_assert(m_basis_heading[entering] < 0);
|
||||||
|
int place_in_non_basis = -1 - m_basis_heading[entering];
|
||||||
|
if (static_cast<unsigned>(place_in_non_basis) >= m_nbasis.size()) {
|
||||||
|
// entering variable in not in m_nbasis, we need to put it back;
|
||||||
|
m_basis_heading[entering] = place_in_non_basis = m_nbasis.size();
|
||||||
|
m_nbasis.push_back(entering);
|
||||||
|
}
|
||||||
|
|
||||||
|
int place_in_basis = m_basis_heading[leaving];
|
||||||
|
m_basis_heading[entering] = place_in_basis;
|
||||||
|
m_basis[place_in_basis] = entering;
|
||||||
|
m_basis_heading[leaving] = -place_in_non_basis - 1;
|
||||||
|
m_nbasis[place_in_non_basis] = leaving;
|
||||||
|
if (m_tracing_basis_changes)
|
||||||
|
trace_basis_change(entering, leaving);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void change_basis(unsigned entering, unsigned leaving) {
|
||||||
|
lean_assert(m_basis_heading[entering] < 0);
|
||||||
|
|
||||||
|
int place_in_basis = m_basis_heading[leaving];
|
||||||
|
int place_in_non_basis = - m_basis_heading[entering] - 1;
|
||||||
|
m_basis_heading[entering] = place_in_basis;
|
||||||
|
m_basis[place_in_basis] = entering;
|
||||||
|
|
||||||
|
m_basis_heading[leaving] = -place_in_non_basis - 1;
|
||||||
|
m_nbasis[place_in_non_basis] = leaving;
|
||||||
|
|
||||||
|
if (m_tracing_basis_changes)
|
||||||
|
trace_basis_change(entering, leaving);
|
||||||
|
}
|
||||||
|
|
||||||
|
void restore_basis_change(unsigned entering, unsigned leaving) {
|
||||||
|
if (m_basis_heading[entering] < 0) {
|
||||||
|
return; // the basis has not been changed
|
||||||
|
}
|
||||||
|
change_basis_unconditionally(leaving, entering);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool non_basic_column_is_set_correctly(unsigned j) const {
|
||||||
|
if (j >= this->m_n())
|
||||||
|
return false;
|
||||||
|
switch (this->m_column_types[j]) {
|
||||||
|
case column_type::fixed:
|
||||||
|
case column_type::boxed:
|
||||||
|
if (!this->x_is_at_bound(j))
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case column_type::low_bound:
|
||||||
|
if (!this->x_is_at_low_bound(j))
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case column_type::upper_bound:
|
||||||
|
if (!this->x_is_at_upper_bound(j))
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case column_type::free_column:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
lean_assert(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool non_basic_columns_are_set_correctly() const {
|
||||||
|
for (unsigned j : this->m_nbasis)
|
||||||
|
if (!column_is_feasible(j)) {
|
||||||
|
print_column_info(j, std::cout);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_column_bound_info(unsigned j, std::ostream & out) const {
|
||||||
|
out << column_name(j) << " type = " << column_type_to_string(m_column_types[j]) << std::endl;
|
||||||
|
switch (m_column_types[j]) {
|
||||||
|
case column_type::fixed:
|
||||||
|
case column_type::boxed:
|
||||||
|
out << "(" << m_low_bounds[j] << ", " << m_upper_bounds[j] << ")" << std::endl;
|
||||||
|
break;
|
||||||
|
case column_type::low_bound:
|
||||||
|
out << m_low_bounds[j] << std::endl;
|
||||||
|
break;
|
||||||
|
case column_type::upper_bound:
|
||||||
|
out << m_upper_bounds[j] << std::endl;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_column_info(unsigned j, std::ostream & out) const {
|
||||||
|
out << "column_index = " << j << ", name = "<< column_name(j) << " type = " << column_type_to_string(m_column_types[j]) << std::endl;
|
||||||
|
switch (m_column_types[j]) {
|
||||||
|
case column_type::fixed:
|
||||||
|
case column_type::boxed:
|
||||||
|
out << "(" << m_low_bounds[j] << ", " << m_upper_bounds[j] << ")" << std::endl;
|
||||||
|
break;
|
||||||
|
case column_type::low_bound:
|
||||||
|
out << m_low_bounds[j] << std::endl;
|
||||||
|
break;
|
||||||
|
case column_type::upper_bound:
|
||||||
|
out << m_upper_bounds[j] << std::endl;
|
||||||
|
break;
|
||||||
|
case column_type::free_column:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
lean_assert(false);
|
||||||
|
}
|
||||||
|
std::cout << "basis heading = " << m_basis_heading[j] << std::endl;
|
||||||
|
std::cout << "x = " << m_x[j] << std::endl;
|
||||||
|
/*
|
||||||
|
std::cout << "cost = " << m_costs[j] << std::endl;
|
||||||
|
std:: cout << "m_d = " << m_d[j] << std::endl;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
bool column_is_free(unsigned j) { return this->m_column_type[j] == free; }
|
||||||
|
|
||||||
|
bool column_has_upper_bound(unsigned j) {
|
||||||
|
switch(m_column_types[j]) {
|
||||||
|
case column_type::free_column:
|
||||||
|
case column_type::low_bound:
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bounds_for_boxed_are_set_correctly() const {
|
||||||
|
for (unsigned j = 0; j < m_column_types.size(); j++) {
|
||||||
|
if (m_column_types[j] != column_type::boxed) continue;
|
||||||
|
if (m_low_bounds[j] > m_upper_bounds[j])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool column_has_low_bound(unsigned j) {
|
||||||
|
switch(m_column_types[j]) {
|
||||||
|
case column_type::free_column:
|
||||||
|
case column_type::upper_bound:
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// only check for basic columns
|
||||||
|
bool calc_current_x_is_feasible() const {
|
||||||
|
unsigned i = this->m_m();
|
||||||
|
while (i--) {
|
||||||
|
if (!column_is_feasible(m_basis[i]))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int find_pivot_index_in_row(unsigned i, const vector<column_cell> & col) const {
|
||||||
|
for (const auto & c: col) {
|
||||||
|
if (c.m_i == i)
|
||||||
|
return c.m_offset;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void transpose_rows_tableau(unsigned i, unsigned ii);
|
||||||
|
|
||||||
|
void pivot_to_reduced_costs_tableau(unsigned i, unsigned j);
|
||||||
|
|
||||||
|
bool pivot_column_tableau(unsigned j, unsigned row_index);
|
||||||
|
bool divide_row_by_pivot(unsigned pivot_row, unsigned pivot_col);
|
||||||
|
|
||||||
|
bool precise() const { return numeric_traits<T>::precise(); }
|
||||||
|
|
||||||
|
simplex_strategy_enum simplex_strategy() const { return
|
||||||
|
m_settings.simplex_strategy();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool use_tableau() const { return m_settings.use_tableau(); }
|
||||||
|
|
||||||
|
template <typename K>
|
||||||
|
static void swap(vector<K> &v, unsigned i, unsigned j) {
|
||||||
|
auto t = v[i];
|
||||||
|
v[i] = v[j];
|
||||||
|
v[j] = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
// called when transposing row i and ii
|
||||||
|
void transpose_basis(unsigned i, unsigned ii) {
|
||||||
|
swap(m_basis, i, ii);
|
||||||
|
swap(m_basis_heading, m_basis[i], m_basis[ii]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool column_is_in_inf_set(unsigned j) const {
|
||||||
|
return m_inf_set.contains(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_column_in_inf_set(unsigned j) {
|
||||||
|
if (column_is_feasible(j)) {
|
||||||
|
m_inf_set.erase(j);
|
||||||
|
} else {
|
||||||
|
m_inf_set.insert(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void insert_column_into_inf_set(unsigned j) {
|
||||||
|
m_inf_set.insert(j);
|
||||||
|
lean_assert(!column_is_feasible(j));
|
||||||
|
}
|
||||||
|
void remove_column_from_inf_set(unsigned j) {
|
||||||
|
m_inf_set.erase(j);
|
||||||
|
lean_assert(column_is_feasible(j));
|
||||||
|
}
|
||||||
|
bool costs_on_nbasis_are_zeros() const {
|
||||||
|
lean_assert(this->basis_heading_is_correct());
|
||||||
|
for (unsigned j = 0; j < this->m_n(); j++) {
|
||||||
|
if (this->m_basis_heading[j] < 0)
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
1019
src/util/lp/lp_core_solver_base.hpp
Normal file
1019
src/util/lp/lp_core_solver_base.hpp
Normal file
File diff suppressed because it is too large
Load diff
131
src/util/lp/lp_core_solver_base_instances.cpp
Normal file
131
src/util/lp/lp_core_solver_base_instances.cpp
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#include <utility>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include "util/vector.h"
|
||||||
|
#include <functional>
|
||||||
|
#include "util/lp/lp_core_solver_base.hpp"
|
||||||
|
template bool lean::lp_core_solver_base<double, double>::A_mult_x_is_off() const;
|
||||||
|
template bool lean::lp_core_solver_base<double, double>::A_mult_x_is_off_on_index(const vector<unsigned> &) const;
|
||||||
|
template bool lean::lp_core_solver_base<double, double>::basis_heading_is_correct() const;
|
||||||
|
template void lean::lp_core_solver_base<double, double>::calculate_pivot_row_of_B_1(unsigned int);
|
||||||
|
template void lean::lp_core_solver_base<double, double>::calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned);
|
||||||
|
template bool lean::lp_core_solver_base<double, double>::column_is_dual_feasible(unsigned int) const;
|
||||||
|
template void lean::lp_core_solver_base<double, double>::fill_reduced_costs_from_m_y_by_rows();
|
||||||
|
template bool lean::lp_core_solver_base<double, double>::find_x_by_solving();
|
||||||
|
template lean::non_basic_column_value_position lean::lp_core_solver_base<double, double>::get_non_basic_column_value_position(unsigned int) const;
|
||||||
|
template lean::non_basic_column_value_position lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::get_non_basic_column_value_position(unsigned int) const;
|
||||||
|
template lean::non_basic_column_value_position lean::lp_core_solver_base<lean::mpq, lean::mpq>::get_non_basic_column_value_position(unsigned int) const;
|
||||||
|
template void lean::lp_core_solver_base<double, double>::init_reduced_costs_for_one_iteration();
|
||||||
|
template lean::lp_core_solver_base<double, double>::lp_core_solver_base(
|
||||||
|
lean::static_matrix<double, double>&, vector<double>&,
|
||||||
|
vector<unsigned int >&,
|
||||||
|
vector<unsigned> &, vector<int> &,
|
||||||
|
vector<double >&,
|
||||||
|
vector<double >&,
|
||||||
|
lean::lp_settings&, const column_namer&, const vector<lean::column_type >&,
|
||||||
|
const vector<double >&,
|
||||||
|
const vector<double >&);
|
||||||
|
|
||||||
|
template bool lean::lp_core_solver_base<double, double>::print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const*, std::ostream &);
|
||||||
|
template bool lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const*, std::ostream &);
|
||||||
|
template void lean::lp_core_solver_base<double, double>::restore_x(unsigned int, double const&);
|
||||||
|
template void lean::lp_core_solver_base<double, double>::set_non_basic_x_to_correct_bounds();
|
||||||
|
template void lean::lp_core_solver_base<double, double>::snap_xN_to_bounds_and_free_columns_to_zeroes();
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::snap_xN_to_bounds_and_free_columns_to_zeroes();
|
||||||
|
template void lean::lp_core_solver_base<double, double>::solve_Ax_eq_b();
|
||||||
|
template void lean::lp_core_solver_base<double, double>::solve_Bd(unsigned int);
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq>>::solve_Bd(unsigned int, indexed_vector<lean::mpq>&);
|
||||||
|
template void lean::lp_core_solver_base<double, double>::solve_yB(vector<double >&);
|
||||||
|
template bool lean::lp_core_solver_base<double, double>::update_basis_and_x(int, int, double const&);
|
||||||
|
template void lean::lp_core_solver_base<double, double>::update_x(unsigned int, const double&);
|
||||||
|
template bool lean::lp_core_solver_base<lean::mpq, lean::mpq>::A_mult_x_is_off() const;
|
||||||
|
template bool lean::lp_core_solver_base<lean::mpq, lean::mpq>::A_mult_x_is_off_on_index(const vector<unsigned> &) const;
|
||||||
|
template bool lean::lp_core_solver_base<lean::mpq, lean::mpq>::basis_heading_is_correct() const ;
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::mpq>::calculate_pivot_row_of_B_1(unsigned int);
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::mpq>::calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned);
|
||||||
|
template bool lean::lp_core_solver_base<lean::mpq, lean::mpq>::column_is_dual_feasible(unsigned int) const;
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::mpq>::fill_reduced_costs_from_m_y_by_rows();
|
||||||
|
template bool lean::lp_core_solver_base<lean::mpq, lean::mpq>::find_x_by_solving();
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::mpq>::init_reduced_costs_for_one_iteration();
|
||||||
|
template bool lean::lp_core_solver_base<lean::mpq, lean::mpq>::print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const*, std::ostream &);
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::mpq>::restore_x(unsigned int, lean::mpq const&);
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::mpq>::set_non_basic_x_to_correct_bounds();
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::mpq>::solve_Ax_eq_b();
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::mpq>::solve_Bd(unsigned int);
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::mpq>::solve_yB(vector<lean::mpq>&);
|
||||||
|
template bool lean::lp_core_solver_base<lean::mpq, lean::mpq>::update_basis_and_x(int, int, lean::mpq const&);
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::mpq>::update_x(unsigned int, const lean::mpq&);
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::calculate_pivot_row_of_B_1(unsigned int);
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned);
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::init();
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::init_basis_heading_and_non_basic_columns_vector();
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::init_reduced_costs_for_one_iteration();
|
||||||
|
template lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::lp_core_solver_base(lean::static_matrix<lean::mpq, lean::numeric_pair<lean::mpq> >&, vector<lean::numeric_pair<lean::mpq> >&, vector<unsigned int >&, vector<unsigned> &, vector<int> &, vector<lean::numeric_pair<lean::mpq> >&, vector<lean::mpq>&, lean::lp_settings&, const column_namer&, const vector<lean::column_type >&,
|
||||||
|
const vector<lean::numeric_pair<lean::mpq> >&,
|
||||||
|
const vector<lean::numeric_pair<lean::mpq> >&);
|
||||||
|
template bool lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::print_statistics_with_cost_and_check_that_the_time_is_over(lean::numeric_pair<lean::mpq>, std::ostream&);
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::snap_xN_to_bounds_and_fill_xB();
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::solve_Bd(unsigned int);
|
||||||
|
template bool lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::update_basis_and_x(int, int, lean::numeric_pair<lean::mpq> const&);
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::update_x(unsigned int, const lean::numeric_pair<lean::mpq>&);
|
||||||
|
template lean::lp_core_solver_base<lean::mpq, lean::mpq>::lp_core_solver_base(
|
||||||
|
lean::static_matrix<lean::mpq, lean::mpq>&,
|
||||||
|
vector<lean::mpq>&,
|
||||||
|
vector<unsigned int >&,
|
||||||
|
vector<unsigned> &, vector<int> &,
|
||||||
|
vector<lean::mpq>&,
|
||||||
|
vector<lean::mpq>&,
|
||||||
|
lean::lp_settings&,
|
||||||
|
const column_namer&,
|
||||||
|
const vector<lean::column_type >&,
|
||||||
|
const vector<lean::mpq>&,
|
||||||
|
const vector<lean::mpq>&);
|
||||||
|
template bool lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::print_statistics_with_iterations_and_check_that_the_time_is_over(std::ostream &);
|
||||||
|
template std::string lean::lp_core_solver_base<double, double>::column_name(unsigned int) const;
|
||||||
|
template void lean::lp_core_solver_base<double, double>::pretty_print(std::ostream & out);
|
||||||
|
template void lean::lp_core_solver_base<double, double>::restore_state(double*, double*);
|
||||||
|
template void lean::lp_core_solver_base<double, double>::save_state(double*, double*);
|
||||||
|
template std::string lean::lp_core_solver_base<lean::mpq, lean::mpq>::column_name(unsigned int) const;
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::mpq>::pretty_print(std::ostream & out);
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::mpq>::restore_state(lean::mpq*, lean::mpq*);
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::mpq>::save_state(lean::mpq*, lean::mpq*);
|
||||||
|
template std::string lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::column_name(unsigned int) const;
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::pretty_print(std::ostream & out);
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::restore_state(lean::mpq*, lean::mpq*);
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::save_state(lean::mpq*, lean::mpq*);
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::solve_yB(vector<lean::mpq>&);
|
||||||
|
template void lean::lp_core_solver_base<double, double>::init_lu();
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::mpq>::init_lu();
|
||||||
|
template int lean::lp_core_solver_base<double, double>::pivots_in_column_and_row_are_different(int, int) const;
|
||||||
|
template int lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::pivots_in_column_and_row_are_different(int, int) const;
|
||||||
|
template int lean::lp_core_solver_base<lean::mpq, lean::mpq>::pivots_in_column_and_row_are_different(int, int) const;
|
||||||
|
template bool lean::lp_core_solver_base<double, double>::calc_current_x_is_feasible_include_non_basis(void)const;
|
||||||
|
template bool lean::lp_core_solver_base<lean::mpq, lean::mpq>::calc_current_x_is_feasible_include_non_basis(void)const;
|
||||||
|
template bool lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::calc_current_x_is_feasible_include_non_basis() const;
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::pivot_fixed_vars_from_basis();
|
||||||
|
template bool lean::lp_core_solver_base<double, double>::column_is_feasible(unsigned int) const;
|
||||||
|
template bool lean::lp_core_solver_base<lean::mpq, lean::mpq>::column_is_feasible(unsigned int) const;
|
||||||
|
// template void lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::print_linear_combination_of_column_indices(vector<std::pair<lean::mpq, unsigned int>, std::allocator<std::pair<lean::mpq, unsigned int> > > const&, std::ostream&) const;
|
||||||
|
template bool lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::column_is_feasible(unsigned int) const;
|
||||||
|
template bool lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::snap_non_basic_x_to_bound();
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::init_lu();
|
||||||
|
template bool lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::A_mult_x_is_off_on_index(vector<unsigned int> const&) const;
|
||||||
|
template bool lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::find_x_by_solving();
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::restore_x(unsigned int, lean::numeric_pair<lean::mpq> const&);
|
||||||
|
template bool lean::lp_core_solver_base<double, double>::pivot_for_tableau_on_basis();
|
||||||
|
template bool lean::lp_core_solver_base<lean::mpq, lean::mpq>::pivot_for_tableau_on_basis();
|
||||||
|
template bool lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq>>::pivot_for_tableau_on_basis();
|
||||||
|
template bool lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq>>::pivot_column_tableau(unsigned int, unsigned int);
|
||||||
|
template bool lean::lp_core_solver_base<double, double>::pivot_column_tableau(unsigned int, unsigned int);
|
||||||
|
template bool lean::lp_core_solver_base<lean::mpq, lean::mpq>::pivot_column_tableau(unsigned int, unsigned int);
|
||||||
|
template void lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::transpose_rows_tableau(unsigned int, unsigned int);
|
||||||
|
template bool lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::inf_set_is_correct() const;
|
||||||
|
template bool lean::lp_core_solver_base<double, double>::inf_set_is_correct() const;
|
||||||
|
template bool lean::lp_core_solver_base<lean::mpq, lean::mpq>::inf_set_is_correct() const;
|
||||||
|
template bool lean::lp_core_solver_base<lean::mpq, lean::numeric_pair<lean::mpq> >::infeasibility_costs_are_correct() const;
|
||||||
|
template bool lean::lp_core_solver_base<lean::mpq, lean::mpq >::infeasibility_costs_are_correct() const;
|
||||||
|
template bool lean::lp_core_solver_base<double, double >::infeasibility_costs_are_correct() const;
|
197
src/util/lp/lp_dual_core_solver.h
Normal file
197
src/util/lp/lp_dual_core_solver.h
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
|
Author: Lev Nachmanson
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include "util/lp/static_matrix.h"
|
||||||
|
#include "util/lp/lp_core_solver_base.h"
|
||||||
|
#include <string>
|
||||||
|
#include <limits>
|
||||||
|
#include <set>
|
||||||
|
#include <algorithm>
|
||||||
|
#include "util/vector.h"
|
||||||
|
|
||||||
|
namespace lean {
|
||||||
|
template <typename T, typename X>
|
||||||
|
class lp_dual_core_solver:public lp_core_solver_base<T, X> {
|
||||||
|
public:
|
||||||
|
vector<bool> & m_can_enter_basis;
|
||||||
|
int m_r; // the row of the leaving column
|
||||||
|
int m_p; // leaving column; that is m_p = m_basis[m_r]
|
||||||
|
T m_delta; // the offset of the leaving basis variable
|
||||||
|
int m_sign_of_alpha_r; // see page 27
|
||||||
|
T m_theta_D;
|
||||||
|
T m_theta_P;
|
||||||
|
int m_q;
|
||||||
|
// todo : replace by a vector later
|
||||||
|
std::set<unsigned> m_breakpoint_set; // it is F in "Progress in the dual simplex method ..."
|
||||||
|
std::set<unsigned> m_flipped_boxed;
|
||||||
|
std::set<unsigned> m_tight_set; // it is the set of all breakpoints that become tight when m_q becomes tight
|
||||||
|
vector<T> m_a_wave;
|
||||||
|
vector<T> m_betas; // m_betas[i] is approximately a square of the norm of the i-th row of the reverse of B
|
||||||
|
T m_harris_tolerance;
|
||||||
|
std::set<unsigned> m_forbidden_rows;
|
||||||
|
|
||||||
|
lp_dual_core_solver(static_matrix<T, X> & A,
|
||||||
|
vector<bool> & can_enter_basis,
|
||||||
|
vector<X> & b, // the right side vector
|
||||||
|
vector<X> & x, // the number of elements in x needs to be at least as large as the number of columns in A
|
||||||
|
vector<unsigned> & basis,
|
||||||
|
vector<unsigned> & nbasis,
|
||||||
|
vector<int> & heading,
|
||||||
|
vector<T> & costs,
|
||||||
|
vector<column_type> & column_type_array,
|
||||||
|
vector<X> & low_bound_values,
|
||||||
|
vector<X> & upper_bound_values,
|
||||||
|
lp_settings & settings,
|
||||||
|
const column_namer & column_names):
|
||||||
|
lp_core_solver_base<T, X>(A,
|
||||||
|
b,
|
||||||
|
basis,
|
||||||
|
nbasis,
|
||||||
|
heading,
|
||||||
|
x,
|
||||||
|
costs,
|
||||||
|
settings,
|
||||||
|
column_names,
|
||||||
|
column_type_array,
|
||||||
|
low_bound_values,
|
||||||
|
upper_bound_values),
|
||||||
|
m_can_enter_basis(can_enter_basis),
|
||||||
|
m_a_wave(this->m_m()),
|
||||||
|
m_betas(this->m_m()) {
|
||||||
|
m_harris_tolerance = numeric_traits<T>::precise()? numeric_traits<T>::zero() : T(this->m_settings.harris_feasibility_tolerance);
|
||||||
|
this->solve_yB(this->m_y);
|
||||||
|
this->init_basic_part_of_basis_heading();
|
||||||
|
fill_non_basis_with_only_able_to_enter_columns();
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_a_wave_by_zeros();
|
||||||
|
|
||||||
|
void fill_non_basis_with_only_able_to_enter_columns() {
|
||||||
|
auto & nb = this->m_nbasis;
|
||||||
|
nb.reset();
|
||||||
|
unsigned j = this->m_n();
|
||||||
|
while (j--) {
|
||||||
|
if (this->m_basis_heading[j] >= 0 || !m_can_enter_basis[j]) continue;
|
||||||
|
nb.push_back(j);
|
||||||
|
this->m_basis_heading[j] = - static_cast<int>(nb.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void restore_non_basis();
|
||||||
|
|
||||||
|
bool update_basis(int entering, int leaving);
|
||||||
|
|
||||||
|
void recalculate_xB_and_d();
|
||||||
|
|
||||||
|
void recalculate_d();
|
||||||
|
|
||||||
|
void init_betas();
|
||||||
|
|
||||||
|
void adjust_xb_for_changed_xn_and_init_betas();
|
||||||
|
|
||||||
|
void start_with_initial_basis_and_make_it_dual_feasible();
|
||||||
|
|
||||||
|
bool done();
|
||||||
|
|
||||||
|
T get_edge_steepness_for_low_bound(unsigned p);
|
||||||
|
|
||||||
|
T get_edge_steepness_for_upper_bound(unsigned p);
|
||||||
|
|
||||||
|
T pricing_for_row(unsigned i);
|
||||||
|
|
||||||
|
void pricing_loop(unsigned number_of_rows_to_try, unsigned offset_in_rows);
|
||||||
|
|
||||||
|
bool advance_on_known_p();
|
||||||
|
|
||||||
|
int define_sign_of_alpha_r();
|
||||||
|
|
||||||
|
bool can_be_breakpoint(unsigned j);
|
||||||
|
|
||||||
|
void fill_breakpoint_set();
|
||||||
|
|
||||||
|
void DSE_FTran();
|
||||||
|
T get_delta();
|
||||||
|
|
||||||
|
void restore_d();
|
||||||
|
|
||||||
|
bool d_is_correct();
|
||||||
|
|
||||||
|
void xb_minus_delta_p_pivot_column();
|
||||||
|
|
||||||
|
void update_betas();
|
||||||
|
|
||||||
|
void apply_flips();
|
||||||
|
|
||||||
|
void snap_xN_column_to_bounds(unsigned j);
|
||||||
|
|
||||||
|
void snap_xN_to_bounds();
|
||||||
|
|
||||||
|
void init_beta_precisely(unsigned i);
|
||||||
|
|
||||||
|
void init_betas_precisely();
|
||||||
|
|
||||||
|
// step 7 of the algorithm from Progress
|
||||||
|
bool basis_change_and_update();
|
||||||
|
|
||||||
|
void revert_to_previous_basis();
|
||||||
|
|
||||||
|
non_basic_column_value_position m_entering_boundary_position;
|
||||||
|
bool update_basis_and_x_local(int entering, int leaving, X const & tt);
|
||||||
|
void recover_leaving();
|
||||||
|
|
||||||
|
bool problem_is_dual_feasible() const;
|
||||||
|
|
||||||
|
bool snap_runaway_nonbasic_column(unsigned);
|
||||||
|
|
||||||
|
bool snap_runaway_nonbasic_columns();
|
||||||
|
|
||||||
|
unsigned get_number_of_rows_to_try_for_leaving();
|
||||||
|
|
||||||
|
void update_a_wave(const T & del, unsigned j) {
|
||||||
|
this->m_A.add_column_to_vector(del, j, & m_a_wave[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool delta_keeps_the_sign(int initial_delta_sign, const T & delta);
|
||||||
|
|
||||||
|
void set_status_to_tentative_dual_unbounded_or_dual_unbounded();
|
||||||
|
|
||||||
|
// it is positive if going from low bound to upper bound and negative if going from upper bound to low bound
|
||||||
|
T signed_span_of_boxed(unsigned j) {
|
||||||
|
return this->x_is_at_low_bound(j)? this->bound_span(j): - this->bound_span(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_tight_breakpoints_and_q_to_flipped_set();
|
||||||
|
|
||||||
|
T delta_lost_on_flips_of_tight_breakpoints();
|
||||||
|
|
||||||
|
bool tight_breakpoinst_are_all_boxed();
|
||||||
|
|
||||||
|
T calculate_harris_delta_on_breakpoint_set();
|
||||||
|
|
||||||
|
void fill_tight_set_on_harris_delta(const T & harris_delta );
|
||||||
|
|
||||||
|
void find_q_on_tight_set();
|
||||||
|
|
||||||
|
void find_q_and_tight_set();
|
||||||
|
|
||||||
|
void erase_tight_breakpoints_and_q_from_breakpoint_set();
|
||||||
|
|
||||||
|
bool ratio_test();
|
||||||
|
|
||||||
|
void process_flipped();
|
||||||
|
void update_d_and_xB();
|
||||||
|
|
||||||
|
void calculate_beta_r_precisely();
|
||||||
|
// see "Progress in the dual simplex method for large scale LP problems: practical dual phase 1 algorithms"
|
||||||
|
|
||||||
|
void update_xb_after_bound_flips();
|
||||||
|
|
||||||
|
void one_iteration();
|
||||||
|
|
||||||
|
void solve();
|
||||||
|
|
||||||
|
bool low_bounds_are_set() const { return true; }
|
||||||
|
};
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue