PySMT 0.9.7.dev452__py2.py3-none-any.whl → 0.9.7.dev461__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pysmt/__init__.py CHANGED
@@ -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", 452)
22
+ VERSION: Union[Tuple[int, int, int], Tuple[int, int, int, str, int]] = (0, 9, 7, "dev", 461)
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
pysmt/exceptions.py CHANGED
@@ -131,6 +131,16 @@ class PysmtImportError(PysmtException, ImportError):
131
131
  class PysmtValueError(PysmtException, ValueError):
132
132
  pass
133
133
 
134
+ class PysmtEmptySymbolNameError(PysmtValueError):
135
+ """A symbol with the empty name was built, but they are not enabled."""
136
+
137
+ def __init__(self):
138
+ PysmtValueError.__init__(
139
+ self,
140
+ "The empty string is not a valid symbol name. SMT-LIB allows it "
141
+ "(as `||`), but not every solver does, so pySMT requires it to be "
142
+ "enabled explicitly by setting `env.allow_empty_var_names = True`.")
143
+
134
144
  class PysmtTypeError(PysmtException, TypeError):
135
145
  pass
136
146
 
pysmt/factory.py CHANGED
@@ -190,13 +190,15 @@ class Factory(object):
190
190
 
191
191
  if logic is None:
192
192
  logic = default_logic
193
+ assert isinstance(logic, Logic)
193
194
 
194
195
  solvers = self._filter_solvers(solver_list, logic=logic)
195
196
 
196
197
  if solvers is not None and len(solvers) > 0:
197
198
  # Pick the first solver based on preference list
198
199
  preference_list = self.preferences[solver_type]
199
- SolverClass = self._pick_favorite(preference_list, solver_list, solvers)
200
+ SolverClass = self._pick_favorite(preference_list, solver_list,
201
+ solvers, logic)
200
202
  closer_logic = get_closer_logic(SolverClass.LOGICS, logic)
201
203
  return SolverClass, closer_logic
202
204
 
@@ -205,7 +207,16 @@ class Factory(object):
205
207
  (solver_type, logic))
206
208
 
207
209
 
208
- def _pick_favorite(self, preference_list: List[str], solver_list: Dict[str, Any], solvers: Dict[str, Any]) -> Type[Solver]:
210
+ def _pick_favorite(self, preference_list: List[str], solver_list: Dict[str, Any],
211
+ solvers: Dict[str, Any], logic: Logic) -> Type[Solver]:
212
+ if not logic.theory.linear:
213
+ # The MathSAT family solves nonlinear problems by incremental
214
+ # linearization, which may not terminate on satisfiable instances
215
+ # whose solutions are all irrational (see the note on
216
+ # MathSAT5Solver.LOGICS). Prefer any other capable solver, but keep
217
+ # them as a fallback when nothing else supports the logic.
218
+ preference_list = sorted(preference_list,
219
+ key=lambda n: n.startswith(("msat", "optimsat")))
209
220
  for candidate in preference_list:
210
221
  if candidate in solvers:
211
222
  return solver_list[candidate]
pysmt/formula.py CHANGED
@@ -45,7 +45,8 @@ import pysmt.operators as op
45
45
  from pysmt.fnode import FNode
46
46
  from pysmt.typing import PySMTType
47
47
  from pysmt.fnode import FNode, FNodeContent
48
- from pysmt.exceptions import UndefinedSymbolError, PysmtValueError,PysmtTypeError
48
+ from pysmt.exceptions import (UndefinedSymbolError, PysmtValueError,
49
+ PysmtTypeError, PysmtEmptySymbolNameError)
49
50
  from pysmt.walkers.identitydag import IdentityDagWalker
50
51
  from pysmt.constants import Fraction, Numeral
