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.
Files changed (165) hide show
  1. {pysmt-0.9.7.dev426/PySMT.egg-info → pysmt-0.9.7.dev433}/PKG-INFO +1 -1
  2. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433/PySMT.egg-info}/PKG-INFO +1 -1
  3. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/__init__.py +1 -1
  4. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/fnode.py +5 -1
  5. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/formula.py +38 -0
  6. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/operators.py +5 -2
  7. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/oracles.py +6 -0
  8. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/parsing.py +2 -0
  9. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/printers.py +5 -0
  10. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/shortcuts.py +13 -0
  11. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/simplifier.py +10 -0
  12. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/smtlib/parser/parser.py +2 -0
  13. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/smtlib/printers.py +4 -0
  14. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/cvcfive.py +3 -0
  15. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/cvcfour.py +3 -0
  16. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/msat.py +7 -6
  17. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/yices.py +5 -0
  18. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/z3.py +7 -0
  19. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/examples.py +27 -1
  20. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_parser_examples.py +1 -0
  21. pysmt-0.9.7.dev433/pysmt/test/test_lira.py +141 -0
  22. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_printing.py +9 -1
  23. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_regressions.py +34 -0
  24. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/type_checker.py +5 -0
  25. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/walkers/identitydag.py +3 -0
  26. pysmt-0.9.7.dev426/pysmt/test/test_lira.py +0 -65
  27. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/LICENSE +0 -0
  28. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/MANIFEST.in +0 -0
  29. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/NOTICE +0 -0
  30. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/PySMT.egg-info/SOURCES.txt +0 -0
  31. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/PySMT.egg-info/dependency_links.txt +0 -0
  32. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/PySMT.egg-info/entry_points.txt +0 -0
  33. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/PySMT.egg-info/top_level.txt +0 -0
  34. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/README.rst +0 -0
  35. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/docs/CHANGES.rst +0 -0
  36. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/docs/api_ref.rst +0 -0
  37. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/docs/development.rst +0 -0
  38. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/docs/getting_started.rst +0 -0
  39. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/docs/index.rst +0 -0
  40. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/docs/tutorials/boolean_logic.rst +0 -0
  41. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/docs/tutorials.rst +0 -0
  42. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/__main__.py +0 -0
  43. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/cmd/__init__.py +0 -0
  44. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/cmd/check_version.py +0 -0
  45. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/cmd/install.py +0 -0
  46. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/cmd/installers/__init__.py +0 -0
  47. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/cmd/installers/base.py +0 -0
  48. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/cmd/installers/bdd.py +0 -0
  49. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/cmd/installers/btor.py +0 -0
  50. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/cmd/installers/cvcfive.py +0 -0
  51. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/cmd/installers/cvcfour.py +0 -0
  52. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/cmd/installers/msat.py +0 -0
  53. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/cmd/installers/optimsat.py +0 -0
  54. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/cmd/installers/pico.py +0 -0
  55. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/cmd/installers/yices.py +0 -0
  56. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/cmd/installers/z3.py +0 -0
  57. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/cmd/shell.py +0 -0
  58. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/configuration.py +0 -0
  59. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/constants.py +0 -0
  60. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/decorators.py +0 -0
  61. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/environment.py +0 -0
  62. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/exceptions.py +0 -0
  63. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/factory.py +0 -0
  64. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/logics.py +0 -0
  65. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/optimization/__init__.py +0 -0
  66. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/optimization/goal.py +0 -0
  67. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/optimization/msat.py +0 -0
  68. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/optimization/optimizer.py +0 -0
  69. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/optimization/optimsat.py +0 -0
  70. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/optimization/yices.py +0 -0
  71. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/optimization/z3.py +0 -0
  72. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/rewritings.py +0 -0
  73. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/smtlib/__init__.py +0 -0
  74. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/smtlib/annotations.py +0 -0
  75. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/smtlib/commands.py +0 -0
  76. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/smtlib/parser/__init__.py +0 -0
  77. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/smtlib/script.py +0 -0
  78. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/smtlib/solver.py +0 -0
  79. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/smtlib/utils.py +0 -0
  80. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/__init__.py +0 -0
  81. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/bdd.py +0 -0
  82. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/btor.py +0 -0
  83. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/dynmsat.py +0 -0
  84. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/eager.py +0 -0
  85. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/interpolation.py +0 -0
  86. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/options.py +0 -0
  87. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/pico.py +0 -0
  88. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/portfolio.py +0 -0
  89. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/qelim.py +0 -0
  90. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/smtlib.py +0 -0
  91. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/solvers/solver.py +0 -0
  92. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/substituter.py +0 -0
  93. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/__init__.py +0 -0
  94. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/configs/config1.ini +0 -0
  95. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/configs/config_bad.ini +0 -0
  96. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/omt_examples.py +0 -0
  97. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/optimization_utils.py +0 -0
  98. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/__init__.py +0 -0
  99. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/parser_utils.py +0 -0
  100. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_annotations.py +0 -0
  101. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_fuzzed.py +0 -0
  102. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_generic_wrapper.py +0 -0
  103. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_griggio.py +0 -0
  104. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_model_validation.py +0 -0
  105. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_omt_lib_solver.py +0 -0
  106. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_parser_extensibility.py +0 -0
  107. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_parser_lra.py +0 -0
  108. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_parser_omt.py +0 -0
  109. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_parser_qf_arrays.py +0 -0
  110. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_parser_qf_lia.py +0 -0
  111. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_parser_qf_lira.py +0 -0
  112. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_parser_qf_lra.py +0 -0
  113. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_parser_qf_nia.py +0 -0
  114. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_parser_qf_nra.py +0 -0
  115. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_parser_qf_uf.py +0 -0
  116. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_parser_qf_ufbv.py +0 -0
  117. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_parser_type_error.py +0 -0
  118. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/smtlib/test_smtlibscript.py +0 -0
  119. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_array.py +0 -0
  120. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_back.py +0 -0
  121. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_bdd.py +0 -0
  122. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_bv.py +0 -0
  123. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_bv_simplification.py +0 -0
  124. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_cnf.py +0 -0
  125. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_configuration.py +0 -0
  126. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_constants.py +0 -0
  127. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_cvc_quantifiers.py +0 -0
  128. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_dwf.py +0 -0
  129. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_eager_model.py +0 -0
  130. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_env.py +0 -0
  131. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_euf.py +0 -0
  132. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_formula.py +0 -0
  133. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_hr_parsing.py +0 -0
  134. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_imports.py +0 -0
  135. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_int.py +0 -0
  136. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_interpolation.py +0 -0
  137. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_logics.py +0 -0
  138. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_models.py +0 -0
  139. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_native_qe.py +0 -0
  140. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_nia.py +0 -0
  141. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_nlira.py +0 -0
  142. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_optimization.py +0 -0
  143. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_optimizing.py +0 -0
  144. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_oracles.py +0 -0
  145. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_portfolio.py +0 -0
  146. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_qe.py +0 -0
  147. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_rewritings.py +0 -0
  148. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_shannon_expansion.py +0 -0
  149. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_simplify.py +0 -0
  150. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_size.py +0 -0
  151. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_solving.py +0 -0
  152. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_sorts.py +0 -0
  153. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_string.py +0 -0
  154. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_typechecker.py +0 -0
  155. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_unsat_cores.py +0 -0
  156. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_walker_ext.py +0 -0
  157. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/test/test_walkers.py +0 -0
  158. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/typing.py +0 -0
  159. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/utils.py +0 -0
  160. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/walkers/__init__.py +0 -0
  161. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/walkers/dag.py +0 -0
  162. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/walkers/generic.py +0 -0
  163. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/pysmt/walkers/tree.py +0 -0
  164. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/setup.cfg +0 -0
  165. {pysmt-0.9.7.dev426 → pysmt-0.9.7.dev433}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PySMT
3
- Version: 0.9.7.dev426
3
+ Version: 0.9.7.dev433
4
4
  Summary: A solver-agnostic library for SMT Formulae manipulation and solving
5
5
  Home-page: http://www.pysmt.org
6
6
  Author: PySMT Team
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PySMT
3
- Version: 0.9.7.dev426
3
+ Version: 0.9.7.dev433
4
4
  Summary: A solver-agnostic library for SMT Formulae manipulation and solving
5
5
  Home-page: http://www.pysmt.org
6
6
  Author: PySMT Team
@@ -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", 426)
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,66))
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, BV_TONATURAL])
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._var2term(x) for x in important],
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
  #
@@ -118,6 +118,7 @@ class TestSMTParseExamples(TestCase):
118
118
  logics.QF_BOOL: logics.QF_UF,
119
119
  logics.BOOL: logics.LRA,
120
120
  logics.QF_NIRA: logics.AUFNIRA,
121
+ logics.QF_LIRA: logics.QF_UFLIRA,
121
122
  }
122
123
  fs = get_example_formulae()
123
124
 
@@ -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