PySMT 0.9.7.dev433__tar.gz → 0.9.7.dev439__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 (164) hide show
  1. {pysmt-0.9.7.dev433/PySMT.egg-info → pysmt-0.9.7.dev439}/PKG-INFO +1 -1
  2. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439/PySMT.egg-info}/PKG-INFO +1 -1
  3. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/__init__.py +1 -1
  4. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/factory.py +1 -1
  5. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/optimization/goal.py +61 -26
  6. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/optimization/optimizer.py +10 -9
  7. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/oracles.py +5 -3
  8. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/parsing.py +2 -2
  9. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/rewritings.py +25 -24
  10. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/simplifier.py +5 -3
  11. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/smtlib/parser/parser.py +57 -17
  12. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/smtlib/printers.py +16 -14
  13. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/smtlib/script.py +31 -24
  14. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/smtlib/solver.py +2 -2
  15. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/solvers/bdd.py +2 -2
  16. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/solvers/btor.py +1 -1
  17. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/solvers/cvcfive.py +4 -4
  18. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/solvers/cvcfour.py +5 -4
  19. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/solvers/eager.py +2 -2
  20. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/solvers/msat.py +26 -25
  21. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/solvers/pico.py +1 -1
  22. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/solvers/qelim.py +5 -3
  23. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/solvers/smtlib.py +5 -0
  24. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/solvers/solver.py +7 -5
  25. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/solvers/z3.py +5 -4
  26. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/substituter.py +2 -1
  27. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/smtlib/test_parser_examples.py +128 -1
  28. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_env.py +94 -0
  29. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/type_checker.py +9 -9
  30. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/LICENSE +0 -0
  31. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/MANIFEST.in +0 -0
  32. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/NOTICE +0 -0
  33. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/PySMT.egg-info/SOURCES.txt +0 -0
  34. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/PySMT.egg-info/dependency_links.txt +0 -0
  35. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/PySMT.egg-info/entry_points.txt +0 -0
  36. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/PySMT.egg-info/top_level.txt +0 -0
  37. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/README.rst +0 -0
  38. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/docs/CHANGES.rst +0 -0
  39. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/docs/api_ref.rst +0 -0
  40. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/docs/development.rst +0 -0
  41. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/docs/getting_started.rst +0 -0
  42. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/docs/index.rst +0 -0
  43. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/docs/tutorials/boolean_logic.rst +0 -0
  44. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/docs/tutorials.rst +0 -0
  45. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/__main__.py +0 -0
  46. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/cmd/__init__.py +0 -0
  47. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/cmd/check_version.py +0 -0
  48. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/cmd/install.py +0 -0
  49. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/cmd/installers/__init__.py +0 -0
  50. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/cmd/installers/base.py +0 -0
  51. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/cmd/installers/bdd.py +0 -0
  52. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/cmd/installers/btor.py +0 -0
  53. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/cmd/installers/cvcfive.py +0 -0
  54. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/cmd/installers/cvcfour.py +0 -0
  55. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/cmd/installers/msat.py +0 -0
  56. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/cmd/installers/optimsat.py +0 -0
  57. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/cmd/installers/pico.py +0 -0
  58. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/cmd/installers/yices.py +0 -0
  59. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/cmd/installers/z3.py +0 -0
  60. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/cmd/shell.py +0 -0
  61. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/configuration.py +0 -0
  62. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/constants.py +0 -0
  63. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/decorators.py +0 -0
  64. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/environment.py +0 -0
  65. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/exceptions.py +0 -0
  66. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/fnode.py +0 -0
  67. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/formula.py +0 -0
  68. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/logics.py +0 -0
  69. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/operators.py +0 -0
  70. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/optimization/__init__.py +0 -0
  71. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/optimization/msat.py +0 -0
  72. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/optimization/optimsat.py +0 -0
  73. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/optimization/yices.py +0 -0
  74. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/optimization/z3.py +0 -0
  75. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/printers.py +0 -0
  76. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/shortcuts.py +0 -0
  77. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/smtlib/__init__.py +0 -0
  78. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/smtlib/annotations.py +0 -0
  79. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/smtlib/commands.py +0 -0
  80. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/smtlib/parser/__init__.py +0 -0
  81. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/smtlib/utils.py +0 -0
  82. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/solvers/__init__.py +0 -0
  83. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/solvers/dynmsat.py +0 -0
  84. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/solvers/interpolation.py +0 -0
  85. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/solvers/options.py +0 -0
  86. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/solvers/portfolio.py +0 -0
  87. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/solvers/yices.py +0 -0
  88. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/__init__.py +0 -0
  89. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/configs/config1.ini +0 -0
  90. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/configs/config_bad.ini +0 -0
  91. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/examples.py +0 -0
  92. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/omt_examples.py +0 -0
  93. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/optimization_utils.py +0 -0
  94. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/smtlib/__init__.py +0 -0
  95. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/smtlib/parser_utils.py +0 -0
  96. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/smtlib/test_annotations.py +0 -0
  97. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/smtlib/test_fuzzed.py +0 -0
  98. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/smtlib/test_generic_wrapper.py +0 -0
  99. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/smtlib/test_griggio.py +0 -0
  100. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/smtlib/test_model_validation.py +0 -0
  101. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/smtlib/test_omt_lib_solver.py +0 -0
  102. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/smtlib/test_parser_extensibility.py +0 -0
  103. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/smtlib/test_parser_lra.py +0 -0
  104. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/smtlib/test_parser_omt.py +0 -0
  105. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/smtlib/test_parser_qf_arrays.py +0 -0
  106. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/smtlib/test_parser_qf_lia.py +0 -0
  107. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/smtlib/test_parser_qf_lira.py +0 -0
  108. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/smtlib/test_parser_qf_lra.py +0 -0
  109. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/smtlib/test_parser_qf_nia.py +0 -0
  110. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/smtlib/test_parser_qf_nra.py +0 -0
  111. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/smtlib/test_parser_qf_uf.py +0 -0
  112. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/smtlib/test_parser_qf_ufbv.py +0 -0
  113. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/smtlib/test_parser_type_error.py +0 -0
  114. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/smtlib/test_smtlibscript.py +0 -0
  115. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_array.py +0 -0
  116. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_back.py +0 -0
  117. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_bdd.py +0 -0
  118. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_bv.py +0 -0
  119. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_bv_simplification.py +0 -0
  120. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_cnf.py +0 -0
  121. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_configuration.py +0 -0
  122. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_constants.py +0 -0
  123. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_cvc_quantifiers.py +0 -0
  124. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_dwf.py +0 -0
  125. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_eager_model.py +0 -0
  126. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_euf.py +0 -0
  127. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_formula.py +0 -0
  128. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_hr_parsing.py +0 -0
  129. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_imports.py +0 -0
  130. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_int.py +0 -0
  131. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_interpolation.py +0 -0
  132. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_lira.py +0 -0
  133. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_logics.py +0 -0
  134. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_models.py +0 -0
  135. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_native_qe.py +0 -0
  136. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_nia.py +0 -0
  137. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_nlira.py +0 -0
  138. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_optimization.py +0 -0
  139. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_optimizing.py +0 -0
  140. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_oracles.py +0 -0
  141. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_portfolio.py +0 -0
  142. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_printing.py +0 -0
  143. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_qe.py +0 -0
  144. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_regressions.py +0 -0
  145. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_rewritings.py +0 -0
  146. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_shannon_expansion.py +0 -0
  147. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_simplify.py +0 -0
  148. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_size.py +0 -0
  149. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_solving.py +0 -0
  150. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_sorts.py +0 -0
  151. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_string.py +0 -0
  152. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_typechecker.py +0 -0
  153. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_unsat_cores.py +0 -0
  154. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_walker_ext.py +0 -0
  155. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/test/test_walkers.py +0 -0
  156. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/typing.py +0 -0
  157. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/utils.py +0 -0
  158. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/walkers/__init__.py +0 -0
  159. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/walkers/dag.py +0 -0
  160. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/walkers/generic.py +0 -0
  161. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/walkers/identitydag.py +0 -0
  162. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/pysmt/walkers/tree.py +0 -0
  163. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/setup.cfg +0 -0
  164. {pysmt-0.9.7.dev433 → pysmt-0.9.7.dev439}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PySMT
