Exemple #1
0
 def get_normal(self, N=None, K=None, inverse=False, force=False):
     # remove null summands, and recurse
     assert N is None or N.n == 0
     assert K is None or K.n == 1
     ring = self.ring
     spaces = list(self.items)
     assert len(spaces) > 1, str(self)
     # depth-first recurse
     fs = [space.get_normal(N, K, force=force) for space in spaces]
     f = reduce(Lin.direct_sum, fs)
     assert isinstance(f.tgt, AddSpace)
     spaces = list(f.tgt.items)
     idx = 0
     while idx < len(spaces):
         if force and spaces[idx].n == 0 or spaces[idx] == N:
             spaces.pop(idx)
             tgt, src = AddSpace(ring, *spaces, N=N), f.tgt
             g = Lin(tgt, src, elim.identity(ring, tgt.n))
             f = g * f
             done = False
         else:
             idx += 1
     if inverse:
         f = f.transpose()  # permutation matrix
     return f
Exemple #2
0
 def iso(cls, tgt, src):
     assert isinstance(tgt, Space)
     assert isinstance(src, Space)
     assert tgt.ring is src.ring
     assert tgt.n == src.n
     ring = tgt.ring
     A = elim.identity(ring, tgt.n)
     return Lin(tgt, src, A)
Exemple #3
0
 def counit(K, U):  # method of K ?
     assert isinstance(K, Space)
     assert isinstance(U, Space)
     ring = K.ring
     assert K.n == 1, "not tensor identity"
     tgt = K
     src = U @ U.dual
     A = elim.identity(ring, U.n)
     A.shape = (tgt.n, src.n)
     lin = Lin(tgt, src, A)
     return lin
Exemple #4
0
 def right_distributor(lhs, rhs, inverse=False):
     "A@C+B@C <---- (A+B)@C"
     # These turn out to be identity matrices (on the nose).
     if not isinstance(lhs, AddSpace):
         # There's nothing to distribute
         return (lhs @ rhs).identity()
     src = lhs @ rhs
     tgt = AddSpace(lhs.ring, *[l @ rhs for l in lhs.items])
     if inverse:
         tgt, src = src, tgt
     A = elim.identity(src.ring, src.n)
     return Lin(tgt, src, A)
Exemple #5
0
 def unitor(self, inverse=False):
     "remove all tensor units"
     items = self.items
     src = self
     tgt = [item for item in self.items if item.n != 1]
     if len(tgt) > 1:
         tgt = MulSpace(self.ring, *tgt)
     elif len(tgt):
         tgt = tgt[0]
     else:
         assert 0, "wah?"
     A = elim.identity(self.ring, self.n)
     if inverse:
         src, tgt = tgt, src  # the same A works
     return Lin(tgt, src, A)
Exemple #6
0
 def nullitor(self, inverse=False):
     "remove all zero (null) summands"
     items = self.items
     src = self
     tgt = [item for item in self.items if item.n]
     if len(tgt) > 1:
         tgt = AddSpace(self.ring, *tgt)
     elif len(tgt):
         tgt = tgt[0]
     else:
         assert 0, "wah?"
     A = elim.identity(self.ring, self.n)
     if inverse:
         src, tgt = tgt, src  # the same A works
     return Lin(tgt, src, A)
Exemple #7
0
 def get_swap(self, perm=(1, 0)):
     perm = tuple(perm)
     items = self.items
     assert len(perm) == len(items), ("len(%s)!=%d" % (perm, len(items)))
     assert set(perm) == set(range(len(items)))
     tgt = reduce(add, [items[i] for i in perm])
     N = len(items)
     rows = []
     for i in perm:
         row = []
         for j in range(N):
             if i == j:
                 A = elim.identity(self.ring, items[i].n)
             else:
                 A = elim.zeros(self.ring, items[i].n, items[j].n)
             row.append(A)
         rows.append(row)
     rows = [numpy.concatenate(row, axis=1) for row in rows]
     A = numpy.concatenate(rows)
     return Lin(tgt, self, A)
