From 5e6117cc183513bf676b36078e6507b31caa6ff0 Mon Sep 17 00:00:00 2001 From: Ying Sheng Date: Fri, 18 Jun 2021 23:41:41 -0700 Subject: [PATCH] Adding python API test part 5 (#6743) This commit (follow #6553) adds more functions and unit tests for python API. Subsequent PR will include additional missing functions and unit tests. 1. Adding getNullSort() and mkEmptyBag() functions. 2. Allowing mkOp() with a list of arguments (previously allowed at most 2). 3. Allowing mkString() with additional boolean argument useEscSequences. 4. Corresponding changes to the tests. --- src/api/python/cvc5.pxd | 5 +- src/api/python/cvc5.pxi | 50 +++-- test/python/unit/api/test_solver.py | 306 ++++++++++++++++++++++++++++ 3 files changed, 342 insertions(+), 19 deletions(-) diff --git a/src/api/python/cvc5.pxd b/src/api/python/cvc5.pxd index 9d980267d..623b2f943 100644 --- a/src/api/python/cvc5.pxd +++ b/src/api/python/cvc5.pxd @@ -153,6 +153,7 @@ cdef extern from "api/cpp/cvc5.h" namespace "cvc5::api": Solver(Options*) except + Sort getBooleanSort() except + Sort getIntegerSort() except + + Sort getNullSort() except + Sort getRealSort() except + Sort getRegExpSort() except + Sort getRoundingModeSort() except + @@ -178,10 +179,10 @@ cdef extern from "api/cpp/cvc5.h" namespace "cvc5::api": Term mkTerm(Op op, const vector[Term]& children) except + Term mkTuple(const vector[Sort]& sorts, const vector[Term]& terms) except + Op mkOp(Kind kind) except + - Op mkOp(Kind kind, Kind k) except + Op mkOp(Kind kind, const string& arg) except + Op mkOp(Kind kind, uint32_t arg) except + Op mkOp(Kind kind, uint32_t arg1, uint32_t arg2) except + + Op mkOp(Kind kind, const vector[uint32_t]& args) except + # Sygus related functions Grammar mkSygusGrammar(const vector[Term]& boundVars, const vector[Term]& ntSymbols) except + Term mkSygusVar(Sort sort, const string& symbol) except + @@ -207,9 +208,11 @@ cdef extern from "api/cpp/cvc5.h" namespace "cvc5::api": Term mkRegexpEmpty() except + Term mkRegexpSigma() except + Term mkEmptySet(Sort s) except + + Term mkEmptyBag(Sort s) except + Term mkSepNil(Sort sort) except + Term mkString(const string& s) except + Term mkString(const wstring& s) except + + Term mkString(const string& s, bint useEscSequences) except + Term mkEmptySequence(Sort sort) except + Term mkUniverseSet(Sort sort) except + Term mkBitVector(uint32_t size) except + diff --git a/src/api/python/cvc5.pxi b/src/api/python/cvc5.pxi index 874c63c3d..4bb9da3d1 100644 --- a/src/api/python/cvc5.pxi +++ b/src/api/python/cvc5.pxi @@ -470,6 +470,11 @@ cdef class Solver: sort.csort = self.csolver.getIntegerSort() return sort + def getNullSort(self): + cdef Sort sort = Sort(self) + sort.csort = self.csolver.getNullSort() + return sort + def getRealSort(self): cdef Sort sort = Sort(self) sort.csort = self.csolver.getRealSort() @@ -672,8 +677,8 @@ cdef class Solver: result.cterm = self.csolver.mkTuple(csorts, cterms) return result - - def mkOp(self, kind k, arg0=None, arg1 = None): + @expand_list_arg(num_req_args=0) + def mkOp(self, kind k, *args): ''' Supports the following uses: Op mkOp(Kind kind) @@ -683,28 +688,30 @@ cdef class Solver: Op mkOp(Kind kind, uint32_t arg0, uint32_t arg1) ''' cdef Op op = Op(self) + cdef vector[int] v - if arg0 is None: + if len(args) == 0: op.cop = self.csolver.mkOp(k.k) - elif arg1 is None: - if isinstance(arg0, kind): - op.cop = self.csolver.mkOp(k.k, ( arg0).k) - elif isinstance(arg0, str): + elif len(args) == 1: + if isinstance(args[0], str): op.cop = self.csolver.mkOp(k.k, - arg0.encode()) - elif isinstance(arg0, int): - op.cop = self.csolver.mkOp(k.k, arg0) + args[0].encode()) + elif isinstance(args[0], int): + op.cop = self.csolver.mkOp(k.k, args[0]) + elif isinstance(args[0], list): + for a in args[0]: + v.push_back(( a)) + op.cop = self.csolver.mkOp(k.k, v) else: raise ValueError("Unsupported signature" - " mkOp: {}".format(" X ".join([str(k), str(arg0)]))) - else: - if isinstance(arg0, int) and isinstance(arg1, int): - op.cop = self.csolver.mkOp(k.k, arg0, - arg1) + " mkOp: {}".format(" X ".join([str(k), str(args[0])]))) + elif len(args) == 2: + if isinstance(args[0], int) and isinstance(args[1], int): + op.cop = self.csolver.mkOp(k.k, args[0], args[1]) else: raise ValueError("Unsupported signature" - " mkOp: {}".format(" X ".join([k, arg0, arg1]))) + " mkOp: {}".format(" X ".join([k, args[0], args[1]]))) return op def mkTrue(self): @@ -778,17 +785,24 @@ cdef class Solver: term.cterm = self.csolver.mkEmptySet(s.csort) return term + def mkEmptyBag(self, Sort s): + cdef Term term = Term(self) + term.cterm = self.csolver.mkEmptyBag(s.csort) + return term def mkSepNil(self, Sort sort): cdef Term term = Term(self) term.cterm = self.csolver.mkSepNil(sort.csort) return term - def mkString(self, str s): + def mkString(self, str s, useEscSequences = None): cdef Term term = Term(self) cdef Py_ssize_t size cdef wchar_t* tmp = PyUnicode_AsWideCharString(s, &size) - term.cterm = self.csolver.mkString(c_wstring(tmp, size)) + if isinstance(useEscSequences, bool): + term.cterm = self.csolver.mkString(s.encode(), useEscSequences) + else: + term.cterm = self.csolver.mkString(c_wstring(tmp, size)) PyMem_Free(tmp) return term diff --git a/test/python/unit/api/test_solver.py b/test/python/unit/api/test_solver.py index 1255bf270..8b3ce944e 100644 --- a/test/python/unit/api/test_solver.py +++ b/test/python/unit/api/test_solver.py @@ -43,6 +43,10 @@ def test_get_integer_sort(solver): solver.getIntegerSort() +def test_get_null_sort(solver): + solver.getNullSort() + + def test_get_real_sort(solver): solver.getRealSort() @@ -244,6 +248,15 @@ def test_mk_set_sort(solver): slv.mkSetSort(solver.mkBitVectorSort(4)) +def test_mk_bag_sort(solver): + solver.mkBagSort(solver.getBooleanSort()) + solver.mkBagSort(solver.getIntegerSort()) + solver.mkBagSort(solver.mkBitVectorSort(4)) + slv = pycvc5.Solver() + with pytest.raises(RuntimeError): + slv.mkBagSort(solver.mkBitVectorSort(4)) + + def test_mk_sequence_sort(solver): solver.mkSequenceSort(solver.getBooleanSort()) solver.mkSequenceSort(\ @@ -277,6 +290,42 @@ def test_mk_tuple_sort(solver): slv.mkTupleSort([solver.getIntegerSort()]) +def test_mk_bit_vector(solver): + size0 = 0 + size1 = 8 + size2 = 32 + val1 = 2 + val2 = 2 + solver.mkBitVector(size1, val1) + solver.mkBitVector(size2, val2) + solver.mkBitVector("1010", 2) + solver.mkBitVector("1010", 10) + solver.mkBitVector("1234", 10) + solver.mkBitVector("1010", 16) + solver.mkBitVector("a09f", 16) + solver.mkBitVector(8, "-127", 10) + with pytest.raises(RuntimeError): + solver.mkBitVector(size0, val1) + with pytest.raises(RuntimeError): + solver.mkBitVector(size0, val2) + with pytest.raises(RuntimeError): + solver.mkBitVector("", 2) + with pytest.raises(RuntimeError): + solver.mkBitVector("10", 3) + with pytest.raises(RuntimeError): + solver.mkBitVector("20", 2) + with pytest.raises(RuntimeError): + solver.mkBitVector(8, "101010101", 2) + with pytest.raises(RuntimeError): + solver.mkBitVector(8, "-256", 10) + assert solver.mkBitVector("1010", 2) == solver.mkBitVector("10", 10) + assert solver.mkBitVector("1010", 2) == solver.mkBitVector("a", 16) + assert str(solver.mkBitVector(8, "01010101", 2)) == "#b01010101" + assert str(solver.mkBitVector(8, "F", 16)) == "#b00001111" + assert solver.mkBitVector(8, "-1", 10) ==\ + solver.mkBitVector(8, "FF", 16) + + def test_mk_var(solver): boolSort = solver.getBooleanSort() intSort = solver.getIntegerSort() @@ -312,6 +361,26 @@ def test_mk_uninterpreted_const(solver): slv.mkUninterpretedConst(solver.getBooleanSort(), 1) +def test_mk_abstract_value(solver): + solver.mkAbstractValue("1") + with pytest.raises(ValueError): + solver.mkAbstractValue("0") + with pytest.raises(ValueError): + solver.mkAbstractValue("-1") + with pytest.raises(ValueError): + solver.mkAbstractValue("1.2") + with pytest.raises(ValueError): + solver.mkAbstractValue("1/2") + with pytest.raises(ValueError): + solver.mkAbstractValue("asdf") + + solver.mkAbstractValue(1) + with pytest.raises(ValueError): + solver.mkAbstractValue(-1) + with pytest.raises(ValueError): + solver.mkAbstractValue(0) + + def test_mk_floating_point(solver): t1 = solver.mkBitVector(8) t2 = solver.mkBitVector(4) @@ -345,6 +414,17 @@ def test_mk_empty_set(solver): slv.mkEmptySet(s) +def test_mk_empty_bag(solver): + slv = pycvc5.Solver() + s = solver.mkBagSort(solver.getBooleanSort()) + solver.mkEmptyBag(pycvc5.Sort(solver)) + solver.mkEmptyBag(s) + with pytest.raises(RuntimeError): + solver.mkEmptyBag(solver.getBooleanSort()) + with pytest.raises(RuntimeError): + slv.mkEmptyBag(s) + + def test_mk_empty_sequence(solver): slv = pycvc5.Solver() s = solver.mkSequenceSort(solver.getBooleanSort()) @@ -379,6 +459,33 @@ def test_mk_pos_zero(solver): solver.mkPosZero(3, 5) +def test_mk_op(solver): + # mkOp(Kind kind, Kind k) + with pytest.raises(ValueError): + solver.mkOp(kinds.BVExtract, kinds.Equal) + + # mkOp(Kind kind, const std::string& arg) + solver.mkOp(kinds.Divisible, "2147483648") + with pytest.raises(RuntimeError): + solver.mkOp(kinds.BVExtract, "asdf") + + # mkOp(Kind kind, uint32_t arg) + solver.mkOp(kinds.Divisible, 1) + solver.mkOp(kinds.BVRotateLeft, 1) + solver.mkOp(kinds.BVRotateRight, 1) + with pytest.raises(RuntimeError): + solver.mkOp(kinds.BVExtract, 1) + + # mkOp(Kind kind, uint32_t arg1, uint32_t arg2) + solver.mkOp(kinds.BVExtract, 1, 1) + with pytest.raises(RuntimeError): + solver.mkOp(kinds.Divisible, 1, 2) + + # mkOp(Kind kind, std::vector args) + args = [1, 2, 2] + solver.mkOp(kinds.TupleProject, args) + + def test_mk_pi(solver): solver.mkPi() @@ -526,11 +633,210 @@ def test_mk_sep_nil(solver): slv.mkSepNil(solver.getIntegerSort()) +def test_mk_string(solver): + solver.mkString("") + solver.mkString("asdfasdf") + str(solver.mkString("asdf\\nasdf")) == "\"asdf\\u{5c}nasdf\"" + str(solver.mkString("asdf\\u{005c}nasdf", True)) ==\ + "\"asdf\\u{5c}nasdf\"" + + +def test_mk_term(solver): + bv32 = solver.mkBitVectorSort(32) + a = solver.mkConst(bv32, "a") + b = solver.mkConst(bv32, "b") + v1 = [a, b] + v2 = [a, pycvc5.Term(solver)] + v3 = [a, solver.mkTrue()] + v4 = [solver.mkInteger(1), solver.mkInteger(2)] + v5 = [solver.mkInteger(1), pycvc5.Term(solver)] + v6 = [] + slv = pycvc5.Solver() + + # mkTerm(Kind kind) const + solver.mkPi() + solver.mkTerm(kinds.RegexpEmpty) + solver.mkTerm(kinds.RegexpSigma) + with pytest.raises(RuntimeError): + solver.mkTerm(kinds.ConstBV) + + # mkTerm(Kind kind, Term child) const + solver.mkTerm(kinds.Not, solver.mkTrue()) + with pytest.raises(RuntimeError): + solver.mkTerm(kinds.Not, pycvc5.Term(solver)) + with pytest.raises(RuntimeError): + solver.mkTerm(kinds.Not, a) + with pytest.raises(RuntimeError): + slv.mkTerm(kinds.Not, solver.mkTrue()) + + # mkTerm(Kind kind, Term child1, Term child2) const + solver.mkTerm(kinds.Equal, a, b) + with pytest.raises(RuntimeError): + solver.mkTerm(kinds.Equal, pycvc5.Term(solver), b) + with pytest.raises(RuntimeError): + solver.mkTerm(kinds.Equal, a, pycvc5.Term(solver)) + with pytest.raises(RuntimeError): + solver.mkTerm(kinds.Equal, a, solver.mkTrue()) + with pytest.raises(RuntimeError): + slv.mkTerm(kinds.Equal, a, b) + + # mkTerm(Kind kind, Term child1, Term child2, Term child3) const + solver.mkTerm(kinds.Ite, solver.mkTrue(), solver.mkTrue(), solver.mkTrue()) + with pytest.raises(RuntimeError): + solver.mkTerm(kinds.Ite, pycvc5.Term(solver), solver.mkTrue(), + solver.mkTrue()) + with pytest.raises(RuntimeError): + solver.mkTerm(kinds.Ite, solver.mkTrue(), pycvc5.Term(solver), + solver.mkTrue()) + with pytest.raises(RuntimeError): + solver.mkTerm(kinds.Ite, solver.mkTrue(), solver.mkTrue(), + pycvc5.Term(solver)) + with pytest.raises(RuntimeError): + solver.mkTerm(kinds.Ite, solver.mkTrue(), solver.mkTrue(), b) + with pytest.raises(RuntimeError): + slv.mkTerm(kinds.Ite, solver.mkTrue(), solver.mkTrue(), + solver.mkTrue()) + + # mkTerm(Kind kind, const std::vector& children) const + solver.mkTerm(kinds.Equal, v1) + with pytest.raises(RuntimeError): + solver.mkTerm(kinds.Equal, v2) + with pytest.raises(RuntimeError): + solver.mkTerm(kinds.Equal, v3) + with pytest.raises(RuntimeError): + solver.mkTerm(kinds.Distinct, v6) + + +def test_mk_term_from_op(solver): + bv32 = solver.mkBitVectorSort(32) + a = solver.mkConst(bv32, "a") + b = solver.mkConst(bv32, "b") + v1 = [solver.mkInteger(1), solver.mkInteger(2)] + v2 = [solver.mkInteger(1), pycvc5.Term(solver)] + v3 = [] + v4 = [solver.mkInteger(5)] + slv = pycvc5.Solver() + + # simple operator terms + opterm1 = solver.mkOp(kinds.BVExtract, 2, 1) + opterm2 = solver.mkOp(kinds.Divisible, 1) + + # list datatype + sort = solver.mkParamSort("T") + listDecl = solver.mkDatatypeDecl("paramlist", sort) + cons = solver.mkDatatypeConstructorDecl("cons") + nil = solver.mkDatatypeConstructorDecl("nil") + cons.addSelector("head", sort) + cons.addSelectorSelf("tail") + listDecl.addConstructor(cons) + listDecl.addConstructor(nil) + listSort = solver.mkDatatypeSort(listDecl) + intListSort =\ + listSort.instantiate([solver.getIntegerSort()]) + c = solver.mkConst(intListSort, "c") + lis = listSort.getDatatype() + + # list datatype constructor and selector operator terms + consTerm1 = lis.getConstructorTerm("cons") + consTerm2 = lis.getConstructor("cons").getConstructorTerm() + nilTerm1 = lis.getConstructorTerm("nil") + nilTerm2 = lis.getConstructor("nil").getConstructorTerm() + headTerm1 = lis["cons"].getSelectorTerm("head") + headTerm2 = lis["cons"].getSelector("head").getSelectorTerm() + tailTerm1 = lis["cons"].getSelectorTerm("tail") + tailTerm2 = lis["cons"]["tail"].getSelectorTerm() + + # mkTerm(Op op, Term term) const + solver.mkTerm(kinds.ApplyConstructor, nilTerm1) + solver.mkTerm(kinds.ApplyConstructor, nilTerm2) + with pytest.raises(RuntimeError): + solver.mkTerm(kinds.ApplySelector, nilTerm1) + with pytest.raises(RuntimeError): + solver.mkTerm(kinds.ApplySelector, consTerm1) + with pytest.raises(RuntimeError): + solver.mkTerm(kinds.ApplyConstructor, consTerm2) + with pytest.raises(RuntimeError): + solver.mkTerm(opterm1) + with pytest.raises(RuntimeError): + solver.mkTerm(kinds.ApplySelector, headTerm1) + with pytest.raises(RuntimeError): + solver.mkTerm(opterm1) + with pytest.raises(RuntimeError): + slv.mkTerm(kinds.ApplyConstructor, nilTerm1) + + # mkTerm(Op op, Term child) const + solver.mkTerm(opterm1, a) + solver.mkTerm(opterm2, solver.mkInteger(1)) + solver.mkTerm(kinds.ApplySelector, headTerm1, c) + solver.mkTerm(kinds.ApplySelector, tailTerm2, c) + with pytest.raises(RuntimeError): + solver.mkTerm(opterm2, a) + with pytest.raises(RuntimeError): + solver.mkTerm(opterm1, pycvc5.Term(solver)) + with pytest.raises(RuntimeError): + solver.mkTerm(kinds.ApplyConstructor, consTerm1, solver.mkInteger(0)) + with pytest.raises(RuntimeError): + slv.mkTerm(opterm1, a) + + # mkTerm(Op op, Term child1, Term child2) const + solver.mkTerm(kinds.ApplyConstructor, consTerm1, solver.mkInteger(0), + solver.mkTerm(kinds.ApplyConstructor, nilTerm1)) + with pytest.raises(RuntimeError): + solver.mkTerm(opterm2, solver.mkInteger(1), solver.mkInteger(2)) + with pytest.raises(RuntimeError): + solver.mkTerm(opterm1, a, b) + with pytest.raises(RuntimeError): + solver.mkTerm(opterm2, solver.mkInteger(1), pycvc5.Term(solver)) + with pytest.raises(RuntimeError): + solver.mkTerm(opterm2, pycvc5.Term(solver), solver.mkInteger(1)) + with pytest.raises(RuntimeError): + slv.mkTerm(kinds.ApplyConstructor,\ + consTerm1,\ + solver.mkInteger(0),\ + solver.mkTerm(kinds.ApplyConstructor, nilTerm1)) + + # mkTerm(Op op, Term child1, Term child2, Term child3) const + with pytest.raises(RuntimeError): + solver.mkTerm(opterm1, a, b, a) + with pytest.raises(RuntimeError): + solver.mkTerm(opterm2, solver.mkInteger(1), solver.mkInteger(1), + pycvc5.Term(solver)) + + # mkTerm(Op op, const std::vector& children) const + solver.mkTerm(opterm2, v4) + with pytest.raises(RuntimeError): + solver.mkTerm(opterm2, v1) + with pytest.raises(RuntimeError): + solver.mkTerm(opterm2, v2) + with pytest.raises(RuntimeError): + solver.mkTerm(opterm2, v3) + with pytest.raises(RuntimeError): + slv.mkTerm(opterm2, v4) + + def test_mk_true(solver): solver.mkTrue() solver.mkTrue() +def test_mk_tuple(solver): + solver.mkTuple([solver.mkBitVectorSort(3)], [solver.mkBitVector("101", 2)]) + solver.mkTuple([solver.getRealSort()], [solver.mkInteger("5")]) + + with pytest.raises(RuntimeError): + solver.mkTuple([], [solver.mkBitVector("101", 2)]) + with pytest.raises(RuntimeError): + solver.mkTuple([solver.mkBitVectorSort(4)], + [solver.mkBitVector("101", 2)]) + with pytest.raises(RuntimeError): + solver.mkTuple([solver.getIntegerSort()], [solver.mkReal("5.3")]) + slv = pycvc5.Solver() + with pytest.raises(RuntimeError): + slv.mkTuple([solver.mkBitVectorSort(3)], [slv.mkBitVector("101", 2)]) + with pytest.raises(RuntimeError): + slv.mkTuple([slv.mkBitVectorSort(3)], [solver.mkBitVector("101", 2)]) + + def test_mk_universe_set(solver): solver.mkUniverseSet(solver.getBooleanSort()) with pytest.raises(RuntimeError): -- 2.30.2