Пример #1
0
def head(Fn, B):
    """
    implement monadic ↑
    """
    if B.isScalar() or B.isEmptyVector():
        return B

    if B.isVector():
        return makeScalar(Fn(B.vectorToPy()), Fn(B.prototype()))

    return makeScalar(Fn(B.arrayToPy()), Fn(B.prototype()))
Пример #2
0
def pick(_, A, B):
    """
    implement dyadic ⊃
    """
    assertNotArray(A)
    assertNotArray(B)

    if A.isEmptyVector():
        return B

    assertNotScalar(B)

    if B.isVector():
        IO = indexOrigin()

        try:
            for X in A.vectorToPy():
                X = confirmInteger(X)

                assertTrue(X >= IO, "INDEX ERROR")

                if isinstance(B, aplQuantity):
                    B = B.vectorToPy()[X - IO]
                else:
                    assertError("RANK ERROR")

        except IndexError:
            assertError("INDEX ERROR")

        if isinstance(B, aplQuantity):
            return B

        return makeScalar((B, ), None)
Пример #3
0
def index(Fn, A, B):
    """
    implement dyadic ⍳
    """
    assertNotArray(A)

    if B.isEmptyVector():
        return makeEmptyVector(B.prototype())

    if A.isEmptyVector():
        Rpy = scalarIterator(indexOrigin(), B.elementCount(), B.expressionToGo)

    elif B.isArray():
        Rpy = Fn(A.vectorToPy(), B.arrayToPy())

    else:
        Rpy = Fn(A.vectorToPy(), B.vectorToPy())

    if B.isArray():
        return makeArray(Rpy, B.dimension())

    if B.isVector():
        return makeVector(Rpy, B.dimension())

    return makeScalar(Rpy)
Пример #4
0
def encode(Fn, A, B):
    """
    implement dyadic ⊤
    """
    if B.isEmptyVector():
        # Simplistic
        return makeEmptyVector()

    if A.isEmptyVector():
        # Simplistic
        return makeEmptyVector()

    if B.isArray():
        if A.isScalarLike():
            Rpy = []
            Apy = A.vectorToPy()
            for Bpy in B.arrayToPy():
                Rpy.append(Fn(Apy, Bpy).__next__())

            return makeArray(Rpy, B.dimension())

        assertError("WIP - RANK ERROR")

    if B.isVector():
        assertTrue(B.tally() == 2, "WIP - LENGTH ERROR")

        if A.isArray():
            assertError("WIP - RANK ERROR")

        if A.isVector():
            assertTrue(A.tally() == 2, "WIP - LENGTH ERROR")

            Rpy, Apy = [], A.vectorToPy()
            for Bpy in B.vectorToPy():
                Rpy += Fn(Apy, Bpy)

            Rpy = monadicTranspose(Rpy, (A.tally(), B.tally()))

            return makeArray(Rpy, (A.tally(), B.tally()))

        Rpy, Apy = [], A.vectorToPy()
        for Bpy in B.vectorToPy():
            Rpy += Fn(Apy, Bpy)

    if A.isArray():
        Rpy, Bpy = [], B.scalarToPy()
        for Ait in A.arrayByFirstAxis():
            Rpy += Fn(Ait.vectorToPy(), Bpy)

        return makeArray(Rpy, A.dimension(), B.prototype())

    if A.isVector():
        Rpy = Fn(A.vectorToPy(), B.scalarToPy())

        return makeVector(Rpy, A.tally())

    Rpy = Fn(A.vectorToPy(), B.scalarToPy())

    return makeScalar(Rpy)
