連立二元一次方程式への挑戦

 いきなり『連立二元一次方程式』などと言うと、拒絶反応を起こす人も多いと思います。そんなもの、あまり興味がないとか、学生時代のイヤな数学の授業を思い出すという人も多いとは思います。なぜ、あえてそんなものに私が興味を持ったのかと申しますと、最近読んだ『行列とベクトルのはなし』(大村平著・日科技連出版社)で学んだ『行列』の考え方の一部をコンピュータプログラムにしてみようと思いついたからです。その『行列』や『ベクトル』などが、コンピュータに応用しやすいものであることを、そのプログラムを作って検証してみたいという欲求に駆られてしまいました。
 私は、高校時代に数学で『行列』や『ベクトル』を学んだのに、当時はよくわかりませんでした。その後も、大学の教養課程の数学で、『三角行列』を学んだのですが、十分に理解できませんでした。社会人になって、個人的な趣味で、数学雑誌や数学の書籍を買って読むことが多かったのですが、ほとんど理解できませんでした。私は、私自身に数学的なセンスや才能がないことにその度に気づかされました。しかし、それでもめげずに、今でもその『下手の横好き』が続いています。
 その安直な考え方の延長で、そんなに人間としての私自身がダメならば、機械であるコンピュータの力を借りて、複雑な数学の計算をやってしまおうと考えました。コンピュータのプログラミングであれば、計算間違いしても、それを直すのは簡単です。しかも、数の値を変えて、修正した処理を何度も再現できます。平たく言って、数学の問題を解くのを、それが得意なコンピュータという機械にやらせようと、あれこれプログラミングしてみようというわけです。
 思い起こせば、二十歳の頃、ポケットコンピュータのペーパーウェアの冊子に『行列』の計算をするためのBASICプログラムがいくつか載っていました。当時の私は、ゲームのプログラムには関心がありましたが、こうしたいわゆる数学モノには興味がわきませんでした。今になってみると残念なことです。あの頃の私の頭の中には、コンピュータを使って『行列』の計算をしてみようという考えが全くなかったのです。
 しかし、今回私は、そんなふうに若い頃は意識できなかったことを、あの頃とは違った意識でやってみようと思いつきました。なぜならば、今の私は、コンピュータの使い方のノウハウに関しては、あの頃とは比べ物にならないくらいよく知っているからです。
 と、その前に、私の手元の国語辞典で『連立二元一次方程式』に関連する言葉の意味を調べてみました。私の持っている国語辞典は、私が小学六年生の頃に買いました。つまり、45年くらい前に発行された古い国語辞典で、本の厚みと大きさがある卓上版でした。なので、持ち運びに不便です。けれども、文字が大きくて読みやすいため、いまだに私は利用しています。多少言葉の意味内容が古いかもしれませんが、今回の用語の説明には、あまり支障はないと思います。
 まず、『連立方程式』という言葉から調べました。それは、「二つ以上の方程式が同時になりたつことを求める方程式。」とのことです。何だ当たり前じゃないか、と思う人も多いと思います。例えば、
