示例#1
0
def _mul_CO_CO(t1, t2):
    """
    Returns an iterator of Triples representing the product of t1 (CO) and t2
    (CO).
    
    >>> list(_mul_CO_CO(T(18, None, 3), T(5, None, 5)))
    [(90, *, 15)]
    >>> list(_mul_CO_CO(T(4, None, 3), T(-6, None, 9)))
    [(*, *, 3, phase=0)]
    """

    gcf1 = (rational.gcf(t1.skip, t1.phase) if t1.phase else t1.skip)
    gcf2 = (rational.gcf(t2.skip, t2.phase) if t2.phase else t2.skip)
    newStart = (None if t1.start < 0 or t2.start < 0 else t1.start * t2.start)
    yield T(newStart, None, gcf1 * gcf2)
示例#2
0
def _xorConstant_sub(t, k):
    """
    Subroutine to assist _xorConstant. The Triple t and the constant k must
    both be positive.
    
    ### C(_xorConstant_sub(T(4, None, 5), 6)).asList()
    [(2, *, 40), (8, *, 40), (15, *, 40), (21, *, 40), (27, *, 40), (30, *, 40), (33, *, 40), (36, *, 40)]
    ### C(_xorConstant_sub(T(4, 79, 5), 6)).asList()
    [(30, 54, 6), (55, 73, 6), (2, 14, 6), (15, 39, 6), (70, 82, 6)]
    """

    assert t.start >= 0 and k > 0, "_xorConstant_sub invariant failed!"
    bl = utilities.binlist(k)
    pow2 = 2**len(bl)
    cycle = pow2 // rational.gcf(pow2, t.skip)
    cs = cycle * t.skip

    if t.stop is None:
        for start in range(t.start, t.start + cs, t.skip):
            yield T(start ^ k, None, cs)

    else:
        tLast = t.stop - t.skip

        for start in range(t.start, t.start + cs, t.skip):
            xStart = start ^ k
            j = (tLast - start) // cs

            if j >= 0:
                xStop = xStart + (1 + j) * cs
                yield T(xStart, xStop, cs)
