[95] | 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 |
|
---|