3
- Version: 0.9.7.dev433
3
+ Version: 0.9.7.dev439
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.dev433
3
+ Version: 0.9.7.dev439
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", 433)
22
+ VERSION: Union[Tuple[int, int, int], Tuple[int, int, int, str, int]] = (0, 9, 7, "dev", 439)
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
@@ -615,7 +615,7 @@ class Factory(object):
615
615
  atoms = formula.get_atoms()
616
616
  res = []
617
617
  for a in atoms:
618
- fv = a.get_free_variables()
618
+ fv = self.environment.fvo.get_free_variables(a)
619
619
  if any(v in model for v in fv):
620
620
  if solver.get_value(a).is_true():
621
621
  res.append(a)
@@ -16,12 +16,12 @@
16
16
  # limitations under the License.
17
17
  #
18
18
 
19
- from pysmt.environment import get_env
19
+ from pysmt.environment import Environment, get_env
20
20
  from pysmt.exceptions import PysmtValueError
21
21
  from pysmt.oracles import get_logic
22
22
  from pysmt.logics import Logic, LIA, LRA, BV
23
23
  from pysmt.fnode import FNode
24
- from typing import List, Tuple, Type, cast
24
+ from typing import List, Optional, Tuple, Type, cast
25
25
 
26
26
 
27
27
  class Goal(object):
