2 import ctypes
, ctypes
.util
9 from decimal
import Decimal
10 from fractions
import Fraction
11 from functools
import wraps
14 libisl
= ctypes
.CDLL(ctypes
.util
.find_library('isl'))
16 libisl
.isl_printer_get_str
.restype
= ctypes
.c_char_p
18 def _polymorphic_method(func
):
19 @functools.wraps(func
)
20 def wrapper(self
, other
):
21 if isinstance(other
, Value
):
22 return func(self
, other
)
23 if isinstance(other
, numbers
.Rational
):
24 other
= Value(self
.context
, other
)
25 return func(self
, other
)
26 raise TypeError('operand should be a Value or a Rational')
34 self
._ic
= libisl
.isl_ctx_alloc()
37 def _as_parameter_(self
):
41 libisl
.isl_ctx_free(self
)
43 def __eq__(self
, other
):
44 if not isinstance(other
, Context
):
46 return self
._ic
== other
._ic
53 return super().__new
__(cls
, iv
)
55 return '{}({})'.format(self
.__class
__.__name
__, self
)
57 _RE_NONFINITE
= re
.compile(
58 r
'^\s*(?P<sign>[-+])?((?P<inf>Inf(inity)?)|(?P<nan>NaN))\s*$',
61 _RE_FRACTION
= re
.compile(r
'^(?P<num>[-+]?\d+)(/(?P<den>\d+))?$')
63 __slots__
= ('context', '_iv', '_numerator', '_denominator')
65 def __new__(cls
, context
, numerator
=0, denominator
=None):
66 self
= super().__new
__(cls
)
67 if not isinstance(context
, Context
):
68 raise TypeError('first argument should be a context')
69 self
.context
= context
70 if isinstance(numerator
, cls
._ptr
):
71 assert denominator
is None
73 if libisl
.isl_val_is_rat(self
):
74 # retrieve numerator and denominator as strings to avoid integer
76 ip
= libisl
.isl_printer_to_str(self
.context
)
77 ip
= libisl
.isl_printer_print_val(ip
, self
)
78 string
= libisl
.isl_printer_get_str(ip
).decode()
79 libisl
.isl_printer_free(ip
)
80 m
= self
._RE
_FRACTION
.match(string
)
82 self
._numerator
= int(m
.group('num'))
83 self
._denominator
= int(m
.group('den')) if m
.group('den') else 1
85 self
._numerator
= None
86 self
._denominator
= None
88 if isinstance(numerator
, str) and denominator
is None:
89 m
= self
._RE
_NONFINITE
.match(numerator
)
91 self
._numerator
= None
92 self
._denominator
= None
94 if m
.group('sign') == '-':
95 self
._iv
= libisl
.isl_val_neginfty(context
)
97 self
._iv
= libisl
.isl_val_infty(context
)
100 self
._iv
= libisl
.isl_val_nan(context
)
103 frac
= Fraction(numerator
, denominator
)
105 raise ValueError('invalid literal for {}: {!r}'.format(
106 cls
.__name
__, numerator
))
107 self
._numerator
= frac
.numerator
108 self
._denominator
= frac
.denominator
109 # values passed as strings to avoid integer overflows
110 if frac
.denominator
== 1:
111 numerator
= str(frac
.numerator
).encode()
112 self
._iv
= libisl
.isl_val_read_from_str(context
, numerator
)
114 numerator
= str(frac
.numerator
).encode()
115 numerator
= libisl
.isl_val_read_from_str(context
, numerator
)
116 denominator
= str(frac
.denominator
).encode()
117 denominator
= libisl
.isl_val_read_from_str(context
, denominator
)
118 self
._iv
= libisl
.isl_val_div(numerator
, denominator
)
122 def _as_parameter_(self
):
126 libisl
.isl_val_free(self
)
127 self
.context
# prevents context from being GC'ed before the value
131 if self
._numerator
is None:
132 raise ValueError('not a rational number')
133 return self
._numerator
136 def denominator(self
):
137 if self
._denominator
is None:
138 raise ValueError('not a rational number')
139 return self
._denominator
142 return not bool(libisl
.isl_val_is_zero(self
))
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
))