「大学への数学」2017年6月号掲載の拙稿「機械まかせの数学 Mathematicaで解く東大入試数学」について


B06XWF34YQ月刊誌「大学への数学」2017年6月号で,「機械まかせの数学」という記事を書きました。内容は副題「Mathematicaで解く東大入試数学」のとおりです。

高校生向けの雑誌ですが,大学生,というか,「コンピュータと数学」ということに興味を持てるすべての人が想定読者です。高校数学の知識を前提にしていますが,大学入試問題を解く数学力は不要です。「Mathematicaでしょ,知ってる」という方も,Ver. 10以降のMathematicaを知らないなら,ちょっと驚くかもしれません。

膨大なネタを4ページに収めました。行間をすべて説明するのは大変なので,ここでは一つだけ。

「プログラミング入門=アプリ制作」や「プログラミング入門=ロボット制御」という風潮がありますが,この記事のように,数学を題材にしてプログラミングを学ぶという話は,もっとあっていいと思います。その際,題材とする数学は,高校レベルがいいでしょう。多くの方が基本的知識を持っていますし,問題の難しさも比較的判断しやすいからです(受験勉強のおかげ?)。大学入試問題を使うと,解けても解けなくてもそれなりの驚きがあります。

というわけで,高校生がメインターゲットの雑誌ですが,この記事は高校生以外にもお勧めです。

高3の一年間,この雑誌の学力コンテストで名前を載せ続けたのですが,著者として名前が載ることになるとは思いませんでした。いわゆる,「当時の自分に読ませたい記事」のつもりです。息子に読ませたいかというとちょっと微妙で,ちょうど1歳になる息子が読めるようになる2020年頃には,状況がまったく変わっているかもしれません。

記事中のコードはWolfram Cloudにまとめてあります。Mathematicaは高価なソフトウェアだと思っている人が多いようですが,基本機能はクラウド上で無料で使えます(こちら)。「別の言語でやってみた」という反応も歓迎です。

電子版はないので,お早めにどうぞ。

見本

Taro Yabukiさん(@taroyabuki)がシェアした投稿 –

大人の塗り絵:塗り分けに五色必要な地図(1975年のエイプリルフール)


4102184619四色あれば,地図上の隣り合う領域の色が同じにならないように塗り分けられるという「四色定理」は,1800年代後半に予想され,1976年にコンピュータを使って「証明」された。

定理が「証明」される前の1975年に,マーチン・ガードナーが塗り分けに五色必要だとして発表した次の絵が話題になったという。(参考:Martin Gardner's April Fool's Map

これはエイプリルフールのネタだったのだが,四色で塗り分けたという手紙が数百通届いたらしい。(ロビン・ウィルソン『四色問題』(新潮社, 2013)p.38)

この大人の塗り絵をやってみたい。

0387753664Mathematica in Action で,塗り分ける方法が紹介されているのだが,http://extras.springer.com/からダウンロードできるコードは,最近のMathematicaでは動かない。(Mathematicaの言語仕様は後方互換性を保持しながら進化しているのだが,外部パッケージが本体に取り込まれた場合は,大抵うまくいかない。)

そこで,簡易版を作る。領域の境界線が垂直または水平の2pxの黒い実線の場合にのみ対応するという意味で「簡易」である。

Importで画像を読み込み,MorphologicalComponentsで領域に分割する(Colorize[matrix]で描画)。

四色で塗り分ける。(参考:ヨーロッパの地図の4色を求める

色を1組の真偽値で表し,色が同じでないという条件を連言標準形で記述することで,高速化している。

細かい注意:上の結果は周りが海に囲まれていても大丈夫なように,条件を追加して求めたもので,このコードの結果とはちょっと違うものになっている。

最後の描画はColorize[matrix, ColorRules -> cTable]でもいいのだが,この関数にはバグがあり,Mathematica 10.4.1では正しく動作しない。(製造元には報告済み。Ver.11で修正された。

MathematicaのRegionPlotのバグ


10.3.1ではできたことが,

10.4でできなくなってしまいました(11.2もダメ)。(報告済み)

Mathematicaのサジェスチョンバーはオフにすべき(10.4)(10.4.1で修正)


10.4.1で直ったようです。

Mathematica 9で導入されたサジェスチョンバーのせいで計算結果がおかしくなることがあるようです。テクニカルサポートにバグを報告したら,その回答として教えてもらいました。

例1:以下のコードを1行ずつ実行するとMathematicaが落ちます。

m = SparseArray[{{0, 1, 0}, {1, 0, 1}, {0, 0, 0}}];

n = Map[With[{s = Total[#]}, If[s == 0, #, #/s]] &, Normal[m]];

n.n

例2:以下のコードを1行ずつ実行するとコンテキストが勝手に変わってしまいます。

Context[]

f = Solve[{2 x + y == p, x - 2 y == q}, {x, y}][[1]];

x + y ≤ 4 /. f

Context[]

せっかくフロントエンドとカーネルを分けているのにどうしてこんなことになるのか不思議ですが,文句を言っても計算結果は変わらないので,以下の資料に従って,サジェスチョンバーはオフにしておきましょう。

入力予測インターフェースの機能をオフにする方法

MathematicaのMaxValueとMinValueのバグ(11.2で解決)


11.2で解決

Mathematica 10.1, 10.2, 10.3, 10.4.1, 11.1.1

Mathematicaの最大化MaxValueと最小化MinValueには,簡約のためのSimplifyの中では使えないというバグがあります(製造元には報告済みです)。

例として,0 <= t <= 1, 0 <= p <= 2 Pi, 0 <= q <= 2 Piという制約のもとで,f = Abs[t Sin[p] Sin[q]]という関数の最大値と最小値を求めます。

f = Abs[t Sin[p] Sin[q]];
cond = And[0 <= t <= 1, 0 <= p <= 2 Pi, 0 <= q <= 2 Pi];

当たりを付けるために,まずは数値的に求めます。

{NMaxValue[{f, cond}, {t, p, q}], NMinValue[{f, cond}, {t, p, q}]}

結果が{1., 0.}になることに,特に問題はないでしょう。

解析的に求めようとすると,うまく行きません。(11.2ではうまく行きます。)

MaxValue[{f, cond}, {t, p, q}]
(*結果は割愛。入力がそのまま返される*)

こういう関数の最大・最小は,そのままではうまくいかないとしたものです。残念ですが,これはしょうがない。

しかし,Simplifyの中で使うと計算が進むことがあります。制約条件を仮定して結果を整理することを試みます。

Simplify[MaxValue[{f, cond}, {t, p, q}], cond]

得られる結果は「∞」,もちろん間違いです。MinValueの場合も同様で,「-∞」という間違った結果が得られます。

Simplifyの仮定(外側のcond)が,MaxValueの制約(内側のcond)を簡約しているのが一因だと思います。そういうことがあるのは,次の例でわかります。

Simplify[MaxValue[{1/x^2, 0 < x}, x, Integers], 0 < x]

結果はMaxValue[{x^(-2), True}, x, Integers]になります(11.2では正しい結果「1」が得られます)。制約がTrueになっていますが,これはいけません。

Tweet-a-Programではちょっと違うことが起きているみたいです(こういうのは初めて見ました)。

他に原因があるかどうかはよくわかりません。

MaximizeMinimaizeでは,この問題は発生しません。一般に,MaximizeMinimizeMaxValueMinValueより遅いということになっているのですが,速さよりは正確さが大事なので,こちらを使った方がいいのかもしれません。