Пример #5
0
def decode(Fn, A, B):
    """
    implement dyadic ⊥
    """
    if B.isArray():
        if A.isScalarLike():
            Rpy = []
            for Bit in B.arrayByFirstAxis():
                Rpy.append(Fn(A.promoteScalarToVectorPy(), Bit))

            return makeVector(Rpy, B.dimension()[0], B.prototype())

        if A.isVector():
            assertNotTrue(A.isEmptyVector(), "DOMAIN ERROR")
            assertTrue(A.tally() == B.dimension()[0], "LENGTH ERROR")

            Rpy = []
            for Bit in B.arrayByFirstAxis():
                Rpy.append(Fn(A.vectorToPy(), Bit))

            return makeVector(Rpy, A.dimension(), B.prototype())

        assertTrue(A.rank() == B.rank(), "WIP - RANK ERROR")

        assertTrue(A.dimension()[-1] == B.dimension()[0], "LENGTH ERROR")

        Rpy = []
        for Ait in A.arrayByLastAxis():
            for Bit in B.arrayByFirstAxis():
                Rpy.append(Fn(Ait, Bit))

        return makeArray(Rpy, A.dimension(), B.prototype())

    if B.isVector():
        if A.isEmptyVector() or B.isEmptyVector():
            return makeScalar(0)

        return makeScalar(Fn(A.promoteScalarToVectorPy(), B.vectorToPy()))

    if A.isScalar():
        assertNumeric(A)
        assertNumeric(B)

        return B

    return makeScalar(Fn(A.vectorToPy(), B.scalarIterator()))
Пример #6
0
def enclose(_, B):
    """
    implement monadic ⊂
    """
    if B.isScalar():
        return B

    return makeScalar((B, ), None)
Пример #7
0
def evaluate(expression, cio):
    """
    evaluate an APL expression

    called from parse and routines parse calls so beware indirect recursion
    """
    try:
        expr = expression.lstrip()

        if not expr:
            assertError("SYNTAX ERROR")

        lhs, expr = parse(expr, cio)

        if lhs == []:
            lhs = None
        elif len(lhs) > 1:
            lhs = makeVector(tuple(lhs), -1, None)
        elif isinstance(lhs[0], aplQuantity):
            lhs = lhs[0]
        else:
            lhs = makeScalar(lhs[0], None)

        if not expr:
            return lhs

        if cio.newStmt:
            if lhs is None and expr[0] == '⊣':
                cio.hushImplicit = True
            cio.newStmt = False

        operator = operatorFunction(expr[1:].lstrip()) if lhs is None else None

        if operator is None and lhs is None:
            function = monadicFunction(expr)
        else:
            identity, function = dyadicFunction(expr)

        if not operator is None:
            expr = expr[1:].lstrip()

        rhs = evaluate(expr[1:], cio)
        rhs.expressionToGo = expr

        if operator is None:
            result = function(rhs) if lhs is None else function(lhs, rhs)
        else:
            result = operator(function, identity, rhs)

        return result.resolve() if eagerEvaluation() else result

    except aplException as error:
        if not error.expr:
            error.expr = expr
        raise error
Пример #8
0
def maths(Fn, A, B):
    """
    the basic recursive map for dyadic mathematical functions
    """
    if B.isArray():
        if A.isArray():
            # Check ranks are equal
            Rpy = iterator.maths(maths, Fn, A, B)

        elif A.isVector():
            # Check length is compatible
            Rpy = iterator.maths(maths, Fn, A.vectorIterator(), B)

        else:
            Rpy = iterator.maths(maths, Fn, A.scalarIterator(), B)

        return makeArray(Rpy, B.dimension(), B.prototype())

    if A.isArray():
        if B.isVector():
            # Check length is compatible
            Rpy = iterator.maths(maths, Fn, A, B.vectorIterator())

        else:
            Rpy = iterator.maths(maths, Fn, A, B.scalarIterator())

        return makeArray(Rpy, A.dimension(), A.prototype())

    if B.isVector():
        if A.isVector():
            if B.isEmptyVector():
                assertTrue(A.isEmptyVector(), "LENGTH ERROR")

            Rpy = iterator.maths(maths, Fn, A, B)

        elif B.isEmptyVector():
            return B

        else:
            Rpy = iterator.maths(maths, Fn, A.scalarIterator(), B)

        return makeVector(Rpy, B.dimension(), B.prototype())

    if A.isVector():
        if A.isEmptyVector():
            return A

        else:
            Rpy = iterator.maths(maths, Fn, A, B.scalarIterator())

        return makeVector(Rpy, A.dimension(), A.prototype())

    return makeScalar(iterator.maths(maths, Fn, A, B))
