言語rubyにおける代数の実装 -...

114
オブジェクト指向プログラミング 言語 Ruby における代数の実装 ( ) 2006 9 18

Upload: dangnhan

Post on 29-Aug-2019

214 views

Category:

Documents


0 download

TRANSCRIPT

オブジェクト指向プログラミング言語Rubyにおける代数の実装

原 信一郎(長岡技術科学大学)

2006年9月18日

1

自己紹介

2

algebraとは

代数的対象を表現しようとするRubyのライブラリ

2

algebraとは

代数的対象を表現しようとするRubyのライブラリ

代数的対象 · · · 群、環、体などのシステム、多項式、有理式、行列などのモノ

3

開発の動機

4

algebraの特徴

• インターフェースとしての特徴? Rubyの中に自然に溶け込んでいる? 数学的なアルゴリズムをそのまま表現できる? 数学的対象 = オブジェクト

• 実装としての特徴? 拡張性を重視している? “Pure Ruby” のライブラリである。

5

? 遅い

6

algebraのできること

• 体や環を定義できる? 剰余環? 代数拡大? 商体? 多項式環? 行列環? 有限群

7

• 多項式の因数分解? 整数上? 有理数上? 素体上? 代数体上(1変数のみ)

• 線形代数? 任意の体での連立1次方程式の解? 代数体係数の正方行列の対角化? 整数や任意の体上の多項式の作る行列の単因子を求める? Jordan標準形を求める

8

• 任意の体上の多項式の作るイデアルのグレブナ基底を求める

? 任意の体での連立代数方程式の解? 様々な応用

• 代数方程式? 代数体上の代数方程式の解? 有理数係数多項式の最小分解体やガロア群を求める(苦しい)

9

実例1 · · · 最初に代数系ありき

require ”algebra”

9

実例1 · · · 最初に代数系ありき

require ”algebra”

P = Polynomial(Rational, ”x”) # P = Q[x]

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 # 「入れ物」を定義してから、メンバーを扱う!

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”

10

実例2 · · · 代数構造しか見えない

require ”algebra”

R2, r2, r2 = Root(Rational, 2) # R2 = Q(√

2), r2 = ±√2

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”)

11

P, x = Polynomial(R6, ”x”)

(x**4 - 60*x**2 + 36).factorize

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◦回転させ

る行列を求めよ。

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]

13

実例3【 解答】

u0 = Vector(Rational, 3)[1, 1, 2]

u1, u2 = u0.orthogonal basis

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)

14

M = SquareMatrix(F3, 3)

a = M[u0, u1, u2].transpose

14

M = SquareMatrix(F3, 3)

a = M[u0, u1, u2].transpose

b = M[u0, u2, -u1].transpose

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)

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]]

16

m = M[[a, b, c], [d, e, f], [g, h, i]]k = m * N.unity - m # 差は「要素毎」が優先

16

m = M[[a, b, c], [d, e, f], [g, h, i]]k = m * N.unity - m # 差は「要素毎」が優先k.display

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]]

17

p k.determinant

17

p k.determinant · · · M[[0, 0, 0], [0, 0, 0], [0,0, 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の特徴

• プログラミングの容易さがとことん追求されている。

19

Rubyの特徴

• プログラミングの容易さがとことん追求されている。

• 全てがオブジェクトである。

19

Rubyの特徴

• プログラミングの容易さがとことん追求されている。

• 全てがオブジェクトである。 → クラスもオブジェクト

19

Rubyの特徴

• プログラミングの容易さがとことん追求されている。

• 全てがオブジェクトである。 → クラスもオブジェクト

• 変数に型が無い。

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という新しい数を定義する方法は?

22

Rubyの数システム

新しい数 Z2 における和の定義

【問】既に Integerという数があるとして、そこにZ2という新しい数を定義する方法は?

【答】新旧の数が共にcoerceプロトコルを守ること。

23

    coerceプロトコルとは、古い数における演算の定義を変更することなく、新しい数との演算を可能にする、新旧の数が守るべき規約。

24

Z2における + の定義

 def +(other)

24

Z2における + の定義

 def +(other)

   if other.is a? Z2 # 新しい数同士の和   Z2.new(@body + other.body)

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)

25

Integer における + の(既になされている)定義

 def +(other)

   if other.is a? Integer

   通常のselfとother和

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)

26

Z2 における coerce の定義

 def coerce(other)

   if other.is a? Integer

    [Z2.new(other), self]

  else

   その他の処理  end

 end

27

更に、Z2における + の正しい定義

 def +(other)

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

29

1 + one → 1 は one を知らない

29

1 + one → 1 は one を知らない→ 1 は one に自分の身の処し方を問う

29

1 + one → 1 は one を知らない→ 1 は one に自分の身の処し方を問う→ one は coerce(1) を起動し Z2.new(1) と自身を返す

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

33

F(R)でのcoerceの定義

 def coerce(other)

   [regulate(other), self]

 end

34

まとめ

+ R R[x]

R 1 + 1 1 + x

R[x] x + 1 x + x

x + 1 は x + regulate(1)で計算する。

35

+ R R[x]

R 1 + 1 1 + x

R[x] x + 1 x + x

1 + x で呼び出される x.coerce(1) は [x.regulate(1), x] を返す。

36

型キャストが必要な例

【問】K = Q(√

2), F = K(√

3), L = Q(√

3) とする。x ∈ F と y ∈ L の和x + yはどう計算すべきか?

F

K L

Q

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で書く? グレブナ基底の高速なアルゴリズムを実験する? 他ライブラリをリンクしてしまう

• 未実装のオブジェクトを実装? ベクトル空間、イデアルなど

• 構造の見直し

38

? キャストの工夫? PolynomialとMPolynomialの区別はなくせないか

39

    

おわり

    

http://blade.nagaokaut.ac.jp/˜sinara/ruby/math/algebra/

http://blade.nagaokaut.ac.jp/˜sinara/ruby/rational/

40

3色彩色問題

(問題)次のグラフの各点に色を塗る。線分で結ばれた2点は必ず異なる色で塗るとするとき、3色で塗ることは可能か?

x8

x2

x3

x4 x5

x1

x6x7

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)

43

…x1 - x7

x2 + x7

x3 - x7

x4

x5 + x7

x6

x7ˆ2 + 2

x8

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

47

+ a2b1b2 + a2b1c2 - a2b2c1 - a2c1c2 - a2 - b1ˆ2c1 - b1b2c2

+ b1c1ˆ2 + b2c1c2

a1b2 - a1c2 - a2b1 + a2c1 + b1c2 - b2c1 - 1