Skip to content

Commit

Permalink
Merge pull request #375 from pysmt/sorts
Browse files Browse the repository at this point in the history
Handling of Sorts
  • Loading branch information
mikand committed Mar 3, 2017
2 parents e9fc72f + 9e7ce56 commit 691172b
Show file tree
Hide file tree
Showing 9 changed files with 540 additions and 203 deletions.
8 changes: 8 additions & 0 deletions pysmt/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import pysmt.formula
import pysmt.factory
import pysmt.decorators
import pysmt.typing


class Environment(object):
Expand All @@ -42,6 +43,7 @@ class Environment(object):
"""
TypeCheckerClass = pysmt.type_checker.SimpleTypeChecker
FormulaManagerClass = pysmt.formula.FormulaManager
TypeManagerClass = pysmt.typing.TypeManager
SimplifierClass = pysmt.simplifier.Simplifier
#SubstituterClass = pysmt.substituter.MSSubstituter
SubstituterClass = pysmt.substituter.MGSubstituter
Expand All @@ -52,6 +54,7 @@ class Environment(object):
SizeOracleClass = pysmt.oracles.SizeOracle
AtomsOracleClass = pysmt.oracles.AtomsOracle


def __init__(self):
self._stc = self.TypeCheckerClass(self)
self._formula_manager = self.FormulaManagerClass(self)
Expand All @@ -65,6 +68,7 @@ def __init__(self):
self._fvo = self.FreeVarsOracleClass(self)
self._sizeo = self.SizeOracleClass(self)
self._ao = self.AtomsOracleClass(self)
self._type_manager = self.TypeManagerClass(self)

self._factory = None
# Configurations
Expand All @@ -78,6 +82,10 @@ def __init__(self):
def formula_manager(self):
return self._formula_manager

@property
def type_manager(self):
return self._type_manager

@property
def simplifier(self):
return self._simplifier
Expand Down
26 changes: 23 additions & 3 deletions pysmt/formula.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ def create_node(self, node_type, args, payload=None):
def _create_symbol(self, name, typename=types.BOOL):
if len(name) == 0:
raise PysmtValueError("Empty string is not a valid name")
if not isinstance(typename, types.PySMTType):
raise PysmtValueError("typename must be a PySMTType.")
n = self.create_node(node_type=op.SYMBOL,
args=tuple(),
payload=(name, typename))
Expand Down Expand Up @@ -939,9 +941,7 @@ def normalize(self, formula):
obtain f_b that is the formula f_a expressed on the
FormulaManager b : f_b = b.normalize(f_a)
"""
# TODO: name clash with formula normalization
# TODO: Move this out of the manager and into ad-hoc function
normalizer = IdentityDagWalker(self.env)
normalizer = FormulaContextualizer(self.env)
return normalizer.walk(formula)

def _polymorph_args_to_tuple(self, args):
Expand Down Expand Up @@ -969,3 +969,23 @@ def __contains__(self, node):
return False

#EOC FormulaManager


class FormulaContextualizer(IdentityDagWalker):
"""Helper class to recreate a formula within a new environment."""

def __init__(self, env=None):
IdentityDagWalker.__init__(self, env=env)
self.type_normalize = self.env.type_manager.normalize

def walk_symbol(self, formula, **kwargs):
# Recreate the Symbol taking into account the type information
ty = formula.symbol_type()
newty = self.type_normalize(ty)
return self.mgr.Symbol(formula.symbol_name(), newty)

def walk_array_value(self, formula, args, **kwargs):
# Recreate the ArrayValue taking into account the type information
assign = dict(zip(args[1::2], args[2::2]))
ty = self.type_normalize(formula.array_value_index_type())
return self.mgr.Array(ty, args[0], assign)
6 changes: 5 additions & 1 deletion pysmt/shortcuts.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,16 @@
import warnings
warnings.simplefilter('default')

import pysmt.typing as types
import pysmt.configuration as config
import pysmt.environment
import pysmt.typing as types
import pysmt.smtlib.parser
import pysmt.smtlib.script