Пример #9
0
def reduceFirst(Fn, A, B):
    """
    the map for the ⌿ (reduce along first axis) operator
    """
    if B.isScalar():
        return B

    if B.isVector():
        if B.isEmptyVector():
            assertNotTrue(A is None, "DOMAIN ERROR")

            return makeScalar(A)

        Rpy = iterator.reduceVector(Fn, B)

        if Rpy.isScalar():
            return Rpy

        return makeScalar((Rpy, ), makePrototype(Rpy))

    assertNotArray(B, "WIP - RANK ERROR")
Пример #10
0
def maths(Fn, B):
    """
    the basic recursive map for monadic mathematical functions
    """
    if B.isArray():
        return makeArray(iterator.maths(maths, Fn, B), B.dimension())

    if B.isVector():
        return makeVector(iterator.maths(maths, Fn, B), B.dimension(),
                          B.prototype())

    return makeScalar(iterator.maths(maths, Fn, B))
Пример #11
0
def partition(Fn, A, B):
    """
    implement dyadic ⊂
    """
    assertNotArray(A)

    assertNotTrue(B.isScalar(), "RANK ERROR")

    if A.isEmptyVector() and B.isEmptyVector():
        return B

    if A.isScalar():
        Apy = confirmInteger(A.scalarToPy())

        if Apy == 0:
            return makeEmptyVector()

        return makeScalar((B, ), B.prototype())

    if B.isArray():
        assertTrue(B.dimension() == (2, 2), "WIP - MATRIX ERROR")

        Apy = A.vectorToPy()

        assertTrue(len(Apy) == B.rank(), "LENGTH ERROR")

        Rpy = []
        for Bit in B.arrayByLastAxis():
            Rpy += makeScalar((Fn(
                A.vectorToPy(),
                Bit.vectorToPy(),
            ), B.prototype()))

        Dpy = list(B.dimension())
        Dpy[-1] = 1

        return makeArray(Rpy, Dpy, None)

    return makeVector(Fn(A.vectorToPy(), B.vectorToPy()), -1, B.prototype())
Пример #12
0
    def __next__(self):
        try:
            X, Y = _nextPair(self._A, self._B)

            if isinstance(X, aplQuantity) and isinstance(Y, aplQuantity):
                return self._map(self._fn, X, Y)

            if isinstance(X, aplQuantity):
                return self._map(self._fn, X, makeScalar(Y))

            if isinstance(Y, aplQuantity):
                return self._map(self._fn, makeScalar(X), Y)

            try:
                return self._fn(X, Y)
            except TypeError:
                assertError("DOMAIN ERROR")

        except aplException as error:
            if error.expr is None:
                error.expr = self._expresso
            raise error
Пример #13
0
def reduceVector(Fn, B):
    """
    the iterator for the reduce operator when applied to a vector
    """
    I = reverse(B).__iter__()
    Y = I.__next__()

    if not isinstance(Y, aplQuantity):
        Y = makeScalar(Y)

    try:
        while True:
            X = I.__next__()

            if not isinstance(X, aplQuantity):
                X = makeScalar(X)

            Y = Fn(X, Y).resolve()

    except StopIteration:
        pass

    return Y
