def main(): desc = argv.next() assert desc print("constructing %s" % desc) assert "_" in desc, repr(desc) name, idx = desc.split("_") idx = int(idx) attr = getattr(Weyl, "build_%s" % name) G = attr(idx) print(G) e = G.identity gen = G.gen roots = G.roots els = G.generate() G = Group(els, roots) print("order:", len(els)) ring = element.Z value = zero = Poly({}, ring) q = Poly("q", ring) for g in els: #print(g.word) value = value + q**(len(g.word)) print(value.qstr()) n = len(gen) Hs = [] for idxs in all_subsets(n): print(idxs, end=" ") gen1 = [gen[i] for i in idxs] or [e] H = Group(mulclose(gen1), roots) Hs.append(H) gHs = G.left_cosets(H) value = zero for gH in gHs: items = list(gH) items.sort(key=lambda g: len(g.word)) #for g in items: # print(g.word, end=" ") #print() g = items[0] value = value + q**len(g.word) #print(len(gH)) print(value.qstr()) G = Group(els, roots) burnside(G, Hs)
def test_graded_sl3(): # --------------------------------------------------------------- # slightly more explicit calculation than test_hilbert above ring = Q zero = Poly({}, ring) one = Poly({():1}, ring) x = Poly("x", ring) y = Poly("y", ring) z = Poly("z", ring) u = Poly("u", ring) v = Poly("v", ring) w = Poly("w", ring) rel = x*u + y*v + z*w rels = [rel] rels = grobner(rels) for a in range(4): for b in range(4): gens = [] for p in all_monomials([x, y, z], a, ring): for q in all_monomials([u, v, w], b, ring): rem = p*q #gens.append(pq) for rel in rels: div, rem = rel.reduce(rem) #print(pq, div, rem) gens.append(rem) basis = grobner(gens) assert len(basis) == dim_sl3(a, b) print(len(basis), end=' ', flush=True) print()
def show_qpoly(G): gen = G.gen roots = G.roots els = G.generate() e = G.identity G = Group(els, roots) print("order:", len(els)) ring = element.Z value = zero = Poly({}, ring) q = Poly("q", ring) for g in els: #print(g.word) value = value + q**(len(g.word)) print(value.qstr()) lookup = dict((g, g) for g in G) # remember canonical word n = len(gen) for i in range(n): gen1 = gen[:i] + gen[i + 1:] H = mulclose_short([e] + gen1) eH = Coset(H, roots) H = Group(H, roots) #gHs = G.left_cosets(H) cosets = set([eH]) bdy = set(cosets) while bdy: _bdy = set() for coset in bdy: for g in gen: gH = Coset([g * h for h in coset], roots) if gH not in cosets: cosets.add(gH) _bdy.add(gH) bdy = _bdy value = zero for gH in cosets: items = list(gH) items.sort(key=lambda g: len(g.word)) #for g in items: # print(g.word, end=" ") #print() g = items[0] value = value + q**len(g.word) #print(len(gH)) print(value.qstr())
def test_hilbert_sl3(): # --------------------------------------------------------------- # Here we work out the coefficients of a Hilbert polynomial # given by the rational function top/bot. # These coefficients give the dimension of irreps of SL(3). # See also test_graded_sl3 below. ring = Q zero = Poly({}, ring) one = Poly({():1}, ring) x = Poly("x", ring) y = Poly("y", ring) z = Poly("z", ring) top = one - x*y bot = ((one-x)**3) * ((one-y)**3) def diff(top, bot, var): top, bot = top.diff(var)*bot - bot.diff(var)*top, bot*bot return top, bot fracs = {} fracs[0,0] = (top, bot) N = 3 for i in range(N): for j in range(N): top, bot = fracs[i, j] top, bot = diff(top, bot, 'x') fracs[i, j+1] = top, bot top, bot = fracs[i, j] top, bot = diff(top, bot, 'y') fracs[i+1, j] = top, bot print(".", end="", flush=True) print() for i in range(N+1): for j in range(N+1): if (i, j) not in fracs: continue top, bot = fracs[i, j] t = top.get_const() b = bot.get_const() val = t//b//factorial(i)//factorial(j) assert val == dim_sl3(i, j) print(val, end=" ") print()
def test_graded_1(): ring = Q zero = Poly({}, ring) one = Poly({():1}, ring) h = Poly("h", ring) # grade 1 x = Poly("x", ring) # grade 3 y = Poly("y", ring) # grade 5 lookup = {h:1, x:3, y:5} rels = [ x**5 - y**3 - h**15, # grade == 15 ] print("rels:") for rel in rels: print(rel) print() rels = grobner(rels) n = argv.get("n", 10) grades = dict((i, []) for i in range(n)) for i in range(n): for j in range(n): for k in range(n): g = 1*i + 3*j + 5*k if g >= n: continue for mh in all_monomials([h], i, ring): for mx in all_monomials([x], j, ring): for my in all_monomials([y], k, ring): rem = mh*mx*my while 1: rem0 = rem for rel in rels: div, rem = rel.reduce(rem) if rem == rem0: break grades[g].append(rem) for i in range(n): gens = grades[i] #basis = grobner(gens) if gens else [] #count = len(basis) count = sage_grobner(gens) print(count, end=",", flush=True) print()
def get_poly(self, ring=element.Z): A = self.A n = self.n B = numpy.zeros((n, n), dtype=object) ijs = numpy.transpose(numpy.nonzero(A)) for (i, j) in ijs: assert i != j ii, jj = (j, i) if i > j else (i, j) #ii, jj = i, j name = "a[%d,%d]" % (ii, jj) p = Poly(name, ring) B[i, j] = -p for i in range(n): B[i, i] = -B[i].sum() print("B =") print(B) #for row in B: # for col in row: # print("%6s"%col, end=" ") # print() B = get_submatrix(B, 0) trees = det(B, ring) return trees
def promote(self, other): if isinstance(other, Rational): return other #if isinstance(other, Poly): # return other other = Poly.promote(other, self.base) other = Rational(self.base, other, self.base.one) return other
def get_interp(self, verbose=False): links = self.links wires = {} for link in self.links: f, g, i, j = link label = f.tgt[i] assert label == g.src[j] occurs = wires.setdefault(label, []) occurs.append(link) # dimension of each vector space shapes = list(wires.items()) shapes.sort() shapes = [(k, len(v)) for (k, v) in shapes] #print("shapes:", shapes) shapes = dict(shapes) ring = element.Z polys = [Poly(letters[i], ring) for i in range(len(self.verts))] ops = {} # interpret each vertex name for vi, v in enumerate(self.verts): #print("interpret", v) # shape = (out[0], out[1], ..., in[0], in[1], ...) shape = [] for label in v.tgt + v.src: # out + in shape.append(shapes[label]) #F = numpy.zeros(shape=shape, dtype=object) F = Sparse(shape) idxs = [] for i, label in enumerate(v.tgt): occurs = wires[label] # all the links where this label occurs idx = None for _idx, link in enumerate(occurs): if link[0] == v and link[2] == i: assert idx is None idx = _idx assert idx is not None, "missing link" idxs.append(idx) for i, label in enumerate(v.src): occurs = wires[label] # all the links where this label occurs idx = None for _idx, link in enumerate(occurs): if link[1] == v and link[3] == i: assert idx is None idx = _idx assert idx is not None, "missing link" idxs.append(idx) F[tuple(idxs)] = polys[vi] #F[tuple(idxs)] = 1 # numpy.einsum can't do object dtype... #print(F) op = ops.get(v.name) if op is None: op = F else: op = op + F ops[v.name] = op return Interpretation(self.sig, ops)
def test_genfunc(): N = 6 B2 = lambda a, b : (a+1)*(2*b+1)*(2*a+2*b+3)*(2*a+4*b+4)//12 C2 = lambda a, b : (a+1)*(b+1)*(a+b+2)*(a+2*b+3)//6 for a in range(N): for b in range(N): print("%5s"%C2(a,b), end=" ") print() print() from bruhat.rational import Rational ring = Q zero = Poly({}, ring) one = Poly({():1}, ring) x = Poly("x", ring) y = Poly("y", ring) z = Poly("z", ring) xx = Poly({(("x", 2),) : 1}, ring) xy = Poly({(("x", 1), ("y", 1)) : 1}, ring) fx = Rational(ring, one, (1-x)**4) print( ' '.join([str(fx[i]) for i in range(N)] )) fy = Rational(ring, 1-y**2, (1-y)**5) print( ' '.join([str(fy[i]) for i in range(N)] )) f = fx*fy*Rational(ring, (1-x*y)**4, one) print() for a in range(N): for b in range(N): print("%5s"%f[a, b], end=" ") print() return # <------------- return fx = Rational(ring, one, (1-x)**2) cs = [fx[i] for i in range(5)] assert cs == [1, 2, 3, 4, 5] fy = Rational(ring, 1-y**2, (1-y)**6) cs = [fy[i] for i in range(5)] assert cs == [1, 6, 20, 50, 105] # course generating function for SL(3) irreps f = Rational(ring, 1-x*y, (1-x)**3 * (1-y)**3) cs = [[f[i,j] for i in range(4)] for j in range(4)] assert cs == [[1, 3, 6, 10], [3, 8, 15, 24], [6, 15, 27, 42], [10, 24, 42, 64]]
def test_sl2(): ring = Q zero = Poly({}, ring) one = Poly({():1}, ring) a, b, c, d, e, f, g, h = [Poly(c, ring) for c in 'abcdefgh'] def repr_2d(a, b, c, d): A = numpy.empty((2, 2), dtype=object) A[:] = [[a, b], [c, d]] #A = A.transpose() return A def repr_3d(a, b, c, d): A = numpy.empty((3, 3), dtype=object) A[:] = [[a*a, a*c, c*c], [2*a*b, a*d+b*c, 2*c*d], [b*b, b*d, d*d]] A = A.transpose() return A #a, b, c, d, e, f, g, h = [1, 1, 1, 2, 1, 2, 0, 1] dot = numpy.dot A2 = repr_2d(a, b, c, d) B2 = repr_2d(e, f, g, h) #print(A2) #print(B2) AB2 = dot(A2, B2) #print(AB2) a0, b0, c0, d0 = AB2.flat A3 = repr_3d(a, b, c, d) B3 = repr_3d(e, f, g, h) AB3 = dot(A3, B3) #print(A3) #print(B3) #print(AB3) #print(repr_3d(a0, b0, c0, d0)) assert numpy.alltrue(AB3 == repr_3d(a0, b0, c0, d0))
def __init__(self, base, p, q, vs=None): # f(x) == p(x) / q(x) # q(x)*f(x) == p(x) p = Poly.promote(p, base) q = Poly.promote(q, base) zero, one = base.zero, base.one if vs is None: vs = p.get_vars() + q.get_vars() vs = list(set(vs)) vs.sort() n = len(vs) #assert n>0 #print("Rational(%s, %s, %s)" % (p, q, vs)) fs = {} vzero = tuple((v,zero) for v in vs) top = p.substitute(vzero) bot = q.substitute(vzero) if bot == 0: fs = None else: #print("top=%s, bot=%s" % (top, bot)) f0 = top/bot #print("f0:", lstr(f0)) fs[(0,)*n] = f0 self.base = base self.p = p self.q = q self.fs = fs self.vzero = vzero self.vs = vs self.bot = bot
def test_plucker(): ring = Q zero = Poly({}, ring) one = Poly({():1}, ring) rows, cols = argv.get("rows", 2), argv.get("cols", 4) U = numpy.empty((rows, cols), dtype=object) for i in range(rows): for j in range(cols): U[i, j] = Poly("x[%d,%d]"%(i, j), ring) print(U) COLS = list(range(cols)) w = {} # the plucker coordinates for idxs in choose(COLS, rows): V = U[:, idxs] #print(V) a = determinant(V) w[idxs] = a #print(idxs, a) if (rows, cols) == (2, 4): assert w[0,1]*w[2,3]-w[0,2]*w[1,3]+w[0,3]*w[1,2] == 0 for idxs in choose(COLS, rows-1): for jdxs in choose(COLS, rows+1): if len(idxs) and idxs[-1] >= jdxs[0]: continue #print(idxs, jdxs) sign = ring.one rel = ring.zero for l in range(rows+1): ldxs = idxs+(jdxs[l],) rdxs = jdxs[:l] + jdxs[l+1:] rel += sign*w[ldxs]*w[rdxs] sign *= -1 assert rel==0
def get_weights_sl3(a, b): ring = Q zero = Poly({}, ring) one = Poly({():1}, ring) x = Poly("x", ring) y = Poly("y", ring) z = Poly("z", ring) u = Poly("u", ring) v = Poly("v", ring) w = Poly("w", ring) # See: Fulton & Harris, page 183 grades = { # L_1, L_3 'x' : ( 0, 1), 'y' : (-1, -1), 'z' : ( 1, 0), 'u' : ( 0, -1), 'v' : ( 1, 1), 'w' : (-1, 0), } rel = x*u + y*v + z*w rels = [rel] rels = grobner(rels) gens = [] for p in all_monomials([x, y, z], a, ring): for q in all_monomials([u, v, w], b, ring): rem = p*q for rel in rels: div, rem = rel.reduce(rem) gens.append(rem) basis = grobner(gens) size = sage_grobner(gens) assert size == len(basis) weights = {} for p in basis: g = find_grade(grades, p) weights[g] = weights.get(g, 0) + 1 return weights
def all_monomials(vs, deg, ring): n = len(vs) assert n>0 if n==1: v = vs[0] yield v**deg return items = list(range(deg+1)) for idxs in cross((items,)*(n-1)): idxs = list(idxs) remain = deg - sum(idxs) if remain < 0: continue idxs.append(remain) p = Poly({():1}, ring) assert p==1 for idx, v in zip(idxs, vs): p = p * v**idx yield p
def test_so5(): # Plucker embedding for SO(5) ~= SO(2,3) ring = Q zero = Poly({}, ring) one = Poly({():1}, ring) a = Poly("a", ring) b = Poly("b", ring) c = Poly("c", ring) d = Poly("d", ring) # (2,3) space-time u = Poly("u", ring) # time coord v = Poly("v", ring) # time coord x = Poly("x", ring) # space coord y = Poly("y", ring) # space coord z = Poly("z", ring) # space coord # got from test_quaternion : rels = [ u**2+v**2-x**2-y**2-z**2, a*u + d*v -(a*x + c*z - d*y), a*v - d*u -(a*y - b*z + d*x), -b*u - c*v -(-b*x - c*y - d*z), b*v - c*u -(-a*z - b*y + c*x), ] rels = grobner(rels) for idx in range(6): for jdx in range(6): gens = [] for p in all_monomials([a, b, c, d], idx, ring): for q in all_monomials([u, v, x, y, z], jdx, ring): rem = p*q #for count in range(3): while 1: rem0 = rem for rel in rels: div, rem = rel.reduce(rem) if rem == rem0: break gens.append(rem) #print("gens:", len(gens)) n = sage_grobner(gens) #basis = grobner(gens) print("%3d"%n, end=' ', flush=True) print()
def test(): ring = Q zero = Poly({}, ring) one = Poly({():1}, ring) x = Poly("x", ring) y = Poly("y", ring) z = Poly("z", ring) xx = Poly({(("x", 2),) : 1}, ring) xy = Poly({(("x", 1), ("y", 1)) : 1}, ring) # course generating function for SL(2) irreps f = Rational(ring, one, (1-x)**2) cs = [f[i] for i in range(5)] assert cs == [1, 2, 3, 4, 5] f = Rational(ring, 1-x**2, (1-x)**6) cs = [f[i] for i in range(5)] assert cs == [1, 6, 20, 50, 105] # course generating function for SL(3) irreps f = Rational(ring, 1-x*y, (1-x)**3 * (1-y)**3) cs = [[f[i,j] for i in range(4)] for j in range(4)] assert cs == [[1, 3, 6, 10], [3, 8, 15, 24], [6, 15, 27, 42], [10, 24, 42, 64]] # fine generating function for SL(2) irreps J = Poly("J", ring) L = Poly("L", ring) Li = Poly("Li", ring) vs = [J, L, Li] f = Rational(ring, one, (1-J*L)*(1-J*Li), "J L Li".split()) assert f(L=one, Li=one) == Rational(ring, one, (1-J)**2) if 1: promote = lambda p : Rational(ring, p, one) r_one = Rational(ring, one, one) r_J = promote(J) r_L = promote(L) r_Li = r_one / r_L f = r_one / (1-r_J*r_L)*(1-r_J*r_Li) print(f) for i in range(4): for j in range(4): print(f[i, j], end=' ') print() return for i in range(4): for j in range(4): for k in range(4): print(f[i, j, k], end=' ', flush=True) print() print() # fine generating function for SL(3) irreps J = Poly("J", ring) K = Poly("K", ring) L = Poly("L", ring) Li = Poly("Li", ring) M = Poly("M", ring) Mi = Poly("Mi", ring) vs = [J, K, L, Li, M, Mi] f = Rational(ring, 1-J*K, (1-J*L)*(1-J*M*Li)*(1-J*Mi)*(1-K*Li)*(1-K*L*Mi)*(1-K*M), "J K L Li M Mi".split()) assert f(L=one, Li=one, M=one, Mi=one) \ == Rational(ring, 1-J*K, (1-J)**3 * (1-K)**3) if 0: f._pump(verbose=True) f._pump(verbose=True) f._pump(verbose=True) return def sample(ji, ki, li, mi): N = 3 if li>=0 and mi>=0: val = sum(f[ji, ki, l+li, l, m+mi, m ] for l in range(N) for m in range(N)) elif li>=0 and mi<0: val = sum(f[ji, ki, l+li, l, m, m-mi] for l in range(N) for m in range(N)) elif li<0 and mi<0: val = sum(f[ji, ki, l, l-li, m, m-mi] for l in range(N) for m in range(N)) elif li<0 and mi>=0: val = sum(f[ji, ki, l, l-li, m+mi, m ] for l in range(N) for m in range(N)) return val assert sample(0, 0, 0, 0) == 1 for (li, mi) in [ (-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 0), (0, 1), (1, -1), (1, 0), (1, 1), ]: print(sample(1, 0, li, mi)) for li in range(-2, 3): for mi in range(-2, 3): print(sample(1, 0, li, mi), end=" ", flush=True) print()
def named_poly(cs, names): items = {} for k, v in cs.items(): tpl = tuple((names[i], exp) for (i, exp) in enumerate(k) if exp) items[tpl] = v return Poly(items, ring)
def test_graded_2(): if argv.rational: ring = Q elif argv.gf2: ring = FiniteField(2) else: return zero = Poly({}, ring) one = Poly({():1}, ring) h = Poly("h", ring) x = Poly("x", ring) y = Poly("y", ring) z = Poly("z", ring) lookup = {h:1, x:3, y:4, z:5} vs = list(lookup.keys()) vs.sort(key = str) print("vs", vs) rels = [ #z*x + y*y, #x**3 + z*y, #z*z + y*x*h*h*h, y*x*h, #z*x*h, # grade 9 #z*z, # grade 10 #z*y*h, ] print("rels:") for rel in rels: print(rel) print() rels = grobner(rels) n = argv.get("n", 10) grades = dict((i, []) for i in range(n)) for i in range(n): for j in range(n): for k in range(n): #for l in range(n): g = 1*i + 2*j + 3*k # + 5*l if g >= n: continue for mh in all_monomials([h], i, ring): for mx in all_monomials([x], j, ring): for my in all_monomials([y], k, ring): #for mz in all_monomials([z], l, ring): rem = mh*mx*my #*mz while 1: rem0 = rem for rel in rels: div, rem = rel.reduce(rem) if rem == rem0: break grades[g].append(rem) for i in range(n): gens = grades[i] #print(gens) if argv.sage: count = sage_grobner(gens) else: basis = grobner(gens) if gens else [] count = len(basis) print(count, end=",", flush=True) print()
def test_graded_sl4(): # See: Miller & Sturmfels, p276 ring = Q zero = Poly({}, ring) one = Poly({():1}, ring) poly = lambda v : Poly(v, ring) p1 = poly("p1") p2 = poly("p2") p3 = poly("p3") p4 = poly("p4") p12 = poly("p12") p13 = poly("p13") p14 = poly("p14") p23 = poly("p23") p24 = poly("p24") p34 = poly("p34") p123 = poly("p123") p124 = poly("p124") p134 = poly("p134") p234 = poly("p234") rels = [ p23*p1 - p13*p2 + p12*p3, p24*p1 - p14*p2 + p12*p4, p34*p1 - p14*p3 + p13*p4, p34*p2 - p24*p3 + p23*p4, p14*p23 - p13*p24 + p12*p34, p234*p1 - p134*p2 + p124*p3 - p123*p4, p134*p12 - p124*p13 + p123*p14, p234*p12 - p124*p23 + p123*p24, p234*p13 - p134*p23 + p123*p34, p234*p14 - p134*p24 + p124*p34, ] rels = grobner(rels, verbose=True) print("rels:", rels) print() grades = [ [p1, p2, p3, p4], [p12, p13, p14, p23, p24, p34], [p123, p124, p134, p234], ] multi = argv.get("multi") n = 5 if multi is None else sum(multi)+1 n = argv.get("n", n) for g0 in range(n): for g1 in range(n): for g2 in range(n): if multi is not None and (g0, g1, g2)!=multi: #print(". ", end='') continue elif g0+g1+g2 > n-1: print(". ", end='') continue gens = [] for m0 in all_monomials(grades[0], g0, ring): for m1 in all_monomials(grades[1], g1, ring): for m2 in all_monomials(grades[2], g2, ring): m = m0*m1*m2 #for rel in rels: # div, m = rel.reduce(m) m = reduce_many(rels, m) if m != 0: gens.append(m) print(len(gens), end=':', flush=True) basis = grobner(gens) lhs = len(basis) rhs = (g0+1)*(g1+1)*(g2+1)*(g0+g1+2)*(g1+g2+2)*(g0+g1+g2+3)//12 assert lhs==rhs, ("%s != %s"%(lhs, rhs)) print(len(basis), end=' ', flush=True) # basis.sort(key=str) # heads = {} # for p in basis: # print(p.head, p) # heads[p.head] = p # print(len(heads)) # return print() print()
def get_weights_so5(idx=0, jdx=0): # Plucker embedding for SO(5) ~= SO(2+3) ring = Q zero = Poly({}, ring) one = Poly({():1}, ring) a = Poly("a", ring) b = Poly("b", ring) c = Poly("c", ring) d = Poly("d", ring) z = Poly("z", ring) e = Poly("e", ring) f = Poly("f", ring) g = Poly("g", ring) h = Poly("h", ring) half = one/2 u = half*(e+g) v = half*(f+h) x = half*(e-g) y = half*(h-f) assert u**2+v**2-x**2-y**2-z**2 == e*g + f*h - z**2 # got from test_quaternion : rels = [ e*g + f*h - z**2, a*u + d*v -(a*x + c*z - d*y), a*v - d*u -(a*y - b*z + d*x), -b*u - c*v -(-b*x - c*y - d*z), b*v - c*u -(-a*z - b*y + c*x), ] print("rels:") for rel in rels: print(rel) print() rels = grobner(rels) gens = [] for p in all_monomials([a, b, c, d], idx, ring): for q in all_monomials([e, f, g, h, z], jdx, ring): rem = p*q #for count in range(3): while 1: rem0 = rem for rel in rels: div, rem = rel.reduce(rem) if rem == rem0: break gens.append(rem) #print("gens:", len(gens)) basis = grobner(gens) for p in basis: print(p) n = sage_grobner(gens) assert n == len(basis) print("%3d"%n) grades = { # s q 'e' : ( 0, 1), 'b' : (-1, 1), 'f' : (-2, 1), 'a' : ( 1, 0), 'z' : ( 0, 0), 'd' : (-1, 0), 'h' : ( 2, -1), 'c' : ( 1, -1), 'g' : ( 0, -1), } weights = {} for p in basis: g = find_grade(grades, p) weights[g] = weights.get(g, 0) + 1 return weights
#!/usr/bin/env python3 """ q-deformed Pascal triangles """ from bruhat.element import Z from bruhat.poly import Poly from bruhat.argv import argv ring = Z zero = Poly({}, ring) one = Poly({(): 1}, ring) q = Poly("q", ring) def sl_pascal(row, col): assert 0 <= row assert 0 <= col <= row if col == 0 or col == row: return one left = sl_pascal(row - 1, col - 1) right = sl_pascal(row - 1, col) p = q**(row - col) * left + right #print("sl_pascal: " return p def sp_pascal(row, col): assert 0 <= row
def test_plucker_flag(): ring = Q zero = Poly({}, ring) one = Poly({():1}, ring) n = argv.get("n", 4) U = numpy.empty((n, n), dtype=object) for i in range(n): for j in range(n): U[i, j] = Poly("x[%d,%d]"%(i, j), ring) print(U) N = list(range(n)) w = {} # the plucker coordinates for k in range(1, n): for idxs in choose(N, k): V = U[:k, idxs] #print(V) a = determinant(V) if k==1: w[idxs[0]] = a else: w[idxs] = a #print(idxs, a) assert n==4 p1 = w[0] p2 = w[1] p3 = w[2] p4 = w[3] p12 = w[0,1] p13 = w[0,2] p14 = w[0,3] p23 = w[1,2] p24 = w[1,3] p34 = w[2,3] p123 = w[0,1,2] p124 = w[0,1,3] p134 = w[0,2,3] p234 = w[1,2,3] for rel in [ p23*p1 - p13*p2 + p12*p3, p24*p1 - p14*p2 + p12*p4, p34*p1 - p14*p3 + p13*p4, p34*p2 - p24*p3 + p23*p4, p14*p23 - p13*p24 + p12*p34, p234*p1 - p134*p2 + p124*p3 - p123*p4, p134*p12 - p124*p13 + p123*p14, p234*p12 - p124*p23 + p123*p24, p234*p13 - p134*p23 + p123*p34, p234*p14 - p134*p24 + p124*p34, ]: assert rel == 0 return for idxs in choose(N, rows-1): for jdxs in choose(N, rows+1): if len(idxs) and idxs[-1] >= jdxs[0]: continue print(idxs, jdxs) sign = ring.one rel = ring.zero for l in range(rows+1): ldxs = idxs+(jdxs[l],) rdxs = jdxs[:l] + jdxs[l+1:] rel += sign*w[ldxs]*w[rdxs] sign *= -1 print(rel)