M test/sets/cases.py => test/sets/cases.py +1 -2
@@ 8,6 8,5 @@ assert SetRange(2, 4).range_subtract(single(2)) == SetRange(-2, 0)
assert SetRange(2, 4).range_gt(single(0)) is False
assert SetRange(2, 4).range_ge(single(2)) is None
assert SetRange(2, 4).range_le(single(4)) is None
-print(SetRange(2, 4).range_le(single(3))) # TODO None? should be bool.
-
+assert SetRange(2, 4).range_le(single(3)) is None
assert SetRange(-9,1).range_gt(single(1)) is None
M test/sets/intersection.py => test/sets/intersection.py +4 -0
@@ 14,3 14,7 @@ assert SetIntersection().ext_absorb(SetRange(-10, 10), SetStepping(-11,20)) == S
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 SetIntersection([SetRange(0,10), SetStepping(0,1)]).param_mult(SetIntersection([SetRange(3,3)])) == SetIntersection([SetRange(0,30), SetStepping(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 +16 -13
@@ 14,15 14,17 @@
def merge_intersect(a, b):
"""Sees if either side knows how to merge the two sets into one object."""
+ if a == b: # If identical, they're basically already merged.
+ return a
+ # If can merge either way, do that.
if fun := getattr(a, 'set_intersect', None):
ret = fun(b)
- if ret is not None: return ret
-
+ if ret is not None:
+ return ret
if fun := getattr(b, 'set_intersect', None):
- return fun(a)
-
- if a == b:
- return a
+ ret = fun(a)
+ if ret:
+ return ret
def intersect_absorb_1(into, add):
for el in into:
@@ 42,15 44,15 @@ def intersect_absorb(into=None, *lst):
into = intersect_absorb_1(into, el)
return into
-
def _do_op_2(self, opkey, x):
"""Do the operation with the given single other argument. Raw generator version."""
for set in self:
meth = getattr(set, opkey, None)
if callable(meth): # (some function may do something)
lst = (x if isinstance(x, SetIntersection) else (x,))
- for got in map(meth, lst): # (`None` abstains)
- if got is not None: yield got
+ for got in map(meth, lst):
+ if got is not None: # (`None` abstains)
+ yield got
elif meth == 'id': # (doesn't change input set)
yield set
@@ 95,7 97,7 @@ class SetIntersection(tuple):
def _intersection_union(self, y):
# NOTE: y is first because it may be a one-time iterable.
for ey in y:
- allnone = True
+ all_none = True
for e in self:
assert getattr(e, 'set_union', None), (y, self)
got = e.set_union(ey)
@@ 103,8 105,8 @@ class SetIntersection(tuple):
got = ey.set_union(e)
if got is not None:
yield got # Found a combination.
- allnone = False
- if allnone: # None made a combined result.
+ all_none = False
+ if all_none: # None made a combined result.
yield ey
def set_union(self, y):
@@ 125,7 127,8 @@ def _m1(param_key):
def _m2(param_key):
def ret(y, self):
- return self.ext_absorb(*_do_op_2(self, param_key, y))
+ return self.ext_absorb(*_do_op_2(self, param_key, y),
+ *_do_op_2(y, f"rev_{param_key}", self))
return ret
from type_stack_calc.util.fun_info import fun_info
M type_stack_calc/sets/stepping.py => type_stack_calc/sets/stepping.py +11 -5
@@ 209,6 209,7 @@ for name in ['sqrt', 'log', 'log2', 'log10', 'exp', 'sinh', 'cosh',
def param_from_2(name):
num_name, stepping_name = f"num_{name}", f"stepping_{name}"
def ret(self, y):
+ assert isinstance(self, SetStepping), self
if isinstance(y, SetStepping):
return getattr(self, stepping_name)(y)
elif isinstance(y, SetRange):
@@ 223,10 224,15 @@ def param_from_2(name):
from type_stack_calc.util.fun_info import fun_info
for k in ['mult', 'add', 'divide', 'subtract', 'modulo']:
- got = fun_info.get(k)
- setattr(SetStepping, f"param_{k}", param_from_2(k))
- if got is not None and got.infix:
- setattr(SetStepping, f"param_{got.infix}", param_from_2(k))
-
+ info = fun_info.get(k)
+ fun = param_from_2(k)
+ setattr(SetStepping, f"param_{k}", fun)
+ if info.commute: # If it commutes can just swap them to implement.
+ setattr(SetStepping, f"rev_param_{k}", fun)
+ if info is not None and info.infix:
+ setattr(SetStepping, f"param_{info.infix}", fun)
+ if info.commute:
+ setattr(SetStepping, f"rev_param_{info.infix}", fun)
+
for k in ['union', 'inside']: # (intersect also deals with range)
setattr(SetStepping, f"set_{k}", param_from_2(k))