From patchwork Sun Mar 10 20:09:26 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?S=C3=B6ren_Tempel?= X-Patchwork-Id: 61603 Return-Path: X-Original-To: patchwork@mira.cbaines.net Delivered-To: patchwork@mira.cbaines.net Received: by mira.cbaines.net (Postfix, from userid 113) id A2B9C27BBE2; Sun, 10 Mar 2024 20:12:22 +0000 (GMT) X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on mira.cbaines.net X-Spam-Level: X-Spam-Status: No, score=-2.7 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,SPF_HELO_PASS,URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.6 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mira.cbaines.net (Postfix) with ESMTPS id C956427BBEC for ; Sun, 10 Mar 2024 20:12:16 +0000 (GMT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rjPWQ-0003WR-2h; Sun, 10 Mar 2024 16:11:50 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rjPWK-0003V4-P7 for guix-patches@gnu.org; Sun, 10 Mar 2024 16:11:47 -0400 Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1rjPWJ-0002Qq-Oj; Sun, 10 Mar 2024 16:11:44 -0400 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1rjPWe-0003iu-IK; Sun, 10 Mar 2024 16:12:04 -0400 X-Loop: help-debbugs@gnu.org Subject: [bug#69074] [PATCH v2 06/14] gnu: Add python-pysmt. Resent-From: soeren@soeren-tempel.net Original-Sender: "Debbugs-submit" Resent-CC: lars@6xq.net, marius@gnu.org, me@bonfacemunyoki.com, sharlatanus@gmail.com, jgart@dismail.de, guix-patches@gnu.org Resent-Date: Sun, 10 Mar 2024 20:12:04 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 69074 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 69074@debbugs.gnu.org Cc: troy@troyfigiel.com, Lars-Dominik Braun , Marius Bakke , Munyoki Kilyungi , Sharlatan Hellseher , jgart X-Debbugs-Original-Xcc: Lars-Dominik Braun , Marius Bakke , Munyoki Kilyungi , Sharlatan Hellseher , jgart Received: via spool by 69074-submit@debbugs.gnu.org id=B69074.171010149814199 (code B ref 69074); Sun, 10 Mar 2024 20:12:04 +0000 Received: (at 69074) by debbugs.gnu.org; 10 Mar 2024 20:11:38 +0000 Received: from localhost ([127.0.0.1]:37966 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rjPW1-0003gi-O3 for submit@debbugs.gnu.org; Sun, 10 Mar 2024 16:11:38 -0400 Received: from magnesium.8pit.net ([45.76.88.171]:44758) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rjPVt-0003eq-9y; Sun, 10 Mar 2024 16:11:18 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; s=opensmtpd; bh=MmA59co2 Hch0xDY7iVs04dfWyyZpYSxCy5403wrQW4k=; h=references:in-reply-to:date: subject:cc:to:from; d=soeren-tempel.net; b=aOp9L4b5NZjAQE9KTIO5ote2Nkv aoPXdkBfwGoRhDZd/OvM5f486DbHBC09h3kjAK4zJijZ7k42L7DcMoLx862grRSF54GDAd 6iSBmsz+bsE5l6eIEZPaFK/I1JZ5uOJtSAqFkA6Rc1PiNI6RuIouXBlALfa2K7NfrUIJ+F LTIs= Received: from localhost (dynamic-2a02-3102-49da-001b-9766-31d2-bfd2-3d82.310.pool.telefonica.de [2a02:3102:49da:1b:9766:31d2:bfd2:3d82]) by magnesium.8pit.net (OpenSMTPD) with ESMTPSA id 2d2a0e80 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:YES); Sun, 10 Mar 2024 21:10:39 +0100 (CET) From: soeren@soeren-tempel.net Date: Sun, 10 Mar 2024 21:09:26 +0100 Message-ID: <37b09a67f0fb1e1c33994b145fd05aab064c876c.1710101374.git.soeren@soeren-tempel.net> X-Mailer: git-send-email 2.44.0 In-Reply-To: <19ef0993fd8891d02402943609f70de73e0b233a.1710101374.git.soeren@soeren-tempel.net> References: <19ef0993fd8891d02402943609f70de73e0b233a.1710101374.git.soeren@soeren-tempel.net> MIME-Version: 1.0 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org Sender: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org X-getmail-retrieved-from-mailbox: Patches From: Sören Tempel * gnu/packages/patches/python-pysmt-fix-pow-return-type.patch: New patch. * gnu/packages/patches/python-pysmt-fix-smtlib-serialization-test.patch: New patch. * gnu/local.mk (dist_patch_DATA): Add them. * gnu/packages/python-xyz.scm (python-pysmt): New variable. --- gnu/local.mk | 2 + .../python-pysmt-fix-pow-return-type.patch | 258 ++++++++++++++++++ ...-pysmt-fix-smtlib-serialization-test.patch | 86 ++++++ gnu/packages/python-xyz.scm | 32 +++ 4 files changed, 378 insertions(+) create mode 100644 gnu/packages/patches/python-pysmt-fix-pow-return-type.patch create mode 100644 gnu/packages/patches/python-pysmt-fix-smtlib-serialization-test.patch diff --git a/gnu/local.mk b/gnu/local.mk index fbdb285695..1946fdcbb6 100644 --- a/gnu/local.mk +++ b/gnu/local.mk @@ -1925,6 +1925,8 @@ dist_patch_DATA = \ %D%/packages/patches/python-pyan3-fix-absolute-path-bug.patch \ %D%/packages/patches/python-pyan3-fix-positional-arguments.patch \ %D%/packages/patches/python-pygpgme-fix-pinentry-tests.patch \ + %D%/packages/patches/python-pysmt-fix-pow-return-type.patch \ + %D%/packages/patches/python-pysmt-fix-smtlib-serialization-test.patch \ %D%/packages/patches/python-pytorch-runpath.patch \ %D%/packages/patches/python-pytorch-system-libraries.patch \ %D%/packages/patches/python-pytorch-1.9.0-system-libraries.patch \ diff --git a/gnu/packages/patches/python-pysmt-fix-pow-return-type.patch b/gnu/packages/patches/python-pysmt-fix-pow-return-type.patch new file mode 100644 index 0000000000..0ec2d41b3c --- /dev/null +++ b/gnu/packages/patches/python-pysmt-fix-pow-return-type.patch @@ -0,0 +1,258 @@ +Backport of an upstream patch which fixes a test failure with our +packaged version of the Z3 SMT solver. + +Taken from: https://github.com/pysmt/pysmt/commit/f522e8cd8f3e75ff85f5eae29b427e18a6701859 + +diff --git a/pysmt/formula.py b/pysmt/formula.py +index ea4b46c..6cb9cbf 100644 +--- a/pysmt/formula.py ++++ b/pysmt/formula.py +@@ -252,11 +252,7 @@ class FormulaManager(object): + + if base.is_constant(): + val = base.constant_value() ** exponent.constant_value() +- if base.is_constant(types.REAL): +- return self.Real(val) +- else: +- assert base.is_constant(types.INT) +- return self.Int(val) ++ return self.Real(val) + return self.create_node(node_type=op.POW, args=(base, exponent)) + + def Div(self, left, right): +diff --git a/pysmt/logics.py b/pysmt/logics.py +index ef88dd6..9dc45b1 100644 +--- a/pysmt/logics.py ++++ b/pysmt/logics.py +@@ -495,6 +495,12 @@ QF_NRA = Logic(name="QF_NRA", + real_arithmetic=True, + linear=False) + ++QF_NIRA = Logic(name="QF_NIRA", ++ description="""Quantifier-free integer and real arithmetic.""", ++ quantifier_free=True, ++ integer_arithmetic=True, ++ real_arithmetic=True, ++ linear=False) + + QF_RDL = Logic(name="QF_RDL", + description=\ +@@ -619,41 +625,41 @@ QF_AUFBVLIRA = Logic(name="QF_AUFBVLIRA", + AUTO = Logic(name="Auto", + description="Special logic used to indicate that the logic to be used depends on the formula.") + +-SMTLIB2_LOGICS = frozenset([ AUFLIA, +- AUFLIRA, +- AUFNIRA, +- ALIA, +- LRA, +- LIA, +- NIA, +- NRA, +- UFLRA, +- UFNIA, +- UFLIRA, +- QF_ABV, +- QF_AUFBV, +- QF_AUFLIA, +- QF_ALIA, +- QF_AX, +- QF_BV, +- QF_IDL, +- QF_LIA, +- QF_LRA, +- QF_NIA, +- QF_NRA, +- QF_RDL, +- QF_UF, +- QF_UFBV , +- QF_UFIDL, +- QF_UFLIA, +- QF_UFLRA, +- QF_UFNRA, +- QF_UFNIA, +- QF_UFLIRA, +- QF_SLIA +- ]) +- +-LOGICS = SMTLIB2_LOGICS | frozenset([ QF_BOOL, BOOL, QF_AUFBVLIRA]) ++SMTLIB2_LOGICS = frozenset([AUFLIA, ++ AUFLIRA, ++ AUFNIRA, ++ ALIA, ++ LRA, ++ LIA, ++ NIA, ++ NRA, ++ UFLRA, ++ UFNIA, ++ UFLIRA, ++ QF_ABV, ++ QF_AUFBV, ++ QF_AUFLIA, ++ QF_ALIA, ++ QF_AX, ++ QF_BV, ++ QF_IDL, ++ QF_LIA, ++ QF_LRA, ++ QF_NIA, ++ QF_NRA, ++ QF_RDL, ++ QF_UF, ++ QF_UFBV, ++ QF_UFIDL, ++ QF_UFLIA, ++ QF_UFLRA, ++ QF_UFNRA, ++ QF_UFNIA, ++ QF_UFLIRA, ++ QF_SLIA ++ ]) ++ ++LOGICS = SMTLIB2_LOGICS | frozenset([QF_BOOL, BOOL, QF_AUFBVLIRA, QF_NIRA]) + + QF_LOGICS = frozenset(_l for _l in LOGICS if _l.quantifier_free) + +@@ -668,8 +674,8 @@ PYSMT_LOGICS = frozenset([QF_BOOL, QF_IDL, QF_LIA, QF_LRA, QF_RDL, QF_UF, QF_UFI + QF_BV, QF_UFBV, + QF_ABV, QF_AUFBV, QF_AUFLIA, QF_ALIA, QF_AX, + QF_AUFBVLIRA, +- QF_NRA, QF_NIA, UFBV, BV, +- ]) ++ QF_NRA, QF_NIA, QF_NIRA, UFBV, BV, ++ ]) + + # PySMT Logics includes additional features: + # - constant arrays: QF_AUFBV becomes QF_AUFBV* +@@ -697,7 +703,6 @@ for l in PYSMT_LOGICS: + ext_logics.add(nl) + + +- + LOGICS = LOGICS | frozenset(ext_logics) + PYSMT_LOGICS = PYSMT_LOGICS | frozenset(ext_logics) + +diff --git a/pysmt/solvers/z3.py b/pysmt/solvers/z3.py +index 3fb42b9..210b771 100644 +--- a/pysmt/solvers/z3.py ++++ b/pysmt/solvers/z3.py +@@ -595,6 +595,8 @@ class Z3Converter(Converter, DagWalker): + None, None, + 0, None, + expr.ast) ++ print("Z3: SMTLIB") ++ print(s) + stream_in = StringIO(s) + r = parser.get_script(stream_in).get_last_formula(self.mgr) + key = (askey(expr), None) +diff --git a/pysmt/test/examples.py b/pysmt/test/examples.py +index 73455ee..b653185 100644 +--- a/pysmt/test/examples.py ++++ b/pysmt/test/examples.py +@@ -898,12 +898,12 @@ def get_full_example_formulae(environment=None): + logic=pysmt.logics.QF_NRA + ), + +- Example(hr="((p ^ 2) = 0)", +- expr=Equals(Pow(p, Int(2)), Int(0)), ++ Example(hr="((p ^ 2) = 0.0)", ++ expr=Equals(Pow(p, Int(2)), Real(0)), + is_valid=False, + is_sat=True, +- logic=pysmt.logics.QF_NIA +- ), ++ logic=pysmt.logics.QF_NIRA ++ ), + + Example(hr="((r ^ 2.0) = 0.0)", + expr=Equals(Pow(r, Real(2)), Real(0)), +diff --git a/pysmt/test/test_back.py b/pysmt/test/test_back.py +index bceb45b..7a0ad63 100644 +--- a/pysmt/test/test_back.py ++++ b/pysmt/test/test_back.py +@@ -55,10 +55,10 @@ class TestBasic(TestCase): + res = msat.converter.back(term) + self.assertFalse(f == res) + +- def do_back(self, solver_name, z3_string_buffer=False): ++ def do_back(self, solver_name, via_smtlib=False): + for formula, _, _, logic in get_example_formulae(): + if logic.quantifier_free: +- if logic.theory.custom_type and z3_string_buffer: ++ if logic.theory.custom_type and via_smtlib: + # Printing of declare-sort from Z3 is not conformant + # with the SMT-LIB. We might consider extending our + # parser. +@@ -67,7 +67,7 @@ class TestBasic(TestCase): + s = Solver(name=solver_name, logic=logic) + term = s.converter.convert(formula) + if solver_name == "z3": +- if z3_string_buffer: ++ if via_smtlib: + res = s.converter.back_via_smtlib(term) + else: + res = s.converter.back(term) +@@ -84,8 +84,8 @@ class TestBasic(TestCase): + + @skipIfSolverNotAvailable("z3") + def test_z3_back_formulae(self): +- self.do_back("z3", z3_string_buffer=False) +- self.do_back("z3", z3_string_buffer=True) ++ self.do_back("z3", via_smtlib=True) ++ self.do_back("z3", via_smtlib=False) + + + if __name__ == '__main__': +diff --git a/pysmt/type_checker.py b/pysmt/type_checker.py +index b700fcf..7ce05aa 100644 +--- a/pysmt/type_checker.py ++++ b/pysmt/type_checker.py +@@ -33,6 +33,8 @@ class SimpleTypeChecker(walkers.DagWalker): + + def __init__(self, env=None): + walkers.DagWalker.__init__(self, env=env) ++ # Return None if the type cannot be computed rather than ++ # raising an exception. + self.be_nice = False + + def _get_key(self, formula, **kwargs): +@@ -42,7 +44,7 @@ class SimpleTypeChecker(walkers.DagWalker): + """ Returns the pysmt.types type of the formula """ + res = self.walk(formula) + if not self.be_nice and res is None: +- raise PysmtTypeError("The formula '%s' is not well-formed" \ ++ raise PysmtTypeError("The formula '%s' is not well-formed" + % str(formula)) + return res + +@@ -114,7 +116,7 @@ class SimpleTypeChecker(walkers.DagWalker): + + def walk_bv_comp(self, formula, args, **kwargs): + # We check that all children are BV and the same size +- a,b = args ++ a, b = args + if a != b or (not a.is_bv_type()): + return None + return BVType(1) +@@ -187,7 +189,7 @@ class SimpleTypeChecker(walkers.DagWalker): + if args[0].is_bool_type(): + raise PysmtTypeError("The formula '%s' is not well-formed." + "Equality operator is not supported for Boolean" +- " terms. Use Iff instead." \ ++ " terms. Use Iff instead." + % str(formula)) + elif args[0].is_bv_type(): + return self.walk_bv_to_bool(formula, args) +@@ -324,10 +326,7 @@ class SimpleTypeChecker(walkers.DagWalker): + def walk_pow(self, formula, args, **kwargs): + if args[0] != args[1]: + return None +- # Exponent must be positive for INT +- if args[0].is_int_type() and formula.arg(1).constant_value() < 0 : +- return None +- return args[0] ++ return REAL + + # EOC SimpleTypeChecker + diff --git a/gnu/packages/patches/python-pysmt-fix-smtlib-serialization-test.patch b/gnu/packages/patches/python-pysmt-fix-smtlib-serialization-test.patch new file mode 100644 index 0000000000..eee555f807 --- /dev/null +++ b/gnu/packages/patches/python-pysmt-fix-smtlib-serialization-test.patch @@ -0,0 +1,86 @@ +Backport of an upstream patch fixing a test suite failure. + +Taken from: https://github.com/pysmt/pysmt/commit/a246669a487aff69f5da34570ef867841d18508a + +diff --git a/pysmt/test/smtlib/test_parser_examples.py b/pysmt/test/smtlib/test_parser_examples.py +index cca4194..c0852be 100644 +--- a/pysmt/test/smtlib/test_parser_examples.py ++++ b/pysmt/test/smtlib/test_parser_examples.py +@@ -29,6 +29,7 @@ from pysmt.shortcuts import Iff + from pysmt.shortcuts import read_smtlib, write_smtlib, get_env + from pysmt.exceptions import PysmtSyntaxError + ++ + class TestSMTParseExamples(TestCase): + + def test_parse_examples(self): +@@ -41,7 +42,6 @@ class TestSMTParseExamples(TestCase): + buf = StringIO() + script_out = smtlibscript_from_formula(f_out) + script_out.serialize(outstream=buf) +- #print(buf) + + buf.seek(0) + parser = SmtLibParser() +@@ -49,7 +49,6 @@ class TestSMTParseExamples(TestCase): + f_in = script_in.get_last_formula() + self.assertEqual(f_in.simplify(), f_out.simplify()) + +- + @skipIfNoSolverForLogic(logics.QF_BV) + def test_parse_examples_bv(self): + """For BV we represent a superset of the operators defined in SMT-LIB. +@@ -108,7 +107,18 @@ class TestSMTParseExamples(TestCase): + self.assertValid(Iff(f_in, f_out), f_in.serialize()) + + def test_dumped_logic(self): +- # Dumped logic matches the logic in the example ++ # Dumped logic matches the logic in the example. ++ # ++ # There are a few cases where we use a logic ++ # that does not exist in SMT-LIB, and the SMT-LIB ++ # serialization logic will find a logic that ++ # is more expressive. We need to adjust the test ++ # for those cases (see rewrite dict below). ++ rewrite = { ++ logics.QF_BOOL: logics.QF_UF, ++ logics.BOOL: logics.LRA, ++ logics.QF_NIRA: logics.AUFNIRA, ++ } + fs = get_example_formulae() + + for (f_out, _, _, logic) in fs: +@@ -121,14 +131,9 @@ class TestSMTParseExamples(TestCase): + for cmd in script_in: + if cmd.name == "set-logic": + logic_in = cmd.args[0] +- if logic == logics.QF_BOOL: +- self.assertEqual(logic_in, logics.QF_UF) +- elif logic == logics.BOOL: +- self.assertEqual(logic_in, logics.LRA) +- else: +- self.assertEqual(logic_in, logic, script_in) ++ self.assertEqual(logic_in, rewrite.get(logic, logic)) + break +- else: # Loops exited normally ++ else: # Loops exited normally + print("-"*40) + print(script_in) + +@@ -136,7 +141,7 @@ class TestSMTParseExamples(TestCase): + fs = get_example_formulae() + + fdi, tmp_fname = mkstemp() +- os.close(fdi) # Close initial file descriptor ++ os.close(fdi) # Close initial file descriptor + for (f_out, _, _, _) in fs: + write_smtlib(f_out, tmp_fname) + # with open(tmp_fname) as fin: +@@ -197,7 +202,6 @@ class TestSMTParseExamples(TestCase): + f_in = script.get_last_formula() + self.assertSat(f_in) + +- + def test_int_promotion_define_fun(self): + script = """ + (define-fun x () Int 8) diff --git a/gnu/packages/python-xyz.scm b/gnu/packages/python-xyz.scm index f9bd733ecd..0c6265f60e 100644 --- a/gnu/packages/python-xyz.scm +++ b/gnu/packages/python-xyz.scm @@ -32303,6 +32303,38 @@ (define-public python-opcodes and BMI2).") (license license:bsd-2)))) +(define-public python-pysmt + (package + (name "python-pysmt") + (version "0.9.5") + (source + (origin + (method git-fetch) + (patches (search-patches "python-pysmt-fix-pow-return-type.patch" + "python-pysmt-fix-smtlib-serialization-test.patch")) + (uri (git-reference + (url "https://github.com/pysmt/pysmt") + (commit (string-append "v" version)))) + (file-name (git-file-name name version)) + (sha256 + (base32 "0hrxv23y5ip4ijfx5pvbwc2fq4zg9jz42wc9zqgqm0g0mjc9ckvh")))) + (build-system pyproject-build-system) + (arguments + `(#:phases (modify-phases %standard-phases + (add-before 'check 'set-pysmt-solver + (lambda _ + (setenv "PYSMT_SOLVER" "z3")))))) + (native-inputs (list python-pytest)) + (propagated-inputs (list z3)) + (home-page "https://github.com/pysmt/pysmt") + (synopsis + "Solver-agnostic library for SMT formula manipulation and solving") + (description + "This Python module provides a solver-agnostic abstraction for +working with @acronym{SMT, Satisfiability Modulo Theory} formulas. For example, +it allows manipulation and solving such formulas.") + (license license:asl2.0))) + (define-public python-rpyc (package (name "python-rpyc")