PySMT 0.9.7.dev431__tar.gz → 0.9.7.dev436__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.dev431/PySMT.egg-info → pysmt-0.9.7.dev436}/PKG-INFO +1 -1
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436/PySMT.egg-info}/PKG-INFO +1 -1
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/__init__.py +1 -1
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/fnode.py +5 -1
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/formula.py +38 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/operators.py +5 -2
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/oracles.py +6 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/parsing.py +2 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/printers.py +5 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/shortcuts.py +13 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/simplifier.py +10 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/smtlib/parser/parser.py +55 -15
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/smtlib/printers.py +4 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/solvers/cvcfive.py +3 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/solvers/cvcfour.py +3 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/solvers/msat.py +6 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/solvers/yices.py +5 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/solvers/z3.py +7 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/examples.py +27 -1
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/smtlib/test_parser_examples.py +129 -1
- pysmt-0.9.7.dev436/pysmt/test/test_lira.py +141 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_printing.py +9 -1
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/type_checker.py +5 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/walkers/identitydag.py +3 -0
- pysmt-0.9.7.dev431/pysmt/test/test_lira.py +0 -65
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/LICENSE +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/MANIFEST.in +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/NOTICE +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/PySMT.egg-info/SOURCES.txt +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/PySMT.egg-info/dependency_links.txt +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/PySMT.egg-info/entry_points.txt +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/PySMT.egg-info/top_level.txt +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/README.rst +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/docs/CHANGES.rst +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/docs/api_ref.rst +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/docs/development.rst +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/docs/getting_started.rst +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/docs/index.rst +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/docs/tutorials/boolean_logic.rst +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/docs/tutorials.rst +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/__main__.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/cmd/__init__.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/cmd/check_version.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/cmd/install.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/cmd/installers/__init__.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/cmd/installers/base.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/cmd/installers/bdd.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/cmd/installers/btor.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/cmd/installers/cvcfive.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/cmd/installers/cvcfour.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/cmd/installers/msat.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/cmd/installers/optimsat.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/cmd/installers/pico.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/cmd/installers/yices.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/cmd/installers/z3.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/cmd/shell.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/configuration.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/constants.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/decorators.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/environment.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/exceptions.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/factory.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/logics.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/optimization/__init__.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/optimization/goal.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/optimization/msat.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/optimization/optimizer.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/optimization/optimsat.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/optimization/yices.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/optimization/z3.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/rewritings.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/smtlib/__init__.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/smtlib/annotations.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/smtlib/commands.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/smtlib/parser/__init__.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/smtlib/script.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/smtlib/solver.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/smtlib/utils.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/solvers/__init__.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/solvers/bdd.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/solvers/btor.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/solvers/dynmsat.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/solvers/eager.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/solvers/interpolation.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/solvers/options.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/solvers/pico.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/solvers/portfolio.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/solvers/qelim.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/solvers/smtlib.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/solvers/solver.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/substituter.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/__init__.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/configs/config1.ini +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/configs/config_bad.ini +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/omt_examples.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/optimization_utils.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/smtlib/__init__.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/smtlib/parser_utils.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/smtlib/test_annotations.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/smtlib/test_fuzzed.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/smtlib/test_generic_wrapper.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/smtlib/test_griggio.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/smtlib/test_model_validation.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/smtlib/test_omt_lib_solver.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/smtlib/test_parser_extensibility.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/smtlib/test_parser_lra.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/smtlib/test_parser_omt.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/smtlib/test_parser_qf_arrays.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/smtlib/test_parser_qf_lia.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/smtlib/test_parser_qf_lira.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/smtlib/test_parser_qf_lra.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/smtlib/test_parser_qf_nia.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/smtlib/test_parser_qf_nra.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/smtlib/test_parser_qf_uf.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/smtlib/test_parser_qf_ufbv.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/smtlib/test_parser_type_error.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/smtlib/test_smtlibscript.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_array.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_back.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_bdd.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_bv.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_bv_simplification.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_cnf.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_configuration.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_constants.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_cvc_quantifiers.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_dwf.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_eager_model.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_env.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_euf.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_formula.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_hr_parsing.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_imports.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_int.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_interpolation.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_logics.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_models.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_native_qe.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_nia.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_nlira.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_optimization.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_optimizing.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_oracles.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_portfolio.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_qe.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_regressions.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_rewritings.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_shannon_expansion.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_simplify.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_size.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_solving.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_sorts.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_string.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_typechecker.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_unsat_cores.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_walker_ext.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/test/test_walkers.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/typing.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/utils.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/walkers/__init__.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/walkers/dag.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/walkers/generic.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/pysmt/walkers/tree.py +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/setup.cfg +0 -0
- {pysmt-0.9.7.dev431 → pysmt-0.9.7.dev436}/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", 436)
|
|
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()
|
|
@@ -304,6 +304,40 @@ class Tokenizer(object):
|
|
|
304
304
|
# EOC Tokenizer
|
|
305
305
|
|
|
306
306
|
|
|
307
|
+
#
|
|
308
|
+
# Helpers to expand the SMT-LIB n-ary applications of operators that pySMT
|
|
309
|
+
# only exposes as binary ones. The SMT-LIB standard attaches one of the
|
|
310
|
+
# attributes :left-assoc, :right-assoc, :chainable or :pairwise to every such
|
|
311
|
+
# operator; the three functions below implement the first three (:pairwise is
|
|
312
|
+
# already covered by mgr.AllDifferent).
|
|
313
|
+
#
|
|
314
|
+
# In all cases a single argument is accepted and behaves as the identity (or
|
|
315
|
+
# as `true` for the chainable operators, where the conjunction is empty).
|
|
316
|
+
# The standard requires at least two arguments, but pySMT has always been
|
|
317
|
+
# lenient about this for `and`, `or`, `+` and `*`, and we keep it uniform.
|
|
318
|
+
#
|
|
319
|
+
|
|
320
|
+
def _left_assoc(operator: Callable) -> Callable:
|
|
321
|
+
"""(op a b c) is expanded to (op (op a b) c)"""
|
|
322
|
+
def res(*args):
|
|
323
|
+
return functools.reduce(operator, args)
|
|
324
|
+
return res
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def _right_assoc(operator: Callable) -> Callable:
|
|
328
|
+
"""(op a b c) is expanded to (op a (op b c))"""
|
|
329
|
+
def res(*args):
|
|
330
|
+
return functools.reduce(lambda acc, x: operator(x, acc), reversed(args))
|
|
331
|
+
return res
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
def _chainable(mgr: FormulaManager, operator: Callable) -> Callable:
|
|
335
|
+
"""(op a b c) is expanded to (and (op a b) (op b c))"""
|
|
336
|
+
def res(*args):
|
|
337
|
+
return mgr.And([operator(l, r) for l, r in zip(args, args[1:])])
|
|
338
|
+
return res
|
|
339
|
+
|
|
340
|
+
|
|
307
341
|
class SmtLibParser(object):
|
|
308
342
|
"""Parse an SmtLib file and builds an SmtLibScript object.
|
|
309
343
|
The main function is get_script (and its wrapper
|
|
@@ -373,25 +407,32 @@ class SmtLibParser(object):
|
|
|
373
407
|
"!": self._enter_annotation,
|
|
374
408
|
"exists": self._enter_quantifier,
|
|
375
409
|
"forall": self._enter_quantifier,
|
|
410
|
+
# '+' and '*' are :left-assoc, but pySMT builds them n-ary
|
|
411
|
+
# natively; the other n-ary operators are folded, see the
|
|
412
|
+
# _left_assoc/_right_assoc/_chainable helpers above.
|
|
376
413
|
'+': self._operator_adapter(self.Plus),
|
|
377
414
|
'-': self._operator_adapter(self._minus_or_uminus),
|
|
378
415
|
'*': self._operator_adapter(self.Times),
|
|
379
|
-
'/': self._operator_adapter(self._division),
|
|
416
|
+
'/': self._operator_adapter(_left_assoc(self._division)),
|
|
417
|
+
'div': self._operator_adapter(_left_assoc(mgr.Div)),
|
|
380
418
|
'pow': self._operator_adapter(mgr.Pow),
|
|
381
|
-
'>': self._operator_adapter(self.GT),
|
|
382
|
-
'<': self._operator_adapter(self.LT),
|
|
383
|
-
'>=': self._operator_adapter(self.GE),
|
|
384
|
-
'<=': self._operator_adapter(self.LE),
|
|
385
|
-
'=': self._operator_adapter(self._equals_or_iff),
|
|
419
|
+
'>': self._operator_adapter(_chainable(mgr, self.GT)),
|
|
420
|
+
'<': self._operator_adapter(_chainable(mgr, self.LT)),
|
|
421
|
+
'>=': self._operator_adapter(_chainable(mgr, self.GE)),
|
|
422
|
+
'<=': self._operator_adapter(_chainable(mgr, self.LE)),
|
|
423
|
+
'=': self._operator_adapter(_chainable(mgr, self._equals_or_iff)),
|
|
386
424
|
'not': self._operator_adapter(mgr.Not),
|
|
387
425
|
'and': self._operator_adapter(mgr.And),
|
|
388
426
|
'or': self._operator_adapter(mgr.Or),
|
|
389
|
-
'xor': self._operator_adapter(mgr.Xor),
|
|
390
|
-
'=>': self._operator_adapter(mgr.Implies),
|
|
391
|
-
'<->':
|
|
427
|
+
'xor': self._operator_adapter(_left_assoc(mgr.Xor)),
|
|
428
|
+
'=>': self._operator_adapter(_right_assoc(mgr.Implies)),
|
|
429
|
+
# '<->' is a pySMT extension: treated as :left-assoc, like 'xor'
|
|
430
|
+
'<->': self._operator_adapter(_left_assoc(mgr.Iff)),
|
|
392
431
|
'ite': self._operator_adapter(self.Ite),
|
|
393
432
|
'distinct': self._operator_adapter(self.AllDifferent),
|
|
394
433
|
'to_real': self._operator_adapter(mgr.ToReal),
|
|
434
|
+
'to_int': self._operator_adapter(mgr.ToInt),
|
|
435
|
+
'is_int': self._operator_adapter(mgr.IsInt),
|
|
395
436
|
'concat': self._operator_adapter(mgr.BVConcat),
|
|
396
437
|
'bvnot': self._operator_adapter(mgr.BVNot),
|
|
397
438
|
'bvand': self._operator_adapter(mgr.BVAnd),
|
|
@@ -405,12 +446,12 @@ class SmtLibParser(object):
|
|
|
405
446
|
'bvlshr': self._operator_adapter(mgr.BVLShr),
|
|
406
447
|
'bvsub': self._operator_adapter(mgr.BVSub),
|
|
407
448
|
'bvult': self._operator_adapter(mgr.BVULT),
|
|
408
|
-
'bvxor': self._operator_adapter(mgr.BVXor),
|
|
449
|
+
'bvxor': self._operator_adapter(_left_assoc(mgr.BVXor)),
|
|
409
450
|
'_': self._smtlib_underscore,
|
|
410
451
|
# Extended Functions
|
|
411
452
|
'bvnand': self._operator_adapter(mgr.BVNand),
|
|
412
453
|
'bvnor': self._operator_adapter(mgr.BVNor),
|
|
413
|
-
'bvxnor': self._operator_adapter(mgr.BVXnor),
|
|
454
|
+
'bvxnor': self._operator_adapter(_left_assoc(mgr.BVXnor)),
|
|
414
455
|
'bvcomp': self._operator_adapter(mgr.BVComp),
|
|
415
456
|
'bvsdiv': self._operator_adapter(mgr.BVSDiv),
|
|
416
457
|
'bvsrem': self._operator_adapter(mgr.BVSRem),
|
|
@@ -490,7 +531,7 @@ class SmtLibParser(object):
|
|
|
490
531
|
self.cache.update({'false': mgr.FALSE(), 'true': mgr.TRUE()})
|
|
491
532
|
|
|
492
533
|
def _minus_or_uminus(self, *args) -> FNode:
|
|
493
|
-
"""Utility function that handles
|
|
534
|
+
"""Utility function that handles unary and n-ary minus"""
|
|
494
535
|
mgr = self.env.formula_manager
|
|
495
536
|
if len(args) == 1:
|
|
496
537
|
lty = self.get_type(args[0])
|
|
@@ -504,9 +545,8 @@ class SmtLibParser(object):
|
|
|
504
545
|
return mgr.Real(-1 * args[0].constant_value())
|
|
505
546
|
mult = mgr.Real(-1)
|
|
506
547
|
return mgr.Times(mult, args[0])
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
return self.Minus(args[0], args[1])
|
|
548
|
+
# '-' is :left-assoc: (- a b c) is (- (- a b) c)
|
|
549
|
+
return functools.reduce(self.Minus, args)
|
|
510
550
|
|
|
511
551
|
def _enter_smtlib_as(self, stack: List[List[Union[Callable, FNode, Any]]], tokens: Tokenizer, key: str):
|
|
512
552
|
"""Utility function that handles 'as' that is a special function in SMTLIB"""
|
|
@@ -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:
|
|
@@ -427,6 +427,7 @@ class MSatConverter(Converter, DagWalker):
|
|
|
427
427
|
self._msat_lib.MSAT_TAG_BV_LSHR: self._back_adapter(self.mgr.BVLShr),
|
|
428
428
|
self._msat_lib.MSAT_TAG_BV_ASHR: self._back_adapter(self.mgr.BVAShr),
|
|
429
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),
|
|
430
431
|
self._msat_lib.MSAT_TAG_INT_FROM_UBV: self._back_adapter(self.mgr.BVToNatural),
|
|
431
432
|
self._msat_lib.MSAT_TAG_ARRAY_READ: self._back_adapter(self.mgr.Select),
|
|
432
433
|
self._msat_lib.MSAT_TAG_ARRAY_WRITE: self._back_adapter(self.mgr.Store),
|
|
@@ -461,6 +462,8 @@ class MSatConverter(Converter, DagWalker):
|
|
|
461
462
|
self._msat_lib.MSAT_TAG_LEQ: self._sig_most_generic_bool_binary,
|
|
462
463
|
self._msat_lib.MSAT_TAG_PLUS: self._sig_most_generic_bool_binary,
|
|
463
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]),
|
|
464
467
|
self._msat_lib.MSAT_TAG_BV_MUL: self._sig_binary,
|
|
465
468
|
self._msat_lib.MSAT_TAG_BV_ADD: self._sig_binary,
|
|
466
469
|
self._msat_lib.MSAT_TAG_BV_UDIV:self._sig_binary,
|
|
@@ -1004,6 +1007,9 @@ class MSatConverter(Converter, DagWalker):
|
|
|
1004
1007
|
# In mathsat toreal is implicit
|
|
1005
1008
|
return args[0]
|
|
1006
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
|
+
|
|
1007
1013
|
def walk_bv_tonatural(self, formula: FNode, args: List[Any], **kwargs) -> Any:
|
|
1008
1014
|
return self._msat_lib.msat_make_int_from_ubv(self.msat_env(), args[0])
|
|
1009
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
|
#
|
|
@@ -25,9 +25,12 @@ from pysmt.test import TestCase, skipIfNoSolverForLogic, main
|
|
|
25
25
|
from pysmt.test.examples import get_example_formulae
|
|
26
26
|
from pysmt.smtlib.parser import SmtLibParser, Tokenizer
|
|
27
27
|
from pysmt.smtlib.script import smtlibscript_from_formula
|
|
28
|
-
from pysmt.shortcuts import Iff
|
|
28
|
+
from pysmt.shortcuts import Iff, Symbol, And, Implies, Xor, LT, GE, Equals, \
|
|
29
|
+
Plus, Minus, Times, Div, AllDifferent, BVXor, BVConcat
|
|
29
30
|
from pysmt.shortcuts import read_smtlib, write_smtlib, get_env
|
|
30
31
|
from pysmt.exceptions import PysmtSyntaxError
|
|
32
|
+
from pysmt.smtlib.commands import ASSERT
|
|
33
|
+
from pysmt.typing import INT, REAL, BV8
|
|
31
34
|
|
|
32
35
|
|
|
33
36
|
class TestSMTParseExamples(TestCase):
|
|
@@ -118,6 +121,7 @@ class TestSMTParseExamples(TestCase):
|
|
|
118
121
|
logics.QF_BOOL: logics.QF_UF,
|
|
119
122
|
logics.BOOL: logics.LRA,
|
|
120
123
|
logics.QF_NIRA: logics.AUFNIRA,
|
|
124
|
+
logics.QF_LIRA: logics.QF_UFLIRA,
|
|
121
125
|
}
|
|
122
126
|
fs = get_example_formulae()
|
|
123
127
|
|
|
@@ -215,6 +219,130 @@ class TestSMTParseExamples(TestCase):
|
|
|
215
219
|
for cmd in s:
|
|
216
220
|
self.assertEqual(cmd.args[2], get_type(cmd.args[3]))
|
|
217
221
|
|
|
222
|
+
def test_nary_operators(self):
|
|
223
|
+
"""All the SMT-LIB n-ary operators are expanded as the standard
|
|
224
|
+
prescribes: see https://github.com/pysmt/pysmt/issues/638"""
|
|
225
|
+
INT_DECLS = "(declare-fun a () Int)(declare-fun b () Int)" \
|
|
226
|
+
"(declare-fun c () Int)(declare-fun d () Int)"
|
|
227
|
+
BOOL_DECLS = "(declare-fun p () Bool)(declare-fun q () Bool)" \
|
|
228
|
+
"(declare-fun r () Bool)"
|
|
229
|
+
BV_DECLS = "(declare-fun x () (_ BitVec 8))(declare-fun y () (_ BitVec 8))" \
|
|
230
|
+
"(declare-fun z () (_ BitVec 8))"
|
|
231
|
+
|
|
232
|
+
# (declarations, n-ary application, expected expansion)
|
|
233
|
+
cases = [
|
|
234
|
+
# :right-assoc
|
|
235
|
+
(BOOL_DECLS, "(=> p q r)", "(=> p (=> q r))"),
|
|
236
|
+
(BOOL_DECLS, "(=> p q r p)", "(=> p (=> q (=> r p)))"),
|
|
237
|
+
# :left-assoc
|
|
238
|
+
(BOOL_DECLS, "(xor p q r)", "(xor (xor p q) r)"),
|
|
239
|
+
(BOOL_DECLS, "(<-> p q r)", "(<-> (<-> p q) r)"),
|
|
240
|
+
(INT_DECLS, "(- a b c)", "(- (- a b) c)"),
|
|
241
|
+
(INT_DECLS, "(- a b c d)", "(- (- (- a b) c) d)"),
|
|
242
|
+
(INT_DECLS, "(/ a b c)", "(/ (/ a b) c)"),
|
|
243
|
+
(INT_DECLS, "(div a b c)", "(div (div a b) c)"),
|
|
244
|
+
(BV_DECLS, "(bvxor x y z)", "(bvxor (bvxor x y) z)"),
|
|
245
|
+
(BV_DECLS, "(bvxnor x y z)", "(bvxnor (bvxnor x y) z)"),
|
|
246
|
+
# :chainable
|
|
247
|
+
(INT_DECLS, "(> a b c)", "(and (> a b) (> b c))"),
|
|
248
|
+
(INT_DECLS, "(>= a b c d)", "(and (>= a b) (>= b c) (>= c d))"),
|
|
249
|
+
(INT_DECLS, "(< a b c)", "(and (< a b) (< b c))"),
|
|
250
|
+
(INT_DECLS, "(<= a b c)", "(and (<= a b) (<= b c))"),
|
|
251
|
+
(INT_DECLS, "(= a b c)", "(and (= a b) (= b c))"),
|
|
252
|
+
(BOOL_DECLS, "(= p q r)", "(and (<-> p q) (<-> q r))"),
|
|
253
|
+
# unary applications: identity for the associative operators,
|
|
254
|
+
# vacuously true for the chainable ones
|
|
255
|
+
(BOOL_DECLS, "(=> p)", "p"),
|
|
256
|
+
(BOOL_DECLS, "(xor p)", "p"),
|
|
257
|
+
(INT_DECLS, "(/ a)", "a"),
|
|
258
|
+
(INT_DECLS, "(= a)", "true"),
|
|
259
|
+
(INT_DECLS, "(< a)", "true"),
|
|
260
|
+
]
|
|
261
|
+
for decls, nary, expected in cases:
|
|
262
|
+
self.assertEqual(self._parse_assertion(decls, nary),
|
|
263
|
+
self._parse_assertion(decls, expected),
|
|
264
|
+
"wrong expansion of %s" % nary)
|
|
265
|
+
|
|
266
|
+
def test_nary_operators_end_to_end(self):
|
|
267
|
+
"""Parse a whole SMT-LIB2 script using the n-ary operators and check
|
|
268
|
+
the resulting formulae against the ones built with the pySMT API"""
|
|
269
|
+
script = """
|
|
270
|
+
; no set-logic: no pySMT logic covers BV + non-linear Int/Real at once
|
|
271
|
+
(declare-fun a () Int)
|
|
272
|
+
(declare-fun b () Int)
|
|
273
|
+
(declare-fun c () Int)
|
|
274
|
+
(declare-fun r () Real)
|
|
275
|
+
(declare-fun s () Real)
|
|
276
|
+
(declare-fun t () Real)
|
|
277
|
+
(declare-fun p () Bool)
|
|
278
|
+
(declare-fun q () Bool)
|
|
279
|
+
(declare-fun u () Bool)
|
|
280
|
+
(declare-fun x () (_ BitVec 8))
|
|
281
|
+
(declare-fun y () (_ BitVec 8))
|
|
282
|
+
(declare-fun z () (_ BitVec 8))
|
|
283
|
+
(assert (< a b c))
|
|
284
|
+
(assert (>= a b c))
|
|
285
|
+
(assert (= a b c))
|
|
286
|
+
(assert (= p q u))
|
|
287
|
+
(assert (= (- a b c) (+ a b c)))
|
|
288
|
+
(assert (= (div a b c) (* a b c)))
|
|
289
|
+
(assert (= (/ r s t) r))
|
|
290
|
+
(assert (=> p q u))
|
|
291
|
+
(assert (xor p q u))
|
|
292
|
+
(assert (distinct a b c))
|
|
293
|
+
(assert (= (bvxor x y z) x))
|
|
294
|
+
(assert (= (concat x y z) (concat z y x)))
|
|
295
|
+
(check-sat)
|
|
296
|
+
"""
|
|
297
|
+
a, b, c = (Symbol(name, INT) for name in "abc")
|
|
298
|
+
r, s, t = (Symbol(name, REAL) for name in "rst")
|
|
299
|
+
p, q, u = (Symbol(name) for name in "pqu")
|
|
300
|
+
x, y, z = (Symbol(name, BV8) for name in "xyz")
|
|
301
|
+
|
|
302
|
+
expected = [
|
|
303
|
+
# :chainable
|
|
304
|
+
And(LT(a, b), LT(b, c)),
|
|
305
|
+
And(GE(a, b), GE(b, c)),
|
|
306
|
+
And(Equals(a, b), Equals(b, c)),
|
|
307
|
+
And(Iff(p, q), Iff(q, u)),
|
|
308
|
+
# :left-assoc ('+' and '*' stay flat n-ary)
|
|
309
|
+
Equals(Minus(Minus(a, b), c), Plus(a, b, c)),
|
|
310
|
+
Equals(Div(Div(a, b), c), Times(a, b, c)),
|
|
311
|
+
Equals(Div(Div(r, s), t), r),
|
|
312
|
+
# :right-assoc
|
|
313
|
+
Implies(p, Implies(q, u)),
|
|
314
|
+
# :left-assoc
|
|
315
|
+
Xor(Xor(p, q), u),
|
|
316
|
+
# :pairwise
|
|
317
|
+
AllDifferent(a, b, c),
|
|
318
|
+
# bit-vectors
|
|
319
|
+
Equals(BVXor(BVXor(x, y), z), x),
|
|
320
|
+
Equals(BVConcat(BVConcat(x, y), z), BVConcat(BVConcat(z, y), x)),
|
|
321
|
+
]
|
|
322
|
+
|
|
323
|
+
parser = SmtLibParser()
|
|
324
|
+
parsed = [cmd.args[0] for cmd in
|
|
325
|
+
parser.get_script(StringIO(script)).filter_by_command_name(ASSERT)]
|
|
326
|
+
|
|
327
|
+
self.assertEqual(len(parsed), len(expected))
|
|
328
|
+
for got, exp in zip(parsed, expected):
|
|
329
|
+
self.assertEqual(got, exp)
|
|
330
|
+
# ...and the conjunction of all of them is what the script means
|
|
331
|
+
self.assertEqual(
|
|
332
|
+
SmtLibParser().get_script(StringIO(script)).get_last_formula(),
|
|
333
|
+
And(expected))
|
|
334
|
+
|
|
335
|
+
def test_nary_div_is_integer_division(self):
|
|
336
|
+
"""'div' is the Ints division, so it must not be promoted to Real"""
|
|
337
|
+
f = self._parse_assertion("(declare-fun a () Int)", "(div a 2 3)")
|
|
338
|
+
self.assertEqual(get_env().stc.get_type(f), INT)
|
|
339
|
+
|
|
340
|
+
@staticmethod
|
|
341
|
+
def _parse_assertion(declarations, expression):
|
|
342
|
+
script = "%s (assert %s)" % (declarations, expression)
|
|
343
|
+
parser = SmtLibParser()
|
|
344
|
+
return parser.get_script(StringIO(script)).get_last_formula()
|
|
345
|
+
|
|
218
346
|
def test_typing_define_fun(self):
|
|
219
347
|
script = """
|
|
220
348
|
(define-fun x () Int 8.2)
|