ax + by = c
a'x +b'y = c'
という二つの方程式があって、その未知数(元とも言います。)xとyのとりうる値がそれぞれ共通になる(例えば、x=2, y=3)ものを言います。誰だって、義務教育の数学でそれくらい勉強しているじゃないか、と思う人も多いと思います。事実、私もその一人でした。上の二つの方程式と『連立方程式』という言葉を、数学の教科書からも先生からも覚え込まされて、簡単な練習問題をやらされて答え合わせをさせられて、それで終わりでした。
 だから、子供のうちは、誰でもそのようにして獲得した知識や学力だけで十分だと思います。若者は、誰でもその程度の知識を記憶できます。そして、それは受験勉強以外には何の役にも立たないのが普通だと思います。誰も、その程度で成人して、何の不思議も問題も起こらない、と私は考えます。そんな知識を、無理やり日常生活に当てはめてみても、ムダな結果を知るのが関の山です。
 けれども、最近私は、『行列』を数学書で学び直して、プログラムでそれをコンピュータにやらせてみたところ、上の二つの方程式が連立方程式にならない場合があることを見つけてしまいました。中学の数学でそれを学んだ頃に抱いていたイメージでは、そんなことはなかったはずです。数学の先生や教科書から学んだ通り、あるいは練習問題を解いた通り、いつでも明快な答えが得られる確実な知識のはずでした。
 このことに関しては、あとでそのプログラムを示してから説明しましょう。ここでは本題に戻って、『連立方程式』周辺の言葉の意味や定義を、私の持っている国語辞典で調べることを続けてみます。そもそも、『方程式』とは、何でしょう。それは、「等式に含まれる未知数に、ある特別の数値を与える時に成立する等式。」のことだそうです。ちなみに、『等式』とは、「等号(左右双方の式が等しいことを表す=の符号)で結びつけられた二つ以上の数式」のことだそうです。その反対は、『不等式』で、「不等号(二つの数が等しくないことを示す><の符号)で結びつけられている式。」のことだそうです。また、『未知数』は、「方程式などで、まだ値の不明な数」のことで、その反対語は『既知数』で「すでに値がわかっている数」のことだそうです。
 ついでに、「二元一次方程式」についても、調べてみました。数学用語としての『元』とは、「代数方程式の未知数のこと」です。だから、xとyの二つの未知数が使われている方程式は、『二元方程式』と呼ばれます。また、数学用語としての『次』とは、未知数の乗数を表します。すなわち、一次方程式とは、一乗数の未知数からなる方程式のことです。よく中学や高校の数学で『二次方程式』というものを学びますが、二乗の未知数を持つ方程式のことです。さらに、『代数方程式』とは何かというと、「数の代わりに、aやxやnなどの文字を記号として使い、数の性質や関係を研究する数学、すなわち『代数(学)』で使われる方程式」のことです。私の持っている辞書は古いので、次のような数学用語も載っています。参考として述べておきます。『解析(学)』とは、「関数の性質を研究する、高等数学の一つ。」という意味です。また、『幾何(学)』は、「物の形・大きさ・その他空間の性質を研究する、数学の一部門のこと。」を言います。さらに、『行列』とは、「数を長方形、または、正方形に並べて、ひとまとめにしたもの。」とありました。ここまで書いてあると、意味内容の正確さよりも、表現の面白さに気をとられてしまいます。
 そもそも、「数学を専門に研究する」数学者ではない人が、数学に興味を持ってもおかしくはなかったはずです。日本の数学教育において二次関数のグラフなどで必ず学ぶことになる、あの平面上のxとyの『座標』というものを考え出したのは誰だったのかを考えてみてください。それは、あのフランスの哲学者で有名なデカルトさんでした。彼は、二つの実数によって平面上の点の位置を表すという方法、すなわち、X軸とY軸のグラフを描く『座標』という方法を発見するなどして、のちの『解析幾何学』の発展の基礎を築いたそうです。(日本の数学者の矢野健太郎さんの著作物の一つ『数学の歩み』に、そのようなことが記述されていました。)
 だいぶ前置きをしましたが、ウィンドウズのHTMLアプリケーションとして動くVBスクリプトのプログラムを以下に示しておきましょう。


連立二元一次方程式V1.00.hta

<STYLE TYPE="text/css">

  BODY  { background-color:rgb(80%,70%,70%); overflow:auto; }
  SPAN  { font-size:20pt; height:20pt; padding:4pt; margin:3pt 0pt;
          cursor:default; }
  .coef { font-size:24pt; }
  .fita { font-size:20pt; font-style:italic; }
  .wbtn { font-size:14pt; background-color:white;
          border-bottom: thin solid gray;
          border-right: thin solid gray; }

</STYLE>

<HTA:Application Id=oHTA Scroll=no  Contextmenu=no />


<BODY scroll=No>