Пример #14
0
def find(Fn, A, B):
    """
    implement dyadic ∊
    """
    A.resolve()

    Apy = A.arrayToPy() if A.isArray() else A.vectorToPy()
    Bpy = B.arrayToPy() if B.isArray() else B.vectorToPy()

    Rpy = Fn(Apy, Bpy)

    if B.isArray():
        return makeArray(Rpy, B.dimension(), B.prototype())

    if B.isVector():
        return makeVector(Rpy, B.dimension(), B.prototype())

    return makeScalar(Rpy, B.prototype())
Пример #15
0
def scanLast(Fn, _, B):
    """
    the map for the \ (scan along last axis) operator
    """
    if B.isScalar():
        return B

    if B.isVector():
        if B.isEmptyVector():
            return B

        if B.isScalarLike():
            return makeScalar(B.scalarToPy())

        Rpy = iterator.scanVector(Fn, B)

        return makeVector(Rpy, B.dimension(), B.prototype())

    assertNotArray(B, "WIP - RANK ERROR")
Пример #16
0
def membership(Fn, A, B):
    """
    implement dyadic ∊
    """
    if A.isEmptyVector():
        return A

    Apy = A.arrayToPy() if A.isArray() else A.vectorToPy()
    Bpy = B.arrayToPy() if B.isArray() else B.vectorToPy()

    Rpy = Fn(Apy, Bpy)

    if A.isArray():
        return makeArray(Rpy, A.dimension(), A.prototype())

    if A.isVector():
        return makeVector(Rpy, A.dimension(), A.prototype())

    return makeScalar(Rpy, A.prototype())
Пример #17
0
def disclose(Fn, B):
    """
    implement monadic ⊃
    """
    if B.isArray():
        return makeArray(Fn(B.arrayToPy()), B.dimension(), B.prototype())

    if B.isVector():
        if B.isEmptyVector():
            return B

        return makeVector(Fn(B.vectorToPy()), B.dimension(), B.prototype())

    if B.isScalar():
        Bpy = B.scalarToPy()

        if isinstance(Bpy, aplQuantity):
            return Bpy

        return makeScalar(Bpy, None)
Пример #18
0
def depth(_, B):
    """
    implement monadic ≡
    """
    return makeScalar(B.depth())
Пример #19
0
def tally(_, B):
    """
    implement monadic ≢
    """
    return makeScalar(B.tally())
Пример #20
0
def setEvaluationMode(mode):
    """
    set the eager/lazy evaluation mode (from command line flags)
    """
    return _EE.set(makeScalar(mode))
Пример #21
0
def setIndexOrigin(value):
    """
    set the index origin (from command line flags)
    """
    return _IO.set(makeScalar(value))
Пример #22
0
    '↑':        lambda B: mapper.head(iterator.head, B),
    '/':        lambda B: assertError("SYNTAX ERROR"),
    '⌿':        lambda B: assertError("SYNTAX ERROR"),
    '\\':       lambda B: assertError("SYNTAX ERROR"),
    '⍀':        lambda B: assertError("SYNTAX ERROR"),
    '⍋':        lambda B: mapper.grade(False, B),
    '⍒':        lambda B: mapper.grade(True, B),
    '⌷':        lambda B: assertError("VALENCE ERROR"),

    # Miscellaneous
    '⍺':        lambda B: assertError("VALENCE ERROR"),
    '⍕':        _toBeImplemented,       # monadic format
    '⍎':        _toBeImplemented,       # execute
    '⊤':        lambda B: assertError("VALENCE ERROR"),
    '⊥':        lambda B: assertError("VALENCE ERROR"),
    '⊣':        lambda B: makeScalar(0),
    '⊢':        lambda B: B,
}

# ------------------------------

def     monadicFunction(symbol):
    """
    return the monadic function given its APL symbol

    raises INVALID TOKEN if the symbol is not recognised
    """
    try:
        return _MonadicFunctions[symbol[0]]
    except KeyError:
        assertError("INVALID TOKEN")
Пример #23
0
def noMatch(Fn, A, B):
    """
    recursive implementation of dyadic ≢
    """
    return makeScalar(int(not _matchMap(Fn, A, B)))