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