decoint 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,377 @@
1
+ from .interval import Interval
2
+ from dataclasses import dataclass
3
+ from .decorations import Decoration, combine
4
+ from gmpy2 import mpfr as Number
5
+ from gmpy2 import is_nan, context, get_context
6
+
7
+ ctx = get_context()
8
+ ctx.precision = 53
9
+ ctx.emin = -1073
10
+ ctx.emax = 1024
11
+
12
+ @dataclass(frozen=True)
13
+ class DecoratedInterval:
14
+ interval: Interval = Interval.empty()
15
+ decoration: Decoration = Decoration.COM
16
+ nai: bool = False
17
+
18
+ def __post_init__(self):
19
+
20
+ if isinstance(self.interval, str):
21
+ try:
22
+ parsed_decoration = DecoratedInterval.from_string(self.interval)
23
+ object.__setattr__(self, "interval", parsed_decoration.interval)
24
+ object.__setattr__(self, "decoration", parsed_decoration.decoration)
25
+ object.__setattr__(self, "nai", parsed_decoration.nai)
26
+ except Exception:
27
+ object.__setattr__(self, "interval", Interval(Number('nan'), Number('nan')))
28
+ object.__setattr__(self, "decoration", Decoration.ILL)
29
+ object.__setattr__(self, "nai", True)
30
+ return
31
+
32
+ if not isinstance(self.interval, Interval):
33
+ object.__setattr__(self, "nai", True)
34
+ object.__setattr__(self, "interval", Interval(Number('nan'), Number('nan')))
35
+ object.__setattr__(self, "decoration", Decoration.ILL)
36
+
37
+ if not isinstance(self.decoration, Decoration):
38
+ object.__setattr__(self, "nai", True)
39
+ object.__setattr__(self, "interval", Interval(Number('nan'), Number('nan')))
40
+ object.__setattr__(self, "decoration", Decoration.ILL)
41
+
42
+ if self.nai:
43
+ if self.decoration != Decoration.ILL:
44
+ object.__setattr__(self, "decoration", Decoration.ILL)
45
+ object.__setattr__(self, "interval", Interval(Number('nan'), Number('nan')))
46
+
47
+ if self.decoration == Decoration.ILL:
48
+ object.__setattr__(self, "nai", True)
49
+ object.__setattr__(self, "interval", Interval(Number('nan'), Number('nan')))
50
+
51
+ if is_nan(self.interval.lo) or is_nan(self.interval.hi):
52
+ object.__setattr__(self, "nai", True)
53
+ object.__setattr__(self, "interval", Interval(Number('nan'), Number('nan')))
54
+ object.__setattr__(self, "decoration", Decoration.ILL)
55
+
56
+ if self.interval.is_empty and not self.nai:
57
+ object.__setattr__(self, "decoration", Decoration.TRV)
58
+
59
+ if not self.interval.is_bounded and not self.nai and not self.interval.is_empty and self.decoration > Decoration.DAC:
60
+ object.__setattr__(self, "decoration", Decoration.DAC)
61
+
62
+
63
+ @classmethod
64
+ def empty(cls):
65
+ return cls(Interval.empty(), Decoration.TRV)
66
+
67
+ @classmethod
68
+ def entire(cls):
69
+ return cls(Interval.entire(), Decoration.DAC)
70
+
71
+ @classmethod
72
+ def new_nai(cls):
73
+ return cls(Interval(Number('nan'), Number('nan')), Decoration.ILL, nai = True)
74
+
75
+ @classmethod
76
+ def _coerce(cls, value):
77
+ if isinstance(value, cls):
78
+ return value
79
+
80
+ if isinstance(value, Interval):
81
+ if value.is_empty:
82
+ return cls(value, Decoration.TRV)
83
+ if not value.is_bounded:
84
+ return cls(value, Decoration.DAC)
85
+ return cls(value, Decoration.COM)
86
+
87
+ if isinstance(value, str):
88
+ try:
89
+ x = cls.from_string(value)
90
+ return(x)
91
+ except Exception:
92
+ return cls.new_nai()
93
+
94
+ try:
95
+ bare_interval = Interval._coerce(value)
96
+ return cls._coerce(bare_interval)
97
+ except Exception as e:
98
+ return cls.new_nai()
99
+
100
+ @classmethod
101
+ def from_string(cls, s: str):
102
+ s_s = s.strip()
103
+
104
+ if s_s in ("[nan]", "[nai]", "nai", "[nai]_ill", "[nan, nan]_ill"):
105
+ return cls.new_nai()
106
+
107
+ if "_" in s_s:
108
+ interval_part, dec_part = s.rsplit("_", 1)
109
+ try:
110
+ dec = Decoration[dec_part.upper()]
111
+ except KeyError:
112
+ return cls.new_nai()
113
+ try:
114
+ bare_int = Interval.from_string(interval_part)
115
+ except ValueError:
116
+ return cls.new_nai()
117
+ else:
118
+ try:
119
+ bare_int = Interval.from_string(s_s)
120
+ except ValueError:
121
+ return cls.new_nai()
122
+ if bare_int.is_empty:
123
+ dec = Decoration.TRV
124
+ elif bare_int.lo == Number('-inf') or bare_int.hi == Number('inf'):
125
+ dec = Decoration.DAC
126
+ else:
127
+ dec = Decoration.COM
128
+ return cls(bare_int, dec)
129
+
130
+ @property
131
+ def is_nai(self):
132
+ return self.nai
133
+
134
+ @property
135
+ def is_empty(self):
136
+ return self.interval.is_empty
137
+
138
+ @property
139
+ def is_entire(self):
140
+ return self.interval.is_entire
141
+
142
+ @property
143
+ def is_common(self):
144
+ if self.is_nai:
145
+ return False
146
+ return self.interval.is_common
147
+
148
+ @property
149
+ def width(self):
150
+ if self.is_nai:
151
+ return Number('nan')
152
+ return self.interval.width
153
+
154
+ @property
155
+ def is_singleton(self):
156
+ if self.is_nai:
157
+ return False
158
+ return self.interval.lo == self.interval.hi
159
+
160
+ @property
161
+ def radius(self):
162
+ if self.is_nai:
163
+ return Number('nan')
164
+ return self.interval.radius
165
+
166
+ @property
167
+ def midpoint(self):
168
+ if self.is_nai:
169
+ return Number('nan')
170
+ return self.interval.midpoint
171
+
172
+ @property
173
+ def magnitude(self):
174
+ if self.is_nai:
175
+ return Number('nan')
176
+ return self.interval.magnitude
177
+
178
+ @property
179
+ def mignitude(self):
180
+ if self.is_nai:
181
+ return Number('nan')
182
+ return self.interval.mignitude
183
+
184
+ def contains(self, x):
185
+ if self.is_nai:
186
+ return False
187
+ return self.interval.contains(x)
188
+
189
+ def subset(self, other):
190
+ other = self._coerce(other)
191
+ if self.is_nai or other.is_nai:
192
+ return False
193
+ return self.interval.subset(other.interval)
194
+
195
+ def proper_subset(self, other):
196
+ other = self._coerce(other)
197
+ if self.is_nai or other.is_nai:
198
+ return False
199
+ return self.interval.proper_subset(other.interval)
200
+
201
+ def overlaps(self, other):
202
+ other = self._coerce(other)
203
+ if self.is_nai or other.is_nai:
204
+ return False
205
+ return self.interval.overlaps(other.interval)
206
+
207
+ def disjoint(self, other):
208
+ other = self._coerce(other)
209
+ if self.is_nai or other.is_nai:
210
+ return False
211
+ return self.interval.disjoint(other.interval)
212
+
213
+ def precedes(self, other):
214
+ other = self._coerce(other)
215
+ if self.is_nai or other.is_nai:
216
+ return False
217
+ return self.interval.precedes(other.interval)
218
+
219
+ def meets(self, other):
220
+ other = self._coerce(other)
221
+ if self.is_nai or other.is_nai:
222
+ return False
223
+ return self.interval.meets(other.interval)
224
+
225
+ def sup_sub(self, other):
226
+ other = self._coerce(other)
227
+ if self.is_nai or other.is_nai:
228
+ return False
229
+ return self.interval.sup_sub(other.interval)
230
+
231
+ def interior(self, other):
232
+ other = self._coerce(other)
233
+ if self.is_nai or other.is_nai:
234
+ return False
235
+ return self.interval.interior(other.interval)
236
+
237
+ def inf_sub(self, other):
238
+ other = self._coerce(other)
239
+ if self.is_nai or other.is_nai:
240
+ return False
241
+ return self.interval.inf_sub(other.interval)
242
+
243
+ def __repr__(self):
244
+ if self.nai:
245
+ return "DecoratedInterval(nai)"
246
+
247
+ return (
248
+ f"DecoratedInterval("
249
+ f"{self.interval}, "
250
+ f"{str(self.decoration)})")
251
+
252
+ def __str__(self):
253
+ if self.nai:
254
+ return "[nai]_ill"
255
+ int_str = str(self.interval)
256
+ dec_str = self.decoration.name.lower()
257
+ return f"{int_str}_{dec_str}"
258
+
259
+ def __add__(self, other):
260
+ from .decorated_arithmetic import add
261
+ other = self._coerce(other)
262
+ if self.is_nai or other.is_nai:
263
+ return DecoratedInterval.new_nai()
264
+ return add(self, other)
265
+
266
+ def __sub__(self, other):
267
+ from .decorated_arithmetic import sub
268
+ other = self._coerce(other)
269
+ if self.is_nai or other.is_nai:
270
+ return DecoratedInterval.new_nai()
271
+ return sub(self, other)
272
+
273
+ def __mul__(self, other):
274
+ from .decorated_arithmetic import mul
275
+ other = self._coerce(other)
276
+ if self.is_nai or other.is_nai:
277
+ return DecoratedInterval.new_nai()
278
+ return mul(self, other)
279
+
280
+ def __truediv__(self, other):
281
+ from .decorated_arithmetic import div
282
+ other = self._coerce(other)
283
+ if self.is_nai or other.is_nai:
284
+ return DecoratedInterval.new_nai()
285
+ return div(self, other)
286
+
287
+ def __radd__(self, other):
288
+ from .decorated_arithmetic import add
289
+ other = self._coerce(other)
290
+ if self.is_nai or other.is_nai:
291
+ return DecoratedInterval.new_nai()
292
+ return add(other, self)
293
+
294
+ def __rsub__(self, other):
295
+ from .decorated_arithmetic import sub
296
+ other = self._coerce(other)
297
+ if self.is_nai or other.is_nai:
298
+ return DecoratedInterval.new_nai()
299
+ return sub(other, self)
300
+
301
+ def __rmul__(self, other):
302
+ from .decorated_arithmetic import mul
303
+ other = self._coerce(other)
304
+ if self.is_nai or other.is_nai:
305
+ return DecoratedInterval.new_nai()
306
+ return mul(other, self)
307
+
308
+ def __rtruediv__(self, other):
309
+ from .decorated_arithmetic import div
310
+ other = self._coerce(other)
311
+ if self.is_nai or other.is_nai:
312
+ return DecoratedInterval.new_nai()
313
+ return div(other, self)
314
+
315
+ def __lt__(self, other):
316
+ other = self._coerce(other)
317
+ if self.is_nai or other.is_nai:
318
+ return False
319
+ return self.interval < other.interval
320
+
321
+ def __gt__(self, other):
322
+ other = self._coerce(other)
323
+ if self.is_nai or other.is_nai:
324
+ return False
325
+ return self.interval > other.interval
326
+
327
+ def strictly_less_than(self, other):
328
+ other = self._coerce(other)
329
+ if self.is_nai or other.is_nai:
330
+ return False
331
+ return self.interval.strictly_less_than(other.interval)
332
+
333
+ def intersection(self, other):
334
+ other = self._coerce(other)
335
+ if self.is_nai or other.is_nai:
336
+ return DecoratedInterval.new_nai()
337
+
338
+ interval = self.interval.intersection(other.interval)
339
+ dec = combine(self.decoration, other.decoration, Decoration.TRV)
340
+ return DecoratedInterval(interval, dec)
341
+
342
+ def hull(self, other):
343
+ other = self._coerce(other)
344
+ if self.is_nai or other.is_nai:
345
+ return DecoratedInterval.new_nai()
346
+ interval = self.interval.hull(other.interval)
347
+ dec = combine(self.decoration, other.decoration, Decoration.TRV)
348
+ return DecoratedInterval(interval, dec)
349
+
350
+ def __eq__(self, other):
351
+ other = self._coerce(other)
352
+ if self.is_nai or other.is_nai:
353
+ return False
354
+ if (self.interval.lo == other.interval.lo) and (self.interval.hi == other.interval.hi):
355
+ return True
356
+ return False
357
+
358
+ def strictly_precedes(self, other):
359
+ other = self._coerce(other)
360
+ if self.is_nai or other.is_nai:
361
+ return False
362
+ return self.interval.strictly_precedes(other.interval)
363
+
364
+ def __neg__(self):
365
+ if self.is_nai:
366
+ return DecoratedInterval.new_nai()
367
+ return DecoratedInterval(-self.interval, self.decoration)
368
+
369
+ def inf(self):
370
+ if self.is_nai:
371
+ return Number('nan')
372
+ return self.interval.lo
373
+
374
+ def sup(self):
375
+ if self.is_nai:
376
+ return Number('nan')
377
+ return self.interval.hi
decoint/decorations.py ADDED
@@ -0,0 +1,18 @@
1
+ from enum import IntEnum
2
+
3
+ class Decoration(IntEnum):
4
+ ILL = 0
5
+ TRV = 1
6
+ DEF = 2
7
+ DAC = 3
8
+ COM = 4
9
+
10
+ def __str__(self):
11
+ return self.name.lower()
12
+
13
+ def combine(*decorations: Decoration) -> Decoration:
14
+ # IEEE 1788 requires that the minimum decoration has to be the one that is returned
15
+ if not decorations:
16
+ return Decoration.ILL
17
+
18
+ return min(decorations)