2 import ctypes
, ctypes
.util
8 from decimal
import Decimal
9 from fractions
import Fraction
10 from functools
import wraps
13 libisl
= ctypes
.CDLL(ctypes
.util
.find_library('isl'))
15 libisl
.isl_printer_get_str
.restype
= ctypes
.c_char_p
23 self
._ic
= libisl
.isl_ctx_alloc()
26 def _as_parameter_(self
):
30 libisl
.isl_ctx_free(self
)
32 def __eq__(self
, other
):
33 if not isinstance(other
, Context
):
35 return self
._ic
== other
._ic
42 return super().__new
__(cls
, iv
)
44 return '{}({})'.format(self
.__class
__.__name
__, self
)
46 _RE_NONFINITE
= re
.compile(
47 r
'^\s*(?P<sign>[-+])?((?P<inf>Inf(inity)?)|(?P<nan>NaN))\s*$',
50 _RE_FRACTION
= re
.compile(r
'^(?P<num>[-+]?\d+)(/(?P<den>\d+))?$')
52 __slots__
= ('context', '_iv', '_numerator', '_denominator')
54 def __new__(cls
, context
, numerator
=0, denominator
=None):
55 self
= super().__new
__(cls
)
56 if not isinstance(context
, Context
):
57 raise TypeError('first argument should be a context')
58 self
.context
= context
59 if isinstance(numerator
, cls
._ptr
):
60 assert denominator
is None
62 if libisl
.isl_val_is_rat(self
):
63 # retrieve numerator and denominator as strings to avoid integer
65 ip
= libisl
.isl_printer_to_str(self
.context
)
66 ip
= libisl
.isl_printer_print_val(ip
, self
)
67 string
= libisl
.isl_printer_get_str(ip
).decode()
68 libisl
.isl_printer_free(ip
)
69 m
= self
._RE
_FRACTION
.match(string
)
71 self
._numerator
= int(m
.group('num'))
72 self
._denominator
= int(m
.group('den')) if m
.group('den') else 1
74 self
._numerator
= None
75 self
._denominator
= None
77 if isinstance(numerator
, str) and denominator
is None:
78 m
= self
._RE
_NONFINITE
.match(numerator
)
80 self
._numerator
= None
81 self
._denominator
= None
83 if m
.group('sign') == '-':
84 self
._iv
= libisl
.isl_val_neginfty(context
)
86 self
._iv
= libisl
.isl_val_infty(context
)
89 self
._iv
= libisl
.isl_val_nan(context
)
92 frac
= Fraction(numerator
, denominator
)
94 raise ValueError('invalid literal for {}: {!r}'.format(
95 cls
.__name
__, numerator
))
96 self
._numerator
= frac
.numerator
97 self
._denominator
= frac
.denominator
98 # values passed as strings to avoid integer overflows
99 if frac
.denominator
== 1:
100 numerator
= str(frac
.numerator
).encode()
101 self
._iv
= libisl
.isl_val_read_from_str(context
, numerator
)
103 numerator
= str(frac
.numerator
).encode()
104 numerator
= libisl
.isl_val_read_from_str(context
, numerator
)
105 denominator
= str(frac
.denominator
).encode()
106 denominator
= libisl
.isl_val_read_from_str(context
, denominator
)
107 self
._iv
= libisl
.isl_val_div(numerator
, denominator
)
111 def _as_parameter_(self
):
115 libisl
.isl_val_free(self
)
116 self
.context
# prevents context from being GC'ed before the value
120 if self
._numerator
is None:
121 raise ValueError('not a rational number')
122 return self
._numerator
125 def denominator(self
):
126 if self
._denominator
is None:
127 raise ValueError('not a rational number')
128 return self
._denominator
131 return not bool(libisl
.isl_val_is_zero(self
))
133 def _polymorphic(func
):
135 def wrapper(self
, other
):
136 if isinstance(other
, Value
):
137 return func(self
, other
)
138 if isinstance(other
, numbers
.Rational
):
139 other
= Value(self
.context
, other
)
140 return func(self
, other
)
141 raise TypeError('operand should be a Value or a Rational')
145 def __lt__(self
, other
):
146 return bool(libisl
.isl_val_lt(self
, other
))
149 def __le__(self
, other
):
150 return bool(libisl
.isl_val_le(self
, other
))
153 def __gt__(self
, other
):
154 return bool(libisl
.isl_val_gt(self
, other
))
157 def __ge__(self
, other
):
158 return bool(libisl
.isl_val_ge(self
, other
))
161 def __eq__(self
, other
):
162 return bool(libisl
.isl_val_eq(self
, other
))
164 # __ne__ is not implemented, ISL semantics does not match Python's on
168 val
= libisl
.isl_val_copy(self
)
169 val
= libisl
.isl_val_abs(val
)
170 return self
.__class
__(self
.context
, self
._ptr
(val
))
176 val
= libisl
.isl_val_copy(self
)
177 val
= libisl
.isl_val_neg(val
)
178 return self
.__class
__(self
.context
, self
._ptr
(val
))
181 val
= libisl
.isl_val_copy(self
)
182 val
= libisl
.isl_val_floor(val
)
183 return self
.__class
__(self
.context
, self
._ptr
(val
))
186 val
= libisl
.isl_val_copy(self
)
187 val
= libisl
.isl_val_ceil(val
)
188 return self
.__class
__(self
.context
, self
._ptr
(val
))
191 val
= libisl
.isl_val_copy(self
)
192 val
= libisl
.isl_val_trunc(val
)
193 return self
.__class
__(self
.context
, self
._ptr
(val
))
196 def __add__(self
, other
):
197 val1
= libisl
.isl_val_copy(self
)
198 val2
= libisl
.isl_val_copy(other
)
199 val
= libisl
.isl_val_add(val1
, val2
)
200 return self
.__class
__(self
.context
, self
._ptr
(val
))
205 def __sub__(self
, other
):
206 val1
= libisl
.isl_val_copy(self
)
207 val2
= libisl
.isl_val_copy(other
)
208 val
= libisl
.isl_val_sub(val1
, val2
)
209 return self
.__class
__(self
.context
, self
._ptr
(val
))
214 def __mul__(self
, other
):
215 val1
= libisl
.isl_val_copy(self
)
216 val2
= libisl
.isl_val_copy(other
)
217 val
= libisl
.isl_val_mul(val1
, val2
)
218 return self
.__class
__(self
.context
, self
._ptr
(val
))
223 def __truediv__(self
, other
):
224 val1
= libisl
.isl_val_copy(self
)
225 val2
= libisl
.isl_val_copy(other
)
226 val
= libisl
.isl_val_div(val1
, val2
)
227 return self
.__class
__(self
.context
, self
._ptr
(val
))
229 __rtruediv__
= __truediv__
232 if libisl
.isl_val_is_rat(self
):
233 return self
.numerator
/ self
.denominator
234 elif libisl
.isl_val_is_infty(self
):
236 elif libisl
.isl_val_is_neginfty(self
):
239 assert libisl
.isl_val_is_nan(self
)
243 return bool(libisl
.isl_val_is_rat(self
))
245 def is_infinite(self
):
246 return bool(libisl
.isl_val_is_infty(self
) or
247 libisl
.isl_val_is_neginfty(self
))
250 return bool(libisl
.isl_val_is_nan(self
))
253 if libisl
.isl_val_is_rat(self
):
254 if self
.denominator
== 1:
255 return '{}'.format(self
.numerator
)
257 return '{}/{}'.format(self
.numerator
, self
.denominator
)
258 elif libisl
.isl_val_is_infty(self
):
260 elif libisl
.isl_val_is_neginfty(self
):
263 assert libisl
.isl_val_is_nan(self
)
267 return '{}({!r})'.format(self
.__class
__.__name
__, str(self
))