3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-08-04 02:10:23 +00:00

Merge branch 'master' into polysat

This commit is contained in:
Jakob Rath 2023-07-10 09:45:55 +02:00
commit 59c3234fb8
196 changed files with 4705 additions and 4168 deletions

View file

@ -41,7 +41,7 @@ jobs:
type=edge type=edge
type=sha,prefix=ubuntu-20.04-bare-z3-sha- type=sha,prefix=ubuntu-20.04-bare-z3-sha-
- name: Build and push Bare Z3 Docker Image - name: Build and push Bare Z3 Docker Image
uses: docker/build-push-action@v4.0.0 uses: docker/build-push-action@v4.1.1
with: with:
context: . context: .
push: true push: true

View file

@ -81,7 +81,7 @@ if (EXISTS "${GIT_DIR}")
# This mimics the behaviour of the old build system. # This mimics the behaviour of the old build system.
set(Z3_FULL_VERSION_STR "${Z3_FULL_VERSION_STR} ${Z3_GIT_DESCRIPTION}") set(Z3_FULL_VERSION_STR "${Z3_FULL_VERSION_STR} ${Z3_GIT_DESCRIPTION}")
else() else()
message(STATUS "Not including git descrption in version") message(STATUS "Not including git description in version")
endif() endif()
else() else()
message(WARNING "Failed to add git dependency.") message(WARNING "Failed to add git dependency.")
@ -462,7 +462,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
# generate files used for Z3's build. Changes to these files will trigger # generate files used for Z3's build. Changes to these files will trigger
# a rebuild of all the generated files. # a rebuild of all the generated files.
################################################################################ ################################################################################
# Note: ``update_api.py`` is deliberately not here because it not used # Note: ``update_api.py`` is deliberately not here because it is not used
# to generate every generated file. The targets that need it list it explicitly. # to generate every generated file. The targets that need it list it explicitly.
set(Z3_GENERATED_FILE_EXTRA_DEPENDENCIES set(Z3_GENERATED_FILE_EXTRA_DEPENDENCIES
"${PROJECT_SOURCE_DIR}/scripts/mk_genfile_common.py" "${PROJECT_SOURCE_DIR}/scripts/mk_genfile_common.py"

View file

@ -348,7 +348,7 @@ These notes are help developers and packagers of Z3.
### Install/Uninstall ### Install/Uninstall
Install and uninstall targets are supported. Use ``CMAKE_INSTALL_PREFIX`` to Install and uninstall targets are supported. Use ``CMAKE_INSTALL_PREFIX`` to
set the install prefix. If you also need need to control which directories are set the install prefix. If you also need to control which directories are
used for install set the documented ``CMAKE_INSTALL_*`` options. used for install set the documented ``CMAKE_INSTALL_*`` options.
To install run To install run

View file

@ -62,7 +62,7 @@ Version 4.12.0
Clauses that are deduced by theories are marked by default Clauses that are deduced by theories are marked by default
by 'smt', and when more detailed information by 'smt', and when more detailed information
is available with proof hints or proof objects. is available with proof hints or proof objects.
Instantations are considered useful to track so they Instantiations are considered useful to track so they
are logged using terms of the form are logged using terms of the form
(inst (not (forall (x) body)) body[t/x] (bind t)), where (inst (not (forall (x) body)) body[t/x] (bind t)), where
@ -88,7 +88,7 @@ Version 4.12.0
checker cannot check. It is mainly a limitation checker cannot check. It is mainly a limitation
of the arithmetic solver not pulling relevant information. of the arithmetic solver not pulling relevant information.
Ensuring a tight coupling with proof hints and the validator Ensuring a tight coupling with proof hints and the validator
capabilites is open ended future work and good material for theses. capabilities is open ended future work and good material for theses.
- bit-vector inferences - are treated as trusted - bit-vector inferences - are treated as trusted
(there is no validation, it always blindly succeeds) (there is no validation, it always blindly succeeds)
- arrays, datatypes - there is no custom validation for - arrays, datatypes - there is no custom validation for
@ -158,13 +158,13 @@ Version 4.11.2
with SMT format that is extensible. The resulting format is a mild extension of SMTLIB with with SMT format that is extensible. The resulting format is a mild extension of SMTLIB with
three extra commands assume, learn, del. They track input clauses, generated clauses and deleted clauses. three extra commands assume, learn, del. They track input clauses, generated clauses and deleted clauses.
They are optionally augmented by proof hints. Two proof hints are used in the current version: "rup" and "farkas". They are optionally augmented by proof hints. Two proof hints are used in the current version: "rup" and "farkas".
"rup" is used whent the generated clause can be justified by reverse unit propagation. "farkas" is used when "rup" is used when the generated clause can be justified by reverse unit propagation. "farkas" is used when
the clause can be justified by a combination of Farkas cutting planes. There is a built-in proof checker for the the clause can be justified by a combination of Farkas cutting planes. There is a built-in proof checker for the
format. Quantifier instantiations are also tracked as proof hints. format. Quantifier instantiations are also tracked as proof hints.
Other proof hints are to be added as the feature set is tested and developed. The fallback, buit-in, Other proof hints are to be added as the feature set is tested and developed. The fallback, built-in,
self-checker uses z3 to check that the generated clause is a consequence. Note that this is generally self-checker uses z3 to check that the generated clause is a consequence. Note that this is generally
insufficient as generated clauses are in principle required to only be satisfiability preserving. insufficient as generated clauses are in principle required to only be satisfiability preserving.
Proof checking and tranformation operations is overall open ended. Proof checking and transformation operations is overall open ended.
The log for the first commit introducing this change contains further information on the format. The log for the first commit introducing this change contains further information on the format.
- fix to re-entrancy bug in user propagator (thanks to Clemens Eisenhofer). - fix to re-entrancy bug in user propagator (thanks to Clemens Eisenhofer).
- handle _toExpr for quantified formulas in JS bindings - handle _toExpr for quantified formulas in JS bindings
@ -638,7 +638,7 @@ xor88, parno, gario, Bauna, GManNickG, hanwentao, dinu09, fhowar, Cici, chinissa
(assert F) (assert F)
(check-sat a) (check-sat a)
(check-sat) (check-sat)
If 'F' is unstatisfiable independently of the assumption 'a', and If 'F' is unsatisfiable independently of the assumption 'a', and
the inconsistency can be detected by just performing propagation, the inconsistency can be detected by just performing propagation,
Then, version <= 4.3.1 may return Then, version <= 4.3.1 may return
unsat unsat

View file

@ -139,7 +139,7 @@ def mk_z3consts_py_internal(api_files, output_dir):
assert False, "Invalid %s, line: %s" % (api_file, linenum) assert False, "Invalid %s, line: %s" % (api_file, linenum)
else: else:
assert mode == IN_ENUM assert mode == IN_ENUM
words = re.split('[^\-a-zA-Z0-9_]+', line) words = re.split('[^-a-zA-Z0-9_]+', line)
m = closebrace_pat.match(line) m = closebrace_pat.match(line)
if m: if m:
name = words[1] name = words[1]
@ -227,7 +227,7 @@ def mk_z3consts_dotnet_internal(api_files, output_dir):
assert False, "Invalid %s, line: %s" % (api_file, linenum) assert False, "Invalid %s, line: %s" % (api_file, linenum)
else: else:
assert mode == IN_ENUM assert mode == IN_ENUM
words = re.split('[^\-a-zA-Z0-9_]+', line) words = re.split('[^-a-zA-Z0-9_]+', line)
m = closebrace_pat.match(line) m = closebrace_pat.match(line)
if m: if m:
name = words[1] name = words[1]
@ -315,7 +315,7 @@ def mk_z3consts_java_internal(api_files, package_name, output_dir):
assert False, "Invalid %s, line: %s" % (api_file, linenum) assert False, "Invalid %s, line: %s" % (api_file, linenum)
else: else:
assert mode == IN_ENUM assert mode == IN_ENUM
words = re.split('[^\-a-zA-Z0-9_]+', line) words = re.split('[^-a-zA-Z0-9_]+', line)
m = closebrace_pat.match(line) m = closebrace_pat.match(line)
if m: if m:
name = words[1] name = words[1]
@ -441,7 +441,7 @@ def mk_z3consts_ml_internal(api_files, output_dir):
assert False, "Invalid %s, line: %s" % (api_file, linenum) assert False, "Invalid %s, line: %s" % (api_file, linenum)
else: else:
assert mode == IN_ENUM assert mode == IN_ENUM
words = re.split('[^\-a-zA-Z0-9_]+', line) words = re.split('[^-a-zA-Z0-9_]+', line)
m = closebrace_pat.match(line) m = closebrace_pat.match(line)
if m: if m:
name = words[1] name = words[1]
@ -574,7 +574,7 @@ def mk_def_file_internal(defname, dll_name, export_header_files):
for line in api: for line in api:
m = pat1.match(line) m = pat1.match(line)
if m: if m:
words = re.split('\W+', line) words = re.split(r'\W+', line)
i = 0 i = 0
for w in words: for w in words:
if w == 'Z3_API': if w == 'Z3_API':
@ -618,9 +618,9 @@ def mk_gparams_register_modules_internal(h_files_full_path, path):
fout = open(fullname, 'w') fout = open(fullname, 'w')
fout.write('// Automatically generated file.\n') fout.write('// Automatically generated file.\n')
fout.write('#include "util/gparams.h"\n') fout.write('#include "util/gparams.h"\n')
reg_pat = re.compile('[ \t]*REG_PARAMS\(\'([^\']*)\'\)') reg_pat = re.compile(r'[ \t]*REG_PARAMS\(\'([^\']*)\'\)')
reg_mod_pat = re.compile('[ \t]*REG_MODULE_PARAMS\(\'([^\']*)\', *\'([^\']*)\'\)') reg_mod_pat = re.compile(r'[ \t]*REG_MODULE_PARAMS\(\'([^\']*)\', *\'([^\']*)\'\)')
reg_mod_descr_pat = re.compile('[ \t]*REG_MODULE_DESCRIPTION\(\'([^\']*)\', *\'([^\']*)\'\)') reg_mod_descr_pat = re.compile(r'[ \t]*REG_MODULE_DESCRIPTION\(\'([^\']*)\', *\'([^\']*)\'\)')
for h_file in sorted_headers_by_component(h_files_full_path): for h_file in sorted_headers_by_component(h_files_full_path):
added_include = False added_include = False
with io.open(h_file, encoding='utf-8', mode='r') as fin: with io.open(h_file, encoding='utf-8', mode='r') as fin:
@ -698,9 +698,9 @@ def mk_install_tactic_cpp_internal(h_files_full_path, path):
fout.write('#include "cmd_context/tactic_cmds.h"\n') fout.write('#include "cmd_context/tactic_cmds.h"\n')
fout.write('#include "cmd_context/simplifier_cmds.h"\n') fout.write('#include "cmd_context/simplifier_cmds.h"\n')
fout.write('#include "cmd_context/cmd_context.h"\n') fout.write('#include "cmd_context/cmd_context.h"\n')
tactic_pat = re.compile('[ \t]*ADD_TACTIC\(.*\)') tactic_pat = re.compile(r'[ \t]*ADD_TACTIC\(.*\)')
probe_pat = re.compile('[ \t]*ADD_PROBE\(.*\)') probe_pat = re.compile(r'[ \t]*ADD_PROBE\(.*\)')
simplifier_pat = re.compile('[ \t]*ADD_SIMPLIFIER\(.*\)') simplifier_pat = re.compile(r'[ \t]*ADD_SIMPLIFIER\(.*\)')
for h_file in sorted_headers_by_component(h_files_full_path): for h_file in sorted_headers_by_component(h_files_full_path):
added_include = False added_include = False
try: try:
@ -780,10 +780,10 @@ def mk_mem_initializer_cpp_internal(h_files_full_path, path):
fullname = os.path.join(path, 'mem_initializer.cpp') fullname = os.path.join(path, 'mem_initializer.cpp')
fout = open(fullname, 'w') fout = open(fullname, 'w')
fout.write('// Automatically generated file.\n') fout.write('// Automatically generated file.\n')
initializer_pat = re.compile('[ \t]*ADD_INITIALIZER\(\'([^\']*)\'\)') initializer_pat = re.compile(r'[ \t]*ADD_INITIALIZER\(\'([^\']*)\'\)')
# ADD_INITIALIZER with priority # ADD_INITIALIZER with priority
initializer_prio_pat = re.compile('[ \t]*ADD_INITIALIZER\(\'([^\']*)\',[ \t]*(-?[0-9]*)\)') initializer_prio_pat = re.compile(r'[ \t]*ADD_INITIALIZER\(\'([^\']*)\',[ \t]*(-?[0-9]*)\)')
finalizer_pat = re.compile('[ \t]*ADD_FINALIZER\(\'([^\']*)\'\)') finalizer_pat = re.compile(r'[ \t]*ADD_FINALIZER\(\'([^\']*)\'\)')
for h_file in sorted_headers_by_component(h_files_full_path): for h_file in sorted_headers_by_component(h_files_full_path):
added_include = False added_include = False
with io.open(h_file, encoding='utf-8', mode='r') as fin: with io.open(h_file, encoding='utf-8', mode='r') as fin:
@ -952,7 +952,7 @@ def mk_hpp_from_pyg(pyg_file, output_dir):
'UINT_MAX' : UINT_MAX, 'UINT_MAX' : UINT_MAX,
'max_memory_param' : max_memory_param, 'max_memory_param' : max_memory_param,
'max_steps_param' : max_steps_param, 'max_steps_param' : max_steps_param,
# Note that once this function is enterred that function # Note that once this function is entered that function
# executes with respect to the globals of this module and # executes with respect to the globals of this module and
# not the globals defined here # not the globals defined here
'def_module_params' : def_module_params, 'def_module_params' : def_module_params,

View file

@ -395,7 +395,7 @@ def check_java():
else: else:
# Search for jni.h in the library directories... # Search for jni.h in the library directories...
t = open('errout', 'r') t = open('errout', 'r')
open_pat = re.compile("\[search path for class files: (.*)\]") open_pat = re.compile(r"\[search path for class files: (.*)\]")
cdirs = [] cdirs = []
for line in t: for line in t:
m = open_pat.match(line) m = open_pat.match(line)
@ -812,8 +812,8 @@ def parse_options():
def extract_c_includes(fname): def extract_c_includes(fname):
result = {} result = {}
# We look for well behaved #include directives # We look for well behaved #include directives
std_inc_pat = re.compile("[ \t]*#include[ \t]*\"(.*)\"[ \t]*") std_inc_pat = re.compile(r"[ \t]*#include[ \t]*\"(.*)\"[ \t]*")
system_inc_pat = re.compile("[ \t]*#include[ \t]*\<.*\>[ \t]*") system_inc_pat = re.compile(r"[ \t]*#include[ \t]*\<.*\>[ \t]*")
# We should generate and error for any occurrence of #include that does not match the previous pattern. # We should generate and error for any occurrence of #include that does not match the previous pattern.
non_std_inc_pat = re.compile(".*#include.*") non_std_inc_pat = re.compile(".*#include.*")
@ -1720,7 +1720,7 @@ class DotNetDLLComponent(Component):
print("Version output to csproj:", version) print("Version output to csproj:", version)
core_csproj_str = """<Project Sdk="Microsoft.NET.Sdk"> core_csproj_str = r"""<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard1.4</TargetFramework> <TargetFramework>netstandard1.4</TargetFramework>
@ -2246,7 +2246,7 @@ class DotNetExampleComponent(ExampleComponent):
else: else:
platform = 'x86' platform = 'x86'
dotnet_proj_str = """<Project Sdk="Microsoft.NET.Sdk"> dotnet_proj_str = r"""<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework> <TargetFramework>netcoreapp2.0</TargetFramework>
@ -3162,7 +3162,7 @@ def mk_vs_proj_property_groups(f, name, target_ext, type):
f.write(' <Keyword>Win32Proj</Keyword>\n') f.write(' <Keyword>Win32Proj</Keyword>\n')
f.write(' <PlatformToolset>%s</PlatformToolset>\n' % get_platform_toolset_str()) f.write(' <PlatformToolset>%s</PlatformToolset>\n' % get_platform_toolset_str())
f.write(' </PropertyGroup>\n') f.write(' </PropertyGroup>\n')
f.write(' <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\n') f.write(' <Import Project="$(VCTargetsPath)\\Microsoft.Cpp.Default.props" />\n')
f.write(' <PropertyGroup Condition="\'$(Configuration)|$(Platform)\'==\'Debug|Win32\'" Label="Configuration">\n') f.write(' <PropertyGroup Condition="\'$(Configuration)|$(Platform)\'==\'Debug|Win32\'" Label="Configuration">\n')
f.write(' <ConfigurationType>%s</ConfigurationType>\n' % type) f.write(' <ConfigurationType>%s</ConfigurationType>\n' % type)
f.write(' <CharacterSet>Unicode</CharacterSet>\n') f.write(' <CharacterSet>Unicode</CharacterSet>\n')
@ -3173,24 +3173,24 @@ def mk_vs_proj_property_groups(f, name, target_ext, type):
f.write(' <CharacterSet>Unicode</CharacterSet>\n') f.write(' <CharacterSet>Unicode</CharacterSet>\n')
f.write(' <UseOfMfc>false</UseOfMfc>\n') f.write(' <UseOfMfc>false</UseOfMfc>\n')
f.write(' </PropertyGroup>\n') f.write(' </PropertyGroup>\n')
f.write(' <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\n') f.write(' <Import Project="$(VCTargetsPath)\\Microsoft.Cpp.props" />\n')
f.write(' <ImportGroup Label="ExtensionSettings" />\n') f.write(' <ImportGroup Label="ExtensionSettings" />\n')
f.write(' <ImportGroup Label="PropertySheets">\n') f.write(' <ImportGroup Label="PropertySheets">\n')
f.write(' <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists(\'$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props\')" Label="LocalAppDataPlatform" /> </ImportGroup>\n') f.write(' <Import Project="$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props" Condition="exists(\'$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\')" Label="LocalAppDataPlatform" /> </ImportGroup>\n')
f.write(' <PropertyGroup Label="UserMacros" />\n') f.write(' <PropertyGroup Label="UserMacros" />\n')
f.write(' <PropertyGroup>\n') f.write(' <PropertyGroup>\n')
f.write(' <OutDir Condition="\'$(Configuration)|$(Platform)\'==\'Debug|Win32\'">$(SolutionDir)\$(ProjectName)\$(Configuration)\</OutDir>\n') f.write(' <OutDir Condition="\'$(Configuration)|$(Platform)\'==\'Debug|Win32\'">$(SolutionDir)\\$(ProjectName)\\$(Configuration)\\</OutDir>\n')
f.write(' <TargetName Condition="\'$(Configuration)|$(Platform)\'==\'Debug|Win32\'">%s</TargetName>\n' % name) f.write(' <TargetName Condition="\'$(Configuration)|$(Platform)\'==\'Debug|Win32\'">%s</TargetName>\n' % name)
f.write(' <TargetExt Condition="\'$(Configuration)|$(Platform)\'==\'Debug|Win32\'">.%s</TargetExt>\n' % target_ext) f.write(' <TargetExt Condition="\'$(Configuration)|$(Platform)\'==\'Debug|Win32\'">.%s</TargetExt>\n' % target_ext)
f.write(' <OutDir Condition="\'$(Configuration)|$(Platform)\'==\'Release|Win32\'">$(SolutionDir)\$(ProjectName)\$(Configuration)\</OutDir>\n') f.write(' <OutDir Condition="\'$(Configuration)|$(Platform)\'==\'Release|Win32\'">$(SolutionDir)\\$(ProjectName)\\$(Configuration)\\</OutDir>\n')
f.write(' <TargetName Condition="\'$(Configuration)|$(Platform)\'==\'Release|Win32\'">%s</TargetName>\n' % name) f.write(' <TargetName Condition="\'$(Configuration)|$(Platform)\'==\'Release|Win32\'">%s</TargetName>\n' % name)
f.write(' <TargetExt Condition="\'$(Configuration)|$(Platform)\'==\'Release|Win32\'">.%s</TargetExt>\n' % target_ext) f.write(' <TargetExt Condition="\'$(Configuration)|$(Platform)\'==\'Release|Win32\'">.%s</TargetExt>\n' % target_ext)
f.write(' </PropertyGroup>\n') f.write(' </PropertyGroup>\n')
f.write(' <PropertyGroup Condition="\'$(Configuration)|$(Platform)\'==\'Debug|Win32\'">\n') f.write(' <PropertyGroup Condition="\'$(Configuration)|$(Platform)\'==\'Debug|Win32\'">\n')
f.write(' <IntDir>$(ProjectName)\$(Configuration)\</IntDir>\n') f.write(' <IntDir>$(ProjectName)\\$(Configuration)\\</IntDir>\n')
f.write(' </PropertyGroup>\n') f.write(' </PropertyGroup>\n')
f.write(' <PropertyGroup Condition="\'$(Configuration)|$(Platform)\'==\'Release|Win32\'">\n') f.write(' <PropertyGroup Condition="\'$(Configuration)|$(Platform)\'==\'Release|Win32\'">\n')
f.write(' <IntDir>$(ProjectName)\$(Configuration)\</IntDir>\n') f.write(' <IntDir>$(ProjectName)\\$(Configuration)\\</IntDir>\n')
f.write(' </PropertyGroup>\n') f.write(' </PropertyGroup>\n')
@ -3267,7 +3267,7 @@ def mk_vs_proj(name, components):
mk_vs_proj_link_exe(f, name, debug=False) mk_vs_proj_link_exe(f, name, debug=False)
f.write(' </ItemDefinitionGroup>\n') f.write(' </ItemDefinitionGroup>\n')
mk_vs_proj_dep_groups(f, name, components) mk_vs_proj_dep_groups(f, name, components)
f.write(' <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\n') f.write(' <Import Project="$(VCTargetsPath)\\Microsoft.Cpp.targets" />\n')
f.write(' <ImportGroup Label="ExtensionTargets">\n') f.write(' <ImportGroup Label="ExtensionTargets">\n')
f.write(' </ImportGroup>\n') f.write(' </ImportGroup>\n')
f.write('</Project>\n') f.write('</Project>\n')
@ -3308,7 +3308,7 @@ def mk_vs_proj_dll(name, components):
mk_vs_proj_link_dll(f, name, debug=False) mk_vs_proj_link_dll(f, name, debug=False)
f.write(' </ItemDefinitionGroup>\n') f.write(' </ItemDefinitionGroup>\n')
mk_vs_proj_dep_groups(f, name, components) mk_vs_proj_dep_groups(f, name, components)
f.write(' <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\n') f.write(' <Import Project="$(VCTargetsPath)\\Microsoft.Cpp.targets" />\n')
f.write(' <ImportGroup Label="ExtensionTargets">\n') f.write(' <ImportGroup Label="ExtensionTargets">\n')
f.write(' </ImportGroup>\n') f.write(' </ImportGroup>\n')
f.write('</Project>\n') f.write('</Project>\n')

View file

@ -116,8 +116,8 @@ class APITypes:
def def_Types(self, api_files): def def_Types(self, api_files):
global Closures global Closures
pat1 = re.compile(" *def_Type\(\'(.*)\',[^\']*\'(.*)\',[^\']*\'(.*)\'\)[ \t]*") pat1 = re.compile(r" *def_Type\(\'(.*)\',[^\']*\'(.*)\',[^\']*\'(.*)\'\)[ \t]*")
pat2 = re.compile("Z3_DECLARE_CLOSURE\((.*),(.*), \((.*)\)\)") pat2 = re.compile(r"Z3_DECLARE_CLOSURE\((.*),(.*), \((.*)\)\)")
for api_file in api_files: for api_file in api_files:
with open(api_file, 'r') as api: with open(api_file, 'r') as api:
for line in api: for line in api:

View file

@ -22,7 +22,7 @@ A tactic for performing Ackermann reduction for bit-vector formulas
### Long Description ### Long Description
The Ackermann reduction replaces uninterpreted functions $f(t_1), f(t_2)$ The Ackermann reduction replaces uninterpreted functions $f(t_1), f(t_2)$
by fresh variables $f_1, f_2$ and addes axioms $t_1 \simeq t_2 \implies f_1 \simeq f_2$. by fresh variables $f_1, f_2$ and adds axioms $t_1 \simeq t_2 \implies f_1 \simeq f_2$.
The reduction has the effect of eliminating uninterpreted functions. When the reduction The reduction has the effect of eliminating uninterpreted functions. When the reduction
produces a pure bit-vector benchmark, it allows Z3 to use a specialized SAT solver. produces a pure bit-vector benchmark, it allows Z3 to use a specialized SAT solver.

View file

@ -231,7 +231,7 @@ namespace api {
void handle_exception(z3_exception & ex); void handle_exception(z3_exception & ex);
char const * get_exception_msg() const { return m_exception_msg.c_str(); } char const * get_exception_msg() const { return m_exception_msg.c_str(); }
// Interrupt the current interruptable object // Interrupt the current interruptible object
void interrupt(); void interrupt();
void invoke_error_handler(Z3_error_code c); void invoke_error_handler(Z3_error_code c);

View file

@ -742,7 +742,7 @@ extern "C" {
fpa_util & fu = ctx->fpautil(); fpa_util & fu = ctx->fpautil();
if (!ctx->bvutil().is_bv(to_expr(bv)) || if (!ctx->bvutil().is_bv(to_expr(bv)) ||
!fu.is_float(to_sort(s))) { !fu.is_float(to_sort(s))) {
SET_ERROR_CODE(Z3_INVALID_ARG, "bv sort the flaot sort expected"); SET_ERROR_CODE(Z3_INVALID_ARG, "bv sort the float sort expected");
return nullptr; return nullptr;
} }
expr * a = fu.mk_to_fp(to_sort(s), to_expr(bv)); expr * a = fu.mk_to_fp(to_sort(s), to_expr(bv));

View file

@ -1092,15 +1092,15 @@ extern "C" {
Z3_CATCH; Z3_CATCH;
} }
void Z3_API Z3_solver_propagate_consequence(Z3_context c, Z3_solver_callback s, unsigned num_fixed, Z3_ast const* fixed_ids, unsigned num_eqs, Z3_ast const* eq_lhs, Z3_ast const* eq_rhs, Z3_ast conseq) { bool Z3_API Z3_solver_propagate_consequence(Z3_context c, Z3_solver_callback s, unsigned num_fixed, Z3_ast const* fixed_ids, unsigned num_eqs, Z3_ast const* eq_lhs, Z3_ast const* eq_rhs, Z3_ast conseq) {
Z3_TRY; Z3_TRY;
LOG_Z3_solver_propagate_consequence(c, s, num_fixed, fixed_ids, num_eqs, eq_lhs, eq_rhs, conseq); LOG_Z3_solver_propagate_consequence(c, s, num_fixed, fixed_ids, num_eqs, eq_lhs, eq_rhs, conseq);
RESET_ERROR_CODE(); RESET_ERROR_CODE();
expr* const * _fixed_ids = (expr* const*) fixed_ids; expr* const * _fixed_ids = (expr* const*) fixed_ids;
expr* const * _eq_lhs = (expr*const*) eq_lhs; expr* const * _eq_lhs = (expr*const*) eq_lhs;
expr* const * _eq_rhs = (expr*const*) eq_rhs; expr* const * _eq_rhs = (expr*const*) eq_rhs;
reinterpret_cast<user_propagator::callback*>(s)->propagate_cb(num_fixed, _fixed_ids, num_eqs, _eq_lhs, _eq_rhs, to_expr(conseq)); return reinterpret_cast<user_propagator::callback*>(s)->propagate_cb(num_fixed, _fixed_ids, num_eqs, _eq_lhs, _eq_rhs, to_expr(conseq));
Z3_CATCH; Z3_CATCH_RETURN(false);
} }
void Z3_API Z3_solver_propagate_created(Z3_context c, Z3_solver s, Z3_created_eh created_eh) { void Z3_API Z3_solver_propagate_created(Z3_context c, Z3_solver s, Z3_created_eh created_eh) {

View file

@ -320,7 +320,7 @@ namespace z3 {
/** /**
\brief Create a recursive datatype over a single sort. \brief Create a recursive datatype over a single sort.
\c name is the name of the recursive datatype \c name is the name of the recursive datatype
\c n - the numer of constructors of the datatype \c n - the number of constructors of the datatype
\c cs - the \c n constructors used to define the datatype \c cs - the \c n constructors used to define the datatype
References to the datatype can be created using \ref datatype_sort. References to the datatype can be created using \ref datatype_sort.
@ -4496,14 +4496,14 @@ namespace z3 {
Z3_solver_propagate_consequence(ctx(), cb, fixed.size(), _fixed.ptr(), lhs.size(), _lhs.ptr(), _rhs.ptr(), conseq); Z3_solver_propagate_consequence(ctx(), cb, fixed.size(), _fixed.ptr(), lhs.size(), _lhs.ptr(), _rhs.ptr(), conseq);
} }
void propagate(expr_vector const& fixed, expr const& conseq) { bool propagate(expr_vector const& fixed, expr const& conseq) {
assert(cb); assert(cb);
assert((Z3_context)conseq.ctx() == (Z3_context)ctx()); assert((Z3_context)conseq.ctx() == (Z3_context)ctx());
array<Z3_ast> _fixed(fixed); array<Z3_ast> _fixed(fixed);
Z3_solver_propagate_consequence(ctx(), cb, _fixed.size(), _fixed.ptr(), 0, nullptr, nullptr, conseq); return Z3_solver_propagate_consequence(ctx(), cb, _fixed.size(), _fixed.ptr(), 0, nullptr, nullptr, conseq);
} }
void propagate(expr_vector const& fixed, bool propagate(expr_vector const& fixed,
expr_vector const& lhs, expr_vector const& rhs, expr_vector const& lhs, expr_vector const& rhs,
expr const& conseq) { expr const& conseq) {
assert(cb); assert(cb);
@ -4513,7 +4513,7 @@ namespace z3 {
array<Z3_ast> _lhs(lhs); array<Z3_ast> _lhs(lhs);
array<Z3_ast> _rhs(rhs); array<Z3_ast> _rhs(rhs);
Z3_solver_propagate_consequence(ctx(), cb, _fixed.size(), _fixed.ptr(), lhs.size(), _lhs.ptr(), _rhs.ptr(), conseq); return Z3_solver_propagate_consequence(ctx(), cb, _fixed.size(), _fixed.ptr(), lhs.size(), _lhs.ptr(), _rhs.ptr(), conseq);
} }
}; };

View file

@ -3770,7 +3770,7 @@ namespace Microsoft.Z3
} }
/// <summary> /// <summary>
/// Create a simplifie that applies <paramref name="t1"/> and /// Create a simplifier that applies <paramref name="t1"/> and
/// then <paramref name="t2"/>. /// then <paramref name="t2"/>.
/// </summary> /// </summary>
public Simplifier AndThen(Simplifier t1, Simplifier t2, params Simplifier[] ts) public Simplifier AndThen(Simplifier t1, Simplifier t2, params Simplifier[] ts)

View file

@ -97,7 +97,7 @@ namespace Microsoft.Z3
} }
/// <summary> /// <summary>
/// The Symbols's hash code. /// The Symbol's hash code.
/// </summary> /// </summary>
/// <returns>A hash code</returns> /// <returns>A hash code</returns>
public override int GetHashCode() public override int GetHashCode()

View file

@ -58,7 +58,7 @@ namespace Microsoft.Z3
public delegate void CreatedEh(Expr term); public delegate void CreatedEh(Expr term);
/// <summary> /// <summary>
/// Delegate type for callback into solver's branching. The values can be overriden by calling <see cref="NextSplit" />. /// Delegate type for callback into solver's branching. The values can be overridden by calling <see cref="NextSplit" />.
/// </summary> /// </summary>
/// <param name="term">A bit-vector or Boolean used for branching</param> /// <param name="term">A bit-vector or Boolean used for branching</param>
/// <param name="idx">If the term is a bit-vector, then an index into the bit-vector being branched on</param> /// <param name="idx">If the term is a bit-vector, then an index into the bit-vector being branched on</param>
@ -252,11 +252,29 @@ namespace Microsoft.Z3
/// <summary> /// <summary>
/// Propagate consequence /// Propagate consequence
/// <returns>
/// <see langword="true" /> if the propagated expression is new for the solver;
/// <see langword="false" /> if the propagation was ignored
/// </returns>
/// </summary> /// </summary>
public void Propagate(IEnumerable<Expr> terms, Expr conseq) public bool Propagate(IEnumerable<Expr> terms, Expr conseq)
{
return Propagate(terms, new EqualityPairs(), conseq);
}
/// <summary>
/// Propagate consequence
/// <returns>
/// <see langword="true" /> if the propagated expression is new for the solver;
/// <see langword="false" /> if the propagation was ignored
/// </returns>
/// </summary>
public bool Propagate(IEnumerable<Expr> terms, EqualityPairs equalities, Expr conseq)
{ {
var nTerms = Z3Object.ArrayToNative(terms.ToArray()); var nTerms = Z3Object.ArrayToNative(terms.ToArray());
Native.Z3_solver_propagate_consequence(ctx.nCtx, this.callback, (uint)nTerms.Length, nTerms, 0u, null, null, conseq.NativeObject); var nLHS = Z3Object.ArrayToNative(equalities.LHS.ToArray());
var nRHS = Z3Object.ArrayToNative(equalities.RHS.ToArray());
return Native.Z3_solver_propagate_consequence(ctx.nCtx, this.callback, (uint)nTerms.Length, nTerms, (uint)equalities.Count, nLHS, nRHS, conseq.NativeObject) != 0;
} }
@ -375,4 +393,72 @@ namespace Microsoft.Z3
} }
} }
} }
/// <summary>
/// A list of equalities used as justifications for propagation
/// </summary>
public class EqualityPairs {
readonly List<Expr> lhsList = new List<Expr>();
readonly List<Expr> rhsList = new List<Expr>();
/// <summary>
/// The left hand sides of the equalities
/// </summary>
public Expr[] LHS => lhsList.ToArray();
/// <summary>
/// The right hand sides of the equalities
/// </summary>
public Expr[] RHS => rhsList.ToArray();
/// <summary>
/// The number of equalities
/// </summary>
public int Count => lhsList.Count;
/// <summary>
/// Adds an equality to the list. The sorts of the arguments have to be the same.
/// <param name="lhs">The left hand side of the equality</param>
/// <param name="rhs">The right hand side of the equality</param>
/// </summary>
public void Add(Expr lhs, Expr rhs) {
lhsList.Add(lhs);
rhsList.Add(rhs);
}
/// <summary>
/// Checks if two equality lists are equal.
/// The function does not take symmetries, shuffling, or duplicates into account.
/// </summary>
public override bool Equals(object obj) {
if (ReferenceEquals(this, obj))
return true;
if (!(obj is EqualityPairs other))
return false;
if (lhsList.Count != other.lhsList.Count)
return false;
for (int i = 0; i < lhsList.Count; i++) {
if (!lhsList[i].Equals(other.lhsList[i]))
return false;
}
return true;
}
/// <summary>
/// Gets a hash code for the list of equalities
/// </summary>
public override int GetHashCode() {
int hash = lhsList.Count;
unchecked {
for (int i = 0; i < lhsList.Count; i++) {
hash ^= lhsList[i].GetHashCode();
hash *= 17;
hash ^= rhsList[i].GetHashCode();
hash *= 29;
}
return hash;
}
}
}
} }

View file

@ -2309,7 +2309,7 @@ public class Context implements AutoCloseable {
/** /**
* Create the empty regular expression. * Create the empty regular expression.
* Coresponds to re.none * Corresponds to re.none
*/ */
public final <R extends Sort> ReExpr<R> mkEmptyRe(ReSort<R> s) public final <R extends Sort> ReExpr<R> mkEmptyRe(ReSort<R> s)
{ {

View file

@ -226,6 +226,7 @@ DLL_VIS JNIEXPORT void JNICALL Java_com_microsoft_z3_Native_propagateAdd(JNIEnv
} }
} }
DLL_VIS JNIEXPORT bool JNICALL Java_com_microsoft_z3_Native_propagateNextSplit(JNIEnv * jenv, jclass cls, jobject jobj, jlong ctx, jlong solver, jlong javainfo, jlong e, long idx, int phase) { DLL_VIS JNIEXPORT bool JNICALL Java_com_microsoft_z3_Native_propagateNextSplit(JNIEnv * jenv, jclass cls, jobject jobj, jlong ctx, jlong solver, jlong javainfo, jlong e, long idx, int phase) {
JavaInfo *info = (JavaInfo*)javainfo; JavaInfo *info = (JavaInfo*)javainfo;
Z3_solver_callback cb = info->cb; Z3_solver_callback cb = info->cb;

View file

@ -166,7 +166,7 @@ public class Quantifier extends BoolExpr
* @param sorts Sorts of bound variables. * @param sorts Sorts of bound variables.
* @param names Names of bound variables * @param names Names of bound variables
* @param body Body of quantifier * @param body Body of quantifier
* @param weight Weight used to indicate priority for qunatifier instantiation * @param weight Weight used to indicate priority for quantifier instantiation
* @param patterns Nullable patterns * @param patterns Nullable patterns
* @param noPatterns Nullable noPatterns * @param noPatterns Nullable noPatterns
* @param quantifierID Nullable quantifierID * @param quantifierID Nullable quantifierID

View file

@ -350,7 +350,7 @@ for (let fn of functions) {
param.sizeIndex = defParams[idx].sizeIndex; param.sizeIndex = defParams[idx].sizeIndex;
if (!param.isArray && param.isPtr) { if (!param.isArray && param.isPtr) {
// not clear why some things are written as `int * x` and others `int x[]` // not clear why some things are written as `int * x` and others `int x[]`
// but we can jsut cast // but we can just cast
param.isArray = true; param.isArray = true;
param.isPtr = false; param.isPtr = false;
} }

View file

@ -223,7 +223,7 @@ correctly found by gcc.
I specifically left the cygwin part of the code intact as I have no I specifically left the cygwin part of the code intact as I have no
idea what the original author meant by this, neither do I use or idea what the original author meant by this, neither do I use or
tested this patch in the cygwin or mingw environemt. I think that this tested this patch in the cygwin or mingw environment. I think that this
code is rather outdated and shouldn't really work. E.g., in the code is rather outdated and shouldn't really work. E.g., in the
--staticlib mode adding z3linkdep (which is libz3-static.a) as an --staticlib mode adding z3linkdep (which is libz3-static.a) as an
argument to `ocamlmklib` will yield the following broken archive argument to `ocamlmklib` will yield the following broken archive

View file

@ -292,7 +292,7 @@ if 'bdist_wheel' in sys.argv and '--plat-name' not in sys.argv:
distos = RELEASE_METADATA[2] distos = RELEASE_METADATA[2]
if distos in ('debian', 'ubuntu'): if distos in ('debian', 'ubuntu'):
raise Exception( raise Exception(
"Linux binary distributions must be built on centos to conform to PEP 513 or alpine if targetting musl" "Linux binary distributions must be built on centos to conform to PEP 513 or alpine if targeting musl"
) )
elif distos == 'glibc': elif distos == 'glibc':
if arch == 'x64': if arch == 'x64':

View file

@ -5385,7 +5385,7 @@ def EnumSort(name, values, ctx=None):
""" """
if z3_debug(): if z3_debug():
_z3_assert(isinstance(name, str), "Name must be a string") _z3_assert(isinstance(name, str), "Name must be a string")
_z3_assert(all([isinstance(v, str) for v in values]), "Eumeration sort values must be strings") _z3_assert(all([isinstance(v, str) for v in values]), "Enumeration sort values must be strings")
_z3_assert(len(values) > 0, "At least one value expected") _z3_assert(len(values) > 0, "At least one value expected")
ctx = _get_ctx(ctx) ctx = _get_ctx(ctx)
num = len(values) num = len(values)
@ -11286,6 +11286,8 @@ def Plus(re):
>>> print(simplify(InRe("", re))) >>> print(simplify(InRe("", re)))
False False
""" """
if z3_debug():
_z3_assert(is_expr(re), "expression expected")
return ReRef(Z3_mk_re_plus(re.ctx_ref(), re.as_ast()), re.ctx) return ReRef(Z3_mk_re_plus(re.ctx_ref(), re.as_ast()), re.ctx)
@ -11299,6 +11301,8 @@ def Option(re):
>>> print(simplify(InRe("aa", re))) >>> print(simplify(InRe("aa", re)))
False False
""" """
if z3_debug():
_z3_assert(is_expr(re), "expression expected")
return ReRef(Z3_mk_re_option(re.ctx_ref(), re.as_ast()), re.ctx) return ReRef(Z3_mk_re_option(re.ctx_ref(), re.as_ast()), re.ctx)
@ -11317,6 +11321,8 @@ def Star(re):
>>> print(simplify(InRe("", re))) >>> print(simplify(InRe("", re)))
True True
""" """
if z3_debug():
_z3_assert(is_expr(re), "expression expected")
return ReRef(Z3_mk_re_star(re.ctx_ref(), re.as_ast()), re.ctx) return ReRef(Z3_mk_re_star(re.ctx_ref(), re.as_ast()), re.ctx)
@ -11330,6 +11336,8 @@ def Loop(re, lo, hi=0):
>>> print(simplify(InRe("", re))) >>> print(simplify(InRe("", re)))
False False
""" """
if z3_debug():
_z3_assert(is_expr(re), "expression expected")
return ReRef(Z3_mk_re_loop(re.ctx_ref(), re.as_ast(), lo, hi), re.ctx) return ReRef(Z3_mk_re_loop(re.ctx_ref(), re.as_ast(), lo, hi), re.ctx)
@ -11343,11 +11351,17 @@ def Range(lo, hi, ctx=None):
""" """
lo = _coerce_seq(lo, ctx) lo = _coerce_seq(lo, ctx)
hi = _coerce_seq(hi, ctx) hi = _coerce_seq(hi, ctx)
if z3_debug():
_z3_assert(is_expr(lo), "expression expected")
_z3_assert(is_expr(hi), "expression expected")
return ReRef(Z3_mk_re_range(lo.ctx_ref(), lo.ast, hi.ast), lo.ctx) return ReRef(Z3_mk_re_range(lo.ctx_ref(), lo.ast, hi.ast), lo.ctx)
def Diff(a, b, ctx=None): def Diff(a, b, ctx=None):
"""Create the difference regular expression """Create the difference regular expression
""" """
if z3_debug():
_z3_assert(is_expr(a), "expression expected")
_z3_assert(is_expr(b), "expression expected")
return ReRef(Z3_mk_re_diff(a.ctx_ref(), a.ast, b.ast), a.ctx) return ReRef(Z3_mk_re_diff(a.ctx_ref(), a.ast, b.ast), a.ctx)
def AllChar(regex_sort, ctx=None): def AllChar(regex_sort, ctx=None):
@ -11690,7 +11704,7 @@ class UserPropagateBase:
num_eqs = len(eqs) num_eqs = len(eqs)
_lhs, _num_lhs = _to_ast_array([x for x, y in eqs]) _lhs, _num_lhs = _to_ast_array([x for x, y in eqs])
_rhs, _num_rhs = _to_ast_array([y for x, y in eqs]) _rhs, _num_rhs = _to_ast_array([y for x, y in eqs])
Z3_solver_propagate_consequence(e.ctx.ref(), ctypes.c_void_p( return Z3_solver_propagate_consequence(e.ctx.ref(), ctypes.c_void_p(
self.cb), num_fixed, _ids, num_eqs, _lhs, _rhs, e.ast) self.cb), num_fixed, _ids, num_eqs, _lhs, _rhs, e.ast)
def conflict(self, deps = [], eqs = []): def conflict(self, deps = [], eqs = []):

View file

@ -275,7 +275,7 @@ def prove(claim, assume=None, verbose=0):
def get_models(f, k): def get_models(f, k):
""" """
Returns the first k models satisfiying f. Returns the first k models satisfying f.
If f is not satisfiable, returns False. If f is not satisfiable, returns False.
If f cannot be solved, returns None If f cannot be solved, returns None
If f is satisfiable, returns the first k models If f is satisfiable, returns the first k models
@ -485,7 +485,7 @@ def model_str(m, as_str=True):
x = 10, y = 3 x = 10, y = 3
EXAMPLES: EXAMPLES:
see doctest exampels from function prove() see doctest examples from function prove()
""" """
if z3_debug(): if z3_debug():

View file

@ -3614,7 +3614,7 @@ extern "C" {
/** /**
\brief Retrieve the string constant stored in \c s. \brief Retrieve the string constant stored in \c s.
Characters outside the basic printiable ASCII range are escaped. Characters outside the basic printable ASCII range are escaped.
\pre Z3_is_string(c, s) \pre Z3_is_string(c, s)
@ -4897,7 +4897,7 @@ extern "C" {
/** /**
\brief Return a hash code for the given AST. \brief Return a hash code for the given AST.
The hash code is structural but two different AST objects can map to the same hash. The hash code is structural but two different AST objects can map to the same hash.
The result of \c Z3_get_ast_id returns an indentifier that is unique over the The result of \c Z3_get_ast_id returns an identifier that is unique over the
set of live AST objects. set of live AST objects.
def_API('Z3_get_ast_hash', UINT, (_in(CONTEXT), _in(AST))) def_API('Z3_get_ast_hash', UINT, (_in(CONTEXT), _in(AST)))
@ -5346,7 +5346,7 @@ extern "C" {
Z3_ast const to[]); Z3_ast const to[]);
/** /**
\brief Substitute funcions in \c from with new expressions in \c to. \brief Substitute functions in \c from with new expressions in \c to.
The expressions in \c to can have free variables. The free variable in \c to at index 0 The expressions in \c to can have free variables. The free variable in \c to at index 0
refers to the first argument of \c from, the free variable at index 1 corresponds to the second argument. refers to the first argument of \c from, the free variable at index 1 corresponds to the second argument.
@ -7026,13 +7026,13 @@ extern "C" {
Z3_on_clause_eh on_clause_eh); Z3_on_clause_eh on_clause_eh);
/** /**
\brief register a user-properator with the solver. \brief register a user-propagator with the solver.
\param c - context. \param c - context.
\param s - solver object. \param s - solver object.
\param user_context - a context used to maintain state for callbacks. \param user_context - a context used to maintain state for callbacks.
\param push_eh - a callback invoked when scopes are pushed \param push_eh - a callback invoked when scopes are pushed
\param pop_eh - a callback invoked when scopes are poped \param pop_eh - a callback invoked when scopes are popped
\param fresh_eh - a solver may spawn new solvers internally. This callback is used to produce a fresh user_context to be associated with fresh solvers. \param fresh_eh - a solver may spawn new solvers internally. This callback is used to produce a fresh user_context to be associated with fresh solvers.
def_API('Z3_solver_propagate_init', VOID, (_in(CONTEXT), _in(SOLVER), _in(VOID_PTR), _fnptr(Z3_push_eh), _fnptr(Z3_pop_eh), _fnptr(Z3_fresh_eh))) def_API('Z3_solver_propagate_init', VOID, (_in(CONTEXT), _in(SOLVER), _in(VOID_PTR), _fnptr(Z3_push_eh), _fnptr(Z3_pop_eh), _fnptr(Z3_fresh_eh)))
@ -7150,11 +7150,15 @@ extern "C" {
This is a callback a client may invoke during the fixed_eh callback. This is a callback a client may invoke during the fixed_eh callback.
The callback adds a propagation consequence based on the fixed values of the The callback adds a propagation consequence based on the fixed values of the
\c ids. \c ids.
The solver might discard the propagation in case it is true in the current state.
The function returns false in this case; otw. the function returns true.
At least one propagation in the final callback has to return true in order to
prevent the solver from finishing.
def_API('Z3_solver_propagate_consequence', VOID, (_in(CONTEXT), _in(SOLVER_CALLBACK), _in(UINT), _in_array(2, AST), _in(UINT), _in_array(4, AST), _in_array(4, AST), _in(AST))) def_API('Z3_solver_propagate_consequence', BOOL, (_in(CONTEXT), _in(SOLVER_CALLBACK), _in(UINT), _in_array(2, AST), _in(UINT), _in_array(4, AST), _in_array(4, AST), _in(AST)))
*/ */
void Z3_API Z3_solver_propagate_consequence(Z3_context c, Z3_solver_callback cb, unsigned num_fixed, Z3_ast const* fixed, unsigned num_eqs, Z3_ast const* eq_lhs, Z3_ast const* eq_rhs, Z3_ast conseq); bool Z3_API Z3_solver_propagate_consequence(Z3_context c, Z3_solver_callback cb, unsigned num_fixed, Z3_ast const* fixed, unsigned num_eqs, Z3_ast const* eq_lhs, Z3_ast const* eq_rhs, Z3_ast conseq);
/** /**
\brief Check whether the assertions in a given solver are consistent or not. \brief Check whether the assertions in a given solver are consistent or not.

View file

@ -72,7 +72,7 @@ struct z3_replayer::imp {
void check_arg(unsigned pos, value_kind k) const { void check_arg(unsigned pos, value_kind k) const {
if (pos >= m_args.size()) { if (pos >= m_args.size()) {
TRACE("z3_replayer", tout << "too few arguments " << m_args.size() << " expecting " << kind2string(k) << "\n";); TRACE("z3_replayer", tout << pos << " too few arguments " << m_args.size() << " expecting " << kind2string(k) << "\n";);
throw z3_replayer_exception("invalid argument reference"); throw z3_replayer_exception("invalid argument reference");
} }
if (m_args[pos].m_kind != k) { if (m_args[pos].m_kind != k) {

View file

@ -370,7 +370,7 @@ inline func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, bool is_real) {
if (is_real) { if (is_real) {
return m_manager->mk_func_decl(symbol("^0"), m_real_decl, m_real_decl, m_real_decl, func_decl_info(m_family_id, OP_POWER0)); return m_manager->mk_func_decl(symbol("^0"), m_real_decl, m_real_decl, m_real_decl, func_decl_info(m_family_id, OP_POWER0));
} }
return m_manager->mk_func_decl(symbol("^0"), m_int_decl, m_int_decl, m_int_decl, func_decl_info(m_family_id, OP_POWER0)); return m_manager->mk_func_decl(symbol("^0"), m_int_decl, m_int_decl, m_real_decl, func_decl_info(m_family_id, OP_POWER0));
case OP_TO_REAL: return m_to_real_decl; case OP_TO_REAL: return m_to_real_decl;
case OP_TO_INT: return m_to_int_decl; case OP_TO_INT: return m_to_int_decl;
case OP_IS_INT: return m_is_int_decl; case OP_IS_INT: return m_is_int_decl;
@ -834,7 +834,7 @@ bool arith_util::is_considered_uninterpreted(func_decl* f, unsigned n, expr* con
func_decl* arith_util::mk_ipower0() { func_decl* arith_util::mk_ipower0() {
sort* s = mk_int(); sort* s = mk_int();
sort* rs[2] = { s, s }; sort* rs[2] = { s, s };
return m_manager.mk_func_decl(arith_family_id, OP_POWER0, 0, nullptr, 2, rs, s); return m_manager.mk_func_decl(arith_family_id, OP_POWER0, 0, nullptr, 2, rs, mk_real());
} }
func_decl* arith_util::mk_rpower0() { func_decl* arith_util::mk_rpower0() {

View file

@ -1378,6 +1378,7 @@ void ast_manager::init() {
ENSURE(model_value_family_id == mk_family_id("model-value")); ENSURE(model_value_family_id == mk_family_id("model-value"));
ENSURE(user_sort_family_id == mk_family_id("user-sort")); ENSURE(user_sort_family_id == mk_family_id("user-sort"));
ENSURE(arith_family_id == mk_family_id("arith")); ENSURE(arith_family_id == mk_family_id("arith"));
ENSURE(poly_family_id == mk_family_id("polymorphic"));
basic_decl_plugin * plugin = alloc(basic_decl_plugin); basic_decl_plugin * plugin = alloc(basic_decl_plugin);
register_plugin(basic_family_id, plugin); register_plugin(basic_family_id, plugin);
m_bool_sort = plugin->mk_bool_sort(); m_bool_sort = plugin->mk_bool_sort();
@ -2019,6 +2020,11 @@ sort * ast_manager::mk_uninterpreted_sort(symbol const & name, unsigned num_para
return plugin->mk_sort(kind, num_parameters, parameters); return plugin->mk_sort(kind, num_parameters, parameters);
} }
sort * ast_manager::mk_type_var(symbol const& name) {
sort_info si(poly_family_id, 0);
return mk_sort(name, &si);
}
func_decl * ast_manager::mk_func_decl(symbol const & name, unsigned arity, sort * const * domain, sort * range, func_decl * ast_manager::mk_func_decl(symbol const & name, unsigned arity, sort * const * domain, sort * range,
bool assoc, bool comm, bool inj) { bool assoc, bool comm, bool inj) {
func_decl_info info(null_family_id, null_decl_kind); func_decl_info info(null_family_id, null_decl_kind);

View file

@ -85,6 +85,7 @@ const family_id user_sort_family_id = 4;
const family_id last_builtin_family_id = 4; const family_id last_builtin_family_id = 4;
const family_id arith_family_id = 5; const family_id arith_family_id = 5;
const family_id poly_family_id = 6;
// ----------------------------------- // -----------------------------------
// //
@ -622,6 +623,7 @@ public:
sort_size const & get_num_elements() const { return get_info()->get_num_elements(); } sort_size const & get_num_elements() const { return get_info()->get_num_elements(); }
void set_num_elements(sort_size const& s) { get_info()->set_num_elements(s); } void set_num_elements(sort_size const& s) { get_info()->set_num_elements(s); }
unsigned get_size() const { return get_obj_size(); } unsigned get_size() const { return get_obj_size(); }
bool is_type_var() const { return get_family_id() == poly_family_id; }
}; };
// ----------------------------------- // -----------------------------------
@ -1709,6 +1711,8 @@ public:
sort * mk_uninterpreted_sort(symbol const & name) { return mk_uninterpreted_sort(name, 0, nullptr); } sort * mk_uninterpreted_sort(symbol const & name) { return mk_uninterpreted_sort(name, 0, nullptr); }
sort * mk_type_var(symbol const& name);
sort * mk_sort(symbol const & name, sort_info const & info) { sort * mk_sort(symbol const & name, sort_info const & info) {
if (info.get_family_id() == null_family_id) { if (info.get_family_id() == null_family_id) {
return mk_uninterpreted_sort(name); return mk_uninterpreted_sort(name);

View file

@ -651,7 +651,7 @@ func_decl * bv_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p
for (unsigned i = 0; i < num_args; ++i) { for (unsigned i = 0; i < num_args; ++i) {
if (args[i]->get_sort() != r->get_domain(i)) { if (args[i]->get_sort() != r->get_domain(i)) {
std::ostringstream buffer; std::ostringstream buffer;
buffer << "Argument " << mk_pp(args[i], m) << " at position " << i << " has sort " << mk_pp(args[i]->get_sort(), m) << " it does does not match declaration " << mk_pp(r, m); buffer << "Argument " << mk_pp(args[i], m) << " at position " << i << " has sort " << mk_pp(args[i]->get_sort(), m) << " it does not match declaration " << mk_pp(r, m);
m.raise_exception(buffer.str()); m.raise_exception(buffer.str());
return nullptr; return nullptr;
} }

View file

@ -96,7 +96,7 @@ enum bv_op_kind {
OP_BUMUL_OVFL, // unsigned multiplication overflow predicate (negation of OP_BUMUL_NO_OVFL) OP_BUMUL_OVFL, // unsigned multiplication overflow predicate (negation of OP_BUMUL_NO_OVFL)
OP_BSMUL_OVFL, // signed multiplication over/underflow predicate OP_BSMUL_OVFL, // signed multiplication over/underflow predicate
OP_BSDIV_OVFL, // signed division overflow perdicate OP_BSDIV_OVFL, // signed division overflow predicate
OP_BNEG_OVFL, // negation overflow predicate OP_BNEG_OVFL, // negation overflow predicate

View file

@ -7,7 +7,7 @@ Module Name:
Abstract: Abstract:
char_plugin for unicode suppport char_plugin for unicode support
Author: Author:

View file

@ -7,7 +7,7 @@ Module Name:
Abstract: Abstract:
char_plugin for unicode suppport char_plugin for unicode support
Author: Author:

View file

@ -78,7 +78,7 @@ public:
* *
* x = t -> fresh * x = t -> fresh
* x := if(fresh, t, diff(t)) * x := if(fresh, t, diff(t))
* where diff is a diagnonalization function available in domains of size > 1. * where diff is a diagonalization function available in domains of size > 1.
* *
*/ */
@ -807,7 +807,7 @@ bool iexpr_inverter::uncnstr(unsigned num, expr * const * args) const {
/** /**
\brief Create a fresh variable for abstracting (f args[0] ... args[num-1]) \brief Create a fresh variable for abstracting (f args[0] ... args[num-1])
Return true if it a new variable was created, and false if the variable already existed for this Return true if a new variable was created, and false if the variable already existed for this
application. Store the variable in v application. Store the variable in v
*/ */
void iexpr_inverter::mk_fresh_uncnstr_var_for(sort * s, expr_ref & v) { void iexpr_inverter::mk_fresh_uncnstr_var_for(sort * s, expr_ref & v) {

View file

@ -275,7 +275,7 @@ namespace datatype {
} }
parameter const & name = parameters[0]; parameter const & name = parameters[0];
if (!name.is_symbol()) { if (!name.is_symbol()) {
TRACE("datatype", tout << "expected symol parameter at position " << 0 << " got: " << name << "\n";); TRACE("datatype", tout << "expected symbol parameter at position " << 0 << " got: " << name << "\n";);
throw invalid_datatype(); throw invalid_datatype();
} }
for (unsigned i = 1; i < num_parameters; ++i) { for (unsigned i = 1; i < num_parameters; ++i) {

View file

@ -52,7 +52,7 @@ namespace datatype {
class accessor { class accessor {
symbol m_name; symbol m_name;
sort_ref m_range; sort_ref m_range;
unsigned m_index; // reference to recursive data-type may only get resolved after all mutually recursive data-types are procssed. unsigned m_index; // reference to recursive data-type may only get resolved after all mutually recursive data-types are processed.
constructor* m_constructor{ nullptr }; constructor* m_constructor{ nullptr };
public: public:
accessor(ast_manager& m, symbol const& n, sort* range): accessor(ast_manager& m, symbol const& n, sort* range):

View file

@ -19,7 +19,7 @@ Notes:
- data structures form the (legacy) SMT solver. - data structures form the (legacy) SMT solver.
- it still uses eager path compression. - it still uses eager path compression.
NB. The worklist is in reality inheritied from the legacy SMT solver. NB. The worklist is in reality inherited from the legacy SMT solver.
It is claimed to have the same effect as delayed congruence table reconstruction from egg. It is claimed to have the same effect as delayed congruence table reconstruction from egg.
Similar to the legacy solver, parents are partially deduplicated. Similar to the legacy solver, parents are partially deduplicated.

View file

@ -16,7 +16,7 @@ Author:
Notes: Notes:
- congruence closure justifications are given a timestamp so it is easy to sort them. - congruence closure justifications are given a timestamp so it is easy to sort them.
See the longer descriptoin in euf_proof_checker.cpp See the longer description in euf_proof_checker.cpp
--*/ --*/

View file

@ -65,7 +65,7 @@ bool macro_finder::is_arith_macro(expr * n, proof * pr, bool deps_valid, expr_de
// functions introduced within macros are Skolem functions // functions introduced within macros are Skolem functions
// To avoid unsound expansion of these as macros (because they // To avoid unsound expansion of these as macros (because they
// appear in model conversions and are therefore not fully // appear in model conversions and are therefore not fully
// replacable) we prevent these from being treated as macro functions. // replaceable) we prevent these from being treated as macro functions.
if (m_macro_manager.contains(f) || f->is_skolem()) if (m_macro_manager.contains(f) || f->is_skolem())
return false; return false;

View file

@ -32,7 +32,7 @@ Revision History:
where T[X] does not contain f. where T[X] does not contain f.
This class is responsible for storing macros and expanding them. This class is responsible for storing macros and expanding them.
It has support for backtracking and tagging declarations in an expression as forbidded for being macros. It has support for backtracking and tagging declarations in an expression as forbidden for being macros.
*/ */
class macro_manager { class macro_manager {
ast_manager & m; ast_manager & m;

View file

@ -207,7 +207,7 @@ void defined_names::impl::mk_definition(expr * e, app * n, sort_ref_buffer & var
// the instantiation rules for store(a, i, v) are: // the instantiation rules for store(a, i, v) are:
// store(a, i, v)[j] = if i = j then v else a[j] with patterns {a[j], store(a, i, v)} { store(a, i, v)[j] } // store(a, i, v)[j] = if i = j then v else a[j] with patterns {a[j], store(a, i, v)} { store(a, i, v)[j] }
// The first pattern is not included. // The first pattern is not included.
// TBD use a model-based scheme for exracting instantiations instead of // TBD use a model-based scheme for extracting instantiations instead of
// using multi-patterns. // using multi-patterns.
// //

View file

@ -109,6 +109,7 @@ pattern_inference_cfg::pattern_inference_cfg(ast_manager & m, pattern_inference_
m_le(), m_le(),
m_nested_arith_only(true), m_nested_arith_only(true),
m_block_loop_patterns(params.m_pi_block_loop_patterns), m_block_loop_patterns(params.m_pi_block_loop_patterns),
m_decompose_patterns(params.m_pi_decompose_patterns),
m_candidates(m), m_candidates(m),
m_pattern_weight_lt(m_candidates_info), m_pattern_weight_lt(m_candidates_info),
m_collect(m, *this), m_collect(m, *this),
@ -407,6 +408,9 @@ bool pattern_inference_cfg::pattern_weight_lt::operator()(expr * n1, expr * n2)
app* pattern_inference_cfg::mk_pattern(app* candidate) { app* pattern_inference_cfg::mk_pattern(app* candidate) {
if (!m_decompose_patterns)
return m.mk_pattern(candidate);
auto has_var_arg = [&](expr* e) { auto has_var_arg = [&](expr* e) {
if (!is_app(e)) if (!is_app(e))
return false; return false;

View file

@ -20,6 +20,7 @@ Revision History:
#include "ast/ast.h" #include "ast/ast.h"
#include "ast/rewriter/rewriter.h" #include "ast/rewriter/rewriter.h"
#include "ast/rewriter/rewriter_def.h"
#include "params/pattern_inference_params.h" #include "params/pattern_inference_params.h"
#include "util/vector.h" #include "util/vector.h"
#include "util/uint_set.h" #include "util/uint_set.h"
@ -69,6 +70,7 @@ class pattern_inference_cfg : public default_rewriter_cfg {
expr * const * m_no_patterns; expr * const * m_no_patterns;
bool m_nested_arith_only; bool m_nested_arith_only;
bool m_block_loop_patterns; bool m_block_loop_patterns;
bool m_decompose_patterns;
struct info { struct info {
uint_set m_free_vars; uint_set m_free_vars;

View file

@ -260,7 +260,7 @@ class reduce_hypotheses {
{ cls.push_back(cls_fact->get_arg(i)); } { cls.push_back(cls_fact->get_arg(i)); }
} else { cls.push_back(cls_fact); } } else { cls.push_back(cls_fact); }
// construct new resovent // construct new resolvent
ptr_buffer<expr> new_fact_cls; ptr_buffer<expr> new_fact_cls;
bool found; bool found;
// XXX quadratic // XXX quadratic
@ -604,7 +604,7 @@ public:
// -- otherwise, the fact has not changed. nothing to simplify // -- otherwise, the fact has not changed. nothing to simplify
SASSERT(m.get_fact(tmp) == m.get_fact(m.get_parent(p, i))); SASSERT(m.get_fact(tmp) == m.get_fact(m.get_parent(p, i)));
parents.push_back(tmp); parents.push_back(tmp);
// remember that we have this derivation while we have not poped the trail // remember that we have this derivation while we have not popped the trail
// but only if the proof is closed (i.e., a real unit) // but only if the proof is closed (i.e., a real unit)
if (is_closed(tmp) && !m_units.contains(m.get_fact(tmp))) { if (is_closed(tmp) && !m_units.contains(m.get_fact(tmp))) {
m_units.insert(m.get_fact(tmp), tmp); m_units.insert(m.get_fact(tmp), tmp);

View file

@ -1121,7 +1121,7 @@ bool arith_rewriter::divides(expr* num, expr* den, expr_ref& result) {
if (m_util.is_numeral(arg, num_r)) num_e = arg; if (m_util.is_numeral(arg, num_r)) num_e = arg;
} }
for (expr* arg : args2) { for (expr* arg : args2) {
// dont remove divisor on (div (* -1 x) (* -1 y)) because rewriting would diverge. // don't remove divisor on (div (* -1 x) (* -1 y)) because rewriting would diverge.
if (mark.is_marked(arg) && (!m_util.is_numeral(arg, num_r) || !num_r.is_minus_one())) { if (mark.is_marked(arg) && (!m_util.is_numeral(arg, num_r) || !num_r.is_minus_one())) {
result = remove_divisor(arg, num, den); result = remove_divisor(arg, num, den);
return true; return true;
@ -1569,22 +1569,49 @@ br_status arith_rewriter::mk_to_real_core(expr * arg, expr_ref & result) {
} }
br_status arith_rewriter::mk_is_int(expr * arg, expr_ref & result) { br_status arith_rewriter::mk_is_int(expr * arg, expr_ref & result) {
numeral a; numeral n;
if (m_util.is_numeral(arg, a)) {
result = a.is_int() ? m.mk_true() : m.mk_false(); if (m_util.is_numeral(arg, n)) {
result = n.is_int() ? m.mk_true() : m.mk_false();
return BR_DONE; return BR_DONE;
} }
else if (m_util.is_to_real(arg)) {
if (m_util.is_to_real(arg)) {
result = m.mk_true(); result = m.mk_true();
return BR_DONE; return BR_DONE;
} }
else {
ptr_buffer<expr> todo;
todo.push_back(arg);
expr_fast_mark1 mark;
for (unsigned i = 0; i < todo.size(); ++i) {
expr* e = todo[i];
if (mark.is_marked(e))
continue;
mark.mark(e, true);
if (m_util.is_to_real(e))
continue;
if (m_util.is_numeral(e, n)) {
if (n.is_int())
continue;
goto bail;
}
if (m_util.is_mul(e) || m_util.is_add(e) || m_util.is_sub(e) || m_util.is_uminus(e)) {
for (expr* a : *to_app(e))
todo.push_back(a);
continue;
}
goto bail;
}
result = m.mk_true();
return BR_DONE;
bail:
result = m.mk_eq(m.mk_app(get_fid(), OP_TO_REAL, result = m.mk_eq(m.mk_app(get_fid(), OP_TO_REAL,
m.mk_app(get_fid(), OP_TO_INT, arg)), m.mk_app(get_fid(), OP_TO_INT, arg)),
arg); arg);
return BR_REWRITE3; return BR_REWRITE3;
} }
}
br_status arith_rewriter::mk_abs_core(expr * arg, expr_ref & result) { br_status arith_rewriter::mk_abs_core(expr * arg, expr_ref & result) {
result = m.mk_ite(m_util.mk_ge(arg, m_util.mk_numeral(rational(0), m_util.is_int(arg))), arg, m_util.mk_uminus(arg)); result = m.mk_ite(m_util.mk_ge(arg, m_util.mk_numeral(rational(0), m_util.is_int(arg))), arg, m_util.mk_uminus(arg));
@ -1916,7 +1943,7 @@ br_status arith_rewriter::mk_tan_core(expr * arg, expr_ref & result) {
br_status arith_rewriter::mk_asin_core(expr * arg, expr_ref & result) { br_status arith_rewriter::mk_asin_core(expr * arg, expr_ref & result) {
// Remark: we assume that ForAll x : asin(-x) == asin(x). // Remark: we assume that ForAll x : asin(-x) == asin(x).
// Mathematica uses this as an axiom. Although asin is an underspecified function for x < -1 or x > 1. // Mathematica uses this as an axiom. Although asin is an underspecified function for x < -1 or x > 1.
// Actually, in Mathematica, asin(x) is a total function that returns a complex number fo x < -1 or x > 1. // Actually, in Mathematica, asin(x) is a total function that returns a complex number for x < -1 or x > 1.
rational k; rational k;
if (is_numeral(arg, k)) { if (is_numeral(arg, k)) {
if (k.is_zero()) { if (k.is_zero()) {

View file

@ -26,6 +26,7 @@ Notes:
void bool_rewriter::updt_params(params_ref const & _p) { void bool_rewriter::updt_params(params_ref const & _p) {
bool_rewriter_params p(_p); bool_rewriter_params p(_p);
m_flat_and_or = p.flat_and_or(); m_flat_and_or = p.flat_and_or();
m_sort_disjunctions = p.sort_disjunctions();
m_elim_and = p.elim_and(); m_elim_and = p.elim_and();
m_elim_ite = p.elim_ite(); m_elim_ite = p.elim_ite();
m_local_ctx = p.local_ctx(); m_local_ctx = p.local_ctx();
@ -183,7 +184,7 @@ br_status bool_rewriter::mk_flat_and_core(unsigned num_args, expr * const * args
} }
br_status bool_rewriter::mk_nflat_or_core(unsigned num_args, expr * const * args, expr_ref & result) { br_status bool_rewriter::mk_nflat_or_core(unsigned num_args, expr * const * args, expr_ref & result) {
bool s = false; bool s = false; // whether we have canceled some disjuncts or found some out or order
ptr_buffer<expr> buffer; ptr_buffer<expr> buffer;
expr_fast_mark1 neg_lits; expr_fast_mark1 neg_lits;
expr_fast_mark2 pos_lits; expr_fast_mark2 pos_lits;
@ -292,8 +293,10 @@ br_status bool_rewriter::mk_nflat_or_core(unsigned num_args, expr * const * args
return st; return st;
#endif #endif
if (s) { if (s) {
if (m_sort_disjunctions) {
ast_lt lt; ast_lt lt;
std::sort(buffer.begin(), buffer.end(), lt); std::sort(buffer.begin(), buffer.end(), lt);
}
result = m().mk_or(sz, buffer.data()); result = m().mk_or(sz, buffer.data());
return BR_DONE; return BR_DONE;
} }
@ -329,7 +332,7 @@ br_status bool_rewriter::mk_flat_or_core(unsigned num_args, expr * const * args,
} }
} }
if (mk_nflat_or_core(flat_args.size(), flat_args.data(), result) == BR_FAILED) { if (mk_nflat_or_core(flat_args.size(), flat_args.data(), result) == BR_FAILED) {
if (!ordered) { if (m_sort_disjunctions && !ordered) {
ast_lt lt; ast_lt lt;
std::sort(flat_args.begin(), flat_args.end(), lt); std::sort(flat_args.begin(), flat_args.end(), lt);
} }
@ -662,12 +665,19 @@ br_status bool_rewriter::try_ite_value(app * ite, app * val, expr_ref & result)
SASSERT(m().is_value(val)); SASSERT(m().is_value(val));
if (m().are_distinct(val, e)) { if (m().are_distinct(val, e)) {
if (get_depth(t) < 500)
mk_eq(t, val, result); mk_eq(t, val, result);
else
result = m().mk_eq(t, val);
result = m().mk_and(result, cond); result = m().mk_and(result, cond);
return BR_REWRITE2; return BR_REWRITE2;
} }
if (m().are_distinct(val, t)) { if (m().are_distinct(val, t)) {
if (get_depth(e) < 500)
mk_eq(e, val, result); mk_eq(e, val, result);
else
result = m().mk_eq(e, val);
result = m().mk_and(result, m().mk_not(cond)); result = m().mk_and(result, m().mk_not(cond));
return BR_REWRITE2; return BR_REWRITE2;
} }

View file

@ -53,6 +53,7 @@ class bool_rewriter {
ast_manager & m_manager; ast_manager & m_manager;
hoist_rewriter m_hoist; hoist_rewriter m_hoist;
bool m_flat_and_or = false; bool m_flat_and_or = false;
bool m_sort_disjunctions = true;
bool m_local_ctx = false; bool m_local_ctx = false;
bool m_elim_and = false; bool m_elim_and = false;
bool m_blast_distinct = false; bool m_blast_distinct = false;

View file

@ -307,7 +307,7 @@ namespace euf {
} }
}; };
SASSERT(e); SASSERT(e);
if (num_scopes() > 0) if (num_scopes() > 0 && m_canonical.size() > n->get_id())
m_trail.push(vtrail(m_canonical, n->get_id())); m_trail.push(vtrail(m_canonical, n->get_id()));
m_canonical.setx(n->get_id(), e); m_canonical.setx(n->get_id(), e);
m_epochs.setx(n->get_id(), m_epoch, 0); m_epochs.setx(n->get_id(), m_epoch, 0);

View file

@ -1394,14 +1394,13 @@ void cmd_context::reset_macros() {
} }
void cmd_context::reset_cmds() { void cmd_context::reset_cmds() {
for (auto& kv : m_cmds) { for (auto& [k,v] : m_cmds) {
kv.m_value->reset(*this); v->reset(*this);
} }
} }
void cmd_context::finalize_cmds() { void cmd_context::finalize_cmds() {
for (auto& kv : m_cmds) { for (auto& [k,c] : m_cmds) {
cmd * c = kv.m_value;
c->finalize(*this); c->finalize(*this);
dealloc(c); dealloc(c);
} }
@ -1433,6 +1432,7 @@ void cmd_context::reset(bool finalize) {
m_builtin_decls.reset(); m_builtin_decls.reset();
m_extra_builtin_decls.reset(); m_extra_builtin_decls.reset();
m_check_logic.reset(); m_check_logic.reset();
m_proof_cmds = nullptr;
reset_object_refs(); reset_object_refs();
reset_cmds(); reset_cmds();
reset_psort_decls(); reset_psort_decls();

View file

@ -43,6 +43,7 @@ Proof checker for clauses created during search.
#include "util/small_object_allocator.h" #include "util/small_object_allocator.h"
#include "ast/ast_util.h" #include "ast/ast_util.h"
#include "ast/ast_ll_pp.h" #include "ast/ast_ll_pp.h"
#include "ast/arith_decl_plugin.h"
#include "smt/smt_solver.h" #include "smt/smt_solver.h"
#include "sat/sat_solver.h" #include "sat/sat_solver.h"
#include "sat/sat_drat.h" #include "sat/sat_drat.h"
@ -63,6 +64,7 @@ class proof_trim {
vector<expr_ref_vector> m_clauses; vector<expr_ref_vector> m_clauses;
bool_vector m_is_infer; bool_vector m_is_infer;
symbol m_rup; symbol m_rup;
bool m_empty = false;
void mk_clause(expr_ref_vector const& clause) { void mk_clause(expr_ref_vector const& clause) {
trim.init_clause(); trim.init_clause();
@ -121,25 +123,32 @@ public:
*/ */
void infer(expr_ref_vector const& clause, app* hint) { void infer(expr_ref_vector const& clause, app* hint) {
if (m_empty)
return;
if (hint && !is_rup(hint) && m_checker.check(hint)) { if (hint && !is_rup(hint) && m_checker.check(hint)) {
auto clause1 = m_checker.clause(hint); auto clause1 = m_checker.clause(hint);
if (clause1.size() != clause.size()) { if (clause1.size() != clause.size()) {
mk_clause(clause1); mk_clause(clause1);
trim.assume(m_clauses.size());
clause1.push_back(hint); clause1.push_back(hint);
trim.assume(m_clauses.size());
m_clauses.push_back(clause1); m_clauses.push_back(clause1);
m_is_infer.push_back(true); m_is_infer.push_back(true);
if (clause.empty()) {
mk_clause(clause); mk_clause(clause);
trim.infer(m_clauses.size()); trim.infer(m_clauses.size());
m_clauses.push_back(clause); m_clauses.push_back(clause);
m_clauses.back().push_back(hint); m_clauses.back().push_back(hint);
m_is_infer.push_back(true); m_is_infer.push_back(true);
if (clause.empty()) m_empty = true;
do_trim(std::cout); do_trim(std::cout);
}
return; return;
} }
} }
mk_clause(clause); mk_clause(clause);
if (is_rup(hint)) if (is_rup(hint))
trim.infer(m_clauses.size()); trim.infer(m_clauses.size());
@ -149,20 +158,32 @@ public:
if (hint) if (hint)
m_clauses.back().push_back(hint); m_clauses.back().push_back(hint);
m_is_infer.push_back(true); m_is_infer.push_back(true);
if (clause.empty()) if (clause.empty()) {
m_empty = true;
do_trim(std::cout); do_trim(std::cout);
} }
}
void updt_params(params_ref const& p) { void updt_params(params_ref const& p) {
trim.updt_params(p); trim.updt_params(p);
} }
expr_ref mk_dep(unsigned id, unsigned_vector const& deps) {
arith_util a(m);
expr_ref_vector args(m);
args.push_back(a.mk_int(id));
for (auto d : deps)
args.push_back(a.mk_int(d));
return expr_ref(m.mk_app(symbol("deps"), args.size(), args.data(), m.mk_proof_sort()), m);
}
void do_trim(std::ostream& out) { void do_trim(std::ostream& out) {
ast_pp_util pp(m); ast_pp_util pp(m);
auto ids = trim.trim(); auto ids = trim.trim();
for (unsigned id : ids) { for (auto const& [id, deps] : ids) {
auto const& clause = m_clauses[id]; auto& clause = m_clauses[id];
bool is_infer = m_is_infer[id]; bool is_infer = m_is_infer[id];
clause.push_back(mk_dep(id, deps));
for (expr* e : clause) for (expr* e : clause)
pp.collect(e); pp.collect(e);
@ -258,8 +279,12 @@ public:
} }
void add_literal(expr* e) override { void add_literal(expr* e) override {
if (m.is_proof(e)) if (m.is_proof(e)) {
if (!m_proof_hint)
m_proof_hint = to_app(e); m_proof_hint = to_app(e);
}
else if (!m.is_bool(e))
throw default_exception("literal should be either a Proof or Bool");
else else
m_lits.push_back(e); m_lits.push_back(e);
} }

View file

@ -348,6 +348,26 @@ std::ostream& psort_user_decl::display(std::ostream & out) const {
return out << ")"; return out << ")";
} }
// -------------------
// psort_type_var_decl
psort_type_var_decl::psort_type_var_decl(unsigned id, pdecl_manager & m, symbol const & n):
psort_decl(id, 0, m, n) {
m_psort_kind = PSORT_TV;
}
void psort_type_var_decl::finalize(pdecl_manager & m) {
psort_decl::finalize(m);
}
sort * psort_type_var_decl::instantiate(pdecl_manager & m, unsigned n, sort * const * s) {
return m.m().mk_type_var(m_name);
}
std::ostream& psort_type_var_decl::display(std::ostream & out) const {
return out << "(declare-type-var " << m_name << ")";
}
// ------------------- // -------------------
// psort_dt_decl // psort_dt_decl
@ -969,6 +989,10 @@ psort_decl * pdecl_manager::mk_psort_dt_decl(unsigned num_params, symbol const &
return new (a().allocate(sizeof(psort_dt_decl))) psort_dt_decl(m_id_gen.mk(), num_params, *this, n); return new (a().allocate(sizeof(psort_dt_decl))) psort_dt_decl(m_id_gen.mk(), num_params, *this, n);
} }
psort_decl * pdecl_manager::mk_psort_type_var_decl(symbol const & n) {
return new (a().allocate(sizeof(psort_type_var_decl))) psort_type_var_decl(m_id_gen.mk(), *this, n);
}
psort_decl * pdecl_manager::mk_psort_builtin_decl(symbol const & n, family_id fid, decl_kind k) { psort_decl * pdecl_manager::mk_psort_builtin_decl(symbol const & n, family_id fid, decl_kind k) {
return new (a().allocate(sizeof(psort_builtin_decl))) psort_builtin_decl(m_id_gen.mk(), *this, n, fid, k); return new (a().allocate(sizeof(psort_builtin_decl))) psort_builtin_decl(m_id_gen.mk(), *this, n, fid, k);

View file

@ -86,7 +86,7 @@ typedef ptr_hashtable<psort, psort_hash_proc, psort_eq_proc> psort_table;
#define PSORT_DECL_VAR_PARAMS UINT_MAX #define PSORT_DECL_VAR_PARAMS UINT_MAX
typedef enum { PSORT_BASE = 0, PSORT_USER, PSORT_BUILTIN, PSORT_DT } psort_decl_kind; typedef enum { PSORT_BASE = 0, PSORT_USER, PSORT_BUILTIN, PSORT_DT, PSORT_TV } psort_decl_kind;
class psort_decl : public pdecl { class psort_decl : public pdecl {
protected: protected:
@ -124,6 +124,18 @@ public:
std::ostream& display(std::ostream & out) const override; std::ostream& display(std::ostream & out) const override;
}; };
class psort_type_var_decl : public psort_decl {
protected:
friend class pdecl_manager;
psort * m_def;
psort_type_var_decl(unsigned id, pdecl_manager & m, symbol const & n);
size_t obj_size() const override { return sizeof(psort_type_var_decl); }
void finalize(pdecl_manager & m) override;
public:
sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s) override;
std::ostream& display(std::ostream & out) const override;
};
class psort_builtin_decl : public psort_decl { class psort_builtin_decl : public psort_decl {
protected: protected:
friend class pdecl_manager; friend class pdecl_manager;
@ -304,6 +316,7 @@ public:
psort_decl * mk_psort_dt_decl(unsigned num_params, symbol const & n); psort_decl * mk_psort_dt_decl(unsigned num_params, symbol const & n);
psort_decl * mk_psort_user_decl(unsigned num_params, symbol const & n, psort * def); psort_decl * mk_psort_user_decl(unsigned num_params, symbol const & n, psort * def);
psort_decl * mk_psort_builtin_decl(symbol const & n, family_id fid, decl_kind k); psort_decl * mk_psort_builtin_decl(symbol const & n, family_id fid, decl_kind k);
psort_decl * mk_psort_type_var_decl(symbol const& n);
paccessor_decl * mk_paccessor_decl(unsigned num_params, symbol const & s, ptype const & p); paccessor_decl * mk_paccessor_decl(unsigned num_params, symbol const & s, ptype const & p);
pconstructor_decl * mk_pconstructor_decl(unsigned num_params, symbol const & s, symbol const & r, unsigned num, paccessor_decl * const * as); pconstructor_decl * mk_pconstructor_decl(unsigned num_params, symbol const & s, symbol const & r, unsigned num, paccessor_decl * const * as);
pdatatype_decl * mk_pdatatype_decl(unsigned num_params, symbol const & s, unsigned num, pconstructor_decl * const * cs); pdatatype_decl * mk_pdatatype_decl(unsigned num_params, symbol const & s, unsigned num, pconstructor_decl * const * cs);

View file

@ -0,0 +1,4 @@
BasedOnStyle: Google
IndentWidth: 4
ColumnLimit: 0
NamespaceIndentation: All

View file

@ -19,6 +19,7 @@ Revision History:
--*/ --*/
// clang-format off
#pragma once #pragma once
#include "util/vector.h" #include "util/vector.h"

View file

@ -17,6 +17,7 @@ Revision History:
--*/ --*/
// clang-format off
#pragma once #pragma once
#include "util/vector.h" #include "util/vector.h"

View file

@ -18,6 +18,7 @@ Revision History:
--*/ --*/
// clang-format off
#include <string> #include <string>
#include "math/lp/static_matrix.h" #include "math/lp/static_matrix.h"
namespace lp { namespace lp {

View file

@ -17,6 +17,7 @@ Revision History:
--*/ --*/
// clang-format off
#include "math/lp/numeric_pair.h" #include "math/lp/numeric_pair.h"
#include "math/lp/core_solver_pretty_printer_def.h" #include "math/lp/core_solver_pretty_printer_def.h"
template lp::core_solver_pretty_printer<lp::mpq, lp::mpq>::core_solver_pretty_printer(const lp::lp_core_solver_base<lp::mpq, lp::mpq> &, std::ostream & out); template lp::core_solver_pretty_printer<lp::mpq, lp::mpq>::core_solver_pretty_printer(const lp::lp_core_solver_base<lp::mpq, lp::mpq> &, std::ostream & out);

View file

@ -17,6 +17,7 @@ Revision History:
--*/ --*/
// clang-format off
#pragma once #pragma once
#include <limits> #include <limits>
#include <string> #include <string>

View file

@ -17,6 +17,7 @@ Revision History:
--*/ --*/
// clang-format off
#pragma once #pragma once
#include <limits> #include <limits>
@ -279,9 +280,9 @@ template <typename T, typename X> void core_solver_pretty_printer<T, X>::print()
print_row(i); print_row(i);
} }
m_out << std::endl; m_out << std::endl;
if (m_core_solver.inf_set().size()) { if (m_core_solver.inf_heap().size()) {
m_out << "inf columns: "; m_out << "inf columns: ";
print_vector(m_core_solver.inf_set(), m_out); print_vector(m_core_solver.inf_heap(), m_out);
m_out << std::endl; m_out << std::endl;
} }
} }

View file

@ -17,6 +17,7 @@
--*/ --*/
// clang-format off
#pragma once #pragma once
#include <functional> #include <functional>
#include "math/lp/nex.h" #include "math/lp/nex.h"

View file

@ -17,6 +17,7 @@ Revision History:
--*/ --*/
// clang-format off
#include "math/lp/lp_settings.h" #include "math/lp/lp_settings.h"
#include "math/lp/dense_matrix_def.h" #include "math/lp/dense_matrix_def.h"
#ifdef Z3DEBUG #ifdef Z3DEBUG

View file

@ -17,6 +17,7 @@ Revision History:
--*/ --*/
// clang-format off
#pragma once #pragma once
#ifdef Z3DEBUG #ifdef Z3DEBUG
#include "util/vector.h" #include "util/vector.h"

View file

@ -17,6 +17,7 @@ Revision History:
--*/ --*/
// clang-format off
#pragma once #pragma once
#include "math/lp/lp_settings.h" #include "math/lp/lp_settings.h"

View file

@ -18,6 +18,7 @@
replaced rooted_mons.h and rooted_mon, rooted_mon_tabled replaced rooted_mons.h and rooted_mon, rooted_mon_tabled
--*/ --*/
// clang-format off
#include "math/lp/emonics.h" #include "math/lp/emonics.h"
#include "math/lp/nla_defs.h" #include "math/lp/nla_defs.h"

View file

@ -18,6 +18,7 @@
to replace rooted_mons.h and rooted_mon, rooted_mon_tabled to replace rooted_mons.h and rooted_mon, rooted_mon_tabled
--*/ --*/
// clang-format off
#pragma once #pragma once
#include "math/lp/lp_utils.h" #include "math/lp/lp_utils.h"

View file

@ -17,6 +17,7 @@ Revision History:
--*/ --*/
// clang-format off
#pragma once #pragma once
#include "math/lp/lp_utils.h" #include "math/lp/lp_utils.h"
#include "util/map.h" #include "util/map.h"
@ -49,6 +50,15 @@ public:
m_set.insert(j); m_set.insert(j);
} }
void remove(constraint_index j) {
m_set.remove(j);
unsigned i = 0;
for (auto& p : m_vector)
if (p.first != j)
m_vector[i++] = p;
m_vector.shrink(i);
}
void add_expl(const explanation& e) { void add_expl(const explanation& e) {
if (e.m_vector.empty()) { if (e.m_vector.empty()) {
for (constraint_index j : e.m_set) for (constraint_index j : e.m_set)

View file

@ -18,6 +18,7 @@
--*/ --*/
// clang-format off
#pragma once #pragma once
#include "util/rational.h" #include "util/rational.h"
#include "math/lp/monic.h" #include "math/lp/monic.h"

View file

@ -17,6 +17,7 @@
--*/ --*/
// clang-format off
#include "math/lp/factorization_factory_imp.h" #include "math/lp/factorization_factory_imp.h"
#include "math/lp/nla_core.h" #include "math/lp/nla_core.h"
namespace nla { namespace nla {

View file

@ -17,6 +17,7 @@
--*/ --*/
// clang-format off
#pragma once #pragma once
#include "math/lp/factorization.h" #include "math/lp/factorization.h"
namespace nla { namespace nla {

View file

@ -17,6 +17,7 @@ Revision History:
--*/ --*/
// clang-format off
#pragma once #pragma once
#include <functional> #include <functional>
namespace lp { namespace lp {

View file

@ -17,6 +17,7 @@
--*/ --*/
// clang-format off
#include "math/lp/gomory.h" #include "math/lp/gomory.h"
#include "math/lp/int_solver.h" #include "math/lp/int_solver.h"
#include "math/lp/lar_solver.h" #include "math/lp/lar_solver.h"

View file

@ -15,6 +15,7 @@ Author:
Revision History: Revision History:
--*/ --*/
// clang-format off
#pragma once #pragma once
#include "math/lp/lar_term.h" #include "math/lp/lar_term.h"
#include "math/lp/lia_move.h" #include "math/lp/lia_move.h"

View file

@ -26,6 +26,7 @@ Revision History:
--*/ --*/
// clang-format off
#pragma once #pragma once
#include "math/lp/numeric_pair.h" #include "math/lp/numeric_pair.h"
#include "util/ext_gcd.h" #include "util/ext_gcd.h"

View file

@ -9,6 +9,7 @@ Author:
Lev Nachmanson (levnach) Lev Nachmanson (levnach)
--*/ --*/
// clang-format off
#include "math/lp/int_solver.h" #include "math/lp/int_solver.h"
#include "math/lp/lar_solver.h" #include "math/lp/lar_solver.h"
#include "math/lp/hnf_cutter.h" #include "math/lp/hnf_cutter.h"

View file

@ -14,6 +14,7 @@ Author:
Lev Nachmanson (levnach) Lev Nachmanson (levnach)
--*/ --*/
// clang-format off
#pragma once #pragma once
#include "math/lp/lar_term.h" #include "math/lp/lar_term.h"

View file

@ -17,6 +17,7 @@
--*/ --*/
// clang-format off
#include "math/lp/horner.h" #include "math/lp/horner.h"
#include "math/lp/nla_core.h" #include "math/lp/nla_core.h"

View file

@ -17,6 +17,7 @@
--*/ --*/
// clang-format off
#pragma once #pragma once
#include "math/lp/nla_common.h" #include "math/lp/nla_common.h"

View file

@ -17,6 +17,7 @@ Revision History:
--*/ --*/
// clang-format off
#pragma once #pragma once
#include "math/lp/lp_settings.h" #include "math/lp/lp_settings.h"
#include "math/lp/lar_constraints.h" #include "math/lp/lar_constraints.h"

View file

@ -17,6 +17,7 @@ Revision History:
--*/ --*/
// clang-format off
#pragma once #pragma once
#include "util/vector.h" #include "util/vector.h"

View file

@ -17,6 +17,7 @@ Revision History:
--*/ --*/
// clang-format off
#pragma once #pragma once
namespace lp { namespace lp {

View file

@ -17,6 +17,7 @@ Revision History:
--*/ --*/
// clang-format off
#include "util/vector.h" #include "util/vector.h"
#include "math/lp/indexed_vector_def.h" #include "math/lp/indexed_vector_def.h"
namespace lp { namespace lp {

View file

@ -17,6 +17,7 @@ Revision History:
--*/ --*/
// clang-format off
#pragma once #pragma once
#include "util/vector.h" #include "util/vector.h"

View file

@ -17,6 +17,7 @@ Revision History:
--*/ --*/
// clang-format off
#pragma once #pragma once
#include "util/vector.h" #include "util/vector.h"

View file

@ -15,7 +15,7 @@
Revision History: Revision History:
--*/ --*/
// clang-format off
#include "math/lp/int_solver.h" #include "math/lp/int_solver.h"
#include "math/lp/lar_solver.h" #include "math/lp/lar_solver.h"
#include "math/lp/int_branch.h" #include "math/lp/int_branch.h"
@ -63,7 +63,7 @@ int int_branch::find_inf_int_base_column() {
mpq small_value(1024); mpq small_value(1024);
unsigned n = 0; unsigned n = 0;
lar_core_solver & lcs = lra.m_mpq_lar_core_solver; lar_core_solver & lcs = lra.m_mpq_lar_core_solver;
unsigned prev_usage = 0; // to quiet down the compile unsigned prev_usage = 0; // to quiet down the compiler
unsigned k = 0; unsigned k = 0;
unsigned usage; unsigned usage;
unsigned j; unsigned j;

View file

@ -15,6 +15,7 @@ Author:
Revision History: Revision History:
--*/ --*/
// clang-format off
#pragma once #pragma once
#include "math/lp/lar_solver.h" #include "math/lp/lar_solver.h"

View file

@ -15,6 +15,7 @@ Author:
Revision History: Revision History:
--*/ --*/
// clang-format off
#include "math/lp/int_solver.h" #include "math/lp/int_solver.h"
#include "math/lp/lar_solver.h" #include "math/lp/lar_solver.h"

View file

@ -19,6 +19,7 @@ Author:
Revision History: Revision History:
--*/ --*/
// clang-format off
#pragma once #pragma once
#include "math/lp/lia_move.h" #include "math/lp/lia_move.h"

View file

@ -45,6 +45,7 @@ Accumulative:
--*/ --*/
// clang-format off
#include "math/lp/int_solver.h" #include "math/lp/int_solver.h"
#include "math/lp/lar_solver.h" #include "math/lp/lar_solver.h"

View file

@ -24,6 +24,7 @@ Author:
Revision History: Revision History:
--*/ --*/
// clang-format off
#pragma once #pragma once
#include "math/lp/lia_move.h" #include "math/lp/lia_move.h"

View file

@ -2,8 +2,7 @@
Copyright (c) 2017 Microsoft Corporation Copyright (c) 2017 Microsoft Corporation
Author: Lev Nachmanson Author: Lev Nachmanson
*/ */
// clang-format off
#include <utility>
#include "math/lp/int_solver.h" #include "math/lp/int_solver.h"
#include "math/lp/lar_solver.h" #include "math/lp/lar_solver.h"
#include "math/lp/lp_utils.h" #include "math/lp/lp_utils.h"
@ -17,51 +16,199 @@ namespace lp {
int_solver::patcher::patcher(int_solver& lia): int_solver::patcher::patcher(int_solver& lia):
lia(lia), lia(lia),
lra(lia.lra), lra(lia.lra),
lrac(lia.lrac), lrac(lia.lrac)
m_num_nbasic_patches(0),
m_patch_cost(0),
m_next_patch(0),
m_delay(0)
{} {}
bool int_solver::patcher::should_apply() { void int_solver::patcher::remove_fixed_vars_from_base() {
#if 1 unsigned num = lra.A_r().column_count();
return true; for (unsigned v = 0; v < num; v++) {
#else if (!lia.is_base(v) || !lia.is_fixed(v))
if (m_delay == 0) { continue;
return true; auto const & r = lra.basic2row(v);
for (auto const& c : r) {
if (c.var() != v && !lia.is_fixed(c.var())) {
lra.pivot(c.var(), v);
break;
}
}
} }
--m_delay;
return false;
#endif
} }
lia_move int_solver::patcher::operator()() {
return patch_nbasic_columns(); unsigned int_solver::patcher::count_non_int() {
unsigned non_int = 0;
for (auto j : lra.r_basis())
if (lra.column_is_int(j) && !lra.column_value_is_int(j))
++non_int;
return non_int;
}
lia_move int_solver::patcher::patch_basic_columns() {
remove_fixed_vars_from_base();
lia.settings().stats().m_patches++;
lp_assert(lia.is_feasible());
// unsigned non_int_before, non_int_after;
// non_int_before = count_non_int();
// unsigned num = lra.A_r().column_count();
for (unsigned j : lra.r_basis())
if (!lra.get_value(j).is_int())
patch_basic_column(j);
// non_int_after = count_non_int();
// verbose_stream() << non_int_before << " -> " << non_int_after << "\n";
if (!lia.has_inf_int()) {
lia.settings().stats().m_patches_success++;
return lia_move::sat;
}
return lia_move::undef;
}
// clang-format on
/**
* \brief find integral and minimal, in the absolute values, deltas such that x - alpha*delta is integral too.
*/
bool get_patching_deltas(const rational& x, const rational& alpha,
rational& delta_plus, rational& delta_minus) {
auto a1 = numerator(alpha);
auto a2 = denominator(alpha);
auto x1 = numerator(x);
auto x2 = denominator(x);
if (!divides(x2, a2))
return false;
// delta has to be integral.
// We need to find delta such that x1/x2 + (a1/a2)*delta is integral (we are going to flip the delta sign later).
// Then a2*x1/x2 + a1*delta is integral, but x2 and x1 are coprime:
// that means that t = a2/x2 is
// integral. We established that a2 = x2*t Then x1 + a1*delta*(x2/a2) = x1
// + a1*(delta/t) is integral. Taking into account that t and a1 are
// coprime we have delta = t*k, where k is an integer.
rational t = a2 / x2;
// std::cout << "t = " << t << std::endl;
// Now we have x1/x2 + (a1/x2)*k is integral, or (x1 + a1*k)/x2 is integral.
// It is equivalent to x1 + a1*k = x2*m, where m is an integer
// We know that a2 and a1 are coprime, and x2 divides a2, so x2 and a1 are
// coprime. We can find u and v such that u*a1 + v*x2 = 1.
rational u, v;
gcd(a1, x2, u, v);
lp_assert(gcd(a1, x2, u, v).is_one());
// std::cout << "u = " << u << ", v = " << v << std::endl;
// std::cout << "x= " << (x1 / x2) << std::endl;
// std::cout << "x + (a1 / a2) * (-u * t) * x1 = "
// << x + (a1 / a2) * (-u * t) * x1 << std::endl;
lp_assert((x + (a1 / a2) * (-u * t) * x1).is_int());
// 1 = (u- l*x2 ) * a1 + (v + l*a1)*x2, for every integer l.
rational d = u * t * x1;
// We can prove that x+alpha*d is integral,
// and any other delta, satisfying x+alpha*delta, is equal to d modulo a2.
delta_plus = mod(d, a2);
lp_assert(delta_plus > 0);
delta_minus = delta_plus - a2;
lp_assert(delta_minus < 0);
return true;
}
/**
* \brief try to patch the basic column v
*/
bool int_solver::patcher::patch_basic_column_on_row_cell(unsigned v, row_cell<mpq> const& c) {
if (v == c.var())
return false;
if (!lra.column_is_int(c.var())) // could use real to patch integer
return false;
if (c.coeff().is_int())
return false;
mpq a = fractional_part(c.coeff());
mpq r = fractional_part(lra.get_value(v));
lp_assert(0 < r && r < 1);
lp_assert(0 < a && a < 1);
mpq delta_plus, delta_minus;
if (!get_patching_deltas(r, a, delta_plus, delta_minus))
return false;
if (lia.random() % 2) {
return try_patch_column(v, c.var(), delta_plus) ||
try_patch_column(v, c.var(), delta_minus);
} else {
return try_patch_column(v, c.var(), delta_minus) ||
try_patch_column(v, c.var(), delta_plus);
}
}
// clang-format off
bool int_solver::patcher::try_patch_column(unsigned v, unsigned j, mpq const& delta) {
const auto & A = lra.A_r();
if (delta < 0) {
if (lia.has_lower(j) && lia.get_value(j) + impq(delta) < lra.get_lower_bound(j))
return false;
}
else {
if (lia.has_upper(j) && lia.get_value(j) + impq(delta) > lra.get_upper_bound(j))
return false;
}
for (auto const& c : A.column(j)) {
unsigned row_index = c.var();
unsigned i = lrac.m_r_basis[row_index];
auto old_val = lia.get_value(i);
auto new_val = old_val - impq(c.coeff()*delta);
if (lia.has_lower(i) && new_val < lra.get_lower_bound(i))
return false;
if (lia.has_upper(i) && new_val > lra.get_upper_bound(i))
return false;
if (old_val.is_int() && !new_val.is_int()){
return false; // do not waste resources on this case
}
lp_assert(i != v || new_val.is_int())
}
lra.set_value_for_nbasic_column(j, lia.get_value(j) + impq(delta));
return true;
}
void int_solver::patcher::patch_basic_column(unsigned v) {
SASSERT(!lia.is_fixed(v));
for (auto const& c : lra.basic2row(v))
if (patch_basic_column_on_row_cell(v, c))
return;
} }
lia_move int_solver::patcher::patch_nbasic_columns() { lia_move int_solver::patcher::patch_nbasic_columns() {
remove_fixed_vars_from_base();
lia.settings().stats().m_patches++; lia.settings().stats().m_patches++;
lp_assert(lia.is_feasible()); lp_assert(lia.is_feasible());
m_num_nbasic_patches = 0; m_patch_success = 0;
m_patch_cost = 0; m_patch_fail = 0;
for (unsigned j : lia.lrac.m_r_nbasis) { m_num_ones = 0;
patch_nbasic_column(j); m_num_divides = 0;
//unsigned non_int_before = count_non_int();
unsigned num = lra.A_r().column_count();
for (unsigned v = 0; v < num; v++) {
if (lia.is_base(v))
continue;
patch_nbasic_column(v);
} }
unsigned num_fixed = 0;
for (unsigned v = 0; v < num; v++)
if (lia.is_fixed(v))
++num_fixed;
lp_assert(lia.is_feasible()); lp_assert(lia.is_feasible());
//verbose_stream() << "patch " << m_patch_success << " fails " << m_patch_fail << " ones " << m_num_ones << " divides " << m_num_divides << " num fixed " << num_fixed << "\n";
//lra.display(verbose_stream());
//exit(0);
//unsigned non_int_after = count_non_int();
// verbose_stream() << non_int_before << " -> " << non_int_after << "\n";
if (!lia.has_inf_int()) { if (!lia.has_inf_int()) {
lia.settings().stats().m_patches_success++; lia.settings().stats().m_patches_success++;
m_delay = 0;
m_next_patch = 0;
return lia_move::sat; return lia_move::sat;
} }
if (m_patch_cost > 0 && m_num_nbasic_patches * 10 < m_patch_cost) {
m_delay = std::min(20u, m_next_patch++);
}
else {
m_delay = 0;
m_next_patch = 0;
}
return lia_move::undef; return lia_move::undef;
} }
@ -71,17 +218,48 @@ void int_solver::patcher::patch_nbasic_column(unsigned j) {
impq l, u; impq l, u;
mpq m; mpq m;
bool has_free = lia.get_freedom_interval_for_column(j, inf_l, l, inf_u, u, m); bool has_free = lia.get_freedom_interval_for_column(j, inf_l, l, inf_u, u, m);
m_patch_cost += lra.A_r().number_of_non_zeroes_in_column(j); if (!has_free)
if (!has_free) {
return; return;
}
bool m_is_one = m.is_one(); bool m_is_one = m.is_one();
bool val_is_int = lia.value_is_int(j); bool val_is_int = lia.value_is_int(j);
#if 0
const auto & A = lra.A_r();
#endif
// check whether value of j is already a multiple of m. // check whether value of j is already a multiple of m.
if (val_is_int && (m_is_one || (val.x / m).is_int())) { if (val_is_int && (m_is_one || (val.x / m).is_int())) {
if (m_is_one)
++m_num_ones;
else
++m_num_divides;
#if 0
for (auto c : A.column(j)) {
unsigned row_index = c.var();
unsigned i = lrac.m_r_basis[row_index];
if (!lia.get_value(i).is_int() ||
(lia.has_lower(i) && lia.get_value(i) < lra.get_lower_bound(i)) ||
(lia.has_upper(i) && lia.get_value(i) > lra.get_upper_bound(i))) {
verbose_stream() << "skip " << j << " " << m << ": ";
lia.display_row(verbose_stream(), A.m_rows[row_index]);
verbose_stream() << "\n";
}
}
#endif
return; return;
} }
#if 0
if (!m_is_one) {
// lia.display_column(verbose_stream(), j);
for (auto c : A.column(j)) {
continue;
unsigned row_index = c.var();
lia.display_row(verbose_stream(), A.m_rows[row_index]);
verbose_stream() << "\n";
}
}
#endif
TRACE("patch_int", TRACE("patch_int",
tout << "TARGET j" << j << " -> ["; tout << "TARGET j" << j << " -> [";
if (inf_l) tout << "-oo"; else tout << l; if (inf_l) tout << "-oo"; else tout << l;
@ -89,9 +267,33 @@ void int_solver::patcher::patch_nbasic_column(unsigned j) {
if (inf_u) tout << "oo"; else tout << u; if (inf_u) tout << "oo"; else tout << u;
tout << "]"; tout << "]";
tout << ", m: " << m << ", val: " << val << ", is_int: " << lra.column_is_int(j) << "\n";); tout << ", m: " << m << ", val: " << val << ", is_int: " << lra.column_is_int(j) << "\n";);
#if 0
verbose_stream() << "path " << m << " ";
if (!inf_l) verbose_stream() << "infl " << l.x << " ";
if (!inf_u) verbose_stream() << "infu " << u.x << " ";
verbose_stream() << "\n";
if (m.is_big() || (!inf_l && l.x.is_big()) || (!inf_u && u.x.is_big())) { if (m.is_big() || (!inf_l && l.x.is_big()) || (!inf_u && u.x.is_big())) {
return; return;
} }
#endif
#if 0
verbose_stream() << "TARGET v" << j << " -> [";
if (inf_l) verbose_stream() << "-oo"; else verbose_stream() << ceil(l.x) << " " << l << "\n";
verbose_stream() << ", ";
if (inf_u) verbose_stream() << "oo"; else verbose_stream() << floor(u.x) << " " << u << "\n";
verbose_stream() << "]";
verbose_stream() << ", m: " << m << ", val: " << val << ", is_int: " << lra.column_is_int(j) << "\n";
#endif
#if 0
if (!inf_l)
l = impq(ceil(l));
if (!inf_u)
u = impq(floor(u));
#endif
if (!inf_l) { if (!inf_l) {
l = impq(m_is_one ? ceil(l) : m * ceil(l / m)); l = impq(m_is_one ? ceil(l) : m * ceil(l / m));
if (inf_u || l <= u) { if (inf_u || l <= u) {
@ -99,8 +301,23 @@ void int_solver::patcher::patch_nbasic_column(unsigned j) {
lra.set_value_for_nbasic_column(j, l); lra.set_value_for_nbasic_column(j, l);
} }
else { else {
--m_num_nbasic_patches; //verbose_stream() << "fail: " << j << " " << m << "\n";
++m_patch_fail;
TRACE("patch_int", tout << "not patching " << l << "\n";); TRACE("patch_int", tout << "not patching " << l << "\n";);
#if 0
verbose_stream() << "not patched\n";
for (auto c : A.column(j)) {
unsigned row_index = c.var();
unsigned i = lrac.m_r_basis[row_index];
if (!lia.get_value(i).is_int() ||
(lia.has_lower(i) && lia.get_value(i) < lra.get_lower_bound(i)) ||
(lia.has_upper(i) && lia.get_value(i) > lra.get_upper_bound(i))) {
lia.display_row(verbose_stream(), A.m_rows[row_index]);
verbose_stream() << "\n";
}
}
#endif
return;
} }
} }
else if (!inf_u) { else if (!inf_u) {
@ -112,7 +329,21 @@ void int_solver::patcher::patch_nbasic_column(unsigned j) {
lra.set_value_for_nbasic_column(j, impq(0)); lra.set_value_for_nbasic_column(j, impq(0));
TRACE("patch_int", tout << "patching with 0\n";); TRACE("patch_int", tout << "patching with 0\n";);
} }
++m_num_nbasic_patches; ++m_patch_success;
#if 0
verbose_stream() << "patched " << j << "\n";
for (auto c : A.column(j)) {
unsigned row_index = c.var();
unsigned i = lrac.m_r_basis[row_index];
if (!lia.get_value(i).is_int() ||
(lia.has_lower(i) && lia.get_value(i) < lra.get_lower_bound(i)) ||
(lia.has_upper(i) && lia.get_value(i) > lra.get_upper_bound(i))) {
lia.display_row(verbose_stream(), A.m_rows[row_index]);
verbose_stream() << "\n";
}
}
#endif
} }
int_solver::int_solver(lar_solver& lar_slv) : int_solver::int_solver(lar_solver& lar_slv) :
@ -326,7 +557,7 @@ static void set_upper(impq & u, bool & inf_u, impq const & v) {
// this function assumes that all basic columns dependend on j are feasible // this function assumes that all basic columns dependend on j are feasible
bool int_solver::get_freedom_interval_for_column(unsigned j, bool & inf_l, impq & l, bool & inf_u, impq & u, mpq & m) { bool int_solver::get_freedom_interval_for_column(unsigned j, bool & inf_l, impq & l, bool & inf_u, impq & u, mpq & m) {
if (lrac.m_r_heading[j] >= 0) // the basic var if (lrac.m_r_heading[j] >= 0 || is_fixed(j)) // basic or fixed var
return false; return false;
TRACE("random_update", display_column(tout, j) << ", is_int = " << column_is_int(j) << "\n";); TRACE("random_update", display_column(tout, j) << ", is_int = " << column_is_int(j) << "\n";);
@ -361,10 +592,9 @@ bool int_solver::get_freedom_interval_for_column(unsigned j, bool & inf_l, impq
unsigned i = lrac.m_r_basis[row_index]; unsigned i = lrac.m_r_basis[row_index];
impq const & xi = get_value(i); impq const & xi = get_value(i);
lp_assert(lrac.m_r_solver.column_is_feasible(i)); lp_assert(lrac.m_r_solver.column_is_feasible(i));
if (column_is_int(i) && !a.is_int()) if (column_is_int(i) && !a.is_int() && xi.is_int())
m = lcm(m, denominator(a)); m = lcm(m, denominator(a));
if (!inf_l && !inf_u) { if (!inf_l && !inf_u) {
if (l == u) if (l == u)
continue; continue;
@ -372,15 +602,15 @@ bool int_solver::get_freedom_interval_for_column(unsigned j, bool & inf_l, impq
if (a.is_neg()) { if (a.is_neg()) {
if (has_lower(i)) if (has_lower(i))
set_lower(l, inf_l, delta(a, xi, lrac.m_r_lower_bounds()[i])); set_lower(l, inf_l, delta(a, xi, lra.get_lower_bound(i)));
if (has_upper(i)) if (has_upper(i))
set_upper(u, inf_u, delta(a, xi, lrac.m_r_upper_bounds()[i])); set_upper(u, inf_u, delta(a, xi, lra.get_upper_bound(i)));
} }
else { else {
if (has_upper(i)) if (has_upper(i))
set_lower(l, inf_l, delta(a, xi, lrac.m_r_upper_bounds()[i])); set_lower(l, inf_l, delta(a, xi, lra.get_upper_bound(i)));
if (has_lower(i)) if (has_lower(i))
set_upper(u, inf_u, delta(a, xi, lrac.m_r_lower_bounds()[i])); set_upper(u, inf_u, delta(a, xi, lra.get_lower_bound(i)));
} }
} }
@ -481,12 +711,9 @@ bool int_solver::at_upper(unsigned j) const {
std::ostream & int_solver::display_row(std::ostream & out, lp::row_strip<rational> const & row) const { std::ostream & int_solver::display_row(std::ostream & out, lp::row_strip<rational> const & row) const {
bool first = true; bool first = true;
auto & rslv = lrac.m_r_solver; auto & rslv = lrac.m_r_solver;
for (const auto &c : row) for (const auto &c : row) {
{ if (is_fixed(c.var())) {
if (is_fixed(c.var())) if (!get_value(c.var()).is_zero()) {
{
if (!get_value(c.var()).is_zero())
{
impq val = get_value(c.var()) * c.coeff(); impq val = get_value(c.var()) * c.coeff();
if (!first && val.is_pos()) if (!first && val.is_pos())
out << "+"; out << "+";
@ -505,17 +732,11 @@ for (const auto &c : row)
} }
else if (c.coeff().is_minus_one()) else if (c.coeff().is_minus_one())
out << "-"; out << "-";
else else {
{ if (c.coeff().is_pos() && !first)
if (c.coeff().is_pos())
{
if (!first)
out << "+"; out << "+";
}
if (c.coeff().is_big()) if (c.coeff().is_big())
{
out << " b*"; out << " b*";
}
else else
out << c.coeff(); out << c.coeff();
} }
@ -523,8 +744,7 @@ for (const auto &c : row)
first = false; first = false;
} }
out << "\n"; out << "\n";
for (const auto &c : row) for (const auto &c : row) {
{
if (is_fixed(c.var())) if (is_fixed(c.var()))
continue; continue;
rslv.print_column_info(c.var(), out); rslv.print_column_info(c.var(), out);
@ -533,14 +753,13 @@ for (const auto &c : row)
} }
return out; return out;
} }
std::ostream& int_solver::display_row_info(std::ostream & out, unsigned row_index) const { std::ostream& int_solver::display_row_info(std::ostream & out, unsigned row_index) const {
auto & rslv = lrac.m_r_solver; auto & rslv = lrac.m_r_solver;
auto const& row = rslv.m_A.m_rows[row_index]; auto const& row = rslv.m_A.m_rows[row_index];
return display_row(out, row); return display_row(out, row);
} }
bool int_solver::shift_var(unsigned j, unsigned range) { bool int_solver::shift_var(unsigned j, unsigned range) {
if (is_fixed(j) || is_base(j)) if (is_fixed(j) || is_base(j))
return false; return false;
@ -549,11 +768,13 @@ bool int_solver::shift_var(unsigned j, unsigned range) {
bool inf_l = false, inf_u = false; bool inf_l = false, inf_u = false;
impq l, u; impq l, u;
mpq m; mpq m;
VERIFY(get_freedom_interval_for_column(j, inf_l, l, inf_u, u, m) || settings().get_cancel_flag()); if (!get_freedom_interval_for_column(j, inf_l, l, inf_u, u, m))
return false;
if (settings().get_cancel_flag()) if (settings().get_cancel_flag())
return false; return false;
const impq & x = get_value(j); const impq & x = get_value(j);
// x, the value of j column, might be shifted on a multiple of m // x, the value of j column, might be shifted on a multiple of m
if (inf_l && inf_u) { if (inf_l && inf_u) {
impq new_val = m * impq(random() % (range + 1)) + x; impq new_val = m * impq(random() % (range + 1)) + x;
lra.set_value_for_nbasic_column(j, new_val); lra.set_value_for_nbasic_column(j, new_val);
@ -570,6 +791,7 @@ bool int_solver::shift_var(unsigned j, unsigned range) {
if (!inf_l && !inf_u && l >= u) if (!inf_l && !inf_u && l >= u)
return false; return false;
if (inf_u) { if (inf_u) {
SASSERT(!inf_l); SASSERT(!inf_l);
impq new_val = x + m * impq(random() % (range + 1)); impq new_val = x + m * impq(random() % (range + 1));
@ -640,21 +862,14 @@ int int_solver::select_int_infeasible_var() {
unsigned n = 0; unsigned n = 0;
lar_core_solver & lcs = lra.m_mpq_lar_core_solver; lar_core_solver & lcs = lra.m_mpq_lar_core_solver;
unsigned prev_usage = 0; // to quiet down the compile unsigned prev_usage = 0; // to quiet down the compile
unsigned k = 0;
unsigned usage;
unsigned j;
enum state { small_box, is_small_value, any_value, not_found }; enum state { small_box, is_small_value, any_value, not_found };
state st = not_found; state st = not_found;
// 1. small box for (unsigned j : lra.r_basis()) {
// 2. small value
// 3. any value
for (; k < lra.r_basis().size(); k++) {
j = lra.r_basis()[k];
if (!column_is_int_inf(j)) if (!column_is_int_inf(j))
continue; continue;
usage = lra.usage_in_terms(j); unsigned usage = lra.usage_in_terms(j);
if (is_boxed(j) && (new_range = lcs.m_r_upper_bounds()[j].x - lcs.m_r_lower_bounds()[j].x - rational(2*usage)) <= small_value) { if (is_boxed(j) && (new_range = lcs.m_r_upper_bounds()[j].x - lcs.m_r_lower_bounds()[j].x - rational(2*usage)) <= small_value) {
SASSERT(!is_fixed(j)); SASSERT(!is_fixed(j));
if (st != small_box) { if (st != small_box) {
@ -688,12 +903,12 @@ int int_solver::select_int_infeasible_var() {
continue; continue;
SASSERT(st == not_found || st == any_value); SASSERT(st == not_found || st == any_value);
st = any_value; st = any_value;
if (n == 0 /*|| usage > prev_usage*/) { if (n == 0 || usage > prev_usage) {
result = j; result = j;
prev_usage = usage; prev_usage = usage;
n = 1; n = 1;
} }
else if (usage > 0 && /*usage == prev_usage && */ (random() % (++n) == 0)) else if (usage > 0 && usage == prev_usage && (random() % (++n) == 0))
result = j; result = j;
} }

View file

@ -17,6 +17,7 @@ Revision History:
--*/ --*/
// clang-format off
#pragma once #pragma once
#include "math/lp/lp_settings.h" #include "math/lp/lp_settings.h"
#include "math/lp/static_matrix.h" #include "math/lp/static_matrix.h"
@ -44,17 +45,23 @@ class int_solver {
int_solver& lia; int_solver& lia;
lar_solver& lra; lar_solver& lra;
lar_core_solver& lrac; lar_core_solver& lrac;
unsigned m_num_nbasic_patches; unsigned m_patch_success = 0;
unsigned m_patch_cost; unsigned m_patch_fail = 0;
unsigned m_next_patch; unsigned m_num_ones = 0;
unsigned m_delay; unsigned m_num_divides = 0;
public: public:
patcher(int_solver& lia); patcher(int_solver& lia);
bool should_apply(); bool should_apply() const { return true; }
lia_move operator()(); lia_move operator()() { return patch_basic_columns(); }
void patch_nbasic_column(unsigned j); void patch_nbasic_column(unsigned j);
bool patch_basic_column_on_row_cell(unsigned v, row_cell<mpq> const& c);
void patch_basic_column(unsigned j);
bool try_patch_column(unsigned v, unsigned j, mpq const& delta);
unsigned count_non_int();
private: private:
void remove_fixed_vars_from_base();
lia_move patch_nbasic_columns(); lia_move patch_nbasic_columns();
lia_move patch_basic_columns();
}; };
lar_solver& lra; lar_solver& lra;

View file

@ -17,6 +17,7 @@ Revision History:
--*/ --*/
// clang-format off
#pragma once #pragma once
#include <utility> #include <utility>

View file

@ -17,6 +17,7 @@ Revision History:
--*/ --*/
// clang-format off
#include <utility> #include <utility>
#include <memory> #include <memory>
#include <string> #include <string>

View file

@ -5,6 +5,7 @@ Author:
Lev Nachmanson (levnach) Lev Nachmanson (levnach)
--*/ --*/
// clang-format off
#pragma once #pragma once
#include "util/vector.h" #include "util/vector.h"
#include <string> #include <string>
@ -16,7 +17,7 @@ Author:
#include "math/lp/stacked_vector.h" #include "math/lp/stacked_vector.h"
#include "util/stacked_value.h" #include "util/stacked_value.h"
namespace lp { namespace lp {
// clang-format off
class lar_core_solver { class lar_core_solver {
vector<std::pair<mpq, unsigned>> m_infeasible_linear_combination; vector<std::pair<mpq, unsigned>> m_infeasible_linear_combination;
int m_infeasible_sum_sign; // todo: get rid of this field int m_infeasible_sum_sign; // todo: get rid of this field
@ -93,6 +94,8 @@ public:
void solve(); void solve();
void pivot(int entering, int leaving) { m_r_solver.pivot(entering, leaving); }
bool lower_bounds_are_set() const { return true; } bool lower_bounds_are_set() const { return true; }
const indexed_vector<mpq> & get_pivot_row() const { const indexed_vector<mpq> & get_pivot_row() const {

View file

@ -9,6 +9,7 @@ Revision History:
--*/ --*/
// clang-format off
#pragma once #pragma once
#include <string> #include <string>
@ -85,8 +86,8 @@ unsigned lar_core_solver::get_number_of_non_ints() const {
void lar_core_solver::solve() { void lar_core_solver::solve() {
TRACE("lar_solver", tout << m_r_solver.get_status() << "\n";); TRACE("lar_solver", tout << m_r_solver.get_status() << "\n";);
lp_assert(m_r_solver.non_basic_columns_are_set_correctly()); lp_assert(m_r_solver.non_basic_columns_are_set_correctly());
lp_assert(m_r_solver.inf_set_is_correct()); lp_assert(m_r_solver.inf_heap_is_correct());
TRACE("find_feas_stats", tout << "infeasibles = " << m_r_solver.inf_set_size() << ", int_infs = " << get_number_of_non_ints() << std::endl;); TRACE("find_feas_stats", tout << "infeasibles = " << m_r_solver.inf_heap_size() << ", int_infs = " << get_number_of_non_ints() << std::endl;);
if (m_r_solver.current_x_is_feasible() && m_r_solver.m_look_for_feasible_solution_only) { if (m_r_solver.current_x_is_feasible() && m_r_solver.m_look_for_feasible_solution_only) {
m_r_solver.set_status(lp_status::OPTIMAL); m_r_solver.set_status(lp_status::OPTIMAL);
TRACE("lar_solver", tout << m_r_solver.get_status() << "\n";); TRACE("lar_solver", tout << m_r_solver.get_status() << "\n";);
@ -117,11 +118,9 @@ void lar_core_solver::solve() {
} }
lp_assert(r_basis_is_OK()); lp_assert(r_basis_is_OK());
lp_assert(m_r_solver.non_basic_columns_are_set_correctly()); lp_assert(m_r_solver.non_basic_columns_are_set_correctly());
lp_assert(m_r_solver.inf_set_is_correct()); lp_assert(m_r_solver.inf_heap_is_correct());
TRACE("lar_solver", tout << m_r_solver.get_status() << "\n";); TRACE("lar_solver", tout << m_r_solver.get_status() << "\n";);
} }
} // namespace lp
}

View file

@ -2,7 +2,7 @@
Copyright (c) 2017 Microsoft Corporation Copyright (c) 2017 Microsoft Corporation
Author: Nikolaj Bjorner, Lev Nachmanson Author: Nikolaj Bjorner, Lev Nachmanson
*/ */
// clang-format off
#include "math/lp/lar_solver.h" #include "math/lp/lar_solver.h"
#include "smt/params/smt_params_helper.hpp" #include "smt/params/smt_params_helper.hpp"
@ -42,7 +42,6 @@ namespace lp {
delete t; delete t;
} }
bool lar_solver::sizes_are_correct() const { bool lar_solver::sizes_are_correct() const {
lp_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_column_types.size()); lp_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_column_types.size());
lp_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); lp_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size());
@ -50,7 +49,6 @@ namespace lp {
return true; return true;
} }
std::ostream& lar_solver::print_implied_bound(const implied_bound& be, std::ostream& out) const { std::ostream& lar_solver::print_implied_bound(const implied_bound& be, std::ostream& out) const {
out << "implied bound\n"; out << "implied bound\n";
unsigned v = be.m_j; unsigned v = be.m_j;
@ -215,7 +213,7 @@ namespace lp {
void lar_solver::fill_explanation_from_crossed_bounds_column(explanation& evidence) const { void lar_solver::fill_explanation_from_crossed_bounds_column(explanation& evidence) const {
lp_assert(static_cast<int>(get_column_type(m_crossed_bounds_column)) >= static_cast<int>(column_type::boxed)); lp_assert(static_cast<int>(get_column_type(m_crossed_bounds_column)) >= static_cast<int>(column_type::boxed));
lp_assert(!m_mpq_lar_core_solver.m_r_solver.column_is_feasible(m_crossed_bounds_column)); lp_assert(!column_is_feasible(m_crossed_bounds_column));
// this is the case when the lower bound is in conflict with the upper one // this is the case when the lower bound is in conflict with the upper one
const ul_pair& ul = m_columns_to_ul_pairs[m_crossed_bounds_column]; const ul_pair& ul = m_columns_to_ul_pairs[m_crossed_bounds_column];
@ -244,6 +242,14 @@ namespace lp {
set.erase(j); set.erase(j);
} }
void lar_solver::clean_popped_elements_for_heap(unsigned n, lpvar_heap& heap) {
vector<int> to_remove;
for (unsigned j : heap)
if (j >= n)
to_remove.push_back(j);
for (unsigned j : to_remove)
heap.erase(j);
}
void lar_solver::pop(unsigned k) { void lar_solver::pop(unsigned k) {
@ -271,7 +277,7 @@ namespace lp {
unsigned m = A_r().row_count(); unsigned m = A_r().row_count();
clean_popped_elements(m, m_rows_with_changed_bounds); clean_popped_elements(m, m_rows_with_changed_bounds);
clean_inf_set_of_r_solver_after_pop(); clean_inf_heap_of_r_solver_after_pop();
lp_assert( lp_assert(
m_settings.simplex_strategy() == simplex_strategy_enum::undecided || m_settings.simplex_strategy() == simplex_strategy_enum::undecided ||
m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau());
@ -328,7 +334,7 @@ namespace lp {
void lar_solver::set_costs_to_zero(const lar_term& term) { void lar_solver::set_costs_to_zero(const lar_term& term) {
auto& rslv = m_mpq_lar_core_solver.m_r_solver; auto& rslv = m_mpq_lar_core_solver.m_r_solver;
auto& jset = m_mpq_lar_core_solver.m_r_solver.inf_set(); // hijack this set that should be empty right now auto& jset = m_mpq_lar_core_solver.m_r_solver.inf_heap(); // hijack this set that should be empty right now
lp_assert(jset.empty()); lp_assert(jset.empty());
for (lar_term::ival p : term) { for (lar_term::ival p : term) {
@ -667,16 +673,16 @@ namespace lp {
m_mpq_lar_core_solver.m_r_solver.add_delta_to_x_and_track_feasibility(bj, -A_r().get_val(c) * delta); m_mpq_lar_core_solver.m_r_solver.add_delta_to_x_and_track_feasibility(bj, -A_r().get_val(c) * delta);
TRACE("change_x_del", TRACE("change_x_del",
tout << "changed basis column " << bj << ", it is " << tout << "changed basis column " << bj << ", it is " <<
(m_mpq_lar_core_solver.m_r_solver.column_is_feasible(bj) ? "feas" : "inf") << std::endl;); (column_is_feasible(bj) ? "feas" : "inf") << std::endl;);
} }
} }
void lar_solver::update_x_and_inf_costs_for_column_with_changed_bounds(unsigned j) { void lar_solver::update_x_and_inf_costs_for_column_with_changed_bounds(unsigned j) {
if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) {
if (costs_are_used()) { if (costs_are_used()) {
bool was_infeas = m_mpq_lar_core_solver.m_r_solver.inf_set_contains(j); bool was_infeas = m_mpq_lar_core_solver.m_r_solver.inf_heap_contains(j);
m_mpq_lar_core_solver.m_r_solver.track_column_feasibility(j); m_mpq_lar_core_solver.m_r_solver.track_column_feasibility(j);
if (was_infeas != m_mpq_lar_core_solver.m_r_solver.inf_set_contains(j)) if (was_infeas != m_mpq_lar_core_solver.m_r_solver.inf_heap_contains(j))
m_basic_columns_with_changed_cost.insert(j); m_basic_columns_with_changed_cost.insert(j);
} }
else { else {
@ -1293,12 +1299,12 @@ namespace lp {
lp_assert(m_mpq_lar_core_solver.m_r_solver.basis_heading_is_correct()); lp_assert(m_mpq_lar_core_solver.m_r_solver.basis_heading_is_correct());
} }
void lar_solver::clean_inf_set_of_r_solver_after_pop() { void lar_solver::clean_inf_heap_of_r_solver_after_pop() {
vector<unsigned> became_feas; vector<unsigned> became_feas;
clean_popped_elements(A_r().column_count(), m_mpq_lar_core_solver.m_r_solver.inf_set()); clean_popped_elements_for_heap(A_r().column_count(), m_mpq_lar_core_solver.m_r_solver.inf_heap());
std::unordered_set<unsigned> basic_columns_with_changed_cost; std::unordered_set<unsigned> basic_columns_with_changed_cost;
m_inf_index_copy.reset(); m_inf_index_copy.reset();
for (auto j : m_mpq_lar_core_solver.m_r_solver.inf_set()) for (auto j : m_mpq_lar_core_solver.m_r_solver.inf_heap())
m_inf_index_copy.push_back(j); m_inf_index_copy.push_back(j);
for (auto j : m_inf_index_copy) { for (auto j : m_inf_index_copy) {
if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) {
@ -1316,16 +1322,16 @@ namespace lp {
lp_assert(m_mpq_lar_core_solver.m_r_solver.m_basis_heading[j] < 0); lp_assert(m_mpq_lar_core_solver.m_r_solver.m_basis_heading[j] < 0);
m_mpq_lar_core_solver.m_r_solver.m_d[j] -= m_mpq_lar_core_solver.m_r_solver.m_costs[j]; m_mpq_lar_core_solver.m_r_solver.m_d[j] -= m_mpq_lar_core_solver.m_r_solver.m_costs[j];
m_mpq_lar_core_solver.m_r_solver.m_costs[j] = zero_of_type<mpq>(); m_mpq_lar_core_solver.m_r_solver.m_costs[j] = zero_of_type<mpq>();
m_mpq_lar_core_solver.m_r_solver.remove_column_from_inf_set(j); m_mpq_lar_core_solver.m_r_solver.remove_column_from_inf_heap(j);
} }
became_feas.clear(); became_feas.clear();
for (unsigned j : m_mpq_lar_core_solver.m_r_solver.inf_set()) { for (unsigned j : m_mpq_lar_core_solver.m_r_solver.inf_heap()) {
lp_assert(m_mpq_lar_core_solver.m_r_heading[j] >= 0); lp_assert(m_mpq_lar_core_solver.m_r_heading[j] >= 0);
if (m_mpq_lar_core_solver.m_r_solver.column_is_feasible(j)) if (column_is_feasible(j))
became_feas.push_back(j); became_feas.push_back(j);
} }
for (unsigned j : became_feas) for (unsigned j : became_feas)
m_mpq_lar_core_solver.m_r_solver.remove_column_from_inf_set(j); m_mpq_lar_core_solver.m_r_solver.remove_column_from_inf_heap(j);
} }
@ -1346,8 +1352,8 @@ namespace lp {
} }
bool lar_solver::term_is_int(const vector<std::pair<mpq, unsigned int>>& coeffs) const { bool lar_solver::term_is_int(const vector<std::pair<mpq, unsigned int>>& coeffs) const {
for (auto const& p : coeffs) for (auto const& [coeff, v] : coeffs)
if (!(column_is_int(p.second) && p.first.is_int())) if (!(column_is_int(v) && coeff.is_int()))
return false; return false;
return true; return true;
} }
@ -1374,66 +1380,6 @@ namespace lp {
return m_mpq_lar_core_solver.column_is_free(j); return m_mpq_lar_core_solver.column_is_free(j);
} }
// column is at lower or upper bound, lower and upper bound are different.
// the lower/upper bound is not strict.
// the LP obtained by making the bound strict is infeasible
// -> the column has to be fixed
bool lar_solver::is_fixed_at_bound(column_index const& j) {
if (column_is_fixed(j))
return false;
mpq val;
if (!has_value(j, val))
return false;
lp::lconstraint_kind k;
if (column_has_upper_bound(j) &&
get_upper_bound(j).x == val) {
verbose_stream() << "check upper " << j << "\n";
push();
if (column_is_int(j))
k = LE, val -= 1;
else
k = LT;
auto ci = mk_var_bound(j, k, val);
update_column_type_and_bound(j, k, val, ci);
auto st = find_feasible_solution();
pop(1);
return st == lp_status::INFEASIBLE;
}
if (column_has_lower_bound(j) &&
get_lower_bound(j).x == val) {
verbose_stream() << "check lower " << j << "\n";
push();
if (column_is_int(j))
k = GE, val += 1;
else
k = GT;
auto ci = mk_var_bound(j, k, val);
update_column_type_and_bound(j, k, val, ci);
auto st = find_feasible_solution();
pop(1);
return st == lp_status::INFEASIBLE;
}
return false;
}
bool lar_solver::has_fixed_at_bound() {
verbose_stream() << "has-fixed-at-bound\n";
unsigned num_fixed = 0;
for (unsigned j = 0; j < A_r().m_columns.size(); ++j) {
auto ci = column_index(j);
if (is_fixed_at_bound(ci)) {
++num_fixed;
verbose_stream() << "fixed " << j << "\n";
}
}
verbose_stream() << "num fixed " << num_fixed << "\n";
if (num_fixed > 0)
find_feasible_solution();
return num_fixed > 0;
}
// below is the initialization functionality of lar_solver // below is the initialization functionality of lar_solver
bool lar_solver::strategy_is_undecided() const { bool lar_solver::strategy_is_undecided() const {
@ -1504,7 +1450,7 @@ namespace lp {
m_mpq_lar_core_solver.m_r_x.resize(j + 1); m_mpq_lar_core_solver.m_r_x.resize(j + 1);
m_mpq_lar_core_solver.m_r_lower_bounds.increase_size_by_one(); m_mpq_lar_core_solver.m_r_lower_bounds.increase_size_by_one();
m_mpq_lar_core_solver.m_r_upper_bounds.increase_size_by_one(); m_mpq_lar_core_solver.m_r_upper_bounds.increase_size_by_one();
m_mpq_lar_core_solver.m_r_solver.inf_set_increase_size_by_one(); m_mpq_lar_core_solver.m_r_solver.inf_heap_increase_size_by_one();
m_mpq_lar_core_solver.m_r_solver.m_costs.resize(j + 1); m_mpq_lar_core_solver.m_r_solver.m_costs.resize(j + 1);
m_mpq_lar_core_solver.m_r_solver.m_d.resize(j + 1); m_mpq_lar_core_solver.m_r_solver.m_d.resize(j + 1);
lp_assert(m_mpq_lar_core_solver.m_r_heading.size() == j); // as A().column_count() on the entry to the method lp_assert(m_mpq_lar_core_solver.m_r_heading.size() == j); // as A().column_count() on the entry to the method
@ -1609,6 +1555,18 @@ namespace lp {
return ret; return ret;
} }
/**
* \brief ensure there is a column index corresponding to vi
* If vi is already a column, just return vi
* If vi is for a term, then create a row that uses the term.
*/
var_index lar_solver::ensure_column(var_index vi) {
if (lp::tv::is_term(vi))
return to_column(vi);
else
return vi;
}
void lar_solver::add_row_from_term_no_constraint(const lar_term* term, unsigned term_ext_index) { void lar_solver::add_row_from_term_no_constraint(const lar_term* term, unsigned term_ext_index) {
TRACE("dump_terms", print_term(*term, tout) << std::endl;); TRACE("dump_terms", print_term(*term, tout) << std::endl;);
@ -1780,13 +1738,20 @@ namespace lp {
lconstraint_kind kind, lconstraint_kind kind,
const mpq& right_side, const mpq& right_side,
constraint_index constr_index) { constraint_index constr_index) {
TRACE("lar_solver_feas", tout << "j = " << j << " was " << (this->column_is_feasible(j)?"feas":"non-feas") << std::endl;);
m_constraints.activate(constr_index); m_constraints.activate(constr_index);
if (column_has_upper_bound(j)) if (column_has_upper_bound(j))
update_column_type_and_bound_with_ub(j, kind, right_side, constr_index); update_column_type_and_bound_with_ub(j, kind, right_side, constr_index);
else else
update_column_type_and_bound_with_no_ub(j, kind, right_side, constr_index); update_column_type_and_bound_with_no_ub(j, kind, right_side, constr_index);
TRACE("lar_solver_feas", tout << "j = " << j << " became " << (this->column_is_feasible(j)?"feas":"non-feas") << ", and " << (this->column_is_bounded(j)? "bounded":"non-bounded") << std::endl;);
} }
// clang-format on
void lar_solver::insert_to_columns_with_changed_bounds(unsigned j) {
m_columns_with_changed_bounds.insert(j);
TRACE("lar_solver", tout << "column " << j << (column_is_feasible(j) ? " feas" : " non-feas") << "\n";);
}
// clang-format off
void lar_solver::update_column_type_and_bound_check_on_equal(unsigned j, void lar_solver::update_column_type_and_bound_check_on_equal(unsigned j,
lconstraint_kind kind, lconstraint_kind kind,
const mpq& right_side, const mpq& right_side,
@ -1876,7 +1841,7 @@ namespace lp {
} }
} }
// clang-format on
void lar_solver::update_bound_with_ub_lb(var_index j, lconstraint_kind kind, const mpq& right_side, constraint_index ci) { void lar_solver::update_bound_with_ub_lb(var_index j, lconstraint_kind kind, const mpq& right_side, constraint_index ci) {
lp_assert(column_has_lower_bound(j) && column_has_upper_bound(j)); lp_assert(column_has_lower_bound(j) && column_has_upper_bound(j));
lp_assert(m_mpq_lar_core_solver.m_column_types[j] == column_type::boxed || lp_assert(m_mpq_lar_core_solver.m_column_types[j] == column_type::boxed ||
@ -1886,8 +1851,7 @@ namespace lp {
switch (kind) { switch (kind) {
case LT: case LT:
y_of_bound = -1; y_of_bound = -1;
case LE: case LE: {
{
auto up = numeric_pair<mpq>(right_side, y_of_bound); auto up = numeric_pair<mpq>(right_side, y_of_bound);
if (up < m_mpq_lar_core_solver.m_r_lower_bounds[j]) { if (up < m_mpq_lar_core_solver.m_r_lower_bounds[j]) {
set_infeasible_column(j); set_infeasible_column(j);
@ -1896,12 +1860,11 @@ namespace lp {
m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; m_mpq_lar_core_solver.m_r_upper_bounds[j] = up;
set_upper_bound_witness(j, ci); set_upper_bound_witness(j, ci);
insert_to_columns_with_changed_bounds(j); insert_to_columns_with_changed_bounds(j);
}
break; break;
}
case GT: case GT:
y_of_bound = 1; y_of_bound = 1;
case GE: case GE: {
{
auto low = numeric_pair<mpq>(right_side, y_of_bound); auto low = numeric_pair<mpq>(right_side, y_of_bound);
if (low > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { if (low > m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
set_infeasible_column(j); set_infeasible_column(j);
@ -1910,13 +1873,12 @@ namespace lp {
return; return;
} }
m_mpq_lar_core_solver.m_r_lower_bounds[j] = low; m_mpq_lar_core_solver.m_r_lower_bounds[j] = low;
insert_to_columns_with_changed_bounds(j);
set_lower_bound_witness(j, ci); set_lower_bound_witness(j, ci);
m_mpq_lar_core_solver.m_column_types[j] = (low == m_mpq_lar_core_solver.m_r_upper_bounds[j] ? column_type::fixed : column_type::boxed); m_mpq_lar_core_solver.m_column_types[j] = (low == m_mpq_lar_core_solver.m_r_upper_bounds[j] ? column_type::fixed : column_type::boxed);
} insert_to_columns_with_changed_bounds(j);
break; break;
case EQ: }
{ case EQ: {
auto v = numeric_pair<mpq>(right_side, zero_of_type<mpq>()); auto v = numeric_pair<mpq>(right_side, zero_of_type<mpq>());
if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j] || v < m_mpq_lar_core_solver.m_r_lower_bounds[j]) { if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j] || v < m_mpq_lar_core_solver.m_r_lower_bounds[j]) {
set_infeasible_column(j); set_infeasible_column(j);
@ -1934,6 +1896,7 @@ namespace lp {
m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed;
} }
} }
// clang-format off
void lar_solver::update_bound_with_no_ub_lb(var_index j, lconstraint_kind kind, const mpq& right_side, constraint_index ci) { void lar_solver::update_bound_with_no_ub_lb(var_index j, lconstraint_kind kind, const mpq& right_side, constraint_index ci) {
lp_assert(column_has_lower_bound(j) && !column_has_upper_bound(j)); lp_assert(column_has_lower_bound(j) && !column_has_upper_bound(j));
lp_assert(m_mpq_lar_core_solver.m_column_types[j] == column_type::lower_bound); lp_assert(m_mpq_lar_core_solver.m_column_types[j] == column_type::lower_bound);
@ -1942,33 +1905,30 @@ namespace lp {
switch (kind) { switch (kind) {
case LT: case LT:
y_of_bound = -1; y_of_bound = -1;
case LE: case LE: {
{
auto up = numeric_pair<mpq>(right_side, y_of_bound); auto up = numeric_pair<mpq>(right_side, y_of_bound);
if (up < m_mpq_lar_core_solver.m_r_lower_bounds[j]) { if (up < m_mpq_lar_core_solver.m_r_lower_bounds[j]) {
set_infeasible_column(j); set_infeasible_column(j);
} }
m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; m_mpq_lar_core_solver.m_r_upper_bounds[j] = up;
set_upper_bound_witness(j, ci); set_upper_bound_witness(j, ci);
insert_to_columns_with_changed_bounds(j);
m_mpq_lar_core_solver.m_column_types[j] = (up == m_mpq_lar_core_solver.m_r_lower_bounds[j] ? column_type::fixed : column_type::boxed); m_mpq_lar_core_solver.m_column_types[j] = (up == m_mpq_lar_core_solver.m_r_lower_bounds[j] ? column_type::fixed : column_type::boxed);
} insert_to_columns_with_changed_bounds(j);
break; break;
}
case GT: case GT:
y_of_bound = 1; y_of_bound = 1;
case GE: case GE: {
{
auto low = numeric_pair<mpq>(right_side, y_of_bound); auto low = numeric_pair<mpq>(right_side, y_of_bound);
if (low < m_mpq_lar_core_solver.m_r_lower_bounds[j]) { if (low < m_mpq_lar_core_solver.m_r_lower_bounds[j]) {
return; return;
} }
m_mpq_lar_core_solver.m_r_lower_bounds[j] = low; m_mpq_lar_core_solver.m_r_lower_bounds[j] = low;
insert_to_columns_with_changed_bounds(j);
set_lower_bound_witness(j, ci); set_lower_bound_witness(j, ci);
} insert_to_columns_with_changed_bounds(j);
break; break;
case EQ: }
{ case EQ: {
auto v = numeric_pair<mpq>(right_side, zero_of_type<mpq>()); auto v = numeric_pair<mpq>(right_side, zero_of_type<mpq>());
if (v < m_mpq_lar_core_solver.m_r_lower_bounds[j]) { if (v < m_mpq_lar_core_solver.m_r_lower_bounds[j]) {
set_infeasible_column(j); set_infeasible_column(j);
@ -1984,9 +1944,8 @@ namespace lp {
default: default:
UNREACHABLE(); UNREACHABLE();
} }
} }
// clang-format off
void lar_solver::update_bound_with_ub_no_lb(var_index j, lconstraint_kind kind, const mpq& right_side, constraint_index ci) { void lar_solver::update_bound_with_ub_no_lb(var_index j, lconstraint_kind kind, const mpq& right_side, constraint_index ci) {
lp_assert(!column_has_lower_bound(j) && column_has_upper_bound(j)); lp_assert(!column_has_lower_bound(j) && column_has_upper_bound(j));
lp_assert(m_mpq_lar_core_solver.m_column_types[j] == column_type::upper_bound); lp_assert(m_mpq_lar_core_solver.m_column_types[j] == column_type::upper_bound);
@ -2012,9 +1971,10 @@ namespace lp {
set_infeasible_column(j); set_infeasible_column(j);
} }
m_mpq_lar_core_solver.m_r_lower_bounds[j] = low; m_mpq_lar_core_solver.m_r_lower_bounds[j] = low;
insert_to_columns_with_changed_bounds(j);
set_lower_bound_witness(j, ci); set_lower_bound_witness(j, ci);
m_mpq_lar_core_solver.m_column_types[j] = (low == m_mpq_lar_core_solver.m_r_upper_bounds[j] ? column_type::fixed : column_type::boxed); m_mpq_lar_core_solver.m_column_types[j] = (low == m_mpq_lar_core_solver.m_r_upper_bounds[j] ? column_type::fixed : column_type::boxed);
insert_to_columns_with_changed_bounds(j);
} }
break; break;
case EQ: case EQ:
@ -2035,35 +1995,30 @@ namespace lp {
UNREACHABLE(); UNREACHABLE();
} }
} }
// clang-format on
void lar_solver::update_bound_with_no_ub_no_lb(var_index j, lconstraint_kind kind, const mpq& right_side, constraint_index ci) { void lar_solver::update_bound_with_no_ub_no_lb(var_index j, lconstraint_kind kind, const mpq& right_side, constraint_index ci) {
lp_assert(!column_has_lower_bound(j) && !column_has_upper_bound(j)); lp_assert(!column_has_lower_bound(j) && !column_has_upper_bound(j));
insert_to_columns_with_changed_bounds(j);
mpq y_of_bound(0); mpq y_of_bound(0);
switch (kind) { switch (kind) {
case LT: case LT:
y_of_bound = -1; y_of_bound = -1;
case LE: case LE: {
{
auto up = numeric_pair<mpq>(right_side, y_of_bound); auto up = numeric_pair<mpq>(right_side, y_of_bound);
m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; m_mpq_lar_core_solver.m_r_upper_bounds[j] = up;
set_upper_bound_witness(j, ci); set_upper_bound_witness(j, ci);
m_mpq_lar_core_solver.m_column_types[j] = column_type::upper_bound; m_mpq_lar_core_solver.m_column_types[j] = column_type::upper_bound;
} } break;
break;
case GT: case GT:
y_of_bound = 1; y_of_bound = 1;
case GE: case GE: {
{
auto low = numeric_pair<mpq>(right_side, y_of_bound); auto low = numeric_pair<mpq>(right_side, y_of_bound);
m_mpq_lar_core_solver.m_r_lower_bounds[j] = low; m_mpq_lar_core_solver.m_r_lower_bounds[j] = low;
insert_to_columns_with_changed_bounds(j);
set_lower_bound_witness(j, ci); set_lower_bound_witness(j, ci);
m_mpq_lar_core_solver.m_column_types[j] = column_type::lower_bound; m_mpq_lar_core_solver.m_column_types[j] = column_type::lower_bound;
}
break; } break;
case EQ: case EQ: {
{
auto v = numeric_pair<mpq>(right_side, zero_of_type<mpq>()); auto v = numeric_pair<mpq>(right_side, zero_of_type<mpq>());
set_upper_bound_witness(j, ci); set_upper_bound_witness(j, ci);
set_lower_bound_witness(j, ci); set_lower_bound_witness(j, ci);
@ -2075,8 +2030,9 @@ namespace lp {
default: default:
UNREACHABLE(); UNREACHABLE();
} }
insert_to_columns_with_changed_bounds(j);
} }
// clang-format off
bool lar_solver::column_corresponds_to_term(unsigned j) const { bool lar_solver::column_corresponds_to_term(unsigned j) const {
return tv::is_term(m_var_register.local_to_external(j)); return tv::is_term(m_var_register.local_to_external(j));
} }
@ -2180,7 +2136,7 @@ namespace lp {
} }
bool lar_solver::get_equality_and_right_side_for_term_on_current_x(tv const& t, mpq& rs, constraint_index& ci, bool& upper_bound) const { bool lar_solver::get_equality_and_right_side_for_term_on_current_x(tv const& t, mpq& rs, constraint_index& ci, bool& upper_bound) const {
lp_assert(t.is_term()) lp_assert(t.is_term());
unsigned j; unsigned j;
bool is_int; bool is_int;
if (!m_var_register.external_is_used(t.index(), j, is_int)) if (!m_var_register.external_is_used(t.index(), j, is_int))

View file

@ -17,30 +17,32 @@
--*/ --*/
// clang-format off
#pragma once #pragma once
#include "util/vector.h" #include <algorithm>
#include <utility> #include <functional>
#include "util/debug.h" #include <stack>
#include "util/buffer.h" #include <string>
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
#include <string> #include <utility>
#include <algorithm>
#include <stack> #include "math/lp/bound_analyzer_on_row.h"
#include <functional> #include "math/lp/implied_bound.h"
#include "math/lp/int_solver.h"
#include "math/lp/lar_constraints.h" #include "math/lp/lar_constraints.h"
#include "math/lp/lar_core_solver.h" #include "math/lp/lar_core_solver.h"
#include "math/lp/numeric_pair.h"
#include "math/lp/lp_primal_core_solver.h"
#include "math/lp/random_updater.h"
#include "util/stacked_value.h"
#include "math/lp/stacked_vector.h"
#include "math/lp/implied_bound.h"
#include "math/lp/bound_analyzer_on_row.h"
#include "math/lp/int_solver.h"
#include "math/lp/nra_solver.h"
#include "math/lp/lp_types.h"
#include "math/lp/lp_bound_propagator.h" #include "math/lp/lp_bound_propagator.h"
#include "math/lp/lp_primal_core_solver.h"
#include "math/lp/lp_types.h"
#include "math/lp/nra_solver.h"
#include "math/lp/numeric_pair.h"
#include "math/lp/random_updater.h"
#include "math/lp/stacked_vector.h"
#include "util/buffer.h"
#include "util/debug.h"
#include "util/stacked_value.h"
#include "util/vector.h"
namespace lp { namespace lp {
@ -48,10 +50,9 @@ class int_branch;
class int_solver; class int_solver;
class lar_solver : public column_namer { class lar_solver : public column_namer {
struct term_hasher { struct term_hasher {
std::size_t operator()(const lar_term &t) const std::size_t operator()(const lar_term& t) const {
{
using std::size_t;
using std::hash; using std::hash;
using std::size_t;
using std::string; using std::string;
size_t seed = 0; size_t seed = 0;
int i = 0; int i = 0;
@ -66,8 +67,7 @@ class lar_solver : public column_namer {
}; };
struct term_comparer { struct term_comparer {
bool operator()(const lar_term &a, const lar_term& b) const bool operator()(const lar_term& a, const lar_term& b) const {
{
return a == b; return a == b;
} }
}; };
@ -94,7 +94,7 @@ class lar_solver : public column_namer {
// these are basic columns with the value changed, so the corresponding row in the tableau // these are basic columns with the value changed, so the corresponding row in the tableau
// does not sum to zero anymore // does not sum to zero anymore
u_set m_incorrect_columns; u_set m_incorrect_columns;
// copy of m_r_solver.inf_set() // copy of m_r_solver.inf_heap()
unsigned_vector m_inf_index_copy; unsigned_vector m_inf_index_copy;
stacked_value<unsigned> m_term_count; stacked_value<unsigned> m_term_count;
vector<lar_term*> m_terms; vector<lar_term*> m_terms;
@ -135,8 +135,7 @@ class lar_solver : public column_namer {
inline void clear_columns_with_changed_bounds() { m_columns_with_changed_bounds.clear(); } inline void clear_columns_with_changed_bounds() { m_columns_with_changed_bounds.clear(); }
inline void increase_by_one_columns_with_changed_bounds() { m_columns_with_changed_bounds.increase_size_by_one(); } inline void increase_by_one_columns_with_changed_bounds() { m_columns_with_changed_bounds.increase_size_by_one(); }
inline void insert_to_columns_with_changed_bounds(unsigned j) { m_columns_with_changed_bounds.insert(j); } void insert_to_columns_with_changed_bounds(unsigned j);
void update_column_type_and_bound_check_on_equal(unsigned j, lconstraint_kind kind, const mpq& right_side, constraint_index constr_index, unsigned&); void update_column_type_and_bound_check_on_equal(unsigned j, lconstraint_kind kind, const mpq& right_side, constraint_index constr_index, unsigned&);
void update_column_type_and_bound(unsigned j, lconstraint_kind kind, const mpq& right_side, constraint_index constr_index); void update_column_type_and_bound(unsigned j, lconstraint_kind kind, const mpq& right_side, constraint_index constr_index);
void update_column_type_and_bound_with_ub(var_index j, lconstraint_kind kind, const mpq& right_side, constraint_index constr_index); void update_column_type_and_bound_with_ub(var_index j, lconstraint_kind kind, const mpq& right_side, constraint_index constr_index);
@ -161,12 +160,10 @@ class lar_solver : public column_namer {
bool sizes_are_correct() const; bool sizes_are_correct() const;
bool implied_bound_is_correctly_explained(implied_bound const& be, const vector<std::pair<mpq, unsigned>>& explanation) const; bool implied_bound_is_correctly_explained(implied_bound const& be, const vector<std::pair<mpq, unsigned>>& explanation) const;
void substitute_basis_var_in_terms_for_row(unsigned i); void substitute_basis_var_in_terms_for_row(unsigned i);
template <typename T> template <typename T>
unsigned calculate_implied_bounds_for_row(unsigned row_index, lp_bound_propagator<T>& bp) { unsigned calculate_implied_bounds_for_row(unsigned row_index, lp_bound_propagator<T>& bp) {
if (A_r().m_rows[row_index].size() > settings().max_row_length_for_bound_propagation || row_has_a_big_num(row_index)) if (A_r().m_rows[row_index].size() > settings().max_row_length_for_bound_propagation || row_has_a_big_num(row_index))
return 0; return 0;
@ -178,6 +175,7 @@ class lar_solver : public column_namer {
bp); bp);
} }
static void clean_popped_elements_for_heap(unsigned n, lpvar_heap& set);
static void clean_popped_elements(unsigned n, u_set& set); static void clean_popped_elements(unsigned n, u_set& set);
bool maximize_term_on_tableau(const lar_term& term, bool maximize_term_on_tableau(const lar_term& term,
impq& term_max); impq& term_max);
@ -230,7 +228,7 @@ class lar_solver : public column_namer {
void remove_last_column_from_basis_tableau(unsigned j); void remove_last_column_from_basis_tableau(unsigned j);
void remove_last_column_from_tableau(); void remove_last_column_from_tableau();
void pop_tableau(); void pop_tableau();
void clean_inf_set_of_r_solver_after_pop(); void clean_inf_heap_of_r_solver_after_pop();
inline bool column_value_is_integer(unsigned j) const { return get_column_value(j).is_int(); } inline bool column_value_is_integer(unsigned j) const { return get_column_value(j).is_int(); }
bool model_is_int_feasible() const; bool model_is_int_feasible() const;
@ -256,7 +254,6 @@ public:
return m_fixed_var_table_int; return m_fixed_var_table_int;
} }
const map<mpq, unsigned, obj_hash<mpq>, default_eq<mpq>>& fixed_var_table_real() const { const map<mpq, unsigned, obj_hash<mpq>, default_eq<mpq>>& fixed_var_table_real() const {
return m_fixed_var_table_real; return m_fixed_var_table_real;
} }
@ -269,7 +266,8 @@ public:
return is_int ? fixed_var_table_int().find(mpq, j) : fixed_var_table_real().find(mpq, j); return is_int ? fixed_var_table_int().find(mpq, j) : fixed_var_table_real().find(mpq, j);
} }
template <typename T> void remove_non_fixed_from_table(T&); template <typename T>
void remove_non_fixed_from_table(T&);
unsigned external_to_column_index(unsigned) const; unsigned external_to_column_index(unsigned) const;
@ -366,9 +364,6 @@ public:
} }
} }
bool is_fixed_at_bound(column_index const& j);
bool has_fixed_at_bound();
bool is_fixed(column_index const& j) const { return column_is_fixed(j); } bool is_fixed(column_index const& j) const { return column_is_fixed(j); }
inline column_index to_column_index(unsigned v) const { return column_index(external_to_column_index(v)); } inline column_index to_column_index(unsigned v) const { return column_index(external_to_column_index(v)); }
bool external_is_used(unsigned) const; bool external_is_used(unsigned) const;
@ -376,6 +371,7 @@ public:
bool compare_values(var_index j, lconstraint_kind kind, const mpq& right_side); bool compare_values(var_index j, lconstraint_kind kind, const mpq& right_side);
var_index add_term(const vector<std::pair<mpq, var_index>>& coeffs, unsigned ext_i); var_index add_term(const vector<std::pair<mpq, var_index>>& coeffs, unsigned ext_i);
void register_existing_terms(); void register_existing_terms();
var_index ensure_column(var_index vi);
constraint_index add_var_bound(var_index, lconstraint_kind, const mpq&); constraint_index add_var_bound(var_index, lconstraint_kind, const mpq&);
constraint_index add_var_bound_check_on_equal(var_index, lconstraint_kind, const mpq&, var_index&); constraint_index add_var_bound_check_on_equal(var_index, lconstraint_kind, const mpq&, var_index&);
@ -383,33 +379,36 @@ public:
void set_cut_strategy(unsigned cut_frequency); void set_cut_strategy(unsigned cut_frequency);
inline unsigned column_count() const { return A_r().column_count(); } inline unsigned column_count() const { return A_r().column_count(); }
inline var_index local_to_external(var_index idx) const { inline var_index local_to_external(var_index idx) const {
return tv::is_term(idx)? return tv::is_term(idx) ? m_term_register.local_to_external(idx) : m_var_register.local_to_external(idx);
m_term_register.local_to_external(idx) : m_var_register.local_to_external(idx);
} }
bool column_corresponds_to_term(unsigned) const; bool column_corresponds_to_term(unsigned) const;
const lar_term& column_to_term(unsigned j) const {
SASSERT(column_corresponds_to_term(j));
return get_term(column2tv(to_column_index(j)));
}
inline unsigned row_count() const { return A_r().row_count(); } inline unsigned row_count() const { return A_r().row_count(); }
bool var_is_registered(var_index vj) const; bool var_is_registered(var_index vj) const;
void clear_inf_set() { void clear_inf_heap() {
m_mpq_lar_core_solver.m_r_solver.inf_set().clear(); m_mpq_lar_core_solver.m_r_solver.inf_heap().clear();
} }
inline void remove_column_from_inf_set(unsigned j) {
m_mpq_lar_core_solver.m_r_solver.remove_column_from_inf_set(j); void pivot(int entering, int leaving) {
m_mpq_lar_core_solver.pivot(entering, leaving);
} }
template <typename ChangeReport> template <typename ChangeReport>
void change_basic_columns_dependend_on_a_given_nb_column_report(unsigned j, void change_basic_columns_dependend_on_a_given_nb_column_report(unsigned j,
const numeric_pair<mpq>& delta, const numeric_pair<mpq>& delta,
const ChangeReport& after) { const ChangeReport& after) {
for (const auto& c : A_r().m_columns[j]) { for (const auto& c : A_r().m_columns[j]) {
unsigned bj = m_mpq_lar_core_solver.m_r_basis[c.var()]; unsigned bj = m_mpq_lar_core_solver.m_r_basis[c.var()];
if (tableau_with_costs()) { if (tableau_with_costs())
m_basic_columns_with_changed_cost.insert(bj); m_basic_columns_with_changed_cost.insert(bj);
}
m_mpq_lar_core_solver.m_r_solver.add_delta_to_x_and_track_feasibility(bj, -A_r().get_val(c) * delta); m_mpq_lar_core_solver.m_r_solver.add_delta_to_x_and_track_feasibility(bj, -A_r().get_val(c) * delta);
after(bj); after(bj);
TRACE("change_x_del", TRACE("change_x_del",
tout << "changed basis column " << bj << ", it is " << tout << "changed basis column " << bj << ", it is " << (m_mpq_lar_core_solver.m_r_solver.column_is_feasible(bj) ? "feas" : "inf") << std::endl;);
( m_mpq_lar_core_solver.m_r_solver.column_is_feasible(bj)? "feas":"inf") << std::endl;);
} }
} }
@ -417,7 +416,6 @@ public:
void set_value_for_nbasic_column_report(unsigned j, void set_value_for_nbasic_column_report(unsigned j,
const impq& new_val, const impq& new_val,
const ChangeReport& after) { const ChangeReport& after) {
lp_assert(!is_base(j)); lp_assert(!is_base(j));
auto& x = m_mpq_lar_core_solver.m_r_x[j]; auto& x = m_mpq_lar_core_solver.m_r_x[j];
auto delta = new_val - x; auto delta = new_val - x;
@ -462,21 +460,18 @@ public:
return m_mpq_lar_core_solver.m_r_solver.column_has_lower_bound(j); return m_mpq_lar_core_solver.m_r_solver.column_has_lower_bound(j);
} }
inline inline constraint_index get_column_upper_bound_witness(unsigned j) const {
constraint_index get_column_upper_bound_witness(unsigned j) const {
if (tv::is_term(j)) { if (tv::is_term(j)) {
j = m_var_register.external_to_local(j); j = m_var_register.external_to_local(j);
} }
return m_columns_to_ul_pairs()[j].upper_bound_witness(); return m_columns_to_ul_pairs()[j].upper_bound_witness();
} }
inline inline const impq& get_upper_bound(column_index j) const {
const impq& get_upper_bound(column_index j) const {
return m_mpq_lar_core_solver.m_r_solver.m_upper_bounds[j]; return m_mpq_lar_core_solver.m_r_solver.m_upper_bounds[j];
} }
inline inline const impq& get_lower_bound(column_index j) const {
const impq& get_lower_bound(column_index j) const {
return m_mpq_lar_core_solver.m_r_solver.m_lower_bounds[j]; return m_mpq_lar_core_solver.m_r_solver.m_lower_bounds[j];
} }
bool has_lower_bound(var_index var, constraint_index& ci, mpq& value, bool& is_strict) const; bool has_lower_bound(var_index var, constraint_index& ci, mpq& value, bool& is_strict) const;
@ -486,6 +481,7 @@ public:
unsigned map_term_index_to_column_index(unsigned j) const; unsigned map_term_index_to_column_index(unsigned j) const;
bool column_is_fixed(unsigned j) const; bool column_is_fixed(unsigned j) const;
bool column_is_free(unsigned j) const; bool column_is_free(unsigned j) const;
bool column_is_feasible(unsigned j) const { return m_mpq_lar_core_solver.m_r_solver.column_is_feasible(j);}
unsigned column_to_reported_index(unsigned j) const; unsigned column_to_reported_index(unsigned j) const;
lp_settings& settings(); lp_settings& settings();
lp_settings const& settings() const; lp_settings const& settings() const;
@ -583,7 +579,10 @@ public:
inline void set_int_solver(int_solver* int_slv) { m_int_solver = int_slv; } inline void set_int_solver(int_solver* int_slv) { m_int_solver = int_slv; }
inline int_solver* get_int_solver() { return m_int_solver; } inline int_solver* get_int_solver() { return m_int_solver; }
inline const int_solver* get_int_solver() const { return m_int_solver; } inline const int_solver* get_int_solver() const { return m_int_solver; }
inline const lar_term & get_term(tv const& t) const { lp_assert(t.is_term()); return *m_terms[t.id()]; } inline const lar_term& get_term(tv const& t) const {
lp_assert(t.is_term());
return *m_terms[t.id()];
}
lp_status find_feasible_solution(); lp_status find_feasible_solution();
void move_non_basic_columns_to_bounds(bool); void move_non_basic_columns_to_bounds(bool);
bool move_non_basic_column_to_bounds(unsigned j, bool); bool move_non_basic_column_to_bounds(unsigned j, bool);
@ -626,14 +625,12 @@ public:
bool column_is_int(column_index const& j) const { return column_is_int((unsigned)j); } bool column_is_int(column_index const& j) const { return column_is_int((unsigned)j); }
// const impq& get_ivalue(column_index const& j) const { return get_column_value(j); } // const impq& get_ivalue(column_index const& j) const { return get_column_value(j); }
const impq& get_column_value(column_index const& j) const { return m_mpq_lar_core_solver.m_r_x[j]; } const impq& get_column_value(column_index const& j) const { return m_mpq_lar_core_solver.m_r_x[j]; }
inline inline var_index external_to_local(unsigned j) const {
var_index external_to_local(unsigned j) const {
var_index local_j; var_index local_j;
if (m_var_register.external_is_used(j, local_j) || if (m_var_register.external_is_used(j, local_j) ||
m_term_register.external_is_used(j, local_j)) { m_term_register.external_is_used(j, local_j)) {
return local_j; return local_j;
} } else {
else {
return -1; return -1;
} }
} }
@ -644,6 +641,5 @@ public:
} }
friend int_solver; friend int_solver;
friend int_branch; friend int_branch;
}; };
} } // namespace lp

View file

@ -17,6 +17,7 @@
--*/ --*/
// clang-format off
#pragma once #pragma once
#include "math/lp/indexed_vector.h" #include "math/lp/indexed_vector.h"
#include "util/map.h" #include "util/map.h"

View file

@ -17,6 +17,7 @@ Revision History:
--*/ --*/
// clang-format off
#pragma once #pragma once
namespace lp { namespace lp {
enum class lia_move { enum class lia_move {

View file

@ -7,6 +7,7 @@ Author:
Nikolaj Bjorner (nbjorner) Nikolaj Bjorner (nbjorner)
--*/ --*/
// clang-format off
#pragma once #pragma once
#include "util/inf_rational.h" #include "util/inf_rational.h"

View file

@ -4,20 +4,23 @@
Nikolaj Bjorner (nbjorner) Nikolaj Bjorner (nbjorner)
Lev Nachmanson (levnach) Lev Nachmanson (levnach)
*/ */
//clang-format off
#pragma once #pragma once
#include "math/lp/lp_settings.h"
#include <utility> #include <utility>
#include "math/lp/lp_settings.h"
#include "util/uint_set.h"
namespace lp { namespace lp {
template <typename T> template <typename T>
class lp_bound_propagator { class lp_bound_propagator {
class edge; // forward definition class edge; // forward definition
// vertex represents a column // vertex represents a column
// The set of vertices is organised in a tree. // The set of vertices is organized in a tree.
// The edges of the tree are rows, // The edges of the tree are rows,
// Vertices with m_neg set to false grow with the same rate as the root. // Vertices with m_neg set to false grow with the same rate as the root.
// Vertices with m_neq set to true diminish with the same rate as the roow grows. // Vertices with m_neq set to true diminish with the same rate as the roow grows.
// When two vertices with the same m_neg have the same value of columns // When two vertices with the same m_neg have the same value of columns
// then we have an equality betweet the columns. // then we have an equality between the columns.
class vertex { class vertex {
unsigned m_column; unsigned m_column;
vector<edge> m_edges; vector<edge> m_edges;
@ -26,10 +29,8 @@ class lp_bound_propagator {
// it is handy to find the common ancestor // it is handy to find the common ancestor
public: public:
vertex() {} vertex() {}
vertex(unsigned column) : vertex(unsigned column) : m_column(column),
m_column(column), m_level(0) {}
m_level(0)
{}
unsigned column() const { return m_column; } unsigned column() const { return m_column; }
const vertex* parent() const { return m_edge_from_parent.source(); } const vertex* parent() const { return m_edge_from_parent.source(); }
vertex* parent() { return m_edge_from_parent.source(); } vertex* parent() { return m_edge_from_parent.source(); }
@ -58,6 +59,7 @@ class lp_bound_propagator {
vertex* m_source; vertex* m_source;
vertex* m_target; vertex* m_target;
int m_row; int m_row;
public: public:
edge(vertex* source, vertex* target, int row) : m_source(source), m_target(target), m_row(row) {} edge(vertex* source, vertex* target, int row) : m_source(source), m_target(target), m_row(row) {}
edge() : m_source(nullptr), m_target(nullptr), m_row(-1) {} edge() : m_source(nullptr), m_target(nullptr), m_row(-1) {}
@ -69,7 +71,10 @@ class lp_bound_propagator {
edge reverse() const { return edge(m_target, m_source, m_row); } edge reverse() const { return edge(m_target, m_source, m_row); }
}; };
static int other(int x, int y, int z) { SASSERT(x == z || y == z); return x == z ? y : x; } static int other(int x, int y, int z) {
SASSERT(x == z || y == z);
return x == z ? y : x;
}
std::ostream& print_vert(std::ostream& out, const vertex* v) const { std::ostream& print_vert(std::ostream& out, const vertex* v) const {
out << "(c = " << v->column() << ", parent = {"; out << "(c = " << v->column() << ", parent = {";
if (v->parent()) if (v->parent())
@ -113,8 +118,6 @@ class lp_bound_propagator {
T& m_imp; T& m_imp;
vector<implied_bound> m_ibounds; vector<implied_bound> m_ibounds;
map<mpq, unsigned, obj_hash<mpq>, default_eq<mpq>> m_val2fixed_row; map<mpq, unsigned, obj_hash<mpq>, default_eq<mpq>> m_val2fixed_row;
bool is_fixed_row(unsigned r, unsigned& x) { bool is_fixed_row(unsigned r, unsigned& x) {
@ -165,7 +168,8 @@ class lp_bound_propagator {
} }
TRACE("cheap_eq", TRACE("cheap_eq",
tout << "v_j = "; lp().print_column_info(v_j, tout) << std::endl; tout << "v_j = ";
lp().print_column_info(v_j, tout) << std::endl;
tout << "v = "; print_vert(tout, v) << std::endl; tout << "v = "; print_vert(tout, v) << std::endl;
tout << "found j " << j << std::endl; lp().print_column_info(j, tout) << std::endl; tout << "found j " << j << std::endl; lp().print_column_info(j, tout) << std::endl;
tout << "found j = " << j << std::endl;); tout << "found j = " << j << std::endl;);
@ -214,8 +218,7 @@ class lp_bound_propagator {
if (not_set(y)) { if (not_set(y)) {
set_fixed_vertex(m_root); set_fixed_vertex(m_root);
explain_fixed_in_row(row_index, m_fixed_vertex_explanation); explain_fixed_in_row(row_index, m_fixed_vertex_explanation);
} } else {
else {
vertex* v = add_child_with_check(row_index, y, m_root, polarity); vertex* v = add_child_with_check(row_index, y, m_root, polarity);
if (v) if (v)
explore_under(v); explore_under(v);
@ -243,19 +246,15 @@ class lp_bound_propagator {
if (c.coeff().is_one() || c.coeff().is_minus_one()) { if (c.coeff().is_one() || c.coeff().is_minus_one()) {
x = c.var(); x = c.var();
x_cell = &c; x_cell = &c;
} } else
else
return false; return false;
} } else if (not_set(y)) {
else if (not_set(y)) {
if (c.coeff().is_one() || c.coeff().is_minus_one()) { if (c.coeff().is_one() || c.coeff().is_minus_one()) {
y = c.var(); y = c.var();
y_cell = &c; y_cell = &c;
} } else
else
return false; return false;
} } else
else
return false; return false;
} }
if (is_set(x)) { if (is_set(x)) {
@ -302,11 +301,8 @@ class lp_bound_propagator {
~reset_cheap_eq() { p.reset_cheap_eq_eh(); } ~reset_cheap_eq() { p.reset_cheap_eq_eh(); }
}; };
public: public:
lp_bound_propagator(T& imp) : m_imp(imp) {}
lp_bound_propagator(T& imp):
m_imp(imp) {}
const vector<implied_bound>& ibounds() const { return m_ibounds; } const vector<implied_bound>& ibounds() const { return m_ibounds; }
@ -361,22 +357,19 @@ public:
found_bound = implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict); found_bound = implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict);
TRACE("try_add_bound", m_imp.lp().print_implied_bound(found_bound, tout);); TRACE("try_add_bound", m_imp.lp().print_implied_bound(found_bound, tout););
} }
} } else {
else {
m_improved_lower_bounds[j] = m_ibounds.size(); m_improved_lower_bounds[j] = m_ibounds.size();
m_ibounds.push_back(implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict)); m_ibounds.push_back(implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict));
TRACE("try_add_bound", m_imp.lp().print_implied_bound(m_ibounds.back(), tout);); TRACE("try_add_bound", m_imp.lp().print_implied_bound(m_ibounds.back(), tout););
} }
} } else { // the upper bound case
else { // the upper bound case
if (try_get_value(m_improved_upper_bounds, j, k)) { if (try_get_value(m_improved_upper_bounds, j, k)) {
auto& found_bound = m_ibounds[k]; auto& found_bound = m_ibounds[k];
if (v < found_bound.m_bound || (v == found_bound.m_bound && !found_bound.m_strict && strict)) { if (v < found_bound.m_bound || (v == found_bound.m_bound && !found_bound.m_strict && strict)) {
found_bound = implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict); found_bound = implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict);
TRACE("try_add_bound", m_imp.lp().print_implied_bound(found_bound, tout);); TRACE("try_add_bound", m_imp.lp().print_implied_bound(found_bound, tout););
} }
} } else {
else {
m_improved_upper_bounds[j] = m_ibounds.size(); 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)); m_ibounds.push_back(implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict));
TRACE("try_add_bound", m_imp.lp().print_implied_bound(m_ibounds.back(), tout);); TRACE("try_add_bound", m_imp.lp().print_implied_bound(m_ibounds.back(), tout););
@ -430,10 +423,14 @@ public:
explain_fixed_in_row(row_index, m_fixed_vertex_explanation); explain_fixed_in_row(row_index, m_fixed_vertex_explanation);
set_fixed_vertex(v); set_fixed_vertex(v);
TRACE("cheap_eq", TRACE("cheap_eq",
tout << "polarity switch: " << polarity << "\nv = "; print_vert(tout , v) << "\nu = "; tout << "fixed vertex explanation\n"; tout << "polarity switch: " << polarity << "\nv = ";
for (auto p : m_fixed_vertex_explanation) print_vert(tout, v) << "\nu = "; tout << "fixed vertex explanation\n";
lp().constraints().display(tout, [this](lpvar j) { return lp().get_variable_name(j);}, p.ci());); for (auto p
: m_fixed_vertex_explanation)
lp()
.constraints()
.display(
tout, [this](lpvar j) { return lp().get_variable_name(j); }, p.ci()););
} }
bool tree_contains(vertex* v) const { bool tree_contains(vertex* v) const {
@ -449,19 +446,18 @@ public:
return v; return v;
} }
unsigned column(unsigned row, unsigned index) { unsigned column(unsigned row, unsigned index) {
return lp().get_row(row)[index].var(); return lp().get_row(row)[index].var();
} }
bool fixed_phase() const { return m_fixed_vertex; } bool fixed_phase() const { return m_fixed_vertex; }
// Returns the vertex to start exploration from, or nullptr. // Returns the vertex to start exploration from, or nullptr.
// It is assumed that parent->column() is present in the row // It is assumed that parent->column() is present in the row
vertex* get_child_from_row(unsigned row_index, vertex* parent) { vertex* get_child_from_row(unsigned row_index, vertex* parent) {
TRACE("cheap_eq_det", print_row(tout, row_index);); TRACE("cheap_eq_det", print_row(tout, row_index););
unsigned x, y; int row_polarity; unsigned x, y;
int row_polarity;
if (!is_tree_offset_row(row_index, x, y, row_polarity)) { if (!is_tree_offset_row(row_index, x, y, row_polarity)) {
TRACE("cheap_eq_det", tout << "not an offset row\n";); TRACE("cheap_eq_det", tout << "not an offset row\n";);
return nullptr; return nullptr;
@ -508,12 +504,10 @@ public:
is_int(k->column()) == is_int(v->column()) && is_int(k->column()) == is_int(v->column()) &&
!is_equal(k->column(), v->column())) { !is_equal(k->column(), v->column())) {
report_eq(k, v); report_eq(k, v);
} } else {
else {
TRACE("cheap_eq", tout << "no report\n";); TRACE("cheap_eq", tout << "no report\n";);
} }
} } else {
else {
TRACE("cheap_eq", tout << "registered: " << val(v) << " -> { "; print_vert(tout, v) << "} \n";); TRACE("cheap_eq", tout << "registered: " << val(v) << " -> { "; print_vert(tout, v) << "} \n";);
table.insert(val(v), v); table.insert(val(v), v);
} }
@ -557,12 +551,12 @@ public:
vector<edge> path = connect_in_tree(v_i, v_j); vector<edge> path = connect_in_tree(v_i, v_j);
lp::explanation exp = get_explanation_from_path(path); lp::explanation exp = get_explanation_from_path(path);
add_eq_on_columns(exp, v_i->column(), v_j->column(), false); add_eq_on_columns(exp, v_i->column(), v_j->column(), false);
} }
std::ostream& print_expl(std::ostream& out, const explanation& exp) const { std::ostream& print_expl(std::ostream& out, const explanation& exp) const {
for (auto p : exp) for (auto p : exp)
lp().constraints().display(out, [this](lpvar j) { return lp().get_variable_name(j);}, p.ci()); lp().constraints().display(
out, [this](lpvar j) { return lp().get_variable_name(j); }, p.ci());
return out; return out;
} }
@ -574,8 +568,7 @@ public:
tout << "reporting eq " << j << ", " << k << "\n"; tout << "reporting eq " << j << ", " << k << "\n";
tout << "reported idx " << je << ", " << ke << "\n"; tout << "reported idx " << je << ", " << ke << "\n";
print_expl(tout, exp); print_expl(tout, exp);
tout << "theory_vars v" << lp().local_to_external(je) << " == v" << lp().local_to_external(ke) << "\n"; tout << "theory_vars v" << lp().local_to_external(je) << " == v" << lp().local_to_external(ke) << "\n";);
);
bool added = m_imp.add_eq(je, ke, exp, is_fixed); bool added = m_imp.add_eq(je, ke, exp, is_fixed);
if (added) { if (added) {
@ -693,7 +686,6 @@ public:
try_add_equation_with_fixed_tables(row_index, e.target()); try_add_equation_with_fixed_tables(row_index, e.target());
} }
void cheap_eq_tree(unsigned row_index) { void cheap_eq_tree(unsigned row_index) {
reset_cheap_eq _reset(*this); reset_cheap_eq _reset(*this);
TRACE("cheap_eq_det", tout << "row_index = " << row_index << "\n";); TRACE("cheap_eq_det", tout << "row_index = " << row_index << "\n";);
@ -713,7 +705,8 @@ public:
} }
std::ostream& print_row(std::ostream& out, unsigned row_index) const { std::ostream& print_row(std::ostream& out, unsigned row_index) const {
unsigned x, y; int polarity; unsigned x, y;
int polarity;
if (true || !is_tree_offset_row(row_index, x, y, polarity)) if (true || !is_tree_offset_row(row_index, x, y, polarity))
return lp().get_int_solver()->display_row_info(out, row_index); return lp().get_int_solver()->display_row_info(out, row_index);
@ -724,8 +717,7 @@ public:
if (c.coeff().is_one()) { if (c.coeff().is_one()) {
if (!first) if (!first)
out << "+"; out << "+";
} } else if (c.coeff().is_minus_one())
else if (c.coeff().is_minus_one())
out << "-"; out << "-";
out << lp().get_variable_name(c.var()) << " "; out << lp().get_variable_name(c.var()) << " ";
first = false; first = false;
@ -764,6 +756,5 @@ public:
table.insert(j); table.insert(j);
return true; return true;
} }
}; };
} } // namespace lp

Some files were not shown because too many files have changed in this diff Show more