計算数理演習 · 2020. 7. 16. · 計算数理演習 齊藤宣一...
TRANSCRIPT
計算数理演習
齊藤 宣一(東京大学大学院数理科学研究科)norikazu[at]ms.u-tokyo.ac.jp
2020年 6月 12日
• この資料は,2020年度 Sセメスター(金曜 3限,駒場情報教育棟 E41室)に行われる*1,計算数理演習(東京大学理学部数学科,教養学部統合自然科学科)の講義資料です.この講義は,直前(金曜 2限)に行われる,計算数理 Iの講義内容に沿った,数値計算の実習を行います.
• この講義では,計算を行う際に,数値計算システムMATLAB(https://www.u-tokyo.ac.jp/adm/dics/
ja/matlabcwl.htm)を利用します.現在,欧米の数値解析のテキストの計算例は,“ほとんどすべて”MATLAB
という数値計算システムを用いて作成されています.プログラム例も MATLAB で書かれています.すなわち,欧米の大学生は,MATLAB を用いた数値計算の経験をしていると思って間違いありません.
• 講義の際に配布した「MATLAB超入門」を付録として付けました.
*1 曜日・時限・場所は,その予定であったということです.
目次1 ITC-LMSの使い方と LATEXによる文書の作成 1
1.1 講義の説明 . . . . . . . . . . . . . . . . . . . . 1
1.1.1 日程と講義の進め方 . . . . . . . . . . . . . 1
1.1.2 成績評価 . . . . . . . . . . . . . . . . . . . 1
1.1.3 レポートの提出の形式と方法 . . . . . . . . 2
1.1.4 MATLABの利用 . . . . . . . . . . . . . . 2
1.2 ITC-LMSの利用 . . . . . . . . . . . . . . . . 3
1.3 Cloud LATEXの利用 . . . . . . . . . . . . . . . 4
1.3.1 準備 . . . . . . . . . . . . . . . . . . . . . 4
1.3.2 ログイン . . . . . . . . . . . . . . . . . . . 5
1.3.3 新規プロジェクトの作成 . . . . . . . . . . 5
1.3.4 文書の作成 . . . . . . . . . . . . . . . . . 7
1.3.5 文書のコンパイル . . . . . . . . . . . . . . 7
1.3.6 PDFファイルのダウンロード . . . . . . . 8
1.3.7 【参考】キーボードの設定 . . . . . . . . . 9
1.4 LATEXのコマンドの勉強 . . . . . . . . . . . . . 11
1.5 課題 1 . . . . . . . . . . . . . . . . . . . . . . 11
2 MATLABの使い方 12
2.1 MATLABとは? . . . . . . . . . . . . . . . . 12
2.2 インストールあるいはオンラインでの利用 . . . 13
2.3 MATLABの基礎 . . . . . . . . . . . . . . . . 13
2.4 はじめの例題 . . . . . . . . . . . . . . . . . . . 14
2.5 課題 2 . . . . . . . . . . . . . . . . . . . . . . 17
3 非線形方程式の反復解法 19
3.1 Newton法 . . . . . . . . . . . . . . . . . . . . 19
3.2 収束の速さ . . . . . . . . . . . . . . . . . . . . 22
3.3 重解 (f ′(a)=0)の場合 . . . . . . . . . . . . . . 24
3.4 多変数の Newton法 . . . . . . . . . . . . . . . 26
3.5 課題 3 . . . . . . . . . . . . . . . . . . . . . . 29
課題 2へのコメント 32
4 固有値問題 37
4.1 冪乗法 . . . . . . . . . . . . . . . . . . . . . . 37
i
4.2 逆冪乗法 . . . . . . . . . . . . . . . . . . . . . 41
4.3 課題 4 . . . . . . . . . . . . . . . . . . . . . . 45
5 数値積分 47
5.1 複合 Newton-Cotes公式 . . . . . . . . . . . . 47
5.2 誤差挙動と収束の速さ . . . . . . . . . . . . . . 50
5.3 課題 5 . . . . . . . . . . . . . . . . . . . . . . 53
6 常微分方程式の初期値問題 56
6.1 Euler法と Heun法 . . . . . . . . . . . . . . . 56
6.2 誤差の考察 . . . . . . . . . . . . . . . . . . . . 59
6.3 ベクトル値の微分方程式 . . . . . . . . . . . . . 62
6.4 課題 6 . . . . . . . . . . . . . . . . . . . . . . 65
∞ 発展課題 66
付録 A MATLAB超入門 1
A.1 MATLAB . . . . . . . . . . . . . . . . . . . . 1
A.2 基本操作 . . . . . . . . . . . . . . . . . . . . . 2
A.3 基本演算 . . . . . . . . . . . . . . . . . . . . . 3
A.3.1 四則演算など . . . . . . . . . . . . . . . . 3
A.3.2 特別な記号名など . . . . . . . . . . . . . . 4
A.3.3 組み込み関数 . . . . . . . . . . . . . . . . 4
A.3.4 出力フォーマット . . . . . . . . . . . . . . 6
A.4 ベクトルと行列 . . . . . . . . . . . . . . . . . 7
A.4.1 定義と演算 . . . . . . . . . . . . . . . . . 7
A.4.2 ノルム,行列式と逆行列など . . . . . . . . 10
A.4.3 特別な行列 . . . . . . . . . . . . . . . . . 12
A.4.4 成分毎の演算 . . . . . . . . . . . . . . . . 14
A.4.5 ベクトルから行列を生成 . . . . . . . . . . 15
A.4.6 連立一次方程式の解法 . . . . . . . . . . . 16
A.5 2Dグラフィクス . . . . . . . . . . . . . . . . . 17
A.5.1 関数のグラフの描画 . . . . . . . . . . . . . 17
A.5.2 複数のグラフの描画 . . . . . . . . . . . . . 18
A.5.3 格子や凡例 . . . . . . . . . . . . . . . . . 19
A.5.4 ファイルへの保存 . . . . . . . . . . . . . . 20
A.6 Mファイルの利用 . . . . . . . . . . . . . . . . 22
A.7 プログラミングと for文 . . . . . . . . . . . . . 24
A.8 二分法と if文および while文 . . . . . . . . . . 25
ii
A.9 応用:Fourier級数の収束 . . . . . . . . . . . . 29
A.10 ファイルへの入出力 . . . . . . . . . . . . . . . 31
A.10.1 出力 . . . . . . . . . . . . . . . . . . . . . 31
A.10.2 入力 . . . . . . . . . . . . . . . . . . . . . 32
A.11 プログラミングにおける注意 . . . . . . . . . . 33
A.12 連立一次方程式の解法: LU分解 . . . . . . . . 34
付録 B Durand–Kerner法と Gauss型積分公式の実装 39
B.1 Durand–Kerner法の実装 . . . . . . . . . . . . 39
B.2 Gauss型積分公式の実装 . . . . . . . . . . . . . 42
iii
2020年 4月 10, 17日 (担当:齊藤宣一)
計算数理演習 第 1回課題 (数学科,統合自然科学科)
1 ITC-LMSの使い方と LATEXによる文書の作成
1.1 講義の説明
1.1.1 日程と講義の進め方
4/10 休講4/17, 4/24 ガイダンス,ITC-LMSの使い方,Cloud LATEXに
よるレポートの作成5/1, 5/8 MATLABの使い方5/22, 5/29 非線形方程式6/5, 6/12 固有値問題6/19, 6/26 定積分7/3, 7/10 常微分方程式
• 講義では,おおよそ 2週で一つの課題に取り組む.• 受講者は,はじめに例題を自分で実行し検討する.次に,課題に取り組む.最後に,結果をレポートにまとめる.
• そして,ITC-LMS*2の『課題』にあるレポート提出機能を用いて,レポートを提出する.レポートの提出期限は,余裕をもって設定するので,かならずすべて(6つ)提出すること.
1.1.2 成績評価課題は全部で 6つある.期限までに必ずすべて提出すること
(期限は ITC-LMSに明示する).*3
課題 1と課題 2は,提出の有無のみをチェックする.内容の良し悪しの評価は,課題 3–課題 6に対してのみ行う.成績評価は,この課題に対するレポートの評価のみに基づい
*2 1.2項で詳しく説明する.*3 ただし,様々な事情で期限までに提出できない場合は,個別に(メールで)相談して下さい.一度,提出できなかったからといって,以後の提出を諦めないようにして下さい.
1
て行う.
1.1.3 レポートの提出の形式と方法• レポートは,PDF形式(*****.pdf)のファイルで,ITC-LMS のレポート登録機能を通じて提出されたもののみを受け付ける.紙にプリントアウトしたものは受け付けない.
• レポートのファイル名は,好きなように付けて良い.
• レポートの構成は次のようにすること:– 名前– 課題の内容(改めて自分で簡単にまとめる)– 計算に使用したプログラム(適宜省略可.簡単な説明も付けた方が良い)
– 計算結果のまとめ(入力と出力など)– 結果に対する考察(理論通り/異なる,予想通り/異なる,など)
– 図や表を入れるとわかりやすいが,あまり凝り過ぎると,締め切りに間に合わなくなります.
1.1.4 MATLABの利用• この講義では,数値計算システムMATLAB
https://www.u-
tokyo.ac.jp/adm/dics/ja/matlabcwl.html
を用いて計算を行うことを前提とする(あとの注意も参照せよ).
• 現在,欧米の数値解析のテキストの例題は,ほとんどすべて,MATLABという数値計算システムを用いて作成されている.プログラム例も MATLAB で書かれている.すなわち,皆さんと同世代の欧米の大学生は,MATLAB
を用いて数値計算をしていると思って間違いない.• MATLABは,いわゆる「数式処理」ではない.高級プログラミング言語のような使い方ができる.
• 東京大学では,大学全体でライセンス契約をしているので,ECCS の端末だけでなく,皆さん自身の PC にインストールして使用したりオンラインで利用したりでき
2
る.詳しい使い方は,次の課題 2で説明する.
注意:MATLAB 以外のツールを用いて計算ができる人は,自分の使いたいものを使って計算しても良い.(使用したプログラミング言語やソフトウエアで,評価を変えることはありません.)
1.2 ITC-LMSの利用
本講義は,学習管理システム ITC-LMS(Information
Technology Center–Learning Management System)を用いて行う.Webブラウザで,
ITC-LMS
https://itc-lms.ecc.u-tokyo.ac.jp/
にアクセスし,ログインをする(ユーザ名とパスワードは ECCS
と同じ).
履修登録をしている人は,すでににコース登録がされている(はず).まだ,履修登録をするか迷っている人は,次のようにして,自分でコース登録をすること.後に履修登録をしなければ,(しかるべき時期に)自動的にコース登録も無効になる.
1. ITC-LMS 画面の上部にある『コース検索』をクリックして,『コース検索』画面に移る.
2.「コース名:計算数理演習」で検索をする.3. ‘‘0505134 計算数理演習’’,‘‘0505176 計算数理演習a’’,
‘‘08E1026 計算数理演習’’ が出てくるので,(自分の履修している)講義名あるいは代表 コース名(“0505134
計算数理演習”)をクリックして,講義画面に移る.4. 上部にある『受講登録』ボタンを押す(2回?).
■ ITC-LMSの機能
•「課題」· · · ここで課題の提出する.期限内にしか提出できない.
•「教材」· · · 参考資料を,ここで公開する.•「掲示板」の活用を歓迎する.何かの問題・困難を自分で解決した場合,あるいは質問して解決した場合に,それ
3
を掲示板に書き込んで,他の受講生と共有することを勧める.
•「履修者からのメッセージ」の活用も歓迎する.• マニュアルは,ITC-LMSの画面の上部の “Manual”にある.
1.3 Cloud LATEXの利用
• 上述のように演習のレポートは PDF形式のファイルで提出すること.(数学とは関係のないことなので)レポートを作成するソフトウエアは,なんでも良い.
• しかし,せっかくの機会なので,LATEXの利用を,強くすすめる.
• すでに,LaTeXを利用している人は,自分の使いやすい環境でレポートを作成して良い.
• 利用経験のない人には,Cloud LATEX https:
//cloudlatex.io/の利用をすすめる.• Cloud LATEX では,Web 上ですべての作業ができるので,インストールは不要で,自分の PCはもちろん,どんな場所ででも利用できる.
• 以下では,Cloud LATEXを用いてレポートを作成する手順を説明する.すでに LATEXを利用した経験があり,初歩的な説明が不要な人は 1.3 と 1.4 をとばして,直接,1.5 の第 1 回課題に進んで良い.繰り返すが,この方法を強制しているわけではない.LATEXの利用経験のある受講生は,自分の好きなやり方を使ってよい.
1.3.1 準備Cloud LATEXを使う前に,次の準備が必要である.
1. ITC-LMSの講義のページの『教材』のところにある “sin
関数のグラフ (sin.pdf)”をダウンロードしておく.2. メールアドレスを確認する.Cloud LaTeX を利用するには,メールアドレスが必要になる.ECCSの提供しているクラウドメール “なんとか@g.ecc.u-tokyo.ac.jp”の利用が好ましいが,個人で利用しているもの(Gmailなど)でも良い.スマホで利用しているものでも良い.使
4
い慣れていているものが良い.Cloud LATEX の登録と,メールアドレス確証,毎回のログイン ID に使うのみであり,教員や TAと,このメールアドレスを使って,連絡を取ることはない.
3. Cloud LATEX
https://cloudlatex.io/
で「新規登録」を押すと,図 1.1 のような画面になる.必要事項(“任意”のところは書く必要は無い)記入して「登録」を押すと,登録したメールアドレスにメールが届くので,「メールアドレスの認証」をクリックする.そうすると,Cloud LATEXが利用できるようになる.
図 1.1
1.3.2 ログイン以上の準備を終えてから,ログインする(→ 図 1.2).
1.3.3 新規プロジェクトの作成「新規プロジェクト」を選択し(→ 図 1.3),適当なプロジェクト名(例えば “kadai0”)をつける(→ 図 1.4).説明は書いても書かなくても良い(図 1.4では “練習”とした).
5
図 1.2
図 1.3
図 1.4
6
1.3.4 文書の作成kadai0 をクリックする(→ 図 1.5).その後,左段の
main.tex を選ぶと,図 1.6 のような画面が出てくる.この中央の段が文章を作成する部分,右段が仕上がりを確認する部分である.
図 1.5 kadai0の選択
図 1.6 Cloud LATEX の画面.左段がファイルの一覧,中央の段が文章を作成する部分,右段が仕上がりを確認する部分.
ここで,先ほど準備でダウンロードしていた “sin.pdf” をmain.texの下にコピーしておく(→ 図 1.7).ここまでを確認した上で,中央の段を,リスト 1.1のように書き換える(→ 図 1.6).全て消して書き直すのではなく,すでにあるものを修正したり,削除したりすると良い.バックスラッシュ \ が正しく入力できていることに注意せよ(→ 1.3.7).
1.3.5 文書のコンパイル入力が完了したら,上部の コンパイル を押す.右段が図 1.8
のようになったら,成功である.そうでなく,文章のプレビュー
7
図 1.7 “sin.pdf”のコピー
がでて来ずに,中央の段に図 1.9のようなエラーがでた場合には,そこに記述ミスがあるので,修正の上,コンパイル を押す.
リスト 1.1 文書作成の例\documentclass{jsarticle}
\usepackage[dvipdfmx]{graphicx}
\title{初めてのレポート}
\author{学生証番号XXXXXXX 数理太郎}
\date{\today}
\begin{document}
\maketitle
正弦関数$y = \sin x$は,$x$について解析的である.指数関数$e^x$を Taylor展開すると,\[ e^x = \sum_{n=0}^\infty \frac{x^n}{n!}\]
となる.
\begin{figure}
\centering
\includegraphics[width=.4\textwidth]{sin.pdf}
\caption{図の説明}
\label{fig:sin}
\end{figure}
図の参照は,図\ref{fig:sin}のようにする.\end{document}
1.3.6 PDFファイルのダウンロード最後に,作成した文書を PDFファイルとしてダウンロードする.上部の PDF を押す(→ 図 1.10)と,図 1.11のようになる.Safari(あるいは利用しているウェッブブラウザ)のメニューから,適当な名前をつけて保存すれば良い(→ 図 1.12).
8
図 1.8 文章のコンパイル
図 1.9 コンパイル時のエラー
図 1.10 PDFファイルの出力
1.3.7 【参考】キーボードの設定LATEXコマンドの入力には,バックスラッシュ \ を頻繁に使
う.したがって,自分の利用している環境で, \ を入力する方法を確認しておく必要がある.例えば,ECCS の Mac 環境で(デフォルトで)採用されている日本語環境(Google日本語環境)では, \ のキーは無く,
入力の際には, option + Y= を同時に押すことで, \ がでてくる.毎回こんなことをしていては手間がかかるので,初期設定を変えておく.
9
図 1.11 PDFファイルの表示
図 1.12 PDFファイルの保存
図 1.13のように,画面右上の A のマークにマウスを合わせて,「環境設定」を選ぶ.そうすると,図 1.14がでてくるので,“Y=で入力する文字” を “円記号 (Y=)” から “バックスラッシュ(\)”に変えておく.
図 1.13 Google日本語入力
10
図 1.14 Google日本語入力の初期設定の変更
1.4 LATEXのコマンドの勉強
『教材』のページにある,
「LATEXマニュアル」
という資料にざっと目を通して,どのようなことができるのかを確認する.すぐに使うわけではないが,いくつか例を試して訓練しておくと,後々レポート作成に役立つ(かも知れない).
1.5 課題 1
課題 1.1.
• 今学期に受講した数学の講義のノート(あるいは適当な数学の本)を LATEXを使って清書せよ.
• 分量は,1 ページ以上 2 ページ以内(すなわち,1 + α
ページ.ただし,0 < α ≤ 1とする).• 最終的な pdfファイルを,課題の答えとして,ITC-LMS
を通じて,期限までに提出せよ(期限は ITC-LMSに明示してある).
• 今回の課題は簡単なので,課題 1 の提出が終わり次第,次の課題(第 2回)に進むこと.
11
2020年 5月 1, 8日 (担当:齊藤宣一)
計算数理演習 第 2回課題 (数学科,統合自然科学科)
2 MATLABの使い方2.1 MATLABとは?
ウィキペディアでは次のように説明されている:
“MATLAB(マトラボ)は,アメリカ合衆国のMathWorks
社が開発している数値解析ソフトウェアであり,その中で使うプログラミング言語の名称でもある.MATLABは,行列計算,関数とデータの可視化,アルゴリズム開発,グラフィカルインターフェイスや,他言語 (C/C++/Java/Python)とのインターフェイスの機能を有している.MATLABは,主に,数値計算を扱う事ができるが,追加のオプション Symbolic Math Toolbox
を使うことで,数式処理の能力を得ることができる.2004 年で,MATLABは産業界,教育界において 100万人ユーザーを達成しており*4,工学,理学,経済学など幅広い業種で利用されている.(https://ja.wikipedia.org/wiki/MATLAB)”
参考 URLと参考書を挙げる:
• 東京大学向けの MATLAB ポータルサイト https://
www.u-tokyo.ac.jp/adm/dics/ja/matlabcwl.html
の『MATLAB入門』や『オンラインコース』• 桜井鉄也:MATLAB/Scilabで理解する数値計算,東京大学出版会,2003年(3,045円)
• A. Quarteroni, F. Saleri, P. Gervasio:Scientific Com-
puting with MATLAB and Octave, 4th edit., Springer,
2014(加古孝,千葉文浩訳,MATLABと Octaveによる科学技術計算,丸善出版,2014年)
*4 MathWorksのウェッブページの基本情報によれば,現在 300万人のようです (https://jp.mathworks.com/company/aboutus.html).
12
2.2 インストールあるいはオンラインでの利用
MATLABを自宅の環境から利用するには,UTokyo Account
を利用してMathWorksアカウントを取得する必要がある.初年次ゼミナール理科の
【授業 portal】https://fye.c.u-tokyo.ac.jp/students/
のページに,
『アカウントセットアップ手順詳細』https://www.sodan.ecc.u-tokyo.ac.jp/faq/
utokyo-matlab-cwl/
が記されているので,「アカウントセットアップ」までを必ず自分で行うこと.「Matlabのインストール」では,ダウンロードした上で,自分のコンピュータ上で利用する方法が述べられている.インストールには,かなり時間がかかる(したがって通信量もかかる)ので,インストールはせずに,オンラインで利用しても良い:
MATLAB Online
https://matlab.mathworks.com/
オンラインで利用する際にも,あらかじめ,“MathWorksアカウント”を取得しておく必要がある.なお,“科学の技法・東京大学「初年次ゼミナール理科」副読本 (2019年度版,2020年度版は??)”
https://fye.c.u-tokyo.ac.jp/students/
の「Step 4.1 MathWorksアカウントの取得とMATLABの利用」も参考になる.
2.3 MATLABの基礎
具体的に課題に進む前に,“急がば回れ” の精神で,『教材』にある,
「MATLAB超入門」
13
という資料を読んで,入力例をすべて自分で試して,同じ出力が得られることを確認すること.それから改めて,次項「はじめの例題」に進むこと.ただし,MATLABの利用に関しては,受講者によって前提とできる経験が大きく違うことが想定される.したがって,次項「はじめの例題」の内容,特にリスト 2.1–2.4を読んで,『だいたい解る』と思う人は,そのまま 2.5項「第 2回課題」に進んで良い.必要に応じて,『教材』 にある,「MATLAB超入門」を参照すると良い.
2.4 はじめの例題
次の問題を考えよう.� �円周率 π の近似値を計算せよ.� �いろいろなやり方があるが,半径が 1の円に内接する正 n角形の周長を pn,外接する正 n角形の周長を qn とするとき,
pn < 2π < qn
であることを利用しよう.ただし,n ≥ 3は整数である.n = 6
のときは,p6 は半径 1の円に内接する正 6角形の周長なので,p6 = 6となることはすぐにわかる.
πn
sin(
πn
)sin
(πn
)O
1
1
図 2.1 半径 1の円に内接する正 n角形
しばらくは,pn のみを考える.一般に,
pn = 2n sin(πn
)︸ ︷︷ ︸
=σn
= 2nσn
14
であるが,これを直接計算して pn を求めることは,π の値を使って π の値を求めることになり,本末転倒である.しかし,今の場合,σ2n が σn を用いて表現できるので,それを用いてp2n を計算しよう.実際,0 < α < π
2 の場合には,
sin(α2
)=
√1− cosα
2=
√1−
√1− sin2 α
2
が成り立つので,
σ2n = sin
(π/n
2
)=
√1−
√1− σ2
n
2
となる.すなわち,
p2n = 2(2n)σ2n = 2(2n)
√1−
√1− σ2
n
2
が得られる.一方で,σ6 = 1/2である.
リスト 2.1 comp pi1.mの中身
function res = comp_pi1
sig = 1/2; p = 6; n = 6; res=[];
while sig > 1e-10
sig = sqrt((1 - sqrt(1 - sig*sig))/2);
p = 4*n*sig;
n = 2*n;
res = [res;n,p,p/2-pi];
end
end
この考えに基づいて,pn (n = 6, 12, 24, . . .) を計算するMATLABプログラムがリスト 2.1である(これは,ITC-LMS
の『教材』にある kadai2.zipに含まれる).p = pn は 2π を近似する量なので,(MATLAB に組み込まれている)π の値と比較することで,近似の正確さを比較することができる.また,sig = σn → 0 (n → ∞) となるので,σn ≤ 10−10 となった段階で計算を終了する.また,このプロプラムでは,(n, pn, pn/2− π)の値を結果として出力する.実行結果をリスト 2.2に示す.良好な結果が得られているだろうか?
リスト 2.2 comp pi1.mの実行結果>> format shortE
>> comp_pi1
ans =
15
1.2000e+01 6.2117e+00 -3.5764e-02
2.4000e+01 6.2653e+00 -8.9640e-03
4.8000e+01 6.2787e+00 -2.2425e-03
9.6000e+01 6.2821e+00 -5.6070e-04
1.9200e+02 6.2829e+00 -1.4018e-04
3.8400e+02 6.2831e+00 -3.5046e-05
7.6800e+02 6.2832e+00 -8.7614e-06
1.5360e+03 6.2832e+00 -2.1904e-06
3.0720e+03 6.2832e+00 -5.4755e-07
6.1440e+03 6.2832e+00 -1.3700e-07
1.2288e+04 6.2832e+00 -3.4949e-08
2.4576e+04 6.2832e+00 -8.2686e-09
4.9152e+04 6.2832e+00 -8.2686e-09
9.8304e+04 6.2832e+00 -8.2686e-09
1.9661e+05 6.2832e+00 -8.2686e-09
3.9322e+05 6.2832e+00 1.0163e-06
7.8643e+05 6.2832e+00 -3.4978e-07
1.5729e+06 6.2832e+00 1.6043e-05
3.1457e+06 6.2832e+00 -5.8139e-06
6.2915e+06 6.2833e+00 8.1611e-05
1.2583e+07 6.2833e+00 8.1611e-05
2.5166e+07 6.2861e+00 1.4801e-03
5.0332e+07 6.3196e+00 1.8214e-02
1.0066e+08 6.3640e+00 4.0388e-02
2.0133e+08 6.7082e+00 2.1251e-01
4.0265e+08 8.4853e+00 1.1010e+00
8.0531e+08 1.2000e+01 2.8584e+00
1.6106e+09 0 -3.1416e+00
結果を検討してみる.n = 196608 ≈1.9661e+05 までは*5,誤差は順調に 0 に減衰しているが,n をそれ以上大きくしても,誤差は減衰せず(振動すらしている),n = 1610612736 ≈1.6106e+09に至っては,pn の値自体が 0
になってしまっている.このように期待する結果が得られない理由は,課題 2.1で考察してもらうが,ここでは,qn を併用することで,期待する近似値が得られることを先に示しておく.実際,幾何学的な考察により,(pn, qn)と (p2n, q2n)の間に,
q2n =2pnqnpn + qn
, p2n =√pnq2n
という関係が成り立つことがわける.q6 = 4√3 も簡単にわか
るので,この漸化式に基づいて,(pn, qn) (n = 6, 12, 24, . . .)を計算するMATLABプログラムはリスト 2.3のようになる.このプログラムでも,(n, pn/2, pn/2− π)の値を結果として出力
*5 表示スペースの都合で “>> format shortE ”としているが,皆さんが自分で計算する際には,“ >> format longE” とすることをすすめる.
16
する.qn − pn ≤ 10−10 となるまで計算を行う.今度は,誤差が順調に 0に減衰している.
リスト 2.3 comp pi2.mの中身
function res = comp_pi2
p=6; q=4*sqrt(3); n=6; diff=q-p; res=[];
while diff > 1e-10
q=2*p*q/(p+q); p=sqrt(p*q); diff=q-p;
n = 2*n;
res = [res;n,p/2,p/2-pi];
end
end
リスト 2.4 comp pi2.mの実行結果>> format shortE
>> comp_pi2
ans =
1.2000e+01 3.1058e+00 -3.5764e-02
2.4000e+01 3.1326e+00 -8.9640e-03
4.8000e+01 3.1394e+00 -2.2425e-03
9.6000e+01 3.1410e+00 -5.6070e-04
1.9200e+02 3.1415e+00 -1.4018e-04
3.8400e+02 3.1416e+00 -3.5046e-05
7.6800e+02 3.1416e+00 -8.7614e-06
1.5360e+03 3.1416e+00 -2.1904e-06
3.0720e+03 3.1416e+00 -5.4759e-07
6.1440e+03 3.1416e+00 -1.3690e-07
1.2288e+04 3.1416e+00 -3.4224e-08
2.4576e+04 3.1416e+00 -8.5561e-09
4.9152e+04 3.1416e+00 -2.1390e-09
9.8304e+04 3.1416e+00 -5.3476e-10
1.9661e+05 3.1416e+00 -1.3369e-10
3.9322e+05 3.1416e+00 -3.3423e-11
7.8643e+05 3.1416e+00 -8.3564e-12
なお,実際に π の近似値を得るためには,pn と qn を両方計算して,一致している桁を採用することになる.
2.5 課題 2
次の 2つの課題に取り組み,結果を LATEXを用いてレポートにまとめ,ITC-LMSを通じて,期限までに提出せよ(期限はITC-LMSに明示してある).
課題 2.1. 2.4 項「はじめの例題」で考察した π の近似値の計算方法(comp pi1.m)の問題点を考察せよ.そして,その考察
17
に基づいた回避策を考案せよ.さらに,それを計算するプログラム comp pi3.mを作成し,実行結果を検討せよ.[ヒント:計算数理 I・計算数理のガイダンスの際に紹介した現象が原因である.]
課題 2.2. 関数
f(x) =
1 (0 < x < π)
0 (x = −π, 0)
−1 (−π < x < 0)
の Fourier級数展開は,
f(x) =4
π
∞∑k=1
sin(2k − 1)x
2k − 1
となる.Fourier級数展開の収束の様子を図示せよ.具体的には,「MATLAB超入門」で説明した four1(x,n)の真似をして,関数 four2(x, n)を作れ.four_draw1(n, fun, m)
で,fun = @four2として,n = 5, 50のときの図を表示せよ.このとき,結果が four1.pdf に保存されるが,ファイル名をかえておかないと,上書きされてしまうので注意すること.また,four_draw2(fun, m) も実行して,Fourier 級数の収束の様子を観察せよ(このとき,プログラム中の n の数を増やしても良い).出力した結果の図 3 枚(four_draw1 で 2 枚,four_draw2で 1枚)を,課題への答えとして報告せよ.[ヒント:LATEXでの図の扱いは,「LATEXマニュアル」の §5
にある.また,計算結果と Fourier級数の収束に関する種々の定理を対応させて考察がされていると,大変良いレポートになる.]
18
2020年 5月 22, 29日 (担当:齊藤宣一)
計算数理演習 第 3回課題 (数学科,統合自然科学科)
3 非線形方程式の反復解法以下の説明で利用するプログラム集(kadai3.zip)は,ITC-
LMSの『教材』からダウンロードできる.
3.1 Newton法
微分可能な関数 f : R → Rに対して,方程式 f(a) = 0の解を計算することを考える.Newton法では,反復列 {xk}を,
xk+1 = xk − f(xk)
f ′(xk)(k ≥ 0) (1)
で生成する.ただし,x0 は初期値として与える.
リスト 3.1 newton1.mの中身
% Newton Method
function [xv,fx,inc,k]=newton1(fun,dfun,kmax,tol,ig)
% vectors
xv=[]; fx=[]; inc=[];
% initial settings
x=ig; k=0; dif=tol+1; inc=[inc;0];
xv=[xv;x]; f=fun(x); fx=[fx;f];
% Newton iteration
while k<kmax && dif>tol
df=dfun(x);
if abs(df)<1.0e-15
disp(’df/dx=0’); break;
end
xnew=x-f/df; dif=abs(xnew-x); x=xnew; k=k+1;
xv=[xv;x]; f=fun(x); fx=[fx;f]; inc=[inc;dif];
end
end
リスト 3.1 は,fun, dfun, kmax, tol, ig をデータとして入力すると,3つのベクトル xv, fx, inc, kを結果として出力する.ここで,
fuc = f(x), dfuc = f ′(x)
であり,これらは予め定義しておくか,文字列として入力しなければならない.kmax = kmax は最大反復回数,tol = εは許
19
容誤差限界 (error tolerance),ig = x0 は初期値 (initial guess)
である.また,
xv =
x0
x1
...xk+1
, fx =
f(x0)f(x1)
...f(xk+1)
の意味である.さらに,増分(increment)
dif = ∆xk+1 = |xk+1 − xk| =∣∣∣∣ f(xk)
f ′(xk)
∣∣∣∣に着目し,
∆xk+1 ≤ ε
となったら,値がこれ以上更新されないと判断して,計算を終了する.その際,
inc =
∆x0
∆x1
∆x2
...∆xk+1
の値も出力する(∆x0 = 0としておく).ただし,この xk+1 をaの近似値として採用する際には,念のため,一緒に出力されている ∆xk+1 や f(xk+1)の値(と変化の様子)も確認した方が良い.なお,計算は,反復回数が kmax を超えたときと,f ′(xk)の値が |f(xk)| ≤ 10−15 となった際にも(f ′(xk) ≈ 0 と判断して)終了することにする.例題として,関数
f(x) = ex − 2x2 (2)
を取り上げよう.図 3.1により(あるいは関数の増減を調べることにより),方程式 f(x) = 0には 3つの解 a1 < a2 < a3 が存在することがわかる.さらに,図 3.1から,−0.7 < a1 < 0.3,1.3 < a2 < 1.7,2.5 < a3 < 3がわかる.このことは,初期値を選ぶ際の,重要な情報である.それでは,a1を計算してみよう.f(x) = ex−2x2と f ′(x) =
ex − 4xを,それぞれ,func31.m,dfunc31.mという名前で作成しておく(→ リスト 3.2と 3.3).
20
図 3.1 y = ex − 2x2 のグラフ.
リスト 3.2 func31.m
function [y]=func31(x)
y = exp(x) - 2 * x .^ 2;
end
リスト 3.3 dfunc31.m
function [y]=dfunc31(x)
y = exp(x) - 4*x;
end
初期値 x0 = −1として計算すると,次のような出力が得られる.ただし,なるべく多くの桁を観察するため,format long
で表示桁数を増やしておく.
リスト 3.4 newton1.m,func31.m, dfunc31.mの実行結果>> format long
>> [xv,fx,inc,k]=newton1(@func31,@dfunc31,10,1e-12,-1)
xv =
-1.000000000000000
-0.626335712601346
-0.544080790288722
-0.539846453645710
-0.539835276980653
-0.539835276902820
-0.539835276902820
fx =
-1.632120558828558
-0.250045899400802
-0.011672788141587
-0.000030648914159
-0.000000000213432
0
0
inc =
21
0
0.373664287398654
0.082254922312624
0.004234336643013
0.000011176665057
0.000000000077833
0
k =
6
これより*6,a1 の近似値として,
a1 ≈ −0.5398352769
が採用できることがわかる.もっと正確な近似値が欲しい場合には,tol の値を,例えば 1e-15などとすれば良い.なお,実際には,別の初期値 x0(で a1に収束するもの)も用いて結果を確かめておくべきである.もちろん,初期値を変えれば得られる解は変わるし,反復列が収束しない場合もあり得る.これについては,講義で説明した命題を基に,ある程度の “見積もり”を得ることはできる.すなわち,例えば a1 を計算する際には,a1 を含むような閉区間 J で,g(x) = x− f(x)/f ′(x)に対して |g′(x)| < 1 (x ∈ J)となるものを探しておいて,x0 ∈ J
とすれば良いのである.
3.2 収束の速さ
次に収束の速さについて考察する.講義で説明したように,f(a) = 0かつ f ′(a) ̸= 0ならば,Newton法は aに 2次収束する.これを実験的に確かめよう.そのために,リスト 3.5に示す newton2.mを使う.このプログラムでは,方程式 f(a) = 0の解 a(= sol)(の存在と)数値は既知であるとして,
ek = |xk − a|, yk+1 =ek+1
ek, zk+1 =
ek+1
e2k
を観察する.講義で説明した命題により,zk が有界に留まれば(このとき yk → 0のはず),2次収束が実験的に確認できることになる.一方で,yk が区間 (0, 1)内に留まれば,この反復列は線形収束している (講義では説明していないが,演習問題にしている).
*6 kとして出力される値が k + 1を意味する.
22
なお,リスト 3.5において,
err =
e0e1...
ek+1
, yv =
y0y1...
yk+1
, zv =
z0z1...
zk+1
であり,err(end)は,ベクトル errの最後の成分(すなわち上の表記で err(end)= ek+1)を表す.また,tol= 10−7 はこれ以上小さくはできない.というのも,例えば,tol= 10−8 とすると,ek ≈ 10−8 の際 e2k ≈ 10−16 となってしまい,この値は計算機イプシロンと同程度である.結果,zk+1 の計算で “零割”が発生してしまう.
リスト 3.5 newton2.m
% Newton Method--convergence rate
% Exact solution (sol) of equation is assumed to be
known
function [xv,err,yv,zv,k]=newton2(fun,dfun,sol,ig)
% preliminaries
kmax = 50; tol = 1.0e-7;
xv=[]; err=[]; yv=[]; zv=[];
% Newton iteration
x=ig; k=0; err=[err;abs(x-sol)];
yv=[yv;0]; zv=[zv;0]; xv=[xv;x];
while k<kmax && err(end)>tol
f=fun(x); df=dfun(x);
if abs(df)<1e-15
disp(’df/dx=0’); break;
end
xnew=x-f/df; x=xnew; xv=[xv;x];
err=[err;abs(x-sol)]; k=k+1;
y=err(end)/err(end-1); yv=[yv;y];
z=err(end)/(err(end-1)^2); zv=[zv;z];
end
end
newton1.m で tol = 1e-16 と し て ,近 似 値 a1 =
−0.539835276902820を求めておき,これを使う.
リスト 3.6 newton2.m,func31.m, dfunc31.mの実行結果>> [xv,err,yv,zv,k]=newton2(@func31,@dfunc31,
-0.539835276902820,-1)
xv =
-1.000000000000000
-0.626335712601346
-0.544080790288722
-0.539846453645710
-0.539835276980653
23
err =
0.460164723097180
0.086500435698526
0.004245513385902
0.000011176742890
0.000000000077833
yv =
0
0.187977112013992
0.049080832386774
0.002632601024591
0.000006963832224
zv =
0
0.408499614548449
0.567405608890017
0.620090148186236
0.623064545104923
k =
4
予想された挙動が観察できたので,xk → a1 は 2次収束であることが確認できた.
3.3 重解 (f ′(a)=0)の場合
例題として関数
f(x) = x3 − x2 − 8x+ 12 = (x− 2)2(x+ 3)
と方程式 f(x) = 0 を考える.特に,a = 2 を Newton 法で求めてみる.このとき,反復列が線形収束することは保証されているが,f ′(a) = 0なので,2次収束は保証されない.
リスト 3.7 func32.m
function [y]=func32(x)
y = x.^3 - x.^2 - 8*x + 12;
end
リスト 3.8 dfunc32.m
function [y]=dfunc32(x)
y = 3*x.^2 - 2*x - 8;
end
リスト 3.9 newton1.m, func32.m, dfunc32.mの実行結果>> [xv,fx,inc,k]=newton1(@func32,@dfunc32,50,1e-12,-1)
xv =
24
-1.000000000000000
5.000000000000000
3.736842105263158
...(略)...
2.000000032616468
2.000000010831684
2.000000010831684
fx =
18.000000000000000
72.000000000000000
20.322495990669193
...(略)...
0.000000000000007
0
0
inc =
0
6.000000000000000
1.263157894736842
0.769258787106174
...(略)...
0.000000036159451
0.000000021784785
0
k =
30
このようになり,近似値が求まるが,先の例と比較すると,反復回数が多くなっている.実際,収束の速さを調べると.
リスト 3.10 newton2.m, func32.m, dfunc32.mの実行結果>> [xv,err,yv,zv,k]=newton2(@func32,@dfunc32,2,-1)
xv =
-1.000000000000000
5.000000000000000
3.736842105263158
........
2.000000273071422
2.000000136464338
2.000000068775920
err =
3.000000000000000
3.000000000000000
1.736842105263158
........
0.000000273071422
0.000000136464338
0.000000068775920
yv =
0
1.000000000000000
0.578947368421053
........
25
0.500111448250154
0.499738629157594
0.503984561885280
zv =
1.0e+06 *
0
0.000000333333333
0.000000192982456
........
0.915919574861420
1.830065649659247
3.693159466274046
k =
27
yk は有界に留まっているが,zk は 3.69× 106 程度まで増大しているので,この収束は線形収束であるが,2次収束ではないことが,実験的に観察できる(正確には,“予想ができる”だけであるが).
3.4 多変数の Newton法
2変数の連立方程式
f(x, y) = 0, g(x, y) = 0
の解 a =
(a
b
)を求めるために,
xk+1 = xk − [Df(xk)]−1f(xk)
で点列 xk を生成する方法を 2変数の Newton法と言う*7.ただし,
xk =
(xk
yk
), f(xk) =
(f(xk)g(xk)
),
Df(xk) =
(fx(x, y) fy(x, y)gx(x, y) gy(x, y)
)としている.Df(xk)
−1f(xk) の部分の計算は,逆行列Df(xk)
−1 を具体的に構成し f(xk) との積を計算するのではなく,連立一次方程式
[Df(xk)]w = f(xk)
を解いて,w を求めれば良い.
*7 講義では点列を x(k) のように書いた.
26
リスト 3.11 は,2 変数の Newton 法を実行するプログラムである.f = fun(x) = f(xk),df = dfun(x) = Df(xk),かつ,
w = df \ f
である.
リスト 3.11 newton multi.m
function [xv,fx,inc,k]=newton_multi(fun,dfun,kmax,tol,
xig)
% preliminaries
xv=[]; fx=[]; inc=[]; x=xig; k=0; dif=tol+1;
xv=[xv;x’]; f=fun(x); fx=[fx;f’];
% Newton iteration
while k<kmax && dif>tol
df=dfun(x);
if rcond(df)<1e-15
error(’df/dx is singular’);
end
xnew=x-df\f; dif=norm(xnew-x,inf);
x=xnew; k=k+1; xv=[xv;x’];
f=fun(x); fx=[fx;f’]; inc=[inc;dif];
end
end
リスト 3.12 func35.m
function [y] = func35(x)
y = [x(1).^2 + x(2).^2 - 1; sin(pi*x(1)/2)+x(2).^3];
end
リスト 3.13 dfunc35.m
function [J]=dfunc35(x)
J = zeros(2,2); pi2 = 0.5*pi;
J(1,1) = 2*x(1); J(1,2) = 2*x(2);
J(2,1) = pi2*cos(pi2*x(1)); J(2,2) = 3*x(2)^2;
end
例題として連立方程式
f(x, y) = x2 + y2 − 1 = 0,
g(x, y) = sin(πx
2
)+ y3 = 0
を考えよう.図 3.2に示した概形から,方程式は x < 0,x > 0
の範囲にそれぞれ一つずつ解を持つ.初期値を (−1, 3)として newton multi.mを実行した結果を,リスト 3.14に示す.9回の反復で近似点列が ∥xk−a∥ ≤ 10−12
27
を満たし,結果として,
xk =
(−0.4760958225375550.879393408982743
)が近似解として採用できることがわかる(これは左上の解である).
x
y
x2 + y2 = 1
sin(π2 x) + y3 = 0
図 3.2 f(x, y) = x2 + y2 − 1 = 0と g(x, y) = sin(πx2
)+ y3 = 0
リスト 3.14 newton multi.m, func35.m, dfunc35.mの実行結果>> [xv,fx,inc,k] = newton_multi(@func35,@dfunc35,30,1e
-12,[-1;3])
xv =
-1.000000000000000 3.000000000000000
0.611111111111111 2.037037037037037
0.084298839204560 1.330350078878363
-0.682637981687283 1.086942772239160
-0.464388543455896 0.926185232351480
-0.474932917929831 0.881232465659848
-0.476094241088657 0.879396947572791
-0.476095822531193 0.879393408994728
-0.476095822537555 0.879393408982743
-0.476095822537555 0.879393408982743
fx =
9.000000000000000 26.000000000000000
3.522976680384089 9.271877746671759
0.776937626662902 2.486524932393973
0.647439204165037 0.405867248922834
0.073475803919055 0.128032360082282
0.002131935066279 0.005615911642756
0.000004717798127 0.000010030808405
0.000000000015022 0.000000000035132
0 0
0 0
inc =
28
1.611111111111111
0.706686958158675
0.766936820891843
0.218249438231387
0.044952766691633
0.001835518087057
0.000003538578063
0.000000000011985
0
k =
9
リスト 3.15 に,近似点列 xk を可視化するプログラムを示す*8.計算結果を図 3.3に示す.
リスト 3.15 newton plot2D.m
function [xv,fx,inc,k] = newton_plot2D(fun,dfun,xig)
% implementation of Newton iteration
kmax = 100; tol = 1.0e-15;
[xv,fx,inc,k] = newton_multi(fun,dfun,kmax,tol,xig);
% drawing results
xvv=circshift(xv,-1); xvv(end,:)=xv(end,:); figure(1);
hold on;
quiver(xv(:,1),xv(:,2), xvv(:,1)-xv(:,1), xvv(:,2)-xv
(:,2), 0,’b’,’LineWidth’,3,’MaxHeadSize’,0.1);
% initial point
plot(xig(1), xig(2),’o’,’MarkerEdgeColor’,’b’,’
MarkerFaceColor’,’b’,’MarkerSize’,10);
% final point
plot(xv(end,1), xv(end,2),’h’,’MarkerEdgeColor’,’r’,’
MarkerFaceColor’,’r’,’MarkerSize’,10);
% decoration
grid on;axis equal;xlabel("x"); ylabel("y");
saveas(1,’newton_plot2D.pdf’);
end
いろいろな初期値で newton plot2D.mを試して,近似点列の収束の様子を観察せよ.
3.5 課題 3
以下の課題に取り組み,レポートを ITC-LMSを通じて,期限までに提出せよ(期限は ITC-LMS に明示してある).以下の課題 3.1,3.2,3.3は必修とする.必ず取り組むこと.
*8 いろいろな技巧が応用されているので,細かい説明はしません.興味のある人は解読してください.そして,もっとセンスの良いプログラムを作ったら教えてください.
29
図 3.3 newton plot2D.m, func35.m, dfunc35.m の実行結果.左:初期値 (−1, 3),右:初期値 (5,−2).
課題 3.1. 方程式 f(x) = ex−2x2 = 0について,−2 ≤ x0 ≤ 10
の範囲の初期値を,収束先の値や,発散・振動などで分類せよ.すなわち,“x0 ∈ J1 ⇒ xk → a1”,“x0 ∈ J∞ ⇒ xk → ±∞”
となるような区間 J1, J2, J3, J∞ などを実験的に求めよ.ただし,区間 −2 ≤ x ≤ 10を “隙間無く”分割しなくても良い.例えば,a1 を含むような小さな区間で良い.
課題 3.2. 簡易 Newton法
xk+1 = xk − f(xk)
f ′(x0)(k ≥ 0) (3)
を実行するプログラム newton3.m とその収束の速さを調べるプログラム newton4.mを作成せよ.newton1.mと newton2.m
からの変更点は,共に,
df=dfunc(x) → df = dfunc(ig)
とすれば良いのみである.その上で,課題 3.1と同様の考察を行って,さらに,Newton法の場合と収束の速さを比較せよ.
課題 3.3. mをあらかじめ定めておくパラメータとして,反復列を
xk+1 = xk −mf(xk)
f ′(xk)(k ≥ 0) (4)
で生成する方法を修正 Newton 法と言う.これを実行するプログラム newton5.m とその収束の速さを調べるプログラムnewton6.mを作成せよ.newton1.mと newton2.mからの変更点は,共に,
newton1(...,ig) → newton5(...,ig,m),
x-f/df → x-m*f/df
30
などとすれば良いのみである.その上で,方程式 f(x) = x3 −x2 − 8x+12 = 0の重根 a = 2を求める際に,修正 Newton法の反復列が a = 2に 2次収束するようなmを実験的に求めよ.
31
2020年 5月 29日 (担当:齊藤宣一)
計算数理演習 第 2回課題へのコメント(数学科,統合自然科学科)
課題 2へのコメント課題 2.1へのコメント
半径 1の円に内接する正 n角形の周長
pn = 2n sin(πn
)= 2nσn
(σn = sin
(πn
))を,
σ6 =1
2, σ2n = sin
(π/n
2
)=
√1−
√1− σ2
n
2
を用いて,
p2n = 2(2n)σ2n = 2(2n)
√1−
√1− σ2
n
2
で計算した.σn → 0 (n → ∞)なので,nが十分に大きい時には,1−σ2
n ≈1となり,1−
√1− σ2
n の計算で桁落ちが起こる.この影響で,最後は,p2n ≈ 0となってしまう.回避策としては,値の近い数の減算 1−
√1− σ2
n が現れないように式を変形して計算しすれば良いであろう.例えば,
σ2n =
√1−
√1− σ2
n
2·
√1−
√1 + σ2
n
1 +√1− σ2
n
=σn√
2(1 +√
1− σ2n)
と変形してから計算する.これを行うMATLABプログラムがリスト 3.16(comp pi3.m),実行結果がリスト 3.17である.
リスト 3.16 comp pi3.mの中身
function res = comp_pi3
sig = 1/2; p = 6; n = 6; res=[];
while sig > 1e-10
sig = sig / sqrt(2*(1 + sqrt(1 - sig*sig)));
p = 4*n*sig; n = 2*n;
32
res = [res;n,p,p/2-pi];
end
end
リスト 3.17 comp pi3.mの実行結果>> format shortE
>> comp_pi3
ans =
1.2000e+01 6.2117e+00 -3.5764e-02
2.4000e+01 6.2653e+00 -8.9640e-03
4.8000e+01 6.2787e+00 -2.2425e-03
.......
9.8304e+04 6.2832e+00 -5.3476e-10
1.9661e+05 6.2832e+00 -1.3369e-10
3.9322e+05 6.2832e+00 -3.3423e-11
7.8643e+05 6.2832e+00 -8.3560e-12
1.5729e+06 6.2832e+00 -2.0899e-12
3.1457e+06 6.2832e+00 -5.2314e-13
6.2915e+06 6.2832e+00 -1.3145e-13
1.2583e+07 6.2832e+00 -3.3751e-14
2.5166e+07 6.2832e+00 -8.8818e-15
5.0332e+07 6.2832e+00 -2.6645e-15
1.0066e+08 6.2832e+00 -8.8818e-16
2.0133e+08 6.2832e+00 0
4.0265e+08 6.2832e+00 0
........
課題 2.2へのコメント
問題は,階段関数
f(x) =
1 (0 < x < π)
0 (x = −π, 0)
−1 (−π < x < 0)
の Fourier級数展開
f(x) =4
π
∞∑k=1
sin(2k − 1)x
2k − 1
の部分和
fN (x) =4
π
N∑k=1
sin(2k − 1)x
2k − 1
について,
• f5(x)と f50(x)の図を表示せよ,
33
• fN → f (N → ∞)の様子を観察せよ,
というものであった.さて,多くの人のレポートでは図 3.4のようなグラフが描画されていた.一方で,図 3.5のようなグラフを描画している人も少なからず居た.この 4 つの図を良く見比べて欲しい.実は,図 3.4(右)は不正確なグラフである.Fourier級数の一般論により,−π ≤ x ≤ π を固定すると,
fN (x) → f(x− 0) + f(x+ 0)
2(N → ∞)
となる.xが連続点ならば,fN (x) → f(x)となるが,不連続点の場合には,その近傍で振動を生ずる.これを Gibbs の現象と言うのであった.*9
このことを心にとどめた上で,再度,図 3.4(右)と図 3.5(右)
を比較してみる.この 2つの違いは明確である.すなわち,図3.5(右)で確認される不連続点のまわりでの振動現象(Gibbsの現象)が,図 3.4(右) では観察できない.Gibbs の現象は,元の関数の不連続性が原因であって,N を大きくしたからといって,解消されるわけではない.すなわち,図 3.4(右) は不正確である.
図 3.4 (左) f5(x) (m = 100),(右) f50(x) (m = 100)
この原因は,描画の際に設定したパラメータの不備にある.すなわち,関数のグラフを描画する際には,自然数 m を(ユーザが勝手に)選んで,区間 [− 3
2π,32π]
を m − 1 等分して分点 x0, . . . , xm を作る(これを,linspace(-1.5*%pi, 1.5*%pi, m)’が行う).すなわち,
h =3π
m
*9 もし,f(x) が滑らかな周期関数であれば,fN は f に一様収束するが,いまは,f は不連続なので,この定理は使えない.
34
図 3.5 (左) f5(x) (m = 400),(右) f50(x) (m = 400)
として,分点
xi = −3
2π + ih (n = 0, . . . ,m)
をつくる.そして,これを,(xi, f(xi))と (xi+1, f(xi+1))を順に線分で結んで,曲線(本当は折れ線)を描画するのであった.図 3.5 では,m = 400 としているが,図 3.4 は,m = 100 としている.すなわち,m = 100では,分割の大きさが適切でなく,あたかも,振動がおとなしいようなグラフを描画していまうのである.このような場合には,分割数を適切にとらなければならないことが分かったが,どれくらいが “適切” なのかは,事前にわかる訳ではない.とはいえ,今の場合は,mは描画のためのパラメータであるから,“適当に大きくとる”のが良いであろう.すなわち,mを順に大きくして,複数の図を描き,結果に違いがでないのを確認するのが良い(図 3.6–3.8).なお,この問題から得られる教訓は次のようなものである:
教訓� �元の問題には現れない,計算のために導入したパラメータは,一見,計算がうまく行っているように見えても,複数の組み合わせで試して,結果に違いが出ないかを確認するべきである.� �
35
図 3.6 f50(x) (m = 250)
図 3.7 f50(x) (m = 300)
図 3.8 f50(x) (m = 350)
36
2020年 6月 5, 12日 (担当:齊藤宣一) 計算数理演習 第 4回課題 (数学科,統合自然科学科)
4 固有値問題A ∈ Cn×n に対する固有値問題
λ ∈ C, 0 ̸= v ∈ Cn, Av = λv
を考察する.以下の説明で利用するプログラム集(kadai4.zip)は,ITC-
LMSの『教材』からダウンロードできる.
4.1 冪乗法
x(0) ∈ Cn を初期値として,次のように点列 x(k) (k =
1, 2, . . .)を生成する:
y(k) = Ax(k), x(k+1) =1
∥y(k)∥2y(k).
このとき,(A に対する適切な仮定の下で)十分大きな k に対して,x(k) は,絶対値最大の固有値の固有ベクトルの近似を与える.さらに,絶対値最大の固有値の近似は,Rayleigh 商を使って,
µk = RA(x(k))
def.=
⟨Ax(k),x(k)⟩∥x(k)∥22
で与えられる.例題として,
A =
5 4 1 14 5 1 11 1 4 21 1 2 4
(5)
を考える.絶対値最大の固有値と正規化された固有ベクトルは,
λ4 = 10, v4 =
2/√10
2/√10
1/√10
1/√10
≈
0.63250.63250.31620.3162
37
となる.*10
冪乗法を試す前に,MATLABコマンドを使って,固有値と固有ベクトルを計算しておく.*11
リスト 4.1 MATLABコマンドを使った固有値と固有ベクトル>> A=[5 4 1 1; 4 5 1 1; 1 1 4 2; 1 1 2 4];
>> eig(A)
ans =
1.0000
2.0000
5.0000
10.0000
>> [V,D] = eig(A)
V =
0.7071 0.0000 -0.3162 0.6325
-0.7071 0.0000 -0.3162 0.6325
-0.0000 -0.7071 0.6325 0.3162
0 0.7071 0.6325 0.3162
D =
1.0000 0 0 0
0 2.0000 0 0
0 0 5.0000 0
0 0 0 10.0000
冪乗法(power method)のプログラムの例をリスト4.2 (power1.m) に示す.このプログラムでは,与えられたtol(=tolerance 許容)に対して,
incdef.=
∣∣∣∣µk − µk−1
µk
∣∣∣∣ ≤ tol
が満たされた時点で,これ以上反復を続けても数値が改善されないと判断して,計算を終了する(inc=increment 増分).
リスト 4.2 power1.m
function [ev, evec] = power1(A, init, tol)
kmax=100; ev = []; evec = [];
k=0; x = init / norm(init); muold = 0; inc = tol+1;
while (k<=kmax && inc >= tol)
y=A*x; mu=dot(y, x); inc=abs((mu-muold)/mu);
ev=[ev;k,mu,inc]; evec=[evec; x’]; x=y/norm(y);
muold=mu; k=k+1;
end
end
*10 答えがわかっているのだから,近似計算をする必要はないが,ここでの目標は,冪乗法が妥当な方法であることを確認することである.したがって,あえて,答えのわかっている問題で試すのである.
*11 前の脚注と同じ注意を心に留めること.近似値がわかればそれで良い,ということではない.
38
power1.mの実行例をリスト 4.3に示す.initは初期ベクトル x(0) である.また,ev(= eigen value 固有値)は� �
0 µ0 inc...
k µk inc� �を出力する.また,evec(= eigen vecor 固有ベクトル)は,µk に対応する固有ベクトル x(k) の各成分 (xk,1, . . . , xk,4)
T を出力する.� �
x0,1, . . . , x0,4
...
xk,1, . . . , xk,4� �リスト 4.3 power1.mを使った Aの絶対値最大の固有値の計算
>> A=[5 4 1 1; 4 5 1 1; 1 1 4 2; 1 1 2 4];
>> [ev, evec] = power1(A, [1 0 0 0]’, 1e-8)
ev =
0 5.0000 1.0000
1.0000 9.6047 0.4794
... 略 ...
11.0000 10.0000 0.0000
12.0000 10.0000 0.0000
13.0000 10.0000 0.0000
evec =
1.0000 0 0 0
0.7625 0.6100 0.1525 0.1525
... 略 ...
0.6325 0.6325 0.3161 0.3161
0.6325 0.6325 0.3162 0.3162
0.6325 0.6325 0.3162 0.3162
>> [ev, evec] = power1(A, [1 1 1 1]’, 1e-8)
ev =
0 9.5000 1.0000
1.0000 9.8649 0.0370
2.0000 9.9655 0.0101
... 略 ...
10.0000 10.0000 0.0000
11.0000 10.0000 0.0000
12.0000 10.0000 0.0000
evec =
0.5000 0.5000 0.5000 0.5000
0.5719 0.5719 0.4159 0.4159
0.6040 0.6040 0.3677 0.3677
... 略 ...
39
0.6324 0.6324 0.3164 0.3164
0.6324 0.6324 0.3163 0.3163
0.6324 0.6324 0.3163 0.3163
>> [ev, evec] = power1(A, [2 2 1 1]’, 1e-8)
ev =
0 10 1
1 10 0
一方で,リスト 4.4に示したように,初期ベクトルを x(0) =
(1, 2, 3,−9)Tと選ぶと,近似固有値として λ3 = 5が得られている.これは,⟨v4,x
(0)⟩ = 0,すなわち,x(0) ∈ span{v1,v2,v3}となっており,冪乗法の収束に関する定理*12の仮定が満たされていないためであり,定理とは矛盾しない.実際,x(0) を少しだけずらして,x(0) = (1.1, 2, 3,−9)T とすると,正しくλ4 = 10が得られる (リスト 4.4).
リスト 4.4 power1.mを使った Aの絶対値最大の固有値の計算>> [ev, evec] = power1(A, [1 2 3 -9]’, 1e-8)
ev =
0 2.7053 1.0000
1.0000 3.9824 0.3207
2.0000 4.7727 0.1656
... 略 ...
10.0000 5.0000 0.0000
11.0000 5.0000 0.0000
12.0000 5.0000 0.0000
evec =
0.1026 0.2052 0.3078 -0.9234
0.2400 0.2742 -0.1028 -0.9255
0.3000 0.3081 -0.4135 -0.8026
... 略 ...
0.3162 0.3162 -0.6323 -0.6326
0.3162 0.3162 -0.6324 -0.6325
0.3162 0.3162 -0.6324 -0.6325
>> [ev, evec] = power1(A, [1.1 2 3 -9]’, 1e-8)
ev =
0 2.7145 1.0000
1.0000 3.9944 0.3204
2.0000 4.7891 0.1659
... 略 ...
18.0000 10.0000 0.0000
19.0000 10.0000 0.0000
20.0000 10.0000 0.0000
evec =
0.1127 0.2050 0.3075 -0.9224
0.2559 0.2866 -0.0990 -0.9179
*12 講義ノート §3, 定理 3.5を見よ.
40
0.3323 0.3396 -0.3983 -0.7846
... 略 ...
0.6325 0.6325 0.3160 0.3160
0.6325 0.6325 0.3161 0.3161
0.6325 0.6325 0.3162 0.3162
4.2 逆冪乗法
求めたい固有値 λ の近くの α ∈ C を選び,反復列を次で生成する:
y(k) = (A− αI)−1x(k), x(k+1) =1
∥y(k)∥y(k)
なお,y(k) は,連立一次方程式
(A− αI)y(k) = x(k)
を解いて求める.近似固有値は,次で得られる:
µk =1
RA(x(k))+ α.
逆冪乗法(inverse power method)のプログラム例をリスト4.5(invpower1.m)に示す.
リスト 4.5 invpower1.m
function [ev, evec] = invpower1(A, init, alpha, tol)
kmax=100; ev = []; evec = [];
B = A - alpha*eye(size(A));
k=0; x = init / norm(init); muold = 0; inc = tol+1;
while (k<=kmax && inc >= tol)
y = B\x; mu=dot(y, x); inc=abs((mu-muold)/mu);
ev=[ev;k,1/mu+alpha,inc]; evec=[evec; x’];
x=y/norm(y); muold = mu; k=k+1;
end
end
α = 0 とすると絶対値最小の固有値が求められる (リスト4.6).
リスト 4.6 invpower1.mを使った Aの絶対値最小の固有値の計算>> [ev, evec] = invpower1(A, [1 0 0 0]’, 0, 1e-8)
ev =
0 1.7857 1.0000
1.0000 1.0136 0.4324
2.0000 1.0003 0.0131
3.0000 1.0000 0.0003
4.0000 1.0000 0.0000
41
5.0000 1.0000 0.0000
6.0000 1.0000 0.0000
7.0000 1.0000 0.0000
evec =
1.0000 0 0 0
0.7857 -0.6173 -0.0281 -0.0281
0.7183 -0.6957 -0.0085 -0.0085
0.7088 -0.7054 -0.0020 -0.0020
0.7074 -0.7068 -0.0004 -0.0004
0.7072 -0.7071 -0.0001 -0.0001
0.7071 -0.7071 -0.0000 -0.0000
0.7071 -0.7071 -0.0000 -0.0000
α を変化させると,いろいろな固有値が求められる (リスト4.7).ただし,固有ベクトルの取り方次第では,予期せぬ固有値を求めることがある.
リスト 4.7 invpower1.mを使った Aの固有値の計算>> [ev, evec] = invpower1(A, [1 1 1 1]’, 1.7, 1e-8)
ev =
0 8.9079 1.0000
1.0000 6.8064 0.2915
2.0000 5.4104 0.2734
...略 ...
19.0000 2.0000 0.0000
20.0000 2.0000 0.0000
21.0000 2.0000 0.0000
evec =
0.5000 0.5000 0.5000 0.5000
0.2815 0.2815 0.6487 0.6487
-0.0147 -0.0147 0.7070 0.7070
...略 ...
-0.0001 -0.0001 -0.7069 0.7073
-0.0000 -0.0000 -0.7071 0.7071
-0.0000 -0.0000 -0.7071 0.7071
>> [ev, evec] = invpower1(A, [1 0 0 0]’, 1.7, 1e-8)
ev =
0 0.1272 1.0000
1.0000 0.9880 0.5473
2.0000 0.9996 0.0163
3.0000 1.0000 0.0005
4.0000 1.0000 0.0000
5.0000 1.0000 0.0000
6.0000 1.0000 0.0000
7.0000 1.0000 0.0000
evec =
1.0000 0 0 0
-0.6248 0.7791 -0.0359 -0.0359
0.7173 -0.6966 -0.0107 -0.0107
-0.7054 0.7088 -0.0025 -0.0025
0.7074 -0.7068 -0.0006 -0.0006
42
-0.7070 0.7072 -0.0001 -0.0001
0.7071 -0.7071 -0.0000 -0.0000
-0.7071 0.7071 -0.0000 -0.0000
>> [ev, evec] = invpower1(A, [1 1 1 1]’, 5.7, 1e-8)
ev =
0 20.7500 1.0000
1.0000 4.7980 1.0599
2.0000 4.9948 0.2182
3.0000 4.9999 0.0071
4.0000 5.0000 0.0002
5.0000 5.0000 0.0000
6.0000 5.0000 0.0000
7.0000 5.0000 0.0000
evec =
0.5000 0.5000 0.5000 0.5000
0.5617 0.5617 -0.4295 -0.4295
-0.2651 -0.2651 0.6555 0.6555
0.3244 0.3244 -0.6283 -0.6283
-0.3149 -0.3149 0.6331 0.6331
0.3164 0.3164 -0.6323 -0.6323
-0.3162 -0.3162 0.6325 0.6325
0.3162 0.3162 -0.6325 -0.6325
逆冪乗法を利用するにあたり,固有値の存在範囲についての情報があると便利である:A = (ai,j) ∈ Cn×n のすべての固有値は
G =
n⋃i=1
{z ∈ C | |z − ai,i| ≤ ri}
の中に含まれる (Gershgorinの定理).ただし,
ri =∑
1≤j≤nj ̸=i
|ai,j |
とおいている.リスト 4.8 (gershgorin2.m) では,G を描画し,G を含むような複素平面上の長方形 [xmin, xmax] × [ymin, ymax] (res =
xmin, xmax, ymin, ymax) を出力する.*13特に,A が実対称行列の場合,すべての固有値は区間 [xmin, xmax]に含まれる.
リスト 4.8 gershgorin2.m
function [res] = gershgorin2(A)
D = diag(A); center = [real(D),imag(D)];
radius = sum(abs(A-diag(D)),2);
*13 2019 年の講義で gershgorin1.m というプログラムを作って紹介したが,その後,改良版の gershgorin2.mを作った.2020年の講義では,改良版のみ紹介する.
43
% draw circles
t = linspace(0,2*pi,100)’;
x = kron(ones(’like’,t)’,center(:,1)’)+kron(cos(t),
radius’);
y = kron(ones(’like’,t)’,center(:,2)’)+kron(sin(t),
radius’);
figure(1); plot(x,y,’Color’,’b’);
daspect([1 1 1]); grid on; xlabel("Real"); ylabel("
Imaginary");
saveas(1,’gers2.pdf’);
%
res=[min(real(D)-radius),max(real(D)+radius),min(imag(D
)-radius),max(imag(D)+radius)];
end
リスト 4.9 gershgorin2.mを使った Aの固有値の存在範囲の計算>> [res]=gershgorin2(A)
res =
-1 11 -6 6
図 4.1 Gershgorinの円
(5)の Aについて計算してみると,リスト 4.9と図 4.1のようになる.これより,絶対値最大の固有値について |λ4| ≤ 11
という評価が得られるので,この情報を利用して,α = 11と選んで,逆冪乗法を適用するとリスト 4.10のようになる.リスト 4.3と比較すると,単純に冪乗法を適用するよりも,少ない反復回数で,近似固有値が得られていることがわかる*14.
*14 冪乗法では一回の反復で行列とベクトルの積を計算するのみであるが,逆冪乗法では連立一次方程式を計算しなければならないので,反復回数のみでは,計算の手間の比較はできない.
44
リスト 4.10 invpower1.m を使った A の絶対値最大固有値の存在範囲の計算
>> [ev, evec] = invpower1(A, [1 0 0 0]’, 11, 1e-8)
ev =
0 8.8571 1.0000
1.0000 9.9830 0.5254
2.0000 9.9997 0.0164
3.0000 10.0000 0.0003
4.0000 10.0000 0.0000
5.0000 10.0000 0.0000
6.0000 10.0000 0.0000
evec =
1.0000 0 0 0
-0.7308 -0.5742 -0.2610 -0.2610
0.6447 0.6288 0.3074 0.3074
-0.6340 -0.6324 -0.3148 -0.3148
0.6327 0.6325 0.3160 0.3160
-0.6325 -0.6325 -0.3162 -0.3162
0.6325 0.6325 0.3162 0.3162
>> [ev, evec] = invpower1(A, [1 1 1 1]’, 11, 1e-8)
ev =
0 9.9091 1.0000
1.0000 9.9974 0.0810
2.0000 9.9999 0.0025
3.0000 10.0000 0.0001
4.0000 10.0000 0.0000
5.0000 10.0000 0.0000
6.0000 10.0000 0.0000
evec =
0.5000 0.5000 0.5000 0.5000
-0.6139 -0.6139 -0.3508 -0.3508
0.6295 0.6295 0.3221 0.3221
-0.6320 -0.6320 -0.3172 -0.3172
0.6324 0.6324 0.3164 0.3164
-0.6324 -0.6324 -0.3163 -0.3163
0.6325 0.6325 0.3162 0.3162
4.3 課題 4
以下の課題に取り組み,レポートを ITC-LMSを通じて,期限までに提出せよ(期限は ITC-LMS に明示してある).課題4.1と 4.2は必修である.必ず取り組むこと.
課題 4.1. 2つの行列
A+ =
30 2 3 135 11 10 89 7 6 124 14 15 1
, A− =
−30 2 3 135 11 10 89 7 6 124 14 15 1
45
を考える*15.第 (1, 1) 成分以外の成分は全て等しいことに注意せよ.A+ の絶対値最大の固有値と固有ベクトルを冪乗法を使って求めよ.次に,A− の絶対値最大の固有値と固有ベクトルを冪乗法を使って求め,A+ の場合との収束の速さの違いについて考察せよ.
課題 4.2. 行列
A =
3 1 0 0 0 0 01 2 1 0 0 0 00 1 1 1 0 0 00 0 1 0 1 0 00 0 0 1 1 1 00 0 0 0 1 2 10 0 0 0 0 1 3
の最大固有値と絶対値が最大になる負の固有値を (できるだけ工夫して)求めよ.
*15 MATLABのコマンド eig( )を使って,A+ と A− の固有値をあらかじめ計算しておくと良い.理由は,前の脚注を見よ.
46
2020年 6月 19, 26日 (担当:齊藤宣一)
計算数理演習 第 5回課題 (数学科,統合自然科学科)
5 数値積分以下の説明で利用するプログラム集 (kadai5.zip) は,ITC-
LMS の『教材』からダウンロードできる.
有界な閉区間 [a, b]上の実数値関数 f(x)について,定積分
Q(f) =
∫ b
a
f(x) dx
の値を計算する問題を考える.
5.1 複合 Newton-Cotes公式
複合 Newton-Cotes公式を復習しておこう.[a, b]内に相異なるm+ 1個の点
a = x1 < x2 < · · · < xm < xm+1 = b
を配置して*16,小区間 Ii = [xi, xi+1] (i = 1, . . . ,m)を定義する.そして,Q(f)を
Q(f) =m∑i=1
∫ xi+1
xi
f(x) dx
と各小区間 Ii 上での積分に分割する.また,
xi+ 12=
xi + xi+1
2, hi = xi+1 − xi, h = max
1≤i≤mhi
と定義しておく.
複合中点則
Rh(f) =m∑i=1
f(xi+ 12)hi.
複合台形則
Th(f) =m∑i=1
f(xi) + f(xi+1)
2hi.
*16 講義ノートでは a = x0 < x1 < · · · < xm−1 < xm = bを考えているので注意すること.なお,これらは等間隔である必要はない.
47
複合 Simpson則
Sh(f) =
m∑i=1
f(xi) + 4f(xi+ 12) + f(xi+1)
6hi.
等間隔分割
xi = a+ (i− 1)h, h =b− a
m
に基づく複合中点則をMATLABで実行する際には次の様に考える.まず,linspace を使って,x = (x1, . . . , xm+1)
T を定義する*17.そして,各小区間の中点からなるベクトル
xc = (x 12, . . . , xm+ 1
2)T =
(x1 + x2
2, . . . ,
xm + xm+1
2
)T
を計算し,f = (f(x 1
2), . . . , f(xm+ 1
2))T
を計算する.さらに,各小区間の長さからなるベクトル
h = (x2 − x1, x3 − x2, . . . , xm+1 − xm)T
を用意して*18,
Rh(f) = f · h (ベクトルの内積)
と計算する.一方で,複合台形則は,
yl = (f(x1), . . . , f(xm))T,
yr = (f(x2), . . . , f(xm+1))T
と定めて,Th(f) =
(yl + yr) · h2
と計算すれば良い.複合 Simpson 則は,これらのアイデアを組み合わせれば良い.これら実行するプログラムをリスト5.1–5.3に示す.
リスト 5.1 c rect.m
% composite rectangle rule
function integ = c_rect(a,b,m,func)
x = linspace(a,b,m+1)’; % sample points
*17 Tはベクトル・行列の転置を表す.*18 計算しなくても,h = (h, h, . . . , h)T であることはわかっているが,将来,積分点を非等間隔に拡張する可能性を考慮して,このようにしておく.
48
xc = (x(1:end-1)+ x(2:end))/2; % midpoints
y = func(xc); h = diff(x);
integ = dot(y,h);
end
リスト 5.2 c trape.m
% composite trapezoidal rule
function integ = c_trape(a,b,m,func)
x = linspace(a,b,m+1)’; h = diff(x);
yl = func(x(1:end-1)); yr = func(x(2:end));
integ = dot(yl + yr, h)/2;
end
リスト 5.3 c simps.m
% composite Simpson rule
function integ = c_simps(a,b,m,func)
x = linspace(a,b,m+1)’; h = diff(x);
yl = func(x(1:end-1)); yr = func(x(2:end));
xc = (x(1:end-1)+ x(2:end))/2; yc = func(xc);
integ = dot(yl+4*yc+yr,h)/6;
end
例題として,Q0 =
∫ π
0
sinx dx = 2
を計算する.それには,リスト 5.4のように関数 y = func40(x) = sinx
を定義しておき,リスト 5.5のようにすれば良い.
リスト 5.4 func40.m
% sin-function
function y = func40(x)
y=sin(x);
end
リスト 5.5 c rect.mの実行結果>> c_rect(0, pi, 10, @func40)
ans =
2.0082
あるいは,もっと簡単に,関数 c rect.mの変数の部分に直接sinxを指定することもできる.それには,リスト 5.6のようにすれば良い.
リスト 5.6 c rect.m, c trape.m, c simps.mの実行結果
49
>> format long
>> c_rect(0,pi,10,@(x)sin(x))
ans =
2.008248407907974
>> c_rect(0,pi,20,@(x)sin(x))
ans =
2.002057648285417
>> c_rect(0,pi,40,@(x)sin(x))
ans =
2.000514134394606
>> c_trape(0,pi,10,@(x)sin(x))
ans =
1.983523537509455
>> c_trape(0,pi,40,@(x)sin(x))
ans =
1.998971810497066
>> c_simps(0,pi,10,@(x)sin(x))
ans =
2.000006784441801
5.2 誤差挙動と収束の速さ
複合中点則の誤差を調べるために,
Eh(f) = Q(f)−Rh(f)
を調べる.講義で証明したように,f ∈ C2[a, b]ならば,
|Eh(f)| ≤b− a
24h2∥f ′′∥∞ (6)
が成り立つことがわかっている.この,h → 0の際に,誤差が h2 に比例して減衰する事実を実験的に確かめたい.そのために,とりあえず,g(h) = Chr という関係式を考える(C と r は hには依存しない正定数).このとき,
r =log g(h)− log g(h/2)
log 2
となるので,これに注意して,計算結果に対して
rh(f) =log |Eh(f)| − log |Eh/2(f)|
log 2(7)
と定義して,この量を観察してみよう.そのために,リスト 5.7
を用意した.
リスト 5.7 NI order.m
50
% convergence rate of composite rules
function [vh, verr, order] = NI_order(a,b,func,rule,Qex
,m)
err1 = abs(Qex - rule(a,b,m,func));
err2 = abs(Qex - rule(a,b,2*m,func));
vh=[(b-a)/m;(b-a)/(2*m)]; verr=[err1;err2];
order = (log(err1) - log(err2))/log(2);
end
いま,複合中点則で計算をしたいので,ruleとして c rectを与える.さらに,Qex = Q(f)とmを与えて,
err1 = |Eh(f)|, err2 = |Eh/2(f)|,
vh =
(h
h/2
), verr =
(|Eh(f)||Eh/2(f)|
)を計算する.また,order= rh(f)としている.例として,Q0 を計算してみよう.
リスト 5.8 NI order.mの実行結果>> [vh, verr, order] = NI_order(0,pi,@func40,@c_rect
,2,10)
vh =
0.314159265358979
0.157079632679490
verr =
0.008248407907974
0.002057648285417
order =
2.003119277065236
>> [vh, verr, order] = NI_order(0,pi,@func40,@c_rect
,2,20)
vh =
0.157079632679490
0.078539816339745
verr =
0.002057648285417
0.000514134394606
order =
2.000778968945630
>> [vh, verr, order] = NI_order(0,pi,@func40,@c_rect
,2,40)
vh =
0.078539816339745
0.039269908169872
verr =
1.0e-03 *
0.514134394605570
0.128516254437550
order =
2.000194689170498
51
結果を表 5.2にまとめる.
表 5.1 Q0 を複合中点則 Rh(f)で計算.
h Eh(f) rh(f)
0.3146 0.008248407907974 —
0.1571 0.002057648285417 2.003
0.0785 0.000514134394606 2.001
0.0393 0.000128516254437 2.000
表より,十分小さな hに対して,|Eh| ≈ Ch2 の関係が成り立っていることが見て取れる.すなわち,このとき,(6) の不等式が等号で成立していることが,実験的に確認できたわけである.同様の計算を,複合台形則,複合 Simpson 則で行うには,
ruleとして,c trape,c simpsを与えれば良い.次のリスト 5.9 も,複合公式の収束を調べるプログラムである.
リスト 5.9 NI order plot.m
% errors of composite rules
function NI_order_plot(a,b,func,rule,Qex,mmin,mmax)
h = zeros(mmax-mmin+1)’;
err = zeros(mmax-mmin+1)’;
for m = mmin:mmax
tmp = abs(Qex - rule(a,b,m,func));
err(m-mmin+1) = tmp;
h(m-mmin+1) = (b-a)/m;
end
loglog(h, err,’o-b’,’LineWidth’,2); grid on;
xlabel("h"); ylabel("error"); saveas(1,’NIorder.pdf’);
end
このプログラムでは,mmin ≤ m ≤ mman の範囲の m に対して,
h =
...h...
, err =
...
|Eh(f)|...
を計算して(h = (b−a)/m),これを両対数グラフでプロット,すなわち,(log h, log |Eh(f)|)をプロットする.例えば,
リスト 5.10 NI order plot.mの実行結果>> NI_order_plot(0, pi, @func40, @c_rect, 2, 5, 105)
52
と入力すると,図 5.1が得られる.図 5.1より,直線の傾きが 2であることがわかる(目盛りの読み方に注意).すなわち,直線の切片を C とすると,
log |Eh(f)| = 2 log h+ C
という関係があることがわかる.これより,
|Eh(f)| = eCh2
が得られる.このようにして,理論的な誤差評価を実験的に検証することができる.
図 5.1 複合中点則の誤差 (log h, log |Eh(f)|)のプロット.
5.3 課題 5
以下の課題に取り組み,レポートを ITC-LMSを通じて,期限までに提出せよ(期限は ITC-LMS に明示してある).この課題 5.1は必修する.必ず取り組むこと.
課題 5.1. 次の 3つの積分 Q1, Q2, Q3 を,等間隔分割
xi = a+ (i− 1)h, h =b− a
m
に基づく複合中点則,複合台形則,複合 Simpson 則で計算し
53
て,収束の速さ(hと誤差の関係)を考察せよ:
Q1 =
∫ 1
0
x2 sin(πx) dx =π2 − 4
π3,
Q2 =
∫ 1
1/√2
√1− x2 dx =
π
8− 1
4,
Q3 =
∫ β
α
cos2 x dx =π
8− 1
4(α = sin−1 1√
2, β = sin−1 1
).
この課題を遂行するにあたり,次のように関数を用意しておくと便利である (これらも kadai4.zipに含まれている).
リスト 5.11 func41.m
% function for kadai4, Q1
function y = func41(x)
y = (x.^2) .* sin(pi*x);
end
リスト 5.12 func42.m
% function for kadai4, Q2
function y = func42(x)
y = sqrt(1 - x.^2);
end
リスト 5.13 func43.m
% function for kadai4, Q3
function y = func43(x)
y = (cos(x)) .^2 ;
end
さらに次の様に数値を定義しておくと便利である.
リスト 5.14 NIvalues.m
% numerical values
Q1 = (pi^2-4) / (pi^3);
Q2 = pi/8 - 1/4;
Q3 = pi/8 - 1/4;
alpha = asin(1/sqrt(2));
beta = asin(1);
Q4 = 2*pi/3;
Q5 = 13*pi/16 - 23/15;
リスト 5.15 NIvalues.mの実行結果>> NIvalues
54
>> Q1
Q1 =
0.189303748450993
>> alpha
alpha =
0.785398163397448
55
2020年 7月 3, 10日 (担当:齊藤宣一)
計算数理演習 第 6回課題 (数学科,統合自然科学科)
6 常微分方程式の初期値問題以下の説明で利用するプログラム集 (kadai6.zip) は,ITC-
LMS の『教材』からダウンロードできる.
常微分方程式の初期値問題
du(t)
dt= f(t, u(t)) (t0 ≤ t ≤ T ), u(t0) = a
に対する代表的な Runge-Kutta 型の解法を考える.なお,講義では,tの区間としては [0, T ]を扱ったが,ここでは,より一般に,T > t0 に対して,[t0, T ]を考える.
6.1 Euler法と Heun法
正の整数 N に対して,h =T − t0N
とおき(一様刻み幅),
tn = t0 + nh (n = 0, . . . , N)
と定義して,Un ≈ u(tn)を求めることを考える.Euler法*19
では,
Un+1 = Un + hf(tn, Un) (n = 0, . . . , N − 1)
で Un を求める.ただし,U0 = aとする.
リスト 6.1 euler.m
% Euler method
function [t, u]=euler(odefunc, t0, T, init, N)
% time increment and initial value
h = (T-t0)/N; t=[t0]; w = init;
% solution vectors
u=[]; u=[u;w];
% iteration
time = t0;
for i=1:N
w = w + h*odefunc(time,w);
time = t0 + i*h; u = [u; w]; t = [t; time];
end
end
*19 より正確には,前進 Euler法と言う.
56
この Euler法で近似解を求めるプログラム (リスト 6.1)において,
t =
t0...tN
, u =
u(t0)...
u(tN )
, init = a
を意味している.また,odefuncは,f(t, u)のことであり,これは別に関数として定義しておく必要がある(例えば,リスト6.2).
リスト 6.2 func51.m, f(t, y) = cos(2y)
function f = func51(t, y)
f = cos(2*y);
end
これを,odefunc = func51,t0 = 0,t1 = 2,a = 0,N = 20
で実行するには次のようにする:
リスト 6.3 euler.mの実行>> [t, u]=euler(@func51, 0, 2, 0, 20)
t =
0
0.1000
0.2000
0.3000
.....
1.9000
2.0000
u =
0
0.1000
0.1980
0.2903
.....
0.7697
0.7728
一方,Heun法では,
Un+1 = Un +h
2(k1 + k2)
k1 = f(tn, Un)
k2 = f (tn + h,Un + hf(tn, Un))
により,{Un} を計算する.プログラムはリスト 6.4 のようになる.
リスト 6.4 heun.m
57
% Heun method
function [t, u] = heun(odefunc, t0, T, init, N)
% time increment and initial value
h = (T-t0)/N; t=[t0]; w = init;
% solution vectors
u=[]; u=[u;w];
% iteration
time = t0;
for i=1:N
k1=odefunc(time,w); k2=odefunc(time+h,w+h*k1);
w = w + h*(k1+k2)/2; time = t0 + i*h;
u = [u; w]; t = [t;time];
end
end
数値だけではわかりにくいので,解 u(t)のグラフを書くことを考える.そのために,リスト 6.5に示す OdePlot1 を用意する.
リスト 6.5 OdePlot1.m, 微分方程式の解を描画するプログラム
% 2d visualization
function OdePlot1(Solver, odefunc, t0, T, init, N)
[t, u] = Solver(odefunc, t0, T, init, N);
plot(t, u, ’LineWidth’,2);
xlabel(’t’); ylabel(’u’); saveas(1,’OdePlot1.pdf’);
end
この関数では,Solver=euler または Solver=heun とすれば良い (リスト 6.9).実行例を示す (図 6.1).
リスト 6.6 OdePlot1.mの実行>> OdePlot1(@euler, @func51, 0, 2, 0, 20)
>> OdePlot1(@heun, @func51, 0, 2, 0, 20)
図 6.1 u′ = cos(2u),u(0) = 0 の解 u(t) のグラフ.左がEuler法,右が Heun法.
58
6.2 誤差の考察
次に,Euler法と Heun法の誤差
Eh = max0≤n≤N
|u(tn)− Un|
を考察する.講義で説明したように,
Eh ≤
{CEh (Euler法)
CHh2 (Heun法)
(8)
がわかっている.CE と CH は適当な正定数である.これを実験的に確かめよう.そのためにリスト 6.7を利用する.
リスト 6.7 OrderPlot.m
% accuracy: log-log plot of errors
function [res] = OrderPlot(Solver, odefunc, exact, t0,
T, init)
NN=4; kmax=8; hv=[]; err1=[];
%
for k=1:kmax
[t, u] = Solver(odefunc, t0, T, init, NN);
err = exact(t)-u; err1 = [err1; norm(err,inf)];
hv=[hv; (T-t0)/NN]; NN = 2*NN;
end
% log-log plot
loglog(hv, err1,’b-o’,’LineWidth’,2); xlabel(’h’);
ylabel(’error’); grid on; saveas(1,’OrderPlot.pdf’);
% results
res=[hv,err1];
end
この関数では,odefunc = f(t, u)と初期値 aに対する,微分方程式の厳密解 u(t)を与えて,その誤差を計算する.具体的には,
hk =T − t02k−1N
(k = 1, . . . , kmax)
に対して (hk+1 = hk/2の関係があることに注意せよ),
err = ek =
u(t0)− U0
...u(tN )− UN
を計算して,
hv =
h1
...hkmax
, error =
∥e1∥∞...
∥ekmax∥∞
=
Eh1
...Ehkmax
59
とする.OrderPlot は,この (hk, Ehk) (k = 1, . . . , kmax) の
数値を出力するとともに,これらを両対数グラフに描画する.
リスト 6.8 func51sol.m,関数 (9)
function f = func51sol(t)
f = 0.5*asin( (exp(4*t)-1) ./ (exp(4*t)+1) );
end
さて,odefunc = cos(2u),a = 0 に対する,微分方程式の厳密解は,
u(t) =1
2sin−1
(e4t − 1
e4t + 1
)(9)
である(各自確かめよ).これは,func51solとしてすでに定義してある (リスト 6.8).計算結果は,次の通りである(リスト 6.9と図 6.2).
リスト 6.9 OrderPlot.mの実行>> [res]=OrderPlot(@euler,@func51,@func51sol,0,2,0)
res =
0.5000 0.1193
0.2500 0.0512
0.1250 0.0242
0.0625 0.0118
0.0312 0.0058
0.0156 0.0029
0.0078 0.0014
0.0039 0.0007
>> [res]=OrderPlot(@heun,@func51,@func51sol,0,2,0)
res =
0.5000 0.0657
0.2500 0.0125
0.1250 0.0027
0.0625 0.0006
0.0312 0.0002
0.0156 0.0000
0.0078 0.0000
0.0039 0.0000
両対数グラフでプロットしたときに,各点 (hk, Ehk)が直線
Y = αX + β (X = log h, Y = logEh)
上にあると仮定しよう.そうすると,
Eh = Chα (C = eβ)
が結論できる.したがって,図 6.2より,
Eh ≈
{C1h (Euler法)
C2h2 (Heun法)
60
図 6.2 (h,Eh)の両対数グラフ.左が Euler法,右が Heun法.
が成り立つことがわかり,(8)が (等号で成立することが)実験的に確かめられた.グラフを基にした考察でなくても,
ph =logEh − logEh/2
log h− log(h/2)
の値を計算することで,(8) を確認することもできる (リスト6.10).
リスト 6.10 OrderNumber.m
% accuracy: numerics
function [res] = OrderNumer(Solver, odefunc, exact, t0,
T, init)
NN=8; hv=[]; errv=[]; kmax=8;
%
for k=1:kmax
[t, u] = Solver(odefunc, t0, T, init, NN);
err = exact(t)-u; errv = [errv; norm(err,inf)];
hv=[hv; (T-t0)/NN]; NN = 2*NN;
end
% computaion of p
for k=1:kmax-1
p(k) = (log(errv(k))-log(errv(k+1)))/log(2);
end
p(kmax)=0;
% results
res=[hv,errv,p’];
end
これを,Heun法について実行すると,
リスト 6.11 OrderNumer.mの実行>> [res]=OrderNumer(@heun,@func51,@func51sol,0,2,0)
res =
0.2500 0.0125 2.2118
0.1250 0.0027 2.1092
0.0625 0.0006 2.0547
0.0312 0.0002 2.0269
61
0.0156 0.0000 2.0136
0.0078 0.0000 2.0068
0.0039 0.0000 2.0034
0.0020 0.0000 0
となる.左から,h,Eh,ph の値が並んでいる.これより,h
が十分小さいとき,p ≈ 2,すなわち,Eh ≈ Ch2 が成り立つことが,実験的に確かめられた.Euler法に関しては,各自で確かめよ.
6.3 ベクトル値の微分方程式
競合の関係下にある 2 種類の生物の増殖の数理モデルとして,Lotoka–Volterra微分方程式系
du1
dt= c1u1(1− b1u1 − d2u2),
du2
dt= −c2u2(1− b2u2 − d1u1)
がある.u1 = u1(t)と u2 = u2(t)は 2種類の生物の個体密度,c1, c2 はそれぞれの生物の増殖係数,さらに,b1, b2, d1, d2 は,互いの競合の関係や,環境の影響を表現する定数である.この系は,
d
dtu(t) = f(t,u(t)) (10)
と書ける.ただし,
u(t) =
(u1(t)u2(t)
), f(t,u) =
(c1u1(1− b1u1 − d2u2)−c2u2(1− b2u2 − d1u1)
)としている.以下では,c1 = c2 = d1 = d2 = 1,b1 = b2 = 0の場合を考察する.f(t,u)は,リスト 6.12 のように定義すれば良い.
リスト 6.12 LotVol.m
% Lotka-Volterra system
function [fn] = LotVol(t, y)
c1=1; c2=1; d1=1; d2=1; b1=0; b2=0;
[n,m] = size(y); fn = zeros(n, m);
fn(1) = c1*y(1)*(1-b1*y(1)-d2*y(2));
fn(2) = -c2*y(2)*(1-b2*y(2)-d1*y(1));
end
まえに作った eulerや heunは,そのまま,ベクトル値の関数が扱える.ただし,初期値 initには,平面上の点を与える
62
必要がある.またこの場合,解 uは,ベクトルでなく,
u =
u1(t0) u2(t0)u1(t1) u2(t1)
......
u1(tN ) u2(tN )
の形の行列として扱われる.初期値を a = (u1(0), u2(0)) =
(0.5, 0.8) したときの実行は,例えば,次のようにする.
リスト 6.13 Lotoka–Volterra系の計算>> [t, u]=heun(@LotVol,0,5,[0.5,0.8],10)
t =
0
0.5000
.....
4.5000
5.0000
u =
0.5000 0.8000
0.5800 0.6325
.....
0.8781 1.8789
0.5911 1.5976
>> OdePlot1(@heun, @LotVol, 0, 5, [0.5,0.8], 60)
図 6.3 OdePlot1( )の結果.
ただし,このような連立微分方程式を考える際には,相図(u1, u2)に興味があることが多い.MATLABでは,
u(:,1) =
u1(t0)...
u1(tN )
, u(:,2) =
u2(t0)...
u2(tN )
の意味で扱われるので,これを利用して,次のリスト 6.14 (初
63
期値を指定する) とリスト 6.15 (初期値をランダムに選ぶ.ただし,初期値の個数のみ指定する)を作る.
リスト 6.14 OdePlot2.m
% phase diagram for 2d case
function OdePlot2(Solver, odefunc, t0, T, init, N)
[t, u] = Solver(odefunc, t0, T, init, N);
plot(u(:,1),u(:,2)); xlabel(’u1’); ylabel(’u2’);
saveas(1,’OdePlot2.pdf’);
end
リスト 6.15 OdePlot3.m
% phase diagram for 2d case
function OdePlot3(Solver, odefunc, t0, T, num, N)
figure(3); hold on; len=1.0;
for i=1:num
init=[len*rand(),len*rand()];
[t, u] = Solver(odefunc, t0, T, init, N);
plot(u(:,1),u(:,2));
end
xlabel(’u1’); ylabel(’u2’); saveas(3,’OdePlot3.pdf’);
end
実行例は,次の通りである.
リスト 6.16 OdePlot2.mと OdePlot3.mの実行>> OdePlot2(@heun,@LotVol,0,10,[0.5,0.8],100)
>> OdePlot3(@heun,@LotVol,0,20,10,5000)
図 6.4 Lotoka–Volterra 系の解の相図.左は初期値(0.5, 0.8) の際の相図.右は初期値を 10 個ランダムに選んだ際の相図.
いまの場合,Lotoka–Volterra系の平衡点は,
u1 − u1u2 = 0, −u2 + u1u2 = 0
を解くことで,(0, 0),(1, 1)であることがわかる.上の計算結果から,(1, 1)は安定な平衡点であり,一方で,(0, 0)は不安定な平衡点であることが予想できる.
64
6.4 課題 6
以下の課題に取り組み,レポートを ITC-LMSを通じて,期限までに提出せよ(期限は ITC-LMS に明示してある).この課題 6.1–6.2は必修する.必ず取り組むこと.
課題 6.1. 古典的 Runge–Kutta法
Un+1 = Un +h
6(k1 + 2k2 + 2k3 + k4)
k1 = f(tn, Un)
k2 = f(tn + 1
2h,Un + 12hk1
)k3 = f
(tn + 1
2h,Un + 12hk2
)k4 = f (tn + h,Un + hk3)
を計算するプログラム rk(odefunc,t0,T,init,N) を作成せよ.それには,heunの対応する部分を,
リスト 6.17 heunから rkへの修正k1 = odefunc(time, w);
k2 = odefunc(time+h/2, w+(h/2)*k1);
k3 = odefunc(time+h/2, w+(h/2)*k2);
k4 = odefunc(time+h, w+h*k3);
w = w + h*(k1 + 2*k2 + 2*k3 + k4)/6;
と書きかえれば良いのみである.そして,自分で常微分方程式の初期値問題の例題を作り,
Euler法,Heun法,古典的Runge–Kutta法の精度 (Eh ≤ Chp
の形の収束性) を比較せよ.例題の作り方は,講義での説明を参考にせよ(u′ = 定数 などの,あまりにも明らかなものは避けること).
課題 6.2. 次の連立常微分方程式の相図を,いろいろな初期値に対して描画せよ.*20
dx
dt= −y −
(x4
4− x2
2+
y2
2
)(x3 − x),
dy
dt= x3 − x−
(x4
4− x2
2+
y2
2
)y.
この問題に関しては,結果を描画するのみで良い.
*20 参考:Hirsch, Smale, Devaney(著),桐木他(訳): 力学系入門—微分方程式からカオスまで—,共立出版,2017年,§10.5
65
2020年 5月 15日 (担当:齊藤宣一)
計算数理演習 第∞回課題 (数学科,統合自然科学科)
∞ 発展課題発展課題は必修の課題ではない.課題を終えてもなお,余力のある人・意欲のある人は,以下の問題についても(部分的で良いので)取り組んで考察の結果をレポートにまとめよ.レポートは,ITC-LMSの発展問題の提出場所に提出せよ.期限は 8月 7日 23:00とする.+αの成績として評価する.
発展問題 1. 関数
f(x) = coshx+ cosx− 2
を考える.方程式 f(x) = 0には,唯一の解 a = 0が存在することを示せ.この方程式に Newton法を適用した際に 2次収束が観察できないことを実験的に確かめよ.また,この方程式に修正 Newton 法を適用した際に,最も収束が速くなる m を実験的に求めて,理由を数学的に説明せよ.
発展問題 2. Kepler方程式
M = E − ε sinE
を考えよう.0 < ε < 1 と 0 ≤ M ≤ 2π は与えれた定数で,E が求めるべき未知数である.N を十分大きな正の整数として,Mn = (2π/N)n (n = 0, 1, . . . , N)とおく.各Mn について,Kepler方程式を Newton法で解いて得られた近似解を En
とする.ε を一つ固定して,(Mn, En) (n = 0, 1, . . . , N) をプロットせよ(あるいは線分で結べ).いくつかの異なる ε に対して,同じことを行い,結果を重ねて比較せよ.この結果が,物理的に何を意味しているのかを調査せよ.
発展問題 3. 行列
A =
0 0 0 −261 0 0 510 1 0 −330 0 1 9
66
の絶対値最小の固有値を逆冪乗法で求めよ.また,絶対値最大の固有値を求めるために冪乗法を適用すると,どのような結果になるかを報告せよ.また,その理由を考えよ.
発展問題 4. 積分
Q4 =
∫ 2π
0
dx
5− 4 cosx=
2π
3
を,等間隔分割
xi = a+ (i− 1)h, h =b− a
m
に基づく複合中点則,複合台形則,複合 Simpson 則で計算して,収束の速さ(h の誤差への依存性)を考察せよ.
発展問題 5. g(x) = −x6− 4x5+3x4+16x3− 11x2− 12x+9
に対して,定積分
Q5 =
∫ 1
0
(1− x)√
g(x) dx =13
16π − 23
15
を複合 Newton-Cotes 則で計算し,誤差のオーダ(| 誤差 | ≤Chα と表した時の αのこと)を実験的に調べよ.
発展問題 6. 付録 Bで説明するGauss型積分公式について,方程式 (12) を解くことで W0, . . . ,Wn が計算できることを証明し,get weight.m (リスト B.7)の中身を説明せよ.
発展問題 7. 微分方程式
x′′(t) = − x(t)
R(t), y′′(t) = − y(t)
R(t)
を考える.ただし,R(t) = [x(t)2+y(t)2]3/2である.パラメータ 0 ≤ k < 1を使って,初期条件を
x(0) = 1− k,
x′(0) = 0,
y(0) = 0,
y′(0) =
(1 + k
1− k
) 12
と定めると,解は周期 2π で周期的になる.(なお,(x(t), y(t))
は,離心率が kで,焦点の一つに原点を持つ楕円を描く.)この問題を,古典的 Runge-Kutta法で解いて,軌道を描け.
67
付録 A MATLAB超入門A.1 MATLAB
Wikipediaでは次のように説明されている:
“MATLAB(マトラボ)は,アメリカ合衆国のMathWorks
社が開発している数値解析ソフトウェアであり,その中で使うプログラミング言語の名称でもある.MATLABは,行列計算,関数とデータの可視化,アルゴリズム開発,グラフィカルインターフェイスや,他言語 (C/C++/Java/Python)とのインターフェイスの機能を有している.MATLABは,主に,数値計算を扱う事ができるが,追加のオプション Symbolic Math Toolbox
を使うことで,数式処理の能力を得ることができる.2004 年で,MATLABは産業界,教育界において 100万人ユーザーを達成しており*21,工学,理学,経済学など幅広い業種で利用されている.(https://ja.wikipedia.org/wiki/MATLAB)”
参考 URLと参考書を挙げる:
• 東京大学向けの MATLAB ポータルサイト https://
www.u-tokyo.ac.jp/adm/dics/ja/matlabcwl.html
の『MATLAB入門』や『オンラインコース』• 桜井鉄也:MATLAB/Scilabで理解する数値計算,東京大学出版会,2003年(3,045円)
• A. Quarteroni, F. Saleri, P. Gervasio:Scientific Com-
puting with MATLAB and Octave, 4th edit., Springer,
2014(加古孝,千葉文浩訳,MATLABと Octaveによる科学技術計算,丸善出版,2014年)
この文書では,MATLABを用いて数値計算を行うための必要最低限の内容を説明する.より詳しいことは,上記の参考Web
ページや参考書で各自で勉強して欲しい.ただし,MATLAB
の良さを活かした数値計算プログラミングをしている本は少ないので,Quarteroni 氏の本にある MATLAB プログラムの例を参考に,自分で数値計算プログラムを書いてみることをお勧めする.この文書でも,この本のプログラミングを大いに参考
*21 MathWorksのウェッブページの基本情報によれば,現在 400万人のようです (https://jp.mathworks.com/company/aboutus.html).
1
にしている.なお,MATLAB は,ECCS からだけでなく,UTokyo Ac-
countを利用することで,個人のPCにインストールして使うこともできるし,オンラインで利用することもできる.詳しくは,https://fye.c.u-tokyo.ac.jp/students/ のページの『アカウントセットアップ手順詳細』https://www.sodan.ecc.
u-tokyo.ac.jp/faq/utokyo-matlab-cwl/ を参照せよ.
A.2 基本操作
MATLAB を起動する.Mac の場合は,アプリケーションフォルダ(→ 図 A.1)からMATLABを起動する(→ 図 A.2).
図 A.1 アプリケーション
次の図 A.3のようなウインドウが出てくる.MATLAB の画面に表示されている-->の後に,2 + 3 と入力して,[enter/return]をおすと,答えとして 5が出力される(→リスト A.1).
リスト A.1 はじめの例題>> 1+2 [enter/return]
ans =
3
この資料において,以後は,[enter/return]を省略する.
2
図 A.2 MATLAB
図 A.3 MATLABの画面と 2 + 3の実行
A.3 基本演算
A.3.1 四則演算など例を挙げる.詳しい説明はしないが,意味は理解できるであろう.
リスト A.2 四則演算など>> 3+4
ans =
7
>> 3-4
ans =
-1
>> 3+(-4)
ans =
3
-1
>> 3*4
ans =
12
>> 3/4
ans =
0.7500
>> 3^4
ans =
81
>> 4^(-2)
ans =
0.0625
A.3.2 特別な記号名など
リスト A.3 特別な記号名など>> pi
ans =
3.1416
>> 3*pi
ans =
9.4248
>> 2 + 3i
ans =
2.0000 + 3.0000i
>> 2 + 3j
ans =
2.0000 + 3.0000i
>> (1 + 2i)*(1 - 2i)
ans =
5
>> (1 + 2i)*(1 - 2j)
ans =
5
虚数単位としては iと jの両方が使える.1 + 2iを記述する際には,1+2iと書くこと.1+2*iと記述すると,iは実数と見なされ,1 + 2 × iが計算される.(ただし,この講義では,複素数は使わない.)
A.3.3 組み込み関数
リスト A.4 組み込み関数% 絶対値>> abs(-1.2)
ans =
1.2000
4
% 対数>> log10(10)
ans =
1
>> log(10)
ans =
2.3026
% 三角関数・逆三角関数>> sin(pi/6)+2*cos(pi/4)
ans =
1.9142
>> 4*atan(1)
ans =
3.1416
% 整数部分>> round(1.2)
ans =
1
>> round(-1.2)
ans =
-1
>> floor(-1.2)
ans =
-2
% 偏角>> angle(1+2i)
ans =
1.1071
絶対値 |x| abs(x)
平方根√x sqrt(x)
指数関数 ex exp(x)
自然対数 log x log(x)
常用対数 log10 x log10(x)
三角関数 sinxなど sin(x)など逆三角関数 acos x = cos−1 xなど acos(x)など双曲線関数 tanhxなど tanh(x)など最近整数への丸め round(x)
切り捨て floor(x)
剰余 a/bの余り rem(a, b)
偏角 (位相角)θ z = reiθ (θ ∈ [−π, π)) angle(z)
なお,上の % ではじまる行はコメント行であり,計算に
5
影響はない.以下では,何をしているのかを説明するために,適宜コメントを挿入するが,自分で実行する際には,省略して良い.
A.3.4 出力フォーマットformat で出力フォーマットと表示桁数の制御ができる.以下において,e+00は 100 の意味である.
リスト A.5 出力フォーマット>> x=3*pi
x =
9.4248
% 15桁の固定小数点表示>> format long
>> x
x =
9.424777960769379
% 15桁の浮動小数点表示>> format longE
>> x
x =
9.424777960769379e+00
% 5桁の固定小数点表示>> format short
>> x
x =
9.4248
% 5桁の浮動小数点表示>> format shortE
>> x
x =
9.4248e+00
% 出力フォーマットの取得>> get(0,’format’)
ans =
’shortE’
% 出力フォーマットのクリア>> format
>> x
x =
9.4248
ただし,表示桁数が変わっても,MATLAB 内で記憶されている桁数は変わらない.
6
なお,MATLABでは,特に指定しなければ,数値はすべて倍精度実数型*22の変数として扱われる.特に整数として扱いたいときには,int16などで変換する必要があるが,この講義で必要になることはない.
A.4 ベクトルと行列
A.4.1 定義と演算行列を扱う際には,次のようにする.括弧 [ ] とカンマ , とセミコロン ; の役割に注意すること.
リスト A.6 行列とベクトル% 行列の定義>> A = [3,-1,0; 1, 4, 2; 1, 1, 3]
A =
3 -1 0
1 4 2
1 1 3
>> B = [-2, 2, 5; 1, 3, 4; 1, -1, 2]
B =
-2 2 5
1 3 4
1 -1 2
% 行列の成分>> A(1,2)
ans =
-1
>> B(3,3)
ans =
2
% Aの 2列目>> A(:,2)
ans =
-1
4
1
% Bの 3行目>> B(3,:)
ans =
1 -1 2
*22 1985年に IEEE (Institute of Electrical and Electronics Engineers)
が定めた数の規格.本当は,2008年に発表されたその更新版 IEEE754–
2008における binary64を意味する.
7
% 行列の演算>> 4*A - 2*B
ans =
16 -8 -10
2 10 0
2 6 8
% 行列の積>> A*B
ans =
-7 3 11
4 12 25
2 2 15
% 横ベクトルの定義>> u=[1, 2, 3]
u =
1 2 3
% 縦ベクトルの定義>> v = [4, 5, 6]’
v =
4
5
6
>> w = [7; 8; 9]
w =
7
8
9
% 行列とベクトルの転置>> A’
ans =
3 1 1
-1 4 1
0 2 3
>> u’
ans =
1
2
3
>> v’
ans =
4 5 6
% 行列とベクトルの積>> A*v
ans =
7
36
8
27
% ベクトルの内積(横×縦)>> u*v
ans =
32
% ベクトルの内積(横×縦)>> u*u’
ans =
14
また,
リスト A.7 ベクトルの生成 1
[a: h: b]
で,[a, a+h, a+2h, ..., b-h, b] の形のベクトルの自動生成もできる.
リスト A.8 ベクトルの生成>> x = [1: 0.5: 3]’
x =
1.0000
1.5000
2.0000
2.5000
3.0000
>> x = [1: 0.1: 2]’
x =
1.0000
1.1000
1.2000
1.3000
1.4000
1.5000
1.6000
1.7000
1.8000
1.9000
2.0000
あるいは,
リスト A.9 ベクトルの生成 2
linspace(a, b, n)
を使って次のようにしても良い.
9
リスト A.10 ベクトルの生成>> linspace(0, 1, 5)
ans =
0 0.2500 0.5000 0.7500 1.0000
>> linspace(0, 1, 8)’
ans =
0
0.1429
0.2857
0.4286
0.5714
0.7143
0.8571
1.0000
A.4.2 ノルム,行列式と逆行列など
ベクトル x = (xi) =
x1
...
xn
∈ Rn と 1 ≤ p < ∞に対して,
∥x∥p =
(n∑
i=1
|xi|p)1/p
を xの pノルムと言う.また,
∥x∥∞ = max1≤i≤n
|xi|
を xの∞ノルム,あるいは,最大値ノルムと言う.さらに,n次の正方行列 Aに対して,
∥A∥p = max0 ̸=x∈Rn
∥Ax∥p∥x∥p
を Aの行列 pノルムと言う.
リスト A.11 ノルムなど>> x = [1; 2; 3];
>> y = [4, 5, 6];
>> A = [3, -1, 0; 1, 4, 2; 1, 1, 3];
>> B = [-2, 2, 5; 1, 3, 4; 1, -1, 2];
% ベクトルの 2ノルム>> norm(x, 2)
ans =
3.7417
>> norm(y, 2)
ans =
10
8.7750
>> norm(x)
ans =
3.7417
% ベクトルの 1ノルム>> norm(y, 1)
ans =
15
% ベクトルのinftyノルム>> norm(x, inf)
ans =
3
% 行列のノルム>> norm(A, 2)
ans =
5.2997
>> norm(A)
ans =
5.2997
>> norm(A, 1)
ans =
6
>> norm(A, inf)
ans =
7
% 行列式>> det(A),det(B)
ans =
31
ans =
-36
% 逆行列>> A^(-1)
ans =
0.3226 0.0968 -0.0645
-0.0323 0.2903 -0.1935
-0.0968 -0.1290 0.4194
>> inv(A)
ans =
0.3226 0.0968 -0.0645
-0.0323 0.2903 -0.1935
-0.0968 -0.1290 0.4194
なお,処理の最後に ; を入れておくと,処理はされるが結果が表示されなくなる.
リスト A.12 結果の非表示>> x = [1, 2, 3]’
11
x =
1
2
3
>> x = [1, 2, 3]’;
A.4.3 特別な行列
リスト A.13 特別な行列% 単位行列>> eye(3, 3)
ans =
1 0 0
0 1 0
0 0 1
>> eye(3, 5)
ans =
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
% 成分がすべて 1の行列>> ones(2, 3)
ans =
1 1 1
1 1 1
% 零行列>> zeros(4, 3)
ans =
0 0 0
0 0 0
0 0 0
0 0 0
% 成分が擬似乱数の行列>> rand(3, 5)
ans =
0.7477 0.0710 0.9823 0.8944 0.8426
0.3469 0.7784 0.1682 0.6671 0.8306
0.6954 0.0799 0.7511 0.4484 0.4111
size で行列のサイズを取得できる.A がすでに定義されているとき,引数に size(A)を入れると Aと同じサイズの単位行列などを生成する.例えば,
リスト A.14 行列のサイズ>> A = [1, 2; 3, 4];
>> B = [1, 2, 3; 4, 5, 6];
12
% 行列のサイズの取得>> size(A)
ans =
2 2
>> size(B)
ans =
2 3
%
>> eye(size(A))
ans =
1 0
0 1
>> ones(size(B))
ans =
1 1 1
1 1 1
対角行列や上三角行列の作り方は次の通り.
リスト A.15 対角行列と三角行列>> u = [1, 2, 3];
>> A = [1, 2, 3; 4, 5, 6; 7, 8, 9];
% 対角行列の生成>> diag(u)
ans =
1 0 0
0 2 0
0 0 3
% 対角成分の取得>> diag(A)
ans =
1
5
9
% 対角行列の生成>> diag(diag(A))
ans =
1 0 0
0 5 0
0 0 9
% 下三角行列の取得>> tril(A)
ans =
1 0 0
4 5 0
7 8 9
% 狭義下三角行列の取得
13
>> tril(A, -1)
ans =
0 0 0
4 0 0
7 8 0
% 上三角行列の取得>> triu(A)
ans =
1 2 3
0 5 6
0 0 9
% 狭義上三角行列の取得>> triu(A,1)
ans =
0 2 3
0 0 6
0 0 0
A.4.4 成分毎の演算行列 A = (aij) ∈ Rn×n と B = (bij) ∈ Rn×n に対して,成分毎の積
A⊗B =
a11b11 a12b12 · · · a1nb1na21b21 a22b22 · · · a2nb2n
......
. . ....
an1bn1 an2bn2 · · · annbnn
,
成分毎の累乗
A⊗A⊗ · · · ⊗A︸ ︷︷ ︸m 回
=
am11 am12 · · · am1nam21 am22 · · · am2n...
.... . .
...amn1 amn2 · · · amnn
,
成分毎の商
A⊘B =
a11/b11 a12/b12 · · · a1n/b1na21/b21 a22/b22 · · · a2n/b2n
......
. . ....
an1/bn1 an2/bn2 · · · ann/bnn
は次のように計算できる.
リスト A.16 成分毎の演算>> A = [3, -1, 0; 1, 4, 2; 1, 1, 3];
>> B = [-2, 2, 5; 1, 3, 4; 1, -1, 2];
14
>> A .* B
ans =
-6 -2 0
1 12 8
1 -1 6
>> A .^ 4
ans =
81 1 0
1 256 16
1 1 81
>> A ./ B
ans =
-1.5000 -0.5000 0
1.0000 1.3333 0.5000
1.0000 -1.0000 1.5000
A.4.5 ベクトルから行列を生成
リスト A.17 成分毎の演算>> u = [1, 2, 3]’
u =
1
2
3
>> v = [4, 5, 6]’
v =
4
5
6
% ベクトルから行列を生成>> X = [u, v]
X =
1 4
2 5
3 6
% ベクトルからベクトルを生成>> w = [u ; v]
w =
1
2
3
4
5
6
% 行列からベクトルを生成>> z = X(:)
z =
15
1
2
3
4
5
6
% 行列の 1行目をベクトルとして取得>> X(1,:)
ans =
1 4
% 行列の 1列目をベクトルとして取得>> X(:,1)
ans =
1
2
3
A.4.6 連立一次方程式の解法
リスト A.18 連立一次方程式% 係数行列と右辺ベクトルの作成>> A=rand(3,3)
A =
0.1401 0.7799 0.3927
0.7830 0.1351 0.4347
0.5467 0.9970 0.8673
>> b=rand(3,1)
b =
0.2025
0.5130
0.5067
% 連立一次方程式の解法>> x = A \ b
x =
0.5882
0.1105
0.0864
% 正しく解けているかチェック>> norm(A*x-b, inf)
ans =
1.1102e-16
連立一次方程式の解法については後でもう少し詳しく解説する.
16
A.5 2Dグラフィクス
A.5.1 関数のグラフの描画0 ≤ x ≤ 2π で関数 y = sinxのグラフを描く.そのために,xの区間の [0, 2π]を 100− 1等分して,縦ベクトル xを用意して,つぎのように入力する.すると,xと同じ大きさ縦ベクトル yで,対応する sinxの値を成分にもつものが定義される.それを,plotdで描画する.
リスト A.19 y = sinxのグラフの描画>> x = linspace(0, 2*pi, 100)’;
>> y = sin(x);
>> plot(x, y)
図 A.4 y = sinx (0 ≤ x ≤ 2π)
リスト A.19では,xや yを縦ベクトルとして扱っているが,横ベクトルとして扱っても同じ出力が得られる.後の利用との整合性のため,グラフ描画の際には縦ベクトルを使うことに決めておくと,混乱が少ないであろう*23.グラフ毎に色を指定するには,次のようにする.
リスト A.20 y = sinxのグラフの描画% 赤い実線>> plot(x, y, ’r’)
% マゼンタの破線>> plot(x, y, ’--m’)
% 青いアスタリスク>> plot(x, y, ’b*’)
*23 x は縦,y は横のようなデータでも,MATLABは受け付けてくれますが.
17
図 A.5 赤い線で描画
図 A.6 マゼンタの破線で描画
図 A.7 青いアスタリスクで描画
A.5.2 複数のグラフの描画関数を重ねるには次のようにすれば良い.
リスト A.21 y = sinx, sin(3x)のグラフの描画>> x = linspace(0, 2*pi, 100)’;
>> y1 = sin(x);
>> y2 = sin(3*x);
18
表 A.1
記号 色 記号 線種
y 黄 . 点m マゼンタ ◦ 丸c シアン × ×r 赤 + 十字g 緑 ∗ アスタリスクb 青 - –線w 白 : 点線k 黒 -. 鎖線
– 破線
% 方法 1
>> plot(x, [y1,y2])
% 方法 2
>> hold on
>> plot(x, y1)
>> plot(x, y2)
図 A.8 y = sinx, sin(3x) (0 ≤ x ≤ 2π)
方法 2のように書いておくと線の装飾が容易である.
A.5.3 格子や凡例格子の表示,凡例やタイトルの付け方は次の通り(図 A.9).
リスト A.22 格子,凡例やタイトルなど>> x = linspace(0, 2*pi, 100)’;
>> y1 = sin(x);
19
>> y2 = sin(3*x);
>> hold on
% 線を太くして描画>> plot(x, y1, ’LineWidth’,3)
>> plot(x, y2, ’LineWidth’,3)
% 図のタイトル>> title(’三角関数’)
% 軸のラベル>> xlabel(’x’)
>> ylabel(’y’)
% グラフの縦横比を 1:1に>> axis equal
% 凡例>> legend(’sin(x)’,’sin(3x)’)
% 格子>> grid on
図 A.9 格子,凡例やタイトルなどの例
A.5.4 ファイルへの保存描画したグラフをファイルに保存する.グラフを表示しているウインドウを選択した状態で,上部メニューで,� �ファイル > 保存� �
とする.出てくるウインドウで次の項目を指定すると,「指定したフォルダ」に,fig1.pdf,fig1.epsなどの名前でにファイルとして保存される.
20
図 A.10 グラフィクス・ウインドウ
項目 例
名前: fig1
形式: Portable Document Format (*.pdf)
あるいは,
項目 例
名前: fig1
形式: EPS file (*.eps)
なお,この操作は,次のようにコマンドからも行える.保存されるのは,作業中のフォルダになる.数字の “1”は,グラフのウインドウに表示されている “Figure 1”の “’1”である.
リスト A.23 グラフィクスの保存>> saveas(1,’fig1.pdf’)
>> saveas(1,’fig1.eps’)
なお,グラフィクス・ウインドウには「グラフィクス・ウインドウ番号 Figure **」が自動的に 1, 2, . . . とふられるが,これを自分で指定するときには,
リスト A.24 グラフィクス・ウインドウ番号の指定% グラフィクス番号を 5に指定>> figure(5)
とする.
21
A.6 Mファイルの利用
関数 f(x) = e−x + x2 sin(3x)のグラフを書きたいときには,前に説明したように,
リスト A.25 関数の描画>> x = linspace(0, 2*pi, 100)’;
>> y = exp(-x) + (x.^2).*sin(3*x);
>> plot(x, y)
とすれば良い
図 A.11 エディターの起動
この f(x) を,後で再度利用したいときには,これを一つの関数として定義しておくと便利である.それには次のようにする.まず,図 A.11 で示したボタンを押し,MATLAB に付属のテキストエディタを起動する(図 A.12)*24.あるいは,コマンドウインドウで,
リスト A.26 エディタの起動>> edit
とする.そして,次のリストA.27のように入力する(図A.12).
リスト A.27 func1.mの中身
% 関数 1
function y = func1(x)
y = exp(-x) + (x .^ 2) .* sin(3.0*x);
end
入力した後に,これを,例えば,func1.mという名前で保存する(図 A.13).このようなファイルをM ファイルという.これを用いて,
*24 あるいは,自分の使い慣れたテキストエディタを用いても良い.
22
図 A.12 エディタへの入力
図 A.13 ファイルの保存
リスト A.28 関数>> x = linspace(0, 2*pi, 100)’;
>> y = func1(x);
>> plot(x, y)
とすれば良い.なお,関数は一般に,� �function 答え = 関数の名前(データ)
関数の中身end� �
の形をしている.
リスト A.29 comm1.mの中身
x = linspace(0, 2*pi, 100)’;
y = func1(x);
plot(x, y, ’LineWidth’,3);
title(’三角関数’);
xlabel(’x’);
ylabel(’y’);
grid on;
23
Mファイルは作業を自動化するために使うことができる.例えば,comm1.m のようなファイルを作成し,MATLAB ウインドウ上部の 実行 ボタンを押すか,コマンドウインドウで以下のようにする:
リスト A.30 comm1.mの実行>> comm1
A.7 プログラミングと for文
MATLABでは,関数(数学の組み込み関数でなく,サブプログラム (sub-program)と呼ぶべきもの)を自前で定義することにより,プログラミングを行う.例示のために,まずは,リスト A.31のようなファイル sum-
frac1.mを作成する(中身は後で説明する).
リスト A.31 sumfrac1.mの中身
% 1からnまでの逆数の和function wa = sumfrac1(n)
wa = 0.0;
for i = 1:n
wa = wa + 1.0/i;
end
end
この関数を利用するには次のようにする.
>> sumfrac1(10)
ans =
2.9290
>> sumfrac1(100)
ans =
5.1874
さて,sumfrac1.mの中身を簡単に説明する.
wa = 0.0;
for i=1:n
wa = wa + 1.0/i;
end
の部分は for文を用いた繰り返し計算をしている.これは,
24
for文� �for i=1:n
(処理)
end� �の形をしており,まず,i=1 に対して (処理) を行い,次に,i=2 に対して (処理) を行う,これを続けていき,最後に,i=n に対して (処理) を行ったら,この for 文の処理は終了である.したがって,例えば,sumfrac1(10) を実行すると,i=1 のとき wa=0.0+1.0/1.0,i=2 のときwa=0.0+1.0/1.0+1.0/2.0 となり,これが続けられ,最後にi=10で,wa=0.0+1.0/1.0+1.0/2.0+...+1.0/10.0となり,このときの waが計算結果として表示される.
A.8 二分法と if文および while文
方程式 f(x)
def.= ex − 2x− 1 = 0
の(唯一の)正の解 x = aを計算する方法を考察する.初等的な考察により,1 < a < 2,かつ,f(1) < 0,f(2) > 0であることがわかる.二分法 (bisection method)では,まず,
[α0, β0] = [1, 2]
とする.そして,k ≥ 0に対して,
xk =1
2(αk + βk),
[αk+1, βk+1] =
{[αk, xk] (f(xk)f(βk) ≥ 0のとき)
[xk, βk] (f(xk)f(βk) < 0のとき)
と定める.このとき,
|xk − a| ≤ βk+1 − αk+1 =
(1
2
)k+1
(β0 − α0)
が成り立つ.これより,|xk − a| ≤ εを満たす近似解が欲しい
場合には,反復回数が k∗ =1
log 2log
|β − α|ε
程度必要となる
こともわかる*25.
*25 詳しくは,“齊藤宣一:数値解析入門(大学数学の入門 9)東京大学出版会,2012 年” の §4.2 を見よ(ただし,この本の対応する不等式には誤りがある.この資料の不等式が正しい.).
25
これをMATLABで実行するには,次の func2.mと bisec1.m
のような関数を作成する(自分で作成するときには, % で始まるコメント行は入力しなくて良い).
リスト A.32 func2.mの中身
% 関数 2
function y = func2(x)
y = exp(x) - 2*x - 1;
end
リスト A.33 bisec1.mの中身
% 二分法% 入力 初期区間 [a, b],許容誤差限界 ep
% 関数 fun (function で定義しておく)
% 出力 xvect=[x1, x2,...], fx=[f(x1),f(x2),...]
% xdiff = [e1, e2, ...] ek=(bk-ak)/2
function [xvect, fx, xdif] = bisec1(a, b, ep, fun)
% 最大反復回数kmax = (1.0/log(2.0))*log((b-a)/ep) + 1;
% とりあえず成分が 0個のベクトルを定義xvect=[]; fx=[]; xdif=[];
% 二分法の反復計算for k = 1:kmax
% 誤差の見積もり ek = (bk-ak)/2
xdif = [xdif ; 0.5*abs(b - a)];
% 中点xk=c=(b+a)/2を定義しf(xk)=f(c)を計算c = (a + b)/2; x = c; fc = fun(x);
xvect = [xvect ; x]; fx = [fx ; fc];
x = a;
% 新しい区間の定義if fc*fun(x)>=0.0
a=c;
else
b=c;
end % if の終了end %for の終了end
bisec1(a, b, ep, fun)の中にある,a, b, ep, funは,ユーザが与えるデータであり,これを引数と言う.ここでは,a = α0,b = β0,ep = ε,func = f(x) = ex − 2x− 1の意味で用いている.「新しい区間の定義」のために,ここでは,if 文を用いている.基本形は次の通りである.
26
if文� �if (条件)
(処理)
end� �この表現では,(条件)が成立するときには (処理)を実行する.また,
if文� �if (条件)
(処理1)
else
(処理2)
end� �という書式もある.このときには,(条件)が成立するときには(処理1)を実行し,それ以外の場合には,(処理2)を実行する.(条件)の書き方は次の通り.
a ≥ b a>=b
a ≤ b a<=b
a > b a>b
a < b a<b
a = b a==b
a ̸= b a~=b
bisec1.m を実行するには,リスト A.34 のようにすれば良い.funには既に定義してある func2.mを代入する.関数を引数として利用するには,“@func2” のように記述する.なお,1.0e-7は 1.0× 10−7 の意味である.
リスト A.34 bisec1.mの実行>> format long
>> [xvect, fx, xdif] = bisec1(1, 2, 1e-7, @func2)
xvect =
1.500000000000000
1.250000000000000
...
1.256431221961975
1.256431162357330
fx =
0.481689070338065
-0.009657042538159
...
0.000000020175239
-0.000000069998384
xdif =
0.500000000000000
27
0.250000000000000
...
0.000000119209290
0.000000059604645
なお,kmaxを使わずに,βk+1 −αk+1 ≤ εとなるまで反復を続けても同じである.このような操作を実現するには,while
文を用いる.while文の基本形は次の通りである.while文� �while (条件)
(処理)
end� �この表現では,(条件)が成立する限りにおいて (処理)を実行する.while 文を用いて bisec1.m を修正した関数が bisec2.m である.diff = βk+1 − αk+1 > εが成立している限り,反復を続けるようになっている.言い換えれば,diff ≤ εが成り立っているときには,反復を終了するのである.当然のことながら,bisec1.m と bisec2.m を用いた計算結果は同じになる.リストA.34とリスト A.36を見よ.
リスト A.35 bisec2.mの中身
% 二分法% 入力 初期区間 [a, b],許容誤差限界 ep
% 関数 fun (function で定義しておく)
% 出力 xvect=[x1, x2,...], fx=[f(x1),f(x2),...]
% xdiff = [e1, e2, ...] ek=(bk-ak)/2
function [xvect, fx, xdif] = bisec2(a, b, ep, fun)
% とりあえず成分が 0個のベクトルを定義xvect=[]; fx=[]; xdif=[];
% 初期の diff = beta_0 - alpha_0 を計算しておくdiff = b - a;
% 二分法の反復計算while diff > ep
% 誤差の見積もり ek = (bk-ak)/2
xdif = [xdif ; 0.5*abs(diff)];
% 中点xk=c=(b+a)/2を定義しf(xk)=f(c)を計算c = (a + b)/2; x = c; fc = fun(x);
xvect = [xvect ; x]; fx = [fx ; fc];
x = a;
% 新しい区間の定義if fc*fun(x)>=0.0
a=c;
else
b=c;
end % if の終了% diff = beta_{k+1} - alpha_{k+1}
28
diff = b - a;
end %while の終了end
リスト A.36 bisec2.mの実行>> [xvect, fx, xdif] = bisec2(1, 2, 1e-7, @func2)
xvect =
1.500000000000000
1.250000000000000
...
1.256431221961975
1.256431162357330
fx =
0.481689070338065
-0.009657042538159
...
0.000000020175239
-0.000000069998384
xdif =
0.500000000000000
0.250000000000000
...
0.000000119209290
0.000000059604645
A.9 応用:Fourier級数の収束
いままでのまとめとして,関数
f(x) = π − |x| (−π ≦ x ≦ π)
の Fourier級数展開
f(x) =π
2+
4
π
(cosx
12+
cos 3x
32+
cos 5x
52+ · · ·
)の収束の様子を図示する関数を作成しよう.そのために,第 n
項までの部分和
Sn(x) =π
2+
4
π
n∑i=1
cos((2i− 1)x)
(2i− 1)2
を考える.
リスト A.37 four1.mの中身
% Fourier 級数の例題 1
function y = four1(x, n)
y = cos(x);
29
for i=2:n
y = y + cos((2*i-1)*x)/((2*i-1)^2);
end
y = pi/2.0 + (4.0/pi)*y;
end
リスト A.38 four draw1.mの中身
% Fourier 級数の描画 (指定された n のみ)
function four_draw1(n, fun, m)
x = linspace(-1.5*pi, 1.5*pi, m)’;
y = fun(x, n);
figure(1); plot(x, y);
axis equal;
grid on; title(’フーリエ級数の収束’);
xlabel(’x’); ylabel(’y’);
saveas(1,’four1.pdf’);
% saveas(1,’four1.eps’);
end
リスト A.39 four draw2.mの中身
% Fourier 級数の描画 (n = 1, 10, 20, 50のみ)
function four_draw2(fun, m)
x = linspace(-1.5*pi, 1.5*pi, m)’;
yy = [];
y = fun(x, 1); yy = [yy, y];
y = fun(x, 10); yy = [yy, y];
y = fun(x, 20); yy = [yy, y];
y = fun(x, 50); yy = [yy, y];
figure(1); plot(x, yy);
axis equal;
grid on; title(’フーリエ級数の収束’);
xlabel(’x’); ylabel(’y’);
legend(’n=1’,’n=10’,’n=20’,’n=50’)
saveas(1,’four2.pdf’);
% saveas(1,’four2.eps’);
end
簡単に説明すると,four1(x, n) では,与えられた x = x
と n = nに対して,最初の endが終了した時点で,
y =n∑
i=1
cos((2i− 1)x)
(2i− 1)2
を計算している.そして,最終的な答えとして,
π
2+
4
πy
を出力するのである.
30
一方,four_draw1(n, fun, m) では,与えた n = n に対して,y = Sn(x) のグラフを描画する.そのために,区間[− 3
2π,32π] を m − 1 等分してベクトル x を作り,描画用の
データ (x, y)を作る.また,描画の後に,結果を four1.pdf
または textttfour1.eps と言う名前のファイルに保存する.four_draw2(fun, m) では,n = 1, 10, 20, 50 に対して,y =
Sn(x) のグラフを重ねて描画し,,結果を four2.pdf またはtextttfour2.eps と言う名前のファイルに保存する.fun には,上で作った four1(x, n)を与えれば良い.これらを実行するにはリスト A.40 のようにする.結果は,図 A.14と図 A.15となる.
リスト A.40 four draw1.mと four draw2.mの実行>> four_draw1(10, @four1, 100)
>> four_draw2(@four1, 100)
図 A.14 four draw1(10, @four1, 100)の結果.
A.10 ファイルへの入出力
A.10.1 出力2つのベクトルのデータを,test.txtに書き込む.
リスト A.41 データの作成とファイルへの書き込み>> x=[1,2,3,4];
>> y=[5,6,7,8];
>> z=[x;y]
z =
1 2 3 4
5 6 7 8
31
図 A.15 four draw2(@four1, 100)の結果.
>> F1 = fopen(’test.txt’,’w’);
>> fprintf(F1,’%f %f\n’,z);
>> fclose(F1);
実際に,test.txt の中身は次のようになっている(元々のzの形との違いに注意せよ).
test.txt� �1.000000 5.000000
2.000000 6.000000
3.000000 7.000000
4.000000 8.000000� �A.10.2 入力先ほど作成した test.txtからデータを読み込む.
リスト A.42 ファイルからのデータの読み込み>> F1 = fopen(’test.txt’,’r’);
>> zz = fscanf(F1,’%f %f’,[2 Inf])
zz =
1 2 3 4
5 6 7 8
>> fclose(F1);
fscanf の最後の引数では,読み込むデータの行数を指定する.%inf はデータがある限り読み込むよう指定する命令である.
32
A.11 プログラミングにおける注意
2つの行列 A = (aij), B = (bij) ∈ RN×N の積 C = AB を計算する際に,
1. C の各成分を Aと B の成分を使って直接計算する:
cij =N∑
k=1
aikbkj .
2. MATLABのコマンドで計算する:C=A*B.
の 2通りの計算の仕方がある(→リスト A.43).
リスト A.43 comp prod1.mの中身
function comp_prod1(N)
% 乱数を用いて行列を定義A=rand(N,N); B=rand(N,N);
% 行列Cを定義しておくC=zeros(N,N);
% 成分を直接計算してC=ABを計算するtic
for i=1:N
for j=1:N
for k=1:N
C(i,j) = C(i,j) + A(i,k)*B(k,j);
end
end
end
toc;
% MATLABのコマンドで C=ABを計算するtic
C=A*B;
toc;
end
これらの方法を比較するために,実行時間の計測をしてみよう.そのためには,ticと tocを使う.� �tic; (コマンド) toc;� �これで,(コマンド)が実行される時間が計測できる.
リスト A.44 行列積の計算時間の比較>> comp_prod1(10)
経過時間は 0.001856 秒です.経過時間は 0.050425 秒です.>> comp_prod1(10)
33
経過時間は 0.001179 秒です.経過時間は 0.000051 秒です.>> comp_prod1(10)
経過時間は 0.000142 秒です.経過時間は 0.000097 秒です.>> comp_prod1(100)
経過時間は 0.007502 秒です.経過時間は 0.008514 秒です.>> comp_prod1(100)
経過時間は 0.010103 秒です.経過時間は 0.005795 秒です.>> comp_prod1(100)
経過時間は 0.009108 秒です.経過時間は 0.000146 秒です.>> comp_prod1(200)
経過時間は 0.047880 秒です.経過時間は 0.001439 秒です.>> comp_prod1(500)
経過時間は 0.419640 秒です.経過時間は 0.012738 秒です.
実際に何度か計算した結果が,リスト A.44 である.MAT-
LABでは “ベクトル化演算”が採用されているので,成分を持ち出さずに行列・ベクトルのまま表現した方が,処理が一般*26
には速い.ただし,この講義で行う計算で,その違いを実感するのは難しいので,あまり気にする必要はないが,折に触れて,プログラミングの上手な人の書いたものを参考にする姿勢は重要である.
A.12 連立一次方程式の解法: LU分解
連立一次方程式
Ax = b ⇔n∑
j=1
aijxj = bi (1 ≤ i ≤ n)
の解法については既に述べたが,本節ではもう少し踏み込んだ説明をする*27.Aが正則行列であれば,
PA = LU
*26 原則として,ということであり,絶対にということではありません.MATLAB内では様々な技巧が駆使されているので,単純に比較するのは難しいです.リスト A.44 の比較も,実行するコンピュータやタイミングで結果は異なります.
*27 講義では詳しく触れなかったので,その補足の目的がある.
34
の形に分解が可能である*28.これを,LU分解と言う.ただし,Lは対角成分がすべて 1であるような下三角行列,U は上三角行列,P は置換行列である.A = (aij) ∈ Rn×n が正定値実対称行列,あるいは,狭義優対角行列
|aii| >∑j ̸=i
|aij | (1 ≤ i ≤ n) (11)
のときには,P = I とできる*29.このとき,連立一次方程式を,
LUx = Pb ⇔
{Ly = Pb
Ux = y
と書き直すことができる.そして,Ly = Pbを解いた後,この結果を用いて Ux = y を解いて xを求める.
リスト A.45 LU分解に基づく連立一次方程式の解法>> A = [1, 4, 2; 3, -1, 0; 1, 1, 3];
>> b = [1; 2; 3];
% LU分解>> [L ,U, P] = lu(A)
L =
1.0000 0 0
0.3333 1.0000 0
0.3333 0.3077 1.0000
U =
3.0000 -1.0000 0
0 4.3333 2.0000
0 0 2.3846
P =
0 1 0
1 0 0
0 0 1
% Ly=Pbの解法>> y = L \ P*b
y =
2.0000
0.3333
2.2308
% Ux=yの解法>> x = U \ y
x =
0.5484
-0.3548
0.9355
*28 齊藤宣一:数値解析入門 (東大出版,2012年)の定理 2.6.2を見よ.*29 齊藤宣一:数値解析入門 (東大出版,2012年)の定理 2.4.2と定理 2.5.1
を見よ.
35
% 残差のチェック>> norm(b-A*x)
ans =
0
% 次のように一度に書いても良い>> x = U \ (L \ P*b)
x =
0.5484
-0.3548
0.9355
% 残差のチェック>> norm(b-A*x)
ans =
0
それぞれの部分で必要とされる乗除算回数を数えてみると次のようになる.
• LU分解:
n−1∑k=1
(n− k + 1)(n− k) =1
3n(n− 1)(n+ 1) ∼ 1
3n3.
• Ly = Pbの解法:
n∑k=2
(k − 1) =1
2n(n− 1) ∼ 1
2n2.
• Ux = y の解法:
n∑k=1
{1 + (n− k)} =1
2n(n+ 1) ∼ 1
2n2.
ここで,一般に,an と bn に対して, limn→∞
(an/bn) = 1となることを,an ∼ bnと書いている.したがって,Ax = bを解くのに要する乗除算の回数は,おおよそ n3/3 + n2 ∼ n3/3となる.MATLABの関数 randを用いて,
A = nI + rand(n,n) ∈ Rn×n
の形の行列を考え (これは,(11)を満たす),実際に LU分解をするのに要する時間を計測する (リスト A.46).A を取り替えて 3回同じ計算をした結果を描画する.結果は,図 A.16のようになる.
リスト A.46 lutime.mの中身
function lutime(N)
x=[]; y1=[]; y2=[]; y3=[]; z=[];
36
for n=1:20:N+1
% 1
A=n*eye(n,n)+rand(n,n); tic; [L,U,P]=lu(A);
m=toc; x=[x;n]; y1=[y1;m]; z=[z;n^3/3];
%2
A=n*eye(n,n)+rand(n,n); tic; [L,U,P]=lu(A);m=toc; y2=[
y2;m];
%3
A=n*eye(n,n)+rand(n,n); tic; [L,U,P]=lu(A);m=toc; y3=[
y3;m];
end
%
z=(3/(n^3))*m*z;
%
figure(1); hold on;
plot(x,y1,’b-’,’LineWidth’,2);
plot(x,y2,’r-’,’LineWidth’,2);
plot(x,y3,’g-’,’LineWidth’,2);
plot(x,z,’k--’);
xlabel("size n"); ylabel("time [sec]");
legend(’LU1’,’LU2’,’LU3’,’(Const.)n^3/3’); grid on;
saveas(1,’lutime.pdf’);
end
図 A.16 LU分解をするのに要する時間
Ax(l) = b(l) (l = 1, 2, . . . ,m)を解くという問題を考えよう.特に,b(l) が,b(l−1) と x(l−1) から定義されることを想定する(もちろん,b(1) は与えられる).したがって,計算を並列的に行うことはできず,逐次的にしなければならない.このとき,各 l に対して,ガウスの消去法で解を求めると,すべての計算を終えるのに必要な乗除算の回数は mn3/3 となる.一方で,LU 分解をはじめに一回だけ行い,各 l に対しては,算出された L と U を用いて前進消去,後退代入のみを行うと,全体で
37
は,n3/3 +mn2 回程度の乗除算を行うことになる.この差はm が十分に大きいとき,例えば m ∼ n の際には深刻である.
実際, n · n3/3
n3/3 + n · n2∼ n
4であり,(n/4) 倍もの差が生じてし
まうのである.
— 以上 —
38
付録 B Durand–Kerner法と Gauss型積分公式の実装
B.1 Durand–Kerner法の実装
n ≥ 1を整数,cj ∈ C (j = 0, . . . , n)とする.n次の代数方程式
f(z) = zn + c1zn−1 + c2z
n−2 + · · ·+ cn−1z + cn = 0
= (z − a1)(z − a2) · · · (z − an)
の n 個の複素根 a1, . . . , an を数値的に求めるための Durand–
Kerner(DK)法とは,反復列 z(k) = (z(k)1 , . . . , z
(k)n )を,
z(k+1)j = z
(k)j −
f(z(k)j )∏
i ̸=j
(z(k)j − z
(k)i )
(j = 1, . . . , n)
で生成する方法である.z(0) = (z
(0)1 , . . . , z
(0)n )としては,n個の解 a1, . . . , an を含む
ような複素平面上の円盤 |z − β| ≤ Rを構成し,円周上を等分割した点
z(0)j = β +R exp
[i
(2π(j − 1)
n+ γ
)](j = 1, . . . , n)
を採用することが多い.これを,Aberth の方法と言う.γ は適当な実数である.
MATLABでは,例えば,z =
z1
z2
z3
に対して,
z − zT =
0 z1 − z2 z1 − z3z2 − z1 0 z2 − z3z3 − z1 z3 − z2 0
と計算されることを利用する.すなわち,行列
z(k) − (z(k))T + I
の第 i 行の積がちょうど∏j ̸=i
(z(k)i − z
(k)j ) となる.積を計算す
るには,prod(A,2) を利用すれば良い.これは,行列 A の各行の積を成分とする列ベクトルを返すコマンドである.なお,
39
MATLAB では,w が複素ベクトルのとき,w’ は w の共役転置を表すので,単なる転置を取る際には,transpose(w)とする.*30
DK法のプログラムをリスト B.1に示す.
リスト B.1 durand kerner1.m
% Durand-Kerner method
function [roots, it] = durand_kerner1(func, n, beta, r,
kmax, tol)
% Aberthの方法による初期値の設定% betaと rは別に計算して与える or beta=0, r十分大とするgamma=1.7;
xig = beta+r*transpose(exp(1.0i*(2*pi/n*(0:n-1)+gamma
)));
xx=[xig];
% Newton iteration
x=xig; k=0; dif=tol+1; len = length(x);
while k<kmax && dif>tol
f=func(x); df = prod(x-transpose(x)+eye(len),2);
if norm(df,inf)<1.0e-15
error("df/dx=0");
end
xnew=x-f./df; dif=norm(f,inf); x=xnew; k=k+1; xx=[xx,
xnew];
end
% 計算結果roots = x; it = k;
% 結果の図示% Aberthの円を黒点線で描くt = linspace(0,2*pi,200); xi=beta+r*exp(1i*t);
plot(real(xi),imag(xi),’k--’); hold on;
% Durand-Kerner法の反復列for j=1:len
plot(real(xx(j,:)),imag(xx(j,:)),’b.’,’MarkerSize’
,15);
end
% 最終結果plot(real(xnew),imag(xnew),’rx’,’MarkerSize’,20,’
LineWidth’,3);
% 図の装飾grid on;axis equal;xlabel("Real"); ylabel("Imaginary");
saveas(1,’durand_kerner1.pdf’);
end
*30 私がはじめにMATLAB で DK 法の計算をしようとしたとき,このことに気がつかず,随分悩んだ.
40
例題として,方程式
f(z) = (z + 2− i)(z + 2 + i)(z − 3− 2i)(z − 1)(z − 2)
= z5 − 2(1 + i)z4 − 2(4 + i)z3 + 2(4 + 5i)z2
+ (31 + 14i)z − 30− 20i = 0
を DK法で解こう(リスト B.2を見よ).この方程式のすべての根は,中心 β = 2
5 + 25 i,半径 R = 3.4 の円盤内にある.*31
あるいは,あまり深く考えずに,β = 0,R = 10などとしてみる.結果をリスト B.3と図 B.1に示す.
リスト B.2 func39.m
function y=func39(x)
% r=[-2+i,-2-i,1,2,3+2*i]
% p= poly2sym(sym(poly(r)));
y=x.^5 - x.^4.*(2 + 2i) - x.^3*(8 + 2i) + x.^2*(8 + 10i
) + x.*(31 + 14i) - (30 + 20i);
end
リスト B.3 DK法の実行>> [roots,it] = durand_kerner1(@func39, 5, 2/5+2*i/5,
3.4, 20, 1e-12)
roots =
1.0000 + 0.0000i
-2.0000 + 1.0000i
-2.0000 - 1.0000i
2.0000 + 0.0000i
3.0000 + 2.0000i
it =
9
>> [roots,it] = durand_kerner1(@func39, 5, 0, 10, 20, 1
e-12)
roots =
1.0000 + 0.0000i
-2.0000 + 1.0000i
-2.0000 - 1.0000i
2.0000 - 0.0000i
3.0000 + 2.0000i
it =
14
*31 齊藤宣一:数値解析 (共立出版,2017年)の §1.6を見よ.
41
β = 25 + 2
5 i, R = 3.4 β = 0, R = 10
図 B.1 方程式 f(z) = z5 − 2(1+ i)z4 − 2(4+ i)z3 +2(4+
5i)z2 + (31 + 14i)z − 30− 20i = 0の根を DK法で求める.
B.2 Gauss型積分公式の実装
[a, b] 上で重み関数 w(x) に対する直交多項式系 {ϕk}k≥0 を考える.ϕn+1(x) = 0の根を x0, x1, . . . , xn とし
Wi =
∫ b
a
w(x)∏j ̸=i
x− xj
xj − xidx
と定める.このとき,関数 f(x)に対する Gauss型積分公式は∫ b
a
w(x)f(x) dx ≈ Qw,n(f) =n∑
i=0
Wif(xi)
で与えられる.Gauss型積分公式を実装してみよう.区間 [0, 1]上の重み関数 w(x) = 1に対する直交多項式は以下のようになる.
ϕ0(x) = 1,
ϕ1(x) = 2x− 1,
ϕ2(x) = 6x2 − 6x+ 1,
ϕ3(x) = 20x3 − 30x2 + 12x− 1.
リスト B.4 poly2.m
% function for Gauss quadrature deg =2
function y = ploy2(x)
y = (6*x.^2 - 6*x + 1)/6;
end
リスト B.5 poly3.m
% function for Gauss quadrature deg =3
42
function y = ploy3(x)
y = (20*x.^3 - 30*x.^2 + 12*x - 1) / 20;
end
これらの多項式 ϕn+1(x) = 0 の根 x0, . . . , xn を求めるために,Durand–Kerner 法を用いる.すななわち,z(k) =
(z(k)0 , . . . , z
(k)n )T を,
z(k+1)j = z
(k)j −
ϕn+1(z(k)j )∏
j ̸=i(z(k)i − z
(k)j )
(j = 0, . . . , n)
で生成する.
リスト B.6 dk1.m
% Durand-Kerner method
function roots = dk1(func, kmax, tol, xig)
% Newton iteration
x=xig; k=0; dif=tol+1;
len = length(x);
while k<kmax && dif>tol
f=func(x); df = prod(x-transpose(x)+eye(len),2);
if norm(df,inf)<1.0e-15
error("df/dx=0");
end
xnew=x-f./df; dif=norm(f,inf); x=xnew; k=k+1;
end
roots = x;
end
一方で,重みW0, . . . ,Wn の計算には以下の関係を用いる:1 1 1 · · · 1x0 x1 x2 · · · xn
x20 x2
0 x20 · · · x2
n...
. . ....
xn0 xn
1 xn2 · · · xn
n
W0
W1
W2
...Wn
=
11/21/3...
1/(n+ 1)
. (12)
x0, . . . , xn を与えたとき方程式 (12) を解いて W0, . . . ,Wn
を返すプログラムをリスト B.7 に示す.また,以上の準備に基づいて Gauss 型公式を実行するプログラムをリスト B.8 に示す.
リスト B.7 get weight.m
function weights = get_weight(nodes)
len=length(nodes);
weights=fliplr(vander(nodes))’\(1./(1:len)’);
end
43
リスト B.8 gauss.m
function integ = gauss(func,nodes,weights)
integ = dot(func(nodes), weights);
end
発展問題 5の積分Q5を計算してみよう (リスト B.9).なお,NIvalues.mは第 5回の課題で用いた.
リスト B.9 Gauss型積分の実行>> NIvalues
>> node2 = dk1(@poly2,100,1.0e-12,rand(2,1))
node2 =
0.788675134594813
0.211324865405187
>> weight2 = get_weight(node2)
weight2 =
0.500000000000000
0.500000000000000
>> gauss(@func45,node2,weight2)
ans =
1.028191591450871
>> gauss(@func45,node2,weight2) - Q5
ans =
0.008980893742497
>> node3 = dk1(@poly3,100,1.0e-12,rand(3,1))
node3 =
0.112701665379258
0.887298334620742
0.500000000000000
>> weight3 = get_weight(node3)
weight3 =
0.277777777777777
0.277777777777777
0.444444444444445
>> gauss(@func45,node3,weight3)
ans =
1.019505216742847
>> gauss(@func45,node3,weight3) - Q5
ans =
2.945190344731952e-04
— 以上 —
44