言語rubyにおける代数の実装 -...
TRANSCRIPT
4
algebraの特徴
• インターフェースとしての特徴? Rubyの中に自然に溶け込んでいる? 数学的なアルゴリズムをそのまま表現できる? 数学的対象 = オブジェクト
• 実装としての特徴? 拡張性を重視している? “Pure Ruby” のライブラリである。
7
• 多項式の因数分解? 整数上? 有理数上? 素体上? 代数体上(1変数のみ)
• 線形代数? 任意の体での連立1次方程式の解? 代数体係数の正方行列の対角化? 整数や任意の体上の多項式の作る行列の単因子を求める? Jordan標準形を求める
8
• 任意の体上の多項式の作るイデアルのグレブナ基底を求める
? 任意の体での連立代数方程式の解? 様々な応用
• 代数方程式? 代数体上の代数方程式の解? 有理数係数多項式の最小分解体やガロア群を求める(苦しい)
9
実例1 · · · 最初に代数系ありき
require ”algebra”
P = Polynomial(Rational, ”x”) # P = Q[x]x = P.var # 「入れ物」を定義してから、メンバーを扱う!
9
実例1 · · · 最初に代数系ありき
require ”algebra”
P = Polynomial(Rational, ”x”) # P = Q[x]x = P.var # 「入れ物」を定義してから、メンバーを扱う!
(x + 1)**3 · · · xˆ3 + 3xˆ2 + 3x + 1
9
実例1 · · · 最初に代数系ありき
require ”algebra”
P = Polynomial(Rational, ”x”) # P = Q[x]x = P.var # 「入れ物」を定義してから、メンバーを扱う!
(x + 1)**3 · · · xˆ3 + 3xˆ2 + 3x + 1
Q = Polynomial(P, ”y”) # Q = Q[x][y]
9
実例1 · · · 最初に代数系ありき
require ”algebra”
P = Polynomial(Rational, ”x”) # P = Q[x]x = P.var # 「入れ物」を定義してから、メンバーを扱う!
(x + 1)**3 · · · xˆ3 + 3xˆ2 + 3x + 1
Q = Polynomial(P, ”y”) # Q = Q[x][y]y = Q.var
9
実例1 · · · 最初に代数系ありき
require ”algebra”
P = Polynomial(Rational, ”x”) # P = Q[x]x = P.var # 「入れ物」を定義してから、メンバーを扱う!
(x + 1)**3 · · · xˆ3 + 3xˆ2 + 3x + 1
Q = Polynomial(P, ”y”) # Q = Q[x][y]y = Q.var
(x + y + 1)**2 · · · yˆ2 + (2x + 2)y + xˆ2 + 2x + 1
9
実例1 · · · 最初に代数系ありき
require ”algebra”
P = Polynomial(Rational, ”x”) # P = Q[x]x = P.var # 「入れ物」を定義してから、メンバーを扱う!
(x + 1)**3 · · · xˆ3 + 3xˆ2 + 3x + 1
Q = Polynomial(P, ”y”) # Q = Q[x][y]y = Q.var
(x + y + 1)**2 · · · yˆ2 + (2x + 2)y + xˆ2 + 2x + 1
#Q, x, y = Polynomial(Rational, ”x”, ”y”)でOK
10
実例2 · · · 代数構造しか見えない
require ”algebra”
R2, r2, r2 = Root(Rational, 2) # R2 = Q(√
2), r2 = ±√2R3, r3, r3 = Root(R2, 3) # R3 = Q(
√2)(√
3), r3 = ±√3
10
実例2 · · · 代数構造しか見えない
require ”algebra”
R2, r2, r2 = Root(Rational, 2) # R2 = Q(√
2), r2 = ±√2R3, r3, r3 = Root(R2, 3) # R3 = Q(
√2)(√
3), r3 = ±√3R6, r6, r6 = Root(R3, 6) # R6 = R3, r6 = ±√6
10
実例2 · · · 代数構造しか見えない
require ”algebra”
R2, r2, r2 = Root(Rational, 2) # R2 = Q(√
2), r2 = ±√2R3, r3, r3 = Root(R2, 3) # R3 = Q(
√2)(√
3), r3 = ±√3R6, r6, r6 = Root(R3, 6) # R6 = R3, r6 = ±√6r6 · · · -r2r3
10
実例2 · · · 代数構造しか見えない
require ”algebra”
R2, r2, r2 = Root(Rational, 2) # R2 = Q(√
2), r2 = ±√2R3, r3, r3 = Root(R2, 3) # R3 = Q(
√2)(√
3), r3 = ±√3R6, r6, r6 = Root(R3, 6) # R6 = R3, r6 = ±√6r6 · · · -r2r3
(r6 + r2)*(r6 - r2) · · · 4
11
P, x = Polynomial(R6, ”x”)
(x**4 - 60*x**2 + 36).factorize
· · · (x - 2r3 - 3r2)(x + 2r3 - 3r2)(x - 2r3 + 3r2)(x + 2r3 +
3r2)
12
実例3 · · · 「業務」の現場で
【問題】xyz-空間のベクトル
112
を軸にして90◦回転させ
る行列を求めよ。
【解答】Vector(Rational, 3)[1, 1, 2].rotation matrix(90)
12
実例3 · · · 「業務」の現場で
【問題】xyz-空間のベクトル
112
を軸にして90◦回転させ
る行列を求めよ。
【解答】Vector(Rational, 3)[1, 1, 2].rotation matrix(90)
うそ
13
実例3【 解答】
u0 = Vector(Rational, 3)[1, 1, 2]
u1, u2 = u0.orthogonal basis #u1,u2 ∈ Vector(Rational,3)
13
実例3【 解答】
u0 = Vector(Rational, 3)[1, 1, 2]
u1, u2 = u0.orthogonal basis #u1,u2 ∈ Vector(Rational,3)
F1, n1, = Root(Rational, u1.norm2) # n1 =√|u1|2 ∈ F1
13
実例3【 解答】
u0 = Vector(Rational, 3)[1, 1, 2]
u1, u2 = u0.orthogonal basis #u1,u2 ∈ Vector(Rational,3)
F1, n1, = Root(Rational, u1.norm2) # n1 =√|u1|2 ∈ F1
u1 = Vector(F1, 3) ** u1 / n1
13
実例3【 解答】
u0 = Vector(Rational, 3)[1, 1, 2]
u1, u2 = u0.orthogonal basis #u1,u2 ∈ Vector(Rational,3)
F1, n1, = Root(Rational, u1.norm2) # n1 =√|u1|2 ∈ F1
u1 = Vector(F1, 3) ** u1 / n1 # 単なる u1 / n1 はエラー
13
実例3【 解答】
u0 = Vector(Rational, 3)[1, 1, 2]
u1, u2 = u0.orthogonal basis #u1,u2 ∈ Vector(Rational,3)
F1, n1, = Root(Rational, u1.norm2) # n1 =√|u1|2 ∈ F1
u1 = Vector(F1, 3) ** u1 / n1 # 単なる u1 / n1 はエラーu2 = u2 - u2.inner product(u1) * u1 # u2 - (u2, u1)u1
13
実例3【 解答】
u0 = Vector(Rational, 3)[1, 1, 2]
u1, u2 = u0.orthogonal basis #u1,u2 ∈ Vector(Rational,3)
F1, n1, = Root(Rational, u1.norm2) # n1 =√|u1|2 ∈ F1
u1 = Vector(F1, 3) ** u1 / n1 # 単なる u1 / n1 はエラーu2 = u2 - u2.inner product(u1) * u1 # u2 - (u2, u1)u1
F2, n2, = Root(F1, u2.norm2)
13
実例3【 解答】
u0 = Vector(Rational, 3)[1, 1, 2]
u1, u2 = u0.orthogonal basis #u1,u2 ∈ Vector(Rational,3)
F1, n1, = Root(Rational, u1.norm2) # n1 =√|u1|2 ∈ F1
u1 = Vector(F1, 3) ** u1 / n1 # 単なる u1 / n1 はエラーu2 = u2 - u2.inner product(u1) * u1 # u2 - (u2, u1)u1
F2, n2, = Root(F1, u2.norm2)
u2 = Vector(F2, 3) ** u2 / n2
13
実例3【 解答】
u0 = Vector(Rational, 3)[1, 1, 2]
u1, u2 = u0.orthogonal basis #u1,u2 ∈ Vector(Rational,3)
F1, n1, = Root(Rational, u1.norm2) # n1 =√|u1|2 ∈ F1
u1 = Vector(F1, 3) ** u1 / n1 # 単なる u1 / n1 はエラーu2 = u2 - u2.inner product(u1) * u1 # u2 - (u2, u1)u1
F2, n2, = Root(F1, u2.norm2)
u2 = Vector(F2, 3) ** u2 / n2
F3, n0, = Root(F2, u0.norm2)
13
実例3【 解答】
u0 = Vector(Rational, 3)[1, 1, 2]
u1, u2 = u0.orthogonal basis #u1,u2 ∈ Vector(Rational,3)
F1, n1, = Root(Rational, u1.norm2) # n1 =√|u1|2 ∈ F1
u1 = Vector(F1, 3) ** u1 / n1 # 単なる u1 / n1 はエラーu2 = u2 - u2.inner product(u1) * u1 # u2 - (u2, u1)u1
F2, n2, = Root(F1, u2.norm2)
u2 = Vector(F2, 3) ** u2 / n2
F3, n0, = Root(F2, u0.norm2)
u0 = Vector(F3, 3) ** u0 / n0
14
M = SquareMatrix(F3, 3)
a = M[u0, u1, u2].transpose
b = M[u0, u2, -u1].transpose
c = b * a.inverse # ∵ b = c ∗ a
14
M = SquareMatrix(F3, 3)
a = M[u0, u1, u2].transpose
b = M[u0, u2, -u1].transpose
c = b * a.inverse # ∵ b = c ∗ a
c.display
14
M = SquareMatrix(F3, 3)
a = M[u0, u1, u2].transpose
b = M[u0, u2, -u1].transpose
c = b * a.inverse # ∵ b = c ∗ a
c.display· · ·
14
M = SquareMatrix(F3, 3)
a = M[u0, u1, u2].transpose
b = M[u0, u2, -u1].transpose
c = b * a.inverse # ∵ b = c ∗ a
c.display· · · (9秒後)
14
M = SquareMatrix(F3, 3)
a = M[u0, u1, u2].transpose
b = M[u0, u2, -u1].transpose
c = b * a.inverse # ∵ b = c ∗ a
c.display· · · (9秒後)
1/6, -1/3r2r3 + 1/6, 1/6r2r3 + 1/31/3r2r3 + 1/6, 1/6, -1/6r2r3 + 1/3-1/6r2r3 + 1/3, 1/6r2r3 + 1/3, 2/3
(r2, r3はそれぞれ ±√2, ±√3)
15
実例4 Cayley-Hamiltonの定理
require ”algebra”
R = MPolynomial(Integer)a,b,c,d,e,f,g,h,i,j = R.vars("abcdefghij")
15
実例4 Cayley-Hamiltonの定理
require ”algebra”
R = MPolynomial(Integer)a,b,c,d,e,f,g,h,i,j = R.vars("abcdefghij")M = SquareMatrix(R, 3)
15
実例4 Cayley-Hamiltonの定理
require ”algebra”
R = MPolynomial(Integer)a,b,c,d,e,f,g,h,i,j = R.vars("abcdefghij")M = SquareMatrix(R, 3)
# M = M(Z[a, b, c, d, e, f, g, h, i], 3, 3)
15
実例4 Cayley-Hamiltonの定理
require ”algebra”
R = MPolynomial(Integer)a,b,c,d,e,f,g,h,i,j = R.vars("abcdefghij")M = SquareMatrix(R, 3)
# M = M(Z[a, b, c, d, e, f, g, h, i], 3, 3)N = SquareMatrix(M, 3)
15
実例4 Cayley-Hamiltonの定理
require ”algebra”
R = MPolynomial(Integer)a,b,c,d,e,f,g,h,i,j = R.vars("abcdefghij")M = SquareMatrix(R, 3)
# M = M(Z[a, b, c, d, e, f, g, h, i], 3, 3)N = SquareMatrix(M, 3)
# N = M(M(Z[a, b, c, d, e, f, g, h, i], 3, 3), 3, 3)
16
m = M[[a, b, c], [d, e, f], [g, h, i]]k = m * N.unity - m # 差は「要素毎」が優先k.display· · · [[0, b, c], [d, -a + e, f], [g, h, -a +
i]], [[-b, 0, 0], [0, -b, 0], [0, 0, -b]], [[-c,0, 0], [0, -c, 0], [0, 0, -c]]
[[-d, 0, 0], [0, -d, 0], [0, 0, -d ]], [[a - e,b, c], [d, 0, f], [g, h, -e + i]], [[-f, 0, 0],[0, -f, 0], [0, 0, -f]]
[[-g, 0, 0], [0, -g, 0], [0, 0, -g]], [[-h, 0,0], [0, -h, 0], [0, 0, -h]], [ [ a - i, b, c],[d, e - i, f], [g, h, 0]]
18∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣
a b c
d e f
g h i
− aE3 −bE3 −cE3
−dE3
a b c
d e f
g h i
− eE3 −fE3
−gE3 −hE3
a b c
d e f
g h i
− iE3
∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣= 0
19
Rubyの特徴
• プログラミングの容易さがとことん追求されている。
• 全てがオブジェクトである。 → クラスもオブジェクト
• 変数に型が無い。 → duck typing
• Bignumが実装されている。
20
クラスは代数系に見える
class Fixnum
alias plus +
def +(other)
plus(other) % 2
end
end
1 + 1 · · · 0
2項演算子は演算の左辺のクラスで定義されるメソッドである。
21
class Z2
def initialize(x); @body = x % 2; end
def body; @body; end
def +(other); Z2.new(@body + other.body); end
def to s; [”zero”, ”one”][@body]; end
end
one = Z2.new(1)
puts one · · · oneputs one + one · · · zero
22
Rubyの数システム
新しい数 Z2 における和の定義
【問】既に Integerという数があるとして、そこにZ2という新しい数を定義する方法は?
【答】新旧の数が共にcoerceプロトコルを守ること。
24
Z2における + の定義
def +(other)
if other.is a? Z2 # 新しい数同士の和 Z2.new(@body + other.body)
elsif other.is a? Integer # 古い数との和 Z2.new(@body + other)
end
end
24
Z2における + の定義
def +(other)
if other.is a? Z2 # 新しい数同士の和 Z2.new(@body + other.body)
elsif other.is a? Integer # 古い数との和 Z2.new(@body + other)
end
end
これで one + one, one + 1 が可能。
24
Z2における + の定義
def +(other)
if other.is a? Z2 # 新しい数同士の和 Z2.new(@body + other.body)
elsif other.is a? Integer # 古い数との和 Z2.new(@body + other)
end
end
これで one + one, one + 1 が可能。 では、1 + one はどうする?
25
Integer における + の(既になされている)定義
def +(other)
if other.is a? Integer
通常のselfとother和 else # 未知の数との和 me, it = other.coerce(self)
me + it
end
end
26
Z2 における coerce の定義
def coerce(other)
if other.is a? Integer
[Z2.new(other), self]
else
その他の処理 end
end
27
更に、Z2における + の正しい定義
def +(other)
if other.is a? Z2 # 新しい数同士の和 Z2.new(@body + other.body)
elsif other.is a? Integer # 古い数との和 Z2.new(@body + other)
27
更に、Z2における + の正しい定義
def +(other)
if other.is a? Z2 # 新しい数同士の和 Z2.new(@body + other.body)
elsif other.is a? Integer # 古い数との和 Z2.new(@body + other)
else # 将来の拡張に備える me, it = other.coerce(self)
me + it
end
end
28
coerceのまとめ
+ Integer Z2
Integer 1 + 1 1 + one
Z2 one + 1 one + one
one + 1, one + oneは Z2で定義すればよい。
28
coerceのまとめ
+ Integer Z2
Integer 1 + 1 1 + one
Z2 one + 1 one + one
one + 1, one + oneは Z2で定義すればよい。 1 + oneは…
29
1 + one → 1 は one を知らない→ 1 は one に自分の身の処し方を問う→ one は coerce(1) を起動し Z2.new(1) と自身を返す→ 1 は受け取った2つのオブジェクトの + を計算する
29
1 + one → 1 は one を知らない→ 1 は one に自分の身の処し方を問う→ one は coerce(1) を起動し Z2.new(1) と自身を返す→ 1 は受け取った2つのオブジェクトの + を計算する
29
1 + one → 1 は one を知らない→ 1 は one に自分の身の処し方を問う→ one は coerce(1) を起動し Z2.new(1) と自身を返す→ 1 は受け取った2つのオブジェクトの + を計算する
結局 one + 1 も 1 + one もZ2側で定義できる!
30
algebraの数システム
代数系から代数系を作る
• 環 R から多項式環 R[x] を作る
• 環 R からその上の行列環 M(R, m, n) を作る
• 環 R と元 p ∈ R から剰余環環 R/(p) を作る
• 環 R からその商環 RS を作る
31
一般にRからF(R)を作ったとき、自然な埋め込みあるいは射影φ : R → F(R) がある。これをcoerceに組み込む
F(R)での+の定義
def +(other)
if o = regulate(other)
# selfとoの和の計算 else
x , y = other.coerce(self)
x + y
end
end
32
F(R)でのregulateの定義
def regulate(x)
if x.is a? self.class # x ∈ F(R) x
elsif y = ground.regulate(x) # 再帰的呼び出し φ(y) # φ : R → F(R) else
nil
end
end
36
型キャストが必要な例
【問】K = Q(√
2), F = K(√
3), L = Q(√
3) とする。x ∈ F と y ∈ L の和x + yはどう計算すべきか?
F
K L
Q【答】y ∈ L を y′ ∈ Fにキャストしてx + y′を計算する。
37
今後の課題
• 高速化? 素体など基礎部分ををCで書く? グレブナ基底の高速なアルゴリズムを実験する? 他ライブラリをリンクしてしまう
• 未実装のオブジェクトを実装? ベクトル空間、イデアルなど
• 構造の見直し
39
おわり
http://blade.nagaokaut.ac.jp/˜sinara/ruby/math/algebra/
http://blade.nagaokaut.ac.jp/˜sinara/ruby/rational/
41
(解)各点に F3 = Z/3Z の元を割り当てる。xi と xj の色が異なることは xi = xj + 1 あるいは xi = xj + 2 で表現できるので、これは (xi − xj − 1)(xi − xj − 2) = 0 と表現できる。これが、(i, j) ∈ L について成り立てばよい。ここで、L = {(1, 2), (1, 5), (1, 6), (2, 3), (2, 4), (2, 8), (3, 4),(3, 8), (4, 5), (4, 7), (5, 6), (5, 7), (6, 7), (7, 8)} である。
簡約グレブナ基底を求めるとG = {x1−x7, x2+x8, x3−x7, x4, x5+x7, x6, x7
2+2, x8}となる。G の零点集合が空でないことは容易に確かめることができる。
42
require ”algebra”
F3 = ResidueClassRing(Integer, 3)
vs = (1..8).map{|i| ”x#{i}”}xs = MPolynomial.create(F3, *vs).vars
fs = [[1,2],[1,5],[1,6],[2,3],[2,4], [2,8],[3,4],[3,8],[4,5],[4,7], [5,6],[5,7],[6,7],[7,8]].each do |i, j| i, j = (i-1)%xs.size, (j-1)%xs.size
fs.push((xs[i] - xs[j] - 1)*(xs[i] - xs[j] - 2))
end
fs.push(xs[7])
puts Groebner.basis(fs)
44
垂心の存在の証明
require ”algebra”
R = MPolynomial(Rational)
x,y,a1,a2,b1,b2,c1,c2 = R.vars(”xya1a2b1b2c1c2”)
V = Vector(R, 2)
X, A, B, C = V[x,y], V[a1,a2], V[b1,b2], V[c1,c2]
def perpendicular(p0, p1, p2, p3)
45
# 0のときp0-p1がp2-p3と垂直 (p0-p1).inner product(p2-p3)
end
l1 = perpendicular(X, A, B, C)
l2 = perpendicular(X, B, C, A)
l3 = perpendicular(X, C, A, B)
def line(p1, p2, p3)
SquareMatrix.det([[1, *p1], [1, *p2], [1, *p3]])
end
46
s = line(A, B, C)
g = Groebner.basis [l1, l2, l3, s-1]
# s-1 は三角形がつぶれていない条件を表現している
g.each do |f| p f
end
· · · x + a1a2b1 - a1a2c1 - a1b1c2 + a1c1c2 + a2ˆ2b2 -
a2ˆ2c2 - a2b1ˆ2 + a2b1c1 - a2b2ˆ2 + a2c2ˆ2 + b1ˆ2c2 -
b1c1c2 - b1 + b2ˆ2c2 - b2c2ˆ2
y - a1ˆ2b1 + a1ˆ2c1 + a1b1ˆ2 - a1c1ˆ2 - a2ˆ2b1 + a2ˆ2c1