<SPAN CLASS=coef id=c1 >?</SPAN><SPAN CLASS=fita >x</SPAN>
<SPAN> + </SPAN>
<SPAN CLASS=coef id=c2 >?</SPAN><SPAN CLASS=fita >y</SPAN>
<SPAN> = </SPAN>
<SPAN CLASS=coef id=c0 >?</SPAN><BR>

<SPAN CLASS=coef id=c1 >?</SPAN><SPAN CLASS=fita >x</SPAN>
<SPAN> + </SPAN>
<SPAN CLASS=coef id=c2 >?</SPAN><SPAN CLASS=fita >y</SPAN>
<SPAN> = </SPAN>
<SPAN CLASS=coef id=c0 >?</SPAN><BR>


<SPAN CLASS=wbtn id=Btn1 >xとyを求める</SPAN>
<SPAN>  </SPAN>
<SPAN CLASS=wbtn id=Btn2 >数値のクリア</SPAN><BR>
<SPAN id=Mes ></SPAN>

</BODY>


<SCRIPT language="VBScript">
Option Explicit

Dim target


Call ResizeTo(400, 280)

Document.Title = "連立二元一次方程式"


Sub Document_Onmouseover

    Set target = Window.event.srcElement

    If target.classname = "coef" Then

       If target.style.color = "" Then

          target.style.color = "red"

       End If

    End If

End Sub


Sub Document_Onmouseout

    Set target = Window.event.srcElement

    If target.classname = "coef" Then

       If target.style.color = "red" Then

          target.style.color = ""

       End If

    End If

End Sub


Sub Document_OnkeyPress
    Dim tk, kc


    If target.classname <> "coef" Then Exit Sub

    tk = Window.event.keyCode
    kc = Chr(tk)


    If tk = 8 Then   ' Backspace code?

       Mes.InnerText = KeyinBackspace()

    ElseIf kc = "-" Then

       Mes.InnerText = KeyinMinus()

    Else

        Mes.InnerText = KeyinNumber(kc)

    End If

End Sub


Private Function KeyinBackspace()
    Dim wv

    If target.InnerText = "?" Then

       KeyinBackspace = "まず数値を入れてください。"

    Else

       wv = Abs(Eval(target.InnerText))

       If wv < 10 Then

          target.InnerText = "?"

       Else       

          target.InnerText = Cstr(wv \ 10)

       End If

       KeyinBackspace = ""

    End If

End Function


Private Function KeyinMinus()
    Dim wv

    If target.InnerText = "?" Then

       KeyinMinus = "まず数値を入れてください。"

    Else

       wv = 0 - Eval(target.InnerText)

       If wv < 0 Then

          target.InnerText = "(" & wv & ")"

       Else

          target.InnerText = wv

       End If

       KeyinMinus = ""

    End If

End Function


Private Function KeyinNumber(kc)
    Dim idx, wv


    idx = InStr(1, "0123456789", kc)

    If idx > 0 Then

       If target.InnerText = "?" Then

          wv = 0

       Else

          wv = Eval(target.InnerText) * 10

       End If

       target.InnerText = Cstr(wv + idx - 1)

       KeyinNumber = ""

    Else

       KeyinNumber = "数値しか入りません。"

    End If

End Function


Sub Btn1_OnClick

    If QMarkcheck() Then

       Mes.InnerText = "数値に?があります。"

    Else

       Mes.InnerText = calcMatrix()

    End If

End Sub


Private Function QMarkcheck()

    If c1(0).InnerText = "?" Or c1(1).InnerText = "?" Or _
       c2(0).InnerText = "?" Or c2(1).InnerText = "?" Or _
       c0(0).InnerText = "?" Or c0(1).InnerText = "?" Then

       QMarkcheck = True

    Else

       QMarkcheck = False

    End If

End Function