# Import types from shortcuts
from pysmt.typing import INT, BOOL, REAL, BVType, FunctionType, ArrayType, Type
assert INT or BOOL or REAL or BVType or FunctionType or ArrayType or Type


def get_env():
"""Returns the global environment.
Expand Down
2 changes: 1 addition & 1 deletion pysmt/smtlib/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -1112,7 +1112,7 @@ def _cmd_define_sort(self, current, tokens):
return SmtLibCommand(current, [name, [], rtype])

def _cmd_get_assertions(self, current, tokens):
"""(get_assertions)"""
"""(get-assertions)"""
self.parse_atoms(tokens, current, 0)
return SmtLibCommand(current, [])

Expand Down
13 changes: 0 additions & 13 deletions pysmt/test/test_formula.py
Original file line number Diff line number Diff line change
Expand Up @@ -1015,19 +1015,6 @@ def test_formula_in_formula_manager(self):
self.assertTrue(and_x_x in self.mgr)
self.assertFalse(and_y_y in self.mgr)

def test_typing(self):
self.assertTrue(BOOL.is_bool_type())
self.assertFalse(BOOL.is_function_type())

self.assertTrue(REAL.is_real_type())
self.assertFalse(REAL.is_bool_type())

self.assertTrue(INT.is_int_type())
self.assertFalse(INT.is_real_type())

self.assertTrue(self.ftype.is_function_type())
self.assertFalse(self.ftype.is_int_type())

def test_array_value(self):
a1 = self.mgr.Array(INT, self.mgr.Int(0))
a2 = self.mgr.Array(INT, self.mgr.Int(0),
Expand Down
176 changes: 176 additions & 0 deletions pysmt/test/test_sorts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
#
# This file is part of pySMT.
#
# Copyright 2014 Andrea Micheli and Marco Gario
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from six import StringIO

from pysmt.shortcuts import FreshSymbol, EqualsOrIff, Select, TRUE, FALSE, Function
from pysmt.shortcuts import Array, BV
from pysmt.typing import INT, BOOL, REAL
from pysmt.typing import Type, ArrayType, FunctionType, BVType
from pysmt.typing import PartialType
from pysmt.test import TestCase, main
from pysmt.smtlib.parser import SmtLibParser
from pysmt.exceptions import PysmtValueError, PysmtTypeError


SMTLIB_SRC="""\
(define-sort Set (T) (Array T Bool))
(define-sort I () Int)
(declare-const s1 (Set I))
(declare-const a I)
(declare-const b Int)
(assert (= (select s1 a) true))
(assert (= (select s1 b) false))
(check-sat)
"""

class TestSorts(TestCase):

def test_smtlib_sort(self):
# parser = SmtLibParser()
# buf = StringIO(SMTLIB_SRC)
# script = parser.get_script(buf)
pass

def test_basic_types(self):
self.assertTrue(BOOL.is_bool_type())
self.assertFalse(BOOL.is_function_type())

self.assertTrue(REAL.is_real_type())
self.assertFalse(REAL.is_bool_type())

self.assertTrue(INT.is_int_type())
self.assertFalse(INT.is_real_type())

ftype = FunctionType(REAL, [REAL, REAL])
self.assertTrue(ftype.is_function_type())
self.assertFalse(ftype.is_int_type())

self.assertNotEqual(BOOL, INT)
self.assertEqual(REAL, REAL)

AAIBR = ArrayType(ArrayType(INT, BOOL), REAL)
self.assertEqual(str(AAIBR), "Array{Array{Int, Bool}, Real}")

bt1 = BVType(4)
bt2 = BVType(4)
self.assertEqual(bt1, bt2)
self.assertEqual(bt1.width, 4)

def test_fake_arrays(self):
FakeArrayType = Type("FakeArray", 2)
with self.assertRaises(PysmtValueError):
FreshSymbol(FakeArrayType)
FakeArrayII = FakeArrayType(INT, INT)
self.assertEqual(str(FakeArrayII), "FakeArray{Int, Int}")
self.assertEqual(FakeArrayII.as_smtlib(False), "(FakeArray Int Int)")
s = FreshSymbol(FakeArrayII)
self.assertIsNotNone(s)

def test_simple_sorts(self):
# (define-sort I () Int)
# (define-sort Set (T) (Array T Bool))
I = INT
SET = PartialType("Set", lambda t1: ArrayType(t1, BOOL))
self.assertEqual(ArrayType(INT, BOOL), SET(I))

# (declare-const s1 (Set I))
# (declare-const a I)
# (declare-const b Int)
s1 = FreshSymbol(SET(I))
a = FreshSymbol(I)
b = FreshSymbol(INT)

# (= (select s1 a) true)
# (= (select s1 b) false)
f1 = EqualsOrIff(Select(s1, a), TRUE())
f2 = EqualsOrIff(Select(s1, b), FALSE())
self.assertIsNotNone(f1)
self.assertIsNotNone(f2)

# Cannot instantiate a PartialType directly:
with self.assertRaises(PysmtValueError):
FreshSymbol(SET)

# (declare-sort A 0)
# Uninterpreted sort
A = Type("A", 0)
B = Type("B")

c1 = FreshSymbol(A)
c2 = FreshSymbol(A)
c3 = FreshSymbol(Type("A"))
c4 = FreshSymbol(B)
EqualsOrIff(c1, c2)
EqualsOrIff(c2, c3)
with self.assertRaises(PysmtTypeError):
EqualsOrIff(c1, c4)

with self.assertRaises(PysmtValueError):
Type("A", 1)

C = Type("C", 1)
c5 = FreshSymbol(C(A))
c6 = FreshSymbol(C(B))
self.assertIsNotNone(c5)
with self.assertRaises(PysmtTypeError):
EqualsOrIff(c5, c6)

# Nesting
ty = C(C(C(C(C(A)))))
self.assertIsNotNone(FreshSymbol(ty))

pty = PartialType("pty", lambda S,T: S(S(S(S(S(T))))))
self.assertEqual(pty(C,A), ty)

def test_normalization(self):
from pysmt.environment import Environment

env2 = Environment()
mgr2 = env2.formula_manager

ty = ArrayType(BOOL, REAL)
x = FreshSymbol(ty)
fty = FunctionType(BOOL, (ty,))
f = FreshSymbol(fty)
g = Function(f, (x,))
self.assertIsNotNone(g)
self.assertNotIn(g, mgr2)
g2 = mgr2.normalize(g)
self.assertIn(g2, mgr2)
# Since the types are from two different environments, they
# should be different.
x2 = g2.arg(0)
ty2 = x2.symbol_type()
self.assertFalse(ty2 is ty, ty)
fname = g2.function_name()
fty2 = fname.symbol_type()
self.assertFalse(fty2 is fty, fty)

# Test ArrayValue
h = Array(BVType(4), BV(0, 4))
h2 = mgr2.normalize(h)
self.assertEqual(h.array_value_index_type(),
h2.array_value_index_type())
self.assertFalse(h.array_value_index_type() is \
h2.array_value_index_type())


if __name__ == '__main__':
main()
8 changes: 1 addition & 7 deletions pysmt/type_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,15 +175,9 @@ def walk_bv_extend(self, formula, args, **kwargs):

def walk_math_relation(self, formula, args, **kwargs):
#pylint: disable=unused-argument
if args[0].is_real_type():
return self.walk_type_to_type(formula, args, REAL, BOOL)
if args[0].is_int_type():
return self.walk_type_to_type(formula, args, INT, BOOL)
if args[0].is_bv_type():
return self.walk_bv_to_bool(formula, args)
if args[0].is_array_type():
return self.walk_type_to_type(formula, args, args[0], BOOL)
return None
return self.walk_type_to_type(formula, args, args[0], BOOL)

def walk_ite(self, formula, args, **kwargs):
assert formula is not None
Expand Down

0 comments on commit 691172b

Please sign in to comment.