ジュニア算数オリンピックにおけるユークリッド幾何学の問題の解答の自動化を模索している。まず三角形定理ループを回し、回答できなかったら1ステップの作図を試していって、それらで回答できるか探る。それでも駄目だったら2ステップ、3ステップと増やしていく。交点の確認はこの方法を使う。
『図の四角形ABCDはAB=BC=CDで、角B=168度、角C=108度です。角Dの大きさを求めなさい。
』
初期条件。いろいろ増えてしまったけど、必要な気がしている。
graph := [ A : [ [[B], [], []], [[D], [], []] ] , B : [ [[A], [], []], [[C], [], []] ] , C : [ [[B], [], []], [[D], [], []] ] , D : [ [[A], [], []], [[C], [], []] ] ]; clockwise_lst := [ A : [ [B, [], [], [D]], [D, [B], [], []], ~ #循環リストをこう表すことにした。[X, Y, Z, ~] ] , B : [ [C, [], [], [A]], [A, [C], [], []], ~ ] , C : [ [D, [], [], [B]], [B, [D], [], []], ~ ] , D : [ [A, [], [], [C]], [C, [A], [], []], ~ ] ]; angle_lst := [ A : [ [ [B, [], [], [D]], [D, [B], [], []] ] ] , B : [ [ [C, [], [], [A]], [A, [C], [], []] ] ] , C : [ [ [D, [], [], [B]], [B, [D], [], []] ] ] , D : [ [ [A, [], [], [C]], [C, [A], [], []] ] ] ]; parallel_lines_lst := [ ]; coplanar_lst := [ [A, B, C, D] ]; triangle_lst := [ ]; always { ABC_p == 168; BCD_p == 108; AB == BC == CD; }
辺による辺の和も180°の角の和も無し。angle_lstによる角の和も無し。平行線も無し。graphを辿っても三角形は見つからない。
セットアップが終わったので、作図に移る。
ジュニア算数オリンピック 二次元上のユークリッド幾何の問題 その25 - ニート歴10年からの数学日記、
セットアップ時の角の和の取得法について - ニート歴10年からの数学日記、
ジュニア算数オリンピック 二次元上のユークリッド幾何の問題 その21 - ニート歴10年からの数学日記の後半、
ジュニア算数オリンピック 二次元上のユークリッド幾何の問題 その18 - ニート歴10年からの数学日記、
ジュニア算数オリンピック 二次元上のユークリッド幾何の問題 その17 - ニート歴10年からの数学日記、
ジュニア算数オリンピック 二次元上のユークリッド幾何の問題 その16 - ニート歴10年からの数学日記、
辺りを参考にしようかな、後ろに行くほどもう参考にならないと思うけど。
まず点と点を結ぶ所から。
graphの最初のAを確認して、graphの繋がっていないCと単純に繋げる。clockwise_lstや、angle_lstも更新しなければならない。
まずgraphを更新する。
clockwise_lstのAにおいて、新しく作るCはどこに入るのか。
予想に反して、BとDの両方を問わなければいけないのかな?循環リストだから、2番目か3番目のどちらかなのだけど。
angle_lstなら、Bを問うだけで良いと思うんだけどな。
Aの所にCを追加する時に、AとCでBを共有していて(AにおいてBが通る辺のどれかの点がCと繋がっていたり、CにおいてBが通る辺のどれかの点がAと繋がっているのでも本当は良いと思うのだけど)、angle_lstのBにおいて時計回りでCからAなんで、Aから見てCはBより時計が進んだ側にある(手元で図を描いて理解している)、と言えるのではないか。
更にDに着目すると、時計回りでAからCなんで、Aから見てCはDより時計が戻った側にある。
よって、angle_lstのAにおいて、B、C、Dの順番なはずだ。Cにおいては逆のこと、つまりD、C、Bが言えるはずだ。
clockwise_lstもそれに合わせて更新しておこうか?なんかまだ洗練されてないけど。
graph := [ A : [ [[B], [], []], [[D], [], []], [[C], [], []] ] , B : [ [[A], [], []], [[C], [], []] ] , C : [ [[B], [], []], [[D], [], []], [[A], [], []] ] , D : [ [[A], [], []], [[C], [], []] ] ]; clockwise_lst := [ A : [ [B, [], [], [C, D]], [C, [B], [], [D]], [D, [B, C], [], []], ~ #循環リストをこう表すことにした。[X, Y, Z, ~] ] , B : [ [C, [], [], [A]], [A, [C], [], []], ~ ] , C : [ [D, [], [], [B, A]], [A, [D], [], [B]], [B, [D, A], [], []], ~ ] , D : [ [A, [], [], [C]], [C, [A], [], []], ~ ] ]; angle_lst := [ A : [ [ [B, [], [], [C, D]], [C, [B], [], [D]], [D, [B, C], [], []] ] ] , B : [ [ [C, [], [], [A]], [A, [C], [], []] ] ] , C : [ [ [D, [], [], [B, A]], [A, [D], [], [B]], [B, [D, A], [], []] ] ] , D : [ [ [A, [], [], [C]], [C, [A], [], []] ] ] ]; parallel_lines_lst := [ ]; coplanar_lst := [ [A, B, C, D] ]; triangle_lst := [ ]; always { ABC_p == 168; BCD_p == 108; AB == BC == CD; }
で、どういう順番で調べていけば良いのかっていうのが分からないというか、模索中で。
まあ、angle_lstから、
BAC_p + CAD_p == BAD_p;
ACD_p + ACB_p == BCD_p;
(angle_lstの角が最大のポジティブなら、その反転側は最小のネガティブなはずで、その最小のネガティブとそれぞれの角を足したのも登録すべきだった)
graphから△ABCと△ACDは言えると思うけど。
辺の和とか180°の角の和とか、平行線は無いし。
そのまま三角形定理ループにかけたら(三角形定理ループで条件が明らかになったらそのままオートで三角関数にもかけるんで)答えが出ちゃうわけだけど。
辺ACを基準に、angle_lstのAの中のCと、Cの中のAで、Bの位置が逆同士なんで三角関数にかけれる(しかしもう三角形として見つかっているのでかけない)とか、そういう判断もあるんだろうか。
次の作図に行くことにしよう。
次は線を同じ分だけ延長しよう。作図はリセットする。
graphを最初から見ていって、Aの1番目を延長する。Bの逆側に新しいEを加える。AB == AEもalwaysに加える。
更にangle_lstのAの、上だろうが下だろうが一番端がBの角があれば、逆側にEを加える。clockwise_lstを更新する。またそれぞれにEも加える。
graph := [ A : [ [[B], [], [E]], [[D], [], []] ] , B : [ [[A, E], [], []], [[C], [], []] ] , C : [ [[B], [], []], [[D], [], []] ] , D : [ [[A], [], []], [[C], [], []] ] , E : [ [[A, B], [], []] ] ]; clockwise_lst := [ A : [ [B, [], [], [D, E]], [D, [B], [], [E]], [E, [B, D], [], []] ~ #循環リストをこう表すことにした。[X, Y, Z, ~] ] , B : [ [C, [], [], [A]], [A, [C], [], []], ~ ] , C : [ [D, [], [], [B]], [B, [D], [], []], ~ ] , D : [ [A, [], [], [C]], [C, [A], [], []], ~ ] , E : [ [A, [], [], []] ] ]; angle_lst := [ A : [ [ [B, [], [], [D, E]], [D, [B], [], [E]], [E, [B, D], [], []] ] ] , B : [ [ [C, [], [], [A]], [A, [C], [], []] ] ] , C : [ [ [D, [], [], [B]], [B, [D], [], []] ] ] , D : [ [ [A, [], [], [C]], [C, [A], [], []] ] ] , E : [ ] ]; parallel_lines_lst := [ ]; coplanar_lst := [ [A, B, C, D] ]; triangle_lst := [ ]; always { ABC_p == 168; BCD_p == 108; AB == BC == CD; AB == AE; }
模索中だが、辺の和と180°の角の和を更新する。
AB + AE == BE
BAD_p + DAE_p == BAE_h
Eに繋がっている辺はAE以外に無いから三角関数は無理で、AからはBへは直線で、ADで調べることになるだろう。AとDを基準に、しかしangle_lstのDの中のAより上には何も無いので、何も無し。
ああ後、coplanar_lstにもEを追加するんだった。
こんな感じだろうか。次の作図に行こう。
二等辺三角形の作図は、三角形が無いし、交点の判断以外は難しくないので、飛ばすことにしよう。
じゃあ、クラスタの貼り合わせ。しかしそうすると、cluster_lstも必要なんじゃないか。凄い量だけど、新しい3つの情報は全てセットのようなものだから、自分な中では自然に思える。
試しにADで反転させるなら、元BをE、元CをFとして、
[[A, B, C, D], [BAD_p, AB, ABC_p, BC, BCD_p, CD, ADC_p, AD]]
[[A, E, F, D], [DAE_p, AE, AEF_p, EF, DFE_p, DF, ADF_p, AD]]
というようなイメージなんだが、まずgraphにこのクラスタの通りにEとFと辺を追加する。
いやしかし、点Aに新しく追加したAEだけど、AD上の点だとか、AB上の点と繋がってないわけで、あの方法が使えないのか。
新しく作った角BAEとかがプラスにならなくても、貼り合わせるということだけはやる予定なんだが。
今まではgraphを更新し、cluster_lstに対応するように登録して、後はイコールだとかを登録する流れだった。作った角の和がポジティブだったら、合体させてそれもcluster_lstに登録していた。
今回は、それに加えて、angle_lstやclockwise_lstやcoplanar_lstも登録する必要がある。angle_lstは角の和がポジティブだと分からない状態では、バラバラに登録するしか無い。clockwise_lstは今回は難しくないと思うけど、どちらもポジティブだし。coplanar_lstも難しくないし。
graph := [ A : [ [[B], [], []], [[D], [], []], [[E], [], []] ] , B : [ [[A], [], []], [[C], [], []] ] , C : [ [[B], [], []], [[D], [], []] ] , D : [ [[A], [], []], [[C], [], []], [[F], [], []] ] , E : [ [[A], [], []], [[F], [], []] ] , F : [ [[D], [], []], [[E], [], []] ] ]; clockwise_lst := [ A : [ [B, [], [], [D, E]], [D, [B], [], [E]], [E, [B, D], [], []] ~ ] , B : [ [C, [], [], [A]], [A, [C], [], []], ~ ] , C : [ [D, [], [], [B]], [B, [D], [], []], ~ ] , D : [ [A, [], [], [C, F]], [C, [A], [], [F]], [F, [A, C], [], []] ~ ] , E : [ [A, [F], [], []], [F, [], [], [A]], ~ ] , F : [ [E, [D], [], []], [D, [], [], [E]], ~ ] ]; angle_lst := [ A : [ [ [B, [], [], [D]], [D, [B], [], []] ] , [ [D, [], [], [E]], [E, [D], [], []] ] ] , B : [ [ [C, [], [], [A]], [A, [C], [], []] ] ] , C : [ [ [D, [], [], [B]], [B, [D], [], []] ] ] , D : [ [ [A, [], [], [C]], [C, [A], [], []] ] , [ [F, [], [], [D]], [D, [F], [], []] ] ] , E : [ [ [A, [F], [], []], [F, [], [], [A]] ] ] , F : [ [ [E, [D], [], []], [D, [], [], [E]] ] ] ]; parallel_lines_lst := [ ]; coplanar_lst := [ [A, B, C, D, E, F] ]; triangle_lst := [ ]; cluster_lst := [ [[A, B, C, D], [BAD_p, AB, ABC_p, BC, BCD_p, CD, ADC_p, AD]], [[A, E, F, D], [DAE_p, AE, AEF_p, EF, DFE_p, DF, ADF_p, AD]] ]; always { ABC_p == 168; BCD_p == 108; AB == BC == CD; AEF_p == 168; DFE_p == 108; AE == EF == DF; 後はクラスターの対応する部分をイコールで }
こういうイメージだ。適当だったけど。
クラスターの角を、時計回りを基準に反転させるのがちょっと違う作業だったのかな。
この後の作業は無視しているし、(条件が判明し次第の角の)統合とかの作業もあるはずなのだけど。
一晩開けて思うのだけど、自動化を視野に入れたかったから書かなかったけど、イコールで無く以上以下を視野に入れれば、この角の和はポジティブだと分かるし、だからクラスタとしても登録できる。angle_lstにも登録できる。
同一平面上にあって、クラスタが同じ辺を共有していて、その角の和が両方180°以下の時に、新しいクラスタとして登録する、というのは毎回作図後のフェーズで確認しよう。
angle_lstもclockwise_lstから同じように毎回拡張できるようにしたいが。あるいはangle_lst同士か?本当に模索中なんで。
いや、angle_lst同士だろうな。時計回りだから可能になる。同じ点を共有していて、途中とでも足し合わせたらプラスになるなら、大きくできるか、新しく追加できるか、どちらかはまだ分からないが。
角の呼び方を時計回りに限定する、っていうのもアリなんだよな。そうすると、少なくとも角1や角2よりは明解になる。
それは良い考えだと思うしぜひ採用したいが、その時には角が180°以下だとどういうルートで判断するかが問題になるだろうな。
次の正三角形も、交点の判定の仕方はもう考えたし、角の割り方も位置関係が分からないなら分からないなりに方法を用意してあるし、考えなくても良いんじゃないかな。
とりあえず、他の問題でもこの方法論が通用するか見ていこう。それであと可能だと分かったらポジティブやネガティブを撤廃しよう。プログラムは、全てのジャンルで通用するかを調べていって、作るにしても最後に作れば良いんじゃないかな。