@@ -51,6 +51,23 @@ class Goal(object):
51
51
  ```
52
52
  """
53
53
 
54
+ # The class-level default keeps subclasses that do not call Goal.__init__
55
+ # working against the global environment, as they did before.
56
+ _env: Optional[Environment] = None
57
+
58
+ def __init__(self, env: Optional[Environment]=None):
59
+ """
60
+ :param env: The environment the goal lives in; the global one if None
61
+ """
62
+ self._env = env if env is not None else get_env()
63
+
64
+ @property
65
+ def env(self) -> Environment:
66
+ """The environment this goal lives in."""
67
+ if self._env is None:
68
+ self._env = get_env()
69
+ return self._env
70
+
54
71
  def is_maximization_goal(self) -> bool:
55
72
  return False
56
73
 
@@ -67,7 +84,7 @@ class Goal(object):
67
84
  return False
68
85
 
69
86
  def get_logic(self) -> Logic:
70
- logic = get_logic(self.term())
87
+ logic = get_logic(self.term(), env=self.env)
71
88
  if logic <= LIA:
72
89
  return LIA
73
90
  elif logic <= LRA:
@@ -99,11 +116,14 @@ class MaximizationGoal(Goal):
99
116
  Warning: some Optimizer may not support this goal
100
117
  """
101
118
 
102
- def __init__(self, formula: FNode, signed: bool = False):
119
+ def __init__(self, formula: FNode, signed: bool = False,
120
+ env: Optional[Environment]=None):
103
121
  """
104
122
  :param formula: The target formula
105
123
  :type formula: FNode
124
+ :param env: The environment the goal lives in; the global one if None
106
125
  """
126
+ Goal.__init__(self, env)
107
127
  self.formula = formula
108
128
  self._bv_signed = signed
109
129
 
@@ -127,11 +147,14 @@ class MinimizationGoal(Goal):
127
147
  Warning: some Optimizer may not support this goal
128
148
  """
129
149
 
130
- def __init__(self, formula: FNode, sign: bool = False):
150
+ def __init__(self, formula: FNode, sign: bool = False,
151
+ env: Optional[Environment]=None):
131
152
  """
132
153
  :param formula: The target formula
133
154
  :type formula: FNode
155
+ :param env: The environment the goal lives in; the global one if None
134
156
  """
157
+ Goal.__init__(self, env)
135
158
  self.formula = formula
136
159
  self._bv_signed = sign
137
160
 
@@ -156,19 +179,22 @@ class MinMaxGoal(MinimizationGoal):
156
179
  Warning: some Optimizer may not support this goal
157
180
  """
158
181
 
159
- def __init__(self, terms: List[FNode], sign: bool = False):
182
+ def __init__(self, terms: List[FNode], sign: bool = False,
183
+ env: Optional[Environment]=None):
160
184
  """
161
185
  :param terms: List of FNode
186
+ :param env: The environment the goal lives in; the global one if None
162
187
  """
188
+ if env is None:
189
+ env = get_env()
163
190
  if len(terms) == 0:
164
191
  raise PysmtValueError("MinMaxGoal requires at least one term")
165
- elif terms[0].get_type().is_bv_type():
166
- formula = get_env().formula_manager.MaxBV(sign, terms)
192
+ elif env.stc.get_type(terms[0]).is_bv_type():
193
+ formula = env.formula_manager.MaxBV(sign, terms)
167
194
  else:
168
- formula = get_env().formula_manager.Max(terms)
169
- MinimizationGoal.__init__(self, formula)
195
+ formula = env.formula_manager.Max(terms)
196
+ MinimizationGoal.__init__(self, formula, sign, env=env)
170
197
  self.terms = terms
171
- self._bv_signed = sign
172
198
 
173
199
  def is_minmax_goal(self) -> bool:
174
200
  return True
@@ -185,19 +211,22 @@ class MaxMinGoal(MaximizationGoal):
185
211
  Warning: some Optimizer may not support this goal
186
212
  """
187
213
 
188
- def __init__(self, terms: List[FNode], sign: bool = False):
214
+ def __init__(self, terms: List[FNode], sign: bool = False,
215
+ env: Optional[Environment]=None):
189
216
  """
190
217
  :param terms: List of FNode
218
+ :param env: The environment the goal lives in; the global one if None
191
219
  """
220
+ if env is None:
221
+ env = get_env()
192
222
  if len(terms) == 0:
193
223
  raise PysmtValueError("MaxMinGoal requires at least one term")
194
- elif terms[0].get_type().is_bv_type():
195
- formula = get_env().formula_manager.MinBV(sign, terms)
224
+ elif env.stc.get_type(terms[0]).is_bv_type():
225
+ formula = env.formula_manager.MinBV(sign, terms)
196
226
  else:
197
- formula = get_env().formula_manager.Min(terms)
198
- MaximizationGoal.__init__(self, formula)
227
+ formula = env.formula_manager.Min(terms)
228
+ MaximizationGoal.__init__(self, formula, sign, env=env)
199
229
  self.terms = terms
200
- self._bv_signed = sign
201
230
 
202
231
  def is_maxmin_goal(self) -> bool:
203
232
  return True
@@ -211,27 +240,33 @@ class MaxSMTGoal(Goal):
211
240
  MaxSMT goal common to all solvers.
212
241
  """
213
242
 
214
- def __init__(self, real_weights: bool=True):
215
- """Accepts soft clauses and the relative weights"""
243
+ def __init__(self, real_weights: bool=True,
244
+ env: Optional[Environment]=None):
245
+ """Accepts soft clauses and the relative weights
246
+
247
+ :param env: The environment the goal lives in; the global one if None
248
+ """
249
+ Goal.__init__(self, env)
216
250
  self.soft: List[Tuple[FNode, FNode]] = []
217
251
  self._bv_signed = False
218
252
  self._real_weights = real_weights
219
253
 
220
254
  def add_soft_clause(self, clause: FNode, weight: FNode):
221
255
  """Accepts soft clauses and the relative weights"""
222
- mgr = get_env().formula_manager
223
- if not clause.get_type().is_bool_type():
256
+ mgr = self.env.formula_manager
257
+ get_type = self.env.stc.get_type
258
+ if not get_type(clause).is_bool_type():
224
259
  raise PysmtValueError(
225
260
  "Clause '%s' has to be a boolean formula; given type is: '%s'" %
226
- (str(clause), str(clause.get_type()))
261
+ (str(clause), str(get_type(clause)))
227
262
  )
228
263
  if isinstance(weight, FNode):
229
264
  if not weight.is_constant():
230
265
  raise PysmtValueError(
231
266
  "Weight '%s' has to be a constant; given type is: '%s'" %
232
- (str(weight), str(weight.get_type()))
267
+ (str(weight), str(get_type(weight)))
233
268
  )
234
- weight_type = weight.get_type()
269
+ weight_type = get_type(weight)
235
270
  if not weight_type.is_real_type() and not weight_type.is_int_type():
236
271
  raise PysmtValueError(
237
272
  "Weight '%s' has to be a real or integer type; given type is: '%s'" %
@@ -240,7 +275,7 @@ class MaxSMTGoal(Goal):
240
275
  if weight_type.is_real_type() and not self._real_weights:
241
276
  raise PysmtValueError(
242
277
  "Weight '%s' has to be an integer because the flag 'real_weights' is set to 'False'; given type is: '%s'" %
243
- (str(weight), str(weight.get_type()))
278
+ (str(weight), str(weight_type))
244
279
  )
245
280
  if weight_type.is_int_type() and self._real_weights:
246
281
  weight = mgr.Real(cast(int, weight.constant_value()))
@@ -260,7 +295,7 @@ class MaxSMTGoal(Goal):
260
295
 
261
296
  def term(self) -> FNode:
262
297
  formula = None
263
- mgr = get_env().formula_manager
298
+ mgr = self.env.formula_manager
264
299
  zero = mgr.Real(0) if self.real_weights() else mgr.Int(0)
265
300
  for (c, w) in self.soft:
266
301
  if formula is not None:
@@ -21,7 +21,7 @@ import warnings
21
21
  from pysmt.solvers.solver import Solver
22
22
  from pysmt.exceptions import PysmtValueError, GoalNotSupportedError
23
23
  from pysmt.optimization.goal import Goal, MaxSMTGoal, MinimizationGoal, MaximizationGoal
24
- from pysmt.typing import INT, REAL, BVType, _BVType
24
+ from pysmt.typing import INT, REAL, _BVType
25
25
  from pysmt.logics import LIA, LRA, BV, QF_LIRA, Logic
26
26
  from pysmt.environment import Environment
27
27
  from pysmt.fnode import FNode
@@ -118,7 +118,7 @@ class Optimizer(Solver):
118
118
  elif otype.is_real_type():
119
119
  return REAL
120
120
  elif otype.is_bv_type():
121
- return BVType(otype.width)
121
+ return self.environment.type_manager.BVType(otype.width)
122
122
  else:
123
123
  raise PysmtValueError("Invalid optimization function type: %s" % otype)
124
124
 
@@ -263,7 +263,7 @@ class OptSearchInterval(OptComparationFunctions):
263
263
 
264
264
  lower, upper = None, None
265
265
  if not goal.is_maxsmt_goal():
266
- term_type = goal.term().get_type()
266
+ term_type = environment.stc.get_type(goal.term())
267
267
  # For bit-vectors, start lower and upper bounds to their width limit
268
268
  if term_type.is_bv_type():
269
269
  assert isinstance(term_type, _BVType)
@@ -320,7 +320,7 @@ class OptSearchInterval(OptComparationFunctions):
320
320
  l = self._upper - (cast(Union[int, Fraction], abs(self._upper)) + 1)
321
321
  elif self._lower is not None and self._upper is None:
322
322
  u = self._lower + cast(Union[int, Fraction], abs(self._lower)) + 1
323
- term_type = self._obj.term().get_type()
323
+ term_type = self.environment.stc.get_type(self._obj.term())
324
324
  assert l is not None and u is not None
325
325
  if term_type.is_int_type() or term_type.is_bv_type():
326
326
  pivot = (l + u) // 2
@@ -417,8 +417,9 @@ class OptPareto(OptComparationFunctions):
417
417
  return correct_operator(self.goal.term(), self.val)
418
418
 
419
419
 
420
- def _warn_diverge_real_goal(goal: Goal):
421
- if (goal.is_maximization_goal() or goal.is_minimization_goal()) and goal.term().get_type().is_real_type():
420
+ def _warn_diverge_real_goal(goal: Goal, env: Environment):
421
+ if (goal.is_maximization_goal() or goal.is_minimization_goal()) and \
422
+ env.stc.get_type(goal.term()).is_real_type():
422
423
  warnings.warn("Algorithm might diverge on Real minimization/maximization objectives.")
423
424
 
424
425
 
@@ -488,9 +489,9 @@ class ExternalOptimizerMixin(Optimizer):
488
489
  """
489
490
  Core algorithm for the optimization process.
490
491
  Based on the strategy, it will either perform a linear or binary search"""
491
- _warn_diverge_real_goal(goal)
492
+ _warn_diverge_real_goal(goal, self.environment)
492
493
  if goal.is_maxsmt_goal():
493
- goal = MaximizationGoal(goal.term())
494
+ goal = MaximizationGoal(goal.term(), env=self.environment)
494
495
  model = None
495
496
  client_data = self._setup()
496
497
 
@@ -528,7 +529,7 @@ class ExternalOptimizerMixin(Optimizer):
528
529
  objs = [OptPareto(goal, self.environment) for goal in goals]
529
530
 
530
531
  for g in goals:
531
- _warn_diverge_real_goal(g)
532
+ _warn_diverge_real_goal(g, self.environment)
532
533
 
533
534
  terminated = False
534
535
  client_data = self._setup()
@@ -276,7 +276,8 @@ class TheoryOracle(walkers.DagWalker):
276
276
  theory_out = theory_out.combine(t)
277
277
  # Check for non-linear counting the arguments having at least
278
278
  # one free variable
279
- if sum(1 for x in formula.args() if x.get_free_variables()) > 1:
279
+ if sum(1 for x in formula.args()
280
+ if self.env.fvo.get_free_variables(x)) > 1:
280
281
  theory_out = theory_out.set_linear(False)
281
282
  # This is not in DL anymore
282
283
  theory_out = theory_out.set_difference_logic(False)
@@ -324,9 +325,10 @@ class TheoryOracle(walkers.DagWalker):
324
325
  for t in args[1:]:
325
326
  theory_out = theory_out.combine(t)
326
327
  # Check for non-linear
328
+ get_free_vars = self.env.fvo.get_free_variables
327
329
  left, right = formula.args()
328
- if len(left.get_free_variables()) != 0 and \
329
- len(right.get_free_variables()) != 0:
330
+ if len(get_free_vars(left)) != 0 and \
331
+ len(get_free_vars(right)) != 0:
330
332
  theory_out = theory_out.set_linear(False)
331
333
  elif formula.arg(1).is_zero():
332
334
  # DivBy0 is non-linear
@@ -306,7 +306,7 @@ class BVTypeTok(GrammarSymbol):
306
306
  self.width = width
307
307
 
308
308
  def nud(self, parser):
309
- return types.BVType(self.width)
309
+ return parser.env.type_manager.BVType(self.width)
310
310
 
311
311
  class IntTypeTok(GrammarSymbol):
312
312
  def nud(self, parser):
@@ -369,7 +369,7 @@ class OpenArrayTypeTok(GrammarSymbol):
369
369
  parser.expect(ClosePar, ")")
370
370
  return parser.mgr.Array(idx_type, default)
371
371
  else:
372
- return types.ArrayType(idx_type, el_type)
372
+ return parser.env.type_manager.ArrayType(idx_type, el_type)
373
373
 
374
374
 
375
375
  class OpenPar(GrammarSymbol):
@@ -40,6 +40,7 @@ class CNFizer(DagWalker):
40
40
  DagWalker.__init__(self, environment)
41
41
 
42
42
  self.mgr = self.env.formula_manager
43
+ self.simplify = self.env.simplifier.simplify
43
44
  self._introduced_variables: Dict[FNode, FNode] = {}
44
45
 
45
46
  def _key_var(self, formula: FNode) -> FNode:
@@ -72,7 +73,7 @@ class CNFizer(DagWalker):
72
73
  # Prune clauses as ~tl -> l1 v ... v lk
73
74
  simp = None
74
75
  break
75
- elif lit == self.mgr.Not(tl).simplify():
76
+ elif lit == self.simplify(self.mgr.Not(tl)):
76
77
  # Simplify tl -> l1 v ... v lk
77
78
  # into l1 v ... v lk
78
79
  continue
@@ -111,7 +112,7 @@ class CNFizer(DagWalker):
111
112
  return args[0]
112
113
 
113
114
  k = self._key_var(formula)
114
- _cnf = [frozenset([k] + [self.mgr.Not(a).simplify() for a,_ in args])]
115
+ _cnf = [frozenset([k] + [self.simplify(self.mgr.Not(a)) for a,_ in args])]
115
116
  for a,c in args:
116
117
  _cnf.append(frozenset([a, self.mgr.Not(k)]))
117
118
  for clause in c:
@@ -136,15 +137,15 @@ class CNFizer(DagWalker):
136
137
  elif a.is_false():
137
138
  return self.mgr.TRUE(), CNFizer.TRUE_CNF
138
139
  else:
139
- return self.mgr.Not(a).simplify(), _cnf
140
+ return self.simplify(self.mgr.Not(a)), _cnf
140
141
 
141
142
  def walk_implies(self, formula, args, **kwargs):
142
143
  a, cnf_a = args[0]
143
144
  b, cnf_b = args[1]
144
145
 
145
146
  k = self._key_var(formula)
146
- not_a = self.mgr.Not(a).simplify()
147
- not_b = self.mgr.Not(b).simplify()
147
+ not_a = self.simplify(self.mgr.Not(a))
148
+ not_b = self.simplify(self.mgr.Not(b))
148
149
  not_k = self.mgr.Not(k)
149
150
 
150
151
  return k, (cnf_a | cnf_b | frozenset([frozenset([not_a, b, not_k]),
@@ -156,8 +157,8 @@ class CNFizer(DagWalker):
156
157
  b, cnf_b = args[1]
157
158
 
158
159
  k = self._key_var(formula)
159
- not_a = self.mgr.Not(a).simplify()
160
- not_b = self.mgr.Not(b).simplify()
160
+ not_a = self.simplify(self.mgr.Not(a))
161
+ not_b = self.simplify(self.mgr.Not(b))
161
162
  not_k = self.mgr.Not(k)
162
163
 
163
164
  return k, (cnf_a | cnf_b | frozenset([frozenset([not_a, not_b, k]),
@@ -184,9 +185,9 @@ class CNFizer(DagWalker):
184
185
  else:
185
186
  (i,cnf_i),(t,cnf_t),(e,cnf_e) = args
186
187
  k = self._key_var(formula)
187
- not_i = self.mgr.Not(i).simplify()
188
- not_t = self.mgr.Not(t).simplify()
189
- not_e = self.mgr.Not(e).simplify()
188
+ not_i = self.simplify(self.mgr.Not(i))
189
+ not_t = self.simplify(self.mgr.Not(t))
190
+ not_e = self.simplify(self.mgr.Not(e))
190
191
  not_k = self.mgr.Not(k)
191
192
 
192
193
  return k, (cnf_i | cnf_t | cnf_e |
@@ -198,7 +199,7 @@ class CNFizer(DagWalker):
198
199
  @handles(op.THEORY_OPERATORS)
199
200
  def walk_theory_op(self, formula, **kwargs):
200
201
  #pylint: disable=unused-argument
201
- if formula.get_type().is_bool_type():
202
+ if self.env.stc.get_type(formula).is_bool_type():
202
203
  return formula, CNFizer.TRUE_CNF
203
204
  return CNFizer.THEORY_PLACEHOLDER
204
205
 
@@ -305,7 +306,7 @@ class PolarityCNFizer(CNFizer):
305
306
  if pol:
306
307
  _cnf.extend(frozenset([a, self.mgr.Not(k)]) for a, _ in args)
307
308
  else:
308
- _cnf.extend([frozenset([k] + [self.mgr.Not(a).simplify() for a, _ in args])])
309
+ _cnf.extend([frozenset([k] + [self.simplify(self.mgr.Not(a)) for a, _ in args])])
309
310
 
310
311
  return k, frozenset(_cnf)
311
312
 
@@ -318,7 +319,7 @@ class PolarityCNFizer(CNFizer):
318
319
  if pol:
319
320
  _cnf.extend([frozenset([self.mgr.Not(k)] + [a for a, _ in args])])
320
321
  else:
321
- _cnf.extend(frozenset([k, self.mgr.Not(a).simplify()]) for a, c in args)
322
+ _cnf.extend(frozenset([k, self.simplify(self.mgr.Not(a))]) for a, c in args)
322
323
 
323
324
  return k, frozenset(_cnf)
324
325
 
@@ -327,8 +328,8 @@ class PolarityCNFizer(CNFizer):
327
328
  b, cnf_b = args[1]
328
329
 
329
330
  k = self._key_var(formula)
330
- not_a = self.mgr.Not(a).simplify()
331
- not_b = self.mgr.Not(b).simplify()
331
+ not_a = self.simplify(self.mgr.Not(a))
332
+ not_b = self.simplify(self.mgr.Not(b))
332
333
  not_k = self.mgr.Not(k)
333
334
  _cnf = []
334
335
  if pol:
@@ -345,8 +346,8 @@ class PolarityCNFizer(CNFizer):
345
346
  _, cnf_bn = args[3]
346
347
 
347
348
  k = self._key_var(formula)
348
- not_a = self.mgr.Not(a).simplify()
349
- not_b = self.mgr.Not(b).simplify()
349
+ not_a = self.simplify(self.mgr.Not(a))
350
+ not_b = self.simplify(self.mgr.Not(b))
350
351
  not_k = self.mgr.Not(k)
351
352
 
352
353
  return k, (cnf_ap | cnf_an | cnf_bp | cnf_bn
@@ -360,9 +361,9 @@ class PolarityCNFizer(CNFizer):
360
361
  return CNFizer.THEORY_PLACEHOLDER
361
362
  (i, cnf_ip), (_, cnf_in), (t, cnf_t), (e, cnf_e) = args
362
363
  k = self._key_var(formula)
363
- not_i = self.mgr.Not(i).simplify()
364
- not_t = self.mgr.Not(t).simplify()
365
- not_e = self.mgr.Not(e).simplify()
364
+ not_i = self.simplify(self.mgr.Not(i))
365
+ not_t = self.simplify(self.mgr.Not(t))
366
+ not_e = self.simplify(self.mgr.Not(e))
366
367
  not_k = self.mgr.Not(k)
367
368
 
368
369
  _cnf = []
@@ -590,7 +591,7 @@ class PrenexNormalizer(DagWalker):
590
591
  # matrix. If we find a quantifier over a variable in this set
591
592
  # we need to alpha-rename before adding the quantifier to the
592
593
  # final list and accumulate the matrix.
593
- reserved = formula.get_free_variables()
594
+ reserved = self.env.fvo.get_free_variables(formula)
594
595
 
595
596
  # We iterate to each argument, each could have a sequence of
596
597
  # quantifiers that we need to merge
@@ -603,7 +604,7 @@ class PrenexNormalizer(DagWalker):
603
604
  # we need alpha-renaming: prepare the substitution map
604
605
  sub = dict((v,self.mgr.FreshSymbol(v.symbol_type()))
605
606
  for v in needs_rename)
606
- sub_matrix = sub_matrix.substitute(sub)
607
+ sub_matrix = self.env.substituter.substitute(sub_matrix, sub)
607
608
 
608
609
  # The new variables for this quantifiers will be
609
610
  # its old variables, minus the one needing
@@ -1109,7 +1110,7 @@ def propagate_toplevel(formula: FNode, env: Optional["pysmt.environment.Environm
1109
1110
  else:
1110
1111
  sigma[k] = v
1111
1112
 
1112
- res = formula.substitute(sigma)
1113
+ res = env.substituter.substitute(formula, sigma)
1113
1114
  if preserve_equivalence:
1114
1115
  res = mgr.And(res, mgr.And([mgr.Equals(k, sigma[k]) for k in sigma]))
1115
- return res.simplify() if do_simplify else res
1116
+ return env.simplifier.simplify(res) if do_simplify else res
@@ -265,7 +265,8 @@ class Simplifier(pysmt.walkers.DagWalker):
265
265
  assert len(args) == 1
266
266
  sf = args[0]
267
267
 
268
- varset = set(formula.quantifier_vars()).intersection(sf.get_free_variables())
268
+ varset = set(formula.quantifier_vars()).intersection(
269
+ self.env.fvo.get_free_variables(sf))
269
270
 
270
271
  if len(varset) == 0:
271
272
  return sf
@@ -276,7 +277,8 @@ class Simplifier(pysmt.walkers.DagWalker):
276
277
  assert len(args) == 1
277
278
  sf = args[0]
278
279
 
279
- varset = set(formula.quantifier_vars()).intersection(sf.get_free_variables())
280
+ varset = set(formula.quantifier_vars()).intersection(
281
+ self.env.fvo.get_free_variables(sf))
280
282
 
281
283
  if len(varset) == 0:
282
284
  return sf
@@ -1151,7 +1153,7 @@ class BddSimplifier(Simplifier):
1151
1153
  def abstract_and_simplify(self, formula: FNode) -> FNode:
1152
1154
  abs_formula = self.walk(formula)
1153
1155
  abs_res = self.back(self.convert(abs_formula))
1154
- res = abs_res.substitute(self.ba_map)
1156
+ res = self.env.substituter.substitute(abs_res, self.ba_map)
1155
1157
  return res
1156
1158
 
1157
1159
  @handles(op.RELATIONS)
@@ -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,22 +407,27 @@ 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),
@@ -407,12 +446,12 @@ class SmtLibParser(object):
407
446
  'bvlshr': self._operator_adapter(mgr.BVLShr),
408
447
  'bvsub': self._operator_adapter(mgr.BVSub),
409
448
  'bvult': self._operator_adapter(mgr.BVULT),
410
- 'bvxor': self._operator_adapter(mgr.BVXor),
449
+ 'bvxor': self._operator_adapter(_left_assoc(mgr.BVXor)),
411
450
  '_': self._smtlib_underscore,
412
451
  # Extended Functions
413
452
  'bvnand': self._operator_adapter(mgr.BVNand),
414
453
  'bvnor': self._operator_adapter(mgr.BVNor),
415
- 'bvxnor': self._operator_adapter(mgr.BVXnor),
454
+ 'bvxnor': self._operator_adapter(_left_assoc(mgr.BVXnor)),
416
455
  'bvcomp': self._operator_adapter(mgr.BVComp),
417
456
  'bvsdiv': self._operator_adapter(mgr.BVSDiv),
418
457
  'bvsrem': self._operator_adapter(mgr.BVSRem),
@@ -492,7 +531,7 @@ class SmtLibParser(object):
492
531
  self.cache.update({'false': mgr.FALSE(), 'true': mgr.TRUE()})
493
532
 
494
533
  def _minus_or_uminus(self, *args) -> FNode:
495
- """Utility function that handles both unary and binary minus"""
534
+ """Utility function that handles unary and n-ary minus"""
496
535
  mgr = self.env.formula_manager
497
536
  if len(args) == 1:
498
537
  lty = self.get_type(args[0])
@@ -506,9 +545,8 @@ class SmtLibParser(object):
506
545
  return mgr.Real(-1 * args[0].constant_value())
507
546
  mult = mgr.Real(-1)
508
547
  return mgr.Times(mult, args[0])
509
- else:
510
- assert len(args) == 2
511
- 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)
512
550
 
513
551
  def _enter_smtlib_as(self, stack: List[List[Union[Callable, FNode, Any]]], tokens: Tokenizer, key: str):
514
552
  """Utility function that handles 'as' that is a special function in SMTLIB"""
@@ -1581,9 +1619,11 @@ class SmtLibZ3Parser(SmtLibParser):
1581
1619
  self.interpreted['ubv_to_int'] = self._operator_adapter(mgr.BVToNatural)
1582
1620
 
1583
1621
  def _ext_rotate_left(self, x, y):
1584
- return self.env.formula_manager.BVRol(x, y.simplify().constant_value())
1622
+ amount = self.env.simplifier.simplify(y).constant_value()
1623
+ return self.env.formula_manager.BVRol(x, amount)
1585
1624
 
1586
1625
  def _ext_rotate_right(self, x, y):
1587
- return self.env.formula_manager.BVRor(x, y.simplify().constant_value())
1626
+ amount = self.env.simplifier.simplify(y).constant_value()
1627
+ return self.env.formula_manager.BVRor(x, amount)
1588
1628
 
1589
1629
  # EOC SmtLibZ3Parser