Exemple #8
0
 def get_swap(self, perm=(1, 0)):
     perm = tuple(perm)
     items = self.items
     assert self.grade is not None
     assert len(perm) == len(items)
     assert set(perm) == set(range(len(items)))
     sign = self.ring.one
     N = len(items)
     for i in range(N):
         for j in range(i + 1, N):
             if perm[i] > perm[j] and (items[i].grade * items[j].grade) % 2:
                 sign *= -1
     A = sign * elim.identity(self.ring, self.n)
     shape = tuple(item.n for item in items)
     A.shape = shape + shape
     axes = list(perm)
     for i in range(N):
         axes.append(i + len(perm))
     A = A.transpose(axes)
     tgt = reduce(matmul, [self.items[i] for i in perm])
     A = A.reshape((tgt.n, self.n))  # its a square matrix
     return Lin(tgt, self, A)
Exemple #9
0
    def get_normal(self, N=None, K=None, inverse=False, force=False):
        #print("\nMulSpace.get_normal", self.name)
        assert N is None or N.n == 0
        assert K is None or K.n == 1
        ring = self.ring

        # depth-first recurse
        spaces = list(self.items)
        assert len(spaces) > 1, str(self)
        fs = [space.get_normal(N, K, force=force) for space in spaces]
        f = reduce(matmul, fs)
        assert isinstance(f.tgt, MulSpace)
        assert f.src == self
        spaces = list(f.tgt.items)

        #print("spaces:")
        #print([space.name for space in spaces])

        # first deal with N, K factors (*)
        idx = 0
        while idx < len(spaces):
            space = spaces[idx]
            if force and space.n == 0 or space == N:
                # kills everything
                tgt = N
                g = Lin.zero(tgt, f.tgt)
                f = g * f
                if inverse:
                    f = f.transpose()  # permutation matrix
                return f  # <-------------- return
            elif force and space.n == 1 or space == K:
                spaces.pop(idx)
            else:
                idx += 1

        #print("spaces:", [space.name for space in spaces])
        #print("self.items:", [space.name for space in self.items])

        if len(spaces) < len(f.tgt.items):
            tgt, src = MulSpace(ring, *spaces, K=K), f.tgt
            g = Lin(tgt, src, elim.identity(ring, tgt.n))
            f = g * f
            #print(tgt)

        #print("f.tgt", f.tgt)
        if spaces:
            gs = [space.get_normal(N, K, force=force)
                  for space in spaces]  # <--------- recurse
            spaces = [g.tgt for g in gs]
            g = reduce(matmul, gs)
            assert f.tgt == g.src
            f = g * f
            # go back to (*) ?

        # now distribute over AddSpace's
        for idx, space in enumerate(spaces):
            if isinstance(space, AddSpace):
                break
        else:
            if inverse:
                f = f.transpose()  # permutation matrix
            return f  # <---------------- return

        if idx + 1 < len(spaces):
            head = spaces[:idx]
            lhs = spaces[idx]
            rhs = MulSpace(ring, *spaces[idx + 1:], K=K)
            g = Lin.right_distributor(lhs, rhs)
            if head:
                head = MulSpace(ring, *head)
                g = head.identity() @ g
            f = g * f
        elif len(spaces) > 1:
            lhs = MulSpace(ring, *spaces[:idx], K=K)
            rhs = spaces[idx]
            #print("f =", f.homstr())
            assert f.tgt == lhs @ rhs
            #print("left_distributor", lhs, rhs)
            g = Lin.left_distributor(lhs, rhs)
            f = g * f

        g = f.tgt.get_normal(N, K, force=force)  # <-------------- recurse
        f = g * f
        if inverse:
            f = f.transpose()  # permutation matrix
        return f
Exemple #10
0
 def identity(self):
     A = elim.identity(self.ring, self.n)
     return Lin(self, self, A)
