大人の塗り絵:塗り分けに五色必要な地図(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 10.4のRegionPlotのバグ


10.3.1ではできたことが,

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

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のバグ


Mathematica 10.1, 10.2, 10.3, 10.4.1, 11

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.}になることに,特に問題はないでしょう。

解析的に求めようとすると,うまく行きません。

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]になります。制約がTrueになっていますが,これはいけません。

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

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

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

MathematicaのIntegrateのバグ


Mathematica 10.1, 10.2, 10.3, 10.4.1, 11の積分(Integrate)には,仮定の利用に関して,9.0や10.0には無かったバグがあります。(製造元には報告済みです。)

例として,Abs[(x + 1) (x - a) (x - 1)]-1 <= x <= 1で積分することを考えます。

Absの中にパラメータがaがありますが,これは実数だと仮定します。Integrateには,そういう仮定を与えるための便利なオプションAssumptionsがあります。

Integrate[Abs[(x + 1) (x - a) (x - 1)], {x, -1, 1}, 
 Assumptions -> Element[a, Reals]]

これで,a <= -1なら-4a/3a >= 1なら4a/3,それ以外つまり-1 < a < 1なら(-a^4 + 6a^2 + 3)/6と,aの値で場合分けされた結果が得られます。すばらしい。

しかし,仮定がうまく取り入れられない,取り入れられないならまだしも,仮定を使ったせいで間違った答えが出てきてしまうことがあります。

Integrate[Abs[(x + 1) (x - 2 a + b) (x - 1)], {x, -1, 1}, 
 Assumptions -> And[-1 < a < 1, b == a]]

Mathematicaの一部のバージョンでは1/2という結果になりますが,これは間違いです。b == aという仮定を考慮すると被積分関数は最初の例と同じになるので,積分結果は(-a^4 + 6a^2 + 3)/6にならなければなりません。

どういうわけか,Integrateの中に直接数式を書かなければうまくいきます。

f = Abs[(x + 1) (x - a) (x - 1)];
Integrate[f, {x, -1, 1}, 
 Assumptions -> And[-1 < a < 1, b == a]]

原因はよくわかりませんが,Assumptionsは怖くて使えません。

この積分は,Mathematica 9.0(Windows)や10.0(Raspberry Pi)では正しく行えただけに,10.1でできなくなって残念です。機能追加と品質保持の優先順位が間違っている気がします。

Mathematica の新バージョンには,常に多くの新しい機能が含まれている.しかし当初からの周到なデザインにより,すべてのバージョン間でほぼ完全な互換性が保たれている.その結果,例えば1988年のバージョン1用に書かれたほとんどすべてのプログラムは,Mathematica バージョン7でもそのまま変更なしで走り,かつ実行速度も大いに向上している.(Mathematica バージョン1以降の非互換変更

この理想を,バージョン8以降でも大切にしてほしいものです。