判別式を根で表せたので、今度は基本対称式で表すことを考えましょう。3次方程式の場合基本対称式は根をp, q, rで表したとき、
s1 = p + q + r
s2 = pq + pr + qr
s3 = pqr
の3つがあります。判別式は6次なので、これらの基本対称式の積で6次になる式の線形結合になります。そのような6次の積は以下の7つがあります。
t1 = s16
t2 = s14s2
t3 = s13s3
t4 = s12s2
t5 = s1s2s3
t6 = s23
t7 = s32
これらを根で表します。
t1 = p6 + 6p5q + 6p5r + 15p4q2 + 30p4qr + 15p4r2 + 20p3q3 + 60p3q2r + 60p3qr2 + 20p3r3 + 15p2q4 + 60p2q3r + 90p2q2r2 + 60p2qr3 + 15p2r4 + 6pq5 + 30pq4r + 60pq3r2 + 60pq2r3 + 30pqr4 + 6pr5 + q6 + 6q5r + 15q4r2 + 20q3r3 + 15q2r4 + 6qr5 + r6
t2 = p5q + p5r + 4p4q2 + 9p4qr + 4p4r2 + 6p3q3 + 22p3q2r + 22p3qr2 + 6p3r3 + 4p2q4 + 22p2q3r + 36p2q2r2 + 22p2qr3 + 4p2r4 + pq5 + 9pq4r + 22pq3r2 + 22pq2r3 + 9pqr4 + pr5 + q5r + 4q4r2 + 6q3r3 + 4q2r4 + qr5
t3 = p4qr + 3p3q2r + 3p3qr2 + 3p2q3r + 6p2q2r2 + 3p2qr3 + pq4r + 3pq3r2 + 3pq2r3 + pqr4
t4 = p4q2 + 2p4qr + p4r2 + 2p3q3 + 8p3q2r + 8p3qr2 + 2p3r3 + p2q4 + 8p2q3r + 15p2q2r2 + 8p2qr3 + p2r4 + 2pq4r + 8pq3r2 + 8pq2r3 + 2pqr4 + q4r2 + 2q3r3 + q2r4
t5 = p3q2r + p3qr2 + p2q3r + 3p2q2r2 + p2qr3 + pq3r2 + pq2r3
t6 = p3q3 + 3p3q2r + 3p3qr2 + p3r3 + 3p2q3r + 6p2q2r2 + 3p2qr3 + 3pq3r2 + 3pq2r3 + q3r3
t7 = p2q2r2
これらで判別式を表せばよいわけです。なかなか大変そうですね。しかし、例えばp4q2が対称式の中にあれば、
p4r2 p2q4 q4r2 p2r4 q2r4
もあるはずです。だから、一つに代表させればよいわけです。p, q, rの指数が降順になる項で代表させましょう。代表する項は、
p6 p5q p4q2 p4qr p3q3 p3q2r p2q2r2
の7つあります。基本対称式の積も7つありましたね。これは偶然でしょうか。
ちょっと考えると、
s1 -> p
s2 -> pq
s3 -> pqr
と置き換えると対応がつくことがわかります。また、基本対称式の積は線形独立なのは明らかなので、これで対称式は基本対称式で表されることが証明されました。
基本対称式の積を代表項r1, ..., r7で表すと、
t1 = r1 + 6r2 + 15r3 + 30r4 + 20r5 + 60r6 + 90r7
t2 = r2 + 4r3 + 9r4 + 6r5 + 22r6 + 36r7
t3 = r4 + 3r6 + 6r7
t4 = r3 + 2r4 + 2r5 + 8r6 + 15r7
t5 = r6 + 3r7
t6 = r5 + 3r6 + 6r7
t7 = r7
これを解いて、
r1 = t1 + -6t2 + 6t3 + 9t4 + -12t5 + -2t6 + 3t7
r2 = t2 + -1t3 + -4t4 + 7t5 + 2t6 + -3t7
r3 = -2t3 + t4 + 4t5 + -2t6 + -3t7
r4 = t3 + -3t5 + 3t7
r5 = -3t5 + t6 + 3t7
r6 = t5 + -3t7
r7 = t7
これを判別式に代入すれば、判別式を3次方程式の係数で表すことができます。
-4a3c + a2b2 + 18abc - 4b3 - 27c2
4次は
-27a4d2 + 18a3bcd - 4a3c3 - 4a2b3d + a2b2c2 + 144a2bd2 - 6a2c2d - 80ab2cd + 18abc3 - 192acd2 + 16b4d - 4b3c2 - 128b2d2 + 144bc2d - 27c4 + 256d3
5次は
256a5e3 - 192a4bde2 - 128a4c2e2 + 144a4cd2e - 27a4d4 + 144a3b2ce2 - 6a3b2d2e - 80a3bc2de + 18a3bcd3 - 1600a3be3 + 16a3c4e - 4a3c3d2 + 160a3cde2 - 36a3d3e - 27a2b4e2 + 18a2b3cde - 4a2b3d3 - 4a2b2c3e + a2b2c2d2 + 1020a2b2de2 + 560a2bc2e2 - 746a2bcd2e + 144a2bd4 + 24a2c3de - 6a2c2d3 + 2000a2ce3 - 50a2d2e2 - 630ab3ce2 + 24ab3d2e + 356ab2c2de - 80ab2cd3 + 2250ab2e3 - 72abc4e + 18abc3d2 - 2050abcde2 + 160abd3e - 900ac3e2 + 1020ac2d2e - 192acd4 - 2500ade3 + 108b5e2 - 72b4cde + 16b4d3 + 16b3c3e - 4b3c2d2 - 900b3de2 + 825b2c2e2 + 560b2cd2e - 128b2d4 - 630bc3de + 144bc2d3 - 3750bce3 + 2000bd2e2 + 108c5e - 27c4d2 + 2250c2de2 - 1600cd3e + 256d5 + 3125e4
となりました。
from itertools import * from fractions import Fraction def inverse(A): def find_not_zero(m): for m1 in range(m + 1, n): if A[m1][m] != 0: return m1 def swap(m): m1 = find_not_zero(m) A[m], A[m1] = A[m1], A[m] B[m], B[m1] = B[m1], B[m] def div(row, d): for k in range(n): row[k] /= d def sub(row, row0, m): for k in range(n): row[k] -= row0[k] * m def is_all_int(B): return all(e.denominator == 1 for v in B for e in v) A = [ map(Fraction, v) for v in A ] n = len(A) B = [ [ 1 if i == j else 0 for j in range(n) ] for i in range(n) ] for m in range(n): if A[m][m] == 0: swap(m) a = A[m][m] div(A[m], a) div(B[m], a) for k in range(m + 1, n): a = A[k][m] sub(A[k], A[m], a) sub(B[k], B[m], a) for m in range(n - 2, -1, -1): for k in range(m + 1, n): sub(B[m], B[k], A[m][k]) if not is_all_int(B): print "error : B includes fractions." exit(1) return [ map(int, v) for v in B ] def mul(A, v): N = len(A) return [ sum(A[j][i] * v[j] for j in range(N)) for i in range(N) ] class cPolynomial(dict): def __init__(self, k = 0): if k != 0: self[(0,)*N] = k def __add__(self, a): return self.add_sub(True, a) def __sub__(self, a): return self.add_sub(False, a) def add_sub(self, isadd, a): b = self.copy() for term, coeff in a.iteritems(): if isadd: b.add(term, coeff) else: b.add(term, -coeff) return b def __mul__(self, a): p = cPolynomial() for t1, c1 in self.iteritems(): for t2, c2 in a.iteritems(): t = tuple(e1 + e2 for e1, e2 in izip(t1, t2)) p.add(t, c1 * c2) return p def __pow__(self, e): if e == 0: return cPolynomial(1) return self * self ** (e - 1) def add(self, term, coeff): if coeff == 0: return if term in self: c = self.get(term) if c + coeff == 0: self.pop(term) else: self[term] += coeff else: self[term] = coeff def copy(self): b = cPolynomial() for key, value in self.iteritems(): b[key] = value return b def __str__(self): items = self.items() items.sort() return self.toStr(list(reversed(items))) def toStr(self, terms): if len(terms) == 0: return "0" return self.strTerm(terms[0], True) \ + "".join(self.strTerm(t, False) for t in terms[1:]) def strTerm(self, (term, coeff), ishead): return self.strCoeff(coeff, ishead) \ + "".join(self.strTerm2(k, t) for k, t in enumerate(term)) def strCoeff(self, c, ishead): if c == 1: return "" if ishead else " + " elif c == -1: return "-" if ishead else " - " elif c > 0: return str(c) if ishead else " + " + str(c) else: return str(c) if ishead else " - " + str(-c) def strTerm2(self, k, e): if e > 0: return chr(97 + k) + ("" if e == 1 else "^" + str(e)) else: return "" # x_k def mono(k): p = cPolynomial() term = tuple(1 if k == i else 0 for i in range(N)) p[term] = 1 return p # x_k1..x_kn def mono2(ks): p = cPolynomial() a = list(ks) term = tuple(1 if a.count(i) == 1 else 0 for i in range(N)) p[term] = 1 return p def calc_diff_product(): p = cPolynomial(1) for k, l in combinations(range(N), 2): p = p * (mono(k) - mono(l)) return p def determinant(): p = calc_diff_product() return p * p def collect_reprs(n, m, upper = -1): if upper == -1: upper = m if n == 0: if m == 0: yield () return for k in xrange(min(m, upper), -1, -1): for t in collect_reprs(n - 1, m - k, k): yield (k,) + t def bases(N, M): def add(s1, s2): return tuple(e1 + e2 for e1, e2 in izip(s1, s2)) def mono(k): return tuple(int(l == k) for l in xrange(1, N + 1)) bs = [ [] ] for k in xrange(1, M + 1): b = set() if k <= N: b.add(mono(k)) for l in (l for l in xrange(1, N + 1) if l < k): b.update(add(s1, mono(l)) for s1 in bs[k-l]) bs.append(list(b)) return list(reversed(sorted(bs[-1]))) def sym2poly(b): return reduce(lambda x, (k, e): x * ss[k] ** e, enumerate(b), cPolynomial(1)) def encode(p): def is_descending(t): return all(k >= l for k, l in izip(t, t[1:])) a = [ 0 ] * L for t, c in p.iteritems(): if is_descending(t): a[rs[t]] = c return a def convert(p): for t, c in p.iteritems(): s = sum((k + 1) % 2 * e for k, e in enumerate(t)) if s % 2 == 1: p[t] = -c N = 5 M = N * (N - 1) # dimension ss = [ reduce(lambda p, ks: p + mono2(ks), combinations(range(N), n), cPolynomial()) for n in xrange(1, N + 1) ] rs = dict((r, k) for k, r in enumerate(collect_reprs(N, M))) L = len(rs) bs = bases(N, M) bs2 = map(sym2poly, bs) A = map(encode, bs2) D = determinant() v = encode(D) w = mul(inverse(A), v) p = cPolynomial() p.update((bs[k], w[k]) for k in range(L) if w[k] != 0) convert(p) print p