51
52
  from pysmt.constants import (is_pysmt_fraction,
@@ -107,7 +108,7 @@ class FormulaManager(object):
107
108
 
108
109
  def _create_symbol(self, name: str, typename: PySMTType=types.BOOL) -> FNode:
109
110
  if len(name) == 0 and not self.env.allow_empty_var_names:
110
- raise PysmtValueError("Empty string is not a valid name")
111
+ raise PysmtEmptySymbolNameError()
111
112
  if not isinstance(typename, types.PySMTType):
112
113
  raise PysmtValueError("typename must be a PySMTType.")
113
114
  n = self.create_node(node_type=op.SYMBOL,
pysmt/parsing.py CHANGED
@@ -22,7 +22,8 @@ from typing import List, Optional
22
22
  import pysmt
23
23
  import pysmt.typing as types
24
24
  from pysmt.environment import get_env
25
- from pysmt.exceptions import PysmtSyntaxError, UndefinedSymbolError
25
+ from pysmt.exceptions import (PysmtSyntaxError, UndefinedSymbolError,
26
+ PysmtEmptySymbolNameError)
26
27
  from pysmt.constants import Fraction
27
28
 
28
29
 
@@ -332,6 +333,9 @@ class Constant(GrammarSymbol):
332
333
  class Identifier(GrammarSymbol):
333
334
  def __init__(self, name, env):
334
335
  GrammarSymbol.__init__(self)
336
+ if name == "" and not env.allow_empty_var_names:
337
+ # Otherwise this would be reported as an undefined symbol
338
+ raise PysmtEmptySymbolNameError()
335
339
  self.value = env.formula_manager.get_symbol(name)
336
340
  if self.value is None:
337
341
  raise UndefinedSymbolError(name)
pysmt/solvers/msat.py CHANGED
@@ -35,7 +35,7 @@ from pysmt.utils import assert_not_none
35
35
  from pysmt.walkers import DagWalker
36
36
  from pysmt.exceptions import (SolverReturnedUnknownResultError,
37
37
  InternalSolverError,
38
- NonLinearError, PysmtValueError, PysmtTypeError,
38
+ PysmtValueError, PysmtTypeError,
39
39
  ConvertExpressionError)
40
40
  from pysmt.decorators import clear_pending_pop, catch_conversion_error
41
41
  from pysmt.solvers.qelim import QuantifierEliminator
@@ -180,9 +180,37 @@ class MathSAT5Solver(IncrementalTrackingSolver, UnsatCoreSolver, SmtLibBasicSolv
180
180
 
181
181
  __lib_name__ = "mathsat"
182
182
 
183
+ # NOTE on nonlinear arithmetic (QF_NRA/QF_NIA, and OptiMathSAT, which
184
+ # inherits this LOGICS set).
185
+ #
186
+ # MathSAT solves nonlinear problems by incremental linearization: the
187
+ # nonlinear terms are abstracted away as free symbols and then
188
+ # progressively constrained with linear lemmas, until either the
189
+ # abstraction is refuted (UNSAT) or a model of the abstraction happens to
190
+ # be a model of the original formula (SAT). Every model MathSAT can build
191
+ # therefore assigns *rational* values only; irrational (algebraic) values
192
+ # are not representable.
193
+ #
194
+ # This is fine for UNSAT instances and for SAT instances that admit a
195
+ # rational solution, but not for SAT instances whose solutions are all
196
+ # irrational: on e.g. `x * x = 2` no finite set of linear lemmas refutes
197
+ # the abstraction, and no model of the abstraction ever satisfies the
198
+ # original constraint, so the refinement loop does not terminate. MathSAT
199
+ # diverges rather than returning `unknown`, and there is currently no
200
+ # option to bound the number of refinement rounds. The only available
201
+ # mitigation is a soft timeout installed with `msat_set_termination_test`,
202
+ # which pySMT does not expose, and which could only be wall-clock based
203
+ # (hence non-reproducible), since the internal statistics that would give a
204
+ # deterministic budget cannot be retrieved through the API.
205
+ # See the discussion in https://github.com/pysmt/pysmt/pull/844.
206
+ #
207
+ # Practical consequences:
208
+ # - formulas that need algebraic witnesses must be sent to a solver with a
209
+ # complete NRA decision procedure (z3, cvc5);
210
+ # - the nonlinear examples and tests run against MathSAT are kept
211
+ # rational on purpose (e.g. `r * r = 4.0` instead of `r * r = 2.0`).
183
212
  LOGICS: Iterable[Logic] = PYSMT_QF_LOGICS -\
184
- set(l for l in PYSMT_QF_LOGICS \
185
- if not l.theory.linear or l.theory.strings)
213
+ set(l for l in PYSMT_QF_LOGICS if l.theory.strings)
186
214
 
187
215
  OptionsClass = MathSATOptions
188
216
 
@@ -407,6 +435,7 @@ class MSatConverter(Converter, DagWalker):
407
435
  self._msat_lib.MSAT_TAG_LEQ: self._back_adapter(self.mgr.LE),
408
436
  self._msat_lib.MSAT_TAG_PLUS: self._back_adapter(self.mgr.Plus),
409
437
  self._msat_lib.MSAT_TAG_TIMES: self._back_adapter(self.mgr.Times),
438
+ self._msat_lib.MSAT_TAG_DIVIDE: self._back_adapter(self.mgr.Div),
410
439
  self._msat_lib.MSAT_TAG_BV_MUL: self._back_adapter(self.mgr.BVMul),
411
440
  self._msat_lib.MSAT_TAG_BV_ADD: self._back_adapter(self.mgr.BVAdd),
412
441
  self._msat_lib.MSAT_TAG_BV_UDIV: self._back_adapter(self.mgr.BVUDiv),
@@ -463,6 +492,7 @@ class MSatConverter(Converter, DagWalker):
463
492
  self._msat_lib.MSAT_TAG_LEQ: self._sig_most_generic_bool_binary,
464
493
  self._msat_lib.MSAT_TAG_PLUS: self._sig_most_generic_bool_binary,
465
494
  self._msat_lib.MSAT_TAG_TIMES: self._sig_most_generic_bool_binary,
495
+ self._msat_lib.MSAT_TAG_DIVIDE: self._sig_most_generic_bool_binary,
466
496
  self._msat_lib.MSAT_TAG_FLOOR: lambda term, args:\
467
497
  self.tm.FunctionType(types.INT, [types.REAL]),
468
498
  self._msat_lib.MSAT_TAG_BV_MUL: self._sig_binary,
@@ -700,7 +730,7 @@ class MSatConverter(Converter, DagWalker):
700
730
  val, width = map(int, str(term).split("_"))
701
731
  res = self.mgr.BV(val, width)
702
732
  elif self._msat_lib.msat_term_is_constant(self.msat_env(), term):
703
- rep = self._msat_lib.msat_term_repr(term)
733
+ rep = self._restore_empty(self._msat_lib.msat_term_repr(term))
704
734
  ty = self._msat_lib.msat_term_get_type(term)
705
735
  if self._msat_lib.msat_term_is_boolean_constant(self.msat_env(), term):
706
736
  res = self.mgr.Symbol(rep, types.BOOL)
@@ -987,16 +1017,33 @@ class MSatConverter(Converter, DagWalker):
987
1017
 
988
1018
  def walk_times(self, formula: FNode, args: List[Any], **kwargs) -> Any:
989
1019
  res = args[0]
990
- nl_count = 0 if self._msat_lib.msat_term_is_number(self.msat_env(), res) else 1
991
1020
  for x in args[1:]:
992
- if not self._msat_lib.msat_term_is_number(self.msat_env(), x):
993
- nl_count += 1
994
- if nl_count >= 2:
995
- raise NonLinearError(formula)
996
- else:
997
- res = self._msat_lib.msat_make_times(self.msat_env(), res, x)
1021
+ res = self._msat_lib.msat_make_times(self.msat_env(), res, x)
998
1022
  return res
999
1023
 
1024
+ def walk_pow(self, formula: FNode, args: List[Any], **kwargs) -> Any:
1025
+ # MathSAT rejects exponents it cannot handle by returning an error
1026
+ # term, which convert() turns into an InternalSolverError.
1027
+ return self._msat_lib.msat_make_pow(self.msat_env(), args[0], args[1])
1028
+
1029
+ def walk_div(self, formula: FNode, args: List[Any], **kwargs) -> Any:
1030
+ num, den = args
1031
+ if self.env.stc.get_type(formula).is_real_type():
1032
+ return self._msat_lib.msat_make_divide(self.msat_env(), num, den)
1033
+ # msat_make_divide is real division, while pySMT follows the SMT-LIB
1034
+ # semantics for integers: den >= 0 ? floor(num/den) : ceil(num/den).
1035
+ # ceil(a) is rewritten as -floor(-a).
1036
+ zero = self._msat_lib.msat_make_number(self.msat_env(), "0")
1037
+ neg = self._msat_lib.msat_make_number(self.msat_env(), "-1")
1038
+ cond = self._msat_lib.msat_make_leq(self.msat_env(), zero, den)
1039
+ div = self._msat_lib.msat_make_floor(self.msat_env(),
1040
+ self._msat_lib.msat_make_divide(self.msat_env(), num, den))
1041
+ n_den = self._msat_lib.msat_make_times(self.msat_env(), neg, den)
1042
+ n_div = self._msat_lib.msat_make_times(self.msat_env(), neg,
1043
+ self._msat_lib.msat_make_floor(self.msat_env(),
1044
+ self._msat_lib.msat_make_divide(self.msat_env(), num, n_den)))
1045
+ return self._msat_lib.msat_make_term_ite(self.msat_env(), cond, div, n_div)
1046
+
1000
1047
  def walk_function(self, formula: FNode, args: List[Any], **kwargs) -> Any:
1001
1048
  name = formula.function_name()
1002
1049
  if name not in self.symbol_to_decl:
@@ -1094,10 +1141,10 @@ class MSatConverter(Converter, DagWalker):
1094
1141
  if not var.is_symbol():
1095
1142
  raise PysmtTypeError("Trying to declare as a variable something "
1096
1143
  "that is not a symbol: %s" % var)
1097
- if var.symbol_name() not in self.symbol_to_decl:
1144
+ if var not in self.symbol_to_decl:
1098
1145
  tp = self._type_to_msat(var.symbol_type())
1099
1146
  decl = self._msat_lib.msat_declare_function(self.msat_env(),
1100
- var.symbol_name(),
1147
+ self._rename_empty(var.symbol_name()),
1101
1148
  tp)
1102
1149
  if self._msat_lib.MSAT_ERROR_DECL(decl):
1103
1150
  msat_msg = self._msat_lib.msat_last_error_message(self.msat_env())
pysmt/solvers/solver.py CHANGED
@@ -16,6 +16,7 @@
16
16
  # limitations under the License.
17
17
  #
18
18
  from fractions import Fraction
19
+ import pysmt.formula
19
20
  from pysmt.typing import BOOL
20
21
  from pysmt.solvers.options import SolverOptions
21
22
  from pysmt.decorators import clear_pending_pop
@@ -566,3 +567,25 @@ class Converter(object):
566
567
  def back(self, expr: Any, *args: Any, **kwargs: Any) -> FNode:
567
568
  """Convert an expression of the Solver into a PySMT term."""
568
569
  raise NotImplementedError
570
+
571
+ # SMT-LIB allows a symbol with the empty name (`||`), but some
572
+ # solvers refuse to declare it (MathSAT) or cannot print it back
573
+ # (Z3). Those converters rename it to a fresh, unused name on the
574
+ # way in and undo the renaming on the way out.
575
+ _empty_name_subst: Optional[str] = None
576
+ mgr: 'pysmt.formula.FormulaManager'
577
+
578
+ def _rename_empty(self, name: str) -> str:
579
+ """Map a pySMT symbol name to the name used by the solver."""
580
+ if name != "":
581
+ return name
582
+ if self._empty_name_subst is None:
583
+ i = 0
584
+ while ("__pysmt_empty_name_%d" % i) in self.mgr.symbols:
585
+ i += 1
586
+ self._empty_name_subst = "__pysmt_empty_name_%d" % i
587
+ return self._empty_name_subst
588
+
589
+ def _restore_empty(self, name: str) -> str:
590
+ """Inverse of _rename_empty()."""
591
+ return "" if name == self._empty_name_subst else name
pysmt/solvers/z3.py CHANGED
@@ -573,7 +573,7 @@ class Z3Converter(Converter, DagWalker):
573
573
  else:
574
574
  # it must be a symbol
575
575
  try:
576
- return self.mgr.get_symbol(str(expr))
576
+ return self.mgr.get_symbol(self._restore_empty(str(expr)))
577
577
  except UndefinedSymbolError:
578
578
  import warnings
579
579
  symb_type = self._z3_to_type(expr.sort())
@@ -582,7 +582,7 @@ class Z3Converter(Converter, DagWalker):
582
582
  template="__z3_%d")
583
583
  elif z3.is_function(expr):
584
584
  # This needs to be after we try to convert regular Symbols
585
- fsymbol = self.mgr.get_symbol(expr.decl().name())
585
+ fsymbol = self.mgr.get_symbol(self._restore_empty(expr.decl().name()))
586
586
  return self.mgr.Function(fsymbol, args)
587
587
 
588
588
  # If we reach this point, we did not manage to translate the expression
@@ -622,6 +622,11 @@ class Z3Converter(Converter, DagWalker):
622
622
  expr.ast)
623
623
  stream_in = StringIO(s)
624
624
  r = parser.get_script(stream_in).get_last_formula(self.mgr)
625
+ if self._empty_name_subst is not None:
626
+ # Undo the renaming of the empty symbol name (see Converter)
627
+ src = self.mgr.get_symbol(self._empty_name_subst)
628
+ r = self.env.substituter.substitute(
629
+ r, {src: self.mgr.Symbol("", src.symbol_type())})
625
630
  key = (askey(expr), None)
626
631
  self._back_memoization[key] = r
627
632
  return r
@@ -642,7 +647,7 @@ class Z3Converter(Converter, DagWalker):
642
647
 
643
648
  def walk_symbol(self, formula: FNode, **kwargs) -> z3.Ast:
644
649
  symbol_type = formula.symbol_type()
645
- sname = formula.symbol_name()
650
+ sname = self._rename_empty(formula.symbol_name())
646
651
  z3_sname = z3.Z3_mk_string_symbol(self.ctx.ref(), sname)
647
652
  if symbol_type.is_bool_type():
648
653
  sort_ast = self.z3BoolSort.ast
@@ -756,7 +761,7 @@ class Z3Converter(Converter, DagWalker):
756
761
  z3dom[i] = self._type_to_z3(t).ast
757
762
  z3ret = self._type_to_z3(tp.return_type).ast
758
763
  z3name = z3.Z3_mk_string_symbol(self.ctx.ref(),
759
- func_name.symbol_name())
764
+ self._rename_empty(func_name.symbol_name()))
760
765
  z3func = z3.Z3_mk_func_decl(self.ctx.ref(), z3name,
761
766
  arity, z3dom, z3ret)
