PySMT 0.9.7.dev426__tar.gz → 0.9.7.dev433__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pysmt-0.9.7.dev426/PySMT.egg-info → pysmt-0.9.7.dev433}/PKG-INFO +1 -1
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433/PySMT.egg-info}/PKG-INFO +1 -1
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/__init__.py +1 -1
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/fnode.py +5 -1
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/formula.py +38 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/operators.py +5 -2
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/oracles.py +6 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/parsing.py +2 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/printers.py +5 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/shortcuts.py +13 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/simplifier.py +10 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/smtlib/parser/parser.py +2 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/smtlib/printers.py +4 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/cvcfive.py +3 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/cvcfour.py +3 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/msat.py +7 -6
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/yices.py +5 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/z3.py +7 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/examples.py +27 -1
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_parser_examples.py +1 -0
- pysmt-0.9.7.dev433/pysmt/test/test_lira.py +141 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_printing.py +9 -1
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_regressions.py +34 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/type_checker.py +5 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/walkers/identitydag.py +3 -0
- pysmt-0.9.7.dev426/pysmt/test/test_lira.py +0 -65
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/LICENSE +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/MANIFEST.in +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/NOTICE +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/PySMT.egg-info/SOURCES.txt +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/PySMT.egg-info/dependency_links.txt +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/PySMT.egg-info/entry_points.txt +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/PySMT.egg-info/top_level.txt +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/README.rst +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/docs/CHANGES.rst +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/docs/api_ref.rst +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/docs/development.rst +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/docs/getting_started.rst +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/docs/index.rst +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/docs/tutorials/boolean_logic.rst +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/docs/tutorials.rst +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/__main__.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/cmd/__init__.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/cmd/check_version.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/cmd/install.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/cmd/installers/__init__.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/cmd/installers/base.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/cmd/installers/bdd.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/cmd/installers/btor.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/cmd/installers/cvcfive.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/cmd/installers/cvcfour.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/cmd/installers/msat.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/cmd/installers/optimsat.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/cmd/installers/pico.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/cmd/installers/yices.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/cmd/installers/z3.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/cmd/shell.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/configuration.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/constants.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/decorators.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/environment.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/exceptions.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/factory.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/logics.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/optimization/__init__.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/optimization/goal.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/optimization/msat.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/optimization/optimizer.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/optimization/optimsat.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/optimization/yices.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/optimization/z3.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/rewritings.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/smtlib/__init__.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/smtlib/annotations.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/smtlib/commands.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/smtlib/parser/__init__.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/smtlib/script.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/smtlib/solver.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/smtlib/utils.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/__init__.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/bdd.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/btor.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/dynmsat.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/eager.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/interpolation.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/options.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/pico.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/portfolio.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/qelim.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/smtlib.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/solver.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/substituter.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/__init__.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/configs/config1.ini +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/configs/config_bad.ini +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/omt_examples.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/optimization_utils.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/__init__.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/parser_utils.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_annotations.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_fuzzed.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_generic_wrapper.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_griggio.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_model_validation.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_omt_lib_solver.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_parser_extensibility.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_parser_lra.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_parser_omt.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_parser_qf_arrays.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_parser_qf_lia.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_parser_qf_lira.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_parser_qf_lra.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_parser_qf_nia.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_parser_qf_nra.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_parser_qf_uf.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_parser_qf_ufbv.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_parser_type_error.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_smtlibscript.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_array.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_back.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_bdd.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_bv.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_bv_simplification.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_cnf.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_configuration.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_constants.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_cvc_quantifiers.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_dwf.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_eager_model.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_env.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_euf.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_formula.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_hr_parsing.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_imports.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_int.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_interpolation.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_logics.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_models.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_native_qe.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_nia.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_nlira.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_optimization.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_optimizing.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_oracles.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_portfolio.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_qe.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_rewritings.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_shannon_expansion.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_simplify.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_size.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_solving.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_sorts.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_string.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_typechecker.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_unsat_cores.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_walker_ext.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_walkers.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/typing.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/utils.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/walkers/__init__.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/walkers/dag.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/walkers/generic.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/walkers/tree.py +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/setup.cfg +0 -0
- {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/setup.py +0 -0
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
from typing import Tuple, Union
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
VERSION: Union[Tuple[int, int, int], Tuple[int, int, int, str, int]] = (0, 9, 7, "dev",
|
|
22
|
+
VERSION: Union[Tuple[int, int, int], Tuple[int, int, int, str, int]] = (0, 9, 7, "dev", 433)
|
|
23
23
|
|
|
24
24
|
# Try to provide human-readable version of latest commit for dev versions
|
|
25
25
|
# E.g. v0.5.1-4-g49a49f2-wip
|
|
@@ -29,7 +29,7 @@ from pysmt.operators import (FORALL, EXISTS, AND, OR, NOT, IMPLIES, IFF,
|
|
|
29
29
|
PLUS, MINUS, TIMES, DIV,
|
|
30
30
|
LE, LT, EQUALS,
|
|
31
31
|
ITE,
|
|
32
|
-
TOREAL,
|
|
32
|
+
TOREAL, TOINT,
|
|
33
33
|
BV_CONSTANT, BV_NOT, BV_AND, BV_OR, BV_XOR,
|
|
34
34
|
BV_CONCAT, BV_EXTRACT,
|
|
35
35
|
BV_ULT, BV_ULE, BV_NEG, BV_ADD, BV_SUB,
|
|
@@ -256,6 +256,10 @@ class FNode(object):
|
|
|
256
256
|
"""Test whether the node is the ToReal operator."""
|
|
257
257
|
return self.node_type() == TOREAL
|
|
258
258
|
|
|
259
|
+
def is_toint(self) -> bool:
|
|
260
|
+
"""Test whether the node is the ToInt operator."""
|
|
261
|
+
return self.node_type() == TOINT
|
|
262
|
+
|
|
259
263
|
def is_forall(self) -> bool:
|
|
260
264
|
"""Test whether the node is the ForAll operator."""
|
|
261
265
|
return self.node_type() == FORALL
|
|
@@ -493,6 +493,44 @@ class FormulaManager(object):
|
|
|
493
493
|
raise PysmtTypeError("Argument is of type %s, but INT was "
|
|
494
494
|
"expected!\n" % t)
|
|
495
495
|
|
|
496
|
+
def ToInt(self, formula: FNode) -> FNode:
|
|
497
|
+
""" Cast a formula to integer type.
|
|
498
|
+
|
|
499
|
+
This is the SMT-LIB to_int function, i.e. the floor: it rounds
|
|
500
|
+
towards minus infinity, hence ToInt(-3/2) is -2 and not -1.
|
|
501
|
+
"""
|
|
502
|
+
t = self.env.stc.get_type(formula)
|
|
503
|
+
if t == types.INT:
|
|
504
|
+
# Ignore casting of an Int
|
|
505
|
+
return formula
|
|
506
|
+
elif t == types.REAL:
|
|
507
|
+
if formula.is_real_constant():
|
|
508
|
+
value = cast(fractions.Fraction, formula.constant_value())
|
|
509
|
+
# Floor division on the numerator/denominator, so that this
|
|
510
|
+
# also works for the gmpy2 mpq backend (see pysmt.constants)
|
|
511
|
+
return self.Int(value.numerator // value.denominator)
|
|
512
|
+
return self.create_node(node_type=op.TOINT,
|
|
513
|
+
args=(formula,))
|
|
514
|
+
else:
|
|
515
|
+
raise PysmtTypeError("Argument is of type %s, but REAL was "
|
|
516
|
+
"expected!\n" % t)
|
|
517
|
+
|
|
518
|
+
def IsInt(self, formula: FNode) -> FNode:
|
|
519
|
+
""" Returns whether the given real formula has an integer value.
|
|
520
|
+
|
|
521
|
+
This is the SMT-LIB is_int predicate, expanded into its SMT-LIB
|
|
522
|
+
definition: (is_int t) is (= t (to_real (to_int t))).
|
|
523
|
+
"""
|
|
524
|
+
t = self.env.stc.get_type(formula)
|
|
525
|
+
if t == types.INT:
|
|
526
|
+
# An Int is always an integer
|
|
527
|
+
return self.TRUE()
|
|
528
|
+
elif t == types.REAL:
|
|
529
|
+
return self.Equals(formula, self.ToReal(self.ToInt(formula)))
|
|
530
|
+
else:
|
|
531
|
+
raise PysmtTypeError("Argument is of type %s, but REAL was "
|
|
532
|
+
"expected!\n" % t)
|
|
533
|
+
|
|
496
534
|
def AtMostOne(self, *args: Union[FNode, Iterable[FNode]]) -> FNode:
|
|
497
535
|
""" At most one of the bool expressions can be true at anytime.
|
|
498
536
|
|
|
@@ -25,7 +25,7 @@ from itertools import chain
|
|
|
25
25
|
from typing import List
|
|
26
26
|
|
|
27
27
|
|
|
28
|
-
ALL_TYPES = list(range(0,
|
|
28
|
+
ALL_TYPES = list(range(0,67))
|
|
29
29
|
|
|
30
30
|
(
|
|
31
31
|
FORALL, EXISTS, AND, OR, NOT, IMPLIES, IFF, # Boolean Logic (0-6)
|
|
@@ -79,6 +79,7 @@ DIV, # Arithmetic Division (62)
|
|
|
79
79
|
POW, # Arithmetic Power (63)
|
|
80
80
|
ALGEBRAIC_CONSTANT, # Algebraic Number (64)
|
|
81
81
|
BV_TONATURAL, # BV to Natural Conversion (65)
|
|
82
|
+
TOINT, # LIRA to_int() function, i.e. floor (66)
|
|
82
83
|
) = ALL_TYPES
|
|
83
84
|
|
|
84
85
|
QUANTIFIERS = frozenset([FORALL, EXISTS])
|
|
@@ -110,7 +111,8 @@ BV_OPERATORS = frozenset([BV_NOT, BV_AND, BV_OR, BV_XOR,
|
|
|
110
111
|
STR_OPERATORS = frozenset([STR_LENGTH, STR_CONCAT, STR_INDEXOF, STR_REPLACE,
|
|
111
112
|
STR_SUBSTR, STR_CHARAT, STR_TO_INT, INT_TO_STR,])
|
|
112
113
|
|
|
113
|
-
IRA_OPERATORS = frozenset([PLUS, MINUS, TIMES, TOREAL, DIV, POW,
|
|
114
|
+
IRA_OPERATORS = frozenset([PLUS, MINUS, TIMES, TOREAL, TOINT, DIV, POW,
|
|
115
|
+
BV_TONATURAL])
|
|
114
116
|
|
|
115
117
|
ARRAY_OPERATORS = frozenset([ARRAY_SELECT, ARRAY_STORE, ARRAY_VALUE])
|
|
116
118
|
|
|
@@ -178,6 +180,7 @@ __OP_STR__ = {
|
|
|
178
180
|
EQUALS : "EQUALS",
|
|
179
181
|
ITE : "ITE",
|
|
180
182
|
TOREAL : "TOREAL",
|
|
183
|
+
TOINT : "TOINT",
|
|
181
184
|
BV_CONSTANT : "BV_CONSTANT",
|
|
182
185
|
BV_NOT : "BV_NOT",
|
|
183
186
|
BV_AND : "BV_AND",
|
|
@@ -246,6 +246,12 @@ class TheoryOracle(walkers.DagWalker):
|
|
|
246
246
|
"""Extends the Theory with LIRA."""
|
|
247
247
|
theory_out = args[0].set_lira() # This makes a copy of args[0]
|
|
248
248
|
return theory_out
|
|
249
|
+
|
|
250
|
+
def walk_toint(self, formula: FNode, args: List[Theory], **kwargs) -> Theory:
|
|
251
|
+
#pylint: disable=unused-argument
|
|
252
|
+
"""Extends the Theory with LIRA."""
|
|
253
|
+
theory_out = args[0].set_lira() # This makes a copy of args[0]
|
|
254
|
+
return theory_out
|
|
249
255
|
rtype = formula.symbol_name()
|
|
250
256
|
|
|
251
257
|
@walkers.handles([op.STR_LENGTH, op.STR_INDEXOF, op.STR_TO_INT])
|
|
@@ -199,6 +199,8 @@ class HRLexer(Lexer):
|
|
|
199
199
|
"ZEXT": InfixOpAdapter(self.BVHack(self.mgr.BVZExt), 90),# BVZext
|
|
200
200
|
"SEXT": InfixOpAdapter(self.BVHack(self.mgr.BVSExt), 90),# BVSext
|
|
201
201
|
"ToReal": UnaryOpAdapter(self.mgr.ToReal, 100),#
|
|
202
|
+
"ToInt": UnaryOpAdapter(self.mgr.ToInt, 100),#
|
|
203
|
+
"IsInt": UnaryOpAdapter(self.mgr.IsInt, 100),#
|
|
202
204
|
"Int": IntTypeTok(),# Int Type
|
|
203
205
|
"Real": RealTypeTok(),# Real Type
|
|
204
206
|
"Bool": BoolTypeTok(),# Bool Type
|
|
@@ -177,6 +177,11 @@ class HRPrinter(TreeWalker):
|
|
|
177
177
|
yield formula.arg(0)
|
|
178
178
|
self.write(")")
|
|
179
179
|
|
|
180
|
+
def walk_toint(self, formula: FNode) -> Iterator[FNode]:
|
|
181
|
+
self.write("ToInt(")
|
|
182
|
+
yield formula.arg(0)
|
|
183
|
+
self.write(")")
|
|
184
|
+
|
|
180
185
|
def walk_str_constant(self, formula: FNode):
|
|
181
186
|
formula_value = formula.constant_value()
|
|
182
187
|
assert isinstance(formula_value, str), \
|
|
@@ -361,6 +361,19 @@ def ToReal(formula: FNode) -> FNode:
|
|
|
361
361
|
return get_env().formula_manager.ToReal(formula)
|
|
362
362
|
|
|
363
363
|
|
|
364
|
+
def ToInt(formula: FNode) -> FNode:
|
|
365
|
+
"""Explicit cast of a term into an Int term.
|
|
366
|
+
|
|
367
|
+
This is the SMT-LIB to_int function, i.e. the floor.
|
|
368
|
+
"""
|
|
369
|
+
return get_env().formula_manager.ToInt(formula)
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
def IsInt(formula: FNode) -> FNode:
|
|
373
|
+
"""Returns whether the given real term has an integer value."""
|
|
374
|
+
return get_env().formula_manager.IsInt(formula)
|
|
375
|
+
|
|
376
|
+
|
|
364
377
|
def AtMostOne(*args: Union[FNode, Iterable[FNode]]) -> FNode:
|
|
365
378
|
"""At most one can be true at anytime.
|
|
366
379
|
|
|
@@ -463,6 +463,16 @@ class Simplifier(pysmt.walkers.DagWalker):
|
|
|
463
463
|
return self.manager.Real(cast(int, args[0].constant_value()))
|
|
464
464
|
return self.manager.ToReal(args[0])
|
|
465
465
|
|
|
466
|
+
def walk_toint(self, formula: FNode, args: List[FNode], **kwargs) -> FNode:
|
|
467
|
+
assert len(args) == 1
|
|
468
|
+
if args[0].is_toreal():
|
|
469
|
+
# to_int(to_real(x)) is x, since x is an integer.
|
|
470
|
+
# Note that the converse does not hold: to_real(to_int(y)) is
|
|
471
|
+
# y only when y happens to have an integer value.
|
|
472
|
+
return args[0].arg(0)
|
|
473
|
+
# Folding of real constants is done by the FormulaManager
|
|
474
|
+
return self.manager.ToInt(args[0])
|
|
475
|
+
|
|
466
476
|
def walk_bv_and(self, formula: FNode, args: List[FNode], **kwargs) -> FNode:
|
|
467
477
|
simplified = None
|
|
468
478
|
width = formula.bv_width()
|
|
@@ -392,6 +392,8 @@ class SmtLibParser(object):
|
|
|
392
392
|
'ite': self._operator_adapter(self.Ite),
|
|
393
393
|
'distinct': self._operator_adapter(self.AllDifferent),
|
|
394
394
|
'to_real': self._operator_adapter(mgr.ToReal),
|
|
395
|
+
'to_int': self._operator_adapter(mgr.ToInt),
|
|
396
|
+
'is_int': self._operator_adapter(mgr.IsInt),
|
|
395
397
|
'concat': self._operator_adapter(mgr.BVConcat),
|
|
396
398
|
'bvnot': self._operator_adapter(mgr.BVNot),
|
|
397
399
|
'bvand': self._operator_adapter(mgr.BVAnd),
|
|
@@ -94,6 +94,7 @@ class SmtPrinter(TreeWalker):
|
|
|
94
94
|
def walk_lt(self, formula): return self.walk_nary(formula, "<")
|
|
95
95
|
def walk_ite(self, formula): return self.walk_nary(formula, "ite")
|
|
96
96
|
def walk_toreal(self, formula): return self.walk_nary(formula, "to_real")
|
|
97
|
+
def walk_toint(self, formula): return self.walk_nary(formula, "to_int")
|
|
97
98
|
def walk_div(self, formula): return self.walk_nary(formula, "/")
|
|
98
99
|
def walk_pow(self, formula): return self.walk_nary(formula, "pow")
|
|
99
100
|
def walk_bv_and(self, formula): return self.walk_nary(formula, "bvand")
|
|
@@ -422,6 +423,9 @@ class SmtDagPrinter(DagWalker):
|
|
|
422
423
|
def walk_toreal(self, formula: FNode, args: List[str]) -> str:
|
|
423
424
|
return self.walk_nary(formula, args, "to_real")
|
|
424
425
|
|
|
426
|
+
def walk_toint(self, formula: FNode, args: List[str]) -> str:
|
|
427
|
+
return self.walk_nary(formula, args, "to_int")
|
|
428
|
+
|
|
425
429
|
def walk_div(self, formula: FNode, args: List[str]) -> str:
|
|
426
430
|
return self.walk_nary(formula, args, "/")
|
|
427
431
|
|
|
@@ -394,6 +394,9 @@ class CVC5Converter(Converter, DagWalker):
|
|
|
394
394
|
def walk_toreal(self, formula, args, **kwargs):
|
|
395
395
|
return self.cvc5_solver.mkTerm(Kind.TO_REAL, args[0])
|
|
396
396
|
|
|
397
|
+
def walk_toint(self, formula, args, **kwargs):
|
|
398
|
+
return self.cvc5_solver.mkTerm(Kind.TO_INTEGER, args[0])
|
|
399
|
+
|
|
397
400
|
def walk_function(self, formula, args, **kwargs):
|
|
398
401
|
name = formula.function_name()
|
|
399
402
|
if name not in self.declared_vars:
|
|
@@ -351,6 +351,9 @@ class CVC4Converter(Converter, DagWalker):
|
|
|
351
351
|
def walk_toreal(self, formula, args, **kwargs):
|
|
352
352
|
return self.mkExpr(CVC4.TO_REAL, args[0])
|
|
353
353
|
|
|
354
|
+
def walk_toint(self, formula, args, **kwargs):
|
|
355
|
+
return self.mkExpr(CVC4.TO_INTEGER, args[0])
|
|
356
|
+
|
|
354
357
|
def walk_function(self, formula, args, **kwargs):
|
|
355
358
|
name = formula.function_name()
|
|
356
359
|
if name not in self.declared_vars:
|
|
@@ -322,7 +322,7 @@ class MathSAT5Solver(IncrementalTrackingSolver, UnsatCoreSolver, SmtLibBasicSolv
|
|
|
322
322
|
def all_sat(self, important, callback):
|
|
323
323
|
self.push()
|
|
324
324
|
self._msat_lib.msat_all_sat(self.msat_env(),
|
|
325
|
-
[self.
|
|
325
|
+
[self.converter.convert(x) for x in important],
|
|
326
326
|
callback)
|
|
327
327
|
self.pop()
|
|
328
328
|
|
|
@@ -336,11 +336,6 @@ class MathSAT5Solver(IncrementalTrackingSolver, UnsatCoreSolver, SmtLibBasicSolv
|
|
|
336
336
|
for _ in range(levels):
|
|
337
337
|
self._msat_lib.msat_pop_backtrack_point(self.msat_env())
|
|
338
338
|
|
|
339
|
-
def _var2term(self, var):
|
|
340
|
-
decl = self._msat_lib.msat_find_decl(self.msat_env(), var.symbol_name())
|
|
341
|
-
titem = self._msat_lib.msat_make_term(self.msat_env(), decl, [])
|
|
342
|
-
return titem
|
|
343
|
-
|
|
344
339
|
def set_preferred_var(self, var, val=None):
|
|
345
340
|
tvar = self.converter.convert(var)
|
|
346
341
|
mval = self._msat_lib.MSAT_UNDEF
|
|
@@ -432,6 +427,7 @@ class MSatConverter(Converter, DagWalker):
|
|
|
432
427
|
self._msat_lib.MSAT_TAG_BV_LSHR: self._back_adapter(self.mgr.BVLShr),
|
|
433
428
|
self._msat_lib.MSAT_TAG_BV_ASHR: self._back_adapter(self.mgr.BVAShr),
|
|
434
429
|
self._msat_lib.MSAT_TAG_BV_COMP: self._back_adapter(self.mgr.BVComp),
|
|
430
|
+
self._msat_lib.MSAT_TAG_FLOOR: self._back_adapter(self.mgr.ToInt),
|
|
435
431
|
self._msat_lib.MSAT_TAG_INT_FROM_UBV: self._back_adapter(self.mgr.BVToNatural),
|
|
436
432
|
self._msat_lib.MSAT_TAG_ARRAY_READ: self._back_adapter(self.mgr.Select),
|
|
437
433
|
self._msat_lib.MSAT_TAG_ARRAY_WRITE: self._back_adapter(self.mgr.Store),
|
|
@@ -466,6 +462,8 @@ class MSatConverter(Converter, DagWalker):
|
|
|
466
462
|
self._msat_lib.MSAT_TAG_LEQ: self._sig_most_generic_bool_binary,
|
|
467
463
|
self._msat_lib.MSAT_TAG_PLUS: self._sig_most_generic_bool_binary,
|
|
468
464
|
self._msat_lib.MSAT_TAG_TIMES: self._sig_most_generic_bool_binary,
|
|
465
|
+
self._msat_lib.MSAT_TAG_FLOOR: lambda term, args:\
|
|
466
|
+
types.FunctionType(types.INT, [types.REAL]),
|
|
469
467
|
self._msat_lib.MSAT_TAG_BV_MUL: self._sig_binary,
|
|
470
468
|
self._msat_lib.MSAT_TAG_BV_ADD: self._sig_binary,
|
|
471
469
|
self._msat_lib.MSAT_TAG_BV_UDIV:self._sig_binary,
|
|
@@ -1009,6 +1007,9 @@ class MSatConverter(Converter, DagWalker):
|
|
|
1009
1007
|
# In mathsat toreal is implicit
|
|
1010
1008
|
return args[0]
|
|
1011
1009
|
|
|
1010
|
+
def walk_toint(self, formula: FNode, args: List[Any], **kwargs) -> Any:
|
|
1011
|
+
return self._msat_lib.msat_make_floor(self.msat_env(), args[0])
|
|
1012
|
+
|
|
1012
1013
|
def walk_bv_tonatural(self, formula: FNode, args: List[Any], **kwargs) -> Any:
|
|
1013
1014
|
return self._msat_lib.msat_make_int_from_ubv(self.msat_env(), args[0])
|
|
1014
1015
|
|
|
@@ -470,6 +470,11 @@ class YicesConverter(Converter, DagWalker):
|
|
|
470
470
|
def walk_toreal(self, formula: FNode, args, **kwargs):
|
|
471
471
|
return args[0]
|
|
472
472
|
|
|
473
|
+
def walk_toint(self, formula: FNode, args, **kwargs):
|
|
474
|
+
res = yices_api.yices_floor(args[0])
|
|
475
|
+
self._check_term_result(res)
|
|
476
|
+
return res
|
|
477
|
+
|
|
473
478
|
def walk_function(self, formula: FNode, args, **kwargs):
|
|
474
479
|
name = formula.function_name()
|
|
475
480
|
if name not in self.symbol_to_decl:
|
|
@@ -340,6 +340,8 @@ class Z3Converter(Converter, DagWalker):
|
|
|
340
340
|
z3.Z3_OP_IMPLIES: lambda args, expr: self.mgr.Implies(args[0], args[1]),
|
|
341
341
|
z3.Z3_OP_ITE: lambda args, expr: self.mgr.Ite(args[0], args[1], args[2]),
|
|
342
342
|
z3.Z3_OP_TO_REAL: lambda args, expr: self.mgr.ToReal(args[0]),
|
|
343
|
+
z3.Z3_OP_TO_INT: lambda args, expr: self.mgr.ToInt(args[0]),
|
|
344
|
+
z3.Z3_OP_IS_INT: lambda args, expr: self.mgr.IsInt(args[0]),
|
|
343
345
|
z3.Z3_OP_BAND : lambda args, expr: self.mgr.BVAnd(args),
|
|
344
346
|
z3.Z3_OP_BOR : lambda args, expr: self.mgr.BVOr(args),
|
|
345
347
|
z3.Z3_OP_BXOR : lambda args, expr: self.mgr.BVXor(args[0], args[1]),
|
|
@@ -737,6 +739,11 @@ class Z3Converter(Converter, DagWalker):
|
|
|
737
739
|
z3.Z3_inc_ref(self.ctx.ref(), z3term)
|
|
738
740
|
return z3term
|
|
739
741
|
|
|
742
|
+
def walk_toint(self, formula, args, **kwargs):
|
|
743
|
+
z3term = z3.Z3_mk_real2int(self.ctx.ref(), args[0])
|
|
744
|
+
z3.Z3_inc_ref(self.ctx.ref(), z3term)
|
|
745
|
+
return z3term
|
|
746
|
+
|
|
740
747
|
def _z3_func_decl(self, func_name):
|
|
741
748
|
"""Create a Z3 Function Declaration for the given function."""
|
|
742
749
|
try:
|
|
@@ -23,7 +23,7 @@ from pysmt.shortcuts import (Symbol, Function,
|
|
|
23
23
|
Int, Real, FALSE, TRUE,
|
|
24
24
|
And, Iff, Or, Not, Implies, Ite,
|
|
25
25
|
LT, LE, GT, GE,
|
|
26
|
-
Times, Pow, Equals, Plus, Minus, Div, ToReal,
|
|
26
|
+
Times, Pow, Equals, Plus, Minus, Div, ToReal, ToInt,
|
|
27
27
|
ForAll, Exists,
|
|
28
28
|
BV, SBV, BVOne, BVZero,
|
|
29
29
|
BVNot, BVAnd, BVOr, BVXor,
|
|
@@ -698,6 +698,32 @@ def get_full_example_formulae(environment: Optional[Environment]=None) -> List[E
|
|
|
698
698
|
is_sat=False,
|
|
699
699
|
logic=pysmt.logics.QF_UFLIRA
|
|
700
700
|
),
|
|
701
|
+
|
|
702
|
+
# ToInt is the floor, hence it rounds towards minus infinity
|
|
703
|
+
Example(hr="((r = -3/2) -> (ToInt(r) = -2))",
|
|
704
|
+
expr=Implies(Equals(r, Real(Fraction(-3, 2))),
|
|
705
|
+
Equals(ToInt(r), Int(-2))),
|
|
706
|
+
is_valid=True,
|
|
707
|
+
is_sat=True,
|
|
708
|
+
logic=pysmt.logics.QF_LIRA
|
|
709
|
+
),
|
|
710
|
+
|
|
711
|
+
# ToInt must not truncate towards zero
|
|
712
|
+
Example(hr="((r = -3/2) & (ToInt(r) = -1))",
|
|
713
|
+
expr=And(Equals(r, Real(Fraction(-3, 2))),
|
|
714
|
+
Equals(ToInt(r), Int(-1))),
|
|
715
|
+
is_valid=False,
|
|
716
|
+
is_sat=False,
|
|
717
|
+
logic=pysmt.logics.QF_LIRA
|
|
718
|
+
),
|
|
719
|
+
|
|
720
|
+
Example(hr="((ToInt(r) = p) & (0.0 < r))",
|
|
721
|
+
expr=And(Equals(ToInt(r), p),
|
|
722
|
+
GT(r, Real(0))),
|
|
723
|
+
is_valid=False,
|
|
724
|
+
is_sat=True,
|
|
725
|
+
logic=pysmt.logics.QF_LIRA
|
|
726
|
+
),
|
|
701
727
|
#
|
|
702
728
|
# STR
|
|
703
729
|
#
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
#
|
|
2
|
+
# This file is part of pySMT.
|
|
3
|
+
#
|
|
4
|
+
# Copyright 2014 Andrea Micheli and Marco Gario
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
#
|
|
18
|
+
from pysmt.shortcuts import *
|
|
19
|
+
from pysmt.constants import Fraction
|
|
20
|
+
from pysmt.exceptions import PysmtTypeError
|
|
21
|
+
from pysmt.typing import INT, REAL, FunctionType
|
|
22
|
+
from pysmt.test import TestCase, main
|
|
23
|
+
from pysmt.logics import QF_LIRA, QF_UFLIRA, UFLIRA
|
|
24
|
+
|
|
25
|
+
class TestLIRA(TestCase):
|
|
26
|
+
|
|
27
|
+
def test_lira(self):
|
|
28
|
+
a = Symbol("a", REAL)
|
|
29
|
+
b = Symbol("b", INT)
|
|
30
|
+
|
|
31
|
+
check = And(Equals(a, Real(3)), Equals(a, ToReal(b)))
|
|
32
|
+
for sname in get_env().factory.all_solvers(logic=QF_UFLIRA):
|
|
33
|
+
with Solver(name=sname) as s:
|
|
34
|
+
s.add_assertion(check)
|
|
35
|
+
c = s.solve()
|
|
36
|
+
self.assertTrue(c)
|
|
37
|
+
self.assertEqual(s.get_value(b), Int(3))
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_toreal(self):
|
|
41
|
+
a = Symbol("a", REAL)
|
|
42
|
+
b = Symbol("b", INT)
|
|
43
|
+
|
|
44
|
+
self.assertEqual(a, ToReal(a))
|
|
45
|
+
self.assertEqual(Plus(a, Real(1)), ToReal(Plus(a, Real(1))))
|
|
46
|
+
|
|
47
|
+
self.assertEqual(ToReal(b), ToReal(ToReal(b)))
|
|
48
|
+
self.assertEqual(ToReal(Plus(b, Int(1))),
|
|
49
|
+
ToReal(ToReal(Plus(b, Int(1)))))
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def test_toint_is_floor(self):
|
|
53
|
+
# to_int rounds towards minus infinity, it does not truncate
|
|
54
|
+
self.assertEqual(ToInt(Real(Fraction(-3, 2))), Int(-2))
|
|
55
|
+
self.assertEqual(ToInt(Real(Fraction(3, 2))), Int(1))
|
|
56
|
+
self.assertEqual(ToInt(Real(Fraction(-1, 3))), Int(-1))
|
|
57
|
+
self.assertEqual(ToInt(Real(0)), Int(0))
|
|
58
|
+
self.assertEqual(ToInt(Real(-2)), Int(-2))
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def test_toint(self):
|
|
62
|
+
a = Symbol("a", REAL)
|
|
63
|
+
b = Symbol("b", INT)
|
|
64
|
+
|
|
65
|
+
# Casting an Int is a no-op
|
|
66
|
+
self.assertEqual(b, ToInt(b))
|
|
67
|
+
self.assertEqual(Plus(b, Int(1)), ToInt(Plus(b, Int(1))))
|
|
68
|
+
|
|
69
|
+
self.assertTrue(ToInt(a).is_toint())
|
|
70
|
+
self.assertEqual(get_type(ToInt(a)), INT)
|
|
71
|
+
|
|
72
|
+
for bad in (TRUE(), Symbol("x"), BV(1, 8)):
|
|
73
|
+
with self.assertRaises(PysmtTypeError):
|
|
74
|
+
ToInt(bad)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def test_toint_simplify(self):
|
|
78
|
+
a = Symbol("a", REAL)
|
|
79
|
+
b = Symbol("b", INT)
|
|
80
|
+
|
|
81
|
+
# to_int(to_real(b)) is b, since b is an integer
|
|
82
|
+
self.assertEqual(b, ToInt(ToReal(b)).simplify())
|
|
83
|
+
self.assertEqual(Plus(b, Int(1)),
|
|
84
|
+
ToInt(ToReal(Plus(b, Int(1)))).simplify())
|
|
85
|
+
|
|
86
|
+
# The converse does NOT hold: to_real(to_int(a)) is a only when a
|
|
87
|
+
# happens to have an integer value.
|
|
88
|
+
self.assertNotEqual(a, ToReal(ToInt(a)).simplify())
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def test_isint(self):
|
|
92
|
+
a = Symbol("a", REAL)
|
|
93
|
+
b = Symbol("b", INT)
|
|
94
|
+
|
|
95
|
+
# is_int is expanded into its SMT-LIB definition
|
|
96
|
+
self.assertEqual(IsInt(a), Equals(a, ToReal(ToInt(a))))
|
|
97
|
+
# An Int is trivially an integer
|
|
98
|
+
self.assertEqual(IsInt(b), TRUE())
|
|
99
|
+
|
|
100
|
+
with self.assertRaises(PysmtTypeError):
|
|
101
|
+
IsInt(TRUE())
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def test_toint_solving(self):
|
|
105
|
+
a = Symbol("a", REAL)
|
|
106
|
+
|
|
107
|
+
for sname in get_env().factory.all_solvers(logic=QF_LIRA):
|
|
108
|
+
# 7/2 floors to 3
|
|
109
|
+
self.assertSat(And(Equals(a, Real(Fraction(7, 2))),
|
|
110
|
+
Equals(ToInt(a), Int(3))),
|
|
111
|
+
solver_name=sname)
|
|
112
|
+
# -3/2 floors to -2, and in particular not to -1
|
|
113
|
+
self.assertSat(And(Equals(a, Real(Fraction(-3, 2))),
|
|
114
|
+
Equals(ToInt(a), Int(-2))),
|
|
115
|
+
solver_name=sname)
|
|
116
|
+
self.assertUnsat(And(Equals(a, Real(Fraction(-3, 2))),
|
|
117
|
+
Equals(ToInt(a), Int(-1))),
|
|
118
|
+
solver_name=sname)
|
|
119
|
+
# 1/2 is not an integer
|
|
120
|
+
self.assertUnsat(And(IsInt(a), Equals(a, Real(Fraction(1, 2)))),
|
|
121
|
+
solver_name=sname)
|
|
122
|
+
self.assertSat(And(IsInt(a), Equals(a, Real(Fraction(4, 2)))),
|
|
123
|
+
solver_name=sname)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def test_uflira(self):
|
|
127
|
+
a = Symbol("a", REAL)
|
|
128
|
+
b = Symbol("b", INT)
|
|
129
|
+
h = Symbol("ih", FunctionType(REAL, [REAL, INT]))
|
|
130
|
+
|
|
131
|
+
# ( ToReal(b) = a /\ h(ToReal(b), b) >= 3) -> (h(a,b) >= 0)
|
|
132
|
+
check = Implies(And(Equals(ToReal(b), a),
|
|
133
|
+
GE(Function(h, (ToReal(b), b)), Real(3))),
|
|
134
|
+
GE(Function(h, (a, b)), Real(0)))
|
|
135
|
+
|
|
136
|
+
for sname in get_env().factory.all_solvers(logic=UFLIRA):
|
|
137
|
+
self.assertValid(check, solver_name=sname)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
if __name__ == '__main__':
|
|
141
|
+
main()
|
|
@@ -20,7 +20,7 @@ from io import StringIO
|
|
|
20
20
|
from pysmt.shortcuts import Or, And, Not, Plus, Iff, Implies
|
|
21
21
|
from pysmt.shortcuts import Exists, ForAll, Ite, ExactlyOne
|
|
22
22
|
from pysmt.shortcuts import Bool, Real, Int, Symbol, Function
|
|
23
|
-
from pysmt.shortcuts import Times, Minus, Equals, LE, LT, ToReal, FreshSymbol
|
|
23
|
+
from pysmt.shortcuts import Times, Minus, Equals, LE, LT, ToReal, ToInt, FreshSymbol
|
|
24
24
|
from pysmt.typing import REAL, INT, FunctionType
|
|
25
25
|
from pysmt.smtlib.printers import SmtPrinter, SmtDagPrinter
|
|
26
26
|
from pysmt.smtlib.annotations import Annotations
|
|
@@ -139,6 +139,14 @@ class TestPrinting(TestCase):
|
|
|
139
139
|
self.assertEqual(rp.to_smtlib(daggify=False), "(to_real p)")
|
|
140
140
|
self.assertEqual(rp.to_smtlib(daggify=True), "(let ((.def_0 (to_real p))) .def_0)")
|
|
141
141
|
|
|
142
|
+
def test_toint(self):
|
|
143
|
+
r = Symbol("r", REAL)
|
|
144
|
+
ir = ToInt(r)
|
|
145
|
+
|
|
146
|
+
self.assertEqual(ir.to_smtlib(daggify=False), "(to_int r)")
|
|
147
|
+
self.assertEqual(ir.to_smtlib(daggify=True), "(let ((.def_0 (to_int r))) .def_0)")
|
|
148
|
+
self.assertEqual(ir.serialize(), "ToInt(r)")
|
|
149
|
+
|
|
142
150
|
def test_threshold_printing(self):
|
|
143
151
|
x = Symbol("x")
|
|
144
152
|
f = And(x,x)
|
|
@@ -574,6 +574,40 @@ class TestRegressions(TestCase):
|
|
|
574
574
|
s.add_assertion(f)
|
|
575
575
|
self.assertFalse(s.solve())
|
|
576
576
|
|
|
577
|
+
@skipIfSolverNotAvailable("msat")
|
|
578
|
+
def test_msat_all_sat_theory_atoms(self):
|
|
579
|
+
# Regression test: MathSAT5Solver.all_sat must accept arbitrary
|
|
580
|
+
# SMT-atoms as "important" terms, not only Boolean symbols.
|
|
581
|
+
# Previously the "important" terms were converted with a helper
|
|
582
|
+
# (_var2term) that assumed each term was a declared symbol, so
|
|
583
|
+
# passing a theory atom raised an AssertionError.
|
|
584
|
+
x = Symbol("x", INT)
|
|
585
|
+
f = And(LE(Int(0), x), LE(x, Int(5)))
|
|
586
|
+
atom = LE(x, Int(2)) # a theory atom, not a Boolean symbol
|
|
587
|
+
|
|
588
|
+
result = []
|
|
589
|
+
|
|
590
|
+
def callback(model, converter, res):
|
|
591
|
+
res.append(And(converter.back(v) for v in model))
|
|
592
|
+
return 1 # continue enumeration
|
|
593
|
+
|
|
594
|
+
with Solver(name="msat",
|
|
595
|
+
solver_options={
|
|
596
|
+
"dpll.allsat_minimize_model": "false",
|
|
597
|
+
"dpll.allsat_allow_duplicates": "false",
|
|
598
|
+
"preprocessor.toplevel_propagation": "false",
|
|
599
|
+
"preprocessor.simplification": "0",
|
|
600
|
+
}) as msat:
|
|
601
|
+
msat.add_assertion(f)
|
|
602
|
+
# This call used to raise AssertionError on a theory atom.
|
|
603
|
+
msat.all_sat([atom], lambda m: callback(m, msat.converter, result))
|
|
604
|
+
|
|
605
|
+
# The atom can be both true (x in [0,2]) and false (x in [3,5]),
|
|
606
|
+
# so we expect exactly the two disjoint total assignments.
|
|
607
|
+
self.assertEqual(len(result), 2, result)
|
|
608
|
+
self.assertIn(atom, result)
|
|
609
|
+
self.assertIn(Not(atom), result)
|
|
610
|
+
|
|
577
611
|
|
|
578
612
|
if __name__ == "__main__":
|
|
579
613
|
main()
|
|
@@ -79,6 +79,11 @@ class SimpleTypeChecker(walkers.DagWalker):
|
|
|
79
79
|
#pylint: disable=unused-argument
|
|
80
80
|
return self.walk_type_to_type(formula, args, INT, REAL)
|
|
81
81
|
|
|
82
|
+
@walkers.handles(op.TOINT)
|
|
83
|
+
def walk_real_to_int(self, formula: FNode, args: List[PySMTType], **kwargs) -> Optional[PySMTType]:
|
|
84
|
+
#pylint: disable=unused-argument
|
|
85
|
+
return self.walk_type_to_type(formula, args, REAL, INT)
|
|
86
|
+
|
|
82
87
|
def walk_real_to_real(self, formula: FNode, args: List[PySMTType], **kwargs) -> Optional[PySMTType]:
|
|
83
88
|
#pylint: disable=unused-argument
|
|
84
89
|
return self.walk_type_to_type(formula, args, REAL, REAL)
|
|
@@ -114,6 +114,9 @@ class IdentityDagWalker(DagWalker):
|
|
|
114
114
|
def walk_toreal(self, formula: FNode, args: List[FNode], **kwargs) -> FNode:
|
|
115
115
|
return self.mgr.ToReal(args[0])
|
|
116
116
|
|
|
117
|
+
def walk_toint(self, formula: FNode, args: List[FNode], **kwargs) -> FNode:
|
|
118
|
+
return self.mgr.ToInt(args[0])
|
|
119
|
+
|
|
117
120
|
def walk_bv_constant(self, formula: FNode, **kwargs) -> FNode:
|
|
118
121
|
return self.mgr.BV(cast(int, formula.constant_value()), formula.bv_width())
|
|
119
122
|
|