1 | from decimal import Decimal
|
---|
2 | from math import floor, ceil
|
---|
3 | from typing import Optional
|
---|
4 |
|
---|
5 | class Interval:
|
---|
6 | '''
|
---|
7 | An interval [min, max].
|
---|
8 | '''
|
---|
9 | #ZERO = Interval(0,0) can't be done in Python...
|
---|
10 |
|
---|
11 |
|
---|
12 | def __init__(self, min:Decimal, max:Decimal):
|
---|
13 | '''
|
---|
14 | AN interval [min,max]. If min > max, then there are no values in this
|
---|
15 | interval.
|
---|
16 |
|
---|
17 | @param min the minimum value of the interval
|
---|
18 | @param max the maximum value of the interval
|
---|
19 | '''
|
---|
20 | if min == None or max == None:
|
---|
21 | raise ValueError("min and max must contain not None")
|
---|
22 | self._min = min
|
---|
23 | self._max = max
|
---|
24 |
|
---|
25 | def getMin(self)->Decimal :
|
---|
26 | '''
|
---|
27 | @return the minimum value of the interval
|
---|
28 | '''
|
---|
29 | return self._min
|
---|
30 |
|
---|
31 | def getMax(self) ->Decimal :
|
---|
32 | '''
|
---|
33 | @return the maximum value of the interval
|
---|
34 | '''
|
---|
35 | return self._max
|
---|
36 |
|
---|
37 | def isEmpty(self)->bool :
|
---|
38 | '''
|
---|
39 | @return true iff this range does not contain any element.
|
---|
40 | '''
|
---|
41 | return self._min > self._max
|
---|
42 |
|
---|
43 | def contains(self, value:Decimal ) ->bool :
|
---|
44 | '''
|
---|
45 | @param value the value to test
|
---|
46 | @return true iff min ≤ value ≤ max
|
---|
47 | '''
|
---|
48 | return self._min<=value and self._max>= value
|
---|
49 |
|
---|
50 | def add(self, other:"Interval" ) ->"Interval" :
|
---|
51 | '''
|
---|
52 | @param other {@link Interval} to be added to this
|
---|
53 | @return new interval [ this.min + other.min , this.max + other.max ]
|
---|
54 | '''
|
---|
55 | return Interval(self._min + other._min, self._max+other._max)
|
---|
56 |
|
---|
57 | def intersect(self, other:"Interval" ) ->"Interval" :
|
---|
58 | '''
|
---|
59 | @param other another {@link Interval} intersect with
|
---|
60 | @return intersection of this with other. returns null if intersection is
|
---|
61 | empty.
|
---|
62 | '''
|
---|
63 | return Interval(max(self._min,other._min),min(self._max,other._max))
|
---|
64 |
|
---|
65 | def invert(self, other:"Interval") -> Optional["Interval"] :
|
---|
66 | '''
|
---|
67 | @param other the other minmax to deal with
|
---|
68 | @return the range of values that, when added to a value from other, will
|
---|
69 | possibly get in our range. effectively, [min-other.max,
|
---|
70 | max-other.min]. Returns None if the resulting range is empty.
|
---|
71 | '''
|
---|
72 | newmin = self._min-other._max
|
---|
73 | newmax = self._max-other._min
|
---|
74 | if newmin>newmax:
|
---|
75 | return None;
|
---|
76 | return Interval(newmin, newmax);
|
---|
77 |
|
---|
78 | def subtract(self, value:Decimal) ->"Interval" :
|
---|
79 | '''
|
---|
80 | @param value the value to subtract
|
---|
81 | @return Interval with both min and max reduced by value.
|
---|
82 | '''
|
---|
83 | return Interval(self._min-value, self._max-value)
|
---|
84 |
|
---|
85 | def multiply(self, weight:Decimal ) -> "Interval" :
|
---|
86 | return Interval(self._min*weight, self._max*weight)
|
---|
87 |
|
---|
88 | #Override
|
---|
89 | def __repr__(self) ->str:
|
---|
90 | return "Interval[" + str(self._min) + "," + str(self._max) + "]"
|
---|
91 |
|
---|
92 | def round(self, precision:int)->"Interval" :
|
---|
93 | '''
|
---|
94 | @param precision number of digits required
|
---|
95 | @return this but with modified precision. The interval is rounded so that
|
---|
96 | the new interval is inside the old one.
|
---|
97 | '''
|
---|
98 | factor=Decimal(10)**precision
|
---|
99 | return Interval( ceil(self._min * factor)/factor,
|
---|
100 | floor(self._max * factor)/factor)
|
---|
101 |
|
---|
102 | #Override
|
---|
103 | def __hash__(self)->int:
|
---|
104 | return hash((self._min, self._max))
|
---|
105 |
|
---|
106 | def __eq__(self, other):
|
---|
107 | return isinstance(other, self.__class__) and \
|
---|
108 | self._min == other._min and \
|
---|
109 | self._max == other._max
|
---|
110 |
|
---|