Private Function calcMatrix()
    Dim rstr, delta, elm_x, elm_y, d1(1), d2(1), d0(1)

    d1(0) = Eval(c1(0).InnerText)
    d1(1) = Eval(c1(1).InnerText)
    d2(0) = Eval(c2(0).InnerText)
    d2(1) = Eval(c2(1).InnerText)
    d0(0) = Eval(c0(0).InnerText)
    d0(1) = Eval(c0(1).InnerText)

    delta = d1(0) * d2(1) - d2(0) * d1(1)
    elm_x = d2(1) * d0(0) - d2(0) * d0(1)
    elm_y = d1(0) * d0(1) - d1(1) * d0(0)

    If delta = 0 Then

       rstr = "連立方程式ではありません。"

    Else

       rstr = "x  = " & Reduce(elm_x, delta) & " , " &_
              "y  = " & Reduce(elm_y, delta)

    End If

    calcMatrix = rstr

End Function


Private Function Reduce(child, adult)
    Dim rstr, idx, clower, alower, prefix, surfix
    Dim chsg, adsg, chpv, adpv, rsig


    If child < 0 Then

       chsg = -1
       chpv = Abs(child)

    Else

       chsg = 1
       chpv = child

    End If


    If adult < 0 Then

       adsg = -1
       adpv = Abs(adult)

    Else

       adsg = 1
       adpv = adult

    End If


    If chpv = adpv Then

       Reduce = Cstr(child \ adult)

       Exit Function

    End If


    For idx = adpv to 2 step -1

        If adpv mod idx = 0 Then

           If chpv mod idx = 0 Then

              Exit For

           End If

        End If

    Next

    clower = chpv \ idx
    alower = adpv \ idx
    rsig = chsg * adsg

    If alower = 1 Then

       rstr = Cstr(clower \ alower * rsig)

    Else

        If rsig = -1 Then

           prefix = "-("
           surfix = ")"

        Else

           prefix = ""
           surfix = ""

        End If

        rstr = prefix & clower & " / " & alower & surfix

    End If

    Reduce = rstr

End Function


Sub Btn2_OnClick

    c1(0).InnerText = "?"
    c1(1).InnerText = "?"
    c2(0).InnerText = "?"
    c2(1).InnerText = "?"
    c0(0).InnerText = "?"
    c0(1).InnerText = "?"

    Mes.InnerText = ""

End Sub


</SCRIPT>


 このプログラムの操作方法は、次の通りです。マウスを操作して、画面上のカーソル矢印をウィンドウ上の”?”の位置に持っていきます。
?x+?y=?
のそれぞれの”?”の位置にカーソル矢印を持っていくと、”?”の色が黒から赤に変わります。その赤に変わった箇所に、0から9の数字をキーボードから打ちこみます。打ち込む値を間違えたならば、バックスペースキーを打って、数字を打ち直します。『数値のクリア』ボタンをマウスで押すと、打ちこんだ数値がすべて”?”に戻ります。”?”を全て数値に変えたならば、『xとyを求める』ボタンをマウスで押します。すると、ウィンドウの下の方にxとyの計算結果が整数または分数で現れます。例えば、
2x + 3y = 12
3x + 6y = 21
などと数値を打ちこんでから『xとyを求める』ボタンを押すと、
x = 3, y = 2
などと計算結果が出てきます。足し算と掛け算で検算してみると、コンピュータの出した答えが正しいことが簡単にわかります。
 あるいは、このプログラムを利用して、昔なつかしの『つるかめ算』をやってみましょう。「鶴と亀とが合わせて10匹いる。それらの足の数が総計32本である時、鶴と亀はそれぞれ何匹か。」という問題があったとします。この時、「2本足の鶴の数をx、4本足の亀の数をy」とすると、
