069a2ee6c7b08ccd8afa44f74d51a87fb0af3433 — Jasper den Ouden 6 months ago e02d345
If the first argument was SetStepping the stepping promulgated the type, but now also does the second argument sometimes, intersection allows "the reverse case"
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))