Exemple #11
0
def main():

    ring = element.Q
    zero = ring.zero
    one = ring.one

    n = argv.get("n", 3)
    if argv.cyclic:
        G = Group.cyclic(n)
    else:
        G = Group.symmetric(n)

    comm = G.is_abelian()

    print(G)

    d = len(G)
    K = Space(ring, 1, name="K")
    V = Space(ring, d, name="V")
    VV = V @ V

    scalar = K.identity()
    I = V.identity()
    swap = VV.get_swap()

    lunit = Lin(V, K @ V, elim.identity(ring, d))
    runit = Lin(V, V @ K, elim.identity(ring, d))

    cap = Lin(K, V @ V)  # tgt, src
    cup = Lin(V @ V, K)  # tgt, src
    for i in range(d):
        cup[i + d * i, 0] = one
        cap[0, i + d * i] = one

    # green spiders
    g_ = Lin(K, V)  # uniform discard
    _g = Lin(V, K)  # uniform create
    g_gg = Lin(VV, V)  # copy
    gg_g = Lin(V, VV)  # pointwise mul

    for i in range(d):
        g_[0, i] = one
        _g[i, 0] = one
        g_gg[i + d * i, i] = one
        gg_g[i, i + d * i] = one

    eq = lambda lhs, rhs: lhs.weak_eq(rhs)

    assert eq(g_gg >> (g_ @ I), I)  # counit
    assert eq(g_gg >> (I @ g_), I)  # counit
    assert eq(g_gg >> (g_gg @ I), g_gg >> (I @ g_gg))  # coassoc

    assert eq(gg_g * (_g @ I), I)  # unit
    assert eq(gg_g * (I @ _g), I)  # unit
    assert eq(gg_g * (gg_g @ I), gg_g * (I @ gg_g))  # assoc

    assert eq((g_gg @ I) >> (I @ gg_g), (I @ g_gg) >> (gg_g @ I))  # frobenius
    assert eq((g_gg @ I) >> (I @ gg_g), gg_g >> g_gg)  # extended frobenius

    assert eq(_g >> g_, d * scalar)

    assert eq(gg_g >> g_, cap)
    assert eq(_g >> g_gg, cup)

    # red spiders
    r_ = Lin(K, V)  # discard unit
    _r = Lin(V, K)  # create unit
    r_rr = Lin(VV, V)  # comul
    rr_r = Lin(V, VV)  # mul

    # hopf involution
    inv = Lin(V, V)

    lookup = dict((v, k) for (k, v) in enumerate(G))
    for i in range(d):
        g = G[i]
        if g.is_identity():
            r_[0, i] = one
            _r[i, 0] = one
        inv[lookup[~g], i] = one

        for j in range(d):
            h = G[j]
            gh = g * h
            k = lookup[gh]
            rr_r[k, i + j * d] = one
            r_rr[i + j * d, k] = one

    assert eq(r_rr >> (r_ @ I), I)  # unit
    assert eq(r_rr >> (I @ r_), I)  # unit
    assert eq(r_rr >> (r_rr @ I), r_rr >> (I @ r_rr))  # assoc

    assert eq(rr_r * (_r @ I), I)  # unit
    assert eq(rr_r * (I @ _r), I)  # unit
    assert eq(rr_r * (rr_r @ I), rr_r * (I @ rr_r))  # assoc

    assert eq((r_rr @ I) >> (I @ rr_r), (I @ r_rr) >> (rr_r @ I))  # frobenius
    assert eq((r_rr @ I) >> (I @ rr_r), rr_r >> r_rr)  # extended frobenius

    assert eq((_r >> r_), scalar)

    assert not eq(rr_r >> r_, cap)
    assert not eq(_r >> r_rr, cup)

    # K[G] is a bialgebra
    assert eq(rr_r >> g_, g_ @ g_)
    assert eq(_r >> g_gg, _r @ _r)
    assert eq(_r >> g_, scalar)
    if not argv.skip:
        assert eq(rr_r >> g_gg, (g_gg @ g_gg) >> (I @ swap @ I) >>
                  (rr_r @ rr_r))
    print("K[G] is comm  ", eq(swap >> rr_r, rr_r))
    print("K[G] is cocomm", eq(g_gg >> swap, g_gg))

    # K[G] is hopf
    rhs = g_ >> _r
    assert eq(g_gg >> (I @ inv) >> rr_r, rhs)
    assert eq(g_gg >> (inv @ I) >> rr_r, rhs)

    # k^G is a bialgebra
    assert eq(gg_g >> r_, r_ @ r_)
    assert eq(_g >> r_rr, _g @ _g)
    assert eq(_g >> r_, scalar)
    if not argv.skip:
        assert eq(gg_g >> r_rr, (r_rr @ r_rr) >> (I @ swap @ I) >>
                  (gg_g @ gg_g))

    # k^G is hopf
    rhs = r_ >> _g
    assert eq(r_rr >> (I @ inv) >> gg_g, rhs)
    assert eq(r_rr >> (inv @ I) >> gg_g, rhs)
    print("k^G is comm   ", eq(swap >> gg_g, gg_g))
    print("k^G is cocomm ", eq(r_rr >> swap, r_rr))

    #print(rr_r)
    #print(r_rr)

    # unimodular
    r_cup = _r >> r_rr
    g_cap = gg_g >> g_
    assert eq(r_cup >> (I @ g_), _g)
    assert eq(r_cup >> (g_ @ I), _g)
    assert eq((I @ _r) >> g_cap, r_)
    assert eq((_r @ I) >> g_cap, r_)
    assert eq(inv, (I @ r_cup) >> (swap @ I) >> (I @ g_cap))
    assert eq(inv, (r_cup @ I) >> (I @ swap) >> (g_cap @ I))

    assert eq(r_rr >> rr_r, d * I)
    assert eq(g_gg >> gg_g, I)  # special

    # complementary frobenius structures ?
    # Heunen & Vicary eq (6.4)
    lhs = (_r @ I) >> (r_rr @ g_gg) >> (I @ gg_g @ I) >> (I @ g_ @ I) >> (
        I @ lunit) >> rr_r
    rhs = g_ >> _r
    assert eq(lhs, rhs)

    lhs = (I @ _r) >> (r_rr @ g_gg) >> (I @ gg_g @ I) >> (I @ g_ @ I) >> (
        I @ lunit) >> rr_r
    #assert eq(lhs, rhs) # FAIL

    lhs = (_g @ I) >> (g_gg @ r_rr) >> (I @ rr_r @ I) >> (I @ r_ @ I) >> (
        I @ lunit) >> gg_g
    rhs = r_ >> _g
    assert eq(lhs, rhs)

    lhs = (I @ _g) >> (g_gg @ r_rr) >> (I @ rr_r @ I) >> (I @ r_ @ I) >> (
        I @ lunit) >> gg_g
    #assert eq(lhs, rhs) # FAIL

    # Heunen & Vicary eq (6.5)
    lhs = (_r @ I) >> (r_rr @ I) >> (I @ gg_g) >> (I @ g_)
    rhs = (I @ _r) >> (I @ r_rr) >> (gg_g @ I) >> (g_ @ I)
    assert eq(lhs, rhs)

    lhs = (_g @ I) >> (g_gg @ I) >> (I @ rr_r) >> (I @ r_)
    rhs = (I @ _g) >> (I @ g_gg) >> (rr_r @ I) >> (r_ @ I)
    assert eq(lhs, rhs)

    assert eq(r_rr, r_rr >> swap) == G.is_abelian()
    assert eq(rr_r, swap >> rr_r) == G.is_abelian()

    assert eq(_r >> r_rr, _r >> r_rr >> swap)
    assert eq(rr_r >> r_, swap >> rr_r >> r_)
Exemple #12
0
 def identity(self, *args):
     return elim.identity(self.ring, *args)