1x + 1y = 10
2x + 4y = 32
という二つの方程式ができます。このプログラムに、画面上のウィンドウから6つの数値を打ちこみます。そして、『xとyを求める』ボタンを押すと、
x = 4, y = 6
が見事に求まります。
 実は、このプログラムの計算の仕組みは簡単です。『行列式』同士の割り算で、xとyの値がダイレクトに求まります。あとは、その割り算でできた分数の約分をできるならやって、その答えをウィンドウ画面上に出します。行列式は、足し算あるいは引き算と掛け算だけですから、基本的には四則演算の連続で、コンピュータは答えを求めることができます。それを人間がやる場合は、『つるかめ算』という算数テクニックを用いるか、あるいは、方程式の変形(加減法や代入法)によるxかyの消去法という数学テクニックを用いて、問題を解きます。以上のことから、コンピュータが問題を計算する仕組みは、人間がそれなりのテクニックを覚えて問題を解くやり方とは全く違います。だから、コンピュータと人間とでお互いのやり方を交換してやってみたら、お互いに時間と労力が余分にかかって、非能率になってしまうかもしれません。
 さて、次のような値を打ちこんで、コンピュータに計算させてみましょう。
2x + 3y = 12
4x + 6y = 24
 私たち人間は、何も気がつかないで、直観的にこの二つの方程式の答えが「x = 3, y = 2」であると出してしまいます。しかし、私の作ったコンピュータプログラムでは、途中で計算をやめて「連立方程式ではありません。」というメッセージを出します。xあるいはyを求める値は分数なのですが、その分母の側の行列式の計算が0(ゼロ)になるためです。割られる値(分子)がゼロなのは、いっこうにかまいません。けれども、割る値(分母)がゼロだと、「0で割ることはできない。」という数学のルールに違反します。上の二つの式を注意深く見ると、両辺にそれぞれ2を掛けているか否かの違いだけで、同じ方程式であることがわかります。とすると、この二元一次方程式は一つしかないのと同じになります。xとyの組み合わせの答えは、この方程式だけでは、分数の値も含めて一つに定まらないことがわかります。xとyのグラフで描くと、2本の直線がピタッと1本に重なる状態になります。
 また、次のような場合にも、「連立方程式ではありません。」というメッセージが出ます。
2x + 3y = 12
4x + 6y = 22
 今度の上下の方程式は、両辺にそれぞれ2を掛けているか否かで確かめてみると、同じものではなくて、それぞれ別の方程式のようです。しかし、例えば、上の方程式で「x = 3, y = 2」がなりたつものの、下の方程式では「x = 3, y = 2」がなりたちません。その代わりに「x = 1, y = 3」はなりたちます。が、このxとyの値の組み合わせは、上の方程式ではなりたちません。xとyのグラフで描くと、どこまで行っても平行で、交わることのない2本の直線が見られます。
 このように、連立二元一次方程式をコンピュータプログラムで計算させてみると、今まで意識することのなかった物事に気づくきっかけを与えてもらえます。言い換えると、それは、一種の『大人の数学』、すなわち、「大人になってわかる数学」のようなものです。若い頃に知識として獲得して理解していたことが貧弱であればあったほど、年老いてそれは目映(まばゆ)く感じられるものなのかもしれません。
 今回のプログラミングの計算で行列式を使ったことのメリットは、他にもありました。計算式のプログラミングが簡単であったため、そのコンピュータプログラムと値をやり取りするための仕組み、すなわち、マン・マシン・インターフェース(Man-Machine Interface: MMIと以下略します。)に注意と労力を向けることができました。HTMLやVBスクリプトでは、標準的なMMIが用意されています。しかし、あえてそれらを使わずに、自前のMMIをプログラミングしてみました。確かに、標準的なデータ入力フィールド(HTMLのINPUTタグやTEXTAREAタグ)などがありますが、画面上のウィンドウ内のレイアウトがスッキリせず、キーボードからデータを受け取った後の入力エラーチェックも面倒くさくなりそうでした。このコンピュータプログラムを少しでも操作性のある、便利に使えるものにするために、データを打ちこむ仕組みや計算結果を表す仕組みを工夫してみました。今回のプログラムの半分以上は、そのような操作性のよいMMIを実現するために組み立てられていると思います。
 しかしながら、このコンピュータプログラムは、さらにもっと操作性がよくなるような感じがしました。その辺のところを、バージョンアップして次回のブログ記事あたりで披露したいと考えています。