## ~jasper/type_stack_calc

4dcd4aabf306af401ced69a2684ec26a83fbd043 — Jasper den Ouden 6 months ago
```Stepping substract, Stepping step positive. Bit more testing of intersections, sorting intersections.
```
```4 files changed, 45 insertions(+), 18 deletions(-)

M test/sets/general.py
M test/sets/intersection.py
M type_stack_calc/sets/intersection.py
M type_stack_calc/sets/stepping.py
```
`M test/sets/general.py => test/sets/general.py +2 -3`
```@@ 26,10 26,9 @@ def did_inc(*args):
# Compares using the function to calculated sets.
for _n in range(50):
fr = -30 + 60*random()
-    step = randint(-30,30)
-    if step == 0: step = 1
+    step = randint(1,30)

-    sets = [SetRange(fr, fr + 4*random()), SetStepping(randint(-30, 30), step)]
+    sets = [SetRange(fr, fr + 4*random()), SetStepping(randint(1, 30), step)]
sets.append(SetIntersection(sets))  # TODO it doesnt have .random
for set in sets:
for k, info in fun_info.items():

```
`M test/sets/intersection.py => test/sets/intersection.py +34 -9`
```@@ 1,20 1,45 @@

-from type_stack_calc.sets.range import SetRange
-from type_stack_calc.sets.stepping import SetStepping
-from type_stack_calc.sets.intersection import SetIntersection
+from type_stack_calc.sets.range import SetRange as r
+from type_stack_calc.sets.stepping import SetStepping as s
+from type_stack_calc.sets.intersection import SetIntersection as si
from type_stack_calc.sets.empty import Empty

+from type_stack_calc.util.fun_info import fun_info
+
# Jumps over expect empty.

#print(Intersection(Range(-10, 10), Stepping(-11,2)))
#print(Intersection.cls_absorb(Range(-10, 10), Stepping(-11,20)) == Intersection(9))

-assert SetIntersection().ext_absorb(SetRange(-10, 10), SetStepping(-11,20)) == SetIntersection((9,))
+assert si().ext_absorb(r(-10, 10), s(-11,20)) == si((9,))
+
+assert si().ext_absorb(r(-10, 10), s(-11,30))[0] is Empty
+assert s(0,30).in_set_clamps_hard(1,10) is Empty
+
+def check(a, b, *what):
+    a, b = si(sorted(a)), si(sorted(b))
+    for name, eq in what:
+        eq = si(sorted(eq))  # (im lazy)
+        meth_name = f"param_{name}" if name[0]!=':' else name[1:]
+        got = getattr(a, meth_name)(b)
+        assert got == eq, f"{a} {name} {b}:\n {eq} vs {got}"
+        if fun_info[name].commute:  # Try other way round if it commutes.
+            got = getattr(b, meth_name)(a)
+            assert got == eq, f"{b} {name} {a}:\n {eq} vs {got} (commuted)"

-assert SetIntersection().ext_absorb(SetRange(-10, 10), SetStepping(-11,30))[0] is Empty
-assert SetStepping(0, 30).set_intersect(SetRange(1,10)) is Empty
-assert SetStepping(0,30).in_set_clamps_hard(1,10) is Empty
+assert s(0, 30).set_intersect(r(1,10)) is Empty
+assert si([r(0,10), s(0,1)]).param_mult(si([r(3,3)])) \
+        == si([s(0,3), r(0,30)])
+# Range & set versus constant.
+check([r(0,10), s(0,1)], [r(3,3)],
+      ('mult', [r(0,30), s(0,3)]),
+      ('subtract',  [r(-3,7), s(0,1)]))
+# Range & set x 2.
+check([s(0,1), r(0,10)], [s(0,2), r(0,10)],
+      ('mult', [r(0,100), s(0,2)]),
+      ('subtract',  [r(-10,10), s(0,1)]))

-assert SetIntersection([SetRange(0,10), SetStepping(0,1)]).param_mult(SetIntersection([SetRange(3,3)])) == SetIntersection([SetRange(0,30), SetStepping(0,3)])
+assert s(0,1).param_mult(r(3,3)) == s(0,3)

-assert SetStepping(0,1).param_mult(SetRange(3,3)) == SetStepping(0,3)

```
`M type_stack_calc/sets/intersection.py => type_stack_calc/sets/intersection.py +1 -1`
```@@ 72,7 72,7 @@ class SetIntersection(tuple):
if fix_val_fun := getattr(self, 'fix_val', None):
vals = map(fix_val_fun, vals)

-        return type(self)(intersect_absorb(*vals))
+        return type(self)(sorted(intersect_absorb(*vals)))

repr_prep = 'intersect'
def __repr__(self):

```
`M type_stack_calc/sets/stepping.py => type_stack_calc/sets/stepping.py +8 -5`
```@@ 21,7 21,7 @@ NOTE: `None` results or omissions of methods often means it turns into a regular
def __new__(cls, orig, step):
assert isinstance(orig, int)# TODO support float too? Subdivisions?
assert isinstance(step, int)
-        assert step != 0
+        assert step > 0, step
orig = orig % step  # Simplify the origin.
return super(SetStepping, cls).__new__(cls, (orig, step))

@@ 32,7 32,7 @@ NOTE: `None` results or omissions of methods often means it turns into a regular
i += 1
if i+1 >=len(ints):
return None
-        return type(self)(ints[i], ints[i+1] - ints[i]).union(*ints[i+1:])
+        return type(self)(ints[i], abs(ints[i+1] - ints[i])).union(*ints[i+1:])

@property
def orig(self): return self[0]

@@ 170,12 170,15 @@ NOTE: `None` results or omissions of methods often means it turns into a regular
return type(self)(orig + y, step)

stepping_subtract, stepping_add = 2*[stepping_union]  # EXPLAIN
+    def num_subtract_disabled(self, y):
+        orig, step = self
+        return type(self)(orig -y, step)

-    def rev_param_substract(self, y):
+    def rev_param_subtract(self, y):
"""Just for the case of a constant other end."""
if isinstance(y, SetRange) and y[0] == y[1]:
orig, step = self
-            return type(self)(orig - y, step)
+            return type(self)(orig - y[0], step)

def num_modulo(self, y):
orig, step = self

@@ 191,7 194,7 @@ NOTE: `None` results or omissions of methods often means it turns into a regular
def param_negative(self):
"""Negative value stepping."""
orig, step = self
-        return type(self)(-orig, -step)
+        return type(self)(-orig, step)

def param_abs(self):
"""Figure ability to deal with absolute value."""

```