示例#3
0
def _mod_OO_CC(t1, t2):
    """
    Returns an iterator over Triples representing all values in t1 (OO) modulus
    all values in t2 (CC).
    
    ### list(_mod_OO_CC(T(None, None, 5, 0), T(35, 105, 7)))
    [(0, 98, 1)]
    ### list(_mod_OO_CC(T(None, None, 5, 0), T(35, 42, 7)))
    [(0, 35, 5)]
    ### list(_mod_OO_CC(T(None, None, 5, 3), T(35, 56, 7)))
    [(0, 49, 1)]
    """

    gcf = rational.gcf(t1.skip, t2.skip)

    if (t2.stop - t2.start) < (t1.skip * t2.skip // gcf):
        # not enough for a full cycle, so do indiv values
        s = set()

        for n in t2:
            s.update(_modConstant_set(t1, n))

        for obj in utilities.tripleIteratorFromIterable(s):
            yield obj

    else:
        # enough for a full cycle
        tTemp = next(_mod_OO_OO(t1, T(None, None, t2.skip, t2.phase)))
        newStop = (t2.stop - t2.skip - 1) + tTemp.skip
        yield T(tTemp.start, newStop, tTemp.skip)
示例#4
0
def _mul_OO_CO(t1, t2):
    """
    Returns a list representing the product of t1 (OO) and t2 (CO).
    Because of the prime fallout problem, the results of this method are
    usually supersets of the actual answers, which await meta-Triples (see
    the docstring for the _mul_OO_OO method).
    
    >>> list(_mul_OO_CO(T(None, None, 5, 0), T(0, None, 4)))
    [(*, *, 20, phase=0)]
    """

    a, b, c, d = t1.phase, t1.skip, t2.start, t2.skip

    if a == 0:
        if c == 0:
            # (bi)(dj) case
            yield T(None, None, b * d, 0)

        else:
            gcf = rational.gcf(abs(c), d)
            cNew = c // gcf
            dNew = d // gcf

            if (1 - cNew) % dNew == 0 or (-1 - cNew) % dNew == 0:
                yield T(None, None, b * gcf, 0)
            else:
                yield T(None, None, b, 0)

    elif c == 0:
        yield T(None, None, d, 0)

    else:
        yield T(None, None, 1, 0)
示例#5
0
def addOp(t1, t2):
    """
    Returns an iterator of Triples representing the sum of the input Triples.
    No particular attempt is made to optimize the return result, since
    TripleCollections should be used to do the needed optimizations.
    
    Doctests are present in the specific helper functions.
    """

    try:
        kind1 = (t1.start is None, t1.stop is None)
        kind2 = (t2.start is None, t2.stop is None)
        gcf = rational.gcf(t1.skip, t2.skip)
        t = (kind1, kind2)

        if t == ((False, False), (False, False)):
            r = _add_CC_CC(t1, t2)
        elif t in _add_dispatchTable:
            r = _add_dispatchTable[t](t1, t2, gcf)
        else:
            r = _add_dispatchTable[(kind2, kind1)](t2, t1, gcf)

    except AttributeError:
        r = iter([_addConstant(t1, t2)])

    return r
示例#6
0
def _mul_OC_OC(t1, t2):
    """
    Returns a list representing the product of t1 (OC) and t2 (OC).
    
    >>> list(_mul_OC_OC(T(None, 0, 5), T(None, 0, 7)))
    [(35, *, 35)]
    >>> list(_mul_OC_OC(T(None, 0, 5), T(None, 6, 3)))
    [(*, *, 15, phase=0)]
    """

    gcf1 = (rational.gcf(t1.skip, t1.phase) if t1.phase else t1.skip)
    gcf2 = (rational.gcf(t2.skip, t2.phase) if t2.phase else t2.skip)
    newSkip = gcf1 * gcf2
    selfLast = t1.stop - t1.skip
    otherLast = t2.stop - t2.skip
    newStart = (None if selfLast > 0 or otherLast > 0 else selfLast *
                otherLast)
    yield T(newStart, None, gcf1 * gcf2)
示例#7
0
def convert(t, oldBasis, newBasis, round=True):
    """
    Returns an iterator of Triples representing t converted from oldBasis to
    newBasis. No particular attempt is made to optimize the return result,
    since TripleCollections should be used to do the needed optimizations.

    If round is True values will be rounded (0.5 rounds up). If round is False
    values will be integer-division truncated.
    
    >>> T, C = (triple.Triple, collection.Collection)
    >>> C(convert(T(1, 11, 2), 4, 4, True)).asList()
    [(1, 11, 2)]
    >>> C(convert(T(1, 11, 2), 4, 4, False)).asList()
    [(1, 11, 2)]
    >>> C(convert(T(1, 11, 2), 4, 16, True)).asList()
    [(4, 44, 8)]
    >>> C(convert(T(1, 11, 2), 4, 16, False)).asList()
    [(4, 44, 8)]
    >>> C(convert(T(1, 17, 2), 16, 4, True)).asList()
    [(0, 5, 1)]
    >>> C(convert(T(1, 17, 2), 16, 4, False)).asList()
    [(0, 4, 1)]
    >>> C(convert(T(2, 29, 3), 9, 12, True)).asList()
    [(3, 39, 4)]
    >>> C(convert(T(2, 29, 3), 9, 12, False)).asList()
    [(2, 38, 4)]
    """

    if oldBasis == newBasis:
        yield t

    else:
        gcf = rational.gcf(oldBasis, newBasis)
        lcm = (oldBasis * newBasis) // gcf

        if gcf == oldBasis:
            for tProduct in t.mul(newBasis // oldBasis):
                yield tProduct

        elif gcf == newBasis:
            divisor = oldBasis // newBasis

            if round:
                for tDividend in t.add(divisor // 2):
                    for tQuotient in tDividend.div(divisor):
                        yield tQuotient

            else:
                for tQuotient in t.div(divisor):
                    yield tQuotient

        else:
            for tScaled in t.mul(lcm // oldBasis):
                for tResult in convert(tScaled, lcm, newBasis, round):
                    yield tResult
示例#8
0
def _mul_CO_OC(t1, t2):
    """
    Returns an iterator of Triples representing the product of t1 (CO) and t2
    (OC).
    
    >>> list(_mul_CO_OC(T(4, None, 3), T(None, 15, 9)))
    [(*, *, 3, phase=0)]
    >>> list(_mul_CO_OC(T(21, None, 7), T(None, 0, 4)))
    [(*, -56, 28)]
    """

    gcf1 = (rational.gcf(t1.skip, t1.phase) if t1.phase else t1.skip)
    gcf2 = (rational.gcf(t2.skip, t2.phase) if t2.phase else t2.skip)
    newSkip = gcf1 * gcf2

    if t1.start >= 0 and (t2.stop - t2.skip) < 0:
        newStop = t1.start * (t2.stop - t2.skip) + newSkip
    else:
        newStop = None

    yield T(None, newStop, newSkip)
示例#9
0
def _mod_OO_OO(t1, t2):
    """
    Returns an iterator over Triples representing all values in t1 (OO) modulus
    all values in t2 (OO).
    
    ### list(_mod_OO_OO(T(None, None, 5, 0), T(None, None, 7, 0)))
    [(0, *, 1)]
    ### list(_mod_OO_OO(T(None, None, 6, 2), T(None, None, 4, 0)))
    [(0, *, 2)]
    ### list(_mod_OO_OO(T(None, None, 24, 11), T(None, None, 9, 6)))
    [(2, *, 3)]
    """

    gcf = rational.gcf(t1.skip, t2.skip)

    if gcf == 1:
        yield T(0, None, 1)
    elif t2.phase == 0:
        yield T(t1.phase % gcf, None, gcf)
    else:
        newSkip = rational.gcf(gcf, t2.phase)
        yield T(t1.phase % newSkip, None, newSkip)
示例#10
0
def _mul_OO_OC(t1, t2):
    """
    Returns a list representing the product of t1 (OO) and t2 (OC).
    Because of the prime fallout problem, the results of this method are
    usually supersets of the actual answers, which await meta-Triples (see
    the docstring for the _mul_OO_OO method).
    
    >>> list(_mul_OO_OC(T(None, None, 5, 0), T(None, 0, 4)))
    [(*, *, 20, phase=0)]
    >>> list(_mul_OO_OC(T(None, None, 5, 0), T(None, 10, 4)))
    [(*, *, 10, phase=0)]
    >>> list(_mul_OO_OC(T(None, None, 5, 2), T(None, 0, 3)))
    [(*, *, 1, phase=0)]
    """

    a, b, c, d = t1.phase, t1.skip, t2.stop - t2.skip, t2.skip

    if a == 0:
        if c == 0:
            # (bi)(-dj) case, d>0, j>=0, i any integer
            # this becomes (-bd)(ij), and if j=1, this spans all values
            yield T(None, None, b * d, 0)

        else:
            # (bi)(c-dj) case, d>0, j>=0, i any integer
            gcf = rational.gcf(abs(c), d)
            cNew = c // gcf
            dNew = d // gcf

            if (1 - cNew) % dNew == 0 or (-1 - cNew) % dNew == 0:
                yield T(None, None, b * gcf, 0)
            else:
                yield T(None, None, b, 0)  # fallback case

    elif c == 0:
        yield T(None, None, d, 0)  # fallback case

    else:
        yield T(None, None, 1, 0)  # full fallback case
示例#11
0
    def intersection(self, other):
        """
        Returns a Triple representing the intersection of self and other, or
        None if they do not intersect.
        
        >>> Triple(1, 11, 2).intersection(Triple(3, 6, 1))
        (3, 7, 2)
        >>> Triple(1, 13, 4).intersection(Triple(9, 49, 4))
        (9, 13, 4)
        >>> Triple(4, 34, 3).intersection(Triple(1, 31, 6))
        (7, 31, 6)
        >>> Triple(4, 34, 3).intersection(Triple(3, 33, 6)) is None
        True
        >>> Triple(4, 7, 3).intersection(Triple(1, 31, 6)) is None
        True
        >>> Triple(1, 10, 1).intersection(Triple(10, 20, 1)) is None
        True
        >>> Triple(None, 20, 1).intersection(Triple(10, 30, 1))
        (10, 20, 1)
        >>> Triple(None, 68, 6).intersection(Triple(23, None, 9))
        (32, 68, 18)
        >>> Triple(None, 14, 2).intersection(Triple(None, 28, 7))
        (*, 14, 14)
        >>> Triple(None, None, 2, 1).intersection(Triple(None, None, 2, 1))
        (*, *, 2, phase=1)
        >>> Triple(None, None, 5, 2).intersection(Triple(None, None, 10, 7))
        (*, *, 10, phase=7)
        """

        gcf = rational.gcf(self.skip, other.skip)
        lcm = (self.skip * other.skip) // gcf

        if self.phase % gcf != other.phase % gcf:
            return None

        firsts, lasts = [], []

        for x, y in ((self, other), (other, self)):
            thisStart = x.start

            if thisStart is not None:
                while thisStart % y.skip != y.phase:
                    thisStart += x.skip

                if x.stop is not None and thisStart >= x.stop:
                    return None

                firsts.append(thisStart)

            if x.stop is not None:
                thisLast = x.stop - x.skip

                while thisLast % y.skip != y.phase:
                    thisLast -= x.skip

                if x.start is not None and thisLast < x.start:
                    return None

                lasts.append(thisLast)

        thisStart = (max(firsts) if firsts else None)
        thisStop = (min(lasts) + lcm if lasts else None)

        if thisStart is not None and thisStop is not None and thisStart >= thisStop:
            return None

        if thisStart is None and thisStop is None:
            newPhase = (self.phase if self.skip >= other.skip else other.phase)
        else:
            newPhase = None

        return Triple(thisStart, thisStop, lcm, newPhase)
示例#12
0
def _mul_OO_OO(t1, t2):
    """
    Given two doubly-open Triples (None, None, a, b) and (None, None, c,
    d), the actual product is the union of the following two meta-Triples:
    
        (None, None, (bc, None, ac), (bd, None, ad))
        (None, None, (ac-bc, None, ac), ((a-b)(c-d), None, ac-ad))
    
    However, there is currently no support for meta-Triples (i.e. Triples
    whose starts, stops, skips and/or phases are themselves Triples). This
    limitation could be addressed at some point in the future.
    
    For the time being this method usually returns (None, None, 1, 0),
    which is at least a superset of the actual answer. There are some
    special cases handled here, such as both Triples having a phase of
    zero, or one having a phase of zero and certain t2 conditions
    holding for the t2, where a real answer is returned.
    
    >>> list(_mul_OO_OO(T(None, None, 2, 0), T(None, None, 4, 0)))
    [(*, *, 8, phase=0)]
    >>> list(_mul_OO_OO(T(None, None, 2, 0), T(None, None, 4, 1)))
    [(*, *, 2, phase=0)]
    >>> list(_mul_OO_OO(T(None, None, 4, 2), T(None, None, 2, 0)))
    [(*, *, 4, phase=0)]
    >>> list(_mul_OO_OO(T(None, None, 2, 0), T(None, None, 7, 3)))
    [(*, *, 1, phase=0)]
    """

    finalCase = False

    if t1.phase == 0:
        if t2.phase == 0:
            yield T(None, None, t1.skip * t2.skip, 0)

        else:
            b = t1.skip * t2.phase
            c = t1.skip * t2.skip
            newSkip = rational.gcf(b, c)
            b //= newSkip
            c //= newSkip

            if (1 - b) % c == 0 or (-1 - b) % c == 0:
                yield T(None, None, newSkip, 0)
            else:
                yield T(None, None, 1, 0)  # fallback case

    elif t2.phase == 0:
        b = t2.skip * t1.phase
        c = t2.skip * t1.skip
        newSkip = rational.gcf(b, c)
        b //= newSkip
        c //= newSkip

        if (1 - b) % c == 0 or (-1 - b) % c == 0:
            yield T(None, None, newSkip, 0)
        else:
            finalCase = True

    else:
        finalCase = True

    if finalCase:
        # We have (a+bi) times (c+di)
        # This breaks into ac + f * (xi + yj + zij)
        a, b, c, d = t1.phase, t1.skip, t2.phase, t2.skip
        x, y, z = b * c, a * d, b * d
        f = rational.gcf(rational.gcf(x, y), z)
        x //= f
        y //= f
        z //= f

        if abs(x) == 1 or abs(y) == 1:
            yield T(None, None, f, (a * c) % f)
        elif (1 - y) % z == 0 or (-1 - y) % z == 0 or (1 - x) % z == 0 or (
                -1 - x) % z == 0:
            yield T(None, None, f, (a * c) % f)
        else:
            yield T(None, None, 1, 0)  # fallback case
示例#13
0
def _andConstant(t, k):
    """
    Returns an iterator of Triples with the results of a constant logical-ANDed
    with t.
    
    >>> T = triple.Triple
    >>> list(_andConstant(T(1, 100, 1), 0))
    [(0, 1, 1)]
    >>> list(_andConstant(T(0, None, 12), 4))
    [(0, 8, 4)]
    >>> list(_andConstant(T(14, 770, 7), 5))
    [(1, 7, 3), (0, 10, 5)]
    >>> list(_andConstant(T(None, None, 7, 2), -3))
    [(*, *, 28, phase=0), (*, *, 28, phase=9), (*, *, 28, phase=16), (*, *, 28, phase=21)]
    >>> list(_andConstant(T(None, 303, 7), -3))
    [(*, 308, 28), (*, 317, 28), (*, 324, 28), (*, 301, 28)]
    >>> list(_andConstant(T(51, None, 7), -3))
    [(56, *, 28), (65, *, 28), (72, *, 28), (49, *, 28)]
    >>> list(_andConstant(T(16, 37, 7), -3))
    [(28, 56, 28), (16, 44, 28), (21, 49, 28)]
    """
    
    Triple = triple.Triple
    
    if k == 0:
        yield Triple(0, 1, 1)
    
    elif k == -1:
        yield t
    
    elif k < 0:
        # because binlist only works with non-negative numbers, create an
        # equivalent positive value for k which will result in the same output
        bl = binlist(-k-1)
        pow2 = 2 ** len(bl)
        cycle = pow2 // rational.gcf(pow2, t.skip)
        bigCycle = cycle * t.skip
        
        if t.start is None and t.stop is None:
            for start in range(t.phase, t.phase + bigCycle, t.skip):
                yield Triple(None, None, bigCycle, start & k)
        
        elif t.start is None:
            last = t.stop - t.skip
            d = dict((n % bigCycle, n) for n in range(last, last - bigCycle, -t.skip))
            
            for start in range(t.phase, t.phase + bigCycle, t.skip):
                yield Triple(None, (d[start] & k) + bigCycle, bigCycle, start & k)
        
        elif t.stop is None:
            d = dict((n % bigCycle, n) for n in range(t.start, t.start + bigCycle, t.skip))
            
            for start in range(t.phase, t.phase + bigCycle, t.skip):
                yield Triple(d[start] & k, None, bigCycle, start & k)
        
        else:
            last = t.stop - t.skip
            dStarts = {}
            
            for n in range(t.start, t.start + bigCycle, t.skip):
                if n > last:
                    break
                
                dStarts[n % bigCycle] = n & k
            
            dStops = {}
            
            for n in range(last, last - bigCycle, -t.skip):
                if n < t.start:
                    break
                
                dStops[n % bigCycle] = (n & k) + bigCycle
            
            for start in range(t.phase, t.phase + bigCycle, t.skip):
                if start in dStarts:
                    actualStart = dStarts[start]
                    stop = dStops.get(start, actualStart + bigCycle)
                    yield Triple(actualStart, stop, bigCycle)
    
    else:
        bl = binlist(k)
        pow2 = 2 ** len(bl)
        cycle = pow2 // rational.gcf(pow2, t.skip)
        
        if t.start is None:
            if t.stop is None:
                start = t.phase
                stop = start + cycle * t.skip
            
            else:
                stop = t.stop
                start = stop - cycle * t.skip
        
        elif t.stop is None:
            start = t.start
            stop = start + cycle * t.skip
        
        else:
            start = t.start
            stop = min(t.stop, start + cycle * t.skip)
        
        s = set(n & k for n in range(start, stop, t.skip))
        
        for t in utilities.tripleIteratorFromIterable(s):
            yield t
示例#14
0
def _divConstant(t, k):
    """
    Returns an iterator of Triples resulting from the division of the specified
    Triple by the specified constant.
    
    ### C(_divConstant(T(15, None, 4), -1))
    Ranges: [(*, -11, 4)]
    ### C(_divConstant(T(150, 45000, 50), 64))
    Ranges: [(2, 703, 1)]
    ### C(_divConstant(T(None, None, 7, 2), 5))
    Ranges: [(*, *, 7, phase=0), (*, *, 7, phase=1), (*, *, 7, phase=3), (*, *, 7, phase=4), (*, *, 7, phase=6)]
    ### C(_divConstant(T(None, None, 12, 2), 8))
    Ranges: [(*, *, 3, phase=0), (*, *, 3, phase=1)]
    ### C(_divConstant(T(None, 122, 12, 2), 8))
    Ranges: [(*, 15, 3), (*, 16, 3)]
    ### C(_divConstant(T(50, None, 12, 2), 8))
    Ranges: [(6, *, 3), (7, *, 3)]
    ### C(_divConstant(T(50, 110, 12), 8))
    Singles: [7, 10], Ranges: [(6, 15, 3)]
    ### C(_divConstant(T(3, None, 5), 0))
    Traceback (most recent call last):
      ...
    ZeroDivisionError: _divConstant called with zero constant!
    """
    
    if k == 0:
        raise ZeroDivisionError("_divConstant called with zero constant!")
    
    if k < 0:
        t = -t
        k = -k
    
    if k == 1:
        yield t
    
    elif k >= t.skip:
        newStart = (None if t.start is None else t.start // k)
        newStop = (None if t.stop is None else 1 + (t.stop - t.skip) // k)
        yield T(newStart, newStop, 1)
    
    else:
        gcf = rational.gcf(t.skip, k)
        phaseSkip = t.skip // gcf
        
        if t.start is None and t.stop is None:
            for i in T(t.phase, t.phase + phaseSkip * k, t.skip):
                yield T(None, None, phaseSkip, i // k)
        
        elif t.start is None:
            for i in T(t.stop - phaseSkip * k, t.stop, t.skip):
                yield T(None, i // k + phaseSkip, phaseSkip)
        
        elif t.stop is None:
            for i in T(t.start, t.start + phaseSkip * k, t.skip):
                yield T(i // k, None, phaseSkip)
        
        else:
            start = t.start
            loopStop = min(t.stop, t.start + phaseSkip * k)
            
            while start < loopStop:
                startDiv = start // k
                thisLast = t.stop - t.skip
                thisLastDiv = thisLast // k
                
                while thisLastDiv % phaseSkip != startDiv % phaseSkip:
                    thisLast -= t.skip
                    thisLastDiv = thisLast // k
                
                yield T(startDiv, thisLastDiv + phaseSkip, phaseSkip)
                start += t.skip