├── requirements.txt ├── apronpy ├── __init__.py ├── cdll.py ├── abstract0.py ├── oct.py ├── tcons0.py ├── box.py ├── t1p.py ├── polka.py ├── lincons0.py ├── linexpr0.py ├── dimension.py ├── var.py ├── mpz.py ├── texpr0.py ├── mpq.py ├── mpfr.py ├── texpr1.py ├── interval.py ├── linexpr1.py ├── scalar.py ├── coeff.py ├── environment.py ├── manager.py ├── tcons1.py ├── lincons1.py ├── playground.py └── abstract1.py ├── setup.py ├── README.md ├── tests ├── test_var.py ├── test_mpz.py ├── test_mpfr.py ├── test_mpq.py ├── test_texpr1.py ├── test_tcons1.py ├── test_environment.py ├── test_linexpr1.py ├── test_lincons1.py ├── test_coeff.py ├── test_scalar.py ├── test_box.py └── test_interval.py ├── LICENSE └── .gitignore /requirements.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apronpy/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apronpy/cdll.py: -------------------------------------------------------------------------------- 1 | """ 2 | C DLLs 3 | ====== 4 | 5 | :Author: Caterina Urban 6 | """ 7 | from ctypes import util, CDLL 8 | 9 | libc = CDLL(util.find_library('c')) 10 | 11 | libapron = CDLL('libapron.so') 12 | 13 | libgmp = CDLL(util.find_library('gmp')) 14 | libmpfr = CDLL(util.find_library('mpfr')) 15 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | setup( 4 | name='apronpy', 5 | version='1.0.12', 6 | author='Caterina Urban', 7 | author_email='caterina.urban@gmail.com', 8 | description='Python Interface for the APRON Numerical Abstract Domain Library', 9 | long_description=open('README.md').read(), 10 | long_description_content_type='text/markdown', 11 | url='https://github.com/caterinaurban/apronpy', 12 | packages=find_packages(), 13 | ) 14 | -------------------------------------------------------------------------------- /apronpy/abstract0.py: -------------------------------------------------------------------------------- 1 | """ 2 | APRON Abstract Values (Level 0) 3 | =============================== 4 | 5 | :Author: Caterina Urban 6 | """ 7 | from _ctypes import Structure, POINTER 8 | from ctypes import c_void_p 9 | 10 | from apronpy.manager import Manager 11 | 12 | 13 | class Abstract0(Structure): 14 | """ 15 | struct ap_abstract0_t { 16 | void* value; /* Abstract value of the underlying library */ 17 | ap_manager_t* man; /* Used to identify the effective type of value */ 18 | }; 19 | """ 20 | 21 | _fields_ = [ 22 | ('value', c_void_p), 23 | ('man', POINTER(Manager)) 24 | ] 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # apronpy 2 | 3 | Python Interface for the 4 | [APRON Numerical Abstract Domain Library](http://apron.cri.ensmp.fr/library/). 5 | 6 | ## Getting Started 7 | 8 | ### Prerequisites 9 | 10 | * Install [**APRON**](https://github.com/antoinemine/apron) 11 | 12 | * Install [**Python 3.x**](http://www.python.org/) 13 | 14 | ### Installation 15 | 16 | * Create a virtual Python environment: 17 | 18 | | Linux or Mac OS X | 19 | | ----------------------------------- | 20 | | `virtualenv --python=python3 ` | 21 | 22 | * Install apronpy in the virtual environment: 23 | 24 | | Linux or Mac OS X | 25 | | --------------------------------- | 26 | | `.//bin/pip install apronpy` | 27 | 28 | -------------------------------------------------------------------------------- /apronpy/oct.py: -------------------------------------------------------------------------------- 1 | """ 2 | APRON Octagons 3 | ============== 4 | 5 | :Author: Caterina Urban 6 | """ 7 | from _ctypes import POINTER 8 | from ctypes import CDLL 9 | 10 | from apronpy.abstract1 import PyAbstract1 11 | from apronpy.manager import PyManager, Manager 12 | 13 | 14 | liboctD = CDLL('liboctD.so') 15 | liboctMPQ = CDLL('liboctMPQ.so') 16 | 17 | 18 | class PyOctDManager(PyManager): 19 | 20 | def __init__(self): 21 | super().__init__(liboctD.oct_manager_alloc()) 22 | 23 | 24 | class PyOctMPQManager(PyManager): 25 | 26 | def __init__(self): 27 | super().__init__(liboctMPQ.oct_manager_alloc()) 28 | 29 | 30 | liboctD.oct_manager_alloc.restype = POINTER(Manager) 31 | liboctMPQ.oct_manager_alloc.restype = POINTER(Manager) 32 | 33 | 34 | class PyOct(PyAbstract1): # parallelizable implementation 35 | pass 36 | -------------------------------------------------------------------------------- /tests/test_var.py: -------------------------------------------------------------------------------- 1 | """ 2 | APRON (String) Variables - Unit Tests 3 | ===================================== 4 | 5 | :Author: Caterina Urban 6 | """ 7 | import unittest 8 | from copy import deepcopy 9 | 10 | from apronpy.var import PyVar 11 | 12 | 13 | class TestPyVar(unittest.TestCase): 14 | 15 | def test_init(self): 16 | self.assertEqual(str(PyVar('x0')), 'x0') 17 | self.assertEqual(str(PyVar('X')), 'X') 18 | 19 | def test_deepcopy(self): 20 | x0 = PyVar('X') 21 | x1 = deepcopy(x0) 22 | x2 = x0 23 | self.assertNotEqual(id(x0), id(x1)) 24 | self.assertEqual(id(x0), id(x2)) 25 | 26 | def test_cmp(self): 27 | self.assertTrue(PyVar('X') < PyVar('x0')) 28 | self.assertFalse(PyVar('X') == PyVar('x0')) 29 | self.assertTrue(PyVar('x0') == PyVar('x0')) 30 | self.assertFalse(PyVar('X') > PyVar('x0')) 31 | self.assertTrue(PyVar('y') > PyVar('x0')) 32 | 33 | 34 | if __name__ == '__main__': 35 | unittest.main() 36 | -------------------------------------------------------------------------------- /apronpy/tcons0.py: -------------------------------------------------------------------------------- 1 | """ 2 | APRON Tree Constraints (Level 0) 3 | ================================ 4 | 5 | :Author: Caterina Urban 6 | """ 7 | from _ctypes import Structure, POINTER 8 | 9 | from apronpy.scalar import Scalar, c_uint, c_size_t 10 | from apronpy.texpr0 import Texpr0 11 | 12 | 13 | class Tcons0(Structure): 14 | """ 15 | typedef struct ap_tcons0_t { 16 | ap_texpr0_t* texpr0; /* expression */ 17 | ap_constyp_t constyp; /* type of constraint */ 18 | ap_scalar_t* scalar; /* maybe NULL. For EQMOD constraint, indicates the modulo */ 19 | } ap_tcons0_t; 20 | """ 21 | 22 | _fields_ = [ 23 | ('texpr0', POINTER(Texpr0)), 24 | ('constyp', c_uint), 25 | ('scalar', POINTER(Scalar)) 26 | ] 27 | 28 | 29 | class Tcons0Array(Structure): 30 | """ 31 | typedef struct ap_tcons0_array_t { 32 | ap_tcons0_t* p; 33 | size_t size; 34 | } ap_tcons0_array_t; 35 | """ 36 | 37 | _fields_ = [ 38 | ('p', POINTER(Tcons0)), 39 | ('size', c_size_t) 40 | ] 41 | -------------------------------------------------------------------------------- /apronpy/box.py: -------------------------------------------------------------------------------- 1 | """ 2 | APRON Boxes 3 | =========== 4 | 5 | :Author: Caterina Urban 6 | """ 7 | from _ctypes import POINTER 8 | from ctypes import CDLL 9 | 10 | from apronpy.abstract1 import PyAbstract1 11 | from apronpy.manager import PyManager, Manager 12 | 13 | 14 | libboxD = CDLL('libboxD.so') 15 | libboxMPQ = CDLL('libboxMPQ.so') 16 | libboxMPFR = CDLL('libboxMPFR.so') 17 | 18 | 19 | class PyBoxDManager(PyManager): 20 | 21 | def __init__(self): 22 | super().__init__(libboxD.box_manager_alloc()) 23 | 24 | 25 | class PyBoxMPQManager(PyManager): 26 | 27 | def __init__(self): 28 | super().__init__(libboxMPQ.box_manager_alloc()) 29 | 30 | 31 | class PyBoxMPFRManager(PyManager): 32 | 33 | def __init__(self): 34 | super().__init__(libboxMPFR.box_manager_alloc()) 35 | 36 | 37 | libboxD.box_manager_alloc.restype = POINTER(Manager) 38 | libboxMPQ.box_manager_alloc.restype = POINTER(Manager) 39 | libboxMPFR.box_manager_alloc.restype = POINTER(Manager) 40 | 41 | 42 | class PyBox(PyAbstract1): # parallelizable implementation 43 | pass 44 | -------------------------------------------------------------------------------- /apronpy/t1p.py: -------------------------------------------------------------------------------- 1 | """ 2 | APRON Taylor1+ 3 | ============== 4 | 5 | :Author: Caterina Urban 6 | """ 7 | from _ctypes import POINTER 8 | from ctypes import CDLL 9 | 10 | from apronpy.abstract1 import PyAbstract1 11 | from apronpy.manager import PyManager, Manager 12 | 13 | 14 | libt1pD = CDLL('libt1pD.so') 15 | libt1pMPQ = CDLL('libt1pMPQ.so') 16 | libt1pMPFR = CDLL('libt1pMPFR.so') 17 | 18 | 19 | class PyT1pDManager(PyManager): 20 | 21 | def __init__(self): 22 | super().__init__(libt1pD.t1p_manager_alloc()) 23 | 24 | 25 | class PyT1pMPQManager(PyManager): 26 | 27 | def __init__(self): 28 | super().__init__(libt1pMPQ.t1p_manager_alloc()) 29 | 30 | 31 | class PyT1pMPFRManager(PyManager): 32 | 33 | def __init__(self): 34 | super().__init__(libt1pMPFR.t1p_manager_alloc()) 35 | 36 | 37 | libt1pD.t1p_manager_alloc.restype = POINTER(Manager) 38 | libt1pMPQ.t1p_manager_alloc.restype = POINTER(Manager) 39 | libt1pMPFR.t1p_manager_alloc.restype = POINTER(Manager) 40 | 41 | 42 | class PyT1p(PyAbstract1): # parallelizable implementation 43 | pass 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Caterina Urban 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /apronpy/polka.py: -------------------------------------------------------------------------------- 1 | """ 2 | APRON Polyhedra 3 | =============== 4 | 5 | :Author: Caterina Urban 6 | """ 7 | from _ctypes import POINTER 8 | from ctypes import CDLL 9 | 10 | from apronpy.abstract1 import PyAbstract1 11 | from apronpy.manager import PyManager, Manager 12 | 13 | 14 | libpolkaMPQ = CDLL('libpolkaMPQ.so') 15 | libpolkaRll = CDLL('libpolkaRll.so') 16 | 17 | 18 | class PyPolkaMPQlooseManager(PyManager): 19 | 20 | def __init__(self): 21 | super().__init__(libpolkaMPQ.pk_manager_alloc(False)) 22 | 23 | 24 | class PyPolkaMPQstrictManager(PyManager): 25 | 26 | def __init__(self): 27 | super().__init__(libpolkaMPQ.pk_manager_alloc(True)) 28 | 29 | 30 | class PyPolkaRlllooseManager(PyManager): 31 | 32 | def __init__(self): 33 | super().__init__(libpolkaRll.pk_manager_alloc(False)) 34 | 35 | 36 | class PyPolkaRllstrictManager(PyManager): 37 | 38 | def __init__(self): 39 | super().__init__(libpolkaRll.pk_manager_alloc(True)) 40 | 41 | 42 | libpolkaMPQ.pk_manager_alloc.restype = POINTER(Manager) 43 | libpolkaRll.pk_manager_alloc.restype = POINTER(Manager) 44 | 45 | 46 | class PyPolka(PyAbstract1): # parallelizable implementation 47 | pass 48 | -------------------------------------------------------------------------------- /tests/test_mpz.py: -------------------------------------------------------------------------------- 1 | """ 2 | GMP Multi-Precision Integers - Unit Tests 3 | ========================================= 4 | 5 | :Author: Caterina Urban 6 | """ 7 | import unittest 8 | from copy import deepcopy 9 | 10 | from apronpy.mpz import PyMPZ 11 | 12 | 13 | class TestPyMPZ(unittest.TestCase): 14 | 15 | def test_initialization_assignment_conversion(self): 16 | self.assertEqual(str(PyMPZ()), '0') 17 | self.assertEqual(str(PyMPZ(0.0)), '0') 18 | self.assertEqual(str(PyMPZ(9)), '9') 19 | 20 | def test_deepcopy(self): 21 | z0 = PyMPZ(3) 22 | z1 = deepcopy(z0) 23 | z2 = z0 24 | self.assertNotEqual(id(z0), id(z1)) 25 | self.assertEqual(id(z0), id(z2)) 26 | 27 | def test_arithmetic(self): 28 | self.assertEqual(PyMPZ(9) + PyMPZ(3), PyMPZ(9 + 3)) 29 | self.assertEqual(PyMPZ(9) - PyMPZ(3), PyMPZ(9 - 3)) 30 | self.assertEqual(PyMPZ(9) * PyMPZ(3), PyMPZ(9 * 3)) 31 | self.assertEqual(-PyMPZ(9), PyMPZ(-9)) 32 | self.assertEqual(abs(PyMPZ(-9)), PyMPZ(abs(-9))) 33 | 34 | def test_comparison(self): 35 | self.assertTrue(PyMPZ(3) < PyMPZ(9)) 36 | self.assertTrue(PyMPZ(3) <= PyMPZ(9)) 37 | self.assertTrue(PyMPZ(9) <= PyMPZ(9)) 38 | self.assertTrue(PyMPZ(9) == PyMPZ(9)) 39 | self.assertTrue(PyMPZ(3) != PyMPZ(9)) 40 | self.assertTrue(PyMPZ(9) >= PyMPZ(9)) 41 | self.assertTrue(PyMPZ(9) >= PyMPZ(3)) 42 | self.assertTrue(PyMPZ(9) > PyMPZ(3)) 43 | 44 | 45 | if __name__ == '__main__': 46 | unittest.main() 47 | -------------------------------------------------------------------------------- /tests/test_mpfr.py: -------------------------------------------------------------------------------- 1 | """ 2 | MPFR Multiprecision Floating-Point Numbers - Unit Tests 3 | ======================================================= 4 | 5 | :Author: Caterina Urban 6 | """ 7 | import unittest 8 | from copy import deepcopy 9 | 10 | from apronpy.mpfr import PyMPFR 11 | 12 | 13 | class TestPyMPFR(unittest.TestCase): 14 | 15 | def test_initialization_assignment_conversion(self): 16 | self.assertEqual(str(PyMPFR(9)), '9.0') 17 | self.assertEqual(str(PyMPFR(-9)), '-9.0') 18 | 19 | def test_deepcopy(self): 20 | f0 = PyMPFR(9) 21 | f1 = deepcopy(f0) 22 | f2 = f0 23 | self.assertNotEqual(id(f0), id(f1)) 24 | self.assertEqual(id(f0), id(f2)) 25 | 26 | def test_arithmetic(self): 27 | self.assertEqual(PyMPFR(9) + PyMPFR(3), PyMPFR(9 + 3)) 28 | self.assertEqual(PyMPFR(9) - PyMPFR(3), PyMPFR(9 - 3)) 29 | self.assertEqual(PyMPFR(9) * PyMPFR(3), PyMPFR(9 * 3)) 30 | self.assertEqual(-PyMPFR(9), PyMPFR(-9)) 31 | self.assertEqual(abs(PyMPFR(-9)), PyMPFR(abs(-9))) 32 | 33 | def test_comparison(self): 34 | self.assertTrue(PyMPFR(3) < PyMPFR(9)) 35 | self.assertTrue(PyMPFR(3) <= PyMPFR(9)) 36 | self.assertTrue(PyMPFR(9) <= PyMPFR(9)) 37 | self.assertTrue(PyMPFR(9) == PyMPFR(9)) 38 | self.assertTrue(PyMPFR(3) != PyMPFR(9)) 39 | self.assertTrue(PyMPFR(9) >= PyMPFR(9)) 40 | self.assertTrue(PyMPFR(9) >= PyMPFR(3)) 41 | self.assertTrue(PyMPFR(9) > PyMPFR(3)) 42 | 43 | 44 | if __name__ == '__main__': 45 | unittest.main() 46 | -------------------------------------------------------------------------------- /tests/test_mpq.py: -------------------------------------------------------------------------------- 1 | """ 2 | GMP Multi-Precision Rationals - Unit Tests 3 | ========================================== 4 | 5 | :Author: Caterina Urban 6 | """ 7 | import unittest 8 | from copy import deepcopy 9 | 10 | from apronpy.mpq import PyMPQ 11 | 12 | 13 | class TestPyMPQ(unittest.TestCase): 14 | 15 | def test_initialization_assignment_conversion(self): 16 | self.assertEqual(str(PyMPQ()), '0') 17 | self.assertEqual(str(PyMPQ(0)), '0') 18 | self.assertEqual(str(PyMPQ(0.5)), '1/2') 19 | self.assertEqual(str(PyMPQ(0, 1)), '0') 20 | self.assertEqual(str(PyMPQ(1, 2)), '1/2') 21 | self.assertEqual(str(PyMPQ(2, 4)), '1/2') 22 | 23 | def test_deepcopy(self): 24 | q0 = PyMPQ(1, 2) 25 | q1 = deepcopy(q0) 26 | q2 = q0 27 | self.assertNotEqual(id(q0), id(q1)) 28 | self.assertEqual(id(q0), id(q2)) 29 | 30 | def test_arithmetic(self): 31 | self.assertEqual(PyMPQ(1, 2) + PyMPQ(1, 4), PyMPQ(3, 4)) 32 | self.assertEqual(PyMPQ(1, 2) - PyMPQ(1, 4), PyMPQ(1, 4)) 33 | self.assertEqual(PyMPQ(1, 2) * PyMPQ(1, 4), PyMPQ(1, 8)) 34 | self.assertEqual(-PyMPQ(1, 2), PyMPQ(-1, 2)) 35 | self.assertEqual(-PyMPQ(2, 4), PyMPQ(-1, 2)) 36 | self.assertEqual(abs(PyMPQ(-1, 2)), PyMPQ(abs(-1), abs(2))) 37 | 38 | def test_comparison(self): 39 | self.assertTrue(PyMPQ(1, 4) < PyMPQ(1, 2)) 40 | self.assertTrue(PyMPQ(1, 4) <= PyMPQ(1, 2)) 41 | self.assertTrue(PyMPQ(1, 2) <= PyMPQ(1, 2)) 42 | self.assertTrue(PyMPQ(1, 2) == PyMPQ(1, 2)) 43 | self.assertTrue(PyMPQ(1, 4) != PyMPQ(1, 2)) 44 | self.assertTrue(PyMPQ(1, 2) >= PyMPQ(1, 2)) 45 | self.assertTrue(PyMPQ(1, 2) >= PyMPQ(1, 4)) 46 | self.assertTrue(PyMPQ(1, 2) > PyMPQ(1, 4)) 47 | 48 | 49 | if __name__ == '__main__': 50 | unittest.main() 51 | -------------------------------------------------------------------------------- /tests/test_texpr1.py: -------------------------------------------------------------------------------- 1 | """ 2 | APRON Tree Expressions (Level 1) - Unit Tests 3 | ============================================= 4 | 5 | :Author: Caterina Urban 6 | """ 7 | import unittest 8 | 9 | from apronpy.coeff import PyDoubleScalarCoeff, PyMPQScalarCoeff 10 | from apronpy.environment import PyEnvironment 11 | from apronpy.linexpr1 import PyLinexpr1 12 | from apronpy.texpr1 import PyTexpr1 13 | from apronpy.var import PyVar 14 | 15 | 16 | class TestPyTexpr1(unittest.TestCase): 17 | 18 | def test_init(self): 19 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 20 | x = PyLinexpr1(e) 21 | x0 = PyLinexpr1(e, 0) 22 | self.assertEqual(str(PyTexpr1(x)), '0.0') 23 | self.assertEqual(str(PyTexpr1(x0)), '0.0 + 0.0 · x0 + 0.0 · y + 0.0 · z') 24 | x.set_coeff(PyVar('x0'), PyDoubleScalarCoeff(-1)) 25 | x.set_coeff(PyVar('z'), PyDoubleScalarCoeff(-9)) 26 | x.set_cst(PyDoubleScalarCoeff(8)) 27 | self.assertEqual(str(PyTexpr1(x)), '8.0 - 1.0 · x0 - 9.0 · z') 28 | 29 | def test_substitute(self): 30 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 31 | x0 = PyLinexpr1(e) 32 | x0.set_coeff(PyVar('x0'), PyMPQScalarCoeff(1)) 33 | x0.set_cst(PyMPQScalarCoeff(3)) 34 | t0 = PyTexpr1(x0) 35 | self.assertEqual(str(t0), '3 + 1 · x0') 36 | x1 = PyLinexpr1(e) 37 | x1.set_coeff(PyVar('x0'), PyMPQScalarCoeff(1)) 38 | x1.set_cst(PyMPQScalarCoeff(-1)) 39 | t1 = PyTexpr1(x1) 40 | self.assertEqual(str(t1), '-1 + 1 · x0') 41 | self.assertEqual(str(t0.substitute(PyVar('x0'), t1)), '3 + 1 · (-1 + 1 · x0)') 42 | x2 = PyLinexpr1(e) 43 | x2.set_coeff(PyVar('x0'), PyMPQScalarCoeff(1)) 44 | x2.set_cst(PyMPQScalarCoeff(2)) 45 | t2 = PyTexpr1(x2) 46 | self.assertEqual(str(t2), '2 + 1 · x0') 47 | 48 | 49 | if __name__ == '__main__': 50 | unittest.main() 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | .hypothesis/ 50 | .pytest_cache/ 51 | 52 | # Translations 53 | *.mo 54 | *.pot 55 | 56 | # Django stuff: 57 | *.log 58 | local_settings.py 59 | db.sqlite3 60 | 61 | # Flask stuff: 62 | instance/ 63 | .webassets-cache 64 | 65 | # Scrapy stuff: 66 | .scrapy 67 | 68 | # Sphinx documentation 69 | docs/_build/ 70 | 71 | # PyBuilder 72 | target/ 73 | 74 | # Jupyter Notebook 75 | .ipynb_checkpoints 76 | 77 | # IPython 78 | profile_default/ 79 | ipython_config.py 80 | 81 | # pyenv 82 | .python-version 83 | 84 | # celery beat schedule file 85 | celerybeat-schedule 86 | 87 | # SageMath parsed files 88 | *.sage.py 89 | 90 | # Environments 91 | .env 92 | .venv 93 | env/ 94 | venv/ 95 | ENV/ 96 | env.bak/ 97 | venv.bak/ 98 | 99 | # Spyder project settings 100 | .spyderproject 101 | .spyproject 102 | 103 | # Rope project settings 104 | .ropeproject 105 | 106 | # mkdocs documentation 107 | /site 108 | 109 | # mypy 110 | .mypy_cache/ 111 | .dmypy.json 112 | dmypy.json 113 | 114 | # Pyre type checker 115 | .pyre/ 116 | 117 | # PyCharm 118 | .idea 119 | -------------------------------------------------------------------------------- /apronpy/lincons0.py: -------------------------------------------------------------------------------- 1 | """ 2 | APRON Linear Constraints (Level 0) 3 | ================================== 4 | 5 | :Author: Caterina Urban 6 | """ 7 | from _ctypes import Structure, POINTER 8 | from ctypes import c_bool 9 | from enum import IntEnum 10 | 11 | from apronpy.cdll import libapron 12 | from apronpy.linexpr0 import Linexpr0 13 | from apronpy.scalar import Scalar, c_uint, c_size_t 14 | 15 | 16 | class ConsTyp(IntEnum): 17 | """ 18 | typedef enum ap_constyp_t { 19 | AP_CONS_EQ, /* equality constraint */ 20 | AP_CONS_SUPEQ, /* >= constraint */ 21 | AP_CONS_SUP, /* > constraint */ 22 | AP_CONS_EQMOD, /* congruence equality constraint */ 23 | AP_CONS_DISEQ /* disequality constraint */ 24 | } ap_constyp_t; 25 | """ 26 | AP_CONS_EQ = 0 27 | AP_CONS_SUPEQ = 1 28 | AP_CONS_SUP = 2 29 | AP_CONS_EQMOD = 3 30 | AP_CONS_DISEQ = 4 31 | 32 | def __repr__(self): 33 | if self.value == 0: 34 | return '==' 35 | elif self.value == 1: 36 | return '>=' 37 | elif self.value == 2: 38 | return '>' 39 | elif self.value == 3: 40 | return '%=' 41 | elif self.value == 4: 42 | return '!=' 43 | return ValueError('no matching constraint type') 44 | 45 | 46 | class Lincons0(Structure): 47 | """ 48 | typedef struct ap_lincons0_t { 49 | ap_linexpr0_t* linexpr0; /* expression */ 50 | ap_constyp_t constyp; /* type of constraint */ 51 | ap_scalar_t* scalar; /* maybe NULL. For EQMOD constraint, indicates the modulo */ 52 | } ap_lincons0_t; 53 | """ 54 | 55 | _fields_ = [ 56 | ('linexpr0', POINTER(Linexpr0)), 57 | ('constyp', c_uint), 58 | ('scalar', POINTER(Scalar)) 59 | ] 60 | 61 | 62 | class Lincons0Array(Structure): 63 | """ 64 | typedef struct ap_lincons0_array_t { 65 | ap_lincons0_t* p; 66 | size_t size; 67 | } ap_lincons0_array_t; 68 | """ 69 | 70 | _fields_ = [ 71 | ('p', POINTER(Lincons0)), 72 | ('size', c_size_t) 73 | ] 74 | 75 | 76 | libapron.ap_lincons0_is_unsat.argtypes = [POINTER(Lincons0)] 77 | libapron.ap_lincons0_is_unsat.restype = c_bool 78 | -------------------------------------------------------------------------------- /apronpy/linexpr0.py: -------------------------------------------------------------------------------- 1 | """ 2 | APRON Linear Expressions (Level 0) 3 | ================================== 4 | 5 | :Author: Caterina Urban 6 | """ 7 | from _ctypes import Structure, Union, POINTER 8 | from ctypes import c_uint, c_size_t, c_bool 9 | from enum import IntEnum 10 | 11 | from apronpy.cdll import libapron 12 | from apronpy.coeff import Coeff 13 | from apronpy.dimension import Dim 14 | 15 | 16 | class LinexprDiscr(IntEnum): 17 | """ 18 | typedef enum ap_linexpr_discr_t { 19 | AP_LINEXPR_DENSE, 20 | AP_LINEXPR_SPARSE 21 | } ap_linexpr_discr_t; 22 | """ 23 | AP_LINEXPR_DENSE = 0 24 | AP_LINEXPR_SPARSE = 1 25 | 26 | 27 | class LinTerm(Structure): 28 | """ 29 | typedef struct ap_linterm_t { 30 | ap_dim_t dim; 31 | ap_coeff_t coeff; 32 | } ap_linterm_t; 33 | """ 34 | 35 | _fields_ = [ 36 | ('dim', Dim), 37 | ('coeff', Coeff) 38 | ] 39 | 40 | def __repr__(self): 41 | return '{}'.format(self.coeff) 42 | 43 | 44 | class Linexpr0(Structure): 45 | """ 46 | typedef struct ap_linexpr0_t { 47 | ap_coeff_t cst; /* constant */ 48 | ap_linexpr_discr_t discr; /* discriminant for array */ 49 | size_t size; /* size of the array */ 50 | union { 51 | ap_coeff_t* coeff; /* array of coefficients */ 52 | ap_linterm_t* linterm; /* array of linear terms */ 53 | } p; 54 | } ap_linexpr0_t; 55 | """ 56 | 57 | class P(Union): 58 | """ 59 | union { 60 | ap_coeff_t* coeff; /* array of coefficients */ 61 | ap_linterm_t* linterm; /* array of linear terms */ 62 | } p; 63 | """ 64 | 65 | _fields_ = [ 66 | ('coeff', POINTER(Coeff)), 67 | ('linterm', POINTER(LinTerm)) 68 | ] 69 | 70 | _fields_ = [ 71 | ('cst', Coeff), 72 | ('discr', c_uint), 73 | ('size', c_size_t), 74 | ('p', P) 75 | ] 76 | 77 | 78 | libapron.ap_linexpr0_minimize.argtypes = [POINTER(Linexpr0)] 79 | libapron.ap_linexpr0_copy.argtypes = [POINTER(Linexpr0)] 80 | libapron.ap_linexpr0_copy.restype = POINTER(Linexpr0) 81 | libapron.ap_linexpr0_is_integer.argtypes = [POINTER(Linexpr0), c_size_t] 82 | libapron.ap_linexpr0_is_integer.restype = c_bool 83 | libapron.ap_linexpr0_is_real.argtypes = [POINTER(Linexpr0), c_size_t] 84 | libapron.ap_linexpr0_is_real.restype = c_bool 85 | libapron.ap_linexpr0_is_linear.argtypes = [POINTER(Linexpr0)] 86 | libapron.ap_linexpr0_is_linear.restype = c_bool 87 | libapron.ap_linexpr0_is_quasilinear.argtypes = [POINTER(Linexpr0)] 88 | libapron.ap_linexpr0_is_quasilinear.restype = c_bool 89 | -------------------------------------------------------------------------------- /apronpy/dimension.py: -------------------------------------------------------------------------------- 1 | """ 2 | APRON Dimensions 3 | ================ 4 | 5 | :Author: Caterina Urban 6 | """ 7 | from _ctypes import Structure, POINTER 8 | from ctypes import c_uint, c_size_t 9 | 10 | 11 | class Dim(c_uint): 12 | 13 | def __repr__(self): 14 | return str(self.value) 15 | 16 | def __lt__(self, other: 'Dim'): 17 | assert isinstance(other, Dim) 18 | return self.value < other.value 19 | 20 | def __le__(self, other: 'Dim'): 21 | assert isinstance(other, Dim) 22 | return self.__lt__(other) or self.__eq__(other) 23 | 24 | def __eq__(self, other: 'Dim'): 25 | assert isinstance(other, Dim) 26 | return self.value == other.value 27 | 28 | def __ne__(self, other: 'Dim'): 29 | assert isinstance(other, Dim) 30 | return not self.__eq__(other) 31 | 32 | def __ge__(self, other: 'Dim'): 33 | assert isinstance(other, Dim) 34 | return self.__gt__(other) or self.__eq__(other) 35 | 36 | def __gt__(self, other: 'Dim'): 37 | assert isinstance(other, Dim) 38 | return self.value > other.value 39 | 40 | 41 | AP_DIM_MAX = Dim(c_uint(-1).value) 42 | 43 | 44 | class Dimension(Structure): 45 | """ 46 | typedef struct ap_dimension_t { 47 | size_t intdim; 48 | size_t realdim; 49 | } ap_dimension_t; 50 | """ 51 | 52 | _fields_ = [ 53 | ('intdim', c_size_t), 54 | ('realdim', c_size_t) 55 | ] 56 | 57 | 58 | class DimChange(Structure): 59 | """ 60 | typedef struct ap_dimchange_t { 61 | ap_dim_t* dim; /* Assumed to be an array of size intdim+realdim */ 62 | size_t intdim ; /* Number of integer dimensions to add/remove */ 63 | size_t realdim; /* Number of real dimensions to add/remove */ 64 | } ap_dimchange_t; 65 | """ 66 | 67 | _fields_ = [ 68 | ('dim', POINTER(Dim)), 69 | ('intdim', c_size_t), 70 | ('realdim', c_size_t) 71 | ] 72 | 73 | 74 | class DimChange2(Structure): 75 | """ 76 | typedef struct ap_dimchange2_t { 77 | ap_dimchange_t* add; /* If not NULL, specifies the adding new dimensions */ 78 | ap_dimchange_t* remove; /* If not NULL, specifies the removal of dimensions */ 79 | } ap_dimchange2_t; 80 | """ 81 | 82 | _fields_ = [ 83 | ('add', POINTER(DimChange)), 84 | ('remove', POINTER(DimChange)) 85 | ] 86 | 87 | 88 | class DimPerm(Structure): 89 | """ 90 | typedef struct ap_dimperm_t { 91 | ap_dim_t* dim; /* Array assumed to be of size size */ 92 | size_t size; 93 | } ap_dimperm_t; 94 | """ 95 | 96 | _fields_ = [ 97 | ('dim', POINTER(Dim)), 98 | ('size', c_size_t) 99 | ] 100 | -------------------------------------------------------------------------------- /apronpy/var.py: -------------------------------------------------------------------------------- 1 | """ 2 | APRON (String) Variables 3 | ======================== 4 | 5 | :Author: Caterina Urban 6 | """ 7 | from _ctypes import Structure 8 | from ctypes import CFUNCTYPE, c_int, c_char_p, c_void_p 9 | 10 | from apronpy.cdll import libapron 11 | 12 | 13 | class VarOperations(Structure): 14 | """ 15 | typedef struct ap_var_operations_t { 16 | int (*compare)(ap_var_t v1, ap_var_t v2); /* Total ordering function */ 17 | int (*hash)(ap_var_t v); /* Hash function */ 18 | ap_var_t (*copy)(ap_var_t var); /* Duplication function */ 19 | void (*free)(ap_var_t var); /* Deallocation function */ 20 | char* (*to_string)(ap_var_t var); /* Conversion to a dynamically allocated string */ 21 | } ap_var_operations_t; 22 | """ 23 | 24 | _fields_ = [ 25 | ('compare', CFUNCTYPE(c_int, c_void_p, c_void_p)), 26 | ('hash', CFUNCTYPE(c_int, c_void_p)), 27 | ('copy', CFUNCTYPE(c_void_p, c_void_p)), 28 | ('free', CFUNCTYPE(None, c_void_p)), 29 | ('to_string', CFUNCTYPE(c_char_p, c_char_p)) 30 | ] 31 | 32 | 33 | class PyVar: 34 | 35 | def __init__(self, name: str): 36 | self.var = name 37 | 38 | def __deepcopy__(self, memodict=None): 39 | if memodict is None: 40 | memodict = {} 41 | result = PyVar(self.var) 42 | memodict[id(self)] = result 43 | return result 44 | 45 | @property 46 | def _as_parameter_(self): 47 | return self.var.encode('utf-8') 48 | 49 | @staticmethod 50 | def from_param(argument): 51 | assert isinstance(argument, PyVar) 52 | return argument.var.encode('utf-8') 53 | 54 | def __repr__(self): 55 | return self.var 56 | 57 | def __lt__(self, other: 'PyVar'): 58 | assert isinstance(other, PyVar) 59 | operations = VarOperations.in_dll(libapron, 'ap_var_operations_default') 60 | return operations.compare(self, other) < 0 61 | 62 | def __le__(self, other: 'PyVar'): 63 | assert isinstance(other, PyVar) 64 | return self.__lt__(other) or self.__eq__(other) 65 | 66 | def __eq__(self, other): 67 | assert isinstance(other, PyVar) 68 | operations = VarOperations.in_dll(libapron, 'ap_var_operations_default') 69 | return operations.compare(self, other) == 0 70 | 71 | def __ne__(self, other): 72 | assert isinstance(other, PyVar) 73 | return not self.__eq__(other) 74 | 75 | def __ge__(self, other): 76 | assert isinstance(other, PyVar) 77 | return self.__gt__(other) or self.__eq__(other) 78 | 79 | def __gt__(self, other): 80 | assert isinstance(other, PyVar) 81 | operations = VarOperations.in_dll(libapron, 'ap_var_operations_default') 82 | return operations.compare(self, other) > 0 83 | -------------------------------------------------------------------------------- /tests/test_tcons1.py: -------------------------------------------------------------------------------- 1 | """ 2 | APRON Tree Constraints (Level 1) - Unit Tests 3 | ============================================= 4 | 5 | :Author: Caterina Urban 6 | """ 7 | import unittest 8 | from copy import deepcopy 9 | 10 | from apronpy.texpr1 import PyTexpr1 11 | 12 | from apronpy.coeff import PyDoubleScalarCoeff, PyMPQScalarCoeff 13 | from apronpy.environment import PyEnvironment 14 | from apronpy.lincons0 import ConsTyp 15 | from apronpy.lincons1 import PyLincons1 16 | from apronpy.linexpr1 import PyLinexpr1 17 | from apronpy.tcons1 import PyTcons1 18 | from apronpy.var import PyVar 19 | 20 | 21 | class TestPyTcons1(unittest.TestCase): 22 | 23 | def test_init(self): 24 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 25 | x = PyLinexpr1(e) 26 | x.set_coeff(PyVar('x0'), PyDoubleScalarCoeff(3)) 27 | x.set_coeff(PyVar('z'), PyDoubleScalarCoeff(-9)) 28 | x.set_cst(PyDoubleScalarCoeff(8)) 29 | c = PyLincons1(ConsTyp.AP_CONS_SUPEQ, x) 30 | self.assertEqual(str(PyTcons1(c)), '8.0 + 3.0 · x0 - 9.0 · z >= 0') 31 | self.assertEqual(str(PyTcons1.unsat(e)), '-1.0 >= 0') 32 | z = PyLincons1(ConsTyp.AP_CONS_DISEQ, PyLinexpr1(e)) 33 | self.assertEqual(str(PyTcons1(z)), '0.0 != 0') 34 | 35 | def test_make(self): 36 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 37 | x = PyLinexpr1(e) 38 | x.set_coeff(PyVar('x0'), PyDoubleScalarCoeff(3)) 39 | x.set_coeff(PyVar('z'), PyDoubleScalarCoeff(-9)) 40 | x.set_cst(PyDoubleScalarCoeff(8)) 41 | c = PyTcons1.make(PyTexpr1(x), ConsTyp.AP_CONS_SUPEQ) 42 | self.assertEqual(str(c), '8.0 + 3.0 · x0 - 9.0 · z >= 0') 43 | 44 | def test_deepcopy(self): 45 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 46 | x = PyLinexpr1(e) 47 | x.set_coeff(PyVar('x0'), PyDoubleScalarCoeff(3)) 48 | x.set_coeff(PyVar('z'), PyDoubleScalarCoeff(-9)) 49 | x.set_cst(PyDoubleScalarCoeff(8)) 50 | c0 = PyTcons1.make(PyTexpr1(x), ConsTyp.AP_CONS_SUPEQ) 51 | c1 = deepcopy(c0) 52 | c2 = c0 53 | self.assertNotEqual(id(c0), id(c1)) 54 | self.assertEqual(id(c0), id(c2)) 55 | 56 | def test_substitute(self): 57 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 58 | x0 = PyLinexpr1(e) 59 | x0.set_coeff(PyVar('x0'), PyMPQScalarCoeff(1)) 60 | x0.set_cst(PyMPQScalarCoeff(3)) 61 | t0 = PyTexpr1(x0) 62 | c0 = PyTcons1.make(t0, ConsTyp.AP_CONS_SUPEQ) 63 | self.assertEqual(str(c0), '3 + 1 · x0 >= 0') 64 | x1 = PyLinexpr1(e) 65 | x1.set_coeff(PyVar('x0'), PyMPQScalarCoeff(1)) 66 | x1.set_cst(PyMPQScalarCoeff(-1)) 67 | t1 = PyTexpr1(x1) 68 | c1 = PyTcons1.make(t1, ConsTyp.AP_CONS_SUPEQ) 69 | self.assertEqual(str(c1), '-1 + 1 · x0 >= 0') 70 | self.assertEqual(str(c0.substitute(PyVar('x0'), t1)), '3 + 1 · (-1 + 1 · x0) >= 0') 71 | 72 | 73 | if __name__ == '__main__': 74 | unittest.main() 75 | -------------------------------------------------------------------------------- /tests/test_environment.py: -------------------------------------------------------------------------------- 1 | """ 2 | APRON Environments - Unit Tests 3 | =============================== 4 | 5 | :Author: Caterina Urban 6 | """ 7 | import unittest 8 | from copy import deepcopy 9 | 10 | from apronpy.environment import PyEnvironment 11 | from apronpy.var import PyVar 12 | 13 | 14 | class TestPyEnvironment(unittest.TestCase): 15 | 16 | def test_init(self): 17 | self.assertEqual(str(PyEnvironment([PyVar('x')], [PyVar('y'), PyVar('z')])), '{x|y,z}') 18 | self.assertEqual(str(PyEnvironment([], [PyVar('y'), PyVar('z')])), '{|y,z}') 19 | self.assertEqual(str(PyEnvironment(real_vars=[PyVar('y'), PyVar('z')])), '{|y,z}') 20 | self.assertEqual(str(PyEnvironment([PyVar('x')], [])), '{x|}') 21 | self.assertEqual(str(PyEnvironment([PyVar('x')])), '{x|}') 22 | self.assertRaises(ValueError, PyEnvironment, [PyVar('x')], [PyVar('x'), PyVar('y')]) 23 | 24 | def test_deepcopy(self): 25 | e0 = PyEnvironment([PyVar('x')], [PyVar('y'), PyVar('z')]) 26 | e1 = deepcopy(e0) 27 | e2 = e0 28 | self.assertEqual(id(e0), id(e1)) 29 | self.assertEqual(id(e0), id(e2)) 30 | 31 | def test_len(self): 32 | self.assertEqual(len(PyEnvironment([PyVar('x')], [PyVar('y'), PyVar('z')])), 3) 33 | self.assertEqual(len(PyEnvironment([], [PyVar('y'), PyVar('z')])), 2) 34 | self.assertEqual(len(PyEnvironment(real_vars=[PyVar('y'), PyVar('z')])), 2) 35 | self.assertEqual(len(PyEnvironment([PyVar('x')], [])), 1) 36 | self.assertEqual(len(PyEnvironment([PyVar('x')])), 1) 37 | self.assertEqual(len(PyEnvironment()), 0) 38 | 39 | def test_add(self): 40 | e1 = PyEnvironment([PyVar('x')], [PyVar('y'), PyVar('z')]) 41 | e2 = PyEnvironment([PyVar('x')], [PyVar('y')]) 42 | self.assertEqual(str(e1), str(e2.add(real_vars=[PyVar('z')]))) 43 | self.assertRaises(ValueError, e1.add, [PyVar('x')]) 44 | 45 | def test_remove(self): 46 | e1 = PyEnvironment([PyVar('x')], [PyVar('y'), PyVar('z')]) 47 | e2 = PyEnvironment([], [PyVar('y'), PyVar('z')]) 48 | self.assertEqual(str(e1.remove([PyVar('x')])), str(e2)) 49 | self.assertRaises(ValueError, e1.remove, [PyVar('w')]) 50 | 51 | def test_contains(self): 52 | self.assertTrue(PyVar('x') in PyEnvironment([PyVar('x')], [PyVar('y')])) 53 | self.assertFalse(PyVar('y') in PyEnvironment([PyVar('x')])) 54 | self.assertFalse(PyVar('x') not in PyEnvironment([PyVar('x')], [PyVar('y')])) 55 | self.assertTrue(PyVar('y') not in PyEnvironment([PyVar('x')])) 56 | 57 | def test_cmp(self): 58 | self.assertTrue(PyEnvironment([PyVar('x')]) < PyEnvironment([PyVar('x')], [PyVar('y')])) 59 | self.assertFalse(PyEnvironment([PyVar('x')]) > PyEnvironment([PyVar('x')])) 60 | self.assertTrue(PyEnvironment([PyVar('x')]) == PyEnvironment([PyVar('x')], [])) 61 | self.assertFalse(PyEnvironment([PyVar('x')]) == PyEnvironment([PyVar('x')], [PyVar('y')])) 62 | self.assertTrue(PyEnvironment([PyVar('x')]) > PyEnvironment()) 63 | self.assertFalse(PyEnvironment([PyVar('x')]) < PyEnvironment()) 64 | self.assertTrue(PyEnvironment().add([PyVar('x')]) == PyEnvironment([PyVar('x')])) 65 | self.assertTrue(PyEnvironment([PyVar('x')]).remove([PyVar('x')]) == PyEnvironment()) 66 | 67 | def test_union(self): 68 | e1 = PyEnvironment([PyVar('x')], [PyVar('y')]) 69 | self.assertEqual(e1, PyEnvironment([PyVar('x')]).union(PyEnvironment([], [PyVar('y')]))) 70 | e2 = PyEnvironment([], [PyVar('y'), PyVar('z')]) 71 | self.assertEqual(e2, PyEnvironment([], [PyVar('y')]) | PyEnvironment([], [PyVar('z')])) 72 | e3 = PyEnvironment([PyVar('x')], []) 73 | self.assertEqual(PyEnvironment() | PyEnvironment([PyVar('x')], []), e3) 74 | self.assertEqual(PyEnvironment([PyVar('x')], []) | PyEnvironment(), e3) 75 | e4 = PyEnvironment([PyVar('x')], []) 76 | self.assertRaises(ValueError, e4.union, PyEnvironment([], [PyVar('x')])) 77 | 78 | def test_rename(self): 79 | e1 = PyEnvironment([PyVar('x')], [PyVar('y')]) 80 | e2 = PyEnvironment([PyVar('x')], [PyVar('z')]) 81 | self.assertEqual(e1.rename([PyVar('y')], [PyVar('z')]), e2) 82 | self.assertRaises(ValueError, e2.rename, [PyVar('x')], [PyVar('z')]) 83 | 84 | 85 | if __name__ == '__main__': 86 | unittest.main() 87 | -------------------------------------------------------------------------------- /tests/test_linexpr1.py: -------------------------------------------------------------------------------- 1 | """ 2 | APRON Linear Expressions (Level 1) - Unit Tests 3 | =============================================== 4 | 5 | :Author: Caterina Urban 6 | """ 7 | import unittest 8 | from copy import deepcopy 9 | 10 | from apronpy.coeff import PyDoubleScalarCoeff, PyDoubleIntervalCoeff 11 | from apronpy.environment import PyEnvironment 12 | from apronpy.linexpr1 import PyLinexpr1 13 | from apronpy.var import PyVar 14 | 15 | 16 | class TestPyLinexpr1(unittest.TestCase): 17 | 18 | def test_init(self): 19 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 20 | self.assertEqual(str(PyLinexpr1(e)), '0.0') 21 | self.assertEqual(str(PyLinexpr1(e, 0)), '0.0·x0 + 0.0·y + 0.0·z + 0.0') 22 | 23 | def test_deepcopy(self): 24 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 25 | x0 = PyLinexpr1(e) 26 | x1 = deepcopy(x0) 27 | x2 = x0 28 | self.assertNotEqual(id(x0), id(x1)) 29 | self.assertEqual(id(x0), id(x2)) 30 | 31 | def test_is_integer(self): 32 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 33 | x0 = PyLinexpr1(e) 34 | x0.set_coeff(PyVar('x0'), PyDoubleScalarCoeff(3)) 35 | self.assertTrue(x0.is_integer()) 36 | x1 = PyLinexpr1(e) 37 | x1.set_coeff(PyVar('x0'), PyDoubleScalarCoeff(3)) 38 | x1.set_coeff(PyVar('z'), PyDoubleScalarCoeff(-9)) 39 | self.assertFalse(x1.is_integer()) 40 | x2 = PyLinexpr1(e) 41 | x2.set_coeff(PyVar('z'), PyDoubleScalarCoeff(-9)) 42 | self.assertFalse(x2.is_integer()) 43 | 44 | def test_is_real(self): 45 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 46 | x0 = PyLinexpr1(e) 47 | x0.set_coeff(PyVar('x0'), PyDoubleScalarCoeff(3)) 48 | self.assertFalse(x0.is_real()) 49 | x1 = PyLinexpr1(e) 50 | x1.set_coeff(PyVar('x0'), PyDoubleScalarCoeff(3)) 51 | x1.set_coeff(PyVar('z'), PyDoubleScalarCoeff(-9)) 52 | self.assertFalse(x1.is_real()) 53 | x2 = PyLinexpr1(e) 54 | x2.set_coeff(PyVar('z'), PyDoubleScalarCoeff(-9)) 55 | self.assertTrue(x2.is_real()) 56 | 57 | def test_is_linear(self): 58 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 59 | x0 = PyLinexpr1(e) 60 | x0.set_coeff(PyVar('x0'), PyDoubleScalarCoeff(3)) 61 | x0.set_cst(PyDoubleScalarCoeff(-9)) 62 | self.assertTrue(x0.is_linear()) 63 | x1 = PyLinexpr1(e) 64 | x1.set_coeff(PyVar('x0'), PyDoubleIntervalCoeff(3, 3)) 65 | x1.set_cst(PyDoubleIntervalCoeff(-9, 9)) 66 | self.assertFalse(x1.is_linear()) 67 | x2 = PyLinexpr1(e) 68 | x2.set_coeff(PyVar('x0'), PyDoubleScalarCoeff(3)) 69 | x2.set_cst(PyDoubleIntervalCoeff(-9, 9)) 70 | self.assertFalse(x2.is_linear()) 71 | 72 | def test_is_quasilinear(self): 73 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 74 | x0 = PyLinexpr1(e) 75 | x0.set_coeff(PyVar('x0'), PyDoubleScalarCoeff(3)) 76 | x0.set_cst(PyDoubleScalarCoeff(-9)) 77 | self.assertTrue(x0.is_quasilinear()) 78 | x1 = PyLinexpr1(e) 79 | x1.set_coeff(PyVar('x0'), PyDoubleIntervalCoeff(3, 3)) 80 | x1.set_cst(PyDoubleIntervalCoeff(-9, 9)) 81 | self.assertFalse(x1.is_quasilinear()) 82 | x2 = PyLinexpr1(e) 83 | x2.set_coeff(PyVar('x0'), PyDoubleScalarCoeff(3)) 84 | x2.set_cst(PyDoubleIntervalCoeff(-9, 9)) 85 | self.assertTrue(x2.is_quasilinear()) 86 | 87 | def test_get_cst(self): 88 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 89 | self.assertEqual(PyLinexpr1(e).get_cst(), PyDoubleScalarCoeff(0.0)) 90 | self.assertNotEqual(PyLinexpr1(e).get_cst(), PyDoubleScalarCoeff(-3)) 91 | 92 | def test_set_cst(self): 93 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 94 | x = PyLinexpr1(e) 95 | x.set_cst(PyDoubleScalarCoeff(9)) 96 | self.assertEqual(str(x), '9.0') 97 | 98 | def test_get_coeff(self): 99 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 100 | self.assertEqual(PyLinexpr1(e).get_coeff(PyVar('x0')), PyDoubleScalarCoeff(0.0)) 101 | self.assertNotEqual(PyLinexpr1(e).get_coeff(PyVar('x0')), PyDoubleScalarCoeff(-3)) 102 | 103 | def test_set_coeff(self): 104 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 105 | x = PyLinexpr1(e) 106 | x.set_coeff(PyVar('z'), PyDoubleScalarCoeff(-9)) 107 | self.assertEqual(str(x), '-9.0·z + 0.0') 108 | 109 | 110 | if __name__ == '__main__': 111 | unittest.main() 112 | -------------------------------------------------------------------------------- /apronpy/mpz.py: -------------------------------------------------------------------------------- 1 | """ 2 | GMP Multi-Precision Integers 3 | ============================ 4 | 5 | :Author: Caterina Urban 6 | """ 7 | from _ctypes import Structure, POINTER, byref 8 | from ctypes import c_int, c_ulonglong, c_double, c_char_p, c_size_t, create_string_buffer, c_char 9 | from typing import Union 10 | 11 | from apronpy.cdll import libgmp 12 | 13 | # initialization and assignment functions 14 | MPZ_clear = libgmp.__gmpz_clear 15 | MPZ_init_set = libgmp.__gmpz_init_set 16 | MPZ_init_set_d = libgmp.__gmpz_init_set_d 17 | # conversion functions 18 | MPZ_get_str = libgmp.__gmpz_get_str 19 | # comparison functions 20 | MPZ_cmp = libgmp.__gmpz_cmp # -1: op1 < op2, 0: op1 == op2, 1: op1 > op2 21 | # arithmetic functions 22 | MPZ_add = libgmp.__gmpz_add 23 | MPZ_sub = libgmp.__gmpz_sub 24 | MPZ_mul = libgmp.__gmpz_mul 25 | MPZ_neg = libgmp.__gmpz_neg 26 | MPZ_abs = libgmp.__gmpz_abs 27 | MPZ_sizeinbase = libgmp.__gmpz_sizeinbase 28 | 29 | 30 | class MPZ(Structure): 31 | """ 32 | typedef struct 33 | { 34 | int _mp_alloc; 35 | int _mp_size; 36 | mp_limb_t *_mp_d; 37 | } __mpz_struct; 38 | """ 39 | _fields_ = [ 40 | ('_mp_alloc', c_int), 41 | ('_mp_size', c_int), 42 | ('_mp_d', POINTER(c_ulonglong)) 43 | ] 44 | 45 | def __repr__(self): 46 | buffer = create_string_buffer(MPZ_sizeinbase(self, 10) + 2) 47 | return MPZ_get_str(buffer, 10, self).decode('utf-8') 48 | 49 | 50 | class PyMPZ: 51 | 52 | def __init__(self, value: Union[MPZ, int, float] = 0): 53 | self.mpz = MPZ() 54 | if isinstance(value, MPZ): 55 | MPZ_init_set(self, value) 56 | else: 57 | assert isinstance(value, (int, float)) 58 | MPZ_init_set_d(self, c_double(value)) 59 | 60 | def __deepcopy__(self, memodict=None): 61 | if memodict is None: 62 | memodict = {} 63 | result = PyMPZ(self.mpz) 64 | memodict[id(self)] = result 65 | return result 66 | 67 | def __del__(self): 68 | MPZ_clear(self) 69 | del self.mpz 70 | 71 | @property 72 | def _as_parameter_(self): 73 | return byref(self.mpz) 74 | 75 | @staticmethod 76 | def from_param(argument): 77 | assert isinstance(argument, PyMPZ) 78 | return argument 79 | 80 | def __repr__(self): 81 | buffer = create_string_buffer(MPZ_sizeinbase(self, 10) + 2) 82 | return MPZ_get_str(buffer, 10, self.mpz).decode('utf-8') 83 | 84 | def __lt__(self, other: 'PyMPZ'): 85 | assert isinstance(other, PyMPZ) 86 | return MPZ_cmp(self, other) < 0 87 | 88 | def __le__(self, other: 'PyMPZ'): 89 | assert isinstance(other, PyMPZ) 90 | return self.__lt__(other) or self.__eq__(other) 91 | 92 | def __eq__(self, other: 'PyMPZ'): 93 | assert isinstance(other, PyMPZ) 94 | return MPZ_cmp(self, other) == 0 95 | 96 | def __ne__(self, other: 'PyMPZ'): 97 | assert isinstance(other, PyMPZ) 98 | return not self.__eq__(other) 99 | 100 | def __ge__(self, other: 'PyMPZ'): 101 | assert isinstance(other, PyMPZ) 102 | return self.__gt__(other) or self.__eq__(other) 103 | 104 | def __gt__(self, other: 'PyMPZ'): 105 | assert isinstance(other, PyMPZ) 106 | return MPZ_cmp(self, other) > 0 107 | 108 | def __add__(self, other: 'PyMPZ') -> 'PyMPZ': 109 | assert isinstance(other, PyMPZ) 110 | mpz = type(self)(0) 111 | MPZ_add(mpz, self, other) 112 | return mpz 113 | 114 | def __sub__(self, other: 'PyMPZ') -> 'PyMPZ': 115 | assert isinstance(other, PyMPZ) 116 | mpz = type(self)(0) 117 | MPZ_sub(mpz, self, other) 118 | return mpz 119 | 120 | def __mul__(self, other: 'PyMPZ') -> 'PyMPZ': 121 | assert isinstance(other, PyMPZ) 122 | mpz = type(self)(0) 123 | MPZ_mul(mpz, self, other) 124 | return mpz 125 | 126 | def __neg__(self) -> 'PyMPZ': 127 | mpz = type(self)(0) 128 | MPZ_neg(mpz, self) 129 | return mpz 130 | 131 | def __abs__(self) -> 'PyMPZ': 132 | mpz = type(self)(0) 133 | MPZ_abs(mpz, self) 134 | return mpz 135 | 136 | 137 | # initialization and assignment functions 138 | MPZ_clear.argtypes = [PyMPZ] 139 | MPZ_init_set.argtypes = [PyMPZ, POINTER(MPZ)] 140 | MPZ_init_set_d.argtypes = [PyMPZ, c_double] 141 | # conversion functions 142 | MPZ_get_str.argtypes = [POINTER(c_char), c_int, POINTER(MPZ)] 143 | MPZ_get_str.restype = c_char_p 144 | # comparison functions 145 | MPZ_cmp.argtypes = [PyMPZ, PyMPZ] 146 | # arithmetic functions 147 | MPZ_add.argtypes = [PyMPZ, PyMPZ, PyMPZ] 148 | MPZ_sub.argtypes = [PyMPZ, PyMPZ, PyMPZ] 149 | MPZ_mul.argtypes = [PyMPZ, PyMPZ, PyMPZ] 150 | MPZ_neg.argtypes = [PyMPZ, PyMPZ] 151 | MPZ_abs.argtypes = [PyMPZ, PyMPZ] 152 | MPZ_sizeinbase.argtypes = [POINTER(MPZ), c_int] 153 | MPZ_sizeinbase.restype = c_size_t 154 | -------------------------------------------------------------------------------- /apronpy/texpr0.py: -------------------------------------------------------------------------------- 1 | """ 2 | APRON Tree Expressions (Level 0) 3 | ================================ 4 | 5 | :Author: Caterina Urban 6 | """ 7 | from _ctypes import Structure, Union, POINTER 8 | from ctypes import c_uint 9 | from enum import IntEnum 10 | 11 | from apronpy.cdll import libapron 12 | from apronpy.coeff import Coeff 13 | from apronpy.dimension import Dim 14 | from apronpy.linexpr0 import Linexpr0 15 | from apronpy.mpfr import Rnd 16 | 17 | 18 | class TexprOp(IntEnum): 19 | """ 20 | typedef enum ap_texpr_op_t { 21 | /* Binary operators */ 22 | AP_TEXPR_ADD, AP_TEXPR_SUB, AP_TEXPR_MUL, AP_TEXPR_DIV, 23 | AP_TEXPR_MOD, /* either integer or real, no rounding */ 24 | AP_TEXPR_POW, 25 | /* Unary operators */ 26 | AP_TEXPR_NEG /* no rounding */, 27 | AP_TEXPR_CAST, AP_TEXPR_SQRT, 28 | } ap_texpr_op_t; 29 | """ 30 | AP_TEXPR_ADD = 0 31 | AP_TEXPR_SUB = 1 32 | AP_TEXPR_MUL = 2 33 | AP_TEXPR_DIV = 3 34 | AP_TEXPR_MOD = 4 35 | AP_TEXPR_POW = 5 36 | AP_TEXPR_NEG = 6 37 | AP_TEXPR_CAST = 7 38 | AP_TEXPR_SQRT = 8 39 | 40 | def __repr__(self): 41 | if self.value == 0: 42 | return '+' 43 | elif self.value == 1: 44 | return '-' 45 | elif self.value == 2: 46 | return '·' 47 | elif self.value == 3: 48 | return '/' 49 | elif self.value == 4: 50 | return '%' 51 | elif self.value == 5: 52 | return '^' 53 | elif self.value == 6: 54 | return '-' 55 | elif self.value == 7: 56 | return 'cast' 57 | elif self.value == 8: 58 | return 'sqrt' 59 | return ValueError('no matching constraint type') 60 | 61 | 62 | class TexprRtype(IntEnum): 63 | """ 64 | typedef enum ap_texpr_rtype_t { 65 | AP_RTYPE_REAL, // real (no rounding) 66 | AP_RTYPE_INT, // integer 67 | AP_RTYPE_SINGLE, // IEEE 754 32-bit single precision, e.g.: C's float 68 | AP_RTYPE_DOUBLE, // IEEE 754 64-bit double precision, e.g.: C's double 69 | AP_RTYPE_EXTENDED, // non-standard 80-bit double extended, e.g.: Intel's long double 70 | AP_RTYPE_QUAD, // non-standard 128-bit quadruple precision, e.g.: Motorola's long double 71 | AP_RTYPE_SIZE // Not to be used ! 72 | } ap_texpr_rtype_t; 73 | """ 74 | AP_RTYPE_REAL = 0 75 | AP_RTYPE_INT = 1 76 | AP_RTYPE_SINGLE = 2 77 | AP_RTYPE_DOUBLE = 3 78 | AP_RTYPE_EXTENDED = 4 79 | AP_RTYPE_QUAD = 5 80 | AP_RTYPE_SIZE = 6 81 | 82 | 83 | class TexprRdir(IntEnum): 84 | """ 85 | typedef enum ap_texpr_rdir_t { 86 | AP_RDIR_NEAREST = GMP_RNDN, /* Nearest */ 87 | AP_RDIR_ZERO = GMP_RNDZ, /* Zero (truncation for integers) */ 88 | AP_RDIR_UP = GMP_RNDU, /* + Infinity */ 89 | AP_RDIR_DOWN = GMP_RNDD, /* - Infinity */ 90 | AP_RDIR_RND, /* All possible mode, non deterministically */ 91 | AP_RDIR_SIZE /* Not to be used ! */ 92 | } ap_texpr_rdir_t; 93 | """ 94 | AP_RDIR_NEAREST = Rnd.MPFR_RNDN 95 | AP_RDIR_ZERO = Rnd.MPFR_RNDZ 96 | AP_RDIR_UP = Rnd.MPFR_RNDU 97 | AP_RDIR_DOWN = Rnd.MPFR_RNDD 98 | AP_RDIR_RND = 4 99 | AP_RDIR_SIZE = 5 100 | 101 | 102 | class Texpr0Node(Structure): 103 | """ 104 | typedef struct ap_texpr0_node_t { 105 | ap_texpr_op_t op; 106 | ap_texpr_rtype_t type; 107 | ap_texpr_rdir_t dir; 108 | struct ap_texpr0_t* exprA; /* First operand */ 109 | struct ap_texpr0_t* exprB; /* Second operand (for binary operations) or NULL */ 110 | } ap_texpr0_node_t; 111 | """ 112 | pass 113 | 114 | 115 | class TexprDiscr(IntEnum): 116 | """ 117 | typedef enum ap_texpr_discr_t { 118 | AP_TEXPR_CST, AP_TEXPR_DIM, AP_TEXPR_NODE 119 | } ap_texpr_discr_t; 120 | """ 121 | AP_TEXPR_CST = 0 122 | AP_TEXPR_DIM = 1 123 | AP_TEXPR_NODE = 2 124 | 125 | 126 | class Texpr0(Structure): 127 | """ 128 | typedef struct ap_texpr0_t { 129 | ap_texpr_discr_t discr; 130 | union { 131 | ap_coeff_t cst; 132 | ap_dim_t dim; 133 | ap_texpr0_node_t* node; 134 | } val; 135 | } ap_texpr0_t; 136 | """ 137 | 138 | class Val(Union): 139 | """ 140 | union { 141 | ap_coeff_t cst; 142 | ap_dim_t dim; 143 | ap_texpr0_node_t* node; 144 | } val; 145 | """ 146 | 147 | _fields_ = [ 148 | ('cst', Coeff), 149 | ('dim', Dim), 150 | ('node', POINTER(Texpr0Node)) 151 | ] 152 | 153 | _fields_ = [ 154 | ('discr', c_uint), 155 | ('val', Val) 156 | ] 157 | 158 | 159 | Texpr0Node._fields_ = [ 160 | ('op', c_uint), 161 | ('type', c_uint), 162 | ('dir', c_uint), 163 | ('exprA', POINTER(Texpr0)), 164 | ('exprB', POINTER(Texpr0)) 165 | ] 166 | 167 | 168 | libapron.ap_texpr0_copy.argtypes = [POINTER(Texpr0)] 169 | libapron.ap_texpr0_copy.restype = POINTER(Texpr0) 170 | libapron.ap_texpr0_free.argtypes = [POINTER(Texpr0)] 171 | libapron.ap_texpr0_from_linexpr0.argtypes = [POINTER(Linexpr0)] 172 | libapron.ap_texpr0_from_linexpr0.restype = POINTER(Texpr0) 173 | libapron.ap_texpr0_substitute.argtypes = [POINTER(Texpr0), Dim, POINTER(Texpr0)] 174 | libapron.ap_texpr0_substitute.restype = POINTER(Texpr0) 175 | libapron.ap_texpr0_substitute_with.argtypes = [POINTER(Texpr0), Dim, POINTER(Texpr0)] 176 | -------------------------------------------------------------------------------- /apronpy/mpq.py: -------------------------------------------------------------------------------- 1 | """ 2 | GMP Multi-Precision Rationals 3 | ============================= 4 | 5 | :Author: Caterina Urban 6 | """ 7 | from _ctypes import Structure, byref, POINTER 8 | from ctypes import c_int, c_char_p, c_double, c_longlong, c_ulonglong, c_char, create_string_buffer 9 | from typing import Union 10 | 11 | from apronpy.cdll import libgmp 12 | from apronpy.mpz import MPZ, MPZ_sizeinbase 13 | 14 | MPQ_canonicalize = libgmp.__gmpq_canonicalize 15 | # initialization functions 16 | MPQ_init = libgmp.__gmpq_init 17 | MPQ_clear = libgmp.__gmpq_clear 18 | # assignment functions 19 | MPQ_set = libgmp.__gmpq_set 20 | MPQ_set_si = libgmp.__gmpq_set_si 21 | MPQ_set_d = libgmp.__gmpq_set_d 22 | # conversion functions 23 | MPQ_get_str = libgmp.__gmpq_get_str 24 | # comparison functions 25 | MPQ_cmp = libgmp.__gmpq_cmp # -1: op1 < op2, 0: op1 == op2, 1: op1 > op2 26 | # arithmetic functions 27 | MPQ_add = libgmp.__gmpq_add 28 | MPQ_sub = libgmp.__gmpq_sub 29 | MPQ_mul = libgmp.__gmpq_mul 30 | MPQ_neg = libgmp.__gmpq_neg 31 | MPQ_abs = libgmp.__gmpq_abs 32 | 33 | 34 | class MPQ(Structure): 35 | """ 36 | typedef struct 37 | { 38 | __mpz_struct _mp_num; 39 | __mpz_struct _mp_den; 40 | } __mpq_struct; 41 | """ 42 | _fields_ = [ 43 | ('_mp_num', MPZ), 44 | ('_mp_den', MPZ) 45 | ] 46 | 47 | def __repr__(self): 48 | n = MPZ_sizeinbase(self._mp_num, 10) 49 | d = MPZ_sizeinbase(self._mp_den, 10) 50 | buffer = create_string_buffer(n + d + 3) 51 | return MPQ_get_str(buffer, 10, self).decode('utf-8') 52 | 53 | 54 | class PyMPQ: 55 | 56 | def __init__(self, value_or_numerator: Union[MPQ, float, int] = 0, denominator: int = 1): 57 | self.mpq = MPQ() 58 | MPQ_init(self) 59 | if isinstance(value_or_numerator, MPQ): 60 | MPQ_set(self, value_or_numerator) 61 | elif isinstance(value_or_numerator, float): 62 | MPQ_set_d(self, value_or_numerator) 63 | else: 64 | assert isinstance(value_or_numerator, int) and isinstance(denominator, int) 65 | MPQ_set_si(self, c_longlong(value_or_numerator), c_ulonglong(denominator)) 66 | MPQ_canonicalize(self) 67 | 68 | def __deepcopy__(self, memodict=None): 69 | if memodict is None: 70 | memodict = {} 71 | result = PyMPQ(self.mpq) 72 | memodict[id(self)] = result 73 | return result 74 | 75 | def __del__(self): 76 | MPQ_clear(self) 77 | del self.mpq 78 | 79 | @property 80 | def _as_parameter_(self): 81 | return byref(self.mpq) 82 | 83 | @staticmethod 84 | def from_param(argument): 85 | assert isinstance(argument, PyMPQ) 86 | return argument 87 | 88 | # noinspection PyProtectedMember 89 | def __repr__(self): 90 | n = MPZ_sizeinbase(self.mpq._mp_num, 10) 91 | d = MPZ_sizeinbase(self.mpq._mp_den, 10) 92 | buffer = create_string_buffer(n + d + 3) 93 | return MPQ_get_str(buffer, 10, self).decode('utf-8') 94 | 95 | def __lt__(self, other: 'PyMPQ'): 96 | assert isinstance(other, PyMPQ) 97 | return MPQ_cmp(self, other) < 0 98 | 99 | def __le__(self, other: 'PyMPQ'): 100 | assert isinstance(other, PyMPQ) 101 | return self.__lt__(other) or self.__eq__(other) 102 | 103 | def __eq__(self, other: 'PyMPQ'): 104 | assert isinstance(other, PyMPQ) 105 | return MPQ_cmp(self, other) == 0 106 | 107 | def __ne__(self, other: 'PyMPQ'): 108 | assert isinstance(other, PyMPQ) 109 | return not self.__eq__(other) 110 | 111 | def __ge__(self, other: 'PyMPQ'): 112 | assert isinstance(other, PyMPQ) 113 | return self.__gt__(other) or self.__eq__(other) 114 | 115 | def __gt__(self, other: 'PyMPQ'): 116 | assert isinstance(other, PyMPQ) 117 | return MPQ_cmp(self, other) > 0 118 | 119 | def __add__(self, other: 'PyMPQ') -> 'PyMPQ': 120 | assert isinstance(other, PyMPQ) 121 | mpq = type(self)(0, 1) 122 | MPQ_add(mpq, self, other) 123 | return mpq 124 | 125 | def __sub__(self, other: 'PyMPQ') -> 'PyMPQ': 126 | assert isinstance(other, PyMPQ) 127 | mpq = type(self)(0, 1) 128 | MPQ_sub(mpq, self, other) 129 | return mpq 130 | 131 | def __mul__(self, other: 'PyMPQ') -> 'PyMPQ': 132 | assert isinstance(other, PyMPQ) 133 | mpq = type(self)(0, 1) 134 | MPQ_mul(mpq, self, other) 135 | return mpq 136 | 137 | def __neg__(self) -> 'PyMPQ': 138 | mpq = type(self)(0, 1) 139 | MPQ_neg(mpq, self) 140 | return mpq 141 | 142 | def __abs__(self) -> 'PyMPQ': 143 | mpq = type(self)(0, 1) 144 | MPQ_abs(mpq, self) 145 | return mpq 146 | 147 | 148 | MPQ_canonicalize.argtypes = [PyMPQ] 149 | # initialization functions 150 | MPQ_init.argtypes = [PyMPQ] 151 | MPQ_clear.argtypes = [PyMPQ] 152 | # assignment functions 153 | MPQ_set.argtypes = [PyMPQ, POINTER(MPQ)] 154 | MPQ_set_si.argtypes = [PyMPQ, c_longlong, c_ulonglong] 155 | MPQ_set_d.argtypes = [PyMPQ, c_double] 156 | # conversion functions 157 | MPQ_get_str.argtypes = [POINTER(c_char), c_int, POINTER(MPQ)] 158 | MPQ_get_str.restype = c_char_p 159 | # comparison functions 160 | MPQ_cmp.argtypes = [PyMPQ, PyMPQ] 161 | # arithmetic functions 162 | MPQ_add.argtypes = [PyMPQ, PyMPQ, PyMPQ] 163 | MPQ_sub.argtypes = [PyMPQ, PyMPQ, PyMPQ] 164 | MPQ_mul.argtypes = [PyMPQ, PyMPQ, PyMPQ] 165 | MPQ_neg.argtypes = [PyMPQ, PyMPQ] 166 | MPQ_abs.argtypes = [PyMPQ, PyMPQ] 167 | -------------------------------------------------------------------------------- /apronpy/mpfr.py: -------------------------------------------------------------------------------- 1 | """ 2 | MPFR Multiprecision Floating-Point Numbers 3 | ========================================== 4 | 5 | :Author: Caterina Urban 6 | """ 7 | from _ctypes import Structure, POINTER, byref 8 | from ctypes import c_long, c_int, c_ulonglong, c_double 9 | from enum import IntEnum 10 | from typing import Union 11 | 12 | from apronpy.cdll import libmpfr 13 | 14 | 15 | # initialization and assignment functions 16 | MPFR_init = libmpfr.mpfr_init 17 | MPFR_clear = libmpfr.mpfr_clear 18 | MPFR_set = libmpfr.mpfr_set 19 | MPFR_set_d = libmpfr.mpfr_set_d 20 | # conversion functions 21 | MPFR_get_d = libmpfr.mpfr_get_d 22 | # comparison functions 23 | MPFR_cmp = libmpfr.mpfr_cmp # -1: op1 < op2, 0: op1 == op2, 1: op1 > op2 24 | # arithmetic functions 25 | MPFR_add = libmpfr.mpfr_add 26 | MPFR_sub = libmpfr.mpfr_sub 27 | MPFR_mul = libmpfr.mpfr_mul 28 | MPFR_neg = libmpfr.mpfr_neg 29 | MPFR_abs = libmpfr.mpfr_abs 30 | 31 | 32 | class MPFR(Structure): 33 | """ 34 | typedef struct { 35 | mpfr_prec_t _mpfr_prec; 36 | mpfr_sign_t _mpfr_sign; 37 | mpfr_exp_t _mpfr_exp; 38 | mp_limb_t *_mpfr_d; 39 | } __mpfr_struct; 40 | """ 41 | _fields_ = [ 42 | ('_mpfr_prec', c_long), 43 | ('_mpfr_sign', c_int), 44 | ('_mpfr_exp', c_long), 45 | ('_mpfr_d', POINTER(c_ulonglong)) 46 | ] 47 | 48 | def __repr__(self): 49 | return '{}'.format(MPFR_get_d(self, 0)) 50 | 51 | 52 | class Rnd(IntEnum): 53 | """ 54 | typedef enum { 55 | MPFR_RNDN=0, /* round to nearest, with ties to even */ 56 | MPFR_RNDZ, /* round toward zero */ 57 | MPFR_RNDU, /* round toward +Inf */ 58 | MPFR_RNDD, /* round toward -Inf */ 59 | MPFR_RNDA, /* round away from zero */ 60 | MPFR_RNDF, /* faithful rounding */ 61 | MPFR_RNDNA=-1 /* round to nearest, with ties away from zero (mpfr_round) */ 62 | } mpfr_rnd_t; 63 | """ 64 | MPFR_RNDN = 0 65 | MPFR_RNDZ = 1 66 | MPFR_RNDU = 2 67 | MPFR_RNDD = 3 68 | MPFR_RNDA = 4 69 | MPFR_RNDF = 5 70 | MPFR_RNDNA = -1 71 | 72 | 73 | class PyMPFR: 74 | 75 | def __init__(self, value: Union[MPFR, int, float], rounding: Rnd = Rnd.MPFR_RNDN): 76 | self.mpfr = MPFR() 77 | MPFR_init(self) 78 | if isinstance(value, MPFR): 79 | MPFR_set(self, value, rounding) 80 | else: 81 | assert isinstance(value, (int, float)) 82 | MPFR_set_d(self, value, rounding) 83 | self.rounding = rounding 84 | 85 | def __deepcopy__(self, memodict=None): 86 | if memodict is None: 87 | memodict = {} 88 | result = PyMPFR(self.mpfr, self.rounding) 89 | memodict[id(self)] = result 90 | return result 91 | 92 | def __del__(self): 93 | MPFR_clear(self) 94 | del self.mpfr 95 | del self.rounding 96 | 97 | @property 98 | def _as_parameter_(self): 99 | return byref(self.mpfr) 100 | 101 | @staticmethod 102 | def from_param(argument): 103 | assert isinstance(argument, PyMPFR) 104 | return argument 105 | 106 | def __repr__(self): 107 | return '{}'.format(MPFR_get_d(self.mpfr, 0)) 108 | 109 | def __lt__(self, other: 'PyMPFR'): 110 | assert isinstance(other, PyMPFR) 111 | return MPFR_cmp(self, other) < 0 112 | 113 | def __le__(self, other: 'PyMPFR'): 114 | assert isinstance(other, PyMPFR) 115 | return self.__lt__(other) or self.__eq__(other) 116 | 117 | def __eq__(self, other: 'PyMPFR'): 118 | assert isinstance(other, PyMPFR) 119 | return MPFR_cmp(self, other) == 0 120 | 121 | def __ne__(self, other: 'PyMPFR'): 122 | assert isinstance(other, PyMPFR) 123 | return not self.__eq__(other) 124 | 125 | def __ge__(self, other: 'PyMPFR'): 126 | assert isinstance(other, PyMPFR) 127 | return self.__gt__(other) or self.__eq__(other) 128 | 129 | def __gt__(self, other: 'PyMPFR'): 130 | assert isinstance(other, PyMPFR) 131 | return MPFR_cmp(self, other) > 0 132 | 133 | def __add__(self, other: 'PyMPFR') -> 'PyMPFR': 134 | assert isinstance(other, PyMPFR) 135 | mpfr = type(self)(0) 136 | MPFR_add(mpfr, self, other) 137 | return mpfr 138 | 139 | def __sub__(self, other: 'PyMPFR') -> 'PyMPFR': 140 | assert isinstance(other, PyMPFR) 141 | mpfr = type(self)(0) 142 | MPFR_sub(mpfr, self, other) 143 | return mpfr 144 | 145 | def __mul__(self, other: 'PyMPFR') -> 'PyMPFR': 146 | assert isinstance(other, PyMPFR) 147 | mpfr = type(self)(0) 148 | MPFR_mul(mpfr, self, other) 149 | return mpfr 150 | 151 | def __neg__(self) -> 'PyMPFR': 152 | mpfr = type(self)(0) 153 | MPFR_neg(mpfr, self) 154 | return mpfr 155 | 156 | def __abs__(self) -> 'PyMPFR': 157 | mpfr = type(self)(0) 158 | MPFR_abs(mpfr, self) 159 | return mpfr 160 | 161 | 162 | # initialization and assignment functions 163 | MPFR_init.argtypes = [PyMPFR] 164 | MPFR_clear.argtypes = [PyMPFR] 165 | MPFR_set.argtypes = [PyMPFR, POINTER(MPFR), c_int] 166 | MPFR_set_d.argtypes = [PyMPFR, c_double, c_int] 167 | # conversion functions 168 | MPFR_get_d.argtypes = [POINTER(MPFR), c_int] 169 | MPFR_get_d.restype = c_double 170 | # comparison functions 171 | MPFR_cmp.argtypes = [PyMPFR, PyMPFR] 172 | # arithmetic functions 173 | MPFR_add.argtypes = [PyMPFR, PyMPFR, PyMPFR] 174 | MPFR_sub.argtypes = [PyMPFR, PyMPFR, PyMPFR] 175 | MPFR_mul.argtypes = [PyMPFR, PyMPFR, PyMPFR] 176 | MPFR_neg.argtypes = [PyMPFR, PyMPFR] 177 | MPFR_abs.argtypes = [PyMPFR, PyMPFR] 178 | -------------------------------------------------------------------------------- /tests/test_lincons1.py: -------------------------------------------------------------------------------- 1 | """ 2 | APRON Linear Constraints (Level 1) - Unit Tests 3 | =============================================== 4 | 5 | :Author: Caterina Urban 6 | """ 7 | import unittest 8 | 9 | from apronpy.scalar import PyMPQScalar 10 | 11 | from apronpy.coeff import PyDoubleScalarCoeff, PyMPQScalarCoeff 12 | from apronpy.environment import PyEnvironment 13 | from apronpy.lincons0 import ConsTyp 14 | from apronpy.lincons1 import PyLincons1, PyLincons1Array 15 | from apronpy.linexpr1 import PyLinexpr1 16 | from apronpy.var import PyVar 17 | 18 | 19 | class TestPyLincons1(unittest.TestCase): 20 | 21 | def test_init(self): 22 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 23 | x1 = PyLinexpr1(e) 24 | x1.set_coeff(PyVar('x0'), PyDoubleScalarCoeff(3)) 25 | x1.set_coeff(PyVar('z'), PyDoubleScalarCoeff(-9)) 26 | x1.set_cst(PyDoubleScalarCoeff(8)) 27 | c1 = PyLincons1(ConsTyp.AP_CONS_SUPEQ, x1) 28 | self.assertEqual(str(c1), '3.0·x0 - 9.0·z + 8.0 >= 0') 29 | self.assertEqual(str(PyLincons1.unsat(e)), '-1.0 >= 0') 30 | self.assertEqual(str(PyLincons1(ConsTyp.AP_CONS_DISEQ, PyLinexpr1(e))), '0.0 != 0') 31 | x2 = PyLinexpr1(e) 32 | x2.set_coeff(PyVar('y'), PyMPQScalarCoeff(1)) 33 | k = PyMPQScalar(2) 34 | c2 = PyLincons1(ConsTyp.AP_CONS_EQMOD, x2, k) 35 | self.assertEqual(str(c2), '1·y + 0.0 %= 2') 36 | 37 | def test_is_unsat(self): 38 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 39 | x = PyLinexpr1(e) 40 | x.set_coeff(PyVar('x0'), PyDoubleScalarCoeff(3)) 41 | x.set_coeff(PyVar('z'), PyDoubleScalarCoeff(-9)) 42 | x.set_cst(PyDoubleScalarCoeff(8)) 43 | c = PyLincons1(ConsTyp.AP_CONS_SUPEQ, x) 44 | self.assertFalse(c.is_unsat()) 45 | self.assertTrue(PyLincons1.unsat(e).is_unsat()) 46 | self.assertTrue(PyLincons1(ConsTyp.AP_CONS_DISEQ, PyLinexpr1(e)).is_unsat()) 47 | 48 | def test_get_typ(self): 49 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 50 | x = PyLinexpr1(e) 51 | c = PyLincons1(ConsTyp.AP_CONS_SUPEQ, x) 52 | self.assertEqual(repr(c.get_typ()), '>=') 53 | self.assertNotEqual(repr(c.get_typ()), '<') 54 | 55 | def test_set_typ(self): 56 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 57 | x = PyLinexpr1(e) 58 | c = PyLincons1(ConsTyp.AP_CONS_SUPEQ, x) 59 | c.set_typ(ConsTyp.AP_CONS_DISEQ) 60 | self.assertEqual(str(c), '0.0 != 0') 61 | 62 | def test_get_cst(self): 63 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 64 | x = PyLinexpr1(e) 65 | c = PyLincons1(ConsTyp.AP_CONS_SUPEQ, x) 66 | self.assertEqual(c.get_cst(), PyDoubleScalarCoeff(0.0)) 67 | self.assertNotEqual(c.get_cst(), PyDoubleScalarCoeff(-3)) 68 | 69 | def test_set_cst(self): 70 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 71 | x = PyLinexpr1(e) 72 | c = PyLincons1(ConsTyp.AP_CONS_SUPEQ, x) 73 | c.set_cst(PyDoubleScalarCoeff(9)) 74 | self.assertEqual(str(c), '9.0 >= 0') 75 | 76 | def test_get_coeff(self): 77 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 78 | x = PyLinexpr1(e) 79 | c = PyLincons1(ConsTyp.AP_CONS_SUPEQ, x) 80 | self.assertEqual(c.get_coeff(PyVar('x0')), PyDoubleScalarCoeff(0.0)) 81 | self.assertNotEqual(c.get_coeff(PyVar('x0')), PyDoubleScalarCoeff(-3)) 82 | 83 | def test_set_coeff(self): 84 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 85 | x = PyLinexpr1(e) 86 | c = PyLincons1(ConsTyp.AP_CONS_SUPEQ, x) 87 | c.set_coeff(PyVar('z'), PyDoubleScalarCoeff(-9)) 88 | self.assertEqual(str(c), '-9.0·z + 0.0 >= 0') 89 | 90 | 91 | class TestPyLincons1Array(unittest.TestCase): 92 | 93 | def test_init(self): 94 | e = PyEnvironment([PyVar('x'), PyVar('y')], [PyVar('z')]) 95 | x1 = PyLinexpr1(e) 96 | x1.set_coeff(PyVar('x'), PyDoubleScalarCoeff(3)) 97 | x1.set_coeff(PyVar('z'), PyDoubleScalarCoeff(-9)) 98 | x1.set_cst(PyDoubleScalarCoeff(8)) 99 | c1 = PyLincons1(ConsTyp.AP_CONS_SUPEQ, x1) 100 | x2 = PyLinexpr1(e) 101 | x2.set_coeff(PyVar('x'), PyDoubleScalarCoeff(1)) 102 | c2 = PyLincons1(ConsTyp.AP_CONS_SUP, x2) 103 | a = PyLincons1Array([c1, c2]) 104 | self.assertEqual(str(a), '3.0·x - 9.0·z + 8.0 >= 0 ∧ 1.0·x + 0.0 > 0') 105 | 106 | def test_get(self): 107 | e = PyEnvironment([PyVar('x'), PyVar('y')], [PyVar('z')]) 108 | x1 = PyLinexpr1(e) 109 | x1.set_coeff(PyVar('x'), PyDoubleScalarCoeff(3)) 110 | x1.set_coeff(PyVar('z'), PyDoubleScalarCoeff(-9)) 111 | x1.set_cst(PyDoubleScalarCoeff(8)) 112 | c1 = PyLincons1(ConsTyp.AP_CONS_SUPEQ, x1) 113 | x2 = PyLinexpr1(e) 114 | x2.set_coeff(PyVar('x'), PyDoubleScalarCoeff(1)) 115 | c2 = PyLincons1(ConsTyp.AP_CONS_SUP, x2) 116 | a = PyLincons1Array([c1, c2]) 117 | c = a.get(1) 118 | self.assertNotEqual(str(c), str(c1)) 119 | self.assertEqual(str(c), str(c2)) 120 | 121 | def test_set(self): 122 | e = PyEnvironment([PyVar('x'), PyVar('y')], [PyVar('z')]) 123 | x1 = PyLinexpr1(e) 124 | x1.set_coeff(PyVar('x'), PyDoubleScalarCoeff(3)) 125 | x1.set_coeff(PyVar('z'), PyDoubleScalarCoeff(-9)) 126 | x1.set_cst(PyDoubleScalarCoeff(8)) 127 | c1 = PyLincons1(ConsTyp.AP_CONS_SUPEQ, x1) 128 | x2 = PyLinexpr1(e) 129 | x2.set_coeff(PyVar('x'), PyDoubleScalarCoeff(1)) 130 | c2 = PyLincons1(ConsTyp.AP_CONS_SUP, x2) 131 | a = PyLincons1Array([c1, c2]) 132 | x = PyLinexpr1(e) 133 | x.set_coeff(PyVar('y'), PyDoubleScalarCoeff(1)) 134 | c = PyLincons1(ConsTyp.AP_CONS_SUP, x) 135 | a.set(0, c) 136 | self.assertEqual(str(a), '1.0·y + 0.0 > 0 ∧ 1.0·x + 0.0 > 0') 137 | 138 | 139 | if __name__ == '__main__': 140 | unittest.main() 141 | -------------------------------------------------------------------------------- /apronpy/texpr1.py: -------------------------------------------------------------------------------- 1 | """ 2 | APRON Tree Expressions (Level 1) 3 | ================================ 4 | 5 | :Author: Caterina Urban 6 | """ 7 | from _ctypes import Structure, POINTER 8 | from ctypes import c_char_p, c_int, c_bool 9 | from typing import Union 10 | 11 | from apronpy.cdll import libapron 12 | from apronpy.coeff import PyCoeff 13 | from apronpy.environment import Environment, PyEnvironment 14 | from apronpy.linexpr1 import PyLinexpr1 15 | from apronpy.texpr0 import Texpr0, TexprDiscr, TexprOp, TexprRtype, TexprRdir 16 | from apronpy.var import PyVar 17 | 18 | 19 | class Texpr1(Structure): 20 | """ 21 | typedef struct ap_texpr1_t { 22 | ap_texpr0_t* texpr0; 23 | ap_environment_t* env; 24 | } ap_texpr1_t; 25 | """ 26 | 27 | _fields_ = [ 28 | ('texpr0', POINTER(Texpr0)), 29 | ('env', POINTER(Environment)) 30 | ] 31 | 32 | def __repr__(self): 33 | def precendence(texpr0): 34 | op_precedence = { 35 | TexprOp.AP_TEXPR_ADD: 1, 36 | TexprOp.AP_TEXPR_SUB: 1, 37 | TexprOp.AP_TEXPR_MUL: 2, 38 | TexprOp.AP_TEXPR_DIV: 2, 39 | TexprOp.AP_TEXPR_MOD: 2, 40 | TexprOp.AP_TEXPR_POW: 3, 41 | TexprOp.AP_TEXPR_NEG: 4, 42 | TexprOp.AP_TEXPR_CAST: 5, 43 | TexprOp.AP_TEXPR_SQRT: 5 44 | } 45 | if texpr0.discr == TexprDiscr.AP_TEXPR_CST or texpr0.discr == TexprDiscr.AP_TEXPR_DIM: 46 | return op_precedence[TexprOp.AP_TEXPR_NEG] 47 | return op_precedence[texpr0.val.node.contents.op] 48 | 49 | def do(texpr0, env): 50 | if texpr0.discr == TexprDiscr.AP_TEXPR_CST: 51 | return '{}'.format(texpr0.val.cst) 52 | elif texpr0.discr == TexprDiscr.AP_TEXPR_DIM: 53 | return '{}'.format(env.var_of_dim[texpr0.val.dim.value].decode('utf-8')) 54 | else: # texpr0.discr == TexprDiscr.AP_TEXPR_NODE 55 | prec = precendence(texpr0) 56 | prec_a = precendence(texpr0.val.node.contents.exprA.contents) 57 | if prec_a < prec: 58 | expr_a = '({})'.format(do(texpr0.val.node.contents.exprA.contents, env)) 59 | else: 60 | expr_a = do(texpr0.val.node.contents.exprA.contents, env) 61 | op = texpr0.val.node.contents.op 62 | if texpr0.val.node.contents.exprB: # binary operation 63 | prec_b = precendence(texpr0.val.node.contents.exprB.contents) 64 | if prec_b <= prec: 65 | expr_b = '({})'.format(do(texpr0.val.node.contents.exprB.contents, env)) 66 | else: 67 | expr_b = do(texpr0.val.node.contents.exprB.contents, env) 68 | return '{} {} {}'.format(expr_a, repr(TexprOp(op)), expr_b) 69 | else: 70 | return '{} {}'.format(repr(TexprOp(op)), expr_a) 71 | 72 | return do(self.texpr0.contents, self.env.contents).replace('+ -', '- ') 73 | 74 | 75 | class PyTexpr1: 76 | 77 | def __init__(self, expr: Union[POINTER(Texpr1), PyLinexpr1]): 78 | if isinstance(expr, PyLinexpr1): 79 | self.texpr1: POINTER(Texpr1) = libapron.ap_texpr1_from_linexpr1(expr) 80 | else: 81 | assert isinstance(expr, POINTER(Texpr1)) 82 | self.texpr1: POINTER(Texpr1) = expr 83 | 84 | def __deepcopy__(self, memodict=None): 85 | if memodict is None: 86 | memodict = {} 87 | result = type(self)(libapron.ap_texpr1_copy(self)) 88 | memodict[id(self)] = result 89 | return result 90 | 91 | def __del__(self): 92 | libapron.ap_texpr1_free(self) 93 | del self.texpr1 94 | 95 | @classmethod 96 | def cst(cls, environment: PyEnvironment, cst: PyCoeff): 97 | return cls(libapron.ap_texpr1_cst(environment, cst)) 98 | 99 | @classmethod 100 | def var(cls, environment: PyEnvironment, var: PyVar): 101 | return cls(libapron.ap_texpr1_var(environment, var)) 102 | 103 | @classmethod 104 | def unop(cls, op: TexprOp, expr, typ: TexprRtype, rdir: TexprRdir): 105 | return cls(libapron.ap_texpr1_unop(op, libapron.ap_texpr1_copy(expr), typ, rdir)) 106 | 107 | @classmethod 108 | def binop(cls, op: TexprOp, expr_a, expr_b, typ: TexprRtype, rdir: TexprRdir): 109 | left = libapron.ap_texpr1_copy(expr_a) 110 | right = libapron.ap_texpr1_copy(expr_b) 111 | return cls(libapron.ap_texpr1_binop(op, left, right, typ, rdir)) 112 | 113 | @property 114 | def _as_parameter_(self): 115 | return self.texpr1 116 | 117 | @staticmethod 118 | def from_param(argument): 119 | assert isinstance(argument, PyTexpr1) 120 | return argument 121 | 122 | def __repr__(self): 123 | return '{}'.format(self.texpr1.contents) 124 | 125 | def has_variable(self, var: PyVar): 126 | return bool(libapron.ap_texpr1_has_var(self, var)) 127 | 128 | def substitute(self, var: PyVar, dst: 'PyTexpr1'): 129 | return type(self)(libapron.ap_texpr1_substitute(self, var._as_parameter_, dst)) 130 | 131 | 132 | libapron.ap_texpr1_cst.argtypes = [PyEnvironment, PyCoeff] 133 | libapron.ap_texpr1_cst.restype = POINTER(Texpr1) 134 | libapron.ap_texpr1_var.argtypes = [PyEnvironment, c_char_p] 135 | libapron.ap_texpr1_var.restype = POINTER(Texpr1) 136 | libapron.ap_texpr1_unop.argtypes = [c_int, POINTER(Texpr1), c_int, c_int] 137 | libapron.ap_texpr1_unop.restype = POINTER(Texpr1) 138 | libapron.ap_texpr1_binop.argtypes = [c_int, POINTER(Texpr1), POINTER(Texpr1), c_int, c_int] 139 | libapron.ap_texpr1_binop.restype = POINTER(Texpr1) 140 | libapron.ap_texpr1_copy.argtypes = [PyTexpr1] 141 | libapron.ap_texpr1_copy.restype = POINTER(Texpr1) 142 | libapron.ap_texpr1_free.argtypes = [PyTexpr1] 143 | libapron.ap_texpr1_from_linexpr1.argtypes = [PyLinexpr1] 144 | libapron.ap_texpr1_from_linexpr1.restype = POINTER(Texpr1) 145 | libapron.ap_texpr1_has_var.argtypes = [PyTexpr1, PyVar] 146 | libapron.ap_texpr1_has_var.restype = c_bool 147 | libapron.ap_texpr1_substitute.argtypes = [PyTexpr1, c_char_p, PyTexpr1] 148 | libapron.ap_texpr1_substitute.restype = POINTER(Texpr1) 149 | -------------------------------------------------------------------------------- /apronpy/interval.py: -------------------------------------------------------------------------------- 1 | """ 2 | APRON Intervals on Scalars 3 | ========================== 4 | 5 | :Author: Caterina Urban 6 | """ 7 | from _ctypes import Structure, POINTER, byref 8 | from abc import ABCMeta 9 | from ctypes import c_double, c_int, c_bool 10 | 11 | from apronpy.cdll import libapron 12 | from apronpy.mpfr import PyMPFR, Rnd 13 | from apronpy.mpq import PyMPQ 14 | from apronpy.scalar import Scalar, PyScalar, PyDoubleScalar, PyMPQScalar, PyMPFRScalar 15 | 16 | 17 | class Interval(Structure): 18 | """ 19 | typedef struct ap_interval_t { 20 | ap_scalar_t* inf; 21 | ap_scalar_t* sup; 22 | } ap_interval_t; 23 | """ 24 | 25 | _fields_ = [ 26 | ('inf', POINTER(Scalar)), 27 | ('sup', POINTER(Scalar)) 28 | ] 29 | 30 | def __repr__(self): 31 | return '[{},{}]'.format(self.inf.contents, self.sup.contents) 32 | 33 | 34 | class PyInterval(metaclass=ABCMeta): 35 | 36 | def __init__(self, value_or_inf, sup=None): 37 | if isinstance(value_or_inf, POINTER(Interval)): 38 | self.interval = value_or_inf 39 | else: 40 | self.interval = libapron.ap_interval_alloc() 41 | if isinstance(value_or_inf, Interval): 42 | libapron.ap_interval_set(self, byref(value_or_inf)) 43 | elif isinstance(value_or_inf, c_double) and isinstance(sup, c_double): 44 | libapron.ap_interval_set_double(self, value_or_inf, sup) 45 | elif isinstance(value_or_inf, PyMPQ) and isinstance(sup, PyMPQ): 46 | libapron.ap_interval_set_mpq(self, value_or_inf, sup) 47 | elif isinstance(value_or_inf, PyMPFR) and isinstance(sup, PyMPFR): 48 | libapron.ap_interval_set_mpfr(self, value_or_inf, sup) 49 | else: 50 | assert isinstance(value_or_inf, PyScalar) and isinstance(sup, PyScalar) 51 | libapron.ap_interval_set_scalar(self, value_or_inf, sup) 52 | 53 | @classmethod 54 | def top(cls): 55 | interval = cls(0, 0) 56 | libapron.ap_interval_set_top(interval) 57 | return interval 58 | 59 | @classmethod 60 | def bottom(cls): 61 | interval = cls(0, 0) 62 | libapron.ap_interval_set_bottom(interval) 63 | return interval 64 | 65 | def __deepcopy__(self, memodict=None): 66 | if memodict is None: 67 | memodict = {} 68 | result = type(self)(self.interval.contents) 69 | memodict[id(self)] = result 70 | return result 71 | 72 | def __del__(self): 73 | libapron.ap_interval_free(self) 74 | del self.interval 75 | 76 | @property 77 | def _as_parameter_(self): 78 | return self.interval 79 | 80 | @staticmethod 81 | def from_param(argument): 82 | assert isinstance(argument, PyInterval) 83 | return argument 84 | 85 | def __repr__(self): 86 | return str(self.interval.contents) 87 | 88 | def is_bottom(self): 89 | return bool(libapron.ap_interval_is_bottom(self)) 90 | 91 | def __lt__(self, other: 'PyInterval'): 92 | assert isinstance(other, PyInterval) 93 | return libapron.ap_interval_cmp(self, other) == -1 94 | 95 | def __le__(self, other: 'PyInterval'): 96 | assert isinstance(other, PyInterval) 97 | return self.__lt__(other) or self.__eq__(other) 98 | 99 | def __eq__(self, other): 100 | assert isinstance(other, PyInterval) 101 | return libapron.ap_interval_cmp(self, other) == 0 102 | 103 | def __ne__(self, other): 104 | assert isinstance(other, PyInterval) 105 | return not self.__eq__(other) 106 | 107 | def __ge__(self, other): 108 | assert isinstance(other, PyInterval) 109 | return self.__gt__(other) or self.__eq__(other) 110 | 111 | def __gt__(self, other): 112 | assert isinstance(other, PyInterval) 113 | return libapron.ap_interval_cmp(self, other) == 1 114 | 115 | def is_top(self): 116 | return bool(libapron.ap_interval_is_top(self)) 117 | 118 | def __neg__(self) -> 'PyInterval': 119 | interval = type(self)(0, 0) 120 | libapron.ap_interval_neg(interval, self) 121 | return interval 122 | 123 | 124 | libapron.ap_interval_alloc.restype = POINTER(Interval) 125 | libapron.ap_interval_set.argtypes = [PyInterval, POINTER(Interval)] 126 | libapron.ap_interval_set_int.argtypes = [PyInterval, c_int, c_int] 127 | libapron.ap_interval_set_double.argtypes = [PyInterval, c_double, c_double] 128 | libapron.ap_interval_set_mpq.argtypes = [PyInterval, PyMPQ, PyMPQ] 129 | libapron.ap_interval_set_mpfr.argtypes = [PyInterval, PyMPFR, PyMPFR] 130 | libapron.ap_interval_set_scalar.argtypes = [PyInterval, PyScalar, PyScalar] 131 | libapron.ap_interval_is_bottom.argtypes = [PyInterval] 132 | libapron.ap_interval_is_bottom.restype = c_bool 133 | libapron.ap_interval_is_top.argtypes = [PyInterval] 134 | libapron.ap_interval_is_top.restype = c_bool 135 | libapron.ap_interval_cmp.argtypes = [PyInterval, PyInterval] 136 | libapron.ap_interval_neg.argtypes = [PyInterval, PyInterval] 137 | 138 | 139 | class PyDoubleInterval(PyInterval): 140 | 141 | def __init__(self, value_or_inf=0.0, sup=0.0): 142 | if isinstance(value_or_inf, Interval): 143 | super().__init__(value_or_inf) 144 | elif isinstance(value_or_inf, PyDoubleScalar) and isinstance(sup, PyDoubleScalar): 145 | super().__init__(value_or_inf, sup) 146 | elif isinstance(value_or_inf, c_double) and isinstance(sup, c_double): 147 | super().__init__(value_or_inf, sup) 148 | else: 149 | super().__init__(c_double(value_or_inf), c_double(sup)) 150 | 151 | 152 | class PyMPQInterval(PyInterval): 153 | 154 | def __init__(self, value_or_inf_num=0, sup_num=0, inf_den=1, sup_den=1): 155 | if isinstance(value_or_inf_num, Interval): 156 | super().__init__(value_or_inf_num) 157 | elif isinstance(value_or_inf_num, PyMPQScalar) and isinstance(sup_num, PyMPQScalar): 158 | super().__init__(value_or_inf_num, sup_num) 159 | elif isinstance(value_or_inf_num, PyMPQ) and isinstance(sup_num, PyMPQ): 160 | super().__init__(value_or_inf_num, sup_num) 161 | else: 162 | super().__init__(PyMPQ(value_or_inf_num, inf_den), PyMPQ(sup_num, sup_den)) 163 | 164 | 165 | class PyMPFRInterval(PyInterval): 166 | 167 | def __init__(self, value_or_inf, sup=None, rounding: Rnd = Rnd.MPFR_RNDN): 168 | if isinstance(value_or_inf, Interval): 169 | super().__init__(value_or_inf) 170 | elif isinstance(value_or_inf, PyMPFRScalar) and isinstance(sup, PyMPFRScalar): 171 | super().__init__(value_or_inf, sup) 172 | elif isinstance(value_or_inf, PyMPFR) and isinstance(sup, PyMPFR): 173 | super().__init__(value_or_inf, sup) 174 | else: 175 | super().__init__(PyMPFR(value_or_inf, rounding), PyMPFR(sup, rounding)) 176 | -------------------------------------------------------------------------------- /apronpy/linexpr1.py: -------------------------------------------------------------------------------- 1 | """ 2 | APRON Linear Expressions (Level 1) 3 | ================================== 4 | 5 | :Author: Caterina Urban 6 | """ 7 | from _ctypes import Structure, POINTER, byref 8 | from copy import deepcopy 9 | from ctypes import c_uint, c_size_t, c_char_p 10 | 11 | from apronpy.cdll import libapron 12 | from apronpy.coeff import Coeff, CoeffDiscr, PyDoubleIntervalCoeff, PyDoubleScalarCoeff, \ 13 | PyMPQScalarCoeff, PyMPFRScalarCoeff, PyMPQIntervalCoeff, PyMPFRIntervalCoeff, PyCoeff 14 | from apronpy.environment import Environment, PyEnvironment 15 | from apronpy.linexpr0 import Linexpr0, LinexprDiscr 16 | from apronpy.scalar import ScalarDiscr 17 | from apronpy.var import PyVar 18 | 19 | 20 | class Linexpr1(Structure): 21 | """ 22 | typedef struct ap_linexpr1_t { 23 | ap_linexpr0_t* linexpr0; 24 | ap_environment_t* env; 25 | } ap_linexpr1_t; 26 | """ 27 | 28 | _fields_ = [ 29 | ('linexpr0', POINTER(Linexpr0)), 30 | ('env', POINTER(Environment)) 31 | ] 32 | 33 | def __deepcopy__(self, memodict=None): 34 | if memodict is None: 35 | memodict = {} 36 | result = libapron.ap_linexpr1_copy(byref(self)) 37 | memodict[id(self)] = result 38 | return result 39 | 40 | def __repr__(self): 41 | linexpr0 = self.linexpr0.contents 42 | env = self.env.contents 43 | result = '' 44 | if linexpr0.discr == LinexprDiscr.AP_LINEXPR_DENSE: 45 | result += ' + '.join( 46 | '{}·{}'.format(linexpr0.p.coeff[i], env.var_of_dim[i].decode('utf-8')) 47 | for i in range(linexpr0.size) 48 | ) 49 | result += ' + {}'.format(linexpr0.cst) if result else '{}'.format(linexpr0.cst) 50 | else: 51 | assert linexpr0.discr == LinexprDiscr.AP_LINEXPR_SPARSE 52 | terms = list() 53 | for i in range(linexpr0.size): 54 | coeff = linexpr0.p.linterm[i].coeff 55 | dim = linexpr0.p.linterm[i].dim.value 56 | if dim < env.intdim + env.realdim: 57 | terms.append('{}·{}'.format(coeff, env.var_of_dim[dim].decode('utf-8'))) 58 | result += ' + '.join(terms) 59 | result += ' + {}'.format(linexpr0.cst) if result else '{}'.format(linexpr0.cst) 60 | return result.replace('+ -', '- ') 61 | 62 | 63 | class PyLinexpr1: 64 | 65 | def __init__(self, linexpr1_or_environment, discr=LinexprDiscr.AP_LINEXPR_SPARSE): 66 | if isinstance(linexpr1_or_environment, Linexpr1): 67 | self.linexpr1 = linexpr1_or_environment 68 | else: 69 | assert isinstance(linexpr1_or_environment, PyEnvironment) 70 | size = len(linexpr1_or_environment) 71 | self.linexpr1 = libapron.ap_linexpr1_make(linexpr1_or_environment, discr, size) 72 | 73 | def __deepcopy__(self, memodict=None): 74 | if memodict is None: 75 | memodict = {} 76 | result = PyLinexpr1(deepcopy(self.linexpr1)) 77 | memodict[id(self)] = result 78 | return result 79 | 80 | def __del__(self): 81 | libapron.ap_linexpr1_clear(self) 82 | del self.linexpr1 83 | 84 | @property 85 | def _as_parameter_(self): 86 | return byref(self.linexpr1) 87 | 88 | @staticmethod 89 | def from_param(argument): 90 | assert isinstance(argument, PyLinexpr1) 91 | return argument 92 | 93 | def __repr__(self): 94 | return '{}'.format(self.linexpr1) 95 | 96 | def is_integer(self): 97 | linexpr0 = self.linexpr1.linexpr0 98 | intdim = self.linexpr1.env.contents.intdim 99 | return bool(libapron.ap_linexpr0_is_integer(linexpr0, intdim)) 100 | 101 | def is_real(self): 102 | linexpr0 = self.linexpr1.linexpr0 103 | intdim = self.linexpr1.env.contents.intdim 104 | return bool(libapron.ap_linexpr0_is_real(linexpr0, intdim)) 105 | 106 | def is_linear(self): 107 | linexpr0 = self.linexpr1.linexpr0 108 | return bool(libapron.ap_linexpr0_is_linear(linexpr0)) 109 | 110 | def is_quasilinear(self): 111 | linexpr0 = self.linexpr1.linexpr0 112 | return bool(libapron.ap_linexpr0_is_quasilinear(linexpr0)) 113 | 114 | def get_cst(self): 115 | cst = deepcopy(self.linexpr1.linexpr0.contents.cst) 116 | if cst.discr == CoeffDiscr.AP_COEFF_INTERVAL: 117 | if cst.val.interval.contents.inf.contents.discr == ScalarDiscr.AP_SCALAR_MPQ: 118 | result = PyMPQIntervalCoeff(cst) 119 | elif cst.val.interval.contents.inf.contents.discr == ScalarDiscr.AP_SCALAR_MPFR: 120 | result = PyMPFRIntervalCoeff(cst) 121 | else: 122 | assert cst.val.interval.contents.inf.contents.discr == ScalarDiscr.AP_SCALAR_DOUBLE 123 | result = PyDoubleIntervalCoeff(cst) 124 | else: 125 | assert cst.discr == CoeffDiscr.AP_COEFF_SCALAR 126 | if cst.val.scalar.contents.discr == ScalarDiscr.AP_SCALAR_MPQ: 127 | result = PyMPQScalarCoeff(cst) 128 | elif cst.val.scalar.contents.discr == ScalarDiscr.AP_SCALAR_MPFR: 129 | result = PyMPFRScalarCoeff(cst) 130 | else: 131 | assert cst.val.scalar.contents.discr == ScalarDiscr.AP_SCALAR_DOUBLE 132 | result = PyDoubleScalarCoeff(cst) 133 | return result 134 | 135 | def set_cst(self, cst: PyCoeff): 136 | libapron.ap_coeff_set(byref(self.linexpr1.linexpr0.contents.cst), cst.coeff) 137 | 138 | def get_coeff(self, var: PyVar): 139 | coeff = libapron.ap_linexpr1_coeffref(self, var._as_parameter_) 140 | if coeff.contents.discr == CoeffDiscr.AP_COEFF_INTERVAL: 141 | discr = coeff.contents.val.interval.contents.inf.contents.discr 142 | if discr == ScalarDiscr.AP_SCALAR_MPQ: 143 | result = PyMPQIntervalCoeff() 144 | elif discr == ScalarDiscr.AP_SCALAR_MPFR: 145 | result = PyMPFRIntervalCoeff(0, 0) 146 | else: # discr == ScalarDiscr.AP_SCALAR_DOUBLE 147 | result = PyDoubleIntervalCoeff() 148 | else: # CoeffDiscr.AP_COEFF_SCALAR 149 | if coeff.contents.val.scalar.contents.discr == ScalarDiscr.AP_SCALAR_MPQ: 150 | result = PyMPQScalarCoeff() 151 | elif coeff.contents.val.scalar.contents.discr == ScalarDiscr.AP_SCALAR_MPFR: 152 | result = PyMPFRScalarCoeff(0) 153 | else: # coeff.contents.val.scalar.contents.discr == ScalarDiscr.AP_SCALAR_DOUBLE 154 | result = PyDoubleScalarCoeff() 155 | libapron.ap_linexpr1_get_coeff(result, self, var._as_parameter_) 156 | return result 157 | 158 | def set_coeff(self, var: PyVar, coeff: PyCoeff): 159 | libapron.ap_coeff_set(libapron.ap_linexpr1_coeffref(self, var._as_parameter_), coeff.coeff) 160 | 161 | 162 | libapron.ap_linexpr1_make.argtypes = [PyEnvironment, c_uint, c_size_t] 163 | libapron.ap_linexpr1_make.restype = Linexpr1 164 | libapron.ap_linexpr1_copy.argtypes = [POINTER(Linexpr1)] 165 | libapron.ap_linexpr1_copy.restype = Linexpr1 166 | libapron.ap_linexpr1_clear.argtypes = [PyLinexpr1] 167 | libapron.ap_linexpr1_coeffref.argtypes = [PyLinexpr1, c_char_p] 168 | libapron.ap_linexpr1_coeffref.restype = POINTER(Coeff) 169 | libapron.ap_linexpr1_get_coeff.argtypes = [PyCoeff, PyLinexpr1, c_char_p] 170 | -------------------------------------------------------------------------------- /tests/test_coeff.py: -------------------------------------------------------------------------------- 1 | """ 2 | APRON Coefficients - Unit Tests 3 | =============================== 4 | 5 | :Author: Caterina Urban 6 | """ 7 | import unittest 8 | from copy import deepcopy 9 | 10 | from apronpy.coeff import PyDoubleScalarCoeff, PyMPQScalarCoeff, PyMPFRScalarCoeff, \ 11 | PyDoubleIntervalCoeff, PyMPQIntervalCoeff, PyMPFRIntervalCoeff 12 | 13 | 14 | class TestPyDoubleScalarCoeff(unittest.TestCase): 15 | 16 | def test_init(self): 17 | self.assertEqual(str(PyDoubleScalarCoeff()), '0.0') 18 | 19 | def test_deepcopy(self): 20 | c0 = PyDoubleScalarCoeff() 21 | c1 = deepcopy(c0) 22 | c2 = c0 23 | self.assertNotEqual(id(c0), id(c1)) 24 | self.assertEqual(id(c0), id(c2)) 25 | 26 | def test_cmp(self): 27 | self.assertTrue(PyDoubleScalarCoeff(-0.5) < PyDoubleScalarCoeff()) 28 | self.assertFalse(PyDoubleScalarCoeff() < PyDoubleScalarCoeff(-0.5)) 29 | self.assertTrue(PyDoubleScalarCoeff() == PyDoubleScalarCoeff(0)) 30 | self.assertFalse(PyDoubleScalarCoeff() == PyDoubleScalarCoeff(-0.5)) 31 | self.assertTrue(PyDoubleScalarCoeff() > PyDoubleScalarCoeff(-0.5)) 32 | self.assertFalse(PyDoubleScalarCoeff(-0.5) > PyDoubleScalarCoeff()) 33 | 34 | def test_neg(self): 35 | self.assertEqual(-PyDoubleScalarCoeff(-0.5), PyDoubleScalarCoeff(0.5)) 36 | self.assertEqual(-PyDoubleScalarCoeff(0), PyDoubleScalarCoeff(0)) 37 | self.assertEqual(-PyDoubleScalarCoeff(0.5), PyDoubleScalarCoeff(-0.5)) 38 | 39 | 40 | class TestPyMPQScalarCoeff(unittest.TestCase): 41 | 42 | def test_init(self): 43 | self.assertEqual(str(PyMPQScalarCoeff()), '0') 44 | 45 | def test_deepcopy(self): 46 | c0 = PyMPQScalarCoeff() 47 | c1 = deepcopy(c0) 48 | c2 = c0 49 | self.assertNotEqual(id(c0), id(c1)) 50 | self.assertEqual(id(c0), id(c2)) 51 | 52 | def test_cmp(self): 53 | self.assertTrue(PyMPQScalarCoeff(-1, 2) < PyMPQScalarCoeff()) 54 | self.assertFalse(PyMPQScalarCoeff() < PyMPQScalarCoeff(-1, 2)) 55 | self.assertTrue(PyMPQScalarCoeff() == PyMPQScalarCoeff(0)) 56 | self.assertFalse(PyMPQScalarCoeff() == PyMPQScalarCoeff(-1, 2)) 57 | self.assertTrue(PyMPQScalarCoeff() > PyMPQScalarCoeff(-1, 2)) 58 | self.assertFalse(PyMPQScalarCoeff(-1, 2) > PyMPQScalarCoeff()) 59 | 60 | def test_neg(self): 61 | self.assertEqual(-PyMPQScalarCoeff(-1, 2), PyMPQScalarCoeff(1, 2)) 62 | self.assertEqual(-PyMPQScalarCoeff(0), PyMPQScalarCoeff(0)) 63 | self.assertEqual(-PyMPQScalarCoeff(1, 2), PyMPQScalarCoeff(-1, 2)) 64 | 65 | 66 | class TestPyMPFRScalarCoeff(unittest.TestCase): 67 | 68 | def test_init(self): 69 | self.assertEqual(str(PyMPFRScalarCoeff(0)), '0.0') 70 | 71 | def test_deepcopy(self): 72 | c0 = PyMPFRScalarCoeff(0) 73 | c1 = deepcopy(c0) 74 | c2 = c0 75 | self.assertNotEqual(id(c0), id(c1)) 76 | self.assertEqual(id(c0), id(c2)) 77 | 78 | def test_cmp(self): 79 | self.assertTrue(PyMPFRScalarCoeff(-0.5) < PyMPFRScalarCoeff(0)) 80 | self.assertFalse(PyMPFRScalarCoeff(0) < PyMPFRScalarCoeff(-0.5)) 81 | self.assertTrue(PyMPFRScalarCoeff(0) == PyMPFRScalarCoeff(0)) 82 | self.assertFalse(PyMPFRScalarCoeff(0) == PyMPFRScalarCoeff(-0.5)) 83 | self.assertTrue(PyMPFRScalarCoeff(0) > PyMPFRScalarCoeff(-0.5)) 84 | self.assertFalse(PyMPFRScalarCoeff(-0.5) > PyMPFRScalarCoeff(0)) 85 | 86 | def test_neg(self): 87 | self.assertEqual(-PyMPFRScalarCoeff(-0.5), PyMPFRScalarCoeff(0.5)) 88 | self.assertEqual(-PyMPFRScalarCoeff(0), PyMPFRScalarCoeff(0)) 89 | self.assertEqual(-PyMPFRScalarCoeff(0.5), PyMPFRScalarCoeff(-0.5)) 90 | 91 | 92 | class TestPyDoubleIntervalCoeff(unittest.TestCase): 93 | 94 | def test_init(self): 95 | self.assertEqual(str(PyDoubleIntervalCoeff()), '[0.0,0.0]') 96 | 97 | def test_deepcopy(self): 98 | c0 = PyDoubleIntervalCoeff() 99 | c1 = deepcopy(c0) 100 | c2 = c0 101 | self.assertNotEqual(id(c0), id(c1)) 102 | self.assertEqual(id(c0), id(c2)) 103 | 104 | def test_cmp(self): 105 | self.assertTrue(PyDoubleIntervalCoeff() < PyDoubleIntervalCoeff(-0.5, 0.5)) 106 | self.assertFalse(PyDoubleIntervalCoeff(-0.5, 0.5) < PyDoubleIntervalCoeff()) 107 | self.assertTrue(PyDoubleIntervalCoeff() == PyDoubleIntervalCoeff(0)) 108 | self.assertFalse(PyDoubleIntervalCoeff() == PyDoubleIntervalCoeff(-0.5, 0.5)) 109 | self.assertTrue(PyDoubleIntervalCoeff(-0.5, 0.5) > PyDoubleIntervalCoeff()) 110 | self.assertFalse(PyDoubleIntervalCoeff() > PyDoubleIntervalCoeff(-0.5, 0.5)) 111 | 112 | def test_neg(self): 113 | self.assertEqual(-PyDoubleIntervalCoeff(-1, 2), PyDoubleIntervalCoeff(-2, 1)) 114 | self.assertEqual(-PyDoubleIntervalCoeff(), PyDoubleIntervalCoeff(0, 0)) 115 | self.assertEqual(-PyDoubleIntervalCoeff(1, 2), PyDoubleIntervalCoeff(-2, -1)) 116 | 117 | 118 | class TestPyMPQIntervalCoeff(unittest.TestCase): 119 | 120 | def test_init(self): 121 | self.assertEqual(str(PyMPQIntervalCoeff()), '[0,0]') 122 | 123 | def test_deepcopy(self): 124 | c0 = PyMPQIntervalCoeff() 125 | c1 = deepcopy(c0) 126 | c2 = c0 127 | self.assertNotEqual(id(c0), id(c1)) 128 | self.assertEqual(id(c0), id(c2)) 129 | 130 | def test_cmp(self): 131 | self.assertTrue(PyMPQIntervalCoeff() < PyMPQIntervalCoeff(-1, 1, 2, 2)) 132 | self.assertFalse(PyMPQIntervalCoeff(-1, 1, 2, 2) < PyMPQIntervalCoeff()) 133 | self.assertTrue(PyMPQIntervalCoeff() == PyMPQIntervalCoeff(0, 0)) 134 | self.assertFalse(PyMPQIntervalCoeff() == PyMPQIntervalCoeff(-1, 1, 2, 2)) 135 | self.assertTrue(PyMPQIntervalCoeff(-1, 1, 2, 2) > PyMPQIntervalCoeff()) 136 | self.assertFalse(PyMPQIntervalCoeff() > PyMPQIntervalCoeff(-1, 1, 2, 2)) 137 | 138 | def test_neg(self): 139 | self.assertEqual(-PyMPQIntervalCoeff(-1, 2), PyMPQIntervalCoeff(-2, 1)) 140 | self.assertEqual(-PyMPQIntervalCoeff(), PyMPQIntervalCoeff(0, 0)) 141 | self.assertEqual(-PyMPQIntervalCoeff(1, 2), PyMPQIntervalCoeff(-2, -1)) 142 | 143 | 144 | class TestPyMPFRIntervalCoeff(unittest.TestCase): 145 | 146 | def test_init(self): 147 | self.assertEqual(str(PyMPFRIntervalCoeff(0, 0)), '[0.0,0.0]') 148 | 149 | def test_deepcopy(self): 150 | c0 = PyMPFRIntervalCoeff(0, 0) 151 | c1 = deepcopy(c0) 152 | c2 = c0 153 | self.assertNotEqual(id(c0), id(c1)) 154 | self.assertEqual(id(c0), id(c2)) 155 | 156 | def test_cmp(self): 157 | self.assertTrue(PyMPFRIntervalCoeff(0, 0) < PyMPFRIntervalCoeff(-0.5, 0.5)) 158 | self.assertFalse(PyMPFRIntervalCoeff(-0.5, 0.5) < PyMPFRIntervalCoeff(0, 0)) 159 | self.assertTrue(PyMPFRIntervalCoeff(0, 0) == PyMPFRIntervalCoeff(0.0, 0.0)) 160 | self.assertFalse(PyMPFRIntervalCoeff(0, 0) == PyMPFRIntervalCoeff(-0.5, 0.5)) 161 | self.assertTrue(PyMPFRIntervalCoeff(-0.5, 0.5) > PyMPFRIntervalCoeff(0, 0)) 162 | self.assertFalse(PyMPFRIntervalCoeff(0, 0) > PyMPFRIntervalCoeff(-0.5, 0.5)) 163 | 164 | def test_neg(self): 165 | self.assertEqual(-PyMPFRIntervalCoeff(-1, 2), PyMPFRIntervalCoeff(-2, 1)) 166 | self.assertEqual(-PyMPFRIntervalCoeff(0, 0), PyMPFRIntervalCoeff(0, 0)) 167 | self.assertEqual(-PyMPFRIntervalCoeff(1, 2), PyMPFRIntervalCoeff(-2, -1)) 168 | 169 | 170 | if __name__ == '__main__': 171 | unittest.main() 172 | -------------------------------------------------------------------------------- /apronpy/scalar.py: -------------------------------------------------------------------------------- 1 | """ 2 | APRON Scalar Numbers 3 | ==================== 4 | 5 | :Author: Caterina Urban 6 | """ 7 | from abc import ABCMeta 8 | from copy import deepcopy 9 | from ctypes import * 10 | from enum import IntEnum 11 | 12 | from apronpy.mpfr import MPFR, PyMPFR, Rnd 13 | from apronpy.mpq import PyMPQ, MPQ 14 | from apronpy.cdll import libapron 15 | 16 | 17 | class ScalarDiscr(IntEnum): 18 | """ 19 | typedef enum ap_scalar_discr_t { 20 | AP_SCALAR_DOUBLE, /* double-precision floating-point number */ 21 | AP_SCALAR_MPQ, /* GMP arbitrary precision rational */ 22 | AP_SCALAR_MPFR, /* MPFR floating-point number */ 23 | } ap_scalar_discr_t; 24 | """ 25 | AP_SCALAR_DOUBLE = 0 26 | AP_SCALAR_MPQ = 1 27 | AP_SCALAR_MPFR = 2 28 | 29 | 30 | class Scalar(Structure): 31 | """ 32 | typedef struct ap_scalar_t { 33 | ap_scalar_discr_t discr; 34 | union { 35 | double dbl; 36 | mpq_ptr mpq; /* +infty coded by 1/0, -infty coded by -1/0 */ 37 | mpfr_ptr mpfr; 38 | } val; 39 | } ap_scalar_t; 40 | """ 41 | 42 | class Val(Union): 43 | """ 44 | union { 45 | double dbl; 46 | mpq_ptr mpq; /* +infty coded by 1/0, -infty coded by -1/0 */ 47 | mpfr_ptr mpfr; 48 | } val; 49 | """ 50 | 51 | _fields_ = [ 52 | ('dbl', c_double), 53 | ('mpq_ptr', POINTER(MPQ)), 54 | ('mpfr_ptr', POINTER(MPFR)) 55 | ] 56 | 57 | _fields_ = [ 58 | ('discr', c_uint), 59 | ('val', Val) 60 | ] 61 | 62 | def __deepcopy__(self, memodict=None): 63 | if memodict is None: 64 | memodict = {} 65 | result = libapron.ap_scalar_alloc_set(byref(self)).contents 66 | memodict[id(self)] = result 67 | return result 68 | 69 | def __repr__(self): 70 | if self.discr == ScalarDiscr.AP_SCALAR_MPQ: 71 | return '{}'.format(self.val.mpq_ptr.contents) 72 | elif self.discr == ScalarDiscr.AP_SCALAR_MPFR: 73 | return '{}'.format(self.val.mpfr_ptr.contents) 74 | else: # self.discr == Discr.AP_SCALAR_DOUBLE 75 | return '{}'.format(self.val.dbl) 76 | 77 | 78 | class PyScalar(metaclass=ABCMeta): 79 | 80 | def __init__(self, value, discr: ScalarDiscr = ScalarDiscr.AP_SCALAR_DOUBLE): 81 | if isinstance(value, Scalar): 82 | self.scalar = byref(value) 83 | elif discr == ScalarDiscr.AP_SCALAR_MPQ: 84 | self.scalar = libapron.ap_scalar_alloc_set_mpq(value) 85 | elif discr == ScalarDiscr.AP_SCALAR_MPFR: 86 | self.scalar = libapron.ap_scalar_alloc_set_mpfr(value) 87 | else: 88 | assert discr == ScalarDiscr.AP_SCALAR_DOUBLE 89 | self.scalar = libapron.ap_scalar_alloc_set_double(value) 90 | 91 | @classmethod 92 | def init_infty(cls, sign: int): 93 | scalar = cls(0) 94 | libapron.ap_scalar_set_infty(scalar, sign) 95 | return scalar 96 | 97 | def __deepcopy__(self, memodict=None): 98 | if memodict is None: 99 | memodict = {} 100 | result = type(self)(deepcopy(self.scalar.contents)) 101 | memodict[id(self)] = result 102 | return result 103 | 104 | def __del__(self): 105 | libapron.ap_scalar_free(self) 106 | del self.scalar 107 | 108 | @property 109 | def _as_parameter_(self): 110 | return self.scalar 111 | 112 | @staticmethod 113 | def from_param(argument): 114 | assert isinstance(argument, PyScalar) 115 | return argument 116 | 117 | def __repr__(self): 118 | return '{}'.format(self.scalar.contents) 119 | 120 | def infty(self): 121 | """-1: -infty, 0: finite; 1: +infty""" 122 | return libapron.ap_scalar_infty(self) 123 | 124 | def __lt__(self, other: 'PyScalar'): 125 | assert isinstance(other, PyScalar) 126 | return libapron.ap_scalar_cmp(self, other) < 0 127 | 128 | def __le__(self, other: 'PyScalar'): 129 | assert isinstance(other, PyScalar) 130 | return self.__lt__(other) or self.__eq__(other) 131 | 132 | def __eq__(self, other: 'PyScalar'): 133 | assert isinstance(other, PyScalar) 134 | return libapron.ap_scalar_cmp(self, other) == 0 135 | 136 | def __ne__(self, other: 'PyScalar'): 137 | assert isinstance(other, PyScalar) 138 | return not self.__eq__(other) 139 | 140 | def __ge__(self, other: 'PyScalar'): 141 | assert isinstance(other, PyScalar) 142 | return self.__gt__(other) or self.__eq__(other) 143 | 144 | def __gt__(self, other: 'PyScalar'): 145 | assert isinstance(other, PyScalar) 146 | return libapron.ap_scalar_cmp(self, other) > 0 147 | 148 | def sign(self): 149 | """-1: negative, 0: null, +1: positive""" 150 | return libapron.ap_scalar_sgn(self) 151 | 152 | def __neg__(self) -> 'PyScalar': 153 | scalar = type(self)(0) 154 | libapron.ap_scalar_neg(scalar, self) 155 | return scalar 156 | 157 | 158 | libapron.ap_scalar_alloc.restype = POINTER(Scalar) 159 | libapron.ap_scalar_set.argtypes = [POINTER(Scalar), PyScalar] 160 | libapron.ap_scalar_alloc_set.argtypes = [POINTER(Scalar)] 161 | libapron.ap_scalar_alloc_set.restype = POINTER(Scalar) 162 | libapron.ap_scalar_alloc_set_double.argtypes = [c_double] 163 | libapron.ap_scalar_alloc_set_double.restype = POINTER(Scalar) 164 | libapron.ap_scalar_alloc_set_mpq.argtypes = [PyMPQ] 165 | libapron.ap_scalar_alloc_set_mpq.restype = POINTER(Scalar) 166 | libapron.ap_scalar_alloc_set_mpfr.argtypes = [PyMPFR] 167 | libapron.ap_scalar_alloc_set_mpfr.restype = POINTER(Scalar) 168 | libapron.ap_scalar_set_infty.argtypes = [PyScalar, c_int] 169 | libapron.ap_scalar_free.argtypes = [PyScalar] 170 | libapron.ap_scalar_infty.argtypes = [PyScalar] 171 | libapron.ap_scalar_cmp.argtypes = [PyScalar, PyScalar] 172 | libapron.ap_scalar_sgn.argtypes = [PyScalar] 173 | libapron.ap_scalar_neg.argtypes = [PyScalar, PyScalar] 174 | 175 | 176 | class PyDoubleScalar(PyScalar): 177 | 178 | def __init__(self, value=0.0): 179 | if isinstance(value, Scalar): 180 | super().__init__(discr=ScalarDiscr.AP_SCALAR_DOUBLE, value=value) 181 | elif isinstance(value, c_double): 182 | super().__init__(discr=ScalarDiscr.AP_SCALAR_DOUBLE, value=value) 183 | else: 184 | assert isinstance(value, (int, float)) 185 | super().__init__(discr=ScalarDiscr.AP_SCALAR_DOUBLE, value=c_double(value)) 186 | 187 | 188 | class PyMPQScalar(PyScalar): 189 | 190 | def __init__(self, value_or_numerator=0, denumerator=1): 191 | if isinstance(value_or_numerator, (Scalar, PyMPQ)): 192 | super().__init__(discr=ScalarDiscr.AP_SCALAR_MPQ, value=value_or_numerator) 193 | elif isinstance(value_or_numerator, float): 194 | mpq = PyMPQ(value_or_numerator) 195 | super().__init__(discr=ScalarDiscr.AP_SCALAR_MPQ, value=mpq) 196 | else: 197 | assert isinstance(value_or_numerator, int) and isinstance(denumerator, int) 198 | mpq = PyMPQ(value_or_numerator, denumerator) 199 | super().__init__(discr=ScalarDiscr.AP_SCALAR_MPQ, value=mpq) 200 | 201 | 202 | class PyMPFRScalar(PyScalar): 203 | 204 | def __init__(self, value, rounding: Rnd = Rnd.MPFR_RNDN): 205 | if isinstance(value, (Scalar, PyMPFR)): 206 | super().__init__(discr=ScalarDiscr.AP_SCALAR_MPFR, value=value) 207 | else: 208 | super().__init__(discr=ScalarDiscr.AP_SCALAR_MPFR, value=PyMPFR(value, rounding)) 209 | -------------------------------------------------------------------------------- /apronpy/coeff.py: -------------------------------------------------------------------------------- 1 | """ 2 | APRON Coefficients 3 | ================== 4 | 5 | :Author: Caterina Urban 6 | """ 7 | from _ctypes import Union, Structure, POINTER, byref 8 | from abc import ABCMeta 9 | from copy import deepcopy 10 | from ctypes import c_uint 11 | from enum import IntEnum 12 | 13 | from apronpy.cdll import libapron 14 | from apronpy.interval import Interval, PyInterval, PyDoubleInterval, PyMPQInterval, PyMPFRInterval 15 | from apronpy.mpfr import Rnd 16 | from apronpy.scalar import Scalar, PyScalar, PyDoubleScalar, PyMPQScalar, PyMPFRScalar 17 | 18 | 19 | class CoeffDiscr(IntEnum): 20 | """ 21 | typedef enum ap_coeff_discr_t { 22 | AP_COEFF_SCALAR, 23 | AP_COEFF_INTERVAL 24 | } ap_coeff_discr_t; 25 | """ 26 | AP_COEFF_SCALAR = 0 27 | AP_COEFF_INTERVAL = 1 28 | 29 | 30 | class Coeff(Structure): 31 | """ 32 | typedef struct ap_coeff_t { 33 | ap_coeff_discr_t discr; /* discriminant for coefficient */ 34 | union { 35 | ap_scalar_t* scalar; /* cst (normal linear expression) */ 36 | ap_interval_t* interval; /* interval (quasi-linear expression) */ 37 | } val; 38 | } ap_coeff_t; 39 | """ 40 | class Val(Union): 41 | """ 42 | union { 43 | ap_scalar_t* scalar; /* cst (normal linear expression) */ 44 | ap_interval_t* interval; /* interval (quasi-linear expression) */ 45 | } val; 46 | """ 47 | 48 | _fields_ = [ 49 | ('scalar', POINTER(Scalar)), 50 | ('interval', POINTER(Interval)) 51 | ] 52 | 53 | _fields_ = [ 54 | ('discr', c_uint), 55 | ('val', Val) 56 | ] 57 | 58 | def __deepcopy__(self, memodict=None): 59 | if memodict is None: 60 | memodict = {} 61 | result = libapron.ap_coeff_alloc(self.discr) 62 | libapron.ap_coeff_set(result, byref(self)) 63 | memodict[id(self)] = result.contents 64 | return result.contents 65 | 66 | def __repr__(self): 67 | if self.discr == CoeffDiscr.AP_COEFF_INTERVAL: 68 | return '{}'.format(self.val.interval.contents) 69 | else: 70 | assert self.discr == CoeffDiscr.AP_COEFF_SCALAR 71 | return '{}'.format(self.val.scalar.contents) 72 | 73 | 74 | class PyCoeff(metaclass=ABCMeta): 75 | 76 | def __init__(self, value, discr: CoeffDiscr = CoeffDiscr.AP_COEFF_SCALAR): 77 | if isinstance(value, Coeff): 78 | self.coeff = byref(value) 79 | else: 80 | self.coeff = libapron.ap_coeff_alloc(discr) 81 | if discr == CoeffDiscr.AP_COEFF_INTERVAL: 82 | libapron.ap_coeff_set_interval(self, value) 83 | else: 84 | assert discr == CoeffDiscr.AP_COEFF_SCALAR 85 | libapron.ap_coeff_set_scalar(self, value) 86 | 87 | def __deepcopy__(self, memodict=None): 88 | if memodict is None: 89 | memodict = {} 90 | result = type(self)(deepcopy(self.coeff.contents)) 91 | memodict[id(self)] = result 92 | return result 93 | 94 | def __del__(self): 95 | libapron.ap_coeff_free(self) 96 | del self.coeff 97 | 98 | @property 99 | def _as_parameter_(self): 100 | return self.coeff 101 | 102 | @staticmethod 103 | def from_param(argument): 104 | assert isinstance(argument, PyCoeff) 105 | return argument 106 | 107 | def __repr__(self): 108 | return '{}'.format(self.coeff.contents) 109 | 110 | def __lt__(self, other: 'PyCoeff'): 111 | assert isinstance(other, PyCoeff) 112 | return libapron.ap_coeff_cmp(self, other) == -1 113 | 114 | def __le__(self, other: 'PyCoeff'): 115 | assert isinstance(other, PyCoeff) 116 | return self.__lt__(other) or self.__eq__(other) 117 | 118 | def __eq__(self, other: 'PyCoeff'): 119 | assert isinstance(other, PyCoeff) 120 | return libapron.ap_coeff_cmp(self, other) == 0 121 | 122 | def __ne__(self, other: 'PyCoeff'): 123 | assert isinstance(other, PyCoeff) 124 | return not self.__eq__(other) 125 | 126 | def __ge__(self, other: 'PyCoeff'): 127 | assert isinstance(other, PyCoeff) 128 | return self.__gt__(other) or self.__eq__(other) 129 | 130 | def __gt__(self, other: 'PyCoeff'): 131 | assert isinstance(other, PyCoeff) 132 | return libapron.ap_coeff_cmp(self, other) == 1 133 | 134 | def __neg__(self) -> 'PyCoeff': 135 | if self.coeff.contents.discr == CoeffDiscr.AP_COEFF_INTERVAL: 136 | coeff = type(self)(0, 0) 137 | else: # self.coeff.contents.discr == CoefficientDiscr.AP_COEFF_SCALAR 138 | coeff = type(self)(0) 139 | libapron.ap_coeff_neg(coeff, self) 140 | return coeff 141 | 142 | 143 | libapron.ap_coeff_alloc.argtypes = [c_uint] 144 | libapron.ap_coeff_alloc.restype = POINTER(Coeff) 145 | libapron.ap_coeff_set.argtypes = [POINTER(Coeff), POINTER(Coeff)] 146 | libapron.ap_coeff_set_scalar.argtypes = [PyCoeff, PyScalar] 147 | libapron.ap_coeff_set_interval.argtypes = [PyCoeff, PyInterval] 148 | libapron.ap_coeff_cmp.argtypes = [PyCoeff, PyCoeff] 149 | libapron.ap_coeff_neg.argtypes = [PyCoeff, PyCoeff] 150 | 151 | 152 | class PyScalarCoeff(PyCoeff, metaclass=ABCMeta): 153 | 154 | def __init__(self, scalar: PyScalar): 155 | super().__init__(discr=CoeffDiscr.AP_COEFF_SCALAR, value=scalar) 156 | 157 | 158 | class PyDoubleScalarCoeff(PyScalarCoeff): 159 | 160 | def __init__(self, value=0.0): 161 | if isinstance(value, (Coeff, PyDoubleScalar)): 162 | super().__init__(value) 163 | else: 164 | super().__init__(PyDoubleScalar(value)) 165 | 166 | 167 | class PyMPQScalarCoeff(PyScalarCoeff): 168 | 169 | def __init__(self, value_or_numerator=0, denumerator=1): 170 | if isinstance(value_or_numerator, (Coeff, PyMPQScalar)): 171 | super().__init__(value_or_numerator) 172 | else: 173 | super().__init__(PyMPQScalar(value_or_numerator, denumerator)) 174 | 175 | 176 | class PyMPFRScalarCoeff(PyScalarCoeff): 177 | 178 | def __init__(self, value, rounding: Rnd = Rnd.MPFR_RNDN): 179 | if isinstance(value, (Coeff, PyMPFRScalar)): 180 | super().__init__(value) 181 | else: 182 | super().__init__(PyMPFRScalar(value, rounding)) 183 | 184 | 185 | class PyIntervalCoeff(PyCoeff, metaclass=ABCMeta): 186 | 187 | def __init__(self, interval: PyInterval): 188 | super().__init__(discr=CoeffDiscr.AP_COEFF_INTERVAL, value=interval) 189 | 190 | 191 | class PyDoubleIntervalCoeff(PyIntervalCoeff): 192 | 193 | def __init__(self, value_or_inf=0.0, sup=0.0): 194 | if isinstance(value_or_inf, (Coeff, PyDoubleInterval)): 195 | super().__init__(value_or_inf) 196 | else: 197 | super().__init__(PyDoubleInterval(value_or_inf, sup)) 198 | 199 | 200 | class PyMPQIntervalCoeff(PyIntervalCoeff): 201 | 202 | def __init__(self, value_or_inf_num=0, sup_num=0, inf_den=1, sup_den=1): 203 | if isinstance(value_or_inf_num, (Coeff, PyMPQInterval)): 204 | super().__init__(value_or_inf_num) 205 | else: 206 | super().__init__(PyMPQInterval(value_or_inf_num, sup_num, inf_den, sup_den)) 207 | 208 | 209 | class PyMPFRIntervalCoeff(PyIntervalCoeff): 210 | 211 | def __init__(self, value_or_inf, sup=None, rounding: Rnd = Rnd.MPFR_RNDN): 212 | if isinstance(value_or_inf, (Coeff, PyMPFRInterval)): 213 | super().__init__(value_or_inf) 214 | else: 215 | super().__init__(PyMPFRInterval(value_or_inf, sup, rounding)) 216 | -------------------------------------------------------------------------------- /tests/test_scalar.py: -------------------------------------------------------------------------------- 1 | """ 2 | APRON Scalar Numbers - Unit Tests 3 | ================================= 4 | 5 | :Author: Caterina Urban 6 | """ 7 | import unittest 8 | from copy import deepcopy 9 | from ctypes import c_double 10 | 11 | from apronpy.mpfr import PyMPFR 12 | from apronpy.mpq import PyMPQ 13 | from apronpy.scalar import PyDoubleScalar, PyMPQScalar, PyMPFRScalar 14 | 15 | 16 | class TestPyDoubleScalar(unittest.TestCase): 17 | 18 | def test_init(self): 19 | self.assertEqual(str(PyDoubleScalar()), '0.0') 20 | self.assertEqual(str(PyDoubleScalar(0)), '0.0') 21 | self.assertEqual(str(PyDoubleScalar(0.0)), '0.0') 22 | self.assertEqual(str(PyDoubleScalar(c_double(0))), '0.0') 23 | self.assertEqual(str(PyDoubleScalar(c_double(0.0))), '0.0') 24 | self.assertEqual(str(PyDoubleScalar(-9)), '-9.0') 25 | self.assertEqual(str(PyDoubleScalar(c_double(-9))), '-9.0') 26 | self.assertEqual(str(PyDoubleScalar(9)), '9.0') 27 | self.assertEqual(str(PyDoubleScalar(c_double(9))), '9.0') 28 | self.assertEqual(str(PyDoubleScalar(0.5)), '0.5') 29 | self.assertEqual(str(PyDoubleScalar(c_double(0.5))), '0.5') 30 | self.assertEqual(str(PyDoubleScalar.init_infty(-9)), '-inf') 31 | self.assertEqual(str(PyDoubleScalar.init_infty(0)), '0.0') 32 | self.assertEqual(str(PyDoubleScalar.init_infty(9)), 'inf') 33 | 34 | def test_infty(self): 35 | self.assertEqual(PyDoubleScalar(9).infty(), 0) 36 | self.assertEqual(PyDoubleScalar.init_infty(-9).infty(), -1) 37 | self.assertEqual(PyDoubleScalar.init_infty(0).infty(), 0) 38 | self.assertEqual(PyDoubleScalar.init_infty(9).infty(), 1) 39 | 40 | def test_deepcopy(self): 41 | s0 = PyDoubleScalar(9) 42 | s1 = deepcopy(s0) 43 | s2 = s0 44 | self.assertNotEqual(id(s0), id(s1)) 45 | self.assertEqual(id(s0), id(s2)) 46 | 47 | def test_cmp(self): 48 | self.assertTrue(PyDoubleScalar(0.5) < PyDoubleScalar(9)) 49 | self.assertTrue(PyDoubleScalar(9) == PyDoubleScalar(9)) 50 | self.assertTrue(PyDoubleScalar(9) > PyDoubleScalar(0.5)) 51 | 52 | def test_sign(self): 53 | self.assertEqual(PyDoubleScalar(-9).sign(), -1) 54 | self.assertEqual(PyDoubleScalar(c_double(-9)).sign(), -1) 55 | self.assertEqual(PyDoubleScalar(9).sign(), 1) 56 | self.assertEqual(PyDoubleScalar(c_double(9)).sign(), 1) 57 | self.assertEqual(PyDoubleScalar(0).sign(), 0) 58 | self.assertEqual(PyDoubleScalar(c_double(0)).sign(), 0) 59 | self.assertEqual(PyDoubleScalar.init_infty(-9).sign(), -1) 60 | self.assertEqual(PyDoubleScalar.init_infty(0).sign(), 0) 61 | self.assertEqual(PyDoubleScalar.init_infty(9).sign(), 1) 62 | 63 | def test_neg(self): 64 | self.assertEqual(-PyDoubleScalar(-9), PyDoubleScalar(9)) 65 | self.assertEqual(-PyDoubleScalar(c_double(-9)), PyDoubleScalar(c_double(9))) 66 | self.assertEqual(-PyDoubleScalar(9), PyDoubleScalar(-9)) 67 | self.assertEqual(-PyDoubleScalar(c_double(9)), PyDoubleScalar(c_double(-9))) 68 | self.assertEqual(-PyDoubleScalar(0), PyDoubleScalar(0)) 69 | self.assertEqual(-PyDoubleScalar(c_double(0)), PyDoubleScalar(c_double(0))) 70 | self.assertEqual(-PyDoubleScalar.init_infty(-9), PyDoubleScalar.init_infty(9)) 71 | self.assertEqual(-PyDoubleScalar.init_infty(0), PyDoubleScalar.init_infty(0)) 72 | self.assertEqual(-PyDoubleScalar.init_infty(9), PyDoubleScalar.init_infty(-9)) 73 | 74 | 75 | class TestPyMPQScalar(unittest.TestCase): 76 | 77 | def test_initialization(self): 78 | self.assertEqual(str(PyMPQScalar()), '0') 79 | self.assertEqual(str(PyMPQScalar(0)), '0') 80 | self.assertEqual(str(PyMPQScalar(0, 1)), '0') 81 | self.assertEqual(str(PyMPQScalar(PyMPQ(0))), '0') 82 | self.assertEqual(str(PyMPQScalar(PyMPQ(0, 1))), '0') 83 | self.assertEqual(str(PyMPQScalar(-9)), '-9') 84 | self.assertEqual(str(PyMPQScalar(PyMPQ(-9))), '-9') 85 | self.assertEqual(str(PyMPQScalar(9)), '9') 86 | self.assertEqual(str(PyMPQScalar(PyMPQ(9))), '9') 87 | self.assertEqual(str(PyMPQScalar(1, 2)), '1/2') 88 | self.assertEqual(str(PyMPQScalar(PyMPQ(1, 2))), '1/2') 89 | self.assertEqual(str(PyMPQScalar.init_infty(-9)), '-9/0') 90 | self.assertEqual(str(PyMPQScalar.init_infty(0)), '0') 91 | self.assertEqual(str(PyMPQScalar.init_infty(9)), '9/0') 92 | 93 | def test_infty(self): 94 | self.assertEqual(PyMPQScalar(9).infty(), 0) 95 | self.assertEqual(PyMPQScalar.init_infty(-9).infty(), -1) 96 | self.assertEqual(PyMPQScalar.init_infty(0).infty(), 0) 97 | self.assertEqual(PyMPQScalar.init_infty(9).infty(), 1) 98 | 99 | def test_deepcopy(self): 100 | s0 = PyMPQScalar(9) 101 | s1 = deepcopy(s0) 102 | s2 = s0 103 | self.assertNotEqual(id(s0), id(s1)) 104 | self.assertEqual(id(s0), id(s2)) 105 | 106 | def test_cmp(self): 107 | self.assertTrue(PyMPQScalar(1, 2) < PyMPQScalar(9)) 108 | self.assertTrue(PyMPQScalar(9) == PyMPQScalar(9)) 109 | self.assertTrue(PyMPQScalar(9) > PyMPQScalar(1, 2)) 110 | 111 | def test_sign(self): 112 | self.assertEqual(PyMPQScalar(-9).sign(), -1) 113 | self.assertEqual(PyMPQScalar(PyMPQ(-9)).sign(), -1) 114 | self.assertEqual(PyMPQScalar(9).sign(), 1) 115 | self.assertEqual(PyMPQScalar(PyMPQ(9)).sign(), 1) 116 | self.assertEqual(PyMPQScalar(0).sign(), 0) 117 | self.assertEqual(PyMPQScalar(PyMPQ(0)).sign(), 0) 118 | self.assertEqual(PyMPQScalar.init_infty(-9).sign(), -1) 119 | self.assertEqual(PyMPQScalar.init_infty(0).sign(), 0) 120 | self.assertEqual(PyMPQScalar.init_infty(9).sign(), 1) 121 | 122 | 123 | class TestPyMPFRScalar(unittest.TestCase): 124 | 125 | def test_init(self): 126 | self.assertEqual(str(PyMPFRScalar(0)), '0.0') 127 | self.assertEqual(str(PyMPFRScalar(0.0)), '0.0') 128 | self.assertEqual(str(PyMPFRScalar(PyMPFR(0))), '0.0') 129 | self.assertEqual(str(PyMPFRScalar(PyMPFR(0.0))), '0.0') 130 | self.assertEqual(str(PyMPFRScalar(-9)), '-9.0') 131 | self.assertEqual(str(PyMPFRScalar(PyMPFR(-9))), '-9.0') 132 | self.assertEqual(str(PyMPFRScalar(9)), '9.0') 133 | self.assertEqual(str(PyMPFRScalar(PyMPFR(9))), '9.0') 134 | self.assertEqual(str(PyMPFRScalar(0.5)), '0.5') 135 | self.assertEqual(str(PyMPFRScalar(PyMPFR(0.5))), '0.5') 136 | self.assertEqual(str(PyMPFRScalar.init_infty(-9)), '-inf') 137 | self.assertEqual(str(PyMPFRScalar.init_infty(0)), 'inf') # ! 138 | self.assertEqual(str(PyMPFRScalar.init_infty(9)), 'inf') 139 | 140 | def test_infty(self): 141 | self.assertEqual(PyMPFRScalar(9).infty(), 0) 142 | self.assertEqual(PyMPFRScalar.init_infty(-9).infty(), -1) 143 | self.assertEqual(PyMPFRScalar.init_infty(0).infty(), 1) # ! 144 | self.assertEqual(PyMPFRScalar.init_infty(9).infty(), 1) 145 | 146 | def test_deepcopy(self): 147 | s0 = PyMPFRScalar(9) 148 | s1 = deepcopy(s0) 149 | s2 = s0 150 | self.assertNotEqual(id(s0), id(s1)) 151 | self.assertEqual(id(s0), id(s2)) 152 | 153 | def test_cmp(self): 154 | self.assertTrue(PyMPFRScalar(0.5) < PyMPFRScalar(9)) 155 | self.assertTrue(PyMPFRScalar(9) == PyMPFRScalar(9)) 156 | self.assertTrue(PyMPFRScalar(9) > PyMPFRScalar(0.5)) 157 | 158 | def test_sign(self): 159 | self.assertEqual(PyMPFRScalar(-9).sign(), -1) 160 | self.assertEqual(PyMPFRScalar(PyMPFR(-9)).sign(), -1) 161 | self.assertEqual(PyMPFRScalar(9).sign(), 1) 162 | self.assertEqual(PyMPFRScalar(PyMPFR(9)).sign(), 1) 163 | self.assertEqual(PyMPFRScalar(0).sign(), 0) 164 | self.assertEqual(PyMPFRScalar(PyMPFR(0)).sign(), 0) 165 | self.assertEqual(PyMPFRScalar.init_infty(-9).sign(), -1) 166 | self.assertEqual(PyMPFRScalar.init_infty(0).sign(), 1) # ! 167 | self.assertEqual(PyMPFRScalar.init_infty(9).sign(), 1) 168 | 169 | def test_neg(self): 170 | self.assertEqual(-PyMPFRScalar(-9), PyMPFRScalar(9)) 171 | self.assertEqual(-PyMPFRScalar(PyMPFR(-9)), PyMPFRScalar(PyMPFR(9))) 172 | self.assertEqual(-PyMPFRScalar(9), PyMPFRScalar(-9)) 173 | self.assertEqual(-PyMPFRScalar(PyMPFR(9)), PyMPFRScalar(PyMPFR(-9))) 174 | self.assertEqual(-PyMPFRScalar(0), PyMPFRScalar(0)) 175 | self.assertEqual(-PyMPFRScalar(PyMPFR(0)), PyMPFRScalar(PyMPFR(0))) 176 | self.assertEqual(-PyMPFRScalar.init_infty(-9), PyMPFRScalar.init_infty(9)) 177 | self.assertNotEqual(-PyMPFRScalar.init_infty(0), PyMPFRScalar.init_infty(0)) # ! 178 | self.assertEqual(-PyMPFRScalar.init_infty(9), PyMPFRScalar.init_infty(-9)) 179 | 180 | 181 | if __name__ == '__main__': 182 | unittest.main() 183 | -------------------------------------------------------------------------------- /apronpy/environment.py: -------------------------------------------------------------------------------- 1 | """ 2 | APRON Environments 3 | ================== 4 | 5 | :Author: Caterina Urban 6 | """ 7 | from _ctypes import Structure, POINTER, byref 8 | from ctypes import c_size_t, c_char_p 9 | from typing import List, Type, Union 10 | 11 | from apronpy.cdll import libapron 12 | from apronpy.dimension import Dim, AP_DIM_MAX, DimChange, DimPerm 13 | from apronpy.var import PyVar 14 | 15 | 16 | class Environment(Structure): 17 | """ 18 | typedef struct ap_environment_t { 19 | ap_var_t* var_of_dim; 20 | /* 21 | Array of size intdim+realdim, indexed by dimensions. 22 | - It should not contain identical strings.. 23 | - Slice [0..intdim-1] is lexicographically sorted, 24 | and denotes integer variables. 25 | - Slice [intdim..intdim+realdim-1] is lexicographically sorted, 26 | and denotes real variables. 27 | - The memory allocated for the variables are attached to the structure 28 | (they are freed when the structure is no longer in use) 29 | */ 30 | size_t intdim; /* Number of integer variables */ 31 | size_t realdim;/* Number of real variables */ 32 | size_t count; /* For reference counting */ 33 | } ap_environment_t; 34 | """ 35 | 36 | _fields_ = [ 37 | ('var_of_dim', POINTER(c_char_p)), 38 | ('intdim', c_size_t), 39 | ('realdim', c_size_t), 40 | ('count', c_size_t) 41 | ] 42 | 43 | def __repr__(self): 44 | result = '{' 45 | result += ','.join(self.var_of_dim[i].decode('utf-8') for i in range(self.intdim)) 46 | result += '|' 47 | result += ','.join( 48 | self.var_of_dim[self.intdim+i].decode('utf-8') for i in range(self.realdim) 49 | ) 50 | result += '}' 51 | return result 52 | 53 | 54 | class PyEnvironment: 55 | 56 | # noinspection PyTypeChecker 57 | def __init__(self, environment_or_int_vars: Union[POINTER(Environment), List[PyVar]] = None, 58 | real_vars: List[PyVar] = None): 59 | if isinstance(environment_or_int_vars, POINTER(Environment)): 60 | self.environment = environment_or_int_vars 61 | else: 62 | if environment_or_int_vars: 63 | int_size = len(environment_or_int_vars) 64 | typ: Type = c_char_p * int_size 65 | int_arr = typ(*(x._as_parameter_ for x in environment_or_int_vars)) 66 | else: 67 | int_size = 0 68 | int_arr = None 69 | if real_vars: 70 | real_size = len(real_vars) 71 | typ: Type = c_char_p * real_size 72 | real_arr = typ(*(x._as_parameter_ for x in real_vars)) 73 | else: 74 | real_size = 0 75 | real_arr = None 76 | environment = libapron.ap_environment_alloc(int_arr, int_size, real_arr, real_size) 77 | self.environment = environment 78 | if not self.environment: 79 | raise ValueError('clashing variable names') 80 | 81 | def __deepcopy__(self, memodict=None): 82 | if memodict is None: 83 | memodict = {} 84 | self.environment.contents.count += 1 85 | memodict[id(self)] = self 86 | return self 87 | 88 | def __del__(self): 89 | if self.environment: 90 | if self.environment.contents.count <= 1: 91 | libapron.ap_environment_free2(self) 92 | del self.environment 93 | else: 94 | self.environment.contents.count -= 1 95 | 96 | @property 97 | def _as_parameter_(self): 98 | return self.environment 99 | 100 | @staticmethod 101 | def from_param(argument): 102 | assert isinstance(argument, PyEnvironment) 103 | return argument 104 | 105 | # noinspection PyTypeChecker 106 | def add(self, int_vars: List[PyVar] = None, real_vars: List[PyVar] = None): 107 | if int_vars: 108 | i_size = len(int_vars) 109 | typ: Type = c_char_p * i_size 110 | int_arr = typ(*(x._as_parameter_ for x in int_vars)) 111 | else: 112 | i_size = 0 113 | int_arr = None 114 | if real_vars: 115 | r_size = len(real_vars) 116 | typ: Type = c_char_p * r_size 117 | real_arr = typ(*(x._as_parameter_ for x in real_vars)) 118 | else: 119 | r_size = 0 120 | real_arr = None 121 | self.environment = libapron.ap_environment_add(self, int_arr, i_size, real_arr, r_size) 122 | if not self.environment: 123 | raise ValueError('clashing variable names') 124 | return self 125 | 126 | # noinspection PyTypeChecker 127 | def rename(self, old_vars: List[PyVar], new_vars: List[PyVar]): 128 | o_size = len(old_vars) 129 | n_size = len(new_vars) 130 | assert o_size == n_size 131 | old_typ: Type = c_char_p * o_size 132 | old_arr = old_typ(*(x._as_parameter_ for x in old_vars)) 133 | new_typ: Type = c_char_p * o_size 134 | new_arr = new_typ(*(x._as_parameter_ for x in new_vars)) 135 | p = DimPerm() 136 | self.environment = libapron.ap_environment_rename(self, old_arr, new_arr, o_size, p) 137 | if not self.environment: 138 | raise ValueError('invalid renaming') 139 | return self 140 | 141 | # noinspection PyTypeChecker 142 | def remove(self, del_vars: List[PyVar] = None): 143 | if del_vars: 144 | size = len(del_vars) 145 | typ: Type = c_char_p * size 146 | arr = typ(*(x._as_parameter_ for x in del_vars)) 147 | else: 148 | size = 0 149 | arr = None 150 | self.environment = libapron.ap_environment_remove(self, arr, size) 151 | if not self.environment: 152 | raise ValueError('non-existing variable(s)') 153 | return self 154 | 155 | def __repr__(self): 156 | return str(self.environment.contents) 157 | 158 | def __len__(self): 159 | return self.environment.contents.intdim + self.environment.contents.realdim 160 | 161 | def __contains__(self, item: 'PyVar'): 162 | assert isinstance(item, PyVar) 163 | return libapron.ap_environment_dim_of_var(self, item) != AP_DIM_MAX 164 | 165 | def __lt__(self, other: 'PyEnvironment'): 166 | assert isinstance(other, PyEnvironment) 167 | return libapron.ap_environment_compare(self, other) == -1 168 | 169 | def __le__(self, other: 'PyEnvironment'): 170 | assert isinstance(other, PyEnvironment) 171 | return self.__lt__(other) or self.__eq__(other) 172 | 173 | def __eq__(self, other: 'PyEnvironment'): 174 | assert isinstance(other, PyEnvironment) 175 | return libapron.ap_environment_compare(self, other) == 0 176 | 177 | def __ne__(self, other: 'PyEnvironment'): 178 | assert isinstance(other, PyEnvironment) 179 | return not self.__eq__(other) 180 | 181 | def __ge__(self, other: 'PyEnvironment'): 182 | assert isinstance(other, PyEnvironment) 183 | return self.__gt__(other) or self.__eq__(other) 184 | 185 | def __gt__(self, other: 'PyEnvironment'): 186 | assert isinstance(other, PyEnvironment) 187 | return libapron.ap_environment_compare(self, other) == 1 188 | 189 | def __or__(self, other: 'PyEnvironment') -> 'PyEnvironment': 190 | assert isinstance(other, PyEnvironment) 191 | d1 = DimChange() 192 | d2 = DimChange() 193 | environment = libapron.ap_environment_lce(self, other, byref(d1), byref(d2)) 194 | if not environment: 195 | raise ValueError('incompatible environments') 196 | return PyEnvironment(environment) 197 | 198 | def union(self, other: 'PyEnvironment') -> 'PyEnvironment': 199 | assert isinstance(other, PyEnvironment) 200 | return self.__or__(other) 201 | 202 | 203 | pyvar_p = POINTER(c_char_p) 204 | libapron.ap_environment_alloc_empty.restype = POINTER(Environment) 205 | libapron.ap_environment_alloc.argtypes = [pyvar_p, c_size_t, pyvar_p, c_size_t] 206 | libapron.ap_environment_alloc.restype = POINTER(Environment) 207 | libapron.ap_environment_add.argtypes = [PyEnvironment, pyvar_p, c_size_t, pyvar_p, c_size_t] 208 | libapron.ap_environment_add.restype = POINTER(Environment) 209 | libapron.ap_environment_remove.argtypes = [PyEnvironment, pyvar_p, c_size_t] 210 | libapron.ap_environment_remove.restype = POINTER(Environment) 211 | libapron.ap_environment_compare.argtypes = [PyEnvironment, PyEnvironment] 212 | libapron.ap_environment_dim_of_var.argtypes = [PyEnvironment, PyVar] 213 | libapron.ap_environment_dim_of_var.restype = Dim 214 | dimchange_p = POINTER(DimChange) 215 | libapron.ap_environment_lce.argtypes = [PyEnvironment, PyEnvironment, dimchange_p, dimchange_p] 216 | libapron.ap_environment_lce.restype = POINTER(Environment) 217 | dimperm_p = POINTER(DimPerm) 218 | libapron.ap_environment_rename.argtypes = [PyEnvironment, pyvar_p, pyvar_p, c_size_t, dimperm_p] 219 | libapron.ap_environment_rename.restype = POINTER(Environment) 220 | -------------------------------------------------------------------------------- /apronpy/manager.py: -------------------------------------------------------------------------------- 1 | """ 2 | APRON Manager 3 | 4 | :Author: Caterina Urban 5 | """ 6 | from _ctypes import Structure, POINTER 7 | from abc import ABCMeta 8 | from ctypes import c_char_p, c_void_p, CFUNCTYPE, c_size_t, c_int, c_bool, c_uint 9 | from enum import IntEnum 10 | 11 | from apronpy.cdll import libapron 12 | 13 | 14 | class FunId(IntEnum): 15 | """ 16 | typedef enum ap_funid_t { 17 | AP_FUNID_UNKNOWN, 18 | AP_FUNID_COPY, 19 | AP_FUNID_FREE, 20 | AP_FUNID_ASIZE, /* For avoiding name conflict with AP_FUNID_SIZE */ 21 | AP_FUNID_MINIMIZE, 22 | AP_FUNID_CANONICALIZE, 23 | AP_FUNID_HASH, 24 | AP_FUNID_APPROXIMATE, 25 | AP_FUNID_FPRINT, 26 | AP_FUNID_FPRINTDIFF, 27 | AP_FUNID_FDUMP, 28 | AP_FUNID_SERIALIZE_RAW, 29 | AP_FUNID_DESERIALIZE_RAW, 30 | AP_FUNID_BOTTOM, 31 | AP_FUNID_TOP, 32 | AP_FUNID_OF_BOX, 33 | AP_FUNID_DIMENSION, 34 | AP_FUNID_IS_BOTTOM, 35 | AP_FUNID_IS_TOP, 36 | AP_FUNID_IS_LEQ, 37 | AP_FUNID_IS_EQ, 38 | AP_FUNID_IS_DIMENSION_UNCONSTRAINED, 39 | AP_FUNID_SAT_INTERVAL, 40 | AP_FUNID_SAT_LINCONS, 41 | AP_FUNID_SAT_TCONS, 42 | AP_FUNID_BOUND_DIMENSION, 43 | AP_FUNID_BOUND_LINEXPR, 44 | AP_FUNID_BOUND_TEXPR, 45 | AP_FUNID_TO_BOX, 46 | AP_FUNID_TO_LINCONS_ARRAY, 47 | AP_FUNID_TO_TCONS_ARRAY, 48 | AP_FUNID_TO_GENERATOR_ARRAY, 49 | AP_FUNID_MEET, 50 | AP_FUNID_MEET_ARRAY, 51 | AP_FUNID_MEET_LINCONS_ARRAY, 52 | AP_FUNID_MEET_TCONS_ARRAY, 53 | AP_FUNID_JOIN, 54 | AP_FUNID_JOIN_ARRAY, 55 | AP_FUNID_ADD_RAY_ARRAY, 56 | AP_FUNID_ASSIGN_LINEXPR_ARRAY, 57 | AP_FUNID_SUBSTITUTE_LINEXPR_ARRAY, 58 | AP_FUNID_ASSIGN_TEXPR_ARRAY, 59 | AP_FUNID_SUBSTITUTE_TEXPR_ARRAY, 60 | AP_FUNID_ADD_DIMENSIONS, 61 | AP_FUNID_REMOVE_DIMENSIONS, 62 | AP_FUNID_PERMUTE_DIMENSIONS, 63 | AP_FUNID_FORGET_ARRAY, 64 | AP_FUNID_EXPAND, 65 | AP_FUNID_FOLD, 66 | AP_FUNID_WIDENING, 67 | AP_FUNID_CLOSURE, 68 | AP_FUNID_SIZE, 69 | AP_FUNID_CHANGE_ENVIRONMENT, 70 | AP_FUNID_RENAME_ARRAY, 71 | AP_FUNID_SIZE2 72 | } ap_funid_t; 73 | """ 74 | AP_FUNID_UNKNOWN = 0 75 | AP_FUNID_COPY = 1 76 | AP_FUNID_FREE = 2 77 | AP_FUNID_ASIZE = 3 78 | AP_FUNID_MINIMIZE = 4 79 | AP_FUNID_CANONICALIZE = 5 80 | AP_FUNID_HASH = 6 81 | AP_FUNID_APPROXIMATE = 7 82 | AP_FUNID_FPRINT = 8 83 | AP_FUNID_FPRINTDIFF = 9 84 | AP_FUNID_FDUMP = 10 85 | AP_FUNID_SERIALIZE_RAW = 11 86 | AP_FUNID_DESERIALIZE_RAW = 12 87 | AP_FUNID_BOTTOM = 13 88 | AP_FUNID_TOP = 14 89 | AP_FUNID_OF_BOX = 15 90 | AP_FUNID_DIMENSION = 16 91 | AP_FUNID_IS_BOTTOM = 17 92 | AP_FUNID_IS_TOP = 18 93 | AP_FUNID_IS_LEQ = 19 94 | AP_FUNID_IS_EQ = 20 95 | AP_FUNID_IS_DIMENSION_UNCONSTRAINED = 21 96 | AP_FUNID_SAT_INTERVAL = 22 97 | AP_FUNID_SAT_LINCONS = 23 98 | AP_FUNID_SAT_TCONS = 24 99 | AP_FUNID_BOUND_DIMENSION = 25 100 | AP_FUNID_BOUND_LINEXPR = 26 101 | AP_FUNID_BOUND_TEXPR = 27 102 | AP_FUNID_TO_BOX = 28 103 | AP_FUNID_TO_LINCONS_ARRAY = 29 104 | AP_FUNID_TO_TCONS_ARRAY = 30 105 | AP_FUNID_TO_GENERATOR_ARRAY = 31 106 | AP_FUNID_MEET = 32 107 | AP_FUNID_MEET_ARRAY = 33 108 | AP_FUNID_MEET_LINCONS_ARRAY = 34 109 | AP_FUNID_MEET_TCONS_ARRAY = 35 110 | AP_FUNID_JOIN = 36 111 | AP_FUNID_JOIN_ARRAY = 37 112 | AP_FUNID_ADD_RAY_ARRAY = 38 113 | AP_FUNID_ASSIGN_LINEXPR_ARRAY = 39 114 | AP_FUNID_SUBSTITUTE_LINEXPR_ARRAY = 40 115 | AP_FUNID_ASSIGN_TEXPR_ARRAY = 41 116 | AP_FUNID_SUBSTITUTE_TEXPR_ARRAY = 42 117 | AP_FUNID_ADD_DIMENSIONS = 43 118 | AP_FUNID_REMOVE_DIMENSIONS = 44 119 | AP_FUNID_PERMUTE_DIMENSIONS = 45 120 | AP_FUNID_FORGET_ARRAY = 46 121 | AP_FUNID_EXPAND = 47 122 | AP_FUNID_FOLD = 48 123 | AP_FUNID_WIDENING = 49 124 | AP_FUNID_CLOSURE = 50 125 | AP_FUNID_SIZE = 51 126 | AP_FUNID_CHANGE_ENVIRONMENT = 52 127 | AP_FUNID_RENAME_ARRAY = 53 128 | AP_FUNID_SIZE2 = 54 129 | 130 | 131 | class Exc(IntEnum): 132 | """ 133 | typedef enum ap_exc_t { 134 | AP_EXC_NONE, /* no exception detected */ 135 | AP_EXC_TIMEOUT, /* timeout detected */ 136 | AP_EXC_OUT_OF_SPACE, /* out of space detected */ 137 | AP_EXC_OVERFLOW, /* magnitude overflow detected */ 138 | AP_EXC_INVALID_ARGUMENT, /* invalid arguments */ 139 | AP_EXC_NOT_IMPLEMENTED, /* not implemented */ 140 | AP_EXC_SIZE 141 | } ap_exc_t; 142 | """ 143 | AP_EXC_NONE = 0 144 | AP_EXC_TIMEOUT = 1 145 | AP_EXC_OUT_OF_SPACE = 2 146 | AP_EXC_OVERFLOW = 3 147 | AP_EXC_INVALID_ARGUMENT = 4 148 | AP_EXC_NOT_IMPLEMENTED = 5 149 | AP_EXC_SIZE = 6 150 | 151 | 152 | class ExcLog(Structure): 153 | """ 154 | typedef struct ap_exclog_t { 155 | ap_exc_t exn; 156 | ap_funid_t funid; 157 | char* msg; /* dynamically allocated */ 158 | struct ap_exclog_t* tail; 159 | } ap_exclog_t; 160 | """ 161 | pass 162 | 163 | 164 | ExcLog._fields_ = [ 165 | ('exn', c_uint), 166 | ('funid', c_uint), 167 | ('msg', c_char_p), 168 | ('tail', POINTER(ExcLog)) 169 | ] 170 | 171 | 172 | class Result(Structure): 173 | """ 174 | typedef struct ap_result_t { 175 | ap_exclog_t* exclog; /* history of exceptions */ 176 | ap_exc_t exn; /* exception for the last called function */ 177 | bool flag_exact; /* result is mathematically exact or don't know */ 178 | bool flag_best; /* result is best correct approximation or don't know */ 179 | } ap_result_t; 180 | """ 181 | 182 | _fields_ = [ 183 | ('exclog', POINTER(ExcLog)), 184 | ('exn', c_uint), 185 | ('flag_exact', c_bool), 186 | ('flag_best', c_bool) 187 | ] 188 | 189 | 190 | class FunOpt(Structure): 191 | """ 192 | typedef struct ap_funopt_t { 193 | int algorithm; 194 | /* Algorithm selection: 195 | - 0 is default algorithm; 196 | - MAX_INT is most accurate available; 197 | - MIN_INT is most efficient available; 198 | - otherwise, no accuracy or speed meaning 199 | */ 200 | size_t timeout; /* unit !? */ 201 | /* Above the given computation time, the function may abort with the 202 | exception flag flag_time_out on. 203 | */ 204 | size_t max_object_size; /* in abstract object size unit. */ 205 | /* If during the computation, the size of some object reach this limit, the 206 | function may abort with the exception flag flag_out_of_space on. 207 | */ 208 | bool flag_exact_wanted; 209 | /* return information about exactitude if possible 210 | */ 211 | bool flag_best_wanted; 212 | /* return information about best correct approximation if possible 213 | */ 214 | } ap_funopt_t; 215 | """ 216 | 217 | _fields_ = [ 218 | ('algorithm', c_int), 219 | ('timeout', c_size_t), 220 | ('max_object_size', c_size_t), 221 | ('flag_exact_wanted', c_bool), 222 | ('flag_best_wanted', c_bool) 223 | ] 224 | 225 | 226 | # noinspection PyTypeChecker 227 | class Option(Structure): 228 | """ 229 | typedef struct ap_option_t { 230 | ap_funopt_t funopt[AP_FUNID_SIZE]; 231 | bool abort_if_exception[AP_EXC_SIZE]; 232 | ap_scalar_discr_t scalar_discr; /* Preferred type for scalars */ 233 | } ap_option_t; 234 | """ 235 | 236 | _fields_ = [ 237 | ('funopt', FunOpt * FunId.AP_FUNID_SIZE), 238 | ('abort_if_exception', c_bool * Exc.AP_EXC_SIZE), 239 | ('scalar_discr', c_uint) 240 | ] 241 | 242 | 243 | # noinspection PyTypeChecker 244 | class Manager(Structure): 245 | """ 246 | typedef struct ap_manager_t { 247 | const char* library; /* name of the effective library */ 248 | const char* version; /* version of the effective library */ 249 | void* internal; /* library dependent, 250 | should be different for each thread 251 | (working space) */ 252 | void* funptr[AP_FUNID_SIZE]; /* Array of function pointers, 253 | initialized by the effective library */ 254 | ap_option_t option; /* Options (in) */ 255 | ap_result_t result; /* Exceptions and other indications (out) */ 256 | void (*internal_free)(void*); /* deallocation function for internal */ 257 | size_t count; /* reference counter */ 258 | } ap_manager_t; 259 | """ 260 | 261 | _fields_ = [ 262 | ('library', c_char_p), 263 | ('version', c_char_p), 264 | ('internal', c_void_p), 265 | ('funpts', c_void_p * FunId.AP_FUNID_SIZE), 266 | ('option', Option), 267 | ('result', Result), 268 | ('internal_free', CFUNCTYPE(None, c_void_p)), 269 | ('count', c_size_t) 270 | ] 271 | 272 | 273 | class PyManager(metaclass=ABCMeta): 274 | 275 | def __init__(self, manager: POINTER(Manager)): 276 | self.manager = manager 277 | 278 | def __del__(self): 279 | libapron.ap_manager_free(self) 280 | del self.manager 281 | 282 | @property 283 | def _as_parameter_(self): 284 | return self.manager 285 | 286 | @staticmethod 287 | def from_param(argument): 288 | assert isinstance(argument, PyManager) 289 | return argument 290 | 291 | 292 | libapron.ap_manager_free.argtypes = [POINTER(Manager)] 293 | 294 | -------------------------------------------------------------------------------- /tests/test_box.py: -------------------------------------------------------------------------------- 1 | """ 2 | APRON Boxes - Unit Tests 3 | ======================== 4 | 5 | :Author: Caterina Urban 6 | """ 7 | import unittest 8 | from copy import deepcopy 9 | 10 | from apronpy.box import PyBox, PyBoxDManager, PyBoxMPQManager, PyBoxMPFRManager 11 | from apronpy.environment import PyEnvironment 12 | from apronpy.interval import PyDoubleInterval, PyMPQInterval, PyMPFRInterval 13 | from apronpy.manager import PyManager 14 | from apronpy.texpr0 import TexprOp, TexprRtype, TexprRdir 15 | from apronpy.texpr1 import PyTexpr1 16 | from apronpy.var import PyVar 17 | 18 | 19 | class TestPyDBox(unittest.TestCase): 20 | 21 | def test_bottom(self): 22 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 23 | man: PyManager = PyBoxDManager() 24 | self.assertTrue(PyBox.bottom(man, e).is_bottom()) 25 | b1 = PyBox(man, e, variables=[PyVar('x0')], intervals=[PyDoubleInterval(-2.5, 2.5)]) 26 | self.assertFalse(b1.is_bottom()) 27 | b2 = PyBox(man, e, variables=[PyVar('y')], intervals=[PyMPQInterval(-5, 5, 2, 2)]) 28 | self.assertFalse(b2.is_bottom()) 29 | b3 = PyBox(man, e, variables=[PyVar('z')], intervals=[PyMPFRInterval(-2.5, 2.5)]) 30 | self.assertFalse(b3.is_bottom()) 31 | self.assertFalse(PyBox.top(man, e).is_bottom()) 32 | 33 | def test_default(self): 34 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 35 | man: PyManager = PyBoxDManager() 36 | b1 = PyBox(man, e, variables=[PyVar('x0')], intervals=[PyDoubleInterval(-2.5, 2.5)]) 37 | self.assertFalse(b1.is_bottom()) 38 | self.assertFalse(b1.is_top()) 39 | b2 = PyBox(man, e, variables=[PyVar('y')], intervals=[PyMPQInterval(-5, 5, 2, 2)]) 40 | self.assertFalse(b2.is_bottom()) 41 | self.assertFalse(b2.is_top()) 42 | b3 = PyBox(man, e, variables=[PyVar('z')], intervals=[PyMPFRInterval(-2.5, 2.5)]) 43 | self.assertFalse(b3.is_bottom()) 44 | self.assertFalse(b3.is_top()) 45 | 46 | def test_top(self): 47 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 48 | man: PyManager = PyBoxDManager() 49 | self.assertFalse(PyBox.bottom(man, e).is_top()) 50 | b1 = PyBox(man, e, variables=[PyVar('x0')], intervals=[PyDoubleInterval(-2.5, 2.5)]) 51 | self.assertFalse(b1.is_bottom()) 52 | b2 = PyBox(man, e, variables=[PyVar('y')], intervals=[PyMPQInterval(-5, 5, 2, 2)]) 53 | self.assertFalse(b2.is_bottom()) 54 | b3 = PyBox(man, e, variables=[PyVar('z')], intervals=[PyMPFRInterval(-2.5, 2.5)]) 55 | self.assertFalse(b3.is_bottom()) 56 | self.assertTrue(PyBox.top(man, e).is_top()) 57 | 58 | def test_deepcopy(self): 59 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 60 | man: PyManager = PyBoxDManager() 61 | b0 = PyBox(man, e, variables=[PyVar('x0')], intervals=[PyDoubleInterval(-2.5, 2.5)]) 62 | b1 = deepcopy(b0) 63 | b2 = b0 64 | self.assertNotEqual(id(b0), id(b1)) 65 | self.assertEqual(id(b0), id(b2)) 66 | 67 | def test_meet(self): 68 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 69 | man: PyManager = PyBoxDManager() 70 | b0 = PyBox.bottom(man, e) 71 | b1d = PyBox(man, e, variables=[PyVar('x0')], intervals=[PyDoubleInterval(-2.5, 0.0)]) 72 | b1q = PyBox(man, e, variables=[PyVar('x0')], intervals=[PyMPQInterval(-5, 0, 2, 1)]) 73 | b1f = PyBox(man, e, variables=[PyVar('x0')], intervals=[PyMPFRInterval(-2.5, 0.0)]) 74 | b2d = PyBox(man, e, variables=[PyVar('x0')], intervals=[PyDoubleInterval(0.0, 2.5)]) 75 | b2q = PyBox(man, e, variables=[PyVar('x0')], intervals=[PyMPQInterval(0, 5, 1, 2)]) 76 | b2f = PyBox(man, e, variables=[PyVar('x0')], intervals=[PyMPFRInterval(0.0, 2.5)]) 77 | b3d = PyBox(man, e, variables=[PyVar('x0')], intervals=[PyDoubleInterval(0.0, 0.0)]) 78 | b3q = PyBox(man, e, variables=[PyVar('x0')], intervals=[PyMPQInterval(0, 0, 1, 1)]) 79 | b3f = PyBox(man, e, variables=[PyVar('x0')], intervals=[PyMPFRInterval(0.0, 0.0)]) 80 | b4 = PyBox.top(man, e) 81 | self.assertTrue(b0.meet(b1d) == b0) 82 | self.assertTrue(b0.meet(b1q) == b0) 83 | self.assertTrue(b0.meet(b1f) == b0) 84 | self.assertTrue(b0.meet(b2d) == b0) 85 | self.assertTrue(b0.meet(b2q) == b0) 86 | self.assertTrue(b0.meet(b2f) == b0) 87 | self.assertTrue(b0.meet(b3d) == b0) 88 | self.assertTrue(b0.meet(b3q) == b0) 89 | self.assertTrue(b0.meet(b3f) == b0) 90 | self.assertTrue(b1d.meet(b2d) == b3d) 91 | self.assertTrue(b1d.meet(b3d) == b3d) 92 | self.assertTrue(b2d.meet(b3d) == b3d) 93 | self.assertTrue(b1q.meet(b2q) == b3q) 94 | self.assertTrue(b1q.meet(b3q) == b3q) 95 | self.assertTrue(b2q.meet(b3q) == b3q) 96 | self.assertTrue(b1f.meet(b2f) == b3f) 97 | self.assertTrue(b1f.meet(b3f) == b3f) 98 | self.assertTrue(b2f.meet(b3f) == b3f) 99 | self.assertTrue(b1d.meet(b4) == b1d) 100 | self.assertTrue(b1q.meet(b4) == b1q) 101 | self.assertTrue(b1f.meet(b4) == b1f) 102 | self.assertTrue(b2d.meet(b4) == b2d) 103 | self.assertTrue(b2q.meet(b4) == b2q) 104 | self.assertTrue(b2f.meet(b4) == b2f) 105 | self.assertTrue(b3d.meet(b4) == b3d) 106 | self.assertTrue(b3q.meet(b4) == b3q) 107 | self.assertTrue(b3f.meet(b4) == b3f) 108 | 109 | 110 | class TestPyMPQBox(unittest.TestCase): 111 | 112 | def test_bottom(self): 113 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 114 | man: PyManager = PyBoxMPQManager() 115 | self.assertTrue(PyBox.bottom(man, e).is_bottom()) 116 | b1 = PyBox(man, e, variables=[PyVar('x0')], intervals=[PyDoubleInterval(-2.5, 2.5)]) 117 | self.assertFalse(b1.is_bottom()) 118 | b2 = PyBox(man, e, variables=[PyVar('y')], intervals=[PyMPQInterval(-5, 5, 2, 2)]) 119 | self.assertFalse(b2.is_bottom()) 120 | b3 = PyBox(man, e, variables=[PyVar('z')], intervals=[PyMPFRInterval(-2.5, 2.5)]) 121 | self.assertFalse(b3.is_bottom()) 122 | self.assertFalse(PyBox.top(man, e).is_bottom()) 123 | 124 | def test_default(self): 125 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 126 | man: PyManager = PyBoxMPQManager() 127 | b1 = PyBox(man, e, variables=[PyVar('x0')], intervals=[PyDoubleInterval(-2.5, 2.5)]) 128 | self.assertFalse(b1.is_bottom()) 129 | self.assertFalse(b1.is_top()) 130 | b2 = PyBox(man, e, variables=[PyVar('y')], intervals=[PyMPQInterval(-5, 5, 2, 2)]) 131 | self.assertFalse(b2.is_bottom()) 132 | self.assertFalse(b2.is_top()) 133 | b3 = PyBox(man, e, variables=[PyVar('z')], intervals=[PyMPFRInterval(-2.5, 2.5)]) 134 | self.assertFalse(b3.is_bottom()) 135 | self.assertFalse(b3.is_top()) 136 | 137 | def test_top(self): 138 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 139 | man: PyManager = PyBoxMPQManager() 140 | self.assertFalse(PyBox.bottom(man, e).is_top()) 141 | b1 = PyBox(man, e, variables=[PyVar('x0')], intervals=[PyDoubleInterval(-2.5, 2.5)]) 142 | self.assertFalse(b1.is_bottom()) 143 | b2 = PyBox(man, e, variables=[PyVar('y')], intervals=[PyMPQInterval(-5, 5, 2, 2)]) 144 | self.assertFalse(b2.is_bottom()) 145 | b3 = PyBox(man, e, variables=[PyVar('z')], intervals=[PyMPFRInterval(-2.5, 2.5)]) 146 | self.assertFalse(b3.is_bottom()) 147 | self.assertTrue(PyBox.top(man, e).is_top()) 148 | 149 | def test_bound_variable(self): 150 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 151 | man: PyManager = PyBoxMPQManager() 152 | variables = [PyVar('x0'), PyVar('y')] 153 | intervals = [PyMPQInterval(-3, 2), PyMPQInterval(-2, 2, 1, 1)] 154 | b = PyBox(man, e, variables=variables, intervals=intervals) 155 | self.assertEqual(str(b.bound_variable(PyVar('y'))), '[-2,2]') 156 | 157 | def test_bound_texpr(self): 158 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 159 | man: PyManager = PyBoxMPQManager() 160 | variables = [PyVar('x0'), PyVar('y')] 161 | intervals = [PyMPQInterval(-3, 2), PyMPQInterval(-2, 2, 1, 1)] 162 | b = PyBox(man, e, variables=variables, intervals=intervals) 163 | x0 = PyTexpr1.var(e, PyVar('x0')) 164 | x1 = PyTexpr1.var(e, PyVar('y')) 165 | add = PyTexpr1.binop(TexprOp.AP_TEXPR_ADD, x0, x1, TexprRtype.AP_RTYPE_REAL, TexprRdir.AP_RDIR_RND) 166 | self.assertEqual(str(b.bound_texpr(add)), '[-5,4]') 167 | 168 | def test_forget(self): 169 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 170 | man: PyManager = PyBoxMPQManager() 171 | variables = [PyVar('x0'), PyVar('y')] 172 | intervals = [PyMPQInterval(-3, 2), PyMPQInterval(-2, 2, 1, 1)] 173 | b = PyBox(man, e, variables=variables, intervals=intervals) 174 | self.assertEqual(str(b.forget([PyVar('y')])), '1·x0 + 3 >= 0 ∧ -1·x0 + 2 >= 0') 175 | 176 | 177 | class TestPyMPFRBox(unittest.TestCase): 178 | 179 | def test_bottom(self): 180 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 181 | man: PyManager = PyBoxMPFRManager() 182 | self.assertTrue(PyBox.bottom(man, e).is_bottom()) 183 | b1 = PyBox(man, e, variables=[PyVar('x0')], intervals=[PyDoubleInterval(-2.5, 2.5)]) 184 | self.assertFalse(b1.is_bottom()) 185 | b2 = PyBox(man, e, variables=[PyVar('y')], intervals=[PyMPQInterval(-5, 5, 2, 2)]) 186 | self.assertFalse(b2.is_bottom()) 187 | b3 = PyBox(man, e, variables=[PyVar('z')], intervals=[PyMPFRInterval(-2.5, 2.5)]) 188 | self.assertFalse(b3.is_bottom()) 189 | self.assertFalse(PyBox.top(man, e).is_bottom()) 190 | 191 | def test_default(self): 192 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 193 | man: PyManager = PyBoxMPFRManager() 194 | b1 = PyBox(man, e, variables=[PyVar('x0')], intervals=[PyDoubleInterval(-2.5, 2.5)]) 195 | self.assertFalse(b1.is_bottom()) 196 | self.assertFalse(b1.is_top()) 197 | b2 = PyBox(man, e, variables=[PyVar('y')], intervals=[PyMPQInterval(-5, 5, 2, 2)]) 198 | self.assertFalse(b2.is_bottom()) 199 | self.assertFalse(b2.is_top()) 200 | b3 = PyBox(man, e, variables=[PyVar('z')], intervals=[PyMPFRInterval(-2.5, 2.5)]) 201 | self.assertFalse(b3.is_bottom()) 202 | self.assertFalse(b3.is_top()) 203 | 204 | def test_top(self): 205 | e = PyEnvironment([PyVar('x0'), PyVar('y')], [PyVar('z')]) 206 | man: PyManager = PyBoxMPFRManager() 207 | self.assertFalse(PyBox.bottom(man, e).is_top()) 208 | b1 = PyBox(man, e, variables=[PyVar('x0')], intervals=[PyDoubleInterval(-2.5, 2.5)]) 209 | self.assertFalse(b1.is_bottom()) 210 | b2 = PyBox(man, e, variables=[PyVar('y')], intervals=[PyMPQInterval(-5, 5, 2, 2)]) 211 | self.assertFalse(b2.is_bottom()) 212 | b3 = PyBox(man, e, variables=[PyVar('z')], intervals=[PyMPFRInterval(-2.5, 2.5)]) 213 | self.assertFalse(b3.is_bottom()) 214 | self.assertTrue(PyBox.top(man, e).is_top()) 215 | 216 | 217 | if __name__ == '__main__': 218 | unittest.main() 219 | -------------------------------------------------------------------------------- /apronpy/tcons1.py: -------------------------------------------------------------------------------- 1 | """ 2 | APRON Tree Constraints (Level 1) 3 | ================================ 4 | 5 | :Author: Caterina Urban 6 | """ 7 | from _ctypes import Structure, POINTER, byref 8 | from copy import deepcopy 9 | from ctypes import c_size_t 10 | from typing import List, Union 11 | 12 | from apronpy.cdll import libapron 13 | from apronpy.coeff import PyDoubleScalarCoeff 14 | from apronpy.environment import Environment, PyEnvironment 15 | from apronpy.lincons0 import ConsTyp 16 | from apronpy.lincons1 import PyLincons1 17 | from apronpy.scalar import c_uint, PyScalar 18 | from apronpy.tcons0 import Tcons0, Tcons0Array 19 | from apronpy.texpr0 import TexprOp, TexprDiscr 20 | from apronpy.texpr1 import PyTexpr1 21 | from apronpy.var import PyVar 22 | 23 | 24 | class Tcons1(Structure): 25 | """ 26 | typedef struct ap_tcons1_t { 27 | ap_tcons0_t tcons0; 28 | ap_environment_t* env; 29 | } ap_tcons1_t; 30 | """ 31 | 32 | _fields_ = [ 33 | ('tcons0', Tcons0), 34 | ('env', POINTER(Environment)) 35 | ] 36 | 37 | def __deepcopy__(self, memodict=None): 38 | if memodict is None: 39 | memodict = {} 40 | result = Tcons1() 41 | result.tcons0 = Tcons0() 42 | result.tcons0.texpr0 = libapron.ap_texpr0_copy(self.tcons0.texpr0) 43 | result.tcons0.constyp = self.tcons0.constyp 44 | if self.tcons0.scalar: 45 | result.tcons0.scalar = libapron.ap_scalar_alloc_set(self.tcons0.scalar) 46 | else: 47 | result.tcons0.scalar = None 48 | self.env.contents.count += 1 49 | result.env = self.env 50 | memodict[id(self)] = result 51 | return result 52 | 53 | def __repr__(self): 54 | def precendence(texpr0): 55 | op_precedence = { 56 | TexprOp.AP_TEXPR_ADD: 1, 57 | TexprOp.AP_TEXPR_SUB: 1, 58 | TexprOp.AP_TEXPR_MUL: 2, 59 | TexprOp.AP_TEXPR_DIV: 2, 60 | TexprOp.AP_TEXPR_MOD: 2, 61 | TexprOp.AP_TEXPR_POW: 3, 62 | TexprOp.AP_TEXPR_NEG: 4, 63 | TexprOp.AP_TEXPR_CAST: 5, 64 | TexprOp.AP_TEXPR_SQRT: 5 65 | } 66 | if texpr0.discr == TexprDiscr.AP_TEXPR_CST or texpr0.discr == TexprDiscr.AP_TEXPR_DIM: 67 | return op_precedence[TexprOp.AP_TEXPR_NEG] 68 | return op_precedence[texpr0.val.node.contents.op] 69 | 70 | def do(texpr0, env): 71 | if texpr0.discr == TexprDiscr.AP_TEXPR_CST: 72 | return '{}'.format(texpr0.val.cst) 73 | elif texpr0.discr == TexprDiscr.AP_TEXPR_DIM: 74 | return '{}'.format(env.var_of_dim[texpr0.val.dim.value].decode('utf-8')) 75 | else: # texpr0.discr == TexprDiscr.AP_TEXPR_NODE 76 | prec = precendence(texpr0) 77 | prec_a = precendence(texpr0.val.node.contents.exprA.contents) 78 | if prec_a < prec: 79 | expr_a = '(' + do(texpr0.val.node.contents.exprA.contents, env) + ')' 80 | else: 81 | expr_a = do(texpr0.val.node.contents.exprA.contents, env) 82 | op = texpr0.val.node.contents.op 83 | if texpr0.val.node.contents.exprB: # binary operation 84 | prec_b = precendence(texpr0.val.node.contents.exprB.contents) 85 | if prec_b <= prec: 86 | expr_b = '(' + do(texpr0.val.node.contents.exprB.contents, env) + ')' 87 | else: 88 | expr_b = do(texpr0.val.node.contents.exprB.contents, env) 89 | return '{} {} {}'.format(expr_a, repr(TexprOp(op)), expr_b) 90 | else: 91 | return '{} {}'.format(repr(TexprOp(op)), expr_a) 92 | 93 | constyp = ConsTyp(self.tcons0.constyp) 94 | scalar = self.tcons0.scalar 95 | result = do(self.tcons0.texpr0.contents, self.env.contents).replace('+ -', '- ') 96 | if scalar: 97 | return '{} {} {}'.format(result, repr(constyp), scalar.contents) 98 | else: 99 | return '{} {} 0'.format(result, repr(constyp)) 100 | 101 | 102 | class TCons1Array(Structure): 103 | """ 104 | typedef struct ap_tcons1_array_t { 105 | ap_tcons0_array_t tcons0_array; 106 | ap_environment_t* env; 107 | } ap_tcons1_array_t; 108 | """ 109 | 110 | _fields_ = [ 111 | ('tcons0_array', Tcons0Array), 112 | ('env', POINTER(Environment)) 113 | ] 114 | 115 | def __repr__(self): 116 | def precendence(texpr0): 117 | op_precedence = { 118 | TexprOp.AP_TEXPR_ADD: 1, 119 | TexprOp.AP_TEXPR_SUB: 1, 120 | TexprOp.AP_TEXPR_MUL: 2, 121 | TexprOp.AP_TEXPR_DIV: 2, 122 | TexprOp.AP_TEXPR_MOD: 2, 123 | TexprOp.AP_TEXPR_POW: 3, 124 | TexprOp.AP_TEXPR_NEG: 4, 125 | TexprOp.AP_TEXPR_CAST: 5, 126 | TexprOp.AP_TEXPR_SQRT: 5 127 | } 128 | if texpr0.discr == TexprDiscr.AP_TEXPR_CST or texpr0.discr == TexprDiscr.AP_TEXPR_DIM: 129 | return op_precedence[TexprOp.AP_TEXPR_NEG] 130 | return op_precedence[texpr0.val.node.contents.op] 131 | 132 | def do(texpr0, env): 133 | if texpr0.discr == TexprDiscr.AP_TEXPR_CST: 134 | return '{}'.format(texpr0.val.cst) 135 | elif texpr0.discr == TexprDiscr.AP_TEXPR_DIM: 136 | return '{}'.format(env.var_of_dim[texpr0.val.dim.value].decode('utf-8')) 137 | else: # texpr0.discr == TexprDiscr.AP_TEXPR_NODE 138 | prec = precendence(texpr0) 139 | prec_a = precendence(texpr0.val.node.contents.exprA.contents) 140 | if prec_a < prec: 141 | expr_a = '(' + do(texpr0.val.node.contents.exprA.contents, env) + ')' 142 | else: 143 | expr_a = do(texpr0.val.node.contents.exprA.contents, env) 144 | op = texpr0.val.node.contents.op 145 | if texpr0.val.node.contents.exprB: # binary operation 146 | prec_b = precendence(texpr0.val.node.contents.exprB.contents) 147 | if prec_b <= prec: 148 | expr_b = '(' + do(texpr0.val.node.contents.exprB.contents, env) + ')' 149 | else: 150 | expr_b = do(texpr0.val.node.contents.exprB.contents, env) 151 | return '{} {} {}'.format(expr_a, repr(TexprOp(op)), expr_b) 152 | else: 153 | return '{} {}'.format(repr(TexprOp(op)), expr_a) 154 | 155 | array = list() 156 | for i in range(self.tcons0_array.size): 157 | constyp = ConsTyp(self.tcons0_array.p[i].constyp) 158 | scalar = self.tcons0_array.p[i].scalar 159 | result = do(self.tcons0_array.p[i].texpr0.contents, self.env.contents) 160 | result = result.replace('+ -', '- ') 161 | if scalar: 162 | array.append('{} {} {}'.format(result, repr(constyp), scalar.contents)) 163 | else: 164 | array.append('{} {} 0'.format(result, repr(constyp))) 165 | return ' ∧ '.join(array) 166 | 167 | 168 | class PyTcons1: 169 | 170 | def __init__(self, cons: Union[PyLincons1, Tcons1]): 171 | if isinstance(cons, PyLincons1): 172 | self.tcons1 = Tcons1() 173 | texpr = libapron.ap_texpr0_from_linexpr0(cons.lincons1.lincons0.linexpr0) 174 | self.tcons1.tcons0.texpr0 = texpr 175 | self.tcons1.tcons0.constyp = c_uint(cons.lincons1.lincons0.constyp) 176 | scalar = cons.lincons1.lincons0.scalar 177 | if scalar: 178 | self.tcons1.tcons0.scalar = libapron.ap_scalar_alloc_set(scalar) 179 | cons.lincons1.env.contents.count += 1 180 | self.tcons1.env = cons.lincons1.env 181 | else: 182 | self.tcons1 = cons 183 | 184 | @classmethod 185 | def make(cls, texpr: PyTexpr1, typ: ConsTyp, cst: PyScalar = None): 186 | tcons1 = Tcons1() 187 | tcons1.tcons0 = Tcons0() 188 | tcons1.tcons0.texpr0 = libapron.ap_texpr0_copy(texpr.texpr1.contents.texpr0) 189 | tcons1.tcons0.constyp = c_uint(typ) 190 | if cst: 191 | tcons1.tcons0.scalar = libapron.ap_scalar_alloc_set(cst) 192 | else: 193 | tcons1.tcons0.scalar = None 194 | texpr.texpr1.contents.env.contents.count += 1 195 | tcons1.env = texpr.texpr1.contents.env 196 | return cls(tcons1) 197 | 198 | @classmethod 199 | def unsat(cls, environment: PyEnvironment): 200 | x = PyTexpr1.cst(environment, PyDoubleScalarCoeff(-1.0)) 201 | return cls.make(x, ConsTyp.AP_CONS_SUPEQ) 202 | 203 | def __deepcopy__(self, memodict=None): 204 | if memodict is None: 205 | memodict = {} 206 | result = PyTcons1(deepcopy(self.tcons1)) 207 | memodict[id(self)] = result 208 | return result 209 | 210 | def __del__(self): 211 | libapron.ap_tcons1_clear(self) 212 | del self.tcons1 213 | 214 | @property 215 | def _as_parameter_(self): 216 | return byref(self.tcons1) 217 | 218 | @staticmethod 219 | def from_param(argument): 220 | assert isinstance(argument, PyTcons1) 221 | return argument 222 | 223 | def __repr__(self): 224 | return '{}'.format(self.tcons1) 225 | 226 | def substitute(self, var: PyVar, dst: PyTexpr1): 227 | self.tcons1.env.contents.count += 1 228 | dim = libapron.ap_environment_dim_of_var(PyEnvironment(self.tcons1.env), var) 229 | texpr0 = self.tcons1.tcons0.texpr0 230 | libapron.ap_texpr0_substitute_with(texpr0, dim, dst.texpr1.contents.texpr0) 231 | return self 232 | 233 | 234 | libapron.ap_tcons1_clear.argtypes = [PyTcons1] 235 | 236 | 237 | class PyTcons1Array: 238 | 239 | def __init__(self, tcons1s: Union[TCons1Array, List[PyTcons1]] = None, 240 | environment: PyEnvironment = None): 241 | if isinstance(tcons1s, TCons1Array): 242 | self.tcons1array = tcons1s 243 | elif tcons1s: 244 | size = len(tcons1s) 245 | self.tcons1array = libapron.ap_tcons1_array_make(tcons1s[0].tcons1.env, size) 246 | for i in range(size): 247 | libapron.ap_tcons1_array_set(self, i, deepcopy(tcons1s[i].tcons1)) 248 | else: 249 | self.tcons1array = libapron.ap_tcons1_array_make(environment, 0) 250 | 251 | def __del__(self): 252 | libapron.ap_tcons1_array_clear(self) 253 | del self.tcons1array 254 | 255 | @property 256 | def _as_parameter_(self): 257 | return byref(self.tcons1array) 258 | 259 | @staticmethod 260 | def from_param(argument): 261 | assert isinstance(argument, PyTcons1Array) 262 | return argument 263 | 264 | def __repr__(self): 265 | return '{}'.format(self.tcons1array) 266 | 267 | 268 | libapron.ap_tcons1_array_make.argtypes = [POINTER(Environment), c_size_t] 269 | libapron.ap_tcons1_array_make.restype = TCons1Array 270 | libapron.ap_tcons1_array_clear.argtypes = [PyTcons1Array] 271 | libapron.ap_tcons1_array_set.argtypes = [PyTcons1Array, c_size_t, POINTER(Tcons1)] 272 | -------------------------------------------------------------------------------- /apronpy/lincons1.py: -------------------------------------------------------------------------------- 1 | """ 2 | APRON Linear Constraints (Level 1) 3 | ================================== 4 | 5 | :Author: Caterina Urban 6 | """ 7 | from _ctypes import Structure, POINTER, byref 8 | from copy import deepcopy 9 | from ctypes import c_char_p, c_size_t 10 | from typing import List, Union 11 | 12 | from apronpy.cdll import libapron 13 | from apronpy.coeff import PyDoubleScalarCoeff, CoeffDiscr, PyMPQIntervalCoeff, \ 14 | PyMPFRIntervalCoeff, \ 15 | PyDoubleIntervalCoeff, PyMPQScalarCoeff, PyMPFRScalarCoeff, PyCoeff, Coeff 16 | from apronpy.environment import Environment, PyEnvironment 17 | from apronpy.lincons0 import Lincons0, ConsTyp, Lincons0Array 18 | from apronpy.linexpr0 import LinexprDiscr 19 | from apronpy.linexpr1 import PyLinexpr1 20 | from apronpy.scalar import PyScalar, c_uint, ScalarDiscr 21 | from apronpy.var import PyVar 22 | 23 | 24 | class Lincons1(Structure): 25 | """ 26 | typedef struct ap_lincons1_t { 27 | ap_lincons0_t lincons0; 28 | ap_environment_t* env; 29 | } ap_lincons1_t; 30 | """ 31 | 32 | _fields_ = [ 33 | ('lincons0', Lincons0), 34 | ('env', POINTER(Environment)) 35 | ] 36 | 37 | def __deepcopy__(self, memodict=None): 38 | if memodict is None: 39 | memodict = {} 40 | result = Lincons1() 41 | result.lincons0 = Lincons0() 42 | result.lincons0.linexpr0 = libapron.ap_linexpr0_copy(self.lincons0.linexpr0) 43 | result.lincons0.constyp = self.lincons0.constyp 44 | if self.lincons0.scalar: 45 | result.lincons0.scalar = libapron.ap_scalar_alloc_set(self.lincons0.scalar) 46 | else: 47 | result.lincons0.scalar = None 48 | self.env.contents.count += 1 49 | result.env = self.env 50 | memodict[id(self)] = result 51 | return result 52 | 53 | def __repr__(self): 54 | linexpr0 = self.lincons0.linexpr0.contents 55 | constyp = ConsTyp(self.lincons0.constyp) 56 | scalar = self.lincons0.scalar 57 | env = self.env.contents 58 | result = '' 59 | if linexpr0.discr == LinexprDiscr.AP_LINEXPR_DENSE: 60 | result += ' + '.join( 61 | '{}·{}'.format(linexpr0.p.coeff[i], env.var_of_dim[i].decode('utf-8')) 62 | for i in range(linexpr0.size) 63 | ) 64 | result += ' + {}'.format(linexpr0.cst) if result else '{}'.format(linexpr0.cst) 65 | else: # self.discr == LinexprDiscr.AP_LINEXPR_SPARSE: 66 | terms = list() 67 | for i in range(linexpr0.size): 68 | coeff = linexpr0.p.linterm[i].coeff 69 | dim = linexpr0.p.linterm[i].dim.value 70 | if dim < env.intdim + env.realdim: 71 | terms.append('{}·{}'.format(coeff, env.var_of_dim[dim].decode('utf-8'))) 72 | result += ' + '.join(terms) 73 | result += ' + {}'.format(linexpr0.cst) if result else '{}'.format(linexpr0.cst) 74 | if scalar: 75 | return '{} {} {}'.format(result.replace('+ -', '- '), repr(constyp), scalar.contents) 76 | else: 77 | return '{} {} 0'.format(result.replace('+ -', '- '), repr(constyp)) 78 | 79 | 80 | class Lincons1Array(Structure): 81 | """ 82 | typedef struct ap_lincons1_array_t { 83 | ap_lincons0_array_t lincons0_array; 84 | ap_environment_t* env; 85 | } ap_lincons1_array_t; 86 | """ 87 | 88 | _fields_ = [ 89 | ('lincons0_array', Lincons0Array), 90 | ('env', POINTER(Environment)) 91 | ] 92 | 93 | def __repr__(self): 94 | env = self.env.contents 95 | array = list() 96 | for i in range(self.lincons0_array.size): 97 | 98 | linexpr0 = self.lincons0_array.p[i].linexpr0.contents 99 | constyp = ConsTyp(self.lincons0_array.p[i].constyp) 100 | scalar = self.lincons0_array.p[i].scalar 101 | 102 | result = '' 103 | if linexpr0.discr == LinexprDiscr.AP_LINEXPR_DENSE: 104 | result += ' + '.join( 105 | '{}·{}'.format(linexpr0.p.coeff[j], env.var_of_dim[j].decode('utf-8')) 106 | for j in range(linexpr0.size) if str(linexpr0.p.coeff[j]) != '0' 107 | ) 108 | result += ' + {}'.format(linexpr0.cst) if result else '{}'.format(linexpr0.cst) 109 | else: # self.discr == LinexprDiscr.AP_LINEXPR_SPARSE: 110 | terms = list() 111 | for j in range(linexpr0.size): 112 | coeff = linexpr0.p.linterm[j].coeff 113 | dim = linexpr0.p.linterm[j].dim.value 114 | if dim < env.intdim + env.realdim: 115 | terms.append('{}·{}'.format(coeff, env.var_of_dim[dim].decode('utf-8'))) 116 | result += ' + '.join(terms) 117 | result += ' + {}'.format(linexpr0.cst) if result else '{}'.format(linexpr0.cst) 118 | if scalar: 119 | result = result.replace('+ -', '- ') 120 | array.append('{} {} {}'.format(result, repr(constyp), scalar.contents)) 121 | else: 122 | array.append('{} {} 0'.format(result.replace('+ -', '- '), repr(constyp))) 123 | return ' ∧ '.join(array) 124 | 125 | 126 | class PyLincons1: 127 | 128 | def __init__(self, lincons1_or_typ: Union[Lincons1, ConsTyp], linexpr: PyLinexpr1 = None, scalar: PyScalar = None): 129 | if isinstance(lincons1_or_typ, Lincons1): 130 | self.lincons1 = lincons1_or_typ 131 | else: 132 | self.lincons1 = Lincons1() 133 | linexpr_copy = deepcopy(linexpr.linexpr1) 134 | self.lincons1.lincons0.linexpr0 = linexpr_copy.linexpr0 135 | self.lincons1.lincons0.constyp = c_uint(lincons1_or_typ) 136 | if scalar: 137 | scalar_copy = deepcopy(scalar.scalar.contents) 138 | s = libapron.ap_scalar_alloc_set(byref(scalar_copy)) 139 | self.lincons1.lincons0.scalar = s 140 | self.lincons1.env = linexpr_copy.env 141 | 142 | @classmethod 143 | def unsat(cls, environment: PyEnvironment): 144 | x = PyLinexpr1(environment) 145 | x.set_cst(PyDoubleScalarCoeff(-1.0)) 146 | lincons = cls(ConsTyp.AP_CONS_SUPEQ, x) 147 | return lincons 148 | 149 | def __del__(self): 150 | libapron.ap_lincons1_clear(self) 151 | del self.lincons1 152 | 153 | @property 154 | def _as_parameter_(self): 155 | return byref(self.lincons1) 156 | 157 | @staticmethod 158 | def from_param(argument): 159 | assert isinstance(argument, PyLincons1) 160 | return argument 161 | 162 | def __repr__(self): 163 | return '{}'.format(self.lincons1) 164 | 165 | def is_unsat(self): 166 | return bool(libapron.ap_lincons0_is_unsat(self.lincons1.lincons0)) 167 | 168 | def get_typ(self): 169 | return ConsTyp(self.lincons1.lincons0.constyp) 170 | 171 | def set_typ(self, typ: ConsTyp): 172 | self.lincons1.lincons0.constyp = c_uint(typ) 173 | 174 | def get_cst(self): 175 | cst = self.lincons1.lincons0.linexpr0.contents.cst 176 | if cst.discr == CoeffDiscr.AP_COEFF_INTERVAL: 177 | if cst.val.interval.contents.inf.contents.discr == ScalarDiscr.AP_SCALAR_MPQ: 178 | result = PyMPQIntervalCoeff() 179 | elif cst.val.interval.contents.inf.contents.discr == ScalarDiscr.AP_SCALAR_MPFR: 180 | result = PyMPFRIntervalCoeff(0, 0) 181 | else: # cst.val.interval.contents.inf.contents.discr == ScalarDiscr.AP_SCALAR_DOUBLE 182 | result = PyDoubleIntervalCoeff() 183 | else: # CoeffDiscr.AP_COEFF_SCALAR 184 | if cst.val.scalar.contents.discr == ScalarDiscr.AP_SCALAR_MPQ: 185 | result = PyMPQScalarCoeff() 186 | elif cst.val.scalar.contents.discr == ScalarDiscr.AP_SCALAR_MPFR: 187 | result = PyMPFRScalarCoeff(0) 188 | else: # cst.val.scalar.contents.discr == ScalarDiscr.AP_SCALAR_DOUBLE 189 | result = PyDoubleScalarCoeff() 190 | libapron.ap_coeff_set(result.coeff, self.lincons1.lincons0.linexpr0.contents.cst) 191 | return result 192 | 193 | def set_cst(self, cst: PyCoeff): 194 | libapron.ap_coeff_set(byref(self.lincons1.lincons0.linexpr0.contents.cst), cst.coeff) 195 | 196 | def get_coeff(self, var: PyVar): 197 | coeff = libapron.ap_lincons1_coeffref(self, var._as_parameter_) 198 | if coeff.contents.discr == CoeffDiscr.AP_COEFF_INTERVAL: 199 | discr = coeff.contents.val.interval.contents.inf.contents.discr 200 | if discr == ScalarDiscr.AP_SCALAR_MPQ: 201 | result = PyMPQIntervalCoeff() 202 | elif discr == ScalarDiscr.AP_SCALAR_MPFR: 203 | result = PyMPFRIntervalCoeff(0, 0) 204 | else: # discr == ScalarDiscr.AP_SCALAR_DOUBLE 205 | result = PyDoubleIntervalCoeff() 206 | else: # CoeffDiscr.AP_COEFF_SCALAR 207 | if coeff.contents.val.scalar.contents.discr == ScalarDiscr.AP_SCALAR_MPQ: 208 | result = PyMPQScalarCoeff() 209 | elif coeff.contents.val.scalar.contents.discr == ScalarDiscr.AP_SCALAR_MPFR: 210 | result = PyMPFRScalarCoeff(0) 211 | else: # coeff.contents.val.scalar.contents.discr == ScalarDiscr.AP_SCALAR_DOUBLE 212 | result = PyDoubleScalarCoeff() 213 | libapron.ap_lincons1_get_coeff(result.coeff, self, var._as_parameter_) 214 | return result 215 | 216 | def set_coeff(self, var: PyVar, coeff: PyCoeff): 217 | libapron.ap_coeff_set(libapron.ap_lincons1_coeffref(self, var._as_parameter_), coeff.coeff) 218 | 219 | 220 | libapron.ap_lincons1_clear.argtypes = [PyLincons1] 221 | libapron.ap_lincons1_coeffref.argtypes = [PyLincons1, c_char_p] 222 | libapron.ap_lincons1_coeffref.restype = POINTER(Coeff) 223 | libapron.ap_lincons1_get_coeff.argtypes = [POINTER(Coeff), PyLincons1, c_char_p] 224 | 225 | 226 | class PyLincons1Array: 227 | 228 | def __init__(self, lincons1s: Union[Lincons1Array, List[PyLincons1]] = None, 229 | environment: PyEnvironment = None): 230 | if isinstance(lincons1s, Lincons1Array): 231 | self.lincons1array = lincons1s 232 | elif lincons1s: 233 | size = len(lincons1s) 234 | self.lincons1array = libapron.ap_lincons1_array_make(lincons1s[0].lincons1.env, size) 235 | for i in range(size): 236 | libapron.ap_lincons1_array_set(self, i, deepcopy(lincons1s[i].lincons1)) 237 | else: 238 | self.lincons1array = libapron.ap_lincons1_array_make(environment, 0) 239 | 240 | def __del__(self): 241 | libapron.ap_lincons1_array_clear(self) 242 | del self.lincons1array 243 | 244 | @property 245 | def _as_parameter_(self): 246 | return byref(self.lincons1array) 247 | 248 | @staticmethod 249 | def from_param(argument): 250 | assert isinstance(argument, PyLincons1Array) 251 | return argument 252 | 253 | def __len__(self): 254 | return self.lincons1array.lincons0_array.size 255 | 256 | def __repr__(self): 257 | return '{}'.format(self.lincons1array) 258 | 259 | def get(self, i): 260 | return PyLincons1(deepcopy(libapron.ap_lincons1_array_get(self, i))) 261 | 262 | def set(self, i, lincons: PyLincons1): 263 | libapron.ap_lincons1_array_set(self, i, deepcopy(lincons.lincons1)) 264 | 265 | 266 | libapron.ap_lincons1_array_make.argtypes = [POINTER(Environment), c_size_t] 267 | libapron.ap_lincons1_array_make.restype = Lincons1Array 268 | libapron.ap_lincons1_array_clear.argtypes = [PyLincons1Array] 269 | libapron.ap_lincons1_array_get.argtypes = [PyLincons1Array, c_size_t] 270 | libapron.ap_lincons1_array_get.restype = Lincons1 271 | libapron.ap_lincons1_array_set.argtypes = [PyLincons1Array, c_size_t, POINTER(Lincons1)] 272 | -------------------------------------------------------------------------------- /tests/test_interval.py: -------------------------------------------------------------------------------- 1 | """ 2 | APRON Intervals on Scalars - Unit Tests 3 | ======================================= 4 | 5 | :Author: Caterina Urban 6 | """ 7 | import unittest 8 | from copy import deepcopy 9 | from ctypes import c_double 10 | 11 | from apronpy.interval import PyDoubleInterval, PyMPQInterval, PyMPFRInterval 12 | from apronpy.mpfr import PyMPFR 13 | from apronpy.mpq import PyMPQ 14 | from apronpy.scalar import PyDoubleScalar, PyMPQScalar, PyMPFRScalar 15 | 16 | 17 | class TestPyDoubleInterval(unittest.TestCase): 18 | 19 | def test_init(self): 20 | self.assertEqual(str(PyDoubleInterval()), '[0.0,0.0]') 21 | self.assertEqual(str(PyDoubleInterval(0, 0)), '[0.0,0.0]') 22 | self.assertEqual(str(PyDoubleInterval(0.0, 0.0)), '[0.0,0.0]') 23 | self.assertEqual(str(PyDoubleInterval(c_double(0), c_double(0))), '[0.0,0.0]') 24 | self.assertEqual(str(PyDoubleInterval(c_double(0.0), c_double(0.0))), '[0.0,0.0]') 25 | self.assertEqual(str(PyDoubleInterval(PyDoubleScalar(0), PyDoubleScalar(0))), '[0.0,0.0]') 26 | self.assertEqual( 27 | str(PyDoubleInterval(PyDoubleScalar(0.0), PyDoubleScalar(0.0))), '[0.0,0.0]' 28 | ) 29 | self.assertEqual(str(PyDoubleInterval(-0.5, 0.5)), '[-0.5,0.5]') 30 | self.assertEqual(str(PyDoubleInterval(c_double(-0.5), c_double(0.5))), '[-0.5,0.5]') 31 | self.assertEqual( 32 | str(PyDoubleInterval(PyDoubleScalar(-0.5), PyDoubleScalar(0.5))), '[-0.5,0.5]' 33 | ) 34 | self.assertEqual(str(PyDoubleInterval.top()), '[-inf,inf]') 35 | self.assertEqual(str(PyDoubleInterval.bottom()), '[1.0,-1.0]') 36 | 37 | def test_deepcopy(self): 38 | i0 = PyDoubleInterval(0, 0) 39 | i1 = deepcopy(i0) 40 | i2 = i0 41 | self.assertNotEqual(id(i0), id(i1)) 42 | self.assertEqual(id(i0), id(i2)) 43 | 44 | def test_is_bottom(self): 45 | self.assertFalse(PyDoubleInterval().is_bottom()) 46 | self.assertFalse(PyDoubleInterval(0, 0).is_bottom()) 47 | self.assertFalse(PyDoubleInterval(0.0, 0.0).is_bottom()) 48 | self.assertFalse(PyDoubleInterval(c_double(0), c_double(0)).is_bottom()) 49 | self.assertFalse(PyDoubleInterval(c_double(0.0), c_double(0.0)).is_bottom()) 50 | self.assertFalse(PyDoubleInterval(PyDoubleScalar(0), PyDoubleScalar(0)).is_bottom()) 51 | self.assertFalse(PyDoubleInterval(PyDoubleScalar(0.0), PyDoubleScalar(0.0)).is_bottom()) 52 | self.assertFalse(PyDoubleInterval(-0.5, 0.5).is_bottom()) 53 | self.assertFalse(PyDoubleInterval(c_double(-0.5), c_double(0.5)).is_bottom()) 54 | self.assertFalse(PyDoubleInterval(PyDoubleScalar(-0.5), PyDoubleScalar(0.5)).is_bottom()) 55 | self.assertFalse(PyDoubleInterval.top().is_bottom()) 56 | self.assertTrue(PyDoubleInterval.bottom().is_bottom()) 57 | 58 | def test_cmp(self): 59 | self.assertTrue(PyDoubleInterval.bottom() < PyDoubleInterval()) 60 | self.assertFalse(PyDoubleInterval() < PyDoubleInterval.bottom()) 61 | self.assertTrue(PyDoubleInterval() < PyDoubleInterval(-0.5, 0.5)) 62 | self.assertFalse(PyDoubleInterval(-0.5, 0.5) < PyDoubleInterval()) 63 | self.assertTrue(PyDoubleInterval(-0.5, 0.5) < PyDoubleInterval.top()) 64 | self.assertFalse(PyDoubleInterval.top() < PyDoubleInterval(-0.5, 0.5)) 65 | self.assertFalse(PyDoubleInterval.bottom() == PyDoubleInterval()) 66 | self.assertTrue(PyDoubleInterval() == PyDoubleInterval(0, 0)) 67 | self.assertFalse(PyDoubleInterval() == PyDoubleInterval(-0.5, 0.5)) 68 | self.assertTrue( 69 | PyDoubleInterval(-0.5, 0.5) == PyDoubleInterval(c_double(-0.5), c_double(0.5)) 70 | ) 71 | self.assertFalse(PyDoubleInterval(-0.5, 0.5) == PyDoubleInterval.top()) 72 | self.assertFalse(PyDoubleInterval.bottom() > PyDoubleInterval()) 73 | self.assertTrue(PyDoubleInterval() > PyDoubleInterval.bottom()) 74 | self.assertFalse(PyDoubleInterval() > PyDoubleInterval(-0.5, 0.5)) 75 | self.assertTrue(PyDoubleInterval(-0.5, 0.5) > PyDoubleInterval()) 76 | self.assertFalse(PyDoubleInterval(-0.5, 0.5) > PyDoubleInterval.top()) 77 | self.assertTrue(PyDoubleInterval.top() > PyDoubleInterval(-0.5, 0.5)) 78 | self.assertTrue(PyDoubleInterval(-3, -1) <= PyDoubleInterval(PyDoubleScalar.init_infty(-1), PyDoubleScalar(-1))) 79 | 80 | def test_is_top(self): 81 | self.assertFalse(PyDoubleInterval().is_top()) 82 | self.assertFalse(PyDoubleInterval(0, 0).is_top()) 83 | self.assertFalse(PyDoubleInterval(0.0, 0.0).is_top()) 84 | self.assertFalse(PyDoubleInterval(c_double(0), c_double(0)).is_top()) 85 | self.assertFalse(PyDoubleInterval(c_double(0.0), c_double(0.0)).is_top()) 86 | self.assertFalse(PyDoubleInterval(PyDoubleScalar(0), PyDoubleScalar(0)).is_top()) 87 | self.assertFalse(PyDoubleInterval(PyDoubleScalar(0.0), PyDoubleScalar(0.0)).is_top()) 88 | self.assertFalse(PyDoubleInterval(-0.5, 0.5).is_top()) 89 | self.assertFalse(PyDoubleInterval(c_double(-0.5), c_double(0.5)).is_top()) 90 | self.assertFalse(PyDoubleInterval(PyDoubleScalar(-0.5), PyDoubleScalar(0.5)).is_top()) 91 | self.assertTrue(PyDoubleInterval.top().is_top()) 92 | self.assertFalse(PyDoubleInterval.bottom().is_top()) 93 | 94 | def test_neg(self): 95 | self.assertEqual(-PyDoubleInterval.bottom(), PyDoubleInterval.bottom()) 96 | self.assertEqual(-PyDoubleInterval(-1, 2), PyDoubleInterval(-2, 1)) 97 | self.assertEqual(-PyDoubleInterval(), PyDoubleInterval(0, 0)) 98 | self.assertEqual( 99 | -PyDoubleInterval(-0.5, 0.5), PyDoubleInterval(c_double(-0.5), c_double(0.5)) 100 | ) 101 | self.assertEqual(-PyDoubleInterval(1, 2), PyDoubleInterval(-2, -1)) 102 | self.assertEqual(-PyDoubleInterval.top(), PyDoubleInterval.top()) 103 | 104 | 105 | class TestPyMPQInterval(unittest.TestCase): 106 | 107 | def test_init(self): 108 | self.assertEqual(str(PyMPQInterval()), '[0,0]') 109 | self.assertEqual(str(PyMPQInterval(0, 0)), '[0,0]') 110 | self.assertEqual(str(PyMPQInterval(0, 0, 1, 1)), '[0,0]') 111 | self.assertEqual(str(PyMPQInterval(PyMPQScalar(0), PyMPQScalar(0))), '[0,0]') 112 | self.assertEqual(str(PyMPQInterval(PyMPQScalar(0, 1), PyMPQScalar(0, 1))), '[0,0]') 113 | self.assertEqual(str(PyMPQInterval(-1, 1, 2, 2)), '[-1/2,1/2]') 114 | self.assertEqual(str(PyMPQInterval(PyMPQ(-1, 2), PyMPQ(1, 2))), '[-1/2,1/2]') 115 | self.assertEqual(str(PyMPQInterval(PyMPQScalar(-1, 2), PyMPQScalar(1, 2))), '[-1/2,1/2]') 116 | self.assertEqual(str(PyMPQInterval.top()), '[-1/0,1/0]') 117 | self.assertEqual(str(PyMPQInterval.bottom()), '[1,-1]') 118 | 119 | def test_deepcopy(self): 120 | i0 = PyMPQInterval(0, 0) 121 | i1 = deepcopy(i0) 122 | i2 = i0 123 | self.assertNotEqual(id(i0), id(i1)) 124 | self.assertEqual(id(i0), id(i2)) 125 | 126 | def test_is_bottom(self): 127 | self.assertFalse(PyMPQInterval().is_bottom()) 128 | self.assertFalse(PyMPQInterval(0, 0).is_bottom()) 129 | self.assertFalse(PyMPQInterval(0, 0, 1, 1).is_bottom()) 130 | self.assertFalse(PyMPQInterval(PyMPQScalar(0), PyMPQScalar(0)).is_bottom()) 131 | self.assertFalse(PyMPQInterval(PyMPQScalar(0, 1), PyMPQScalar(0, 1)).is_bottom()) 132 | self.assertFalse(PyMPQInterval(-1, 1, 2, 2).is_bottom()) 133 | self.assertFalse(PyMPQInterval(PyMPQ(-1, 2), PyMPQ(1, 2)).is_bottom()) 134 | self.assertFalse(PyMPQInterval(PyMPQScalar(-1, 2), PyMPQScalar(1, 2)).is_bottom()) 135 | self.assertFalse(PyMPQInterval.top().is_bottom()) 136 | self.assertTrue(PyMPQInterval.bottom().is_bottom()) 137 | 138 | def test_cmp(self): 139 | self.assertTrue(PyMPQInterval.bottom() < PyMPQInterval()) 140 | self.assertFalse(PyMPQInterval() < PyMPQInterval.bottom()) 141 | self.assertTrue(PyMPQInterval() < PyMPQInterval(-1, 1, 2, 2)) 142 | self.assertFalse(PyMPQInterval(-1, 1, 2, 2) < PyMPQInterval()) 143 | self.assertTrue(PyMPQInterval(-1, 1, 2, 2) < PyMPQInterval.top()) 144 | self.assertFalse(PyMPQInterval.top() < PyMPQInterval(-1, 1, 2, 2)) 145 | self.assertFalse(PyMPQInterval.bottom() == PyMPQInterval()) 146 | self.assertTrue(PyMPQInterval() == PyMPQInterval(0, 0)) 147 | self.assertFalse(PyMPQInterval() == PyMPQInterval(-1, 1, 2, 2)) 148 | self.assertTrue(PyMPQInterval(-1, 1, 2, 2) == PyMPQInterval(PyMPQ(-1, 2), PyMPQ(1, 2))) 149 | self.assertFalse(PyMPQInterval(-1, 1, 2, 2) == PyMPQInterval.top()) 150 | self.assertFalse(PyMPQInterval.bottom() > PyMPQInterval()) 151 | self.assertTrue(PyMPQInterval() > PyMPQInterval.bottom()) 152 | self.assertFalse(PyMPQInterval() > PyMPQInterval(-1, 1, 2, 2)) 153 | self.assertTrue(PyMPQInterval(-1, 1, 2, 2) > PyMPQInterval()) 154 | self.assertFalse(PyMPQInterval(-1, 1, 2, 2) > PyMPQInterval.top()) 155 | self.assertTrue(PyMPQInterval.top() > PyMPQInterval(-1, 1, 2, 2)) 156 | self.assertTrue(PyMPQInterval(-3, -1) <= PyMPQInterval(PyMPQScalar.init_infty(-1), PyMPQScalar(-1))) 157 | 158 | def test_is_top(self): 159 | self.assertFalse(PyMPQInterval().is_top()) 160 | self.assertFalse(PyMPQInterval(0, 0).is_top()) 161 | self.assertFalse(PyMPQInterval(0, 0, 1, 1).is_top()) 162 | self.assertFalse(PyMPQInterval(PyMPQScalar(0), PyMPQScalar(0)).is_top()) 163 | self.assertFalse(PyMPQInterval(PyMPQScalar(0, 1), PyMPQScalar(0, 1)).is_top()) 164 | self.assertFalse(PyMPQInterval(-1, 1, 2, 2).is_top()) 165 | self.assertFalse(PyMPQInterval(PyMPQ(-1, 2), PyMPQ(1, 2)).is_top()) 166 | self.assertFalse(PyMPQInterval(PyMPQScalar(-1, 2), PyMPQScalar(1, 2)).is_top()) 167 | self.assertTrue(PyMPQInterval.top().is_top()) 168 | self.assertFalse(PyMPQInterval.bottom().is_top()) 169 | 170 | def test_neg(self): 171 | self.assertEqual(-PyMPQInterval.bottom(), PyMPQInterval.bottom()) 172 | self.assertEqual(-PyMPQInterval(-1, 2), PyMPQInterval(-2, 1)) 173 | self.assertEqual(-PyMPQInterval(), PyMPQInterval(0, 0)) 174 | self.assertEqual(-PyMPQInterval(-1, 1, 2, 2), PyMPQInterval(-PyMPQ(1, 2), PyMPQ(1, 2))) 175 | self.assertEqual(-PyMPQInterval(1, 1, 2, 2), PyMPQInterval(-PyMPQ(1, 2), -PyMPQ(1, 2))) 176 | self.assertEqual(-PyMPQInterval(1, 1, 2, 2), PyMPQInterval(PyMPQ(-1, 2), PyMPQ(-1, 2))) 177 | self.assertEqual(-PyMPQInterval(1, 2), PyMPQInterval(-2, -1)) 178 | self.assertEqual(-PyMPQInterval.top(), PyMPQInterval.top()) 179 | 180 | 181 | class TestPyMPFRInterval(unittest.TestCase): 182 | 183 | def test_init(self): 184 | self.assertEqual(str(PyMPFRInterval(0, 0)), '[0.0,0.0]') 185 | self.assertEqual(str(PyMPFRInterval(0.0, 0.0)), '[0.0,0.0]') 186 | self.assertEqual(str(PyMPFRInterval(PyMPFRScalar(0), PyMPFRScalar(0))), '[0.0,0.0]') 187 | self.assertEqual(str(PyMPFRInterval(PyMPFRScalar(0.0), PyMPFRScalar(0.0))), '[0.0,0.0]') 188 | self.assertEqual(str(PyMPFRInterval(-0.5, 0.5)), '[-0.5,0.5]') 189 | self.assertEqual(str(PyMPFRInterval(PyMPFR(-0.5), PyMPFR(0.5))), '[-0.5,0.5]') 190 | self.assertEqual(str(PyMPFRInterval(PyMPFRScalar(-0.5), PyMPFRScalar(0.5))), '[-0.5,0.5]') 191 | self.assertEqual(str(PyMPFRInterval.top()), '[-inf,inf]') 192 | self.assertEqual(str(PyMPFRInterval.bottom()), '[1.0,-1.0]') 193 | 194 | def test_deepcopy(self): 195 | i0 = PyMPFRInterval(0, 0) 196 | i1 = deepcopy(i0) 197 | i2 = i0 198 | self.assertNotEqual(id(i0), id(i1)) 199 | self.assertEqual(id(i0), id(i2)) 200 | 201 | def test_is_bottom(self): 202 | self.assertFalse(PyMPFRInterval(0, 0).is_bottom()) 203 | self.assertFalse(PyMPFRInterval(0.0, 0.0).is_bottom()) 204 | self.assertFalse(PyMPFRInterval(PyMPFRScalar(0), PyMPFRScalar(0)).is_bottom()) 205 | self.assertFalse(PyMPFRInterval(PyMPFRScalar(0.0), PyMPFRScalar(0.0)).is_bottom()) 206 | self.assertFalse(PyMPFRInterval(-0.5, 0.5).is_bottom()) 207 | self.assertFalse(PyMPFRInterval(PyMPFR(-0.5), PyMPFR(0.5)).is_bottom()) 208 | self.assertFalse(PyMPFRInterval(PyMPFRScalar(-0.5), PyMPFRScalar(0.5)).is_bottom()) 209 | self.assertFalse(PyMPFRInterval.top().is_bottom()) 210 | self.assertTrue(PyMPFRInterval.bottom().is_bottom()) 211 | 212 | def test_cmp(self): 213 | self.assertTrue(PyMPFRInterval.bottom() < PyMPFRInterval(0, 0)) 214 | self.assertFalse(PyMPFRInterval(0, 0) < PyMPFRInterval.bottom()) 215 | self.assertTrue(PyMPFRInterval(0, 0) < PyMPFRInterval(-0.5, 0.5)) 216 | self.assertFalse(PyMPFRInterval(-0.5, 0.5) < PyMPFRInterval(0, 0)) 217 | self.assertTrue(PyMPFRInterval(-0.5, 0.5) < PyMPFRInterval.top()) 218 | self.assertFalse(PyMPFRInterval.top() < PyMPFRInterval(-0.5, 0.5)) 219 | self.assertFalse(PyMPFRInterval.bottom() == PyMPFRInterval(0, 0)) 220 | self.assertTrue(PyMPFRInterval(0, 0) == PyMPFRInterval(0, 0)) 221 | self.assertFalse(PyMPFRInterval(0, 0) == PyMPFRInterval(-0.5, 0.5)) 222 | self.assertTrue(PyMPFRInterval(-0.5, 0.5) == PyMPFRInterval(PyMPFR(-0.5), PyMPFR(0.5))) 223 | self.assertFalse(PyMPFRInterval(-0.5, 0.5) == PyMPFRInterval.top()) 224 | self.assertFalse(PyMPFRInterval.bottom() > PyMPFRInterval(0, 0)) 225 | self.assertTrue(PyMPFRInterval(0, 0) > PyMPFRInterval.bottom()) 226 | self.assertFalse(PyMPFRInterval(0, 0) > PyMPFRInterval(-0.5, 0.5)) 227 | self.assertTrue(PyMPFRInterval(-0.5, 0.5) > PyMPFRInterval(0, 0)) 228 | self.assertFalse(PyMPFRInterval(-0.5, 0.5) > PyMPFRInterval.top()) 229 | self.assertTrue(PyMPFRInterval.top() > PyMPFRInterval(-0.5, 0.5)) 230 | 231 | def test_is_top(self): 232 | self.assertFalse(PyMPFRInterval(0, 0).is_top()) 233 | self.assertFalse(PyMPFRInterval(0.0, 0.0).is_top()) 234 | self.assertFalse(PyMPFRInterval(PyMPFRScalar(0), PyMPFRScalar(0)).is_top()) 235 | self.assertFalse(PyMPFRInterval(PyMPFRScalar(0.0), PyMPFRScalar(0.0)).is_top()) 236 | self.assertFalse(PyMPFRInterval(-0.5, 0.5).is_top()) 237 | self.assertFalse(PyMPFRInterval(PyMPFR(-0.5), PyMPFR(0.5)).is_top()) 238 | self.assertFalse(PyMPFRInterval(PyMPFRScalar(-0.5), PyMPFRScalar(0.5)).is_top()) 239 | self.assertTrue(PyMPFRInterval.top().is_top()) 240 | self.assertFalse(PyMPFRInterval.bottom().is_top()) 241 | 242 | def test_neg(self): 243 | self.assertEqual(-PyMPFRInterval.bottom(), PyMPFRInterval.bottom()) 244 | self.assertEqual(-PyMPFRInterval(-1, 2), PyMPFRInterval(-2, 1)) 245 | self.assertEqual(-PyMPFRInterval(0, 0), PyMPFRInterval(0, 0)) 246 | self.assertEqual(-PyMPFRInterval(-0.5, 0.5), PyMPFRInterval(PyMPFR(-0.5), PyMPFR(0.5))) 247 | self.assertEqual(-PyMPFRInterval(1, 2), PyMPFRInterval(-2, -1)) 248 | self.assertEqual(-PyMPFRInterval.top(), PyMPFRInterval.top()) 249 | 250 | 251 | if __name__ == '__main__': 252 | unittest.main() 253 | -------------------------------------------------------------------------------- /apronpy/playground.py: -------------------------------------------------------------------------------- 1 | import faulthandler 2 | 3 | from apronpy.abstract1 import PyAbstract1 4 | from apronpy.cdll import libapron 5 | from apronpy.coeff import PyMPQScalarCoeff 6 | from apronpy.environment import PyEnvironment 7 | from apronpy.lincons0 import ConsTyp 8 | from apronpy.lincons1 import PyLincons1, PyLincons1Array 9 | from apronpy.linexpr1 import PyLinexpr1 10 | from apronpy.manager import PyManager, MemBuf 11 | from apronpy.polka import PyPolkaMPQstrictManager, PyPolka, libpolkaMPQ 12 | from apronpy.tcons1 import PyTcons1, PyTcons1Array 13 | from apronpy.texpr0 import TexprOp, TexprRtype, TexprRdir 14 | from apronpy.texpr1 import PyTexpr1 15 | from apronpy.var import PyVar 16 | 17 | faulthandler.enable() 18 | 19 | # libapron.ap_texpr1_print.argtypes = [POINTER(Texpr1)] 20 | # libapron.ap_texpr1_print(t.texpr1) 21 | # print() 22 | 23 | e = PyEnvironment([], [ 24 | PyVar('i1'), PyVar('i2'), 25 | PyVar('b1'), PyVar('h1'), 26 | PyVar('h2'), PyVar('b2'), 27 | PyVar('o1'), PyVar('o2'), 28 | ]) 29 | # outcome: o1 < o2 30 | x0 = PyLinexpr1(e) 31 | x0.set_coeff(PyVar('o1'), PyMPQScalarCoeff(-1)) 32 | x0.set_coeff(PyVar('o2'), PyMPQScalarCoeff(1)) 33 | c0 = PyLincons1(ConsTyp.AP_CONS_SUP, x0) 34 | print('c0', c0) 35 | o1 = PyTexpr1.var(e, PyVar('o1')) 36 | o2 = PyTexpr1.var(e, PyVar('o2')) 37 | x0bis = PyTexpr1.binop(TexprOp.AP_TEXPR_SUB, o2, o1, TexprRtype.AP_RTYPE_DOUBLE, TexprRdir.AP_RDIR_RND) 38 | c0bis = PyTcons1.make(x0bis, ConsTyp.AP_CONS_SUP) 39 | print('c0bis', c0bis) 40 | 41 | a0 = PyLincons1Array([c0]) 42 | m0 = PyPolkaMPQstrictManager() 43 | p0 = PyPolka(m0, e) #.meet(a0) 44 | print('p0', p0) 45 | 46 | s = libapron.ap_abstract1_serialize_raw(m0, p0) 47 | 48 | man_p = PyManager 49 | pya1 = PyAbstract1 50 | # ap_membuf_t ap_abstract1_serialize_raw(ap_manager_t* man, ap_abstract1_t* a); 51 | libapron.ap_abstract1_serialize_raw.argtypes = [man_p, pya1] 52 | libapron.ap_abstract1_serialize_raw.restype = MemBuf 53 | 54 | #p0 = PyPolkaMPQstrictManager(e).meet(a0) 55 | # p0bis = PyPolkaMPQstrictManager(e).meet(a0) 56 | # print('p0/p0bis', p0, p0bis) 57 | # a0bis = PyTcons1Array([c0bis.tcons1]) 58 | # p0bisbis = PyPolkaMPQstrictManager(e).meet(a0bis) 59 | # print('p0bisbis', p0bisbis) 60 | 61 | # o1 = 4 * h1 -1 * h2 + 4 62 | # o2 = -0.2 * h1 + 0.3 * h2 + 0.4 63 | # h1 = PyTexpr1.var(e, PyVar('h1')) 64 | # h2 = PyTexpr1.var(e, PyVar('h2')) 65 | # w1 = PyTexpr1.cst(e, PyMPQScalarCoeff(0.4)) 66 | # w2 = PyTexpr1.cst(e, PyMPQScalarCoeff(0.1)) 67 | # b1 = PyTexpr1.cst(e, PyMPQScalarCoeff(0.4)) 68 | # c1 = PyTexpr1.binop(TexprOp.AP_TEXPR_MUL, w1, h1, TexprRtype.AP_RTYPE_DOUBLE, TexprRdir.AP_RDIR_RND) 69 | # c2 = PyTexpr1.binop(TexprOp.AP_TEXPR_MUL, w2, h2, TexprRtype.AP_RTYPE_DOUBLE, TexprRdir.AP_RDIR_RND) 70 | # x0 = PyTexpr1.binop(TexprOp.AP_TEXPR_SUB, c1, c2, TexprRtype.AP_RTYPE_DOUBLE, TexprRdir.AP_RDIR_RND) 71 | # x2a = PyTexpr1.binop(TexprOp.AP_TEXPR_ADD, x0, b1, TexprRtype.AP_RTYPE_DOUBLE, TexprRdir.AP_RDIR_RND) 72 | # w3 = PyTexpr1.cst(e, PyMPQScalarCoeff(-0.2)) 73 | # w4 = PyTexpr1.cst(e, PyMPQScalarCoeff(0.3)) 74 | # b2 = PyTexpr1.cst(e, PyMPQScalarCoeff(0.4)) 75 | # c3 = PyTexpr1.binop(TexprOp.AP_TEXPR_MUL, w3, h1, TexprRtype.AP_RTYPE_DOUBLE, TexprRdir.AP_RDIR_RND) 76 | # c4 = PyTexpr1.binop(TexprOp.AP_TEXPR_MUL, w4, h2, TexprRtype.AP_RTYPE_DOUBLE, TexprRdir.AP_RDIR_RND) 77 | # x1 = PyTexpr1.binop(TexprOp.AP_TEXPR_ADD, c3, c4, TexprRtype.AP_RTYPE_DOUBLE, TexprRdir.AP_RDIR_RND) 78 | # x2b = PyTexpr1.binop(TexprOp.AP_TEXPR_ADD, x1, b2, TexprRtype.AP_RTYPE_DOUBLE, TexprRdir.AP_RDIR_RND) 79 | # p1 = p0.substitute(PyVar('o2'), x2b) 80 | # p2 = p1.substitute(PyVar('o1'), x2a) 81 | # print('x2b', x2b) 82 | # p2bis = p0bis.substitute([PyVar('o1'), PyVar('o2')], [x2a, x2b]) 83 | # p1bis = p0bisbis.substitute(PyVar('o2'), x2b) 84 | # print(p1, p2, p2bis, p1bis) 85 | 86 | # ALT 87 | 88 | #(- 3602879701896397/18014398509481984) · h1 + 5404319552844595/18014398509481984 · h2 + 3602879701896397/9007199254740992 89 | 90 | # # e 91 | # e = PyEnvironment([], [ 92 | # PyVar('i1'), PyVar('i2'), 93 | # PyVar('b1'), PyVar('h1'), 94 | # PyVar('h2'), PyVar('b2'), 95 | # PyVar('o1'), PyVar('o2'), 96 | # # PyVar('i3'), PyVar('i4'), 97 | # # PyVar('b3'), PyVar('h3'), 98 | # # PyVar('h4'), PyVar('b4'), 99 | # # PyVar('o3'), PyVar('o4'), 100 | # # PyVar('i5'), PyVar('i6'), 101 | # # PyVar('b5'), PyVar('h5'), 102 | # # PyVar('h6'), PyVar('b6'), 103 | # # PyVar('o5'), PyVar('o6'), 104 | # # PyVar('i7'), PyVar('i8'), 105 | # # PyVar('b7'), PyVar('h7'), 106 | # # PyVar('h8'), PyVar('b8'), 107 | # # PyVar('o7'), PyVar('o8'), 108 | # # PyVar('i9'), PyVar('i10'), 109 | # # PyVar('b9'), PyVar('h9'), 110 | # # PyVar('h10'), PyVar('b10'), 111 | # # PyVar('o9'), PyVar('o10'), 112 | # # PyVar('i11'), PyVar('i12'), 113 | # # PyVar('b11'), PyVar('h11'), 114 | # # PyVar('h12'), PyVar('b12'), 115 | # # PyVar('o11'), PyVar('o12') 116 | # ]) 117 | # result = PyPolkaMPQstrict.bottom(e) 118 | # 119 | # for i in range(4): 120 | # for j in range(4): 121 | # 122 | # # outcome: o1 < o2 123 | # x0 = PyLinexpr1(e) 124 | # x0.set_coeff(PyVar('o1'), PyMPFRScalarCoeff(-1)) 125 | # x0.set_coeff(PyVar('o2'), PyMPFRScalarCoeff(1)) 126 | # c0 = PyLincons1(ConsTyp.AP_CONS_SUP, x0) 127 | # a0 = PyLincons1Array([c0]) 128 | # p0 = PyPolkaMPQstrict(e).meet(a0) 129 | # p0bis = PyPolkaMPQstrict(e) 130 | # 131 | # print('Output') 132 | # print('p0: {}'.format(p0)) 133 | # print('p0bis: {}'.format(p0bis)) 134 | # print('p0 <= p0bis (expected: True): {}'.format(p0 <= p0bis)) 135 | # print('p0bis <= p0 (expected: False): {}'.format(p0bis <= p0)) 136 | # print() 137 | # 138 | # if i == 0: 139 | # # relu: assumption 0 <= o1, 0 <= o2 140 | # x1a = PyLinexpr1(e) 141 | # x1a.set_coeff(PyVar('o1'), PyMPFRScalarCoeff(1)) 142 | # c1a = PyLincons1(ConsTyp.AP_CONS_SUPEQ, x1a) # 0 <= o1 143 | # x1b = PyLinexpr1(e) 144 | # x1b.set_coeff(PyVar('o2'), PyMPFRScalarCoeff(1)) 145 | # c1b = PyLincons1(ConsTyp.AP_CONS_SUPEQ, x1b) # 0 <= o2 146 | # a1 = PyLincons1Array([c1a, c1b]) 147 | # p1 = p0.meet(a1) 148 | # p1bis = p0bis.meet(a1) 149 | # elif i == 1: 150 | # # relu: o2 = 0, assumption 0 <= o1, o2 < 0 151 | # x1a = PyLinexpr1(e) 152 | # x1a.set_cst(PyMPFRScalarCoeff(0.0)) 153 | # p1a = p0.substitute(PyVar('o2'), x1a) 154 | # p1abis = p0bis.substitute(PyVar('o2'), x1a) 155 | # x1b = PyLinexpr1(e) 156 | # x1b.set_coeff(PyVar('o1'), PyMPFRScalarCoeff(1)) 157 | # c1b = PyLincons1(ConsTyp.AP_CONS_SUPEQ, x1b) # 0 <= o1 158 | # x1c = PyLinexpr1(e) 159 | # x1c.set_coeff(PyVar('o2'), PyMPFRScalarCoeff(-1)) 160 | # c1c = PyLincons1(ConsTyp.AP_CONS_SUP, x1c) # o2 < 0 161 | # a1 = PyLincons1Array([c1b, c1c]) 162 | # p1 = p1a.meet(a1) 163 | # p1bis = p1abis.meet(a1) 164 | # elif i == 2: 165 | # # relu: o1 = 0, assumption o1 < 0, 0 <= o2 166 | # x1a = PyLinexpr1(e) 167 | # x1a.set_cst(PyMPFRScalarCoeff(0.0)) 168 | # p1a = p0.substitute(PyVar('o1'), x1a) 169 | # p1abis = p0bis.substitute(PyVar('o1'), x1a) 170 | # x1b = PyLinexpr1(e) 171 | # x1b.set_coeff(PyVar('o1'), PyMPFRScalarCoeff(-1)) 172 | # c1b = PyLincons1(ConsTyp.AP_CONS_SUP, x1b) # o1 < 0 173 | # x1c = PyLinexpr1(e) 174 | # x1c.set_coeff(PyVar('o2'), PyMPFRScalarCoeff(1)) 175 | # c1c = PyLincons1(ConsTyp.AP_CONS_SUPEQ, x1c) # 0 <= o2 176 | # a1 = PyLincons1Array([c1b, c1c]) 177 | # p1 = p1a.meet(a1) 178 | # p1bis = p1abis.meet(a1) 179 | # else: 180 | # # relu: o1 = 0, o2 = 0, assumption o1 < 0, o2 < 0 181 | # x1a = PyLinexpr1(e) 182 | # x1a.set_cst(PyMPFRScalarCoeff(0.0)) 183 | # p1a = p0.substitute(PyVar('o1'), x1a) 184 | # p1abis = p0bis.substitute(PyVar('o1'), x1a) 185 | # x1b = PyLinexpr1(e) 186 | # x1b.set_cst(PyMPFRScalarCoeff(0.0)) 187 | # p1b = p1a.substitute(PyVar('o2'), x1b) 188 | # p1bbis = p1abis.substitute(PyVar('o1'), x1b) 189 | # x1c = PyLinexpr1(e) 190 | # x1c.set_coeff(PyVar('o1'), PyMPFRScalarCoeff(-1)) 191 | # c1c = PyLincons1(ConsTyp.AP_CONS_SUP, x1c) # o1 < 0 192 | # x1d = PyLinexpr1(e) 193 | # x1d.set_coeff(PyVar('o2'), PyMPFRScalarCoeff(-1)) 194 | # c1d = PyLincons1(ConsTyp.AP_CONS_SUP, x1d) # o2 < 0 195 | # a1 = PyLincons1Array([c1c, c1d]) 196 | # p1 = p1b.meet(a1) 197 | # p1bis = p1bbis.meet(a1) 198 | # 199 | # print('ReLU(o1, o2) {}:{}'.format(i, j)) 200 | # print('p1: {}'.format(p1)) 201 | # print('p1bis: {}'.format(p1bis)) 202 | # print('p1 <= p1bis (expected: True): {}'.format(p1 <= p1bis)) 203 | # print('p1bis <= p1 (expected: False): {}'.format(p1bis <= p1)) 204 | # print() 205 | # 206 | # # o1 = -0.7566400101700294 * h1 -0.7521230014426193 * h2 + 0.6 207 | # # o2 = 66145339249.11405 * h1 + 68702343992.50064 * h2 + 0.6 208 | # x2a = PyLinexpr1(e) 209 | # x2a.set_coeff(PyVar('h1'), PyMPFRScalarCoeff(4)) 210 | # x2a.set_coeff(PyVar('h2'), PyMPFRScalarCoeff(-1)) 211 | # x2a.set_cst(PyMPFRScalarCoeff(4)) 212 | # x2b = PyLinexpr1(e) 213 | # x2b.set_coeff(PyVar('h1'), PyMPFRScalarCoeff(-2)) 214 | # x2b.set_coeff(PyVar('h2'), PyMPFRScalarCoeff(3)) 215 | # x2b.set_cst(PyMPFRScalarCoeff(4)) 216 | # p2a = p1.substitute(PyVar('o1'), x2a) 217 | # p2b = p2a.substitute(PyVar('o2'), x2b) 218 | # p2abis = p1bis.substitute(PyVar('o1'), x2a) 219 | # p2bbis = p2abis.substitute(PyVar('o2'), x2b) 220 | # 221 | # print('Layer(o1,o2) {}:{}'.format(i, j)) 222 | # print('p2b: {}'.format(p2b)) 223 | # print('p2bis: {}'.format(p2bbis)) 224 | # print('p2b <= p2bbis (expected: True): {}'.format(p2b <= p2bbis)) 225 | # print('p2bis <= p2b (expected: False): {}'.format(p2bbis <= p2b)) 226 | # print() 227 | # 228 | # if j == 0: 229 | # # relu: assumption 0 <= h1, 0 <= h2 230 | # x3a = PyLinexpr1(e) 231 | # x3a.set_coeff(PyVar('h1'), PyMPFRScalarCoeff(1)) 232 | # c3a = PyLincons1(ConsTyp.AP_CONS_SUPEQ, x3a) # 0 <= h1 233 | # x3b = PyLinexpr1(e) 234 | # x3b.set_coeff(PyVar('h2'), PyMPFRScalarCoeff(1)) 235 | # c3b = PyLincons1(ConsTyp.AP_CONS_SUPEQ, x3b) # 0 <= h2 236 | # a3 = PyLincons1Array([c3a, c3b]) 237 | # p3 = p2b.meet(a3) 238 | # p3bis = p2bbis.meet(a3) 239 | # elif j == 1: 240 | # # relu: h2 = 0, assumption 0 <= h1, h2 < 0 241 | # x3a = PyLinexpr1(e) 242 | # x3a.set_cst(PyMPFRScalarCoeff(0.0)) 243 | # p3a = p2b.substitute(PyVar('h2'), x3a) 244 | # p3abis = p2bbis.substitute(PyVar('h2'), x3a) 245 | # x3b = PyLinexpr1(e) 246 | # x3b.set_coeff(PyVar('h1'), PyMPFRScalarCoeff(1)) 247 | # c3b = PyLincons1(ConsTyp.AP_CONS_SUPEQ, x3b) # 0 <= h1 248 | # x3c = PyLinexpr1(e) 249 | # x3c.set_coeff(PyVar('h2'), PyMPFRScalarCoeff(-1)) 250 | # c3c = PyLincons1(ConsTyp.AP_CONS_SUP, x3c) # h2 < 0 251 | # a3 = PyLincons1Array([c3b, c3c]) 252 | # p3 = p3a.meet(a3) 253 | # p3bis = p3abis.meet(a3) 254 | # elif j == 2: 255 | # # relu: h1 = 0, assumption h1 < 0, 0 <= h2 256 | # x3a = PyLinexpr1(e) 257 | # x3a.set_cst(PyMPFRScalarCoeff(0.0)) 258 | # p3a = p2b.substitute(PyVar('h1'), x3a) 259 | # p3abis = p2bbis.substitute(PyVar('h1'), x3a) 260 | # x3b = PyLinexpr1(e) 261 | # x3b.set_coeff(PyVar('h1'), PyMPFRScalarCoeff(-1)) 262 | # c3b = PyLincons1(ConsTyp.AP_CONS_SUP, x3b) # h1 < 0 263 | # x3c = PyLinexpr1(e) 264 | # x3c.set_coeff(PyVar('h2'), PyMPFRScalarCoeff(1)) 265 | # c3c = PyLincons1(ConsTyp.AP_CONS_SUPEQ, x3c) # 0 <= h2 266 | # a3 = PyLincons1Array([c3b, c3c]) 267 | # p3 = p3a.meet(a3) 268 | # p3bis = p3abis.meet(a3) 269 | # else: 270 | # # relu: h1 = 0, h2 = 0, assumption h1 < 0, h2 < 0 271 | # x3a = PyLinexpr1(e) 272 | # x3a.set_cst(PyMPFRScalarCoeff(0.0)) 273 | # p3a = p2b.substitute(PyVar('h1'), x3a) 274 | # p3abis = p2bbis.substitute(PyVar('h1'), x3a) 275 | # x3b = PyLinexpr1(e) 276 | # x3b.set_cst(PyMPFRScalarCoeff(0.0)) 277 | # p3b = p3a.substitute(PyVar('h2'), x3b) 278 | # p3bbis = p3abis.substitute(PyVar('h1'), x3b) 279 | # x3c = PyLinexpr1(e) 280 | # x3c.set_coeff(PyVar('h1'), PyMPFRScalarCoeff(-1)) 281 | # c3c = PyLincons1(ConsTyp.AP_CONS_SUP, x3c) # h1 < 0 282 | # x3d = PyLinexpr1(e) 283 | # x3d.set_coeff(PyVar('h2'), PyMPFRScalarCoeff(-1)) 284 | # c3d = PyLincons1(ConsTyp.AP_CONS_SUP, x3d) # h2 < 0 285 | # a3 = PyLincons1Array([c3c, c3d]) 286 | # p3 = p3b.meet(a3) 287 | # p3bis = p3bbis.meet(a3) 288 | # 289 | # print('ReLU(h1,h2) {}:{}'.format(i, j)) 290 | # print('p3: {}'.format(p3)) 291 | # print('p3bis: {}'.format(p3bis)) 292 | # print('p3 <= p3bis (expected: True): {}'.format(p3 <= p3bis)) 293 | # print('p3is <= p3 (expected: False): {}'.format(p3bis <= p3)) 294 | # print() 295 | # 296 | # # h1 = -3563343016573.1133 * i1 + -7126686033146.326 * i2 + 0.35 297 | # # h2 = -4042063042100.3296 * i1 + -8084126084200.859 * i2 + 0.35 298 | # x4a = PyLinexpr1(e) 299 | # x4a.set_coeff(PyVar('i1'), PyMPFRScalarCoeff(1)) 300 | # x4a.set_coeff(PyVar('i2'), PyMPFRScalarCoeff(-1)) 301 | # x4a.set_cst(PyMPFRScalarCoeff(1)) 302 | # x4b = PyLinexpr1(e) 303 | # x4b.set_coeff(PyVar('i1'), PyMPFRScalarCoeff(-1)) 304 | # x4b.set_coeff(PyVar('i2'), PyMPFRScalarCoeff(2)) 305 | # x4b.set_cst(PyMPFRScalarCoeff(1)) 306 | # p4a = p3.substitute(PyVar('h1'), x4a) 307 | # p4b = p4a.substitute(PyVar('h2'), x4b) 308 | # p4abis = p3bis.substitute(PyVar('h1'), x4a) 309 | # p4bbis = p4abis.substitute(PyVar('h2'), x4b) 310 | # 311 | # print('Layer(h1,h2) {}:{}'.format(i, j)) 312 | # print('p4b: {}'.format(p4b)) 313 | # print('p4bis: {}'.format(p4bbis)) 314 | # print('p4b <= p4bbis (expected: True): {}'.format(p4b <= p4bbis)) 315 | # print('p4bbis <= p4b (expected: False): {}'.format(p4bbis <= p4b)) 316 | # print() 317 | # 318 | # # 0 <= i1 <= 1, 0 <= i2 <= 1 319 | # x5a = PyLinexpr1(e) 320 | # # x5a.set_coeff(PyVar('i1'), PyMPFRScalarCoeff(1)) 321 | # c5a = PyLincons1(ConsTyp.AP_CONS_SUPEQ, x5a) # i1 >= 0 322 | # x5b = PyLinexpr1(e) 323 | # # x5b.set_coeff(PyVar('i1'), PyMPFRScalarCoeff(-1)) 324 | # # x5b.set_cst(PyMPFRScalarCoeff(1)) 325 | # c5b = PyLincons1(ConsTyp.AP_CONS_SUPEQ, x5b) # -i1 + 1 >= 0 326 | # x5c = PyLinexpr1(e) 327 | # x5c.set_coeff(PyVar('i2'), PyMPFRScalarCoeff(1)) 328 | # c5c = PyLincons1(ConsTyp.AP_CONS_SUPEQ, x5c) # i2 >= 0 329 | # x5d = PyLinexpr1(e) 330 | # x5d.set_coeff(PyVar('i2'), PyMPFRScalarCoeff(-1)) 331 | # x5d.set_cst(PyMPFRScalarCoeff(1)) 332 | # c5d = PyLincons1(ConsTyp.AP_CONS_SUPEQ, x5d) # -i2 + 1 >= 0 333 | # a5 = PyLincons1Array([c5a, c5b, c5c, c5d]) 334 | # p5 = p4b.meet(a5) 335 | # p5bis = p4bbis.meet(a5) 336 | # 337 | # print('Input {}:{}'.format(i, j)) 338 | # print('p5: {}'.format(p5)) 339 | # print('p5is: {}'.format(p5bis)) 340 | # print('p5 <= p5bis (expected: True): {}'.format(p5 <= p5bis)) 341 | # print('p5bis <= p5b (expected: False): {}'.format(p5bis <= p5)) 342 | # print() 343 | # print() 344 | # 345 | # result = result.join(p5) 346 | # 347 | # print('Result: {}'.format(result)) 348 | # print() 349 | 350 | print("Done") 351 | -------------------------------------------------------------------------------- /apronpy/abstract1.py: -------------------------------------------------------------------------------- 1 | """ 2 | APRON Abstract Values (Level 1) 3 | =============================== 4 | 5 | :Author: Caterina Urban 6 | """ 7 | from _ctypes import Structure, POINTER, byref 8 | from abc import ABCMeta 9 | from ctypes import c_size_t, c_char_p, c_bool 10 | from typing import List, Type, Union 11 | 12 | from apronpy.abstract0 import Abstract0 13 | from apronpy.cdll import libapron 14 | from apronpy.environment import Environment, PyEnvironment 15 | from apronpy.interval import Interval, PyInterval 16 | from apronpy.lincons1 import Lincons1Array, PyLincons1Array 17 | from apronpy.linexpr1 import PyLinexpr1, Linexpr1 18 | from apronpy.manager import PyManager 19 | from apronpy.tcons1 import PyTcons1Array, TCons1Array 20 | from apronpy.texpr1 import PyTexpr1, Texpr1 21 | from apronpy.var import PyVar 22 | 23 | APRON_assign_linexpr_array = libapron.ap_abstract1_assign_linexpr_array 24 | APRON_assign_texpr_array = libapron.ap_abstract1_assign_texpr_array 25 | APRON_substitute_linexpr_array = libapron.ap_abstract1_substitute_linexpr_array 26 | APRON_substitute_texpr_array = libapron.ap_abstract1_substitute_texpr_array 27 | 28 | 29 | class Abstract1(Structure): 30 | """ 31 | typedef struct ap_abstract1_t { 32 | ap_abstract0_t* abstract0; 33 | ap_environment_t* env; 34 | } ap_abstract1_t; 35 | """ 36 | 37 | _fields_ = [ 38 | ('abstract0', POINTER(Abstract0)), 39 | ('env', POINTER(Environment)) 40 | ] 41 | 42 | 43 | class PyAbstract1(metaclass=ABCMeta): 44 | 45 | # noinspection PyTypeChecker 46 | def __init__(self, manager: PyManager, 47 | abstract1_or_environment: Union[Abstract1, PyEnvironment], 48 | bottom: bool = False, array: Union[PyLincons1Array, PyTcons1Array] = None, 49 | variables: List[PyVar] = None, intervals: List[PyInterval] = None): 50 | self.manager = manager 51 | if isinstance(abstract1_or_environment, Abstract1): 52 | self.abstract1 = abstract1_or_environment 53 | elif bottom: 54 | assert isinstance(abstract1_or_environment, PyEnvironment) 55 | self.abstract1 = libapron.ap_abstract1_bottom(self.manager, abstract1_or_environment) 56 | elif array and isinstance(array, PyLincons1Array): 57 | assert isinstance(abstract1_or_environment, PyEnvironment) 58 | man = self.manager 59 | a1 = libapron.ap_abstract1_of_lincons_array(man, abstract1_or_environment, array) 60 | self.abstract1 = a1 61 | elif array and isinstance(array, PyTcons1Array): 62 | assert isinstance(abstract1_or_environment, PyEnvironment) 63 | man = self.manager 64 | a1 = libapron.ap_abstract1_of_tcons_array(man, abstract1_or_environment, array) 65 | self.abstract1 = a1 66 | elif variables and intervals: 67 | assert isinstance(abstract1_or_environment, PyEnvironment) 68 | size = len(variables) 69 | v_typ: Type = c_char_p * size 70 | v_arr = v_typ(*(x._as_parameter_ for x in variables)) 71 | i_typ: Type = POINTER(Interval) * size 72 | i_arr = i_typ(*(x._as_parameter_ for x in intervals)) 73 | man = self.manager 74 | a1 = libapron.ap_abstract1_of_box(man, abstract1_or_environment, v_arr, i_arr, size) 75 | self.abstract1 = a1 76 | else: 77 | assert isinstance(abstract1_or_environment, PyEnvironment) 78 | self.abstract1 = libapron.ap_abstract1_top(self.manager, abstract1_or_environment) 79 | 80 | def closure(self): 81 | return type(self)(self.manager, libapron.ap_abstract1_closure(self.manager, False, self)) 82 | 83 | @classmethod 84 | def bottom(cls, manager: PyManager, environment: PyEnvironment): 85 | return cls(manager, environment, bottom=True) 86 | 87 | @classmethod 88 | def from_constraints(cls, manager: PyManager, environment: PyEnvironment, array): 89 | return cls(manager, environment, array=array) 90 | 91 | @classmethod 92 | def top(cls, manager: PyManager, environment: PyEnvironment): 93 | return cls(manager, environment) 94 | 95 | def __deepcopy__(self, memodict=None): 96 | if memodict is None: 97 | memodict = {} 98 | abstract1 = libapron.ap_abstract1_copy(self.manager, self) 99 | result = type(self)(self.manager, abstract1) 100 | memodict[id(self)] = result 101 | return result 102 | 103 | def __del__(self): 104 | libapron.ap_abstract1_clear(self.manager, self) 105 | del self.abstract1 106 | 107 | @property 108 | def _as_parameter_(self): 109 | return byref(self.abstract1) 110 | 111 | @staticmethod 112 | def from_param(argument): 113 | assert isinstance(argument, PyAbstract1) 114 | return argument 115 | 116 | @property 117 | def to_lincons(self) -> PyLincons1Array: 118 | return PyLincons1Array(libapron.ap_abstract1_to_lincons_array(self.manager, self)) 119 | 120 | @property 121 | def to_tcons(self) -> PyTcons1Array: 122 | return PyTcons1Array(libapron.ap_abstract1_to_tcons_array(self.manager, self)) 123 | 124 | def __repr__(self): 125 | array = PyLincons1Array(libapron.ap_abstract1_to_lincons_array(self.manager, self)) 126 | return '{}'.format(array) 127 | 128 | @property 129 | def environment(self) -> PyEnvironment: 130 | environment = libapron.ap_abstract1_environment(self.manager, self) 131 | environment.contents.count += 1 132 | return PyEnvironment(environment) 133 | 134 | @environment.setter 135 | def environment(self, environment: PyEnvironment): 136 | e_size = len(environment) 137 | a1 = libapron.ap_abstract1_change_environment(self.manager, False, self, environment, e_size, False) 138 | self.abstract1 = a1 139 | 140 | def is_bottom(self): 141 | return bool(libapron.ap_abstract1_is_bottom(self.manager, self)) 142 | 143 | def is_top(self): 144 | return bool(libapron.ap_abstract1_is_top(self.manager, self)) 145 | 146 | def __le__(self, other: 'PyAbstract1'): 147 | assert isinstance(other, PyAbstract1) 148 | return bool(libapron.ap_abstract1_is_leq(self.manager, self, other)) 149 | 150 | def is_leq(self, other: 'PyAbstract1'): 151 | assert isinstance(other, PyAbstract1) 152 | return self.__le__(other) 153 | 154 | def __eq__(self, other: 'PyAbstract1'): 155 | assert isinstance(other, PyAbstract1) 156 | return bool(libapron.ap_abstract1_is_eq(self.manager, self, other)) 157 | 158 | def is_eq(self, other: 'PyAbstract1'): 159 | assert isinstance(other, PyAbstract1) 160 | return self.__eq__(other) 161 | 162 | def bound_variable(self, var: PyVar): 163 | return PyInterval(libapron.ap_abstract1_bound_variable(self.manager, self, var)) 164 | 165 | def bound_linexpr(self, linexpr: PyLinexpr1): 166 | return PyInterval(libapron.ap_abstract1_bound_linexpr(self.manager, self, linexpr)) 167 | 168 | def bound_texpr(self, texpr: PyTexpr1): 169 | return PyInterval(libapron.ap_abstract1_bound_texpr(self.manager, self, texpr)) 170 | 171 | def meet(self, other: Union['PyAbstract1', PyLincons1Array, PyTcons1Array]): 172 | if isinstance(other, PyLincons1Array): 173 | abstract1 = libapron.ap_abstract1_meet_lincons_array(self.manager, False, self, other) 174 | return type(self)(self.manager, abstract1) 175 | elif isinstance(other, PyTcons1Array): 176 | abstract1 = libapron.ap_abstract1_meet_tcons_array(self.manager, False, self, other) 177 | return type(self)(self.manager, abstract1) 178 | else: 179 | assert isinstance(other, PyAbstract1) 180 | abstract1 = libapron.ap_abstract1_meet(self.manager, False, self, other) 181 | return type(self)(self.manager, abstract1) 182 | 183 | def join(self, other: 'PyAbstract1'): 184 | assert isinstance(other, PyAbstract1) 185 | return type(self)(self.manager, libapron.ap_abstract1_join(self.manager, False, self, other)) 186 | 187 | def widening(self, other: 'PyAbstract1'): 188 | assert isinstance(other, PyAbstract1) 189 | return type(self)(self.manager, libapron.ap_abstract1_widening(self.manager, self, other)) 190 | 191 | # noinspection PyTypeChecker 192 | def assign(self, var_or_vars: PyVar, expr_or_exprs: Union[PyLinexpr1, PyTexpr1]): 193 | man = self.manager 194 | if isinstance(var_or_vars, PyVar): 195 | var = var_or_vars 196 | expr = expr_or_exprs 197 | if isinstance(expr, PyLinexpr1): 198 | abstract1 = libapron.ap_abstract1_assign_linexpr(man, False, self, var, expr, None) 199 | return type(self)(self.manager, abstract1) 200 | else: 201 | assert isinstance(expr, PyTexpr1) 202 | abstract1 = libapron.ap_abstract1_assign_texpr(man, False, self, var, expr, None) 203 | return type(self)(self.manager, abstract1) 204 | else: 205 | assert isinstance(var_or_vars, list) 206 | assert all(isinstance(var, PyVar) for var in var_or_vars) 207 | exprs = expr_or_exprs 208 | if all(isinstance(expr, PyLinexpr1) for expr in exprs): 209 | v_size = len(var_or_vars) 210 | e_size = len(exprs) 211 | assert v_size == e_size 212 | v_typ: Type = c_char_p * v_size 213 | v_arr = v_typ(*(x._as_parameter_ for x in var_or_vars)) 214 | e_typ: Type = Linexpr1 * e_size 215 | e_arr = e_typ(*(e.linexpr1 for e in exprs)) 216 | a1 = APRON_assign_linexpr_array(man, False, self, v_arr, e_arr, v_size, None) 217 | return type(self)(self.manager, a1) 218 | else: 219 | assert all(isinstance(expr, PyTexpr1) for expr in exprs) 220 | v_size = len(var_or_vars) 221 | e_size = len(exprs) 222 | assert v_size == e_size 223 | v_typ: Type = c_char_p * v_size 224 | v_arr = v_typ(*(x._as_parameter_ for x in var_or_vars)) 225 | e_typ: Type = Texpr1 * e_size 226 | e_arr = e_typ(*(e.texpr1.contents for e in exprs)) 227 | a1 = APRON_assign_texpr_array(man, False, self, v_arr, e_arr, v_size, None) 228 | return type(self)(self.manager, a1) 229 | 230 | # noinspection PyTypeChecker 231 | def substitute(self, var_or_vars: Union[PyVar, List[PyVar]], 232 | expr_or_exprs: Union[PyLinexpr1, PyTexpr1, List[PyLinexpr1], List[PyTexpr1]]): 233 | man = self.manager 234 | if isinstance(var_or_vars, PyVar): 235 | var = var_or_vars 236 | expr = expr_or_exprs 237 | if isinstance(expr, PyLinexpr1): 238 | a1 = libapron.ap_abstract1_substitute_linexpr(man, False, self, var, expr, None) 239 | return type(self)(self.manager, a1) 240 | else: 241 | assert isinstance(expr, PyTexpr1) 242 | a1 = libapron.ap_abstract1_substitute_texpr(man, False, self, var, expr, None) 243 | return type(self)(self.manager, a1) 244 | else: 245 | assert isinstance(var_or_vars, list) 246 | assert all(isinstance(var, PyVar) for var in var_or_vars) 247 | exprs = expr_or_exprs 248 | if all(isinstance(expr, PyLinexpr1) for expr in exprs): 249 | v_size = len(var_or_vars) 250 | e_size = len(exprs) 251 | assert v_size == e_size 252 | v_typ: Type = c_char_p * v_size 253 | v_arr = v_typ(*(x._as_parameter_ for x in var_or_vars)) 254 | e_typ: Type = Linexpr1 * e_size 255 | e_arr = e_typ(*(e.linexpr1 for e in exprs)) 256 | a1 = APRON_substitute_linexpr_array(man, False, self, v_arr, e_arr, v_size, None) 257 | return type(self)(self.manager, a1) 258 | else: 259 | assert all(isinstance(expr, PyTexpr1) for expr in exprs) 260 | v_size = len(var_or_vars) 261 | e_size = len(exprs) 262 | assert v_size == e_size 263 | v_typ: Type = c_char_p * v_size 264 | v_arr = v_typ(*(x._as_parameter_ for x in var_or_vars)) 265 | e_typ: Type = Texpr1 * e_size 266 | e_arr = e_typ(*(e.texpr1.contents for e in exprs)) 267 | a1 = APRON_substitute_texpr_array(man, False, self, v_arr, e_arr, v_size, None) 268 | return type(self)(self.manager, a1) 269 | 270 | # noinspection PyTypeChecker 271 | def forget(self, variables: List[PyVar]): 272 | v_size = len(variables) 273 | v_typ: Type = c_char_p * v_size 274 | v_arr = v_typ(*(x._as_parameter_ for x in variables)) 275 | a1 = libapron.ap_abstract1_forget_array(self.manager, False, self, v_arr, v_size, False) 276 | return type(self)(self.manager, a1) 277 | 278 | 279 | man_p = PyManager 280 | pya1 = PyAbstract1 281 | libapron.ap_abstract1_copy.argtypes = [man_p, pya1] 282 | libapron.ap_abstract1_copy.restype = Abstract1 283 | libapron.ap_abstract1_clear.argtypes = [man_p, pya1] 284 | libapron.ap_abstract1_bottom.argtypes = [man_p, PyEnvironment] 285 | libapron.ap_abstract1_bottom.restype = Abstract1 286 | pyvar_p = POINTER(c_char_p) 287 | pyitv_p = POINTER(POINTER(Interval)) 288 | libapron.ap_abstract1_of_box.argtypes = [man_p, PyEnvironment, pyvar_p, pyitv_p, c_size_t] 289 | libapron.ap_abstract1_of_box.restype = Abstract1 290 | libapron.ap_abstract1_top.argtypes = [man_p, PyEnvironment] 291 | libapron.ap_abstract1_top.restype = Abstract1 292 | libapron.ap_abstract1_environment.argtypes = [man_p, pya1] 293 | libapron.ap_abstract1_environment.restype = POINTER(Environment) 294 | libapron.ap_abstract1_is_bottom.argtypes = [man_p, pya1] 295 | libapron.ap_abstract1_is_bottom.restype = c_bool 296 | libapron.ap_abstract1_is_top.argtypes = [man_p, pya1] 297 | libapron.ap_abstract1_is_top.restype = c_bool 298 | libapron.ap_abstract1_is_leq.argtypes = [man_p, pya1, pya1] 299 | libapron.ap_abstract1_is_leq.restype = c_bool 300 | libapron.ap_abstract1_is_eq.argtypes = [man_p, pya1, pya1] 301 | libapron.ap_abstract1_is_eq.restype = c_bool 302 | libapron.ap_abstract1_bound_linexpr.argtypes = [man_p, pya1, PyLinexpr1] 303 | libapron.ap_abstract1_bound_linexpr.restype = POINTER(Interval) 304 | libapron.ap_abstract1_bound_texpr.argtypes = [man_p, pya1, PyTexpr1] 305 | libapron.ap_abstract1_bound_texpr.restype = POINTER(Interval) 306 | libapron.ap_abstract1_bound_variable.argtypes = [man_p, pya1, PyVar] 307 | libapron.ap_abstract1_bound_variable.restype = POINTER(Interval) 308 | libapron.ap_abstract1_to_lincons_array.argtypes = [man_p, pya1] 309 | libapron.ap_abstract1_to_lincons_array.restype = Lincons1Array 310 | libapron.ap_abstract1_to_tcons_array.argtypes = [man_p, pya1] 311 | libapron.ap_abstract1_to_tcons_array.restype = TCons1Array 312 | libapron.ap_abstract1_meet.argtypes = [man_p, c_bool, pya1, pya1] 313 | libapron.ap_abstract1_meet.restype = Abstract1 314 | libapron.ap_abstract1_meet_lincons_array.argtypes = [man_p, c_bool, pya1, PyLincons1Array] 315 | libapron.ap_abstract1_meet_lincons_array.restype = Abstract1 316 | libapron.ap_abstract1_meet_tcons_array.argtypes = [man_p, c_bool, pya1, PyTcons1Array] 317 | libapron.ap_abstract1_meet_tcons_array.restype = Abstract1 318 | libapron.ap_abstract1_join.argtypes = [man_p, c_bool, pya1, pya1] 319 | libapron.ap_abstract1_join.restype = Abstract1 320 | libapron.ap_abstract1_widening.argtypes = [man_p, pya1, pya1] 321 | libapron.ap_abstract1_widening.restype = Abstract1 322 | libapron.ap_abstract1_closure.argtypes = [man_p, c_bool, pya1] 323 | libapron.ap_abstract1_closure.restype = Abstract1 324 | pyl1 = PyLinexpr1 325 | pya1_p = POINTER(Abstract1) 326 | libapron.ap_abstract1_of_lincons_array.argtypes = [man_p, PyEnvironment, PyLincons1Array] 327 | libapron.ap_abstract1_of_lincons_array.restype = Abstract1 328 | libapron.ap_abstract1_of_tcons_array.argtypes = [man_p, PyEnvironment, PyTcons1Array] 329 | libapron.ap_abstract1_of_tcons_array.restype = Abstract1 330 | pyl1_p = POINTER(Linexpr1) 331 | APRON_assign_linexpr_array.argtypes = [man_p, c_bool, pya1, pyvar_p, pyl1_p, c_size_t, pya1_p] 332 | APRON_assign_linexpr_array.restype = Abstract1 333 | libapron.ap_abstract1_assign_linexpr.argtypes = [man_p, c_bool, pya1, PyVar, pyl1, pya1_p] 334 | libapron.ap_abstract1_assign_linexpr.restype = Abstract1 335 | APRON_substitute_linexpr_array.argtypes = [man_p, c_bool, pya1, pyvar_p, pyl1_p, c_size_t, pya1_p] 336 | APRON_substitute_linexpr_array.restype = Abstract1 337 | libapron.ap_abstract1_substitute_linexpr.argtypes = [man_p, c_bool, pya1, PyVar, pyl1, pya1_p] 338 | libapron.ap_abstract1_substitute_linexpr.restype = Abstract1 339 | pyt1_p = POINTER(Texpr1) 340 | APRON_assign_texpr_array.argtypes = [man_p, c_bool, pya1, pyvar_p, pyt1_p, c_size_t, pya1_p] 341 | APRON_assign_texpr_array.restype = Abstract1 342 | libapron.ap_abstract1_assign_texpr.argtypes = [man_p, c_bool, pya1, PyVar, PyTexpr1, pya1_p] 343 | libapron.ap_abstract1_assign_texpr.restype = Abstract1 344 | APRON_substitute_texpr_array.argtypes = [man_p, c_bool, pya1, pyvar_p, pyt1_p, c_size_t, pya1_p] 345 | APRON_substitute_texpr_array.restype = Abstract1 346 | libapron.ap_abstract1_substitute_texpr.argtypes = [man_p, c_bool, pya1, PyVar, PyTexpr1, pya1_p] 347 | libapron.ap_abstract1_substitute_texpr.restype = Abstract1 348 | libapron.ap_abstract1_forget_array.argtypes = [man_p, c_bool, pya1, pyvar_p, c_size_t, c_bool] 349 | libapron.ap_abstract1_forget_array.restype = Abstract1 350 | pyenv = PyEnvironment 351 | libapron.ap_abstract1_change_environment.argtypes = [man_p, c_bool, pya1, pyenv, c_size_t, c_bool] 352 | libapron.ap_abstract1_change_environment.restype = Abstract1 353 | --------------------------------------------------------------------------------