Jekyll2018-03-27T10:17:31+00:00https://masahirodll.com/Masahiro Hiranointelligence aronudMasahiro Hiranomasahiro.dll_at_gmail.comhttps://masahirodll.comDeep learning on Ubuntu 16.04 with Titan X Pascal (Part 2)2017-02-20T16:56:15+00:002017-02-20T16:56:15+00:00https://masahirodll.com/deeplearning/deep-learning-on-ubuntu-16-04-with-titan-x-pascal-part-2<p>「コンシューマ向け最強のデュープラーニング用マシンが欲しいんや!」</p>
<p><a href="http://masahirodll.com/misc/?p=464" target="_blank">Deep learning on Ubuntu 16.04 with Titan X Pascal (Part 1)</a>のつづきです.</p>
<p>GPUが搭載されているUbuntu 16.04がインストールされている計算機にNVIDIA ドライバがインストールされていれば,ここから始めてもOKです.</p>
<p>Dockerのインストールから,JupyterでTensorflowを走らせるところまでを紹介します.</p>
<h2 id="1-docker-のインストール"><span style="font-family: Dosis, sans-serif; font-size: 30px; letter-spacing: -0.4px;">1. Docker のインストール</span></h2>
<p><a href="https://docs.docker.com/engine/installation/linux/ubuntu/" target="_blank">公式ドキュメント</a> が非常に親切にまとめられていて,この通りやるとまずつまずくことはないと思います.</p>
<p>やることはすぐ終わるのですが,少し手順が複雑なので公式ドキュメントを参照してください.上記のインストールが終わったら,Dockerを使いやすくするため,<a href="https://docs.docker.com/engine/installation/linux/linux-postinstall/" target="_blank">LInuxインストール後のステップ</a> も行ってください.(この作業をすると,dockerのコマンドを叩く時に毎回sudoする必要が無くなり,起動時に自動的にdockerが走るように設定できます.)</p>
<h2 id="2-nvidia-dockerのインストール">2. NVIDIA-Dockerのインストール</h2>
<p>このままだとdockerからGPUを活用することができませんので,DockerのプラグインであるNVIDIA-dockerを入れます.(2017/2/18時点でのコマンドですので,バージョンアップ等によって異なる場合があります.<a href="https://github.com/NVIDIA/nvidia-docker#ubuntu-distributions" target="_blank">github:NVIDIA/nvidia-docker</a>を参考にしてください.)</p>
<h3 id="2-1-パッケージのダウンロード">2. 1 パッケージのダウンロード</h3>
<p>一度 docker daemonを再起動しておきましょう.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo service docker restart
</code></pre></div></div>
<p>続いてパッケージをダウンロードします.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>wget -P /tmp https://github.com/NVIDIA/nvidia-docker/releases/download/v1.0.0/nvidia-docker_1.0.0-1_amd64.deb
</code></pre></div></div>
<p>セキュリティの設定によっては,証明書関連でエラーが出ることがありますので,その際はかわりに以下を実行してください.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>wget --no-check-certificate -P /tmp https://github.com/NVIDIA/nvidia-docker/releases/download/v1.0.0/nvidia-docker_1.0.0-1_amd64.deb
</code></pre></div></div>
<p>(なぜかwgetの際にホスト名が解決できないというエラーが出たのですが,上のコマンドを何度も叩いているうちにダウンロードできました.奥が深いです.)</p>
<h3 id="2-2-パッケージのインストール">2. 2 パッケージのインストール</h3>
<p>パッケージをインストールします.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo dpkg -i /tmp/nvidia-docker*.deb && rm /tmp/nvidia-docker*.deb
</code></pre></div></div>
<h3 id="2-3-動作確認">2. 3 動作確認</h3>
<p>NVIDIA ドライバをインストールした時と同様に,nvidia-smiで動作確認してみましょう.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nvidia-docker run --rm nvidia/cuda nvidia-smi
</code></pre></div></div>
<p>実行した結果,以下のようにプロファイルが表示されればインストール成功です.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>+-----------------------------------------------------------------------------+
| NVIDIA-SMI 375.39 Driver Version: 375.39 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 TITAN X (Pascal) Off | 0000:02:00.0 On | N/A |
| 23% 28C P8 9W / 250W | 63MiB / 12187MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
+-----------------------------------------------------------------------------+
</code></pre></div></div>
<h2 id="3-tensorflowを動かしてみる">3. Tensorflowを動かしてみる.</h2>
<p>ここまででDocker上でGPUを使うことができるようになりました.</p>
<p>後は好きなようにDockerイメージを作ってrunさせるだけです.</p>
<p>ここでは,TensorFlowの開発チームが提供している出来合いのイメージがありますので,それを使ってTensorFlowを動かしてみます.</p>
<h3 id="3-1-tensorflowイメージの実行">3. 1 TensorFlowイメージの実行</h3>
<p>Docker Hub上のTensorFlowのリポジトリからビルド済みのイメージを使って起動してみます.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nvidia-docker run -it -p 8888:8888 gcr.io/tensorflow/tensorflow:latest-gpu
</code></pre></div></div>
<p>すると,</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>masa@hinton:~$ nvidia-docker run -it -p 8888:8888 gcr.io/tensorflow/tensorflow:latest-gpu
[I 01:46:58.799 NotebookApp] Writing notebook server cookie secret to /root/.local/share/jupyter/runtime/notebook_cookie_secret
[W 01:46:58.815 NotebookApp] WARNING: The notebook server is listening on all IP addresses and not using encryption. This is not recommended.
[I 01:46:58.819 NotebookApp] Serving notebooks from local directory: /notebooks
[I 01:46:58.819 NotebookApp] 0 active kernels
[I 01:46:58.819 NotebookApp] The Jupyter Notebook is running at: http://[all ip addresses on your system]:8888/?token=e1da5e296207ae2f4f1e6787e331174e375b4c674f7f6df7
[I 01:46:58.819 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
[C 01:46:58.819 NotebookApp]
Copy/paste this URL into your browser when you connect for the first time,
to login with a token:
http://localhost:8888/?token=e1da5e296207ae2f4f1e6787e331174e375b4c674f7f6df7
</code></pre></div></div>
<p>となり,jupyter server が起動したことが確認できます.</p>
<p>jupyterの初回起動時には認証が要求されるようなので,ここで出て来たURLをクリックするかブラウザにコピペすると,jupyter notebookが起動できます.</p>
<p>あらかじめリポジトリで用意してくれているtensorflowのチュートリアルがありますので,それをいじってみてtensorflowがきちんと動いていることを確認して見るとよいでしょう.</p>
<h2 id="4-おわりに">4. おわりに</h2>
<p>ここまでで,Ubuntu上にインストールしたdockerからtensorflowのイメージをrunさせる方法までを紹介しました.</p>
<p>ですが,実際に運用するとなると計算機サーバーとして使いたくなることがあると思います.例えば他のPCからsshで接続したいとか,手元のブラウザからjupyter使いたいとかです.</p>
<p>一応自分が使っている環境ではサーバーとして運用していますので,その方法をDeep learning on Ubuntu 16.04 with Titan X Pascal (Part 3) で紹介します.</p>Masahiro Hiranomasahiro.dll_at_gmail.comhttps://masahirodll.com「コンシューマ向け最強のデュープラーニング用マシンが欲しいんや!」Deep learning on Ubuntu 16.04 with Titan X Pascal (Part 1)2017-02-19T12:32:42+00:002017-02-19T12:32:42+00:00https://masahirodll.com/deeplearning/deep-learning-on-ubuntu-16-04-with-titan-x-pascal-part-1<p>「コンシューマ向け最強のデュープラーニング用マシンが欲しいんや!」</p>
<p>Ubuntu 16.04 + Titan X (Pascal)でやっている記事が意外と少ないみたいなので備忘録がてら書き残します.</p>
<p>マシンの調達等を除けば,半日〜1日ぐらいでセットアップできると思います.</p>
<p>このPart 1では,新しく調達したPCにNVIDIAドライバをインストールするところまで紹介します.</p>
<p>Dockerのインストールからは,<a href="http://masahirodll.com/misc/?p=513">Deep learning on Ubuntu 16.04 with Titan X Pascal (Part 2)</a>で.</p>
<h2 id="0-はじめに">0. はじめに</h2>
<p>デュープラーニングで使われているライブラリ群は今まさに急激な進歩を遂げています.これゆえ,頻繁に更新が行われてぐんぐん性能が向上していったり便利になったりするのは素晴らしいことなのですが,ライブラリ同士の相性の問題で動かなくなったりすることもしばしばあります.また,複数人で同じマシンを使う場合や,ちょっとライブラリを試してみたいといった時に,環境がごちゃごちゃになって収拾がつかなくなってしまう恐れもあります.</p>
<p>このため,近年急速に注目を集めているDocker上で簡単に深層学習環境が構築できるシステムを作ってみました.計算力が必要な時は,AWSやAzureなどのクラウドプラットフォームから用意しておいたDockerのイメージをダウンロードすればすぐに同じ手元と同じ環境をクラウド上に再現することができますし,万が一計算機がぶっ壊れた時も環境構築にかかる手間が大幅に削減できます.</p>
<p>Docker上でもGPU使えるの?と思う方もいるかもしれませんが,2016年にNVIDIA謹製のDockerのプラグインが登場し,これを使って簡単にGPU対応のコンテナを作ることができるようになりました.</p>
<h2 id="1-用意するハードウェア">1. 用意するハードウェア</h2>
<h3 id="1-1-pc">1. 1 PC</h3>
<p>深層学習用マシンでは基本的にGPUを24時間酷使するので,信頼性の高い電源が使われているゲーミングマシンをベースに組むとよいでしょう.今回は定評のある<a href="http://www.dell.com/jp/p/alienware-area51-r2/pd?oc=caaaw5114jp&model_id=alienware-area51-r2" target="_blank">DellのAlienware Area-51 Surpremacy</a>を使いましたが,最近のNVIDIA GPUが乗るPCであれば大丈夫です.</p>
<p>ちなみに,Alienwareでは入力に使うUSBデバイス(キーボード)が接続されていないと起動しないというよくわからない仕様になっていますので,キーボードを接続したまま運用したほうがいいです.じゃないとsshとかで気持ちよくsudo rebootとかやると,そのまま帰ってこなくなってしまいます.</p>
<h3 id="1-2-gpu">1. 2 GPU</h3>
<p>深層学習を気持ちよく回すためには性能の良いGPUが必須です.AlienwareにもNVIDIA GTX1080が乗っているのですが,計算時間にダイレクトに影響するので,Pascalアーキテクチャ初のデスクトップ向けGPUであるNVIDIA Titan X (Pascal)を使います.押しも押されぬ現行最高スペックのシングルGPUで,GTX1080に比べてメモリが8GBから12GBになったことで学習できるニューラルネットの規模が大幅に向上しています.日本国内では<a href="https://www.amazon.co.jp/NVIDIA-Pascal-GPUアーキテクチャー採用グラフィックカード-TITAN-X/dp/B01M0C8QXE" target="_blank">amazon</a>のみが販売しています.お値段20万ほどです.</p>
<h3 id="1-3-usbメモリ">1. 3 USBメモリ</h3>
<p>Ubuntuをインストールするライブメディアに使用します.Ubuntuを丸々コピーするので,4GB以上あるものが望ましいです.</p>
<h2 id="2-ライブusbメモリの準備">2. ライブUSBメモリの準備</h2>
<p>Ubuntuをクリーンインストールするために,USBでUbuntuのインストールメディアを用意します.</p>
<p>深層学習用の計算機はLinuxがインストールされていることがほとんどです.おそらくTensorflowが基本的にはLinuxにのみ対応していることや,各種機械学習系ライブラリがpythonで提供されているためだと思います.一応Tensorflow0.10からWindowsにも対応しているらしいですが,tensorflowのgithubをみる限り,Windows(GPU)環境でテストされていないみたいです.また,Linuxのなかでもインターネット上のリソースも豊富であることや扱いやすいことから,Ubuntuが選ばれています.</p>
<p>Ubuntuのクリーンインストールは,Ubuntuのイメージを焼き付けたUSBメモリから起動することで行いますので,あらかじめUSBメモリにUbuntu 16.04.01 LTS (64bit) のイメージを焼きつけます.</p>
<p>(注意:以下の作業はWindowsで行うことを想定していますが,他のOSでも同様にライブメディアを作成することができます.)</p>
<p>(この部分は,<a href="http://kledgeb.blogspot.jp/2016/04/unetbootin-5-windowsunetbootinubuntuusb.html" target="_blank">kledgeb: UNetbootin その5 – WindowsでUNetbootinを利用するには・UbuntuのライブUSBメモリーを作成する</a>の記事でも丁寧に解説されています.)</p>
<h3 id="2-1-usbメモリのフォーマット">2. 1 USBメモリのフォーマット</h3>
<p>ライブメディアを作るために,まずはUSBメモリをフォーマットします.フォーマットすると中身が全て書き換えられますので,必ず中のファイルを退避させておいてください.</p>
<p>エクスプローラー上でUSBメモリドライブを右クリックし,「フォーマット」を選択します.</p>
<p>ファイルシステムを「FAT32」に設定した上で,開始ボタンを押すとフォーマット完了です.</p>
<h3 id="2-2-ubuntuのイメージのダウンロード">2. 2 Ubuntuのイメージのダウンロード</h3>
<p>Ubuntuの公式サイト(https://www.ubuntu.com/download/desktop)から Ubuntu 16.04.1 LTSのイメージ(ubuntu-16.04.1-desktop-amd64.iso)をダウンロードします.</p>
<h3 id="2-3-ubuntuイメージをusbメモリに焼き付ける">2. 3 UbuntuイメージをUSBメモリに焼き付ける</h3>
<p>ダウンロードしたイメージをUSBメモリに焼き付けるために,UNetbootinというソフトをインストールします.公式サイト(https://unetbootin.github.io/)からWindows版をダウンロードします.</p>
<p>UNetbootinを起動したら,「ディスクイメージ」を選択し,先ほどダウンロードしておいた.isoファイルを選択してください.</p>
<p>一番下のタイプには「USBドライブ」,ドライブにはUSBメモリのドライブ文字を選択してOKをおすと,あとは自動でライブUSBメモリができます.(少し時間がかかります.)</p>
<p><span style="color: #ff6600; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px;">(注意:ウイルスバスターなどのウイルス対策ソフトを使っている場合は,この工程で失敗することがあります.一時的にオフにして作業をしてください.)</span></p>
<h2 id="3-gpuの換装">3. GPUの換装</h2>
<p>グラフィックボードを換装(あるいは増設)します.必ず電源ケーブルを引き抜いた状態でおこなってください.</p>
<p>PCI Express x16のスロットが2つある場合は,上にある方を優先して使います.</p>
<p>また,(おそらく)NVIDIAのグラフィックボードのドライバは共存できませんので,異なるバージョンのNVIDIAグラフィックボードは共存させないほうが良いと思います.(よく調べていませんので,work aroundがあるかもしれません.)</p>
<h2 id="4-ubuntuのインストール">4. Ubuntuのインストール</h2>
<p>まずはUbuntuをインストールしましょう.「Ubuntu クリーンインストール」等の検索ワードでたくさんの親切な記事がヒットしますので,ここでは簡潔に説明します.</p>
<h3 id="4-1-ブートドライブの順番を変更">4. 1 ブートドライブの順番を変更</h3>
<p>事前に作成しておいたライブUSBメモリをPCに挿した状態で,F2を押しながら起動し,UEFIのセッティング画面に入ります.(UEFIによって異なるボタンが割り当てられていることがあります.)</p>
<p>ブートドライブの順番を,USBドライブを一番上に移動し,変更を保存後再起動します.</p>
<h3 id="4-2-ubuntuのインストール">4. 2 Ubuntuのインストール</h3>
<p>うまくいって入れば,再起動後にUbuntuのブートローダ(GRUB)が起動します.</p>
<p>Try ubuntu without installを選択し,後は順序通り設定を進めてインストールします.</p>
<p>クリーンインストールの場合,特に詰まる部分もないと思います.</p>
<p> </p>
<h2 id="5-nvidiaドライバのインストール">5. NVIDIAドライバのインストール</h2>
<p><span style="color: #ff6600;">ここから先は構築するマシンがインターネットに接続されていることが必要です.</span></p>
<p>「4. Ubuntuのインストール」まででUbuntuがインストールされた状態になりますが,このままではグラフィックボードを活用することができません.</p>
<p>デフォルトの状態だと,NVIDIAの純正ドライバをリバースエンジニアリングして作成されたnouveauというドライバが動いています.通常の使用だとこれでも問題ないのですが,今回はCUDAを使うためにNVIDIAのプロプライエタリなドライバをインストールします.</p>
<p>ただ問題なのが,Ubuntu 16 ではUEFIでセキュアブートが有効になっているとカーネルレベルでも署名がないドライバのロードができないようになっているため,インストールに失敗することがあります.そこで,カーネルレベルで署名なしのドライバがインストールできるようにするか,セキュアブートそのものをオフにしてしまうことによってインストールできるようにします.</p>
<p>ここでは,本当はセキュリティ的に問題があるのですが,セキュアブートをオフにすることにします.前者の方法は,Qiitaで記事をまとめている方(<a href="http://qiita.com/chiral/items/3105c52fc9fdb528dbd7" target="_blank">ubuntu16でNVIDIAのドライバインストールでハマった時</a>)がいらっしゃるのでそちらを参考にしてください.</p>
<p>ちなみに,nouveauをオフにしないとnvidiaドライバのインストールに失敗するという報告(例えば,<a href="http://qiita.com/ttomoaki/items/5a180f61647750eb8d70" target="_blank">Qiitaの記事</a>)がありますが,自分がやった時は明示的にオフにしなくても大丈夫でした.<a href="http://qiita.com/chiral/items/3105c52fc9fdb528dbd7">上のリンク</a>の方も,nouveauをオフにしなくてもうまくいったと報告しています.</p>
<p>(別件でUbuntu 14でも同様にnvidiaのドライバをインストールしたのですが,こちらもUEFIでセキュアブートをオフにしないとX windowが起動しませんでした.)</p>
<h3 id="5-1-uefiのセキュアブートをオフにする">5. 1 UEFIのセキュアブートをオフにする</h3>
<p>上述した通り,セキュリティレベルを下げてドライバがインストール可能な状態にします.</p>
<p>[Secure Boot]のようなメニューがありますので,[Enabled]から[Disabled]に変更します.</p>
<p>必ず変更を保存してから,再起動します.</p>
<h3 id="5-2-ドライバのインストール">5. 2 ドライバのインストール</h3>
<p>X windowが起動したままだとNVIDIAドライバのインストールできないので,</p>
<p>ログイン画面でalt+ctrl+F1を押してコンソール画面(tty1)に切り替えます.</p>
<p>まず最初に,グラフィックドライバを提供しているubuntuリポジトリを登録します.</p>
<pre>$ sudo add-apt-repository ppa:graphics-drivers/ppa
$ sudo apt-get update</pre>
<p>http://www.nvidia.co.jp/Download/index.aspx?lang=jp で自分の環境に対応するNVIDIAドライバのバージョンを確認します.(インストール時点のバージョンは 375.39 )</p>
<p>apt-cacheで検索するとより最新のドライバがヒットすることもありますが,ここでは確実に行くために上のURLで出てきたバージョンのドライバを使います.</p>
<pre>$ sudo apt-get install nvidia-375</pre>
<p>再起動します.</p>
<pre>$ sudo reboot</pre>
<p>ドライバが正しくインストールされたことを以下のコマンドで確認します.</p>
<pre>$ nvidia-smi</pre>
<p>すると,下記のようにドライバがインストールされていることが確認できます.</p>
<pre>+-----------------------------------------------------------------------------+
| NVIDIA-SMI 375.39 Driver Version: 375.39 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 TITAN X (Pascal) Off | 0000:02:00.0 On | N/A |
| 23% 30C P8 8W / 250W | 63MiB / 12186MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| 0 4733 G /usr/lib/xorg/Xorg 60MiB |
+-----------------------------------------------------------------------------+</pre>
<p>以上で,NVIDIA ドライバのインストールが完了です.</p>
<p>長くなったので,Dockerのインストールからは次のポスト <a href="http://masahirodll.com/misc/?p=513">Deep learning on Ubuntu 16.04 with Titan X Pascal (Part 2)</a> で紹介します.</p>Masahiro Hiranomasahiro.dll_at_gmail.comhttps://masahirodll.com「コンシューマ向け最強のデュープラーニング用マシンが欲しいんや!」ブラウザで簡単な2D物理シミュレーション2015-06-03T23:32:28+00:002015-06-03T23:32:28+00:00https://masahirodll.com/physicsengine/simple-2d-physics-simulation<p>Gigazineにも紹介されていたmatter-jsというライブラリを用いると,
ブラウザ上で簡単な2Dシミュレーションができる.</p>
<p><a href="http://brm.io/matter-js/" target="_blank">http://brm.io/matter-js/</a></p>
<p><a href="http://gigazine.net/news/20150122-matter-js/" target="_blank">http://gigazine.net/news/20150122-matter-js/</a></p>
<p>matter.jsを使った物理シミュレーションの一番シンプルなやり方</p>
<ol>
<li>index.htmlを作成.</li>
</ol>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"><!DOCTYPE html></span>
<span class="nt"><html</span> <span class="na">lang=</span><span class="s">"ja"</span><span class="nt">></span>
<span class="nt"><head></span>
<span class="nt"><meta</span> <span class="na">charset=</span><span class="s">"utf-8"</span><span class="nt">></span>
<span class="nt"><script </span><span class="na">src=</span><span class="s">"Matterjs/matter.js"</span><span class="nt">></script></span>
<span class="nt"></head></span>
<span class="nt"><body></span>
<span class="nt"><script </span><span class="na">type=</span><span class="s">"text/javascript"</span><span class="nt">></span>
<span class="c1">// Matter.js module aliases</span>
<span class="kd">var</span> <span class="nx">Engine</span> <span class="o">=</span> <span class="nx">Matter</span><span class="p">.</span><span class="nx">Engine</span><span class="p">,</span>
<span class="nx">World</span> <span class="o">=</span> <span class="nx">Matter</span><span class="p">.</span><span class="nx">World</span><span class="p">,</span>
<span class="nx">Bodies</span> <span class="o">=</span> <span class="nx">Matter</span><span class="p">.</span><span class="nx">Bodies</span><span class="p">;</span>
<span class="c1">// create a Matter.js engine</span>
<span class="kd">var</span> <span class="nx">engine</span> <span class="o">=</span> <span class="nx">Engine</span><span class="p">.</span><span class="nx">create</span><span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">);</span>
<span class="c1">// create two boxes and a ground</span>
<span class="kd">var</span> <span class="nx">boxA</span> <span class="o">=</span> <span class="nx">Bodies</span><span class="p">.</span><span class="nx">rectangle</span><span class="p">(</span><span class="mi">400</span><span class="p">,</span> <span class="mi">200</span><span class="p">,</span> <span class="mi">80</span><span class="p">,</span> <span class="mi">80</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">boxB</span> <span class="o">=</span> <span class="nx">Bodies</span><span class="p">.</span><span class="nx">rectangle</span><span class="p">(</span><span class="mi">450</span><span class="p">,</span> <span class="mi">50</span><span class="p">,</span> <span class="mi">80</span><span class="p">,</span> <span class="mi">80</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">ground</span> <span class="o">=</span> <span class="nx">Bodies</span><span class="p">.</span><span class="nx">rectangle</span><span class="p">(</span><span class="mi">400</span><span class="p">,</span> <span class="mi">610</span><span class="p">,</span> <span class="mi">810</span><span class="p">,</span> <span class="mi">60</span><span class="p">,</span> <span class="p">{</span> <span class="na">isStatic</span><span class="p">:</span> <span class="kc">true</span> <span class="p">});</span>
<span class="c1">// add all of the bodies to the world</span>
<span class="nx">World</span><span class="p">.</span><span class="nx">add</span><span class="p">(</span><span class="nx">engine</span><span class="p">.</span><span class="nx">world</span><span class="p">,</span> <span class="p">[</span><span class="nx">boxA</span><span class="p">,</span> <span class="nx">boxB</span><span class="p">,</span> <span class="nx">ground</span><span class="p">]);</span>
<span class="c1">// run the engine</span>
<span class="nx">Engine</span><span class="p">.</span><span class="nx">run</span><span class="p">(</span><span class="nx">engine</span><span class="p">);</span>
<span class="nt"></script></span>
<span class="nt"></body></span>
<span class="nt"></html></span>
</code></pre></div></div>
<ol start="2">
<li>index.htmlと同じフォルダに<a href="https://github.com/liabru/matter-js/blob/master/build/matter.js" target="_blank">matter.js</a>を配置する.</li>
<li>index.htmlをブラウザで開くと長方形が2つ落下するデモが見れる.</li>
</ol>Masahiro Hiranomasahiro.dll_at_gmail.comhttps://masahirodll.comGigazineにも紹介されていたmatter-jsというライブラリを用いると, ブラウザ上で簡単な2Dシミュレーションができる. http://brm.io/matter-js/ http://gigazine.net/news/20150122-matter-js/ matter.jsを使った物理シミュレーションの一番シンプルなやり方 index.htmlを作成. <!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <script src="Matterjs/matter.js"></script> </head> <body> <script type="text/javascript"> // Matter.js module aliases var Engine = Matter.Engine, World = Matter.World, Bodies = Matter.Bodies; // create a Matter.js engine var engine = Engine.create(document.body); // create two boxes and a ground var boxA = Bodies.rectangle(400, 200, 80, 80); var boxB = Bodies.rectangle(450, 50, 80, 80); var ground = Bodies.rectangle(400, 610, 810, 60, { isStatic: true }); // add all of the bodies to the world World.add(engine.world, [boxA, boxB, ground]); // run the engine Engine.run(engine); </script> </body> </html> index.htmlと同じフォルダにmatter.jsを配置する. index.htmlをブラウザで開くと長方形が2つ落下するデモが見れる.How to make a HTML5-based presentation2015-06-02T01:40:49+00:002015-06-02T01:40:49+00:00https://masahirodll.com/presentation/how-to-make-a-html5-based-presentation<p>HTML5ベースのプレゼンがはやってるみたいなので,どうやって実現しているか(とそのフレームワーク)を調査.</p>
<p>HTML5-based presentationならアニメーションをAdobe Edge Animateで簡単に作れる.(<a href="http://therichwebexperience.com/blog/terry_ryan/2012/10/add_edge_animate_compositions_to_reveal_js" target="_blank">http://therichwebexperience.com/blog/terry_ryan/2012/10/add_edge_animate_compositions_to_reveal_js</a></p>
<p>CSS3アニメーションの参考サイト</p>
<p>(<a href="http://webkikaku.co.jp/staff/htmlcss/css3animation/" target="_blank">http://webkikaku.co.jp/staff/htmlcss/css3animation/</a>)</p>
<p>Animate.css</p>
<p>(<a href="http://daneden.github.io/animate.css/" target="_blank">http://daneden.github.io/animate.css/</a>)</p>
<p>reveal.jsを使ったプレゼンの簡単なイントロ</p>
<p>(<a href="http://webbeginner.hatenablog.com/entry/2014/03/30/012720" target="_blank">http://webbeginner.hatenablog.com/entry/2014/03/30/012720</a>)</p>
<p>日本語フォントの設定例</p>
<p>(<a href="http://g-azami.tumblr.com/post/76447906591/a-2014-edition-japanese-css-font-family-set" target="_blank">http://g-azami.tumblr.com/post/76447906591/a-2014-edition-japanese-css-font-family-set</a>)</p>
<p>ちなみに,reveal.jsで日本語をメイリオ,英語をMyriad Proにしたいなら,使用しているテーマ(例えば,css/theme/black.css)でfont-familyを検索して,</p>
<p><code class="highlighter-rouge">font-family: 'Source Sans Pro', Helvetica, sans-serif;</code></p>
<p>のところを</p>
<p><code class="highlighter-rouge">font-family: Myriad Pro, Meiryo, Verdana, "游ゴシック", YuGothic, "Hiragino Kaku Gothic ProN", sans-serif;</code></p>
<p>に書き換えると良い.(2箇所)</p>Masahiro Hiranomasahiro.dll_at_gmail.comhttps://masahirodll.comHTML5ベースのプレゼンがはやってるみたいなので,どうやって実現しているか(とそのフレームワーク)を調査.Tutorial - 1D Curvature Flow2015-05-29T11:43:47+00:002015-05-29T11:43:47+00:00https://masahirodll.com/discretedifferentialgeometry/tutorial-1d-curvature-flow<p>Caltechで開講されていた”Discrete Differential Geometry”という講義の中で,Homeworkとして提示されていたものだが,curvature flow(曲率フロー)の良いチュートリアルでもあるので全訳する.</p>
<p>original URL: <a href="http://brickisland.net/cs177fa12/?p=320">http://brickisland.net/cs177fa12/?p=320</a></p>
<p>適宜理解が進むように内容をプラスしながら説明しているので,必ずしも原本通りではない上に,一部理解しきれずに訳している部分がある.また,<strong>Remarks</strong>はすべて,訳者によるものである.</p>
<h2 id="curvature-flow"><strong>Curvature Flow</strong></h2>
<p>今回のホームワークでは,曲率フロー(curvature flow)<script type="math/tex">^{*1}</script>について詳しく見ていこう.
実はPoisson方程式について学んでいる時に出てきた平均曲率フロー(mean curvature flow)も曲率フローの一種である.
ジオメトリ<script type="math/tex">^{*2}</script>の滑らかさを図る指標としてエネルギー<script type="math/tex">E</script>を定義し,各点おいて定義された最急降下方向を指すベクトル場に沿って<script type="math/tex">E</script>を減らせるというふうに考えることで曲率フローを考察しよう.
<script type="math/tex">E</script>をある種のポテンシャルであると考えるとイメージが掴みやすいだろう.
すなわち,たくさんのエネルギーを持った”しわしわな”曲面のエネルギーを減少させることにより,より滑らかな曲面を得るというものである.このような考え方は,「エネルギー分布」として捉えるとより鮮明になる.すなわち,エネルギーの高い部分はしわしわな曲面を表し,低い部分は滑らかな曲面を表す.下図は2次元の場合のエネルギー分布の例である.</p>
<p><img src="http://brickisland.net/cs177fa12/wp-content/uploads/2012/12/ddg_energy_landscape.svg" alt="http://brickisland.net/cs177fa12/wp-content/uploads/2012/12/ddg_energy_landscape.svg" /></p>
<p>ジオメトリを滑らかにするためには,より滑らかな形状を発見しながらこのエネルギー分布上で下に向かってスキーのように滑走していけばよい.言うなれば,焼きたてのパンの上に載せたひとかけのバターが溶けていく様子や,水滴が落ちるときに完全な球形になっていくことを想像するとわかりやすいだろう.</p>
<p>数式を使ってより具体的に見ていこう.<script type="math/tex">f</script>を多様体<script type="math/tex">M</script>(曲線や曲面)からユークリッド空間へのはめ込み(immersion)<script type="math/tex">^{*3}</script>であるとしよう.
<script type="math/tex">E</script>を<script type="math/tex">f</script>の実数値関数としよう.このとき,曲率フローは以下の偏微分方程式 \[ \dot{f} = \frac{\partial f}{\partial t} = - \nabla E(f) \] の解である.
ここで,<script type="math/tex">f_0</script>を初期解とする.この偏微分方程式は,曲面上のある点が微小時間に動く変位は,その点がエネルギーを最も効率よく小さくしようとした時に動く変位であると解釈できる.</p>
<p>曲面において,最もよく使われるのがDirichletエネルギー<script type="math/tex">^{*4}</script> \[ E_D (f) = \frac{1}{4} \int_M |\nabla f|^2 dA \] とWillmoreエネルギー \[ E_W (f) = \frac{1}{4} \int_M (\kappa_1 - \kappa_2)^2 dA = \int_M H^2 dA - \int_M K dA \] である.ここで,<script type="math/tex">\kappa_1, \kappa_2</script>はそれぞれ<script type="math/tex">f</script>によって定まる主曲率を表す.これら2つのエネルギーはともに曲面のシワシワ度合いを測るものであるのだが,一体これらの間にはどういった関係があるのだろうか.</p>
<blockquote>
<p>Exercise 4.1<br />
<script type="math/tex">M</script>を境界を持たない曲面であるとする.このとき,Willmoreエネルギーは \[ E_W = \int_M H^2 dA + \mbox{const.} \] とかけることを示せ.また,この定数は曲率フローを考える際にはあまり意味を持たないことを説明せよ.(ヒント:Gauss-Bonnetの定理によれば,閉曲面のガウス曲率の積分はいくつになっただろうか.また,平坦なエネルギー場に魅力はあるだろうか?)</p>
</blockquote>
<p>Willmoreエネルギーの定義は平均曲率の<script type="math/tex">L^2</script>ノルム(の2乗)を表している一方で,Dirichletエネルギーは勾配の<script type="math/tex">L^2</script>ノルム(の2乗)を表していると解釈できる.これらの量は見かけ上異なっているように見えるが,実はとても似通った性質を持った量なのだ.</p>
<blockquote>
<p>Exercise 4.2<br />
<script type="math/tex">M</script>を境界を持たない曲面であるとする.このとき,DirichletエネルギーとWillmoreエネルギーはそれぞれ,\[ E_D = \langle \Delta f, f \rangle + \mbox{const.} \] \[ E_W = \langle \Delta^2 f, f\rangle + \mbox{const.} \] とかけることを示せ.(ヒント:Greenの第一恒等式(Green’s first identity)と平均曲率ベクトルの定義を思い出そう.)</p>
</blockquote>
<p>これらの表式から,DirichletエネルギーとWillmoreエネルギーはともにとてもよい性質を持った<script type="math/tex">f</script>の2次式であることがわかるだろう.しかし,ここで注意しなければならないのは,Laplace-Beltrami作用素<script type="math/tex">\Delta</script>が<script type="math/tex">f</script>自身の関数であるので,これの勾配フローはむしろうんざりするような非線形式になる.後ほど,この非線形性を対処する方法について見ていこう.</p>
<hr />
<h3 id="remarks"><strong>Remarks</strong></h3>
<p><script type="math/tex">^{*1}</script> フロー: 多様体の言葉では,1径数変換群(1-parameter transformation group)と呼ばれるものである.
少し解説すると,コンパクトな多様体<script type="math/tex">M</script>においては,任意のベクトル場が完備であるので,<script type="math/tex">M</script>の任意の点<script type="math/tex">p</script>を初期値とする積分曲線<script type="math/tex">c(t,p)</script>が<script type="math/tex">t\ \in (-\infty, \infty)</script>で定義できる.
このことから,実数<script type="math/tex">t</script>を一つ固定した写像<script type="math/tex">\varphi\_t:M \to M</script>を考え,<script type="math/tex">M</script>の各点<script type="math/tex">p</script>に対して点<script type="math/tex">c(t,p)</script>を対応させる写像が群をなす(例えば,<script type="math/tex">\varphi_{t+s} = \varphi_t \circ \varphi_s</script>)とき, <script type="math/tex">\{\varphi_t\}_{t \in \mathbb{R}}</script>を<script type="math/tex">M</script>の1径数変換群(フロー)という.
このように,多様体<script type="math/tex">M</script>上の完備なベクトル場と1径数変換群が一対一に対応しており,ベクトル場が「流れ」のような速度ベクトル場の場合には,<script type="math/tex">\{\varphi_t\}_{t\in \mathbb{R}}</script>は「流れそのもの」を表すものであると解釈できる(松本,多様体の基礎,pp247に詳しい).
より簡単な解釈としては,形状を表現する写像<script type="math/tex">f</script>に時間の変数を付加して時変なものとした<script type="math/tex">f(t)</script>として考えても良いだろう.</p>
<p><script type="math/tex">^{*2}</script> ジオメトリ: 幾何学的に解析・操作する対象のこと.</p>
<p><script type="math/tex">^{*3}</script> はめ込み: <script type="math/tex">C^{\infty}</script>-級関数<script type="math/tex">f:M \to N</script>が,任意の点<script type="math/tex">p \in M</script>において<script type="math/tex">f</script>の微分 <script type="math/tex">f_{*}: T_p M \to T_{f(p)} N</script> が単射であるとき,<script type="math/tex">f</script>をはめ込み(immersion)という(森田,微分形式の幾何学).
埋め込み(embedding)ではなく,はめ込みとしたのはおそらく,曲線自身が交わることを許容することを強調しているのではないかと思う.</p>
<p><script type="math/tex">^{*4}</script>: Dirichletエネルギーの表式の中で,通常スカラー値関数に対して定義される勾配がベクトル値関数に対して作用しているので戸惑ったかもしれないが,これはJacobianに他ならないことに気がつけば大丈夫だろう.
あるいは写像の微分として理解してもよい.
( <a href="http://math.stackexchange.com/questions/222720/gradient-of-a-vector-valued-function">http://math.stackexchange.com/questions/222720/gradient-of-a-vector-valued-function</a> )</p>
<hr />
<p>今2つのエネルギーを定義したが,一体どうやってこの勾配フローを求めるのだろうか?関数<script type="math/tex">\phi : \mathbb{R}^n \to \mathbb{R}</script>に対する勾配を思い出してみると,</p>
<script type="math/tex; mode=display">\begin{align*}
\nabla \phi = \left(
\begin{array}{c}
\partial \phi / \partial x^1 \\
\vdots \\
\partial \phi / \partial x^n
\end{array}
\right)
\end{align*}</script>
<p>であった.
<script type="math/tex">\mathbb{R}^n</script>のような素直な有限次元ベクトルに対して定義された関数の勾配であればこのような定義で十分なのであるが,Willmoreエネルギーのような無限次元の関数空間に対して作用する勾配は一体どのように定義すればよいのだろうか.
一般的に,関数<script type="math/tex">\phi</script>の点<script type="math/tex">x</script>における勾配<script type="math/tex">\nabla \phi(x)</script>は\[ \langle \nabla \phi (x), u \rangle = \lim_{h\to 0} \frac{\phi(x+hu) - \phi(x)}{h} \mbox{ ,for all } u \] として唯一に定義できる<script type="math/tex">^*1</script>.
ただし,<script type="math/tex">\langle \cdot , \cdot \rangle</script>はベクトル空間上の内積とする.
言い換えると,勾配との内積をとれば,任意の方向の方向微分を計算できるということである.ここで注目すべきことは,この定義は「微分可能性」の定義としても使えるということである.
すなわち,「ある関数が点<script type="math/tex">x</script>において微分可能であるための必要十分条件は,任意の方向微分があるベクトル<script type="math/tex">\nabla \phi (x)</script>によって特徴付けられる」ということである.
幾何的に言うと,微分可能性とは,関数に対して十分に近い距離から観察すると平坦な形状と全く区別がつかないということである.</p>
<blockquote>
<p>Exercise 4.3
勾配は最急降下方向であることを示せ.</p>
</blockquote>
<blockquote>
<p>Exercise 4.4<br />
関数<script type="math/tex">\phi: \mathbb{R}^2 \to \mathbb{R}; (x_1, x_2) \mapsto x_1^2 - x_2^2</script>に対して上述の定義によって導いた勾配が通常の偏微分による勾配と同じものになることを示せ.</p>
</blockquote>
<blockquote>
<p>Exercise 4.5<br />
<script type="math/tex">M</script>を境界を持たない曲面であるとする.Laplace-Beltrami作用素は<script type="math/tex">f</script>に関して一定であることを仮定すると,上述の<script type="math/tex">\nabla</script>の定義を用いて以下の式が成り立つことを示せ.\[ \nabla E_D(f) \approx HN \] Dirichletエネルギーの勾配フローは,前回の宿題で考察した平均曲率フロー<script type="math/tex">\dot{f} = - HN</script>と似ていることがわかるだろう.</p>
</blockquote>
<p>この近似勾配<script type="math/tex">HN</script>は,真の勾配に対しての線形化(linearization)と呼ばれる.
一般的なテクニックとして,式の中の一部の値を固定して残りが線形性を持つようにすることができる.
これは実応用上非常に重要であるものだが,この近似が最終的な結果にどのように影響するのかを理解することもまた重要である.</p>
<p>最後に,一つ心に留めておかなければならないことは,勾配の定義の左辺に登場する内積<script type="math/tex">\langle \cdot, \cdot \rangle</script>の取り方によって異なる場合があるということである.
なぜ内積が重要なのだろうか?直感的には,勾配はエネルギーが最も早く大きくなる方向を選べばいいように思える.しかし,ここでいう「最も早く」というのがクセモノなのである.離散曲線の頂点を表現するのに実ベクトル<script type="math/tex">\mathbf{x} \in \mathbb{R}^m</script>を用いたとすると,我々は曲線の長さに応じて増加する曲線のエネルギーについて関心があるのであって,<script type="math/tex">\mathbf{x}</script>自身のユークリッド距離に応じて増加するエネルギーについてではないのだ.先ほど考えたエネルギー分布を用いて考えてみよう.左図の矢印はユークリッド空間に自然に入る計量を用いた時のnormが1のベクトルを表す一方で,右図の矢印は離散曲線上の$L^2$ノルムを用いた時のnormが1のベクトルを表す.これらの図からわかるように,勾配に沿った降下は異なる2つの軌跡を取りうるということを示している.</p>
<p><img src="http://brickisland.net/cs177fa12/wp-content/uploads/2012/12/ddg_gradient_metric.svg" alt="http://brickisland.net/cs177fa12/wp-content/uploads/2012/12/ddg_gradient_metric.svg" /></p>
<blockquote>
<p>Exercise 4.6<br />
正定値行列 <script type="math/tex">B\in \mathbb{R}^{n\times n}</script> によって定義される <script type="math/tex">\mathbb{R}^n</script> 上の内積 <script type="math/tex">\langle \mathbf{u},\mathbf{v} \rangle = \mathbf{u}^T B \mathbf{v}</script> を考えよう.
このとき,この内積によって定まる勾配 <script type="math/tex">\nabla_B</script> は通常の勾配 <script type="math/tex">\nabla</script> と以下の関係式で表されることを示せ.\[ \nabla_B = B^{-1} T \]</p>
</blockquote>
<p>この行列<script type="math/tex">B</script>は,各自由度がどの程度全体に影響するかを表す「質量」を意味することから,離散幾何においてしばしば質量行列(mass matrix)と呼ばれる.
離散微分形式(discrete differential form)を用いて定式化している場合は,(適切な定数倍をした)対角Hodgeスター(diagonal Hodge star)をしばしば採用する.
これは,区分定数内挿と通常の<script type="math/tex">L^2</script>内積を用いることを意味する.区分定数内挿とはどういうことかということを,三角メッシュ面に対するprimal 1-formを例にとって説明すると,各辺に保存された積分値(discrete 1-formと呼ぶのであった)を,その辺に対応するダイヤモンド領域(下図)に割り当てられる値とするということである.</p>
<p><img src="http://brickisland.net/cs177fa12/wp-content/uploads/2012/12/ddg_piecewise_constant_interpolation.svg" alt="http://brickisland.net/cs177fa12/wp-content/uploads/2012/12/ddg_piecewise_constant_interpolation.svg" /></p>
<p>離散微分幾何において<script type="math/tex">*_k</script>は,
<script type="math/tex">k</script> 次元の単体<script type="math/tex">\sigma_i</script>それぞれに対して一つの要素を割り当てる実対角行列を表す.
<script type="math/tex">*_k</script> の対角要素は,
<script type="math/tex">{({*}_k)}_{ii} = \vert \sigma_i^* \vert / \vert \sigma_i \vert</script>
である.</p>
<p>ここで<script type="math/tex">\sigma_i^*</script>は<script type="math/tex">\sigma</script>の(外心を用いた)双対を表し,<script type="math/tex">\vert \cdot \vert</script>は体積を表す.
このとき,n次元のprimal discrete k-formに対応する質量行列は,</p>
<script type="math/tex; mode=display">\begin{align*}
B_k = \left(
\begin{array}{c}
n \\
k
\end{array}
\right) *_k
\end{align*}</script>
<p>となる.また,n次元のdual discrete k-formに対応する質量行列も同様に</p>
<script type="math/tex; mode=display">\begin{align*}
B_k^* = \left(
\begin{array}{c}
n \\
k
\end{array}
\right) *_{n-k}^{-1}
\end{align*}</script>
<p>となる.
これらの行列は離散曲率フローの方程式を導出する際に役に立つだろう.</p>
<hr />
<h3 id="remarks-1"><strong>Remarks</strong></h3>
<p><script type="math/tex">^{*1}</script>: 無限次元ベクトルに関する微分法の厳密な取り扱いは,関数解析学に属するものである.<script type="math/tex">\phi</script>は関数というよりも汎関数(functional)と呼ぶべきものであり,ここで与えられている微分の定義も汎関数微分と呼ばれるものである.また,<script type="math/tex">u</script>のかわりにノルム1の試験関数<script type="math/tex">f</script>を用いるのが一般的である.ちなみに,勾配フローはBanach空間であるので,この種の微分はFréchet微分と呼ばれる.</p>
<h2 id="flow-on-curves"><strong>Flow on Curves</strong></h2>
<p><img src="http://brickisland.net/cs177fa12/wp-content/uploads/2012/12/ddg_curve_energy.svg" alt="http://brickisland.net/cs177fa12/wp-content/uploads/2012/12/ddg_curve_energy.svg" /></p>
<p>ここからは,曲面ではなく平面内の曲線に限定することにしよう.前述したように,曲線のジオメトリははめ込み写像
\[ \gamma: I=[0,L]\in \mathbb{R} \to \mathbb{R}^2; s \mapsto \gamma(s) \]
を用いて表せる.
曲線のエネルギーは単純に曲率<script type="math/tex">\kappa</script>の積分<script type="math/tex">E(\gamma) = \int_0^L \kappa^2 ds</script>を用いるのが一般的である.
まずは(よくやるように)滑らかな曲線で曲率に対して成り立ついくつかの事実を見ていこう.</p>
<blockquote>
<p>Exercise 4.7<br />
滑らかな曲線<script type="math/tex">\gamma</script>の接ベクトル場は,<script type="math/tex">I</script>上の関数<script type="math/tex">\theta:I \to \mathbb{R}</script>を用いて<script type="math/tex">T=(\cos \theta, \sin \theta)</script>と表せる.
この時,法線曲率は,<script type="math/tex">X</script>を反時計回りを正にとった単位ベクトル場としたとき,\[ \kappa = d\theta(X) \] で表される<script type="math/tex">^{*1}</script>.
これは,スカラ曲率<script type="math/tex">^{*2}</script>が接線方向に変化するということを意味している.</p>
</blockquote>
<blockquote>
<p>Exercise 4.8<br />
閉曲線<script type="math/tex">\gamma</script>(smooth or discrete)の全曲率(total curvature)は常に<script type="math/tex">2\pi</script>の整数倍となることを説明せよ.
\[ \int_0^L \kappa ds = 2\pi k, k\in \mathbb{Z}\](<script type="math/tex">k</script>はこの曲線の回転数と呼ばれる量である.)</p>
</blockquote>
<p>より強い結果として,曲線の回転数は正則ホモトピー(regular homotopy)<script type="math/tex">^{*3}</script>な変形を施しても不変であるというWhitney-Grausteinの定理と呼ばれるものがある.
下図に示すものは<strong>正則ではない</strong>変形を施したものである.この図において,変形の途中に曲線の空白領域が潰れてしまっていることにより回転数が2から1に減少していることに着目して欲しい.</p>
<p><img src="http://brickisland.net/cs177fa12/wp-content/uploads/2012/12/ddg_irregular_homotopy.svg" alt="http://brickisland.net/cs177fa12/wp-content/uploads/2012/12/ddg_irregular_homotopy.svg" /></p>
<p>これらの考え方をもとに,曲率フローのアルゴリズムを設計していくことにしよう.</p>
<hr />
<h3 id="remarks-2"><strong>Remarks</strong></h3>
<p><script type="math/tex">^{*1}</script>: 接ベクトルのかわりに曲線の法線ベクトルを対応させるものとしてGaussの表示(Gauss map)がある.[小林昭七,曲線と曲面の微分幾何,p7]に詳しい.</p>
<p><script type="math/tex">^{*2}</script>: スカラ曲率とは,Riemann多様体の最も基本的な曲率不変量である.高々2次元Riemann多様体においては,他の曲率を完全に特徴づける量であることが知られており,この値が0ならば平坦に近く,大きければ強い曲がり方を持っていると解釈することができる.また,2次元においてはGauss曲率のちょうど2倍になることも知られている.</p>
<p><script type="math/tex">^{*3}</script> 正則ホモトピー:曲線を他の曲線に滑らかに正則性を保ちながら変形できるとき2つの曲線の間のはめ込みは正則ホモトピー(regular homotopy)であるという.正則とは,はめ込み写像の微分の大きさが常に0にならないことをいう.</p>
<h2 id="discrete-curves"><strong>Discrete Curves</strong></h2>
<p>さて,話を離散の世界に持って行こう.<script type="math/tex">\gamma_1, \gamma_2, \ldots, \gamma_n \in \mathbb{R}^2</script>を頂点として持つような線分の集合として離散曲線<script type="math/tex">\gamma</script>を定義しよう.</p>
<p><img src="http://brickisland.net/cs177fa12/wp-content/uploads/2012/12/ddg_discrete_curve.svg" alt="http://brickisland.net/cs177fa12/wp-content/uploads/2012/12/ddg_discrete_curve.svg" /></p>
<p>配布したコードでは,曲線は1つのポリゴンを持つハーフエッジメッシュとして表現しているため,曲線上で繰り返し処理を行う際には下記のようにすればよいだろう.</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">FaceIter</span> <span class="n">gamma</span> <span class="o">=</span> <span class="n">mesh</span><span class="p">.</span><span class="n">faces</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span>
<span class="n">HalfEdgeIter</span> <span class="n">he</span> <span class="o">=</span> <span class="n">gamma</span><span class="o">-></span><span class="n">he</span><span class="p">;</span>
<span class="k">do</span> <span class="p">{</span>
<span class="c1">// do something interesting here!
</span> <span class="n">he</span> <span class="o">=</span> <span class="n">he</span><span class="o">-></span><span class="n">next</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">while</span><span class="p">(</span> <span class="n">he</span> <span class="o">!=</span> <span class="n">gamma</span><span class="o">-></span><span class="n">he</span> <span class="p">);</span>
</code></pre></div></div>
<p>曲面の場合と同様に,曲線におけるprimal, dual「メッシュ」を考えることができる.ここでは,primalにおける頂点に対して,その頂点と隣接する辺の中点を結んだ辺上領域をdualとして割り当て,また,primalにおける辺に対して,その中点の頂点をdual割り当てよう.</p>
<p><img src="http://brickisland.net/cs177fa12/wp-content/uploads/2012/12/ddg_simplicial_dual_1d.svg" alt="http://brickisland.net/cs177fa12/wp-content/uploads/2012/12/ddg_simplicial_dual_1d.svg" /></p>
<p>Discrete exterior calculusの言葉を借りれば,<script type="math/tex">\gamma \in (\mathbb{R}^2)^n</script>は<script type="math/tex">\mathbb{R}^2</script>を吐き出すようなprimal 0-formである.
(すなわち,各頂点に対して<script type="math/tex">\mathbb{R}^2</script>を割り当てるようなものである.)</p>
<blockquote>
<p>Exercise 4.9<br />
primal 0-formの対角Hodgeスターの非ゼロ要素は,<script type="math/tex">L_i = \frac{1}{2}(\vert\gamma_{i+1} - \gamma_i \vert + \vert \gamma_i - \gamma_{i-1} \vert)</script> を用いて, <script type="math/tex">(*_0)_{ii} = L_{ii}</script> となることを示せ.</p>
</blockquote>
<blockquote>
<p>Coding 4.1<br />
primal辺の長さを返すメソッド<code class="highlighter-rouge">Edge::length()</code>と外心dual辺の長さを返すメソッド<code class="highlighter-rouge">Vertex::dualLength()</code>をそれぞれ実装せよ.(後者は,前者を呼び出すだけなので一行で済むはず!)
続いてprimal 0-formの対角Hodgeスターを構成するメソッド<code class="highlighter-rouge">IsometricWillmoreFlow1D::buildMassMatrix()</code>を実装せよ.</p>
</blockquote>
<blockquote>
<p>Exercise 4.10<br />
離散曲線において,dual辺 <script type="math/tex">e_{ij}^*</script> に沿った全曲率は対応する頂点における外角<script type="math/tex">\varphi_{ij} \in \mathbb{R}</script>,すなわち連続する線分のなす角度と等しいことを示せ.(Stoke’s theorem!)
\[ \varphi_{ij} = \theta_j - \theta_i = \int_{e_{ij}^*} \kappa ds \]</p>
</blockquote>
<p>この事実は,外角 <script type="math/tex">\phi</script> は「積分された」曲率を表わすことに他ならない.外角に離散Hodgeスターを適用することによって,各点ごとの曲率 <script type="math/tex">\kappa</script> が得られる.\[ \kappa = *\varphi\] この値は数値的に曲率フローを構成する際に自由度として用いることができることを追って確認しよう.</p>
<blockquote>
<p>Coding 4.2<br />
上記で適宜した各点ごとの曲率<script type="math/tex">\kappa</script>を返すメソッド<code class="highlighter-rouge">Vertex::curvature()</code>を実装せよ.(<script type="math/tex">\varphi</script>はDECの言葉で表すと何に相当するだろうか.また,<script type="math/tex">\kappa</script>は?)</p>
</blockquote>
<p>次の問題は,いままで定義してきたがどのように役立つかといったことや,作用素がどの空間からどの空間へ連れて行ってくれるのかを理解する良い練習となるだろう.</p>
<blockquote>
<p>Exercise 4.11<br />
曲率に対して区分定数内挿を施した時,離散曲線に対して,<script type="math/tex">E(\gamma)</script>は\[ E(\gamma) = \sum_{i} \varphi_i^2 / L_{i} \]と表せることを示せ.</p>
</blockquote>
<p>これにより,離散曲率エネルギーがどのように表されるかがわかった.次に勾配を表わす公式を導出しよう.</p>
<blockquote>
<p>Exercise 4.12<br />
<script type="math/tex">\varphi</script>を<script type="math/tex">u,v \in \mathbb{R}^2</script>のなす角とする.<script type="math/tex">u</script>に関する<script type="math/tex">\varphi</script>の勾配は\[ \nabla_u \varphi = - \frac{v_{\perp u}}{2A}\] と表される事を示せ.
ただし,<script type="math/tex">v_{\perp u}</script>は<script type="math/tex">u</script>に直交する<script type="math/tex">v</script>の成分を表し,<script type="math/tex">A</script>を<script type="math/tex">u</script>と<script type="math/tex">v</script>のなす三角形の面積であるとする.</p>
</blockquote>
<p><img src="http://brickisland.net/cs177fa12/wp-content/uploads/2012/12/ddg_angle_gradient.svg" alt="http://brickisland.net/cs177fa12/wp-content/uploads/2012/12/ddg_angle_gradient.svg" /></p>
<blockquote>
<p>Exercise 4.13<br />
<script type="math/tex">a,b</script>を<script type="math/tex">\mathbb{R}^2</script>の点とする.
<script type="math/tex">L</script>をベクトル<script type="math/tex">u=b-a</script>の長さとするとき,\[ \nabla_a L = - \hat{u} \] と \[ \nabla_b L = \hat{u} \]が成り立つことを示せ.</p>
</blockquote>
<p><img src="http://brickisland.net/cs177fa12/wp-content/uploads/2012/12/ddg_length_gradient.svg" alt="ddg_length_gradient" class="center-image" /></p>
<blockquote>
<p>Exercise 4.14<br />
これまでの練習問題の結果を用いて,曲率エネルギーの$i$番目の項\[ E_i = \varphi_i^2 \] の頂点<script type="math/tex">\gamma_{i-1}, \gamma_i, \gamma_{i+1}</script>に関する勾配は以下のように書けることを示せ.<br />
<script type="math/tex">% <![CDATA[
\begin{align*}
\nabla_{\gamma_{i-1}} E_i &= \frac{\varphi_i}{L_i L_{i-1}} \left( \frac{v_{\perp u}}{A_i} + \frac{\varphi_i}{2L_i} \hat{u} \right) \\
\nabla_{\gamma_{i+1}} E_i &= \frac{\varphi_i}{L_i^2} \left( \frac{u_{\perp v}-v_{\perp u}}{A_i} + \frac{\varphi_i}{2L_i} (\hat{v}-\hat{u}) \right) \\
\nabla_{\gamma_i} E_i &= -\frac{\varphi_i}{L_i L_{i+1}} \left( \frac{u_{\perp v}}{A_i} + \frac{\varphi_i}{2L_i} \hat{v} \right)
\end{align*} %]]></script></p>
</blockquote>
<p><img src="http://brickisland.net/cs177fa12/wp-content/uploads/2012/12/ddg_exterior_angle_gradient.svg" alt="ddg_exterior_angle_gradient" /></p>
<blockquote>
<p>ただし,<script type="math/tex">\varphi_i</script>は頂点<script type="math/tex">i</script>における外角,<script type="math/tex">L_i</script>をdual辺の長さ,<script type="math/tex">A_i</script>を辺<script type="math/tex">u=\gamma_i - \gamma_{i-1}</script>と辺<script type="math/tex">v=\gamma_{i+1} - \gamma_i</script>がなす三角形の面積とする.
(実はこれら以外の<script type="math/tex">\gamma_j</script>に関する<script type="math/tex">E_i</script>の勾配は全てゼロになるのだが,なぜだろう?勾配は計量によって変わりうることを思い出そう!)</p>
</blockquote>
<blockquote>
<p>Coding 4.3<br />
上の公式を用いて<code class="highlighter-rouge">WillmoreFlow1D::computeGradient()</code>を実装しよう.与えられた頂点に関するエネルギーの勾配は<code class="highlighter-rouge">Vertex::energyGradient</code>に格納しよう.
離散曲線全体のエネルギーは各項<script type="math/tex">E_i</script>の和,すなわち各頂点における勾配が及ぼす影響を足しあわせる必要があることに注意しよう.</p>
</blockquote>
<blockquote>
<p>Coding 4.4<br />
フロー方程式\[ \dot{\gamma} = - \nabla E(\gamma) \] を積分するメソッド<code class="highlighter-rouge">WillmoreFlow1D::integrate()</code>を前進オイラー法(forward(explicit) Eular scheme)によって実装せよ.
(時間に関する積分については前回の宿題の末尾を参照のこと)配布したメッシュデータに対してプログラムを実行し,それぞれのケースについて安定的に積分できる(曲線の平滑化に成功する)最大の時間ステップを報告せよ.(時間ステップは,’-‘, ‘=’, ‘_’, ‘+’キーを使うと変更できる.)</p>
</blockquote>
<h2 id="curvature-flow-in-curvature-space"><strong>Curvature Flow in Curvature Space</strong></h2>
<p>そろそろ宿題にうんざりしてきた頃だろうか.でも君は一人じゃない!微分を手で計算するのはキングオブ面倒くさいことだ.(Newton法なんかを使おうと思ったら2階まで微分を計算しなくちゃならない!)でも人生で一度はこの類の計算を行うことは大事だ.そうすることで今自分が何をやっているかをよく理解できるようになるだろう.実際の現場では,手で計算する代わりに,数値微分(numerical differentiation)や自動化微分(automatic differentiation),シンボリック微分(symbolic differentiation)などの方法を使える.これらはぞれぞれ,正確性や効率性,コードの複雑さといったようなトレードオフがあるのでケースバイケースで使い分けることが大事だ.</p>
<p>コンピュータに微分を計算させるという沼に足を突っ込む前に,検討すべき4つ目の選択肢がある事を覚えておいてほしい.
問題のフォーミュレーション自体を簡単なものにしてしまえばいいんだ.
例えば,凸2次問題なんかに落としこむことに成功すれば,あまりの楽さにドキドキしてしまうかもしれない.
「凸2次」とは,エネルギーを実数値をとる同次2次多項式\[ E(x) = \langle Ax, x \rangle \] で表せるようなものだ.
ここで<script type="math/tex">A</script>は,変数<script type="math/tex">x</script>に依存しない正定値エルミート線形作用素である.
離散幾何では,系の自由度<script type="math/tex">x</script>は<script type="math/tex">\mathbb{R}^2</script>のベクトルとして記述することが出来る.
この時,2次エネルギーは,<script type="math/tex">A\in \mathbb{R}^{n\times n}</script>をある対称半正定値行列として,\[ E(x) = x^T A x \] と書ける.
以前,2次元の場合に正定値性によってエネルギーのグラフがどのように変わるかを確認した.</p>
<p><img src="http://brickisland.net/cs177fa12/wp-content/uploads/2012/12/ddg_definiteness.svg" alt="http://brickisland.net/cs177fa12/wp-content/uploads/2012/12/ddg_definiteness.svg" /></p>
<p>正定値性に依らず,2次形式で表されるエネルギーの勾配は,内積によって定まる行列<script type="math/tex">B\in \mathbb{R}^{n\times n}</script>を用いて以下のように線形式で書ける.
\[ \nabla E(x) = 2 B^{-1}Ax \] このように問題を設計することは微分を簡単にするだけではなく,数値計算を行う上でも非常に有利である.というのも,厄介な非線形解を求めるアルゴリズムを走らせるかわりに,連立線形方程式を解くだけの後進オイラー法(backward Euler method)を使うことが出来るのだ.もっというと,<script type="math/tex">A</script>は不変であるので,予め前処理を一度施して後退代入(backsubstitution)することが可能になり計算時間を大幅に削減することが出来る.また,凸2次問題は解析的にも良い性質を持っている.凸なエネルギーの局所最適解はまた,大域的最適解になることが保証されている.これは最急降下法を用いることにより最適解が得られるということを意味している.また,線形な偏微分方程式に関する理論はよく整備されており,解の安定性に関する議論が容易になることもメリットの一つである.(非線形偏微分方程式に関する理論は <a href="http://mathoverflow.net/questions/15292/why-cant-there-be-a-general-theory-of-nonlinear-pde">まるで動物園みたいなもの</a> だ!)</p>
<p>OK,小難しい話はここまでだ.曲率フローに限定して2次問題がもたらす恩恵について見ていこう.
思い出して欲しい.曲率エネルギーは2次エネルギーだったはずだ.
\[ E(\kappa) = \int_0^L \kappa^2 ds \] いままで考察してきたエネルギーとこのフォーミュレーションによるエネルギーとの唯一の違いは,エネルギーがはめ込み写像<script type="math/tex">f</script>の関数ではなく,曲率<script type="math/tex">\kappa</script>の関数として表されていることだ.
この<script type="math/tex">f</script>のかわりに<script type="math/tex">\kappa</script>を用いるという工夫により面倒な非線形性を回避することが出来るのだ.離散曲率を例にとって具体的に言うと,頂点の座標<script type="math/tex">\gamma_i \in \mathbb{R}^2</script>の非線形関数として表される曲率のエネルギーを考えるのではなく,各頂点における曲率を直接保存し操作すればよいのだ.</p>
<blockquote>
<p>Coding 4.5<br />
(各点ごとの)曲率を計算し,<code class="highlighter-rouge">Vertex::kappa</code>というメンバに格納するメソッド<code class="highlighter-rouge">IsometricWillmoreFlow1D::getCurvature()</code>を実装せよ.(<code class="highlighter-rouge">Vertex::curvature()</code>を呼び出せばよい.)</p>
</blockquote>
<p>この問題設定によってもたらされる一つの結論は,勾配が極めて簡単に表現されるということだ.
実際,0-form上<script type="math/tex">L^2</script>内積の勾配は\[ \nabla E(\kappa) = -2\kappa \]と書ける.よって,勾配フローは空間微分を含まない単純な微分方程式に帰着する.
\[ \dot{\kappa} = -2\kappa \]</p>
<blockquote>
<p>Coding 4.6<br />
上記の微分方程式を前進オイラー法によって積分するメソッド
<code class="highlighter-rouge">IsometricWillmoreFlow1D::computeFlowDirection()</code>と
<code class="highlighter-rouge">IsometricWillmoreFlow1D::integrate()</code>を実装せよ.
簡単に書けるはず!</p>
</blockquote>
<p>曲率しか持たない状況でも簡単に曲線を再構成することが出来る.まずは滑らかな曲線で考えよう.
曲率を積分することにより,接ベクトルがわかる.これをさらに積分することで曲線上の位置が計算できる.
つまり,曲線の始点における接線の傾きを<script type="math/tex">\theta_0</script>とすると,任意の位置における接線の傾きの角<script type="math/tex">\theta</script>は,\[ \theta(s) = \theta_0 + \int_0^s d\theta = \theta_0 + \int_0^s \kappa ds \] と表される.
接ベクトル自体は<script type="math/tex">T(s) = (\cos \theta(s), \sin \theta(s))</script>と表される事に注意しよう.
あとはこれを積分することにより,はめ込み写像<script type="math/tex">f</script>自身を再構成することができる.
\[ f(s) = f_0 + \int_I T(s) ds \] ここで,<script type="math/tex">f_0</script>は曲線の始点の位置を表わしている.
この話を離散曲線に持っていこう.この2つのステップはとてもシンプルに書き直す事ができる.まず,始点における外角の方向<script type="math/tex">\varphi_0</script>に辺長だけ伸ばした点を次の頂点とし,次はその頂点における外角の方向<script type="math/tex">\varphi_1</script>に対して辺長だけ同じように伸ばす操作を繰り返せばよいのだ.(下図を見るとより具体的なイメージが分かるだろう)</p>
<p><img src="http://brickisland.net/cs177fa12/wp-content/uploads/2012/12/ddg_curve_reconstruction.svg" alt="http://brickisland.net/cs177fa12/wp-content/uploads/2012/12/ddg_curve_reconstruction.svg" /></p>
<p>式で表すと,\[ \theta_i = \sum_{k=0}^{i} \varphi_k \] とし,\[ T_i = L_i (\cos \theta_i, \sin \theta_i)\](<script type="math/tex">L_i</script>は<script type="math/tex">i</script>番目のprimal辺の長さ)とした時,曲線上の頂点の位置は\[ \gamma_i = \sum_{k=0}^i T_k \] となる.連続曲線の場合とよく似ていることが分かるだろう.
(これらの和を区分積分として解釈できることが分かるだろうか.<script type="math/tex">(\cos \varphi_i, \sin \varphi_i)</script>はどういう量だろう.<script type="math/tex">T_i</script>は?これら2つの量はどういう関係にある?)</p>
<blockquote>
<p>Coding 4.7<br />
<script type="math/tex">T_i</script>と<script type="math/tex">\gamma_i</script>をそれぞれ計算するメソッド<code class="highlighter-rouge">IsometricWillmoreFlow1D::recoverTangents()</code>, <code class="highlighter-rouge">IsometricWillmoreFlow1D::recoverPositions()</code>を実装せよ.
ただし!計算量が<script type="math/tex">O(n^2)</script>となるアルゴリズムを実装した場合は0点とする!
各頂点においていちいち全体の和を計算し直すということはしてはならない.もっといい方法があるはずだ.</p>
</blockquote>
<p>各辺の長さは構成時の値を使い回せばよい.あとはその辺の長さを使って曲線を再構成していけば良いのだ.数学的に言えば,曲率フローはisometricであるといえる.(滑らかな曲線の場合は,isometricという性質は<script type="math/tex">(\cos \alpha, \sin \alpha)</script>が常に単位ベクトルになるという事実を反映している.)</p>
<p>ここまで見てきた離散曲率フローの性質はどれも素敵なものばかりだ.
<!-- we simply subtract some fraction of the curvature each vertex, and compute a couple cumulative sums. 多分さっきみた2ステップのことを言っているのだと思うが,"subtract some fraction of the curvature at each vertexの部分がよくわからないので保留とした. -->
ではなぜ,みんなこのようにやらないのだろうか.「うますぎる話にはトゲがある」ということだ.</p>
<p>閉曲線を例にとって説明しよう.閉曲線上の曲率<script type="math/tex">\kappa</script>を全く任意に変化させてみよう.
この時,閉曲線は閉曲線のまま存在するだろうか.答えはもちろんノーだ.つまり,始点と終点の位置は異なる場所に存在するだろう.</p>
<p><img src="http://brickisland.net/cs177fa12/wp-content/uploads/2012/12/ddg_loop_closure.svg" alt="http://brickisland.net/cs177fa12/wp-content/uploads/2012/12/ddg_loop_closure.svg" /></p>
<p>新しく定めた曲率を積分して得た接ベクトルは「可積分(integrable)」ではないといえよう.
これらは積分したところで閉曲線にはならないからだ.同様に,曲率自体も可積分ではない.
曲率を積分した関数<script type="math/tex">\alpha</script>は,,閉曲線の接ベクトルの方向を表さないからだ.
ここで全曲率の定義を思い出そう.任意の閉曲線<script type="math/tex">\gamma</script>の曲率<script type="math/tex">\kappa</script>は回転数を<script type="math/tex">k\in \mathbb{Z}</script>として,\[ \int_0^L \kappa ds = 2\pi k \] という関係式があった.
また別の言い方として,始点における接ベクトル<script type="math/tex">T(0)</script>と終点における接ベクトル<script type="math/tex">T(L)</script>が一致するともいえる.
<script type="math/tex">\kappa</script>を任意に変化させてもこの条件が満たされるとは限らないのだ.</p>
<blockquote>
<p>Exercise 4.15<br />
時刻0において,上述の全曲率に関する条件を満たす閉曲線<script type="math/tex">\gamma</script>の曲率関数を<script type="math/tex">\kappa</script>とする.曲率の時間変化<script type="math/tex">\dot{\kappa}</script>が定数関数<script type="math/tex">1: [0,L] \to \mathbb{R}; s \mapsto 1</script>に対して<script type="math/tex">L^2</script>内積に関して直交すれば,この条件が満たされることを示せ.</p>
</blockquote>
<p>また,終点が始点と一致する(<script type="math/tex">\gamma(0) = \gamma(L)</script>)条件を導いておこう.
ここで導出は行わないが,この条件は以下の様に簡単に書き下せることがわかる.
\[ \int_0^L \kappa \gamma = 0 \]
つまり,<script type="math/tex">\dot{\kappa}</script>は,はめ込み写像<script type="math/tex">f</script>の<script type="math/tex">x-, y-</script>両座標関数に関して<script type="math/tex">L^2</script>直交しなければならない.
要するに,曲率の変化分が曲線の方向によって張られる2次元の線形部分空間への射影が0にならなければいけないということだ.
\[ \langle \dot{\kappa_1}, 1 \rangle = \langle \dot{\kappa}, \gamma_x \rangle = \langle \dot{\kappa}, \gamma_y \rangle = 0 \]
凸2次エネルギーの時と同様に,線形な拘束条件は非常に扱いやすい.今考えている曲率フローの場合においても,<script type="math/tex">\dot{\kappa}</script>の成分のなかで「禁止された」空間にいるものを排除してやればよいのだ.
すなわち,この空間が直交基底<script type="math/tex">\{ \hat{c}_i \}</script>によって張られたものであるとすると,以下の式<script type="math/tex">^{*1}</script>で表される曲率<script type="math/tex">\dot{\kappa}_c</script>を用いればよいのだ.
\[ \dot{\kappa}_c = \dot{\kappa} - \sum_1^3 \langle \dot{\kappa}, \hat{c}_i \rangle \hat{c}_i \]</p>
<p><img src="http://brickisland.net/cs177fa12/wp-content/uploads/2012/12/ddg_constraint_projection.svg" alt="http://brickisland.net/cs177fa12/wp-content/uploads/2012/12/ddg_constraint_projection.svg" /></p>
<blockquote>
<p> Coding 4.8<br />
3つの拘束方向<script type="math/tex">1, \gamma_x, \gamma_y</script>を縦ベクトルとして構成するようなメソッド<code class="highlighter-rouge">IsometricWillmoreFlow1D::buildConstraints()</code>を実装せよ.</p>
</blockquote>
<blockquote>
<p>Coding 4.9<br />
上記の3つの拘束方向と同じ空間を張る直交基底<script type="math/tex">\{ \hat{c}_1, \hat{c}_2, \hat{c}_3 \}</script>を構成するメソッド<code class="highlighter-rouge">IsometricWillmoreFlow1D::orthogonalizeConstraints()</code>を実装せよ.(Gauss-Schmidtによる直交化を使えば良い.ただし,正しい内積を使うことを忘れずに!)</p>
</blockquote>
<blockquote>
<p>Coding 4.10<br />
直交基底を用いてフローから禁止された方向を取り除き,上記のプロセスを実行するメソッド<code class="highlighter-rouge">IsometricWillmoreFlow::enforceConstraints()</code>を実装せよ.
ここまでくればisometric Willmore flowを試してみることが出来るはずだ.(右クリックからコンテキストメニューで選択するか,’i’キーを押すことでGUIで確認することが出来る.)
配布したメッシュにおいてそれぞれで許容される最大の時間ステップはいくつになるだろうか.各入力曲線について回転数を保存するようなフローになっているだろうか.つまり,離散曲線においてもWhitney-Grausteinの定理が成立していることが書くに出来るだろうか.
<code class="highlighter-rouge">IsometricWillmoreFlow::enforceConstraints</code>をいじって,拘束がある場合とない場合とでフローを実行して違いを確認してみて欲しい.全ての拘束を取り外した時には何が起きるだろうか.これらの拘束は,閉曲線を保つために全て必要だろうか.あるいは取り除いても良い物があるだろうか.</p>
</blockquote>
<p>この新しいフローは確かに曲線を平滑化するが,<code class="highlighter-rouge">WillmoreFlow1D</code>において実装したものとはまるで違うことに気がつくだろう.この違いは一体なんだろう.どちらの場合でも,同じエネルギーに対して最急降下法したはずだ.ここで以前考察したことを思い出してみよう―そうだ.確かに同じエネルギーを使っているが,勾配を定義する際に用いた計量が違うのだ!(勘の良い人は,どうやって2つ目のフローをいじれば1つ目のフローと同じようにみせることができるかも気がついたかもしれない.)更にいうなれば,離散ラプラシアンやPoisson方程式を含むアルゴリズムの性能を向上させる方法が沢山ある.どういうことだかわかるかい?</p>
<p>さあもう十分君は仕事をした!また来年あおう!</p>
<hr />
<p>更新履歴:2015/5/31 第1稿公開
更新履歴:2018/3/17 第2稿公開(kramdownに書き換え)</p>Masahiro Hiranomasahiro.dll_at_gmail.comhttps://masahirodll.comCaltechで開講されていた”Discrete Differential Geometry”という講義の中で,Homeworkとして提示されていたものだが,curvature flow(曲率フロー)の良いチュートリアルでもあるので全訳する. original URL: http://brickisland.net/cs177fa12/?p=320