762
767
  self._z3_func_decl_cache[func_name] = z3func
pysmt/test/examples.py CHANGED
@@ -925,8 +925,8 @@ def get_full_example_formulae(environment: Optional[Environment]=None) -> List[E
925
925
  logic=pysmt.logics.QF_NRA
926
926
  ),
927
927
 
928
- Example(hr="(2.0 = (r * r))",
929
- expr=Equals(Real(2), Times(r,r)),
928
+ Example(hr="(4.0 = (r * r))",
929
+ expr=Equals(Real(4), Times(r,r)),
930
930
  is_valid=False,
931
931
  is_sat=True,
932
932
  logic=pysmt.logics.QF_NRA
@@ -946,8 +946,8 @@ def get_full_example_formulae(environment: Optional[Environment]=None) -> List[E
946
946
  logic=pysmt.logics.QF_NRA
947
947
  ),
948
948
 
949
- Example(hr="((r * r * r) = 25.0)",
950
- expr=Equals(Times(r, r, r), Real(25)),
949
+ Example(hr="((r * r * r) = 27.0)",
950
+ expr=Equals(Times(r, r, r), Real(27)),
951
951
  is_valid=False,
952
952
  is_sat=True,
953
953
  logic=pysmt.logics.QF_NRA
pysmt/test/test_env.py CHANGED
@@ -203,5 +203,17 @@ class TestEnvironment(TestCase):
203
203
  factory.get_quantifier_eliminator()
204
204
 
205
205
 
206
+ def test_nonlinear_demotes_mathsat(self):
207
+ # The MathSAT family is the last resort on nonlinear logics, but still
208
+ # picked when it is the only capable solver.
209
+ pick = get_env().factory._pick_favorite
210
+ available = {'msat': 'MSAT', 'z3': 'Z3'}
211
+ prefs = ['msat', 'z3']
212
+ self.assertEqual(pick(prefs, available, available, logics.QF_NRA), 'Z3')
213
+ self.assertEqual(pick(prefs, available, available, logics.QF_LRA), 'MSAT')
214
+ only_msat = {'msat': 'MSAT'}
215
+ self.assertEqual(pick(prefs, only_msat, only_msat, logics.QF_NRA), 'MSAT')
216
+
217
+
206
218
  if __name__ == '__main__':
207
219
  main()
pysmt/test/test_nlira.py CHANGED
@@ -24,33 +24,33 @@ from pysmt.shortcuts import FreshSymbol, Times, Equals, Div, Real, Int, Pow
24
24
  from pysmt.shortcuts import Solver, Symbol, And, Not, is_sat
25
25
  from pysmt.typing import REAL, INT
26
26
  from pysmt.exceptions import (ConvertExpressionError,
27
- NonLinearError, InternalSolverError,
27
+ NonLinearError,
28
28
  SolverReturnedUnknownResultError)
29
- from pysmt.logics import QF_NRA
29
+ from pysmt.logics import QF_NRA, QF_NIA
30
30
  from pysmt.constants import Fraction
31
31
 
32
32
 
33
33
  class TestNonLinear(TestCase):
34
34
 
35
- @skipIfSolverNotAvailable("z3")
36
35
  def test_times(self):
37
36
  x = FreshSymbol(REAL)
38
37
  f = Equals(Times(x, x), x)
39
- with Solver(name="z3") as s:
40
- self.assertTrue(s.is_sat(f))
38
+ for sname in self.env.factory.all_solvers(logic=QF_NRA):
39
+ with Solver(name=sname, logic=QF_NRA) as s:
40
+ self.assertTrue(s.is_sat(f), sname)
41
41
 
42
- @skipIfSolverNotAvailable("z3")
43
42
  def test_div(self):
44
43
  x = FreshSymbol(REAL)
45
44
  f = Equals(Div(x, x), x)
46
- with Solver(name="z3") as s:
47
- self.assertTrue(s.is_sat(f))
45
+ for sname in self.env.factory.all_solvers(logic=QF_NRA):
46
+ with Solver(name=sname, logic=QF_NRA) as s:
47
+ self.assertTrue(s.is_sat(f), sname)
48
48
 
49
49
  @skipIfSolverNotAvailable("z3")
50
50
  def test_irrational(self):
51
51
  x = FreshSymbol(REAL)
52
52
  f = Equals(Times(x, x), Real(2))
53
- with Solver(name="z3") as s:
53
+ with Solver(name="z3", logic=QF_NRA) as s:
54
54
  self.assertTrue(s.is_sat(f))
55
55
  model = s.get_model()
56
56
  xval = model[x]
@@ -73,38 +73,34 @@ class TestNonLinear(TestCase):
73
73
 
74
74
  def test_unknownresult(self):
75
75
  x = FreshSymbol(REAL)
76
- f = Equals(Times(x, x), Real(2))
76
+ # 4.0 rather than 2.0: the point here is which solvers reject
77
+ # nonlinear arithmetic, not who can represent an algebraic number.
78
+ f = Equals(Times(x, x), Real(4))
77
79
  for sname in self.env.factory.all_solvers():
78
- with Solver(name=sname) as s:
79
- if sname in ["bdd", "picosat", "btor"]:
80
+ if sname in ["bdd", "picosat", "btor"]:
81
+ with Solver(name=sname) as s:
80
82
  with self.assertRaises(ConvertExpressionError):
81
83
  s.is_sat(f)
82
- elif sname in ["yices", "cvc4", "msat", "optimsat"]:
84
+ elif sname in ["yices", "cvc4"]:
85
+ with Solver(name=sname) as s:
83
86
  with self.assertRaises(NonLinearError):
84
87
  s.is_sat(f)
85
- elif sname in ["cvc5"]:
86
- with self.assertRaises(InternalSolverError):
87
- s.is_sat(f)
88
- else:
89
- res = s.is_sat(f)
90
- self.assertTrue(res, sname)
88
+ else:
89
+ with Solver(name=sname, logic=QF_NRA) as s:
90
+ self.assertTrue(s.is_sat(f), sname)
91
91
  self.assertIn(QF_NRA, s.LOGICS, sname)
92
92
 
93
- @skipIfSolverNotAvailable("z3")
94
93
  def test_integer(self):
95
94
  x = FreshSymbol(INT)
96
- f = Equals(Times(x, x), Int(2))
97
- with Solver(name="z3") as s:
98
- self.assertFalse(s.is_sat(f))
99
-
100
- # f = Equals(Times(Int(4), Pow(x, Int(-1))), Int(2))
101
- # self.assertTrue(is_sat(f, solver_name="z3"))
102
-
103
- # f = Equals(Div(Int(4), x), Int(2))
104
- # self.assertTrue(is_sat(f, solver_name="z3"))
105
-
106
- f = Equals(Times(x, x), Int(16))
107
- self.assertTrue(is_sat(f, solver_name="z3"))
95
+ f1 = Equals(Times(x, x), Int(2))
96
+ f2 = Equals(Times(x, x), Int(16))
97
+ for sname in self.env.factory.all_solvers(logic=QF_NIA):
98
+ for f, expected in ((f1, False), (f2, True)):
99
+ with Solver(name=sname, logic=QF_NIA) as s:
100
+ try:
101
+ self.assertEqual(expected, s.is_sat(f), (sname, f))
102
+ except SolverReturnedUnknownResultError:
103
+ pass
108
104
 
109
105
  @skipIfSolverNotAvailable("z3")
110
106
  def test_div_pow(self):
@@ -29,11 +29,13 @@ from pysmt.test import (TestCase, skipIfSolverNotAvailable, skipIfNoSolverForLog
29
29
  skipIfNoQEForLogic)
30
30
  from pysmt.test import main
31
31
  from pysmt.exceptions import (ConvertExpressionError, PysmtValueError,
32
- PysmtTypeError, InternalSolverError)
32
+ PysmtTypeError, InternalSolverError,
33
+ PysmtEmptySymbolNameError, UndefinedSymbolError)
33
34
  from pysmt.test.examples import get_example_formulae
34
35
  from pysmt.environment import Environment
35
36
  from pysmt.rewritings import cnf_as_set
36
37
  from pysmt.smtlib.parser import SmtLibParser
38
+ from pysmt.parsing import parse as hr_parse
37
39
  from pysmt.smtlib.commands import DECLARE_FUN
38
40
  from pysmt.smtlib.script import SmtLibCommand
39
41
  from pysmt.logics import get_closer_smtlib_logic
@@ -270,6 +272,64 @@ class TestRegressions(TestCase):
270
272
  def test_empty_string_symbol(self):
271
273
  with self.assertRaises(PysmtValueError):
272
274
  Symbol("")
275
+ # SMT-LIB allows `||` as a symbol name (see #587), but pySMT
276
+ # requires the user to opt-in explicitly.
277
+ self.env.allow_empty_var_names = True
278
+ self.assertNotEqual(Symbol(""), Symbol(" "))
279
+
280
+ def test_empty_string_symbol_error_message(self):
281
+ # Parsing a symbol with the empty name must point at the option
282
+ # to enable, not fail with an unrelated message.
283
+ smtlib = """(set-logic QF_BV)
284
+ (declare-fun || () (_ BitVec 4))
285
+ (assert (= || || ))
286
+ (check-sat)"""
287
+ with self.assertRaises(PysmtEmptySymbolNameError) as ctx:
288
+ SmtLibParser().get_script(StringIO(smtlib))
289
+ self.assertIn("allow_empty_var_names", str(ctx.exception))
290
+ with self.assertRaises(PysmtEmptySymbolNameError):
291
+ hr_parse("'' & x")
292
+ # Once enabled, the empty name is just an undeclared symbol
293
+ self.env.allow_empty_var_names = True
294
+ with self.assertRaises(UndefinedSymbolError):
295
+ hr_parse("'' & x")
296
+ Symbol("")
297
+ self.assertEqual(hr_parse("''"), Symbol(""))
298
+
299
+ @skipIfNoSolverForLogic(logics.QF_BV)
300
+ def test_empty_string_symbol_in_solvers(self):
301
+ self.env.allow_empty_var_names = True
302
+ empty = Symbol("", BVType(8))
303
+ other = Symbol("other", BVType(8))
304
+ f = Not(Equals(empty, other))
305
+ for sname in self.env.factory.all_solvers(logic=logics.QF_BV):
306
+ with Solver(name=sname, logic=logics.QF_BV) as s:
307
+ s.add_assertion(f)
308
+ self.assertTrue(s.solve(), sname)
309
+ self.assertTrue(s.get_value(empty).is_bv_constant(), sname)
310
+ # Round-trip, but only for converters that can back-convert
311
+ # a regular symbol in the first place.
312
+ try:
313
+ can_back = s.converter.back(s.converter.convert(other)) == other
314
+ except Exception:
315
+ can_back = False
316
+ if can_back:
317
+ self.assertEqual(s.converter.back(s.converter.convert(empty)),
318
+ empty, sname)
319
+
320
+ @skipIfNoSolverForLogic(logics.QF_BV)
321
+ def test_empty_string_symbol_smtlib(self):
322
+ # The benchmark reported in #587 declares `||` and `| |`.
323
+ self.env.allow_empty_var_names = True
324
+ txt = """(set-logic QF_BV)
325
+ (declare-fun || () (_ BitVec 4))
326
+ (declare-fun | | () (_ BitVec 4))
327
+ (assert (not (= || | |)))
328
+ (check-sat)"""
329
+ script = SmtLibParser().get_script(StringIO(txt))
330
+ self.assertEqual({s.symbol_name() for s in script.get_declared_symbols()},
331
+ {"", " "})
332
+ self.assertSat(script.get_last_formula())
273
333
 
274
334
  def test_smtlib_info_quoting(self):
275
335
  cmd = SmtLibCommand(smtcmd.SET_INFO, [":source", "This\nis\nmultiline!"])
@@ -198,7 +198,6 @@ class TestBasic(TestCase):
198
198
  def test_examples_msat(self):
199
199
  for (f, validity, satisfiability, logic) in get_example_formulae():
200
200
  if not logic.quantifier_free: continue
201
- if not logic.theory.linear: continue
202
201
  if logic.theory.strings: continue
203
202
 
204
203
  v = is_valid(f, solver_name='msat', logic=logic)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PySMT
3
- Version: 0.9.7.dev452
3
+ Version: 0.9.7.dev461
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,17 +1,17 @@
1
- pysmt/__init__.py,sha256=H1RSyIhE62I8bMHuJMFdulWPhnFnfJ5WhtMApT7Oz-8,1701
1
+ pysmt/__init__.py,sha256=1SGEofFHRCjIIaHxwnnUVpx8VGc6I0LMZN90e5E-Pxs,1701
2
2
  pysmt/__main__.py,sha256=rR-MV1QtLYqtVoJyY3m5B5Iz-lua0-5o6YSB0W4lKy8,1085
3
3
  pysmt/configuration.py,sha256=Iq_46QZ9z_jpBMk76euJWTqGEwHad2qyiEDPix5sXsA,4538
4
4
  pysmt/constants.py,sha256=pulb6NvROY_X8BePeyyX8T9MJLB79HZ_1FUYSlZ7Jfg,5769
5
5
  pysmt/decorators.py,sha256=dZWnu0lwfVBq6WGoohH5EWVpi6xr-uAEtFBjDUJgnoo,4106
6
6
  pysmt/environment.py,sha256=UUcccuTIGRYdIxvso4aUvfwJiveoDdOwRgTcVHkuupc,7056
7
- pysmt/exceptions.py,sha256=l7JmvC9VML32HeZwIhgxf5L-NQjbbpX4aHCdO9d56nM,5637
8
- pysmt/factory.py,sha256=E0ykatmufugzsOUG5hBPVatuudQ1u5WXlLy8ziKAbdc,31899
7
+ pysmt/exceptions.py,sha256=tnehun1YLztMNF91aQ49z4I1tGAkdRaUHDrPRl8g0DM,6080
8
+ pysmt/factory.py,sha256=nBe8oMy04KPeoOFJexQ1YJS7GQcEIiyg373U-P5jmnk,32575
9
9
  pysmt/fnode.py,sha256=5K0z8Qy3jIbB4N-lyBESXyzDpBDPD92jryNNd50NdLk,36453
10
- pysmt/formula.py,sha256=gUqv0V91Tww9GVeOD2Z_gsZlthUe8NADd0ZbYmK2CEk,50770
10
+ pysmt/formula.py,sha256=uaV9fenYpQBpg4RHJunJLghzx3rEDDyyQj3pQnwLfzE,50805
11
11
  pysmt/logics.py,sha256=HQaq2Odqw8oFNCAo1av0zaFOcPujTopO8frWSBsmNtg,29348
12
12
  pysmt/operators.py,sha256=XGPPoX5bdDsroAkr5rUAiBdi7BXkPaOyst7jEWqLTa0,8329
13
13
  pysmt/oracles.py,sha256=20IQ-YPo5dBMloZxKuS7tvrx4whFF3ZsRdds_iaegck,21769
14
- pysmt/parsing.py,sha256=De_KXONvh07EmxkiPxpY7Nx-jNuh-Uov6EL7IQeDTRo,21114
14
+ pysmt/parsing.py,sha256=sZc-rj--F6oM6_gmIDXSrBWwwAt0rAeRV7zGAjCx57o,21345
15
15
  pysmt/printers.py,sha256=fB2aPwsV7qQxgtqgVndUA_1wWBp5vMPzqBxngmBJmk4,15099
16
16
  pysmt/rewritings.py,sha256=wv1E-YMC0az_pY8KLd2mpDifwLdp7Q_Zh-lE5I8RmEU,42413
17
17
  pysmt/shortcuts.py,sha256=Xiq5JnkjefgwuJAEbmMAjnkyqu35MoALnSp2NYtIeDg,44962
@@ -59,17 +59,17 @@ pysmt/solvers/cvcfour.py,sha256=W8Afm8J7co87Vwt4L80kIoNaPcA3eBLwEnwAw5CcoHg,2579
59
59
  pysmt/solvers/dynmsat.py,sha256=bJokwHoxKWmQGqw9nQerRDb33d5c66Sa91jUYiZXwY0,2124
60
60
  pysmt/solvers/eager.py,sha256=E2wWhRVWe6sVxW2YOwPDhZ8O53uKNuPKwLIvsRsWFPA,3681
61
61
  pysmt/solvers/interpolation.py,sha256=6AO1wMkEKSkptuC4aXlNEO8Be1K2oW3W_er2XGc_aEA,2066
62
- pysmt/solvers/msat.py,sha256=feT1NYkc6cSCvKVtKIk_fPmo_mOIpyKWCrJEMQS9G4s,60568
62
+ pysmt/solvers/msat.py,sha256=YPAEGVf8lTr8fb9x9Ig6O6_wERcIIzpvGUjjVFjIjGw,63669
63
63
  pysmt/solvers/options.py,sha256=DRNUMb5Tlhai4keQkF7Kg34tf3AGbBUd45mqzjsS69c,4036
64
64
  pysmt/solvers/pico.py,sha256=y31QT7ZQVMeKjXc7g4DZrpc1LTzbhCLyE0zyOLd-BsE,10680
65
65
  pysmt/solvers/portfolio.py,sha256=GFKR2S8FoANzZJWUkYVqWEJG7sw04RYgSnwaKJNWuUs,10092
66
66
  pysmt/solvers/qelim.py,sha256=iEQ9PE9IPFA6dxqSMHFp3aIyDCTiZyIlSAduh0txrAg,5451
67
67
  pysmt/solvers/smtlib.py,sha256=daJkKBtTMHLIoQt77dhT8Qh8P6eFBO9mF4C6tialtBc,9924
68
- pysmt/solvers/solver.py,sha256=AqmWoDPKLpjpb0RlyUS-qYGCqPRetZKbiTIT-usczjA,19467
68
+ pysmt/solvers/solver.py,sha256=M-0wQ3Cz0GsV_wzhcogjGE3ACtPDEm6qocUt599-6fM,20404
69
69
  pysmt/solvers/yices.py,sha256=uG08Q9iqctXk-2rDP6H5OO88FE_ml83K0k5j8irpbcg,25910
70
- pysmt/solvers/z3.py,sha256=IOy2jqpdvY9uGKl7W1ehN-ZEHPS4CfIVYYhNbSOBZqw,44642
70
+ pysmt/solvers/z3.py,sha256=eXRSvwTE3LT0skoNTToFHEyvsUGdHvsJwLE4SLX-BEQ,45021
71
71
  pysmt/test/__init__.py,sha256=LEFbVYw4X45sgEI4_ax55g-6G5Y7kj6CLaJr1TQr4ks,5750
72
- pysmt/test/examples.py,sha256=6yWa-hHEMJuo5GEbjWmzg509-LQxVAyr26lxGhcK_jU,40756
72
+ pysmt/test/examples.py,sha256=fogqgP2qEpvaOswVFYRr4Q8o6TKoCLPW9460SL9HVvo,40756
73
73
  pysmt/test/omt_examples.py,sha256=LdL43fLaHiR72Cng_2st4UaYf2ueoZgStcvhccy-RdI,10338
74
74
  pysmt/test/optimization_utils.py,sha256=zbj2bN-3uMaNexF7DSjuQAR0889IcMsCiE__tGtR6zM,15665
75
75
  pysmt/test/test_array.py,sha256=-7R_L0d0MMuemdv0AtqNR2y8rX_w4Xc0NiaDKD4H_lY,7163
@@ -83,7 +83,7 @@ pysmt/test/test_constants.py,sha256=vdjjtAOw5oQg57Bl5tllslnVWBHuRq3Zk33F1xDsBtA,
83
83
  pysmt/test/test_cvc_quantifiers.py,sha256=a40NDyPKNynVpqq9M5pDTR8qFL_EumR8whw8escxP4I,1850
84
84
  pysmt/test/test_dwf.py,sha256=nQubO2IYjW3NnRjNz3xkhpXgK_5coZp9uZ_U-ElmFRw,2850
85
85
  pysmt/test/test_eager_model.py,sha256=hF9V8wQYXVeyW2Bo4sACa98xeJtfOMYjMvjWMHQaGag,3662
86
- pysmt/test/test_env.py,sha256=EZ5DbAK7OXwuoiNMz4naaz5MFYUk-fK0_OKknO-YG70,8166
86
+ pysmt/test/test_env.py,sha256=g98aqMU2dlPW2hQmWy8DxCLfm06upMic5mU91MGX_PQ,8758
87
87
  pysmt/test/test_euf.py,sha256=B0VRx1NwfKZZIG5Fc6gYPj7G6gNWMzYJvgbh-2q2E28,3455
88
88
  pysmt/test/test_formula.py,sha256=nd550r7dBRHvoNKedCCdKfmV0WD4oMfjZekfAtk7GSg,40493
89
89
  pysmt/test/test_hr_parsing.py,sha256=bi-iTu7y1C7diMcWsQ7EI40MipDbzTKbMGPnLWX85A8,3118
@@ -95,19 +95,19 @@ pysmt/test/test_logics.py,sha256=bWwE_7rq9SVcXglE-ugteGeCHXAYFiBdi-QgIL9-9KE,689
95
95
  pysmt/test/test_models.py,sha256=npqGoF-3DgAw0DTx6se32ZEZRFBJDcnkppzgyjLDbps,2748
96
96
  pysmt/test/test_native_qe.py,sha256=RGZgwbpAkPBTjIqcCbOkZ_nQXIDZ4Fznrr7Ldx6oA38,3439
97
97
  pysmt/test/test_nia.py,sha256=x51d0X5jnZnxTPvPLrlD0WilunZ5uNrDU4vWY78_xpU,6640
98
- pysmt/test/test_nlira.py,sha256=_E1HeOarw4TN8AI1X7EQv-utjhwy8hJX3vx-05eHJk0,4969
98
+ pysmt/test/test_nlira.py,sha256=RNG90qzQ_XUI9bazoiBUhSt1N7QKcjlzHm3bqraMDj4,5129
99
99
  pysmt/test/test_optimization.py,sha256=xU0gJbD2SSn5_lA7wF7IKcR54KF6NU0g-2_dDEqXmqA,24358
100
100
  pysmt/test/test_optimizing.py,sha256=P-XnTPEPoEp5LvvZfZoiZziI4z3d_FfL7lFcEuI07bE,1512
101
101
  pysmt/test/test_oracles.py,sha256=cHBPTUoi9cPmIvR-DG4bbzohOaBdUJzpKLoQXImxS_c,5615
102
102
  pysmt/test/test_portfolio.py,sha256=MIlXPyvBHxXnV5V-4PQ1WTTwVIgrR_CUvq-PYUajaiM,7685
103
103
  pysmt/test/test_printing.py,sha256=MwxLcmpwN0DYLlqGNrOZM4U1RPdTM1k75_IMKWQFLts,9064
104
104
  pysmt/test/test_qe.py,sha256=k8zYX-lcij0ua9yuRXl7wErUklEgLSEh68QDpV8J9xs,7157
105
- pysmt/test/test_regressions.py,sha256=Wuah55f5rROEkhTho_zl-uwaMDzc4LPeP3lfQ6nzS8k,21977
105
+ pysmt/test/test_regressions.py,sha256=Mmxf86E9L0MTXJYBYwEqYGuQMCLYKFl2ZK4XQJCJH0A,24810
106
106
  pysmt/test/test_rewritings.py,sha256=1eeseDwZyQD2VrOFBABXHTYJFJOXszP4olbCNeLcwfA,15607
107
107
  pysmt/test/test_shannon_expansion.py,sha256=yaiZuB24wj1Zi-KdzRTmWuzAVaF9bQ603uto7zi6XBs,3082
108
108
  pysmt/test/test_simplify.py,sha256=ckQn_DUxVvGspaRNZmSPHkudhpUlG5K2w6C0wDqhL1w,7620
109
109
  pysmt/test/test_size.py,sha256=p3aqCMHfBiGLxvF0P8hE-PRQTT8VMPIJCjblq8Txh1w,3261
110
- pysmt/test/test_solving.py,sha256=sB9Nz7pTg-MjInl3MKo4rCPDLwxti3Yp1QanwxLZ4As,25637
110
+ pysmt/test/test_solving.py,sha256=pf5ZitNQrVAT2VSn-ZstHNromomL6OxPKBJMdyZzdLk,25588
111
111
  pysmt/test/test_sorts.py,sha256=erfInyPH91WVB8JBUYLteTo5X5skKKP3vEXdUUKC-YE,6033
112
112
  pysmt/test/test_string.py,sha256=Y6VBfkLNKuePo8-HIzcwBH3eaYj0i-k1Y8tpFyw03zw,8096
113
113
  pysmt/test/test_typechecker.py,sha256=S2O8HjN_bLN6sz86TnsWqpRtxHk2VcVsGDoRZCcQnzE,7309
@@ -143,10 +143,10 @@ pysmt/walkers/dag.py,sha256=4CWSgoXm6nONhM-1znKRU4SBCb791OTS-M9QlQFhbs8,5751
143
143
  pysmt/walkers/generic.py,sha256=dmp47kJGtO6rhC2t07Mf_FsYN-lcy64LX-dZggNnWm4,5179
144
144
  pysmt/walkers/identitydag.py,sha256=EAxSneEW91Z8GphlkbMPsPdlac7_FDcVj-_6_aunU2s,10902
145
145
  pysmt/walkers/tree.py,sha256=8oyDSXZtUsCdExcrwG3hKuEgARHgdW6fvz0LZJwjp-k,2983
146
- pysmt-0.9.7.dev452.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
147
- pysmt-0.9.7.dev452.dist-info/licenses/NOTICE,sha256=Ns-Jsa6nbqZUiTEEAM6HqioSZIxQ2RCJzxoBlWQaUfc,601
148
- pysmt-0.9.7.dev452.dist-info/METADATA,sha256=7YalyJRjNuUsu3qa8tLhqU498-dd5f4EfE8o_bPpV7w,1774
149
- pysmt-0.9.7.dev452.dist-info/WHEEL,sha256=4YBfCYNH4wlLpv3pzq1hbEuIlXA4WJabKLFurZ7eTL0,109
150
- pysmt-0.9.7.dev452.dist-info/entry_points.txt,sha256=gDc1XM0xTJJMDGC_nXd0kfbX-Omjke9Dn9F3awMLYIU,57
151
- pysmt-0.9.7.dev452.dist-info/top_level.txt,sha256=NwHQbpTaZMEvjIUdC0bvvj-WUyULe-nt-opK3YQNRMk,6
152
- pysmt-0.9.7.dev452.dist-info/RECORD,,
146
+ pysmt-0.9.7.dev461.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
147
+ pysmt-0.9.7.dev461.dist-info/licenses/NOTICE,sha256=Ns-Jsa6nbqZUiTEEAM6HqioSZIxQ2RCJzxoBlWQaUfc,601
148
+ pysmt-0.9.7.dev461.dist-info/METADATA,sha256=Ec5wIiEr0YFjWydmtI3-BiX-bmpqOH4lmloOZ28ci_k,1774
149
+ pysmt-0.9.7.dev461.dist-info/WHEEL,sha256=4YBfCYNH4wlLpv3pzq1hbEuIlXA4WJabKLFurZ7eTL0,109
150
+ pysmt-0.9.7.dev461.dist-info/entry_points.txt,sha256=gDc1XM0xTJJMDGC_nXd0kfbX-Omjke9Dn9F3awMLYIU,57
151
+ pysmt-0.9.7.dev461.dist-info/top_level.txt,sha256=NwHQbpTaZMEvjIUdC0bvvj-WUyULe-nt-opK3YQNRMk,6
152
+ pysmt-0.9.7.dev461.dist-info/RECORD,,